From c75b4af1a2630ace445da1ec661191601583f79a Mon Sep 17 00:00:00 2001 From: jhendersonHDF Date: Tue, 2 May 2023 14:52:39 -0500 Subject: Add initial version of HDF5 API tests (#2877) --- .github/workflows/codespell.yml | 2 +- CMakeLists.txt | 54 +- hl/c++/test/Makefile.am | 2 +- test/API/CMake/CheckAsan.cmake | 37 + test/API/CMake/CheckUbsan.cmake | 37 + test/API/CMakeLists.txt | 314 + test/API/H5_api_async_test.c | 2730 ++ test/API/H5_api_async_test.h | 29 + test/API/H5_api_attribute_test.c | 11027 ++++++++ test/API/H5_api_attribute_test.h | 203 + test/API/H5_api_dataset_test.c | 11683 ++++++++ test/API/H5_api_dataset_test.h | 331 + test/API/H5_api_datatype_test.c | 2693 ++ test/API/H5_api_datatype_test.h | 79 + test/API/H5_api_file_test.c | 2564 ++ test/API/H5_api_file_test.h | 85 + test/API/H5_api_group_test.c | 2394 ++ test/API/H5_api_group_test.h | 65 + test/API/H5_api_link_test.c | 27072 +++++++++++++++++++ test/API/H5_api_link_test.h | 437 + test/API/H5_api_misc_test.c | 1060 + test/API/H5_api_misc_test.h | 52 + test/API/H5_api_object_test.c | 7172 +++++ test/API/H5_api_object_test.h | 191 + test/API/H5_api_test.c | 227 + test/API/H5_api_test.h | 73 + test/API/H5_api_test_config.h.in | 66 + test/API/H5_api_test_util.c | 819 + test/API/H5_api_test_util.h | 24 + test/API/H5_api_tests_disabled.h | 46 + test/API/README.md | 86 + test/API/driver/CMakeLists.txt | 17 + test/API/driver/h5_api_test_driver.cxx | 910 + test/API/driver/h5_api_test_driver.hxx | 93 + test/API/driver/kwsys/.clang-format | 22 + test/API/driver/kwsys/.hooks-config | 2 + test/API/driver/kwsys/Base64.c | 225 + test/API/driver/kwsys/Base64.h.in | 110 + test/API/driver/kwsys/CMakeLists.txt | 1260 + test/API/driver/kwsys/CONTRIBUTING.rst | 49 + test/API/driver/kwsys/CTestConfig.cmake | 9 + test/API/driver/kwsys/CTestCustom.cmake.in | 14 + test/API/driver/kwsys/CommandLineArguments.cxx | 768 + test/API/driver/kwsys/CommandLineArguments.hxx.in | 270 + test/API/driver/kwsys/Configure.h.in | 89 + test/API/driver/kwsys/Configure.hxx.in | 65 + test/API/driver/kwsys/ConsoleBuf.hxx.in | 398 + test/API/driver/kwsys/Copyright.txt | 38 + test/API/driver/kwsys/Directory.cxx | 236 + test/API/driver/kwsys/Directory.hxx.in | 72 + test/API/driver/kwsys/DynamicLoader.cxx | 495 + test/API/driver/kwsys/DynamicLoader.hxx.in | 106 + test/API/driver/kwsys/Encoding.h.in | 69 + test/API/driver/kwsys/Encoding.hxx.in | 80 + test/API/driver/kwsys/EncodingC.c | 72 + test/API/driver/kwsys/EncodingCXX.cxx | 288 + test/API/driver/kwsys/ExtraTest.cmake.in | 1 + test/API/driver/kwsys/FStream.cxx | 55 + test/API/driver/kwsys/FStream.hxx.in | 278 + test/API/driver/kwsys/GitSetup/.gitattributes | 6 + test/API/driver/kwsys/GitSetup/LICENSE | 202 + test/API/driver/kwsys/GitSetup/NOTICE | 5 + test/API/driver/kwsys/GitSetup/README | 87 + test/API/driver/kwsys/GitSetup/config | 4 + test/API/driver/kwsys/GitSetup/config.sample | 32 + test/API/driver/kwsys/GitSetup/git-gerrit-push | 74 + test/API/driver/kwsys/GitSetup/git-gitlab-push | 177 + test/API/driver/kwsys/GitSetup/pre-commit | 26 + test/API/driver/kwsys/GitSetup/setup-aliases | 6 + test/API/driver/kwsys/GitSetup/setup-gerrit | 147 + test/API/driver/kwsys/GitSetup/setup-gitlab | 140 + test/API/driver/kwsys/GitSetup/setup-hooks | 64 + test/API/driver/kwsys/GitSetup/setup-ssh | 111 + test/API/driver/kwsys/GitSetup/setup-stage | 82 + test/API/driver/kwsys/GitSetup/setup-upstream | 104 + test/API/driver/kwsys/GitSetup/setup-user | 39 + test/API/driver/kwsys/GitSetup/tips | 55 + test/API/driver/kwsys/Glob.cxx | 448 + test/API/driver/kwsys/Glob.hxx.in | 134 + test/API/driver/kwsys/IOStream.cxx | 255 + test/API/driver/kwsys/IOStream.hxx.in | 126 + test/API/driver/kwsys/MD5.c | 494 + test/API/driver/kwsys/MD5.h.in | 97 + test/API/driver/kwsys/Process.h.in | 544 + test/API/driver/kwsys/ProcessUNIX.c | 2920 ++ test/API/driver/kwsys/ProcessWin32.c | 2786 ++ test/API/driver/kwsys/README.rst | 37 + test/API/driver/kwsys/RegularExpression.cxx | 1218 + test/API/driver/kwsys/RegularExpression.hxx.in | 562 + test/API/driver/kwsys/SetupForDevelopment.sh | 20 + test/API/driver/kwsys/SharedForward.h.in | 879 + test/API/driver/kwsys/String.c | 100 + test/API/driver/kwsys/String.h.in | 57 + test/API/driver/kwsys/String.hxx.in | 65 + test/API/driver/kwsys/System.c | 236 + test/API/driver/kwsys/System.h.in | 60 + test/API/driver/kwsys/SystemInformation.cxx | 5466 ++++ test/API/driver/kwsys/SystemInformation.hxx.in | 170 + test/API/driver/kwsys/SystemTools.cxx | 4703 ++++ test/API/driver/kwsys/SystemTools.hxx.in | 981 + test/API/driver/kwsys/Terminal.c | 414 + test/API/driver/kwsys/Terminal.h.in | 170 + test/API/driver/kwsys/clang-format.bash | 128 + test/API/driver/kwsys/hash_fun.hxx.in | 166 + test/API/driver/kwsys/hash_map.hxx.in | 423 + test/API/driver/kwsys/hash_set.hxx.in | 392 + test/API/driver/kwsys/hashtable.hxx.in | 995 + test/API/driver/kwsys/kwsysHeaderDump.pl | 41 + test/API/driver/kwsys/kwsysPlatformTests.cmake | 216 + test/API/driver/kwsys/kwsysPlatformTestsC.c | 108 + test/API/driver/kwsys/kwsysPlatformTestsCXX.cxx | 335 + test/API/driver/kwsys/kwsysPrivate.h | 34 + test/API/driver/kwsys/testCommandLineArguments.cxx | 209 + .../API/driver/kwsys/testCommandLineArguments1.cxx | 93 + test/API/driver/kwsys/testConfigure.cxx | 30 + test/API/driver/kwsys/testConsoleBuf.cxx | 782 + test/API/driver/kwsys/testConsoleBuf.hxx | 17 + test/API/driver/kwsys/testConsoleBufChild.cxx | 55 + test/API/driver/kwsys/testDirectory.cxx | 110 + test/API/driver/kwsys/testDynamicLoader.cxx | 133 + test/API/driver/kwsys/testDynload.c | 13 + test/API/driver/kwsys/testDynloadImpl.c | 10 + test/API/driver/kwsys/testDynloadImpl.h | 15 + test/API/driver/kwsys/testDynloadUse.c | 15 + test/API/driver/kwsys/testEncode.c | 67 + test/API/driver/kwsys/testEncoding.cxx | 286 + test/API/driver/kwsys/testFStream.cxx | 113 + test/API/driver/kwsys/testFail.c | 24 + test/API/driver/kwsys/testHashSTL.cxx | 64 + test/API/driver/kwsys/testProcess.c | 728 + test/API/driver/kwsys/testSharedForward.c.in | 27 + test/API/driver/kwsys/testSystemInformation.cxx | 106 + test/API/driver/kwsys/testSystemTools.bin | Bin 0 -> 766 bytes test/API/driver/kwsys/testSystemTools.cxx | 1128 + test/API/driver/kwsys/testSystemTools.h.in | 12 + test/API/driver/kwsys/testTerminal.c | 22 + test/API/driver/kwsys/update-gitsetup.bash | 20 + test/API/driver/kwsys/update-third-party.bash | 169 + test/API/tarray.c | 2250 ++ test/API/tattr.c | 11929 ++++++++ test/API/tchecksum.c | 251 + test/API/tconfig.c | 199 + test/API/tcoords.c | 724 + test/API/testhdf5.c | 729 + test/API/testhdf5.h | 349 + test/API/tfile.c | 8381 ++++++ test/API/tgenprop.c | 2201 ++ test/API/th5o.c | 1889 ++ test/API/th5s.c | 3538 +++ test/API/tid.c | 1413 + test/API/titerate.c | 1263 + test/API/tmisc.c | 6349 +++++ test/API/trefer.c | 3641 +++ test/API/tselect.c | 16314 +++++++++++ test/API/ttime.c | 231 + test/API/tunicode.c | 867 + test/API/tvlstr.c | 1013 + test/API/tvltypes.c | 3268 +++ test/CMakeLists.txt | 20 + test/h5test.c | 7 + test/h5test.h | 72 +- test/vol.c | 62 +- testpar/API/CMakeLists.txt | 279 + testpar/API/H5_api_async_test_parallel.c | 3668 +++ testpar/API/H5_api_async_test_parallel.h | 29 + testpar/API/H5_api_attribute_test_parallel.c | 47 + testpar/API/H5_api_attribute_test_parallel.h | 20 + testpar/API/H5_api_dataset_test_parallel.c | 8149 ++++++ testpar/API/H5_api_dataset_test_parallel.h | 20 + testpar/API/H5_api_datatype_test_parallel.c | 47 + testpar/API/H5_api_datatype_test_parallel.h | 20 + testpar/API/H5_api_file_test_parallel.c | 367 + testpar/API/H5_api_file_test_parallel.h | 20 + testpar/API/H5_api_group_test_parallel.c | 47 + testpar/API/H5_api_group_test_parallel.h | 20 + testpar/API/H5_api_link_test_parallel.c | 47 + testpar/API/H5_api_link_test_parallel.h | 20 + testpar/API/H5_api_misc_test_parallel.c | 47 + testpar/API/H5_api_misc_test_parallel.h | 20 + testpar/API/H5_api_object_test_parallel.c | 47 + testpar/API/H5_api_object_test_parallel.h | 20 + testpar/API/H5_api_test_parallel.c | 338 + testpar/API/H5_api_test_parallel.h | 188 + testpar/API/t_bigio.c | 1942 ++ testpar/API/t_chunk_alloc.c | 512 + testpar/API/t_coll_chunk.c | 1417 + testpar/API/t_coll_md_read.c | 654 + testpar/API/t_dset.c | 4335 +++ testpar/API/t_file.c | 1032 + testpar/API/t_file_image.c | 371 + testpar/API/t_filter_read.c | 564 + testpar/API/t_mdset.c | 2814 ++ testpar/API/t_ph5basic.c | 192 + testpar/API/t_prop.c | 646 + testpar/API/t_pshutdown.c | 150 + testpar/API/t_shapesame.c | 4516 ++++ testpar/API/t_span_tree.c | 2622 ++ testpar/API/testphdf5.c | 1007 + testpar/API/testphdf5.h | 343 + testpar/CMakeLists.txt | 20 + 200 files changed, 212642 insertions(+), 49 deletions(-) create mode 100644 test/API/CMake/CheckAsan.cmake create mode 100644 test/API/CMake/CheckUbsan.cmake create mode 100644 test/API/CMakeLists.txt create mode 100644 test/API/H5_api_async_test.c create mode 100644 test/API/H5_api_async_test.h create mode 100644 test/API/H5_api_attribute_test.c create mode 100644 test/API/H5_api_attribute_test.h create mode 100644 test/API/H5_api_dataset_test.c create mode 100644 test/API/H5_api_dataset_test.h create mode 100644 test/API/H5_api_datatype_test.c create mode 100644 test/API/H5_api_datatype_test.h create mode 100644 test/API/H5_api_file_test.c create mode 100644 test/API/H5_api_file_test.h create mode 100644 test/API/H5_api_group_test.c create mode 100644 test/API/H5_api_group_test.h create mode 100644 test/API/H5_api_link_test.c create mode 100644 test/API/H5_api_link_test.h create mode 100644 test/API/H5_api_misc_test.c create mode 100644 test/API/H5_api_misc_test.h create mode 100644 test/API/H5_api_object_test.c create mode 100644 test/API/H5_api_object_test.h create mode 100644 test/API/H5_api_test.c create mode 100644 test/API/H5_api_test.h create mode 100644 test/API/H5_api_test_config.h.in create mode 100644 test/API/H5_api_test_util.c create mode 100644 test/API/H5_api_test_util.h create mode 100644 test/API/H5_api_tests_disabled.h create mode 100644 test/API/README.md create mode 100644 test/API/driver/CMakeLists.txt create mode 100644 test/API/driver/h5_api_test_driver.cxx create mode 100644 test/API/driver/h5_api_test_driver.hxx create mode 100644 test/API/driver/kwsys/.clang-format create mode 100644 test/API/driver/kwsys/.hooks-config create mode 100644 test/API/driver/kwsys/Base64.c create mode 100644 test/API/driver/kwsys/Base64.h.in create mode 100644 test/API/driver/kwsys/CMakeLists.txt create mode 100644 test/API/driver/kwsys/CONTRIBUTING.rst create mode 100644 test/API/driver/kwsys/CTestConfig.cmake create mode 100644 test/API/driver/kwsys/CTestCustom.cmake.in create mode 100644 test/API/driver/kwsys/CommandLineArguments.cxx create mode 100644 test/API/driver/kwsys/CommandLineArguments.hxx.in create mode 100644 test/API/driver/kwsys/Configure.h.in create mode 100644 test/API/driver/kwsys/Configure.hxx.in create mode 100644 test/API/driver/kwsys/ConsoleBuf.hxx.in create mode 100644 test/API/driver/kwsys/Copyright.txt create mode 100644 test/API/driver/kwsys/Directory.cxx create mode 100644 test/API/driver/kwsys/Directory.hxx.in create mode 100644 test/API/driver/kwsys/DynamicLoader.cxx create mode 100644 test/API/driver/kwsys/DynamicLoader.hxx.in create mode 100644 test/API/driver/kwsys/Encoding.h.in create mode 100644 test/API/driver/kwsys/Encoding.hxx.in create mode 100644 test/API/driver/kwsys/EncodingC.c create mode 100644 test/API/driver/kwsys/EncodingCXX.cxx create mode 100644 test/API/driver/kwsys/ExtraTest.cmake.in create mode 100644 test/API/driver/kwsys/FStream.cxx create mode 100644 test/API/driver/kwsys/FStream.hxx.in create mode 100644 test/API/driver/kwsys/GitSetup/.gitattributes create mode 100644 test/API/driver/kwsys/GitSetup/LICENSE create mode 100644 test/API/driver/kwsys/GitSetup/NOTICE create mode 100644 test/API/driver/kwsys/GitSetup/README create mode 100644 test/API/driver/kwsys/GitSetup/config create mode 100644 test/API/driver/kwsys/GitSetup/config.sample create mode 100644 test/API/driver/kwsys/GitSetup/git-gerrit-push create mode 100644 test/API/driver/kwsys/GitSetup/git-gitlab-push create mode 100644 test/API/driver/kwsys/GitSetup/pre-commit create mode 100644 test/API/driver/kwsys/GitSetup/setup-aliases create mode 100644 test/API/driver/kwsys/GitSetup/setup-gerrit create mode 100644 test/API/driver/kwsys/GitSetup/setup-gitlab create mode 100644 test/API/driver/kwsys/GitSetup/setup-hooks create mode 100644 test/API/driver/kwsys/GitSetup/setup-ssh create mode 100644 test/API/driver/kwsys/GitSetup/setup-stage create mode 100644 test/API/driver/kwsys/GitSetup/setup-upstream create mode 100644 test/API/driver/kwsys/GitSetup/setup-user create mode 100644 test/API/driver/kwsys/GitSetup/tips create mode 100644 test/API/driver/kwsys/Glob.cxx create mode 100644 test/API/driver/kwsys/Glob.hxx.in create mode 100644 test/API/driver/kwsys/IOStream.cxx create mode 100644 test/API/driver/kwsys/IOStream.hxx.in create mode 100644 test/API/driver/kwsys/MD5.c create mode 100644 test/API/driver/kwsys/MD5.h.in create mode 100644 test/API/driver/kwsys/Process.h.in create mode 100644 test/API/driver/kwsys/ProcessUNIX.c create mode 100644 test/API/driver/kwsys/ProcessWin32.c create mode 100644 test/API/driver/kwsys/README.rst create mode 100644 test/API/driver/kwsys/RegularExpression.cxx create mode 100644 test/API/driver/kwsys/RegularExpression.hxx.in create mode 100644 test/API/driver/kwsys/SetupForDevelopment.sh create mode 100644 test/API/driver/kwsys/SharedForward.h.in create mode 100644 test/API/driver/kwsys/String.c create mode 100644 test/API/driver/kwsys/String.h.in create mode 100644 test/API/driver/kwsys/String.hxx.in create mode 100644 test/API/driver/kwsys/System.c create mode 100644 test/API/driver/kwsys/System.h.in create mode 100644 test/API/driver/kwsys/SystemInformation.cxx create mode 100644 test/API/driver/kwsys/SystemInformation.hxx.in create mode 100644 test/API/driver/kwsys/SystemTools.cxx create mode 100644 test/API/driver/kwsys/SystemTools.hxx.in create mode 100644 test/API/driver/kwsys/Terminal.c create mode 100644 test/API/driver/kwsys/Terminal.h.in create mode 100644 test/API/driver/kwsys/clang-format.bash create mode 100644 test/API/driver/kwsys/hash_fun.hxx.in create mode 100644 test/API/driver/kwsys/hash_map.hxx.in create mode 100644 test/API/driver/kwsys/hash_set.hxx.in create mode 100644 test/API/driver/kwsys/hashtable.hxx.in create mode 100644 test/API/driver/kwsys/kwsysHeaderDump.pl create mode 100644 test/API/driver/kwsys/kwsysPlatformTests.cmake create mode 100644 test/API/driver/kwsys/kwsysPlatformTestsC.c create mode 100644 test/API/driver/kwsys/kwsysPlatformTestsCXX.cxx create mode 100644 test/API/driver/kwsys/kwsysPrivate.h create mode 100644 test/API/driver/kwsys/testCommandLineArguments.cxx create mode 100644 test/API/driver/kwsys/testCommandLineArguments1.cxx create mode 100644 test/API/driver/kwsys/testConfigure.cxx create mode 100644 test/API/driver/kwsys/testConsoleBuf.cxx create mode 100644 test/API/driver/kwsys/testConsoleBuf.hxx create mode 100644 test/API/driver/kwsys/testConsoleBufChild.cxx create mode 100644 test/API/driver/kwsys/testDirectory.cxx create mode 100644 test/API/driver/kwsys/testDynamicLoader.cxx create mode 100644 test/API/driver/kwsys/testDynload.c create mode 100644 test/API/driver/kwsys/testDynloadImpl.c create mode 100644 test/API/driver/kwsys/testDynloadImpl.h create mode 100644 test/API/driver/kwsys/testDynloadUse.c create mode 100644 test/API/driver/kwsys/testEncode.c create mode 100644 test/API/driver/kwsys/testEncoding.cxx create mode 100644 test/API/driver/kwsys/testFStream.cxx create mode 100644 test/API/driver/kwsys/testFail.c create mode 100644 test/API/driver/kwsys/testHashSTL.cxx create mode 100644 test/API/driver/kwsys/testProcess.c create mode 100644 test/API/driver/kwsys/testSharedForward.c.in create mode 100644 test/API/driver/kwsys/testSystemInformation.cxx create mode 100644 test/API/driver/kwsys/testSystemTools.bin create mode 100644 test/API/driver/kwsys/testSystemTools.cxx create mode 100644 test/API/driver/kwsys/testSystemTools.h.in create mode 100644 test/API/driver/kwsys/testTerminal.c create mode 100644 test/API/driver/kwsys/update-gitsetup.bash create mode 100644 test/API/driver/kwsys/update-third-party.bash create mode 100644 test/API/tarray.c create mode 100644 test/API/tattr.c create mode 100644 test/API/tchecksum.c create mode 100644 test/API/tconfig.c create mode 100644 test/API/tcoords.c create mode 100644 test/API/testhdf5.c create mode 100644 test/API/testhdf5.h create mode 100644 test/API/tfile.c create mode 100644 test/API/tgenprop.c create mode 100644 test/API/th5o.c create mode 100644 test/API/th5s.c create mode 100644 test/API/tid.c create mode 100644 test/API/titerate.c create mode 100644 test/API/tmisc.c create mode 100644 test/API/trefer.c create mode 100644 test/API/tselect.c create mode 100644 test/API/ttime.c create mode 100644 test/API/tunicode.c create mode 100644 test/API/tvlstr.c create mode 100644 test/API/tvltypes.c create mode 100644 testpar/API/CMakeLists.txt create mode 100644 testpar/API/H5_api_async_test_parallel.c create mode 100644 testpar/API/H5_api_async_test_parallel.h create mode 100644 testpar/API/H5_api_attribute_test_parallel.c create mode 100644 testpar/API/H5_api_attribute_test_parallel.h create mode 100644 testpar/API/H5_api_dataset_test_parallel.c create mode 100644 testpar/API/H5_api_dataset_test_parallel.h create mode 100644 testpar/API/H5_api_datatype_test_parallel.c create mode 100644 testpar/API/H5_api_datatype_test_parallel.h create mode 100644 testpar/API/H5_api_file_test_parallel.c create mode 100644 testpar/API/H5_api_file_test_parallel.h create mode 100644 testpar/API/H5_api_group_test_parallel.c create mode 100644 testpar/API/H5_api_group_test_parallel.h create mode 100644 testpar/API/H5_api_link_test_parallel.c create mode 100644 testpar/API/H5_api_link_test_parallel.h create mode 100644 testpar/API/H5_api_misc_test_parallel.c create mode 100644 testpar/API/H5_api_misc_test_parallel.h create mode 100644 testpar/API/H5_api_object_test_parallel.c create mode 100644 testpar/API/H5_api_object_test_parallel.h create mode 100644 testpar/API/H5_api_test_parallel.c create mode 100644 testpar/API/H5_api_test_parallel.h create mode 100644 testpar/API/t_bigio.c create mode 100644 testpar/API/t_chunk_alloc.c create mode 100644 testpar/API/t_coll_chunk.c create mode 100644 testpar/API/t_coll_md_read.c create mode 100644 testpar/API/t_dset.c create mode 100644 testpar/API/t_file.c create mode 100644 testpar/API/t_file_image.c create mode 100644 testpar/API/t_filter_read.c create mode 100644 testpar/API/t_mdset.c create mode 100644 testpar/API/t_ph5basic.c create mode 100644 testpar/API/t_prop.c create mode 100644 testpar/API/t_pshutdown.c create mode 100644 testpar/API/t_shapesame.c create mode 100644 testpar/API/t_span_tree.c create mode 100644 testpar/API/testphdf5.c create mode 100644 testpar/API/testphdf5.h diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index a4edb0f..ddf1038 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -11,5 +11,5 @@ jobs: - uses: actions/checkout@v3 - uses: codespell-project/actions-codespell@master with: - skip: ./bin/trace,./hl/tools/h5watch/h5watch.c,./tools/test/h5jam/tellub.c,./config/sanitizer/LICENSE,./config/sanitizer/sanitizers.cmake,./tools/test/h5repack/testfiles/*.dat + skip: ./bin/trace,./hl/tools/h5watch/h5watch.c,./tools/test/h5jam/tellub.c,./config/sanitizer/LICENSE,./config/sanitizer/sanitizers.cmake,./tools/test/h5repack/testfiles/*.dat,./test/API/driver ignore_words_list: isnt,inout,nd,parms,parm,ba,offsetP,ser,ois,had,fiter,fo,clude,refere,minnum,offsetp,creat,ans:,eiter,lastr,ans,isn't,ifset,sur,trun,dne,tthe,hda,filname,te,htmp,minnum,ake,gord,numer,ro,oce,msdos diff --git a/CMakeLists.txt b/CMakeLists.txt index 9da39fa..62bbd00 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -208,20 +208,23 @@ set (HDF5_HL_F90_C_LIBSH_TARGET "${HDF5_HL_F90_C_LIB_CORENAME}-shared") #----------------------------------------------------------------------------- # Define some CMake variables for use later in the project #----------------------------------------------------------------------------- -set (HDF_CONFIG_DIR ${HDF5_SOURCE_DIR}/config) -set (HDF_RESOURCES_DIR ${HDF5_SOURCE_DIR}/config/cmake) -set (HDF5_SRC_DIR ${HDF5_SOURCE_DIR}/src) -set (HDF5_TEST_SRC_DIR ${HDF5_SOURCE_DIR}/test) -set (HDF5_CPP_SRC_DIR ${HDF5_SOURCE_DIR}/c++) -set (HDF5_CPP_TST_DIR ${HDF5_SOURCE_DIR}/c++/test) -set (HDF5_HL_SRC_DIR ${HDF5_SOURCE_DIR}/hl) -set (HDF5_HL_CPP_SRC_DIR ${HDF5_SOURCE_DIR}/hl/c++) -set (HDF5_HL_TOOLS_DIR ${HDF5_SOURCE_DIR}/hl/tools) -set (HDF5_TOOLS_DIR ${HDF5_SOURCE_DIR}/tools) -set (HDF5_TOOLS_SRC_DIR ${HDF5_SOURCE_DIR}/tools/src) -set (HDF5_PERFORM_SRC_DIR ${HDF5_SOURCE_DIR}/tools/src/perform) -set (HDF5_UTILS_DIR ${HDF5_SOURCE_DIR}/utils) -set (HDF5_F90_SRC_DIR ${HDF5_SOURCE_DIR}/fortran) +set (HDF_CONFIG_DIR ${HDF5_SOURCE_DIR}/config) +set (HDF_RESOURCES_DIR ${HDF5_SOURCE_DIR}/config/cmake) +set (HDF5_SRC_DIR ${HDF5_SOURCE_DIR}/src) +set (HDF5_TEST_SRC_DIR ${HDF5_SOURCE_DIR}/test) +set (HDF5_TEST_PAR_DIR ${HDF5_SOURCE_DIR}/testpar) +set (HDF5_TEST_API_SRC_DIR ${HDF5_SOURCE_DIR}/test/API) +set (HDF5_TEST_API_PAR_SRC_DIR ${HDF5_SOURCE_DIR}/testpar/API) +set (HDF5_CPP_SRC_DIR ${HDF5_SOURCE_DIR}/c++) +set (HDF5_CPP_TST_DIR ${HDF5_SOURCE_DIR}/c++/test) +set (HDF5_HL_SRC_DIR ${HDF5_SOURCE_DIR}/hl) +set (HDF5_HL_CPP_SRC_DIR ${HDF5_SOURCE_DIR}/hl/c++) +set (HDF5_HL_TOOLS_DIR ${HDF5_SOURCE_DIR}/hl/tools) +set (HDF5_TOOLS_DIR ${HDF5_SOURCE_DIR}/tools) +set (HDF5_TOOLS_SRC_DIR ${HDF5_SOURCE_DIR}/tools/src) +set (HDF5_PERFORM_SRC_DIR ${HDF5_SOURCE_DIR}/tools/src/perform) +set (HDF5_UTILS_DIR ${HDF5_SOURCE_DIR}/utils) +set (HDF5_F90_SRC_DIR ${HDF5_SOURCE_DIR}/fortran) set (HDF5_JAVA_JNI_SRC_DIR ${HDF5_SOURCE_DIR}/java/src/jni) set (HDF5_JAVA_HDF5_SRC_DIR ${HDF5_SOURCE_DIR}/java/src/hdf) set (HDF5_JAVA_TEST_SRC_DIR ${HDF5_SOURCE_DIR}/java/test) @@ -947,6 +950,25 @@ if (BUILD_TESTING) math (EXPR CTEST_LONG_TIMEOUT "${DART_TESTING_TIMEOUT} * 2") math (EXPR CTEST_VERY_LONG_TIMEOUT "${DART_TESTING_TIMEOUT} * 3") + option (HDF5_TEST_API "Execute HDF5 API tests" OFF) + mark_as_advanced (HDF5_TEST_API) + if (HDF5_TEST_API) + option (HDF5_TEST_API_INSTALL "Install HDF5 API tests" OFF) + mark_as_advanced (HDF5_TEST_API_INSTALL) + + # Enable HDF5 Async API tests + option (HDF5_TEST_API_ENABLE_ASYNC "Enable HDF5 Async API tests" OFF) + mark_as_advanced (HDF5_TEST_API_ENABLE_ASYNC) + + # Build and use HDF5 test driver program for API tests + option (HDF5_TEST_API_ENABLE_DRIVER "Enable HDF5 API test driver program" OFF) + mark_as_advanced (HDF5_TEST_API_ENABLE_DRIVER) + if (HDF5_TEST_API_ENABLE_DRIVER) + set (HDF5_TEST_API_SERVER "" CACHE STRING "Server executable for running API tests") + mark_as_advanced (HDF5_TEST_API_SERVER) + endif () + endif () + option (HDF5_TEST_VFD "Execute tests with different VFDs" OFF) mark_as_advanced (HDF5_TEST_VFD) if (HDF5_TEST_VFD) @@ -1003,11 +1025,11 @@ if (BUILD_TESTING) mark_as_advanced (HDF5_TEST_JAVA) if (NOT HDF5_EXTERNALLY_CONFIGURED) - if (EXISTS "${HDF5_SOURCE_DIR}/test" AND IS_DIRECTORY "${HDF5_SOURCE_DIR}/test") + if (EXISTS "${HDF5_TEST_SRC_DIR}" AND IS_DIRECTORY "${HDF5_TEST_SRC_DIR}") add_subdirectory (test) endif () if (H5_HAVE_PARALLEL) - if (EXISTS "${HDF5_SOURCE_DIR}/testpar" AND IS_DIRECTORY "${HDF5_SOURCE_DIR}/testpar") + if (EXISTS "${HDF5_TEST_PAR_DIR}" AND IS_DIRECTORY "${HDF5_TEST_PAR_DIR}") add_subdirectory (testpar) endif () endif () diff --git a/hl/c++/test/Makefile.am b/hl/c++/test/Makefile.am index 251d56a..73f1463 100644 --- a/hl/c++/test/Makefile.am +++ b/hl/c++/test/Makefile.am @@ -26,7 +26,7 @@ TEST_PROG=ptableTest check_PROGRAMS=$(TEST_PROG) # The tests depend on the hdf5, hdf5 C++, and hdf5_hl libraries -LDADD=$(LIBH5CPP_HL) $(LIBH5_HL) $(LIBH5CPP) $(LIBHDF5) +LDADD=$(LIBH5CPP_HL) $(LIBH5_HL) $(LIBH5TEST) $(LIBH5CPP) $(LIBHDF5) ptableTest_SOURCES=ptableTest.cpp diff --git a/test/API/CMake/CheckAsan.cmake b/test/API/CMake/CheckAsan.cmake new file mode 100644 index 0000000..32f4b45 --- /dev/null +++ b/test/API/CMake/CheckAsan.cmake @@ -0,0 +1,37 @@ +set(ASAN_FLAG "-fsanitize=address") +set(ASAN_C_FLAGS "-O1 -g ${ASAN_FLAG} -fsanitize-address-use-after-scope -fno-omit-frame-pointer -fno-optimize-sibling-calls") +set(ASAN_CXX_FLAGS ${ASAN_C_FLAGS}) + +get_property(ASAN_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) +foreach(lang ${ASAN_LANGUAGES}) + set(ASAN_${lang}_LANG_ENABLED 1) +endforeach() + +if(ASAN_C_LANG_ENABLED) + include(CheckCCompilerFlag) + set(CMAKE_REQUIRED_LINK_OPTIONS ${ASAN_FLAG}) + check_c_compiler_flag(${ASAN_FLAG} ASAN_C_FLAG_SUPPORTED) + if(NOT ASAN_C_FLAG_SUPPORTED) + message(STATUS "Asan flags are not supported by the C compiler.") + else() + if(NOT CMAKE_C_FLAGS_ASAN) + set(CMAKE_C_FLAGS_ASAN ${ASAN_C_FLAGS} CACHE STRING "Flags used by the C compiler during ASAN builds." FORCE) + endif() + endif() + unset(CMAKE_REQUIRED_LINK_OPTIONS) +endif() + +if(ASAN_CXX_LANG_ENABLED) + include(CheckCXXCompilerFlag) + set(CMAKE_REQUIRED_LINK_OPTIONS ${ASAN_FLAG}) + check_cxx_compiler_flag(${ASAN_FLAG} ASAN_CXX_FLAG_SUPPORTED) + if(NOT ASAN_CXX_FLAG_SUPPORTED) + message(STATUS "Asan flags are not supported by the CXX compiler.") + else() + if(NOT CMAKE_CXX_FLAGS_ASAN) + set(CMAKE_CXX_FLAGS_ASAN ${ASAN_CXX_FLAGS} CACHE STRING "Flags used by the CXX compiler during ASAN builds." FORCE) + endif() + endif() + unset(CMAKE_REQUIRED_LINK_OPTIONS) +endif() + diff --git a/test/API/CMake/CheckUbsan.cmake b/test/API/CMake/CheckUbsan.cmake new file mode 100644 index 0000000..f2b9c2c --- /dev/null +++ b/test/API/CMake/CheckUbsan.cmake @@ -0,0 +1,37 @@ +set(UBSAN_FLAG "-fsanitize=undefined") +set(UBSAN_C_FLAGS "-O1 -g ${UBSAN_FLAG} -fno-omit-frame-pointer") +set(UBSAN_CXX_FLAGS ${UBSAN_C_FLAGS}) + +get_property(UBSAN_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) +foreach(lang ${UBSAN_LANGUAGES}) + set(UBSAN_${lang}_LANG_ENABLED 1) +endforeach() + +if(UBSAN_C_LANG_ENABLED) + include(CheckCCompilerFlag) + set(CMAKE_REQUIRED_LINK_OPTIONS ${UBSAN_FLAG}) + check_c_compiler_flag(${UBSAN_FLAG} UBSAN_C_FLAG_SUPPORTED) + if(NOT UBSAN_C_FLAG_SUPPORTED) + message(STATUS "Ubsan flags are not supported by the C compiler.") + else() + if(NOT CMAKE_C_FLAGS_UBSAN) + set(CMAKE_C_FLAGS_UBSAN ${UBSAN_C_FLAGS} CACHE STRING "Flags used by the C compiler during UBSAN builds." FORCE) + endif() + endif() + unset(CMAKE_REQUIRED_LINK_OPTIONS) +endif() + +if(UBSAN_CXX_LANG_ENABLED) + include(CheckCXXCompilerFlag) + set(CMAKE_REQUIRED_LINK_OPTIONS ${UBSAN_FLAG}) + check_cxx_compiler_flag(${UBSAN_FLAG} UBSAN_CXX_FLAG_SUPPORTED) + if(NOT UBSAN_CXX_FLAG_SUPPORTED) + message(STATUS "Ubsan flags are not supported by the CXX compiler.") + else() + if(NOT CMAKE_CXX_FLAGS_UBSAN) + set(CMAKE_CXX_FLAGS_UBSAN ${UBSAN_CXX_FLAGS} CACHE STRING "Flags used by the CXX compiler during UBSAN builds." FORCE) + endif() + endif() + unset(CMAKE_REQUIRED_LINK_OPTIONS) +endif() + diff --git a/test/API/CMakeLists.txt b/test/API/CMakeLists.txt new file mode 100644 index 0000000..d189d67 --- /dev/null +++ b/test/API/CMakeLists.txt @@ -0,0 +1,314 @@ +# Copyright by The HDF Group. +# All rights reserved. +# +# This file is part of HDF5. The full HDF5 copyright notice, including +# terms governing use, modification, and redistribution, is contained in +# the COPYING file, which can be found at the root of the source code +# distribution tree, or in https://www.hdfgroup.org/licenses. +# If you do not have access to either file, you may request a copy from +# help@hdfgroup.org. +# + +#------------------------------------------------------------------------------ +# Set module path +#------------------------------------------------------------------------------ +set(HDF5_TEST_API_CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake") +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${HDF5_TEST_API_CMAKE_MODULE_PATH}) + +# TODO: probably not necessary +#------------------------------------------------------------------------------ +# Setup CMake Environment +#------------------------------------------------------------------------------ +if (WIN32) + message("The HDF5 API test suite is currently not supported on this platform." FATAL_ERROR) +endif () + +#------------------------------------------------------------------------------ +# Setup testing configuration file +#------------------------------------------------------------------------------ +if (HDF5_TEST_PARALLEL) + set (HDF5_TEST_API_HAVE_PARALLEL 1) +endif () +if (HDF5_TEST_API_ENABLE_ASYNC) + set (H5_API_TEST_HAVE_ASYNC 1) +endif () + +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/H5_api_test_config.h.in + ${HDF5_TEST_BINARY_DIR}/H5_api_test_config.h +) + +#------------------------------------------------------------------------------ +# Compile kwsys library and setup TestDriver +#------------------------------------------------------------------------------ +if (HDF5_TEST_API_ENABLE_DRIVER) + add_subdirectory (driver) +endif () + +#------------------------------------------------------------------------------ +# Setup for API tests +#------------------------------------------------------------------------------ + +# Ported HDF5 tests +set (HDF5_API_TESTS_EXTRA + testhdf5 +) + +# List of files generated by the HDF5 API tests which +# should be cleaned up in case the test failed to remove +# them +set (HDF5_API_TESTS_FILES + H5_api_test.h5 + H5_api_async_test.h5 + H5_api_async_test_0.h5 + H5_api_async_test_1.h5 + H5_api_async_test_2.h5 + H5_api_async_test_3.h5 + H5_api_async_test_4.h5 + test_file.h5 + invalid_params_file.h5 + excl_flag_file.h5 + overlapping_file.h5 + file_permission.h5 + flush_file.h5 + property_list_test_file1.h5 + property_list_test_file2.h5 + intent_test_file.h5 + file_obj_count1.h5 + file_obj_count2.h5 + file_mount.h5 + file_name_retrieval.h5 + filespace_info.h5 + test_file_id.h5 + test_close_degree.h5 + test_free_sections.h5 + file_size.h5 + file_info.h5 + double_group_open.h5 + ext_link_file.h5 + ext_link_file_2.h5 + ext_link_file_3.h5 + ext_link_file_4.h5 + ext_link_file_ping_pong_1.h5 + ext_link_file_ping_pong_2.h5 + ext_link_invalid_params_file.h5 + object_copy_test_file.h5 +) + +#----------------------------------------------------------------------------- +# Build the main API test executable +#----------------------------------------------------------------------------- +foreach (api_test ${HDF5_API_TESTS}) + set (HDF5_API_TEST_SRCS + ${HDF5_API_TEST_SRCS} + ${CMAKE_CURRENT_SOURCE_DIR}/H5_api_${api_test}_test.c + ) +endforeach () + +set (HDF5_API_TEST_SRCS + ${HDF5_API_TEST_SRCS} + ${CMAKE_CURRENT_SOURCE_DIR}/H5_api_test.c + ${HDF5_TEST_API_SRC_DIR}/H5_api_test_util.c +) + +add_executable (h5_api_test ${HDF5_API_TEST_SRCS}) +target_include_directories ( + h5_api_test + PRIVATE + "${HDF5_SRC_INCLUDE_DIRS}" + "${HDF5_TEST_SRC_DIR}" + "${HDF5_TEST_API_SRC_DIR}" + "${HDF5_SRC_BINARY_DIR}" + "${HDF5_TEST_BINARY_DIR}" +) +target_compile_options ( + h5_api_test + PRIVATE + "${HDF5_CMAKE_C_FLAGS}" +) +target_compile_definitions ( + h5_api_test + PRIVATE + $<$:${HDF5_DEVELOPER_DEFS}> +) +if (NOT BUILD_SHARED_LIBS) + TARGET_C_PROPERTIES (h5_api_test STATIC) + target_link_libraries ( + h5_api_test + PRIVATE + ${HDF5_TEST_LIB_TARGET} + ) +else () + TARGET_C_PROPERTIES (h5_api_test SHARED) + target_link_libraries ( + h5_api_test + PRIVATE + ${HDF5_TEST_LIBSH_TARGET} + ) +endif () +set_target_properties ( + h5_api_test + PROPERTIES + FOLDER test/API +) +# Add Target to clang-format +if (HDF5_ENABLE_FORMATTERS) + clang_format (HDF5_TEST_h5_api_test_FORMAT h5_api_test) +endif () + +#----------------------------------------------------------------------------- +# Build the ported HDF5 test executables +#----------------------------------------------------------------------------- +foreach (api_test_extra ${HDF5_API_TESTS_EXTRA}) + unset (HDF5_API_TEST_EXTRA_SRCS) + + set (HDF5_API_TEST_EXTRA_SRCS + ${HDF5_API_TEST_EXTRA_SRCS} + ${CMAKE_CURRENT_SOURCE_DIR}/${api_test_extra}.c + ) + + if (${api_test_extra} STREQUAL "testhdf5") + set (HDF5_API_TEST_EXTRA_SRCS + ${HDF5_API_TEST_EXTRA_SRCS} + ${CMAKE_CURRENT_SOURCE_DIR}/tarray.c + ${CMAKE_CURRENT_SOURCE_DIR}/tattr.c + ${CMAKE_CURRENT_SOURCE_DIR}/tchecksum.c + ${CMAKE_CURRENT_SOURCE_DIR}/tconfig.c + ${CMAKE_CURRENT_SOURCE_DIR}/tcoords.c + ${CMAKE_CURRENT_SOURCE_DIR}/tfile.c + ${CMAKE_CURRENT_SOURCE_DIR}/tgenprop.c + ${CMAKE_CURRENT_SOURCE_DIR}/th5o.c + ${CMAKE_CURRENT_SOURCE_DIR}/th5s.c + ${CMAKE_CURRENT_SOURCE_DIR}/tid.c + ${CMAKE_CURRENT_SOURCE_DIR}/titerate.c + ${CMAKE_CURRENT_SOURCE_DIR}/tmisc.c + ${CMAKE_CURRENT_SOURCE_DIR}/trefer.c + ${CMAKE_CURRENT_SOURCE_DIR}/tselect.c + ${CMAKE_CURRENT_SOURCE_DIR}/ttime.c + ${CMAKE_CURRENT_SOURCE_DIR}/tunicode.c + ${CMAKE_CURRENT_SOURCE_DIR}/tvlstr.c + ${CMAKE_CURRENT_SOURCE_DIR}/tvltypes.c + ) + endif () + + add_executable (h5_api_test_${api_test_extra} ${HDF5_API_TEST_EXTRA_SRCS}) + target_include_directories ( + h5_api_test_${api_test_extra} + PRIVATE + "${HDF5_SRC_INCLUDE_DIRS}" + "${HDF5_TEST_SRC_DIR}" + "${HDF5_TEST_API_SRC_DIR}" + "${HDF5_SRC_BINARY_DIR}" + "${HDF5_TEST_BINARY_DIR}" + ) + target_compile_options ( + h5_api_test_${api_test_extra} + PRIVATE + "${HDF5_CMAKE_C_FLAGS}" + ) + target_compile_definitions ( + h5_api_test_${api_test_extra} + PRIVATE + $<$:${HDF5_DEVELOPER_DEFS}> + ) + if (NOT BUILD_SHARED_LIBS) + TARGET_C_PROPERTIES (h5_api_test_${api_test_extra} STATIC) + target_link_libraries (h5_api_test_${api_test_extra} PRIVATE ${HDF5_TEST_LIB_TARGET}) + else () + TARGET_C_PROPERTIES (h5_api_test_${api_test_extra} SHARED) + target_link_libraries (h5_api_test_${api_test_extra} PRIVATE ${HDF5_TEST_LIBSH_TARGET}) + endif () + set_target_properties ( + h5_api_test_${api_test_extra} + PROPERTIES + FOLDER test/API + ) + # Add Target to clang-format + if (HDF5_ENABLE_FORMATTERS) + clang_format (HDF5_TEST_h5_api_test_${api_test_extra}_FORMAT h5_api_test_${api_test_extra}) + endif () +endforeach () + +#----------------------------------------------------------------------------- +# Add tests if HDF5 serial testing is enabled +#----------------------------------------------------------------------------- +if (HDF5_TEST_SERIAL) + if (HDF5_TEST_API_ENABLE_DRIVER) + if ("${HDF5_TEST_API_SERVER}" STREQUAL "") + message (FATAL_ERROR "Please set HDF5_TEST_API_SERVER to point to a server executable for the test driver program.") + endif () + + # Driver options + if (HDF5_TEST_API_SERVER_ALLOW_ERRORS) + set (HDF5_TEST_API_DRIVER_EXTRA_FLAGS --allow-server-errors) + endif () + if (HDF5_TEST_API_CLIENT_HELPER) + set (HDF5_TEST_API_DRIVER_EXTRA_FLAGS ${HDF5_TEST_API_DRIVER_EXTRA_FLAGS} + --client-helper ${HDF5_TEST_API_CLIENT_HELPER} + ) + endif () + if (HDF5_TEST_API_CLIENT_INIT) + set (HDF5_TEST_API_DRIVER_EXTRA_FLAGS ${HDF5_TEST_API_DRIVER_EXTRA_FLAGS} + --client-init ${HDF5_TEST_API_CLIENT_INIT} + ) + endif () + + set(last_api_test "") + foreach (api_test ${HDF5_API_TESTS}) + add_test ( + NAME "h5_api_test_${api_test}" + COMMAND $ + --server ${HDF5_TEST_API_SERVER} + --client $ "${api_test}" + --serial + ${HDF5_TEST_API_DRIVER_EXTRA_FLAGS} + ) + + set_tests_properties("h5_api_test_${api_test}" PROPERTIES DEPENDS "${last_api_test}") + + set(last_api_test "h5_api_test_${api_test}") + endforeach () + + foreach (hdf5_test ${HDF5_API_TESTS_EXTRA}) + add_test ( + NAME "h5_api_test_${hdf5_test}" + COMMAND $ + --server ${HDF5_TEST_API_SERVER} + --client $ + --serial + ${HDF5_TEST_API_DRIVER_EXTRA_FLAGS} + ) + endforeach () + + # Hook external tests to same test suite + foreach (ext_api_test ${HDF5_API_EXT_SERIAL_TESTS}) + add_test ( + NAME "h5_api_ext_test_${ext_api_test}" + COMMAND $ + --server ${HDF5_TEST_API_SERVER} + --client $ + --serial + ${HDF5_TEST_API_DRIVER_EXTRA_FLAGS} + ) + endforeach () + else () + set(last_api_test "") + foreach (api_test ${HDF5_API_TESTS}) + add_test ( + NAME "h5_api_test_${api_test}" + COMMAND $ "${api_test}" + ) + + set_tests_properties("h5_api_test_${api_test}" PROPERTIES DEPENDS "${last_api_test}") + + set(last_api_test "h5_api_test_${api_test}") + endforeach () + + foreach (hdf5_test ${HDF5_API_TESTS_EXTRA}) + add_test ( + NAME "h5_api_test_${hdf5_test}" + COMMAND $ + ) + endforeach () + endif () +endif () diff --git a/test/API/H5_api_async_test.c b/test/API/H5_api_async_test.c new file mode 100644 index 0000000..b5208ba --- /dev/null +++ b/test/API/H5_api_async_test.c @@ -0,0 +1,2730 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "H5_api_async_test.h" + +#ifdef H5ESpublic_H + +static int test_one_dataset_io(void); +static int test_multi_dataset_io(void); +static int test_multi_file_dataset_io(void); +static int test_multi_file_grp_dset_io(void); +static int test_set_extent(void); +static int test_attribute_exists(void); +static int test_attribute_io(void); +static int test_attribute_io_tconv(void); +static int test_attribute_io_compound(void); +static int test_group(void); +static int test_link(void); +static int test_ocopy_orefresh(void); +static int test_file_reopen(void); + +/* + * The array of async tests to be performed. + */ +static int (*async_tests[])(void) = { + test_one_dataset_io, + test_multi_dataset_io, + test_multi_file_dataset_io, + test_multi_file_grp_dset_io, + test_set_extent, + test_attribute_exists, + test_attribute_io, + test_attribute_io_tconv, + test_attribute_io_compound, + test_group, + test_link, + test_ocopy_orefresh, + test_file_reopen, +}; + +/* Highest "printf" file created (starting at 0) */ +int max_printf_file = -1; + +/* + * Create file and dataset, write to dataset + */ +static int +test_one_dataset_io(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + hid_t es_id = H5I_INVALID_HID; + hsize_t dims[2] = {6, 10}; + size_t num_in_progress; + hbool_t op_failed; + int wbuf[6][10]; + int rbuf[6][10]; + int i, j; + + TESTING_MULTIPART("single dataset I/O"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH)) { + SKIPPED(); + HDprintf( + " API functions for basic file, dataset, or flush aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + /* Create dataspace */ + if ((space_id = H5Screate_simple(2, dims, NULL)) < 0) + TEST_ERROR; + + /* Create event stack */ + if ((es_id = H5EScreate()) < 0) + TEST_ERROR; + + /* Create file asynchronously */ + if ((file_id = H5Fcreate_async(ASYNC_API_TEST_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Create the dataset asynchronously */ + if ((dset_id = H5Dcreate_async(file_id, "dset", H5T_NATIVE_INT, space_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(single_dset_eswait) + { + TESTING_2("synchronization using H5ESwait()"); + + /* Initialize wbuf */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) + wbuf[i][j] = 10 * i + j; + + /* Write the dataset asynchronously */ + if (H5Dwrite_async(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf, es_id) < 0) + PART_TEST_ERROR(single_dset_eswait); + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + PART_TEST_ERROR(single_dset_eswait); + if (op_failed) + PART_TEST_ERROR(single_dset_eswait); + + /* Read the dataset asynchronously */ + if (H5Dread_async(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf, es_id) < 0) + PART_TEST_ERROR(single_dset_eswait); + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + PART_TEST_ERROR(single_dset_eswait); + if (op_failed) + PART_TEST_ERROR(single_dset_eswait); + + /* Verify the read data */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) + if (wbuf[i][j] != rbuf[i][j]) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + PART_ERROR(single_dset_eswait); + } /* end if */ + + PASSED(); + } + PART_END(single_dset_eswait); + + PART_BEGIN(single_dset_dclose) + { + TESTING_2("synchronization using H5Dclose()"); + + /* Update wbuf */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) + wbuf[i][j] += 6 * 10; + + /* Write the dataset asynchronously */ + if (H5Dwrite_async(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf, es_id) < 0) + PART_TEST_ERROR(single_dset_dclose); + + /* Close the dataset synchronously */ + if (H5Dclose(dset_id) < 0) + PART_TEST_ERROR(single_dset_dclose); + + /* Re-open the dataset asynchronously */ + if ((dset_id = H5Dopen_async(file_id, "dset", H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(single_dset_dclose); + + /* Read the dataset asynchronously */ + if (H5Dread_async(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf, es_id) < 0) + PART_TEST_ERROR(single_dset_dclose); + + /* Close the dataset synchronously */ + if (H5Dclose(dset_id) < 0) + PART_TEST_ERROR(single_dset_dclose); + + /* Verify the read data */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) + if (wbuf[i][j] != rbuf[i][j]) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + PART_ERROR(single_dset_dclose); + } /* end if */ + + /* Re-open the dataset asynchronously */ + if ((dset_id = H5Dopen_async(file_id, "dset", H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(single_dset_dclose); + + PASSED(); + } + PART_END(single_dset_dclose); + + PART_BEGIN(single_dset_dflush) + { + TESTING_2("synchronization using H5Oflush_async()"); + + /* Update wbuf */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) + wbuf[i][j] += 6 * 10; + + /* Write the dataset asynchronously */ + if (H5Dwrite_async(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf, es_id) < 0) + PART_TEST_ERROR(single_dset_dflush); + + /* Flush the dataset asynchronously. This will effectively work as a + * barrier, guaranteeing the read takes place after the write. */ + if (H5Oflush_async(dset_id, es_id) < 0) + PART_TEST_ERROR(single_dset_dflush); + + /* Read the dataset asynchronously */ + if (H5Dread_async(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf, es_id) < 0) + PART_TEST_ERROR(single_dset_dflush); + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + PART_TEST_ERROR(single_dset_dflush); + if (op_failed) + PART_TEST_ERROR(single_dset_dflush); + + /* Verify the read data */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) + if (wbuf[i][j] != rbuf[i][j]) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + PART_ERROR(single_dset_dflush); + } /* end if */ + + PASSED(); + } + PART_END(single_dset_dflush); + + PART_BEGIN(single_dset_fclose) + { + TESTING_2("synchronization using H5Fclose()"); + + /* Update wbuf */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) + wbuf[i][j] += 6 * 10; + + /* Write the dataset asynchronously */ + if (H5Dwrite_async(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf, es_id) < 0) + PART_TEST_ERROR(single_dset_fclose); + + /* Close the dataset asynchronously */ + if (H5Dclose_async(dset_id, es_id) < 0) + PART_TEST_ERROR(single_dset_fclose); + + /* Close the file synchronously */ + if (H5Fclose(file_id) < 0) + PART_TEST_ERROR(single_dset_fclose); + + /* Reopen the file asynchronously. */ + if ((file_id = H5Fopen_async(ASYNC_API_TEST_FILE, H5F_ACC_RDONLY, H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(single_dset_fclose); + + /* Re-open the dataset asynchronously */ + if ((dset_id = H5Dopen_async(file_id, "dset", H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(single_dset_fclose); + + /* Read the dataset asynchronously */ + if (H5Dread_async(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf, es_id) < 0) + PART_TEST_ERROR(single_dset_fclose); + + /* Close the dataset asynchronously */ + if (H5Dclose_async(dset_id, es_id) < 0) + PART_TEST_ERROR(single_dset_fclose); + + /* Close the file synchronously */ + if (H5Fclose(file_id) < 0) + PART_TEST_ERROR(single_dset_fclose); + + /* Verify the read data */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) + if (wbuf[i][j] != rbuf[i][j]) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + PART_ERROR(single_dset_fclose); + } /* end if */ + + PASSED(); + } + PART_END(single_dset_fclose); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5ESclose(es_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(space_id); + H5Dclose(dset_id); + H5Fclose(file_id); + H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed); + H5ESclose(es_id); + } + H5E_END_TRY; + + return 1; +} /* end test_one_dataset_io() */ + +/* + * Create file and multiple datasets, write to them and read from them + */ +static int +test_multi_dataset_io(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t dset_id[5] = {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID}; + hid_t space_id = H5I_INVALID_HID; + hid_t es_id = H5I_INVALID_HID; + hsize_t dims[2] = {6, 10}; + size_t num_in_progress; + hbool_t op_failed; + char dset_name[32]; + int wbuf[5][6][10]; + int rbuf[5][6][10]; + int i, j, k; + + TESTING_MULTIPART("multi dataset I/O"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH)) { + SKIPPED(); + HDprintf( + " API functions for basic file, dataset, or flush aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + /* Create dataspace */ + if ((space_id = H5Screate_simple(2, dims, NULL)) < 0) + TEST_ERROR; + + /* Create event stack */ + if ((es_id = H5EScreate()) < 0) + TEST_ERROR; + + /* Create file asynchronously */ + if ((file_id = H5Fcreate_async(ASYNC_API_TEST_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(multi_dset_open) + { + TESTING_2("keeping datasets open"); + + /* Loop over datasets */ + for (i = 0; i < 5; i++) { + /* Set dataset name */ + sprintf(dset_name, "dset%d", i); + + /* Create the dataset asynchronously */ + if ((dset_id[i] = H5Dcreate_async(file_id, dset_name, H5T_NATIVE_INT, space_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_dset_open); + + /* Initialize wbuf. Must use a new slice of wbuf for each dset + * since we can't overwrite the buffers until I/O is done. */ + for (j = 0; j < 6; j++) + for (k = 0; k < 10; k++) + wbuf[i][j][k] = 6 * 10 * i + 10 * j + k; + + /* Write the dataset asynchronously */ + if (H5Dwrite_async(dset_id[i], H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf[i], + es_id) < 0) + PART_TEST_ERROR(multi_dset_open); + } /* end for */ + + /* Flush the file asynchronously. This will effectively work as a + * barrier, guaranteeing the read takes place after the write. */ + if (H5Fflush_async(file_id, H5F_SCOPE_LOCAL, es_id) < 0) + PART_TEST_ERROR(multi_dset_open); + + /* Loop over datasets */ + for (i = 0; i < 5; i++) { + /* Read the dataset asynchronously */ + if (H5Dread_async(dset_id[i], H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf[i], es_id) < + 0) + PART_TEST_ERROR(multi_dset_open); + } /* end for */ + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + PART_TEST_ERROR(multi_dset_open); + if (op_failed) + PART_TEST_ERROR(multi_dset_open); + /*printf("\nwbuf:\n"); + for(i = 0; i < 5; i++) { + for(j = 0; j < 6; j++) { + for(k = 0; k < 10; k++) + printf("%d ", wbuf[i][j][k]); + printf("\n"); + } + printf("\n"); + } + printf("\nrbuf:\n"); + for(i = 0; i < 5; i++) { + for(j = 0; j < 6; j++) { + for(k = 0; k < 10; k++) + printf("%d ", rbuf[i][j][k]); + printf("\n"); + } + printf("\n"); + }*/ + /* Verify the read data */ + for (i = 0; i < 5; i++) + for (j = 0; j < 6; j++) + for (k = 0; k < 10; k++) + if (wbuf[i][j][k] != rbuf[i][j][k]) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + PART_ERROR(multi_dset_open); + } /* end if */ + + /* Close the datasets */ + for (i = 0; i < 5; i++) + if (H5Dclose(dset_id[i]) < 0) + PART_TEST_ERROR(multi_dset_open); + + PASSED(); + } + PART_END(multi_dset_open); + + PART_BEGIN(multi_dset_close) + { + TESTING_2("closing datasets between I/O"); + + /* Loop over datasets */ + for (i = 0; i < 5; i++) { + /* Set dataset name */ + sprintf(dset_name, "dset%d", i); + + /* Open the dataset asynchronously */ + if ((dset_id[0] = H5Dopen_async(file_id, dset_name, H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_dset_close); + + /* Update wbuf */ + for (j = 0; j < 6; j++) + for (k = 0; k < 10; k++) + wbuf[i][j][k] += 5 * 6 * 10; + + /* Write the dataset asynchronously */ + if (H5Dwrite_async(dset_id[0], H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf[i], + es_id) < 0) + PART_TEST_ERROR(multi_dset_close); + + /* Close the dataset asynchronously */ + if (H5Dclose_async(dset_id[0], es_id) < 0) + PART_TEST_ERROR(multi_dset_close); + } /* end for */ + + /* Flush the file asynchronously. This will effectively work as a + * barrier, guaranteeing the read takes place after the write. */ + if (H5Fflush_async(file_id, H5F_SCOPE_LOCAL, es_id) < 0) + PART_TEST_ERROR(multi_dset_close); + + /* Loop over datasets */ + for (i = 0; i < 5; i++) { + /* Set dataset name */ + sprintf(dset_name, "dset%d", i); + + /* Open the dataset asynchronously */ + if ((dset_id[0] = H5Dopen_async(file_id, dset_name, H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_dset_close); + + /* Read the dataset asynchronously */ + if (H5Dread_async(dset_id[0], H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf[i], es_id) < + 0) + PART_TEST_ERROR(multi_dset_close); + + /* Close the dataset asynchronously */ + if (H5Dclose_async(dset_id[0], es_id) < 0) + PART_TEST_ERROR(multi_dset_close); + } /* end for */ + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + PART_TEST_ERROR(multi_dset_close); + if (op_failed) + PART_TEST_ERROR(multi_dset_close); + /*printf("\nwbuf:\n"); + for(i = 0; i < 5; i++) { + for(j = 0; j < 6; j++) { + for(k = 0; k < 10; k++) + printf("%d ", wbuf[i][j][k]); + printf("\n"); + } + printf("\n"); + } + printf("\nrbuf:\n"); + for(i = 0; i < 5; i++) { + for(j = 0; j < 6; j++) { + for(k = 0; k < 10; k++) + printf("%d ", rbuf[i][j][k]); + printf("\n"); + } + printf("\n"); + }*/ + /* Verify the read data */ + for (i = 0; i < 5; i++) + for (j = 0; j < 6; j++) + for (k = 0; k < 10; k++) + if (wbuf[i][j][k] != rbuf[i][j][k]) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + PART_ERROR(multi_dset_close); + } /* end if */ + + PASSED(); + } + PART_END(multi_dset_close); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Fclose_async(file_id, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5ESclose(es_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(space_id); + for (i = 0; i < 5; i++) + H5Dclose(dset_id[i]); + H5Fclose(file_id); + H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed); + H5ESclose(es_id); + } + H5E_END_TRY; + + return 1; +} /* end test_multi_dataset_io() */ + +/* + * Create multiple files, each with a single dataset, write to them and read + * from them + */ +static int +test_multi_file_dataset_io(void) +{ + hid_t file_id[5] = {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID}; + hid_t dset_id[5] = {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID}; + hid_t space_id = H5I_INVALID_HID; + hid_t es_id = H5I_INVALID_HID; + hsize_t dims[2] = {6, 10}; + size_t num_in_progress; + hbool_t op_failed; + char file_name[32]; + int wbuf[5][6][10]; + int rbuf[5][6][10]; + int i, j, k; + + TESTING_MULTIPART("multi file dataset I/O"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH)) { + SKIPPED(); + HDprintf( + " API functions for basic file, dataset, or flush aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + /* Create dataspace */ + if ((space_id = H5Screate_simple(2, dims, NULL)) < 0) + TEST_ERROR; + + /* Create event stack */ + if ((es_id = H5EScreate()) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(multi_file_dset_open) + { + TESTING_2("keeping files and datasets open"); + + /* Loop over files */ + for (i = 0; i < 5; i++) { + /* Set file name */ + sprintf(file_name, ASYNC_API_TEST_FILE_PRINTF, i); + + /* Create file asynchronously */ + if ((file_id[i] = + H5Fcreate_async(file_name, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_file_dset_open); + if (i > max_printf_file) + max_printf_file = i; + + /* Create the dataset asynchronously */ + if ((dset_id[i] = H5Dcreate_async(file_id[i], "dset", H5T_NATIVE_INT, space_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_file_dset_open); + + /* Initialize wbuf. Must use a new slice of wbuf for each dset + * since we can't overwrite the buffers until I/O is done. */ + for (j = 0; j < 6; j++) + for (k = 0; k < 10; k++) + wbuf[i][j][k] = 6 * 10 * i + 10 * j + k; + + /* Write the dataset asynchronously */ + if (H5Dwrite_async(dset_id[i], H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf[i], + es_id) < 0) + PART_TEST_ERROR(multi_file_dset_open); + } /* end for */ + + /* Loop over files */ + for (i = 0; i < 5; i++) { + /* Flush the dataset asynchronously. This will effectively work as a + * barrier, guaranteeing the read takes place after the write. */ + if (H5Oflush_async(dset_id[i], es_id) < 0) + PART_TEST_ERROR(multi_file_dset_open); + + /* Read the dataset asynchronously */ + if (H5Dread_async(dset_id[i], H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf[i], es_id) < + 0) + PART_TEST_ERROR(multi_file_dset_open); + } /* end for */ + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + PART_TEST_ERROR(multi_file_dset_open); + if (op_failed) + PART_TEST_ERROR(multi_file_dset_open); + + /* Verify the read data */ + for (i = 0; i < 5; i++) + for (j = 0; j < 6; j++) + for (k = 0; k < 10; k++) + if (wbuf[i][j][k] != rbuf[i][j][k]) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + PART_ERROR(multi_file_dset_open); + } /* end if */ + + /* Close the datasets */ + for (i = 0; i < 5; i++) + if (H5Dclose(dset_id[i]) < 0) + PART_TEST_ERROR(multi_file_dset_open); + + PASSED(); + } + PART_END(multi_file_dset_open); + + PART_BEGIN(multi_file_dset_dclose) + { + TESTING_2("closing datasets between I/O"); + + /* Loop over files */ + for (i = 0; i < 5; i++) { + /* Open the dataset asynchronously */ + if ((dset_id[0] = H5Dopen_async(file_id[i], "dset", H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_file_dset_dclose); + + /* Update wbuf */ + for (j = 0; j < 6; j++) + for (k = 0; k < 10; k++) + wbuf[i][j][k] += 5 * 6 * 10; + + /* Write the dataset asynchronously */ + if (H5Dwrite_async(dset_id[0], H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf[i], + es_id) < 0) + PART_TEST_ERROR(multi_file_dset_dclose); + + /* Close the dataset asynchronously */ + if (H5Dclose_async(dset_id[0], es_id) < 0) + PART_TEST_ERROR(multi_file_dset_dclose); + } /* end for */ + + /* Loop over files */ + for (i = 0; i < 5; i++) { + /* Flush the file asynchronously. This will effectively work as a + * barrier, guaranteeing the read takes place after the write. */ + if (H5Fflush_async(file_id[i], H5F_SCOPE_LOCAL, es_id) < 0) + PART_TEST_ERROR(multi_file_dset_open); + + /* Open the dataset asynchronously */ + if ((dset_id[0] = H5Dopen_async(file_id[i], "dset", H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_file_dset_dclose); + + /* Read the dataset asynchronously */ + if (H5Dread_async(dset_id[0], H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf[i], es_id) < + 0) + PART_TEST_ERROR(multi_file_dset_dclose); + + /* Close the dataset asynchronously */ + if (H5Dclose_async(dset_id[0], es_id) < 0) + PART_TEST_ERROR(multi_file_dset_dclose); + } /* end for */ + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + PART_TEST_ERROR(multi_file_dset_dclose); + if (op_failed) + PART_TEST_ERROR(multi_file_dset_dclose); + + /* Verify the read data */ + for (i = 0; i < 5; i++) + for (j = 0; j < 6; j++) + for (k = 0; k < 10; k++) + if (wbuf[i][j][k] != rbuf[i][j][k]) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + PART_ERROR(multi_file_dset_dclose); + } /* end if */ + + /* Close the files */ + for (i = 0; i < 5; i++) + if (H5Fclose(file_id[i]) < 0) + PART_TEST_ERROR(multi_file_dset_dclose); + + PASSED(); + } + PART_END(multi_file_dset_dclose); + + PART_BEGIN(multi_file_dset_fclose) + { + TESTING_2("closing files between I/O"); + + /* Loop over files */ + for (i = 0; i < 5; i++) { + /* Set file name */ + sprintf(file_name, ASYNC_API_TEST_FILE_PRINTF, i); + + /* Open the file asynchronously */ + if ((file_id[0] = H5Fopen_async(file_name, H5F_ACC_RDWR, H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_file_dset_fclose); + + /* Open the dataset asynchronously */ + if ((dset_id[0] = H5Dopen_async(file_id[0], "dset", H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_file_dset_fclose); + + /* Update wbuf */ + for (j = 0; j < 6; j++) + for (k = 0; k < 10; k++) + wbuf[i][j][k] += 5 * 6 * 10; + + /* Write the dataset asynchronously */ + if (H5Dwrite_async(dset_id[0], H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf[i], + es_id) < 0) + PART_TEST_ERROR(multi_file_dset_fclose); + + /* Close the dataset asynchronously */ + if (H5Dclose_async(dset_id[0], es_id) < 0) + PART_TEST_ERROR(multi_file_dset_fclose); + + /* Close the file asynchronously */ + if (H5Fclose_async(file_id[0], es_id) < 0) + PART_TEST_ERROR(multi_file_dset_fclose); + } /* end for */ + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + PART_TEST_ERROR(multi_file_dset_fclose); + if (op_failed) + PART_TEST_ERROR(multi_file_dset_fclose); + + /* Loop over files */ + for (i = 0; i < 5; i++) { + /* Set file name */ + sprintf(file_name, ASYNC_API_TEST_FILE_PRINTF, i); + + /* Open the file asynchronously */ + if ((file_id[0] = H5Fopen_async(file_name, H5F_ACC_RDONLY, H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_file_dset_fclose); + + /* Open the dataset asynchronously */ + if ((dset_id[0] = H5Dopen_async(file_id[0], "dset", H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_file_dset_fclose); + + /* Read the dataset asynchronously */ + if (H5Dread_async(dset_id[0], H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf[i], es_id) < + 0) + PART_TEST_ERROR(multi_file_dset_fclose); + + /* Close the dataset asynchronously */ + if (H5Dclose_async(dset_id[0], es_id) < 0) + PART_TEST_ERROR(multi_file_dset_fclose); + + /* Close the file asynchronously */ + if (H5Fclose_async(file_id[0], es_id) < 0) + PART_TEST_ERROR(multi_file_dset_fclose); + } /* end for */ + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + PART_TEST_ERROR(multi_file_dset_fclose); + if (op_failed) + PART_TEST_ERROR(multi_file_dset_fclose); + + /* Verify the read data */ + for (i = 0; i < 5; i++) + for (j = 0; j < 6; j++) + for (k = 0; k < 10; k++) + if (wbuf[i][j][k] != rbuf[i][j][k]) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + PART_ERROR(multi_file_dset_fclose); + } /* end if */ + + PASSED(); + } + PART_END(multi_file_dset_fclose); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5ESclose(es_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(space_id); + for (i = 0; i < 5; i++) { + H5Dclose(dset_id[i]); + H5Fclose(file_id[i]); + } /* end for */ + H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed); + H5ESclose(es_id); + } + H5E_END_TRY; + + return 1; +} /* end test_multi_file_dataset_io() */ + +/* + * Create multiple files, each with a single group and dataset, write to them + * and read from them + */ +static int +test_multi_file_grp_dset_io(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t grp_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + hid_t es_id = H5I_INVALID_HID; + hsize_t dims[2] = {6, 10}; + size_t num_in_progress; + hbool_t op_failed; + char file_name[32]; + int wbuf[5][6][10]; + int rbuf[5][6][10]; + int i, j, k; + + TESTING_MULTIPART("multi file dataset I/O with groups"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + /* Create dataspace */ + if ((space_id = H5Screate_simple(2, dims, NULL)) < 0) + TEST_ERROR; + + /* Create event stack */ + if ((es_id = H5EScreate()) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(multi_file_grp_dset_no_kick) + { + TESTING_2("without intermediate calls to H5ESwait()"); + + /* Loop over files */ + for (i = 0; i < 5; i++) { + /* Set file name */ + sprintf(file_name, ASYNC_API_TEST_FILE_PRINTF, i); + + /* Create file asynchronously */ + if ((file_id = H5Fcreate_async(file_name, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT, es_id)) < + 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + if (i > max_printf_file) + max_printf_file = i; + + /* Create the group asynchronously */ + if ((grp_id = H5Gcreate_async(file_id, "grp", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT, es_id)) < + 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + + /* Create the dataset asynchronously */ + if ((dset_id = H5Dcreate_async(grp_id, "dset", H5T_NATIVE_INT, space_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + + /* Initialize wbuf. Must use a new slice of wbuf for each dset + * since we can't overwrite the buffers until I/O is done. */ + for (j = 0; j < 6; j++) + for (k = 0; k < 10; k++) + wbuf[i][j][k] = 6 * 10 * i + 10 * j + k; + + /* Write the dataset asynchronously */ + if (H5Dwrite_async(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf[i], es_id) < + 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + + /* Close the dataset asynchronously */ + if (H5Dclose_async(dset_id, es_id) < 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + + /* Close the group asynchronously */ + if (H5Gclose_async(grp_id, es_id) < 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + + /* Close the file asynchronously */ + if (H5Fclose_async(file_id, es_id) < 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + } /* end for */ + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + if (op_failed) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + + /* Loop over files */ + for (i = 0; i < 5; i++) { + /* Set file name */ + sprintf(file_name, ASYNC_API_TEST_FILE_PRINTF, i); + + /* Open the file asynchronously */ + if ((file_id = H5Fopen_async(file_name, H5F_ACC_RDONLY, H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + + /* Open the group asynchronously */ + if ((grp_id = H5Gopen_async(file_id, "grp", H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + + /* Open the dataset asynchronously */ + if ((dset_id = H5Dopen_async(grp_id, "dset", H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + + /* Read the dataset asynchronously */ + if (H5Dread_async(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf[i], es_id) < 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + + /* Close the dataset asynchronously */ + if (H5Dclose_async(dset_id, es_id) < 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + + /* Close the group asynchronously */ + if (H5Gclose_async(grp_id, es_id) < 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + + /* Close the file asynchronously */ + if (H5Fclose_async(file_id, es_id) < 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + } /* end for */ + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + if (op_failed) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + + /* Verify the read data */ + for (i = 0; i < 5; i++) + for (j = 0; j < 6; j++) + for (k = 0; k < 10; k++) + if (wbuf[i][j][k] != rbuf[i][j][k]) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + PART_ERROR(multi_file_grp_dset_no_kick); + } /* end if */ + + PASSED(); + } + PART_END(multi_file_grp_dset_no_kick); + + PART_BEGIN(multi_file_grp_dset_kick) + { + TESTING_2("with intermediate calls to H5ESwait() (0 timeout)"); + + /* Loop over files */ + for (i = 0; i < 5; i++) { + /* Set file name */ + sprintf(file_name, ASYNC_API_TEST_FILE_PRINTF, i); + + /* Create file asynchronously */ + if ((file_id = H5Fcreate_async(file_name, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT, es_id)) < + 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + if (i > max_printf_file) + max_printf_file = i; + + /* Create the group asynchronously */ + if ((grp_id = H5Gcreate_async(file_id, "grp", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT, es_id)) < + 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + + /* Create the dataset asynchronously */ + if ((dset_id = H5Dcreate_async(grp_id, "dset", H5T_NATIVE_INT, space_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + + /* Update wbuf */ + for (j = 0; j < 6; j++) + for (k = 0; k < 10; k++) + wbuf[i][j][k] += 5 * 6 * 10; + + /* Write the dataset asynchronously */ + if (H5Dwrite_async(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf[i], es_id) < + 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + + /* Close the dataset asynchronously */ + if (H5Dclose_async(dset_id, es_id) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + + /* Close the group asynchronously */ + if (H5Gclose_async(grp_id, es_id) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + + /* Close the file asynchronously */ + if (H5Fclose_async(file_id, es_id) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + + /* Kick the event stack to make progress */ + if (H5ESwait(es_id, 0, &num_in_progress, &op_failed) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + if (op_failed) + PART_TEST_ERROR(multi_file_grp_dset_kick); + } /* end for */ + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + if (op_failed) + PART_TEST_ERROR(multi_file_grp_dset_kick); + + /* Loop over files */ + for (i = 0; i < 5; i++) { + /* Set file name */ + sprintf(file_name, ASYNC_API_TEST_FILE_PRINTF, i); + + /* Open the file asynchronously */ + if ((file_id = H5Fopen_async(file_name, H5F_ACC_RDONLY, H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + + /* Open the group asynchronously */ + if ((grp_id = H5Gopen_async(file_id, "grp", H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + + /* Open the dataset asynchronously */ + if ((dset_id = H5Dopen_async(grp_id, "dset", H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + + /* Read the dataset asynchronously */ + if (H5Dread_async(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf[i], es_id) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + + /* Close the dataset asynchronously */ + if (H5Dclose_async(dset_id, es_id) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + + /* Close the group asynchronously */ + if (H5Gclose_async(grp_id, es_id) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + + /* Close the file asynchronously */ + if (H5Fclose_async(file_id, es_id) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + + /* Kick the event stack to make progress */ + if (H5ESwait(es_id, 0, &num_in_progress, &op_failed) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + if (op_failed) + PART_TEST_ERROR(multi_file_grp_dset_kick); + } /* end for */ + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + if (op_failed) + PART_TEST_ERROR(multi_file_grp_dset_kick); + + /* Verify the read data */ + for (i = 0; i < 5; i++) + for (j = 0; j < 6; j++) + for (k = 0; k < 10; k++) + if (wbuf[i][j][k] != rbuf[i][j][k]) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + PART_ERROR(multi_file_grp_dset_kick); + } /* end if */ + + PASSED(); + } + PART_END(multi_file_grp_dset_kick); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5ESclose(es_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(space_id); + H5Gclose(grp_id); + H5Dclose(dset_id); + H5Fclose(file_id); + H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed); + H5ESclose(es_id); + } + H5E_END_TRY; + + return 1; +} /* end test_multi_file_grp_dset_io() */ + +/* + * Create file and dataset, write to dataset + */ +static int +test_set_extent(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id[6] = {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, + H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID}; + hid_t fspace_out[6] = {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, + H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID}; + hid_t mspace_id = H5I_INVALID_HID; + hid_t dcpl_id = H5I_INVALID_HID; + hid_t es_id = H5I_INVALID_HID; + hsize_t dims[2] = {1, 10}; + hsize_t mdims[2] = {7, 10}; + hsize_t cdims[2] = {2, 3}; + hsize_t start[2] = {0, 0}; + hsize_t count[2] = {1, 10}; + size_t num_in_progress; + hbool_t op_failed; + htri_t tri_ret; + int wbuf[6][10]; + int rbuf[6][10]; + int i, j; + + TESTING("H5Dset_extent() and H5Dget_space()"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + SKIPPED(); + HDprintf(" API functions for basic file, dataset, dataset more, or flush aren't supported with " + "this connector\n"); + return 0; + } + + /* Create file dataspace */ + if ((fspace_id[0] = H5Screate_simple(2, dims, mdims)) < 0) + TEST_ERROR; + + /* Create memory dataspace */ + if ((mspace_id = H5Screate_simple(1, &dims[1], NULL)) < 0) + TEST_ERROR; + + /* Create DCPL */ + if ((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) + TEST_ERROR; + + /* Set chunking */ + if (H5Pset_chunk(dcpl_id, 2, cdims) < 0) + TEST_ERROR; + + /* Initialize wbuf */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) + wbuf[i][j] = 10 * i + j; + + /* Create event stack */ + if ((es_id = H5EScreate()) < 0) + TEST_ERROR; + + /* Create file asynchronously */ + if ((file_id = H5Fcreate_async(ASYNC_API_TEST_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Create the dataset asynchronously */ + if ((dset_id = H5Dcreate_async(file_id, "dset", H5T_NATIVE_INT, fspace_id[0], H5P_DEFAULT, dcpl_id, + H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Extend the first dataset from 1 to 6, 1 at a time */ + for (i = 0; i < 6; i++) { + /* No need to extend on the first iteration */ + if (i) { + /* Copy dataspace */ + if ((fspace_id[i] = H5Scopy(fspace_id[i - 1])) < 0) + TEST_ERROR; + + /* Extend datapace */ + dims[0] = (hsize_t)(i + 1); + if (H5Sset_extent_simple(fspace_id[i], 2, dims, mdims) < 0) + TEST_ERROR; + + /* Extend dataset asynchronously */ + if (H5Dset_extent_async(dset_id, dims, es_id) < 0) + TEST_ERROR; + + /* Select hyperslab in file space to match new region */ + start[0] = (hsize_t)i; + if (H5Sselect_hyperslab(fspace_id[i], H5S_SELECT_SET, start, NULL, count, NULL) < 0) + TEST_ERROR; + } /* end if */ + + /* Get dataset dataspace */ + if ((fspace_out[i] = H5Dget_space_async(dset_id, es_id)) < 0) + TEST_ERROR; + + /* Write the dataset slice asynchronously */ + if (H5Dwrite_async(dset_id, H5T_NATIVE_INT, mspace_id, fspace_id[i], H5P_DEFAULT, wbuf[i], es_id) < 0) + TEST_ERROR; + } /* end for */ + + /* Flush the dataset asynchronously. This will effectively work as a + * barrier, guaranteeing the read takes place after the write. */ + if (H5Oflush_async(dset_id, es_id) < 0) + TEST_ERROR; + + /* Read the entire dataset asynchronously */ + if (H5Dread_async(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf, es_id) < 0) + TEST_ERROR; + + /* Verify extents are correct. We do not need to wait because of the + * "future id" capability. */ + for (i = 0; i < 6; i++) { + if ((tri_ret = H5Sextent_equal(fspace_id[i], fspace_out[i])) < 0) + TEST_ERROR; + if (!tri_ret) + FAIL_PUTS_ERROR(" dataspaces are not equal\n"); + if (i && H5Sclose(fspace_id[i]) < 0) + TEST_ERROR; + if (H5Sclose(fspace_out[i]) < 0) + TEST_ERROR; + } /* end for */ + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Verify the read data */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) + if (wbuf[i][j] != rbuf[i][j]) + FAIL_PUTS_ERROR(" data verification failed\n"); + + /* + * Now try extending the dataset, closing it, reopening it, and getting the + * space. + */ + /* Extend datapace */ + dims[0] = (hsize_t)7; + if (H5Sset_extent_simple(fspace_id[0], 2, dims, mdims) < 0) + TEST_ERROR; + + /* Extend dataset asynchronously */ + if (H5Dset_extent_async(dset_id, dims, es_id) < 0) + TEST_ERROR; + + /* Close dataset asynchronously */ + if (H5Dclose_async(dset_id, es_id) < 0) + TEST_ERROR; + + /* Open dataset asynchronously */ + if ((dset_id = H5Dopen_async(file_id, "dset", H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Get dataset dataspace asynchronously */ + if ((fspace_out[0] = H5Dget_space_async(dset_id, es_id)) < 0) + TEST_ERROR; + + /* Verify the extents match */ + if ((tri_ret = H5Sextent_equal(fspace_id[0], fspace_out[0])) < 0) + TEST_ERROR; + if (!tri_ret) + FAIL_PUTS_ERROR(" dataspaces are not equal\n"); + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Close */ + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + if (H5Sclose(mspace_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id[0]) < 0) + TEST_ERROR; + if (H5Sclose(fspace_out[0]) < 0) + TEST_ERROR; + if (H5Pclose(dcpl_id) < 0) + TEST_ERROR; + if (H5ESclose(es_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(mspace_id); + for (i = 0; i < 6; i++) { + H5Sclose(fspace_id[i]); + H5Sclose(fspace_out[i]); + } /* end for */ + H5Pclose(dcpl_id); + H5Dclose(dset_id); + H5Fclose(file_id); + H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed); + H5ESclose(es_id); + } + H5E_END_TRY; + + return 1; +} /* end test_set_extent() */ + +/* + * Test H5Aexists() + */ +static int +test_attribute_exists(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + hid_t es_id = H5I_INVALID_HID; + hsize_t dims[2] = {6, 10}; + hbool_t exists1; + hbool_t exists2; + size_t num_in_progress; + hbool_t op_failed; + + TESTING("H5Aexists()"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file, dataset, dataset more, attribute, or flush aren't " + "supported with this connector\n"); + return 0; + } + + /* Create dataspace */ + if ((space_id = H5Screate_simple(2, dims, NULL)) < 0) + TEST_ERROR; + + /* Create event stack */ + if ((es_id = H5EScreate()) < 0) + TEST_ERROR; + + /* Open file asynchronously */ + if ((file_id = H5Fopen_async(ASYNC_API_TEST_FILE, H5F_ACC_RDWR, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Create the dataset asynchronously */ + if ((dset_id = H5Dcreate_async(file_id, "attr_exists_dset", H5T_NATIVE_INT, space_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Check if the attribute exists asynchronously */ + if (H5Aexists_async(dset_id, "attr", &exists1, es_id) < 0) + TEST_ERROR; + + /* Flush the dataset asynchronously. This will effectively work as a + * barrier, guaranteeing the create takes place after the existence check + */ + if (H5Oflush_async(dset_id, es_id) < 0) + TEST_ERROR; + + /* Create the attribute asynchronously */ + if ((attr_id = + H5Acreate_async(dset_id, "attr", H5T_NATIVE_INT, space_id, H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Flush the dataset asynchronously. This will effectively work as a + * barrier, guaranteeing the existence check takes place after the create. + */ + if (H5Oflush_async(dset_id, es_id) < 0) + TEST_ERROR; + + /* Check if the attribute exists asynchronously */ + if (H5Aexists_async(dset_id, "attr", &exists2, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Check if H5Aexists returned the correct values */ + if (exists1) + FAIL_PUTS_ERROR(" H5Aexists returned TRUE for an attribute that should not exist"); + if (!exists2) + FAIL_PUTS_ERROR(" H5Aexists returned FALSE for an attribute that should exist"); + + /* Close */ + if (H5Aclose_async(attr_id, es_id) < 0) + TEST_ERROR; + if (H5Dclose_async(dset_id, es_id) < 0) + TEST_ERROR; + if (H5Fclose_async(file_id, es_id) < 0) + TEST_ERROR; + if (H5Sclose(space_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + if (H5ESclose(es_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(space_id); + H5Aclose(attr_id); + H5Dclose(dset_id); + H5Fclose(file_id); + H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed); + H5ESclose(es_id); + } + H5E_END_TRY; + + return 1; +} /* end test_attribute_io() */ + +/* + * Create file, dataset, and attribute, write to attribute + */ +static int +test_attribute_io(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + hid_t es_id = H5I_INVALID_HID; + hsize_t dims[2] = {6, 10}; + size_t num_in_progress; + hbool_t op_failed; + int wbuf[6][10]; + int rbuf[6][10]; + int i, j; + + TESTING("attribute I/O"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file, dataset, dataset more, attribute, or flush aren't " + "supported with this connector\n"); + return 0; + } + + /* Create dataspace */ + if ((space_id = H5Screate_simple(2, dims, NULL)) < 0) + TEST_ERROR; + + /* Create event stack */ + if ((es_id = H5EScreate()) < 0) + TEST_ERROR; + + /* Open file asynchronously */ + if ((file_id = H5Fopen_async(ASYNC_API_TEST_FILE, H5F_ACC_RDWR, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Create the dataset asynchronously */ + if ((dset_id = H5Dcreate_async(file_id, "attr_dset", H5T_NATIVE_INT, space_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Create the attribute asynchronously */ + if ((attr_id = + H5Acreate_async(dset_id, "attr", H5T_NATIVE_INT, space_id, H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Initialize wbuf */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) + wbuf[i][j] = 10 * i + j; + + /* Write the attribute asynchronously */ + if (H5Awrite_async(attr_id, H5T_NATIVE_INT, wbuf, es_id) < 0) + TEST_ERROR; + + /* Flush the dataset asynchronously. This will effectively work as a + * barrier, guaranteeing the read takes place after the write. */ + if (H5Oflush_async(dset_id, es_id) < 0) + TEST_ERROR; + + /* Read the attribute asynchronously */ + if (H5Aread_async(attr_id, H5T_NATIVE_INT, rbuf, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Verify the read data */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) + if (wbuf[i][j] != rbuf[i][j]) + FAIL_PUTS_ERROR(" data verification failed\n"); + + /* Close the attribute asynchronously */ + if (H5Aclose_async(attr_id, es_id) < 0) + TEST_ERROR; + + /* Open the attribute asynchronously */ + if ((attr_id = H5Aopen_async(dset_id, "attr", H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Read the attribute asynchronously */ + if (H5Aread_async(attr_id, H5T_NATIVE_INT, rbuf, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Verify the read data */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) + if (wbuf[i][j] != rbuf[i][j]) + FAIL_PUTS_ERROR(" data verification failed\n"); + + /* Close out of order to see if it trips things up */ + if (H5Dclose_async(dset_id, es_id) < 0) + TEST_ERROR; + if (H5Aclose_async(attr_id, es_id) < 0) + TEST_ERROR; + if (H5Fclose_async(file_id, es_id) < 0) + TEST_ERROR; + if (H5Sclose(space_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + if (H5ESclose(es_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(space_id); + H5Aclose(attr_id); + H5Dclose(dset_id); + H5Fclose(file_id); + H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed); + H5ESclose(es_id); + } + H5E_END_TRY; + + return 1; +} /* end test_attribute_io() */ + +/* + * Create file, dataset, and attribute, write to attribute with type conversion + */ +static int +test_attribute_io_tconv(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + hid_t es_id = H5I_INVALID_HID; + hsize_t dims[2] = {6, 10}; + size_t num_in_progress; + hbool_t op_failed; + int wbuf[6][10]; + int rbuf[6][10]; + int i, j; + + TESTING("attribute I/O with type conversion"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, attribute, or flush aren't supported with this connector\n"); + return 0; + } + + /* Create dataspace */ + if ((space_id = H5Screate_simple(2, dims, NULL)) < 0) + TEST_ERROR; + + /* Create event stack */ + if ((es_id = H5EScreate()) < 0) + TEST_ERROR; + + /* Open file asynchronously */ + if ((file_id = H5Fopen_async(ASYNC_API_TEST_FILE, H5F_ACC_RDWR, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Create the attribute asynchronously by name */ + if ((attr_id = H5Acreate_by_name_async(file_id, "attr_dset", "attr_tconv", H5T_STD_U16BE, space_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Initialize wbuf */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) + wbuf[i][j] = 10 * i + j; + + /* Write the attribute asynchronously */ + if (H5Awrite_async(attr_id, H5T_NATIVE_INT, wbuf, es_id) < 0) + TEST_ERROR; + + /* Flush the dataset asynchronously. This will effectively work as a + * barrier, guaranteeing the read takes place after the write. */ + if (H5Fflush_async(file_id, H5F_SCOPE_LOCAL, es_id) < 0) + TEST_ERROR; + + /* Read the attribute asynchronously */ + if (H5Aread_async(attr_id, H5T_NATIVE_INT, rbuf, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Verify the read data */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) + if (wbuf[i][j] != rbuf[i][j]) + FAIL_PUTS_ERROR(" data verification failed\n"); + + /* Close the attribute asynchronously */ + if (H5Aclose_async(attr_id, es_id) < 0) + TEST_ERROR; + + /* Open the attribute asynchronously */ + if ((attr_id = + H5Aopen_by_name_async(file_id, "attr_dset", "attr_tconv", H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Read the attribute asynchronously */ + if (H5Aread_async(attr_id, H5T_NATIVE_INT, rbuf, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Verify the read data */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) + if (wbuf[i][j] != rbuf[i][j]) + FAIL_PUTS_ERROR(" data verification failed\n"); + + /* Close */ + if (H5Aclose_async(attr_id, es_id) < 0) + TEST_ERROR; + if (H5Fclose_async(file_id, es_id) < 0) + TEST_ERROR; + if (H5Sclose(space_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + if (H5ESclose(es_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(space_id); + H5Aclose(attr_id); + H5Fclose(file_id); + H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed); + H5ESclose(es_id); + } + H5E_END_TRY; + + return 1; +} /* end test_attribute_io_tconv() */ + +/* + * Create file, dataset, and attribute, write to attribute with compound type + * conversion + */ +typedef struct tattr_cmpd_t { + int a; + int b; +} tattr_cmpd_t; + +static int +test_attribute_io_compound(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + hid_t mtype_id = H5I_INVALID_HID; + hid_t ftype_id = H5I_INVALID_HID; + hid_t mtypea_id = H5I_INVALID_HID; + hid_t mtypeb_id = H5I_INVALID_HID; + hid_t es_id = H5I_INVALID_HID; + hsize_t dims[2] = {6, 10}; + size_t num_in_progress; + hbool_t op_failed; + tattr_cmpd_t wbuf[6][10]; + tattr_cmpd_t rbuf[6][10]; + tattr_cmpd_t fbuf[6][10]; + int i, j; + + TESTING("attribute I/O with compound type conversion"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, attribute, or flush aren't supported with this connector\n"); + return 0; + } + + /* Create datatype */ + if ((mtype_id = H5Tcreate(H5T_COMPOUND, sizeof(tattr_cmpd_t))) < 0) + TEST_ERROR; + if (H5Tinsert(mtype_id, "a_name", HOFFSET(tattr_cmpd_t, a), H5T_NATIVE_INT) < 0) + TEST_ERROR; + if (H5Tinsert(mtype_id, "b_name", HOFFSET(tattr_cmpd_t, b), H5T_NATIVE_INT) < 0) + TEST_ERROR; + + if ((mtypea_id = H5Tcreate(H5T_COMPOUND, sizeof(tattr_cmpd_t))) < 0) + TEST_ERROR; + if (H5Tinsert(mtypea_id, "a_name", HOFFSET(tattr_cmpd_t, a), H5T_NATIVE_INT) < 0) + TEST_ERROR; + + if ((mtypeb_id = H5Tcreate(H5T_COMPOUND, sizeof(tattr_cmpd_t))) < 0) + TEST_ERROR; + if (H5Tinsert(mtypeb_id, "b_name", HOFFSET(tattr_cmpd_t, b), H5T_NATIVE_INT) < 0) + TEST_ERROR; + + if ((ftype_id = H5Tcreate(H5T_COMPOUND, 2 + 8)) < 0) + TEST_ERROR; + if (H5Tinsert(ftype_id, "a_name", 0, H5T_STD_U16BE) < 0) + TEST_ERROR; + if (H5Tinsert(ftype_id, "b_name", 2, H5T_STD_I64LE) < 0) + TEST_ERROR; + + /* Create dataspace */ + if ((space_id = H5Screate_simple(2, dims, NULL)) < 0) + TEST_ERROR; + + /* Create event stack */ + if ((es_id = H5EScreate()) < 0) + TEST_ERROR; + + /* Open file asynchronously */ + if ((file_id = H5Fopen_async(ASYNC_API_TEST_FILE, H5F_ACC_RDWR, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Create the attribute asynchronously by name */ + if ((attr_id = H5Acreate_by_name_async(file_id, "attr_dset", "attr_cmpd", ftype_id, space_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Initialize wbuf */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) { + wbuf[i][j].a = 2 * (10 * i + j); + wbuf[i][j].b = 2 * (10 * i + j) + 1; + } /* end for */ + + /* Write the attribute asynchronously */ + if (H5Awrite_async(attr_id, mtype_id, wbuf, es_id) < 0) + TEST_ERROR; + + /* Update fbuf */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) { + fbuf[i][j].a = wbuf[i][j].a; + fbuf[i][j].b = wbuf[i][j].b; + } /* end for */ + + /* Flush the dataset asynchronously. This will effectively work as a + * barrier, guaranteeing the read takes place after the write. */ + if (H5Fflush_async(file_id, H5F_SCOPE_LOCAL, es_id) < 0) + TEST_ERROR; + + /* Read the attribute asynchronously */ + if (H5Aread_async(attr_id, mtype_id, rbuf, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Verify the read data */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) { + if (rbuf[i][j].a != fbuf[i][j].a) + FAIL_PUTS_ERROR(" data verification failed\n"); + if (rbuf[i][j].b != fbuf[i][j].b) + FAIL_PUTS_ERROR(" data verification failed\n"); + } /* end for */ + + /* Clear the read buffer */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) { + rbuf[i][j].a = -2; + rbuf[i][j].b = -2; + } /* end for */ + + /* Read the attribute asynchronously (element a only) */ + if (H5Aread_async(attr_id, mtypea_id, rbuf, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Verify the read data */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) { + if (rbuf[i][j].a != fbuf[i][j].a) + FAIL_PUTS_ERROR(" data verification failed\n"); + if (rbuf[i][j].b != -2) + FAIL_PUTS_ERROR(" data verification failed\n"); + } /* end for */ + + /* Clear the read buffer */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) { + rbuf[i][j].a = -2; + rbuf[i][j].b = -2; + } /* end for */ + + /* Read the attribute asynchronously (element b only) */ + if (H5Aread_async(attr_id, mtypeb_id, rbuf, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Verify the read data */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) { + if (rbuf[i][j].a != -2) + FAIL_PUTS_ERROR(" data verification failed\n"); + if (rbuf[i][j].b != fbuf[i][j].b) + FAIL_PUTS_ERROR(" data verification failed\n"); + } /* end for */ + + /* Update wbuf */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) { + wbuf[i][j].a += 2 * 6 * 10; + wbuf[i][j].b += 2 * 6 * 10; + } /* end for */ + + /* Write the attribute asynchronously (element a only) */ + if (H5Awrite_async(attr_id, mtypea_id, wbuf, es_id) < 0) + TEST_ERROR; + + /* Update fbuf */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) + fbuf[i][j].a = wbuf[i][j].a; + + /* Flush the dataset asynchronously. This will effectively work as a + * barrier, guaranteeing the read takes place after the write. */ + if (H5Fflush_async(file_id, H5F_SCOPE_LOCAL, es_id) < 0) + TEST_ERROR; + + /* Clear the read buffer */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) { + rbuf[i][j].a = -2; + rbuf[i][j].b = -2; + } /* end for */ + + /* Read the attribute asynchronously */ + if (H5Aread_async(attr_id, mtype_id, rbuf, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Verify the read data */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) { + if (rbuf[i][j].a != fbuf[i][j].a) + FAIL_PUTS_ERROR(" data verification failed\n"); + if (rbuf[i][j].b != fbuf[i][j].b) + FAIL_PUTS_ERROR(" data verification failed\n"); + } /* end for */ + + /* Update wbuf */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) { + wbuf[i][j].a += 2 * 6 * 10; + wbuf[i][j].b += 2 * 6 * 10; + } /* end for */ + + /* Write the attribute asynchronously (element b only) */ + if (H5Awrite_async(attr_id, mtypeb_id, wbuf, es_id) < 0) + TEST_ERROR; + + /* Update fbuf */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) + fbuf[i][j].b = wbuf[i][j].b; + + /* Flush the dataset asynchronously. This will effectively work as a + * barrier, guaranteeing the read takes place after the write. */ + if (H5Fflush_async(file_id, H5F_SCOPE_LOCAL, es_id) < 0) + TEST_ERROR; + + /* Clear the read buffer */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) { + rbuf[i][j].a = -2; + rbuf[i][j].b = -2; + } /* end for */ + + /* Read the attribute asynchronously */ + if (H5Aread_async(attr_id, mtype_id, rbuf, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Verify the read data */ + for (i = 0; i < 6; i++) + for (j = 0; j < 10; j++) { + if (rbuf[i][j].a != fbuf[i][j].a) + FAIL_PUTS_ERROR(" data verification failed\n"); + if (rbuf[i][j].b != fbuf[i][j].b) + FAIL_PUTS_ERROR(" data verification failed\n"); + } /* end for */ + + /* Close */ + if (H5Aclose_async(attr_id, es_id) < 0) + TEST_ERROR; + if (H5Fclose_async(file_id, es_id) < 0) + TEST_ERROR; + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Tclose(mtype_id) < 0) + TEST_ERROR; + if (H5Tclose(ftype_id) < 0) + TEST_ERROR; + if (H5Tclose(mtypea_id) < 0) + TEST_ERROR; + if (H5Tclose(mtypeb_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + if (H5ESclose(es_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(space_id); + H5Tclose(mtype_id); + H5Tclose(ftype_id); + H5Tclose(mtypea_id); + H5Tclose(mtypeb_id); + H5Aclose(attr_id); + H5Fclose(file_id); + H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed); + H5ESclose(es_id); + } + H5E_END_TRY; + + return 1; +} /* end test_attribute_io_compound() */ + +/* + * Test group interfaces + */ +static int +test_group(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t parent_group_id = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t subgroup_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + hid_t es_id = H5I_INVALID_HID; + H5G_info_t info1; + H5G_info_t info2; + H5G_info_t info3; + size_t num_in_progress; + hbool_t op_failed; + + TESTING("group operations"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_MORE) || !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, group more, or creation order aren't supported " + "with this connector\n"); + return 0; + } + + /* Create GCPL */ + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) + TEST_ERROR; + + /* Track creation order */ + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0) + TEST_ERROR; + + /* Create event stack */ + if ((es_id = H5EScreate()) < 0) + TEST_ERROR; + + /* Open file asynchronously */ + if ((file_id = H5Fopen_async(ASYNC_API_TEST_FILE, H5F_ACC_RDWR, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Create the parent group asynchronously */ + if ((parent_group_id = + H5Gcreate_async(file_id, "group_parent", H5P_DEFAULT, gcpl_id, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Create 3 subgroups asynchronously, the first with no sub-subgroups, the + * second with 1, and the third with 2 */ + if ((group_id = + H5Gcreate_async(parent_group_id, "group1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + if (H5Gclose_async(group_id, es_id) < 0) + TEST_ERROR; + + if ((group_id = + H5Gcreate_async(parent_group_id, "group2", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + if ((subgroup_id = H5Gcreate_async(group_id, "subgroup1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT, es_id)) < + 0) + TEST_ERROR; + if (H5Gclose_async(subgroup_id, es_id) < 0) + TEST_ERROR; + if (H5Gclose_async(group_id, es_id) < 0) + TEST_ERROR; + + if ((group_id = + H5Gcreate_async(parent_group_id, "group3", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + if ((subgroup_id = H5Gcreate_async(group_id, "subgroup1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT, es_id)) < + 0) + TEST_ERROR; + if (H5Gclose_async(subgroup_id, es_id) < 0) + TEST_ERROR; + if ((subgroup_id = H5Gcreate_async(group_id, "subgroup2", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT, es_id)) < + 0) + TEST_ERROR; + if (H5Gclose_async(subgroup_id, es_id) < 0) + TEST_ERROR; + if (H5Gclose_async(group_id, es_id) < 0) + TEST_ERROR; + + /* Flush the file asynchronously. This will effectively work as a barrier, + * guaranteeing the read takes place after the write. */ + if (H5Fflush_async(file_id, H5F_SCOPE_LOCAL, es_id) < 0) + TEST_ERROR; + + /* Test H5Gget_info_async */ + /* Open group1 asynchronously */ + if ((group_id = H5Gopen_async(parent_group_id, "group1", H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Get info */ + if (H5Gget_info_async(group_id, &info1, es_id) < 0) + TEST_ERROR; + + /* Test H5Gget_info_by_idx_async */ + if (H5Gget_info_by_idx_async(parent_group_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 1, &info2, + H5P_DEFAULT, es_id) < 0) + TEST_ERROR; + + /* Test H5Gget_info_by_name_async */ + if (H5Gget_info_by_name_async(parent_group_id, "group3", &info3, H5P_DEFAULT, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Verify group infos */ + if (info1.nlinks != 0) + FAIL_PUTS_ERROR(" incorrect number of links"); + if (info2.nlinks != 1) + FAIL_PUTS_ERROR(" incorrect number of links"); + if (info3.nlinks != 2) + FAIL_PUTS_ERROR(" incorrect number of links"); + + /* Close */ + if (H5Gclose_async(group_id, es_id) < 0) + TEST_ERROR; + if (H5Gclose_async(parent_group_id, es_id) < 0) + TEST_ERROR; + if (H5Fclose_async(file_id, es_id) < 0) + TEST_ERROR; + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + if (H5ESclose(es_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + H5Gclose(group_id); + H5Gclose(parent_group_id); + H5Fclose(file_id); + H5Pclose(gcpl_id); + H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed); + H5ESclose(es_id); + } + H5E_END_TRY; + + return 1; +} /* end test_group() */ + +/* + * Test link interfaces + */ +static int +test_link(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t parent_group_id = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + hid_t es_id = H5I_INVALID_HID; + hbool_t existsh1; + hbool_t existsh2; + hbool_t existsh3; + hbool_t existss1; + hbool_t existss2; + hbool_t existss3; + size_t num_in_progress; + hbool_t op_failed; + + TESTING("link operations"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_HARD_LINKS) || !(vol_cap_flags_g & H5VL_CAP_FLAG_SOFT_LINKS) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, link, hard link, soft link, flush, or creation order " + "aren't supported with this connector\n"); + return 0; + } + + /* Create GCPL */ + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) + TEST_ERROR; + + /* Track creation order */ + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0) + TEST_ERROR; + + /* Create event stack */ + if ((es_id = H5EScreate()) < 0) + TEST_ERROR; + + /* Open file asynchronously */ + if ((file_id = H5Fopen_async(ASYNC_API_TEST_FILE, H5F_ACC_RDWR, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Create the parent group asynchronously */ + if ((parent_group_id = + H5Gcreate_async(file_id, "link_parent", H5P_DEFAULT, gcpl_id, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Create subgroup asynchronously. */ + if ((group_id = H5Gcreate_async(parent_group_id, "group", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT, es_id)) < + 0) + TEST_ERROR; + if (H5Gclose_async(group_id, es_id) < 0) + TEST_ERROR; + + /* Flush the parent group asynchronously. This will effectively work as a + * barrier, guaranteeing the link to the subgroup is visible to later tasks. + */ + if (H5Oflush_async(parent_group_id, es_id) < 0) + TEST_ERROR; + + /* Create hard link asynchronously */ + if (H5Lcreate_hard_async(parent_group_id, "group", parent_group_id, "hard_link", H5P_DEFAULT, H5P_DEFAULT, + es_id) < 0) + TEST_ERROR; + + /* Flush the parent group asynchronously. This will effectively work as a + * barrier, guaranteeing the soft link create takes place after the hard + * link create. */ + if (H5Oflush_async(parent_group_id, es_id) < 0) + TEST_ERROR; + + /* Create soft link asynchronously */ + if (H5Lcreate_soft_async("/link_parent/group", parent_group_id, "soft_link", H5P_DEFAULT, H5P_DEFAULT, + es_id) < 0) + TEST_ERROR; + + /* Flush the parent group asynchronously. This will effectively work as a + * barrier, guaranteeing the read takes place after the writes. */ + if (H5Oflush_async(parent_group_id, es_id) < 0) + TEST_ERROR; + + /* Check if hard link exists */ + if (H5Lexists_async(parent_group_id, "hard_link", &existsh1, H5P_DEFAULT, es_id) < 0) + TEST_ERROR; + + /* Check if soft link exists */ + if (H5Lexists_async(parent_group_id, "soft_link", &existss1, H5P_DEFAULT, es_id) < 0) + TEST_ERROR; + + /* Flush the parent group asynchronously. This will effectively work as a + * barrier, guaranteeing the delete takes place after the reads. */ + if (H5Oflush_async(parent_group_id, es_id) < 0) + TEST_ERROR; + + /* Delete soft link by index */ + if (H5Ldelete_by_idx_async(parent_group_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 2, H5P_DEFAULT, es_id) < + 0) + TEST_ERROR; + + /* Flush the parent group asynchronously. This will effectively work as a + * barrier, guaranteeing the read takes place after the delete. */ + if (H5Oflush_async(parent_group_id, es_id) < 0) + TEST_ERROR; + + /* Check if hard link exists */ + if (H5Lexists_async(parent_group_id, "hard_link", &existsh2, H5P_DEFAULT, es_id) < 0) + TEST_ERROR; + + /* Check if soft link exists */ + if (H5Lexists_async(parent_group_id, "soft_link", &existss2, H5P_DEFAULT, es_id) < 0) + TEST_ERROR; + + /* Flush the parent group asynchronously. This will effectively work as a + * barrier, guaranteeing the delete takes place after the reads. */ + if (H5Oflush_async(parent_group_id, es_id) < 0) + TEST_ERROR; + + /* Delete hard link */ + if (H5Ldelete_async(parent_group_id, "hard_link", H5P_DEFAULT, es_id) < 0) + TEST_ERROR; + + /* Flush the parent group asynchronously. This will effectively work as a + * barrier, guaranteeing the read takes place after the delete. */ + if (H5Oflush_async(parent_group_id, es_id) < 0) + TEST_ERROR; + + /* Check if hard link exists */ + if (H5Lexists_async(parent_group_id, "hard_link", &existsh3, H5P_DEFAULT, es_id) < 0) + TEST_ERROR; + + /* Check if soft link exists */ + if (H5Lexists_async(parent_group_id, "soft_link", &existss3, H5P_DEFAULT, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Check if existence returns were correct */ + if (!existsh1) + FAIL_PUTS_ERROR(" link exists returned FALSE for link that should exist"); + if (!existss1) + FAIL_PUTS_ERROR(" link exists returned FALSE for link that should exist"); + if (!existsh2) + FAIL_PUTS_ERROR(" link exists returned FALSE for link that should exist"); + if (existss2) + FAIL_PUTS_ERROR(" link exists returned TRUE for link that should not exist"); + if (existsh3) + FAIL_PUTS_ERROR(" link exists returned TRUE for link that should not exist"); + if (existsh3) + FAIL_PUTS_ERROR(" link exists returned TRUE for link that should not exist"); + + /* Close */ + if (H5Gclose_async(parent_group_id, es_id) < 0) + TEST_ERROR; + if (H5Fclose_async(file_id, es_id) < 0) + TEST_ERROR; + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + if (H5ESclose(es_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(group_id); + H5Gclose(parent_group_id); + H5Fclose(file_id); + H5Pclose(gcpl_id); + H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed); + H5ESclose(es_id); + } + H5E_END_TRY; + + return 1; +} /* end test_link() */ + +/* + * Test H5Ocopy() and H5Orefresh() + */ +static int +test_ocopy_orefresh(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t parent_group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + hid_t es_id = H5I_INVALID_HID; + hsize_t dims[2] = {6, 10}; + size_t num_in_progress; + hbool_t op_failed; + + TESTING("H5Ocopy() and H5Orefresh()"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, object more, flush, or refresh aren't " + "supported with this connector\n"); + return 0; + } + + /* Create dataspace */ + if ((space_id = H5Screate_simple(2, dims, NULL)) < 0) + TEST_ERROR; + + /* Create event stack */ + if ((es_id = H5EScreate()) < 0) + TEST_ERROR; + + /* Open file asynchronously */ + if ((file_id = H5Fopen_async(ASYNC_API_TEST_FILE, H5F_ACC_RDWR, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Create the parent group asynchronously */ + if ((parent_group_id = + H5Gcreate_async(file_id, "ocopy_parent", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Create dataset asynchronously. */ + if ((dset_id = H5Dcreate_async(parent_group_id, "dset", H5T_NATIVE_INT, space_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + if (H5Dclose_async(dset_id, es_id) < 0) + TEST_ERROR; + + /* Flush the parent group asynchronously. This will effectively work as a + * barrier, guaranteeing the copy takes place after dataset create. */ + if (H5Oflush_async(parent_group_id, es_id) < 0) + TEST_ERROR; + + /* Copy dataset */ + if (H5Ocopy_async(parent_group_id, "dset", parent_group_id, "copied_dset", H5P_DEFAULT, H5P_DEFAULT, + es_id) < 0) + TEST_ERROR; + + /* Flush the parent group asynchronously. This will effectively work as a + * barrier, guaranteeing the dataset open takes place copy. */ + if (H5Oflush_async(parent_group_id, es_id) < 0) + TEST_ERROR; + + /* Open the copied dataset asynchronously */ + if ((dset_id = H5Dopen_async(parent_group_id, "copied_dset", H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Refresh the copied dataset asynchronously */ + if (H5Orefresh(dset_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Close */ + if (H5Dclose_async(dset_id, es_id) < 0) + TEST_ERROR; + if (H5Gclose_async(parent_group_id, es_id) < 0) + TEST_ERROR; + if (H5Fclose_async(file_id, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + if (H5ESclose(es_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + H5Gclose(parent_group_id); + H5Fclose(file_id); + H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed); + H5ESclose(es_id); + } + H5E_END_TRY; + + return 1; +} /* end test_ocopy_orefresh() */ + +/* + * Test H5Freopen() + */ +static int +test_file_reopen(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t reopened_file_id = H5I_INVALID_HID; + hid_t es_id = H5I_INVALID_HID; + size_t num_in_progress; + hbool_t op_failed; + + TESTING("H5Freopen()"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_MORE)) { + SKIPPED(); + HDprintf(" API functions for basic file or file more aren't supported with this connector\n"); + return 0; + } + + /* Create event stack */ + if ((es_id = H5EScreate()) < 0) + TEST_ERROR; + + /* Open file asynchronously */ + if ((file_id = H5Fopen_async(ASYNC_API_TEST_FILE, H5F_ACC_RDWR, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Reopen file asynchronously */ + if ((reopened_file_id = H5Freopen_async(file_id, es_id)) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Close */ + if (H5Fclose_async(reopened_file_id, es_id) < 0) + TEST_ERROR; + if (H5Fclose_async(file_id, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + if (H5ESclose(es_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Fclose(reopened_file_id); + H5Fclose(file_id); + H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed); + H5ESclose(es_id); + } + H5E_END_TRY; + + return 1; +} /* end test_file_reopen() */ + +/* + * Cleanup temporary test files + */ +static void +cleanup_files(void) +{ + char file_name[64]; + int i; + + H5Fdelete(ASYNC_API_TEST_FILE, H5P_DEFAULT); + for (i = 0; i <= max_printf_file; i++) { + HDsnprintf(file_name, 64, ASYNC_API_TEST_FILE_PRINTF, i); + H5Fdelete(file_name, H5P_DEFAULT); + } /* end for */ +} + +int +H5_api_async_test(void) +{ + size_t i; + int nerrors; + + HDprintf("**********************************************\n"); + HDprintf("* *\n"); + HDprintf("* API Async Tests *\n"); + HDprintf("* *\n"); + HDprintf("**********************************************\n\n"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_ASYNC)) { + SKIPPED(); + HDprintf(" Async APIs aren't supported with this connector\n"); + return 0; + } + + for (i = 0, nerrors = 0; i < ARRAY_LENGTH(async_tests); i++) { + nerrors += (*async_tests[i])() ? 1 : 0; + } + + HDprintf("\n"); + + HDprintf("Cleaning up testing files\n"); + cleanup_files(); + + return nerrors; +} + +#else /* H5ESpublic_H */ + +int +H5_api_async_test(void) +{ + HDprintf("**********************************************\n"); + HDprintf("* *\n"); + HDprintf("* API Async Tests *\n"); + HDprintf("* *\n"); + HDprintf("**********************************************\n\n"); + + HDprintf("SKIPPED due to no async support in HDF5 library\n"); + + return 0; +} + +#endif /* H5ESpublic_H */ diff --git a/test/API/H5_api_async_test.h b/test/API/H5_api_async_test.h new file mode 100644 index 0000000..f6df48a --- /dev/null +++ b/test/API/H5_api_async_test.h @@ -0,0 +1,29 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef H5_API_ASYNC_TEST_H +#define H5_API_ASYNC_TEST_H + +#include "H5_api_test.h" + +int H5_api_async_test(void); + +/************************************************ + * * + * API async test defines * + * * + ************************************************/ + +#define ASYNC_API_TEST_FILE "H5_api_async_test.h5" +#define ASYNC_API_TEST_FILE_PRINTF "H5_api_async_test_%d.h5" + +#endif diff --git a/test/API/H5_api_attribute_test.c b/test/API/H5_api_attribute_test.c new file mode 100644 index 0000000..7f767a7 --- /dev/null +++ b/test/API/H5_api_attribute_test.c @@ -0,0 +1,11027 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "H5_api_attribute_test.h" + +/* + * TODO: Additional tests to be written: + * + * - Test for creating a large attribute. + * - Test for checking that object's max. attr. creation + * order value gets reset when all attributes are removed. + */ + +static int test_create_attribute_on_root(void); +static int test_create_attribute_on_dataset(void); +static int test_create_attribute_on_datatype(void); +static int test_create_attribute_with_null_space(void); +static int test_create_attribute_with_scalar_space(void); +static int test_create_attribute_with_space_in_name(void); +static int test_create_attribute_invalid_params(void); +static int test_open_attribute(void); +static int test_open_attribute_invalid_params(void); +static int test_write_attribute(void); +static int test_write_attribute_invalid_params(void); +static int test_read_attribute(void); +static int test_read_attribute_invalid_params(void); +static int test_read_empty_attribute(void); +static int test_close_attribute_invalid_id(void); +static int test_get_attribute_space_and_type(void); +static int test_get_attribute_space_and_type_invalid_params(void); +static int test_attribute_property_lists(void); +static int test_get_attribute_name(void); +static int test_get_attribute_name_invalid_params(void); +static int test_get_attribute_storage_size(void); +static int test_get_attribute_info(void); +static int test_get_attribute_info_invalid_params(void); +static int test_rename_attribute(void); +static int test_rename_attribute_invalid_params(void); +static int test_attribute_iterate_group(void); +static int test_attribute_iterate_dataset(void); +static int test_attribute_iterate_datatype(void); +static int test_attribute_iterate_index_saving(void); +static int test_attribute_iterate_invalid_params(void); +static int test_attribute_iterate_0_attributes(void); +static int test_delete_attribute(void); +static int test_delete_attribute_invalid_params(void); +static int test_attribute_exists(void); +static int test_attribute_exists_invalid_params(void); +static int test_attribute_many(void); +static int test_attribute_duplicate_id(void); +static int test_get_number_attributes(void); +static int test_attr_shared_dtype(void); + +static herr_t attr_iter_callback1(hid_t location_id, const char *attr_name, const H5A_info_t *ainfo, + void *op_data); +static herr_t attr_iter_callback2(hid_t location_id, const char *attr_name, const H5A_info_t *ainfo, + void *op_data); + +/* + * The array of attribute tests to be performed. + */ +static int (*attribute_tests[])(void) = {test_create_attribute_on_root, + test_create_attribute_on_dataset, + test_create_attribute_on_datatype, + test_create_attribute_with_null_space, + test_create_attribute_with_scalar_space, + test_create_attribute_with_space_in_name, + test_create_attribute_invalid_params, + test_open_attribute, + test_open_attribute_invalid_params, + test_write_attribute, + test_write_attribute_invalid_params, + test_read_attribute, + test_read_attribute_invalid_params, + test_read_empty_attribute, + test_close_attribute_invalid_id, + test_get_attribute_space_and_type, + test_get_attribute_space_and_type_invalid_params, + test_attribute_property_lists, + test_get_attribute_name, + test_get_attribute_name_invalid_params, + test_get_attribute_storage_size, + test_get_attribute_info, + test_get_attribute_info_invalid_params, + test_rename_attribute, + test_rename_attribute_invalid_params, + test_attribute_iterate_group, + test_attribute_iterate_dataset, + test_attribute_iterate_datatype, + test_attribute_iterate_index_saving, + test_attribute_iterate_invalid_params, + test_attribute_iterate_0_attributes, + test_delete_attribute, + test_delete_attribute_invalid_params, + test_attribute_exists, + test_attribute_exists_invalid_params, + test_attribute_duplicate_id, + test_attribute_many, + test_get_number_attributes, + test_attr_shared_dtype}; + +/* + * A test to check that an attribute can be created on + * the root group. + */ +static int +test_create_attribute_on_root(void) +{ + htri_t attr_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID, attr_id2 = H5I_INVALID_HID; + hid_t attr_dtype1 = H5I_INVALID_HID, attr_dtype2 = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + + TESTING_MULTIPART("attribute creation on the root group"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file or attribute aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((space_id = generate_random_dataspace(ATTRIBUTE_CREATE_ON_ROOT_SPACE_RANK, NULL, NULL, TRUE)) < 0) + TEST_ERROR; + + if ((attr_dtype1 = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + if ((attr_dtype2 = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Acreate2) + { + TESTING_2("H5Acreate on the root group"); + + if ((attr_id = H5Acreate2(file_id, ATTRIBUTE_CREATE_ON_ROOT_ATTR_NAME, attr_dtype1, space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s' using H5Acreate\n", + ATTRIBUTE_CREATE_ON_ROOT_ATTR_NAME); + PART_ERROR(H5Acreate2); + } + + /* Verify the attribute has been created */ + if ((attr_exists = H5Aexists(file_id, ATTRIBUTE_CREATE_ON_ROOT_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_CREATE_ON_ROOT_ATTR_NAME); + PART_ERROR(H5Acreate2); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' did not exist\n", ATTRIBUTE_CREATE_ON_ROOT_ATTR_NAME); + PART_ERROR(H5Acreate2); + } + + PASSED(); + } + PART_END(H5Acreate2); + + PART_BEGIN(H5Acreate_by_name) + { + TESTING_2("H5Acreate_by_name on the root group"); + + if ((attr_id2 = H5Acreate_by_name(file_id, "/", ATTRIBUTE_CREATE_ON_ROOT_ATTR_NAME2, attr_dtype2, + space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute on root group using H5Acreate_by_name\n"); + PART_ERROR(H5Acreate_by_name); + } + + /* Verify the attribute has been created */ + if ((attr_exists = H5Aexists(file_id, ATTRIBUTE_CREATE_ON_ROOT_ATTR_NAME2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_CREATE_ON_ROOT_ATTR_NAME2); + PART_ERROR(H5Acreate_by_name); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' did not exist\n", ATTRIBUTE_CREATE_ON_ROOT_ATTR_NAME2); + PART_ERROR(H5Acreate_by_name); + } + + PASSED(); + } + PART_END(H5Acreate_by_name); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype1) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype2) < 0) + TEST_ERROR; + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + if (H5Aclose(attr_id2) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(space_id); + H5Tclose(attr_dtype1); + H5Tclose(attr_dtype2); + H5Aclose(attr_id); + H5Aclose(attr_id2); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that an attribute can be created on + * a dataset. + */ +static int +test_create_attribute_on_dataset(void) +{ + htri_t attr_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID, attr_id2 = H5I_INVALID_HID; + hid_t attr_dtype1 = H5I_INVALID_HID, attr_dtype2 = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t dset_space_id = H5I_INVALID_HID; + hid_t attr_space_id = H5I_INVALID_HID; + + TESTING_MULTIPART("attribute creation on a dataset"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, or attribute aren't supported with this " + "connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", ATTRIBUTE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_CREATE_ON_DATASET_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", ATTRIBUTE_CREATE_ON_DATASET_GROUP_NAME); + goto error; + } + + if ((dset_space_id = + generate_random_dataspace(ATTRIBUTE_CREATE_ON_DATASET_DSET_SPACE_RANK, NULL, NULL, FALSE)) < 0) + TEST_ERROR; + if ((attr_space_id = + generate_random_dataspace(ATTRIBUTE_CREATE_ON_DATASET_ATTR_SPACE_RANK, NULL, NULL, TRUE)) < 0) + TEST_ERROR; + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + if ((attr_dtype1 = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + if ((attr_dtype2 = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, ATTRIBUTE_CREATE_ON_DATASET_DSET_NAME, dset_dtype, dset_space_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Acreate_on_dataset) + { + TESTING_2("H5Acreate on a dataset"); + + if ((attr_id = H5Acreate2(dset_id, ATTRIBUTE_CREATE_ON_DATASET_ATTR_NAME, attr_dtype1, + attr_space_id, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute\n"); + PART_ERROR(H5Acreate_on_dataset); + } + + /* Verify the attribute has been created */ + if ((attr_exists = H5Aexists(dset_id, ATTRIBUTE_CREATE_ON_DATASET_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_CREATE_ON_DATASET_ATTR_NAME); + PART_ERROR(H5Acreate_on_dataset); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' did not exist\n", ATTRIBUTE_CREATE_ON_DATASET_ATTR_NAME); + PART_ERROR(H5Acreate_on_dataset); + } + + PASSED(); + } + PART_END(H5Acreate_on_dataset); + + PART_BEGIN(H5Acreate_by_name_on_dataset) + { + TESTING_2("H5Acreate_by_name on a dataset"); + + if ((attr_id2 = H5Acreate_by_name(group_id, ATTRIBUTE_CREATE_ON_DATASET_DSET_NAME, + ATTRIBUTE_CREATE_ON_DATASET_ATTR_NAME2, attr_dtype2, + attr_space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute on dataset by name\n"); + PART_ERROR(H5Acreate_by_name_on_dataset); + } + + /* Verify the attribute has been created */ + if ((attr_exists = H5Aexists(dset_id, ATTRIBUTE_CREATE_ON_DATASET_ATTR_NAME2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_CREATE_ON_DATASET_ATTR_NAME2); + PART_ERROR(H5Acreate_by_name_on_dataset); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' did not exist\n", ATTRIBUTE_CREATE_ON_DATASET_ATTR_NAME2); + PART_ERROR(H5Acreate_by_name_on_dataset); + } + + PASSED(); + } + PART_END(H5Acreate_by_name_on_dataset); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(dset_space_id) < 0) + TEST_ERROR; + if (H5Sclose(attr_space_id) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype1) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype2) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + if (H5Aclose(attr_id2) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(dset_space_id); + H5Sclose(attr_space_id); + H5Tclose(dset_dtype); + H5Tclose(attr_dtype1); + H5Tclose(attr_dtype2); + H5Dclose(dset_id); + H5Aclose(attr_id); + H5Aclose(attr_id2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that an attribute can be created on + * a committed datatype. + */ +static int +test_create_attribute_on_datatype(void) +{ + htri_t attr_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t type_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID, attr_id2 = H5I_INVALID_HID; + hid_t attr_dtype1 = H5I_INVALID_HID, attr_dtype2 = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + + TESTING_MULTIPART("attribute creation on a committed datatype"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, stored datatype, or attribute aren't supported " + "with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", ATTRIBUTE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_CREATE_ON_DATATYPE_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", ATTRIBUTE_CREATE_ON_DATATYPE_GROUP_NAME); + goto error; + } + + if ((type_id = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create datatype\n"); + goto error; + } + + if (H5Tcommit2(group_id, ATTRIBUTE_CREATE_ON_DATATYPE_DTYPE_NAME, type_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't commit datatype\n"); + goto error; + } + + if ((space_id = generate_random_dataspace(ATTRIBUTE_CREATE_ON_DATATYPE_SPACE_RANK, NULL, NULL, TRUE)) < 0) + TEST_ERROR; + + if ((attr_dtype1 = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + if ((attr_dtype2 = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Acreate_on_datatype) + { + TESTING_2("H5Acreate on a committed datatype"); + + if ((attr_id = H5Acreate2(type_id, ATTRIBUTE_CREATE_ON_DATATYPE_ATTR_NAME, attr_dtype1, space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute on datatype using H5Acreate\n"); + PART_ERROR(H5Acreate_on_datatype); + } + + if ((attr_exists = H5Aexists(type_id, ATTRIBUTE_CREATE_ON_DATATYPE_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + PART_ERROR(H5Acreate_on_datatype); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not exist\n"); + PART_ERROR(H5Acreate_on_datatype); + } + + PASSED(); + } + PART_END(H5Acreate_on_datatype); + + PART_BEGIN(H5Acreate_by_name_on_datatype) + { + TESTING_2("H5Acreate_by_name on a committed datatype"); + + if ((attr_id2 = H5Acreate_by_name(group_id, ATTRIBUTE_CREATE_ON_DATATYPE_DTYPE_NAME, + ATTRIBUTE_CREATE_ON_DATATYPE_ATTR_NAME2, attr_dtype2, space_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute on datatype using H5Acreate_by_name\n"); + PART_ERROR(H5Acreate_by_name_on_datatype); + } + + /* Verify the attribute has been created */ + if ((attr_exists = H5Aexists(type_id, ATTRIBUTE_CREATE_ON_DATATYPE_ATTR_NAME2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + PART_ERROR(H5Acreate_by_name_on_datatype); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not exist\n"); + PART_ERROR(H5Acreate_by_name_on_datatype); + } + + PASSED(); + } + PART_END(H5Acreate_by_name_on_datatype); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype1) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype2) < 0) + TEST_ERROR; + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + if (H5Aclose(attr_id2) < 0) + TEST_ERROR; + if (H5Tclose(type_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(space_id); + H5Tclose(attr_dtype1); + H5Tclose(attr_dtype2); + H5Aclose(attr_id); + H5Aclose(attr_id2); + H5Tclose(type_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that creating an attribute with a + * NULL dataspace is not problematic. + */ +static int +test_create_attribute_with_null_space(void) +{ + htri_t attr_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t attr_dtype = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + + TESTING("attribute creation with a NULL dataspace"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or attribute aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file\n"); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_CREATE_NULL_DATASPACE_TEST_SUBGROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup\n"); + goto error; + } + + if ((space_id = H5Screate(H5S_NULL)) < 0) + TEST_ERROR; + + if ((attr_dtype = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_CREATE_NULL_DATASPACE_TEST_ATTR_NAME, attr_dtype, space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute\n"); + goto error; + } + + /* Verify the attribute has been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_CREATE_NULL_DATASPACE_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not exist\n"); + goto error; + } + + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + + if ((attr_id = H5Aopen(group_id, ATTRIBUTE_CREATE_NULL_DATASPACE_TEST_ATTR_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open attribute\n"); + goto error; + } + + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype) < 0) + TEST_ERROR; + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(space_id); + H5Tclose(attr_dtype); + H5Aclose(attr_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that creating an attribute with a + * scalar dataspace is not problematic. + */ +static int +test_create_attribute_with_scalar_space(void) +{ + htri_t attr_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t attr_dtype = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + + TESTING("attribute creation with a SCALAR dataspace"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or attribute aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file\n"); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_CREATE_SCALAR_DATASPACE_TEST_SUBGROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup\n"); + goto error; + } + + if ((space_id = H5Screate(H5S_SCALAR)) < 0) + TEST_ERROR; + + if ((attr_dtype = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_CREATE_SCALAR_DATASPACE_TEST_ATTR_NAME, attr_dtype, + space_id, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute\n"); + goto error; + } + + /* Verify the attribute has been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_CREATE_SCALAR_DATASPACE_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not exist\n"); + goto error; + } + + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + + if ((attr_id = H5Aopen(group_id, ATTRIBUTE_CREATE_SCALAR_DATASPACE_TEST_ATTR_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open attribute\n"); + goto error; + } + + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype) < 0) + TEST_ERROR; + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(space_id); + H5Tclose(attr_dtype); + H5Aclose(attr_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a space in an attribute's name + * is not problematic. + */ +static int +test_create_attribute_with_space_in_name(void) +{ + htri_t attr_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t attr_id2 = H5I_INVALID_HID; + hid_t attr_dtype = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + + TESTING("attribute creation with a space in attribute's name"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or attribute aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file\n"); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_CREATE_WITH_SPACE_IN_NAME_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", + ATTRIBUTE_CREATE_WITH_SPACE_IN_NAME_GROUP_NAME); + goto error; + } + + if ((space_id = + generate_random_dataspace(ATTRIBUTE_CREATE_WITH_SPACE_IN_NAME_SPACE_RANK, NULL, NULL, TRUE)) < 0) + TEST_ERROR; + + if ((attr_dtype = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_CREATE_WITH_SPACE_IN_NAME_ATTR_NAME, attr_dtype, space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute\n"); + goto error; + } + + /* Verify the attribute has been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_CREATE_WITH_SPACE_IN_NAME_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not exist\n"); + goto error; + } + + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype) < 0) + TEST_ERROR; + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(space_id); + H5Tclose(attr_dtype); + H5Aclose(attr_id); + H5Aclose(attr_id2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that an attribute can't be created when + * H5Acreate is passed invalid parameters. + */ +static int +test_create_attribute_invalid_params(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t attr_dtype = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + + TESTING_MULTIPART("attribute creation with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or attribute aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", ATTRIBUTE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_CREATE_INVALID_PARAMS_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group\n"); + goto error; + } + + if ((space_id = generate_random_dataspace(ATTRIBUTE_CREATE_INVALID_PARAMS_SPACE_RANK, NULL, NULL, TRUE)) < + 0) + TEST_ERROR; + if ((attr_dtype = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Acreate_invalid_loc_id) + { + TESTING_2("H5Acreate with invalid loc_id"); + + H5E_BEGIN_TRY + { + attr_id = H5Acreate2(H5I_INVALID_HID, ATTRIBUTE_CREATE_INVALID_PARAMS_ATTR_NAME, attr_dtype, + space_id, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" created attribute using H5Acreate with an invalid loc_id!\n"); + H5Aclose(attr_id); + PART_ERROR(H5Acreate_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Acreate_invalid_loc_id); + + PART_BEGIN(H5Acreate_invalid_attr_name) + { + TESTING_2("H5Acreate with invalid attribute name"); + + H5E_BEGIN_TRY + { + attr_id = H5Acreate2(group_id, NULL, attr_dtype, space_id, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" created attribute using H5Acreate with a NULL name!\n"); + H5Aclose(attr_id); + PART_ERROR(H5Acreate_invalid_attr_name); + } + + H5E_BEGIN_TRY + { + attr_id = H5Acreate2(group_id, "", attr_dtype, space_id, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" created attribute using H5Acreate with an invalid name of ''!\n"); + H5Aclose(attr_id); + PART_ERROR(H5Acreate_invalid_attr_name); + } + + PASSED(); + } + PART_END(H5Acreate_invalid_attr_name); + + PART_BEGIN(H5Acreate_invalid_datatype) + { + TESTING_2("H5Acreate with an invalid datatype"); + + H5E_BEGIN_TRY + { + attr_id = H5Acreate2(group_id, ATTRIBUTE_CREATE_INVALID_PARAMS_ATTR_NAME, H5I_INVALID_HID, + space_id, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" created attribute using H5Acreate with an invalid datatype!\n"); + H5Aclose(attr_id); + PART_ERROR(H5Acreate_invalid_datatype); + } + + PASSED(); + } + PART_END(H5Acreate_invalid_datatype); + + PART_BEGIN(H5Acreate_invalid_dataspace) + { + TESTING_2("H5Acreate with an invalid dataspace"); + + H5E_BEGIN_TRY + { + attr_id = H5Acreate2(group_id, ATTRIBUTE_CREATE_INVALID_PARAMS_ATTR_NAME, attr_dtype, + H5I_INVALID_HID, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" created attribute using H5Acreate with an invalid dataspace!\n"); + H5Aclose(attr_id); + PART_ERROR(H5Acreate_invalid_dataspace); + } + + PASSED(); + } + PART_END(H5Acreate_invalid_dataspace); + + PART_BEGIN(H5Acreate_invalid_acpl) + { + TESTING_2("H5Acreate with an invalid ACPL"); + + H5E_BEGIN_TRY + { + attr_id = H5Acreate2(group_id, ATTRIBUTE_CREATE_INVALID_PARAMS_ATTR_NAME, attr_dtype, + space_id, H5I_INVALID_HID, H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" created attribute using H5Acreate with an invalid ACPL!\n"); + H5Aclose(attr_id); + PART_ERROR(H5Acreate_invalid_acpl); + } + + PASSED(); + } + PART_END(H5Acreate_invalid_acpl); + + PART_BEGIN(H5Acreate_invalid_aapl) + { + TESTING_2("H5Acreate with an invalid AAPL"); +#ifndef NO_INVALID_PROPERTY_LIST_TESTS + H5E_BEGIN_TRY + { + attr_id = H5Acreate2(group_id, ATTRIBUTE_CREATE_INVALID_PARAMS_ATTR_NAME, attr_dtype, + space_id, H5P_DEFAULT, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" created attribute using H5Acreate with an invalid AAPL!\n"); + H5Aclose(attr_id); + PART_ERROR(H5Acreate_invalid_aapl); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Acreate_invalid_aapl); +#endif + } + PART_END(H5Acreate_invalid_aapl); + + PART_BEGIN(H5Acreate_by_name_invalid_loc_id) + { + TESTING_2("H5Acreate_by_name with an invalid loc_id"); + + H5E_BEGIN_TRY + { + attr_id = H5Acreate_by_name(H5I_INVALID_HID, ATTRIBUTE_CREATE_INVALID_PARAMS_GROUP_NAME, + ATTRIBUTE_CREATE_INVALID_PARAMS_ATTR_NAME, attr_dtype, space_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" created attribute using H5Acreate_by_name with an invalid loc_id!\n"); + H5Aclose(attr_id); + PART_ERROR(H5Acreate_by_name_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Acreate_by_name_invalid_loc_id); + + PART_BEGIN(H5Acreate_by_name_invalid_obj_name) + { + TESTING_2("H5Acreate_by_name with invalid object name"); + + H5E_BEGIN_TRY + { + attr_id = H5Acreate_by_name(group_id, NULL, ATTRIBUTE_CREATE_INVALID_PARAMS_ATTR_NAME, + attr_dtype, space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" created attribute using H5Acreate_by_name with a NULL object name!\n"); + H5Aclose(attr_id); + PART_ERROR(H5Acreate_by_name_invalid_obj_name); + } + + H5E_BEGIN_TRY + { + attr_id = H5Acreate_by_name(group_id, "", ATTRIBUTE_CREATE_INVALID_PARAMS_ATTR_NAME, + attr_dtype, space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf( + " created attribute using H5Acreate_by_name with an invalid object name of ''!\n"); + H5Aclose(attr_id); + PART_ERROR(H5Acreate_by_name_invalid_obj_name); + } + + PASSED(); + } + PART_END(H5Acreate_by_name_invalid_obj_name); + + PART_BEGIN(H5Acreate_by_name_invalid_attr_name) + { + TESTING_2("H5Acreate_by_name with invalid attribute name"); + + H5E_BEGIN_TRY + { + attr_id = H5Acreate_by_name(container_group, ATTRIBUTE_CREATE_INVALID_PARAMS_GROUP_NAME, NULL, + attr_dtype, space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" created attribute using H5Acreate_by_name with a NULL attribute name!\n"); + H5Aclose(attr_id); + PART_ERROR(H5Acreate_by_name_invalid_attr_name); + } + + H5E_BEGIN_TRY + { + attr_id = H5Acreate_by_name(container_group, ATTRIBUTE_CREATE_INVALID_PARAMS_GROUP_NAME, "", + attr_dtype, space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf( + " created attribute using H5Acreate_by_name with an invalid attribute name of ''!\n"); + H5Aclose(attr_id); + PART_ERROR(H5Acreate_by_name_invalid_attr_name); + } + + PASSED(); + } + PART_END(H5Acreate_by_name_invalid_attr_name); + + PART_BEGIN(H5Acreate_by_name_invalid_datatype) + { + TESTING_2("H5Acreate_by_name with invalid datatype"); + + H5E_BEGIN_TRY + { + attr_id = H5Acreate_by_name(container_group, ATTRIBUTE_CREATE_INVALID_PARAMS_GROUP_NAME, + ATTRIBUTE_CREATE_INVALID_PARAMS_ATTR_NAME, H5I_INVALID_HID, + space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" created attribute using H5Acreate_by_name with an invalid datatype!\n"); + H5Aclose(attr_id); + PART_ERROR(H5Acreate_by_name_invalid_datatype); + } + + PASSED(); + } + PART_END(H5Acreate_by_name_invalid_datatype); + + PART_BEGIN(H5Acreate_by_name_invalid_dataspace) + { + TESTING_2("H5Acreate_by_name with invalid dataspace"); + + H5E_BEGIN_TRY + { + attr_id = H5Acreate_by_name(container_group, ATTRIBUTE_CREATE_INVALID_PARAMS_GROUP_NAME, + ATTRIBUTE_CREATE_INVALID_PARAMS_ATTR_NAME, attr_dtype, + H5I_INVALID_HID, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" created attribute using H5Acreate_by_name with an invalid dataspace!\n"); + H5Aclose(attr_id); + PART_ERROR(H5Acreate_by_name_invalid_dataspace); + } + + PASSED(); + } + PART_END(H5Acreate_by_name_invalid_dataspace); + + PART_BEGIN(H5Acreate_by_name_invalid_acpl) + { + TESTING_2("H5Acreate_by_name with invalid ACPL"); + + H5E_BEGIN_TRY + { + attr_id = H5Acreate_by_name(container_group, ATTRIBUTE_CREATE_INVALID_PARAMS_GROUP_NAME, + ATTRIBUTE_CREATE_INVALID_PARAMS_ATTR_NAME, attr_dtype, space_id, + H5I_INVALID_HID, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" created attribute using H5Acreate_by_name with an invalid ACPL!\n"); + H5Aclose(attr_id); + PART_ERROR(H5Acreate_by_name_invalid_acpl); + } + + PASSED(); + } + PART_END(H5Acreate_by_name_invalid_acpl); + + PART_BEGIN(H5Acreate_by_name_invalid_aapl) + { + TESTING_2("H5Acreate_by_name with invalid AAPL"); +#ifndef NO_INVALID_PROPERTY_LIST_TESTS + H5E_BEGIN_TRY + { + attr_id = H5Acreate_by_name(container_group, ATTRIBUTE_CREATE_INVALID_PARAMS_GROUP_NAME, + ATTRIBUTE_CREATE_INVALID_PARAMS_ATTR_NAME, attr_dtype, space_id, + H5P_DEFAULT, H5I_INVALID_HID, H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" created attribute using H5Acreate_by_name with an invalid AAPL!\n"); + H5Aclose(attr_id); + PART_ERROR(H5Acreate_by_name_invalid_aapl); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Acreate_by_name_invalid_aapl); +#endif + } + PART_END(H5Acreate_by_name_invalid_aapl); + + PART_BEGIN(H5Acreate_by_name_invalid_lapl) + { + TESTING_2("H5Acreate_by_name with invalid LAPL"); + + H5E_BEGIN_TRY + { + attr_id = H5Acreate_by_name(container_group, ATTRIBUTE_CREATE_INVALID_PARAMS_GROUP_NAME, + ATTRIBUTE_CREATE_INVALID_PARAMS_ATTR_NAME, attr_dtype, space_id, + H5P_DEFAULT, H5P_DEFAULT, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" created attribute using H5Acreate_by_name with an invalid LAPL!\n"); + H5Aclose(attr_id); + PART_ERROR(H5Acreate_by_name_invalid_lapl); + } + + PASSED(); + } + PART_END(H5Acreate_by_name_invalid_lapl); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(space_id); + H5Tclose(attr_dtype); + H5Aclose(attr_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test for H5Aopen(_by_idx). + */ +static int +test_open_attribute(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + hid_t attr_type = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + + TESTING_MULTIPART("attribute opening"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or attribute aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", ATTRIBUTE_TEST_GROUP_NAME); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create GCPL for attribute creation order tracking\n"); + goto error; + } + + if (H5Pset_attr_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED) < 0) { + H5_FAILED(); + HDprintf(" couldn't set attribute creation order tracking\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_OPEN_TEST_GROUP_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", ATTRIBUTE_OPEN_TEST_GROUP_NAME); + goto error; + } + + if ((space_id = generate_random_dataspace(ATTRIBUTE_OPEN_TEST_SPACE_RANK, NULL, NULL, TRUE)) < 0) + TEST_ERROR; + + if ((attr_type = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + /* Create several attributes */ + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_OPEN_TEST_ATTR_NAME, attr_type, space_id, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s'\n", ATTRIBUTE_OPEN_TEST_ATTR_NAME); + goto error; + } + + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_OPEN_TEST_ATTR_NAME2, attr_type, space_id, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s'\n", ATTRIBUTE_OPEN_TEST_ATTR_NAME2); + goto error; + } + + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_OPEN_TEST_ATTR_NAME3, attr_type, space_id, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s'\n", ATTRIBUTE_OPEN_TEST_ATTR_NAME3); + goto error; + } + + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Aopen) + { + TESTING_2("H5Aopen"); + + if ((attr_id = H5Aopen(group_id, ATTRIBUTE_OPEN_TEST_ATTR_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open attribute '%s' using H5Aopen\n", ATTRIBUTE_OPEN_TEST_ATTR_NAME); + PART_ERROR(H5Aopen); + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close attribute '%s'\n", ATTRIBUTE_OPEN_TEST_ATTR_NAME); + PART_ERROR(H5Aopen); + } + + PASSED(); + } + PART_END(H5Aopen); + + PART_BEGIN(H5Aopen_by_name) + { + TESTING_2("H5Aopen_by_name"); + + if ((attr_id = H5Aopen_by_name(container_group, ATTRIBUTE_OPEN_TEST_GROUP_NAME, + ATTRIBUTE_OPEN_TEST_ATTR_NAME, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open attribute '%s' using H5Aopen_by_name\n", + ATTRIBUTE_OPEN_TEST_ATTR_NAME); + PART_ERROR(H5Aopen_by_name); + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close attribute '%s'\n", ATTRIBUTE_OPEN_TEST_ATTR_NAME); + PART_ERROR(H5Aopen_by_name); + } + + PASSED(); + } + PART_END(H5Aopen_by_name); + + PART_BEGIN(H5Aopen_by_idx_crt_order_increasing) + { + TESTING_2("H5Aopen_by_idx by creation order in increasing order"); + + if ((attr_id = H5Aopen_by_idx(container_group, ATTRIBUTE_OPEN_TEST_GROUP_NAME, H5_INDEX_CRT_ORDER, + H5_ITER_INC, 0, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open attribute '%s' at index %d using H5Aopen_by_idx by creation " + "order in increasing order\n", + ATTRIBUTE_OPEN_TEST_ATTR_NAME, 0); + PART_ERROR(H5Aopen_by_idx_crt_order_increasing); + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close attribute '%s'\n", ATTRIBUTE_OPEN_TEST_ATTR_NAME); + PART_ERROR(H5Aopen_by_idx_crt_order_increasing); + } + + if ((attr_id = H5Aopen_by_idx(container_group, ATTRIBUTE_OPEN_TEST_GROUP_NAME, H5_INDEX_CRT_ORDER, + H5_ITER_INC, 1, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open attribute '%s' at index %d using H5Aopen_by_idx by creation " + "order in increasing order\n", + ATTRIBUTE_OPEN_TEST_ATTR_NAME2, 1); + PART_ERROR(H5Aopen_by_idx_crt_order_increasing); + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close attribute '%s'\n", ATTRIBUTE_OPEN_TEST_ATTR_NAME2); + PART_ERROR(H5Aopen_by_idx_crt_order_increasing); + } + + if ((attr_id = H5Aopen_by_idx(container_group, ATTRIBUTE_OPEN_TEST_GROUP_NAME, H5_INDEX_CRT_ORDER, + H5_ITER_INC, 2, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open attribute '%s' at index %d using H5Aopen_by_idx by creation " + "order in increasing order\n", + ATTRIBUTE_OPEN_TEST_ATTR_NAME3, 2); + PART_ERROR(H5Aopen_by_idx_crt_order_increasing); + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close attribute '%s'\n", ATTRIBUTE_OPEN_TEST_ATTR_NAME3); + PART_ERROR(H5Aopen_by_idx_crt_order_increasing); + } + + PASSED(); + } + PART_END(H5Aopen_by_idx_crt_order_increasing); + + PART_BEGIN(H5Aopen_by_idx_crt_order_decreasing) + { + TESTING_2("H5Aopen_by_idx by creation order in decreasing order"); + + if ((attr_id = H5Aopen_by_idx(container_group, ATTRIBUTE_OPEN_TEST_GROUP_NAME, H5_INDEX_CRT_ORDER, + H5_ITER_DEC, 2, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open attribute '%s' at index %d using H5Aopen_by_idx by creation " + "order in decreasing order\n", + ATTRIBUTE_OPEN_TEST_ATTR_NAME, 2); + PART_ERROR(H5Aopen_by_idx_crt_order_decreasing); + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close attribute '%s'\n", ATTRIBUTE_OPEN_TEST_ATTR_NAME); + PART_ERROR(H5Aopen_by_idx_crt_order_decreasing); + } + + if ((attr_id = H5Aopen_by_idx(container_group, ATTRIBUTE_OPEN_TEST_GROUP_NAME, H5_INDEX_CRT_ORDER, + H5_ITER_DEC, 1, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open attribute '%s' at index %d using H5Aopen_by_idx by creation " + "order in decreasing order\n", + ATTRIBUTE_OPEN_TEST_ATTR_NAME2, 1); + PART_ERROR(H5Aopen_by_idx_crt_order_decreasing); + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close attribute '%s'\n", ATTRIBUTE_OPEN_TEST_ATTR_NAME2); + PART_ERROR(H5Aopen_by_idx_crt_order_decreasing); + } + + if ((attr_id = H5Aopen_by_idx(container_group, ATTRIBUTE_OPEN_TEST_GROUP_NAME, H5_INDEX_CRT_ORDER, + H5_ITER_DEC, 0, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open attribute '%s' at index %d using H5Aopen_by_idx by creation " + "order in decreasing order\n", + ATTRIBUTE_OPEN_TEST_ATTR_NAME3, 0); + PART_ERROR(H5Aopen_by_idx_crt_order_decreasing); + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close attribute '%s'\n", ATTRIBUTE_OPEN_TEST_ATTR_NAME3); + PART_ERROR(H5Aopen_by_idx_crt_order_decreasing); + } + + PASSED(); + } + PART_END(H5Aopen_by_idx_crt_order_decreasing); + + PART_BEGIN(H5Aopen_by_idx_name_order_increasing) + { + TESTING_2("H5Aopen_by_idx by alphabetical order in increasing order"); + + if ((attr_id = H5Aopen_by_idx(container_group, ATTRIBUTE_OPEN_TEST_GROUP_NAME, H5_INDEX_NAME, + H5_ITER_INC, 0, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open attribute '%s' at index %d using H5Aopen_by_idx by alphabetical " + "order in increasing order\n", + ATTRIBUTE_OPEN_TEST_ATTR_NAME, 0); + PART_ERROR(H5Aopen_by_idx_name_order_increasing); + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close attribute '%s'\n", ATTRIBUTE_OPEN_TEST_ATTR_NAME); + PART_ERROR(H5Aopen_by_idx_name_order_increasing); + } + + if ((attr_id = H5Aopen_by_idx(container_group, ATTRIBUTE_OPEN_TEST_GROUP_NAME, H5_INDEX_NAME, + H5_ITER_INC, 1, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open attribute '%s' at index %d using H5Aopen_by_idx by alphabetical " + "order in increasing order\n", + ATTRIBUTE_OPEN_TEST_ATTR_NAME2, 1); + PART_ERROR(H5Aopen_by_idx_name_order_increasing); + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close attribute '%s'\n", ATTRIBUTE_OPEN_TEST_ATTR_NAME2); + PART_ERROR(H5Aopen_by_idx_name_order_increasing); + } + + if ((attr_id = H5Aopen_by_idx(container_group, ATTRIBUTE_OPEN_TEST_GROUP_NAME, H5_INDEX_NAME, + H5_ITER_INC, 2, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open attribute '%s' at index %d using H5Aopen_by_idx by alphabetical " + "order in increasing order\n", + ATTRIBUTE_OPEN_TEST_ATTR_NAME3, 2); + PART_ERROR(H5Aopen_by_idx_name_order_increasing); + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close attribute '%s'\n", ATTRIBUTE_OPEN_TEST_ATTR_NAME3); + PART_ERROR(H5Aopen_by_idx_name_order_increasing); + } + + PASSED(); + } + PART_END(H5Aopen_by_idx_name_order_increasing); + + PART_BEGIN(H5Aopen_by_idx_name_order_decreasing) + { + TESTING_2("H5Aopen_by_idx by alphabetical order in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + if ((attr_id = H5Aopen_by_idx(container_group, ATTRIBUTE_OPEN_TEST_GROUP_NAME, H5_INDEX_NAME, + H5_ITER_DEC, 2, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open attribute '%s' at index %lld using H5Aopen_by_idx by " + "alphabetical order in decreasing order\n", + ATTRIBUTE_OPEN_TEST_ATTR_NAME, 2); + PART_ERROR(H5Aopen_by_idx_name_order_decreasing); + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close attribute '%s'\n", ATTRIBUTE_OPEN_TEST_ATTR_NAME); + PART_ERROR(H5Aopen_by_idx_name_order_decreasing); + } + + if ((attr_id = H5Aopen_by_idx(container_group, ATTRIBUTE_OPEN_TEST_GROUP_NAME, H5_INDEX_NAME, + H5_ITER_DEC, 1, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open attribute '%s' at index %lld using H5Aopen_by_idx by " + "alphabetical order in decreasing order\n", + ATTRIBUTE_OPEN_TEST_ATTR_NAME2, 1); + PART_ERROR(H5Aopen_by_idx_name_order_decreasing); + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close attribute '%s'\n", ATTRIBUTE_OPEN_TEST_ATTR_NAME2); + PART_ERROR(H5Aopen_by_idx_name_order_decreasing); + } + + if ((attr_id = H5Aopen_by_idx(container_group, ATTRIBUTE_OPEN_TEST_GROUP_NAME, H5_INDEX_NAME, + H5_ITER_DEC, 0, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open attribute '%s' at index %lld using H5Aopen_by_idx by " + "alphabetical order in decreasing order\n", + ATTRIBUTE_OPEN_TEST_ATTR_NAME3, 0); + PART_ERROR(H5Aopen_by_idx_name_order_decreasing); + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close attribute '%s'\n", ATTRIBUTE_OPEN_TEST_ATTR_NAME3); + PART_ERROR(H5Aopen_by_idx_name_order_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Aopen_by_idx_name_order_decreasing); +#endif + } + PART_END(H5Aopen_by_idx_name_order_decreasing); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Tclose(attr_type) < 0) + TEST_ERROR; + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(space_id); + H5Tclose(attr_type); + H5Aclose(attr_id); + H5Pclose(gcpl_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that an attribute can't be opened when + * H5Aopen(_by_name/_by_idx) is passed invalid parameters. + */ +static int +test_open_attribute_invalid_params(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + hid_t attr_type = H5I_INVALID_HID; + + TESTING_MULTIPART("attribute opening with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or attribute aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", ATTRIBUTE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_GROUP_NAME); + goto error; + } + + if ((space_id = + generate_random_dataspace(ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_SPACE_RANK, NULL, NULL, TRUE)) < 0) + TEST_ERROR; + + if ((attr_type = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_ATTR_NAME, attr_type, space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s'\n", ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_ATTR_NAME); + goto error; + } + + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Aopen_invalid_loc_id) + { + TESTING_2("H5Aopen with an invalid loc_id"); + + H5E_BEGIN_TRY + { + attr_id = H5Aopen(H5I_INVALID_HID, ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_ATTR_NAME, H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" opened attribute '%s' using H5Aopen with an invalid loc_id!\n", + ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_ATTR_NAME); + H5Aclose(attr_id); + PART_ERROR(H5Aopen_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Aopen_invalid_loc_id); + + PART_BEGIN(H5Aopen_invalid_attr_name) + { + TESTING_2("H5Aopen with an invalid attribute name"); + + H5E_BEGIN_TRY + { + attr_id = H5Aopen(group_id, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" opened attribute '%s' using H5Aopen with a NULL attribute name!\n", + ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_ATTR_NAME); + H5Aclose(attr_id); + PART_ERROR(H5Aopen_invalid_attr_name); + } + + H5E_BEGIN_TRY + { + attr_id = H5Aopen(group_id, "", H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" opened attribute '%s' using H5Aopen with an invalid attribute name of ''!\n", + ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_ATTR_NAME); + H5Aclose(attr_id); + PART_ERROR(H5Aopen_invalid_attr_name); + } + + PASSED(); + } + PART_END(H5Aopen_invalid_attr_name); + + PART_BEGIN(H5Aopen_invalid_aapl) + { + TESTING_2("H5Aopen with an invalid AAPL"); + + H5E_BEGIN_TRY + { + attr_id = H5Aopen(group_id, ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_ATTR_NAME, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" opened attribute '%s' using H5Aopen with an invalid AAPL!\n", + ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_ATTR_NAME); + H5Aclose(attr_id); + PART_ERROR(H5Aopen_invalid_aapl); + } + + PASSED(); + } + PART_END(H5Aopen_invalid_aapl); + + PART_BEGIN(H5Aopen_by_name_invalid_loc_id) + { + TESTING_2("H5Aopen_by_name with an invalid loc_id"); + + H5E_BEGIN_TRY + { + attr_id = + H5Aopen_by_name(H5I_INVALID_HID, ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_GROUP_NAME, + ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_ATTR_NAME, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" opened attribute '%s' using H5Aopen_by_name with an invalid loc_id!\n", + ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_ATTR_NAME); + H5Aclose(attr_id); + PART_ERROR(H5Aopen_by_name_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Aopen_by_name_invalid_loc_id); + + PART_BEGIN(H5Aopen_by_name_invalid_obj_name) + { + TESTING_2("H5Aopen_by_name with an invalid object name"); + + H5E_BEGIN_TRY + { + attr_id = H5Aopen_by_name(container_group, NULL, ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_ATTR_NAME, + H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" opened attribute '%s' using H5Aopen_by_name with a NULL object name!\n", + ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_ATTR_NAME); + H5Aclose(attr_id); + PART_ERROR(H5Aopen_by_name_invalid_obj_name); + } + + H5E_BEGIN_TRY + { + attr_id = H5Aopen_by_name(container_group, "", ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_ATTR_NAME, + H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf( + " opened attribute '%s' using H5Aopen_by_name with an invalid object name of ''!\n", + ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_ATTR_NAME); + H5Aclose(attr_id); + PART_ERROR(H5Aopen_by_name_invalid_obj_name); + } + + PASSED(); + } + PART_END(H5Aopen_by_name_invalid_obj_name); + + PART_BEGIN(H5Aopen_by_name_invalid_attr_name) + { + TESTING_2("H5Aopen_by_name with an invalid attribute name"); + + H5E_BEGIN_TRY + { + attr_id = H5Aopen_by_name(container_group, ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_GROUP_NAME, + NULL, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" opened attribute '%s' using H5Aopen_by_name with a NULL attribute name!\n", + ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_ATTR_NAME); + H5Aclose(attr_id); + PART_ERROR(H5Aopen_by_name_invalid_attr_name); + } + + H5E_BEGIN_TRY + { + attr_id = H5Aopen_by_name(container_group, ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_GROUP_NAME, "", + H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf( + " opened attribute '%s' using H5Aopen_by_name with an invalid attribute name of ''!\n", + ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_ATTR_NAME); + H5Aclose(attr_id); + PART_ERROR(H5Aopen_by_name_invalid_attr_name); + } + + PASSED(); + } + PART_END(H5Aopen_by_name_invalid_attr_name); + + PART_BEGIN(H5Aopen_by_name_invalid_aapl) + { + TESTING_2("H5Aopen_by_name with an invalid AAPL"); + + H5E_BEGIN_TRY + { + attr_id = H5Aopen_by_name(container_group, ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_GROUP_NAME, + ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_ATTR_NAME, H5I_INVALID_HID, + H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" opened attribute '%s' using H5Aopen_by_name with an invalid AAPL!\n", + ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_ATTR_NAME); + H5Aclose(attr_id); + PART_ERROR(H5Aopen_by_name_invalid_aapl); + } + + PASSED(); + } + PART_END(H5Aopen_by_name_invalid_aapl); + + PART_BEGIN(H5Aopen_by_name_invalid_lapl) + { + TESTING_2("H5Aopen_by_name with an invalid LAPL"); + + H5E_BEGIN_TRY + { + attr_id = H5Aopen_by_name(container_group, ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_GROUP_NAME, + ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_ATTR_NAME, H5P_DEFAULT, + H5I_INVALID_HID); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" opened attribute '%s' using H5Aopen_by_name with an invalid LAPL!\n", + ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_ATTR_NAME); + H5Aclose(attr_id); + PART_ERROR(H5Aopen_by_name_invalid_lapl); + } + + PASSED(); + } + PART_END(H5Aopen_by_name_invalid_lapl); + + PART_BEGIN(H5Aopen_by_idx_invalid_loc_id) + { + TESTING_2("H5Aopen_by_idx with an invalid loc_id"); + + H5E_BEGIN_TRY + { + attr_id = H5Aopen_by_idx(H5I_INVALID_HID, ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_GROUP_NAME, + H5_INDEX_NAME, H5_ITER_INC, 0, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" opened attribute '%s' using H5Aopen_by_idx with an invalid loc_id!\n", + ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_ATTR_NAME); + H5Aclose(attr_id); + PART_ERROR(H5Aopen_by_idx_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Aopen_by_idx_invalid_loc_id); + + PART_BEGIN(H5Aopen_by_idx_invalid_obj_name) + { + TESTING_2("H5Aopen_by_idx with an invalid object name"); + + H5E_BEGIN_TRY + { + attr_id = H5Aopen_by_idx(container_group, NULL, H5_INDEX_NAME, H5_ITER_INC, 0, H5P_DEFAULT, + H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" opened attribute '%s' using H5Aopen_by_idx with a NULL object name!\n", + ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_ATTR_NAME); + H5Aclose(attr_id); + PART_ERROR(H5Aopen_by_idx_invalid_obj_name); + } + + H5E_BEGIN_TRY + { + attr_id = H5Aopen_by_idx(container_group, "", H5_INDEX_NAME, H5_ITER_INC, 0, H5P_DEFAULT, + H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf( + " opened attribute '%s' using H5Aopen_by_idx with an invalid object name of ''!\n", + ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_ATTR_NAME); + H5Aclose(attr_id); + PART_ERROR(H5Aopen_by_idx_invalid_obj_name); + } + + PASSED(); + } + PART_END(H5Aopen_by_idx_invalid_obj_name); + + PART_BEGIN(H5Aopen_by_idx_invalid_index_type) + { + TESTING_2("H5Aopen_by_idx with an invalid index type"); + + H5E_BEGIN_TRY + { + attr_id = H5Aopen_by_idx(container_group, ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_GROUP_NAME, + H5_INDEX_UNKNOWN, H5_ITER_INC, 0, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" opened attribute '%s' using H5Aopen_by_idx with invalid index type " + "H5_INDEX_UNKNOWN!\n", + ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_ATTR_NAME); + H5Aclose(attr_id); + PART_ERROR(H5Aopen_by_idx_invalid_index_type); + } + + H5E_BEGIN_TRY + { + attr_id = H5Aopen_by_idx(container_group, ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_GROUP_NAME, + H5_INDEX_N, H5_ITER_INC, 0, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf( + " opened attribute '%s' using H5Aopen_by_idx with invalid index type H5_INDEX_N!\n", + ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_ATTR_NAME); + H5Aclose(attr_id); + PART_ERROR(H5Aopen_by_idx_invalid_index_type); + } + + PASSED(); + } + PART_END(H5Aopen_by_idx_invalid_index_type); + + PART_BEGIN(H5Aopen_by_idx_invalid_iter_order) + { + TESTING_2("H5Aopen_by_idx with an invalid iteration order"); + + H5E_BEGIN_TRY + { + attr_id = H5Aopen_by_idx(container_group, ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_GROUP_NAME, + H5_INDEX_NAME, H5_ITER_UNKNOWN, 0, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" opened attribute '%s' using H5Aopen_by_idx with invalid iteration order " + "H5_ITER_UNKNOWN!\n", + ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_ATTR_NAME); + H5Aclose(attr_id); + PART_ERROR(H5Aopen_by_idx_invalid_iter_order); + } + + H5E_BEGIN_TRY + { + attr_id = H5Aopen_by_idx(container_group, ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_GROUP_NAME, + H5_INDEX_NAME, H5_ITER_N, 0, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" opened attribute '%s' using H5Aopen_by_idx with invalid iteration order " + "H5_ITER_N!\n", + ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_ATTR_NAME); + H5Aclose(attr_id); + PART_ERROR(H5Aopen_by_idx_invalid_iter_order); + } + + PASSED(); + } + PART_END(H5Aopen_by_idx_invalid_iter_order); + + PART_BEGIN(H5Aopen_by_idx_invalid_aapl) + { + TESTING_2("H5Aopen_by_idx with an invalid AAPL"); + + H5E_BEGIN_TRY + { + attr_id = H5Aopen_by_idx(container_group, ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_GROUP_NAME, + H5_INDEX_NAME, H5_ITER_INC, 0, H5I_INVALID_HID, H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" opened attribute '%s' using H5Aopen_by_idx with an invalid AAPL!\n", + ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_ATTR_NAME); + H5Aclose(attr_id); + PART_ERROR(H5Aopen_by_idx_invalid_aapl); + } + + PASSED(); + } + PART_END(H5Aopen_by_idx_invalid_aapl); + + PART_BEGIN(H5Aopen_by_idx_invalid_lapl) + { + TESTING_2("H5Aopen_by_idx with an invalid LAPL"); + + H5E_BEGIN_TRY + { + attr_id = H5Aopen_by_idx(container_group, ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_GROUP_NAME, + H5_INDEX_NAME, H5_ITER_INC, 0, H5P_DEFAULT, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" opened attribute '%s' using H5Aopen_by_idx with an invalid LAPL!\n", + ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_ATTR_NAME); + H5Aclose(attr_id); + PART_ERROR(H5Aopen_by_idx_invalid_lapl); + } + + PASSED(); + } + PART_END(H5Aopen_by_idx_invalid_lapl); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Tclose(attr_type) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(space_id); + H5Tclose(attr_type); + H5Aclose(attr_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a simple write to an attribute + * can be made. + */ +static int +test_write_attribute(void) +{ + hsize_t dims[ATTRIBUTE_WRITE_TEST_SPACE_RANK]; + size_t i, data_size; + htri_t attr_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + void *data = NULL; + + TESTING("H5Awrite"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, attribute, or file flush aren't supported with " + "this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file\n"); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_WRITE_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", ATTRIBUTE_WRITE_TEST_GROUP_NAME); + goto error; + } + + if ((space_id = generate_random_dataspace(ATTRIBUTE_WRITE_TEST_SPACE_RANK, NULL, dims, TRUE)) < 0) + TEST_ERROR; + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_WRITE_TEST_ATTR_NAME, ATTRIBUTE_WRITE_TEST_ATTR_DTYPE, + space_id, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute\n"); + goto error; + } + + /* Verify the attribute has been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_WRITE_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not exist\n"); + goto error; + } + + for (i = 0, data_size = 1; i < ATTRIBUTE_WRITE_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= ATTRIBUTE_WRITE_TEST_ATTR_DTYPE_SIZE; + + if (NULL == (data = HDmalloc(data_size))) + TEST_ERROR; + + for (i = 0; i < data_size / ATTRIBUTE_WRITE_TEST_ATTR_DTYPE_SIZE; i++) + ((int *)data)[i] = (int)i; + + if (H5Awrite(attr_id, ATTRIBUTE_WRITE_TEST_ATTR_DTYPE, data) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to attribute\n"); + goto error; + } + + /* Make sure that the attribute can be flushed to the file */ + if (H5Fflush(file_id, H5F_SCOPE_GLOBAL) < 0) { + H5_FAILED(); + HDprintf(" couldn't flush the attribute\n"); + goto error; + } + + if (data) { + HDfree(data); + data = NULL; + } + + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (data) + HDfree(data); + H5Sclose(space_id); + H5Aclose(attr_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that writing an attribute fails when + * H5Awrite is passed invalid parameters. + */ +static int +test_write_attribute_invalid_params(void) +{ + hsize_t dims[ATTRIBUTE_WRITE_INVALID_PARAMS_TEST_SPACE_RANK]; + size_t i, data_size; + htri_t attr_exists; + herr_t err_ret = -1; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + void *data = NULL; + + TESTING_MULTIPART("H5Awrite with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or attribute aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", ATTRIBUTE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_WRITE_INVALID_PARAMS_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", + ATTRIBUTE_WRITE_INVALID_PARAMS_TEST_GROUP_NAME); + goto error; + } + + if ((space_id = + generate_random_dataspace(ATTRIBUTE_WRITE_INVALID_PARAMS_TEST_SPACE_RANK, NULL, dims, TRUE)) < 0) + TEST_ERROR; + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_WRITE_INVALID_PARAMS_TEST_ATTR_NAME, + ATTRIBUTE_WRITE_INVALID_PARAMS_TEST_ATTR_DTYPE, space_id, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute\n"); + goto error; + } + + /* Verify the attribute has been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_WRITE_INVALID_PARAMS_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not exist\n"); + goto error; + } + + for (i = 0, data_size = 1; i < ATTRIBUTE_WRITE_INVALID_PARAMS_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= ATTRIBUTE_WRITE_INVALID_PARAMS_TEST_ATTR_DTYPE_SIZE; + + if (NULL == (data = HDmalloc(data_size))) + TEST_ERROR; + + for (i = 0; i < data_size / ATTRIBUTE_WRITE_INVALID_PARAMS_TEST_ATTR_DTYPE_SIZE; i++) + ((int *)data)[i] = (int)i; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Awrite_invalid_attr_id) + { + TESTING_2("H5Awrite with an invalid attr_id"); + + H5E_BEGIN_TRY + { + err_ret = H5Awrite(H5I_INVALID_HID, ATTRIBUTE_WRITE_INVALID_PARAMS_TEST_ATTR_DTYPE, data); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" wrote to attribute using an invalid attr_id!\n"); + PART_ERROR(H5Awrite_invalid_attr_id); + } + + PASSED(); + } + PART_END(H5Awrite_invalid_attr_id); + + PART_BEGIN(H5Awrite_invalid_datatype) + { + TESTING_2("H5Awrite with an invalid datatype"); + + H5E_BEGIN_TRY + { + err_ret = H5Awrite(attr_id, H5I_INVALID_HID, data); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" wrote to attribute using an invalid datatype!\n"); + PART_ERROR(H5Awrite_invalid_datatype); + } + + PASSED(); + } + PART_END(H5Awrite_invalid_datatype); + + PART_BEGIN(H5Awrite_invalid_data_buf) + { + TESTING_2("H5Awrite with an invalid data buffer"); + + H5E_BEGIN_TRY + { + err_ret = H5Awrite(attr_id, ATTRIBUTE_WRITE_INVALID_PARAMS_TEST_ATTR_DTYPE, NULL); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" wrote to attribute using an invalid data buffer!\n"); + PART_ERROR(H5Awrite_invalid_data_buf); + } + + PASSED(); + } + PART_END(H5Awrite_invalid_data_buf); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (data) { + HDfree(data); + data = NULL; + } + + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (data) + HDfree(data); + H5Sclose(space_id); + H5Aclose(attr_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that simple data can be read back + * and verified after it has been written to an + * attribute. + */ +static int +test_read_attribute(void) +{ + hsize_t dims[ATTRIBUTE_READ_TEST_SPACE_RANK]; + size_t i, data_size; + htri_t attr_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + void *data = NULL; + void *read_buf = NULL; + + TESTING("H5Aread"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or attribute aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", ATTRIBUTE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_READ_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", ATTRIBUTE_READ_TEST_GROUP_NAME); + goto error; + } + + if ((space_id = generate_random_dataspace(ATTRIBUTE_READ_TEST_SPACE_RANK, NULL, dims, TRUE)) < 0) + TEST_ERROR; + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_READ_TEST_ATTR_NAME, ATTRIBUTE_READ_TEST_ATTR_DTYPE, + space_id, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute\n"); + goto error; + } + + /* Verify the attribute has been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_READ_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not exist\n"); + goto error; + } + + for (i = 0, data_size = 1; i < ATTRIBUTE_READ_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= ATTRIBUTE_READ_TEST_ATTR_DTYPE_SIZE; + + if (NULL == (data = HDmalloc(data_size))) + TEST_ERROR; + if (NULL == (read_buf = HDcalloc(1, data_size))) + TEST_ERROR; + + for (i = 0; i < data_size / ATTRIBUTE_READ_TEST_ATTR_DTYPE_SIZE; i++) + ((int *)data)[i] = (int)i; + + if (H5Awrite(attr_id, ATTRIBUTE_READ_TEST_ATTR_DTYPE, data) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to attribute\n"); + goto error; + } + + if (data) { + HDfree(data); + data = NULL; + } + + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + + if ((attr_id = H5Aopen(group_id, ATTRIBUTE_READ_TEST_ATTR_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open attribute\n"); + goto error; + } + + if (H5Aread(attr_id, ATTRIBUTE_READ_TEST_ATTR_DTYPE, read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from attribute\n"); + goto error; + } + + for (i = 0; i < data_size / ATTRIBUTE_READ_TEST_ATTR_DTYPE_SIZE; i++) { + if (((int *)read_buf)[i] != (int)i) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + goto error; + } + } + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (data) + HDfree(data); + if (read_buf) + HDfree(read_buf); + H5Sclose(space_id); + H5Aclose(attr_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that reading an attribute fails when + * H5Aread is passed invalid parameters. + */ +static int +test_read_attribute_invalid_params(void) +{ + hsize_t dims[ATTRIBUTE_READ_INVALID_PARAMS_TEST_SPACE_RANK]; + size_t i, data_size; + htri_t attr_exists; + herr_t err_ret = -1; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + void *data = NULL; + void *read_buf = NULL; + + TESTING_MULTIPART("H5Aread with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or attribute aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", ATTRIBUTE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_READ_INVALID_PARAMS_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", ATTRIBUTE_READ_INVALID_PARAMS_TEST_GROUP_NAME); + goto error; + } + + if ((space_id = + generate_random_dataspace(ATTRIBUTE_READ_INVALID_PARAMS_TEST_SPACE_RANK, NULL, dims, TRUE)) < 0) + TEST_ERROR; + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_READ_INVALID_PARAMS_TEST_ATTR_NAME, + ATTRIBUTE_READ_INVALID_PARAMS_TEST_ATTR_DTYPE, space_id, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute\n"); + goto error; + } + + /* Verify the attribute has been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_READ_INVALID_PARAMS_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not exist\n"); + goto error; + } + + for (i = 0, data_size = 1; i < ATTRIBUTE_READ_INVALID_PARAMS_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= ATTRIBUTE_READ_INVALID_PARAMS_TEST_ATTR_DTYPE_SIZE; + + if (NULL == (data = HDmalloc(data_size))) + TEST_ERROR; + if (NULL == (read_buf = HDcalloc(1, data_size))) + TEST_ERROR; + + for (i = 0; i < data_size / ATTRIBUTE_READ_INVALID_PARAMS_TEST_ATTR_DTYPE_SIZE; i++) + ((int *)data)[i] = (int)i; + + if (H5Awrite(attr_id, ATTRIBUTE_READ_INVALID_PARAMS_TEST_ATTR_DTYPE, data) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to attribute\n"); + goto error; + } + + if (data) { + HDfree(data); + data = NULL; + } + + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + + if ((attr_id = H5Aopen(group_id, ATTRIBUTE_READ_INVALID_PARAMS_TEST_ATTR_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open attribute\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Aread_invalid_attr_id) + { + TESTING_2("H5Aread with an invalid attr_id"); + + H5E_BEGIN_TRY + { + err_ret = H5Aread(H5I_INVALID_HID, ATTRIBUTE_READ_INVALID_PARAMS_TEST_ATTR_DTYPE, read_buf); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" read attribute with an invalid attr_id!\n"); + PART_ERROR(H5Aread_invalid_attr_id); + } + + PASSED(); + } + PART_END(H5Aread_invalid_attr_id); + + PART_BEGIN(H5Aread_invalid_datatype) + { + TESTING_2("H5Aread with an invalid datatype"); + + H5E_BEGIN_TRY + { + err_ret = H5Aread(attr_id, H5I_INVALID_HID, read_buf); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" read attribute with an invalid datatype!\n"); + PART_ERROR(H5Aread_invalid_datatype); + } + + PASSED(); + } + PART_END(H5Aread_invalid_datatype); + + PART_BEGIN(H5Aread_invalid_read_buf) + { + TESTING_2("H5Aread with an invalid read buffer"); + + H5E_BEGIN_TRY + { + err_ret = H5Aread(attr_id, ATTRIBUTE_READ_INVALID_PARAMS_TEST_ATTR_DTYPE, NULL); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" read attribute with an invalid read buffer!\n"); + PART_ERROR(H5Aread_invalid_read_buf); + } + + PASSED(); + } + PART_END(H5Aread_invalid_read_buf); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (data) + HDfree(data); + if (read_buf) + HDfree(read_buf); + H5Sclose(space_id); + H5Aclose(attr_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * Test reading an empty attribute is ok + */ +static int +test_read_empty_attribute(void) +{ + hsize_t dims[ATTRIBUTE_READ_EMPTY_SPACE_RANK]; + size_t i, data_size; + htri_t attr_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + void *read_buf = NULL; + + TESTING("reading an empty attribute"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or attribute aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", ATTRIBUTE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_READ_EMPTY_ATTR_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", ATTRIBUTE_READ_EMPTY_ATTR_GROUP_NAME); + goto error; + } + + if ((space_id = generate_random_dataspace(ATTRIBUTE_READ_EMPTY_SPACE_RANK, NULL, dims, TRUE)) < 0) + TEST_ERROR; + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_READ_EMPTY_ATTR_NAME, ATTRIBUTE_READ_EMPTY_DTYPE, space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute\n"); + goto error; + } + + /* Verify the attribute has been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_READ_EMPTY_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not exist\n"); + goto error; + } + + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + + if ((attr_id = H5Aopen(group_id, ATTRIBUTE_READ_EMPTY_ATTR_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open attribute\n"); + goto error; + } + + for (i = 0, data_size = 1; i < ATTRIBUTE_READ_EMPTY_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= ATTRIBUTE_READ_EMPTY_DTYPE_SIZE; + + if (NULL == (read_buf = HDcalloc(1, data_size))) + TEST_ERROR; + + if (H5Aread(attr_id, ATTRIBUTE_READ_EMPTY_DTYPE, read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from attribute\n"); + goto error; + } + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (read_buf) + HDfree(read_buf); + H5Sclose(space_id); + H5Aclose(attr_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} +/* + * A test to check that H5Aclose fails when it is passed + * an invalid attribute ID. + */ +static int +test_close_attribute_invalid_id(void) +{ + herr_t err_ret = -1; + hid_t file_id = H5I_INVALID_HID; + + TESTING("H5Aclose with an invalid attribute ID"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file or attribute aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + H5E_BEGIN_TRY + { + err_ret = H5Aclose(H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Aclose succeeded with an invalid attribute ID!\n"); + goto error; + } + + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that valid copies of an attribute's + * dataspace and datatype can be retrieved with + * H5Aget_space and H5Aget_type, respectively. + */ +static int +test_get_attribute_space_and_type(void) +{ + hsize_t attr_dims[ATTRIBUTE_GET_SPACE_TYPE_TEST_SPACE_RANK]; + size_t i; + htri_t attr_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t attr_dtype = H5I_INVALID_HID; + hid_t attr_space_id = H5I_INVALID_HID; + hid_t tmp_type_id = H5I_INVALID_HID; + hid_t tmp_space_id = H5I_INVALID_HID; + + TESTING_MULTIPART("retrieval of an attribute's dataspace and datatype"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_MORE)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or attribute aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", ATTRIBUTE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_GET_SPACE_TYPE_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", ATTRIBUTE_GET_SPACE_TYPE_TEST_GROUP_NAME); + goto error; + } + + if ((attr_space_id = + generate_random_dataspace(ATTRIBUTE_GET_SPACE_TYPE_TEST_SPACE_RANK, NULL, attr_dims, TRUE)) < 0) + TEST_ERROR; + + if ((attr_dtype = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_GET_SPACE_TYPE_TEST_ATTR_NAME, attr_dtype, attr_space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute\n"); + goto error; + } + + /* Verify the attribute has been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_GET_SPACE_TYPE_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not exist\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + /* Retrieve the attribute's datatype and dataspace and verify them */ + PART_BEGIN(H5Aget_type) + { + TESTING_2("H5Aget_type"); + + if ((tmp_type_id = H5Aget_type(attr_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve attribute's datatype\n"); + PART_ERROR(H5Aget_type); + } + + { + htri_t types_equal = H5Tequal(tmp_type_id, attr_dtype); + + if (types_equal < 0) { + H5_FAILED(); + HDprintf(" datatype was invalid\n"); + PART_ERROR(H5Aget_type); + } + + if (!types_equal) { + H5_FAILED(); + HDprintf(" attribute's datatype did not match\n"); + PART_ERROR(H5Aget_type); + } + } + + PASSED(); + } + PART_END(H5Aget_type); + + PART_BEGIN(H5Aget_space) + { + TESTING_2("H5Aget_space"); + + if ((tmp_space_id = H5Aget_space(attr_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve attribute's dataspace\n"); + PART_ERROR(H5Aget_space); + } + + { + hsize_t space_dims[ATTRIBUTE_GET_SPACE_TYPE_TEST_SPACE_RANK]; + + if (H5Sget_simple_extent_dims(tmp_space_id, space_dims, NULL) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve dimensions of dataspace\n"); + PART_ERROR(H5Aget_space); + } + + for (i = 0; i < ATTRIBUTE_GET_SPACE_TYPE_TEST_SPACE_RANK; i++) + if (space_dims[i] != attr_dims[i]) { + H5_FAILED(); + HDprintf(" attribute's dataspace dims didn't match\n"); + PART_ERROR(H5Aget_space); + } + } + + PASSED(); + } + PART_END(H5Aget_space); + + /* Now close the attribute and verify that this still works after opening an + * attribute instead of creating it + */ + if (attr_id >= 0) { + H5E_BEGIN_TRY + { + H5Aclose(attr_id); + } + H5E_END_TRY; + attr_id = H5I_INVALID_HID; + } + if (tmp_type_id >= 0) { + H5E_BEGIN_TRY + { + H5Tclose(tmp_type_id); + } + H5E_END_TRY; + tmp_type_id = H5I_INVALID_HID; + } + if (tmp_space_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(tmp_space_id); + } + H5E_END_TRY; + tmp_space_id = H5I_INVALID_HID; + } + + PART_BEGIN(H5Aget_type_reopened) + { + TESTING_2("H5Aget_type after re-opening an attribute"); + + if ((attr_id = H5Aopen(group_id, ATTRIBUTE_GET_SPACE_TYPE_TEST_ATTR_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open attribute '%s'\n", ATTRIBUTE_GET_SPACE_TYPE_TEST_ATTR_NAME); + PART_ERROR(H5Aget_type_reopened); + } + + if ((tmp_type_id = H5Aget_type(attr_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve attribute's datatype\n"); + PART_ERROR(H5Aget_type_reopened); + } + + { + htri_t types_equal = H5Tequal(tmp_type_id, attr_dtype); + + if (types_equal < 0) { + H5_FAILED(); + HDprintf(" datatype was invalid\n"); + PART_ERROR(H5Aget_type_reopened); + } + + if (!types_equal) { + H5_FAILED(); + HDprintf(" attribute's datatype did not match\n"); + PART_ERROR(H5Aget_type_reopened); + } + } + + if (attr_id >= 0) { + H5E_BEGIN_TRY + { + H5Aclose(attr_id); + } + H5E_END_TRY; + attr_id = H5I_INVALID_HID; + } + + PASSED(); + } + PART_END(H5Aget_type_reopened); + + PART_BEGIN(H5Aget_space_reopened) + { + TESTING_2("H5Aget_space after re-opening an attribute"); + + if ((attr_id = H5Aopen(group_id, ATTRIBUTE_GET_SPACE_TYPE_TEST_ATTR_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open attribute '%s'\n", ATTRIBUTE_GET_SPACE_TYPE_TEST_ATTR_NAME); + PART_ERROR(H5Aget_space_reopened); + } + + if ((tmp_space_id = H5Aget_space(attr_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve attribute's dataspace\n"); + PART_ERROR(H5Aget_space_reopened); + } + + { + hsize_t space_dims[ATTRIBUTE_GET_SPACE_TYPE_TEST_SPACE_RANK]; + + if (H5Sget_simple_extent_dims(tmp_space_id, space_dims, NULL) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve dimensions of dataspace\n"); + PART_ERROR(H5Aget_space_reopened); + } + + for (i = 0; i < ATTRIBUTE_GET_SPACE_TYPE_TEST_SPACE_RANK; i++) { + if (space_dims[i] != attr_dims[i]) { + H5_FAILED(); + HDprintf(" dataspace dims didn't match!\n"); + PART_ERROR(H5Aget_space_reopened); + } + } + } + + if (attr_id >= 0) { + H5E_BEGIN_TRY + { + H5Aclose(attr_id); + } + H5E_END_TRY; + attr_id = H5I_INVALID_HID; + } + + PASSED(); + } + PART_END(H5Aget_space_reopened); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(tmp_space_id) < 0) + TEST_ERROR; + if (H5Sclose(attr_space_id) < 0) + TEST_ERROR; + if (H5Tclose(tmp_type_id) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(tmp_space_id); + H5Sclose(attr_space_id); + H5Tclose(tmp_type_id); + H5Tclose(attr_dtype); + H5Aclose(attr_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that an attribute's dataspace and datatype + * can't be retrieved when H5Aget_space and H5Aget_type are passed + * invalid parameters, respectively. + */ +static int +test_get_attribute_space_and_type_invalid_params(void) +{ + htri_t attr_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t attr_dtype = H5I_INVALID_HID; + hid_t attr_space_id = H5I_INVALID_HID; + hid_t tmp_type_id = H5I_INVALID_HID; + hid_t tmp_space_id = H5I_INVALID_HID; + + TESTING_MULTIPART("H5Aget_type/H5Aget_space with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_MORE)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or attribute aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", ATTRIBUTE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_GET_SPACE_TYPE_INVALID_PARAMS_TEST_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", + ATTRIBUTE_GET_SPACE_TYPE_INVALID_PARAMS_TEST_GROUP_NAME); + goto error; + } + + if ((attr_space_id = generate_random_dataspace(ATTRIBUTE_GET_SPACE_TYPE_INVALID_PARAMS_TEST_SPACE_RANK, + NULL, NULL, TRUE)) < 0) + TEST_ERROR; + + if ((attr_dtype = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_GET_SPACE_TYPE_INVALID_PARAMS_TEST_ATTR_NAME, attr_dtype, + attr_space_id, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute\n"); + goto error; + } + + /* Verify the attribute has been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_GET_SPACE_TYPE_INVALID_PARAMS_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not exist\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + /* Retrieve the attribute's datatype and dataspace and verify them */ + PART_BEGIN(H5Aget_type_invalid_attr_id) + { + TESTING_2("H5Aget_type with an invalid attr_id"); + + H5E_BEGIN_TRY + { + tmp_type_id = H5Aget_type(H5I_INVALID_HID); + } + H5E_END_TRY; + + if (tmp_type_id >= 0) { + H5_FAILED(); + HDprintf(" retrieved copy of attribute's datatype using an invalid attr_id!\n"); + PART_ERROR(H5Aget_type_invalid_attr_id); + } + + PASSED(); + } + PART_END(H5Aget_type_invalid_attr_id); + + PART_BEGIN(H5Aget_space_invalid_attr_id) + { + TESTING_2("H5Aget_space with an invalid attr_id"); + + H5E_BEGIN_TRY + { + tmp_space_id = H5Aget_space(H5I_INVALID_HID); + } + H5E_END_TRY; + + if (tmp_space_id >= 0) { + H5_FAILED(); + HDprintf(" retrieved copy of attribute's dataspace using an invalid attr_id!\n"); + PART_ERROR(H5Aget_space_invalid_attr_id); + } + + PASSED(); + } + PART_END(H5Aget_space_invalid_attr_id); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(attr_space_id) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype) < 0) + TEST_ERROR; + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(tmp_space_id); + H5Sclose(attr_space_id); + H5Tclose(tmp_type_id); + H5Tclose(attr_dtype); + H5Aclose(attr_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that an ACPL used for attribute creation + * can be persisted and that a valid copy of that ACPL can + * be retrieved later with a call to H5Aget_create_plist. + */ +static int +test_attribute_property_lists(void) +{ + H5T_cset_t encoding = H5T_CSET_UTF8; + htri_t attr_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t attr_id1 = H5I_INVALID_HID, attr_id2 = H5I_INVALID_HID; + hid_t attr_dtype1 = H5I_INVALID_HID, attr_dtype2 = H5I_INVALID_HID; + hid_t acpl_id1 = H5I_INVALID_HID, acpl_id2 = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + + TESTING_MULTIPART("attribute property list operations"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GET_PLIST)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, attribute, or getting property list aren't " + "supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file\n"); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_PROPERTY_LIST_TEST_SUBGROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group\n"); + goto error; + } + + if ((space_id = generate_random_dataspace(ATTRIBUTE_PROPERTY_LIST_TEST_SPACE_RANK, NULL, NULL, TRUE)) < 0) + TEST_ERROR; + + if ((attr_dtype1 = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + if ((attr_dtype2 = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + if ((acpl_id1 = H5Pcreate(H5P_ATTRIBUTE_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create ACPL\n"); + goto error; + } + + if (H5Pset_char_encoding(acpl_id1, encoding) < 0) { + H5_FAILED(); + HDprintf(" couldn't set ACPL property value\n"); + goto error; + } + + if ((attr_id1 = H5Acreate2(group_id, ATTRIBUTE_PROPERTY_LIST_TEST_ATTRIBUTE_NAME1, attr_dtype1, space_id, + acpl_id1, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute\n"); + goto error; + } + + if ((attr_id2 = H5Acreate2(group_id, ATTRIBUTE_PROPERTY_LIST_TEST_ATTRIBUTE_NAME2, attr_dtype2, space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute\n"); + goto error; + } + + if (H5Pclose(acpl_id1) < 0) + TEST_ERROR; + + /* Verify the attributes have been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_PROPERTY_LIST_TEST_ATTRIBUTE_NAME1)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not exist\n"); + goto error; + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_PROPERTY_LIST_TEST_ATTRIBUTE_NAME2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not exist\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Aget_create_plist) + { + TESTING_2("H5Aget_create_plist"); + + /* Try to retrieve copies of the two property lists, one which has the property set and one which + * does not */ + if ((acpl_id1 = H5Aget_create_plist(attr_id1)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get property list\n"); + PART_ERROR(H5Aget_create_plist); + } + + if ((acpl_id2 = H5Aget_create_plist(attr_id2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get property list\n"); + PART_ERROR(H5Aget_create_plist); + } + + /* Ensure that property list 1 has the property list set and property list 2 does not */ + encoding = H5T_CSET_ERROR; + + if (H5Pget_char_encoding(acpl_id1, &encoding) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve ACPL property value\n"); + PART_ERROR(H5Aget_create_plist); + } + + if (H5T_CSET_UTF8 != encoding) { + H5_FAILED(); + HDprintf(" ACPL property value was incorrect\n"); + PART_ERROR(H5Aget_create_plist); + } + + encoding = H5T_CSET_ERROR; + + if (H5Pget_char_encoding(acpl_id2, &encoding) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve ACPL property value\n"); + PART_ERROR(H5Aget_create_plist); + } + + if (H5T_CSET_UTF8 == encoding) { + H5_FAILED(); + HDprintf(" ACPL property value was set!\n"); + PART_ERROR(H5Aget_create_plist); + } + + PASSED(); + } + PART_END(H5Aget_create_plist); + + /* Now close the property lists and attribute and see if we can still retrieve copies of + * the property lists upon opening (instead of creating) an attribute + */ + if (acpl_id1 >= 0) { + H5E_BEGIN_TRY + { + H5Pclose(acpl_id1); + } + H5E_END_TRY; + acpl_id1 = H5I_INVALID_HID; + } + if (acpl_id2 >= 0) { + H5E_BEGIN_TRY + { + H5Pclose(acpl_id2); + } + H5E_END_TRY; + acpl_id2 = H5I_INVALID_HID; + } + if (attr_id1 >= 0) { + H5E_BEGIN_TRY + { + H5Aclose(attr_id1); + } + H5E_END_TRY; + attr_id1 = H5I_INVALID_HID; + } + if (attr_id2 >= 0) { + H5E_BEGIN_TRY + { + H5Aclose(attr_id2); + } + H5E_END_TRY; + attr_id2 = H5I_INVALID_HID; + } + + PART_BEGIN(H5Aget_create_plist_reopened) + { + TESTING_2("H5Aget_create_plist after re-opening an attribute"); + + if ((attr_id1 = H5Aopen(group_id, ATTRIBUTE_PROPERTY_LIST_TEST_ATTRIBUTE_NAME1, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't open attribute '%s'\n", ATTRIBUTE_PROPERTY_LIST_TEST_ATTRIBUTE_NAME1); + PART_ERROR(H5Aget_create_plist_reopened); + } + + if ((attr_id2 = H5Aopen(group_id, ATTRIBUTE_PROPERTY_LIST_TEST_ATTRIBUTE_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't open attribute '%s'\n", ATTRIBUTE_PROPERTY_LIST_TEST_ATTRIBUTE_NAME2); + PART_ERROR(H5Aget_create_plist_reopened); + } + + if ((acpl_id1 = H5Aget_create_plist(attr_id1)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get property list\n"); + PART_ERROR(H5Aget_create_plist_reopened); + } + + if ((acpl_id2 = H5Aget_create_plist(attr_id2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get property list\n"); + PART_ERROR(H5Aget_create_plist_reopened); + } + + /* XXX: Check the value to be tested as above */ + PASSED(); + } + PART_END(H5Aget_create_plist_reopened); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Pclose(acpl_id1) < 0) + TEST_ERROR; + if (H5Pclose(acpl_id2) < 0) + TEST_ERROR; + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype1) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype2) < 0) + TEST_ERROR; + if (H5Aclose(attr_id1) < 0) + TEST_ERROR; + if (H5Aclose(attr_id2) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(acpl_id1); + H5Pclose(acpl_id2); + H5Sclose(space_id); + H5Tclose(attr_dtype1); + H5Tclose(attr_dtype2); + H5Aclose(attr_id1); + H5Aclose(attr_id2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that an attribute's name can be + * correctly retrieved with H5Aget_name and + * H5Aget_name_by_idx. + */ +static int +test_get_attribute_name(void) +{ + ssize_t name_buf_size; + htri_t attr_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t attr_dtype = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + char *name_buf = NULL; + + TESTING_MULTIPART("retrieval of an attribute's name"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, attribute, or creation order aren't supported " + "with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", ATTRIBUTE_TEST_GROUP_NAME); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create GCPL for attribute creation order tracking\n"); + goto error; + } + + if (H5Pset_attr_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED) < 0) { + H5_FAILED(); + HDprintf(" couldn't set attribute creation order tracking\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_GET_NAME_TEST_GROUP_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", ATTRIBUTE_GET_NAME_TEST_GROUP_NAME); + goto error; + } + + if ((space_id = generate_random_dataspace(ATTRIBUTE_GET_NAME_TEST_SPACE_RANK, NULL, NULL, TRUE)) < 0) + TEST_ERROR; + + if ((attr_dtype = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + /* Create several attributes */ + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME, attr_dtype, space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s'\n", ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME); + goto error; + } + + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME2, attr_dtype, space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s'\n", ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME2); + goto error; + } + + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME3, attr_dtype, space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s'\n", ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME3); + goto error; + } + + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + + /* Verify the attributes have been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' did not exist\n", ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME); + goto error; + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME2); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' did not exist\n", ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME2); + goto error; + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME3)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME3); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' did not exist\n", ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME3); + goto error; + } + + /* Allocate the name buffer */ + name_buf_size = strlen(ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME) + 2; + if (NULL == (name_buf = (char *)HDmalloc((size_t)name_buf_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for storing attribute's name\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Aget_name) + { + TESTING_2("H5Aget_name"); + + if ((attr_id = H5Aopen(group_id, ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open attribute '%s'\n", ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME); + PART_ERROR(H5Aget_name); + } + + *name_buf = '\0'; + if (H5Aget_name(attr_id, (size_t)name_buf_size, name_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve attribute name\n"); + PART_ERROR(H5Aget_name); + } + + if (HDstrncmp(name_buf, ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME, + strlen(ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME) + 1)) { + H5_FAILED(); + HDprintf(" retrieved attribute name '%s' didn't match '%s'\n", name_buf, + ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME); + PART_ERROR(H5Aget_name); + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close attribute '%s'\n", ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME); + PART_ERROR(H5Aget_name); + } + + PASSED(); + } + PART_END(H5Aget_name); + + H5E_BEGIN_TRY + { + H5Aclose(attr_id); + attr_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Aget_name_by_idx_crt_order_increasing) + { + TESTING_2("H5Aget_name_by_idx by creation order in increasing order"); + + *name_buf = '\0'; + if (H5Aget_name_by_idx(container_group, ATTRIBUTE_GET_NAME_TEST_GROUP_NAME, H5_INDEX_CRT_ORDER, + H5_ITER_INC, 0, name_buf, (size_t)name_buf_size, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve name of attribute at index %d using H5Aget_name_by_index by " + "creation order in increasing order\n", + 0); + PART_ERROR(H5Aget_name_by_idx_crt_order_increasing); + } + + if (HDstrncmp(name_buf, ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME, + strlen(ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME) + 1)) { + H5_FAILED(); + HDprintf(" retrieved attribute name '%s' didn't match '%s'\n", name_buf, + ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME); + PART_ERROR(H5Aget_name_by_idx_crt_order_increasing); + } + + *name_buf = '\0'; + if (H5Aget_name_by_idx(container_group, ATTRIBUTE_GET_NAME_TEST_GROUP_NAME, H5_INDEX_CRT_ORDER, + H5_ITER_INC, 1, name_buf, (size_t)name_buf_size, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve name of attribute at index %d using H5Aget_name_by_index by " + "creation order in increasing order\n", + 1); + PART_ERROR(H5Aget_name_by_idx_crt_order_increasing); + } + + if (HDstrncmp(name_buf, ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME2, + strlen(ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME2) + 1)) { + H5_FAILED(); + HDprintf(" retrieved attribute name '%s' didn't match '%s'\n", name_buf, + ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME2); + PART_ERROR(H5Aget_name_by_idx_crt_order_increasing); + } + + *name_buf = '\0'; + if (H5Aget_name_by_idx(container_group, ATTRIBUTE_GET_NAME_TEST_GROUP_NAME, H5_INDEX_CRT_ORDER, + H5_ITER_INC, 2, name_buf, (size_t)name_buf_size, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve name of attribute at index %d using H5Aget_name_by_index by " + "creation order in increasing order\n", + 2); + PART_ERROR(H5Aget_name_by_idx_crt_order_increasing); + } + + if (HDstrncmp(name_buf, ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME3, + strlen(ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME3) + 1)) { + H5_FAILED(); + HDprintf(" retrieved attribute name '%s' didn't match '%s'\n", name_buf, + ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME3); + PART_ERROR(H5Aget_name_by_idx_crt_order_increasing); + } + + PASSED(); + } + PART_END(H5Aget_name_by_idx_crt_order_increasing); + + PART_BEGIN(H5Aget_name_by_idx_crt_order_decreasing) + { + TESTING_2("H5Aget_name_by_idx by creation order in decreasing order"); + + *name_buf = '\0'; + if (H5Aget_name_by_idx(container_group, ATTRIBUTE_GET_NAME_TEST_GROUP_NAME, H5_INDEX_CRT_ORDER, + H5_ITER_DEC, 2, name_buf, (size_t)name_buf_size, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve name of attribute at index %d using H5Aget_name_by_index by " + "creation order in decreasing order\n", + 2); + PART_ERROR(H5Aget_name_by_idx_crt_order_decreasing); + } + + if (HDstrncmp(name_buf, ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME, + strlen(ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME) + 1)) { + H5_FAILED(); + HDprintf(" retrieved attribute name '%s' didn't match '%s'\n", name_buf, + ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME); + PART_ERROR(H5Aget_name_by_idx_crt_order_decreasing); + } + + *name_buf = '\0'; + if (H5Aget_name_by_idx(container_group, ATTRIBUTE_GET_NAME_TEST_GROUP_NAME, H5_INDEX_CRT_ORDER, + H5_ITER_DEC, 1, name_buf, (size_t)name_buf_size, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve name of attribute at index %d using H5Aget_name_by_index by " + "creation order in decreasing order\n", + 1); + PART_ERROR(H5Aget_name_by_idx_crt_order_decreasing); + } + + if (HDstrncmp(name_buf, ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME2, + strlen(ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME2) + 1)) { + H5_FAILED(); + HDprintf(" retrieved attribute name '%s' didn't match '%s'\n", name_buf, + ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME2); + PART_ERROR(H5Aget_name_by_idx_crt_order_decreasing); + } + + *name_buf = '\0'; + if (H5Aget_name_by_idx(container_group, ATTRIBUTE_GET_NAME_TEST_GROUP_NAME, H5_INDEX_CRT_ORDER, + H5_ITER_DEC, 0, name_buf, (size_t)name_buf_size, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve name of attribute at index %d using H5Aget_name_by_index by " + "creation order in decreasing order\n", + 0); + PART_ERROR(H5Aget_name_by_idx_crt_order_decreasing); + } + + if (HDstrncmp(name_buf, ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME3, + strlen(ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME3) + 1)) { + H5_FAILED(); + HDprintf(" retrieved attribute name '%s' didn't match '%s'\n", name_buf, + ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME3); + PART_ERROR(H5Aget_name_by_idx_crt_order_decreasing); + } + + PASSED(); + } + PART_END(H5Aget_name_by_idx_crt_order_decreasing); + + PART_BEGIN(H5Aget_name_by_idx_name_order_increasing) + { + TESTING_2("H5Aget_name_by_idx by alphabetical order in increasing order"); + + *name_buf = '\0'; + if (H5Aget_name_by_idx(container_group, ATTRIBUTE_GET_NAME_TEST_GROUP_NAME, H5_INDEX_NAME, + H5_ITER_INC, 0, name_buf, (size_t)name_buf_size, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve name of attribute at index %d using H5Aget_name_by_index by " + "alphabetical order in increasing order\n", + 0); + PART_ERROR(H5Aget_name_by_idx_name_order_increasing); + } + + if (HDstrncmp(name_buf, ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME, + strlen(ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME) + 1)) { + H5_FAILED(); + HDprintf(" retrieved attribute name '%s' didn't match '%s'\n", name_buf, + ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME); + PART_ERROR(H5Aget_name_by_idx_name_order_increasing); + } + + *name_buf = '\0'; + if (H5Aget_name_by_idx(container_group, ATTRIBUTE_GET_NAME_TEST_GROUP_NAME, H5_INDEX_NAME, + H5_ITER_INC, 1, name_buf, (size_t)name_buf_size, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve name of attribute at index %d using H5Aget_name_by_index by " + "alphabetical order in increasing order\n", + 1); + PART_ERROR(H5Aget_name_by_idx_name_order_increasing); + } + + if (HDstrncmp(name_buf, ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME2, + strlen(ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME2) + 1)) { + H5_FAILED(); + HDprintf(" retrieved attribute name '%s' didn't match '%s'\n", name_buf, + ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME2); + PART_ERROR(H5Aget_name_by_idx_name_order_increasing); + } + + *name_buf = '\0'; + if (H5Aget_name_by_idx(container_group, ATTRIBUTE_GET_NAME_TEST_GROUP_NAME, H5_INDEX_NAME, + H5_ITER_INC, 2, name_buf, (size_t)name_buf_size, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve name of attribute at index %d using H5Aget_name_by_index by " + "alphabetical order in increasing order\n", + 2); + PART_ERROR(H5Aget_name_by_idx_name_order_increasing); + } + + if (HDstrncmp(name_buf, ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME3, + strlen(ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME3) + 1)) { + H5_FAILED(); + HDprintf(" retrieved attribute name '%s' didn't match '%s'\n", name_buf, + ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME3); + PART_ERROR(H5Aget_name_by_idx_name_order_increasing); + } + + PASSED(); + } + PART_END(H5Aget_name_by_idx_name_order_increasing); + + PART_BEGIN(H5Aget_name_by_idx_name_order_decreasing) + { + TESTING_2("H5Aget_name_by_idx by alphabetical order in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + *name_buf = '\0'; + if (H5Aget_name_by_idx(container_group, ATTRIBUTE_GET_NAME_TEST_GROUP_NAME, H5_INDEX_NAME, + H5_ITER_DEC, 2, name_buf, (size_t)name_buf_size, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve name of attribute at index %lld using H5Aget_name_by_index " + "by alphabetical order in decreasing order\n", + 2); + PART_ERROR(H5Aget_name_by_idx_name_order_decreasing); + } + + if (HDstrncmp(name_buf, ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME, + strlen(ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME) + 1)) { + H5_FAILED(); + HDprintf(" retrieved attribute name '%s' didn't match '%s'\n", name_buf, + ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME); + PART_ERROR(H5Aget_name_by_idx_name_order_decreasing); + } + + *name_buf = '\0'; + if (H5Aget_name_by_idx(container_group, ATTRIBUTE_GET_NAME_TEST_GROUP_NAME, H5_INDEX_NAME, + H5_ITER_DEC, 1, name_buf, (size_t)name_buf_size, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve name of attribute at index %lld using H5Aget_name_by_index " + "by alphabetical order in decreasing order\n", + 1); + PART_ERROR(H5Aget_name_by_idx_name_order_decreasing); + } + + if (HDstrncmp(name_buf, ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME2, + strlen(ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME2) + 1)) { + H5_FAILED(); + HDprintf(" retrieved attribute name '%s' didn't match '%s'\n", name_buf, + ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME2); + PART_ERROR(H5Aget_name_by_idx_name_order_decreasing); + } + + *name_buf = '\0'; + if (H5Aget_name_by_idx(container_group, ATTRIBUTE_GET_NAME_TEST_GROUP_NAME, H5_INDEX_NAME, + H5_ITER_DEC, 0, name_buf, (size_t)name_buf_size, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve name of attribute at index %lld using H5Aget_name_by_index " + "by alphabetical order in decreasing order\n", + 0); + PART_ERROR(H5Aget_name_by_idx_name_order_decreasing); + } + + if (HDstrncmp(name_buf, ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME3, + strlen(ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME3) + 1)) { + H5_FAILED(); + HDprintf(" retrieved attribute name '%s' didn't match '%s'\n", name_buf, + ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME3); + PART_ERROR(H5Aget_name_by_idx_name_order_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Aget_name_by_idx_name_order_decreasing); +#endif + } + PART_END(H5Aget_name_by_idx_name_order_decreasing); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (name_buf) { + HDfree(name_buf); + name_buf = NULL; + } + + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype) < 0) + TEST_ERROR; + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (name_buf) + HDfree(name_buf); + H5Sclose(space_id); + H5Tclose(attr_dtype); + H5Aclose(attr_id); + H5Pclose(gcpl_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that an attribute's name can't be + * retrieved when H5Aget_name(_by_idx) is passed invalid + * parameters. + */ +static int +test_get_attribute_name_invalid_params(void) +{ + ssize_t name_buf_size; + htri_t attr_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t attr_dtype = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + char *name_buf = NULL; + + TESTING_MULTIPART("retrieval of an attribute's name with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_MORE)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or attribute aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", ATTRIBUTE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_GET_NAME_INVALID_PARAMS_TEST_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", + ATTRIBUTE_GET_NAME_INVALID_PARAMS_TEST_GROUP_NAME); + goto error; + } + + if ((space_id = generate_random_dataspace(ATTRIBUTE_GET_NAME_INVALID_PARAMS_TEST_SPACE_RANK, NULL, NULL, + TRUE)) < 0) + TEST_ERROR; + + if ((attr_dtype = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_GET_NAME_INVALID_PARAMS_TEST_ATTRIBUTE_NAME, attr_dtype, + space_id, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute\n"); + goto error; + } + + /* Verify the attribute has been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_GET_NAME_INVALID_PARAMS_TEST_ATTRIBUTE_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not exist\n"); + goto error; + } + + /* + * Allocate an actual buffer for the tests. + */ + + if ((name_buf_size = H5Aget_name(attr_id, 0, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve name buf size\n"); + goto error; + } + + if (NULL == (name_buf = (char *)HDmalloc((size_t)name_buf_size + 1))) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Aget_name_invalid_attr_id) + { + TESTING_2("H5Aget_name with an invalid attr_id"); + + H5E_BEGIN_TRY + { + name_buf_size = H5Aget_name(H5I_INVALID_HID, (size_t)name_buf_size + 1, name_buf); + } + H5E_END_TRY; + + if (name_buf_size >= 0) { + H5_FAILED(); + HDprintf(" retrieved attribute name using H5Aget_name with an invalid attr_id!\n"); + PART_ERROR(H5Aget_name_invalid_attr_id); + } + + PASSED(); + } + PART_END(H5Aget_name_invalid_attr_id); + + PART_BEGIN(H5Aget_name_invalid_name_buf) + { + TESTING_2("H5Aget_name with an invalid name buffer"); + + H5E_BEGIN_TRY + { + name_buf_size = 1; + name_buf_size = H5Aget_name(attr_id, (size_t)name_buf_size, NULL); + } + H5E_END_TRY; + + if (name_buf_size >= 0) { + H5_FAILED(); + HDprintf(" retrieved attribute name using H5Aget_name with an invalid name buffer!\n"); + PART_ERROR(H5Aget_name_invalid_name_buf); + } + + PASSED(); + } + PART_END(H5Aget_name_invalid_name_buf); + + PART_BEGIN(H5Aget_name_by_idx_invalid_loc_id) + { + TESTING_2("H5Aget_name_by_idx with an invalid loc_id"); + + H5E_BEGIN_TRY + { + name_buf_size = H5Aget_name_by_idx( + H5I_INVALID_HID, ATTRIBUTE_GET_NAME_INVALID_PARAMS_TEST_GROUP_NAME, H5_INDEX_NAME, + H5_ITER_INC, 0, name_buf, (size_t)name_buf_size + 1, H5P_DEFAULT); + } + H5E_END_TRY; + + if (name_buf_size >= 0) { + H5_FAILED(); + HDprintf(" retrieved attribute name using H5Aget_name_by_idx with an invalid loc_id!\n"); + PART_ERROR(H5Aget_name_by_idx_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Aget_name_by_idx_invalid_loc_id); + + PART_BEGIN(H5Aget_name_by_idx_invalid_obj_name) + { + TESTING_2("H5Aget_name_by_idx with an invalid object name"); + + H5E_BEGIN_TRY + { + name_buf_size = H5Aget_name_by_idx(container_group, NULL, H5_INDEX_NAME, H5_ITER_INC, 0, + name_buf, (size_t)name_buf_size + 1, H5P_DEFAULT); + } + H5E_END_TRY; + + if (name_buf_size >= 0) { + H5_FAILED(); + HDprintf(" retrieved attribute name using H5Aget_name_by_idx with a NULL object name!\n"); + PART_ERROR(H5Aget_name_by_idx_invalid_obj_name); + } + + H5E_BEGIN_TRY + { + name_buf_size = H5Aget_name_by_idx(container_group, "", H5_INDEX_NAME, H5_ITER_INC, 0, + name_buf, (size_t)name_buf_size + 1, H5P_DEFAULT); + } + H5E_END_TRY; + + if (name_buf_size >= 0) { + H5_FAILED(); + HDprintf(" retrieved attribute name using H5Aget_name_by_idx with an invalid object name " + "of ''!\n"); + PART_ERROR(H5Aget_name_by_idx_invalid_obj_name); + } + + PASSED(); + } + PART_END(H5Aget_name_by_idx_invalid_obj_name); + + PART_BEGIN(H5Aget_name_by_idx_invalid_index_type) + { + TESTING_2("H5Aget_name_by_idx with an invalid index type"); + + H5E_BEGIN_TRY + { + name_buf_size = H5Aget_name_by_idx( + container_group, ATTRIBUTE_GET_NAME_INVALID_PARAMS_TEST_GROUP_NAME, H5_INDEX_UNKNOWN, + H5_ITER_INC, 0, name_buf, (size_t)name_buf_size + 1, H5P_DEFAULT); + } + H5E_END_TRY; + + if (name_buf_size >= 0) { + H5_FAILED(); + HDprintf(" retrieved attribute name using H5Aget_name_by_idx with invalid index type " + "H5_INDEX_UNKNOWN!\n"); + PART_ERROR(H5Aget_name_by_idx_invalid_index_type); + } + + H5E_BEGIN_TRY + { + name_buf_size = H5Aget_name_by_idx( + container_group, ATTRIBUTE_GET_NAME_INVALID_PARAMS_TEST_GROUP_NAME, H5_INDEX_N, + H5_ITER_INC, 0, name_buf, (size_t)name_buf_size + 1, H5P_DEFAULT); + } + H5E_END_TRY; + + if (name_buf_size >= 0) { + H5_FAILED(); + HDprintf(" retrieved attribute name using H5Aget_name_by_idx with invalid index type " + "H5_INDEX_N!\n"); + PART_ERROR(H5Aget_name_by_idx_invalid_index_type); + } + + PASSED(); + } + PART_END(H5Aget_name_by_idx_invalid_index_type); + + PART_BEGIN(H5Aget_name_by_idx_invalid_iter_order) + { + TESTING_2("H5Aget_name_by_idx with an invalid iteration order"); + + H5E_BEGIN_TRY + { + name_buf_size = H5Aget_name_by_idx( + container_group, ATTRIBUTE_GET_NAME_INVALID_PARAMS_TEST_GROUP_NAME, H5_INDEX_NAME, + H5_ITER_UNKNOWN, 0, name_buf, (size_t)name_buf_size + 1, H5P_DEFAULT); + } + H5E_END_TRY; + + if (name_buf_size >= 0) { + H5_FAILED(); + HDprintf(" retrieved attribute name using H5Aget_name_by_idx with invalid iteration order " + "H5_ITER_UNKNOWN!\n"); + PART_ERROR(H5Aget_name_by_idx_invalid_iter_order); + } + + H5E_BEGIN_TRY + { + name_buf_size = H5Aget_name_by_idx( + container_group, ATTRIBUTE_GET_NAME_INVALID_PARAMS_TEST_GROUP_NAME, H5_INDEX_NAME, + H5_ITER_N, 0, name_buf, (size_t)name_buf_size + 1, H5P_DEFAULT); + } + H5E_END_TRY; + + if (name_buf_size >= 0) { + H5_FAILED(); + HDprintf(" retrieved attribute name using H5Aget_name_by_idx with invalid iteration order " + "H5_ITER_N!\n"); + PART_ERROR(H5Aget_name_by_idx_invalid_iter_order); + } + + PASSED(); + } + PART_END(H5Aget_name_by_idx_invalid_iter_order); + + PART_BEGIN(H5Aget_name_by_idx_invalid_name_buf) + { + TESTING_2("H5Aget_name_by_idx with an invalid name buffer"); + + H5E_BEGIN_TRY + { + name_buf_size = 1; + name_buf_size = H5Aget_name_by_idx( + container_group, ATTRIBUTE_GET_NAME_INVALID_PARAMS_TEST_GROUP_NAME, H5_INDEX_NAME, + H5_ITER_INC, 0, NULL, (size_t)name_buf_size, H5P_DEFAULT); + } + H5E_END_TRY; + + if (name_buf_size >= 0) { + H5_FAILED(); + HDprintf( + " retrieved attribute name using H5Aget_name_by_idx with an invalid name buffer!\n"); + PART_ERROR(H5Aget_name_by_idx_invalid_name_buf); + } + + PASSED(); + } + PART_END(H5Aget_name_by_idx_invalid_name_buf); + + PART_BEGIN(H5Aget_name_by_idx_invalid_lapl) + { + TESTING_2("H5Aget_name_by_idx with an invalid LAPL"); + + H5E_BEGIN_TRY + { + name_buf_size = H5Aget_name_by_idx( + container_group, ATTRIBUTE_GET_NAME_INVALID_PARAMS_TEST_GROUP_NAME, H5_INDEX_NAME, + H5_ITER_INC, 0, name_buf, (size_t)name_buf_size + 1, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (name_buf_size >= 0) { + H5_FAILED(); + HDprintf(" retrieved attribute name using H5Aget_name_by_idx with an invalid LAPL!\n"); + PART_ERROR(H5Aget_name_by_idx_invalid_lapl); + } + + PASSED(); + } + PART_END(H5Aget_name_by_idx_invalid_lapl); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (name_buf) { + HDfree(name_buf); + name_buf = NULL; + } + + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype) < 0) + TEST_ERROR; + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (name_buf) + HDfree(name_buf); + H5Sclose(space_id); + H5Tclose(attr_dtype); + H5Aclose(attr_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test for H5Aget_storage_size. + */ +static int +test_get_attribute_storage_size(void) +{ + TESTING("H5Aget_storage_size"); + + SKIPPED(); + + return 0; +} + +/* + * A test to check the functionality of H5Aget_info(_by_idx). + */ +static int +test_get_attribute_info(void) +{ + H5A_info_t attr_info; + htri_t attr_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t attr_dtype = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + + TESTING_MULTIPART("retrieval of attribute info"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, attribute, or creation order aren't supported " + "with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file\n"); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group\n"); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create GCPL for attribute creation order tracking\n"); + goto error; + } + + if (H5Pset_attr_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED) < 0) { + H5_FAILED(); + HDprintf(" couldn't set attribute creation order tracking\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_GET_INFO_TEST_GROUP_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", ATTRIBUTE_GET_INFO_TEST_GROUP_NAME); + goto error; + } + + if ((space_id = generate_random_dataspace(ATTRIBUTE_GET_INFO_TEST_SPACE_RANK, NULL, NULL, TRUE)) < 0) + TEST_ERROR; + + if ((attr_dtype = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + /* Create several attributes */ + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_GET_INFO_TEST_ATTR_NAME, attr_dtype, space_id, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s'\n", ATTRIBUTE_GET_INFO_TEST_ATTR_NAME); + goto error; + } + + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_GET_INFO_TEST_ATTR_NAME2, attr_dtype, space_id, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s'\n", ATTRIBUTE_GET_INFO_TEST_ATTR_NAME2); + goto error; + } + + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_GET_INFO_TEST_ATTR_NAME3, attr_dtype, space_id, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s'\n", ATTRIBUTE_GET_INFO_TEST_ATTR_NAME3); + goto error; + } + + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + + /* Verify the attributes have been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_GET_INFO_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", ATTRIBUTE_GET_INFO_TEST_ATTR_NAME); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' did not exist\n", ATTRIBUTE_GET_INFO_TEST_ATTR_NAME); + goto error; + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_GET_INFO_TEST_ATTR_NAME2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", ATTRIBUTE_GET_INFO_TEST_ATTR_NAME2); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' did not exist\n", ATTRIBUTE_GET_INFO_TEST_ATTR_NAME2); + goto error; + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_GET_INFO_TEST_ATTR_NAME3)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", ATTRIBUTE_GET_INFO_TEST_ATTR_NAME3); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' did not exist\n", ATTRIBUTE_GET_INFO_TEST_ATTR_NAME3); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Aget_info) + { + TESTING_2("H5Aget_info"); + + if ((attr_id = H5Aopen(group_id, ATTRIBUTE_GET_INFO_TEST_ATTR_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open attribute '%s'\n", ATTRIBUTE_GET_INFO_TEST_ATTR_NAME); + PART_ERROR(H5Aget_info); + } + + HDmemset(&attr_info, 0, sizeof(attr_info)); + if (H5Aget_info(attr_id, &attr_info) < 0) { + H5_FAILED(); + HDprintf(" couldn't get attribute info\n"); + PART_ERROR(H5Aget_info); + } + + if (attr_info.corder_valid && (attr_info.corder != 0)) { + H5_FAILED(); + HDprintf(" attribute's creation order value '%lld' did not match expected value '%lld'\n", + (long long)attr_info.corder, (long long)0); + PART_ERROR(H5Aget_info); + } + + /* Ensure that the cset field is at least set to a meaningful value */ + if (attr_info.cset != H5T_CSET_ASCII && attr_info.cset != H5T_CSET_UTF8 && + attr_info.cset != H5T_CSET_ERROR) { + H5_FAILED(); + HDprintf(" attribute info's 'cset' field wasn't set to a meaningful value\n"); + PART_ERROR(H5Aget_info); + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close attribute '%s'\n", ATTRIBUTE_GET_INFO_TEST_ATTR_NAME); + PART_ERROR(H5Aget_info); + } + + PASSED(); + } + PART_END(H5Aget_info); + + H5E_BEGIN_TRY + { + H5Aclose(attr_id); + attr_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Aget_info_by_name) + { + TESTING_2("H5Aget_info_by_name"); + + HDmemset(&attr_info, 0, sizeof(attr_info)); + if (H5Aget_info_by_name(group_id, ".", ATTRIBUTE_GET_INFO_TEST_ATTR_NAME, &attr_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get attribute info by name '%s'\n", ATTRIBUTE_GET_INFO_TEST_ATTR_NAME); + PART_ERROR(H5Aget_info_by_name); + } + + if (attr_info.corder_valid && (attr_info.corder != 0)) { + H5_FAILED(); + HDprintf(" attribute's creation order value '%lld' did not match expected value '%lld'\n", + (long long)attr_info.corder, (long long)0); + PART_ERROR(H5Aget_info_by_name); + } + + /* Ensure that the cset field is at least set to a meaningful value */ + if (attr_info.cset != H5T_CSET_ASCII && attr_info.cset != H5T_CSET_UTF8 && + attr_info.cset != H5T_CSET_ERROR) { + H5_FAILED(); + HDprintf(" attribute info's 'cset' field wasn't set to a meaningful value\n"); + PART_ERROR(H5Aget_info_by_name); + } + + HDmemset(&attr_info, 0, sizeof(attr_info)); + if (H5Aget_info_by_name(group_id, ".", ATTRIBUTE_GET_INFO_TEST_ATTR_NAME2, &attr_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get attribute info by name '%s'\n", + ATTRIBUTE_GET_INFO_TEST_ATTR_NAME2); + PART_ERROR(H5Aget_info_by_name); + } + + if (attr_info.corder_valid && (attr_info.corder != 1)) { + H5_FAILED(); + HDprintf(" attribute's creation order value '%lld' did not match expected value '%lld'\n", + (long long)attr_info.corder, (long long)1); + PART_ERROR(H5Aget_info_by_name); + } + + /* Ensure that the cset field is at least set to a meaningful value */ + if (attr_info.cset != H5T_CSET_ASCII && attr_info.cset != H5T_CSET_UTF8 && + attr_info.cset != H5T_CSET_ERROR) { + H5_FAILED(); + HDprintf(" attribute info's 'cset' field wasn't set to a meaningful value\n"); + PART_ERROR(H5Aget_info_by_name); + } + + HDmemset(&attr_info, 0, sizeof(attr_info)); + if (H5Aget_info_by_name(group_id, ".", ATTRIBUTE_GET_INFO_TEST_ATTR_NAME3, &attr_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get attribute info by name '%s'\n", + ATTRIBUTE_GET_INFO_TEST_ATTR_NAME3); + PART_ERROR(H5Aget_info_by_name); + } + + if (attr_info.corder_valid && (attr_info.corder != 2)) { + H5_FAILED(); + HDprintf(" attribute's creation order value '%lld' did not match expected value '%lld'\n", + (long long)attr_info.corder, (long long)2); + PART_ERROR(H5Aget_info_by_name); + } + + /* Ensure that the cset field is at least set to a meaningful value */ + if (attr_info.cset != H5T_CSET_ASCII && attr_info.cset != H5T_CSET_UTF8 && + attr_info.cset != H5T_CSET_ERROR) { + H5_FAILED(); + HDprintf(" attribute info's 'cset' field wasn't set to a meaningful value\n"); + PART_ERROR(H5Aget_info_by_name); + } + + PASSED(); + } + PART_END(H5Aget_info_by_name); + + PART_BEGIN(H5Aget_info_by_idx_crt_order_increasing) + { + TESTING_2("H5Aget_info_by_idx by creation order in increasing order"); + + HDmemset(&attr_info, 0, sizeof(attr_info)); + if (H5Aget_info_by_idx(group_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, &attr_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get info for attribute at index %d using H5Aget_info_by_idx by " + "creation order in increasing order\n", + 0); + PART_ERROR(H5Aget_info_by_idx_crt_order_increasing); + } + + if (attr_info.corder_valid && (attr_info.corder != 0)) { + H5_FAILED(); + HDprintf(" attribute's creation order value '%lld' did not match expected value '%lld'\n", + (long long)attr_info.corder, (long long)0); + PART_ERROR(H5Aget_info_by_idx_crt_order_increasing); + } + + /* Ensure that the cset field is at least set to a meaningful value */ + if (attr_info.cset != H5T_CSET_ASCII && attr_info.cset != H5T_CSET_UTF8 && + attr_info.cset != H5T_CSET_ERROR) { + H5_FAILED(); + HDprintf(" attribute info's 'cset' field wasn't set to a meaningful value\n"); + PART_ERROR(H5Aget_info_by_idx_crt_order_increasing); + } + + HDmemset(&attr_info, 0, sizeof(attr_info)); + if (H5Aget_info_by_idx(group_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 1, &attr_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get info for attribute at index %d using H5Aget_info_by_idx by " + "creation order in increasing order\n", + 1); + PART_ERROR(H5Aget_info_by_idx_crt_order_increasing); + } + + if (attr_info.corder_valid && (attr_info.corder != 1)) { + H5_FAILED(); + HDprintf(" attribute's creation order value '%lld' did not match expected value '%lld'\n", + (long long)attr_info.corder, (long long)1); + PART_ERROR(H5Aget_info_by_idx_crt_order_increasing); + } + + /* Ensure that the cset field is at least set to a meaningful value */ + if (attr_info.cset != H5T_CSET_ASCII && attr_info.cset != H5T_CSET_UTF8 && + attr_info.cset != H5T_CSET_ERROR) { + H5_FAILED(); + HDprintf(" attribute info's 'cset' field wasn't set to a meaningful value\n"); + PART_ERROR(H5Aget_info_by_idx_crt_order_increasing); + } + + HDmemset(&attr_info, 0, sizeof(attr_info)); + if (H5Aget_info_by_idx(group_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 2, &attr_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get info for attribute at index %d using H5Aget_info_by_idx by " + "creation order in increasing order\n", + 2); + PART_ERROR(H5Aget_info_by_idx_crt_order_increasing); + } + + if (attr_info.corder_valid && (attr_info.corder != 2)) { + H5_FAILED(); + HDprintf(" attribute's creation order value '%lld' did not match expected value '%lld'\n", + (long long)attr_info.corder, (long long)2); + PART_ERROR(H5Aget_info_by_idx_crt_order_increasing); + } + + /* Ensure that the cset field is at least set to a meaningful value */ + if (attr_info.cset != H5T_CSET_ASCII && attr_info.cset != H5T_CSET_UTF8 && + attr_info.cset != H5T_CSET_ERROR) { + H5_FAILED(); + HDprintf(" attribute info's 'cset' field wasn't set to a meaningful value\n"); + PART_ERROR(H5Aget_info_by_idx_crt_order_increasing); + } + + PASSED(); + } + PART_END(H5Aget_info_by_idx_crt_order_increasing); + + PART_BEGIN(H5Aget_info_by_idx_crt_order_decreasing) + { + TESTING_2("H5Aget_info_by_idx by creation order in decreasing order"); + + HDmemset(&attr_info, 0, sizeof(attr_info)); + if (H5Aget_info_by_idx(group_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 2, &attr_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get info for attribute at index %d using H5Aget_info_by_idx by " + "creation order in decreasing order\n", + 2); + PART_ERROR(H5Aget_info_by_idx_crt_order_decreasing); + } + + if (attr_info.corder_valid && (attr_info.corder != 0)) { + H5_FAILED(); + HDprintf(" attribute's creation order value '%lld' did not match expected value '%lld'\n", + (long long)attr_info.corder, (long long)0); + PART_ERROR(H5Aget_info_by_idx_crt_order_decreasing); + } + + /* Ensure that the cset field is at least set to a meaningful value */ + if (attr_info.cset != H5T_CSET_ASCII && attr_info.cset != H5T_CSET_UTF8 && + attr_info.cset != H5T_CSET_ERROR) { + H5_FAILED(); + HDprintf(" attribute info's 'cset' field wasn't set to a meaningful value\n"); + PART_ERROR(H5Aget_info_by_idx_crt_order_decreasing); + } + + HDmemset(&attr_info, 0, sizeof(attr_info)); + if (H5Aget_info_by_idx(group_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 1, &attr_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get info for attribute at index %d using H5Aget_info_by_idx by " + "creation order in decreasing order\n", + 1); + PART_ERROR(H5Aget_info_by_idx_crt_order_decreasing); + } + + if (attr_info.corder_valid && (attr_info.corder != 1)) { + H5_FAILED(); + HDprintf(" attribute's creation order value '%lld' did not match expected value '%lld'\n", + (long long)attr_info.corder, (long long)1); + PART_ERROR(H5Aget_info_by_idx_crt_order_decreasing); + } + + /* Ensure that the cset field is at least set to a meaningful value */ + if (attr_info.cset != H5T_CSET_ASCII && attr_info.cset != H5T_CSET_UTF8 && + attr_info.cset != H5T_CSET_ERROR) { + H5_FAILED(); + HDprintf(" attribute info's 'cset' field wasn't set to a meaningful value\n"); + PART_ERROR(H5Aget_info_by_idx_crt_order_decreasing); + } + + HDmemset(&attr_info, 0, sizeof(attr_info)); + if (H5Aget_info_by_idx(group_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 0, &attr_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get info for attribute at index %d using H5Aget_info_by_idx by " + "creation order in decreasing order\n", + 0); + PART_ERROR(H5Aget_info_by_idx_crt_order_decreasing); + } + + if (attr_info.corder_valid && (attr_info.corder != 2)) { + H5_FAILED(); + HDprintf(" attribute's creation order value '%lld' did not match expected value '%lld'\n", + (long long)attr_info.corder, (long long)2); + PART_ERROR(H5Aget_info_by_idx_crt_order_decreasing); + } + + /* Ensure that the cset field is at least set to a meaningful value */ + if (attr_info.cset != H5T_CSET_ASCII && attr_info.cset != H5T_CSET_UTF8 && + attr_info.cset != H5T_CSET_ERROR) { + H5_FAILED(); + HDprintf(" attribute info's 'cset' field wasn't set to a meaningful value\n"); + PART_ERROR(H5Aget_info_by_idx_crt_order_decreasing); + } + + PASSED(); + } + PART_END(H5Aget_info_by_idx_crt_order_decreasing); + + PART_BEGIN(H5Aget_info_by_idx_name_order_increasing) + { + TESTING_2("H5Aget_info_by_idx by alphabetical order in increasing order"); + + HDmemset(&attr_info, 0, sizeof(attr_info)); + if (H5Aget_info_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, &attr_info, H5P_DEFAULT) < + 0) { + H5_FAILED(); + HDprintf(" couldn't get info for attribute at index %d using H5Aget_info_by_idx by " + "alphabetical order in increasing order\n", + 0); + PART_ERROR(H5Aget_info_by_idx_name_order_increasing); + } + + if (attr_info.corder_valid && (attr_info.corder != 0)) { + H5_FAILED(); + HDprintf(" attribute's creation order value '%lld' did not match expected value '%lld'\n", + (long long)attr_info.corder, (long long)0); + PART_ERROR(H5Aget_info_by_idx_name_order_increasing); + } + + /* Ensure that the cset field is at least set to a meaningful value */ + if (attr_info.cset != H5T_CSET_ASCII && attr_info.cset != H5T_CSET_UTF8 && + attr_info.cset != H5T_CSET_ERROR) { + H5_FAILED(); + HDprintf(" attribute info's 'cset' field wasn't set to a meaningful value\n"); + PART_ERROR(H5Aget_info_by_idx_name_order_increasing); + } + + HDmemset(&attr_info, 0, sizeof(attr_info)); + if (H5Aget_info_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, 1, &attr_info, H5P_DEFAULT) < + 0) { + H5_FAILED(); + HDprintf(" couldn't get info for attribute at index %d using H5Aget_info_by_idx by " + "alphabetical order in increasing order\n", + 1); + PART_ERROR(H5Aget_info_by_idx_name_order_increasing); + } + + if (attr_info.corder_valid && (attr_info.corder != 1)) { + H5_FAILED(); + HDprintf(" attribute's creation order value '%lld' did not match expected value '%lld'\n", + (long long)attr_info.corder, (long long)1); + PART_ERROR(H5Aget_info_by_idx_name_order_increasing); + } + + /* Ensure that the cset field is at least set to a meaningful value */ + if (attr_info.cset != H5T_CSET_ASCII && attr_info.cset != H5T_CSET_UTF8 && + attr_info.cset != H5T_CSET_ERROR) { + H5_FAILED(); + HDprintf(" attribute info's 'cset' field wasn't set to a meaningful value\n"); + PART_ERROR(H5Aget_info_by_idx_name_order_increasing); + } + + HDmemset(&attr_info, 0, sizeof(attr_info)); + if (H5Aget_info_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, 2, &attr_info, H5P_DEFAULT) < + 0) { + H5_FAILED(); + HDprintf(" couldn't get info for attribute at index %d using H5Aget_info_by_idx by " + "alphabetical order in increasing order\n", + 2); + PART_ERROR(H5Aget_info_by_idx_name_order_increasing); + } + + if (attr_info.corder_valid && (attr_info.corder != 2)) { + H5_FAILED(); + HDprintf(" attribute's creation order value '%lld' did not match expected value '%lld'\n", + (long long)attr_info.corder, (long long)2); + PART_ERROR(H5Aget_info_by_idx_name_order_increasing); + } + + /* Ensure that the cset field is at least set to a meaningful value */ + if (attr_info.cset != H5T_CSET_ASCII && attr_info.cset != H5T_CSET_UTF8 && + attr_info.cset != H5T_CSET_ERROR) { + H5_FAILED(); + HDprintf(" attribute info's 'cset' field wasn't set to a meaningful value\n"); + PART_ERROR(H5Aget_info_by_idx_name_order_increasing); + } + + PASSED(); + } + PART_END(H5Aget_info_by_idx_name_order_increasing); + + PART_BEGIN(H5Aget_info_by_idx_name_order_decreasing) + { + TESTING_2("H5Aget_info_by_idx by alphabetical order in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + HDmemset(&attr_info, 0, sizeof(attr_info)); + if (H5Aget_info_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 2, &attr_info, H5P_DEFAULT) < + 0) { + H5_FAILED(); + HDprintf(" couldn't get info for attribute at index %lld using H5Aget_info_by_idx by " + "alphabetical order in decreasing order\n", + 2); + PART_ERROR(H5Aget_info_by_idx_name_order_decreasing); + } + + if (attr_info.corder_valid && (attr_info.corder != 0)) { + H5_FAILED(); + HDprintf(" attribute's creation order value '%lld' did not match expected value '%lld'\n", + (long long)attr_info.corder, (long long)0); + PART_ERROR(H5Aget_info_by_idx_name_order_decreasing); + } + + /* Ensure that the cset field is at least set to a meaningful value */ + if (attr_info.cset != H5T_CSET_ASCII && attr_info.cset != H5T_CSET_UTF8 && + attr_info.cset != H5T_CSET_ERROR) { + H5_FAILED(); + HDprintf(" attribute info's 'cset' field wasn't set to a meaningful value\n"); + PART_ERROR(H5Aget_info_by_idx_name_order_decreasing); + } + + HDmemset(&attr_info, 0, sizeof(attr_info)); + if (H5Aget_info_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 1, &attr_info, H5P_DEFAULT) < + 0) { + H5_FAILED(); + HDprintf(" couldn't get info for attribute at index %lld using H5Aget_info_by_idx by " + "alphabetical order in decreasing order\n", + 1); + PART_ERROR(H5Aget_info_by_idx_name_order_decreasing); + } + + if (attr_info.corder_valid && (attr_info.corder != 1)) { + H5_FAILED(); + HDprintf(" attribute's creation order value '%lld' did not match expected value '%lld'\n", + (long long)attr_info.corder, (long long)1); + PART_ERROR(H5Aget_info_by_idx_name_order_decreasing); + } + + /* Ensure that the cset field is at least set to a meaningful value */ + if (attr_info.cset != H5T_CSET_ASCII && attr_info.cset != H5T_CSET_UTF8 && + attr_info.cset != H5T_CSET_ERROR) { + H5_FAILED(); + HDprintf(" attribute info's 'cset' field wasn't set to a meaningful value\n"); + PART_ERROR(H5Aget_info_by_idx_name_order_decreasing); + } + + HDmemset(&attr_info, 0, sizeof(attr_info)); + if (H5Aget_info_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 0, &attr_info, H5P_DEFAULT) < + 0) { + H5_FAILED(); + HDprintf(" couldn't get info for attribute at index %lld using H5Aget_info_by_idx by " + "alphabetical order in decreasing order\n", + 0); + PART_ERROR(H5Aget_info_by_idx_name_order_decreasing); + } + + if (attr_info.corder_valid && (attr_info.corder != 2)) { + H5_FAILED(); + HDprintf(" attribute's creation order value '%lld' did not match expected value '%lld'\n", + (long long)attr_info.corder, (long long)2); + PART_ERROR(H5Aget_info_by_idx_name_order_decreasing); + } + + /* Ensure that the cset field is at least set to a meaningful value */ + if (attr_info.cset != H5T_CSET_ASCII && attr_info.cset != H5T_CSET_UTF8 && + attr_info.cset != H5T_CSET_ERROR) { + H5_FAILED(); + HDprintf(" attribute info's 'cset' field wasn't set to a meaningful value\n"); + PART_ERROR(H5Aget_info_by_idx_name_order_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Aget_info_by_idx_name_order_decreasing); +#endif + } + PART_END(H5Aget_info_by_idx_name_order_decreasing); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype) < 0) + TEST_ERROR; + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(space_id); + H5Tclose(attr_dtype); + H5Aclose(attr_id); + H5Pclose(gcpl_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that H5Aget_info(_by_name/_by_idx) + * doesn't succeed when passed invalid parameters. + */ +static int +test_get_attribute_info_invalid_params(void) +{ + H5A_info_t attr_info; + htri_t attr_exists; + herr_t err_ret = -1; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t attr_dtype = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + + TESTING_MULTIPART("retrieval of attribute info with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_MORE)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or attribute aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", ATTRIBUTE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_GET_INFO_INVALID_PARAMS_TEST_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", + ATTRIBUTE_GET_INFO_INVALID_PARAMS_TEST_GROUP_NAME); + goto error; + } + + if ((space_id = generate_random_dataspace(ATTRIBUTE_GET_INFO_INVALID_PARAMS_TEST_SPACE_RANK, NULL, NULL, + TRUE)) < 0) + TEST_ERROR; + + if ((attr_dtype = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_GET_INFO_INVALID_PARAMS_TEST_ATTR_NAME, attr_dtype, + space_id, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute\n"); + goto error; + } + + /* Verify the attribute has been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_GET_INFO_INVALID_PARAMS_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not exist\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Aget_info_invalid_attr_id) + { + TESTING_2("H5Aget_info with an invalid attr_id"); + + H5E_BEGIN_TRY + { + err_ret = H5Aget_info(H5I_INVALID_HID, &attr_info); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved attribute info using H5Aget_info with an invalid attr_id!\n"); + PART_ERROR(H5Aget_info_invalid_attr_id); + } + + PASSED(); + } + PART_END(H5Aget_info_invalid_attr_id); + + PART_BEGIN(H5Aget_info_invalid_attr_info_pointer) + { + TESTING_2("H5Aget_info with an invalid attribute info pointer"); + + H5E_BEGIN_TRY + { + err_ret = H5Aget_info(attr_id, NULL); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved attribute info using H5Aget_info with an invalid attr_id!\n"); + PART_ERROR(H5Aget_info_invalid_attr_info_pointer); + } + + PASSED(); + } + PART_END(H5Aget_info_invalid_attr_info_pointer); + + PART_BEGIN(H5Aget_info_by_name_invalid_loc_id) + { + TESTING_2("H5Aget_info_by_name with an invalid loc_id"); + + H5E_BEGIN_TRY + { + err_ret = H5Aget_info_by_name(H5I_INVALID_HID, ".", + ATTRIBUTE_GET_INFO_INVALID_PARAMS_TEST_ATTR_NAME, &attr_info, + H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved attribute info using H5Aget_info_by_name with an invalid loc_id!\n"); + PART_ERROR(H5Aget_info_by_name_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Aget_info_by_name_invalid_loc_id); + + PART_BEGIN(H5Aget_info_by_name_invalid_obj_name) + { + TESTING_2("H5Aget_info_by_name with an invalid object name"); + + H5E_BEGIN_TRY + { + err_ret = + H5Aget_info_by_name(group_id, NULL, ATTRIBUTE_GET_INFO_INVALID_PARAMS_TEST_ATTR_NAME, + &attr_info, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved attribute info using H5Aget_info_by_name with a NULL object name!\n"); + PART_ERROR(H5Aget_info_by_name_invalid_obj_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Aget_info_by_name(group_id, "", ATTRIBUTE_GET_INFO_INVALID_PARAMS_TEST_ATTR_NAME, + &attr_info, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved attribute info using H5Aget_info_by_name with an invalid object name " + "of ''!\n"); + PART_ERROR(H5Aget_info_by_name_invalid_obj_name); + } + + PASSED(); + } + PART_END(H5Aget_info_by_name_invalid_obj_name); + + PART_BEGIN(H5Aget_info_by_name_invalid_attr_name) + { + TESTING_2("H5Aget_info_by_name with an invalid attribute name"); + + H5E_BEGIN_TRY + { + err_ret = H5Aget_info_by_name(group_id, ".", NULL, &attr_info, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf( + " retrieved attribute info using H5Aget_info_by_name with a NULL attribute name!\n"); + PART_ERROR(H5Aget_info_by_name_invalid_attr_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Aget_info_by_name(group_id, ".", "", &attr_info, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved attribute info using H5Aget_info_by_name with an invalid attribute " + "name of ''!\n"); + PART_ERROR(H5Aget_info_by_name_invalid_attr_name); + } + + PASSED(); + } + PART_END(H5Aget_info_by_name_invalid_attr_name); + + PART_BEGIN(H5Aget_info_by_name_invalid_attr_info_pointer) + { + TESTING_2("H5Aget_info_by_name with an invalid attribute info pointer"); + + H5E_BEGIN_TRY + { + err_ret = H5Aget_info_by_name(group_id, ".", ATTRIBUTE_GET_INFO_INVALID_PARAMS_TEST_ATTR_NAME, + NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved attribute info using H5Aget_info_by_name with an invalid attribute " + "info pointer!\n"); + PART_ERROR(H5Aget_info_by_name_invalid_attr_info_pointer); + } + + PASSED(); + } + PART_END(H5Aget_info_by_name_invalid_attr_info_pointer); + + PART_BEGIN(H5Aget_info_by_name_invalid_lapl) + { + TESTING_2("H5Aget_info_by_name with an invalid LAPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Aget_info_by_name(group_id, ".", ATTRIBUTE_GET_INFO_INVALID_PARAMS_TEST_ATTR_NAME, + &attr_info, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved attribute info using H5Aget_info_by_name with an invalid LAPL!\n"); + PART_ERROR(H5Aget_info_by_name_invalid_lapl); + } + + PASSED(); + } + PART_END(H5Aget_info_by_name_invalid_lapl); + + PART_BEGIN(H5Aget_info_by_idx_invalid_loc_id) + { + TESTING_2("H5Aget_info_by_idx with an invalid loc_id"); + + H5E_BEGIN_TRY + { + err_ret = H5Aget_info_by_idx(H5I_INVALID_HID, ".", H5_INDEX_NAME, H5_ITER_INC, 0, &attr_info, + H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved attribute info using H5Aget_info_by_idx with an invalid loc_id!\n"); + PART_ERROR(H5Aget_info_by_idx_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Aget_info_by_idx_invalid_loc_id); + + PART_BEGIN(H5Aget_info_by_idx_invalid_obj_name) + { + TESTING_2("H5Aget_info_by_idx with an invalid object name"); + + H5E_BEGIN_TRY + { + err_ret = H5Aget_info_by_idx(group_id, NULL, H5_INDEX_NAME, H5_ITER_INC, 0, &attr_info, + H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved attribute info using H5Aget_info_by_idx with a NULL object name!\n"); + PART_ERROR(H5Aget_info_by_idx_invalid_obj_name); + } + + H5E_BEGIN_TRY + { + err_ret = + H5Aget_info_by_idx(group_id, "", H5_INDEX_NAME, H5_ITER_INC, 0, &attr_info, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved attribute info using H5Aget_info_by_idx with an invalid object name " + "of ''!\n"); + PART_ERROR(H5Aget_info_by_idx_invalid_obj_name); + } + + PASSED(); + } + PART_END(H5Aget_info_by_idx_invalid_obj_name); + + PART_BEGIN(H5Aget_info_by_idx_invalid_index_type) + { + TESTING_2("H5Aget_info_by_idx with an invalid index type"); + + H5E_BEGIN_TRY + { + err_ret = H5Aget_info_by_idx(group_id, ".", H5_INDEX_UNKNOWN, H5_ITER_INC, 0, &attr_info, + H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved attribute info using H5Aget_info_by_idx with invalid index type " + "H5_INDEX_UNKNOWN!\n"); + PART_ERROR(H5Aget_info_by_idx_invalid_index_type); + } + + H5E_BEGIN_TRY + { + err_ret = + H5Aget_info_by_idx(group_id, ".", H5_INDEX_N, H5_ITER_INC, 0, &attr_info, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved attribute info using H5Aget_info_by_idx with invalid index type " + "H5_INDEX_N!\n"); + PART_ERROR(H5Aget_info_by_idx_invalid_index_type); + } + + PASSED(); + } + PART_END(H5Aget_info_by_idx_invalid_index_type); + + PART_BEGIN(H5Aget_info_by_idx_invalid_iter_order) + { + TESTING_2("H5Aget_info_by_idx with an invalid iteration order"); + + H5E_BEGIN_TRY + { + err_ret = H5Aget_info_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_UNKNOWN, 0, &attr_info, + H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved attribute info using H5Aget_info_by_idx with invalid iteration order " + "H5_ITER_UNKNOWN!\n"); + PART_ERROR(H5Aget_info_by_idx_invalid_iter_order); + } + + H5E_BEGIN_TRY + { + err_ret = + H5Aget_info_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_N, 0, &attr_info, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved attribute info using H5Aget_info_by_idx with invalid iteration order " + "H5_ITER_N!\n"); + PART_ERROR(H5Aget_info_by_idx_invalid_iter_order); + } + + PASSED(); + } + PART_END(H5Aget_info_by_idx_invalid_iter_order); + + PART_BEGIN(H5Aget_info_by_idx_invalid_attr_info_pointer) + { + TESTING_2("H5Aget_info_by_idx with an invalid attribute info pointer"); + + H5E_BEGIN_TRY + { + err_ret = H5Aget_info_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved attribute info using H5Aget_info_by_idx with an invalid attribute " + "info pointer!\n"); + PART_ERROR(H5Aget_info_by_idx_invalid_attr_info_pointer); + } + + PASSED(); + } + PART_END(H5Aget_info_by_idx_invalid_attr_info_pointer); + + PART_BEGIN(H5Aget_info_by_idx_invalid_lapl) + { + TESTING_2("H5Aget_info_by_idx with an invalid LAPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Aget_info_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, &attr_info, + H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved attribute info using H5Aget_info_by_idx with an invalid LAPL!\n"); + PART_ERROR(H5Aget_info_by_idx_invalid_lapl); + } + + PASSED(); + } + PART_END(H5Aget_info_by_idx_invalid_lapl); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype) < 0) + TEST_ERROR; + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(space_id); + H5Tclose(attr_dtype); + H5Aclose(attr_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that an attribute can be renamed + * with H5Arename and H5Arename_by_name. + */ +static int +test_rename_attribute(void) +{ + htri_t attr_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID, attr_id2 = H5I_INVALID_HID; + hid_t attr_dtype = H5I_INVALID_HID; + hid_t attr_space_id = H5I_INVALID_HID; + + TESTING_MULTIPART("attribute renaming"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_MORE)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or attribute aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", ATTRIBUTE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_RENAME_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", ATTRIBUTE_RENAME_TEST_GROUP_NAME); + goto error; + } + + if ((attr_space_id = generate_random_dataspace(ATTRIBUTE_RENAME_TEST_SPACE_RANK, NULL, NULL, TRUE)) < 0) + TEST_ERROR; + + if ((attr_dtype = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_RENAME_TEST_ATTR_NAME, attr_dtype, attr_space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute\n"); + goto error; + } + + if ((attr_id2 = H5Acreate2(group_id, ATTRIBUTE_RENAME_TEST_ATTR_NAME2, attr_dtype, attr_space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute\n"); + goto error; + } + + /* Verify the attributes have been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_RENAME_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not exist\n"); + goto error; + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_RENAME_TEST_ATTR_NAME2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not exist\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Arename) + { + TESTING_2("H5Arename"); + + if (H5Arename(group_id, ATTRIBUTE_RENAME_TEST_ATTR_NAME, ATTRIBUTE_RENAME_TEST_NEW_NAME) < 0) { + H5_FAILED(); + HDprintf(" couldn't rename attribute '%s' to '%s' using H5Arename\n", + ATTRIBUTE_RENAME_TEST_ATTR_NAME, ATTRIBUTE_RENAME_TEST_NEW_NAME); + PART_ERROR(H5Arename); + } + + /* Verify the attribute has been renamed */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_RENAME_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + PART_ERROR(H5Arename); + } + + if (attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not get renamed!\n"); + PART_ERROR(H5Arename); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_RENAME_TEST_NEW_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + PART_ERROR(H5Arename); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not get renamed!\n"); + PART_ERROR(H5Arename); + } + + PASSED(); + } + PART_END(H5Arename); + + PART_BEGIN(H5Arename_by_name) + { + TESTING_2("H5Arename_by_name"); + + if (H5Arename_by_name(container_group, ATTRIBUTE_RENAME_TEST_GROUP_NAME, + ATTRIBUTE_RENAME_TEST_ATTR_NAME2, ATTRIBUTE_RENAME_TEST_NEW_NAME2, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't rename attribute '%s' to '%s' using H5Arename_by_name\n", + ATTRIBUTE_RENAME_TEST_ATTR_NAME2, ATTRIBUTE_RENAME_TEST_NEW_NAME2); + PART_ERROR(H5Arename_by_name); + } + + /* Verify the attribute has been renamed */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_RENAME_TEST_ATTR_NAME2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + PART_ERROR(H5Arename_by_name); + } + + if (attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not get renamed!\n"); + PART_ERROR(H5Arename_by_name); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_RENAME_TEST_NEW_NAME2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + PART_ERROR(H5Arename_by_name); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not get renamed!\n"); + PART_ERROR(H5Arename_by_name); + } + + PASSED(); + } + PART_END(H5Arename_by_name); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(attr_space_id) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype) < 0) + TEST_ERROR; + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + if (H5Aclose(attr_id2) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(attr_space_id); + H5Tclose(attr_dtype); + H5Aclose(attr_id); + H5Aclose(attr_id2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that an attribute can't be renamed + * when H5Arename(_by_name) is passed invalid parameters. + */ +static int +test_rename_attribute_invalid_params(void) +{ + htri_t attr_exists; + herr_t err_ret = -1; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID, attr_id2 = H5I_INVALID_HID; + hid_t attr_dtype = H5I_INVALID_HID; + hid_t attr_space_id = H5I_INVALID_HID; + + TESTING_MULTIPART("attribute renaming with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_MORE)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or attribute aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", ATTRIBUTE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", + ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_GROUP_NAME); + goto error; + } + + if ((attr_space_id = generate_random_dataspace(ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_SPACE_RANK, NULL, + NULL, TRUE)) < 0) + TEST_ERROR; + + if ((attr_dtype = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_ATTR_NAME, attr_dtype, + attr_space_id, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute\n"); + goto error; + } + + if ((attr_id2 = H5Acreate2(group_id, ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_ATTR_NAME2, attr_dtype, + attr_space_id, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute\n"); + goto error; + } + + /* Verify the attributes have been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not exist\n"); + goto error; + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_ATTR_NAME2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not exist\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Arename_invalid_loc_id) + { + TESTING_2("H5Arename with an invalid loc_id"); + + H5E_BEGIN_TRY + { + err_ret = H5Arename(H5I_INVALID_HID, ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_ATTR_NAME, + ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_NEW_NAME); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" renamed attribute using H5Arename with an invalid loc_id!\n"); + PART_ERROR(H5Arename_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Arename_invalid_loc_id); + + PART_BEGIN(H5Arename_invalid_old_attr_name) + { + TESTING_2("H5Arename with an invalid old attribute name"); + + H5E_BEGIN_TRY + { + err_ret = H5Arename(group_id, NULL, ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_NEW_NAME); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" renamed attribute using H5Arename with a NULL old attribute name!\n"); + PART_ERROR(H5Arename_invalid_old_attr_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Arename(group_id, "", ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_NEW_NAME); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" renamed attribute using H5Arename with an invalid old attribute name of ''!\n"); + PART_ERROR(H5Arename_invalid_old_attr_name); + } + + PASSED(); + } + PART_END(H5Arename_invalid_old_attr_name); + + PART_BEGIN(H5Arename_invalid_new_attr_name) + { + TESTING_2("H5Arename with an invalid new attribute name"); + + H5E_BEGIN_TRY + { + err_ret = H5Arename(group_id, ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_ATTR_NAME, NULL); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" renamed attribute using H5Arename with a NULL new attribute name!\n"); + PART_ERROR(H5Arename_invalid_new_attr_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Arename(group_id, ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_ATTR_NAME, ""); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" renamed attribute using H5Arename with an invalid new attribute name of ''!\n"); + PART_ERROR(H5Arename_invalid_new_attr_name); + } + + PASSED(); + } + PART_END(H5Arename_invalid_new_attr_name); + + PART_BEGIN(H5Arename_by_name_invalid_loc_id) + { + TESTING_2("H5Arename_by_name with an invalid loc_id"); + + H5E_BEGIN_TRY + { + err_ret = + H5Arename_by_name(H5I_INVALID_HID, ".", ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_ATTR_NAME, + ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_NEW_NAME, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" renamed attribute using H5Arename_by_name with an invalid loc_id!\n"); + PART_ERROR(H5Arename_by_name_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Arename_by_name_invalid_loc_id); + + PART_BEGIN(H5Arename_by_name_invalid_obj_name) + { + TESTING_2("H5Arename_by_name with an invalid object name"); + + H5E_BEGIN_TRY + { + err_ret = H5Arename_by_name(group_id, NULL, ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_ATTR_NAME, + ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_NEW_NAME, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" renamed attribute using H5Arename_by_name with a NULL object name!\n"); + PART_ERROR(H5Arename_by_name_invalid_obj_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Arename_by_name(group_id, "", ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_ATTR_NAME, + ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_NEW_NAME, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf( + " renamed attribute using H5Arename_by_name with an invalid object name of ''!\n"); + PART_ERROR(H5Arename_by_name_invalid_obj_name); + } + + PASSED(); + } + PART_END(H5Arename_by_name_invalid_obj_name); + + PART_BEGIN(H5Arename_by_name_invalid_old_attr_name) + { + TESTING_2("H5Arename_by_name with an invalid old attribute name"); + + H5E_BEGIN_TRY + { + err_ret = H5Arename_by_name(group_id, ".", NULL, + ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_NEW_NAME, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" renamed attribute using H5Arename_by_name with a NULL old attribute name!\n"); + PART_ERROR(H5Arename_by_name_invalid_old_attr_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Arename_by_name(group_id, ".", "", ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_NEW_NAME, + H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" renamed attribute using H5Arename_by_name with an invalid old attribute name " + "of ''!\n"); + PART_ERROR(H5Arename_by_name_invalid_old_attr_name); + } + + PASSED(); + } + PART_END(H5Arename_by_name_invalid_old_attr_name); + + PART_BEGIN(H5Arename_by_name_invalid_new_attr_name) + { + TESTING_2("H5Arename_by_name with an invalid new attribute name"); + + H5E_BEGIN_TRY + { + err_ret = H5Arename_by_name(group_id, ".", ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_ATTR_NAME, + NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" renamed attribute using H5Arename_by_name with a NULL new attribute name!\n"); + PART_ERROR(H5Arename_by_name_invalid_new_attr_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Arename_by_name(group_id, ".", ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_ATTR_NAME, "", + H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" renamed attribute using H5Arename_by_name with an invalid new attribute name " + "of ''!\n"); + PART_ERROR(H5Arename_by_name_invalid_new_attr_name); + } + + PASSED(); + } + PART_END(H5Arename_by_name_invalid_new_attr_name); + + PART_BEGIN(H5Arename_by_name_invalid_lapl) + { + TESTING_2("H5Arename_by_name with an invalid LAPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Arename_by_name(group_id, ".", ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_ATTR_NAME, + ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_NEW_NAME, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" renamed attribute using H5Arename_by_name with an invalid LAPL!\n"); + PART_ERROR(H5Arename_by_name_invalid_lapl); + } + + PASSED(); + } + PART_END(H5Arename_by_name_invalid_lapl); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(attr_space_id) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype) < 0) + TEST_ERROR; + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + if (H5Aclose(attr_id2) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(attr_space_id); + H5Tclose(attr_dtype); + H5Aclose(attr_id); + H5Aclose(attr_id2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check the functionality of attribute + * iteration using H5Aiterate(_by_name) on a group. + * Iteration is done in increasing and decreasing + * order of both attribute name and attribute + * creation order. + */ +static int +test_attribute_iterate_group(void) +{ + size_t link_counter; + size_t i; + htri_t attr_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t attr_dtype = H5I_INVALID_HID; + hid_t attr_space_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + + TESTING_MULTIPART("attribute iteration on a group"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ITERATE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, attribute, iterate, or creation order aren't " + "supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group\n"); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create GCPL for attribute creation order tracking\n"); + goto error; + } + + if (H5Pset_attr_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED) < 0) { + H5_FAILED(); + HDprintf(" couldn't set attribute creation order tracking\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_ITERATE_TEST_GRP_SUBGROUP_NAME, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", ATTRIBUTE_ITERATE_TEST_GRP_SUBGROUP_NAME); + goto error; + } + + if ((attr_dtype = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + if ((attr_space_id = + generate_random_dataspace(ATTRIBUTE_ITERATE_TEST_ATTR_SPACE_RANK, NULL, NULL, TRUE)) < 0) + TEST_ERROR; + + /* Create some attributes with a reverse-ordering naming scheme to test creation order */ + for (i = 0; i < ATTRIBUTE_ITERATE_TEST_NUM_ATTRS; i++) { + char attr_name[ATTRIBUTE_ITERATE_TEST_ATTR_NAME_BUF_SIZE]; + + HDsnprintf(attr_name, ATTRIBUTE_ITERATE_TEST_ATTR_NAME_BUF_SIZE, + ATTRIBUTE_ITERATE_TEST_ATTR_NAME "%d", (int)(ATTRIBUTE_ITERATE_TEST_NUM_ATTRS - i - 1)); + + if ((attr_id = H5Acreate2(group_id, attr_name, attr_dtype, attr_space_id, H5P_DEFAULT, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s'\n", attr_name); + goto error; + } + + /* Verify the attribute has been created */ + if ((attr_exists = H5Aexists(group_id, attr_name)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", attr_name); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' did not exist\n", attr_name); + goto error; + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close attribute '%s'\n", attr_name); + goto error; + } + } + + PASSED(); + + BEGIN_MULTIPART + { + /* + * NOTE: A counter is passed to the iteration callback to try to match up the + * expected attributes with a given step throughout all of the following + * iterations. Since the only information we can count on in the attribute + * iteration callback is the attribute's name, we need some other way of + * ensuring that the attributes are coming back in the correct order. + */ + + PART_BEGIN(H5Aiterate2_name_increasing) + { + TESTING_2("H5Aiterate by attribute name in increasing order"); + + link_counter = 0; + + /* Test basic attribute iteration capability using both index types and both index orders */ + if (H5Aiterate2(group_id, H5_INDEX_NAME, H5_ITER_INC, NULL, attr_iter_callback1, &link_counter) < + 0) { + H5_FAILED(); + HDprintf(" H5Aiterate2 by index type name in increasing order failed\n"); + PART_ERROR(H5Aiterate2_name_increasing); + } + + /* Make sure that the attribute iteration callback was actually called */ + if (link_counter == 0) { + H5_FAILED(); + HDprintf(" H5Aiterate sentinel value is unchanged; supplied callback function must not " + "have been called!\n"); + PART_ERROR(H5Aiterate2_name_increasing); + } + + PASSED(); + } + PART_END(H5Aiterate2_name_increasing); + + PART_BEGIN(H5Aiterate2_name_decreasing) + { + TESTING_2("H5Aiterate by attribute name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + link_counter = ATTRIBUTE_ITERATE_TEST_NUM_ATTRS; + + if (H5Aiterate2(group_id, H5_INDEX_NAME, H5_ITER_DEC, NULL, attr_iter_callback1, &link_counter) < + 0) { + H5_FAILED(); + HDprintf(" H5Aiterate2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Aiterate2_name_decreasing); + } + + /* Make sure that the attribute iteration callback was actually called */ + if (link_counter == ATTRIBUTE_ITERATE_TEST_NUM_ATTRS) { + H5_FAILED(); + HDprintf(" H5Aiterate sentinel value is unchanged; supplied callback function must not " + "have been called!\n"); + PART_ERROR(H5Aiterate2_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Aiterate2_name_decreasing); +#endif + } + PART_END(H5Aiterate2_name_decreasing); + + PART_BEGIN(H5Aiterate2_creation_increasing) + { + TESTING_2("H5Aiterate by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + link_counter = 2 * ATTRIBUTE_ITERATE_TEST_NUM_ATTRS; + + if (H5Aiterate2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_INC, NULL, attr_iter_callback1, + &link_counter) < 0) { + H5_FAILED(); + HDprintf(" H5Aiterate2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Aiterate2_creation_increasing); + } + + /* Make sure that the attribute iteration callback was actually called */ + if (link_counter == 2 * ATTRIBUTE_ITERATE_TEST_NUM_ATTRS) { + H5_FAILED(); + HDprintf(" H5Aiterate sentinel value is unchanged; supplied callback function must not " + "have been called!\n"); + PART_ERROR(H5Aiterate2_creation_increasing); + } + + PASSED(); + } + PART_END(H5Aiterate2_creation_increasing); + + PART_BEGIN(H5Aiterate2_creation_decreasing) + { + TESTING_2("H5Aiterate by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + link_counter = 3 * ATTRIBUTE_ITERATE_TEST_NUM_ATTRS; + + if (H5Aiterate2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_DEC, NULL, attr_iter_callback1, + &link_counter) < 0) { + H5_FAILED(); + HDprintf(" H5Aiterate2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Aiterate2_creation_decreasing); + } + + /* Make sure that the attribute iteration callback was actually called */ + if (link_counter == 3 * ATTRIBUTE_ITERATE_TEST_NUM_ATTRS) { + H5_FAILED(); + HDprintf(" H5Aiterate sentinel value is unchanged; supplied callback function must not " + "have been called!\n"); + PART_ERROR(H5Aiterate2_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Aiterate2_creation_decreasing); + + PART_BEGIN(H5Aiterate_by_name_name_increasing) + { + TESTING_2("H5Aiterate_by_name by attribute name in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + link_counter = 0; + + if (H5Aiterate_by_name( + file_id, "/" ATTRIBUTE_TEST_GROUP_NAME "/" ATTRIBUTE_ITERATE_TEST_GRP_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_INC, NULL, attr_iter_callback1, &link_counter, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Aiterate_by_name by index type name in increasing order failed\n"); + PART_ERROR(H5Aiterate_by_name_name_increasing); + } + + /* Make sure that the attribute iteration callback was actually called */ + if (link_counter == 0) { + H5_FAILED(); + HDprintf(" H5Aiterate_by_name sentinel value is unchanged; supplied callback function " + "must not have been called!\n"); + PART_ERROR(H5Aiterate_by_name_name_increasing); + } + + PASSED(); + } + PART_END(H5Aiterate_by_name_name_increasing); + + PART_BEGIN(H5Aiterate_by_name_name_decreasing) + { + TESTING_2("H5Aiterate_by_name by attribute name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + link_counter = ATTRIBUTE_ITERATE_TEST_NUM_ATTRS; + + if (H5Aiterate_by_name( + file_id, "/" ATTRIBUTE_TEST_GROUP_NAME "/" ATTRIBUTE_ITERATE_TEST_GRP_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_DEC, NULL, attr_iter_callback1, &link_counter, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Aiterate_by_name by index type name in decreasing order failed\n"); + PART_ERROR(H5Aiterate_by_name_name_decreasing); + } + + /* Make sure that the attribute iteration callback was actually called */ + if (link_counter == ATTRIBUTE_ITERATE_TEST_NUM_ATTRS) { + H5_FAILED(); + HDprintf(" H5Aiterate_by_name sentinel value is unchanged; supplied callback function " + "must not have been called!\n"); + PART_ERROR(H5Aiterate_by_name_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Aiterate_by_name_name_decreasing); +#endif + } + PART_END(H5Aiterate_by_name_name_decreasing); + + PART_BEGIN(H5Aiterate_by_name_creation_increasing) + { + TESTING_2("H5Aiterate_by_name by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + link_counter = 2 * ATTRIBUTE_ITERATE_TEST_NUM_ATTRS; + + if (H5Aiterate_by_name(file_id, + "/" ATTRIBUTE_TEST_GROUP_NAME "/" ATTRIBUTE_ITERATE_TEST_GRP_SUBGROUP_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_INC, NULL, attr_iter_callback1, &link_counter, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Aiterate_by_name by index type creation order in increasing order failed\n"); + PART_ERROR(H5Aiterate_by_name_creation_increasing); + } + + /* Make sure that the attribute iteration callback was actually called */ + if (link_counter == 2 * ATTRIBUTE_ITERATE_TEST_NUM_ATTRS) { + H5_FAILED(); + HDprintf(" H5Aiterate_by_name sentinel value is unchanged; supplied callback function " + "must not have been called!\n"); + PART_ERROR(H5Aiterate_by_name_creation_increasing); + } + + PASSED(); + } + PART_END(H5Aiterate_by_name_creation_increasing); + + PART_BEGIN(H5Aiterate_by_name_creation_decreasing) + { + TESTING_2("H5Aiterate_by_name by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + link_counter = 3 * ATTRIBUTE_ITERATE_TEST_NUM_ATTRS; + + if (H5Aiterate_by_name(file_id, + "/" ATTRIBUTE_TEST_GROUP_NAME "/" ATTRIBUTE_ITERATE_TEST_GRP_SUBGROUP_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_DEC, NULL, attr_iter_callback1, &link_counter, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Aiterate_by_name by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Aiterate_by_name_creation_decreasing); + } + + /* Make sure that the attribute iteration callback was actually called */ + if (link_counter == 3 * ATTRIBUTE_ITERATE_TEST_NUM_ATTRS) { + H5_FAILED(); + HDprintf(" H5Aiterate_by_name sentinel value is unchanged; supplied callback function " + "must not have been called!\n"); + PART_ERROR(H5Aiterate_by_name_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Aiterate_by_name_creation_decreasing); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(attr_space_id) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype) < 0) + TEST_ERROR; + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(attr_space_id); + H5Tclose(attr_dtype); + H5Aclose(attr_id); + H5Pclose(gcpl_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check the functionality of attribute + * iteration using H5Aiterate(_by_name) on a dataset. + * Iteration is done in increasing and decreasing + * order of both attribute name and attribute + * creation order. + */ +static int +test_attribute_iterate_dataset(void) +{ + size_t link_counter; + size_t i; + htri_t attr_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t attr_dtype = H5I_INVALID_HID; + hid_t dset_space_id = H5I_INVALID_HID; + hid_t attr_space_id = H5I_INVALID_HID; + hid_t dcpl_id = H5I_INVALID_HID; + + TESTING_MULTIPART("attribute iteration on a dataset"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ITERATE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, attribute, iterate, or creation order " + "aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_ITERATE_TEST_DSET_SUBGROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", ATTRIBUTE_ITERATE_TEST_DSET_SUBGROUP_NAME); + goto error; + } + + if ((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create DCPL for attribute creation order tracking\n"); + goto error; + } + + if (H5Pset_attr_creation_order(dcpl_id, H5P_CRT_ORDER_TRACKED) < 0) { + H5_FAILED(); + HDprintf(" couldn't set attribute creation order tracking\n"); + goto error; + } + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + if ((attr_dtype = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + if ((dset_space_id = + generate_random_dataspace(ATTRIBUTE_ITERATE_TEST_DSET_SPACE_RANK, NULL, NULL, FALSE)) < 0) + TEST_ERROR; + if ((attr_space_id = + generate_random_dataspace(ATTRIBUTE_ITERATE_TEST_ATTR_SPACE_RANK, NULL, NULL, TRUE)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, ATTRIBUTE_ITERATE_TEST_DSET_NAME, dset_dtype, dset_space_id, + H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", ATTRIBUTE_ITERATE_TEST_DSET_NAME); + goto error; + } + + /* Create some attributes with a reverse-ordering naming scheme to test creation order */ + for (i = 0; i < ATTRIBUTE_ITERATE_TEST_NUM_ATTRS; i++) { + char attr_name[ATTRIBUTE_ITERATE_TEST_ATTR_NAME_BUF_SIZE]; + + HDsnprintf(attr_name, ATTRIBUTE_ITERATE_TEST_ATTR_NAME_BUF_SIZE, + ATTRIBUTE_ITERATE_TEST_ATTR_NAME "%d", (int)(ATTRIBUTE_ITERATE_TEST_NUM_ATTRS - i - 1)); + + if ((attr_id = H5Acreate2(dset_id, attr_name, attr_dtype, attr_space_id, H5P_DEFAULT, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s'\n", attr_name); + goto error; + } + + /* Verify the attribute has been created */ + if ((attr_exists = H5Aexists(dset_id, attr_name)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", attr_name); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' did not exist\n", attr_name); + goto error; + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close attribute '%s'\n", attr_name); + goto error; + } + } + + PASSED(); + + BEGIN_MULTIPART + { + /* + * NOTE: A counter is passed to the iteration callback to try to match up the + * expected attributes with a given step throughout all of the following + * iterations. Since the only information we can count on in the attribute + * iteration callback is the attribute's name, we need some other way of + * ensuring that the attributes are coming back in the correct order. + */ + + PART_BEGIN(H5Aiterate2_name_increasing) + { + TESTING_2("H5Aiterate by attribute name in increasing order"); + + link_counter = 0; + + /* Test basic attribute iteration capability using both index types and both index orders */ + if (H5Aiterate2(dset_id, H5_INDEX_NAME, H5_ITER_INC, NULL, attr_iter_callback1, &link_counter) < + 0) { + H5_FAILED(); + HDprintf(" H5Aiterate2 by index type name in increasing order failed\n"); + PART_ERROR(H5Aiterate2_name_increasing); + } + + /* Make sure that the attribute iteration callback was actually called */ + if (link_counter == 0) { + H5_FAILED(); + HDprintf(" H5Aiterate sentinel value is unchanged; supplied callback function must not " + "have been called!\n"); + PART_ERROR(H5Aiterate2_name_increasing); + } + + PASSED(); + } + PART_END(H5Aiterate2_name_increasing); + + PART_BEGIN(H5Aiterate2_name_decreasing) + { + TESTING_2("H5Aiterate by attribute name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + link_counter = ATTRIBUTE_ITERATE_TEST_NUM_ATTRS; + + if (H5Aiterate2(dset_id, H5_INDEX_NAME, H5_ITER_DEC, NULL, attr_iter_callback1, &link_counter) < + 0) { + H5_FAILED(); + HDprintf(" H5Aiterate2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Aiterate2_name_decreasing); + } + + /* Make sure that the attribute iteration callback was actually called */ + if (link_counter == ATTRIBUTE_ITERATE_TEST_NUM_ATTRS) { + H5_FAILED(); + HDprintf(" H5Aiterate sentinel value is unchanged; supplied callback function must not " + "have been called!\n"); + PART_ERROR(H5Aiterate2_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Aiterate2_name_decreasing); +#endif + } + PART_END(H5Aiterate2_name_decreasing); + + PART_BEGIN(H5Aiterate2_creation_increasing) + { + TESTING_2("H5Aiterate by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + link_counter = 2 * ATTRIBUTE_ITERATE_TEST_NUM_ATTRS; + + if (H5Aiterate2(dset_id, H5_INDEX_CRT_ORDER, H5_ITER_INC, NULL, attr_iter_callback1, + &link_counter) < 0) { + H5_FAILED(); + HDprintf(" H5Aiterate2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Aiterate2_creation_increasing); + } + + /* Make sure that the attribute iteration callback was actually called */ + if (link_counter == 2 * ATTRIBUTE_ITERATE_TEST_NUM_ATTRS) { + H5_FAILED(); + HDprintf(" H5Aiterate sentinel value is unchanged; supplied callback function must not " + "have been called!\n"); + PART_ERROR(H5Aiterate2_creation_increasing); + } + + PASSED(); + } + PART_END(H5Aiterate2_creation_increasing); + + PART_BEGIN(H5Aiterate2_creation_decreasing) + { + TESTING_2("H5Aiterate by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + link_counter = 3 * ATTRIBUTE_ITERATE_TEST_NUM_ATTRS; + + if (H5Aiterate2(dset_id, H5_INDEX_CRT_ORDER, H5_ITER_DEC, NULL, attr_iter_callback1, + &link_counter) < 0) { + H5_FAILED(); + HDprintf(" H5Aiterate2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Aiterate2_creation_decreasing); + } + + /* Make sure that the attribute iteration callback was actually called */ + if (link_counter == 3 * ATTRIBUTE_ITERATE_TEST_NUM_ATTRS) { + H5_FAILED(); + HDprintf(" H5Aiterate sentinel value is unchanged; supplied callback function must not " + "have been called!\n"); + PART_ERROR(H5Aiterate2_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Aiterate2_creation_decreasing); + + PART_BEGIN(H5Aiterate_by_name_name_increasing) + { + TESTING_2("H5Aiterate_by_name by attribute name in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + link_counter = 0; + + if (H5Aiterate_by_name(file_id, + "/" ATTRIBUTE_TEST_GROUP_NAME "/" ATTRIBUTE_ITERATE_TEST_DSET_SUBGROUP_NAME + "/" ATTRIBUTE_ITERATE_TEST_DSET_NAME, + H5_INDEX_NAME, H5_ITER_INC, NULL, attr_iter_callback1, &link_counter, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Aiterate_by_name by index type name in increasing order failed\n"); + PART_ERROR(H5Aiterate_by_name_name_increasing); + } + + /* Make sure that the attribute iteration callback was actually called */ + if (link_counter == 0) { + H5_FAILED(); + HDprintf(" H5Aiterate_by_name sentinel value is unchanged; supplied callback function " + "must not have been called!\n"); + PART_ERROR(H5Aiterate_by_name_name_increasing); + } + + PASSED(); + } + PART_END(H5Aiterate_by_name_name_increasing); + + PART_BEGIN(H5Aiterate_by_name_name_decreasing) + { + TESTING_2("H5Aiterate_by_name by attribute name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + link_counter = ATTRIBUTE_ITERATE_TEST_NUM_ATTRS; + + if (H5Aiterate_by_name(file_id, + "/" ATTRIBUTE_TEST_GROUP_NAME "/" ATTRIBUTE_ITERATE_TEST_DSET_SUBGROUP_NAME + "/" ATTRIBUTE_ITERATE_TEST_DSET_NAME, + H5_INDEX_NAME, H5_ITER_DEC, NULL, attr_iter_callback1, &link_counter, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Aiterate_by_name by index type name in decreasing order failed\n"); + PART_ERROR(H5Aiterate_by_name_name_decreasing); + } + + /* Make sure that the attribute iteration callback was actually called */ + if (link_counter == ATTRIBUTE_ITERATE_TEST_NUM_ATTRS) { + H5_FAILED(); + HDprintf(" H5Aiterate_by_name sentinel value is unchanged; supplied callback function " + "must not have been called!\n"); + PART_ERROR(H5Aiterate_by_name_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Aiterate_by_name_name_decreasing); +#endif + } + PART_END(H5Aiterate_by_name_name_decreasing); + + PART_BEGIN(H5Aiterate_by_name_creation_increasing) + { + TESTING_2("H5Aiterate_by_name by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + link_counter = 2 * ATTRIBUTE_ITERATE_TEST_NUM_ATTRS; + + if (H5Aiterate_by_name(file_id, + "/" ATTRIBUTE_TEST_GROUP_NAME "/" ATTRIBUTE_ITERATE_TEST_DSET_SUBGROUP_NAME + "/" ATTRIBUTE_ITERATE_TEST_DSET_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_INC, NULL, attr_iter_callback1, &link_counter, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Aiterate_by_name by index type creation order in increasing order failed\n"); + PART_ERROR(H5Aiterate_by_name_creation_increasing); + } + + /* Make sure that the attribute iteration callback was actually called */ + if (link_counter == 2 * ATTRIBUTE_ITERATE_TEST_NUM_ATTRS) { + H5_FAILED(); + HDprintf(" H5Aiterate_by_name sentinel value is unchanged; supplied callback function " + "must not have been called!\n"); + PART_ERROR(H5Aiterate_by_name_creation_increasing); + } + + PASSED(); + } + PART_END(H5Aiterate_by_name_creation_increasing); + + PART_BEGIN(H5Aiterate_by_name_creation_decreasing) + { + TESTING_2("H5Aiterate_by_name by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + link_counter = 3 * ATTRIBUTE_ITERATE_TEST_NUM_ATTRS; + + if (H5Aiterate_by_name(file_id, + "/" ATTRIBUTE_TEST_GROUP_NAME "/" ATTRIBUTE_ITERATE_TEST_DSET_SUBGROUP_NAME + "/" ATTRIBUTE_ITERATE_TEST_DSET_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_DEC, NULL, attr_iter_callback1, &link_counter, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Aiterate_by_name by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Aiterate_by_name_creation_decreasing); + } + + /* Make sure that the attribute iteration callback was actually called */ + if (link_counter == 3 * ATTRIBUTE_ITERATE_TEST_NUM_ATTRS) { + H5_FAILED(); + HDprintf(" H5Aiterate_by_name sentinel value is unchanged; supplied callback function " + "must not have been called!\n"); + PART_ERROR(H5Aiterate_by_name_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Aiterate_by_name_creation_decreasing); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Pclose(dcpl_id) < 0) + TEST_ERROR; + if (H5Sclose(attr_space_id) < 0) + TEST_ERROR; + if (H5Sclose(dset_space_id) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(dcpl_id); + H5Sclose(attr_space_id); + H5Sclose(dset_space_id); + H5Tclose(attr_dtype); + H5Tclose(dset_dtype); + H5Aclose(attr_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check the functionality of attribute + * iteration using H5Aiterate(_by_name) on a committed + * datatype. Iteration is done in increasing and + * decreasing order of both attribute name and attribute + * creation order. + */ +static int +test_attribute_iterate_datatype(void) +{ + size_t link_counter; + size_t i; + htri_t attr_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t type_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t attr_dtype = H5I_INVALID_HID; + hid_t attr_space_id = H5I_INVALID_HID; + hid_t tcpl_id = H5I_INVALID_HID; + + TESTING_MULTIPART("attribute iteration on a committed datatype"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ITERATE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, stored datatype, attribute, iterate, or creation " + "order aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_ITERATE_TEST_DTYPE_SUBGROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", ATTRIBUTE_ITERATE_TEST_DTYPE_SUBGROUP_NAME); + goto error; + } + + if ((tcpl_id = H5Pcreate(H5P_DATATYPE_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create TCPL for attribute creation order tracking\n"); + goto error; + } + + if (H5Pset_attr_creation_order(tcpl_id, H5P_CRT_ORDER_TRACKED) < 0) { + H5_FAILED(); + HDprintf(" couldn't set attribute creation order tracking\n"); + goto error; + } + + if ((type_id = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + if ((attr_dtype = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + if ((attr_space_id = + generate_random_dataspace(ATTRIBUTE_ITERATE_TEST_ATTR_SPACE_RANK, NULL, NULL, TRUE)) < 0) + TEST_ERROR; + + if (H5Tcommit2(group_id, ATTRIBUTE_ITERATE_TEST_DTYPE_NAME, type_id, H5P_DEFAULT, tcpl_id, H5P_DEFAULT) < + 0) { + H5_FAILED(); + HDprintf(" couldn't commit datatype '%s'\n", ATTRIBUTE_ITERATE_TEST_DTYPE_NAME); + goto error; + } + + /* Create some attributes with a reverse-ordering naming scheme to test creation order */ + for (i = 0; i < ATTRIBUTE_ITERATE_TEST_NUM_ATTRS; i++) { + char attr_name[ATTRIBUTE_ITERATE_TEST_ATTR_NAME_BUF_SIZE]; + + HDsnprintf(attr_name, ATTRIBUTE_ITERATE_TEST_ATTR_NAME_BUF_SIZE, + ATTRIBUTE_ITERATE_TEST_ATTR_NAME "%d", (int)(ATTRIBUTE_ITERATE_TEST_NUM_ATTRS - i - 1)); + + if ((attr_id = H5Acreate2(type_id, attr_name, attr_dtype, attr_space_id, H5P_DEFAULT, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s'\n", attr_name); + goto error; + } + + /* Verify the attribute has been created */ + if ((attr_exists = H5Aexists(type_id, attr_name)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", attr_name); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' did not exist\n", attr_name); + goto error; + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close attribute '%s'\n", attr_name); + goto error; + } + } + + PASSED(); + + BEGIN_MULTIPART + { + /* + * NOTE: A counter is passed to the iteration callback to try to match up the + * expected attributes with a given step throughout all of the following + * iterations. Since the only information we can count on in the attribute + * iteration callback is the attribute's name, we need some other way of + * ensuring that the attributes are coming back in the correct order. + */ + + PART_BEGIN(H5Aiterate2_name_increasing) + { + TESTING_2("H5Aiterate by attribute name in increasing order"); + + link_counter = 0; + + /* Test basic attribute iteration capability using both index types and both index orders */ + if (H5Aiterate2(type_id, H5_INDEX_NAME, H5_ITER_INC, NULL, attr_iter_callback1, &link_counter) < + 0) { + H5_FAILED(); + HDprintf(" H5Aiterate2 by index type name in increasing order failed\n"); + PART_ERROR(H5Aiterate2_name_increasing); + } + + /* Make sure that the attribute iteration callback was actually called */ + if (link_counter == 0) { + H5_FAILED(); + HDprintf(" H5Aiterate sentinel value is unchanged; supplied callback function must not " + "have been called!\n"); + PART_ERROR(H5Aiterate2_name_increasing); + } + + PASSED(); + } + PART_END(H5Aiterate2_name_increasing); + + PART_BEGIN(H5Aiterate2_name_decreasing) + { + TESTING_2("H5Aiterate by attribute name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + link_counter = ATTRIBUTE_ITERATE_TEST_NUM_ATTRS; + + if (H5Aiterate2(type_id, H5_INDEX_NAME, H5_ITER_DEC, NULL, attr_iter_callback1, &link_counter) < + 0) { + H5_FAILED(); + HDprintf(" H5Aiterate2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Aiterate2_name_decreasing); + } + + /* Make sure that the attribute iteration callback was actually called */ + if (link_counter == ATTRIBUTE_ITERATE_TEST_NUM_ATTRS) { + H5_FAILED(); + HDprintf(" H5Aiterate sentinel value is unchanged; supplied callback function must not " + "have been called!\n"); + PART_ERROR(H5Aiterate2_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Aiterate2_name_decreasing); +#endif + } + PART_END(H5Aiterate2_name_decreasing); + + PART_BEGIN(H5Aiterate2_creation_increasing) + { + TESTING_2("H5Aiterate by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + link_counter = 2 * ATTRIBUTE_ITERATE_TEST_NUM_ATTRS; + + if (H5Aiterate2(type_id, H5_INDEX_CRT_ORDER, H5_ITER_INC, NULL, attr_iter_callback1, + &link_counter) < 0) { + H5_FAILED(); + HDprintf(" H5Aiterate2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Aiterate2_creation_increasing); + } + + /* Make sure that the attribute iteration callback was actually called */ + if (link_counter == 2 * ATTRIBUTE_ITERATE_TEST_NUM_ATTRS) { + H5_FAILED(); + HDprintf(" H5Aiterate sentinel value is unchanged; supplied callback function must not " + "have been called!\n"); + PART_ERROR(H5Aiterate2_creation_increasing); + } + + PASSED(); + } + PART_END(H5Aiterate2_creation_increasing); + + PART_BEGIN(H5Aiterate2_creation_decreasing) + { + TESTING_2("H5Aiterate by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + link_counter = 3 * ATTRIBUTE_ITERATE_TEST_NUM_ATTRS; + + if (H5Aiterate2(type_id, H5_INDEX_CRT_ORDER, H5_ITER_DEC, NULL, attr_iter_callback1, + &link_counter) < 0) { + H5_FAILED(); + HDprintf(" H5Aiterate2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Aiterate2_creation_decreasing); + } + + /* Make sure that the attribute iteration callback was actually called */ + if (link_counter == 3 * ATTRIBUTE_ITERATE_TEST_NUM_ATTRS) { + H5_FAILED(); + HDprintf(" H5Aiterate sentinel value is unchanged; supplied callback function must not " + "have been called!\n"); + PART_ERROR(H5Aiterate2_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Aiterate2_creation_decreasing); + + PART_BEGIN(H5Aiterate_by_name_name_increasing) + { + TESTING_2("H5Aiterate_by_name by attribute name in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + link_counter = 0; + + if (H5Aiterate_by_name( + file_id, + "/" ATTRIBUTE_TEST_GROUP_NAME "/" ATTRIBUTE_ITERATE_TEST_DTYPE_SUBGROUP_NAME + "/" ATTRIBUTE_ITERATE_TEST_DTYPE_NAME, + H5_INDEX_NAME, H5_ITER_INC, NULL, attr_iter_callback1, &link_counter, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Aiterate_by_name by index type name in increasing order failed\n"); + PART_ERROR(H5Aiterate_by_name_name_increasing); + } + + /* Make sure that the attribute iteration callback was actually called */ + if (link_counter == 0) { + H5_FAILED(); + HDprintf(" H5Aiterate_by_name sentinel value is unchanged; supplied callback function " + "must not have been called!\n"); + PART_ERROR(H5Aiterate_by_name_name_increasing); + } + + PASSED(); + } + PART_END(H5Aiterate_by_name_name_increasing); + + PART_BEGIN(H5Aiterate_by_name_name_decreasing) + { + TESTING_2("H5Aiterate_by_name by attribute name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + link_counter = ATTRIBUTE_ITERATE_TEST_NUM_ATTRS; + + if (H5Aiterate_by_name( + file_id, + "/" ATTRIBUTE_TEST_GROUP_NAME "/" ATTRIBUTE_ITERATE_TEST_DTYPE_SUBGROUP_NAME + "/" ATTRIBUTE_ITERATE_TEST_DTYPE_NAME, + H5_INDEX_NAME, H5_ITER_DEC, NULL, attr_iter_callback1, &link_counter, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Aiterate_by_name by index type name in decreasing order failed\n"); + PART_ERROR(H5Aiterate_by_name_name_decreasing); + } + + /* Make sure that the attribute iteration callback was actually called */ + if (link_counter == ATTRIBUTE_ITERATE_TEST_NUM_ATTRS) { + H5_FAILED(); + HDprintf(" H5Aiterate_by_name sentinel value is unchanged; supplied callback function " + "must not have been called!\n"); + PART_ERROR(H5Aiterate_by_name_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Aiterate_by_name_name_decreasing); +#endif + } + PART_END(H5Aiterate_by_name_name_decreasing); + + PART_BEGIN(H5Aiterate_by_name_creation_increasing) + { + TESTING_2("H5Aiterate_by_name by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + link_counter = 2 * ATTRIBUTE_ITERATE_TEST_NUM_ATTRS; + + if (H5Aiterate_by_name(file_id, + "/" ATTRIBUTE_TEST_GROUP_NAME + "/" ATTRIBUTE_ITERATE_TEST_DTYPE_SUBGROUP_NAME + "/" ATTRIBUTE_ITERATE_TEST_DTYPE_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_INC, NULL, attr_iter_callback1, &link_counter, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Aiterate_by_name by index type creation order in increasing order failed\n"); + PART_ERROR(H5Aiterate_by_name_creation_increasing); + } + + /* Make sure that the attribute iteration callback was actually called */ + if (link_counter == 2 * ATTRIBUTE_ITERATE_TEST_NUM_ATTRS) { + H5_FAILED(); + HDprintf(" H5Aiterate_by_name sentinel value is unchanged; supplied callback function " + "must not have been called!\n"); + PART_ERROR(H5Aiterate_by_name_creation_increasing); + } + + PASSED(); + } + PART_END(H5Aiterate_by_name_creation_increasing); + + PART_BEGIN(H5Aiterate_by_name_creation_decreasing) + { + TESTING_2("H5Aiterate_by_name by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + link_counter = 3 * ATTRIBUTE_ITERATE_TEST_NUM_ATTRS; + + if (H5Aiterate_by_name(file_id, + "/" ATTRIBUTE_TEST_GROUP_NAME + "/" ATTRIBUTE_ITERATE_TEST_DTYPE_SUBGROUP_NAME + "/" ATTRIBUTE_ITERATE_TEST_DTYPE_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_DEC, NULL, attr_iter_callback1, &link_counter, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Aiterate_by_name by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Aiterate_by_name_creation_decreasing); + } + + /* Make sure that the attribute iteration callback was actually called */ + if (link_counter == 3 * ATTRIBUTE_ITERATE_TEST_NUM_ATTRS) { + H5_FAILED(); + HDprintf(" H5Aiterate_by_name sentinel value is unchanged; supplied callback function " + "must not have been called!\n"); + PART_ERROR(H5Aiterate_by_name_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Aiterate_by_name_creation_decreasing); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Pclose(tcpl_id) < 0) + TEST_ERROR; + if (H5Sclose(attr_space_id) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype) < 0) + TEST_ERROR; + if (H5Tclose(type_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(tcpl_id); + H5Sclose(attr_space_id); + H5Tclose(attr_dtype); + H5Tclose(type_id); + H5Aclose(attr_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check the functionality of attribute + * iteration index saving using H5Aiterate(_by_name). + * Iteration is done in increasing and decreasing + * order of both attribute name and attribute + * creation order. + */ +static int +test_attribute_iterate_index_saving(void) +{ + TESTING("attribute iteration index saving capability"); + + SKIPPED(); + + return 1; +} + +/* + * A test to check that an object's attributes can't + * be iterated over when H5Aiterate(_by_name) is + * passed invalid parameters. + */ +static int +test_attribute_iterate_invalid_params(void) +{ + herr_t err_ret = -1; + htri_t attr_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID, attr_id2 = H5I_INVALID_HID, attr_id3 = H5I_INVALID_HID, + attr_id4 = H5I_INVALID_HID; + hid_t attr_dtype = H5I_INVALID_HID; + hid_t attr_space_id = H5I_INVALID_HID; + + TESTING_MULTIPART("attribute iteration with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ITERATE)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, attribute, or iterate aren't supported with this " + "connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file\n"); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_ITERATE_INVALID_PARAMS_TEST_SUBGROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup\n"); + goto error; + } + + if ((attr_dtype = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + if ((attr_space_id = generate_random_dataspace(ATTRIBUTE_ITERATE_INVALID_PARAMS_TEST_ATTR_SPACE_RANK, + NULL, NULL, TRUE)) < 0) + TEST_ERROR; + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_ITERATE_INVALID_PARAMS_TEST_ATTR_NAME, attr_dtype, + attr_space_id, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute\n"); + goto error; + } + + if ((attr_id2 = H5Acreate2(group_id, ATTRIBUTE_ITERATE_INVALID_PARAMS_TEST_ATTR_NAME2, attr_dtype, + attr_space_id, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute\n"); + goto error; + } + + if ((attr_id3 = H5Acreate2(group_id, ATTRIBUTE_ITERATE_INVALID_PARAMS_TEST_ATTR_NAME3, attr_dtype, + attr_space_id, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute\n"); + goto error; + } + + if ((attr_id4 = H5Acreate2(group_id, ATTRIBUTE_ITERATE_INVALID_PARAMS_TEST_ATTR_NAME4, attr_dtype, + attr_space_id, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute\n"); + goto error; + } + + /* Verify the attributes have been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_ITERATE_INVALID_PARAMS_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not exist\n"); + goto error; + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_ITERATE_INVALID_PARAMS_TEST_ATTR_NAME2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not exist\n"); + goto error; + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_ITERATE_INVALID_PARAMS_TEST_ATTR_NAME3)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not exist\n"); + goto error; + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_ITERATE_INVALID_PARAMS_TEST_ATTR_NAME4)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not exist\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Aiterate_invalid_loc_id) + { + TESTING_2("H5Aiterate with an invalid loc_id"); + + H5E_BEGIN_TRY + { + err_ret = + H5Aiterate2(H5I_INVALID_HID, H5_INDEX_NAME, H5_ITER_INC, NULL, attr_iter_callback2, NULL); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" iterated over attributes using H5Aiterate with an invalid loc_id!\n"); + PART_ERROR(H5Aiterate_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Aiterate_invalid_loc_id); + + PART_BEGIN(H5Aiterate_invalid_index_type) + { + TESTING_2("H5Aiterate with an invalid index type"); + + H5E_BEGIN_TRY + { + err_ret = + H5Aiterate2(group_id, H5_INDEX_UNKNOWN, H5_ITER_INC, NULL, attr_iter_callback2, NULL); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" iterated over attributes using H5Aiterate with invalid index type " + "H5_INDEX_UNKNOWN!\n"); + PART_ERROR(H5Aiterate_invalid_index_type); + } + + H5E_BEGIN_TRY + { + err_ret = H5Aiterate2(group_id, H5_INDEX_N, H5_ITER_INC, NULL, attr_iter_callback2, NULL); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf( + " iterated over attributes using H5Aiterate with invalid index type H5_INDEX_N!\n"); + PART_ERROR(H5Aiterate_invalid_index_type); + } + + PASSED(); + } + PART_END(H5Aiterate_invalid_index_type); + + PART_BEGIN(H5Aiterate_invalid_index_order) + { + TESTING_2("H5Aiterate with an invalid index ordering"); + + H5E_BEGIN_TRY + { + err_ret = + H5Aiterate2(group_id, H5_INDEX_NAME, H5_ITER_UNKNOWN, NULL, attr_iter_callback2, NULL); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" iterated over attributes using H5Aiterate with invalid index ordering " + "H5_ITER_UNKNOWN!\n"); + PART_ERROR(H5Aiterate_invalid_index_order); + } + + H5E_BEGIN_TRY + { + err_ret = H5Aiterate2(group_id, H5_INDEX_NAME, H5_ITER_N, NULL, attr_iter_callback2, NULL); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf( + " iterated over attributes using H5Aiterate with invalid index ordering H5_ITER_N!\n"); + PART_ERROR(H5Aiterate_invalid_index_order); + } + + PASSED(); + } + PART_END(H5Aiterate_invalid_index_order); + + PART_BEGIN(H5Aiterate_by_name_invalid_loc_id) + { + TESTING_2("H5Aiterate_by_name with an invalid loc_id"); + + H5E_BEGIN_TRY + { + err_ret = H5Aiterate_by_name(H5I_INVALID_HID, ".", H5_INDEX_NAME, H5_ITER_INC, NULL, + attr_iter_callback2, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" iterated over attributes using H5Aiterate_by_name with an invalid loc_id!\n"); + PART_ERROR(H5Aiterate_by_name_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Aiterate_by_name_invalid_loc_id); + + PART_BEGIN(H5Aiterate_by_name_invalid_obj_name) + { + TESTING_2("H5Aiterate_by_name with an invalid object name"); + + H5E_BEGIN_TRY + { + err_ret = H5Aiterate_by_name(group_id, NULL, H5_INDEX_NAME, H5_ITER_INC, NULL, + attr_iter_callback2, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" iterated over attributes using H5Aiterate_by_name with a NULL object name!\n"); + PART_ERROR(H5Aiterate_by_name_invalid_obj_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Aiterate_by_name(group_id, "", H5_INDEX_NAME, H5_ITER_INC, NULL, + attr_iter_callback2, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" iterated over attributes using H5Aiterate_by_name with an invalid object name " + "of ''!\n"); + PART_ERROR(H5Aiterate_by_name_invalid_obj_name); + } + + PASSED(); + } + PART_END(H5Aiterate_by_name_invalid_obj_name); + + PART_BEGIN(H5Aiterate_by_name_invalid_index_type) + { + TESTING_2("H5Aiterate_by_name with an invalid index type"); + + H5E_BEGIN_TRY + { + err_ret = H5Aiterate_by_name(group_id, ".", H5_INDEX_UNKNOWN, H5_ITER_INC, NULL, + attr_iter_callback2, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" iterated over attributes using H5Aiterate_by_name with invalid index type " + "H5_INDEX_UNKNOWN!\n"); + PART_ERROR(H5Aiterate_by_name_invalid_index_type); + } + + H5E_BEGIN_TRY + { + err_ret = H5Aiterate_by_name(group_id, ".", H5_INDEX_N, H5_ITER_INC, NULL, + attr_iter_callback2, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" iterated over attributes using H5Aiterate_by_name with invalid index type " + "H5_INDEX_N!\n"); + PART_ERROR(H5Aiterate_by_name_invalid_index_type); + } + + PASSED(); + } + PART_END(H5Aiterate_by_name_invalid_index_type); + + PART_BEGIN(H5Aiterate_by_name_invalid_index_order) + { + TESTING_2("H5Aiterate_by_name with an invalid index ordering"); + + H5E_BEGIN_TRY + { + err_ret = H5Aiterate_by_name(group_id, ".", H5_INDEX_NAME, H5_ITER_UNKNOWN, NULL, + attr_iter_callback2, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" iterated over attributes using H5Aiterate_by_name with invalid index ordering " + "H5_ITER_UNKNOWN!\n"); + PART_ERROR(H5Aiterate_by_name_invalid_index_order); + } + + H5E_BEGIN_TRY + { + err_ret = H5Aiterate_by_name(group_id, ".", H5_INDEX_NAME, H5_ITER_N, NULL, + attr_iter_callback2, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" iterated over attributes using H5Aiterate_by_name with invalid index ordering " + "H5_ITER_N!\n"); + PART_ERROR(H5Aiterate_by_name_invalid_index_order); + } + + PASSED(); + } + PART_END(H5Aiterate_by_name_invalid_index_order); + + PART_BEGIN(H5Aiterate_by_name_invalid_lapl) + { + TESTING_2("H5Aiterate_by_name with an invalid LAPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Aiterate_by_name(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, NULL, + attr_iter_callback2, NULL, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" iterated over attributes using H5Aiterate_by_name with an invalid LAPL!\n"); + PART_ERROR(H5Aiterate_by_name_invalid_lapl); + } + + PASSED(); + } + PART_END(H5Aiterate_by_name_invalid_lapl); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(attr_space_id) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype) < 0) + TEST_ERROR; + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + if (H5Aclose(attr_id2) < 0) + TEST_ERROR; + if (H5Aclose(attr_id3) < 0) + TEST_ERROR; + if (H5Aclose(attr_id4) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(attr_space_id); + H5Tclose(attr_dtype); + H5Aclose(attr_id); + H5Aclose(attr_id2); + H5Aclose(attr_id3); + H5Aclose(attr_id4); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that attribute iteration performed + * on an object with no attributes attached to it is + * not problematic. + */ +static int +test_attribute_iterate_0_attributes(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t dset_space_id = H5I_INVALID_HID; + + TESTING_MULTIPART("attribute iteration on object with 0 attributes"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ITERATE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, attribute, or iterate aren't supported " + "with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file\n"); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_ITERATE_TEST_0_ATTRIBUTES_SUBGROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup\n"); + goto error; + } + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + if ((dset_space_id = generate_random_dataspace(ATTRIBUTE_ITERATE_TEST_0_ATTRIBUTES_DSET_SPACE_RANK, NULL, + NULL, FALSE)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, ATTRIBUTE_ITERATE_TEST_0_ATTRIBUTES_DSET_NAME, dset_dtype, + dset_space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Aiterate_0_attributes_native) + { + TESTING_2("H5Aiterate (native order)"); + + if (H5Aiterate2(dset_id, H5_INDEX_NAME, H5_ITER_NATIVE, NULL, attr_iter_callback2, NULL) < 0) { + H5_FAILED(); + HDprintf(" H5Aiterate2 on object with 0 attributes failed\n"); + PART_ERROR(H5Aiterate_0_attributes_native); + } + + PASSED(); + } + PART_END(H5Aiterate_0_attributes_native); + + PART_BEGIN(H5Aiterate_0_attributes_inc) + { + TESTING_2("H5Aiterate (increasing order)"); + + if (H5Aiterate2(dset_id, H5_INDEX_NAME, H5_ITER_INC, NULL, attr_iter_callback2, NULL) < 0) { + H5_FAILED(); + HDprintf(" H5Aiterate2 on object with 0 attributes failed\n"); + PART_ERROR(H5Aiterate_0_attributes_inc); + } + + PASSED(); + } + PART_END(H5Aiterate_0_attributes_inc); + + PART_BEGIN(H5Aiterate_0_attributes_dec) + { + TESTING_2("H5Aiterate (decreasing order)"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + if (H5Aiterate2(dset_id, H5_INDEX_NAME, H5_ITER_DEC, NULL, attr_iter_callback2, NULL) < 0) { + H5_FAILED(); + HDprintf(" H5Aiterate2 on object with 0 attributes failed\n"); + PART_ERROR(H5Aiterate_0_attributes_dec); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Aiterate_0_attributes_dec); +#endif + } + PART_END(H5Aiterate_0_attributes_dec); + + PART_BEGIN(H5Aiterate_by_name_0_attributes_native) + { + TESTING_2("H5Aiterate_by_name (native order)"); + + if (H5Aiterate_by_name(group_id, ATTRIBUTE_ITERATE_TEST_0_ATTRIBUTES_DSET_NAME, H5_INDEX_NAME, + H5_ITER_NATIVE, NULL, attr_iter_callback2, NULL, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Aiterate_by_name on object with 0 attributes failed\n"); + PART_ERROR(H5Aiterate_by_name_0_attributes_native); + } + + PASSED(); + } + PART_END(H5Aiterate_by_name_0_attributes_native); + + PART_BEGIN(H5Aiterate_by_name_0_attributes_inc) + { + TESTING_2("H5Aiterate_by_name (increasing order)"); + + if (H5Aiterate_by_name(group_id, ATTRIBUTE_ITERATE_TEST_0_ATTRIBUTES_DSET_NAME, H5_INDEX_NAME, + H5_ITER_INC, NULL, attr_iter_callback2, NULL, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Aiterate_by_name on object with 0 attributes failed\n"); + PART_ERROR(H5Aiterate_by_name_0_attributes_inc); + } + + PASSED(); + } + PART_END(H5Aiterate_by_name_0_attributes_inc); + + PART_BEGIN(H5Aiterate_by_name_0_attributes_dec) + { + TESTING_2("H5Aiterate_by_name (decreasing order)"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + if (H5Aiterate_by_name(group_id, ATTRIBUTE_ITERATE_TEST_0_ATTRIBUTES_DSET_NAME, H5_INDEX_NAME, + H5_ITER_DEC, NULL, attr_iter_callback2, NULL, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Aiterate_by_name on object with 0 attributes failed\n"); + PART_ERROR(H5Aiterate_by_name_0_attributes_dec); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Aiterate_by_name_0_attributes_dec); +#endif + } + PART_END(H5Aiterate_by_name_0_attributes_dec); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(dset_space_id) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(dset_space_id); + H5Tclose(dset_dtype); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that an attribute can be deleted + * using H5Adelete(_by_idx). + */ +static int +test_delete_attribute(void) +{ + htri_t attr_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t attr_dtype = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + + TESTING_MULTIPART("attribute deletion"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, attribute, or creation order aren't supported " + "with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", ATTRIBUTE_TEST_GROUP_NAME); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create GCPL for attribute creation order tracking\n"); + goto error; + } + + if (H5Pset_attr_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED) < 0) { + H5_FAILED(); + HDprintf(" couldn't set attribute creation order tracking\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_DELETION_TEST_GROUP_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", ATTRIBUTE_DELETION_TEST_GROUP_NAME); + goto error; + } + + if ((space_id = generate_random_dataspace(ATTRIBUTE_DELETION_TEST_SPACE_RANK, NULL, NULL, TRUE)) < 0) + TEST_ERROR; + + if ((attr_dtype = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Adelete) + { + TESTING_2("H5Adelete"); + + /* Test H5Adelete */ + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME, attr_dtype, space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s'\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete); + } + + /* Verify the attribute has been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' didn't exist before deletion\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete); + } + + /* Delete the attribute */ + if (H5Adelete(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME) < 0) { + H5_FAILED(); + HDprintf(" failed to delete attribute '%s'\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete); + } + + /* Verify the attribute has been deleted */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete); + } + + if (attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' exists after deletion!\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete); + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close attribute '%s'\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete); + } + + PASSED(); + } + PART_END(H5Adelete); + + H5E_BEGIN_TRY + { + H5Aclose(attr_id); + attr_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Adelete_by_name) + { + TESTING_2("H5Adelete_by_name"); + + /* Test H5Adelete_by_name */ + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME, attr_dtype, space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s'\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_name); + } + + /* Verify the attribute has been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_name); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' didn't exist before deletion\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_name); + } + + /* Delete the attribute */ + if (H5Adelete_by_name(container_group, ATTRIBUTE_DELETION_TEST_GROUP_NAME, + ATTRIBUTE_DELETION_TEST_ATTR_NAME, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to delete attribute '%s'\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_name); + } + + /* Verify the attribute has been deleted */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_name); + } + + if (attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' exists after deletion!\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_name); + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close attribute '%s'\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_name); + } + + PASSED(); + } + PART_END(H5Adelete_by_name); + + H5E_BEGIN_TRY + { + H5Aclose(attr_id); + attr_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Adelete_by_idx_crt_order_increasing) + { + TESTING_2("H5Adelete_by_idx by creation order in increasing order"); + + /* Create several attributes */ + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME, attr_dtype, space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s'\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close attribute '%s'\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME2, attr_dtype, space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s'\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close attribute '%s'\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME3, attr_dtype, space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s'\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close attribute '%s'\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + /* Verify the attributes have been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' didn't exist before deletion\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' didn't exist before deletion\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME3)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' didn't exist before deletion\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + /* Delete an attribute */ + if (H5Adelete_by_idx(container_group, ATTRIBUTE_DELETION_TEST_GROUP_NAME, H5_INDEX_CRT_ORDER, + H5_ITER_INC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to delete attribute using H5Adelete_by_idx by creation order in " + "increasing order\n"); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + /* Ensure that the attribute is gone and others remain */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + if (attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' exists after deletion!\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' doesn't exist after deletion of a different attribute!\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME3)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' doesn't exist after deletion of a different attribute!\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + /* Repeat until all attributes have been deleted */ + if (H5Adelete_by_idx(container_group, ATTRIBUTE_DELETION_TEST_GROUP_NAME, H5_INDEX_CRT_ORDER, + H5_ITER_INC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to delete attribute using H5Adelete_by_idx by creation order in " + "increasing order\n"); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + if (attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' exists after deletion!\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + if (attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' exists after deletion!\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME3)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' doesn't exist after deletion of a different attribute!\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + if (H5Adelete_by_idx(container_group, ATTRIBUTE_DELETION_TEST_GROUP_NAME, H5_INDEX_CRT_ORDER, + H5_ITER_INC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to delete attribute using H5Adelete_by_idx by creation order in " + "increasing order\n"); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + if (attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' exists after deletion!\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + if (attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' exists after deletion!\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME3)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + if (attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' exists after deletion!\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_crt_order_increasing); + } + + PASSED(); + } + PART_END(H5Adelete_by_idx_crt_order_increasing); + + H5E_BEGIN_TRY + { + H5Aclose(attr_id); + attr_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Adelete_by_idx_crt_order_decreasing) + { + TESTING_2("H5Adelete_by_idx by creation order in decreasing order"); + + /* Create several attributes */ + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME, attr_dtype, space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s'\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close attribute '%s'\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME2, attr_dtype, space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s'\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close attribute '%s'\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME3, attr_dtype, space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s'\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close attribute '%s'\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + /* Verify the attributes have been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' didn't exist before deletion\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' didn't exist before deletion\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME3)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' didn't exist before deletion\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + /* Delete an attribute */ + if (H5Adelete_by_idx(container_group, ATTRIBUTE_DELETION_TEST_GROUP_NAME, H5_INDEX_CRT_ORDER, + H5_ITER_DEC, 2, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to delete attribute using H5Adelete_by_idx by creation order in " + "decreasing order\n"); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + /* Ensure that the attribute is gone and others remain */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + if (attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' exists after deletion!\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' doesn't exist after deletion of a different attribute!\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME3)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' doesn't exist after deletion of a different attribute!\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + /* Repeat until all attributes have been deleted */ + if (H5Adelete_by_idx(container_group, ATTRIBUTE_DELETION_TEST_GROUP_NAME, H5_INDEX_CRT_ORDER, + H5_ITER_DEC, 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to delete attribute using H5Adelete_by_idx by creation order in " + "decreasing order\n"); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + if (attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' exists after deletion!\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + if (attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' exists after deletion!\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME3)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' doesn't exist after deletion of a different attribute!\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + if (H5Adelete_by_idx(container_group, ATTRIBUTE_DELETION_TEST_GROUP_NAME, H5_INDEX_CRT_ORDER, + H5_ITER_DEC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to delete attribute using H5Adelete_by_idx by creation order in " + "decreasing order\n"); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + if (attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' exists after deletion!\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + if (attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' exists after deletion!\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME3)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + if (attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' exists after deletion!\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_crt_order_decreasing); + } + + PASSED(); + } + PART_END(H5Adelete_by_idx_crt_order_decreasing); + + H5E_BEGIN_TRY + { + H5Aclose(attr_id); + attr_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Adelete_by_idx_name_order_increasing) + { + TESTING_2("H5Adelete_by_idx by alphabetical order in increasing order"); + + /* Create several attributes */ + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME, attr_dtype, space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s'\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close attribute '%s'\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME2, attr_dtype, space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s'\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close attribute '%s'\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME3, attr_dtype, space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s'\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close attribute '%s'\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + /* Verify the attributes have been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' didn't exist before deletion\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' didn't exist before deletion\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME3)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' didn't exist before deletion\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + /* Delete an attribute */ + if (H5Adelete_by_idx(container_group, ATTRIBUTE_DELETION_TEST_GROUP_NAME, H5_INDEX_NAME, + H5_ITER_INC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to delete attribute using H5Adelete_by_idx by alphabetical order in " + "increasing order\n"); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + /* Ensure that the attribute is gone and others remain */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + if (attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' exists after deletion!\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' doesn't exist after deletion of a different attribute!\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME3)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' doesn't exist after deletion of a different attribute!\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + /* Repeat until all attributes have been deleted */ + if (H5Adelete_by_idx(container_group, ATTRIBUTE_DELETION_TEST_GROUP_NAME, H5_INDEX_NAME, + H5_ITER_INC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to delete attribute using H5Adelete_by_idx by alphabetical order in " + "increasing order\n"); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + if (attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' exists after deletion!\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + if (attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' exists after deletion!\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME3)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' doesn't exist after deletion of a different attribute!\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + if (H5Adelete_by_idx(container_group, ATTRIBUTE_DELETION_TEST_GROUP_NAME, H5_INDEX_NAME, + H5_ITER_INC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to delete attribute using H5Adelete_by_idx by alphabetical order in " + "increasing order\n"); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + if (attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' exists after deletion!\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + if (attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' exists after deletion!\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME3)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + if (attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' exists after deletion!\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_name_order_increasing); + } + + PASSED(); + } + PART_END(H5Adelete_by_idx_name_order_increasing); + + H5E_BEGIN_TRY + { + H5Aclose(attr_id); + attr_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Adelete_by_idx_name_order_decreasing) + { + TESTING_2("H5Adelete_by_idx by alphabetical order in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Create several attributes */ + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME, attr_dtype, space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s'\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close attribute '%s'\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME2, attr_dtype, space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s'\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close attribute '%s'\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME3, attr_dtype, space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s'\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close attribute '%s'\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + /* Verify the attributes have been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' didn't exist before deletion\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' didn't exist before deletion\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME3)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' didn't exist before deletion\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + /* Delete an attribute */ + if (H5Adelete_by_idx(container_group, ATTRIBUTE_DELETION_TEST_GROUP_NAME, H5_INDEX_NAME, + H5_ITER_DEC, 2, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to delete attribute using H5Adelete_by_idx by alphabetical order in " + "decreasing order\n"); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + /* Ensure that the attribute is gone and others remain */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + if (attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' exists after deletion!\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' doesn't exist after deletion of a different attribute!\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME3)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' doesn't exist after deletion of a different attribute!\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + /* Repeat until all attributes have been deleted */ + if (H5Adelete_by_idx(container_group, ATTRIBUTE_DELETION_TEST_GROUP_NAME, H5_INDEX_NAME, + H5_ITER_DEC, 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to delete attribute using H5Adelete_by_idx by alphabetical order in " + "decreasing order\n"); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + if (attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' exists after deletion!\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + if (attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' exists after deletion!\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME3)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' doesn't exist after deletion of a different attribute!\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + if (H5Adelete_by_idx(container_group, ATTRIBUTE_DELETION_TEST_GROUP_NAME, H5_INDEX_NAME, + H5_ITER_DEC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to delete attribute using H5Adelete_by_idx by alphabetical order in " + "decreasing order\n"); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + if (attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' exists after deletion!\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + if (attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' exists after deletion!\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME2); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_TEST_ATTR_NAME3)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + if (attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' exists after deletion!\n", ATTRIBUTE_DELETION_TEST_ATTR_NAME3); + PART_ERROR(H5Adelete_by_idx_name_order_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Adelete_by_idx_name_order_decreasing); +#endif + } + PART_END(H5Adelete_by_idx_name_order_decreasing); + + H5E_BEGIN_TRY + { + H5Aclose(attr_id); + attr_id = H5I_INVALID_HID; + } + H5E_END_TRY; + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype) < 0) + TEST_ERROR; + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(space_id); + H5Tclose(attr_dtype); + H5Aclose(attr_id); + H5Pclose(gcpl_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that an attribute can't be deleted + * when H5Adelete(_by_name/_by_idx) is passed invalid + * parameters. + */ +static int +test_delete_attribute_invalid_params(void) +{ + herr_t err_ret = -1; + htri_t attr_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t attr_dtype = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + + TESTING_MULTIPART("attribute deletion with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or attribute aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", ATTRIBUTE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_DELETION_INVALID_PARAMS_TEST_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", + ATTRIBUTE_DELETION_INVALID_PARAMS_TEST_GROUP_NAME); + goto error; + } + + if ((space_id = generate_random_dataspace(ATTRIBUTE_DELETION_INVALID_PARAMS_TEST_SPACE_RANK, NULL, NULL, + TRUE)) < 0) + TEST_ERROR; + + if ((attr_dtype = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_DELETION_INVALID_PARAMS_TEST_ATTR_NAME, attr_dtype, + space_id, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute\n"); + goto error; + } + + /* Verify the attribute has been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DELETION_INVALID_PARAMS_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute didn't exists\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Adelete_invalid_loc_id) + { + TESTING_2("H5Adelete with an invalid loc_id"); + + H5E_BEGIN_TRY + { + err_ret = H5Adelete(H5I_INVALID_HID, ATTRIBUTE_DELETION_INVALID_PARAMS_TEST_ATTR_NAME); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" deleted an attribute using H5Adelete with an invalid loc_id!\n"); + PART_ERROR(H5Adelete_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Adelete_invalid_loc_id); + + PART_BEGIN(H5Adelete_invalid_attr_name) + { + TESTING_2("H5Adelete with an invalid attribute name"); + + H5E_BEGIN_TRY + { + err_ret = H5Adelete(group_id, NULL); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" deleted an attribute using H5Adelete with a NULL attribute name!\n"); + PART_ERROR(H5Adelete_invalid_attr_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Adelete(group_id, ""); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" deleted an attribute using H5Adelete with an invalid attribute name of ''!\n"); + PART_ERROR(H5Adelete_invalid_attr_name); + } + + PASSED(); + } + PART_END(H5Adelete_invalid_attr_name); + + PART_BEGIN(H5Adelete_by_name_invalid_loc_id) + { + TESTING_2("H5Adelete_by_name with an invalid loc_id"); + + H5E_BEGIN_TRY + { + err_ret = H5Adelete_by_name(H5I_INVALID_HID, ".", + ATTRIBUTE_DELETION_INVALID_PARAMS_TEST_ATTR_NAME, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" deleted an attribute using H5Adelete_by_name with an invalid loc_id!\n"); + PART_ERROR(H5Adelete_by_name_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Adelete_by_name_invalid_loc_id); + + PART_BEGIN(H5Adelete_by_name_invalid_obj_name) + { + TESTING_2("H5Adelete_by_name with an invalid object name"); + + H5E_BEGIN_TRY + { + err_ret = H5Adelete_by_name(group_id, NULL, ATTRIBUTE_DELETION_INVALID_PARAMS_TEST_ATTR_NAME, + H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" deleted an attribute using H5Adelete_by_name with a NULL object name!\n"); + PART_ERROR(H5Adelete_by_name_invalid_obj_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Adelete_by_name(group_id, "", ATTRIBUTE_DELETION_INVALID_PARAMS_TEST_ATTR_NAME, + H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf( + " deleted an attribute using H5Adelete_by_name with an invalid object name of ''!\n"); + PART_ERROR(H5Adelete_by_name_invalid_obj_name); + } + + PASSED(); + } + PART_END(H5Adelete_by_name_invalid_obj_name); + + PART_BEGIN(H5Adelete_by_name_invalid_attr_name) + { + TESTING_2("H5Adelete_by_name with an invalid attribute name"); + + H5E_BEGIN_TRY + { + err_ret = H5Adelete_by_name(group_id, ".", NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" deleted an attribute using H5Adelete_by_name with a NULL attribute name!\n"); + PART_ERROR(H5Adelete_by_name_invalid_attr_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Adelete_by_name(group_id, ".", "", H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" deleted an attribute using H5Adelete_by_name with an invalid attribute name of " + "''!\n"); + PART_ERROR(H5Adelete_by_name_invalid_attr_name); + } + + PASSED(); + } + PART_END(H5Adelete_by_name_invalid_attr_name); + + PART_BEGIN(H5Adelete_by_name_invalid_lapl) + { + TESTING_2("H5Adelete_by_name with an invalid LAPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Adelete_by_name(group_id, ".", ATTRIBUTE_DELETION_INVALID_PARAMS_TEST_ATTR_NAME, + H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" deleted an attribute using H5Adelete_by_name with an invalid LAPL!\n"); + PART_ERROR(H5Adelete_by_name_invalid_lapl); + } + + PASSED(); + } + PART_END(H5Adelete_by_name_invalid_lapl); + + PART_BEGIN(H5Adelete_by_idx_invalid_loc_id) + { + TESTING_2("H5Adelete_by_idx with an invalid loc_id"); + + H5E_BEGIN_TRY + { + err_ret = H5Adelete_by_idx(H5I_INVALID_HID, ".", H5_INDEX_NAME, H5_ITER_INC, 0, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" deleted an attribute using H5Adelete_by_idx with an invalid loc_id!\n"); + PART_ERROR(H5Adelete_by_idx_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Adelete_by_idx_invalid_loc_id); + + PART_BEGIN(H5Adelete_by_idx_invalid_obj_name) + { + TESTING_2("H5Adelete_by_idx with an invalid object name"); + + H5E_BEGIN_TRY + { + err_ret = H5Adelete_by_idx(group_id, NULL, H5_INDEX_NAME, H5_ITER_INC, 0, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" deleted an attribute using H5Adelete_by_idx with a NULL object name!\n"); + PART_ERROR(H5Adelete_by_idx_invalid_obj_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Adelete_by_idx(group_id, "", H5_INDEX_NAME, H5_ITER_INC, 0, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf( + " deleted an attribute using H5Adelete_by_idx with an invalid object name of ''!\n"); + PART_ERROR(H5Adelete_by_idx_invalid_obj_name); + } + + PASSED(); + } + PART_END(H5Adelete_by_idx_invalid_obj_name); + + PART_BEGIN(H5Adelete_by_idx_invalid_index_type) + { + TESTING_2("H5Adelete_by_idx with an invalid index type"); + + H5E_BEGIN_TRY + { + err_ret = H5Adelete_by_idx(group_id, ".", H5_INDEX_UNKNOWN, H5_ITER_INC, 0, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" deleted an attribute using H5Adelete_by_idx with invalid index type " + "H5_INDEX_UNKNOWN!\n"); + PART_ERROR(H5Adelete_by_idx_invalid_index_type); + } + + H5E_BEGIN_TRY + { + err_ret = H5Adelete_by_idx(group_id, ".", H5_INDEX_N, H5_ITER_INC, 0, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf( + " deleted an attribute using H5Adelete_by_idx with invalid index type H5_INDEX_N!\n"); + PART_ERROR(H5Adelete_by_idx_invalid_index_type); + } + + PASSED(); + } + PART_END(H5Adelete_by_idx_invalid_index_type); + + PART_BEGIN(H5Adelete_by_idx_invalid_index_order) + { + TESTING_2("H5Adelete_by_idx with an invalid index ordering"); + + H5E_BEGIN_TRY + { + err_ret = H5Adelete_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_UNKNOWN, 0, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" deleted an attribute using H5Adelete_by_idx with invalid index ordering " + "H5_ITER_UNKNOWN!\n"); + PART_ERROR(H5Adelete_by_idx_invalid_index_order); + } + + H5E_BEGIN_TRY + { + err_ret = H5Adelete_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_N, 0, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" deleted an attribute using H5Adelete_by_idx with invalid index ordering " + "H5_ITER_N!\n"); + PART_ERROR(H5Adelete_by_idx_invalid_index_order); + } + + PASSED(); + } + PART_END(H5Adelete_by_idx_invalid_index_order); + + PART_BEGIN(H5Adelete_by_idx_invalid_lapl) + { + TESTING_2("H5Adelete_by_idx with an invalid LAPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Adelete_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" deleted an attribute using H5Adelete_by_idx with an invalid LAPL!\n"); + PART_ERROR(H5Adelete_by_idx_invalid_lapl); + } + + PASSED(); + } + PART_END(H5Adelete_by_idx_invalid_lapl); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype) < 0) + TEST_ERROR; + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(space_id); + H5Tclose(attr_dtype); + H5Aclose(attr_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test for H5Aexists and H5Aexists_by_name. + */ +static int +test_attribute_exists(void) +{ + htri_t attr_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t attr_dtype = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + + TESTING_MULTIPART("attribute existence"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or attribute aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_EXISTS_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", ATTRIBUTE_EXISTS_TEST_GROUP_NAME); + goto error; + } + + if ((space_id = generate_random_dataspace(ATTRIBUTE_EXISTS_TEST_SPACE_RANK, NULL, NULL, TRUE)) < 0) + TEST_ERROR; + + if ((attr_dtype = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_EXISTS_TEST_ATTR_NAME, attr_dtype, space_id, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Aexists) + { + TESTING_2("H5Aexists"); + + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_EXISTS_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + PART_ERROR(H5Aexists); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' did not exist\n", ATTRIBUTE_EXISTS_TEST_ATTR_NAME); + PART_ERROR(H5Aexists); + } + + PASSED(); + } + PART_END(H5Aexists); + + PART_BEGIN(H5Aexists_by_name) + { + TESTING_2("H5Aexists_by_name"); + + if ((attr_exists = H5Aexists_by_name(container_group, ATTRIBUTE_EXISTS_TEST_GROUP_NAME, + ATTRIBUTE_EXISTS_TEST_ATTR_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists by name\n"); + PART_ERROR(H5Aexists_by_name); + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute '%s' did not exist by name\n", ATTRIBUTE_EXISTS_TEST_ATTR_NAME); + PART_ERROR(H5Aexists_by_name); + } + + PASSED(); + } + PART_END(H5Aexists_by_name); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(space_id); + H5Tclose(attr_dtype); + H5Aclose(attr_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to ensure that H5Aexists(_by_name) will fail when + * given invalid parameters. + */ +static int +test_attribute_exists_invalid_params(void) +{ + herr_t err_ret = -1; + htri_t attr_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t attr_dtype = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + + TESTING_MULTIPART("attribute existence with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or attribute aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", ATTRIBUTE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_EXISTS_INVALID_PARAMS_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", + ATTRIBUTE_EXISTS_INVALID_PARAMS_TEST_GROUP_NAME); + goto error; + } + + if ((space_id = generate_random_dataspace(ATTRIBUTE_EXISTS_INVALID_PARAMS_TEST_SPACE_RANK, NULL, NULL, + TRUE)) < 0) + TEST_ERROR; + + if ((attr_dtype = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_EXISTS_INVALID_PARAMS_TEST_ATTR_NAME, attr_dtype, space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute\n"); + goto error; + } + + /* Verify the attribute has been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_EXISTS_INVALID_PARAMS_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute didn't exists\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Aexists_invalid_loc_id) + { + TESTING_2("H5Aexists with an invalid loc_id"); + + H5E_BEGIN_TRY + { + err_ret = H5Aexists(H5I_INVALID_HID, ATTRIBUTE_EXISTS_INVALID_PARAMS_TEST_ATTR_NAME); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Aexists with an invalid loc_id succeeded!\n"); + PART_ERROR(H5Aexists_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Aexists_invalid_loc_id); + + PART_BEGIN(H5Aexists_invalid_attr_name) + { + TESTING_2("H5Aexists with invalid attribute name"); + + H5E_BEGIN_TRY + { + err_ret = H5Aexists(group_id, NULL); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Aexists with a NULL attribute name succeeded!\n"); + PART_ERROR(H5Aexists_invalid_attr_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Aexists(group_id, ""); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Aexists with an invalid attribute name of '' succeeded!\n"); + PART_ERROR(H5Aexists_invalid_attr_name); + } + + PASSED(); + } + PART_END(H5Aexists_invalid_attr_name); + + PART_BEGIN(H5Aexists_by_name_invalid_loc_id) + { + TESTING_2("H5Aexists_by_name with an invalid loc_id"); + + H5E_BEGIN_TRY + { + err_ret = H5Aexists_by_name(H5I_INVALID_HID, ATTRIBUTE_EXISTS_INVALID_PARAMS_TEST_GROUP_NAME, + ATTRIBUTE_EXISTS_INVALID_PARAMS_TEST_ATTR_NAME, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Aexists_by_name with an invalid loc_id succeeded!\n"); + PART_ERROR(H5Aexists_by_name_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Aexists_by_name_invalid_loc_id); + + PART_BEGIN(H5Aexists_by_name_invalid_obj_name) + { + TESTING_2("H5Aexists_by_name with invalid object name"); + + H5E_BEGIN_TRY + { + err_ret = H5Aexists_by_name(file_id, NULL, ATTRIBUTE_EXISTS_INVALID_PARAMS_TEST_ATTR_NAME, + H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Aexists_by_name with a NULL object name succeeded!\n"); + PART_ERROR(H5Aexists_by_name_invalid_obj_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Aexists_by_name(file_id, "", ATTRIBUTE_EXISTS_INVALID_PARAMS_TEST_ATTR_NAME, + H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Aexists_by_name with an invalid object name of '' succeeded!\n"); + PART_ERROR(H5Aexists_by_name_invalid_obj_name); + } + + PASSED(); + } + PART_END(H5Aexists_by_name_invalid_obj_name); + + PART_BEGIN(H5Aexists_by_name_invalid_attr_name) + { + TESTING_2("H5Aexists_by_name with invalid attribute name"); + + H5E_BEGIN_TRY + { + err_ret = H5Aexists_by_name(file_id, ATTRIBUTE_EXISTS_INVALID_PARAMS_TEST_GROUP_NAME, NULL, + H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Aexists_by_name with a NULL attribute name succeeded!\n"); + PART_ERROR(H5Aexists_by_name_invalid_attr_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Aexists_by_name(file_id, ATTRIBUTE_EXISTS_INVALID_PARAMS_TEST_GROUP_NAME, "", + H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Aexists_by_name with an invalid attribute name of '' succeeded!\n"); + PART_ERROR(H5Aexists_by_name_invalid_attr_name); + } + + PASSED(); + } + PART_END(H5Aexists_by_name_invalid_attr_name); + + PART_BEGIN(H5Aexists_by_name_invalid_lapl) + { + TESTING_2("H5Aexists_by_name with an invalid link access property list"); + + H5E_BEGIN_TRY + { + err_ret = H5Aexists_by_name(file_id, ATTRIBUTE_EXISTS_INVALID_PARAMS_TEST_GROUP_NAME, + ATTRIBUTE_EXISTS_INVALID_PARAMS_TEST_ATTR_NAME, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Aexists_by_name with an invalid link access property list succeeded!\n"); + PART_ERROR(H5Aexists_by_name_invalid_lapl); + } + + PASSED(); + } + PART_END(H5Aexists_by_name_invalid_lapl); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(space_id); + H5Tclose(attr_dtype); + H5Aclose(attr_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to make sure many attributes can be written + * to the file + */ +static int +test_attribute_many(void) +{ + unsigned u; + htri_t attr_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t attr_dtype = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + char attrname[ATTRIBUTE_MANY_NAME_BUF_SIZE]; /* Name of attribute */ + + TESTING("creating many attributes"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or attribute aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file\n"); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_MANY_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create the group '%s'\n", ATTRIBUTE_MANY_GROUP_NAME); + goto error; + } + + if ((space_id = generate_random_dataspace(ATTRIBUTE_MANY_SPACE_RANK, NULL, NULL, TRUE)) < 0) + TEST_ERROR; + + if ((attr_dtype = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + /* Create many attributes */ + for (u = 0; u < ATTRIBUTE_MANY_NUMB; u++) { + sprintf(attrname, "many-%06u", u); + + if ((attr_id = H5Acreate2(group_id, attrname, attr_dtype, space_id, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute\n"); + goto error; + } + + /* Verify the attribute has been created */ + if ((attr_exists = H5Aexists(group_id, attrname)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not exist\n"); + goto error; + } + + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + } + + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(space_id); + H5Tclose(attr_dtype); + H5Aclose(attr_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to make sure an attribute can be opened for + * a second time + */ +static int +test_attribute_duplicate_id(void) +{ + htri_t attr_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID, attr_id2 = H5I_INVALID_HID; + hid_t attr_dtype = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + + TESTING("duplicated IDs for an attribute"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or attribute aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file\n"); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_DUPLICATE_ID_GRP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create the group '%s'\n", ATTRIBUTE_DUPLICATE_ID_GRP_NAME); + goto error; + } + + if ((space_id = generate_random_dataspace(ATTRIBUTE_DUPLICATE_ID_SPACE_RANK, NULL, NULL, TRUE)) < 0) + TEST_ERROR; + + if ((attr_dtype = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_DUPLICATE_ID_ATTR_NAME, attr_dtype, space_id, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute\n"); + goto error; + } + + /* Verify the attribute has been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_DUPLICATE_ID_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not exist\n"); + goto error; + } + + /* Open the attribute just created and get a second ID */ + if ((attr_id2 = H5Aopen(group_id, ATTRIBUTE_DUPLICATE_ID_ATTR_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" attribute can't be opened for a second time\n"); + goto error; + } + + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + if (H5Aclose(attr_id2) < 0) + TEST_ERROR; + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(space_id); + H5Tclose(attr_dtype); + H5Aclose(attr_id); + H5Aclose(attr_id2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that the number of attributes attached + * to an object (group, dataset, datatype) can be retrieved. + * + * XXX: Cover all of the cases and move to H5O tests. + */ +static int +test_get_number_attributes(void) +{ + H5O_info2_t obj_info; + htri_t attr_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t attr_dtype = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + + TESTING_MULTIPART("retrieval of the number of attributes on an object"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_MORE)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, attribute, or object aren't supported with this " + "connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file\n"); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_GET_NUM_ATTRS_TEST_GRP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create the group '%s'\n", ATTRIBUTE_GET_NUM_ATTRS_TEST_GRP_NAME); + goto error; + } + + if ((space_id = generate_random_dataspace(ATTRIBUTE_GET_NUM_ATTRS_TEST_SPACE_RANK, NULL, NULL, TRUE)) < 0) + TEST_ERROR; + + if ((attr_dtype = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_GET_NUM_ATTRS_TEST_ATTR_NAME, attr_dtype, space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute\n"); + goto error; + } + + /* Verify the attribute has been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_GET_NUM_ATTRS_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not exist\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Oget_info) + { + TESTING_2("H5Oget_info"); + + /* Now get the number of attributes from the group */ + if (H5Oget_info3(group_id, &obj_info, H5O_INFO_ALL) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve group info using H5Oget_info3\n"); + PART_ERROR(H5Oget_info); + } + + if (obj_info.num_attrs != 1) { + H5_FAILED(); + HDprintf(" invalid number of attributes received\n"); + PART_ERROR(H5Oget_info); + } + + PASSED(); + } + PART_END(H5Oget_info); + + PART_BEGIN(H5Oget_info_by_name) + { + TESTING_2("H5Oget_info_by_name"); + + if (H5Oget_info_by_name3(container_group, ATTRIBUTE_GET_NUM_ATTRS_TEST_GRP_NAME, &obj_info, + H5O_INFO_ALL, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve group info using H5Oget_info_by_name3\n"); + PART_ERROR(H5Oget_info_by_name); + } + + if (obj_info.num_attrs != 1) { + H5_FAILED(); + HDprintf(" invalid number of attributes received\n"); + PART_ERROR(H5Oget_info_by_name); + } + + PASSED(); + } + PART_END(H5Oget_info_by_name); + + PART_BEGIN(H5Oget_info_by_idx) + { + TESTING_2("H5Oget_info_by_idx"); + + if (H5Oget_info_by_idx3(container_group, ".", H5_INDEX_NAME, H5_ITER_INC, 0, &obj_info, + H5O_INFO_ALL, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve group info using H5Oget_info_by_idx3\n"); + PART_ERROR(H5Oget_info_by_idx); + } + + if (obj_info.num_attrs != 1) { + H5_FAILED(); + HDprintf(" invalid number of attributes received\n"); + PART_ERROR(H5Oget_info_by_idx); + } + + PASSED(); + } + PART_END(H5Oget_info_by_idx); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype) < 0) + TEST_ERROR; + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(space_id); + H5Tclose(attr_dtype); + H5Aclose(attr_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that the reference count of a named datatype used by + * attribute and a dataset is correct. + * + * XXX: May move to H5O tests. + */ +static int +test_attr_shared_dtype(void) +{ +#ifndef NO_SHARED_DATATYPES + H5O_info2_t obj_info; + htri_t attr_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t attr_dtype = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; +#endif + + TESTING("shared datatype for attributes"); + +#ifndef NO_SHARED_DATATYPES + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_MORE)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, attribute, stored datatype, or object aren't " + "supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file\n"); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_SHARED_DTYPE_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create the group '%s'\n", ATTRIBUTE_SHARED_DTYPE_GROUP_NAME); + goto error; + } + + if ((space_id = generate_random_dataspace(ATTRIBUTE_SHARED_DTYPE_SPACE_RANK, NULL, NULL, TRUE)) < 0) + TEST_ERROR; + + if ((attr_dtype = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + /* Commit datatype to file */ + if (H5Tcommit2(group_id, ATTRIBUTE_SHARED_DTYPE_NAME, attr_dtype, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT) < + 0) { + H5_FAILED(); + HDprintf(" couldn't commit datatype\n"); + goto error; + } + + if (H5Oget_info_by_name3(group_id, ATTRIBUTE_SHARED_DTYPE_NAME, &obj_info, H5O_INFO_ALL, H5P_DEFAULT) < + 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve root group info using H5Oget_info_by_name3\n"); + goto error; + } + + if (obj_info.rc != 1) { + H5_FAILED(); + HDprintf(" reference count of the named datatype is wrong: %u\n", obj_info.rc); + goto error; + } + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_SHARED_DTYPE_ATTR_NAME, attr_dtype, space_id, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute\n"); + goto error; + } + + /* Verify the attribute has been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_SHARED_DTYPE_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute exists\n"); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not exist\n"); + goto error; + } + + if (H5Oget_info_by_name3(group_id, ATTRIBUTE_SHARED_DTYPE_NAME, &obj_info, H5O_INFO_ALL, H5P_DEFAULT) < + 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve root group info using H5Oget_info_by_name3\n"); + goto error; + } + + if (obj_info.rc != 2) { + H5_FAILED(); + HDprintf(" reference count of the named datatype is wrong: %u\n", obj_info.rc); + goto error; + } + + if ((dset_id = H5Dcreate2(group_id, ATTRIBUTE_SHARED_DTYPE_DSET_NAME, attr_dtype, space_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset\n"); + goto error; + } + + if (H5Oget_info_by_name3(group_id, ATTRIBUTE_SHARED_DTYPE_NAME, &obj_info, H5O_INFO_ALL, H5P_DEFAULT) < + 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve root group info using H5Oget_info_by_name3\n"); + goto error; + } + + if (obj_info.rc != 3) { + H5_FAILED(); + HDprintf(" reference count of the named datatype is wrong: %u\n", obj_info.rc); + goto error; + } + + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Tclose(attr_dtype) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Tclose(attr_dtype); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +#else + SKIPPED(); + return 0; +#endif +} + +static herr_t +attr_iter_callback1(hid_t location_id, const char *attr_name, const H5A_info_t *ainfo, void *op_data) +{ + size_t *i = (size_t *)op_data; + size_t counter_val = *((size_t *)op_data); + size_t test_iteration; + char expected_attr_name[ATTRIBUTE_ITERATE_TEST_ATTR_NAME_BUF_SIZE]; + herr_t ret_val = H5_ITER_CONT; + + UNUSED(location_id); + UNUSED(ainfo); + + /* + * Four tests are run in the following order per attribute iteration API call: + * + * - iteration by attribute name in increasing order + * - iteration by attribute name in decreasing order + * - iteration by attribute creation order in increasing order + * - iteration by attribute creation order in decreasing order + * + * Based on how the test is written, this will mean that the attribute names + * will run in increasing order on the first and fourth tests and decreasing + * order on the second and third tests. + */ + test_iteration = (counter_val / ATTRIBUTE_ITERATE_TEST_NUM_ATTRS); + if (test_iteration == 0 || test_iteration == 3) { + HDsnprintf(expected_attr_name, ATTRIBUTE_ITERATE_TEST_ATTR_NAME_BUF_SIZE, + ATTRIBUTE_ITERATE_TEST_ATTR_NAME "%d", + (int)(counter_val % ATTRIBUTE_ITERATE_TEST_NUM_ATTRS)); + } + else { + HDsnprintf( + expected_attr_name, ATTRIBUTE_ITERATE_TEST_ATTR_NAME_BUF_SIZE, + ATTRIBUTE_ITERATE_TEST_ATTR_NAME "%d", + (int)(ATTRIBUTE_ITERATE_TEST_NUM_ATTRS - (counter_val % ATTRIBUTE_ITERATE_TEST_NUM_ATTRS) - 1)); + } + + if (HDstrncmp(attr_name, expected_attr_name, ATTRIBUTE_ITERATE_TEST_ATTR_NAME_BUF_SIZE)) { + HDprintf(" attribute name '%s' didn't match expected name '%s'\n", attr_name, expected_attr_name); + ret_val = H5_ITER_ERROR; + goto done; + } + + /* + * If the attribute's creation order is marked as valid, make sure + * that it corresponds to what is expected based on the order that + * the attributes were created in. + */ + if (ainfo->corder_valid) { + H5O_msg_crt_idx_t expected_crt_order; + + /* + * As the attributes are created with a reverse-ordering naming + * scheme to test creation order, their creation order values will + * be listed in reverse ordering on the first and fourth tests and + * in normal ordering on the second and third tests. + */ + if (test_iteration == 0 || test_iteration == 3) + expected_crt_order = (H5O_msg_crt_idx_t)(ATTRIBUTE_ITERATE_TEST_NUM_ATTRS - + (counter_val % ATTRIBUTE_ITERATE_TEST_NUM_ATTRS) - 1); + else + expected_crt_order = (H5O_msg_crt_idx_t)(counter_val % ATTRIBUTE_ITERATE_TEST_NUM_ATTRS); + + if (ainfo->corder != expected_crt_order) { + H5_FAILED(); + HDprintf(" attribute's creation order value of %lld didn't match expected value of %lld\n", + (long long)ainfo->corder, (long long)expected_crt_order); + ret_val = H5_ITER_ERROR; + goto done; + } + } + +done: + (*i)++; + + return ret_val; +} + +static herr_t +attr_iter_callback2(hid_t location_id, const char *attr_name, const H5A_info_t *ainfo, void *op_data) +{ + UNUSED(location_id); + UNUSED(attr_name); + UNUSED(ainfo); + UNUSED(op_data); + + return 0; +} + +int +H5_api_attribute_test(void) +{ + size_t i; + int nerrors; + + HDprintf("**********************************************\n"); + HDprintf("* *\n"); + HDprintf("* API Attribute Tests *\n"); + HDprintf("* *\n"); + HDprintf("**********************************************\n\n"); + + for (i = 0, nerrors = 0; i < ARRAY_LENGTH(attribute_tests); i++) { + nerrors += (*attribute_tests[i])() ? 1 : 0; + } + + HDprintf("\n"); + + return nerrors; +} diff --git a/test/API/H5_api_attribute_test.h b/test/API/H5_api_attribute_test.h new file mode 100644 index 0000000..7656263 --- /dev/null +++ b/test/API/H5_api_attribute_test.h @@ -0,0 +1,203 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef H5_API_ATTRIBUTE_TEST_H +#define H5_API_ATTRIBUTE_TEST_H + +#include "H5_api_test.h" + +int H5_api_attribute_test(void); + +/************************************************** + * * + * API Attribute test defines * + * * + **************************************************/ + +#define ATTRIBUTE_CREATE_ON_ROOT_SPACE_RANK 1 +#define ATTRIBUTE_CREATE_ON_ROOT_ATTR_NAME "attr_on_root" +#define ATTRIBUTE_CREATE_ON_ROOT_ATTR_NAME2 "attr_on_root2" + +#define ATTRIBUTE_CREATE_ON_DATASET_DSET_SPACE_RANK 2 +#define ATTRIBUTE_CREATE_ON_DATASET_ATTR_SPACE_RANK 1 +#define ATTRIBUTE_CREATE_ON_DATASET_GROUP_NAME "attr_on_dataset_test" +#define ATTRIBUTE_CREATE_ON_DATASET_DSET_NAME "dataset_with_attr" +#define ATTRIBUTE_CREATE_ON_DATASET_ATTR_NAME "attr_on_dataset" +#define ATTRIBUTE_CREATE_ON_DATASET_ATTR_NAME2 "attr_on_dataset2" + +#define ATTRIBUTE_CREATE_ON_DATATYPE_SPACE_RANK 1 +#define ATTRIBUTE_CREATE_ON_DATATYPE_DTYPE_NAME "datatype_with_attr" +#define ATTRIBUTE_CREATE_ON_DATATYPE_GROUP_NAME "attr_on_datatype_test" +#define ATTRIBUTE_CREATE_ON_DATATYPE_ATTR_NAME "attr_on_datatype" +#define ATTRIBUTE_CREATE_ON_DATATYPE_ATTR_NAME2 "attr_on_datatype2" + +#define ATTRIBUTE_CREATE_NULL_DATASPACE_TEST_SUBGROUP_NAME "attr_with_null_space_test" +#define ATTRIBUTE_CREATE_NULL_DATASPACE_TEST_ATTR_NAME "attr_with_null_space" + +#define ATTRIBUTE_CREATE_SCALAR_DATASPACE_TEST_SUBGROUP_NAME "attr_with_scalar_space_test" +#define ATTRIBUTE_CREATE_SCALAR_DATASPACE_TEST_ATTR_NAME "attr_with_scalar_space" + +#define ATTRIBUTE_CREATE_WITH_SPACE_IN_NAME_SPACE_RANK 1 +#define ATTRIBUTE_CREATE_WITH_SPACE_IN_NAME_GROUP_NAME "attr_with_space_in_name_test" +#define ATTRIBUTE_CREATE_WITH_SPACE_IN_NAME_ATTR_NAME "attr with space in name" + +#define ATTRIBUTE_CREATE_INVALID_PARAMS_SPACE_RANK 1 +#define ATTRIBUTE_CREATE_INVALID_PARAMS_GROUP_NAME "attribute_create_invalid_params_test" +#define ATTRIBUTE_CREATE_INVALID_PARAMS_ATTR_NAME "invalid_params_attr" + +#define ATTRIBUTE_OPEN_TEST_SPACE_RANK 1 +#define ATTRIBUTE_OPEN_TEST_GROUP_NAME "attribute_open_test" +#define ATTRIBUTE_OPEN_TEST_ATTR_NAME "attribute_open_test_attr" +#define ATTRIBUTE_OPEN_TEST_ATTR_NAME2 ATTRIBUTE_OPEN_TEST_ATTR_NAME "2" +#define ATTRIBUTE_OPEN_TEST_ATTR_NAME3 ATTRIBUTE_OPEN_TEST_ATTR_NAME "3" + +#define ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_GROUP_NAME "attribute_open_invalid_params_test" +#define ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_SPACE_RANK 1 +#define ATTRIBUTE_OPEN_INVALID_PARAMS_TEST_ATTR_NAME "attribute_open_invalid_params_attr" + +#define ATTRIBUTE_WRITE_TEST_ATTR_DTYPE_SIZE sizeof(int) +#define ATTRIBUTE_WRITE_TEST_ATTR_DTYPE H5T_NATIVE_INT +#define ATTRIBUTE_WRITE_TEST_SPACE_RANK 1 +#define ATTRIBUTE_WRITE_TEST_GROUP_NAME "attr_write_test" +#define ATTRIBUTE_WRITE_TEST_ATTR_NAME "write_test_attr" + +#define ATTRIBUTE_WRITE_INVALID_PARAMS_TEST_ATTR_DTYPE_SIZE sizeof(int) +#define ATTRIBUTE_WRITE_INVALID_PARAMS_TEST_ATTR_DTYPE H5T_NATIVE_INT +#define ATTRIBUTE_WRITE_INVALID_PARAMS_TEST_SPACE_RANK 1 +#define ATTRIBUTE_WRITE_INVALID_PARAMS_TEST_GROUP_NAME "attr_write_invalid_params_test" +#define ATTRIBUTE_WRITE_INVALID_PARAMS_TEST_ATTR_NAME "invalid_params_write_test_attr" + +#define ATTRIBUTE_READ_TEST_ATTR_DTYPE_SIZE sizeof(int) +#define ATTRIBUTE_READ_TEST_ATTR_DTYPE H5T_NATIVE_INT +#define ATTRIBUTE_READ_TEST_SPACE_RANK 1 +#define ATTRIBUTE_READ_TEST_GROUP_NAME "attr_read_test" +#define ATTRIBUTE_READ_TEST_ATTR_NAME "read_test_attr" + +#define ATTRIBUTE_READ_INVALID_PARAMS_TEST_ATTR_DTYPE_SIZE sizeof(int) +#define ATTRIBUTE_READ_INVALID_PARAMS_TEST_ATTR_DTYPE H5T_NATIVE_INT +#define ATTRIBUTE_READ_INVALID_PARAMS_TEST_SPACE_RANK 1 +#define ATTRIBUTE_READ_INVALID_PARAMS_TEST_GROUP_NAME "attr_read_invalid_params_test" +#define ATTRIBUTE_READ_INVALID_PARAMS_TEST_ATTR_NAME "invalid_params_read_test_attr" + +#define ATTRIBUTE_READ_EMPTY_SPACE_RANK 1 +#define ATTRIBUTE_READ_EMPTY_ATTR_GROUP_NAME "read_empty_attr_test" +#define ATTRIBUTE_READ_EMPTY_ATTR_NAME "read_empty_attr" +#define ATTRIBUTE_READ_EMPTY_DTYPE H5T_NATIVE_INT +#define ATTRIBUTE_READ_EMPTY_DTYPE_SIZE sizeof(int) + +#define ATTRIBUTE_GET_SPACE_TYPE_TEST_SPACE_RANK 1 +#define ATTRIBUTE_GET_SPACE_TYPE_TEST_GROUP_NAME "get_attr_space_type_test" +#define ATTRIBUTE_GET_SPACE_TYPE_TEST_ATTR_NAME "get_space_type_test_attr" + +#define ATTRIBUTE_GET_SPACE_TYPE_INVALID_PARAMS_TEST_SPACE_RANK 1 +#define ATTRIBUTE_GET_SPACE_TYPE_INVALID_PARAMS_TEST_GROUP_NAME "get_attr_space_type_invalid_params_test" +#define ATTRIBUTE_GET_SPACE_TYPE_INVALID_PARAMS_TEST_ATTR_NAME "get_space_type_invalid_params_test_attr" + +#define ATTRIBUTE_PROPERTY_LIST_TEST_ATTRIBUTE_NAME1 "property_list_test_attribute1" +#define ATTRIBUTE_PROPERTY_LIST_TEST_ATTRIBUTE_NAME2 "property_list_test_attribute2" +#define ATTRIBUTE_PROPERTY_LIST_TEST_SUBGROUP_NAME "attribute_property_list_test_group" +#define ATTRIBUTE_PROPERTY_LIST_TEST_SPACE_RANK 1 + +#define ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME "attr_name_retrieval_attr" +#define ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME2 ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME "2" +#define ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME3 ATTRIBUTE_GET_NAME_TEST_ATTRIBUTE_NAME "3" +#define ATTRIBUTE_GET_NAME_TEST_SPACE_RANK 1 +#define ATTRIBUTE_GET_NAME_TEST_GROUP_NAME "retrieve_attr_name_test" + +#define ATTRIBUTE_GET_NAME_INVALID_PARAMS_TEST_ATTRIBUTE_NAME "invalid_params_attr_name_retrieval_attr" +#define ATTRIBUTE_GET_NAME_INVALID_PARAMS_TEST_SPACE_RANK 1 +#define ATTRIBUTE_GET_NAME_INVALID_PARAMS_TEST_GROUP_NAME "retrieve_attr_name_invalid_params_test" + +#define ATTRIBUTE_GET_INFO_TEST_SPACE_RANK 1 +#define ATTRIBUTE_GET_INFO_TEST_GROUP_NAME "attr_get_info_test" +#define ATTRIBUTE_GET_INFO_TEST_ATTR_NAME "get_info_test_attr" +#define ATTRIBUTE_GET_INFO_TEST_ATTR_NAME2 ATTRIBUTE_GET_INFO_TEST_ATTR_NAME "2" +#define ATTRIBUTE_GET_INFO_TEST_ATTR_NAME3 ATTRIBUTE_GET_INFO_TEST_ATTR_NAME "3" + +#define ATTRIBUTE_GET_INFO_INVALID_PARAMS_TEST_SPACE_RANK 1 +#define ATTRIBUTE_GET_INFO_INVALID_PARAMS_TEST_GROUP_NAME "attr_get_info_invalid_params_test" +#define ATTRIBUTE_GET_INFO_INVALID_PARAMS_TEST_ATTR_NAME "invalid_params_get_info_test_attr" + +#define ATTRIBUTE_RENAME_TEST_SPACE_RANK 1 +#define ATTRIBUTE_RENAME_TEST_GROUP_NAME "attr_rename_test" +#define ATTRIBUTE_RENAME_TEST_ATTR_NAME "rename_test_attr" +#define ATTRIBUTE_RENAME_TEST_ATTR_NAME2 "rename_test_attr2" +#define ATTRIBUTE_RENAME_TEST_NEW_NAME "renamed_attr" +#define ATTRIBUTE_RENAME_TEST_NEW_NAME2 "renamed_attr2" + +#define ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_SPACE_RANK 1 +#define ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_GROUP_NAME "attr_rename_invalid_params_test" +#define ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_ATTR_NAME "invalid_params_rename_test_attr" +#define ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_ATTR_NAME2 "invalid_params_rename_test_attr2" +#define ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_NEW_NAME "invalid_params_renamed_attr" +#define ATTRIBUTE_RENAME_INVALID_PARAMS_TEST_NEW_NAME2 "invalid_params_renamed_attr2" + +#define ATTRIBUTE_ITERATE_TEST_ATTR_NAME_BUF_SIZE 256 +#define ATTRIBUTE_ITERATE_TEST_DSET_SPACE_RANK 2 +#define ATTRIBUTE_ITERATE_TEST_ATTR_SPACE_RANK 1 +#define ATTRIBUTE_ITERATE_TEST_GRP_SUBGROUP_NAME "attribute_iterate_group_test" +#define ATTRIBUTE_ITERATE_TEST_DSET_SUBGROUP_NAME "attribute_iterate_dset_test" +#define ATTRIBUTE_ITERATE_TEST_DTYPE_SUBGROUP_NAME "attribute_iterate_datatype_test" +#define ATTRIBUTE_ITERATE_TEST_DSET_NAME "attribute_iterate_dset" +#define ATTRIBUTE_ITERATE_TEST_DTYPE_NAME "attribute_iterate_dtype" +#define ATTRIBUTE_ITERATE_TEST_ATTR_NAME "iter_attr" +#define ATTRIBUTE_ITERATE_TEST_NUM_ATTRS 4 + +#define ATTRIBUTE_ITERATE_TEST_0_ATTRIBUTES_DSET_SPACE_RANK 2 +#define ATTRIBUTE_ITERATE_TEST_0_ATTRIBUTES_SUBGROUP_NAME "attribute_iterate_test_0_attributes" +#define ATTRIBUTE_ITERATE_TEST_0_ATTRIBUTES_DSET_NAME "attribute_iterate_dset" + +#define ATTRIBUTE_ITERATE_INVALID_PARAMS_TEST_ATTR_SPACE_RANK 1 +#define ATTRIBUTE_ITERATE_INVALID_PARAMS_TEST_SUBGROUP_NAME "attribute_iterate_invalid_params_test" +#define ATTRIBUTE_ITERATE_INVALID_PARAMS_TEST_ATTR_NAME "invalid_params_iter_attr1" +#define ATTRIBUTE_ITERATE_INVALID_PARAMS_TEST_ATTR_NAME2 "invalid_params_iter_attr2" +#define ATTRIBUTE_ITERATE_INVALID_PARAMS_TEST_ATTR_NAME3 "invalid_params_iter_attr3" +#define ATTRIBUTE_ITERATE_INVALID_PARAMS_TEST_ATTR_NAME4 "invalid_params_iter_attr4" + +#define ATTRIBUTE_DELETION_TEST_SPACE_RANK 1 +#define ATTRIBUTE_DELETION_TEST_GROUP_NAME "attr_deletion_test" +#define ATTRIBUTE_DELETION_TEST_ATTR_NAME "attr_to_be_deleted" +#define ATTRIBUTE_DELETION_TEST_ATTR_NAME2 ATTRIBUTE_DELETION_TEST_ATTR_NAME "2" +#define ATTRIBUTE_DELETION_TEST_ATTR_NAME3 ATTRIBUTE_DELETION_TEST_ATTR_NAME "3" + +#define ATTRIBUTE_DELETION_INVALID_PARAMS_TEST_SPACE_RANK 1 +#define ATTRIBUTE_DELETION_INVALID_PARAMS_TEST_GROUP_NAME "attr_deletion_invalid_params_test" +#define ATTRIBUTE_DELETION_INVALID_PARAMS_TEST_ATTR_NAME "invalid_params_attr_to_be_deleted" + +#define ATTRIBUTE_EXISTS_TEST_GROUP_NAME "attr_exists_test" +#define ATTRIBUTE_EXISTS_TEST_SPACE_RANK 1 +#define ATTRIBUTE_EXISTS_TEST_ATTR_NAME "attr_exists" + +#define ATTRIBUTE_EXISTS_INVALID_PARAMS_TEST_SPACE_RANK 1 +#define ATTRIBUTE_EXISTS_INVALID_PARAMS_TEST_GROUP_NAME "attr_exists_invalid_params_test" +#define ATTRIBUTE_EXISTS_INVALID_PARAMS_TEST_ATTR_NAME "invalid_params_attr_exists" + +#define ATTRIBUTE_MANY_GROUP_NAME "group_for_many_attributes" +#define ATTRIBUTE_MANY_NAME_BUF_SIZE 32U +#define ATTRIBUTE_MANY_NUMB 64U +#define ATTRIBUTE_MANY_SPACE_RANK 1 + +#define ATTRIBUTE_DUPLICATE_ID_GRP_NAME "attr_duplicate_open_test" +#define ATTRIBUTE_DUPLICATE_ID_ATTR_NAME "attr_duplicated_id" +#define ATTRIBUTE_DUPLICATE_ID_SPACE_RANK 1 + +#define ATTRIBUTE_GET_NUM_ATTRS_TEST_GRP_NAME "get_num_attrs_test" +#define ATTRIBUTE_GET_NUM_ATTRS_TEST_ATTR_NAME "get_num_attrs_test_attribute" +#define ATTRIBUTE_GET_NUM_ATTRS_TEST_SPACE_RANK 1 + +#define ATTRIBUTE_SHARED_DTYPE_NAME "Datatype" +#define ATTRIBUTE_SHARED_DTYPE_GROUP_NAME "shared_dtype_group" +#define ATTRIBUTE_SHARED_DTYPE_ATTR_NAME "shared_dtype_attr" +#define ATTRIBUTE_SHARED_DTYPE_DSET_NAME "shared_dtype_dset" +#define ATTRIBUTE_SHARED_DTYPE_SPACE_RANK 1 + +#endif diff --git a/test/API/H5_api_dataset_test.c b/test/API/H5_api_dataset_test.c new file mode 100644 index 0000000..35a19f3 --- /dev/null +++ b/test/API/H5_api_dataset_test.c @@ -0,0 +1,11683 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "H5_api_dataset_test.h" + +/* + * XXX: H5Dread_chunk/H5Dwrite_chunk, H5Dfill/scatter/gather + */ + +static int test_create_dataset_under_root(void); +static int test_create_dataset_under_existing_group(void); +static int test_create_dataset_invalid_params(void); +static int test_create_anonymous_dataset(void); +static int test_create_anonymous_dataset_invalid_params(void); +static int test_create_dataset_null_space(void); +static int test_create_dataset_scalar_space(void); +static int test_create_zero_dim_dset(void); +static int test_create_dataset_random_shapes(void); +static int test_create_dataset_predefined_types(void); +static int test_create_dataset_string_types(void); +static int test_create_dataset_compound_types(void); +static int test_create_dataset_enum_types(void); +static int test_create_dataset_array_types(void); +static int test_create_dataset_creation_properties(void); +static int test_create_many_dataset(void); +static int test_open_dataset(void); +static int test_open_dataset_invalid_params(void); +static int test_close_dataset_invalid_params(void); +static int test_get_dataset_space_and_type(void); +static int test_get_dataset_space_and_type_invalid_params(void); +static int test_get_dataset_space_status(void); +static int test_get_dataset_space_status_invalid_params(void); +static int test_dataset_property_lists(void); +static int test_get_dataset_storage_size(void); +static int test_get_dataset_storage_size_invalid_params(void); +static int test_get_dataset_chunk_storage_size(void); +static int test_get_dataset_chunk_storage_size_invalid_params(void); +static int test_get_dataset_offset(void); +static int test_get_dataset_offset_invalid_params(void); +static int test_read_dataset_small_all(void); +static int test_read_dataset_small_hyperslab(void); +static int test_read_dataset_small_point_selection(void); +static int test_dataset_io_point_selections(void); +#ifndef NO_LARGE_TESTS +static int test_read_dataset_large_all(void); +static int test_read_dataset_large_hyperslab(void); +static int test_read_dataset_large_point_selection(void); +#endif +static int test_read_dataset_invalid_params(void); +static int test_write_dataset_small_all(void); +static int test_write_dataset_small_hyperslab(void); +static int test_write_dataset_small_point_selection(void); +#ifndef NO_LARGE_TESTS +static int test_write_dataset_large_all(void); +static int test_write_dataset_large_hyperslab(void); +static int test_write_dataset_large_point_selection(void); +#endif +static int test_write_dataset_data_verification(void); +static int test_write_dataset_invalid_params(void); +static int test_dataset_builtin_type_conversion(void); +static int test_dataset_compound_partial_io(void); +static int test_dataset_set_extent_chunked_unlimited(void); +static int test_dataset_set_extent_chunked_fixed(void); +static int test_dataset_set_extent_data(void); +static int test_dataset_set_extent_double_handles(void); +static int test_dataset_set_extent_invalid_params(void); +static int test_flush_dataset(void); +static int test_flush_dataset_invalid_params(void); +static int test_refresh_dataset(void); +static int test_refresh_dataset_invalid_params(void); + +/* + * Chunking tests + */ +static int test_create_single_chunk_dataset(void); +static int test_write_single_chunk_dataset(void); +static int test_create_multi_chunk_dataset(void); +static int test_write_multi_chunk_dataset_same_shape_read(void); +static int test_write_multi_chunk_dataset_diff_shape_read(void); +static int test_overwrite_multi_chunk_dataset_same_shape_read(void); +static int test_overwrite_multi_chunk_dataset_diff_shape_read(void); +static int test_read_partial_chunk_all_selection(void); +static int test_read_partial_chunk_hyperslab_selection(void); +static int test_read_partial_chunk_point_selection(void); + +static int test_get_vlen_buf_size(void); + +/* + * The array of dataset tests to be performed. + */ +static int (*dataset_tests[])(void) = { + test_create_dataset_under_root, + test_create_dataset_under_existing_group, + test_create_dataset_invalid_params, + test_create_anonymous_dataset, + test_create_anonymous_dataset_invalid_params, + test_create_dataset_null_space, + test_create_dataset_scalar_space, + test_create_zero_dim_dset, + test_create_dataset_random_shapes, + test_create_dataset_predefined_types, + test_create_dataset_string_types, + test_create_dataset_compound_types, + test_create_dataset_enum_types, + test_create_dataset_array_types, + test_create_dataset_creation_properties, + test_create_many_dataset, + test_open_dataset, + test_open_dataset_invalid_params, + test_close_dataset_invalid_params, + test_get_dataset_space_and_type, + test_get_dataset_space_and_type_invalid_params, + test_get_dataset_space_status, + test_get_dataset_space_status_invalid_params, + test_dataset_property_lists, + test_get_dataset_storage_size, + test_get_dataset_storage_size_invalid_params, + test_get_dataset_chunk_storage_size, + test_get_dataset_chunk_storage_size_invalid_params, + test_get_dataset_offset, + test_get_dataset_offset_invalid_params, + test_read_dataset_small_all, + test_read_dataset_small_hyperslab, + test_read_dataset_small_point_selection, + test_dataset_io_point_selections, +#ifndef NO_LARGE_TESTS + test_read_dataset_large_all, + test_read_dataset_large_hyperslab, + test_read_dataset_large_point_selection, +#endif + test_read_dataset_invalid_params, + test_write_dataset_small_all, + test_write_dataset_small_hyperslab, + test_write_dataset_small_point_selection, +#ifndef NO_LARGE_TESTS + test_write_dataset_large_all, + test_write_dataset_large_hyperslab, + test_write_dataset_large_point_selection, +#endif + test_write_dataset_data_verification, + test_write_dataset_invalid_params, + test_dataset_builtin_type_conversion, + test_dataset_compound_partial_io, + test_dataset_set_extent_chunked_unlimited, + test_dataset_set_extent_chunked_fixed, + test_dataset_set_extent_data, + test_dataset_set_extent_double_handles, + test_dataset_set_extent_invalid_params, + test_flush_dataset, + test_flush_dataset_invalid_params, + test_refresh_dataset, + test_refresh_dataset_invalid_params, + test_create_single_chunk_dataset, + test_write_single_chunk_dataset, + test_create_multi_chunk_dataset, + test_write_multi_chunk_dataset_same_shape_read, + test_write_multi_chunk_dataset_diff_shape_read, + test_overwrite_multi_chunk_dataset_same_shape_read, + test_overwrite_multi_chunk_dataset_diff_shape_read, + test_read_partial_chunk_all_selection, + test_read_partial_chunk_hyperslab_selection, + test_read_partial_chunk_point_selection, + test_get_vlen_buf_size, +}; + +/* + * A test to check that a dataset can be + * created under the root group. + */ +static int +test_create_dataset_under_root(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + + TESTING("dataset creation under root group"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file or dataset aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((fspace_id = generate_random_dataspace(DATASET_CREATE_UNDER_ROOT_SPACE_RANK, NULL, NULL, FALSE)) < 0) + TEST_ERROR; + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + /* Create the Dataset under the root group of the file */ + if ((dset_id = H5Dcreate2(file_id, DATASET_CREATE_UNDER_ROOT_DSET_NAME, dset_dtype, fspace_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_CREATE_UNDER_ROOT_DSET_NAME); + goto error; + } + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + H5Tclose(dset_dtype); + H5Dclose(dset_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a dataset can be created + * under a group that is not the root group. + */ +static int +test_create_dataset_under_existing_group(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + + TESTING("dataset creation under an existing group"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_CREATE_UNDER_EXISTING_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", DATASET_CREATE_UNDER_EXISTING_GROUP_NAME); + goto error; + } + + if ((fspace_id = generate_random_dataspace(DATASET_CREATE_UNDER_EXISTING_SPACE_RANK, NULL, NULL, FALSE)) < + 0) + TEST_ERROR; + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_CREATE_UNDER_EXISTING_DSET_NAME, dset_dtype, fspace_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_CREATE_UNDER_EXISTING_DSET_NAME); + goto error; + } + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + H5Tclose(dset_dtype); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a dataset can't be created + * when H5Dcreate is passed invalid parameters. + */ +static int +test_create_dataset_invalid_params(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + + TESTING_MULTIPART("H5Dcreate with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_CREATE_INVALID_PARAMS_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", DATASET_CREATE_INVALID_PARAMS_GROUP_NAME); + goto error; + } + + if ((fspace_id = generate_random_dataspace(DATASET_CREATE_INVALID_PARAMS_SPACE_RANK, NULL, NULL, FALSE)) < + 0) + TEST_ERROR; + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Dcreate_invalid_loc_id) + { + TESTING_2("H5Dcreate with an invalid loc_id"); + + H5E_BEGIN_TRY + { + dset_id = H5Dcreate2(H5I_INVALID_HID, DATASET_CREATE_INVALID_PARAMS_DSET_NAME, dset_dtype, + fspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (dset_id >= 0) { + H5_FAILED(); + HDprintf(" created dataset using H5Dcreate with an invalid loc_id!\n"); + H5Dclose(dset_id); + PART_ERROR(H5Dcreate_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Dcreate_invalid_loc_id); + + PART_BEGIN(H5Dcreate_invalid_dataset_name) + { + TESTING_2("H5Dcreate with an invalid dataset name"); + + H5E_BEGIN_TRY + { + dset_id = + H5Dcreate2(group_id, NULL, dset_dtype, fspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (dset_id >= 0) { + H5_FAILED(); + HDprintf(" created dataset using H5Dcreate with a NULL dataset name!\n"); + H5Dclose(dset_id); + PART_ERROR(H5Dcreate_invalid_dataset_name); + } + + H5E_BEGIN_TRY + { + dset_id = + H5Dcreate2(group_id, "", dset_dtype, fspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (dset_id >= 0) { + H5_FAILED(); + HDprintf(" created dataset using H5Dcreate with an invalid dataset name of ''!\n"); + H5Dclose(dset_id); + PART_ERROR(H5Dcreate_invalid_dataset_name); + } + + PASSED(); + } + PART_END(H5Dcreate_invalid_dataset_name); + + PART_BEGIN(H5Dcreate_invalid_datatype) + { + TESTING_2("H5Dcreate with an invalid datatype"); + + H5E_BEGIN_TRY + { + dset_id = H5Dcreate2(group_id, DATASET_CREATE_INVALID_PARAMS_DSET_NAME, H5I_INVALID_HID, + fspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (dset_id >= 0) { + H5_FAILED(); + HDprintf(" created dataset using H5Dcreate with an invalid datatype!\n"); + H5Dclose(dset_id); + PART_ERROR(H5Dcreate_invalid_datatype); + } + + PASSED(); + } + PART_END(H5Dcreate_invalid_datatype); + + PART_BEGIN(H5Dcreate_invalid_dataspace) + { + TESTING_2("H5Dcreate with an invalid dataspace"); + + H5E_BEGIN_TRY + { + dset_id = H5Dcreate2(group_id, DATASET_CREATE_INVALID_PARAMS_DSET_NAME, dset_dtype, + H5I_INVALID_HID, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (dset_id >= 0) { + H5_FAILED(); + HDprintf(" created dataset using H5Dcreate with an invalid dataspace!\n"); + H5Dclose(dset_id); + PART_ERROR(H5Dcreate_invalid_dataspace); + } + + PASSED(); + } + PART_END(H5Dcreate_invalid_dataspace); + + PART_BEGIN(H5Dcreate_invalid_lcpl) + { + TESTING_2("H5Dcreate with an invalid LCPL"); + + H5E_BEGIN_TRY + { + dset_id = H5Dcreate2(group_id, DATASET_CREATE_INVALID_PARAMS_DSET_NAME, dset_dtype, fspace_id, + H5I_INVALID_HID, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (dset_id >= 0) { + H5_FAILED(); + HDprintf(" created dataset using H5Dcreate with an invalid LCPL!\n"); + H5Dclose(dset_id); + PART_ERROR(H5Dcreate_invalid_lcpl); + } + + PASSED(); + } + PART_END(H5Dcreate_invalid_lcpl); + + PART_BEGIN(H5Dcreate_invalid_dcpl) + { + TESTING_2("H5Dcreate with an invalid DCPL"); + + H5E_BEGIN_TRY + { + dset_id = H5Dcreate2(group_id, DATASET_CREATE_INVALID_PARAMS_DSET_NAME, dset_dtype, fspace_id, + H5P_DEFAULT, H5I_INVALID_HID, H5P_DEFAULT); + } + H5E_END_TRY; + + if (dset_id >= 0) { + H5_FAILED(); + HDprintf(" created dataset using H5Dcreate with an invalid DCPL!\n"); + H5Dclose(dset_id); + PART_ERROR(H5Dcreate_invalid_dcpl); + } + + PASSED(); + } + PART_END(H5Dcreate_invalid_dcpl); + + PART_BEGIN(H5Dcreate_invalid_dapl) + { + TESTING_2("H5Dcreate with an invalid DAPL"); + + H5E_BEGIN_TRY + { + dset_id = H5Dcreate2(group_id, DATASET_CREATE_INVALID_PARAMS_DSET_NAME, dset_dtype, fspace_id, + H5P_DEFAULT, H5P_DEFAULT, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (dset_id >= 0) { + H5_FAILED(); + HDprintf(" created dataset using H5Dcreate with an invalid DAPL!\n"); + H5Dclose(dset_id); + PART_ERROR(H5Dcreate_invalid_dapl); + } + + PASSED(); + } + PART_END(H5Dcreate_invalid_dapl); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + H5Tclose(dset_dtype); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that an anonymous dataset can be created. + */ +static int +test_create_anonymous_dataset(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + + TESTING("anonymous dataset creation"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_CREATE_ANONYMOUS_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", DATASET_CREATE_ANONYMOUS_GROUP_NAME); + goto error; + } + + if ((fspace_id = generate_random_dataspace(DATASET_CREATE_ANONYMOUS_SPACE_RANK, NULL, NULL, FALSE)) < 0) + TEST_ERROR; + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate_anon(group_id, dset_dtype, fspace_id, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create anonymous dataset\n"); + goto error; + } + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + H5Tclose(dset_dtype); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that an anonymous dataset can't + * be created when H5Dcreate_anon is passed invalid + * parameters. + */ +static int +test_create_anonymous_dataset_invalid_params(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + + TESTING_MULTIPART("anonymous dataset creation with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_CREATE_ANONYMOUS_INVALID_PARAMS_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", + DATASET_CREATE_ANONYMOUS_INVALID_PARAMS_GROUP_NAME); + goto error; + } + + if ((fspace_id = generate_random_dataspace(DATASET_CREATE_ANONYMOUS_INVALID_PARAMS_SPACE_RANK, NULL, NULL, + FALSE)) < 0) + TEST_ERROR; + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Dcreate_anon_invalid_loc_id) + { + TESTING_2("H5Dcreate_anon with an invalid loc_id"); + + H5E_BEGIN_TRY + { + dset_id = H5Dcreate_anon(H5I_INVALID_HID, dset_dtype, fspace_id, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (dset_id >= 0) { + H5_FAILED(); + HDprintf(" created anonymous dataset using an invalid loc_id!\n"); + H5Dclose(dset_id); + PART_ERROR(H5Dcreate_anon_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Dcreate_anon_invalid_loc_id); + + PART_BEGIN(H5Dcreate_anon_invalid_datatype) + { + TESTING_2("H5Dcreate_anon with an invalid dataset datatype"); + + H5E_BEGIN_TRY + { + dset_id = H5Dcreate_anon(group_id, H5I_INVALID_HID, fspace_id, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (dset_id >= 0) { + H5_FAILED(); + HDprintf(" created anonymous dataset using an invalid dataset datatype!\n"); + H5Dclose(dset_id); + PART_ERROR(H5Dcreate_anon_invalid_datatype); + } + + PASSED(); + } + PART_END(H5Dcreate_anon_invalid_datatype); + + PART_BEGIN(H5Dcreate_anon_invalid_dataspace) + { + TESTING_2("H5Dcreate_anon with an invalid dataset dataspace"); + + H5E_BEGIN_TRY + { + dset_id = H5Dcreate_anon(group_id, dset_dtype, H5I_INVALID_HID, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (dset_id >= 0) { + H5_FAILED(); + HDprintf(" created anonymous dataset using an invalid dataset dataspace!\n"); + H5Dclose(dset_id); + PART_ERROR(H5Dcreate_anon_invalid_dataspace); + } + + PASSED(); + } + PART_END(H5Dcreate_anon_invalid_dataspace); + + PART_BEGIN(H5Dcreate_anon_invalid_dcpl) + { + TESTING_2("H5Dcreate_anon with an invalid DCPL"); + + H5E_BEGIN_TRY + { + dset_id = H5Dcreate_anon(group_id, dset_dtype, fspace_id, H5I_INVALID_HID, H5P_DEFAULT); + } + H5E_END_TRY; + + if (dset_id >= 0) { + H5_FAILED(); + HDprintf(" created anonymous dataset using an invalid DCPL!\n"); + H5Dclose(dset_id); + PART_ERROR(H5Dcreate_anon_invalid_dcpl); + } + + PASSED(); + } + PART_END(H5Dcreate_anon_invalid_dcpl); + + PART_BEGIN(H5Dcreate_anon_invalid_dapl) + { + TESTING_2("H5Dcreate_anon with an invalid DAPL"); + + H5E_BEGIN_TRY + { + dset_id = H5Dcreate_anon(group_id, dset_dtype, fspace_id, H5P_DEFAULT, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (dset_id >= 0) { + H5_FAILED(); + HDprintf(" created anonymous dataset using an invalid DAPL!\n"); + H5Dclose(dset_id); + PART_ERROR(H5Dcreate_anon_invalid_dapl); + } + + PASSED(); + } + PART_END(H5Dcreate_anon_invalid_dapl); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + H5Tclose(dset_dtype); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that creating a dataset with a NULL + * dataspace is not problematic. + */ +static int +test_create_dataset_null_space(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + + TESTING("dataset creation with a NULL dataspace"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_CREATE_NULL_DATASPACE_TEST_SUBGROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + DATASET_CREATE_NULL_DATASPACE_TEST_SUBGROUP_NAME); + goto error; + } + + if ((fspace_id = H5Screate(H5S_NULL)) < 0) + TEST_ERROR; + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_CREATE_NULL_DATASPACE_TEST_DSET_NAME, dset_dtype, fspace_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_CREATE_NULL_DATASPACE_TEST_DSET_NAME); + goto error; + } + + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + + if ((dset_id = H5Dopen2(group_id, DATASET_CREATE_NULL_DATASPACE_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_CREATE_NULL_DATASPACE_TEST_DSET_NAME); + goto error; + } + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + H5Tclose(dset_dtype); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that creating a dataset with a scalar + * dataspace is not problematic. + */ +static int +test_create_dataset_scalar_space(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + + TESTING("dataset creation with a SCALAR dataspace"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_CREATE_SCALAR_DATASPACE_TEST_SUBGROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + DATASET_CREATE_SCALAR_DATASPACE_TEST_SUBGROUP_NAME); + goto error; + } + + if ((fspace_id = H5Screate(H5S_SCALAR)) < 0) + TEST_ERROR; + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_CREATE_SCALAR_DATASPACE_TEST_DSET_NAME, dset_dtype, fspace_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_CREATE_SCALAR_DATASPACE_TEST_DSET_NAME); + goto error; + } + + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + + if ((dset_id = H5Dopen2(group_id, DATASET_CREATE_SCALAR_DATASPACE_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_CREATE_SCALAR_DATASPACE_TEST_DSET_NAME); + goto error; + } + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + H5Tclose(dset_dtype); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that creating a dataset with a dataspace + * which contains a 0-sized dimension is not problematic. + */ +static int +test_create_zero_dim_dset(void) +{ + hsize_t dims[ZERO_DIM_DSET_TEST_SPACE_RANK] = {0}; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + int data[1]; + + TESTING("creation of 0-sized dataset"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATATYPE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATATYPE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ZERO_DIM_DSET_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", ZERO_DIM_DSET_TEST_GROUP_NAME); + goto error; + } + + if ((fspace_id = H5Screate_simple(1, dims, NULL)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, ZERO_DIM_DSET_TEST_DSET_NAME, H5T_NATIVE_INT, fspace_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to create 0-sized dataset\n"); + goto error; + } + + if (H5Sselect_none(fspace_id) < 0) { + H5_FAILED(); + HDprintf(" failed to set none selection in dataset's file dataspace\n"); + goto error; + } + + /* Attempt to write 0 elements to dataset */ + if (H5Dwrite(dset_id, H5T_NATIVE_INT, fspace_id, fspace_id, H5P_DEFAULT, data) < 0) { + H5_FAILED(); + HDprintf(" failed to write 0 elements to 0-sized dataset\n"); + goto error; + } + + /* Attempt to read 0 elements from dataset */ + if (H5Dread(dset_id, H5T_NATIVE_INT, fspace_id, fspace_id, H5P_DEFAULT, data) < 0) { + H5_FAILED(); + HDprintf(" failed to read 0 elements from 0-sized dataset\n"); + goto error; + } + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a dataset can be created with + * a variety of different dataspace shapes. + */ +static int +test_create_dataset_random_shapes(void) +{ + size_t i; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID, space_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + + TESTING("dataset creation with random dimension sizes"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_SHAPE_TEST_SUBGROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group\n"); + goto error; + } + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + for (i = 0; i < DATASET_SHAPE_TEST_NUM_ITERATIONS; i++) { + char name[100]; + int ndims = rand() % DATASET_SHAPE_TEST_MAX_DIMS + 1; + + if ((space_id = generate_random_dataspace(ndims, NULL, NULL, FALSE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataspace\n"); + goto error; + } + + HDsprintf(name, "%s%zu", DATASET_SHAPE_TEST_DSET_BASE_NAME, i + 1); + + if ((dset_id = H5Dcreate2(group_id, name, dset_dtype, space_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset\n"); + goto error; + } + + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + } + + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(space_id); + H5Tclose(dset_dtype); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a dataset can be created using + * each of the predefined integer and floating-point + * datatypes. + */ +static int +test_create_dataset_predefined_types(void) +{ + size_t i; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t predefined_type_test_table[] = {H5T_STD_U8LE, H5T_STD_U8BE, H5T_STD_I8LE, H5T_STD_I8BE, + H5T_STD_U16LE, H5T_STD_U16BE, H5T_STD_I16LE, H5T_STD_I16BE, + H5T_STD_U32LE, H5T_STD_U32BE, H5T_STD_I32LE, H5T_STD_I32BE, + H5T_STD_U64LE, H5T_STD_U64BE, H5T_STD_I64LE, H5T_STD_I64BE, + H5T_IEEE_F32LE, H5T_IEEE_F32BE, H5T_IEEE_F64LE, H5T_IEEE_F64BE}; + + TESTING("dataset creation with predefined datatypes"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_PREDEFINED_TYPE_TEST_SUBGROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create sub-container group '%s'\n", + DATASET_PREDEFINED_TYPE_TEST_SUBGROUP_NAME); + goto error; + } + + for (i = 0; i < ARRAY_LENGTH(predefined_type_test_table); i++) { + char name[100]; + + if ((fspace_id = + generate_random_dataspace(DATASET_PREDEFINED_TYPE_TEST_SPACE_RANK, NULL, NULL, FALSE)) < 0) + TEST_ERROR; + + HDsprintf(name, "%s%zu", DATASET_PREDEFINED_TYPE_TEST_BASE_NAME, i); + + if ((dset_id = H5Dcreate2(group_id, name, predefined_type_test_table[i], fspace_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", name); + goto error; + } + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + + if ((dset_id = H5Dopen2(group_id, name, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to open dataset '%s'\n", name); + goto error; + } + + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + } + + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a dataset can be created using + * string datatypes. + */ +static int +test_create_dataset_string_types(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id_fixed = H5I_INVALID_HID, dset_id_variable = H5I_INVALID_HID; + hid_t type_id_fixed = H5I_INVALID_HID, type_id_variable = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + + TESTING_MULTIPART("dataset creation with string types"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_STRING_TYPE_TEST_SUBGROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", DATASET_STRING_TYPE_TEST_SUBGROUP_NAME); + goto error; + } + + if ((type_id_fixed = H5Tcreate(H5T_STRING, DATASET_STRING_TYPE_TEST_STRING_LENGTH)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create fixed-length string type\n"); + goto error; + } + + if ((type_id_variable = H5Tcreate(H5T_STRING, H5T_VARIABLE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create variable-length string type\n"); + goto error; + } + + if ((fspace_id = generate_random_dataspace(DATASET_STRING_TYPE_TEST_SPACE_RANK, NULL, NULL, FALSE)) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Dcreate_fixed_string_type) + { + TESTING_2("creation of fixed-size string dataset"); + + if ((dset_id_fixed = H5Dcreate2(group_id, DATASET_STRING_TYPE_TEST_DSET_NAME1, type_id_fixed, + fspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create fixed-length string dataset '%s'\n", + DATASET_STRING_TYPE_TEST_DSET_NAME1); + PART_ERROR(H5Dcreate_fixed_string_type); + } + + if (dset_id_fixed >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id_fixed); + } + H5E_END_TRY; + dset_id_fixed = H5I_INVALID_HID; + } + + if ((dset_id_fixed = H5Dopen2(group_id, DATASET_STRING_TYPE_TEST_DSET_NAME1, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to open dataset '%s'\n", DATASET_STRING_TYPE_TEST_DSET_NAME1); + PART_ERROR(H5Dcreate_fixed_string_type); + } + + PASSED(); + } + PART_END(H5Dcreate_fixed_string_type); + + PART_BEGIN(H5Dcreate_variable_string_type) + { + TESTING_2("creation of variable-length string dataset"); + + if ((dset_id_variable = + H5Dcreate2(group_id, DATASET_STRING_TYPE_TEST_DSET_NAME2, type_id_variable, fspace_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create variable-length string dataset '%s'\n", + DATASET_STRING_TYPE_TEST_DSET_NAME2); + PART_ERROR(H5Dcreate_variable_string_type); + } + + if (dset_id_variable >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id_variable); + } + H5E_END_TRY; + dset_id_variable = H5I_INVALID_HID; + } + + if ((dset_id_variable = H5Dopen2(group_id, DATASET_STRING_TYPE_TEST_DSET_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" failed to open dataset '%s'\n", DATASET_STRING_TYPE_TEST_DSET_NAME2); + PART_ERROR(H5Dcreate_variable_string_type); + } + + PASSED(); + } + PART_END(H5Dcreate_variable_string_type); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Tclose(type_id_fixed) < 0) + TEST_ERROR; + if (H5Tclose(type_id_variable) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id_fixed) < 0) + TEST_ERROR; + if (H5Dclose(dset_id_variable) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Tclose(type_id_fixed); + H5Tclose(type_id_variable); + H5Sclose(fspace_id); + H5Dclose(dset_id_fixed); + H5Dclose(dset_id_variable); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a dataset can be created using + * a variety of compound datatypes. + */ +static int +test_create_dataset_compound_types(void) +{ + size_t i, j; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t compound_type = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t type_pool[DATASET_COMPOUND_TYPE_TEST_MAX_SUBTYPES]; + int num_passes; + + TESTING("dataset creation with compound datatypes"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + /* + * Make sure to pre-initialize all the compound field IDs + * so we don't try to close an uninitialized ID value; + * memory checkers will likely complain. + */ + for (j = 0; j < DATASET_COMPOUND_TYPE_TEST_MAX_SUBTYPES; j++) + type_pool[j] = H5I_INVALID_HID; + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_COMPOUND_TYPE_TEST_SUBGROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", DATASET_COMPOUND_TYPE_TEST_SUBGROUP_NAME); + goto error; + } + + if ((fspace_id = generate_random_dataspace(DATASET_COMPOUND_TYPE_TEST_DSET_RANK, NULL, NULL, FALSE)) < 0) + TEST_ERROR; + + num_passes = (rand() % DATASET_COMPOUND_TYPE_TEST_MAX_PASSES) + 1; + + for (i = 0; i < (size_t)num_passes; i++) { + size_t num_subtypes; + size_t compound_size = 0; + size_t next_offset = 0; + char dset_name[256]; + + /* + * Also pre-initialize all of the compound field IDs at the + * beginning of each loop so that we don't try to close an + * invalid ID. + */ + for (j = 0; j < DATASET_COMPOUND_TYPE_TEST_MAX_SUBTYPES; j++) + type_pool[j] = H5I_INVALID_HID; + + num_subtypes = (size_t)(rand() % DATASET_COMPOUND_TYPE_TEST_MAX_SUBTYPES) + 1; + + if ((compound_type = H5Tcreate(H5T_COMPOUND, 1)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create compound datatype\n"); + goto error; + } + + /* Start adding subtypes to the compound type */ + for (j = 0; j < num_subtypes; j++) { + size_t member_size; + char member_name[256]; + + HDsnprintf(member_name, 256, "member%zu", j); + + if ((type_pool[j] = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create compound datatype member %zu\n", j); + goto error; + } + + if (!(member_size = H5Tget_size(type_pool[j]))) { + H5_FAILED(); + HDprintf(" couldn't get compound member %zu size\n", j); + goto error; + } + + compound_size += member_size; + + if (H5Tset_size(compound_type, compound_size) < 0) + TEST_ERROR; + + if (H5Tinsert(compound_type, member_name, next_offset, type_pool[j]) < 0) + TEST_ERROR; + + next_offset += member_size; + } + + if (H5Tpack(compound_type) < 0) + TEST_ERROR; + + HDsnprintf(dset_name, sizeof(dset_name), "%s%zu", DATASET_COMPOUND_TYPE_TEST_DSET_NAME, i); + + if ((dset_id = H5Dcreate2(group_id, dset_name, compound_type, fspace_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", dset_name); + goto error; + } + + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + + if ((dset_id = H5Dopen2(group_id, dset_name, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to open dataset '%s'\n", dset_name); + goto error; + } + + for (j = 0; j < num_subtypes; j++) + if (type_pool[j] >= 0 && H5Tclose(type_pool[j]) < 0) + TEST_ERROR; + if (H5Tclose(compound_type) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + } + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + for (i = 0; i < DATASET_COMPOUND_TYPE_TEST_MAX_SUBTYPES; i++) + H5Tclose(type_pool[i]); + H5Tclose(compound_type); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a dataset can be created with + * enum datatypes. + */ +static int +test_create_dataset_enum_types(void) +{ + size_t i; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id_native = H5I_INVALID_HID, dset_id_non_native = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t enum_native = H5I_INVALID_HID, enum_non_native = H5I_INVALID_HID; + const char *enum_type_test_table[] = {"RED", "GREEN", "BLUE", "BLACK", "WHITE", + "PURPLE", "ORANGE", "YELLOW", "BROWN"}; + + TESTING("dataset creation with enum types"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_ENUM_TYPE_TEST_SUBGROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", DATASET_ENUM_TYPE_TEST_SUBGROUP_NAME); + goto error; + } + + if ((enum_native = H5Tcreate(H5T_ENUM, sizeof(int))) < 0) { + H5_FAILED(); + HDprintf(" couldn't create native enum type\n"); + goto error; + } + + for (i = 0; i < ARRAY_LENGTH(enum_type_test_table); i++) + if (H5Tenum_insert(enum_native, enum_type_test_table[i], &i) < 0) + TEST_ERROR; + + if ((enum_non_native = H5Tenum_create(H5T_STD_U32LE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create non-native enum type\n"); + goto error; + } + + for (i = 0; i < DATASET_ENUM_TYPE_TEST_NUM_MEMBERS; i++) { + char val_name[15]; + + HDsprintf(val_name, "%s%zu", DATASET_ENUM_TYPE_TEST_VAL_BASE_NAME, i); + + if (H5Tenum_insert(enum_non_native, val_name, &i) < 0) + TEST_ERROR; + } + + if ((fspace_id = generate_random_dataspace(DATASET_ENUM_TYPE_TEST_SPACE_RANK, NULL, NULL, FALSE)) < 0) + TEST_ERROR; + + if ((dset_id_native = H5Dcreate2(group_id, DATASET_ENUM_TYPE_TEST_DSET_NAME1, enum_native, fspace_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create native enum dataset '%s'\n", DATASET_ENUM_TYPE_TEST_DSET_NAME1); + goto error; + } + + if ((dset_id_non_native = H5Dcreate2(group_id, DATASET_ENUM_TYPE_TEST_DSET_NAME2, enum_non_native, + fspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create non-native enum dataset '%s'\n", DATASET_ENUM_TYPE_TEST_DSET_NAME2); + goto error; + } + + if (H5Dclose(dset_id_native) < 0) + TEST_ERROR; + if (H5Dclose(dset_id_non_native) < 0) + TEST_ERROR; + + if ((dset_id_native = H5Dopen2(group_id, DATASET_ENUM_TYPE_TEST_DSET_NAME1, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to open dataset '%s'\n", DATASET_ENUM_TYPE_TEST_DSET_NAME1); + goto error; + } + + if ((dset_id_non_native = H5Dopen2(group_id, DATASET_ENUM_TYPE_TEST_DSET_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to open dataset '%s'\n", DATASET_ENUM_TYPE_TEST_DSET_NAME2); + goto error; + } + + if (H5Tclose(enum_native) < 0) + TEST_ERROR; + if (H5Tclose(enum_non_native) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id_native) < 0) + TEST_ERROR; + if (H5Dclose(dset_id_non_native) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Tclose(enum_native); + H5Tclose(enum_non_native); + H5Sclose(fspace_id); + H5Dclose(dset_id_native); + H5Dclose(dset_id_non_native); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a dataset can be created using + * array datatypes. + */ +static int +test_create_dataset_array_types(void) +{ + hsize_t array_dims1[DATASET_ARRAY_TYPE_TEST_RANK1]; + hsize_t array_dims2[DATASET_ARRAY_TYPE_TEST_RANK2]; + hsize_t array_dims3[DATASET_ARRAY_TYPE_TEST_RANK3]; + size_t i; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id1 = H5I_INVALID_HID, dset_id2 = H5I_INVALID_HID, dset_id3 = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t array_type_id1 = H5I_INVALID_HID, array_type_id2 = H5I_INVALID_HID, + array_type_id3 = H5I_INVALID_HID; + hid_t array_base_type_id1 = H5I_INVALID_HID, array_base_type_id2 = H5I_INVALID_HID, + array_base_type_id3 = H5I_INVALID_HID; + hid_t nested_type_id = H5I_INVALID_HID; + + TESTING("dataset creation with array types"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_ARRAY_TYPE_TEST_SUBGROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", DATASET_ARRAY_TYPE_TEST_SUBGROUP_NAME); + goto error; + } + + /* Test creation of array with some different types */ + for (i = 0; i < DATASET_ARRAY_TYPE_TEST_RANK1; i++) + array_dims1[i] = (hsize_t)(rand() % MAX_DIM_SIZE + 1); + + if ((array_base_type_id1 = generate_random_datatype(H5T_ARRAY, FALSE)) < 0) + TEST_ERROR; + + if ((array_type_id1 = H5Tarray_create2(array_base_type_id1, DATASET_ARRAY_TYPE_TEST_RANK1, array_dims1)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't create first array type\n"); + goto error; + } + + for (i = 0; i < DATASET_ARRAY_TYPE_TEST_RANK2; i++) + array_dims2[i] = (hsize_t)(rand() % MAX_DIM_SIZE + 1); + + if ((array_base_type_id2 = generate_random_datatype(H5T_ARRAY, FALSE)) < 0) + TEST_ERROR; + + if ((array_type_id2 = H5Tarray_create2(array_base_type_id2, DATASET_ARRAY_TYPE_TEST_RANK2, array_dims2)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't create second array type\n"); + goto error; + } + + /* Test nested arrays */ + for (i = 0; i < DATASET_ARRAY_TYPE_TEST_RANK3; i++) + array_dims3[i] = (hsize_t)(rand() % MAX_DIM_SIZE + 1); + + if ((array_base_type_id3 = generate_random_datatype(H5T_ARRAY, FALSE)) < 0) + TEST_ERROR; + + if ((nested_type_id = H5Tarray_create2(array_base_type_id3, DATASET_ARRAY_TYPE_TEST_RANK3, array_dims3)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't create nested array base type\n"); + goto error; + } + + if ((array_type_id3 = H5Tarray_create2(nested_type_id, DATASET_ARRAY_TYPE_TEST_RANK3, array_dims3)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create nested array type\n"); + goto error; + } + + if ((fspace_id = generate_random_dataspace(DATASET_ARRAY_TYPE_TEST_SPACE_RANK, NULL, NULL, FALSE)) < 0) + TEST_ERROR; + + if ((dset_id1 = H5Dcreate2(group_id, DATASET_ARRAY_TYPE_TEST_DSET_NAME1, array_type_id1, fspace_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create array type dataset '%s'\n", DATASET_ARRAY_TYPE_TEST_DSET_NAME1); + goto error; + } + + if ((dset_id2 = H5Dcreate2(group_id, DATASET_ARRAY_TYPE_TEST_DSET_NAME2, array_type_id2, fspace_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create array type dataset '%s'\n", DATASET_ARRAY_TYPE_TEST_DSET_NAME2); + goto error; + } + + if ((dset_id3 = H5Dcreate2(group_id, DATASET_ARRAY_TYPE_TEST_DSET_NAME3, array_type_id3, fspace_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create nested array type dataset '%s'\n", DATASET_ARRAY_TYPE_TEST_DSET_NAME3); + goto error; + } + + if (H5Dclose(dset_id1) < 0) + TEST_ERROR; + if (H5Dclose(dset_id2) < 0) + TEST_ERROR; + if (H5Dclose(dset_id3) < 0) + TEST_ERROR; + + if ((dset_id1 = H5Dopen2(group_id, DATASET_ARRAY_TYPE_TEST_DSET_NAME1, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to open dataset '%s'\n", DATASET_ARRAY_TYPE_TEST_DSET_NAME1); + goto error; + } + + if ((dset_id2 = H5Dopen2(group_id, DATASET_ARRAY_TYPE_TEST_DSET_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to open dataset '%s'\n", DATASET_ARRAY_TYPE_TEST_DSET_NAME2); + goto error; + } + + if ((dset_id3 = H5Dopen2(group_id, DATASET_ARRAY_TYPE_TEST_DSET_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to open dataset '%s'\n", DATASET_ARRAY_TYPE_TEST_DSET_NAME3); + goto error; + } + + if (H5Tclose(array_base_type_id1) < 0) + TEST_ERROR; + if (H5Tclose(array_base_type_id2) < 0) + TEST_ERROR; + if (H5Tclose(array_base_type_id3) < 0) + TEST_ERROR; + if (H5Tclose(nested_type_id) < 0) + TEST_ERROR; + if (H5Tclose(array_type_id1) < 0) + TEST_ERROR; + if (H5Tclose(array_type_id2) < 0) + TEST_ERROR; + if (H5Tclose(array_type_id3) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id1) < 0) + TEST_ERROR; + if (H5Dclose(dset_id2) < 0) + TEST_ERROR; + if (H5Dclose(dset_id3) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Tclose(array_base_type_id1); + H5Tclose(array_base_type_id2); + H5Tclose(array_base_type_id3); + H5Tclose(nested_type_id); + H5Tclose(array_type_id1); + H5Tclose(array_type_id2); + H5Tclose(array_type_id3); + H5Sclose(fspace_id); + H5Dclose(dset_id1); + H5Dclose(dset_id2); + H5Dclose(dset_id3); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check the functionality of the different + * dataset creation properties. + */ +static int +test_create_dataset_creation_properties(void) +{ + hsize_t dims[DATASET_CREATION_PROPERTIES_TEST_SHAPE_RANK]; + hsize_t chunk_dims[DATASET_CREATION_PROPERTIES_TEST_SHAPE_RANK]; + size_t i; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID, dcpl_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID, compact_dtype = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID, compact_fspace_id = H5I_INVALID_HID; + + TESTING_MULTIPART("dataset creation properties"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILTERS) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER) || !(vol_cap_flags_g & H5VL_CAP_FLAG_TRACK_TIMES) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_FILTERS)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, creation order, track time, or filter " + "pipeline aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_CREATION_PROPERTIES_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", DATASET_CREATION_PROPERTIES_TEST_GROUP_NAME); + goto error; + } + + if ((fspace_id = + generate_random_dataspace(DATASET_CREATION_PROPERTIES_TEST_SHAPE_RANK, NULL, dims, FALSE)) < 0) + TEST_ERROR; + if ((compact_fspace_id = + generate_random_dataspace(DATASET_CREATION_PROPERTIES_TEST_SHAPE_RANK, NULL, NULL, TRUE)) < 0) + TEST_ERROR; + + /* Set chunk dims to be size of dataset - for filters test */ + for (i = 0; i < DATASET_CREATION_PROPERTIES_TEST_SHAPE_RANK; i++) + chunk_dims[i] = dims[i]; + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + if ((compact_dtype = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + /* Test the alloc time property */ + PART_BEGIN(DCPL_alloc_time_test) + { + H5D_alloc_time_t alloc_times[] = {H5D_ALLOC_TIME_DEFAULT, H5D_ALLOC_TIME_EARLY, + H5D_ALLOC_TIME_INCR, H5D_ALLOC_TIME_LATE}; + + TESTING_2("dataset storage space allocation time property"); + + if ((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create DCPL\n"); + PART_ERROR(DCPL_alloc_time_test); + } + + for (i = 0; i < ARRAY_LENGTH(alloc_times); i++) { + char name[100]; + + if (H5Pset_alloc_time(dcpl_id, alloc_times[i]) < 0) { + H5_FAILED(); + HDprintf(" couldn't set alloc time property value\n"); + PART_ERROR(DCPL_alloc_time_test); + } + + HDsprintf(name, "%s%zu", DATASET_CREATION_PROPERTIES_TEST_ALLOC_TIMES_BASE_NAME, i); + + if ((dset_id = H5Dcreate2(group_id, name, dset_dtype, fspace_id, H5P_DEFAULT, dcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", name); + PART_ERROR(DCPL_alloc_time_test); + } + + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + if ((dset_id = H5Dopen2(group_id, name, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", name); + PART_ERROR(DCPL_alloc_time_test); + } + + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + } + + if (dcpl_id >= 0) { + H5E_BEGIN_TRY + { + H5Pclose(dcpl_id); + } + H5E_END_TRY; + dcpl_id = H5I_INVALID_HID; + } + + PASSED(); + } + PART_END(DCPL_alloc_time_test); + + /* Test the attribute creation order property */ + PART_BEGIN(DCPL_attr_crt_order_test) + { + unsigned creation_orders[] = {H5P_CRT_ORDER_TRACKED, + H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED}; + + TESTING_2("attribute creation order property for DCPL"); + + if ((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create DCPL\n"); + PART_ERROR(DCPL_attr_crt_order_test); + } + + for (i = 0; i < ARRAY_LENGTH(creation_orders); i++) { + char name[100]; + + if (H5Pset_attr_creation_order(dcpl_id, creation_orders[i]) < 0) { + H5_FAILED(); + HDprintf(" couldn't set attribute creation order property\n"); + PART_ERROR(DCPL_attr_crt_order_test); + } + + HDsprintf(name, "%s%zu", DATASET_CREATION_PROPERTIES_TEST_CRT_ORDER_BASE_NAME, i); + + if ((dset_id = H5Dcreate2(group_id, name, dset_dtype, fspace_id, H5P_DEFAULT, dcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", name); + PART_ERROR(DCPL_attr_crt_order_test); + } + + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + if ((dset_id = H5Dopen2(group_id, name, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", name); + PART_ERROR(DCPL_attr_crt_order_test); + } + + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + } + + if (dcpl_id >= 0) { + H5E_BEGIN_TRY + { + H5Pclose(dcpl_id); + } + H5E_END_TRY; + dcpl_id = H5I_INVALID_HID; + } + + PASSED(); + } + PART_END(DCPL_attr_crt_order_test); + + /* Test the attribute phase change property */ + PART_BEGIN(DCPL_attr_phase_change_test) + { + TESTING_2("attribute phase change property for DCPL"); + + if ((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create DCPL\n"); + PART_ERROR(DCPL_attr_phase_change_test); + } + + if (H5Pset_attr_phase_change(dcpl_id, DATASET_CREATION_PROPERTIES_TEST_MAX_COMPACT, + DATASET_CREATION_PROPERTIES_TEST_MIN_DENSE) < 0) { + H5_FAILED(); + HDprintf(" couldn't set attribute phase change property\n"); + PART_ERROR(DCPL_attr_phase_change_test); + } + + if ((dset_id = H5Dcreate2(group_id, DATASET_CREATION_PROPERTIES_TEST_PHASE_CHANGE_DSET_NAME, + dset_dtype, fspace_id, H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", + DATASET_CREATION_PROPERTIES_TEST_PHASE_CHANGE_DSET_NAME); + PART_ERROR(DCPL_attr_phase_change_test); + } + + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_CREATION_PROPERTIES_TEST_PHASE_CHANGE_DSET_NAME, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", + DATASET_CREATION_PROPERTIES_TEST_PHASE_CHANGE_DSET_NAME); + PART_ERROR(DCPL_attr_phase_change_test); + } + + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + if (dcpl_id >= 0) { + H5E_BEGIN_TRY + { + H5Pclose(dcpl_id); + } + H5E_END_TRY; + dcpl_id = H5I_INVALID_HID; + } + + PASSED(); + } + PART_END(DCPL_attr_phase_change_test); + + /* Test the fill time property */ + PART_BEGIN(DCPL_fill_time_property_test) + { + H5D_fill_time_t fill_times[] = {H5D_FILL_TIME_IFSET, H5D_FILL_TIME_ALLOC, H5D_FILL_TIME_NEVER}; + + TESTING_2("dataset fill time property"); + + if ((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create DCPL\n"); + PART_ERROR(DCPL_fill_time_property_test); + } + + for (i = 0; i < ARRAY_LENGTH(fill_times); i++) { + char name[100]; + + if (H5Pset_fill_time(dcpl_id, fill_times[i]) < 0) { + H5_FAILED(); + HDprintf(" couldn't set dataset fill time property\n"); + PART_ERROR(DCPL_fill_time_property_test); + } + + HDsprintf(name, "%s%zu", DATASET_CREATION_PROPERTIES_TEST_FILL_TIMES_BASE_NAME, i); + + if ((dset_id = H5Dcreate2(group_id, name, dset_dtype, fspace_id, H5P_DEFAULT, dcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", name); + PART_ERROR(DCPL_fill_time_property_test); + } + + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + if ((dset_id = H5Dopen2(group_id, name, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", name); + PART_ERROR(DCPL_fill_time_property_test); + } + + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + } + + if (dcpl_id >= 0) { + H5E_BEGIN_TRY + { + H5Pclose(dcpl_id); + } + H5E_END_TRY; + dcpl_id = H5I_INVALID_HID; + } + + PASSED(); + } + PART_END(DCPL_fill_time_property_test); + + /* TODO: Test the fill value property */ + + /* Test filters */ + PART_BEGIN(DCPL_filters_test) + { + TESTING_2("dataset filters"); + + if ((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create DCPL\n"); + PART_ERROR(DCPL_filters_test); + } + + if (H5Pset_chunk(dcpl_id, DATASET_CREATION_PROPERTIES_TEST_SHAPE_RANK, chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" couldn't set chunking on DCPL\n"); + PART_ERROR(DCPL_filters_test); + } + + /* Set all of the available filters on the DCPL */ + if (H5Pset_deflate(dcpl_id, 7) < 0) { + H5_FAILED(); + HDprintf(" couldn't set deflate filter on DCPL\n"); + PART_ERROR(DCPL_filters_test); + } + if (H5Pset_shuffle(dcpl_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't set shuffle filter on DCPL\n"); + PART_ERROR(DCPL_filters_test); + } + if (H5Pset_fletcher32(dcpl_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't set fletcher32 filter on DCPL\n"); + PART_ERROR(DCPL_filters_test); + } + if (H5Pset_nbit(dcpl_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't set nbit filter on DCPL\n"); + PART_ERROR(DCPL_filters_test); + } + if (H5Pset_scaleoffset(dcpl_id, H5Z_SO_FLOAT_ESCALE, 2) < 0) { + H5_FAILED(); + HDprintf(" couldn't set scaleoffset filter on DCPL\n"); + PART_ERROR(DCPL_filters_test); + } + + /* + * Use a simple datatype, as not all filters support all datatypes. + */ + if ((dset_id = H5Dcreate2(group_id, DATASET_CREATION_PROPERTIES_TEST_FILTERS_DSET_NAME, + H5T_NATIVE_INT, fspace_id, H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", + DATASET_CREATION_PROPERTIES_TEST_FILTERS_DSET_NAME); + PART_ERROR(DCPL_filters_test); + } + + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_CREATION_PROPERTIES_TEST_FILTERS_DSET_NAME, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", + DATASET_CREATION_PROPERTIES_TEST_FILTERS_DSET_NAME); + PART_ERROR(DCPL_filters_test); + } + + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + if (dcpl_id >= 0) { + H5E_BEGIN_TRY + { + H5Pclose(dcpl_id); + } + H5E_END_TRY; + dcpl_id = H5I_INVALID_HID; + } + + PASSED(); + } + PART_END(DCPL_filters_test); + + /* Test the dataset storage layout property */ + PART_BEGIN(DCPL_storage_layout_test) + { + H5D_layout_t layouts[] = {H5D_COMPACT, H5D_CONTIGUOUS, H5D_CHUNKED}; + + TESTING_2("dataset storage layouts"); + + if ((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create DCPL\n"); + PART_ERROR(DCPL_storage_layout_test); + } + + for (i = 0; i < ARRAY_LENGTH(layouts); i++) { + char name[100]; + + if (H5Pset_layout(dcpl_id, layouts[i]) < 0) { + H5_FAILED(); + HDprintf(" couldn't set storage layout property\n"); + PART_ERROR(DCPL_storage_layout_test); + } + + if (H5D_CHUNKED == layouts[i]) { + hsize_t local_chunk_dims[DATASET_CREATION_PROPERTIES_TEST_CHUNK_DIM_RANK]; + size_t j; + + for (j = 0; j < DATASET_CREATION_PROPERTIES_TEST_CHUNK_DIM_RANK; j++) + local_chunk_dims[j] = (hsize_t)(rand() % (int)dims[j] + 1); + + if (H5Pset_chunk(dcpl_id, DATASET_CREATION_PROPERTIES_TEST_CHUNK_DIM_RANK, + local_chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" couldn't set chunk dimensionality\n"); + PART_ERROR(DCPL_storage_layout_test); + } + } + + HDsprintf(name, "%s%zu", DATASET_CREATION_PROPERTIES_TEST_LAYOUTS_BASE_NAME, i); + + if ((dset_id = + H5Dcreate2(group_id, name, (H5D_COMPACT == layouts[i]) ? compact_dtype : dset_dtype, + (H5D_COMPACT == layouts[i]) ? compact_fspace_id : fspace_id, H5P_DEFAULT, + dcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", name); + PART_ERROR(DCPL_storage_layout_test); + } + + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + if ((dset_id = H5Dopen2(group_id, name, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", name); + PART_ERROR(DCPL_storage_layout_test); + } + + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + } + + if (dcpl_id >= 0) { + H5E_BEGIN_TRY + { + H5Pclose(dcpl_id); + } + H5E_END_TRY; + dcpl_id = H5I_INVALID_HID; + } + + PASSED(); + } + PART_END(DCPL_storage_layout_test); + + /* Test the "track object times" property */ + PART_BEGIN(DCPL_track_obj_times_test) + { + TESTING_2("object time tracking property for DCPL"); + + if ((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create DCPL\n"); + PART_ERROR(DCPL_track_obj_times_test); + } + + if (H5Pset_obj_track_times(dcpl_id, true) < 0) { + H5_FAILED(); + HDprintf(" couldn't set object time tracking property\n"); + PART_ERROR(DCPL_track_obj_times_test); + } + + if ((dset_id = H5Dcreate2(group_id, DATASET_CREATION_PROPERTIES_TEST_TRACK_TIMES_YES_DSET_NAME, + dset_dtype, fspace_id, H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", + DATASET_CREATION_PROPERTIES_TEST_TRACK_TIMES_YES_DSET_NAME); + PART_ERROR(DCPL_track_obj_times_test); + } + + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_CREATION_PROPERTIES_TEST_TRACK_TIMES_YES_DSET_NAME, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", + DATASET_CREATION_PROPERTIES_TEST_TRACK_TIMES_YES_DSET_NAME); + PART_ERROR(DCPL_track_obj_times_test); + } + + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + if (H5Pset_obj_track_times(dcpl_id, false) < 0) { + H5_FAILED(); + HDprintf(" couldn't set object time tracking property\n"); + PART_ERROR(DCPL_track_obj_times_test); + } + + if ((dset_id = H5Dcreate2(group_id, DATASET_CREATION_PROPERTIES_TEST_TRACK_TIMES_NO_DSET_NAME, + dset_dtype, fspace_id, H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", + DATASET_CREATION_PROPERTIES_TEST_TRACK_TIMES_NO_DSET_NAME); + PART_ERROR(DCPL_track_obj_times_test); + } + + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_CREATION_PROPERTIES_TEST_TRACK_TIMES_NO_DSET_NAME, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", + DATASET_CREATION_PROPERTIES_TEST_TRACK_TIMES_NO_DSET_NAME); + PART_ERROR(DCPL_track_obj_times_test); + } + + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + if (dcpl_id >= 0) { + H5E_BEGIN_TRY + { + H5Pclose(dcpl_id); + } + H5E_END_TRY; + dcpl_id = H5I_INVALID_HID; + } + + PASSED(); + } + PART_END(DCPL_track_obj_times_test); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(compact_fspace_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Tclose(compact_dtype) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(compact_fspace_id); + H5Sclose(fspace_id); + H5Tclose(compact_dtype); + H5Tclose(dset_dtype); + H5Dclose(dset_id); + H5Pclose(dcpl_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to create many small datasets (100,000) + */ +static int +test_create_many_dataset(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dataspace_id = H5I_INVALID_HID; + char dset_name[DSET_NAME_BUF_SIZE]; + unsigned char data; + unsigned int i; + + TESTING("creating many datasets"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_MANY_CREATE_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", DATASET_MANY_CREATE_GROUP_NAME); + goto error; + } + + if ((dataspace_id = H5Screate(H5S_SCALAR)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create scalar data space\n"); + goto error; + } + + HDprintf("\n"); + for (i = 0; i < DATASET_NUMB; i++) { + HDprintf("\r %u/%u", i + 1, DATASET_NUMB); + sprintf(dset_name, "dset_%02u", i); + data = i % 256; + + if ((dset_id = H5Dcreate2(group_id, dset_name, H5T_NATIVE_UCHAR, dataspace_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", dset_name); + goto error; + } + + if (H5Dwrite(dset_id, H5T_NATIVE_UCHAR, H5S_ALL, H5S_ALL, H5P_DEFAULT, &data) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", dset_name); + goto error; + } + + if (H5Dclose(dset_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close dataset '%s'\n", dset_name); + goto error; + } + } + + if (H5Sclose(dataspace_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + H5Sclose(dataspace_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that re-opening a dataset with + * H5Dopen succeeds. + */ +static int +test_open_dataset(void) +{ + TESTING("H5Dopen"); + + SKIPPED(); + + return 0; +} + +/* + * A test to check that H5Dopen fails when it is + * passed invalid parameters. + */ +static int +test_open_dataset_invalid_params(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + + TESTING_MULTIPART("H5Dopen with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_OPEN_INVALID_PARAMS_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", DATASET_OPEN_INVALID_PARAMS_GROUP_NAME); + goto error; + } + + if ((fspace_id = generate_random_dataspace(DATASET_OPEN_INVALID_PARAMS_SPACE_RANK, NULL, NULL, FALSE)) < + 0) + TEST_ERROR; + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_OPEN_INVALID_PARAMS_DSET_NAME, dset_dtype, fspace_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_OPEN_INVALID_PARAMS_DSET_NAME); + goto error; + } + + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Dopen_invalid_loc_id) + { + TESTING_2("H5Dopen with an invalid loc_id"); + + H5E_BEGIN_TRY + { + dset_id = H5Dopen2(H5I_INVALID_HID, DATASET_OPEN_INVALID_PARAMS_DSET_NAME, H5P_DEFAULT); + } + H5E_END_TRY; + + if (dset_id >= 0) { + H5_FAILED(); + HDprintf(" opened dataset using H5Dopen2 with an invalid loc_id!\n"); + H5Dclose(dset_id); + PART_ERROR(H5Dopen_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Dopen_invalid_loc_id); + + PART_BEGIN(H5Dopen_invalid_dataset_name) + { + TESTING_2("H5Dopen with an invalid dataset name"); + + H5E_BEGIN_TRY + { + dset_id = H5Dopen2(group_id, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (dset_id >= 0) { + H5_FAILED(); + HDprintf(" opened dataset using H5Dopen2 with a NULL dataset name!\n"); + H5Dclose(dset_id); + PART_ERROR(H5Dopen_invalid_dataset_name); + } + + H5E_BEGIN_TRY + { + dset_id = H5Dopen2(group_id, "", H5P_DEFAULT); + } + H5E_END_TRY; + + if (dset_id >= 0) { + H5_FAILED(); + HDprintf(" opened dataset using H5Dopen2 with an invalid dataset name of ''!\n"); + H5Dclose(dset_id); + PART_ERROR(H5Dopen_invalid_dataset_name); + } + + PASSED(); + } + PART_END(H5Dopen_invalid_dataset_name); + + PART_BEGIN(H5Dopen_invalid_dapl) + { + TESTING_2("H5Dopen with an invalid DAPL"); + + H5E_BEGIN_TRY + { + dset_id = H5Dopen2(group_id, DATASET_OPEN_INVALID_PARAMS_DSET_NAME, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (dset_id >= 0) { + H5_FAILED(); + HDprintf(" opened dataset using H5Dopen2 with an invalid DAPL!\n"); + H5Dclose(dset_id); + PART_ERROR(H5Dopen_invalid_dapl); + } + + PASSED(); + } + PART_END(H5Dopen_invalid_dapl); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + H5Tclose(dset_dtype); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that H5Dclose fails when it is + * passed an invalid dataset ID. + */ +static int +test_close_dataset_invalid_params(void) +{ + herr_t err_ret = -1; + hid_t file_id = H5I_INVALID_HID; + + TESTING("H5Dclose with an invalid dataset ID"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file or dataset aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + H5E_BEGIN_TRY + { + err_ret = H5Dclose(H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Dclose succeeded with an invalid dataset ID!\n"); + goto error; + } + + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that valid copies of a dataset's dataspace + * and datatype can be retrieved with H5Dget_space and + * H5Dget_type, respectively. + */ +static int +test_get_dataset_space_and_type(void) +{ + hsize_t dset_dims[DATASET_GET_SPACE_TYPE_TEST_SPACE_RANK]; + size_t i; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t dset_space_id = H5I_INVALID_HID; + hid_t tmp_type_id = H5I_INVALID_HID; + hid_t tmp_space_id = H5I_INVALID_HID; + + TESTING_MULTIPART("retrieval of a dataset's dataspace and datatype"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_GET_SPACE_TYPE_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", DATASET_GET_SPACE_TYPE_TEST_GROUP_NAME); + goto error; + } + + if ((dset_space_id = + generate_random_dataspace(DATASET_GET_SPACE_TYPE_TEST_SPACE_RANK, NULL, dset_dims, FALSE)) < 0) + TEST_ERROR; + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_GET_SPACE_TYPE_TEST_DSET_NAME, dset_dtype, dset_space_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_GET_SPACE_TYPE_TEST_DSET_NAME); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + /* Retrieve the dataset's datatype and dataspace and verify them */ + PART_BEGIN(H5Dget_type) + { + TESTING_2("H5Dget_type"); + + if ((tmp_type_id = H5Dget_type(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve dataset's datatype\n"); + PART_ERROR(H5Dget_type); + } + + { + htri_t types_equal = H5Tequal(tmp_type_id, dset_dtype); + + if (types_equal < 0) { + H5_FAILED(); + HDprintf(" datatype was invalid\n"); + PART_ERROR(H5Dget_type); + } + + if (!types_equal) { + H5_FAILED(); + HDprintf(" dataset's datatype did not match\n"); + PART_ERROR(H5Dget_type); + } + } + + PASSED(); + } + PART_END(H5Dget_type); + + PART_BEGIN(H5Dget_space) + { + TESTING_2("H5Dget_space"); + + if ((tmp_space_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve dataset's dataspace\n"); + PART_ERROR(H5Dget_space); + } + + { + hsize_t space_dims[DATASET_GET_SPACE_TYPE_TEST_SPACE_RANK]; + + if (H5Sget_simple_extent_dims(tmp_space_id, space_dims, NULL) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve dataspace dimensions\n"); + PART_ERROR(H5Dget_space); + } + + for (i = 0; i < DATASET_GET_SPACE_TYPE_TEST_SPACE_RANK; i++) + if (space_dims[i] != dset_dims[i]) { + H5_FAILED(); + HDprintf(" dataset's dataspace dims didn't match\n"); + PART_ERROR(H5Dget_space); + } + } + + PASSED(); + } + PART_END(H5Dget_space); + + /* Now close the dataset and verify that this still works after + * opening an attribute instead of creating it. + */ + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + if (tmp_type_id >= 0) { + H5E_BEGIN_TRY + { + H5Tclose(tmp_type_id); + } + H5E_END_TRY; + tmp_type_id = H5I_INVALID_HID; + } + if (tmp_space_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(tmp_space_id); + } + H5E_END_TRY; + tmp_space_id = H5I_INVALID_HID; + } + + PART_BEGIN(H5Dget_type_reopened) + { + TESTING_2("H5Dget_type after re-opening a dataset"); + + if ((dset_id = H5Dopen2(group_id, DATASET_GET_SPACE_TYPE_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_GET_SPACE_TYPE_TEST_DSET_NAME); + PART_ERROR(H5Dget_type_reopened); + } + + if ((tmp_type_id = H5Dget_type(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve dataset's datatype\n"); + PART_ERROR(H5Dget_type_reopened); + } + + { + htri_t types_equal = H5Tequal(tmp_type_id, dset_dtype); + + if (types_equal < 0) { + H5_FAILED(); + HDprintf(" datatype was invalid\n"); + PART_ERROR(H5Dget_type_reopened); + } + + if (!types_equal) { + H5_FAILED(); + HDprintf(" dataset's datatype did not match\n"); + PART_ERROR(H5Dget_type_reopened); + } + } + + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + PASSED(); + } + PART_END(H5Dget_type_reopened); + + PART_BEGIN(H5Dget_space_reopened) + { + TESTING_2("H5Dget_space after re-opening a dataset"); + + if ((dset_id = H5Dopen2(group_id, DATASET_GET_SPACE_TYPE_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_GET_SPACE_TYPE_TEST_DSET_NAME); + PART_ERROR(H5Dget_space_reopened); + } + + if ((tmp_space_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve dataset's dataspace\n"); + PART_ERROR(H5Dget_space_reopened); + } + + { + hsize_t space_dims[DATASET_GET_SPACE_TYPE_TEST_SPACE_RANK]; + + if (H5Sget_simple_extent_dims(tmp_space_id, space_dims, NULL) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve dataspace dimensions\n"); + PART_ERROR(H5Dget_space_reopened); + } + + for (i = 0; i < DATASET_GET_SPACE_TYPE_TEST_SPACE_RANK; i++) { + if (space_dims[i] != dset_dims[i]) { + H5_FAILED(); + HDprintf(" dataset's dataspace dims didn't match!\n"); + PART_ERROR(H5Dget_space_reopened); + } + } + } + + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + PASSED(); + } + PART_END(H5Dget_space_reopened); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(tmp_space_id) < 0) + TEST_ERROR; + if (H5Sclose(dset_space_id) < 0) + TEST_ERROR; + if (H5Tclose(tmp_type_id) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(tmp_space_id); + H5Sclose(dset_space_id); + H5Tclose(tmp_type_id); + H5Tclose(dset_dtype); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a dataset's dataspace and datatype + * can't be retrieved when H5Dget_space and H5Dget_type are passed + * invalid parameters, respectively. + */ +static int +test_get_dataset_space_and_type_invalid_params(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t dset_space_id = H5I_INVALID_HID; + hid_t tmp_type_id = H5I_INVALID_HID; + hid_t tmp_space_id = H5I_INVALID_HID; + + TESTING_MULTIPART("H5Dget_type/H5Dget_space with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", ATTRIBUTE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_GET_SPACE_TYPE_INVALID_PARAMS_TEST_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", + DATASET_GET_SPACE_TYPE_INVALID_PARAMS_TEST_GROUP_NAME); + goto error; + } + + if ((dset_space_id = generate_random_dataspace(DATASET_GET_SPACE_TYPE_INVALID_PARAMS_TEST_SPACE_RANK, + NULL, NULL, FALSE)) < 0) + TEST_ERROR; + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_GET_SPACE_TYPE_INVALID_PARAMS_TEST_DSET_NAME, dset_dtype, + dset_space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_GET_SPACE_TYPE_INVALID_PARAMS_TEST_DSET_NAME); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Dget_type_invalid_dset_id) + { + TESTING_2("H5Dget_type with an invalid dset_id"); + + H5E_BEGIN_TRY + { + tmp_type_id = H5Dget_type(H5I_INVALID_HID); + } + H5E_END_TRY; + + if (tmp_type_id >= 0) { + H5_FAILED(); + HDprintf(" retrieved copy of dataset's datatype using an invalid dataset ID!\n"); + PART_ERROR(H5Dget_type_invalid_dset_id); + } + + PASSED(); + } + PART_END(H5Dget_type_invalid_dset_id); + + PART_BEGIN(H5Dget_space_invalid_dset_id) + { + TESTING_2("H5Dget_space with an invalid dset_id"); + + H5E_BEGIN_TRY + { + tmp_space_id = H5Dget_space(H5I_INVALID_HID); + } + H5E_END_TRY; + + if (tmp_space_id >= 0) { + H5_FAILED(); + HDprintf(" retrieved copy of dataset's dataspace using an invalid dataset ID!\n"); + PART_ERROR(H5Dget_space_invalid_dset_id); + } + + PASSED(); + } + PART_END(H5Dget_space_invalid_dset_id); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(dset_space_id) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(tmp_space_id); + H5Sclose(dset_space_id); + H5Tclose(tmp_type_id); + H5Tclose(dset_dtype); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test for H5Dget_space_status. + */ +static int +test_get_dataset_space_status(void) +{ + TESTING("H5Dget_space_status"); + + SKIPPED(); + + return 0; +} + +/* + * A test to check that a dataset's dataspace allocation + * status can't be retrieved with H5Dget_space_status when + * it is passed invalid parameters. + */ +static int +test_get_dataset_space_status_invalid_params(void) +{ + TESTING("H5Dget_space_status with invalid parameters"); + + SKIPPED(); + + return 0; +} + +/* + * A test to check that a DCPL used for dataset creation + * can be persisted and that a valid copy of that DCPL can + * be retrieved later with a call to H5Dget_create_plist. + * Also tests that a valid copy of a DAPL used for dataset + * access can be retrieved with a call to H5Dget_access_plist. + */ +static int +test_dataset_property_lists(void) +{ + const char *path_prefix = "/test_prefix"; + hsize_t dims[DATASET_PROPERTY_LIST_TEST_SPACE_RANK]; + hsize_t chunk_dims[DATASET_PROPERTY_LIST_TEST_SPACE_RANK]; + size_t i; + herr_t err_ret = -1; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id1 = H5I_INVALID_HID, dset_id2 = H5I_INVALID_HID, dset_id3 = H5I_INVALID_HID, + dset_id4 = H5I_INVALID_HID; + hid_t dcpl_id1 = H5I_INVALID_HID, dcpl_id2 = H5I_INVALID_HID; + hid_t dapl_id1 = H5I_INVALID_HID, dapl_id2 = H5I_INVALID_HID; + hid_t dset_dtype1 = H5I_INVALID_HID, dset_dtype2 = H5I_INVALID_HID, dset_dtype3 = H5I_INVALID_HID, + dset_dtype4 = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + char *tmp_prefix = NULL; + char vol_name[5]; + + TESTING_MULTIPART("dataset property list operations"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GET_PLIST)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, or get property list aren't supported " + "with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + /** for DAOS VOL, this test is problematic since auto chunking can be selected, so skip for now */ + if (H5VLget_connector_name(file_id, vol_name, 5) < 0) { + H5_FAILED(); + HDprintf(" couldn't get VOL connector name\n"); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_PROPERTY_LIST_TEST_SUBGROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", DATASET_PROPERTY_LIST_TEST_SUBGROUP_NAME); + goto error; + } + + if ((space_id = generate_random_dataspace(DATASET_PROPERTY_LIST_TEST_SPACE_RANK, NULL, dims, FALSE)) < 0) + TEST_ERROR; + + for (i = 0; i < DATASET_PROPERTY_LIST_TEST_SPACE_RANK; i++) + chunk_dims[i] = (hsize_t)(rand() % (int)dims[i] + 1); + + if ((dset_dtype1 = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + if ((dset_dtype2 = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + if ((dset_dtype3 = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + if ((dset_dtype4 = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + if ((dcpl_id1 = H5Pcreate(H5P_DATASET_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create DCPL\n"); + goto error; + } + + if (H5Pset_chunk(dcpl_id1, DATASET_PROPERTY_LIST_TEST_SPACE_RANK, chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" couldn't set DCPL property\n"); + goto error; + } + + if ((dset_id1 = H5Dcreate2(group_id, DATASET_PROPERTY_LIST_TEST_DSET_NAME1, dset_dtype1, space_id, + H5P_DEFAULT, dcpl_id1, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_PROPERTY_LIST_TEST_DSET_NAME1); + goto error; + } + + if ((dset_id2 = H5Dcreate2(group_id, DATASET_PROPERTY_LIST_TEST_DSET_NAME2, dset_dtype2, space_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_PROPERTY_LIST_TEST_DSET_NAME2); + goto error; + } + + if (H5Pclose(dcpl_id1) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Dget_create_plist) + { + TESTING_2("H5Dget_create_plist"); + + /* Try to receive copies of the two property lists, one which has the property set and one which + * does not */ + if ((dcpl_id1 = H5Dget_create_plist(dset_id1)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get property list\n"); + PART_ERROR(H5Dget_create_plist); + } + + if ((dcpl_id2 = H5Dget_create_plist(dset_id2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get property list\n"); + PART_ERROR(H5Dget_create_plist); + } + + /* Ensure that property list 1 has the property set and property list 2 does not */ + { + hsize_t tmp_chunk_dims[DATASET_PROPERTY_LIST_TEST_SPACE_RANK]; + + HDmemset(tmp_chunk_dims, 0, sizeof(tmp_chunk_dims)); + + if (H5Pget_chunk(dcpl_id1, DATASET_PROPERTY_LIST_TEST_SPACE_RANK, tmp_chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" couldn't get DCPL property value\n"); + PART_ERROR(H5Dget_create_plist); + } + + for (i = 0; i < DATASET_PROPERTY_LIST_TEST_SPACE_RANK; i++) + if (tmp_chunk_dims[i] != chunk_dims[i]) { + H5_FAILED(); + HDprintf(" DCPL property values were incorrect\n"); + PART_ERROR(H5Dget_create_plist); + } + + H5E_BEGIN_TRY + { + err_ret = H5Pget_chunk(dcpl_id2, DATASET_PROPERTY_LIST_TEST_SPACE_RANK, tmp_chunk_dims); + } + H5E_END_TRY; + + /* DAOS VOL can auto chunk, so don't fail */ + if (err_ret >= 0 && strcmp(vol_name, "daos") != 0) { + H5_FAILED(); + HDprintf(" property list 2 shouldn't have had chunk dimensionality set (not a chunked " + "layout)\n"); + PART_ERROR(H5Dget_create_plist); + } + } + + PASSED(); + } + PART_END(H5Dget_create_plist); + + PART_BEGIN(H5Dget_access_plist) + { + TESTING_2("H5Dget_access_plist"); + + if ((dapl_id1 = H5Pcreate(H5P_DATASET_ACCESS)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create DAPL\n"); + PART_ERROR(H5Dget_access_plist); + } + + if (H5Pset_efile_prefix(dapl_id1, path_prefix) < 0) { + H5_FAILED(); + HDprintf(" couldn't set DAPL property\n"); + PART_ERROR(H5Dget_access_plist); + } + + if ((dset_id3 = H5Dcreate2(group_id, DATASET_PROPERTY_LIST_TEST_DSET_NAME3, dset_dtype3, space_id, + H5P_DEFAULT, H5P_DEFAULT, dapl_id1)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset\n"); + PART_ERROR(H5Dget_access_plist); + } + + if ((dset_id4 = H5Dcreate2(group_id, DATASET_PROPERTY_LIST_TEST_DSET_NAME4, dset_dtype4, space_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset\n"); + PART_ERROR(H5Dget_access_plist); + } + + if (dapl_id1 >= 0) { + H5E_BEGIN_TRY + { + H5Pclose(dapl_id1); + } + H5E_END_TRY; + dapl_id1 = H5I_INVALID_HID; + } + + /* Try to receive copies of the two property lists, one which has the property set and one which + * does not */ + if ((dapl_id1 = H5Dget_access_plist(dset_id3)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get property list\n"); + PART_ERROR(H5Dget_access_plist); + } + + if ((dapl_id2 = H5Dget_access_plist(dset_id4)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get property list\n"); + PART_ERROR(H5Dget_access_plist); + } + + /* Ensure that property list 1 has the property set and property list 2 does not */ + { + ssize_t buf_size = 0; + + if ((buf_size = H5Pget_efile_prefix(dapl_id1, NULL, 0)) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve size for property value buffer\n"); + PART_ERROR(H5Dget_access_plist); + } + + if (NULL == (tmp_prefix = (char *)HDcalloc(1, (size_t)buf_size + 1))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for property value\n"); + PART_ERROR(H5Dget_access_plist); + } + + if (H5Pget_efile_prefix(dapl_id1, tmp_prefix, (size_t)buf_size + 1) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve property list value\n"); + PART_ERROR(H5Dget_access_plist); + } + + if (HDstrncmp(tmp_prefix, path_prefix, (size_t)buf_size + 1)) { + H5_FAILED(); + HDprintf(" DAPL values were incorrect!\n"); + PART_ERROR(H5Dget_access_plist); + } + + HDmemset(tmp_prefix, 0, (size_t)buf_size + 1); + + if (H5Pget_efile_prefix(dapl_id2, tmp_prefix, (size_t)buf_size) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve property list value\n"); + PART_ERROR(H5Dget_access_plist); + } + + if (!HDstrncmp(tmp_prefix, path_prefix, (size_t)buf_size + 1)) { + H5_FAILED(); + HDprintf(" DAPL property value was set!\n"); + PART_ERROR(H5Dget_access_plist); + } + } + + PASSED(); + } + PART_END(H5Dget_access_plist); + + /* Now close the property lists and datasets and see if we can still retrieve copies of + * the property lists upon opening (instead of creating) a dataset + */ + if (dcpl_id1 >= 0) { + H5E_BEGIN_TRY + { + H5Pclose(dcpl_id1); + } + H5E_END_TRY; + dcpl_id1 = H5I_INVALID_HID; + } + if (dcpl_id2 >= 0) { + H5E_BEGIN_TRY + { + H5Pclose(dcpl_id2); + } + H5E_END_TRY; + dcpl_id2 = H5I_INVALID_HID; + } + if (dset_id1 >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id1); + } + H5E_END_TRY; + dset_id1 = H5I_INVALID_HID; + } + if (dset_id2 >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id2); + } + H5E_END_TRY; + dset_id2 = H5I_INVALID_HID; + } + + PART_BEGIN(H5Dget_create_plist_reopened) + { + TESTING_2("H5Dget_create_plist after re-opening a dataset"); + + if ((dset_id1 = H5Dopen2(group_id, DATASET_PROPERTY_LIST_TEST_DSET_NAME1, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_PROPERTY_LIST_TEST_DSET_NAME1); + PART_ERROR(H5Dget_create_plist_reopened); + } + + if ((dset_id2 = H5Dopen2(group_id, DATASET_PROPERTY_LIST_TEST_DSET_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_PROPERTY_LIST_TEST_DSET_NAME2); + PART_ERROR(H5Dget_create_plist_reopened); + } + + if ((dcpl_id1 = H5Dget_create_plist(dset_id1)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get property list\n"); + PART_ERROR(H5Dget_create_plist_reopened); + } + + if ((dcpl_id2 = H5Dget_create_plist(dset_id2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get property list\n"); + PART_ERROR(H5Dget_create_plist_reopened); + } + + /* Ensure that property list 1 has the property set and property list 2 does not */ + { + hsize_t tmp_chunk_dims[DATASET_PROPERTY_LIST_TEST_SPACE_RANK]; + + HDmemset(tmp_chunk_dims, 0, sizeof(tmp_chunk_dims)); + + if (H5Pget_chunk(dcpl_id1, DATASET_PROPERTY_LIST_TEST_SPACE_RANK, tmp_chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" couldn't get DCPL property value\n"); + PART_ERROR(H5Dget_create_plist_reopened); + } + + for (i = 0; i < DATASET_PROPERTY_LIST_TEST_SPACE_RANK; i++) + if (tmp_chunk_dims[i] != chunk_dims[i]) { + H5_FAILED(); + HDprintf(" DCPL property values were incorrect\n"); + PART_ERROR(H5Dget_create_plist_reopened); + } + + H5E_BEGIN_TRY + { + err_ret = H5Pget_chunk(dcpl_id2, DATASET_PROPERTY_LIST_TEST_SPACE_RANK, tmp_chunk_dims); + } + H5E_END_TRY; + + /* DAOS VOL can auto chunk, so don't fail */ + if (err_ret >= 0 && strcmp(vol_name, "daos") != 0) { + H5_FAILED(); + HDprintf(" property list 2 shouldn't have had chunk dimensionality set (not a chunked " + "layout)\n"); + PART_ERROR(H5Dget_create_plist_reopened); + } + } + + PASSED(); + } + PART_END(H5Dget_create_plist_reopened); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (tmp_prefix) { + HDfree(tmp_prefix); + tmp_prefix = NULL; + } + + if (H5Pclose(dcpl_id1) < 0) + TEST_ERROR; + if (H5Pclose(dcpl_id2) < 0) + TEST_ERROR; + if (H5Pclose(dapl_id1) < 0) + TEST_ERROR; + if (H5Pclose(dapl_id2) < 0) + TEST_ERROR; + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype1) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype2) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype3) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype4) < 0) + TEST_ERROR; + if (H5Dclose(dset_id1) < 0) + TEST_ERROR; + if (H5Dclose(dset_id2) < 0) + TEST_ERROR; + if (H5Dclose(dset_id3) < 0) + TEST_ERROR; + if (H5Dclose(dset_id4) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (tmp_prefix) + HDfree(tmp_prefix); + H5Pclose(dcpl_id1); + H5Pclose(dcpl_id2); + H5Pclose(dapl_id1); + H5Pclose(dapl_id2); + H5Sclose(space_id); + H5Tclose(dset_dtype1); + H5Tclose(dset_dtype2); + H5Tclose(dset_dtype3); + H5Tclose(dset_dtype4); + H5Dclose(dset_id1); + H5Dclose(dset_id2); + H5Dclose(dset_id3); + H5Dclose(dset_id4); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test for H5Dget_storage_size. + */ +static int +test_get_dataset_storage_size(void) +{ + TESTING("H5Dget_storage_size"); + + SKIPPED(); + + return 0; +} + +/* + * A test to check that a dataset's storage size can't + * be retrieved when H5Dget_storage_size is passed + * invalid parameters. + */ +static int +test_get_dataset_storage_size_invalid_params(void) +{ + TESTING("H5Dget_storage_size with invalid parameters"); + + SKIPPED(); + + return 0; +} + +/* + * A test for H5Dget_chunk_storage_size. + */ +static int +test_get_dataset_chunk_storage_size(void) +{ + TESTING("H5Dget_chunk_storage_size"); + + SKIPPED(); + + return 0; +} + +/* + * A test to check that the size of an allocated chunk in + * a dataset can't be retrieved when H5Dget_chunk_storage_size + * is passed invalid parameters. + */ +static int +test_get_dataset_chunk_storage_size_invalid_params(void) +{ + TESTING("H5Dget_chunk_storage_size with invalid parameters"); + + SKIPPED(); + + return 0; +} + +/* + * A test for H5Dget_offset. + */ +static int +test_get_dataset_offset(void) +{ + TESTING("H5Dget_offset"); + + SKIPPED(); + + return 0; +} + +/* + * A test to check that a dataset's offset can't be + * retrieved when H5Dget_offset is passed invalid + * parameters. + */ +static int +test_get_dataset_offset_invalid_params(void) +{ + TESTING("H5Dget_offset with invalid parameters"); + + SKIPPED(); + + return 0; +} + +/* + * A test to check that a small amount of data can be + * read back from a dataset using an H5S_ALL selection. + */ +static int +test_read_dataset_small_all(void) +{ + hsize_t dims[DATASET_SMALL_READ_TEST_ALL_DSET_SPACE_RANK] = {10, 5, 3}; + size_t i, data_size; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + void *read_buf = NULL; + + TESTING("small read from dataset with H5S_ALL"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_SMALL_READ_TEST_ALL_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", DATASET_SMALL_READ_TEST_ALL_GROUP_NAME); + goto error; + } + + if ((fspace_id = H5Screate_simple(DATASET_SMALL_READ_TEST_ALL_DSET_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_SMALL_READ_TEST_ALL_DSET_NAME, + DATASET_SMALL_READ_TEST_ALL_DSET_DTYPE, fspace_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_SMALL_READ_TEST_ALL_DSET_NAME); + goto error; + } + + for (i = 0, data_size = 1; i < DATASET_SMALL_READ_TEST_ALL_DSET_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_SMALL_READ_TEST_ALL_DSET_DTYPESIZE; + + if (NULL == (read_buf = HDmalloc(data_size))) + TEST_ERROR; + + if (H5Dread(dset_id, DATASET_SMALL_READ_TEST_ALL_DSET_DTYPE, H5S_ALL, H5S_ALL, H5P_DEFAULT, read_buf) < + 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", DATASET_SMALL_READ_TEST_ALL_DSET_NAME); + goto error; + } + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (read_buf) + HDfree(read_buf); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a small amount of data can be + * read back from a dataset using a hyperslab selection. + */ +static int +test_read_dataset_small_hyperslab(void) +{ + hsize_t start[DATASET_SMALL_READ_TEST_HYPERSLAB_DSET_SPACE_RANK]; + hsize_t stride[DATASET_SMALL_READ_TEST_HYPERSLAB_DSET_SPACE_RANK]; + hsize_t count[DATASET_SMALL_READ_TEST_HYPERSLAB_DSET_SPACE_RANK]; + hsize_t block[DATASET_SMALL_READ_TEST_HYPERSLAB_DSET_SPACE_RANK]; + hsize_t dims[DATASET_SMALL_READ_TEST_HYPERSLAB_DSET_SPACE_RANK] = {10, 5, 3}; + size_t i, data_size; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID, fspace_id = H5I_INVALID_HID; + void *read_buf = NULL; + + TESTING("small read from dataset with a hyperslab selection"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_SMALL_READ_TEST_HYPERSLAB_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_SMALL_READ_TEST_HYPERSLAB_GROUP_NAME); + goto error; + } + + if ((fspace_id = H5Screate_simple(DATASET_SMALL_READ_TEST_HYPERSLAB_DSET_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + if ((mspace_id = H5Screate_simple(DATASET_SMALL_READ_TEST_HYPERSLAB_DSET_SPACE_RANK - 1, dims, NULL)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_SMALL_READ_TEST_HYPERSLAB_DSET_NAME, + DATASET_SMALL_READ_TEST_HYPERSLAB_DSET_DTYPE, fspace_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_SMALL_READ_TEST_HYPERSLAB_DSET_NAME); + goto error; + } + + for (i = 0; i < DATASET_SMALL_READ_TEST_HYPERSLAB_DSET_SPACE_RANK; i++) { + start[i] = 0; + stride[i] = 1; + count[i] = dims[i]; + block[i] = 1; + } + + count[2] = 1; + + if (H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET, start, stride, count, block) < 0) + TEST_ERROR; + + for (i = 0, data_size = 1; i < DATASET_SMALL_READ_TEST_HYPERSLAB_DSET_SPACE_RANK - 1; i++) + data_size *= dims[i]; + data_size *= DATASET_SMALL_READ_TEST_HYPERSLAB_DSET_DTYPESIZE; + + if (NULL == (read_buf = HDmalloc(data_size))) + TEST_ERROR; + + if (H5Dread(dset_id, DATASET_SMALL_READ_TEST_HYPERSLAB_DSET_DTYPE, mspace_id, fspace_id, H5P_DEFAULT, + read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", DATASET_SMALL_READ_TEST_HYPERSLAB_DSET_NAME); + goto error; + } + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (H5Sclose(mspace_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (read_buf) + HDfree(read_buf); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a small amount of data can be + * read back from a dataset using a point selection. + */ +static int +test_read_dataset_small_point_selection(void) +{ + hsize_t points[DATASET_SMALL_READ_TEST_POINT_SELECTION_NUM_POINTS * + DATASET_SMALL_READ_TEST_POINT_SELECTION_DSET_SPACE_RANK]; + hsize_t dims[DATASET_SMALL_READ_TEST_POINT_SELECTION_DSET_SPACE_RANK] = {10, 10, 10}; + hsize_t mspace_dims[] = {DATASET_SMALL_READ_TEST_POINT_SELECTION_NUM_POINTS}; + size_t i, data_size; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + void *data = NULL; + + TESTING("small read from dataset with a point selection"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_SMALL_READ_TEST_POINT_SELECTION_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_SMALL_READ_TEST_POINT_SELECTION_GROUP_NAME); + goto error; + } + + if ((fspace_id = H5Screate_simple(DATASET_SMALL_READ_TEST_POINT_SELECTION_DSET_SPACE_RANK, dims, NULL)) < + 0) + TEST_ERROR; + if ((mspace_id = H5Screate_simple(1, mspace_dims, NULL)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_SMALL_READ_TEST_POINT_SELECTION_DSET_NAME, + DATASET_SMALL_READ_TEST_POINT_SELECTION_DSET_DTYPE, fspace_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_SMALL_READ_TEST_POINT_SELECTION_DSET_NAME); + goto error; + } + + data_size = DATASET_SMALL_READ_TEST_POINT_SELECTION_NUM_POINTS * + DATASET_SMALL_READ_TEST_POINT_SELECTION_DSET_DTYPESIZE; + + if (NULL == (data = HDmalloc(data_size))) + TEST_ERROR; + + for (i = 0; i < DATASET_SMALL_READ_TEST_POINT_SELECTION_NUM_POINTS; i++) { + size_t j; + + for (j = 0; j < DATASET_SMALL_READ_TEST_POINT_SELECTION_DSET_SPACE_RANK; j++) + points[(i * DATASET_SMALL_READ_TEST_POINT_SELECTION_DSET_SPACE_RANK) + j] = i; + } + + if (H5Sselect_elements(fspace_id, H5S_SELECT_SET, DATASET_SMALL_READ_TEST_POINT_SELECTION_NUM_POINTS, + points) < 0) { + H5_FAILED(); + HDprintf(" couldn't select points\n"); + goto error; + } + + if (H5Dread(dset_id, DATASET_SMALL_READ_TEST_POINT_SELECTION_DSET_DTYPE, mspace_id, fspace_id, + H5P_DEFAULT, data) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", DATASET_SMALL_READ_TEST_POINT_SELECTION_DSET_NAME); + goto error; + } + + if (data) { + HDfree(data); + data = NULL; + } + + if (H5Sclose(mspace_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (data) + HDfree(data); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * Tests point selection I/O with different patterns + */ +#define DATASET_IO_POINT_DIM_0 6 +#define DATASET_IO_POINT_DIM_1 9 +#define DATASET_IO_POINT_CDIM_0 4 +#define DATASET_IO_POINT_CDIM_1 3 +#define DATASET_IO_POINT_NPOINTS 10 +#define DATASET_IO_POINT_GEN_POINTS(POINTS, I, J) \ + { \ + for ((I) = 0; (I) < DATASET_IO_POINT_NPOINTS; (I)++) \ + do { \ + (POINTS)[2 * (I)] = (hsize_t)(rand() % DATASET_IO_POINT_DIM_0); \ + (POINTS)[2 * (I) + 1] = (hsize_t)(rand() % DATASET_IO_POINT_DIM_1); \ + for ((J) = 0; ((J) < (I)) && (((POINTS)[2 * (I)] != (POINTS)[2 * (J)]) || \ + ((POINTS)[2 * (I) + 1] != (POINTS)[2 * (J) + 1])); \ + (J)++) \ + ; \ + } while ((J) < (I)); \ + } +static int +test_dataset_io_point_selections(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t mspace_id_full = H5I_INVALID_HID, mspace_id_all = H5I_INVALID_HID, fspace_id = H5I_INVALID_HID; + hid_t dcpl_id_chunk = H5I_INVALID_HID; + hsize_t dims[2] = {DATASET_IO_POINT_DIM_0, DATASET_IO_POINT_DIM_1}; + hsize_t cdims[2] = {DATASET_IO_POINT_CDIM_0, DATASET_IO_POINT_CDIM_1}; + hsize_t points[DATASET_IO_POINT_NPOINTS * 2]; + hsize_t points2[DATASET_IO_POINT_NPOINTS * 2]; + hsize_t npoints = DATASET_IO_POINT_NPOINTS; + hsize_t start[2] = {1, 2}; + hsize_t stride[2] = {2, 5}; + hsize_t count[2] = {2, 1}; + hsize_t block[2] = {1, 5}; + int buf_all[DATASET_IO_POINT_DIM_0][DATASET_IO_POINT_DIM_1]; + int file_state[DATASET_IO_POINT_DIM_0][DATASET_IO_POINT_DIM_1]; + int erbuf[DATASET_IO_POINT_DIM_0][DATASET_IO_POINT_DIM_1]; + int buf_point[DATASET_IO_POINT_NPOINTS]; + hbool_t do_chunk; + int i, j; + + TESTING("point selection I/O with all selection in memory and points in file"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + /* Create dataspaces and DCPL */ + if ((mspace_id_full = H5Screate_simple(2, dims, NULL)) < 0) + TEST_ERROR; + if ((mspace_id_all = H5Screate_simple(1, &npoints, NULL)) < 0) + TEST_ERROR; + if ((fspace_id = H5Screate_simple(2, dims, NULL)) < 0) + TEST_ERROR; + if ((dcpl_id_chunk = H5Pcreate(H5P_DATASET_CREATE)) < 0) + TEST_ERROR; + + /* Enable chunking on chunk DCPL */ + if (H5Pset_chunk(dcpl_id_chunk, 2, cdims) < 0) + TEST_ERROR; + + /* Open file */ + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) + TEST_ERROR; + + /* Open container group */ + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) + TEST_ERROR; + + /* Create group */ + if ((group_id = H5Gcreate2(container_group, DATASET_IO_POINT_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) + TEST_ERROR; + + /* Perform with and without chunking */ + for (do_chunk = FALSE;; do_chunk = TRUE) { + if (do_chunk) { + TESTING("point selection I/O with all selection in memory and points in file with chunking"); + + /* Create chunked dataset */ + if ((dset_id = H5Dcreate2(group_id, DATASET_IO_POINT_DSET_NAME_CHUNK, H5T_NATIVE_INT, fspace_id, + H5P_DEFAULT, dcpl_id_chunk, H5P_DEFAULT)) < 0) + TEST_ERROR; + } /* end if */ + else + /* Create non-chunked dataset */ + if ((dset_id = H5Dcreate2(group_id, DATASET_IO_POINT_DSET_NAME_NOCHUNK, H5T_NATIVE_INT, fspace_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR; + + /* Fill write buffer */ + for (i = 0; i < DATASET_IO_POINT_DIM_0; i++) + for (j = 0; j < DATASET_IO_POINT_DIM_1; j++) + buf_all[i][j] = rand(); + + /* Write data */ + if (H5Dwrite(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf_all) < 0) + FAIL_PUTS_ERROR("Failed to write entire dataset"); + + /* Update file_state */ + for (i = 0; i < DATASET_IO_POINT_DIM_0; i++) + for (j = 0; j < DATASET_IO_POINT_DIM_1; j++) + file_state[i][j] = buf_all[i][j]; + + /* Generate points to read */ + DATASET_IO_POINT_GEN_POINTS(points, i, j); + + /* Select points */ + if (H5Sselect_elements(fspace_id, H5S_SELECT_SET, DATASET_IO_POINT_NPOINTS, points) < 0) + TEST_ERROR; + + /* Wipe read buffer */ + memset(buf_point, 0, sizeof(buf_point)); + + /* Read points to "all" memory buffer */ + if (H5Dread(dset_id, H5T_NATIVE_INT, mspace_id_all, fspace_id, H5P_DEFAULT, buf_point) < 0) + FAIL_PUTS_ERROR("Failed to read points from dataset to all memory buffer"); + + /* Verify data */ + for (i = 0; i < DATASET_IO_POINT_NPOINTS; i++) + if (buf_point[i] != file_state[points[2 * i]][points[2 * i + 1]]) + FAIL_PUTS_ERROR("Incorrect data read from points to all memory buffer"); + + /* Generate points to write */ + DATASET_IO_POINT_GEN_POINTS(points, i, j); + + /* Select points */ + if (H5Sselect_elements(fspace_id, H5S_SELECT_SET, DATASET_IO_POINT_NPOINTS, points) < 0) + TEST_ERROR; + + /* Fill write buffer */ + for (i = 0; i < DATASET_IO_POINT_NPOINTS; i++) + buf_point[i] = rand(); + + /* Write points from "all" memory buffer */ + if (H5Dwrite(dset_id, H5T_NATIVE_INT, mspace_id_all, fspace_id, H5P_DEFAULT, buf_point) < 0) + FAIL_PUTS_ERROR("Failed to write points to dataset from all memory buffer"); + + /* Update file state */ + for (i = 0; i < DATASET_IO_POINT_NPOINTS; i++) + file_state[points[2 * i]][points[2 * i + 1]] = buf_point[i]; + + /* Wipe read buffer */ + memset(buf_all, 0, sizeof(buf_all)); + + /* Read entire dataset */ + if (H5Dread(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf_all) < 0) + FAIL_PUTS_ERROR("Failed to read entire dataset"); + + /* Verify data */ + for (i = 0; i < DATASET_IO_POINT_DIM_0; i++) + for (j = 0; j < DATASET_IO_POINT_DIM_1; j++) + if (buf_all[i][j] != file_state[i][j]) + FAIL_PUTS_ERROR("Incorrect data found after writing from all memory buffer to points"); + + PASSED(); + + if (do_chunk) + TESTING("point selection I/O with points in memory and file (same shape) with chunking"); + else + TESTING("point selection I/O with points in memory and file (same shape)"); + + /* Generate points to read */ + DATASET_IO_POINT_GEN_POINTS(points, i, j); + + /* Select points */ + if (H5Sselect_elements(fspace_id, H5S_SELECT_SET, DATASET_IO_POINT_NPOINTS, points) < 0) + TEST_ERROR; + + /* Wipe read buffer */ + memset(buf_all, 0, sizeof(buf_all)); + + /* Generate expected read buffer */ + memset(erbuf, 0, sizeof(erbuf)); + for (i = 0; i < DATASET_IO_POINT_NPOINTS; i++) + erbuf[points[2 * i]][points[2 * i + 1]] = file_state[points[2 * i]][points[2 * i + 1]]; + + /* Read data points->points */ + if (H5Dread(dset_id, H5T_NATIVE_INT, fspace_id, fspace_id, H5P_DEFAULT, buf_all) < 0) + FAIL_PUTS_ERROR("Failed to read points from dataset to points in memory buffer"); + + /* Verify data */ + for (i = 0; i < DATASET_IO_POINT_DIM_0; i++) + for (j = 0; j < DATASET_IO_POINT_DIM_1; j++) + if (buf_all[i][j] != erbuf[i][j]) + FAIL_PUTS_ERROR("Incorrect data found read from points in file to points in memory"); + + /* Generate points to write */ + DATASET_IO_POINT_GEN_POINTS(points, i, j); + + /* Select points */ + if (H5Sselect_elements(fspace_id, H5S_SELECT_SET, DATASET_IO_POINT_NPOINTS, points) < 0) + TEST_ERROR; + + /* Fill write buffer */ + for (i = 0; i < DATASET_IO_POINT_DIM_0; i++) + for (j = 0; j < DATASET_IO_POINT_DIM_1; j++) + buf_all[i][j] = rand(); + + /* Write data points->points */ + if (H5Dwrite(dset_id, H5T_NATIVE_INT, fspace_id, fspace_id, H5P_DEFAULT, buf_all) < 0) + FAIL_PUTS_ERROR("Failed to write from in memory to points in dataset"); + + /* Update file_state */ + for (i = 0; i < DATASET_IO_POINT_NPOINTS; i++) + file_state[points[2 * i]][points[2 * i + 1]] = buf_all[points[2 * i]][points[2 * i + 1]]; + + /* Wipe read buffer */ + memset(buf_all, 0, sizeof(buf_all)); + + /* Read entire dataset */ + if (H5Dread(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf_all) < 0) + FAIL_PUTS_ERROR("Failed to read entire dataset"); + + /* Verify data */ + for (i = 0; i < DATASET_IO_POINT_DIM_0; i++) + for (j = 0; j < DATASET_IO_POINT_DIM_1; j++) + if (buf_all[i][j] != file_state[i][j]) + FAIL_PUTS_ERROR( + "Incorrect data found after writing from points in memory to points in dataset"); + + PASSED(); + + if (do_chunk) + TESTING("point selection I/O with points in memory and file (different shape) with chunking"); + else + TESTING("point selection I/O with points in memory and file (different shape)"); + + /* Generate points to read */ + DATASET_IO_POINT_GEN_POINTS(points, i, j); + DATASET_IO_POINT_GEN_POINTS(points2, i, j); + + /* Select points */ + if (H5Sselect_elements(fspace_id, H5S_SELECT_SET, DATASET_IO_POINT_NPOINTS, points) < 0) + TEST_ERROR; + if (H5Sselect_elements(mspace_id_full, H5S_SELECT_SET, DATASET_IO_POINT_NPOINTS, points2) < 0) + TEST_ERROR; + + /* Wipe read buffer */ + memset(buf_all, 0, sizeof(buf_all)); + + /* Generate expected read buffer */ + memset(erbuf, 0, sizeof(erbuf)); + for (i = 0; i < DATASET_IO_POINT_NPOINTS; i++) + erbuf[points2[2 * i]][points2[2 * i + 1]] = file_state[points[2 * i]][points[2 * i + 1]]; + + /* Read data points->points */ + if (H5Dread(dset_id, H5T_NATIVE_INT, mspace_id_full, fspace_id, H5P_DEFAULT, buf_all) < 0) + FAIL_PUTS_ERROR("Failed to read points from dataset to points in memory buffer"); + + /* Verify data */ + for (i = 0; i < DATASET_IO_POINT_DIM_0; i++) + for (j = 0; j < DATASET_IO_POINT_DIM_1; j++) + if (buf_all[i][j] != erbuf[i][j]) + FAIL_PUTS_ERROR( + "Incorrect data found after reading from points in file to points in memory"); + + /* Generate points to write */ + DATASET_IO_POINT_GEN_POINTS(points, i, j); + DATASET_IO_POINT_GEN_POINTS(points2, i, j); + + /* Select points */ + if (H5Sselect_elements(fspace_id, H5S_SELECT_SET, DATASET_IO_POINT_NPOINTS, points) < 0) + TEST_ERROR; + if (H5Sselect_elements(mspace_id_full, H5S_SELECT_SET, DATASET_IO_POINT_NPOINTS, points2) < 0) + TEST_ERROR; + + /* Fill write buffer */ + for (i = 0; i < DATASET_IO_POINT_DIM_0; i++) + for (j = 0; j < DATASET_IO_POINT_DIM_1; j++) + buf_all[i][j] = rand(); + + /* Write data points->points */ + if (H5Dwrite(dset_id, H5T_NATIVE_INT, mspace_id_full, fspace_id, H5P_DEFAULT, buf_all) < 0) + FAIL_PUTS_ERROR("Failed to write from points in memory to points in dataset"); + + /* Update file_state */ + for (i = 0; i < DATASET_IO_POINT_NPOINTS; i++) + file_state[points[2 * i]][points[2 * i + 1]] = buf_all[points2[2 * i]][points2[2 * i + 1]]; + + /* Wipe read buffer */ + memset(buf_all, 0, sizeof(buf_all)); + + /* Read entire dataset */ + if (H5Dread(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf_all) < 0) + FAIL_PUTS_ERROR("Failed to read entire dataset"); + + /* Verify data */ + for (i = 0; i < DATASET_IO_POINT_DIM_0; i++) + for (j = 0; j < DATASET_IO_POINT_DIM_1; j++) + if (buf_all[i][j] != file_state[i][j]) + FAIL_PUTS_ERROR( + "Incorrect data found after writing from points in memory to points in dataset"); + + PASSED(); + + if (do_chunk) + TESTING("point selection I/O with hyperslab in memory and points in file with chunking"); + else + TESTING("point selection I/O with hyperslab in memory and points in file"); + + /* Generate points to read */ + DATASET_IO_POINT_GEN_POINTS(points, i, j); + + /* Select points */ + if (H5Sselect_elements(fspace_id, H5S_SELECT_SET, DATASET_IO_POINT_NPOINTS, points) < 0) + TEST_ERROR; + + /* Select hyperslab */ + if (H5Sselect_hyperslab(mspace_id_full, H5S_SELECT_SET, start, stride, count, block) < 0) + TEST_ERROR; + + /* Wipe read buffer */ + memset(buf_all, 0, sizeof(buf_all)); + + /* Generate expected read buffer */ + memset(erbuf, 0, sizeof(erbuf)); + for (i = 0; i < DATASET_IO_POINT_NPOINTS; i++) + erbuf[start[0] + (stride[0] * ((hsize_t)i / block[1]))][start[1] + ((hsize_t)i % block[1])] = + file_state[points[2 * i]][points[2 * i + 1]]; + + /* Read data points->hslab */ + if (H5Dread(dset_id, H5T_NATIVE_INT, mspace_id_full, fspace_id, H5P_DEFAULT, buf_all) < 0) + FAIL_PUTS_ERROR("Failed to read points from dataset to hyperslab in memory buffer"); + + /* Verify data */ + for (i = 0; i < DATASET_IO_POINT_DIM_0; i++) + for (j = 0; j < DATASET_IO_POINT_DIM_1; j++) + if (buf_all[i][j] != erbuf[i][j]) + FAIL_PUTS_ERROR( + "Incorrect data found after reading from points in file to hyperslab in memory"); + + /* Generate points to write */ + DATASET_IO_POINT_GEN_POINTS(points, i, j); + + /* Select points */ + if (H5Sselect_elements(fspace_id, H5S_SELECT_SET, DATASET_IO_POINT_NPOINTS, points) < 0) + TEST_ERROR; + + /* Fill write buffer */ + for (i = 0; i < DATASET_IO_POINT_DIM_0; i++) + for (j = 0; j < DATASET_IO_POINT_DIM_1; j++) + buf_all[i][j] = rand(); + + /* Write data hlsab->points */ + if (H5Dwrite(dset_id, H5T_NATIVE_INT, mspace_id_full, fspace_id, H5P_DEFAULT, buf_all) < 0) + FAIL_PUTS_ERROR("Failed to write from hyperslab in memory to points in dataset"); + + /* Update file_state */ + for (i = 0; i < DATASET_IO_POINT_NPOINTS; i++) + file_state[points[2 * i]][points[2 * i + 1]] = + buf_all[start[0] + (stride[0] * ((hsize_t)i / block[1]))][start[1] + ((hsize_t)i % block[1])]; + + /* Wipe read buffer */ + memset(buf_all, 0, sizeof(buf_all)); + + /* Read entire dataset */ + if (H5Dread(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf_all) < 0) + FAIL_PUTS_ERROR("Failed to read entire dataset"); + + /* Verify data */ + for (i = 0; i < DATASET_IO_POINT_DIM_0; i++) + for (j = 0; j < DATASET_IO_POINT_DIM_1; j++) + if (buf_all[i][j] != file_state[i][j]) + FAIL_PUTS_ERROR( + "Incorrect data found after writing from hyperslab in memory to points in dataset"); + + PASSED(); + + if (do_chunk) + TESTING("point selection I/O with points in memory and hyperslab in file with chunking"); + else + TESTING("point selection I/O with points in memory and hyperslab in file"); + + /* Generate points to read */ + DATASET_IO_POINT_GEN_POINTS(points, i, j); + + /* Select points */ + if (H5Sselect_elements(mspace_id_full, H5S_SELECT_SET, DATASET_IO_POINT_NPOINTS, points) < 0) + TEST_ERROR; + + /* Select hyperslab */ + if (H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET, start, stride, count, block) < 0) + TEST_ERROR; + + /* Wipe read buffer */ + memset(buf_all, 0, sizeof(buf_all)); + + /* Generate expected read buffer */ + memset(erbuf, 0, sizeof(erbuf)); + for (i = 0; i < DATASET_IO_POINT_NPOINTS; i++) + erbuf[points[2 * i]][points[2 * i + 1]] = + file_state[start[0] + (stride[0] * ((hsize_t)i / block[1]))] + [start[1] + ((hsize_t)i % block[1])]; + + /* Read data hslab->points */ + if (H5Dread(dset_id, H5T_NATIVE_INT, mspace_id_full, fspace_id, H5P_DEFAULT, buf_all) < 0) + FAIL_PUTS_ERROR("Failed to read hyperslab from dataset to points in memory buffer"); + + /* Verify data */ + for (i = 0; i < DATASET_IO_POINT_DIM_0; i++) + for (j = 0; j < DATASET_IO_POINT_DIM_1; j++) + if (buf_all[i][j] != erbuf[i][j]) + FAIL_PUTS_ERROR( + "Incorrect data found after reading from hyperslab in file to points in memory"); + + /* Generate points to write */ + DATASET_IO_POINT_GEN_POINTS(points, i, j); + + /* Select points */ + if (H5Sselect_elements(mspace_id_full, H5S_SELECT_SET, DATASET_IO_POINT_NPOINTS, points) < 0) + TEST_ERROR; + + /* Fill write buffer */ + for (i = 0; i < DATASET_IO_POINT_DIM_0; i++) + for (j = 0; j < DATASET_IO_POINT_DIM_1; j++) + buf_all[i][j] = rand(); + + /* Write data points->hslab */ + if (H5Dwrite(dset_id, H5T_NATIVE_INT, mspace_id_full, fspace_id, H5P_DEFAULT, buf_all) < 0) + FAIL_PUTS_ERROR("Failed to write from points in memory to hyperslab in dataset"); + + /* Update file_state */ + for (i = 0; i < DATASET_IO_POINT_NPOINTS; i++) + file_state[start[0] + (stride[0] * ((hsize_t)i / block[1]))][start[1] + ((hsize_t)i % block[1])] = + buf_all[points[2 * i]][points[2 * i + 1]]; + + /* Wipe read buffer */ + memset(buf_all, 0, sizeof(buf_all)); + + /* Read entire dataset */ + if (H5Dread(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf_all) < 0) + FAIL_PUTS_ERROR("Failed to read entire dataset"); + + /* Verify data */ + for (i = 0; i < DATASET_IO_POINT_DIM_0; i++) + for (j = 0; j < DATASET_IO_POINT_DIM_1; j++) + if (buf_all[i][j] != file_state[i][j]) + FAIL_PUTS_ERROR( + "Incorrect data found after writing from points in memory to hyperslab in dataset"); + + if (!do_chunk) + PASSED(); + + /* Close dataset */ + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + + /* Exit after chunked run */ + if (do_chunk) + break; + } /* end for */ + + /* Close */ + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + if (H5Pclose(dcpl_id_chunk) < 0) + TEST_ERROR; + if (H5Sclose(mspace_id_full) < 0) + TEST_ERROR; + if (H5Sclose(mspace_id_all) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + H5Sclose(mspace_id_full); + H5Sclose(mspace_id_all); + H5Pclose(dcpl_id_chunk); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} /* end test_dataset_io_point_selections() */ + +#ifndef NO_LARGE_TESTS +/* + * A test to check that a large amount of data can be + * read back from a dataset using an H5S_ALL selection. + */ +static int +test_read_dataset_large_all(void) +{ + hsize_t dims[DATASET_LARGE_READ_TEST_ALL_DSET_SPACE_RANK] = {600, 600, 600}; + size_t i, data_size; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + void *read_buf = NULL; + + TESTING("large read from dataset with H5S_ALL"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_LARGE_READ_TEST_ALL_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", DATASET_LARGE_READ_TEST_ALL_GROUP_NAME); + goto error; + } + + if ((fspace_id = H5Screate_simple(DATASET_LARGE_READ_TEST_ALL_DSET_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_LARGE_READ_TEST_ALL_DSET_NAME, + DATASET_LARGE_READ_TEST_ALL_DSET_DTYPE, fspace_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_LARGE_READ_TEST_ALL_DSET_NAME); + goto error; + } + + for (i = 0, data_size = 1; i < DATASET_LARGE_READ_TEST_ALL_DSET_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_LARGE_READ_TEST_ALL_DSET_DTYPESIZE; + + if (NULL == (read_buf = HDmalloc(data_size))) + TEST_ERROR; + + if (H5Dread(dset_id, DATASET_LARGE_READ_TEST_ALL_DSET_DTYPE, H5S_ALL, H5S_ALL, H5P_DEFAULT, read_buf) < + 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", DATASET_LARGE_READ_TEST_ALL_DSET_NAME); + goto error; + } + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (read_buf) + HDfree(read_buf); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a large amount of data can be + * read back from a dataset using a hyperslab selection. + */ +static int +test_read_dataset_large_hyperslab(void) +{ + hsize_t start[DATASET_LARGE_READ_TEST_HYPERSLAB_DSET_SPACE_RANK]; + hsize_t stride[DATASET_LARGE_READ_TEST_HYPERSLAB_DSET_SPACE_RANK]; + hsize_t count[DATASET_LARGE_READ_TEST_HYPERSLAB_DSET_SPACE_RANK]; + hsize_t block[DATASET_LARGE_READ_TEST_HYPERSLAB_DSET_SPACE_RANK]; + hsize_t dims[DATASET_LARGE_READ_TEST_HYPERSLAB_DSET_SPACE_RANK] = {600, 600, 600}; + size_t i, data_size; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID, fspace_id = H5I_INVALID_HID; + void *read_buf = NULL; + + TESTING("large read from dataset with a hyperslab selection"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_LARGE_READ_TEST_HYPERSLAB_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_LARGE_READ_TEST_HYPERSLAB_GROUP_NAME); + goto error; + } + + if ((fspace_id = H5Screate_simple(DATASET_LARGE_READ_TEST_HYPERSLAB_DSET_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + if ((mspace_id = H5Screate_simple(DATASET_LARGE_READ_TEST_HYPERSLAB_DSET_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_LARGE_READ_TEST_HYPERSLAB_DSET_NAME, + DATASET_LARGE_READ_TEST_HYPERSLAB_DSET_DTYPE, fspace_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_LARGE_READ_TEST_HYPERSLAB_DSET_NAME); + goto error; + } + + for (i = 0; i < DATASET_LARGE_READ_TEST_HYPERSLAB_DSET_SPACE_RANK; i++) { + start[i] = 0; + stride[i] = 1; + count[i] = dims[i]; + block[i] = 1; + } + + if (H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET, start, stride, count, block) < 0) + TEST_ERROR; + + for (i = 0, data_size = 1; i < DATASET_LARGE_READ_TEST_HYPERSLAB_DSET_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_LARGE_READ_TEST_HYPERSLAB_DSET_DTYPESIZE; + + if (NULL == (read_buf = HDmalloc(data_size))) + TEST_ERROR; + + if (H5Dread(dset_id, DATASET_LARGE_READ_TEST_HYPERSLAB_DSET_DTYPE, mspace_id, fspace_id, H5P_DEFAULT, + read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", DATASET_LARGE_READ_TEST_HYPERSLAB_DSET_NAME); + goto error; + } + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (H5Sclose(mspace_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a large amount of data can be + * read back from a dataset using a large point selection. + * + * XXX: Test takes up significant amounts of memory. + */ +static int +test_read_dataset_large_point_selection(void) +{ + hsize_t *points = NULL; + hsize_t dims[DATASET_LARGE_READ_TEST_POINT_SELECTION_DSET_SPACE_RANK] = {225000000}; + size_t i, data_size; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + void *data = NULL; + + TESTING("large read from dataset with a point selection"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_LARGE_READ_TEST_POINT_SELECTION_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_LARGE_READ_TEST_POINT_SELECTION_GROUP_NAME); + goto error; + } + + if ((fspace_id = H5Screate_simple(DATASET_LARGE_READ_TEST_POINT_SELECTION_DSET_SPACE_RANK, dims, NULL)) < + 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_LARGE_READ_TEST_POINT_SELECTION_DSET_NAME, + DATASET_LARGE_READ_TEST_POINT_SELECTION_DSET_DTYPE, fspace_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_LARGE_READ_TEST_POINT_SELECTION_DSET_NAME); + goto error; + } + + for (i = 0, data_size = 1; i < DATASET_LARGE_READ_TEST_POINT_SELECTION_DSET_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_LARGE_READ_TEST_POINT_SELECTION_DSET_DTYPESIZE; + + if (NULL == (data = HDmalloc(data_size))) + TEST_ERROR; + if (NULL == + (points = HDmalloc((data_size / DATASET_LARGE_READ_TEST_POINT_SELECTION_DSET_DTYPESIZE) * + ((DATASET_LARGE_READ_TEST_POINT_SELECTION_DSET_SPACE_RANK) * (sizeof(hsize_t)))))) + TEST_ERROR; + + /* Select the entire dataspace */ + for (i = 0; i < data_size / DATASET_LARGE_READ_TEST_POINT_SELECTION_DSET_DTYPESIZE; i++) { + points[i] = i; + } + + if (H5Sselect_elements(fspace_id, H5S_SELECT_SET, + data_size / DATASET_LARGE_READ_TEST_POINT_SELECTION_DSET_DTYPESIZE, points) < 0) { + H5_FAILED(); + HDprintf(" couldn't select points\n"); + goto error; + } + + if (H5Dread(dset_id, DATASET_LARGE_READ_TEST_POINT_SELECTION_DSET_DTYPE, H5S_ALL, fspace_id, H5P_DEFAULT, + data) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", DATASET_LARGE_READ_TEST_POINT_SELECTION_DSET_NAME); + goto error; + } + + if (data) { + HDfree(data); + data = NULL; + } + + if (points) { + HDfree(points); + points = NULL; + } + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (data) + HDfree(data); + if (points) + HDfree(points); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} +#endif + +/* + * A test to check that data can't be read from a + * dataset when H5Dread is passed invalid parameters. + */ +static int +test_read_dataset_invalid_params(void) +{ + hsize_t dims[DATASET_READ_INVALID_PARAMS_TEST_DSET_SPACE_RANK] = {10, 5, 3}; + herr_t err_ret = -1; + size_t i, data_size; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + void *read_buf = NULL; + + TESTING_MULTIPART("H5Dread with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_READ_INVALID_PARAMS_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_READ_INVALID_PARAMS_TEST_GROUP_NAME); + goto error; + } + + if ((fspace_id = H5Screate_simple(DATASET_READ_INVALID_PARAMS_TEST_DSET_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_READ_INVALID_PARAMS_TEST_DSET_NAME, + DATASET_READ_INVALID_PARAMS_TEST_DSET_DTYPE, fspace_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_READ_INVALID_PARAMS_TEST_DSET_NAME); + goto error; + } + + for (i = 0, data_size = 1; i < DATASET_READ_INVALID_PARAMS_TEST_DSET_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_READ_INVALID_PARAMS_TEST_DSET_DTYPESIZE; + + if (NULL == (read_buf = HDmalloc(data_size))) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Dread_invalid_dset_id) + { + TESTING_2("H5Dread with an invalid dataset ID"); + + H5E_BEGIN_TRY + { + err_ret = H5Dread(H5I_INVALID_HID, DATASET_READ_INVALID_PARAMS_TEST_DSET_DTYPE, H5S_ALL, + H5S_ALL, H5P_DEFAULT, read_buf); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" read from dataset using H5Dread with an invalid dataset ID!\n"); + PART_ERROR(H5Dread_invalid_dset_id); + } + + PASSED(); + } + PART_END(H5Dread_invalid_dset_id); + + PART_BEGIN(H5Dread_invalid_datatype) + { + TESTING_2("H5Dread with an invalid memory datatype"); + + H5E_BEGIN_TRY + { + err_ret = H5Dread(dset_id, H5I_INVALID_HID, H5S_ALL, H5S_ALL, H5P_DEFAULT, read_buf); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" read from dataset using H5Dread with an invalid memory datatype!\n"); + PART_ERROR(H5Dread_invalid_datatype); + } + + PASSED(); + } + PART_END(H5Dread_invalid_datatype); + + PART_BEGIN(H5Dread_invalid_mem_dataspace) + { + TESTING_2("H5Dread with an invalid memory dataspace"); + + H5E_BEGIN_TRY + { + err_ret = H5Dread(dset_id, DATASET_READ_INVALID_PARAMS_TEST_DSET_DTYPE, H5I_INVALID_HID, + H5S_ALL, H5P_DEFAULT, read_buf); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" read from dataset using H5Dread with an invalid memory dataspace!\n"); + PART_ERROR(H5Dread_invalid_mem_dataspace); + } + + PASSED(); + } + PART_END(H5Dread_invalid_mem_dataspace); + + PART_BEGIN(H5Dread_invalid_file_dataspace) + { + TESTING_2("H5Dread with an invalid file dataspace"); + + H5E_BEGIN_TRY + { + err_ret = H5Dread(dset_id, DATASET_READ_INVALID_PARAMS_TEST_DSET_DTYPE, H5S_ALL, + H5I_INVALID_HID, H5P_DEFAULT, read_buf); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" read from dataset using H5Dread with an invalid file dataspace!\n"); + PART_ERROR(H5Dread_invalid_file_dataspace); + } + + PASSED(); + } + PART_END(H5Dread_invalid_file_dataspace); + + PART_BEGIN(H5Dread_invalid_dxpl) + { + TESTING_2("H5Dread with an invalid DXPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Dread(dset_id, DATASET_READ_INVALID_PARAMS_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, + H5I_INVALID_HID, read_buf); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" read from dataset using H5Dread with an invalid DXPL!\n"); + PART_ERROR(H5Dread_invalid_dxpl); + } + + PASSED(); + } + PART_END(H5Dread_invalid_dxpl); + + PART_BEGIN(H5Dread_invalid_data_buf) + { + TESTING_2("H5Dread with an invalid data buffer"); + + H5E_BEGIN_TRY + { + err_ret = H5Dread(dset_id, DATASET_READ_INVALID_PARAMS_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, + H5P_DEFAULT, NULL); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" read from dataset using H5Dread with an invalid data buffer!\n"); + PART_ERROR(H5Dread_invalid_data_buf); + } + + PASSED(); + } + PART_END(H5Dread_invalid_data_buf); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (read_buf) + HDfree(read_buf); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a small write can be + * made to a dataset using an H5S_ALL selection. + */ +static int +test_write_dataset_small_all(void) +{ + hssize_t space_npoints; + hsize_t dims[DATASET_SMALL_WRITE_TEST_ALL_DSET_SPACE_RANK] = {10, 5, 3}; + size_t i; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + void *data = NULL; + + TESTING("small write to dataset with H5S_ALL"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_SMALL_WRITE_TEST_ALL_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", DATASET_SMALL_WRITE_TEST_ALL_GROUP_NAME); + goto error; + } + + if ((fspace_id = H5Screate_simple(DATASET_SMALL_WRITE_TEST_ALL_DSET_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_SMALL_WRITE_TEST_ALL_DSET_NAME, + DATASET_SMALL_WRITE_TEST_ALL_DSET_DTYPE, fspace_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_SMALL_WRITE_TEST_ALL_DSET_NAME); + goto error; + } + + /* Close the dataset and dataspace to ensure that writing works correctly in this manner */ + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + + if ((dset_id = H5Dopen2(group_id, DATASET_SMALL_WRITE_TEST_ALL_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_SMALL_WRITE_TEST_ALL_DSET_NAME); + goto error; + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + goto error; + } + + if ((space_npoints = H5Sget_simple_extent_npoints(fspace_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataspace num points\n"); + goto error; + } + + if (NULL == (data = HDmalloc((hsize_t)space_npoints * DATASET_SMALL_WRITE_TEST_ALL_DSET_DTYPESIZE))) + TEST_ERROR; + + for (i = 0; i < (hsize_t)space_npoints; i++) + ((int *)data)[i] = (int)i; + + if (H5Dwrite(dset_id, DATASET_SMALL_WRITE_TEST_ALL_DSET_DTYPE, H5S_ALL, H5S_ALL, H5P_DEFAULT, data) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", DATASET_SMALL_WRITE_TEST_ALL_DSET_NAME); + goto error; + } + + if (data) { + HDfree(data); + data = NULL; + } + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (data) + HDfree(data); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a small write can be made + * to a dataset using a hyperslab selection. + */ +static int +test_write_dataset_small_hyperslab(void) +{ + hsize_t start[DATASET_SMALL_WRITE_TEST_HYPERSLAB_DSET_SPACE_RANK]; + hsize_t stride[DATASET_SMALL_WRITE_TEST_HYPERSLAB_DSET_SPACE_RANK]; + hsize_t count[DATASET_SMALL_WRITE_TEST_HYPERSLAB_DSET_SPACE_RANK]; + hsize_t block[DATASET_SMALL_WRITE_TEST_HYPERSLAB_DSET_SPACE_RANK]; + hsize_t dims[DATASET_SMALL_WRITE_TEST_HYPERSLAB_DSET_SPACE_RANK] = {10, 5, 3}; + size_t i, data_size; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID, fspace_id = H5I_INVALID_HID; + void *data = NULL; + + TESTING("small write to dataset with a hyperslab selection"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_SMALL_WRITE_TEST_HYPERSLAB_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_SMALL_WRITE_TEST_HYPERSLAB_GROUP_NAME); + goto error; + } + + if ((fspace_id = H5Screate_simple(DATASET_SMALL_WRITE_TEST_HYPERSLAB_DSET_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + if ((mspace_id = H5Screate_simple(DATASET_SMALL_WRITE_TEST_HYPERSLAB_DSET_SPACE_RANK - 1, dims, NULL)) < + 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_SMALL_WRITE_TEST_HYPERSLAB_DSET_NAME, + DATASET_SMALL_WRITE_TEST_HYPERSLAB_DSET_DTYPE, fspace_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_SMALL_WRITE_TEST_HYPERSLAB_DSET_NAME); + goto error; + } + + for (i = 0, data_size = 1; i < DATASET_SMALL_WRITE_TEST_HYPERSLAB_DSET_SPACE_RANK - 1; i++) + data_size *= dims[i]; + data_size *= DATASET_SMALL_WRITE_TEST_HYPERSLAB_DSET_DTYPESIZE; + + if (NULL == (data = HDmalloc(data_size))) + TEST_ERROR; + + for (i = 0; i < data_size / DATASET_SMALL_WRITE_TEST_HYPERSLAB_DSET_DTYPESIZE; i++) + ((int *)data)[i] = (int)i; + + for (i = 0; i < DATASET_SMALL_WRITE_TEST_HYPERSLAB_DSET_SPACE_RANK; i++) { + start[i] = 0; + stride[i] = 1; + count[i] = dims[i]; + block[i] = 1; + } + + count[2] = 1; + + if (H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET, start, stride, count, block) < 0) + TEST_ERROR; + + if (H5Dwrite(dset_id, DATASET_SMALL_WRITE_TEST_HYPERSLAB_DSET_DTYPE, mspace_id, fspace_id, H5P_DEFAULT, + data) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", DATASET_SMALL_WRITE_TEST_HYPERSLAB_DSET_NAME); + goto error; + } + + if (data) { + HDfree(data); + data = NULL; + } + + if (H5Sclose(mspace_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (data) + HDfree(data); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a small write can be made + * to a dataset using a point selection. + */ +static int +test_write_dataset_small_point_selection(void) +{ + hsize_t points[DATASET_SMALL_WRITE_TEST_POINT_SELECTION_NUM_POINTS * + DATASET_SMALL_WRITE_TEST_POINT_SELECTION_DSET_SPACE_RANK]; + hsize_t dims[DATASET_SMALL_WRITE_TEST_POINT_SELECTION_DSET_SPACE_RANK] = {10, 10, 10}; + hsize_t mdims[] = {DATASET_SMALL_WRITE_TEST_POINT_SELECTION_NUM_POINTS}; + size_t i, data_size; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + void *data = NULL; + + TESTING("small write to dataset with a point selection"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_SMALL_WRITE_TEST_POINT_SELECTION_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_SMALL_WRITE_TEST_POINT_SELECTION_GROUP_NAME); + goto error; + } + + if ((fspace_id = H5Screate_simple(DATASET_SMALL_WRITE_TEST_POINT_SELECTION_DSET_SPACE_RANK, dims, NULL)) < + 0) + TEST_ERROR; + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_SMALL_WRITE_TEST_POINT_SELECTION_DSET_NAME, + DATASET_SMALL_WRITE_TEST_POINT_SELECTION_DSET_DTYPE, fspace_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_SMALL_WRITE_TEST_POINT_SELECTION_DSET_NAME); + goto error; + } + + data_size = DATASET_SMALL_WRITE_TEST_POINT_SELECTION_NUM_POINTS * + DATASET_SMALL_WRITE_TEST_POINT_SELECTION_DSET_DTYPESIZE; + + if (NULL == (data = HDmalloc(data_size))) + TEST_ERROR; + + for (i = 0; i < data_size / DATASET_SMALL_WRITE_TEST_POINT_SELECTION_DSET_DTYPESIZE; i++) + ((int *)data)[i] = (int)i; + + for (i = 0; i < DATASET_SMALL_WRITE_TEST_POINT_SELECTION_NUM_POINTS; i++) { + size_t j; + + for (j = 0; j < DATASET_SMALL_WRITE_TEST_POINT_SELECTION_DSET_SPACE_RANK; j++) + points[(i * DATASET_SMALL_WRITE_TEST_POINT_SELECTION_DSET_SPACE_RANK) + j] = i; + } + + if (H5Sselect_elements(fspace_id, H5S_SELECT_SET, DATASET_SMALL_WRITE_TEST_POINT_SELECTION_NUM_POINTS, + points) < 0) { + H5_FAILED(); + HDprintf(" couldn't select points\n"); + goto error; + } + + if (H5Dwrite(dset_id, DATASET_SMALL_WRITE_TEST_POINT_SELECTION_DSET_DTYPE, mspace_id, fspace_id, + H5P_DEFAULT, data) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", DATASET_SMALL_WRITE_TEST_POINT_SELECTION_DSET_NAME); + goto error; + } + + if (data) { + HDfree(data); + data = NULL; + } + + if (H5Sclose(mspace_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (data) + HDfree(data); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +#ifndef NO_LARGE_TESTS +/* + * A test to check that a large write can be made + * to a dataset using an H5S_ALL selection. + */ +static int +test_write_dataset_large_all(void) +{ + hssize_t space_npoints; + hsize_t dims[DATASET_LARGE_WRITE_TEST_ALL_DSET_SPACE_RANK] = {600, 600, 600}; + size_t i, data_size; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + void *data = NULL; + + TESTING("large write to dataset with H5S_ALL"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, basic or more dataset aren't supported with this " + "connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_LARGE_WRITE_TEST_ALL_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", DATASET_LARGE_WRITE_TEST_ALL_GROUP_NAME); + goto error; + } + + if ((fspace_id = H5Screate_simple(DATASET_LARGE_WRITE_TEST_ALL_DSET_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_LARGE_WRITE_TEST_ALL_DSET_NAME, + DATASET_LARGE_WRITE_TEST_ALL_DSET_DTYPE, fspace_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_LARGE_WRITE_TEST_ALL_DSET_NAME); + goto error; + } + + /* Close the dataset and dataspace to ensure that retrieval of file space ID is working */ + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + + if ((dset_id = H5Dopen2(group_id, DATASET_LARGE_WRITE_TEST_ALL_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_LARGE_WRITE_TEST_ALL_DSET_NAME); + goto error; + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + goto error; + } + + if ((space_npoints = H5Sget_simple_extent_npoints(fspace_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataspace num points\n"); + goto error; + } + + if (NULL == (data = HDmalloc((hsize_t)space_npoints * DATASET_LARGE_WRITE_TEST_ALL_DSET_DTYPESIZE))) + TEST_ERROR; + + for (i = 0; i < (hsize_t)space_npoints; i++) + ((int *)data)[i] = (int)i; + + if (H5Dwrite(dset_id, DATASET_LARGE_WRITE_TEST_ALL_DSET_DTYPE, H5S_ALL, H5S_ALL, H5P_DEFAULT, data) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", DATASET_LARGE_WRITE_TEST_ALL_DSET_NAME); + goto error; + } + + if (data) { + HDfree(data); + data = NULL; + } + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a large write can be made + * to a dataset using a hyperslab selection. + */ +static int +test_write_dataset_large_hyperslab(void) +{ + hsize_t start[DATASET_LARGE_WRITE_TEST_HYPERSLAB_DSET_SPACE_RANK]; + hsize_t stride[DATASET_LARGE_WRITE_TEST_HYPERSLAB_DSET_SPACE_RANK]; + hsize_t count[DATASET_LARGE_WRITE_TEST_HYPERSLAB_DSET_SPACE_RANK]; + hsize_t block[DATASET_LARGE_WRITE_TEST_HYPERSLAB_DSET_SPACE_RANK]; + hsize_t dims[DATASET_LARGE_WRITE_TEST_HYPERSLAB_DSET_SPACE_RANK] = {600, 600, 600}; + size_t i, data_size; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID, fspace_id = H5I_INVALID_HID; + void *data = NULL; + + TESTING("large write to dataset with a hyperslab selection"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_LARGE_WRITE_TEST_HYPERSLAB_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_LARGE_WRITE_TEST_HYPERSLAB_GROUP_NAME); + goto error; + } + + if ((fspace_id = H5Screate_simple(DATASET_LARGE_WRITE_TEST_HYPERSLAB_DSET_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + if ((mspace_id = H5Screate_simple(DATASET_LARGE_WRITE_TEST_HYPERSLAB_DSET_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_LARGE_WRITE_TEST_HYPERSLAB_DSET_NAME, + DATASET_LARGE_WRITE_TEST_HYPERSLAB_DSET_DTYPE, fspace_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_LARGE_WRITE_TEST_HYPERSLAB_DSET_NAME); + goto error; + } + + for (i = 0, data_size = 1; i < DATASET_LARGE_WRITE_TEST_HYPERSLAB_DSET_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_LARGE_WRITE_TEST_HYPERSLAB_DSET_DTYPESIZE; + + if (NULL == (data = HDmalloc(data_size))) + TEST_ERROR; + + for (i = 0; i < data_size / DATASET_LARGE_WRITE_TEST_HYPERSLAB_DSET_DTYPESIZE; i++) + ((int *)data)[i] = (int)i; + + for (i = 0; i < DATASET_LARGE_WRITE_TEST_HYPERSLAB_DSET_SPACE_RANK; i++) { + start[i] = 0; + stride[i] = 1; + count[i] = dims[i]; + block[i] = 1; + } + + if (H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET, start, stride, count, block) < 0) + TEST_ERROR; + + if (H5Dwrite(dset_id, DATASET_LARGE_WRITE_TEST_HYPERSLAB_DSET_DTYPE, mspace_id, fspace_id, H5P_DEFAULT, + data) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", DATASET_LARGE_WRITE_TEST_HYPERSLAB_DSET_NAME); + goto error; + } + + if (data) { + HDfree(data); + data = NULL; + } + + if (H5Sclose(mspace_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (data) + HDfree(data); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a large write can be made + * to a dataset using a point selection. + */ +static int +test_write_dataset_large_point_selection(void) +{ + TESTING("large write to dataset with a point selection"); + + SKIPPED(); + + return 0; + +error: + return 1; +} +#endif + +/* + * A test to ensure that data is read back correctly from + * a dataset after it has been written. + */ +static int +test_write_dataset_data_verification(void) +{ + hssize_t space_npoints; + hsize_t dims[DATASET_DATA_VERIFY_WRITE_TEST_DSET_SPACE_RANK] = {10, 10, 10}; + hsize_t start[DATASET_DATA_VERIFY_WRITE_TEST_DSET_SPACE_RANK]; + hsize_t stride[DATASET_DATA_VERIFY_WRITE_TEST_DSET_SPACE_RANK]; + hsize_t count[DATASET_DATA_VERIFY_WRITE_TEST_DSET_SPACE_RANK]; + hsize_t block[DATASET_DATA_VERIFY_WRITE_TEST_DSET_SPACE_RANK]; + hsize_t + points[DATASET_DATA_VERIFY_WRITE_TEST_NUM_POINTS * DATASET_DATA_VERIFY_WRITE_TEST_DSET_SPACE_RANK]; + size_t i, data_size; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + void *data = NULL; + void *write_buf = NULL; + void *read_buf = NULL; + + TESTING_MULTIPART("verification of dataset data using H5Dwrite then H5Dread"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, basic or more dataset aren't supported with this " + "connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_DATA_VERIFY_WRITE_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", DATASET_DATA_VERIFY_WRITE_TEST_GROUP_NAME); + goto error; + } + + if ((fspace_id = H5Screate_simple(DATASET_DATA_VERIFY_WRITE_TEST_DSET_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_DATA_VERIFY_WRITE_TEST_DSET_NAME, + DATASET_DATA_VERIFY_WRITE_TEST_DSET_DTYPE, fspace_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_DATA_VERIFY_WRITE_TEST_DSET_NAME); + goto error; + } + + for (i = 0, data_size = 1; i < DATASET_DATA_VERIFY_WRITE_TEST_DSET_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_DATA_VERIFY_WRITE_TEST_DSET_DTYPESIZE; + + if (NULL == (data = HDmalloc(data_size))) + TEST_ERROR; + + for (i = 0; i < data_size / DATASET_DATA_VERIFY_WRITE_TEST_DSET_DTYPESIZE; i++) + ((int *)data)[i] = (int)i; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Dwrite_all_read) + { + TESTING_2("H5Dwrite using H5S_ALL then H5Dread"); + + if (H5Dwrite(dset_id, DATASET_DATA_VERIFY_WRITE_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, H5P_DEFAULT, + data) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", DATASET_DATA_VERIFY_WRITE_TEST_DSET_NAME); + PART_ERROR(H5Dwrite_all_read); + } + + if (data) { + HDfree(data); + data = NULL; + } + + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_DATA_VERIFY_WRITE_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_DATA_VERIFY_WRITE_TEST_DSET_NAME); + PART_ERROR(H5Dwrite_all_read); + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + PART_ERROR(H5Dwrite_all_read); + } + + if ((space_npoints = H5Sget_simple_extent_npoints(fspace_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataspace num points\n"); + PART_ERROR(H5Dwrite_all_read); + } + + if (NULL == + (data = HDmalloc((hsize_t)space_npoints * DATASET_DATA_VERIFY_WRITE_TEST_DSET_DTYPESIZE))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + PART_ERROR(H5Dwrite_all_read); + } + + if (H5Dread(dset_id, DATASET_DATA_VERIFY_WRITE_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, H5P_DEFAULT, + data) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", DATASET_DATA_VERIFY_WRITE_TEST_DSET_NAME); + PART_ERROR(H5Dwrite_all_read); + } + + for (i = 0; i < (hsize_t)space_npoints; i++) + if (((int *)data)[i] != (int)i) { + H5_FAILED(); + HDprintf(" H5S_ALL selection data verification failed\n"); + PART_ERROR(H5Dwrite_all_read); + } + + if (data) { + HDfree(data); + data = NULL; + } + + PASSED(); + } + PART_END(H5Dwrite_all_read); + + PART_BEGIN(H5Dwrite_hyperslab_read) + { + TESTING_2("H5Dwrite using hyperslab selection then H5Dread"); + + data_size = dims[1] * 2 * DATASET_DATA_VERIFY_WRITE_TEST_DSET_DTYPESIZE; + + if (NULL == (write_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + for (i = 0; i < data_size / DATASET_DATA_VERIFY_WRITE_TEST_DSET_DTYPESIZE; i++) + ((int *)write_buf)[i] = 56; + + for (i = 0, data_size = 1; i < DATASET_DATA_VERIFY_WRITE_TEST_DSET_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_DATA_VERIFY_WRITE_TEST_DSET_DTYPESIZE; + + if (NULL == (data = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset data verification\n"); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + if (H5Dread(dset_id, DATASET_DATA_VERIFY_WRITE_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, H5P_DEFAULT, + data) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", DATASET_DATA_VERIFY_WRITE_TEST_DSET_NAME); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + for (i = 0; i < 2; i++) { + size_t j; + + for (j = 0; j < dims[1]; j++) + ((int *)data)[(i * dims[1] * dims[2]) + (j * dims[2])] = 56; + } + + /* Write to first two rows of dataset */ + start[0] = start[1] = start[2] = 0; + stride[0] = stride[1] = stride[2] = 1; + count[0] = 2; + count[1] = dims[1]; + count[2] = 1; + block[0] = block[1] = block[2] = 1; + + if (H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET, start, stride, count, block) < 0) { + H5_FAILED(); + HDprintf(" couldn't select hyperslab for dataset write\n"); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + { + hsize_t mdims[] = {(hsize_t)2 * dims[1]}; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + PART_ERROR(H5Dwrite_hyperslab_read); + } + } + + if (H5Dwrite(dset_id, DATASET_DATA_VERIFY_WRITE_TEST_DSET_DTYPE, mspace_id, fspace_id, + H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", DATASET_DATA_VERIFY_WRITE_TEST_DSET_NAME); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + if (mspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(mspace_id); + } + H5E_END_TRY; + mspace_id = H5I_INVALID_HID; + } + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_DATA_VERIFY_WRITE_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_DATA_VERIFY_WRITE_TEST_DSET_NAME); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + if ((space_npoints = H5Sget_simple_extent_npoints(fspace_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataspace num points\n"); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + if (NULL == (read_buf = HDmalloc((hsize_t)space_npoints * + DATASET_DATA_VERIFY_WRITE_TEST_DSET_DTYPESIZE))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + if (H5Dread(dset_id, DATASET_DATA_VERIFY_WRITE_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, H5P_DEFAULT, + read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", DATASET_DATA_VERIFY_WRITE_TEST_DSET_NAME); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + if (memcmp(data, read_buf, data_size)) { + H5_FAILED(); + HDprintf(" hyperslab selection data verification failed\n"); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + if (data) { + HDfree(data); + data = NULL; + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + PASSED(); + } + PART_END(H5Dwrite_hyperslab_read); + + PART_BEGIN(H5Dwrite_point_sel_read) + { + TESTING_2("H5Dwrite using point selection then H5Dread"); + + data_size = + DATASET_DATA_VERIFY_WRITE_TEST_NUM_POINTS * DATASET_DATA_VERIFY_WRITE_TEST_DSET_DTYPESIZE; + + if (NULL == (write_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + PART_ERROR(H5Dwrite_point_sel_read); + } + + for (i = 0; i < data_size / DATASET_DATA_VERIFY_WRITE_TEST_DSET_DTYPESIZE; i++) + ((int *)write_buf)[i] = 13; + + for (i = 0, data_size = 1; i < DATASET_DATA_VERIFY_WRITE_TEST_DSET_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_DATA_VERIFY_WRITE_TEST_DSET_DTYPESIZE; + + if (NULL == (data = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset data verification\n"); + PART_ERROR(H5Dwrite_point_sel_read); + } + + if (H5Dread(dset_id, DATASET_DATA_VERIFY_WRITE_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, H5P_DEFAULT, + data) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", DATASET_DATA_VERIFY_WRITE_TEST_DSET_NAME); + PART_ERROR(H5Dwrite_point_sel_read); + } + + for (i = 0; i < dims[0]; i++) { + size_t j; + + for (j = 0; j < dims[1]; j++) { + size_t k; + + for (k = 0; k < dims[2]; k++) { + if (i == j && j == k) + ((int *)data)[(i * dims[1] * dims[2]) + (j * dims[2]) + k] = 13; + } + } + } + + /* Select a series of 10 points in the dataset */ + for (i = 0; i < DATASET_DATA_VERIFY_WRITE_TEST_NUM_POINTS; i++) { + size_t j; + + for (j = 0; j < DATASET_DATA_VERIFY_WRITE_TEST_DSET_SPACE_RANK; j++) + points[(i * DATASET_DATA_VERIFY_WRITE_TEST_DSET_SPACE_RANK) + j] = i; + } + + if (H5Sselect_elements(fspace_id, H5S_SELECT_SET, DATASET_DATA_VERIFY_WRITE_TEST_NUM_POINTS, + points) < 0) { + H5_FAILED(); + HDprintf(" couldn't select elements in dataspace\n"); + PART_ERROR(H5Dwrite_point_sel_read); + } + + { + hsize_t mdims[] = {(hsize_t)DATASET_DATA_VERIFY_WRITE_TEST_NUM_POINTS}; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + PART_ERROR(H5Dwrite_point_sel_read); + } + } + + if (H5Dwrite(dset_id, DATASET_DATA_VERIFY_WRITE_TEST_DSET_DTYPE, mspace_id, fspace_id, + H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", DATASET_DATA_VERIFY_WRITE_TEST_DSET_NAME); + PART_ERROR(H5Dwrite_point_sel_read); + } + + if (mspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(mspace_id); + } + H5E_END_TRY; + mspace_id = H5I_INVALID_HID; + } + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_DATA_VERIFY_WRITE_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_DATA_VERIFY_WRITE_TEST_DSET_NAME); + PART_ERROR(H5Dwrite_point_sel_read); + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + PART_ERROR(H5Dwrite_point_sel_read); + } + + if ((space_npoints = H5Sget_simple_extent_npoints(fspace_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataspace num points\n"); + PART_ERROR(H5Dwrite_point_sel_read); + } + + if (NULL == (read_buf = HDmalloc((hsize_t)space_npoints * + DATASET_DATA_VERIFY_WRITE_TEST_DSET_DTYPESIZE))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + PART_ERROR(H5Dwrite_point_sel_read); + } + + if (H5Dread(dset_id, DATASET_DATA_VERIFY_WRITE_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, H5P_DEFAULT, + read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", DATASET_DATA_VERIFY_WRITE_TEST_DSET_NAME); + PART_ERROR(H5Dwrite_point_sel_read); + } + + if (memcmp(data, read_buf, data_size)) { + H5_FAILED(); + HDprintf(" point selection data verification failed\n"); + PART_ERROR(H5Dwrite_point_sel_read); + } + + PASSED(); + } + PART_END(H5Dwrite_point_sel_read); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (data) { + HDfree(data); + data = NULL; + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (data) + HDfree(data); + if (write_buf) + HDfree(write_buf); + if (read_buf) + HDfree(read_buf); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a dataset can't be written to + * when H5Dwrite is passed invalid parameters. + */ +static int +test_write_dataset_invalid_params(void) +{ + hssize_t space_npoints; + hsize_t dims[DATASET_WRITE_INVALID_PARAMS_TEST_DSET_SPACE_RANK] = {10, 5, 3}; + herr_t err_ret = -1; + size_t i; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + void *data = NULL; + + TESTING_MULTIPART("H5Dwrite with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_WRITE_INVALID_PARAMS_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_WRITE_INVALID_PARAMS_TEST_GROUP_NAME); + goto error; + } + + if ((fspace_id = H5Screate_simple(DATASET_WRITE_INVALID_PARAMS_TEST_DSET_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_WRITE_INVALID_PARAMS_TEST_DSET_NAME, + DATASET_SMALL_WRITE_TEST_ALL_DSET_DTYPE, fspace_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_WRITE_INVALID_PARAMS_TEST_DSET_NAME); + goto error; + } + + if ((space_npoints = H5Sget_simple_extent_npoints(fspace_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataspace num points\n"); + goto error; + } + + if (NULL == (data = HDmalloc((hsize_t)space_npoints * DATASET_WRITE_INVALID_PARAMS_TEST_DSET_DTYPESIZE))) + TEST_ERROR; + + for (i = 0; i < (hsize_t)space_npoints; i++) + ((int *)data)[i] = (int)i; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Dwrite_invalid_dset_id) + { + TESTING_2("H5Dwrite with an invalid dataset ID"); + + H5E_BEGIN_TRY + { + err_ret = H5Dwrite(H5I_INVALID_HID, DATASET_WRITE_INVALID_PARAMS_TEST_DSET_DTYPE, H5S_ALL, + H5S_ALL, H5P_DEFAULT, data); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" wrote to dataset using H5Dwrite with an invalid dataset ID!\n"); + PART_ERROR(H5Dwrite_invalid_dset_id); + } + + PASSED(); + } + PART_END(H5Dwrite_invalid_dset_id); + + PART_BEGIN(H5Dwrite_invalid_datatype) + { + TESTING_2("H5Dwrite with an invalid memory datatype"); + + H5E_BEGIN_TRY + { + err_ret = H5Dwrite(dset_id, H5I_INVALID_HID, H5S_ALL, H5S_ALL, H5P_DEFAULT, data); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" wrote to dataset using H5Dwrite with an invalid memory datatype!\n"); + PART_ERROR(H5Dwrite_invalid_datatype); + } + + PASSED(); + } + PART_END(H5Dwrite_invalid_datatype); + + PART_BEGIN(H5Dwrite_invalid_mem_dataspace) + { + TESTING_2("H5Dwrite with an invalid memory dataspace"); + + H5E_BEGIN_TRY + { + err_ret = H5Dwrite(dset_id, DATASET_WRITE_INVALID_PARAMS_TEST_DSET_DTYPE, H5I_INVALID_HID, + H5S_ALL, H5P_DEFAULT, data); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" wrote to dataset using H5Dwrite with an invalid memory dataspace!\n"); + PART_ERROR(H5Dwrite_invalid_mem_dataspace); + } + + PASSED(); + } + PART_END(H5Dwrite_invalid_mem_dataspace); + + PART_BEGIN(H5Dwrite_invalid_file_dataspace) + { + TESTING_2("H5Dwrite with an invalid file dataspace"); + + H5E_BEGIN_TRY + { + err_ret = H5Dwrite(dset_id, DATASET_WRITE_INVALID_PARAMS_TEST_DSET_DTYPE, H5S_ALL, + H5I_INVALID_HID, H5P_DEFAULT, data); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" wrote to dataset using H5Dwrite with an invalid file dataspace!\n"); + PART_ERROR(H5Dwrite_invalid_file_dataspace); + } + + PASSED(); + } + PART_END(H5Dwrite_invalid_file_dataspace); + + PART_BEGIN(H5Dwrite_invalid_dxpl) + { + TESTING_2("H5Dwrite with an invalid DXPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Dwrite(dset_id, DATASET_WRITE_INVALID_PARAMS_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, + H5I_INVALID_HID, data); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" wrote to dataset using H5Dwrite with an invalid DXPL!\n"); + PART_ERROR(H5Dwrite_invalid_dxpl); + } + + PASSED(); + } + PART_END(H5Dwrite_invalid_dxpl); + + PART_BEGIN(H5Dwrite_invalid_data_buf) + { + TESTING_2("H5Dwrite with an invalid data buffer"); + + H5E_BEGIN_TRY + { + err_ret = H5Dwrite(dset_id, DATASET_WRITE_INVALID_PARAMS_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, + H5P_DEFAULT, NULL); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" wrote to dataset using H5Dwrite with an invalid data buffer!\n"); + PART_ERROR(H5Dwrite_invalid_data_buf); + } + + PASSED(); + } + PART_END(H5Dwrite_invalid_data_buf); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (data) { + HDfree(data); + data = NULL; + } + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (data) + HDfree(data); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to ensure that data is read back correctly from a dataset after it has + * been written, using type conversion with builtin types. + */ +static int +test_dataset_builtin_type_conversion(void) +{ + hssize_t space_npoints; + hsize_t dims[DATASET_DATA_BUILTIN_CONVERSION_TEST_DSET_SPACE_RANK] = {10, 10, 10}; + hsize_t start[DATASET_DATA_BUILTIN_CONVERSION_TEST_DSET_SPACE_RANK]; + hsize_t stride[DATASET_DATA_BUILTIN_CONVERSION_TEST_DSET_SPACE_RANK]; + hsize_t count[DATASET_DATA_BUILTIN_CONVERSION_TEST_DSET_SPACE_RANK]; + hsize_t block[DATASET_DATA_BUILTIN_CONVERSION_TEST_DSET_SPACE_RANK]; + hsize_t points[DATASET_DATA_BUILTIN_CONVERSION_TEST_NUM_POINTS * + DATASET_DATA_BUILTIN_CONVERSION_TEST_DSET_SPACE_RANK]; + size_t i, data_size; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + hid_t file_type_id = H5I_INVALID_HID; + H5T_order_t native_order; + void *data = NULL; + void *write_buf = NULL; + void *read_buf = NULL; + + TESTING_MULTIPART( + "verification of dataset data using H5Dwrite then H5Dread with type conversion of builtin types"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, basic or more dataset aren't supported with this " + "connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((native_order = H5Tget_order(DATASET_DATA_BUILTIN_CONVERSION_TEST_MEM_DTYPE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get native byte order\n"); + goto error; + } + if (native_order == H5T_ORDER_LE) + file_type_id = H5T_STD_I32BE; + else + file_type_id = H5T_STD_I32LE; + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_DATA_BUILTIN_CONVERSION_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", DATASET_DATA_VERIFY_WRITE_TEST_GROUP_NAME); + goto error; + } + + if ((fspace_id = H5Screate_simple(DATASET_DATA_BUILTIN_CONVERSION_TEST_DSET_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_DATA_BUILTIN_CONVERSION_TEST_DSET_NAME, file_type_id, + fspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_DATA_BUILTIN_CONVERSION_TEST_DSET_NAME); + goto error; + } + + for (i = 0, data_size = 1; i < DATASET_DATA_BUILTIN_CONVERSION_TEST_DSET_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_DATA_BUILTIN_CONVERSION_TEST_MEM_DTYPESIZE; + + if (NULL == (data = HDmalloc(data_size))) + TEST_ERROR; + + for (i = 0; i < data_size / DATASET_DATA_BUILTIN_CONVERSION_TEST_MEM_DTYPESIZE; i++) + ((int *)data)[i] = (int)i; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Dwrite_all_read) + { + TESTING_2("H5Dwrite then H5Dread with H5S_ALL selection"); + + if (H5Dwrite(dset_id, DATASET_DATA_BUILTIN_CONVERSION_TEST_MEM_DTYPE, H5S_ALL, H5S_ALL, + H5P_DEFAULT, data) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", + DATASET_DATA_BUILTIN_CONVERSION_TEST_DSET_NAME); + PART_ERROR(H5Dwrite_all_read); + } + + if (data) { + HDfree(data); + data = NULL; + } + + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_DATA_BUILTIN_CONVERSION_TEST_DSET_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_DATA_BUILTIN_CONVERSION_TEST_DSET_NAME); + PART_ERROR(H5Dwrite_all_read); + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + PART_ERROR(H5Dwrite_all_read); + } + + if ((space_npoints = H5Sget_simple_extent_npoints(fspace_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataspace num points\n"); + PART_ERROR(H5Dwrite_all_read); + } + + if (NULL == (data = HDmalloc((hsize_t)space_npoints * + DATASET_DATA_BUILTIN_CONVERSION_TEST_MEM_DTYPESIZE))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + PART_ERROR(H5Dwrite_all_read); + } + + if (H5Dread(dset_id, DATASET_DATA_BUILTIN_CONVERSION_TEST_MEM_DTYPE, H5S_ALL, H5S_ALL, + H5P_DEFAULT, data) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", + DATASET_DATA_BUILTIN_CONVERSION_TEST_DSET_NAME); + PART_ERROR(H5Dwrite_all_read); + } + + for (i = 0; i < (hsize_t)space_npoints; i++) + if (((int *)data)[i] != (int)i) { + H5_FAILED(); + HDprintf(" H5S_ALL selection data verification failed\n"); + PART_ERROR(H5Dwrite_all_read); + } + + if (data) { + HDfree(data); + data = NULL; + } + + PASSED(); + } + PART_END(H5Dwrite_all_read); + + PART_BEGIN(H5Dwrite_hyperslab_read) + { + TESTING_2("H5Dwrite using hyperslab selection then H5Dread"); + + data_size = dims[1] * 2 * DATASET_DATA_BUILTIN_CONVERSION_TEST_MEM_DTYPESIZE; + + if (NULL == (write_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + for (i = 0; i < data_size / DATASET_DATA_BUILTIN_CONVERSION_TEST_MEM_DTYPESIZE; i++) + ((int *)write_buf)[i] = 56; + + for (i = 0, data_size = 1; i < DATASET_DATA_BUILTIN_CONVERSION_TEST_DSET_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_DATA_BUILTIN_CONVERSION_TEST_MEM_DTYPESIZE; + + if (NULL == (data = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset data verification\n"); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + if (H5Dread(dset_id, DATASET_DATA_BUILTIN_CONVERSION_TEST_MEM_DTYPE, H5S_ALL, H5S_ALL, + H5P_DEFAULT, data) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", + DATASET_DATA_BUILTIN_CONVERSION_TEST_DSET_NAME); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + for (i = 0; i < 2; i++) { + size_t j; + + for (j = 0; j < dims[1]; j++) + ((int *)data)[(i * dims[1] * dims[2]) + (j * dims[2])] = 56; + } + + /* Write to first two rows of dataset */ + start[0] = start[1] = start[2] = 0; + stride[0] = stride[1] = stride[2] = 1; + count[0] = 2; + count[1] = dims[1]; + count[2] = 1; + block[0] = block[1] = block[2] = 1; + + if (H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET, start, stride, count, block) < 0) { + H5_FAILED(); + HDprintf(" couldn't select hyperslab for dataset write\n"); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + { + hsize_t mdims[] = {(hsize_t)2 * dims[1]}; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + PART_ERROR(H5Dwrite_hyperslab_read); + } + } + + if (H5Dwrite(dset_id, DATASET_DATA_BUILTIN_CONVERSION_TEST_MEM_DTYPE, mspace_id, fspace_id, + H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", + DATASET_DATA_BUILTIN_CONVERSION_TEST_DSET_NAME); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + if (mspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(mspace_id); + } + H5E_END_TRY; + mspace_id = H5I_INVALID_HID; + } + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_DATA_BUILTIN_CONVERSION_TEST_DSET_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_DATA_BUILTIN_CONVERSION_TEST_DSET_NAME); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + if ((space_npoints = H5Sget_simple_extent_npoints(fspace_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataspace num points\n"); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + if (NULL == (read_buf = HDmalloc((hsize_t)space_npoints * + DATASET_DATA_BUILTIN_CONVERSION_TEST_MEM_DTYPESIZE))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + if (H5Dread(dset_id, DATASET_DATA_BUILTIN_CONVERSION_TEST_MEM_DTYPE, H5S_ALL, H5S_ALL, + H5P_DEFAULT, read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", + DATASET_DATA_BUILTIN_CONVERSION_TEST_DSET_NAME); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + if (memcmp(data, read_buf, data_size)) { + H5_FAILED(); + HDprintf(" hyperslab selection data verification failed\n"); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + if (data) { + HDfree(data); + data = NULL; + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + PASSED(); + } + PART_END(H5Dwrite_hyperslab_read); + + PART_BEGIN(H5Dwrite_point_sel_read) + { + TESTING_2("H5Dwrite using point selection then H5Dread"); + + data_size = DATASET_DATA_BUILTIN_CONVERSION_TEST_NUM_POINTS * + DATASET_DATA_BUILTIN_CONVERSION_TEST_MEM_DTYPESIZE; + + if (NULL == (write_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + PART_ERROR(H5Dwrite_point_sel_read); + } + + for (i = 0; i < data_size / DATASET_DATA_BUILTIN_CONVERSION_TEST_MEM_DTYPESIZE; i++) + ((int *)write_buf)[i] = 13; + + for (i = 0, data_size = 1; i < DATASET_DATA_BUILTIN_CONVERSION_TEST_DSET_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_DATA_BUILTIN_CONVERSION_TEST_MEM_DTYPESIZE; + + if (NULL == (data = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset data verification\n"); + PART_ERROR(H5Dwrite_point_sel_read); + } + + if (H5Dread(dset_id, DATASET_DATA_BUILTIN_CONVERSION_TEST_MEM_DTYPE, H5S_ALL, H5S_ALL, + H5P_DEFAULT, data) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", + DATASET_DATA_BUILTIN_CONVERSION_TEST_DSET_NAME); + PART_ERROR(H5Dwrite_point_sel_read); + } + + for (i = 0; i < dims[0]; i++) { + size_t j; + + for (j = 0; j < dims[1]; j++) { + size_t k; + + for (k = 0; k < dims[2]; k++) { + if (i == j && j == k) + ((int *)data)[(i * dims[1] * dims[2]) + (j * dims[2]) + k] = 13; + } + } + } + + /* Select a series of 10 points in the dataset */ + for (i = 0; i < DATASET_DATA_BUILTIN_CONVERSION_TEST_NUM_POINTS; i++) { + size_t j; + + for (j = 0; j < DATASET_DATA_BUILTIN_CONVERSION_TEST_DSET_SPACE_RANK; j++) + points[(i * DATASET_DATA_BUILTIN_CONVERSION_TEST_DSET_SPACE_RANK) + j] = i; + } + + if (H5Sselect_elements(fspace_id, H5S_SELECT_SET, DATASET_DATA_BUILTIN_CONVERSION_TEST_NUM_POINTS, + points) < 0) { + H5_FAILED(); + HDprintf(" couldn't select elements in dataspace\n"); + PART_ERROR(H5Dwrite_point_sel_read); + } + + { + hsize_t mdims[] = {(hsize_t)DATASET_DATA_BUILTIN_CONVERSION_TEST_NUM_POINTS}; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + PART_ERROR(H5Dwrite_point_sel_read); + } + } + + if (H5Dwrite(dset_id, DATASET_DATA_BUILTIN_CONVERSION_TEST_MEM_DTYPE, mspace_id, fspace_id, + H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", + DATASET_DATA_BUILTIN_CONVERSION_TEST_DSET_NAME); + PART_ERROR(H5Dwrite_point_sel_read); + } + + if (mspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(mspace_id); + } + H5E_END_TRY; + mspace_id = H5I_INVALID_HID; + } + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_DATA_BUILTIN_CONVERSION_TEST_DSET_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_DATA_BUILTIN_CONVERSION_TEST_DSET_NAME); + PART_ERROR(H5Dwrite_point_sel_read); + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + PART_ERROR(H5Dwrite_point_sel_read); + } + + if ((space_npoints = H5Sget_simple_extent_npoints(fspace_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataspace num points\n"); + PART_ERROR(H5Dwrite_point_sel_read); + } + + if (NULL == (read_buf = HDmalloc((hsize_t)space_npoints * + DATASET_DATA_BUILTIN_CONVERSION_TEST_MEM_DTYPESIZE))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + PART_ERROR(H5Dwrite_point_sel_read); + } + + if (H5Dread(dset_id, DATASET_DATA_BUILTIN_CONVERSION_TEST_MEM_DTYPE, H5S_ALL, H5S_ALL, + H5P_DEFAULT, read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", + DATASET_DATA_BUILTIN_CONVERSION_TEST_DSET_NAME); + PART_ERROR(H5Dwrite_point_sel_read); + } + + if (memcmp(data, read_buf, data_size)) { + H5_FAILED(); + HDprintf(" point selection data verification failed\n"); + PART_ERROR(H5Dwrite_point_sel_read); + } + + PASSED(); + } + PART_END(H5Dwrite_point_sel_read); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (data) { + HDfree(data); + data = NULL; + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (data) + HDfree(data); + if (write_buf) + HDfree(write_buf); + if (read_buf) + HDfree(read_buf); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to ensure that data is read back correctly from a dataset after it has + * been written, using partial element I/O with compound types + */ +typedef struct dataset_compount_partial_io_t { + int a; + int b; +} dataset_compount_partial_io_t; + +static int +test_dataset_compound_partial_io(void) +{ + hsize_t dims[1] = {DATASET_COMPOUND_PARTIAL_IO_DSET_DIMS}; + size_t i; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + hid_t full_type_id = H5I_INVALID_HID; + hid_t a_type_id = H5I_INVALID_HID; + hid_t b_type_id = H5I_INVALID_HID; + dataset_compount_partial_io_t wbuf[DATASET_COMPOUND_PARTIAL_IO_DSET_DIMS]; + dataset_compount_partial_io_t rbuf[DATASET_COMPOUND_PARTIAL_IO_DSET_DIMS]; + dataset_compount_partial_io_t fbuf[DATASET_COMPOUND_PARTIAL_IO_DSET_DIMS]; + dataset_compount_partial_io_t erbuf[DATASET_COMPOUND_PARTIAL_IO_DSET_DIMS]; + + TESTING_MULTIPART( + "verification of dataset data using H5Dwrite then H5Dread with partial element compound type I/O"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_DATA_COMPOUND_PARTIAL_IO_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_DATA_COMPOUND_PARTIAL_IO_TEST_GROUP_NAME); + goto error; + } + + if ((space_id = H5Screate_simple(1, dims, NULL)) < 0) + TEST_ERROR; + + if ((full_type_id = H5Tcreate(H5T_COMPOUND, sizeof(dataset_compount_partial_io_t))) < 0) + TEST_ERROR; + if (H5Tinsert(full_type_id, "a", HOFFSET(dataset_compount_partial_io_t, a), H5T_NATIVE_INT) < 0) + TEST_ERROR; + if (H5Tinsert(full_type_id, "b", HOFFSET(dataset_compount_partial_io_t, b), H5T_NATIVE_INT) < 0) + TEST_ERROR; + + if ((a_type_id = H5Tcreate(H5T_COMPOUND, sizeof(dataset_compount_partial_io_t))) < 0) + TEST_ERROR; + if (H5Tinsert(a_type_id, "a", HOFFSET(dataset_compount_partial_io_t, a), H5T_NATIVE_INT) < 0) + TEST_ERROR; + + if ((b_type_id = H5Tcreate(H5T_COMPOUND, sizeof(dataset_compount_partial_io_t))) < 0) + TEST_ERROR; + if (H5Tinsert(b_type_id, "b", HOFFSET(dataset_compount_partial_io_t, b), H5T_NATIVE_INT) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_DATA_COMPOUND_PARTIAL_IO_TEST_DSET_NAME, full_type_id, + space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_DATA_COMPOUND_PARTIAL_IO_TEST_DSET_NAME); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(write_full_read_full) + { + TESTING_2("H5Dwrite then H5Dread with all compound members"); + + /* Initialize wbuf */ + for (i = 0; i < DATASET_COMPOUND_PARTIAL_IO_DSET_DIMS; i++) { + wbuf[i].a = (int)(2 * i); + wbuf[i].b = (int)(2 * i + 1); + } + + /* Write data */ + if (H5Dwrite(dset_id, full_type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf) < 0) + PART_TEST_ERROR(write_full_read_full); + + /* Update fbuf to match file state */ + for (i = 0; i < DATASET_COMPOUND_PARTIAL_IO_DSET_DIMS; i++) { + fbuf[i].a = wbuf[i].a; + fbuf[i].b = wbuf[i].b; + } + + /* Initialize rbuf to -1 */ + for (i = 0; i < DATASET_COMPOUND_PARTIAL_IO_DSET_DIMS; i++) { + rbuf[i].a = -1; + rbuf[i].b = -1; + } + + /* Set erbuf (simply match file state since we're reading the whole + * thing) */ + for (i = 0; i < DATASET_COMPOUND_PARTIAL_IO_DSET_DIMS; i++) { + erbuf[i].a = fbuf[i].a; + erbuf[i].b = fbuf[i].b; + } + + /* Read data */ + if (H5Dread(dset_id, full_type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf) < 0) + PART_TEST_ERROR(write_full_read_full); + + /* Verify data */ + for (i = 0; i < DATASET_COMPOUND_PARTIAL_IO_DSET_DIMS; i++) { + if (rbuf[i].a != erbuf[i].a) + PART_TEST_ERROR(write_full_read_full); + if (rbuf[i].b != erbuf[i].b) + PART_TEST_ERROR(write_full_read_full); + } + + PASSED(); + } + PART_END(write_full_read_full); + + PART_BEGIN(read_a) + { + TESTING_2("H5Dread with compound member a"); + + /* Initialize rbuf to -1 */ + for (i = 0; i < DATASET_COMPOUND_PARTIAL_IO_DSET_DIMS; i++) { + rbuf[i].a = -1; + rbuf[i].b = -1; + } + + /* Set erbuf (element a comes from the file, element b in untouched) + */ + for (i = 0; i < DATASET_COMPOUND_PARTIAL_IO_DSET_DIMS; i++) { + erbuf[i].a = fbuf[i].a; + erbuf[i].b = rbuf[i].b; + } + + /* Read data */ + if (H5Dread(dset_id, a_type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf) < 0) + PART_TEST_ERROR(read_a); + + /* Verify data */ + for (i = 0; i < DATASET_COMPOUND_PARTIAL_IO_DSET_DIMS; i++) { + if (rbuf[i].a != erbuf[i].a) + PART_TEST_ERROR(read_a); + if (rbuf[i].b != erbuf[i].b) + PART_TEST_ERROR(read_a); + } + + PASSED(); + } + PART_END(read_a); + + PART_BEGIN(write_b_read_full) + { + TESTING_2("H5Dwrite with compound member b then H5Dread with all compound members"); + + /* Initialize wbuf */ + for (i = 0; i < DATASET_COMPOUND_PARTIAL_IO_DSET_DIMS; i++) { + wbuf[i].a = (int)(2 * DATASET_COMPOUND_PARTIAL_IO_DSET_DIMS + 2 * i); + wbuf[i].b = (int)(2 * DATASET_COMPOUND_PARTIAL_IO_DSET_DIMS + 2 * i + 1); + } + + /* Write data */ + if (H5Dwrite(dset_id, b_type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf) < 0) + PART_TEST_ERROR(write_full_read_full); + + /* Update fbuf to match file state - only element b was updated */ + for (i = 0; i < DATASET_COMPOUND_PARTIAL_IO_DSET_DIMS; i++) { + fbuf[i].b = wbuf[i].b; + } + + /* Initialize rbuf to -1 */ + for (i = 0; i < DATASET_COMPOUND_PARTIAL_IO_DSET_DIMS; i++) { + rbuf[i].a = -1; + rbuf[i].b = -1; + } + + /* Set erbuf (simply match file state since we're reading the whole + * thing) */ + for (i = 0; i < DATASET_COMPOUND_PARTIAL_IO_DSET_DIMS; i++) { + erbuf[i].a = fbuf[i].a; + erbuf[i].b = fbuf[i].b; + } + + /* Read data */ + if (H5Dread(dset_id, full_type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf) < 0) + PART_TEST_ERROR(write_b_read_full); + + /* Verify data */ + for (i = 0; i < DATASET_COMPOUND_PARTIAL_IO_DSET_DIMS; i++) { + if (rbuf[i].a != erbuf[i].a) + PART_TEST_ERROR(write_b_read_full); + if (rbuf[i].b != erbuf[i].b) + PART_TEST_ERROR(write_b_read_full); + } + + PASSED(); + } + PART_END(write_b_read_full); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + if (H5Tclose(full_type_id) < 0) + TEST_ERROR; + if (H5Tclose(a_type_id) < 0) + TEST_ERROR; + if (H5Tclose(b_type_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(space_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + H5Tclose(full_type_id); + H5Tclose(a_type_id); + H5Tclose(b_type_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a chunked dataset's extent can be + * changed by using H5Dset_extent. This test uses unlimited + * dimensions for the dataset, so the dimensionality of the + * dataset may both shrink and grow. + */ +static int +test_dataset_set_extent_chunked_unlimited(void) +{ + hsize_t dims[DATASET_SET_EXTENT_CHUNKED_UNLIMITED_TEST_SPACE_RANK]; + hsize_t max_dims[DATASET_SET_EXTENT_CHUNKED_UNLIMITED_TEST_SPACE_RANK]; + hsize_t chunk_dims[DATASET_SET_EXTENT_CHUNKED_UNLIMITED_TEST_SPACE_RANK]; + hsize_t new_dims[DATASET_SET_EXTENT_CHUNKED_UNLIMITED_TEST_SPACE_RANK]; + size_t i; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t dcpl_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + + TESTING("H5Dset_extent on chunked dataset with unlimited dimensions"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, basic or more dataset aren't supported with this " + "connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_SET_EXTENT_CHUNKED_UNLIMITED_TEST_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_SET_EXTENT_CHUNKED_UNLIMITED_TEST_GROUP_NAME); + goto error; + } + + for (i = 0; i < DATASET_SET_EXTENT_CHUNKED_UNLIMITED_TEST_SPACE_RANK; i++) { + max_dims[i] = H5S_UNLIMITED; + chunk_dims[i] = (hsize_t)(rand() % MAX_DIM_SIZE + 1); + } + + if ((fspace_id = generate_random_dataspace(DATASET_SET_EXTENT_CHUNKED_UNLIMITED_TEST_SPACE_RANK, max_dims, + dims, FALSE)) < 0) + TEST_ERROR; + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + if ((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) + TEST_ERROR; + + if (H5Pset_chunk(dcpl_id, DATASET_SET_EXTENT_CHUNKED_UNLIMITED_TEST_SPACE_RANK, chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" unable to set dataset chunk dimensionality\n"); + goto error; + } + + if ((dset_id = H5Dcreate2(group_id, DATASET_SET_EXTENT_CHUNKED_UNLIMITED_TEST_DSET_NAME, dset_dtype, + fspace_id, H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_SET_EXTENT_CHUNKED_UNLIMITED_TEST_DSET_NAME); + goto error; + } + + for (i = 0; i < DATASET_SET_EXTENT_CHUNKED_UNLIMITED_TEST_NUM_PASSES; i++) { + size_t j; + + for (j = 0; j < DATASET_SET_EXTENT_CHUNKED_UNLIMITED_TEST_SPACE_RANK; j++) { + /* Ensure that the new dimensionality doesn't match the old dimensionality. */ + do { + new_dims[j] = (hsize_t)(rand() % MAX_DIM_SIZE + 1); + } while (new_dims[j] == dims[j]); + } + + if (H5Dset_extent(dset_id, new_dims) < 0) { + H5_FAILED(); + HDprintf(" failed to set dataset extent\n"); + goto error; + } + + /* Retrieve the new dimensions of the dataset and ensure they + * are different from the original. + */ + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve dataset's dataspace\n"); + goto error; + } + + if (H5Sget_simple_extent_dims(fspace_id, new_dims, NULL) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve dataset dimensionality\n"); + goto error; + } + + /* + * Make sure the dimensions have been changed. + */ + for (j = 0; j < DATASET_SET_EXTENT_CHUNKED_UNLIMITED_TEST_SPACE_RANK; j++) { + if (dims[j] == new_dims[j]) { + H5_FAILED(); + HDprintf(" dataset dimension %llu wasn't changed!\n", (unsigned long long)j); + goto error; + } + } + + /* + * Remember the current dimensionality of the dataset before + * changing them again. + */ + HDmemcpy(dims, new_dims, sizeof(new_dims)); + } + + /* + * Now close and re-open the dataset each pass to check the persistence + * of the changes to the dataset's dimensionality. + */ + for (i = 0; i < DATASET_SET_EXTENT_CHUNKED_UNLIMITED_TEST_NUM_PASSES; i++) { + size_t j; + + for (j = 0; j < DATASET_SET_EXTENT_CHUNKED_UNLIMITED_TEST_SPACE_RANK; j++) { + /* Ensure that the new dimensionality doesn't match the old dimensionality. */ + do { + new_dims[j] = (hsize_t)(rand() % MAX_DIM_SIZE + 1); + } while (new_dims[j] == dims[j]); + } + + if (H5Dset_extent(dset_id, new_dims) < 0) { + H5_FAILED(); + HDprintf(" failed to set dataset extent\n"); + goto error; + } + + /* Retrieve the new dimensions of the dataset and ensure they + * are different from the original. + */ + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + + if ((dset_id = H5Dopen2(group_id, DATASET_SET_EXTENT_CHUNKED_UNLIMITED_TEST_DSET_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" failed to open dataset '%s'\n", + DATASET_SET_EXTENT_CHUNKED_UNLIMITED_TEST_DSET_NAME); + goto error; + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve dataset's dataspace\n"); + goto error; + } + + if (H5Sget_simple_extent_dims(fspace_id, new_dims, NULL) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve dataset dimensionality\n"); + goto error; + } + + /* + * Make sure the dimensions have been changed. + */ + for (j = 0; j < DATASET_SET_EXTENT_CHUNKED_UNLIMITED_TEST_SPACE_RANK; j++) { + if (dims[j] == new_dims[j]) { + H5_FAILED(); + HDprintf(" dataset dimension %llu wasn't changed!\n", (unsigned long long)j); + goto error; + } + } + + /* + * Remember the current dimensionality of the dataset before + * changing them again. + */ + HDmemcpy(dims, new_dims, sizeof(new_dims)); + } + + if (H5Pclose(dcpl_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(dcpl_id); + H5Sclose(fspace_id); + H5Tclose(dset_dtype); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a chunked dataset's extent can be + * changed by using H5Dset_extent. This test uses fixed-size + * dimensions for the dataset, so the dimensionality of the + * dataset may only shrink. + */ +static int +test_dataset_set_extent_chunked_fixed(void) +{ + hsize_t dims[DATASET_SET_EXTENT_CHUNKED_FIXED_TEST_SPACE_RANK]; + hsize_t dims2[DATASET_SET_EXTENT_CHUNKED_FIXED_TEST_SPACE_RANK]; + hsize_t chunk_dims[DATASET_SET_EXTENT_CHUNKED_FIXED_TEST_SPACE_RANK]; + hsize_t new_dims[DATASET_SET_EXTENT_CHUNKED_FIXED_TEST_SPACE_RANK]; + size_t i; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID, dset_id2 = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t dcpl_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID, fspace_id2 = H5I_INVALID_HID; + + TESTING("H5Dset_extent on chunked dataset with fixed dimensions"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, basic or more dataset aren't supported with this " + "connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_SET_EXTENT_CHUNKED_FIXED_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_SET_EXTENT_CHUNKED_FIXED_TEST_GROUP_NAME); + goto error; + } + + for (i = 0; i < DATASET_SET_EXTENT_CHUNKED_FIXED_TEST_SPACE_RANK; i++) { + dims[i] = (hsize_t)(rand() % MAX_DIM_SIZE + 1); + dims2[i] = dims[i]; + do { + chunk_dims[i] = (hsize_t)(rand() % MAX_DIM_SIZE + 1); + } while (chunk_dims[i] > dims[i]); + } + + if ((fspace_id = H5Screate_simple(DATASET_SET_EXTENT_CHUNKED_FIXED_TEST_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + if ((fspace_id2 = H5Screate_simple(DATASET_SET_EXTENT_CHUNKED_FIXED_TEST_SPACE_RANK, dims2, NULL)) < 0) + TEST_ERROR; + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + if ((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) + TEST_ERROR; + + if (H5Pset_chunk(dcpl_id, DATASET_SET_EXTENT_CHUNKED_FIXED_TEST_SPACE_RANK, chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" unable to set dataset chunk dimensionality\n"); + goto error; + } + + /* + * NOTE: Since shrinking the dimension size can quickly end in a situation + * where the dimensions are of size 1 and we can't shrink them further, we + * use two datasets here to ensure the second test can run at least once. + */ + if ((dset_id = H5Dcreate2(group_id, DATASET_SET_EXTENT_CHUNKED_FIXED_TEST_DSET_NAME, dset_dtype, + fspace_id, H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_SET_EXTENT_CHUNKED_FIXED_TEST_DSET_NAME); + goto error; + } + + if ((dset_id2 = H5Dcreate2(group_id, DATASET_SET_EXTENT_CHUNKED_FIXED_TEST_DSET_NAME2, dset_dtype, + fspace_id2, H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_SET_EXTENT_CHUNKED_FIXED_TEST_DSET_NAME2); + goto error; + } + + for (i = 0; i < DATASET_SET_EXTENT_CHUNKED_FIXED_TEST_NUM_PASSES; i++) { + hbool_t skip_iterations = FALSE; + size_t j; + + for (j = 0; j < DATASET_SET_EXTENT_CHUNKED_FIXED_TEST_SPACE_RANK; j++) { + /* Ensure that the new dimensionality is less than the old dimensionality. */ + do { + if (dims[j] == 1) { + skip_iterations = TRUE; + break; + } + else + new_dims[j] = (hsize_t)(rand() % MAX_DIM_SIZE + 1); + } while (new_dims[j] >= dims[j]); + } + + /* + * If we've shrunk one of the dimensions to size 1, skip the rest of + * the iterations. + */ + if (skip_iterations) + break; + + if (H5Dset_extent(dset_id, new_dims) < 0) { + H5_FAILED(); + HDprintf(" failed to set dataset extent\n"); + goto error; + } + + /* Retrieve the new dimensions of the dataset and ensure they + * are different from the original. + */ + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve dataset's dataspace\n"); + goto error; + } + + if (H5Sget_simple_extent_dims(fspace_id, new_dims, NULL) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve dataset dimensionality\n"); + goto error; + } + + /* + * Make sure the dimensions have been changed. + */ + for (j = 0; j < DATASET_SET_EXTENT_CHUNKED_FIXED_TEST_SPACE_RANK; j++) { + if (dims[j] == new_dims[j]) { + H5_FAILED(); + HDprintf(" dataset dimension %llu wasn't changed!\n", (unsigned long long)j); + goto error; + } + } + + /* + * Remember the current dimensionality of the dataset before + * changing them again. + */ + HDmemcpy(dims, new_dims, sizeof(new_dims)); + } + + /* + * Now close and re-open the dataset each pass to check the persistence + * of the changes to the dataset's dimensionality. + */ + for (i = 0; i < DATASET_SET_EXTENT_CHUNKED_FIXED_TEST_NUM_PASSES; i++) { + hbool_t skip_iterations = FALSE; + size_t j; + + for (j = 0; j < DATASET_SET_EXTENT_CHUNKED_FIXED_TEST_SPACE_RANK; j++) { + /* Ensure that the new dimensionality is less than the old dimensionality. */ + do { + if (dims2[j] == 1) { + skip_iterations = TRUE; + break; + } + else + new_dims[j] = (hsize_t)(rand() % MAX_DIM_SIZE + 1); + } while (new_dims[j] >= dims2[j]); + } + + /* + * If we've shrunk one of the dimensions to size 1, skip the rest of + * the iterations. + */ + if (skip_iterations) + break; + + if (H5Dset_extent(dset_id2, new_dims) < 0) { + H5_FAILED(); + HDprintf(" failed to set dataset extent2\n"); + goto error; + } + + /* Retrieve the new dimensions of the dataset and ensure they + * are different from the original. + */ + if (H5Sclose(fspace_id2) < 0) + TEST_ERROR; + if (H5Dclose(dset_id2) < 0) + TEST_ERROR; + + if ((dset_id2 = H5Dopen2(group_id, DATASET_SET_EXTENT_CHUNKED_FIXED_TEST_DSET_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" failed to open dataset '%s'\n", DATASET_SET_EXTENT_CHUNKED_FIXED_TEST_DSET_NAME2); + goto error; + } + + if ((fspace_id2 = H5Dget_space(dset_id2)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve dataset's dataspace\n"); + goto error; + } + + if (H5Sget_simple_extent_dims(fspace_id2, new_dims, NULL) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve dataset dimensionality\n"); + goto error; + } + + /* + * Make sure the dimensions have been changed. + */ + for (j = 0; j < DATASET_SET_EXTENT_CHUNKED_FIXED_TEST_SPACE_RANK; j++) { + if (dims2[j] == new_dims[j]) { + H5_FAILED(); + HDprintf(" dataset dimension %llu wasn't changed!\n", (unsigned long long)j); + goto error; + } + } + + /* + * Remember the current dimensionality of the dataset before + * changing them again. + */ + HDmemcpy(dims2, new_dims, sizeof(new_dims)); + } + + if (H5Pclose(dcpl_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id2) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id2) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(dcpl_id); + H5Sclose(fspace_id); + H5Sclose(fspace_id2); + H5Tclose(dset_dtype); + H5Dclose(dset_id); + H5Dclose(dset_id2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check the data is correct after expanding + * and shrinking the dataset with H5Dset_extent + */ +static int +test_dataset_set_extent_data(void) +{ + hsize_t dims_origin[DATASET_SET_EXTENT_DATA_TEST_SPACE_RANK] = {DATASET_SET_EXTENT_DATA_TEST_SPACE_DIM, + DATASET_SET_EXTENT_DATA_TEST_SPACE_DIM}; + hsize_t dims_expand[DATASET_SET_EXTENT_DATA_TEST_SPACE_RANK] = { + DATASET_SET_EXTENT_DATA_TEST_SPACE_DIM * 2 - 1, DATASET_SET_EXTENT_DATA_TEST_SPACE_DIM * 2 - 1}; + hsize_t dims_shrink[DATASET_SET_EXTENT_DATA_TEST_SPACE_RANK] = { + DATASET_SET_EXTENT_DATA_TEST_SPACE_DIM / 2 + 1, DATASET_SET_EXTENT_DATA_TEST_SPACE_DIM / 2 + 1}; + hsize_t dims_chunk[DATASET_SET_EXTENT_DATA_TEST_SPACE_RANK] = {DATASET_SET_EXTENT_DATA_TEST_SPACE_DIM, + DATASET_SET_EXTENT_DATA_TEST_SPACE_DIM}; + hsize_t dims_max[DATASET_SET_EXTENT_DATA_TEST_SPACE_RANK] = {H5S_UNLIMITED, H5S_UNLIMITED}; + hsize_t dims_out[DATASET_SET_EXTENT_DATA_TEST_SPACE_RANK]; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dcpl_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID, dset_space_id = H5I_INVALID_HID; + int buf_origin[DATASET_SET_EXTENT_DATA_TEST_SPACE_DIM][DATASET_SET_EXTENT_DATA_TEST_SPACE_DIM]; +#ifndef NO_CLEAR_ON_SHRINK + int buf_expand2[DATASET_SET_EXTENT_DATA_TEST_SPACE_DIM][DATASET_SET_EXTENT_DATA_TEST_SPACE_DIM]; +#endif + int buf_expand[DATASET_SET_EXTENT_DATA_TEST_SPACE_DIM * 2 - 1] + [DATASET_SET_EXTENT_DATA_TEST_SPACE_DIM * 2 - 1]; + int buf_shrink[DATASET_SET_EXTENT_DATA_TEST_SPACE_DIM / 2 + 1] + [DATASET_SET_EXTENT_DATA_TEST_SPACE_DIM / 2 + 1]; + int i, j; + + TESTING_MULTIPART("H5Dset_extent on data correctness"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, basic or more dataset aren't supported with this " + "connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_SET_EXTENT_DATA_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", DATASET_SET_EXTENT_DATA_TEST_GROUP_NAME); + goto error; + } + + if ((fspace_id = H5Screate_simple(DATASET_SET_EXTENT_DATA_TEST_SPACE_RANK, dims_origin, dims_max)) < 0) + TEST_ERROR; + + if ((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) + TEST_ERROR; + + if (H5Pset_chunk(dcpl_id, DATASET_SET_EXTENT_DATA_TEST_SPACE_RANK, dims_chunk) < 0) { + H5_FAILED(); + HDprintf(" unable to set dataset chunk dimensionality\n"); + goto error; + } + + if ((dset_id = H5Dcreate2(group_id, DATASET_SET_EXTENT_DATA_TEST_DSET_NAME, H5T_NATIVE_INT, fspace_id, + H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_SET_EXTENT_DATA_TEST_DSET_NAME); + goto error; + } + + for (i = 0; i < DATASET_SET_EXTENT_DATA_TEST_SPACE_DIM; i++) + for (j = 0; j < DATASET_SET_EXTENT_DATA_TEST_SPACE_DIM; j++) + buf_origin[i][j] = i + j; + + /* Write the original data + * X X X X X X X X + * X X X X X X X X + * X X X X X X X X + * X X X X X X X X + * X X X X X X X X + * X X X X X X X X + * X X X X X X X X + * X X X X X X X X + */ + if (H5Dwrite(dset_id, H5T_NATIVE_INT, fspace_id, H5S_ALL, H5P_DEFAULT, buf_origin) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Dset_extent_data_expand) + { + TESTING_2("H5Dset_extent for data expansion"); + + /* Expand the dataset. The extended space should be initialized with the + * the default value (0) + * X X X X X X X X 0 0 0 0 0 0 0 + * X X X X X X X X 0 0 0 0 0 0 0 + * X X X X X X X X 0 0 0 0 0 0 0 + * X X X X X X X X 0 0 0 0 0 0 0 + * X X X X X X X X 0 0 0 0 0 0 0 + * X X X X X X X X 0 0 0 0 0 0 0 + * X X X X X X X X 0 0 0 0 0 0 0 + * X X X X X X X X 0 0 0 0 0 0 0 + * 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + * 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + * 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + * 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + * 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + * 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + * 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + */ + if (H5Dset_extent(dset_id, dims_expand) < 0) + PART_ERROR(H5Dset_extent_data_expand); + + if (H5Dread(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf_expand) < 0) + PART_ERROR(H5Dset_extent_data_expand); + + /* compare the expanded data */ + for (i = 0; i < (int)dims_expand[0]; i++) { + for (j = 0; j < (int)dims_expand[1]; j++) { + if (i >= (int)dims_origin[0] || j >= (int)dims_origin[1]) { + if (buf_expand[i][j] != 0) { + H5_FAILED(); + HDprintf(" buf_expand[%d][%d] = %d. It should be 0\n", i, j, buf_expand[i][j]); + PART_ERROR(H5Dset_extent_data_expand); + } + } + else { + if (buf_expand[i][j] != buf_origin[i][j]) { + H5_FAILED(); + HDprintf(" buf_expand[%d][%d] = %d. It should be %d\n", i, j, buf_expand[i][j], + buf_origin[i][j]); + PART_ERROR(H5Dset_extent_data_expand); + } + } + } + } + + PASSED(); + } + PART_END(H5Dset_extent_data_expand); + + PART_BEGIN(H5Dset_extent_data_shrink) + { + TESTING_2("H5Dset_extent for data shrinking"); + + /* Shrink the dataset. + * X X X X X + * X X X X X + * X X X X X + * X X X X X + * X X X X X + */ + if (H5Dset_extent(dset_id, dims_shrink) < 0) + PART_ERROR(H5Dset_extent_data_shrink); + + if (H5Dread(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf_shrink) < 0) + PART_ERROR(H5Dset_extent_data_shrink); + + /* compare the shrunk data */ + for (i = 0; i < (int)dims_shrink[0]; i++) { + for (j = 0; j < (int)dims_shrink[1]; j++) { + if (buf_shrink[i][j] != buf_origin[i][j]) { + H5_FAILED(); + HDprintf(" buf_shrink[%d][%d] = %d. It should be %d\n", i, j, buf_shrink[i][j], + buf_origin[i][j]); + PART_ERROR(H5Dset_extent_data_shrink); + } + } + } + + PASSED(); + } + PART_END(H5Dset_extent_data_shrink); + + PART_BEGIN(H5Dset_extent_data_expand_to_origin) + { + TESTING_2("H5Dset_extent for data back to the original size"); +#ifndef NO_CLEAR_ON_SHRINK + /* Expand the dataset back to the original size. The data should look like this: + * X X X X X 0 0 0 + * X X X X X 0 0 0 + * X X X X X 0 0 0 + * X X X X X 0 0 0 + * X X X X X 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 + */ + if (H5Dset_extent(dset_id, dims_origin) < 0) + PART_ERROR(H5Dset_extent_data_expand_to_origin); + + if (H5Dread(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf_expand2) < 0) + PART_ERROR(H5Dset_extent_data_expand_to_origin); + + /* compare the expanded data */ + for (i = 0; i < (int)dims_origin[0]; i++) { + for (j = 0; j < (int)dims_origin[1]; j++) { + if (i >= (int)dims_shrink[0] || j >= (int)dims_shrink[1]) { + if (buf_expand2[i][j] != 0) { + H5_FAILED(); + HDprintf(" buf_expand2[%d][%d] = %d. It should be 0\n", i, j, + buf_expand2[i][j]); + PART_ERROR(H5Dset_extent_data_expand_to_origin); + } + } + else { + if (buf_expand2[i][j] != buf_origin[i][j]) { + H5_FAILED(); + HDprintf(" buf_expand2[%d][%d] = %d. It should be %d.\n", i, j, + buf_expand2[i][j], buf_origin[i][j]); + PART_ERROR(H5Dset_extent_data_expand_to_origin); + } + } + } + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Dset_extent_data_expand_to_origin); +#endif + } + PART_END(H5Dset_extent_data_expand_to_origin); + + PART_BEGIN(H5Dset_extent_data_shrink_to_zero) + { + TESTING_2("H5Dset_extent for data shrink to zero size"); + + /* Shrink the dimensions to 0 and verify it */ + dims_shrink[0] = dims_shrink[1] = 0; + + if (H5Dset_extent(dset_id, dims_shrink) < 0) + PART_ERROR(H5Dset_extent_data_shrink_to_zero); + + /* get the space */ + if ((dset_space_id = H5Dget_space(dset_id)) < 0) + PART_ERROR(H5Dset_extent_data_shrink_to_zero); + + /* get dimensions */ + if (H5Sget_simple_extent_dims(dset_space_id, dims_out, NULL) < 0) + PART_ERROR(H5Dset_extent_data_shrink_to_zero); + + if (H5Sclose(dset_space_id) < 0) + PART_ERROR(H5Dset_extent_data_shrink_to_zero); + + /* Verify the dimensions are 0 */ + for (i = 0; i < DATASET_SET_EXTENT_DATA_TEST_SPACE_RANK; i++) + if (dims_out[i] != 0) { + H5_FAILED(); + HDprintf(" dims_out[%d] = %llu. It should be 0.\n", i, + (long long unsigned int)dims_out[i]); + PART_ERROR(H5Dset_extent_data_shrink_to_zero); + } + + PASSED(); + } + PART_END(H5Dset_extent_data_shrink_to_zero); + + PART_BEGIN(H5Dset_extent_data_expand_to_origin_again) + { + TESTING_2("H5Dset_extent for data expansion back to the original again"); +#ifndef NO_CLEAR_ON_SHRINK + /* Expand the dataset back to the original size. The data should look like this: + * 0 0 0 0 0 0 0 0 + * 0 0 0 0 0 0 0 0 + * 0 0 0 0 0 0 0 0 + * 0 0 0 0 0 0 0 0 + * 0 0 0 0 0 0 0 0 + * 0 0 0 0 0 0 0 0 + * 0 0 0 0 0 0 0 0 + * 0 0 0 0 0 0 0 0 + */ + if (H5Dset_extent(dset_id, dims_origin) < 0) + PART_ERROR(H5Dset_extent_data_expand_to_origin_again); + + if (H5Dread(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf_expand2) < 0) + PART_ERROR(H5Dset_extent_data_expand_to_origin_again); + + /* The data should be all zeros */ + for (i = 0; i < (int)dims_origin[0]; i++) { + for (j = 0; j < (int)dims_origin[1]; j++) { + if (buf_expand2[i][j] != 0) { + H5_FAILED(); + HDprintf(" buf_expand2[%d][%d] = %d. It should be 0.\n", i, j, buf_expand2[i][j]); + PART_ERROR(H5Dset_extent_data_expand_to_origin_again); + } + } + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Dset_extent_data_expand_to_origin_again); +#endif + } + PART_END(H5Dset_extent_data_expand_to_origin_again); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Pclose(dcpl_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(dcpl_id); + H5Sclose(fspace_id); + H5Sclose(dset_space_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} /* test_dataset_set_extent_data */ + +/* + * If a dataset is opened twice and one of the handles is + * used to extend the dataset, then the other handle should + * return the new size when queried. + */ +static int +test_dataset_set_extent_double_handles(void) +{ +#ifndef NO_DOUBLE_OBJECT_OPENS + hsize_t dims_origin[DATASET_SET_EXTENT_DOUBLE_HANDLES_TEST_SPACE_RANK] = { + DATASET_SET_EXTENT_DOUBLE_HANDLES_TEST_SPACE_DIM, DATASET_SET_EXTENT_DOUBLE_HANDLES_TEST_SPACE_DIM}; + hsize_t dims_expand[DATASET_SET_EXTENT_DOUBLE_HANDLES_TEST_SPACE_RANK] = { + DATASET_SET_EXTENT_DOUBLE_HANDLES_TEST_SPACE_DIM * 2, + DATASET_SET_EXTENT_DOUBLE_HANDLES_TEST_SPACE_DIM * 2}; + hsize_t dims_chunk[DATASET_SET_EXTENT_DOUBLE_HANDLES_TEST_SPACE_RANK] = { + DATASET_SET_EXTENT_DOUBLE_HANDLES_TEST_SPACE_DIM / 2, + DATASET_SET_EXTENT_DOUBLE_HANDLES_TEST_SPACE_DIM / 2}; + hsize_t dims_max[DATASET_SET_EXTENT_DOUBLE_HANDLES_TEST_SPACE_RANK] = {H5S_UNLIMITED, H5S_UNLIMITED}; + hsize_t dims_out[DATASET_SET_EXTENT_DOUBLE_HANDLES_TEST_SPACE_RANK]; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID, dset_id2 = H5I_INVALID_HID; + hid_t dcpl_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID, dset_space_id = H5I_INVALID_HID; + int i; +#endif + + TESTING("H5Dset_extent on double dataset handles"); + +#ifndef NO_DOUBLE_OBJECT_OPENS + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, basic or more dataset aren't supported with this " + "connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_SET_EXTENT_DOUBLE_HANDLES_TEST_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", DATASET_SET_EXTENT_DATA_TEST_GROUP_NAME); + goto error; + } + + if ((fspace_id = + H5Screate_simple(DATASET_SET_EXTENT_DOUBLE_HANDLES_TEST_SPACE_RANK, dims_origin, dims_max)) < 0) + TEST_ERROR; + + if ((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) + TEST_ERROR; + + if (H5Pset_chunk(dcpl_id, DATASET_SET_EXTENT_DOUBLE_HANDLES_TEST_SPACE_RANK, dims_chunk) < 0) { + H5_FAILED(); + HDprintf(" unable to set dataset chunk dimensionality\n"); + goto error; + } + + /* Create the dataset */ + if ((dset_id = H5Dcreate2(group_id, DATASET_SET_EXTENT_DOUBLE_HANDLES_TEST_DSET_NAME, H5T_NATIVE_INT, + fspace_id, H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_SET_EXTENT_DOUBLE_HANDLES_TEST_DSET_NAME); + goto error; + } + + /* Open the same dataset again */ + if ((dset_id2 = H5Dopen2(group_id, DATASET_SET_EXTENT_DOUBLE_HANDLES_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_SET_EXTENT_DOUBLE_HANDLES_TEST_DSET_NAME); + goto error; + } + + /* Expand the dataset's dimensions with the first dataset handle */ + if (H5Dset_extent(dset_id, dims_expand) < 0) + TEST_ERROR; + + /* Get the data space with the second dataset handle */ + if ((dset_space_id = H5Dget_space(dset_id2)) < 0) + TEST_ERROR; + + /* Get the dimensions with the second dataset handle */ + if (H5Sget_simple_extent_dims(dset_space_id, dims_out, NULL) < 0) + TEST_ERROR; + + if (H5Sclose(dset_space_id) < 0) + TEST_ERROR; + + for (i = 0; i < DATASET_SET_EXTENT_DOUBLE_HANDLES_TEST_SPACE_RANK; i++) + if (dims_out[i] != dims_expand[i]) { + H5_FAILED(); + HDprintf(" dims_out[%d] = %d. It should be %d.\n", i, dims_out[i], dims_expand[i]); + goto error; + } + + if (H5Pclose(dcpl_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id2) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(dcpl_id); + H5Sclose(fspace_id); + H5Sclose(dset_space_id); + H5Dclose(dset_id); + H5Dclose(dset_id2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +#else + SKIPPED(); + return 0; +#endif +} /* test_dataset_set_extent_double_handles */ + +/* + * A test to check that a dataset's extent can't be + * changed when H5Dset_extent is passed invalid parameters. + */ +static int +test_dataset_set_extent_invalid_params(void) +{ + hsize_t dims[DATASET_SET_EXTENT_INVALID_PARAMS_TEST_SPACE_RANK]; + hsize_t chunk_dims[DATASET_SET_EXTENT_INVALID_PARAMS_TEST_SPACE_RANK]; + hsize_t new_dims[DATASET_SET_EXTENT_INVALID_PARAMS_TEST_SPACE_RANK]; + hsize_t compact_dims[DATASET_SET_EXTENT_INVALID_PARAMS_TEST_SPACE_RANK] = {3, 3}; + size_t i; + herr_t err_ret = -1; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t chunked_dset_id = H5I_INVALID_HID, compact_dset_id = H5I_INVALID_HID, + contiguous_dset_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t chunked_dcpl_id = H5I_INVALID_HID, compact_dcpl_id = H5I_INVALID_HID, + contiguous_dcpl_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID, compact_fspace_id = H5I_INVALID_HID; + char vol_name[5]; + + TESTING_MULTIPART("H5Dset_extent with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, basic or more dataset aren't supported with this " + "connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + /** for DAOS VOL, this test is problematic since auto chunking can be selected, so skip for now */ + if (H5VLget_connector_name(file_id, vol_name, 5) < 0) { + H5_FAILED(); + HDprintf(" couldn't get VOL connector name\n"); + goto error; + } + if (strcmp(vol_name, "daos") == 0) { + if (H5Fclose(file_id) < 0) + TEST_ERROR; + SKIPPED(); + return 0; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_SET_EXTENT_INVALID_PARAMS_TEST_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_SET_EXTENT_INVALID_PARAMS_TEST_GROUP_NAME); + goto error; + } + + if ((fspace_id = generate_random_dataspace(DATASET_SET_EXTENT_INVALID_PARAMS_TEST_SPACE_RANK, NULL, dims, + FALSE)) < 0) + TEST_ERROR; + + for (i = 0; i < DATASET_SET_EXTENT_INVALID_PARAMS_TEST_SPACE_RANK; i++) { + do { + new_dims[i] = (hsize_t)(rand() % MAX_DIM_SIZE + 1); + } while (new_dims[i] > dims[i]); + do { + chunk_dims[i] = (hsize_t)(rand() % MAX_DIM_SIZE + 1); + } while (chunk_dims[i] > dims[i]); + } + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + /* Create a compact dataset */ + if ((compact_dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) + TEST_ERROR; + + if (H5Pset_layout(compact_dcpl_id, H5D_COMPACT) < 0) + TEST_ERROR; + + /* Keep the data space small because the storage size of compact dataset is limited to 64K */ + if ((compact_fspace_id = + H5Screate_simple(DATASET_SET_EXTENT_INVALID_PARAMS_TEST_SPACE_RANK, compact_dims, NULL)) < 0) + TEST_ERROR; + + if ((compact_dset_id = + H5Dcreate2(group_id, DATASET_SET_EXTENT_INVALID_LAYOUT_TEST_COMPACT_DSET_NAME, H5T_NATIVE_INT, + compact_fspace_id, H5P_DEFAULT, compact_dcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", + DATASET_SET_EXTENT_INVALID_LAYOUT_TEST_COMPACT_DSET_NAME); + goto error; + } + + /* Create a contiguous dataset */ + if ((contiguous_dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) + TEST_ERROR; + + if (H5Pset_layout(contiguous_dcpl_id, H5D_CONTIGUOUS) < 0) + TEST_ERROR; + + if ((contiguous_dset_id = + H5Dcreate2(group_id, DATASET_SET_EXTENT_INVALID_LAYOUT_TEST_CONTIGUOUS_DSET_NAME, dset_dtype, + fspace_id, H5P_DEFAULT, contiguous_dcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", + DATASET_SET_EXTENT_INVALID_LAYOUT_TEST_CONTIGUOUS_DSET_NAME); + goto error; + } + + /* Create a chunked dataset */ + if ((chunked_dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) + TEST_ERROR; + + if (H5Pset_chunk(chunked_dcpl_id, DATASET_SET_EXTENT_INVALID_PARAMS_TEST_SPACE_RANK, chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" unable to set dataset chunk dimensionality\n"); + goto error; + } + + if ((chunked_dset_id = H5Dcreate2(group_id, DATASET_SET_EXTENT_INVALID_PARAMS_TEST_DSET_NAME, dset_dtype, + fspace_id, H5P_DEFAULT, chunked_dcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_SET_EXTENT_INVALID_PARAMS_TEST_DSET_NAME); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Dset_extent_invalid_layout_compact) + { + TESTING_2("H5Dset_extent with an invalid dataset layout (compact)"); + + H5E_BEGIN_TRY + { + err_ret = H5Dset_extent(compact_dset_id, new_dims); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" setting dataset extent succeeded with an invalid layout (compact)\n"); + PART_ERROR(H5Dset_extent_invalid_layout_compact); + } + + PASSED(); + } + PART_END(H5Dset_extent_invalid_layout_compact); + + PART_BEGIN(H5Dset_extent_invalid_layout_contiguous) + { + TESTING_2("H5Dset_extent with an invalid dataset layout (contiguous)"); + + H5E_BEGIN_TRY + { + err_ret = H5Dset_extent(contiguous_dset_id, new_dims); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" setting dataset extent succeeded with an invalid layout (contiguous)\n"); + PART_ERROR(H5Dset_extent_invalid_layout_contiguous); + } + + PASSED(); + } + PART_END(H5Dset_extent_invalid_layout_contiguous); + + PART_BEGIN(H5Dset_extent_invalid_dset_id) + { + TESTING_2("H5Dset_extent with an invalid dataset ID"); + + H5E_BEGIN_TRY + { + err_ret = H5Dset_extent(H5I_INVALID_HID, new_dims); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" setting dataset extent succeeded with an invalid dataset ID\n"); + PART_ERROR(H5Dset_extent_invalid_dset_id); + } + + PASSED(); + } + PART_END(H5Dset_extent_invalid_dset_id); + + PART_BEGIN(H5Dset_extent_null_dim_pointer) + { + TESTING_2("H5Dset_extent with NULL dimension pointer"); + + H5E_BEGIN_TRY + { + err_ret = H5Dset_extent(chunked_dset_id, NULL); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" setting dataset extent succeeded with a NULL dimension pointer\n"); + PART_ERROR(H5Dset_extent_null_dim_pointer); + } + + PASSED(); + } + PART_END(H5Dset_extent_null_dim_pointer); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Pclose(chunked_dcpl_id) < 0) + TEST_ERROR; + if (H5Pclose(compact_dcpl_id) < 0) + TEST_ERROR; + if (H5Pclose(contiguous_dcpl_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Sclose(compact_fspace_id) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Dclose(chunked_dset_id) < 0) + TEST_ERROR; + if (H5Dclose(compact_dset_id) < 0) + TEST_ERROR; + if (H5Dclose(contiguous_dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(chunked_dcpl_id); + H5Pclose(compact_dcpl_id); + H5Pclose(contiguous_dcpl_id); + H5Sclose(fspace_id); + H5Sclose(compact_fspace_id); + H5Tclose(dset_dtype); + H5Dclose(chunked_dset_id); + H5Dclose(compact_dset_id); + H5Dclose(contiguous_dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} /* test_dataset_set_extent_invalid_params */ + +/* + * A test for H5Dflush. + */ +static int +test_flush_dataset(void) +{ + TESTING("H5Dflush"); + + SKIPPED(); + + return 0; +} + +/* + * A test to check that H5Dflush fails when it is + * passed invalid parameters. + */ +static int +test_flush_dataset_invalid_params(void) +{ + TESTING("H5Dflush with invalid parameters"); + + SKIPPED(); + + return 0; +} + +/* + * A test for H5Drefresh. + */ +static int +test_refresh_dataset(void) +{ + TESTING("H5Drefresh"); + + SKIPPED(); + + return 0; +} + +/* + * A test to check that H5Drefresh fails when it is + * passed invalid parameters. + */ +static int +test_refresh_dataset_invalid_params(void) +{ + TESTING("H5Drefresh"); + + SKIPPED(); + + return 0; +} + +/* + * A test to create a dataset composed of a single chunk. + */ +static int +test_create_single_chunk_dataset(void) +{ + hsize_t dims[DATASET_SINGLE_CHUNK_TEST_SPACE_RANK]; + hsize_t retrieved_chunk_dims[DATASET_SINGLE_CHUNK_TEST_SPACE_RANK]; + size_t i; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t dcpl_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + + TESTING("creation of dataset with single chunk"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GET_PLIST)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, or get property list aren't supported " + "with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_SINGLE_CHUNK_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", DATASET_SINGLE_CHUNK_TEST_GROUP_NAME); + goto error; + } + + if ((fspace_id = generate_random_dataspace(DATASET_SINGLE_CHUNK_TEST_SPACE_RANK, NULL, dims, FALSE)) < 0) + TEST_ERROR; + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + if ((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) + TEST_ERROR; + + if (H5Pset_chunk(dcpl_id, DATASET_SINGLE_CHUNK_TEST_SPACE_RANK, dims) < 0) { + H5_FAILED(); + HDprintf(" failed to set chunking on DCPL\n"); + goto error; + } + + if ((dset_id = H5Dcreate2(group_id, DATASET_SINGLE_CHUNK_TEST_DSET_NAME, dset_dtype, fspace_id, + H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_SINGLE_CHUNK_TEST_DSET_NAME); + goto error; + } + + /* + * See if a copy of the DCPL reports the correct chunking. + */ + if (H5Pclose(dcpl_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close DCPL\n"); + goto error; + } + + if ((dcpl_id = H5Dget_create_plist(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve copy of DCPL\n"); + goto error; + } + + memset(retrieved_chunk_dims, 0, sizeof(retrieved_chunk_dims)); + if (H5Pget_chunk(dcpl_id, DATASET_SINGLE_CHUNK_TEST_SPACE_RANK, retrieved_chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve chunking info\n"); + goto error; + } + + for (i = 0; i < DATASET_SINGLE_CHUNK_TEST_SPACE_RANK; i++) { + if (dims[i] != retrieved_chunk_dims[i]) { + H5_FAILED(); + HDprintf(" chunk dimensionality retrieved from DCPL didn't match originally specified " + "dimensionality\n"); + goto error; + } + } + + /* + * Now close the dataset and retrieve a copy + * of the DCPL after re-opening it. + */ + if (H5Pclose(dcpl_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close DCPL\n"); + goto error; + } + + if (H5Dclose(dset_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close dataset\n"); + goto error; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_SINGLE_CHUNK_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to re-open dataset\n"); + goto error; + } + + if ((dcpl_id = H5Dget_create_plist(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve copy of DCPL\n"); + goto error; + } + + memset(retrieved_chunk_dims, 0, sizeof(retrieved_chunk_dims)); + if (H5Pget_chunk(dcpl_id, DATASET_SINGLE_CHUNK_TEST_SPACE_RANK, retrieved_chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve chunking info\n"); + goto error; + } + + for (i = 0; i < DATASET_SINGLE_CHUNK_TEST_SPACE_RANK; i++) { + if (dims[i] != retrieved_chunk_dims[i]) { + H5_FAILED(); + HDprintf(" chunk dimensionality retrieved from DCPL didn't match originally specified " + "dimensionality\n"); + goto error; + } + } + + if (H5Pclose(dcpl_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(dcpl_id); + H5Sclose(fspace_id); + H5Tclose(dset_dtype); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a single-chunk dataset can be written + * and read correctly. + */ +static int +test_write_single_chunk_dataset(void) +{ + hssize_t space_npoints; + hsize_t dims[DATASET_SINGLE_CHUNK_WRITE_TEST_DSET_SPACE_RANK]; + hsize_t retrieved_chunk_dims[DATASET_SINGLE_CHUNK_WRITE_TEST_DSET_SPACE_RANK]; + size_t i, data_size; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dcpl_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + void *write_buf = NULL; + void *read_buf = NULL; + + TESTING("write to dataset with single chunk"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_GET_PLIST)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, or get property list aren't supported " + "with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_SINGLE_CHUNK_WRITE_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_SINGLE_CHUNK_WRITE_TEST_GROUP_NAME); + goto error; + } + + if ((fspace_id = generate_random_dataspace(DATASET_SINGLE_CHUNK_WRITE_TEST_DSET_SPACE_RANK, NULL, dims, + FALSE)) < 0) + TEST_ERROR; + + if ((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) + TEST_ERROR; + + if (H5Pset_chunk(dcpl_id, DATASET_SINGLE_CHUNK_WRITE_TEST_DSET_SPACE_RANK, dims) < 0) { + H5_FAILED(); + HDprintf(" failed to set chunking on DCPL\n"); + goto error; + } + + if ((dset_id = H5Dcreate2(group_id, DATASET_SINGLE_CHUNK_WRITE_TEST_DSET_NAME, + DATASET_SINGLE_CHUNK_WRITE_TEST_DSET_DTYPE, fspace_id, H5P_DEFAULT, dcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_SINGLE_CHUNK_WRITE_TEST_DSET_NAME); + goto error; + } + + /* + * See if a copy of the DCPL reports the correct chunking. + */ + if (H5Pclose(dcpl_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close DCPL\n"); + goto error; + } + + if ((dcpl_id = H5Dget_create_plist(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve copy of DCPL\n"); + goto error; + } + + memset(retrieved_chunk_dims, 0, sizeof(retrieved_chunk_dims)); + if (H5Pget_chunk(dcpl_id, DATASET_SINGLE_CHUNK_WRITE_TEST_DSET_SPACE_RANK, retrieved_chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve chunking info\n"); + goto error; + } + + for (i = 0; i < DATASET_SINGLE_CHUNK_WRITE_TEST_DSET_SPACE_RANK; i++) { + if (dims[i] != retrieved_chunk_dims[i]) { + H5_FAILED(); + HDprintf(" chunk dimensionality retrieved from DCPL didn't match originally specified " + "dimensionality\n"); + goto error; + } + } + + for (i = 0, data_size = 1; i < DATASET_SINGLE_CHUNK_WRITE_TEST_DSET_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_SINGLE_CHUNK_WRITE_TEST_DSET_DTYPESIZE; + + if (NULL == (write_buf = HDmalloc(data_size))) + TEST_ERROR; + + for (i = 0; i < data_size / DATASET_SINGLE_CHUNK_WRITE_TEST_DSET_DTYPESIZE; i++) + ((int *)write_buf)[i] = (int)i; + + if (H5Dwrite(dset_id, DATASET_SINGLE_CHUNK_WRITE_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, H5P_DEFAULT, + write_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", DATASET_SINGLE_CHUNK_WRITE_TEST_DSET_NAME); + goto error; + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_SINGLE_CHUNK_WRITE_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_SINGLE_CHUNK_WRITE_TEST_DSET_NAME); + goto error; + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + goto error; + } + + if ((space_npoints = H5Sget_simple_extent_npoints(fspace_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataspace num points\n"); + goto error; + } + + if (NULL == + (read_buf = HDmalloc((hsize_t)space_npoints * DATASET_SINGLE_CHUNK_WRITE_TEST_DSET_DTYPESIZE))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + goto error; + } + + if (H5Dread(dset_id, DATASET_SINGLE_CHUNK_WRITE_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, H5P_DEFAULT, + read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", DATASET_SINGLE_CHUNK_WRITE_TEST_DSET_NAME); + goto error; + } + + for (i = 0; i < (hsize_t)space_npoints; i++) + if (((int *)read_buf)[i] != (int)i) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + goto error; + } + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (H5Pclose(dcpl_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (write_buf) + HDfree(write_buf); + if (read_buf) + HDfree(read_buf); + H5Pclose(dcpl_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to create a dataset composed of multiple chunks. + */ +static int +test_create_multi_chunk_dataset(void) +{ + hsize_t dims[DATASET_MULTI_CHUNK_TEST_SPACE_RANK] = {100, 100}; + hsize_t chunk_dims[DATASET_MULTI_CHUNK_TEST_SPACE_RANK] = {10, 10}; + hsize_t retrieved_chunk_dims[DATASET_MULTI_CHUNK_TEST_SPACE_RANK]; + size_t i; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t dcpl_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + + TESTING("creation of dataset with multiple chunks"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GET_PLIST)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, or get property list aren't supported " + "with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_MULTI_CHUNK_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", DATASET_MULTI_CHUNK_TEST_GROUP_NAME); + goto error; + } + + if ((fspace_id = H5Screate_simple(DATASET_MULTI_CHUNK_TEST_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + if ((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) + TEST_ERROR; + + if (H5Pset_chunk(dcpl_id, DATASET_MULTI_CHUNK_TEST_SPACE_RANK, chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" failed to set chunking on DCPL\n"); + goto error; + } + + if ((dset_id = H5Dcreate2(group_id, DATASET_MULTI_CHUNK_TEST_DSET_NAME, dset_dtype, fspace_id, + H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_MULTI_CHUNK_TEST_DSET_NAME); + goto error; + } + + /* + * See if a copy of the DCPL reports the correct chunking. + */ + if (H5Pclose(dcpl_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close DCPL\n"); + goto error; + } + + if ((dcpl_id = H5Dget_create_plist(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve copy of DCPL\n"); + goto error; + } + + memset(retrieved_chunk_dims, 0, sizeof(retrieved_chunk_dims)); + if (H5Pget_chunk(dcpl_id, DATASET_MULTI_CHUNK_TEST_SPACE_RANK, retrieved_chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve chunking info\n"); + goto error; + } + + for (i = 0; i < DATASET_MULTI_CHUNK_TEST_SPACE_RANK; i++) { + if (chunk_dims[i] != retrieved_chunk_dims[i]) { + H5_FAILED(); + HDprintf(" chunk dimensionality retrieved from DCPL didn't match originally specified " + "dimensionality\n"); + goto error; + } + } + + /* + * Now close the dataset and retrieve a copy + * of the DCPL after re-opening it. + */ + if (H5Pclose(dcpl_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close DCPL\n"); + goto error; + } + + if (H5Dclose(dset_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close dataset\n"); + goto error; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_MULTI_CHUNK_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to re-open dataset\n"); + goto error; + } + + if ((dcpl_id = H5Dget_create_plist(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve copy of DCPL\n"); + goto error; + } + + memset(retrieved_chunk_dims, 0, sizeof(retrieved_chunk_dims)); + if (H5Pget_chunk(dcpl_id, DATASET_MULTI_CHUNK_TEST_SPACE_RANK, retrieved_chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve chunking info\n"); + goto error; + } + + for (i = 0; i < DATASET_MULTI_CHUNK_TEST_SPACE_RANK; i++) { + if (chunk_dims[i] != retrieved_chunk_dims[i]) { + H5_FAILED(); + HDprintf(" chunk dimensionality retrieved from DCPL didn't match originally specified " + "dimensionality\n"); + goto error; + } + } + + if (H5Pclose(dcpl_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(dcpl_id); + H5Sclose(fspace_id); + H5Tclose(dset_dtype); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a dataset composed of multiple chunks + * can be written and read correctly. When reading back the + * chunks of the dataset, the file dataspace and memory dataspace + * used are the same shape. + */ +static int +test_write_multi_chunk_dataset_same_shape_read(void) +{ + hsize_t dims[DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK] = {100, 100}; + hsize_t chunk_dims[DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK] = {10, 10}; + hsize_t retrieved_chunk_dims[DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK]; + hsize_t start[DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK]; + hsize_t count[DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK]; + size_t i, data_size, chunk_size; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dcpl_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + void *write_buf = NULL; + int read_buf[10][10]; + + TESTING("write to dataset with multiple chunks using same shaped dataspaces"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_GET_PLIST)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, or get property list aren't supported " + "with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_GROUP_NAME); + goto error; + } + + if ((fspace_id = H5Screate_simple(DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK, dims, + NULL)) < 0) + TEST_ERROR; + + if ((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) + TEST_ERROR; + + if (H5Pset_chunk(dcpl_id, DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK, chunk_dims) < + 0) { + H5_FAILED(); + HDprintf(" failed to set chunking on DCPL\n"); + goto error; + } + + if ((dset_id = H5Dcreate2(group_id, DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_NAME, + DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_DTYPE, fspace_id, + H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", + DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_NAME); + goto error; + } + + /* + * See if a copy of the DCPL reports the correct chunking. + */ + if (H5Pclose(dcpl_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close DCPL\n"); + goto error; + } + + if ((dcpl_id = H5Dget_create_plist(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve copy of DCPL\n"); + goto error; + } + + memset(retrieved_chunk_dims, 0, sizeof(retrieved_chunk_dims)); + if (H5Pget_chunk(dcpl_id, DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK, + retrieved_chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve chunking info\n"); + goto error; + } + + for (i = 0; i < DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; i++) { + if (chunk_dims[i] != retrieved_chunk_dims[i]) { + H5_FAILED(); + HDprintf(" chunk dimensionality retrieved from DCPL didn't match originally specified " + "dimensionality\n"); + goto error; + } + } + + for (i = 0, chunk_size = 1; i < DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; i++) + chunk_size *= chunk_dims[i]; + chunk_size *= DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_DTYPESIZE; + + for (i = 0, data_size = 1; i < DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_DTYPESIZE; + + if (NULL == (write_buf = HDmalloc(data_size))) + TEST_ERROR; + + /* + * Ensure that each underlying chunk contains the values + * + * chunk_index .. (chunk_nelemts - 1) + chunk_index. + * + * That is to say, for a chunk size of 10 x 10, chunk 0 + * contains the values + * + * 0 .. 99 + * + * while the next chunk contains the values + * + * 1 .. 100 + * + * and so on. + */ + for (i = 0; i < data_size / DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_DTYPESIZE; i++) { + size_t j; + size_t base; + size_t tot_adjust; + + /* + * Calculate a starting base value by taking the index value mod + * the size of a chunk in each dimension. + */ + for (j = 0, base = i; j < DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; j++) + if (chunk_dims[j] > 1 && base >= chunk_dims[j]) + base %= chunk_dims[j]; + + /* + * Calculate the adjustment in each dimension. + */ + for (j = 0, tot_adjust = 0; j < DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; j++) { + if (j == (DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK - 1)) + tot_adjust += (i % dims[j]) / chunk_dims[j]; + else { + size_t k; + size_t n_faster_elemts; + + /* + * Calculate the number of elements in faster dimensions. + */ + for (k = j + 1, n_faster_elemts = 1; + k < DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; k++) + n_faster_elemts *= dims[k]; + + tot_adjust += (((i / n_faster_elemts) / chunk_dims[j]) * (dims[j + 1] / chunk_dims[j + 1])) + + (((i / n_faster_elemts) % chunk_dims[j]) * chunk_dims[j + 1]); + } + } + + ((int *)write_buf)[i] = (int)(base + tot_adjust); + } + + /* + * Write every chunk in the dataset. + */ + if (H5Dwrite(dset_id, DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, + H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", + DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_NAME); + goto error; + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + if ((dset_id = + H5Dopen2(group_id, DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", + DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_NAME); + goto error; + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + goto error; + } + + /* + * Create 2-dimensional memory dataspace for read buffer. + */ + { + hsize_t mdims[] = {chunk_dims[0], chunk_dims[1]}; + + if ((mspace_id = H5Screate_simple(2, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" failed to create memory dataspace\n"); + goto error; + } + } + + for (i = 0; i < DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; i++) { + count[i] = chunk_dims[i]; + } + + /* + * Read every chunk in the dataset, checking the data for each one. + */ + HDprintf("\n"); + for (i = 0; i < data_size / chunk_size; i++) { + size_t j, k; + + HDprintf("\r Reading chunk %zu", i); + + for (j = 0; j < DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; j++) { + if (dims[j] == chunk_dims[j]) + start[j] = 0; + else if (j == (DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK - 1)) + /* Fastest changing dimension */ + start[j] = (i * chunk_dims[j]) % dims[j]; + else + start[j] = ((i * chunk_dims[j + 1]) / dims[j + 1]) * (chunk_dims[j]); + } + + /* + * Adjust file dataspace selection for next chunk. + */ + if (H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET, start, NULL, count, NULL) < 0) { + H5_FAILED(); + HDprintf(" failed to set hyperslab selection\n"); + goto error; + } + + for (j = 0; j < chunk_dims[0]; j++) + for (k = 0; k < chunk_dims[1]; k++) + read_buf[j][k] = 0; + + if (H5Dread(dset_id, DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_DTYPE, mspace_id, fspace_id, + H5P_DEFAULT, read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", + DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_NAME); + goto error; + } + + for (j = 0; j < chunk_dims[0]; j++) { + for (k = 0; k < chunk_dims[1]; k++) { + if (read_buf[j][k] != (int)((j * chunk_dims[0]) + k + i)) { + H5_FAILED(); + HDprintf(" data verification failed for chunk %lld\n", (long long)i); + goto error; + } + } + } + } + + if (H5Pclose(dcpl_id) < 0) + TEST_ERROR; + if (H5Sclose(mspace_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (write_buf) + HDfree(write_buf); + H5Pclose(dcpl_id); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a dataset composed of multiple chunks + * can be written and read correctly. When reading back the + * chunks of the dataset, the file dataspace and memory dataspace + * used are differently shaped. + */ +static int +test_write_multi_chunk_dataset_diff_shape_read(void) +{ + hsize_t dims[DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK] = {100, 100}; + hsize_t chunk_dims[DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK] = {10, 10}; + hsize_t retrieved_chunk_dims[DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK]; + hsize_t start[DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK]; + hsize_t count[DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK]; + size_t i, data_size, chunk_size; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dcpl_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + void *write_buf = NULL; + void *read_buf = NULL; + + TESTING("write to dataset with multiple chunks using differently shaped dataspaces"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GET_PLIST)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, or get property list aren't supported " + "with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_GROUP_NAME); + goto error; + } + + if ((fspace_id = H5Screate_simple(DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK, dims, + NULL)) < 0) + TEST_ERROR; + + if ((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) + TEST_ERROR; + + if (H5Pset_chunk(dcpl_id, DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK, chunk_dims) < + 0) { + H5_FAILED(); + HDprintf(" failed to set chunking on DCPL\n"); + goto error; + } + + if ((dset_id = H5Dcreate2(group_id, DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_NAME, + DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_DTYPE, fspace_id, + H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", + DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_NAME); + goto error; + } + + /* + * See if a copy of the DCPL reports the correct chunking. + */ + if (H5Pclose(dcpl_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close DCPL\n"); + goto error; + } + + if ((dcpl_id = H5Dget_create_plist(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve copy of DCPL\n"); + goto error; + } + + memset(retrieved_chunk_dims, 0, sizeof(retrieved_chunk_dims)); + if (H5Pget_chunk(dcpl_id, DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK, + retrieved_chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve chunking info\n"); + goto error; + } + + for (i = 0; i < DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; i++) { + if (chunk_dims[i] != retrieved_chunk_dims[i]) { + H5_FAILED(); + HDprintf(" chunk dimensionality retrieved from DCPL didn't match originally specified " + "dimensionality\n"); + goto error; + } + } + + for (i = 0, chunk_size = 1; i < DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; i++) + chunk_size *= chunk_dims[i]; + chunk_size *= DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_DTYPESIZE; + + for (i = 0, data_size = 1; i < DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_DTYPESIZE; + + if (NULL == (write_buf = HDmalloc(data_size))) + TEST_ERROR; + + /* + * Ensure that each underlying chunk contains the values + * + * chunk_index .. (chunk_nelemts - 1) + chunk_index. + * + * That is to say, for a chunk size of 10 x 10, chunk 0 + * contains the values + * + * 0 .. 99 + * + * while the next chunk contains the values + * + * 1 .. 100 + * + * and so on. + */ + for (i = 0; i < data_size / DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_DTYPESIZE; i++) { + size_t j; + size_t base; + size_t tot_adjust; + + /* + * Calculate a starting base value by taking the index value mod + * the size of a chunk in each dimension. + */ + for (j = 0, base = i; j < DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; j++) + if (chunk_dims[j] > 1 && base >= chunk_dims[j]) + base %= chunk_dims[j]; + + /* + * Calculate the adjustment in each dimension. + */ + for (j = 0, tot_adjust = 0; j < DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; j++) { + if (j == (DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK - 1)) + tot_adjust += (i % dims[j]) / chunk_dims[j]; + else { + size_t k; + size_t n_faster_elemts; + + /* + * Calculate the number of elements in faster dimensions. + */ + for (k = j + 1, n_faster_elemts = 1; + k < DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; k++) + n_faster_elemts *= dims[k]; + + tot_adjust += (((i / n_faster_elemts) / chunk_dims[j]) * (dims[j + 1] / chunk_dims[j + 1])) + + (((i / n_faster_elemts) % chunk_dims[j]) * chunk_dims[j + 1]); + } + } + + ((int *)write_buf)[i] = (int)(base + tot_adjust); + } + + /* + * Write every chunk in the dataset. + */ + if (H5Dwrite(dset_id, DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, + H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", + DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_NAME); + goto error; + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + if ((dset_id = + H5Dopen2(group_id, DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", + DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_NAME); + goto error; + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + goto error; + } + + /* + * Allocate single chunk-sized read buffer. + */ + if (NULL == (read_buf = HDmalloc(chunk_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + goto error; + } + + /* + * Create 1-dimensional memory dataspace for read buffer. + */ + { + hsize_t mdims[] = {chunk_size / DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_DTYPESIZE}; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" failed to create memory dataspace\n"); + goto error; + } + } + + for (i = 0; i < DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; i++) { + count[i] = chunk_dims[i]; + } + + /* + * Read every chunk in the dataset, checking the data for each one. + */ + HDprintf("\n"); + for (i = 0; i < data_size / chunk_size; i++) { + size_t j; + + HDprintf("\r Reading chunk %zu", i); + + for (j = 0; j < DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; j++) { + if (dims[j] == chunk_dims[j]) + start[j] = 0; + else if (j == (DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK - 1)) + /* Fastest changing dimension */ + start[j] = (i * chunk_dims[j]) % dims[j]; + else + start[j] = ((i * chunk_dims[j + 1]) / dims[j + 1]) * (chunk_dims[j]); + } + + /* + * Adjust file dataspace selection for next chunk. + */ + if (H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET, start, NULL, count, NULL) < 0) { + H5_FAILED(); + HDprintf(" failed to set hyperslab selection\n"); + goto error; + } + + memset(read_buf, 0, chunk_size); + if (H5Dread(dset_id, DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_DTYPE, mspace_id, fspace_id, + H5P_DEFAULT, read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", + DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_NAME); + goto error; + } + + for (j = 0; j < (hsize_t)chunk_size / DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_DTYPESIZE; + j++) + if (((int *)read_buf)[j] != (int)(j + i)) { + H5_FAILED(); + HDprintf(" data verification failed for chunk %lld\n", (long long)i); + goto error; + } + } + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (H5Pclose(dcpl_id) < 0) + TEST_ERROR; + if (H5Sclose(mspace_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (write_buf) + HDfree(write_buf); + if (read_buf) + HDfree(read_buf); + H5Pclose(dcpl_id); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a dataset composed of multiple chunks + * can be written and read correctly several times in a row. + * When reading back the chunks of the dataset, the file + * dataspace and memory dataspace used are the same shape. + */ +static int +test_overwrite_multi_chunk_dataset_same_shape_read(void) +{ + hsize_t dims[DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK] = {100, 100}; + hsize_t chunk_dims[DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK] = {10, 10}; + hsize_t retrieved_chunk_dims[DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK]; + hsize_t start[DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK]; + hsize_t count[DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK]; + size_t i, data_size, chunk_size; + size_t niter; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dcpl_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + void *write_buf = NULL; + int read_buf[10][10]; + + TESTING("several overwrites to dataset with multiple chunks using same shaped dataspaces"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GET_PLIST)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, or get property list aren't supported " + "with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_GROUP_NAME); + goto error; + } + + if ((fspace_id = H5Screate_simple(DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK, + dims, NULL)) < 0) + TEST_ERROR; + + if ((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) + TEST_ERROR; + + if (H5Pset_chunk(dcpl_id, DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK, + chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" failed to set chunking on DCPL\n"); + goto error; + } + + if ((dset_id = H5Dcreate2(group_id, DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_NAME, + DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_DTYPE, fspace_id, + H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", + DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_NAME); + goto error; + } + + /* + * See if a copy of the DCPL reports the correct chunking. + */ + if (H5Pclose(dcpl_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close DCPL\n"); + goto error; + } + + if ((dcpl_id = H5Dget_create_plist(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve copy of DCPL\n"); + goto error; + } + + memset(retrieved_chunk_dims, 0, sizeof(retrieved_chunk_dims)); + if (H5Pget_chunk(dcpl_id, DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK, + retrieved_chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve chunking info\n"); + goto error; + } + + for (i = 0; i < DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; i++) { + if (chunk_dims[i] != retrieved_chunk_dims[i]) { + H5_FAILED(); + HDprintf(" chunk dimensionality retrieved from DCPL didn't match originally specified " + "dimensionality\n"); + goto error; + } + } + + for (i = 0, chunk_size = 1; i < DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; i++) + chunk_size *= chunk_dims[i]; + chunk_size *= DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_DTYPESIZE; + + for (i = 0, data_size = 1; i < DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_DTYPESIZE; + + if (NULL == (write_buf = HDmalloc(data_size))) + TEST_ERROR; + + /* + * Create 2-dimensional memory dataspace for read buffer. + */ + { + hsize_t mdims[] = {chunk_dims[0], chunk_dims[1]}; + + if ((mspace_id = H5Screate_simple(2, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" failed to create memory dataspace\n"); + goto error; + } + } + + for (i = 0; i < DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; i++) { + count[i] = chunk_dims[i]; + } + + HDprintf("\n"); + for (niter = 0; niter < DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_NITERS; niter++) { + memset(write_buf, 0, data_size); + + /* + * Ensure that each underlying chunk contains the values + * + * chunk_index .. (chunk_nelemts - 1) + chunk_index. + * + * That is to say, for a chunk size of 10 x 10, chunk 0 + * contains the values + * + * 0 .. 99 + * + * while the next chunk contains the values + * + * 1 .. 100 + * + * and so on. On each iteration, we add 1 to the previous + * values. + */ + for (i = 0; i < data_size / DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_DTYPESIZE; i++) { + size_t j; + size_t base; + size_t tot_adjust; + + /* + * Calculate a starting base value by taking the index value mod + * the size of a chunk in each dimension. + */ + for (j = 0, base = i; j < DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; j++) + if (chunk_dims[j] > 1 && base >= chunk_dims[j]) + base %= chunk_dims[j]; + + /* + * Calculate the adjustment in each dimension. + */ + for (j = 0, tot_adjust = 0; + j < DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; j++) { + if (j == (DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK - 1)) + tot_adjust += (i % dims[j]) / chunk_dims[j]; + else { + size_t k; + size_t n_faster_elemts; + + /* + * Calculate the number of elements in faster dimensions. + */ + for (k = j + 1, n_faster_elemts = 1; + k < DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; k++) + n_faster_elemts *= dims[k]; + + tot_adjust += + (((i / n_faster_elemts) / chunk_dims[j]) * (dims[j + 1] / chunk_dims[j + 1])) + + (((i / n_faster_elemts) % chunk_dims[j]) * chunk_dims[j + 1]); + } + } + + ((int *)write_buf)[i] = (int)(base + tot_adjust + niter); + } + + /* + * Write every chunk in the dataset. + */ + if (H5Dwrite(dset_id, DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, + H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", + DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_NAME); + goto error; + } + + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_NAME, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", + DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_NAME); + goto error; + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + goto error; + } + + /* + * Read every chunk in the dataset, checking the data for each one. + */ + for (i = 0; i < data_size / chunk_size; i++) { + size_t j, k; + + HDprintf("\r Reading chunk %zu", i); + + for (j = 0; j < DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; j++) { + if (dims[j] == chunk_dims[j]) + start[j] = 0; + else if (j == (DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK - 1)) + /* Fastest changing dimension */ + start[j] = (i * chunk_dims[j]) % dims[j]; + else + start[j] = ((i * chunk_dims[j + 1]) / dims[j + 1]) * (chunk_dims[j]); + } + + /* + * Adjust file dataspace selection for next chunk. + */ + if (H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET, start, NULL, count, NULL) < 0) { + H5_FAILED(); + HDprintf(" failed to set hyperslab selection\n"); + goto error; + } + + for (j = 0; j < chunk_dims[0]; j++) + for (k = 0; k < chunk_dims[1]; k++) + read_buf[j][k] = 0; + + if (H5Dread(dset_id, DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_DTYPE, mspace_id, + fspace_id, H5P_DEFAULT, read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", + DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_NAME); + goto error; + } + + for (j = 0; j < chunk_dims[0]; j++) { + for (k = 0; k < chunk_dims[1]; k++) { + if (read_buf[j][k] != (int)((j * chunk_dims[0]) + k + i + niter)) { + H5_FAILED(); + HDprintf(" data verification failed for chunk %lld\n", (long long)i); + goto error; + } + } + } + } + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + + if (H5Pclose(dcpl_id) < 0) + TEST_ERROR; + if (H5Sclose(mspace_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (write_buf) + HDfree(write_buf); + H5Pclose(dcpl_id); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a dataset composed of multiple chunks + * can be written and read correctly several times in a row. + * When reading back the chunks of the dataset, the file + * dataspace and memory dataspace used are differently shaped. + */ +static int +test_overwrite_multi_chunk_dataset_diff_shape_read(void) +{ + hsize_t dims[DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK] = {100, 100}; + hsize_t chunk_dims[DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK] = {10, 10}; + hsize_t retrieved_chunk_dims[DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK]; + hsize_t start[DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK]; + hsize_t count[DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK]; + size_t i, data_size, chunk_size; + size_t niter; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dcpl_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + void *write_buf = NULL; + void *read_buf = NULL; + + TESTING("several overwrites to dataset with multiple chunks using differently shaped dataspaces"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GET_PLIST)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, or get property list aren't supported " + "with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_GROUP_NAME); + goto error; + } + + if ((fspace_id = H5Screate_simple(DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK, + dims, NULL)) < 0) + TEST_ERROR; + + if ((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) + TEST_ERROR; + + if (H5Pset_chunk(dcpl_id, DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK, + chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" failed to set chunking on DCPL\n"); + goto error; + } + + if ((dset_id = H5Dcreate2(group_id, DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_NAME, + DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_DTYPE, fspace_id, + H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", + DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_NAME); + goto error; + } + + /* + * See if a copy of the DCPL reports the correct chunking. + */ + if (H5Pclose(dcpl_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close DCPL\n"); + goto error; + } + + if ((dcpl_id = H5Dget_create_plist(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve copy of DCPL\n"); + goto error; + } + + memset(retrieved_chunk_dims, 0, sizeof(retrieved_chunk_dims)); + if (H5Pget_chunk(dcpl_id, DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK, + retrieved_chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve chunking info\n"); + goto error; + } + + for (i = 0; i < DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; i++) { + if (chunk_dims[i] != retrieved_chunk_dims[i]) { + H5_FAILED(); + HDprintf(" chunk dimensionality retrieved from DCPL didn't match originally specified " + "dimensionality\n"); + goto error; + } + } + + for (i = 0, chunk_size = 1; i < DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; i++) + chunk_size *= chunk_dims[i]; + chunk_size *= DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_DTYPESIZE; + + for (i = 0, data_size = 1; i < DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_DTYPESIZE; + + if (NULL == (write_buf = HDmalloc(data_size))) + TEST_ERROR; + + /* + * Allocate single chunk-sized read buffer. + */ + if (NULL == (read_buf = HDmalloc(chunk_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + goto error; + } + + /* + * Create 1-dimensional memory dataspace for read buffer. + */ + { + hsize_t mdims[] = {chunk_size / DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_DTYPESIZE}; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" failed to create memory dataspace\n"); + goto error; + } + } + + for (i = 0; i < DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; i++) { + count[i] = chunk_dims[i]; + } + + HDprintf("\n"); + for (niter = 0; niter < DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_NITERS; niter++) { + memset(write_buf, 0, data_size); + + /* + * Ensure that each underlying chunk contains the values + * + * chunk_index .. (chunk_nelemts - 1) + chunk_index. + * + * That is to say, for a chunk size of 10 x 10, chunk 0 + * contains the values + * + * 0 .. 99 + * + * while the next chunk contains the values + * + * 1 .. 100 + * + * and so on. On each iteration, we add 1 to the previous + * values. + */ + for (i = 0; i < data_size / DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_DTYPESIZE; i++) { + size_t j; + size_t base; + size_t tot_adjust; + + /* + * Calculate a starting base value by taking the index value mod + * the size of a chunk in each dimension. + */ + for (j = 0, base = i; j < DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; j++) + if (chunk_dims[j] > 1 && base >= chunk_dims[j]) + base %= chunk_dims[j]; + + /* + * Calculate the adjustment in each dimension. + */ + for (j = 0, tot_adjust = 0; + j < DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; j++) { + if (j == (DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK - 1)) + tot_adjust += (i % dims[j]) / chunk_dims[j]; + else { + size_t k; + size_t n_faster_elemts; + + /* + * Calculate the number of elements in faster dimensions. + */ + for (k = j + 1, n_faster_elemts = 1; + k < DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; k++) + n_faster_elemts *= dims[k]; + + tot_adjust += + (((i / n_faster_elemts) / chunk_dims[j]) * (dims[j + 1] / chunk_dims[j + 1])) + + (((i / n_faster_elemts) % chunk_dims[j]) * chunk_dims[j + 1]); + } + } + + ((int *)write_buf)[i] = (int)(base + tot_adjust + niter); + } + + /* + * Write every chunk in the dataset. + */ + if (H5Dwrite(dset_id, DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, + H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", + DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_NAME); + goto error; + } + + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_NAME, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", + DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_NAME); + goto error; + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + goto error; + } + + /* + * Read every chunk in the dataset, checking the data for each one. + */ + for (i = 0; i < data_size / chunk_size; i++) { + size_t j; + + HDprintf("\r Reading chunk %zu", i); + + for (j = 0; j < DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; j++) { + if (dims[j] == chunk_dims[j]) + start[j] = 0; + else if (j == (DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK - 1)) + /* Fastest changing dimension */ + start[j] = (i * chunk_dims[j]) % dims[j]; + else + start[j] = ((i * chunk_dims[j + 1]) / dims[j + 1]) * (chunk_dims[j]); + } + + /* + * Adjust file dataspace selection for next chunk. + */ + if (H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET, start, NULL, count, NULL) < 0) { + H5_FAILED(); + HDprintf(" failed to set hyperslab selection\n"); + goto error; + } + + memset(read_buf, 0, chunk_size); + if (H5Dread(dset_id, DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_DTYPE, mspace_id, + fspace_id, H5P_DEFAULT, read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", + DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_NAME); + goto error; + } + + for (j = 0; + j < (hsize_t)chunk_size / DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_DTYPESIZE; + j++) + if (((int *)read_buf)[j] != (int)(j + i + niter)) { + H5_FAILED(); + HDprintf(" data verification failed for chunk %lld\n", (long long)i); + goto error; + } + } + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (H5Pclose(dcpl_id) < 0) + TEST_ERROR; + if (H5Sclose(mspace_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (write_buf) + HDfree(write_buf); + if (read_buf) + HDfree(read_buf); + H5Pclose(dcpl_id); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to ensure that a partial chunk can be written and + * then read correctly when the selection used in a chunked + * dataset's file dataspace is H5S_ALL. + */ +#define FIXED_DIMSIZE 25 +#define FIXED_CHUNK_DIMSIZE 10 +static int +test_read_partial_chunk_all_selection(void) +{ + DATASET_PARTIAL_CHUNK_READ_ALL_SEL_TEST_DSET_CTYPE write_buf[FIXED_DIMSIZE][FIXED_DIMSIZE]; + DATASET_PARTIAL_CHUNK_READ_ALL_SEL_TEST_DSET_CTYPE read_buf[FIXED_DIMSIZE][FIXED_DIMSIZE]; + hsize_t dims[DATASET_PARTIAL_CHUNK_READ_ALL_SEL_TEST_DSET_SPACE_RANK] = {FIXED_DIMSIZE, FIXED_DIMSIZE}; + hsize_t chunk_dims[DATASET_PARTIAL_CHUNK_READ_ALL_SEL_TEST_DSET_SPACE_RANK] = {FIXED_CHUNK_DIMSIZE, + FIXED_CHUNK_DIMSIZE}; + hsize_t retrieved_chunk_dims[DATASET_PARTIAL_CHUNK_READ_ALL_SEL_TEST_DSET_SPACE_RANK]; + size_t i, j; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dcpl_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + + TESTING("reading a partial chunk using H5S_ALL for file dataspace"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GET_PLIST)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, or get property list aren't supported " + "with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_PARTIAL_CHUNK_READ_ALL_SEL_TEST_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_PARTIAL_CHUNK_READ_ALL_SEL_TEST_GROUP_NAME); + goto error; + } + + if ((fspace_id = H5Screate_simple(DATASET_PARTIAL_CHUNK_READ_ALL_SEL_TEST_DSET_SPACE_RANK, dims, NULL)) < + 0) + TEST_ERROR; + + if ((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) + TEST_ERROR; + + if (H5Pset_chunk(dcpl_id, DATASET_PARTIAL_CHUNK_READ_ALL_SEL_TEST_DSET_SPACE_RANK, chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" failed to set chunking on DCPL\n"); + goto error; + } + + if ((dset_id = H5Dcreate2(group_id, DATASET_PARTIAL_CHUNK_READ_ALL_SEL_TEST_DSET_NAME, + DATASET_PARTIAL_CHUNK_READ_ALL_SEL_TEST_DSET_DTYPE, fspace_id, H5P_DEFAULT, + dcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_PARTIAL_CHUNK_READ_ALL_SEL_TEST_DSET_NAME); + goto error; + } + + /* + * See if a copy of the DCPL reports the correct chunking. + */ + if (H5Pclose(dcpl_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close DCPL\n"); + goto error; + } + + if ((dcpl_id = H5Dget_create_plist(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve copy of DCPL\n"); + goto error; + } + + memset(retrieved_chunk_dims, 0, sizeof(retrieved_chunk_dims)); + if (H5Pget_chunk(dcpl_id, DATASET_PARTIAL_CHUNK_READ_ALL_SEL_TEST_DSET_SPACE_RANK, retrieved_chunk_dims) < + 0) { + H5_FAILED(); + HDprintf(" failed to retrieve chunking info\n"); + goto error; + } + + for (i = 0; i < DATASET_PARTIAL_CHUNK_READ_ALL_SEL_TEST_DSET_SPACE_RANK; i++) { + if (chunk_dims[i] != retrieved_chunk_dims[i]) { + H5_FAILED(); + HDprintf(" chunk dimensionality retrieved from DCPL didn't match originally specified " + "dimensionality\n"); + goto error; + } + } + + for (i = 0; i < FIXED_DIMSIZE; i++) + for (j = 0; j < FIXED_DIMSIZE; j++) + write_buf[i][j] = (DATASET_PARTIAL_CHUNK_READ_ALL_SEL_TEST_DSET_CTYPE)((i * FIXED_DIMSIZE) + j); + + for (i = 0; i < FIXED_DIMSIZE; i++) + for (j = 0; j < FIXED_DIMSIZE; j++) + read_buf[i][j] = -1; + + if (H5Dwrite(dset_id, DATASET_PARTIAL_CHUNK_READ_ALL_SEL_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, H5P_DEFAULT, + write_buf) < 0) { + H5_FAILED(); + HDprintf(" failed to write to dataset\n"); + goto error; + } + + /* + * Close and re-open the dataset to ensure that the data is written. + */ + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if ((dset_id = H5Dopen2(group_id, DATASET_PARTIAL_CHUNK_READ_ALL_SEL_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to re-open dataset\n"); + goto error; + } + + if (H5Dread(dset_id, DATASET_PARTIAL_CHUNK_READ_ALL_SEL_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, H5P_DEFAULT, + read_buf) < 0) { + H5_FAILED(); + HDprintf(" failed to read from dataset\n"); + goto error; + } + + for (i = 0; i < FIXED_DIMSIZE; i++) + for (j = 0; j < FIXED_DIMSIZE; j++) + if (read_buf[i][j] != (int)((i * FIXED_DIMSIZE) + j)) { + H5_FAILED(); + HDprintf( + " data verification failed for read buffer element %lld: expected %lld but was %lld\n", + (long long)((i * FIXED_DIMSIZE) + j), (long long)((i * FIXED_DIMSIZE) + j), + (long long)read_buf[i][j]); + goto error; + } + + if (H5Pclose(dcpl_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(dcpl_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} +#undef FIXED_DIMSIZE +#undef FIXED_CHUNK_DIMSIZE + +/* + * A test to ensure that a partial chunk can be written and + * then read correctly when the selection used in a chunked + * dataset's file dataspace is a hyperslab selection. + */ +#define FIXED_DIMSIZE 25 +#define FIXED_CHUNK_DIMSIZE 10 +#define FIXED_NCHUNKS 9 /* For convenience - make sure to adjust this as necessary */ +static int +test_read_partial_chunk_hyperslab_selection(void) +{ + DATASET_PARTIAL_CHUNK_READ_HYPER_SEL_TEST_DSET_CTYPE write_buf[FIXED_CHUNK_DIMSIZE][FIXED_CHUNK_DIMSIZE]; + DATASET_PARTIAL_CHUNK_READ_HYPER_SEL_TEST_DSET_CTYPE read_buf[FIXED_CHUNK_DIMSIZE][FIXED_CHUNK_DIMSIZE]; + hsize_t dims[DATASET_PARTIAL_CHUNK_READ_HYPER_SEL_TEST_DSET_SPACE_RANK] = {FIXED_DIMSIZE, FIXED_DIMSIZE}; + hsize_t chunk_dims[DATASET_PARTIAL_CHUNK_READ_HYPER_SEL_TEST_DSET_SPACE_RANK] = {FIXED_CHUNK_DIMSIZE, + FIXED_CHUNK_DIMSIZE}; + hsize_t retrieved_chunk_dims[DATASET_PARTIAL_CHUNK_READ_HYPER_SEL_TEST_DSET_SPACE_RANK]; + size_t i, j, k; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dcpl_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + + TESTING("reading a partial chunk using a hyperslab selection in file dataspace"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GET_PLIST)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, or get property list aren't supported " + "with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_PARTIAL_CHUNK_READ_HYPER_SEL_TEST_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_PARTIAL_CHUNK_READ_HYPER_SEL_TEST_GROUP_NAME); + goto error; + } + + if ((fspace_id = + H5Screate_simple(DATASET_PARTIAL_CHUNK_READ_HYPER_SEL_TEST_DSET_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + + if ((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) + TEST_ERROR; + + if (H5Pset_chunk(dcpl_id, DATASET_PARTIAL_CHUNK_READ_HYPER_SEL_TEST_DSET_SPACE_RANK, chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" failed to set chunking on DCPL\n"); + goto error; + } + + if ((dset_id = H5Dcreate2(group_id, DATASET_PARTIAL_CHUNK_READ_HYPER_SEL_TEST_DSET_NAME, + DATASET_PARTIAL_CHUNK_READ_HYPER_SEL_TEST_DSET_DTYPE, fspace_id, H5P_DEFAULT, + dcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_PARTIAL_CHUNK_READ_HYPER_SEL_TEST_DSET_NAME); + goto error; + } + + /* + * See if a copy of the DCPL reports the correct chunking. + */ + if (H5Pclose(dcpl_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close DCPL\n"); + goto error; + } + + if ((dcpl_id = H5Dget_create_plist(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve copy of DCPL\n"); + goto error; + } + + memset(retrieved_chunk_dims, 0, sizeof(retrieved_chunk_dims)); + if (H5Pget_chunk(dcpl_id, DATASET_PARTIAL_CHUNK_READ_HYPER_SEL_TEST_DSET_SPACE_RANK, + retrieved_chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve chunking info\n"); + goto error; + } + + for (i = 0; i < DATASET_PARTIAL_CHUNK_READ_HYPER_SEL_TEST_DSET_SPACE_RANK; i++) { + if (chunk_dims[i] != retrieved_chunk_dims[i]) { + H5_FAILED(); + HDprintf(" chunk dimensionality retrieved from DCPL didn't match originally specified " + "dimensionality\n"); + goto error; + } + } + + for (i = 0; i < FIXED_CHUNK_DIMSIZE; i++) + for (j = 0; j < FIXED_CHUNK_DIMSIZE; j++) + write_buf[i][j] = + (DATASET_PARTIAL_CHUNK_READ_ALL_SEL_TEST_DSET_CTYPE)((i * FIXED_CHUNK_DIMSIZE) + j); + + for (i = 0; i < FIXED_CHUNK_DIMSIZE; i++) + for (j = 0; j < FIXED_CHUNK_DIMSIZE; j++) + read_buf[i][j] = -1; + + /* + * Create chunk-sized memory dataspace for read buffer. + */ + { + hsize_t mdims[DATASET_PARTIAL_CHUNK_READ_HYPER_SEL_TEST_DSET_SPACE_RANK] = {FIXED_CHUNK_DIMSIZE, + FIXED_CHUNK_DIMSIZE}; + + if ((mspace_id = H5Screate_simple(DATASET_PARTIAL_CHUNK_READ_HYPER_SEL_TEST_DSET_SPACE_RANK, mdims, + NULL)) < 0) { + H5_FAILED(); + HDprintf(" failed to create memory dataspace\n"); + goto error; + } + } + + /* + * Write and read each chunk in the dataset. + */ + for (i = 0; i < FIXED_NCHUNKS; i++) { + hsize_t start[DATASET_PARTIAL_CHUNK_READ_HYPER_SEL_TEST_DSET_SPACE_RANK]; + hsize_t count[DATASET_PARTIAL_CHUNK_READ_HYPER_SEL_TEST_DSET_SPACE_RANK]; + hbool_t on_partial_edge_chunk = FALSE; + size_t n_chunks_per_dim = (dims[1] / chunk_dims[1]) + (((dims[1] % chunk_dims[1]) > 0) ? 1 : 0); + + on_partial_edge_chunk = + (i > 0) && (((i + 1) % n_chunks_per_dim == 0) || (i / n_chunks_per_dim == n_chunks_per_dim - 1)); + + for (j = 0; j < DATASET_PARTIAL_CHUNK_READ_HYPER_SEL_TEST_DSET_SPACE_RANK; j++) { + if (j == 0) + start[j] = (i / n_chunks_per_dim) * chunk_dims[j]; + else + start[j] = (i % n_chunks_per_dim) * chunk_dims[j]; + + if (on_partial_edge_chunk) { + /* + * Partial edge chunk + */ + if (j == 0) { + if (i / n_chunks_per_dim == n_chunks_per_dim - 1) + /* This partial edge chunk spans the remainder of the first dimension */ + count[j] = dims[j] - ((i / n_chunks_per_dim) * chunk_dims[j]); + else + /* This partial edge chunk spans the whole first dimension */ + count[j] = chunk_dims[j]; + } + else { + if (i % n_chunks_per_dim == n_chunks_per_dim - 1) + /* This partial edge chunk spans the remainder of the second dimension */ + count[j] = dims[j] - ((i % n_chunks_per_dim) * chunk_dims[j]); + else + /* This partial edge chunk spans the whole second dimension */ + count[j] = chunk_dims[j]; + } + } + else + count[j] = chunk_dims[j]; + } + + if (on_partial_edge_chunk) { + hsize_t m_start[DATASET_PARTIAL_CHUNK_READ_HYPER_SEL_TEST_DSET_SPACE_RANK] = {0, 0}; + + if (H5Sselect_hyperslab(mspace_id, H5S_SELECT_SET, m_start, NULL, count, NULL) < 0) { + H5_FAILED(); + HDprintf(" failed to select hyperslab in memory dataspace\n"); + goto error; + } + } + else { + if (H5Sselect_all(mspace_id) < 0) { + H5_FAILED(); + HDprintf(" failed to select entire memory dataspace\n"); + goto error; + } + } + + if (H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET, start, NULL, count, NULL) < 0) { + H5_FAILED(); + HDprintf(" failed to select hyperslab\n"); + goto error; + } + + HDprintf("\r Writing chunk %zu", i); + + if (H5Dwrite(dset_id, DATASET_PARTIAL_CHUNK_READ_HYPER_SEL_TEST_DSET_DTYPE, mspace_id, fspace_id, + H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" failed to write to dataset\n"); + goto error; + } + + /* + * Close and re-open the dataset to ensure the data gets written. + */ + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if ((dset_id = H5Dopen2(group_id, DATASET_PARTIAL_CHUNK_READ_HYPER_SEL_TEST_DSET_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" failed to re-open dataset\n"); + goto error; + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve dataspace from dataset\n"); + goto error; + } + + if (H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET, start, NULL, count, NULL) < 0) { + H5_FAILED(); + HDprintf(" failed to select hyperslab\n"); + goto error; + } + + HDprintf("\r Reading chunk %zu", i); + + if (H5Dread(dset_id, DATASET_PARTIAL_CHUNK_READ_HYPER_SEL_TEST_DSET_DTYPE, mspace_id, fspace_id, + H5P_DEFAULT, read_buf) < 0) { + H5_FAILED(); + HDprintf(" failed to read from dataset\n"); + goto error; + } + + for (j = 0; j < FIXED_CHUNK_DIMSIZE; j++) + for (k = 0; k < FIXED_CHUNK_DIMSIZE; k++) + if (read_buf[j][k] != (int)((j * FIXED_CHUNK_DIMSIZE) + k)) { + H5_FAILED(); + HDprintf(" data verification failed for read buffer element %lld: expected %lld but " + "was %lld\n", + (long long)((j * FIXED_CHUNK_DIMSIZE) + k), + (long long)((j * FIXED_CHUNK_DIMSIZE) + k), (long long)read_buf[j][k]); + goto error; + } + } + + if (H5Pclose(dcpl_id) < 0) + TEST_ERROR; + if (H5Sclose(mspace_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(dcpl_id); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} +#undef FIXED_DIMSIZE +#undef FIXED_CHUNK_DIMSIZE +#undef FIXED_NCHUNKS + +/* + * A test to ensure that a partial chunk can be written and + * then read correctly when the selection used in a chunked + * dataset's file dataspace is a point selection. + */ +#define FIXED_DIMSIZE 25 +#define FIXED_CHUNK_DIMSIZE 10 +static int +test_read_partial_chunk_point_selection(void) +{ + TESTING("reading a partial chunk using a point selection in file dataspace"); + SKIPPED(); + + return 1; +} +#undef FIXED_DIMSIZE +#undef FIXED_CHUNK_DIMSIZE + +/* + * A test to verify that H5Dvlen_get_buf_size returns + * correct size + */ +static int +test_get_vlen_buf_size(void) +{ + hvl_t wdata[DATASET_GET_VLEN_BUF_SIZE_DSET_SPACE_DIM]; /* Information to write */ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t dataset = H5I_INVALID_HID; + hid_t dspace_id = H5I_INVALID_HID; + hid_t dtype_id = H5I_INVALID_HID; + hbool_t freed_wdata = FALSE; + hsize_t dims1[] = {DATASET_GET_VLEN_BUF_SIZE_DSET_SPACE_DIM}; + hsize_t size; /* Number of bytes which will be used */ + unsigned i, j; + + TESTING("H5Dvlen_get_buf_size"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, or more aren't supported with this " + "connector\n"); + return 0; + } + + /* Allocate and initialize VL data to write */ + for (i = 0; i < DATASET_GET_VLEN_BUF_SIZE_DSET_SPACE_DIM; i++) { + wdata[i].p = HDmalloc((i + 1) * sizeof(unsigned int)); + wdata[i].len = i + 1; + for (j = 0; j < (i + 1); j++) + ((unsigned int *)wdata[i].p)[j] = i * 10 + j; + } /* end for */ + + /* Open the file */ + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_GET_VLEN_BUF_SIZE_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", DATASET_GET_VLEN_BUF_SIZE_GROUP_NAME); + goto error; + } + + /* Create dataspace for dataset */ + if ((dspace_id = H5Screate_simple(DATASET_GET_VLEN_BUF_SIZE_DSET_SPACE_RANK, dims1, NULL)) < 0) + TEST_ERROR; + + /* Create a datatype to refer to */ + if ((dtype_id = H5Tvlen_create(H5T_NATIVE_UINT)) < 0) + TEST_ERROR; + + /* Create a dataset */ + if ((dataset = H5Dcreate2(group_id, DATASET_GET_VLEN_BUF_SIZE_DSET_NAME, dtype_id, dspace_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR; + + /* Write dataset to disk */ + if (H5Dwrite(dataset, dtype_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata) < 0) + TEST_ERROR; + + /* Make certain the correct amount of memory will be used */ + if (H5Dvlen_get_buf_size(dataset, dtype_id, dspace_id, &size) < 0) + TEST_ERROR; + + /* 10 elements allocated = 1 + 2 + 3 + 4 elements for each array position */ + if (size != + ((DATASET_GET_VLEN_BUF_SIZE_DSET_SPACE_DIM * (DATASET_GET_VLEN_BUF_SIZE_DSET_SPACE_DIM + 1)) / 2) * + sizeof(unsigned int)) { + H5_FAILED(); + HDprintf( + " H5Dvlen_get_buf_size returned wrong size (%lu), compared to the correct size (%lu)\n", size, + ((DATASET_GET_VLEN_BUF_SIZE_DSET_SPACE_DIM * (DATASET_GET_VLEN_BUF_SIZE_DSET_SPACE_DIM + 1)) / + 2) * + sizeof(unsigned int)); + goto error; + } + + if (H5Treclaim(dtype_id, dspace_id, H5P_DEFAULT, wdata) < 0) + TEST_ERROR; + freed_wdata = TRUE; + + if (H5Dclose(dataset) < 0) + TEST_ERROR; + + if (H5Tclose(dtype_id) < 0) + TEST_ERROR; + + if (H5Sclose(dspace_id) < 0) + TEST_ERROR; + + if (H5Gclose(group_id) < 0) + TEST_ERROR; + + if (H5Gclose(container_group) < 0) + TEST_ERROR; + + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (!freed_wdata) + H5Treclaim(dtype_id, dspace_id, H5P_DEFAULT, wdata); + H5Sclose(dspace_id); + H5Tclose(dtype_id); + H5Dclose(dataset); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} /* end test_get_vlen_buf_size() */ + +int +H5_api_dataset_test(void) +{ + size_t i; + int nerrors; + + HDprintf("**********************************************\n"); + HDprintf("* *\n"); + HDprintf("* API Dataset Tests *\n"); + HDprintf("* *\n"); + HDprintf("**********************************************\n\n"); + + for (i = 0, nerrors = 0; i < ARRAY_LENGTH(dataset_tests); i++) { + nerrors += (*dataset_tests[i])() ? 1 : 0; + } + + HDprintf("\n"); + + return nerrors; +} diff --git a/test/API/H5_api_dataset_test.h b/test/API/H5_api_dataset_test.h new file mode 100644 index 0000000..5a50a06 --- /dev/null +++ b/test/API/H5_api_dataset_test.h @@ -0,0 +1,331 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef H5_API_DATASET_TEST_H +#define H5_API_DATASET_TEST_H + +#include "H5_api_test.h" + +int H5_api_dataset_test(void); + +/************************************************ + * * + * API Dataset test defines * + * * + ************************************************/ + +#define DATASET_CREATE_UNDER_ROOT_DSET_NAME "/dset_under_root" +#define DATASET_CREATE_UNDER_ROOT_SPACE_RANK 2 + +#define DATASET_CREATE_UNDER_EXISTING_SPACE_RANK 2 +#define DATASET_CREATE_UNDER_EXISTING_GROUP_NAME "dset_under_group_test" +#define DATASET_CREATE_UNDER_EXISTING_DSET_NAME "nested_dset" + +#define DATASET_CREATE_INVALID_PARAMS_SPACE_RANK 2 +#define DATASET_CREATE_INVALID_PARAMS_GROUP_NAME "dset_create_invalid_params_test" +#define DATASET_CREATE_INVALID_PARAMS_DSET_NAME "invalid_params_dset" + +#define DATASET_CREATE_ANONYMOUS_DATASET_NAME "anon_dset" +#define DATASET_CREATE_ANONYMOUS_GROUP_NAME "anon_dset_creation_test" +#define DATASET_CREATE_ANONYMOUS_SPACE_RANK 2 + +#define DATASET_CREATE_ANONYMOUS_INVALID_PARAMS_DATASET_NAME "invalid_params_anon_dset" +#define DATASET_CREATE_ANONYMOUS_INVALID_PARAMS_GROUP_NAME "anon_dset_creation_invalid_params_test" +#define DATASET_CREATE_ANONYMOUS_INVALID_PARAMS_SPACE_RANK 2 + +#define DATASET_CREATE_NULL_DATASPACE_TEST_SUBGROUP_NAME "dataset_with_null_space_test" +#define DATASET_CREATE_NULL_DATASPACE_TEST_DSET_NAME "dataset_with_null_space" + +#define DATASET_CREATE_SCALAR_DATASPACE_TEST_SUBGROUP_NAME "dataset_with_scalar_space_test" +#define DATASET_CREATE_SCALAR_DATASPACE_TEST_DSET_NAME "dataset_with_scalar_space" + +#define ZERO_DIM_DSET_TEST_GROUP_NAME "zero_dim_dset_test" +#define ZERO_DIM_DSET_TEST_SPACE_RANK 1 +#define ZERO_DIM_DSET_TEST_DSET_NAME "zero_dim_dset" + +#define DATASET_MANY_CREATE_GROUP_NAME "group_for_many_datasets" +#define DSET_NAME_BUF_SIZE 64u +#define DATASET_NUMB 100u + +#define DATASET_SHAPE_TEST_DSET_BASE_NAME "dataset_shape_test" +#define DATASET_SHAPE_TEST_SUBGROUP_NAME "dataset_shape_test" +#define DATASET_SHAPE_TEST_NUM_ITERATIONS 5 +#define DATASET_SHAPE_TEST_MAX_DIMS 5 + +#define DATASET_PREDEFINED_TYPE_TEST_SPACE_RANK 2 +#define DATASET_PREDEFINED_TYPE_TEST_BASE_NAME "predefined_type_dset" +#define DATASET_PREDEFINED_TYPE_TEST_SUBGROUP_NAME "predefined_type_dataset_test" + +#define DATASET_STRING_TYPE_TEST_STRING_LENGTH 40 +#define DATASET_STRING_TYPE_TEST_SPACE_RANK 2 +#define DATASET_STRING_TYPE_TEST_DSET_NAME1 "fixed_length_string_dset" +#define DATASET_STRING_TYPE_TEST_DSET_NAME2 "variable_length_string_dset" +#define DATASET_STRING_TYPE_TEST_SUBGROUP_NAME "string_type_dataset_test" + +#define DATASET_COMPOUND_TYPE_TEST_SUBGROUP_NAME "compound_type_dataset_test" +#define DATASET_COMPOUND_TYPE_TEST_DSET_NAME "compound_type_test" +#define DATASET_COMPOUND_TYPE_TEST_MAX_SUBTYPES 5 +#define DATASET_COMPOUND_TYPE_TEST_MAX_PASSES 5 +#define DATASET_COMPOUND_TYPE_TEST_DSET_RANK 2 + +#define DATASET_ENUM_TYPE_TEST_VAL_BASE_NAME "INDEX" +#define DATASET_ENUM_TYPE_TEST_SUBGROUP_NAME "enum_type_dataset_test" +#define DATASET_ENUM_TYPE_TEST_NUM_MEMBERS 16 +#define DATASET_ENUM_TYPE_TEST_SPACE_RANK 2 +#define DATASET_ENUM_TYPE_TEST_DSET_NAME1 "enum_native_dset" +#define DATASET_ENUM_TYPE_TEST_DSET_NAME2 "enum_non_native_dset" + +#define DATASET_ARRAY_TYPE_TEST_SUBGROUP_NAME "array_type_dataset_test" +#define DATASET_ARRAY_TYPE_TEST_DSET_NAME1 "array_type_test1" +#define DATASET_ARRAY_TYPE_TEST_DSET_NAME2 "array_type_test2" +#define DATASET_ARRAY_TYPE_TEST_DSET_NAME3 "array_type_test3" +#define DATASET_ARRAY_TYPE_TEST_SPACE_RANK 2 +#define DATASET_ARRAY_TYPE_TEST_RANK1 2 +#define DATASET_ARRAY_TYPE_TEST_RANK2 2 +#define DATASET_ARRAY_TYPE_TEST_RANK3 2 + +#define DATASET_CREATION_PROPERTIES_TEST_TRACK_TIMES_YES_DSET_NAME "track_times_true_test" +#define DATASET_CREATION_PROPERTIES_TEST_TRACK_TIMES_NO_DSET_NAME "track_times_false_test" +#define DATASET_CREATION_PROPERTIES_TEST_PHASE_CHANGE_DSET_NAME "attr_phase_change_test" +#define DATASET_CREATION_PROPERTIES_TEST_ALLOC_TIMES_BASE_NAME "alloc_time_test" +#define DATASET_CREATION_PROPERTIES_TEST_FILL_TIMES_BASE_NAME "fill_times_test" +#define DATASET_CREATION_PROPERTIES_TEST_CRT_ORDER_BASE_NAME "creation_order_test" +#define DATASET_CREATION_PROPERTIES_TEST_LAYOUTS_BASE_NAME "layout_test" +#define DATASET_CREATION_PROPERTIES_TEST_FILTERS_DSET_NAME "filters_test" +#define DATASET_CREATION_PROPERTIES_TEST_GROUP_NAME "creation_properties_test" +#define DATASET_CREATION_PROPERTIES_TEST_CHUNK_DIM_RANK DATASET_CREATION_PROPERTIES_TEST_SHAPE_RANK +#define DATASET_CREATION_PROPERTIES_TEST_MAX_COMPACT 12 +#define DATASET_CREATION_PROPERTIES_TEST_MIN_DENSE 8 +#define DATASET_CREATION_PROPERTIES_TEST_SHAPE_RANK 3 + +#define DATASET_OPEN_INVALID_PARAMS_SPACE_RANK 2 +#define DATASET_OPEN_INVALID_PARAMS_GROUP_NAME "dataset_open_test" +#define DATASET_OPEN_INVALID_PARAMS_DSET_NAME "open_test_dataset" + +#define DATASET_GET_SPACE_TYPE_TEST_SPACE_RANK 2 +#define DATASET_GET_SPACE_TYPE_TEST_GROUP_NAME "get_dset_space_type_test" +#define DATASET_GET_SPACE_TYPE_TEST_DSET_NAME "get_space_type_test_dset" + +#define DATASET_GET_SPACE_TYPE_INVALID_PARAMS_TEST_SPACE_RANK 2 +#define DATASET_GET_SPACE_TYPE_INVALID_PARAMS_TEST_GROUP_NAME "get_dset_space_type_invalid_params_test" +#define DATASET_GET_SPACE_TYPE_INVALID_PARAMS_TEST_DSET_NAME "get_space_type_test_invalid_params_dset" + +#define DATASET_PROPERTY_LIST_TEST_SUBGROUP_NAME "dataset_property_list_test_group" +#define DATASET_PROPERTY_LIST_TEST_SPACE_RANK 2 +#define DATASET_PROPERTY_LIST_TEST_DSET_NAME1 "property_list_test_dataset1" +#define DATASET_PROPERTY_LIST_TEST_DSET_NAME2 "property_list_test_dataset2" +#define DATASET_PROPERTY_LIST_TEST_DSET_NAME3 "property_list_test_dataset3" +#define DATASET_PROPERTY_LIST_TEST_DSET_NAME4 "property_list_test_dataset4" + +#define DATASET_SMALL_READ_TEST_ALL_DSET_SPACE_RANK 3 +#define DATASET_SMALL_READ_TEST_ALL_DSET_DTYPESIZE sizeof(int) +#define DATASET_SMALL_READ_TEST_ALL_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_SMALL_READ_TEST_ALL_GROUP_NAME "dataset_small_read_all_test" +#define DATASET_SMALL_READ_TEST_ALL_DSET_NAME "dataset_small_read_all_dset" + +#define DATASET_SMALL_READ_TEST_HYPERSLAB_DSET_SPACE_RANK 3 +#define DATASET_SMALL_READ_TEST_HYPERSLAB_DSET_DTYPESIZE sizeof(int) +#define DATASET_SMALL_READ_TEST_HYPERSLAB_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_SMALL_READ_TEST_HYPERSLAB_GROUP_NAME "dataset_small_read_hyperslab_test" +#define DATASET_SMALL_READ_TEST_HYPERSLAB_DSET_NAME "dataset_small_read_hyperslab_dset" + +#define DATASET_SMALL_READ_TEST_POINT_SELECTION_DSET_SPACE_RANK 3 +#define DATASET_SMALL_READ_TEST_POINT_SELECTION_DSET_DTYPESIZE sizeof(int) +#define DATASET_SMALL_READ_TEST_POINT_SELECTION_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_SMALL_READ_TEST_POINT_SELECTION_NUM_POINTS 10 +#define DATASET_SMALL_READ_TEST_POINT_SELECTION_GROUP_NAME "dataset_small_read_point_selection_test" +#define DATASET_SMALL_READ_TEST_POINT_SELECTION_DSET_NAME "dataset_small_read_point_selection_dset" + +#define DATASET_IO_POINT_GROUP_NAME "dataset_io_point_selection_test" +#define DATASET_IO_POINT_DSET_NAME_NOCHUNK "dataset_io_point_selection_dset_nochunk" +#define DATASET_IO_POINT_DSET_NAME_CHUNK "dataset_io_point_selection_dset_chunk" + +#ifndef NO_LARGE_TESTS +#define DATASET_LARGE_READ_TEST_ALL_DSET_SPACE_RANK 3 +#define DATASET_LARGE_READ_TEST_ALL_DSET_DTYPESIZE sizeof(int) +#define DATASET_LARGE_READ_TEST_ALL_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_LARGE_READ_TEST_ALL_GROUP_NAME "dataset_large_read_all_test" +#define DATASET_LARGE_READ_TEST_ALL_DSET_NAME "dataset_large_read_all_dset" + +#define DATASET_LARGE_READ_TEST_HYPERSLAB_DSET_SPACE_RANK 3 +#define DATASET_LARGE_READ_TEST_HYPERSLAB_DSET_DTYPESIZE sizeof(int) +#define DATASET_LARGE_READ_TEST_HYPERSLAB_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_LARGE_READ_TEST_HYPERSLAB_GROUP_NAME "dataset_large_read_hyperslab_test" +#define DATASET_LARGE_READ_TEST_HYPERSLAB_DSET_NAME "dataset_large_read_hyperslab_dset" + +#define DATASET_LARGE_READ_TEST_POINT_SELECTION_DSET_SPACE_RANK 1 +#define DATASET_LARGE_READ_TEST_POINT_SELECTION_DSET_DTYPESIZE sizeof(int) +#define DATASET_LARGE_READ_TEST_POINT_SELECTION_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_LARGE_READ_TEST_POINT_SELECTION_GROUP_NAME "dataset_large_read_point_selection_test" +#define DATASET_LARGE_READ_TEST_POINT_SELECTION_DSET_NAME "dataset_large_read_point_selection_dset" +#endif + +#define DATASET_READ_INVALID_PARAMS_TEST_DSET_SPACE_RANK 3 +#define DATASET_READ_INVALID_PARAMS_TEST_DSET_DTYPESIZE sizeof(int) +#define DATASET_READ_INVALID_PARAMS_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_READ_INVALID_PARAMS_TEST_GROUP_NAME "dataset_read_invalid_params_test" +#define DATASET_READ_INVALID_PARAMS_TEST_DSET_NAME "dataset_read_invalid_params_dset" + +#define DATASET_SMALL_WRITE_TEST_ALL_DSET_SPACE_RANK 3 +#define DATASET_SMALL_WRITE_TEST_ALL_DSET_DTYPESIZE sizeof(int) +#define DATASET_SMALL_WRITE_TEST_ALL_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_SMALL_WRITE_TEST_ALL_GROUP_NAME "dataset_small_write_all_test" +#define DATASET_SMALL_WRITE_TEST_ALL_DSET_NAME "dataset_small_write_all_dset" + +#define DATASET_SMALL_WRITE_TEST_HYPERSLAB_DSET_SPACE_RANK 3 +#define DATASET_SMALL_WRITE_TEST_HYPERSLAB_DSET_DTYPESIZE sizeof(int) +#define DATASET_SMALL_WRITE_TEST_HYPERSLAB_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_SMALL_WRITE_TEST_HYPERSLAB_GROUP_NAME "dataset_small_write_hyperslab_test" +#define DATASET_SMALL_WRITE_TEST_HYPERSLAB_DSET_NAME "dataset_small_write_hyperslab_dset" + +#define DATASET_SMALL_WRITE_TEST_POINT_SELECTION_DSET_SPACE_RANK 3 +#define DATASET_SMALL_WRITE_TEST_POINT_SELECTION_DSET_DTYPESIZE sizeof(int) +#define DATASET_SMALL_WRITE_TEST_POINT_SELECTION_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_SMALL_WRITE_TEST_POINT_SELECTION_NUM_POINTS 10 +#define DATASET_SMALL_WRITE_TEST_POINT_SELECTION_GROUP_NAME "dataset_small_write_point_selection_test" +#define DATASET_SMALL_WRITE_TEST_POINT_SELECTION_DSET_NAME "dataset_small_write_point_selection_dset" + +#ifndef NO_LARGE_TESTS +#define DATASET_LARGE_WRITE_TEST_ALL_DSET_SPACE_RANK 3 +#define DATASET_LARGE_WRITE_TEST_ALL_DSET_DTYPESIZE sizeof(int) +#define DATASET_LARGE_WRITE_TEST_ALL_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_LARGE_WRITE_TEST_ALL_GROUP_NAME "dataset_large_write_all_test" +#define DATASET_LARGE_WRITE_TEST_ALL_DSET_NAME "dataset_large_write_all_dset" + +#define DATASET_LARGE_WRITE_TEST_HYPERSLAB_DSET_SPACE_RANK 3 +#define DATASET_LARGE_WRITE_TEST_HYPERSLAB_DSET_DTYPESIZE sizeof(int) +#define DATASET_LARGE_WRITE_TEST_HYPERSLAB_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_LARGE_WRITE_TEST_HYPERSLAB_GROUP_NAME "dataset_large_write_hyperslab_test" +#define DATASET_LARGE_WRITE_TEST_HYPERSLAB_DSET_NAME "dataset_large_write_hyperslab_dset" + +#define DATASET_LARGE_WRITE_TEST_POINT_SELECTION_DSET_SPACE_RANK 3 +#define DATASET_LARGE_WRITE_TEST_POINT_SELECTION_DSET_DTYPESIZE sizeof(int) +#define DATASET_LARGE_WRITE_TEST_POINT_SELECTION_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_LARGE_WRITE_TEST_POINT_SELECTION_GROUP_NAME "dataset_large_write_point_selection_test" +#define DATASET_LARGE_WRITE_TEST_POINT_SELECTION_DSET_NAME "dataset_large_write_point_selection_dset" +#endif + +#define DATASET_DATA_VERIFY_WRITE_TEST_DSET_SPACE_RANK 3 +#define DATASET_DATA_VERIFY_WRITE_TEST_DSET_DTYPESIZE sizeof(int) +#define DATASET_DATA_VERIFY_WRITE_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_DATA_VERIFY_WRITE_TEST_NUM_POINTS 10 +#define DATASET_DATA_VERIFY_WRITE_TEST_GROUP_NAME "dataset_data_write_verification_test" +#define DATASET_DATA_VERIFY_WRITE_TEST_DSET_NAME "dataset_data_write_verification_dset" + +#define DATASET_WRITE_INVALID_PARAMS_TEST_DSET_SPACE_RANK 3 +#define DATASET_WRITE_INVALID_PARAMS_TEST_DSET_DTYPESIZE sizeof(int) +#define DATASET_WRITE_INVALID_PARAMS_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_WRITE_INVALID_PARAMS_TEST_GROUP_NAME "dataset_write_invalid_params_test" +#define DATASET_WRITE_INVALID_PARAMS_TEST_DSET_NAME "dataset_write_invalid_params_dset" + +#define DATASET_DATA_BUILTIN_CONVERSION_TEST_DSET_SPACE_RANK 3 +#define DATASET_DATA_BUILTIN_CONVERSION_TEST_MEM_DTYPESIZE sizeof(int) +#define DATASET_DATA_BUILTIN_CONVERSION_TEST_MEM_DTYPE H5T_NATIVE_INT +#define DATASET_DATA_BUILTIN_CONVERSION_TEST_NUM_POINTS 10 +#define DATASET_DATA_BUILTIN_CONVERSION_TEST_GROUP_NAME "dataset_builtin_conversion_verification_test" +#define DATASET_DATA_BUILTIN_CONVERSION_TEST_DSET_NAME "dataset_builtin_conversion_verification_dset" + +#define DATASET_COMPOUND_PARTIAL_IO_DSET_DIMS 10 +#define DATASET_DATA_COMPOUND_PARTIAL_IO_TEST_GROUP_NAME "dataset_compound_partial_io_test" +#define DATASET_DATA_COMPOUND_PARTIAL_IO_TEST_DSET_NAME "dataset_compound_partial_io_test" + +#define DATASET_SET_EXTENT_CHUNKED_UNLIMITED_TEST_SPACE_RANK 2 +#define DATASET_SET_EXTENT_CHUNKED_UNLIMITED_TEST_NUM_PASSES 3 +#define DATASET_SET_EXTENT_CHUNKED_UNLIMITED_TEST_GROUP_NAME "set_extent_chunked_unlimited_test" +#define DATASET_SET_EXTENT_CHUNKED_UNLIMITED_TEST_DSET_NAME "set_extent_chunked_unlimited_test_dset" + +#define DATASET_SET_EXTENT_CHUNKED_FIXED_TEST_SPACE_RANK 2 +#define DATASET_SET_EXTENT_CHUNKED_FIXED_TEST_NUM_PASSES 3 +#define DATASET_SET_EXTENT_CHUNKED_FIXED_TEST_GROUP_NAME "set_extent_chunked_fixed_test" +#define DATASET_SET_EXTENT_CHUNKED_FIXED_TEST_DSET_NAME "set_extent_chunked_fixed_test_dset" +#define DATASET_SET_EXTENT_CHUNKED_FIXED_TEST_DSET_NAME2 "set_extent_chunked_fixed_test_dset2" + +#define DATASET_SET_EXTENT_DATA_TEST_SPACE_RANK 2 +#define DATASET_SET_EXTENT_DATA_TEST_GROUP_NAME "set_extent_chunked_data_test" +#define DATASET_SET_EXTENT_DATA_TEST_DSET_NAME "set_extent_chunked_data_test_dset" +#define DATASET_SET_EXTENT_DATA_TEST_SPACE_DIM 8 + +#define DATASET_SET_EXTENT_DOUBLE_HANDLES_TEST_SPACE_RANK 2 +#define DATASET_SET_EXTENT_DOUBLE_HANDLES_TEST_GROUP_NAME "set_extent_chunked_double_handles_test" +#define DATASET_SET_EXTENT_DOUBLE_HANDLES_TEST_DSET_NAME "set_extent_chunked_double_handles_test_dset" +#define DATASET_SET_EXTENT_DOUBLE_HANDLES_TEST_SPACE_DIM 8 + +#define DATASET_SET_EXTENT_INVALID_PARAMS_TEST_SPACE_RANK 2 +#define DATASET_SET_EXTENT_INVALID_PARAMS_TEST_GROUP_NAME "set_extent_invalid_params_test" +#define DATASET_SET_EXTENT_INVALID_PARAMS_TEST_DSET_NAME "set_extent_invalid_params_test_dset" +#define DATASET_SET_EXTENT_INVALID_LAYOUT_TEST_COMPACT_DSET_NAME "set_extent_invalid_layout_test_compact_dset" +#define DATASET_SET_EXTENT_INVALID_LAYOUT_TEST_CONTIGUOUS_DSET_NAME \ + "set_extent_invalid_layout_test_contiguous_dset" + +#define DATASET_SINGLE_CHUNK_TEST_SPACE_RANK 2 +#define DATASET_SINGLE_CHUNK_TEST_GROUP_NAME "single_chunk_dataset_test" +#define DATASET_SINGLE_CHUNK_TEST_DSET_NAME "single_chunk_dataset" + +#define DATASET_SINGLE_CHUNK_WRITE_TEST_DSET_SPACE_RANK 2 +#define DATASET_SINGLE_CHUNK_WRITE_TEST_DSET_DTYPESIZE sizeof(int) +#define DATASET_SINGLE_CHUNK_WRITE_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_SINGLE_CHUNK_WRITE_TEST_GROUP_NAME "single_chunk_dataset_write_test" +#define DATASET_SINGLE_CHUNK_WRITE_TEST_DSET_NAME "single_chunk_dataset" + +#define DATASET_MULTI_CHUNK_TEST_SPACE_RANK 2 +#define DATASET_MULTI_CHUNK_TEST_GROUP_NAME "multi_chunk_dataset_test" +#define DATASET_MULTI_CHUNK_TEST_DSET_NAME "multi_chunk_dataset" + +#define DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK 2 +#define DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_DTYPESIZE sizeof(int) +#define DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_GROUP_NAME \ + "multi_chunk_dataset_write_same_space_read_test" +#define DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_NAME "multi_chunk_dataset" + +#define DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK 2 +#define DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_DTYPESIZE sizeof(int) +#define DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_GROUP_NAME \ + "multi_chunk_dataset_write_diff_space_read_test" +#define DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_NAME "multi_chunk_dataset" + +#define DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK 2 +#define DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_DTYPESIZE sizeof(int) +#define DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_GROUP_NAME \ + "multi_chunk_dataset_same_space_overwrite_test" +#define DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_NAME "multi_chunk_dataset" +#define DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_NITERS 10 + +#define DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK 2 +#define DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_DTYPESIZE sizeof(int) +#define DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_GROUP_NAME \ + "multi_chunk_dataset_diff_space_overwrite_test" +#define DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_NAME "multi_chunk_dataset" +#define DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_NITERS 10 + +#define DATASET_PARTIAL_CHUNK_READ_ALL_SEL_TEST_DSET_SPACE_RANK 2 +#define DATASET_PARTIAL_CHUNK_READ_ALL_SEL_TEST_DSET_DTYPESIZE sizeof(int) +#define DATASET_PARTIAL_CHUNK_READ_ALL_SEL_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_PARTIAL_CHUNK_READ_ALL_SEL_TEST_DSET_CTYPE int +#define DATASET_PARTIAL_CHUNK_READ_ALL_SEL_TEST_GROUP_NAME "read_partial_chunk_all_sel_test" +#define DATASET_PARTIAL_CHUNK_READ_ALL_SEL_TEST_DSET_NAME "read_partial_chunk_all_sel_dset" + +#define DATASET_PARTIAL_CHUNK_READ_HYPER_SEL_TEST_DSET_SPACE_RANK 2 +#define DATASET_PARTIAL_CHUNK_READ_HYPER_SEL_TEST_DSET_DTYPESIZE sizeof(int) +#define DATASET_PARTIAL_CHUNK_READ_HYPER_SEL_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_PARTIAL_CHUNK_READ_HYPER_SEL_TEST_DSET_CTYPE int +#define DATASET_PARTIAL_CHUNK_READ_HYPER_SEL_TEST_GROUP_NAME "read_partial_chunk_hyper_sel_test" +#define DATASET_PARTIAL_CHUNK_READ_HYPER_SEL_TEST_DSET_NAME "read_partial_chunk_hyper_sel_dset" + +#define DATASET_GET_VLEN_BUF_SIZE_DSET_SPACE_RANK 1 +#define DATASET_GET_VLEN_BUF_SIZE_DSET_SPACE_DIM 4 +#define DATASET_GET_VLEN_BUF_SIZE_GROUP_NAME "get_vlen_buffer_size_group" +#define DATASET_GET_VLEN_BUF_SIZE_DSET_NAME "get_vlen_buffer_size_dset" +#endif diff --git a/test/API/H5_api_datatype_test.c b/test/API/H5_api_datatype_test.c new file mode 100644 index 0000000..9d53292 --- /dev/null +++ b/test/API/H5_api_datatype_test.c @@ -0,0 +1,2693 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "H5_api_datatype_test.h" + +/* + * Disable tests that currently compromise internal HDF5 integrity. + */ +#define PROBLEMATIC_TESTS + +static int test_create_committed_datatype(void); +static int test_create_committed_datatype_invalid_params(void); +static int test_create_anonymous_committed_datatype(void); +static int test_create_anonymous_committed_datatype_invalid_params(void); +#ifndef PROBLEMATIC_TESTS +static int test_create_committed_datatype_empty_types(void); +#endif +static int test_recommit_committed_type(void); +static int test_open_committed_datatype(void); +static int test_open_committed_datatype_invalid_params(void); +static int test_reopen_committed_datatype_indirect(void); +static int test_close_committed_datatype_invalid_id(void); +static int test_datatype_property_lists(void); +static int test_create_dataset_with_committed_type(void); +static int test_create_attribute_with_committed_type(void); +static int test_delete_committed_type(void); +static int test_resurrect_datatype(void); +static int test_flush_committed_datatype(void); +static int test_flush_committed_datatype_invalid_params(void); +static int test_refresh_committed_datatype(void); +static int test_refresh_committed_datatype_invalid_params(void); +#ifndef PROBLEMATIC_TESTS +static int test_cant_commit_predefined(void); +#endif +static int test_cant_modify_committed_type(void); + +/* + * The array of datatype tests to be performed. + */ +static int (*datatype_tests[])(void) = { + test_create_committed_datatype, + test_create_committed_datatype_invalid_params, + test_create_anonymous_committed_datatype, + test_create_anonymous_committed_datatype_invalid_params, +#ifndef PROBLEMATIC_TESTS + test_create_committed_datatype_empty_types, +#endif + test_recommit_committed_type, + test_open_committed_datatype, + test_open_committed_datatype_invalid_params, + test_reopen_committed_datatype_indirect, + test_close_committed_datatype_invalid_id, + test_datatype_property_lists, + test_create_dataset_with_committed_type, + test_create_attribute_with_committed_type, + test_delete_committed_type, + test_resurrect_datatype, + test_flush_committed_datatype, + test_flush_committed_datatype_invalid_params, + test_refresh_committed_datatype, + test_refresh_committed_datatype_invalid_params, +#ifndef PROBLEMATIC_TESTS + test_cant_commit_predefined, +#endif + test_cant_modify_committed_type, +}; + +/* + * A test to check that a committed datatype can be created. + */ +static int +test_create_committed_datatype(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t type_id = H5I_INVALID_HID; + + TESTING("creation of a committed datatype"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, or stored datatype aren't supported with this " + "connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATATYPE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATATYPE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATATYPE_CREATE_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", DATATYPE_CREATE_TEST_GROUP_NAME); + goto error; + } + + if ((type_id = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create datatype to commit\n"); + goto error; + } + + if (H5Tcommit2(group_id, DATATYPE_CREATE_TEST_TYPE_NAME, type_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT) < + 0) { + H5_FAILED(); + HDprintf(" couldn't commit datatype '%s'\n", DATATYPE_CREATE_TEST_TYPE_NAME); + goto error; + } + + if (H5Tclose(type_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Tclose(type_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a committed datatype can't be + * created when H5Tcommit2 is passed invalid parameters. + */ +static int +test_create_committed_datatype_invalid_params(void) +{ + herr_t err_ret = -1; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t type_id = H5I_INVALID_HID; + + TESTING_MULTIPART("H5Tcommit2 with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, or stored datatype aren't supported with this " + "connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATATYPE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATATYPE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATATYPE_CREATE_INVALID_PARAMS_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATATYPE_CREATE_INVALID_PARAMS_TEST_GROUP_NAME); + goto error; + } + + if ((type_id = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create datatype to commit\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Tcommit2_invalid_loc_id) + { + TESTING_2("H5Tcommit2 with an invalid loc_id"); + + H5E_BEGIN_TRY + { + err_ret = H5Tcommit2(H5I_INVALID_HID, DATATYPE_CREATE_INVALID_PARAMS_TEST_TYPE_NAME, type_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Tcommit2 succeeded with an invalid loc_id!\n"); + PART_ERROR(H5Tcommit2_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Tcommit2_invalid_loc_id); + + PART_BEGIN(H5Tcommit2_invalid_type_name) + { + TESTING_2("H5Tcommit2 with an invalid datatype name"); + + H5E_BEGIN_TRY + { + err_ret = H5Tcommit2(group_id, NULL, type_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Tcommit2 succeeded with an invalid datatype name!\n"); + PART_ERROR(H5Tcommit2_invalid_type_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Tcommit2(group_id, "", type_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Tcommit2 succeeded with an invalid datatype name!\n"); + PART_ERROR(H5Tcommit2_invalid_type_name); + } + + PASSED(); + } + PART_END(H5Tcommit2_invalid_type_name); + + PART_BEGIN(H5Tcommit2_invalid_type_id) + { + TESTING_2("H5Tcommit2 with an invalid datatype ID"); + + H5E_BEGIN_TRY + { + err_ret = H5Tcommit2(group_id, DATATYPE_CREATE_INVALID_PARAMS_TEST_TYPE_NAME, H5I_INVALID_HID, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Tcommit2 succeeded with an invalid datatype ID!\n"); + PART_ERROR(H5Tcommit2_invalid_type_id); + } + + PASSED(); + } + PART_END(H5Tcommit2_invalid_type_id); + + PART_BEGIN(H5Tcommit2_invalid_lcpl) + { + TESTING_2("H5Tcommit2 with an invalid LCPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Tcommit2(group_id, DATATYPE_CREATE_INVALID_PARAMS_TEST_TYPE_NAME, type_id, + H5I_INVALID_HID, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Tcommit2 succeeded with an invalid LCPL!\n"); + PART_ERROR(H5Tcommit2_invalid_lcpl); + } + + PASSED(); + } + PART_END(H5Tcommit2_invalid_lcpl); + + PART_BEGIN(H5Tcommit2_invalid_tcpl) + { + TESTING_2("H5Tcommit2 with an invalid TCPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Tcommit2(group_id, DATATYPE_CREATE_INVALID_PARAMS_TEST_TYPE_NAME, type_id, + H5P_DEFAULT, H5I_INVALID_HID, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Tcommit2 succeeded with an invalid TCPL!\n"); + PART_ERROR(H5Tcommit2_invalid_tcpl); + } + + PASSED(); + } + PART_END(H5Tcommit2_invalid_tcpl); + + PART_BEGIN(H5Tcommit2_invalid_tapl) + { + TESTING_2("H5Tcommit2 with an invalid TAPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Tcommit2(group_id, DATATYPE_CREATE_INVALID_PARAMS_TEST_TYPE_NAME, type_id, + H5P_DEFAULT, H5P_DEFAULT, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Tcommit2 succeeded with an invalid TAPL!\n"); + PART_ERROR(H5Tcommit2_invalid_tapl); + } + + PASSED(); + } + PART_END(H5Tcommit2_invalid_tapl); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Tclose(type_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Tclose(type_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that an anonymous committed datatype + * can be created with H5Tcommit_anon. + */ +static int +test_create_anonymous_committed_datatype(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t type_id = H5I_INVALID_HID; + + TESTING("creation of anonymous committed datatype"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, or stored datatype aren't supported with this " + "connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATATYPE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATATYPE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATATYPE_CREATE_ANONYMOUS_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", DATATYPE_CREATE_ANONYMOUS_GROUP_NAME); + goto error; + } + + if ((type_id = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create datatype\n"); + goto error; + } + + if (H5Tcommit_anon(group_id, type_id, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't commit anonymous datatype\n"); + goto error; + } + + if (H5Tclose(type_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Tclose(type_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a committed datatype can't be + * created when H5Tcommit_anon is passed invalid parameters. + */ +static int +test_create_anonymous_committed_datatype_invalid_params(void) +{ + herr_t err_ret = -1; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t type_id = H5I_INVALID_HID; + + TESTING_MULTIPART("H5Tcommit_anon with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, or stored datatype aren't supported with this " + "connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATATYPE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATATYPE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATATYPE_CREATE_ANONYMOUS_INVALID_PARAMS_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATATYPE_CREATE_ANONYMOUS_INVALID_PARAMS_GROUP_NAME); + goto error; + } + + if ((type_id = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create datatype\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Tcommit_anon_invalid_loc_id) + { + TESTING_2("H5Tcommit_anon with an invalid loc_id"); + + H5E_BEGIN_TRY + { + err_ret = H5Tcommit_anon(H5I_INVALID_HID, type_id, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Tcommit_anon succeeded with an invalid loc_id!\n"); + PART_ERROR(H5Tcommit_anon_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Tcommit_anon_invalid_loc_id); + + PART_BEGIN(H5Tcommit_anon_invalid_type_id) + { + TESTING_2("H5Tcommit_anon with an invalid datatype ID"); + + H5E_BEGIN_TRY + { + err_ret = H5Tcommit_anon(group_id, H5I_INVALID_HID, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Tcommit_anon succeeded with an invalid datatype ID!\n"); + PART_ERROR(H5Tcommit_anon_invalid_type_id); + } + + PASSED(); + } + PART_END(H5Tcommit_anon_invalid_type_id); + + PART_BEGIN(H5Tcommit_anon_invalid_tcpl) + { + TESTING_2("H5Tcommit_anon with an invalid TCPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Tcommit_anon(group_id, type_id, H5I_INVALID_HID, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Tcommit_anon succeeded with an invalid TCPL!\n"); + PART_ERROR(H5Tcommit_anon_invalid_tcpl); + } + + PASSED(); + } + PART_END(H5Tcommit_anon_invalid_tcpl); + + PART_BEGIN(H5Tcommit_anon_invalid_tapl) + { + TESTING_2("H5Tcommit_anon with an invalid TAPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Tcommit_anon(group_id, type_id, H5P_DEFAULT, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Tcommit_anon succeeded with an invalid TAPL!\n"); + PART_ERROR(H5Tcommit_anon_invalid_tapl); + } + + PASSED(); + } + PART_END(H5Tcommit_anon_invalid_tapl); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Tclose(type_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Tclose(type_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that committing a datatype fails with empty + * compound and enum datatypes. + */ +#ifndef PROBLEMATIC_TESTS +static int +test_create_committed_datatype_empty_types(void) +{ + herr_t err_ret = FAIL; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t type_id = H5I_INVALID_HID; + + TESTING_MULTIPART("creation of committed datatype with empty types"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, or stored datatype aren't supported with this " + "connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATATYPE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATATYPE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATATYPE_CREATE_EMPTY_TYPES_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATATYPE_CREATE_EMPTY_TYPES_TEST_GROUP_NAME); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Tcommit_empty_compound_type) + { + TESTING_2("creation of committed datatype with empty compound type"); + + if ((type_id = H5Tcreate(H5T_COMPOUND, (size_t)32)) < 0) { + H5_FAILED(); + HDprintf(" failed to create compound type\n"); + PART_ERROR(H5Tcommit_empty_compound_type); + } + + H5E_BEGIN_TRY + { + err_ret = H5Tcommit2(group_id, DATATYPE_CREATE_EMPTY_TYPES_TEST_CMPD_TYPE_NAME, type_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" committed empty compound datatype!\n"); + PART_ERROR(H5Tcommit_empty_compound_type); + } + + /* Add a field to the compound datatype */ + if (H5Tinsert(type_id, "a", (size_t)0, H5T_NATIVE_INT) < 0) { + H5_FAILED(); + HDprintf(" failed to insert field into compound datatype\n"); + PART_ERROR(H5Tcommit_empty_compound_type); + } + + /* Attempt to commit the now non-empty compound datatype */ + if (H5Tcommit2(group_id, DATATYPE_CREATE_EMPTY_TYPES_TEST_CMPD_TYPE_NAME, type_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to commit non-empty compound datatype\n"); + PART_ERROR(H5Tcommit_empty_compound_type); + } + + PASSED(); + } + PART_END(H5Tcommit_empty_compound_type); + + if (type_id >= 0) { + H5E_BEGIN_TRY + { + H5Tclose(type_id); + } + H5E_END_TRY; + type_id = H5I_INVALID_HID; + } + + PART_BEGIN(H5Tcommit_empty_enum_type) + { + int enum_val = 1; + + TESTING_2("creation of committed datatype with empty enum type"); + + if ((type_id = H5Tenum_create(H5T_NATIVE_INT)) < 0) { + H5_FAILED(); + HDprintf(" failed to create enum type\n"); + PART_ERROR(H5Tcommit_empty_enum_type); + } + + H5E_BEGIN_TRY + { + err_ret = H5Tcommit2(group_id, DATATYPE_CREATE_EMPTY_TYPES_TEST_ENUM_TYPE_NAME, type_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" committed empty enum datatype!\n"); + PART_ERROR(H5Tcommit_empty_enum_type); + } + + /* Add a field to the enum datatype */ + if (H5Tenum_insert(type_id, "a", &enum_val) < 0) { + H5_FAILED(); + HDprintf(" failed to insert field into enum datatype\n"); + PART_ERROR(H5Tcommit_empty_enum_type); + } + + /* Attempt to commit the now non-empty enum datatype */ + if (H5Tcommit2(group_id, DATATYPE_CREATE_EMPTY_TYPES_TEST_ENUM_TYPE_NAME, type_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to commit non-empty enum datatype\n"); + PART_ERROR(H5Tcommit_empty_enum_type); + } + + PASSED(); + } + PART_END(H5Tcommit_empty_enum_type); + + if (type_id >= 0) { + H5E_BEGIN_TRY + { + H5Tclose(type_id); + } + H5E_END_TRY; + type_id = H5I_INVALID_HID; + } + } + END_MULTIPART; + + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + +error: + H5E_BEGIN_TRY + { + H5Tclose(type_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} +#endif + +/* + * A test to check that a committed datatype can't be re-committed. + */ +static int +test_recommit_committed_type(void) +{ + htri_t is_committed = FALSE; + herr_t err_ret; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t type_id = H5I_INVALID_HID; + + TESTING("inability to re-commit a committed datatype"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, or stored datatype aren't supported with this " + "connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATATYPE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATATYPE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, RECOMMIT_COMMITTED_TYPE_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", RECOMMIT_COMMITTED_TYPE_TEST_GROUP_NAME); + goto error; + } + + /* Copy a predefined datatype and commit the copy */ + if ((type_id = H5Tcopy(H5T_NATIVE_INT)) < 0) { + H5_FAILED(); + HDprintf(" failed to copy predefined integer datatype\n"); + goto error; + } + + if (H5Tcommit2(group_id, "native_int", type_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to commit datatype\n"); + goto error; + } + + if ((is_committed = H5Tcommitted(type_id)) < 0) { + H5_FAILED(); + HDprintf(" failed to determine if datatype is committed\n"); + goto error; + } + + if (!is_committed) { + H5_FAILED(); + HDprintf(" H5Tcommitted() returned false!\n"); + goto error; + } + + /* We should not be able to re-commit a committed type */ + H5E_BEGIN_TRY + { + err_ret = H5Tcommit2(group_id, "native_int", type_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" re-committed an already committed datatype!\n"); + goto error; + } + + if (H5Tclose(type_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Tclose(type_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a committed datatype + * can be opened using H5Topen2. + */ +static int +test_open_committed_datatype(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t type_id = H5I_INVALID_HID; + + TESTING("H5Topen2"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, or stored datatype aren't supported with this " + "connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATATYPE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATATYPE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATATYPE_OPEN_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", DATATYPE_OPEN_TEST_GROUP_NAME); + goto error; + } + + if ((type_id = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create datatype to commit\n"); + goto error; + } + + if (H5Tcommit2(group_id, DATATYPE_OPEN_TEST_TYPE_NAME, type_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT) < + 0) { + H5_FAILED(); + HDprintf(" couldn't commit datatype '%s'\n", DATATYPE_OPEN_TEST_TYPE_NAME); + goto error; + } + + if (H5Tclose(type_id) < 0) + TEST_ERROR; + + if ((type_id = H5Topen2(group_id, DATATYPE_OPEN_TEST_TYPE_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open committed datatype '%s'\n", DATATYPE_OPEN_TEST_TYPE_NAME); + goto error; + } + + if (H5Tclose(type_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Tclose(type_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a committed datatype can't + * be opened when H5Topen2 is passed invalid parameters. + */ +static int +test_open_committed_datatype_invalid_params(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t type_id = H5I_INVALID_HID; + + TESTING_MULTIPART("H5Topen2 with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, or stored datatype aren't supported with this " + "connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATATYPE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATATYPE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATATYPE_OPEN_INVALID_PARAMS_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATATYPE_OPEN_INVALID_PARAMS_TEST_GROUP_NAME); + goto error; + } + + if ((type_id = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create datatype to commit\n"); + goto error; + } + + if (H5Tcommit2(group_id, DATATYPE_OPEN_INVALID_PARAMS_TEST_TYPE_NAME, type_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't commit datatype '%s'\n", DATATYPE_OPEN_INVALID_PARAMS_TEST_TYPE_NAME); + goto error; + } + + if (H5Tclose(type_id) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Topen2_invalid_loc_id) + { + TESTING_2("H5Topen2 with an invalid location ID"); + + H5E_BEGIN_TRY + { + type_id = H5Topen2(H5I_INVALID_HID, DATATYPE_OPEN_INVALID_PARAMS_TEST_TYPE_NAME, H5P_DEFAULT); + } + H5E_END_TRY; + + if (type_id >= 0) { + H5_FAILED(); + HDprintf(" opened committed datatype with an invalid location ID!\n"); + H5Tclose(type_id); + PART_ERROR(H5Topen2_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Topen2_invalid_loc_id); + + PART_BEGIN(H5Topen2_invalid_type_name) + { + TESTING_2("H5Topen2 with an invalid datatype name"); + + H5E_BEGIN_TRY + { + type_id = H5Topen2(group_id, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (type_id >= 0) { + H5_FAILED(); + HDprintf(" opened committed datatype with an invalid datatype name!\n"); + H5Tclose(type_id); + PART_ERROR(H5Topen2_invalid_type_name); + } + + H5E_BEGIN_TRY + { + type_id = H5Topen2(group_id, "", H5P_DEFAULT); + } + H5E_END_TRY; + + if (type_id >= 0) { + H5_FAILED(); + HDprintf(" opened committed datatype with an invalid datatype name!\n"); + H5Tclose(type_id); + PART_ERROR(H5Topen2_invalid_type_name); + } + + PASSED(); + } + PART_END(H5Topen2_invalid_type_name); + + PART_BEGIN(H5Topen2_invalid_tapl) + { + TESTING_2("H5Topen2 with an invalid TAPL"); + + H5E_BEGIN_TRY + { + type_id = H5Topen2(group_id, DATATYPE_OPEN_INVALID_PARAMS_TEST_TYPE_NAME, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (type_id >= 0) { + H5_FAILED(); + HDprintf(" opened committed datatype with an invalid TAPL!\n"); + H5Tclose(type_id); + PART_ERROR(H5Topen2_invalid_tapl); + } + + PASSED(); + } + PART_END(H5Topen2_invalid_tapl); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Tclose(type_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that open named datatypes can be reopened indirectly + * through H5Dget_type without causing problems. + */ +static int +test_reopen_committed_datatype_indirect(void) +{ + size_t dt_size = 0; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t type_id = H5I_INVALID_HID, reopened_type_id = H5I_INVALID_HID; + hid_t strtype = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + + TESTING_MULTIPART("reopening open committed datatypes using H5Dget_type"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, or stored datatype aren't supported with " + "this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATATYPE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATATYPE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATATYPE_REOPEN_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", DATATYPE_REOPEN_TEST_GROUP_NAME); + goto error; + } + + if ((space_id = generate_random_dataspace(DATATYPE_REOPEN_TEST_SPACE_RANK, NULL, NULL, FALSE)) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(reopen_compound_type) + { + TESTING_2("re-open of compound datatype"); + + if ((strtype = H5Tcopy(H5T_C_S1)) < 0) { + H5_FAILED(); + HDprintf(" failed to copy C-string datatype\n"); + PART_ERROR(reopen_compound_type); + } + + if (H5Tset_size(strtype, H5T_VARIABLE) < 0) { + H5_FAILED(); + HDprintf(" failed to set string datatype's size to variable\n"); + PART_ERROR(reopen_compound_type); + } + + if ((type_id = H5Tcreate(H5T_COMPOUND, sizeof(char *))) < 0) { + H5_FAILED(); + HDprintf(" failed to create compound datatype\n"); + PART_ERROR(reopen_compound_type); + } + + if (H5Tinsert(type_id, "vlstr", (size_t)0, strtype) < 0) { + H5_FAILED(); + HDprintf(" failed to insert field into compound datatype\n"); + PART_ERROR(reopen_compound_type); + } + + if (H5Tclose(strtype) < 0) { + H5_FAILED(); + HDprintf(" failed to close string datatype\n"); + PART_ERROR(reopen_compound_type); + } + + /* Get size of compound type */ + if ((dt_size = H5Tget_size(type_id)) == 0) { + H5_FAILED(); + HDprintf(" failed to retrieve size of compound datatype\n"); + PART_ERROR(reopen_compound_type); + } + + /* Commit compound type and verify the size doesn't change */ + if (H5Tcommit2(group_id, "cmpd_type", type_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to commit compound datatype\n"); + PART_ERROR(reopen_compound_type); + } + + if (dt_size != H5Tget_size(type_id)) { + H5_FAILED(); + HDprintf(" committing datatype caused its size to change!\n"); + PART_ERROR(reopen_compound_type); + } + + /* Create dataset with compound type */ + if ((dset_id = H5Dcreate2(group_id, "cmpd_dset", type_id, space_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to create dataset using committed datatype\n"); + PART_ERROR(reopen_compound_type); + } + + /* Indirectly reopen type and verify that the size doesn't change */ + if ((reopened_type_id = H5Dget_type(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" failed to re-open committed datatype using H5Dget_type\n"); + PART_ERROR(reopen_compound_type); + } + + if (dt_size != H5Tget_size(reopened_type_id)) { + H5_FAILED(); + HDprintf(" size of re-opened datatype didn't match size of original datatype\n"); + PART_ERROR(reopen_compound_type); + } + + PASSED(); + } + PART_END(reopen_compound_type); + + H5E_BEGIN_TRY + { + H5Tclose(strtype); + strtype = H5I_INVALID_HID; + H5Tclose(type_id); + type_id = H5I_INVALID_HID; + H5Tclose(reopened_type_id); + reopened_type_id = H5I_INVALID_HID; + H5Dclose(dset_id); + dset_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(reopen_enum_type) + { + int enum_value; + + TESTING_2("re-open of enum datatype"); + + if ((type_id = H5Tenum_create(H5T_NATIVE_INT)) < 0) { + H5_FAILED(); + HDprintf(" failed to create enum datatype\n"); + PART_ERROR(reopen_enum_type); + } + + enum_value = 0; + if (H5Tenum_insert(type_id, "val1", &enum_value) < 0) { + H5_FAILED(); + HDprintf(" failed to insert value into enum datatype\n"); + PART_ERROR(reopen_enum_type); + } + + enum_value = 1; + if (H5Tenum_insert(type_id, "val2", &enum_value) < 0) { + H5_FAILED(); + HDprintf(" failed to insert value into enum datatype\n"); + PART_ERROR(reopen_enum_type); + } + + /* Get size of enum type */ + if ((dt_size = H5Tget_size(type_id)) == 0) { + H5_FAILED(); + HDprintf(" failed to retrieve size of enum datatype\n"); + PART_ERROR(reopen_enum_type); + } + + /* Commit enum type and verify the size doesn't change */ + if (H5Tcommit2(group_id, "enum_type", type_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to commit enum datatype\n"); + PART_ERROR(reopen_enum_type); + } + + if (dt_size != H5Tget_size(type_id)) { + H5_FAILED(); + HDprintf(" committing datatype caused its size to change!\n"); + PART_ERROR(reopen_enum_type); + } + + /* Create dataset with enum type */ + if ((dset_id = H5Dcreate2(group_id, "enum_dset", type_id, space_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to create dataset using committed datatype\n"); + PART_ERROR(reopen_enum_type); + } + + /* Indirectly reopen type and verify that the size doesn't change */ + if ((reopened_type_id = H5Dget_type(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" failed to re-open committed datatype using H5Dget_type\n"); + PART_ERROR(reopen_enum_type); + } + + if (dt_size != H5Tget_size(reopened_type_id)) { + H5_FAILED(); + HDprintf(" size of re-opened datatype didn't match size of original datatype\n"); + PART_ERROR(reopen_enum_type); + } + + PASSED(); + } + PART_END(reopen_enum_type); + + H5E_BEGIN_TRY + { + H5Tclose(type_id); + type_id = H5I_INVALID_HID; + H5Tclose(reopened_type_id); + reopened_type_id = H5I_INVALID_HID; + H5Dclose(dset_id); + dset_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(reopen_vlen_type) + { + TESTING_2("reopen of a variable-length datatype"); + + if ((type_id = H5Tvlen_create(H5T_NATIVE_INT)) < 0) { + H5_FAILED(); + HDprintf(" failed to create variable-length datatype\n"); + PART_ERROR(reopen_vlen_type); + } + + /* Get size of variable-length type */ + if ((dt_size = H5Tget_size(type_id)) == 0) { + H5_FAILED(); + HDprintf(" failed to retrieve size of variable-length datatype\n"); + PART_ERROR(reopen_vlen_type); + } + + /* Commit variable-length type and verify the size doesn't change */ + if (H5Tcommit2(group_id, "vlen_type", type_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to commit variable-length datatype\n"); + PART_ERROR(reopen_vlen_type); + } + + if (dt_size != H5Tget_size(type_id)) { + H5_FAILED(); + HDprintf(" committing datatype caused its size to change!\n"); + PART_ERROR(reopen_vlen_type); + } + + /* Create dataset with variable-length type */ + if ((dset_id = H5Dcreate2(group_id, "vlen_dset", type_id, space_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to create dataset using committed datatype\n"); + PART_ERROR(reopen_vlen_type); + } + + /* Indirectly reopen type and verify that the size doesn't change */ + if ((reopened_type_id = H5Dget_type(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" failed to re-open committed datatype using H5Dget_type\n"); + PART_ERROR(reopen_vlen_type); + } + + if (dt_size != H5Tget_size(reopened_type_id)) { + H5_FAILED(); + HDprintf(" size of re-opened datatype didn't match size of original datatype\n"); + PART_ERROR(reopen_vlen_type); + } + + PASSED(); + } + PART_END(reopen_vlen_type); + + H5E_BEGIN_TRY + { + H5Tclose(type_id); + type_id = H5I_INVALID_HID; + H5Tclose(reopened_type_id); + reopened_type_id = H5I_INVALID_HID; + H5Dclose(dset_id); + dset_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(reopen_opaque_type) + { + const char *tag = "opaque_tag"; + + TESTING_2("reopen of an opaque datatype"); + + if ((type_id = H5Tcreate(H5T_OPAQUE, (size_t)13)) < 0) { + H5_FAILED(); + HDprintf(" failed to create opaque datatype\n"); + PART_ERROR(reopen_opaque_type); + } + + if (H5Tset_tag(type_id, tag) < 0) { + H5_FAILED(); + HDprintf(" failed to set tag on opaque datatype\n"); + PART_ERROR(reopen_opaque_type); + } + + /* Get size of opaque type */ + if ((dt_size = H5Tget_size(type_id)) == 0) { + H5_FAILED(); + HDprintf(" failed to retrieve size of opaque datatype\n"); + PART_ERROR(reopen_opaque_type); + } + + /* Commit opaque type and verify the size doesn't change */ + if (H5Tcommit2(group_id, "opaque_type", type_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to commit opaque datatype\n"); + PART_ERROR(reopen_opaque_type); + } + + if (dt_size != H5Tget_size(type_id)) { + H5_FAILED(); + HDprintf(" committing datatype caused its size to change!\n"); + PART_ERROR(reopen_opaque_type); + } + + /* Create dataset with opaque type */ + if ((dset_id = H5Dcreate2(group_id, "opaque_dset", type_id, space_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to create dataset using committed datatype\n"); + PART_ERROR(reopen_opaque_type); + } + + /* Indirectly reopen type and verify that the size doesn't change */ + if ((reopened_type_id = H5Dget_type(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" failed to re-open committed datatype using H5Dget_type\n"); + PART_ERROR(reopen_opaque_type); + } + + if (dt_size != H5Tget_size(reopened_type_id)) { + H5_FAILED(); + HDprintf(" size of re-opened datatype didn't match size of original datatype\n"); + PART_ERROR(reopen_opaque_type); + } + + PASSED(); + } + PART_END(reopen_opaque_type); + + H5E_BEGIN_TRY + { + H5Tclose(type_id); + type_id = H5I_INVALID_HID; + H5Tclose(reopened_type_id); + reopened_type_id = H5I_INVALID_HID; + H5Dclose(dset_id); + dset_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(reopen_array_type) + { + hsize_t array_dims[] = {2, 3}; + + TESTING_2("reopen of an array datatype"); + + if ((type_id = H5Tarray_create2(H5T_NATIVE_INT, 1, array_dims)) < 0) { + H5_FAILED(); + HDprintf(" failed to create array datatype\n"); + PART_ERROR(reopen_array_type); + } + + /* Get size of array type */ + if ((dt_size = H5Tget_size(type_id)) == 0) { + H5_FAILED(); + HDprintf(" failed to retrieve size of array datatype\n"); + PART_ERROR(reopen_array_type); + } + + /* Commit array type and verify the size doesn't change */ + if (H5Tcommit2(group_id, "array_type", type_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to commit array datatype\n"); + PART_ERROR(reopen_array_type); + } + + if (dt_size != H5Tget_size(type_id)) { + H5_FAILED(); + HDprintf(" committing datatype caused its size to change!\n"); + PART_ERROR(reopen_array_type); + } + + /* Create dataset with array type */ + if ((dset_id = H5Dcreate2(group_id, "array_dset", type_id, space_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to create dataset using committed datatype\n"); + PART_ERROR(reopen_array_type); + } + + /* Indirectly reopen type and verify that the size doesn't change */ + if ((reopened_type_id = H5Dget_type(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" failed to re-open committed datatype using H5Dget_type\n"); + PART_ERROR(reopen_array_type); + } + + if (dt_size != H5Tget_size(reopened_type_id)) { + H5_FAILED(); + HDprintf(" size of re-opened datatype didn't match size of original datatype\n"); + PART_ERROR(reopen_array_type); + } + + PASSED(); + } + PART_END(reopen_array_type); + + H5E_BEGIN_TRY + { + H5Tclose(type_id); + type_id = H5I_INVALID_HID; + H5Tclose(reopened_type_id); + reopened_type_id = H5I_INVALID_HID; + H5Dclose(dset_id); + dset_id = H5I_INVALID_HID; + } + H5E_END_TRY; + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(space_id); + H5Tclose(strtype); + H5Tclose(type_id); + H5Tclose(reopened_type_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that H5Tclose fails when + * it is passed an invalid datatype ID. + */ +static int +test_close_committed_datatype_invalid_id(void) +{ + herr_t err_ret = -1; + hid_t file_id = H5I_INVALID_HID; + + TESTING("H5Tclose with an invalid committed datatype ID"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES)) { + SKIPPED(); + HDprintf( + " API functions for basic file or stored datatype aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + H5E_BEGIN_TRY + { + err_ret = H5Tclose(H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Tclose succeeded with an invalid committed datatype ID!\n"); + goto error; + } + + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a TCPL used for datatype creation + * can be persisted and that a valid copy of that TCPL can + * be retrieved later with a call to H5Tget_create_plist. + */ +static int +test_datatype_property_lists(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t type_id1 = H5I_INVALID_HID, type_id2 = H5I_INVALID_HID; + hid_t tcpl_id1 = H5I_INVALID_HID, tcpl_id2 = H5I_INVALID_HID; + + TESTING_MULTIPART("datatype property list operations"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GET_PLIST)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, stored datatype, or getting property list aren't " + "supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATATYPE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATATYPE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATATYPE_PROPERTY_LIST_TEST_SUBGROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", DATATYPE_PROPERTY_LIST_TEST_SUBGROUP_NAME); + goto error; + } + + if ((type_id1 = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create datatype\n"); + goto error; + } + + if ((type_id2 = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create datatype\n"); + goto error; + } + + if ((tcpl_id1 = H5Pcreate(H5P_DATATYPE_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create TCPL\n"); + goto error; + } + + /* Currently no TCPL routines are defined */ + + if (H5Tcommit2(group_id, DATATYPE_PROPERTY_LIST_TEST_DATATYPE_NAME1, type_id1, H5P_DEFAULT, tcpl_id1, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't commit datatype '%s'\n", DATATYPE_PROPERTY_LIST_TEST_DATATYPE_NAME1); + goto error; + } + + if (H5Tcommit2(group_id, DATATYPE_PROPERTY_LIST_TEST_DATATYPE_NAME2, type_id2, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't commit datatype '%s'\n", DATATYPE_PROPERTY_LIST_TEST_DATATYPE_NAME2); + goto error; + } + + if (H5Pclose(tcpl_id1) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Tget_create_plist) + { + TESTING_2("H5Tget_create_plist"); + + /* Try to receive copies for the two property lists */ + if ((tcpl_id1 = H5Tget_create_plist(type_id1)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get property list\n"); + PART_ERROR(H5Tget_create_plist); + } + + if ((tcpl_id2 = H5Tget_create_plist(type_id2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get property list\n"); + PART_ERROR(H5Tget_create_plist); + } + + PASSED(); + } + PART_END(H5Tget_create_plist); + + /* Now close the property lists and datatypes and see if we can still retrieve copies of + * the property lists upon opening (instead of creating) a datatype + */ + if (tcpl_id1 >= 0) { + H5E_BEGIN_TRY + { + H5Pclose(tcpl_id1); + } + H5E_END_TRY; + tcpl_id1 = H5I_INVALID_HID; + } + if (tcpl_id2 >= 0) { + H5E_BEGIN_TRY + { + H5Pclose(tcpl_id2); + } + H5E_END_TRY; + tcpl_id2 = H5I_INVALID_HID; + } + if (type_id1 >= 0) { + H5E_BEGIN_TRY + { + H5Tclose(type_id1); + } + H5E_END_TRY; + type_id1 = H5I_INVALID_HID; + } + if (type_id2 >= 0) { + H5E_BEGIN_TRY + { + H5Tclose(type_id2); + } + H5E_END_TRY; + type_id2 = H5I_INVALID_HID; + } + + PART_BEGIN(H5Tget_create_plist_reopened) + { + TESTING_2("H5Tget_create_plist after re-opening committed datatype"); + + if ((type_id1 = H5Topen2(group_id, DATATYPE_PROPERTY_LIST_TEST_DATATYPE_NAME1, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't open datatype '%s'\n", DATATYPE_PROPERTY_LIST_TEST_DATATYPE_NAME1); + PART_ERROR(H5Tget_create_plist_reopened); + } + + if ((type_id2 = H5Topen2(group_id, DATATYPE_PROPERTY_LIST_TEST_DATATYPE_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't open datatype '%s'\n", DATATYPE_PROPERTY_LIST_TEST_DATATYPE_NAME2); + PART_ERROR(H5Tget_create_plist_reopened); + } + + if ((tcpl_id1 = H5Tget_create_plist(type_id1)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get property list\n"); + PART_ERROR(H5Tget_create_plist_reopened); + } + + if ((tcpl_id2 = H5Tget_create_plist(type_id2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get property list\n"); + PART_ERROR(H5Tget_create_plist_reopened); + } + + PASSED(); + } + PART_END(H5Tget_create_plist_reopened); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Pclose(tcpl_id1) < 0) + TEST_ERROR; + if (H5Pclose(tcpl_id2) < 0) + TEST_ERROR; + if (H5Tclose(type_id1) < 0) + TEST_ERROR; + if (H5Tclose(type_id2) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(tcpl_id1); + H5Pclose(tcpl_id2); + H5Tclose(type_id1); + H5Tclose(type_id2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a dataset can be created using + * a committed datatype. + */ +static int +test_create_dataset_with_committed_type(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t type_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + + TESTING("dataset creation with a committed datatype"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, or stored datatype aren't supported with " + "this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATATYPE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATATYPE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_CREATE_WITH_DATATYPE_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", DATASET_CREATE_WITH_DATATYPE_TEST_GROUP_NAME); + goto error; + } + + if ((type_id = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create datatype\n"); + goto error; + } + + if (H5Tcommit2(group_id, DATASET_CREATE_WITH_DATATYPE_TEST_TYPE_NAME, type_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't commit datatype '%s'\n", DATASET_CREATE_WITH_DATATYPE_TEST_TYPE_NAME); + goto error; + } + + if (H5Tclose(type_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATATYPE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATATYPE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gopen2(container_group, DATASET_CREATE_WITH_DATATYPE_TEST_GROUP_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_CREATE_WITH_DATATYPE_TEST_GROUP_NAME); + goto error; + } + + if ((type_id = H5Topen2(group_id, DATASET_CREATE_WITH_DATATYPE_TEST_TYPE_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open committed datatype '%s'\n", DATASET_CREATE_WITH_DATATYPE_TEST_TYPE_NAME); + goto error; + } + + if ((fspace_id = generate_random_dataspace(DATATYPE_CREATE_TEST_DATASET_DIMS, NULL, NULL, FALSE)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_CREATE_WITH_DATATYPE_TEST_DSET_NAME, type_id, fspace_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s' using committed datatype\n", + DATASET_CREATE_WITH_DATATYPE_TEST_DSET_NAME); + goto error; + } + + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + + if ((dset_id = H5Dopen2(group_id, DATASET_CREATE_WITH_DATATYPE_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to open dataset '%s'\n", DATASET_CREATE_WITH_DATATYPE_TEST_DSET_NAME); + goto error; + } + + if (H5Tclose(type_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Tclose(type_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that an attribute can be created + * using a committed datatype. + */ +static int +test_create_attribute_with_committed_type(void) +{ + htri_t attr_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t type_id = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + + TESTING("attribute creation with a committed datatype"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, attribute, or stored datatype aren't supported " + "with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATATYPE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATATYPE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, ATTRIBUTE_CREATE_WITH_DATATYPE_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", + ATTRIBUTE_CREATE_WITH_DATATYPE_TEST_GROUP_NAME); + goto error; + } + + if ((type_id = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create datatype\n"); + goto error; + } + + if (H5Tcommit2(group_id, ATTRIBUTE_CREATE_WITH_DATATYPE_TEST_DTYPE_NAME, type_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't commit datatype '%s'\n", ATTRIBUTE_CREATE_WITH_DATATYPE_TEST_DTYPE_NAME); + goto error; + } + + if (H5Tclose(type_id) < 0) + TEST_ERROR; + + if ((type_id = H5Topen2(group_id, ATTRIBUTE_CREATE_WITH_DATATYPE_TEST_DTYPE_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open committed datatype '%s'\n", + ATTRIBUTE_CREATE_WITH_DATATYPE_TEST_DTYPE_NAME); + goto error; + } + + if ((space_id = + generate_random_dataspace(ATTRIBUTE_CREATE_WITH_DATATYPE_TEST_SPACE_RANK, NULL, NULL, TRUE)) < 0) + TEST_ERROR; + + if ((attr_id = H5Acreate2(group_id, ATTRIBUTE_CREATE_WITH_DATATYPE_TEST_ATTR_NAME, type_id, space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s'\n", ATTRIBUTE_CREATE_WITH_DATATYPE_TEST_ATTR_NAME); + goto error; + } + + /* Verify the attribute has been created */ + if ((attr_exists = H5Aexists(group_id, ATTRIBUTE_CREATE_WITH_DATATYPE_TEST_ATTR_NAME)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if attribute '%s' exists\n", + ATTRIBUTE_CREATE_WITH_DATATYPE_TEST_ATTR_NAME); + goto error; + } + + if (!attr_exists) { + H5_FAILED(); + HDprintf(" attribute did not exist\n"); + goto error; + } + + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + + if ((attr_id = H5Aopen(group_id, ATTRIBUTE_CREATE_WITH_DATATYPE_TEST_ATTR_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open attribute '%s'\n", ATTRIBUTE_CREATE_WITH_DATATYPE_TEST_ATTR_NAME); + goto error; + } + + if (H5Tclose(type_id) < 0) + TEST_ERROR; + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Tclose(type_id); + H5Sclose(space_id); + H5Aclose(attr_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a committed datatype can + * be deleted. + */ +static int +test_delete_committed_type(void) +{ + htri_t type_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t type_id = H5I_INVALID_HID; + + TESTING("committed datatype deletion"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, attribute, or stored datatype aren't supported " + "with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATATYPE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATATYPE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATATYPE_DELETE_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group '%s'\n", DATATYPE_DELETE_TEST_GROUP_NAME); + goto error; + } + + if ((type_id = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create datatype\n"); + goto error; + } + + if (H5Tcommit2(group_id, DATATYPE_DELETE_TEST_DTYPE_NAME, type_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't commit datatype '%s'\n", DATATYPE_DELETE_TEST_DTYPE_NAME); + goto error; + } + + if ((type_exists = H5Lexists(group_id, DATATYPE_DELETE_TEST_DTYPE_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if datatype '%s' exists\n", DATATYPE_DELETE_TEST_DTYPE_NAME); + goto error; + } + + if (!type_exists) { + H5_FAILED(); + HDprintf(" datatype didn't exist\n"); + goto error; + } + + if (H5Ldelete(group_id, DATATYPE_DELETE_TEST_DTYPE_NAME, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete datatype '%s'\n", DATATYPE_DELETE_TEST_DTYPE_NAME); + goto error; + } + + if ((type_exists = H5Lexists(group_id, DATATYPE_DELETE_TEST_DTYPE_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if datatype '%s' exists\n", DATATYPE_DELETE_TEST_DTYPE_NAME); + goto error; + } + + if (type_exists) { + H5_FAILED(); + HDprintf(" datatype exists\n"); + goto error; + } + + if (H5Tclose(type_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Tclose(type_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a committed datatype can still be opened when + * the link to the datatype is deleted and then a new one is created. + */ +static int +test_resurrect_datatype(void) +{ +#ifndef NO_ID_PREVENTS_OBJ_DELETE + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t type_id = H5I_INVALID_HID; +#endif /* NO_ID_PREVENTS_OBJ_DELETE */ + + TESTING("resurrecting datatype after deletion"); + +#ifndef NO_ID_PREVENTS_OBJ_DELETE + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_HARD_LINKS)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, link, hard link, or stored datatype aren't " + "supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATATYPE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATATYPE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATATYPE_RESURRECT_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", DATATYPE_RESURRECT_TEST_GROUP_NAME); + goto error; + } + + /* Create a named datatype in the file */ + if ((type_id = H5Tcopy(H5T_NATIVE_INT)) < 0) { + H5_FAILED(); + HDprintf(" failed to copy predefined integer type\n"); + goto error; + } + + if (H5Tcommit2(group_id, DATATYPE_RESURRECT_TEST_DTYPE_NAME, type_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to commit datatype\n"); + goto error; + } + + /* Unlink the datatype while it's open (will mark it for deletion when closed) */ + if (H5Ldelete(group_id, DATATYPE_RESURRECT_TEST_DTYPE_NAME, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to delete datatype\n"); + goto error; + } +#ifndef NO_OBJECT_GET_NAME + /* Check that datatype name is NULL */ + if (H5Iget_name(type_id, NULL, (size_t)0) != 0) { + H5_FAILED(); + HDprintf(" deleted datatype name was not NULL!\n"); + goto error; + } +#endif + + /* Re-link the datatype to the group hierarchy (shouldn't get deleted now) */ + if (H5Lcreate_hard(type_id, ".", group_id, DATATYPE_RESURRECT_TEST_DTYPE_NAME2, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create new link for deleted datatype\n"); + goto error; + } + + /* Close things */ + if (H5Tclose(type_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + /* Re-open the file */ + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATATYPE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATATYPE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gopen2(container_group, DATATYPE_RESURRECT_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container sub-group '%s'\n", DATATYPE_RESURRECT_TEST_GROUP_NAME); + goto error; + } + + /* Attempt to open the datatype under the new name */ + if ((type_id = H5Topen2(group_id, DATATYPE_RESURRECT_TEST_DTYPE_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to open resurrected datatype\n"); + goto error; + } + + if (H5Tclose(type_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); +#else /* NO_ID_PREVENTS_OBJ_DELETE */ + SKIPPED(); +#endif /* NO_ID_PREVENTS_OBJ_DELETE */ + + return 0; + +#ifndef NO_ID_PREVENTS_OBJ_DELETE +error: + H5E_BEGIN_TRY + { + H5Tclose(type_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +#endif /* NO_ID_PREVENTS_OBJ_DELETE */ +} + +static int +test_flush_committed_datatype(void) +{ + TESTING("H5Tflush"); + + SKIPPED(); + + return 0; +} + +static int +test_flush_committed_datatype_invalid_params(void) +{ + TESTING("H5Tflush with invalid parameters"); + + SKIPPED(); + + return 0; +} + +static int +test_refresh_committed_datatype(void) +{ + TESTING("H5Trefresh"); + + SKIPPED(); + + return 0; +} + +static int +test_refresh_committed_datatype_invalid_params(void) +{ + TESTING("H5Trefresh with invalid parameters"); + + SKIPPED(); + + return 0; +} + +/* + * A test to check that predefined HDF5 datatypes can't be directly committed. + * An application should first copy the type with H5Tcopy and then commit the + * copied datatype. + */ +#ifndef PROBLEMATIC_TESTS +static int +test_cant_commit_predefined(void) +{ + herr_t err_ret; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + + TESTING("inability to commit predefined types directly"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, or stored datatype aren't supported with this " + "connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATATYPE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATATYPE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, PREDEFINED_TYPE_COMMIT_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", PREDEFINED_TYPE_COMMIT_TEST_GROUP_NAME); + goto error; + } + + H5E_BEGIN_TRY + { + err_ret = H5Tcommit2(group_id, "committed_predefined_type", H5T_NATIVE_INT, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" committed a predefined datatype directly (without copying it)!\n"); + goto error; + } + + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} +#endif + +/* + * A test to check that a datatype cannot be modified once it has been committed. + */ +static int +test_cant_modify_committed_type(void) +{ + htri_t is_committed = FALSE; + herr_t err_ret; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t type_id = H5I_INVALID_HID; + + TESTING("inability to modify a committed datatype"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, or stored datatype aren't supported with this " + "connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATATYPE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATATYPE_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, MODIFY_COMMITTED_TYPE_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", MODIFY_COMMITTED_TYPE_TEST_GROUP_NAME); + goto error; + } + + /* Copy a predefined datatype and commit the copy */ + if ((type_id = H5Tcopy(H5T_NATIVE_INT)) < 0) { + H5_FAILED(); + HDprintf(" failed to copy predefined integer datatype\n"); + goto error; + } + + if (H5Tcommit2(group_id, "native_int", type_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to commit datatype\n"); + goto error; + } + + if ((is_committed = H5Tcommitted(type_id)) < 0) { + H5_FAILED(); + HDprintf(" failed to determine if datatype is committed\n"); + goto error; + } + + if (!is_committed) { + H5_FAILED(); + HDprintf(" H5Tcommitted() returned false!\n"); + goto error; + } + + /* We should not be able to modify a type after it has been committed. */ + H5E_BEGIN_TRY + { + err_ret = H5Tset_precision(type_id, (size_t)256); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" modified committed datatype!\n"); + goto error; + } + + if (H5Tclose(type_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Tclose(type_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +int +H5_api_datatype_test(void) +{ + size_t i; + int nerrors; + + HDprintf("**********************************************\n"); + HDprintf("* *\n"); + HDprintf("* API Datatype Tests *\n"); + HDprintf("* *\n"); + HDprintf("**********************************************\n\n"); + + for (i = 0, nerrors = 0; i < ARRAY_LENGTH(datatype_tests); i++) { + nerrors += (*datatype_tests[i])() ? 1 : 0; + } + + HDprintf("\n"); + + return nerrors; +} diff --git a/test/API/H5_api_datatype_test.h b/test/API/H5_api_datatype_test.h new file mode 100644 index 0000000..753f9b2 --- /dev/null +++ b/test/API/H5_api_datatype_test.h @@ -0,0 +1,79 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef H5_API_DATATYPE_TEST_H +#define H5_API_DATATYPE_TEST_H + +#include "H5_api_test.h" + +int H5_api_datatype_test(void); + +/************************************************* + * * + * API Datatype test defines * + * * + *************************************************/ + +#define DATATYPE_CREATE_TEST_DATASET_DIMS 2 +#define DATATYPE_CREATE_TEST_GROUP_NAME "committed_datatype_creation_test" +#define DATATYPE_CREATE_TEST_TYPE_NAME "test_type" + +#define DATATYPE_CREATE_INVALID_PARAMS_TEST_SPACE_RANK 2 +#define DATATYPE_CREATE_INVALID_PARAMS_TEST_GROUP_NAME "committed_datatype_creation_invalid_params_test" +#define DATATYPE_CREATE_INVALID_PARAMS_TEST_TYPE_NAME "committed_datatype_creation_invalid_params_datatype" + +#define DATATYPE_CREATE_ANONYMOUS_GROUP_NAME "anonymous_type_creation_test" +#define DATATYPE_CREATE_ANONYMOUS_TYPE_NAME "anon_type" + +#define DATATYPE_CREATE_ANONYMOUS_INVALID_PARAMS_GROUP_NAME "anonymous_type_creation_invalid_params_test" + +#define DATATYPE_CREATE_EMPTY_TYPES_TEST_CMPD_TYPE_NAME "compound_type" +#define DATATYPE_CREATE_EMPTY_TYPES_TEST_ENUM_TYPE_NAME "enum_type" +#define DATATYPE_CREATE_EMPTY_TYPES_TEST_GROUP_NAME "committed_datatype_empty_types_test" + +#define RECOMMIT_COMMITTED_TYPE_TEST_GROUP_NAME "recommit_committed_type_test" + +#define DATATYPE_OPEN_TEST_GROUP_NAME "datatype_open_test" +#define DATATYPE_OPEN_TEST_TYPE_NAME "open_test_datatype" + +#define DATATYPE_OPEN_INVALID_PARAMS_TEST_GROUP_NAME "datatype_open_invalid_params_test" +#define DATATYPE_OPEN_INVALID_PARAMS_TEST_TYPE_NAME "open_invalid_params_test_datatype" + +#define DATATYPE_REOPEN_TEST_SPACE_RANK 2 +#define DATATYPE_REOPEN_TEST_GROUP_NAME "datatype_reopen_test" + +#define DATASET_CREATE_WITH_DATATYPE_TEST_DATASET_DIMS 2 +#define DATASET_CREATE_WITH_DATATYPE_TEST_GROUP_NAME "dataset_create_with_committed_type_test" +#define DATASET_CREATE_WITH_DATATYPE_TEST_TYPE_NAME "committed_type_test_dtype1" +#define DATASET_CREATE_WITH_DATATYPE_TEST_DSET_NAME "committed_type_test_dset" + +#define ATTRIBUTE_CREATE_WITH_DATATYPE_TEST_SPACE_RANK 2 +#define ATTRIBUTE_CREATE_WITH_DATATYPE_TEST_GROUP_NAME "attribute_create_with_committed_type_test" +#define ATTRIBUTE_CREATE_WITH_DATATYPE_TEST_DTYPE_NAME "committed_type_test_dtype2" +#define ATTRIBUTE_CREATE_WITH_DATATYPE_TEST_ATTR_NAME "committed_type_test_attr" + +#define DATATYPE_DELETE_TEST_GROUP_NAME "datatype_deletion_test" +#define DATATYPE_DELETE_TEST_DTYPE_NAME "delete_test_dtype" + +#define DATATYPE_RESURRECT_TEST_GROUP_NAME "datatype_resurrection_test" +#define DATATYPE_RESURRECT_TEST_DTYPE_NAME "delete_test_dtype" +#define DATATYPE_RESURRECT_TEST_DTYPE_NAME2 "resurrected_dtype" + +#define DATATYPE_PROPERTY_LIST_TEST_SUBGROUP_NAME "datatype_property_list_test_group" +#define DATATYPE_PROPERTY_LIST_TEST_DATATYPE_NAME1 "property_list_test_datatype1" +#define DATATYPE_PROPERTY_LIST_TEST_DATATYPE_NAME2 "property_list_test_datatype2" + +#define PREDEFINED_TYPE_COMMIT_TEST_GROUP_NAME "predefined_type_commit_test" + +#define MODIFY_COMMITTED_TYPE_TEST_GROUP_NAME "modify_committed_type_test" + +#endif diff --git a/test/API/H5_api_file_test.c b/test/API/H5_api_file_test.c new file mode 100644 index 0000000..279e9e7 --- /dev/null +++ b/test/API/H5_api_file_test.c @@ -0,0 +1,2564 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "H5_api_file_test.h" + +static int test_create_file(void); +static int test_create_file_invalid_params(void); +static int test_create_file_excl(void); +static int test_open_file(void); +static int test_open_file_invalid_params(void); +static int test_open_nonexistent_file(void); +static int test_file_open_overlap(void); +static int test_file_permission(void); +static int test_reopen_file(void); +static int test_close_file_invalid_id(void); +static int test_flush_file(void); +static int test_file_is_accessible(void); +static int test_file_property_lists(void); +static int test_get_file_intent(void); +static int test_get_file_obj_count(void); +static int test_file_mounts(void); +static int test_get_file_name(void); + +/* + * The array of file tests to be performed. + */ +static int (*file_tests[])(void) = { + test_create_file, + test_create_file_invalid_params, + test_create_file_excl, + test_open_file, + test_open_file_invalid_params, + test_open_nonexistent_file, + test_file_open_overlap, + test_file_permission, + test_reopen_file, + test_close_file_invalid_id, + test_flush_file, + test_file_is_accessible, + test_file_property_lists, + test_get_file_intent, + test_get_file_obj_count, + test_file_mounts, + test_get_file_name, +}; + +/* + * Tests that a file can be created. + */ +static int +test_create_file(void) +{ + hid_t file_id = H5I_INVALID_HID; + char *prefixed_filename = NULL; + + TESTING("H5Fcreate"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file aren't supported with this connector\n"); + return 0; + } + + if (prefix_filename(test_path_prefix, FILE_CREATE_TEST_FILENAME, &prefixed_filename) < 0) { + H5_FAILED(); + HDprintf(" couldn't prefix filename\n"); + goto error; + } + + if ((file_id = H5Fcreate(prefixed_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s'\n", prefixed_filename); + goto error; + } + + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + HDfree(prefixed_filename); + prefixed_filename = NULL; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Fclose(file_id); + } + H5E_END_TRY; + + HDfree(prefixed_filename); + + return 1; +} + +/* + * Tests that a file can't be created when H5Fcreate is passed + * invalid parameters. + */ +static int +test_create_file_invalid_params(void) +{ + hid_t file_id = H5I_INVALID_HID; + char *prefixed_filename = NULL; + + TESTING_MULTIPART("H5Fcreate with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file aren't supported with this connector\n"); + return 0; + } + + if (prefix_filename(test_path_prefix, FILE_CREATE_INVALID_PARAMS_FILE_NAME, &prefixed_filename) < 0) { + H5_FAILED(); + HDprintf(" couldn't prefix filename\n"); + goto error; + } + + BEGIN_MULTIPART + { + PART_BEGIN(H5Fcreate_invalid_name) + { + TESTING_2("H5Fcreate with invalid file name"); + + H5E_BEGIN_TRY + { + file_id = H5Fcreate(NULL, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (file_id >= 0) { + H5_FAILED(); + HDprintf(" file was created with a NULL name!\n"); + H5Fclose(file_id); + PART_ERROR(H5Fcreate_invalid_name); + } + + H5E_BEGIN_TRY + { + file_id = H5Fcreate("", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (file_id >= 0) { + H5_FAILED(); + HDprintf(" file was created with an invalid name of ''!\n"); + H5Fclose(file_id); + PART_ERROR(H5Fcreate_invalid_name); + } + + PASSED(); + } + PART_END(H5Fcreate_invalid_name); + + PART_BEGIN(H5Fcreate_invalid_flags) + { + TESTING_2("H5Fcreate with invalid flags"); + + H5E_BEGIN_TRY + { + file_id = H5Fcreate(prefixed_filename, H5F_ACC_RDWR, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (file_id >= 0) { + H5_FAILED(); + HDprintf(" file was created with invalid flag H5F_ACC_RDWR!\n"); + H5Fclose(file_id); + PART_ERROR(H5Fcreate_invalid_flags); + } + + H5E_BEGIN_TRY + { + file_id = H5Fcreate(prefixed_filename, H5F_ACC_CREAT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (file_id >= 0) { + H5_FAILED(); + HDprintf(" file was created with invalid flag H5F_ACC_CREAT!\n"); + H5Fclose(file_id); + PART_ERROR(H5Fcreate_invalid_flags); + } + + H5E_BEGIN_TRY + { + file_id = H5Fcreate(prefixed_filename, H5F_ACC_SWMR_READ, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (file_id >= 0) { + H5_FAILED(); + HDprintf(" file was created with invalid flag H5F_ACC_SWMR_READ!\n"); + H5Fclose(file_id); + PART_ERROR(H5Fcreate_invalid_flags); + } + + PASSED(); + } + PART_END(H5Fcreate_invalid_flags); + + PART_BEGIN(H5Fcreate_invalid_fcpl) + { + TESTING_2("H5Fcreate with invalid FCPL"); + + H5E_BEGIN_TRY + { + file_id = H5Fcreate(prefixed_filename, H5F_ACC_TRUNC, H5I_INVALID_HID, H5P_DEFAULT); + } + H5E_END_TRY; + + if (file_id >= 0) { + H5_FAILED(); + HDprintf(" file was created with invalid FCPL!\n"); + H5Fclose(file_id); + PART_ERROR(H5Fcreate_invalid_fcpl); + } + + PASSED(); + } + PART_END(H5Fcreate_invalid_fcpl); + } + END_MULTIPART; + + HDfree(prefixed_filename); + prefixed_filename = NULL; + + return 0; + +error: + H5E_BEGIN_TRY + { + /* Attempt to remove the file if it ended up being created. */ + H5Fdelete(prefixed_filename, H5P_DEFAULT); + + H5Fclose(file_id); + } + H5E_END_TRY; + + HDfree(prefixed_filename); + + return 1; +} + +/* + * Tests that file creation will fail when a file is created + * using the H5F_ACC_EXCL flag while the file already exists. + */ +static int +test_create_file_excl(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t file_id2 = H5I_INVALID_HID; + char *prefixed_filename = NULL; + + TESTING("H5Fcreate with H5F_ACC_EXCL/H5F_ACC_TRUNC flag"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file aren't supported with this connector\n"); + return 0; + } + + if (prefix_filename(test_path_prefix, FILE_CREATE_EXCL_FILE_NAME, &prefixed_filename) < 0) { + H5_FAILED(); + HDprintf(" couldn't prefix filename\n"); + goto error; + } + + if ((file_id = H5Fcreate(prefixed_filename, H5F_ACC_EXCL, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create first file\n"); + goto error; + } + + /* Close the file */ + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + /* Try again with H5F_ACC_EXCL. This should fail because the file already + * exists on disk from the previous steps. + */ + H5E_BEGIN_TRY + { + file_id = H5Fcreate(prefixed_filename, H5F_ACC_EXCL, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (file_id >= 0) { + H5_FAILED(); + HDprintf(" created already existing file using H5F_ACC_EXCL flag!\n"); + goto error; + } + + /* Test creating with H5F_ACC_TRUNC. This will truncate the existing file on disk. */ + if ((file_id = H5Fcreate(prefixed_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't truncate the existing file\n"); + goto error; + } + + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + HDfree(prefixed_filename); + prefixed_filename = NULL; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Fclose(file_id); + H5Fclose(file_id2); + } + H5E_END_TRY; + + HDfree(prefixed_filename); + + return 1; +} + +/* + * Tests that a file can be opened. + */ +static int +test_open_file(void) +{ + hid_t file_id = H5I_INVALID_HID; + + TESTING_MULTIPART("H5Fopen"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file aren't supported with this connector\n"); + return 0; + } + + BEGIN_MULTIPART + { + PART_BEGIN(H5Fopen_rdonly) + { + TESTING_2("H5Fopen in read-only mode"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDONLY, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" unable to open file '%s' in read-only mode\n", H5_api_test_filename); + PART_ERROR(H5Fopen_rdonly); + } + + PASSED(); + } + PART_END(H5Fopen_rdonly); + + if (file_id >= 0) { + H5E_BEGIN_TRY + { + H5Fclose(file_id); + } + H5E_END_TRY; + file_id = H5I_INVALID_HID; + } + + PART_BEGIN(H5Fopen_rdwrite) + { + TESTING_2("H5Fopen in read-write mode"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" unable to open file '%s' in read-write mode\n", H5_api_test_filename); + PART_ERROR(H5Fopen_rdwrite); + } + + PASSED(); + } + PART_END(H5Fopen_rdwrite); + + if (file_id >= 0) { + H5E_BEGIN_TRY + { + H5Fclose(file_id); + } + H5E_END_TRY; + file_id = H5I_INVALID_HID; + } + + /* + * XXX: SWMR open flags + */ + } + END_MULTIPART; + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * Tests that a file can't be opened when H5Fopen is given + * invalid parameters. + */ +static int +test_open_file_invalid_params(void) +{ + hid_t file_id = H5I_INVALID_HID; + + TESTING_MULTIPART("H5Fopen with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file aren't supported with this connector\n"); + return 0; + } + + BEGIN_MULTIPART + { + PART_BEGIN(H5Fopen_invalid_name) + { + TESTING_2("H5Fopen with invalid file name"); + + H5E_BEGIN_TRY + { + file_id = H5Fopen(NULL, H5F_ACC_RDWR, H5P_DEFAULT); + } + H5E_END_TRY; + + if (file_id >= 0) { + H5_FAILED(); + HDprintf(" file was opened with a NULL name!\n"); + H5Fclose(file_id); + PART_ERROR(H5Fopen_invalid_name); + } + + H5E_BEGIN_TRY + { + file_id = H5Fopen("", H5F_ACC_RDWR, H5P_DEFAULT); + } + H5E_END_TRY; + + if (file_id >= 0) { + H5_FAILED(); + HDprintf(" file was opened with an invalid name of ''!\n"); + H5Fclose(file_id); + PART_ERROR(H5Fopen_invalid_name); + } + + PASSED(); + } + PART_END(H5Fopen_invalid_name); + + PART_BEGIN(H5Fopen_invalid_flags) + { + TESTING_2("H5Fopen with invalid flags"); + + H5E_BEGIN_TRY + { + file_id = H5Fopen(H5_api_test_filename, H5F_ACC_TRUNC, H5P_DEFAULT); + } + H5E_END_TRY; + + if (file_id >= 0) { + H5_FAILED(); + HDprintf(" file was opened with invalid flag H5F_ACC_TRUNC!\n"); + H5Fclose(file_id); + PART_ERROR(H5Fopen_invalid_flags); + } + + H5E_BEGIN_TRY + { + file_id = H5Fopen(H5_api_test_filename, H5F_ACC_EXCL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (file_id >= 0) { + H5_FAILED(); + HDprintf(" file was opened with invalid flag H5F_ACC_EXCL!\n"); + H5Fclose(file_id); + PART_ERROR(H5Fopen_invalid_flags); + } + + PASSED(); + } + PART_END(H5Fopen_invalid_flags); + } + END_MULTIPART; + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to ensure that opening a file which doesn't exist will fail. + */ +static int +test_open_nonexistent_file(void) +{ + hid_t file_id = H5I_INVALID_HID; + char *prefixed_filename = NULL; + + TESTING("for invalid opening of a non-existent file"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file aren't supported with this connector\n"); + return 0; + } + + if (prefix_filename(test_path_prefix, NONEXISTENT_FILENAME, &prefixed_filename) < 0) { + H5_FAILED(); + HDprintf(" couldn't prefix filename\n"); + goto error; + } + + /* XXX: Make sure to first delete the file so we know for sure it doesn't exist */ + + H5E_BEGIN_TRY + { + file_id = H5Fopen(prefixed_filename, H5F_ACC_RDWR, H5P_DEFAULT); + } + H5E_END_TRY; + + if (file_id >= 0) { + H5_FAILED(); + HDprintf(" non-existent file was opened!\n"); + goto error; + } + + HDfree(prefixed_filename); + prefixed_filename = NULL; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Fclose(file_id); + } + H5E_END_TRY; + + HDfree(prefixed_filename); + + return 1; +} + +/* + * Tests that a file can be opened read-only or read-write + * and things are handled appropriately. + */ +static int +test_file_permission(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dspace_id = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t dtype_id = H5I_INVALID_HID; + char *prefixed_filename = NULL; + herr_t h5_ret = FAIL; + + TESTING_MULTIPART("file permissions (invalid creation of objects in read-only file)"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, attribute, stored datatype aren't " + "supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if (prefix_filename(test_path_prefix, FILE_PERMISSION_TEST_FILENAME, &prefixed_filename) < 0) { + H5_FAILED(); + HDprintf(" couldn't prefix filename\n"); + goto error; + } + + if ((file_id = H5Fcreate(prefixed_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s'\n", prefixed_filename); + goto error; + } + + if ((dspace_id = H5Screate(H5S_SCALAR)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create data space\n"); + goto error; + } + + if ((dset_id = H5Dcreate2(file_id, FILE_PERMISSION_TEST_DSET_NAME, H5T_STD_U32LE, dspace_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create data set: %s\n", FILE_PERMISSION_TEST_DSET_NAME); + goto error; + } + + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + /* Open the file (with read-only permission) */ + if ((file_id = H5Fopen(prefixed_filename, H5F_ACC_RDONLY, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Gcreate_rdonly_file) + { + TESTING_2("invalid creation of group in read-only file"); + + /* Create a group with the read-only file handle (should fail) */ + H5E_BEGIN_TRY + { + group_id = + H5Gcreate2(file_id, FILE_PERMISSION_TEST_GRP_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (group_id >= 0) { + H5_FAILED(); + HDprintf(" a group was created in a read-only file!\n"); + PART_ERROR(H5Gcreate_rdonly_file); + } + + H5E_BEGIN_TRY + { + group_id = H5Gcreate_anon(file_id, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (group_id >= 0) { + H5_FAILED(); + HDprintf(" a group was created in a read-only file!\n"); + PART_ERROR(H5Gcreate_rdonly_file); + } + + PASSED(); + } + PART_END(H5Gcreate_rdonly_file); + + PART_BEGIN(H5Dcreate_rdonly_file) + { + TESTING_2("invalid creation of dataset in read-only file"); + + /* Create a dataset with the read-only file handle (should fail) */ + H5E_BEGIN_TRY + { + dset_id = H5Dcreate2(file_id, FILE_PERMISSION_TEST_DSET2_NAME, H5T_STD_U32LE, dspace_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (dset_id >= 0) { + H5_FAILED(); + HDprintf(" a dataset was created in a read-only file!\n"); + PART_ERROR(H5Dcreate_rdonly_file); + } + + H5E_BEGIN_TRY + { + dset_id = H5Dcreate_anon(file_id, H5T_STD_U32LE, dspace_id, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (dset_id >= 0) { + H5_FAILED(); + HDprintf(" a dataset was created in a read-only file!\n"); + PART_ERROR(H5Dcreate_rdonly_file); + } + + PASSED(); + } + PART_END(H5Dcreate_rdonly_file); + + PART_BEGIN(H5Acreate_rdonly_file) + { + TESTING_2("invalid creation of attribute in read-only file"); + + /* Create an attribute with the read-only file handle (should fail) */ + H5E_BEGIN_TRY + { + attr_id = H5Acreate2(file_id, FILE_PERMISSION_TEST_ATTR_NAME, H5T_NATIVE_INT, dspace_id, + H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (attr_id >= 0) { + H5_FAILED(); + HDprintf(" an attribute was created in a read-only file!\n"); + PART_ERROR(H5Acreate_rdonly_file); + } + + PASSED(); + } + PART_END(H5Acreate_rdonly_file); + + PART_BEGIN(H5Tcommit_rdonly_file) + { + TESTING_2("invalid creation of committed datatype in read-only file"); + + if ((dtype_id = H5Tcopy(H5T_NATIVE_INT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't copy a native datatype\n"); + PART_ERROR(H5Tcommit_rdonly_file); + } + + /* Commit a datatype with the read-only file handle (should fail) */ + H5E_BEGIN_TRY + { + h5_ret = H5Tcommit2(file_id, FILE_PERMISSION_TEST_NAMED_DTYPE, dtype_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (h5_ret >= 0) { + H5_FAILED(); + HDprintf(" a named datatype was committed in a read-only file!\n"); + PART_ERROR(H5Tcommit_rdonly_file); + } + + H5E_BEGIN_TRY + { + h5_ret = H5Tcommit_anon(file_id, dtype_id, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (h5_ret >= 0) { + H5_FAILED(); + HDprintf(" a named datatype was committed in a read-only file!\n"); + PART_ERROR(H5Tcommit_rdonly_file); + } + + PASSED(); + } + PART_END(H5Tcommit_rdonly_file); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Tclose(dtype_id) < 0) + TEST_ERROR; + if (H5Sclose(dspace_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + HDfree(prefixed_filename); + prefixed_filename = NULL; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(dspace_id); + H5Dclose(dset_id); + H5Aclose(attr_id); + H5Tclose(dtype_id); + H5Gclose(group_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + HDfree(prefixed_filename); + + return 1; +} + +/* + * A test to check that a file can be re-opened with H5Freopen. + */ +static int +test_reopen_file(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t file_id2 = H5I_INVALID_HID; + + TESTING("re-open of a file with H5Freopen"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file\n"); + goto error; + } + + if ((file_id2 = H5Freopen(file_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't re-open file\n"); + goto error; + } + + if (H5Fclose(file_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id2) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Fclose(file_id); + H5Fclose(file_id2); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that H5Fclose doesn't succeed for an + * invalid file ID */ +static int +test_close_file_invalid_id(void) +{ + herr_t err_ret = -1; + + TESTING("H5Fclose with an invalid ID"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file aren't supported with this connector\n"); + return 0; + } + + H5E_BEGIN_TRY + { + err_ret = H5Fclose(H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" closed an invalid file ID!\n"); + goto error; + } + + PASSED(); + + return 0; + +error: + return 1; +} + +/* + * A test to check that a file can be flushed using H5Fflush. + */ +static int +test_flush_file(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t dspace_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + char *prefixed_filename = NULL; + char dset_name[32]; + unsigned u; + + TESTING_MULTIPART("H5Fflush"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH)) { + SKIPPED(); + HDprintf(" API functions for basic file, dataset, or file flush aren't supported with this " + "connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if (prefix_filename(test_path_prefix, FILE_FLUSH_TEST_FILENAME, &prefixed_filename) < 0) { + H5_FAILED(); + HDprintf(" couldn't prefix filename\n"); + goto error; + } + + if ((file_id = H5Fcreate(prefixed_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s'\n", prefixed_filename); + goto error; + } + + /* Create multiple small datasets in file */ + if ((dspace_id = H5Screate(H5S_SCALAR)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create data space\n"); + goto error; + } + + for (u = 0; u < 10; u++) { + HDsprintf(dset_name, "Dataset %u", u); + + if ((dset_id = H5Dcreate2(file_id, dset_name, H5T_STD_U32LE, dspace_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create data set: %s\n", dset_name); + goto error; + } + + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Fflush_local) + { + TESTING_2("file flushing at local scope"); + + if (H5Fflush(file_id, H5F_SCOPE_LOCAL) < 0) { + H5_FAILED(); + HDprintf(" unable to flush file with scope H5F_SCOPE_LOCAL\n"); + PART_ERROR(H5Fflush_local); + } + + PASSED(); + } + PART_END(H5Fflush_local); + + PART_BEGIN(H5Fflush_global) + { + TESTING_2("file flushing at global scope"); + + if (H5Fflush(file_id, H5F_SCOPE_GLOBAL) < 0) { + H5_FAILED(); + HDprintf(" unable to flush file with scope H5F_SCOPE_GLOBAL\n"); + PART_ERROR(H5Fflush_global); + } + + PASSED(); + } + PART_END(H5Fflush_global); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(dspace_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + HDfree(prefixed_filename); + prefixed_filename = NULL; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(dspace_id); + H5Dclose(dset_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + HDfree(prefixed_filename); + + return 1; +} + +/* + * A test for H5Fis_accessible. + */ +static int +test_file_is_accessible(void) +{ + const char *const fake_filename = "nonexistent_file.h5"; + char *prefixed_filename = NULL; + htri_t is_accessible = FAIL; + + TESTING_MULTIPART("H5Fis_accessible"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file aren't supported with this connector\n"); + return 0; + } + + if (prefix_filename(test_path_prefix, fake_filename, &prefixed_filename) < 0) { + H5_FAILED(); + HDprintf(" couldn't prefix filename\n"); + goto error; + } + + BEGIN_MULTIPART + { + PART_BEGIN(H5Fis_accessible_valid_file) + { + TESTING_2("H5Fis_accessible on existing file"); + + if ((is_accessible = H5Fis_accessible(H5_api_test_filename, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if file '%s' is accessible with default FAPL\n", + H5_api_test_filename); + PART_ERROR(H5Fis_accessible_valid_file); + } + + if (!is_accessible) { + H5_FAILED(); + HDprintf(" file '%s' is not accessible with default FAPL\n", H5_api_test_filename); + PART_ERROR(H5Fis_accessible_valid_file); + } + + PASSED(); + } + PART_END(H5Fis_accessible_valid_file); + + is_accessible = -1; + + PART_BEGIN(H5Fis_accessible_invalid_file) + { + TESTING_2("H5Fis_accessible on non-existing file"); + + H5E_BEGIN_TRY + { + is_accessible = H5Fis_accessible(prefixed_filename, H5P_DEFAULT); + } + H5E_END_TRY; + + if (is_accessible > 0) { + H5_FAILED(); + HDprintf(" non-existent file '%s' was accessible with default FAPL: is_accessible=%d!\n", + prefixed_filename, is_accessible); + PART_ERROR(H5Fis_accessible_invalid_file); + } + + PASSED(); + } + PART_END(H5Fis_accessible_invalid_file); + } + END_MULTIPART; + + HDfree(prefixed_filename); + prefixed_filename = NULL; + + return 0; + +error: + HDfree(prefixed_filename); + + return 1; +} + +/* + * A test to check that a FCPL used for file creation can + * be persisted and that a valid copy of that FCPL can be + * retrieved later with a call to H5Fget_create_plist. Also + * tests that a valid copy of a FAPL used for file access + * can be retrieved with a call to H5Fget_access_plist. + */ +static int +test_file_property_lists(void) +{ + hsize_t prop_val = 0; + hid_t file_id1 = H5I_INVALID_HID; + hid_t file_id2 = H5I_INVALID_HID; + hid_t fcpl_id1 = H5I_INVALID_HID; + hid_t fcpl_id2 = H5I_INVALID_HID; + hid_t fapl_id1 = H5I_INVALID_HID; + hid_t fapl_id2 = H5I_INVALID_HID; + char *prefixed_filename1 = NULL; + char *prefixed_filename2 = NULL; + + TESTING_MULTIPART("file property list operations"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_GET_PLIST)) { + SKIPPED(); + HDprintf(" API functions for basic or more file or get property list aren't supported with this " + "connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if (prefix_filename(test_path_prefix, FILE_PROPERTY_LIST_TEST_FNAME1, &prefixed_filename1) < 0) { + H5_FAILED(); + HDprintf(" couldn't prefix filename\n"); + goto error; + } + if (prefix_filename(test_path_prefix, FILE_PROPERTY_LIST_TEST_FNAME2, &prefixed_filename2) < 0) { + H5_FAILED(); + HDprintf(" couldn't prefix filename\n"); + goto error; + } + + if ((fcpl_id1 = H5Pcreate(H5P_FILE_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create FCPL\n"); + goto error; + } + + if (H5Pset_userblock(fcpl_id1, FILE_PROPERTY_LIST_TEST_FCPL_PROP_VAL) < 0) { + H5_FAILED(); + HDprintf(" failed to set test property on FCPL\n"); + goto error; + } + + if ((file_id1 = H5Fcreate(prefixed_filename1, H5F_ACC_TRUNC, fcpl_id1, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file\n"); + goto error; + } + + if ((file_id2 = H5Fcreate(prefixed_filename2, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file\n"); + goto error; + } + + if (H5Pclose(fcpl_id1) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Fget_create_plist) + { + TESTING_2("H5Fget_create_plist"); + + /* Try to receive copies of the two property lists, one which has the property set and one which + * does not */ + if ((fcpl_id1 = H5Fget_create_plist(file_id1)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get FCPL\n"); + PART_ERROR(H5Fget_create_plist); + } + + if ((fcpl_id2 = H5Fget_create_plist(file_id2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get FCPL\n"); + PART_ERROR(H5Fget_create_plist); + } + + /* Ensure that property list 1 has the property set and property list 2 does not */ + if (H5Pget_userblock(fcpl_id1, &prop_val) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve test property from FCPL\n"); + PART_ERROR(H5Fget_create_plist); + } + + if (prop_val != FILE_PROPERTY_LIST_TEST_FCPL_PROP_VAL) { + H5_FAILED(); + HDprintf(" retrieved test property value '%llu' did not match expected value '%llu'\n", + (long long unsigned)prop_val, + (long long unsigned)FILE_PROPERTY_LIST_TEST_FCPL_PROP_VAL); + PART_ERROR(H5Fget_create_plist); + } + + if (H5Pget_userblock(fcpl_id2, &prop_val) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve test property from FCPL\n"); + PART_ERROR(H5Fget_create_plist); + } + + if (prop_val == FILE_PROPERTY_LIST_TEST_FCPL_PROP_VAL) { + HDprintf(" retrieved test property value '%llu' matched control value '%llu' when it " + "shouldn't have\n", + (long long unsigned)prop_val, + (long long unsigned)FILE_PROPERTY_LIST_TEST_FCPL_PROP_VAL); + PART_ERROR(H5Fget_create_plist); + } + + PASSED(); + } + PART_END(H5Fget_create_plist); + + PART_BEGIN(H5Fget_access_plist) + { + TESTING_2("H5Fget_access_plist"); + + /* Due to the nature of needing to supply a FAPL with the VOL connector having been set on it to + * the H5Fcreate() call, we cannot exactly test using H5P_DEFAULT as the FAPL for one of the + * create calls in this test. However, the use of H5Fget_access_plist() will still be used to + * check that the FAPL is correct after both creating and opening a file. + */ + if ((fapl_id1 = H5Fget_access_plist(file_id1)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get FAPL\n"); + PART_ERROR(H5Fget_access_plist); + } + + if ((fapl_id2 = H5Fget_access_plist(file_id2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get FAPL\n"); + PART_ERROR(H5Fget_access_plist); + } + + PASSED(); + } + PART_END(H5Fget_access_plist); + + /* Now see if we can still retrieve copies of the property lists upon opening + * (instead of creating) a file. If they were reconstructed properly upon file + * open, the creation property lists should also have the same test values + * as set before. + */ + if (fcpl_id1 >= 0) { + H5E_BEGIN_TRY + { + H5Pclose(fcpl_id1); + } + H5E_END_TRY; + fcpl_id1 = H5I_INVALID_HID; + } + if (fcpl_id2 >= 0) { + H5E_BEGIN_TRY + { + H5Pclose(fcpl_id2); + } + H5E_END_TRY; + fcpl_id2 = H5I_INVALID_HID; + } + if (fapl_id1 >= 0) { + H5E_BEGIN_TRY + { + H5Pclose(fapl_id1); + } + H5E_END_TRY; + fapl_id1 = H5I_INVALID_HID; + } + if (fapl_id2 >= 0) { + H5E_BEGIN_TRY + { + H5Pclose(fapl_id2); + } + H5E_END_TRY; + fapl_id2 = H5I_INVALID_HID; + } + if (file_id1 >= 0) { + H5E_BEGIN_TRY + { + H5Fclose(file_id1); + } + H5E_END_TRY; + file_id1 = H5I_INVALID_HID; + } + if (file_id2 >= 0) { + H5E_BEGIN_TRY + { + H5Fclose(file_id2); + } + H5E_END_TRY; + file_id2 = H5I_INVALID_HID; + } + + PART_BEGIN(H5Fget_create_plist_reopened) + { + TESTING_2("H5Fget_create_plist after re-opening file"); + + if ((file_id1 = H5Fopen(prefixed_filename1, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file\n"); + PART_ERROR(H5Fget_create_plist_reopened); + } + + if ((file_id2 = H5Fopen(prefixed_filename2, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file\n"); + PART_ERROR(H5Fget_create_plist_reopened); + } + + if ((fcpl_id1 = H5Fget_create_plist(file_id1)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get FCPL\n"); + PART_ERROR(H5Fget_create_plist_reopened); + } + + if ((fcpl_id2 = H5Fget_create_plist(file_id2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get FCPL\n"); + PART_ERROR(H5Fget_create_plist_reopened); + } + + /* Check the values of the test property */ + if (H5Pget_userblock(fcpl_id1, &prop_val) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve test property from FCPL\n"); + PART_ERROR(H5Fget_create_plist_reopened); + } + + if (prop_val != FILE_PROPERTY_LIST_TEST_FCPL_PROP_VAL) { + H5_FAILED(); + HDprintf(" retrieved test property value '%llu' did not match expected value '%llu'\n", + (long long unsigned)prop_val, + (long long unsigned)FILE_PROPERTY_LIST_TEST_FCPL_PROP_VAL); + PART_ERROR(H5Fget_create_plist_reopened); + } + + if (H5Pget_userblock(fcpl_id2, &prop_val) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve test property from FCPL\n"); + PART_ERROR(H5Fget_create_plist_reopened); + } + + if (prop_val == FILE_PROPERTY_LIST_TEST_FCPL_PROP_VAL) { + HDprintf(" retrieved test property value '%llu' matched control value '%llu' when it " + "shouldn't have\n", + (long long unsigned)prop_val, + (long long unsigned)FILE_PROPERTY_LIST_TEST_FCPL_PROP_VAL); + PART_ERROR(H5Fget_create_plist_reopened); + } + + PASSED(); + } + PART_END(H5Fget_create_plist_reopened); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Pclose(fcpl_id1) < 0) + TEST_ERROR; + if (H5Pclose(fcpl_id2) < 0) + TEST_ERROR; + if (H5Fclose(file_id1) < 0) + TEST_ERROR; + if (H5Fclose(file_id2) < 0) + TEST_ERROR; + + HDfree(prefixed_filename1); + prefixed_filename1 = NULL; + HDfree(prefixed_filename2); + prefixed_filename2 = NULL; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(fcpl_id1); + H5Pclose(fcpl_id2); + H5Pclose(fapl_id1); + H5Pclose(fapl_id2); + H5Fclose(file_id1); + H5Fclose(file_id2); + } + H5E_END_TRY; + + HDfree(prefixed_filename1); + HDfree(prefixed_filename2); + + return 1; +} + +/* + * A test to check that the file intent flags can be retrieved. + */ +static int +test_get_file_intent(void) +{ + unsigned file_intent; + hid_t file_id = H5I_INVALID_HID; + char *prefixed_filename = NULL; + + TESTING_MULTIPART("retrieval of file intent with H5Fget_intent"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_MORE)) { + SKIPPED(); + HDprintf(" API functions for basic or more file aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if (prefix_filename(test_path_prefix, FILE_INTENT_TEST_FILENAME, &prefixed_filename) < 0) { + H5_FAILED(); + HDprintf(" couldn't prefix filename\n"); + goto error; + } + + /* Test that file intent retrieval works correctly for file create */ + if ((file_id = H5Fcreate(prefixed_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s'\n", prefixed_filename); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Fget_intent_file_creation) + { + TESTING_2("H5Fget_intent on newly-created file"); + + if (H5Fget_intent(file_id, &file_intent) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve file intent\n"); + PART_ERROR(H5Fget_intent_file_creation); + } + + if (H5F_ACC_RDWR != file_intent) { + H5_FAILED(); + HDprintf(" received incorrect file intent for file creation\n"); + PART_ERROR(H5Fget_intent_file_creation); + } + + PASSED(); + } + PART_END(H5Fget_intent_file_creation); + + if (file_id >= 0) { + H5E_BEGIN_TRY + { + H5Fclose(file_id); + } + H5E_END_TRY; + file_id = H5I_INVALID_HID; + } + + PART_BEGIN(H5Fget_intent_rdonly_file_open) + { + TESTING_2("H5Fget_intent for file opened read-only"); + + /* Test that file intent retrieval works correctly for file open */ + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDONLY, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + PART_ERROR(H5Fget_intent_rdonly_file_open); + } + + if (H5Fget_intent(file_id, &file_intent) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve file intent\n"); + PART_ERROR(H5Fget_intent_rdonly_file_open); + } + + if (H5F_ACC_RDONLY != file_intent) { + H5_FAILED(); + HDprintf(" received incorrect file intent for read-only file open\n"); + PART_ERROR(H5Fget_intent_rdonly_file_open); + } + + PASSED(); + } + PART_END(H5Fget_intent_rdonly_file_open); + + if (file_id >= 0) { + H5E_BEGIN_TRY + { + H5Fclose(file_id); + } + H5E_END_TRY; + file_id = H5I_INVALID_HID; + } + + PART_BEGIN(H5Fget_intent_rdwrite_file_open) + { + TESTING_2("H5Fget_intent for file opened read-write"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + PART_ERROR(H5Fget_intent_rdwrite_file_open); + } + + if (H5Fget_intent(file_id, &file_intent) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve file intent\n"); + PART_ERROR(H5Fget_intent_rdwrite_file_open); + } + + if (H5F_ACC_RDWR != file_intent) { + H5_FAILED(); + HDprintf(" received incorrect file intent\n"); + PART_ERROR(H5Fget_intent_rdwrite_file_open); + } + + PASSED(); + } + PART_END(H5Fget_intent_rdwrite_file_open); + + if (file_id >= 0) { + H5E_BEGIN_TRY + { + H5Fclose(file_id); + } + H5E_END_TRY; + file_id = H5I_INVALID_HID; + } + } + END_MULTIPART; + + HDfree(prefixed_filename); + prefixed_filename = NULL; + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Fclose(file_id); + } + H5E_END_TRY; + + HDfree(prefixed_filename); + + return 1; +} + +/* + * A test to check that the number of open objects and IDs of objects in a file + * can be retrieved. + */ +static int +test_get_file_obj_count(void) +{ + ssize_t obj_count; + hid_t file_id = H5I_INVALID_HID; + hid_t file_id2 = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t object_id = H5I_INVALID_HID; + hid_t named_dtype_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t dspace_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + char *prefixed_filename1 = NULL; + char *prefixed_filename2 = NULL; + + TESTING_MULTIPART("retrieval of open object number and IDs"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic or more file, basic dataset, group, datatype, or attribute " + "aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if (prefix_filename(test_path_prefix, GET_OBJ_COUNT_TEST_FILENAME1, &prefixed_filename1) < 0) { + H5_FAILED(); + HDprintf(" couldn't prefix filename\n"); + goto error; + } + if (prefix_filename(test_path_prefix, GET_OBJ_COUNT_TEST_FILENAME2, &prefixed_filename2) < 0) { + H5_FAILED(); + HDprintf(" couldn't prefix filename\n"); + goto error; + } + + if ((file_id = H5Fcreate(prefixed_filename1, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s'\n", prefixed_filename1); + goto error; + } + + if ((group_id = H5Gcreate2(file_id, GET_OBJ_COUNT_TEST_GRP_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", GET_OBJ_COUNT_TEST_GRP_NAME); + goto error; + } + + /* Create a second file while keeping the first file open */ + if ((file_id2 = H5Fcreate(prefixed_filename2, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s'\n", prefixed_filename2); + goto error; + } + + /* Create a named datatype */ + if ((named_dtype_id = H5Tcopy(H5T_NATIVE_INT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't copy a native datatype\n"); + goto error; + } + + if (H5Tcommit2(file_id2, GET_OBJ_COUNT_TEST_NAMED_DTYPE, named_dtype_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't commit a named datatype\n"); + goto error; + } + + /* Create a dataspace for the attribute and dataset */ + if ((dspace_id = H5Screate(H5S_SCALAR)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create data space for attribute\n"); + goto error; + } + + /* Create an attribute for the second file */ + if ((attr_id = H5Acreate2(file_id2, GET_OBJ_COUNT_TEST_ATTR_NAME, H5T_NATIVE_INT, dspace_id, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create the attribute '%s'\n", GET_OBJ_COUNT_TEST_ATTR_NAME); + goto error; + } + + /* Create a dataset for the second file */ + if ((dset_id = H5Dcreate2(file_id2, GET_OBJ_COUNT_TEST_DSET_NAME, H5T_NATIVE_INT, dspace_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create the dataset '%s'\n", GET_OBJ_COUNT_TEST_DSET_NAME); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Fget_obj_count_files) + { + TESTING_2("H5Fget_obj_count for files"); + + /* Get the number of files currently opened */ + if ((obj_count = H5Fget_obj_count((hid_t)H5F_OBJ_ALL, H5F_OBJ_FILE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get the number of open files\n"); + PART_ERROR(H5Fget_obj_count_files); + } + + if (obj_count != 2) { + H5_FAILED(); + HDprintf(" number of open files (%ld) did not match expected number (2)\n", obj_count); + PART_ERROR(H5Fget_obj_count_files); + } + + PASSED(); + } + PART_END(H5Fget_obj_count_files); + + PART_BEGIN(H5Fget_obj_count_grps_single_file) + { + TESTING_2("H5Fget_obj_count for groups in single file"); + + /* Get the number of groups */ + if ((obj_count = H5Fget_obj_count(file_id, H5F_OBJ_GROUP)) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve number of open groups\n"); + PART_ERROR(H5Fget_obj_count_grps_single_file); + } + + if (obj_count != 1) { + H5_FAILED(); + HDprintf(" number of open groups (%ld) did not match expected number (1)\n", obj_count); + PART_ERROR(H5Fget_obj_count_grps_single_file); + } + + PASSED(); + } + PART_END(H5Fget_obj_count_grps_single_file); + + PART_BEGIN(H5Fget_obj_count_grps) + { + TESTING_2("H5Fget_obj_count for groups"); + + /* Get the number of groups in two opened files */ + if ((obj_count = H5Fget_obj_count((hid_t)H5F_OBJ_ALL, H5F_OBJ_GROUP)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get the number of open groups\n"); + PART_ERROR(H5Fget_obj_count_grps); + } + + if (obj_count != 1) { + H5_FAILED(); + HDprintf(" number of open groups (%ld) did not match expected number (1)\n", obj_count); + PART_ERROR(H5Fget_obj_count_grps); + } + + PASSED(); + } + PART_END(H5Fget_obj_count_grps); + + PART_BEGIN(H5Fget_obj_count_types) + { + TESTING_2("H5Fget_obj_count for datatypes"); +#ifndef WRONG_DATATYPE_OBJ_COUNT + /* Get the number of named datatype in two opened files */ + if ((obj_count = H5Fget_obj_count((hid_t)H5F_OBJ_ALL, H5F_OBJ_DATATYPE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get the number of open named datatypes\n"); + PART_ERROR(H5Fget_obj_count_types); + } + + if (obj_count != 1) { + H5_FAILED(); + HDprintf(" number of open named datatypes (%ld) did not match expected number (1)\n", + obj_count); + PART_ERROR(H5Fget_obj_count_types); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Fget_obj_count_types); +#endif + } + PART_END(H5Fget_obj_count_types); + + PART_BEGIN(H5Fget_obj_count_attrs) + { + TESTING_2("H5Fget_obj_count for attributes"); + + /* Get the number of attribute in two opened files */ + if ((obj_count = H5Fget_obj_count((hid_t)H5F_OBJ_ALL, H5F_OBJ_ATTR)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get the number of open attributes\n"); + PART_ERROR(H5Fget_obj_count_attrs); + } + + if (obj_count != 1) { + H5_FAILED(); + HDprintf(" number of open attributes (%ld) did not match expected number (1)\n", + obj_count); + PART_ERROR(H5Fget_obj_count_attrs); + } + + PASSED(); + } + PART_END(H5Fget_obj_count_attrs); + + PART_BEGIN(H5Fget_obj_count_dsets) + { + TESTING_2("H5Fget_obj_count for datasets"); + + /* Get the number of dataset in two opened files */ + if ((obj_count = H5Fget_obj_count((hid_t)H5F_OBJ_ALL, H5F_OBJ_DATASET)) < 0 || obj_count != 1) { + H5_FAILED(); + HDprintf(" couldn't get the number of open datasets\n"); + PART_ERROR(H5Fget_obj_count_dsets); + } + + if (obj_count != 1) { + H5_FAILED(); + HDprintf(" number of open datasets (%ld) did not match expected number (1)\n", obj_count); + PART_ERROR(H5Fget_obj_count_dsets); + } + + PASSED(); + } + PART_END(H5Fget_obj_count_dsets); + + PART_BEGIN(H5Fget_obj_count_all_single_file) + { + TESTING_2("H5Fget_obj_count for all object types in single file"); + + /* Get the number of all open objects */ + if ((obj_count = H5Fget_obj_count(file_id, H5F_OBJ_ALL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve number of open objects\n"); + PART_ERROR(H5Fget_obj_count_all_single_file); + } + + /* One for the file and another for the group */ + if (obj_count != 2) { + H5_FAILED(); + HDprintf(" number of open objects (%ld) did not match expected number (2)\n", obj_count); + PART_ERROR(H5Fget_obj_count_all_single_file); + } + + PASSED(); + } + PART_END(H5Fget_obj_count_all_single_file); + + PART_BEGIN(H5Fget_obj_count_all) + { + TESTING_2("H5Fget_obj_count for all object types"); +#ifndef WRONG_DATATYPE_OBJ_COUNT + /* Get the number of all open objects */ + if ((obj_count = H5Fget_obj_count(H5F_OBJ_ALL, H5F_OBJ_ALL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve number of open objects\n"); + PART_ERROR(H5Fget_obj_count_all); + } + + if (obj_count != 6) { + H5_FAILED(); + HDprintf(" number of open objects (%ld) did not match expected number (6)\n", obj_count); + PART_ERROR(H5Fget_obj_count_all); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Fget_obj_count_all); +#endif + } + PART_END(H5Fget_obj_count_all); + + PART_BEGIN(H5Fget_obj_ids_singular_grp) + { + TESTING_2("H5Fget_obj_ids for a singular group"); + + if (H5Fget_obj_ids(file_id, H5F_OBJ_GROUP, (size_t)obj_count, &object_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't get opened group IDs\n"); + PART_ERROR(H5Fget_obj_ids_singular_grp); + } + + if (object_id != group_id) { + H5_FAILED(); + HDprintf(" opened object ID (%ld) did not match only currently open group ID (%ld)\n", + object_id, group_id); + PART_ERROR(H5Fget_obj_ids_singular_grp); + } + + PASSED(); + } + PART_END(H5Fget_obj_ids_singular_grp); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Sclose(dspace_id) < 0) + TEST_ERROR; + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + if (H5Tclose(named_dtype_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id2) < 0) + TEST_ERROR; + + HDfree(prefixed_filename1); + prefixed_filename1 = NULL; + HDfree(prefixed_filename2); + prefixed_filename2 = NULL; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(group_id); + H5Tclose(named_dtype_id); + H5Sclose(dspace_id); + H5Aclose(attr_id); + H5Dclose(dset_id); + H5Fclose(file_id); + H5Fclose(file_id2); + } + H5E_END_TRY; + + HDfree(prefixed_filename1); + HDfree(prefixed_filename2); + + return 1; +} + +/* + * A test to check that opening files in an overlapping way + * works correctly. + */ +static int +test_file_open_overlap(void) +{ +#ifndef NO_DOUBLE_OBJECT_OPENS + ssize_t obj_count; + hid_t file_id = H5I_INVALID_HID; + hid_t file_id2 = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t dspace_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + char *prefixed_filename = NULL; +#endif + + TESTING("overlapping file opens"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic or more file, dataset, or group aren't supported with this " + "connector\n"); + return 0; + } + +#ifndef NO_DOUBLE_OBJECT_OPENS + if (prefix_filename(test_path_prefix, OVERLAPPING_FILENAME, &prefixed_filename) < 0) { + H5_FAILED(); + HDprintf(" couldn't prefix filename\n"); + goto error; + } + + if ((file_id = H5Fcreate(prefixed_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s'\n", prefixed_filename); + goto error; + } + + if ((file_id2 = H5Fopen(prefixed_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", prefixed_filename); + goto error; + } + + if ((group_id = H5Gcreate2(file_id, OVERLAPPING_OPEN_TEST_GRP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", OVERLAPPING_OPEN_TEST_GRP_NAME); + goto error; + } + + /* Create a dataspace for the dataset */ + if ((dspace_id = H5Screate(H5S_SCALAR)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create data space for dataset\n"); + goto error; + } + + /* Create a dataset in the group of the first file */ + if ((dset_id = H5Dcreate2(group_id, OVERLAPPING_OPEN_TEST_DSET_NAME, H5T_NATIVE_INT, dspace_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create the dataset '%s'\n", OVERLAPPING_OPEN_TEST_DSET_NAME); + goto error; + } + + /* Get the number of objects opened in the first file: 3 == file + dataset + group */ + if ((obj_count = H5Fget_obj_count(file_id, H5F_OBJ_LOCAL | H5F_OBJ_ALL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve the number of objects opened in the file\n"); + goto error; + } + + if (obj_count != 3) { + H5_FAILED(); + HDprintf(" number of objects opened in file (%ld) did not match expected number (3)\n", obj_count); + goto error; + } + + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + /* Create a dataset in the second file */ + if ((dset_id = H5Dcreate2(file_id2, OVERLAPPING_OPEN_TEST_DSET_NAME, H5T_NATIVE_INT, dspace_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create the dataset '%s'\n", OVERLAPPING_OPEN_TEST_DSET_NAME); + goto error; + } + + /* Get the number of objects opened in the first file: 2 == file + dataset */ + if ((obj_count = H5Fget_obj_count(file_id2, H5F_OBJ_ALL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve the number of objects opened in the file\n"); + goto error; + } + + if (obj_count != 2) { + H5_FAILED(); + HDprintf(" number of objects opened in the file (%ld) did not match expected number (2)\n", + obj_count); + goto error; + } + + if (H5Sclose(dspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id2) < 0) + TEST_ERROR; + + HDfree(prefixed_filename); + prefixed_filename = NULL; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(group_id); + H5Sclose(dspace_id); + H5Dclose(dset_id); + H5Fclose(file_id); + H5Fclose(file_id2); + } + H5E_END_TRY; + + HDfree(prefixed_filename); + + return 1; +#else + SKIPPED(); + return 0; +#endif +} + +/* + * A test to check that file mounting and unmounting works + * correctly. + */ +static int +test_file_mounts(void) +{ +#ifndef NO_FILE_MOUNTS + hid_t file_id = H5I_INVALID_HID; + hid_t child_fid = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + char *prefixed_filename = NULL; +#endif + + TESTING("file mounting/unmounting"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_MOUNT) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file, file mount, or basic group aren't supported with this " + "connector\n"); + return 0; + } + +#ifndef NO_FILE_MOUNTS + if (prefix_filename(test_path_prefix, FILE_MOUNT_TEST_FILENAME, &prefixed_filename) < 0) { + H5_FAILED(); + HDprintf(" couldn't prefix filename\n"); + goto error; + } + + if ((file_id = H5Fcreate(prefixed_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s'\n", prefixed_filename); + goto error; + } + + if ((group_id = H5Gcreate2(file_id, FILE_MOUNT_TEST_GRP_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", FILE_MOUNT_TEST_GRP_NAME); + goto error; + } + + if ((child_fid = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + /* Mount one file (child_fid) to the group of another file (file_id) */ + if (H5Fmount(file_id, FILE_MOUNT_TEST_GRP_NAME, child_fid, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't mount file\n"); + goto error; + } + + if (H5Funmount(file_id, FILE_MOUNT_TEST_GRP_NAME) < 0) { + H5_FAILED(); + HDprintf(" couldn't mount file\n"); + goto error; + } + + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + if (H5Fclose(child_fid) < 0) + TEST_ERROR; + + HDfree(prefixed_filename); + prefixed_filename = NULL; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(group_id); + H5Fclose(file_id); + H5Fclose(child_fid); + } + H5E_END_TRY; + + HDfree(prefixed_filename); + + return 1; +#else + SKIPPED(); + return 0; +#endif +} + +/* + * A test to ensure that a file's name can be retrieved. + */ +static int +test_get_file_name(void) +{ + ssize_t file_name_buf_len = 0; + hid_t file_id = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dspace_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t named_dtype_id = H5I_INVALID_HID; + char *prefixed_filename = NULL; + char *file_name_buf = NULL; + + TESTING_MULTIPART("retrieval of file name"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic or more file, basic dataset, group, datatype, or attribute " + "aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if (prefix_filename(test_path_prefix, GET_FILE_NAME_TEST_FNAME, &prefixed_filename) < 0) { + H5_FAILED(); + HDprintf(" couldn't prefix filename\n"); + goto error; + } + + if ((file_id = H5Fcreate(prefixed_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s'\n", prefixed_filename); + goto error; + } + + /* Retrieve the size of the file name */ + if ((file_name_buf_len = H5Fget_name(file_id, NULL, 0)) < 0) + TEST_ERROR; + + /* Allocate buffer for file name */ + if (NULL == (file_name_buf = (char *)HDmalloc((size_t)file_name_buf_len + 1))) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Fget_name_file_id) + { + TESTING_2("H5Fget_name using file ID"); + + memset(file_name_buf, 0, (size_t)file_name_buf_len); + + /* Retrieve the actual file name */ + if (H5Fget_name(file_id, file_name_buf, (size_t)file_name_buf_len + 1) < 0) { + H5_FAILED(); + HDprintf(" couldn't get file name %s\n", prefixed_filename); + PART_ERROR(H5Fget_name_file_id); + } + + if (HDstrncmp(file_name_buf, prefixed_filename, (size_t)file_name_buf_len)) { + H5_FAILED(); + HDprintf(" file name '%s' didn't match expected name '%s'\n", file_name_buf, + prefixed_filename); + PART_ERROR(H5Fget_name_file_id); + } + + PASSED(); + } + PART_END(H5Fget_name_file_id); + + PART_BEGIN(H5Fget_name_grp_id) + { + TESTING_2("H5Fget_name using non-root group ID"); + + /* Attempt to retrieve the name of the file from an object that isn't the root group */ + memset(file_name_buf, 0, (size_t)file_name_buf_len); + + if ((group_id = H5Gcreate2(file_id, GET_FILE_NAME_TEST_GRP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to create group '%s'\n", GET_FILE_NAME_TEST_GRP_NAME); + PART_ERROR(H5Fget_name_grp_id); + } + + if (H5Fget_name(group_id, file_name_buf, (size_t)file_name_buf_len + 1) < 0) { + H5_FAILED(); + HDprintf(" couldn't get file name %s\n", prefixed_filename); + PART_ERROR(H5Fget_name_grp_id); + } + + if (HDstrncmp(file_name_buf, prefixed_filename, (size_t)file_name_buf_len)) { + H5_FAILED(); + HDprintf(" file name '%s' didn't match expected name '%s'\n", file_name_buf, + prefixed_filename); + PART_ERROR(H5Fget_name_grp_id); + } + + if (group_id >= 0) { + H5E_BEGIN_TRY + { + H5Gclose(group_id); + } + H5E_END_TRY; + group_id = H5I_INVALID_HID; + } + + PASSED(); + } + PART_END(H5Fget_name_grp_id); + + PART_BEGIN(H5Fget_name_dset_id) + { + TESTING_2("H5Fget_name using dataset ID"); + + if ((dspace_id = H5Screate(H5S_SCALAR)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataspace\n"); + PART_ERROR(H5Fget_name_dset_id); + } + + /* Create a dataset in the file */ + if ((dset_id = H5Dcreate2(file_id, GET_FILE_NAME_TEST_DSET_NAME, H5T_NATIVE_INT, dspace_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create the dataset '%s'\n", GET_FILE_NAME_TEST_DSET_NAME); + PART_ERROR(H5Fget_name_dset_id); + } + + /* Get and verify file name from the dataset */ + if (H5Fget_name(dset_id, file_name_buf, (size_t)file_name_buf_len + 1) < 0) { + H5_FAILED(); + HDprintf(" couldn't get file name %s\n", prefixed_filename); + PART_ERROR(H5Fget_name_dset_id); + } + + if (HDstrncmp(file_name_buf, prefixed_filename, (size_t)file_name_buf_len)) { + H5_FAILED(); + HDprintf(" file name '%s' didn't match expected name '%s'\n", file_name_buf, + prefixed_filename); + PART_ERROR(H5Fget_name_dset_id); + } + + if (dspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(dspace_id); + } + H5E_END_TRY; + dspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + PASSED(); + } + PART_END(H5Fget_name_dset_id); + + PART_BEGIN(H5Fget_name_attr_id) + { + TESTING_2("H5Fget_name using attribute ID"); + + if ((dspace_id = H5Screate(H5S_SCALAR)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataspace\n"); + PART_ERROR(H5Fget_name_attr_id); + } + + /* Create an attribute for the dataset */ + if ((attr_id = H5Acreate2(file_id, GET_FILE_NAME_TEST_ATTR_NAME, H5T_NATIVE_INT, dspace_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create the attribute '%s'\n", GET_FILE_NAME_TEST_ATTR_NAME); + PART_ERROR(H5Fget_name_attr_id); + } + + /* Get and verify file name from the attribute */ + if (H5Fget_name(attr_id, file_name_buf, (size_t)file_name_buf_len + 1) < 0) { + H5_FAILED(); + HDprintf(" couldn't get file name %s\n", prefixed_filename); + PART_ERROR(H5Fget_name_attr_id); + } + + if (HDstrncmp(file_name_buf, prefixed_filename, (size_t)file_name_buf_len)) { + H5_FAILED(); + HDprintf(" file name '%s' didn't match expected name '%s'\n", file_name_buf, + prefixed_filename); + PART_ERROR(H5Fget_name_attr_id); + } + + if (dspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(dspace_id); + } + H5E_END_TRY; + dspace_id = H5I_INVALID_HID; + } + if (attr_id >= 0) { + H5E_BEGIN_TRY + { + H5Aclose(attr_id); + } + H5E_END_TRY; + attr_id = H5I_INVALID_HID; + } + + PASSED(); + } + PART_END(H5Fget_name_attr_id); + + PART_BEGIN(H5Fget_name_dtype_id) + { + TESTING_2("H5Fget_name using committed datatype ID"); + + /* Create a named datatype */ + if ((named_dtype_id = H5Tcopy(H5T_NATIVE_INT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't copy a native datatype\n"); + PART_ERROR(H5Fget_name_dtype_id); + } + + if (H5Tcommit2(file_id, GET_FILE_NAME_TEST_NAMED_DTYPE, named_dtype_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't commit a named datatype\n"); + PART_ERROR(H5Fget_name_dtype_id); + } + + /* Get and verify file name from the committed datatype */ + if (H5Fget_name(named_dtype_id, file_name_buf, (size_t)file_name_buf_len + 1) < 0) { + H5_FAILED(); + HDprintf(" couldn't get file name %s\n", prefixed_filename); + PART_ERROR(H5Fget_name_dtype_id); + } + + if (HDstrncmp(file_name_buf, prefixed_filename, (size_t)file_name_buf_len)) { + H5_FAILED(); + HDprintf(" file name '%s' didn't match expected name '%s'\n", file_name_buf, + prefixed_filename); + PART_ERROR(H5Fget_name_dtype_id); + } + + if (named_dtype_id >= 0) { + H5E_BEGIN_TRY + { + H5Tclose(named_dtype_id); + } + H5E_END_TRY; + named_dtype_id = H5I_INVALID_HID; + } + + PASSED(); + } + PART_END(H5Fget_name_dtype_id); + + PART_BEGIN(H5Fget_name_dspace_id) + { + ssize_t name_len = 0; + + TESTING_2("invalid H5Fget_name using dataspace ID"); + + if ((dspace_id = H5Screate(H5S_SCALAR)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataspace\n"); + PART_ERROR(H5Fget_name_dspace_id); + } + + /* Try get file name from data space. Supposed to fail because + * it's illegal operation. */ + H5E_BEGIN_TRY + { + name_len = H5Fget_name(dspace_id, file_name_buf, (size_t)file_name_buf_len + 1); + } + H5E_END_TRY; + + if (name_len >= 0) { + H5_FAILED(); + HDprintf(" retrieved file name using H5Fget_name on a dataspace ID!\n"); + PART_ERROR(H5Fget_name_dspace_id); + } + + if (dspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(dspace_id); + } + H5E_END_TRY; + dspace_id = H5I_INVALID_HID; + } + + PASSED(); + } + PART_END(H5Fget_name_dspace_id); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (file_name_buf) { + HDfree(file_name_buf); + file_name_buf = NULL; + } + + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + HDfree(prefixed_filename); + prefixed_filename = NULL; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (file_name_buf) + HDfree(file_name_buf); + H5Tclose(named_dtype_id); + H5Sclose(dspace_id); + H5Dclose(dset_id); + H5Aclose(attr_id); + H5Gclose(group_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + HDfree(prefixed_filename); + + return 1; +} + +/* + * Cleanup temporary test files + */ +static void +cleanup_files(void) +{ + remove_test_file(test_path_prefix, FILE_CREATE_TEST_FILENAME); + remove_test_file(test_path_prefix, FILE_CREATE_EXCL_FILE_NAME); + + /* The below file should not get created */ + /* remove_test_file(test_path_prefix, FILE_CREATE_INVALID_PARAMS_FILE_NAME); */ + +#ifndef NO_DOUBLE_OBJECT_OPENS + remove_test_file(test_path_prefix, OVERLAPPING_FILENAME); +#endif + remove_test_file(test_path_prefix, FILE_PERMISSION_TEST_FILENAME); + remove_test_file(test_path_prefix, FILE_FLUSH_TEST_FILENAME); + remove_test_file(test_path_prefix, FILE_PROPERTY_LIST_TEST_FNAME1); + remove_test_file(test_path_prefix, FILE_PROPERTY_LIST_TEST_FNAME2); + remove_test_file(test_path_prefix, FILE_INTENT_TEST_FILENAME); + remove_test_file(test_path_prefix, GET_OBJ_COUNT_TEST_FILENAME1); + remove_test_file(test_path_prefix, GET_OBJ_COUNT_TEST_FILENAME2); +#ifndef NO_FILE_MOUNTS + remove_test_file(test_path_prefix, FILE_MOUNT_TEST_FILENAME); +#endif + remove_test_file(test_path_prefix, GET_FILE_NAME_TEST_FNAME); +} + +int +H5_api_file_test(void) +{ + size_t i; + int nerrors; + + HDprintf("**********************************************\n"); + HDprintf("* *\n"); + HDprintf("* API File Tests *\n"); + HDprintf("* *\n"); + HDprintf("**********************************************\n\n"); + + for (i = 0, nerrors = 0; i < ARRAY_LENGTH(file_tests); i++) { + nerrors += (*file_tests[i])() ? 1 : 0; + } + + HDprintf("\n"); + + HDprintf("Cleaning up testing files\n"); + cleanup_files(); + + return nerrors; +} diff --git a/test/API/H5_api_file_test.h b/test/API/H5_api_file_test.h new file mode 100644 index 0000000..948cb6a --- /dev/null +++ b/test/API/H5_api_file_test.h @@ -0,0 +1,85 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef H5_API_FILE_TEST_H +#define H5_API_FILE_TEST_H + +#include "H5_api_test.h" + +int H5_api_file_test(void); + +/********************************************* + * * + * API File test defines * + * * + *********************************************/ + +#define FILE_CREATE_TEST_FILENAME "test_file.h5" + +#define FILE_CREATE_INVALID_PARAMS_FILE_NAME "invalid_params_file.h5" + +#define FILE_CREATE_EXCL_FILE_NAME "excl_flag_file.h5" + +#define NONEXISTENT_FILENAME "nonexistent_file.h5" + +#define OVERLAPPING_FILENAME "overlapping_file.h5" +#define OVERLAPPING_OPEN_TEST_GRP_NAME "group" +#define OVERLAPPING_OPEN_TEST_DSET_NAME "dataset" + +#define FILE_PERMISSION_TEST_FILENAME "file_permission.h5" +#define FILE_PERMISSION_TEST_GRP_NAME "group" +#define FILE_PERMISSION_TEST_DSET_NAME "Dataset" +#define FILE_PERMISSION_TEST_DSET2_NAME "Dataset2" +#define FILE_PERMISSION_TEST_ATTR_NAME "attribute" +#define FILE_PERMISSION_TEST_NAMED_DTYPE "named_dtype" + +#define FILE_FLUSH_TEST_FILENAME "flush_file.h5" + +#define FILE_PROPERTY_LIST_TEST_FCPL_PROP_VAL 65536 +#define FILE_PROPERTY_LIST_TEST_FNAME1 "property_list_test_file1.h5" +#define FILE_PROPERTY_LIST_TEST_FNAME2 "property_list_test_file2.h5" + +#define FILE_INTENT_TEST_FILENAME "intent_test_file.h5" + +#define GET_OBJ_COUNT_TEST_FILENAME1 "file_obj_count1.h5" +#define GET_OBJ_COUNT_TEST_FILENAME2 "file_obj_count2.h5" +#define GET_OBJ_COUNT_TEST_GRP_NAME "/group" +#define GET_OBJ_COUNT_TEST_DSET_NAME "Dataset" +#define GET_OBJ_COUNT_TEST_ATTR_NAME "Attribute" +#define GET_OBJ_COUNT_TEST_NAMED_DTYPE "named_dtype" + +#define FILE_MOUNT_TEST_FILENAME "file_mount.h5" +#define FILE_MOUNT_TEST_GRP_NAME "group" + +#define GET_FILE_NAME_TEST_FNAME "file_name_retrieval.h5" +#define GET_FILE_NAME_TEST_GRP_NAME "group" +#define GET_FILE_NAME_TEST_DSET_NAME "dataset" +#define GET_FILE_NAME_TEST_ATTR_NAME "attribute" +#define GET_FILE_NAME_TEST_NAMED_DTYPE "datatype" + +#define FILESPACE_INFO_FILENAME "filespace_info.h5" +#define FSP_SIZE512 (hsize_t)512 + +#define FILE_GET_ID_TEST_FILENAME "test_file_id.h5" + +#define FILE_CLOSE_DEGREE_FILENAME "test_close_degree.h5" + +#define GET_FREE_SECTIONS_FILENAME "test_free_sections.h5" + +#define FILE_SIZE_FILENAME "file_size.h5" +#define KB 1024U + +#define FILE_INFO_FILENAME "file_info.h5" + +#define DOUBLE_GROUP_OPEN_FILENAME "double_group_open.h5" + +#endif diff --git a/test/API/H5_api_group_test.c b/test/API/H5_api_group_test.c new file mode 100644 index 0000000..f652202 --- /dev/null +++ b/test/API/H5_api_group_test.c @@ -0,0 +1,2394 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "H5_api_group_test.h" + +static int test_create_group_under_root(void); +static int test_create_group_under_existing_group(void); +static int test_create_many_groups(void); +static int test_create_deep_groups(void); +static int test_create_intermediate_group(void); +static int test_create_group_invalid_params(void); +static int test_create_anonymous_group(void); +static int test_create_anonymous_group_invalid_params(void); +static int test_open_nonexistent_group(void); +static int test_open_group_invalid_params(void); +static int test_close_group_invalid_id(void); +static int test_group_property_lists(void); +static int test_get_group_info(void); +static int test_get_group_info_invalid_params(void); +static int test_flush_group(void); +static int test_flush_group_invalid_params(void); +static int test_refresh_group(void); +static int test_refresh_group_invalid_params(void); +static int create_group_recursive(hid_t parent_gid, unsigned counter); + +/* + * The array of group tests to be performed. + */ +static int (*group_tests[])(void) = { + test_create_group_under_root, + test_create_group_under_existing_group, + test_create_many_groups, + test_create_deep_groups, + test_create_intermediate_group, + test_create_group_invalid_params, + test_create_anonymous_group, + test_create_anonymous_group_invalid_params, + test_open_nonexistent_group, + test_open_group_invalid_params, + test_close_group_invalid_id, + test_group_property_lists, + test_get_group_info, + test_get_group_info_invalid_params, + test_flush_group, + test_flush_group_invalid_params, + test_refresh_group, + test_refresh_group_invalid_params, +}; + +/* + * A test to check that a group can be created under the root group. + */ +static int +test_create_group_under_root(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t parent_gid = H5I_INVALID_HID; + + TESTING("creation of group under the root group"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file or group aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + /* Create the group under the root group of the file */ + if ((parent_gid = + H5Gcreate2(file_id, GROUP_CREATE_UNDER_ROOT_GNAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", GROUP_CREATE_UNDER_ROOT_GNAME); + goto error; + } + + if (H5Gclose(parent_gid) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(parent_gid); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a group can be created under an existing + * group which is not the root group. + */ +static int +test_create_group_under_existing_group(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t parent_group_id = H5I_INVALID_HID, child_group_id = H5I_INVALID_HID, + grandchild_group_id = H5I_INVALID_HID; + + TESTING("creation of group under existing group using a relative path"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file or group aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file\n"); + goto error; + } + + /* Open the already-existing group (/group_tests) in the file as the parent */ + if ((parent_group_id = H5Gopen2(file_id, GROUP_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open group\n"); + goto error; + } + + /* Create a new group (/group_tests/child_group) under the already-existing parent Group using a relative + * path */ + if ((child_group_id = H5Gcreate2(parent_group_id, GROUP_CREATE_UNDER_GROUP_REL_GNAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group using relative path: %s\n", GROUP_CREATE_UNDER_GROUP_REL_GNAME); + goto error; + } + + /* Create a new group (child_group/grandchild_group) under the already-existing parent Group using an + * absolute path */ + if ((grandchild_group_id = H5Gcreate2(parent_group_id, GROUP_CREATE_UNDER_GROUP_ABS_GNAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group using absolute path: %s\n", GROUP_CREATE_UNDER_GROUP_ABS_GNAME); + goto error; + } + + if (H5Gclose(grandchild_group_id) < 0) + TEST_ERROR; + if (H5Gclose(child_group_id) < 0) + TEST_ERROR; + if (H5Gclose(parent_group_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(grandchild_group_id); + H5Gclose(child_group_id); + H5Gclose(parent_group_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to create many (one million) groups + */ +static int +test_create_many_groups(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t parent_group_id = H5I_INVALID_HID, child_group_id = H5I_INVALID_HID; + char group_name[NAME_BUF_SIZE]; + unsigned i; + + TESTING("H5Gcreate many groups"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file or group aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, GROUP_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group\n"); + goto error; + } + + if ((parent_group_id = H5Gcreate2(container_group, MANY_GROUP_CREATIONS_GNAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", MANY_GROUP_CREATIONS_GNAME); + goto error; + } + + /* Create multiple groups under the parent group */ + HDprintf("\n"); + for (i = 0; i < GROUP_NUMB_MANY; i++) { + HDprintf("\r %u/%u", i + 1, GROUP_NUMB_MANY); + sprintf(group_name, "group %02u", i); + if ((child_group_id = + H5Gcreate2(parent_group_id, group_name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", group_name); + goto error; + } + + if (H5Gclose(child_group_id) < 0) + TEST_ERROR; + } + + if (H5Gclose(parent_group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(child_group_id); + H5Gclose(parent_group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to create groups of the depth GROUP_DEPTH. + */ +static int +test_create_deep_groups(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + + TESTING("H5Gcreate groups of great depths"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file or group aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, GROUP_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group\n"); + goto error; + } + + /* Create the group under the root group of the file */ + if ((group_id = H5Gcreate2(container_group, DEEP_GROUP_CREATIONS_GNAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", DEEP_GROUP_CREATIONS_GNAME); + goto error; + } + + HDprintf("\n"); + if (create_group_recursive(group_id, 1) < 0) + TEST_ERROR; + + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * Recursive function to create groups of the depth GROUP_DEPTH. + */ +static int +create_group_recursive(hid_t parent_gid, unsigned counter) +{ + hid_t child_gid = H5I_INVALID_HID; + char gname[NAME_BUF_SIZE]; + + HDprintf("\r %u/%u", counter, GROUP_DEPTH); + if (counter == 1) + sprintf(gname, "2nd_child_group"); + else if (counter == 2) + sprintf(gname, "3rd_child_group"); + else + sprintf(gname, "%dth_child_group", counter + 1); + if ((child_gid = H5Gcreate2(parent_gid, gname, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", gname); + goto error; + } + + if (counter < GROUP_DEPTH) { + if (create_group_recursive(child_gid, counter + 1) < 0) + TEST_ERROR; + } + + if (H5Gclose(child_gid) < 0) + TEST_ERROR; + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(child_gid); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to create groups automatically using H5Pset_create_intermediate_group + */ +static int +test_create_intermediate_group(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t crt_intmd_lcpl_id = H5I_INVALID_HID; + + TESTING("H5Gcreate group with intermediate group creation"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file or group aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, GROUP_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group\n"); + goto error; + } + + /* Set up plist for creating intermediate groups */ + if ((crt_intmd_lcpl_id = H5Pcreate(H5P_LINK_CREATE)) < 0) + TEST_ERROR; + if (H5Pset_create_intermediate_group(crt_intmd_lcpl_id, TRUE) < 0) + TEST_ERROR; + + /* Create an intermediate group using a relative path */ + if ((group_id = H5Gcreate2(container_group, + GROUP_CREATE_INTMD_REL_INTMD_NAME "/" GROUP_CREATE_INTMD_REL_END_NAME, + crt_intmd_lcpl_id, H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + group_id = H5I_INVALID_HID; + + /* Verify both groups were created */ + if ((group_id = + H5Gopen2(file_id, GROUP_TEST_GROUP_NAME "/" GROUP_CREATE_INTMD_REL_INTMD_NAME, H5P_DEFAULT)) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + group_id = H5I_INVALID_HID; + if ((group_id = H5Gopen2(file_id, + GROUP_TEST_GROUP_NAME "/" GROUP_CREATE_INTMD_REL_INTMD_NAME + "/" GROUP_CREATE_INTMD_REL_END_NAME, + H5P_DEFAULT)) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + group_id = H5I_INVALID_HID; + + /* Create an intermediate group using an absolute path */ + if ((group_id = H5Gcreate2(container_group, + "/" GROUP_TEST_GROUP_NAME "/" GROUP_CREATE_INTMD_ABS_INTMD_NAME + "/" GROUP_CREATE_INTMD_ABS_END_NAME, + crt_intmd_lcpl_id, H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + group_id = H5I_INVALID_HID; + + /* Verify both groups were created */ + if ((group_id = + H5Gopen2(file_id, GROUP_TEST_GROUP_NAME "/" GROUP_CREATE_INTMD_ABS_INTMD_NAME, H5P_DEFAULT)) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + group_id = H5I_INVALID_HID; + if ((group_id = H5Gopen2(file_id, + GROUP_TEST_GROUP_NAME "/" GROUP_CREATE_INTMD_ABS_INTMD_NAME + "/" GROUP_CREATE_INTMD_ABS_END_NAME, + H5P_DEFAULT)) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + group_id = H5I_INVALID_HID; + + /* Create two intermediate groups using an absolute path */ + if ((group_id = H5Gcreate2(container_group, + "/" GROUP_TEST_GROUP_NAME "/" GROUP_CREATE_INTMD_MULT_INTMD1_NAME + "/" GROUP_CREATE_INTMD_MULT_INTMD2_NAME "/" GROUP_CREATE_INTMD_MULT_END_NAME, + crt_intmd_lcpl_id, H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + group_id = H5I_INVALID_HID; + + /* Verify all three groups were created */ + if ((group_id = H5Gopen2(file_id, GROUP_TEST_GROUP_NAME "/" GROUP_CREATE_INTMD_MULT_INTMD1_NAME, + H5P_DEFAULT)) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + group_id = H5I_INVALID_HID; + if ((group_id = H5Gopen2(file_id, + GROUP_TEST_GROUP_NAME "/" GROUP_CREATE_INTMD_MULT_INTMD1_NAME + "/" GROUP_CREATE_INTMD_MULT_INTMD2_NAME, + H5P_DEFAULT)) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + group_id = H5I_INVALID_HID; + if ((group_id = H5Gopen2(file_id, + GROUP_TEST_GROUP_NAME "/" GROUP_CREATE_INTMD_MULT_INTMD1_NAME + "/" GROUP_CREATE_INTMD_MULT_INTMD2_NAME + "/" GROUP_CREATE_INTMD_MULT_END_NAME, + H5P_DEFAULT)) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + group_id = H5I_INVALID_HID; + + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + if (H5Pclose(crt_intmd_lcpl_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + H5Pclose(crt_intmd_lcpl_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a group can't be created when H5Gcreate + * is passed invalid parameters. + */ +static int +test_create_group_invalid_params(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + + TESTING_MULTIPART("H5Gcreate with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file or group aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Gcreate_invalid_loc_id) + { + TESTING_2("H5Gcreate with an invalid loc_id"); + + H5E_BEGIN_TRY + { + group_id = H5Gcreate2(H5I_INVALID_HID, GROUP_CREATE_INVALID_PARAMS_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (group_id >= 0) { + H5_FAILED(); + HDprintf(" created group with invalid loc_id!\n"); + H5Gclose(group_id); + PART_ERROR(H5Gcreate_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Gcreate_invalid_loc_id); + + PART_BEGIN(H5Gcreate_invalid_grp_name) + { + TESTING_2("H5Gcreate with an invalid group name"); + + H5E_BEGIN_TRY + { + group_id = H5Gcreate2(file_id, NULL, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (group_id >= 0) { + H5_FAILED(); + HDprintf(" created group with a NULL name!\n"); + H5Gclose(group_id); + PART_ERROR(H5Gcreate_invalid_grp_name); + } + + H5E_BEGIN_TRY + { + group_id = H5Gcreate2(file_id, "", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (group_id >= 0) { + H5_FAILED(); + HDprintf(" created group with an invalid group name of ''!\n"); + H5Gclose(group_id); + PART_ERROR(H5Gcreate_invalid_grp_name); + } + + PASSED(); + } + PART_END(H5Gcreate_invalid_grp_name); + + PART_BEGIN(H5Gcreate_invalid_lcpl) + { + TESTING_2("H5Gcreate with an invalid LCPL"); + + H5E_BEGIN_TRY + { + group_id = H5Gcreate2(file_id, GROUP_CREATE_INVALID_PARAMS_GROUP_NAME, H5I_INVALID_HID, + H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (group_id >= 0) { + H5_FAILED(); + HDprintf(" created group with invalid LCPL!\n"); + H5Gclose(group_id); + PART_ERROR(H5Gcreate_invalid_lcpl); + } + + PASSED(); + } + PART_END(H5Gcreate_invalid_lcpl); + + PART_BEGIN(H5Gcreate_invalid_gcpl) + { + TESTING_2("H5Gcreate with an invalid GCPL"); + + H5E_BEGIN_TRY + { + group_id = H5Gcreate2(file_id, GROUP_CREATE_INVALID_PARAMS_GROUP_NAME, H5P_DEFAULT, + H5I_INVALID_HID, H5P_DEFAULT); + } + H5E_END_TRY; + + if (group_id >= 0) { + H5_FAILED(); + HDprintf(" created group with invalid GCPL!\n"); + H5Gclose(group_id); + PART_ERROR(H5Gcreate_invalid_gcpl); + } + + PASSED(); + } + PART_END(H5Gcreate_invalid_gcpl); + + PART_BEGIN(H5Gcreate_invalid_gapl) + { + TESTING_2("H5Gcreate with an invalid GAPL"); + + H5E_BEGIN_TRY + { + group_id = H5Gcreate2(file_id, GROUP_CREATE_INVALID_PARAMS_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (group_id >= 0) { + H5_FAILED(); + HDprintf(" created group with invalid GAPL!\n"); + H5Gclose(group_id); + PART_ERROR(H5Gcreate_invalid_gapl); + } + + PASSED(); + } + PART_END(H5Gcreate_invalid_gapl); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(group_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that an anonymous group can be created with + * H5Gcreate_anon. + */ +static int +test_create_anonymous_group(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, new_group_id = H5I_INVALID_HID; + + TESTING("creation of anonymous group"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file or group aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file\n"); + goto error; + } + + if ((container_group = H5Gopen2(file_id, GROUP_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open group\n"); + goto error; + } + + if ((new_group_id = H5Gcreate_anon(file_id, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create anonymous group\n"); + goto error; + } + + if (H5Gclose(new_group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(new_group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that an anonymous group can't be created + * when H5Gcreate_anon is passed invalid parameters. + */ +static int +test_create_anonymous_group_invalid_params(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, new_group_id = H5I_INVALID_HID; + + TESTING_MULTIPART("H5Gcreate_anon with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file or group aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file\n"); + goto error; + } + + if ((container_group = H5Gopen2(file_id, GROUP_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open group\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Gcreate_anon_invalid_loc_id) + { + TESTING_2("H5Gcreate_anon with an invalid loc_id"); + + H5E_BEGIN_TRY + { + new_group_id = H5Gcreate_anon(H5I_INVALID_HID, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (new_group_id >= 0) { + H5_FAILED(); + HDprintf(" created anonymous group with invalid loc_id!\n"); + H5Gclose(new_group_id); + PART_ERROR(H5Gcreate_anon_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Gcreate_anon_invalid_loc_id); + + PART_BEGIN(H5Gcreate_anon_invalid_gcpl) + { + TESTING_2("H5Gcreate_anon with an invalid GCPL"); + + H5E_BEGIN_TRY + { + new_group_id = H5Gcreate_anon(container_group, H5I_INVALID_HID, H5P_DEFAULT); + } + H5E_END_TRY; + + if (new_group_id >= 0) { + H5_FAILED(); + HDprintf(" created anonymous group with invalid GCPL!\n"); + H5Gclose(new_group_id); + PART_ERROR(H5Gcreate_anon_invalid_gcpl); + } + + PASSED(); + } + PART_END(H5Gcreate_anon_invalid_gcpl); + + PART_BEGIN(H5Gcreate_anon_invalid_gapl) + { + TESTING_2("H5Gcreate_anon with an invalid GAPL"); + + H5E_BEGIN_TRY + { + new_group_id = H5Gcreate_anon(container_group, H5P_DEFAULT, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (new_group_id >= 0) { + H5_FAILED(); + HDprintf(" created anonymous group with invalid GAPL!\n"); + H5Gclose(new_group_id); + PART_ERROR(H5Gcreate_anon_invalid_gapl); + } + + PASSED(); + } + PART_END(H5Gcreate_anon_invalid_gapl); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(new_group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a group which doesn't exist cannot + * be opened. + */ +static int +test_open_nonexistent_group(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + + TESTING("for invalid opening of a nonexistent group"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file or group aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file\n"); + goto error; + } + + H5E_BEGIN_TRY + { + group_id = H5Gopen2(file_id, OPEN_NONEXISTENT_GROUP_TEST_GNAME, H5P_DEFAULT); + } + H5E_END_TRY; + + if (group_id >= 0) { + H5_FAILED(); + HDprintf(" opened non-existent group!\n"); + goto error; + } + + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(group_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a group can't be opened when H5Gopen + * is passed invalid parameters. + */ +static int +test_open_group_invalid_params(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + + TESTING_MULTIPART("H5Gopen with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file or group aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Gopen_invalid_loc_id) + { + TESTING_2("H5Gopen with an invalid loc_id"); + + H5E_BEGIN_TRY + { + group_id = H5Gopen2(H5I_INVALID_HID, GROUP_TEST_GROUP_NAME, H5P_DEFAULT); + } + H5E_END_TRY; + + if (group_id >= 0) { + H5_FAILED(); + HDprintf(" opened group using an invalid loc_id!\n"); + H5Gclose(group_id); + PART_ERROR(H5Gopen_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Gopen_invalid_loc_id); + + PART_BEGIN(H5Gopen_invalid_grp_name) + { + TESTING_2("H5Gopen with an invalid group name"); + + H5E_BEGIN_TRY + { + group_id = H5Gopen2(file_id, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (group_id >= 0) { + H5_FAILED(); + HDprintf(" opened group using a NULL name!\n"); + H5Gclose(group_id); + PART_ERROR(H5Gopen_invalid_grp_name); + } + + H5E_BEGIN_TRY + { + group_id = H5Gopen2(file_id, "", H5P_DEFAULT); + } + H5E_END_TRY; + + if (group_id >= 0) { + H5_FAILED(); + HDprintf(" opened group using an invalid name of ''!\n"); + H5Gclose(group_id); + PART_ERROR(H5Gopen_invalid_grp_name); + } + + PASSED(); + } + PART_END(H5Gopen_invalid_grp_name); + + PART_BEGIN(H5Gopen_invalid_gapl) + { + TESTING_2("H5Gopen with an invalid GAPL"); + + H5E_BEGIN_TRY + { + group_id = H5Gopen2(file_id, GROUP_TEST_GROUP_NAME, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (group_id >= 0) { + H5_FAILED(); + HDprintf(" opened group using an invalid GAPL!\n"); + H5Gclose(group_id); + PART_ERROR(H5Gopen_invalid_gapl); + } + + PASSED(); + } + PART_END(H5Gopen_invalid_gapl); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(group_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that H5Gclose doesn't succeed for an + * invalid group ID. + */ +static int +test_close_group_invalid_id(void) +{ + herr_t err_ret = -1; + + TESTING("H5Gclose with an invalid group ID"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic group aren't supported with this connector\n"); + return 0; + } + + H5E_BEGIN_TRY + { + err_ret = H5Gclose(H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" close a group with an invalid ID!\n"); + goto error; + } + + PASSED(); + + return 0; + +error: + return 1; +} + +/* + * A test to check that a GCPL used for group creation can + * be persisted and that a valid copy of that GCPL can be + * retrieved later with a call to H5Gget_create_plist. + */ +static int +test_group_property_lists(void) +{ + unsigned dummy_prop_val = GROUP_PROPERTY_LIST_TEST_DUMMY_VAL; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id1 = H5I_INVALID_HID, group_id2 = H5I_INVALID_HID; + hid_t gcpl_id1 = H5I_INVALID_HID, gcpl_id2 = H5I_INVALID_HID; + + TESTING_MULTIPART("group property list operations"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_GET_PLIST) || !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, property list, creation order aren't supported " + "with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file\n"); + goto error; + } + + if ((container_group = H5Gopen2(file_id, GROUP_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group\n"); + goto error; + } + + if ((gcpl_id1 = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create GCPL\n"); + goto error; + } + + if (H5Pset_link_creation_order(gcpl_id1, dummy_prop_val) < 0) { + H5_FAILED(); + HDprintf(" couldn't set property on GCPL\n"); + goto error; + } + + /* Create the group in the file */ + if ((group_id1 = H5Gcreate2(container_group, GROUP_PROPERTY_LIST_TEST_GROUP_NAME1, H5P_DEFAULT, gcpl_id1, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group\n"); + goto error; + } + + /* Create the second group using H5P_DEFAULT for the GCPL */ + if ((group_id2 = H5Gcreate2(container_group, GROUP_PROPERTY_LIST_TEST_GROUP_NAME2, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group\n"); + goto error; + } + + if (H5Pclose(gcpl_id1) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Gget_create_plist) + { + TESTING_2("H5Gget_create_plist"); + + /* Try to retrieve copies of the two property lists, one which has the property set and one which + * does not */ + if ((gcpl_id1 = H5Gget_create_plist(group_id1)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get GCPL\n"); + PART_ERROR(H5Gget_create_plist); + } + + if ((gcpl_id2 = H5Gget_create_plist(group_id2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get GCPL\n"); + PART_ERROR(H5Gget_create_plist); + } + + /* Ensure that property list 1 has the property set and property list 2 does not */ + dummy_prop_val = 0; + + if (H5Pget_link_creation_order(gcpl_id1, &dummy_prop_val) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve GCPL property value\n"); + PART_ERROR(H5Gget_create_plist); + } + + if (dummy_prop_val != GROUP_PROPERTY_LIST_TEST_DUMMY_VAL) { + H5_FAILED(); + HDprintf(" retrieved GCPL property value '%llu' did not match expected value '%llu'\n", + (unsigned long long)dummy_prop_val, + (unsigned long long)GROUP_PROPERTY_LIST_TEST_DUMMY_VAL); + PART_ERROR(H5Gget_create_plist); + } + + dummy_prop_val = 0; + + if (H5Pget_link_creation_order(gcpl_id2, &dummy_prop_val) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve GCPL property value\n"); + PART_ERROR(H5Gget_create_plist); + } + + if (dummy_prop_val == GROUP_PROPERTY_LIST_TEST_DUMMY_VAL) { + H5_FAILED(); + HDprintf(" retrieved GCPL property value '%llu' matched control value '%llu' when it " + "shouldn't have\n", + (unsigned long long)dummy_prop_val, + (unsigned long long)GROUP_PROPERTY_LIST_TEST_DUMMY_VAL); + PART_ERROR(H5Gget_create_plist); + } + + PASSED(); + } + PART_END(H5Gget_create_plist); + + /* Now see if we can still retrieve copies of the property lists upon opening + * (instead of creating) a group. If they were reconstructed properly upon file + * open, the creation property lists should also have the same test values + * as set before. + */ + if (gcpl_id1 >= 0) { + H5E_BEGIN_TRY + { + H5Pclose(gcpl_id1); + } + H5E_END_TRY; + gcpl_id1 = H5I_INVALID_HID; + } + if (gcpl_id2 >= 0) { + H5E_BEGIN_TRY + { + H5Pclose(gcpl_id2); + } + H5E_END_TRY; + gcpl_id2 = H5I_INVALID_HID; + } + if (group_id1 >= 0) { + H5E_BEGIN_TRY + { + H5Gclose(group_id1); + } + H5E_END_TRY; + group_id1 = H5I_INVALID_HID; + } + if (group_id2 >= 0) { + H5E_BEGIN_TRY + { + H5Gclose(group_id2); + } + H5E_END_TRY; + group_id2 = H5I_INVALID_HID; + } + + PART_BEGIN(H5Gget_create_plist_reopened) + { + TESTING_2("H5Gget_create_plist after re-opening a group"); + + if ((group_id1 = H5Gopen2(container_group, GROUP_PROPERTY_LIST_TEST_GROUP_NAME1, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't open group\n"); + PART_ERROR(H5Gget_create_plist_reopened); + } + + if ((group_id2 = H5Gopen2(container_group, GROUP_PROPERTY_LIST_TEST_GROUP_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't open group\n"); + PART_ERROR(H5Gget_create_plist_reopened); + } + + if ((gcpl_id1 = H5Gget_create_plist(group_id1)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get property list\n"); + PART_ERROR(H5Gget_create_plist_reopened); + } + + if ((gcpl_id2 = H5Gget_create_plist(group_id2)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get property list\n"); + PART_ERROR(H5Gget_create_plist_reopened); + } + + /* Re-check the property values */ + dummy_prop_val = 0; + + if (H5Pget_link_creation_order(gcpl_id1, &dummy_prop_val) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve GCPL property value\n"); + PART_ERROR(H5Gget_create_plist_reopened); + } + + if (dummy_prop_val != GROUP_PROPERTY_LIST_TEST_DUMMY_VAL) { + H5_FAILED(); + HDprintf(" retrieved GCPL property value '%llu' did not match expected value '%llu'\n", + (unsigned long long)dummy_prop_val, + (unsigned long long)GROUP_PROPERTY_LIST_TEST_DUMMY_VAL); + PART_ERROR(H5Gget_create_plist_reopened); + } + + dummy_prop_val = 0; + + if (H5Pget_link_creation_order(gcpl_id2, &dummy_prop_val) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve GCPL property value\n"); + PART_ERROR(H5Gget_create_plist_reopened); + } + + if (dummy_prop_val == GROUP_PROPERTY_LIST_TEST_DUMMY_VAL) { + H5_FAILED(); + HDprintf(" retrieved GCPL property value '%llu' matched control value '%llu' when it " + "shouldn't have\n", + (unsigned long long)dummy_prop_val, + (unsigned long long)GROUP_PROPERTY_LIST_TEST_DUMMY_VAL); + PART_ERROR(H5Gget_create_plist_reopened); + } + + PASSED(); + } + PART_END(H5Gget_create_plist_reopened); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Pclose(gcpl_id1) < 0) + TEST_ERROR; + if (H5Pclose(gcpl_id2) < 0) + TEST_ERROR; + if (H5Gclose(group_id1) < 0) + TEST_ERROR; + if (H5Gclose(group_id2) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(gcpl_id1); + H5Pclose(gcpl_id2); + H5Gclose(group_id1); + H5Gclose(group_id2); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test for the functionality of H5Gget_info(_by_idx). + */ +static int +test_get_group_info(void) +{ + H5G_info_t group_info; + unsigned i; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t parent_group_id = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + char group_name[NAME_BUF_SIZE]; + + TESTING_MULTIPART("retrieval of group info"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_MORE) || !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file or group, creation order aren't supported with this " + "connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, GROUP_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group\n"); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create a GCPL\n"); + goto error; + } + + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0) { + H5_FAILED(); + HDprintf(" couldn't enable link creation order tracking and indexing on GCPL\n"); + goto error; + } + + if ((parent_group_id = H5Gcreate2(container_group, GROUP_GET_INFO_TEST_GROUP_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", GROUP_GET_INFO_TEST_GROUP_NAME); + goto error; + } + + /* Create multiple groups under the parent group */ + for (i = 0; i < GROUP_GET_INFO_TEST_GROUP_NUMB; i++) { + /* Create the groups with a reverse-ordering naming scheme to test creation order */ + HDsnprintf(group_name, NAME_BUF_SIZE, "group %02u", + (unsigned)(GROUP_GET_INFO_TEST_GROUP_NUMB - i - 1)); + + if ((group_id = H5Gcreate2(parent_group_id, group_name, H5P_DEFAULT, gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", group_name); + goto error; + } + + if (H5Gclose(group_id) < 0) + TEST_ERROR; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Gget_info) + { + TESTING_2("retrieval of group info with H5Gget_info"); + + memset(&group_info, 0, sizeof(group_info)); + + /* Retrieve information about the parent group */ + if (H5Gget_info(parent_group_id, &group_info) < 0) { + H5_FAILED(); + HDprintf(" couldn't get group info\n"); + PART_ERROR(H5Gget_info); + } + + if (group_info.nlinks != GROUP_GET_INFO_TEST_GROUP_NUMB) { + H5_FAILED(); + HDprintf(" group's number of links '%lu' doesn't match expected value '%u'\n", + group_info.nlinks, (unsigned int)GROUP_GET_INFO_TEST_GROUP_NUMB); + PART_ERROR(H5Gget_info); + } + + /* + * For the purpose of this test, the max creation order should match + * the number of links in the group. + */ + if (group_info.max_corder != GROUP_GET_INFO_TEST_GROUP_NUMB) { + H5_FAILED(); + HDprintf(" group's max creation order '%lld' doesn't match expected value '%lld'\n", + (long long)group_info.max_corder, (long long)GROUP_GET_INFO_TEST_GROUP_NUMB); + PART_ERROR(H5Gget_info); + } + + /* Ensure that the storage_type field is at least set to a meaningful value */ + if (group_info.storage_type != H5G_STORAGE_TYPE_SYMBOL_TABLE && + group_info.storage_type != H5G_STORAGE_TYPE_COMPACT && + group_info.storage_type != H5G_STORAGE_TYPE_DENSE && + group_info.storage_type != H5G_STORAGE_TYPE_UNKNOWN) { + H5_FAILED(); + HDprintf(" group info's 'storage_type' field wasn't set to a meaningful value\n"); + PART_ERROR(H5Gget_info); + } + + /* Assume that mounted should be FALSE in this case */ + if (group_info.mounted != FALSE) { + H5_FAILED(); + HDprintf(" group info's 'mounted' field was TRUE when it should have been FALSE\n"); + PART_ERROR(H5Gget_info); + } + + PASSED(); + } + PART_END(H5Gget_info); + + PART_BEGIN(H5Gget_info_by_name) + { + TESTING_2("retrieval of group info with H5Gget_info_by_name"); + + memset(&group_info, 0, sizeof(group_info)); + + /* Retrieve information about the parent group */ + if (H5Gget_info_by_name(container_group, GROUP_GET_INFO_TEST_GROUP_NAME, &group_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get group info by name\n"); + PART_ERROR(H5Gget_info_by_name); + } + + if (group_info.nlinks != GROUP_GET_INFO_TEST_GROUP_NUMB) { + H5_FAILED(); + HDprintf(" group's number of links '%lu' doesn't match expected value '%u'\n", + group_info.nlinks, (unsigned int)GROUP_GET_INFO_TEST_GROUP_NUMB); + PART_ERROR(H5Gget_info_by_name); + } + + /* + * For the purpose of this test, the max creation order should match + * the number of links in the group. + */ + if (group_info.max_corder != GROUP_GET_INFO_TEST_GROUP_NUMB) { + H5_FAILED(); + HDprintf(" group's max creation order '%lld' doesn't match expected value '%lld'\n", + (long long)group_info.max_corder, (long long)GROUP_GET_INFO_TEST_GROUP_NUMB); + PART_ERROR(H5Gget_info_by_name); + } + + /* Ensure that the storage_type field is at least set to a meaningful value */ + if (group_info.storage_type != H5G_STORAGE_TYPE_SYMBOL_TABLE && + group_info.storage_type != H5G_STORAGE_TYPE_COMPACT && + group_info.storage_type != H5G_STORAGE_TYPE_DENSE && + group_info.storage_type != H5G_STORAGE_TYPE_UNKNOWN) { + H5_FAILED(); + HDprintf(" group info's 'storage_type' field wasn't set to a meaningful value\n"); + PART_ERROR(H5Gget_info_by_name); + } + + /* Assume that mounted should be FALSE in this case */ + if (group_info.mounted != FALSE) { + H5_FAILED(); + HDprintf(" group info's 'mounted' field was TRUE when it should have been FALSE\n"); + PART_ERROR(H5Gget_info_by_name); + } + + PASSED(); + } + PART_END(H5Gget_info_by_name); + + PART_BEGIN(H5Gget_info_by_idx_crt_order_increasing) + { + TESTING_2("H5Gget_info_by_idx by creation order in increasing order"); + + for (i = 0; i < GROUP_GET_INFO_TEST_GROUP_NUMB; i++) { + memset(&group_info, 0, sizeof(group_info)); + + /* Retrieve information about each group under the parent group */ + if (H5Gget_info_by_idx(container_group, GROUP_GET_INFO_TEST_GROUP_NAME, H5_INDEX_CRT_ORDER, + H5_ITER_INC, (hsize_t)i, &group_info, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get group info for group at index %u\n", i); + PART_ERROR(H5Gget_info_by_idx_crt_order_increasing); + } + + if (group_info.nlinks != 0) { + H5_FAILED(); + HDprintf(" group's number of links '%lu' doesn't match expected value '%d'\n", + group_info.nlinks, 0); + PART_ERROR(H5Gget_info_by_idx_crt_order_increasing); + } + + if (group_info.max_corder != 0) { + H5_FAILED(); + HDprintf(" group's max creation order '%lld' doesn't match expected value '%d'\n", + (long long)group_info.max_corder, 0); + PART_ERROR(H5Gget_info_by_idx_crt_order_increasing); + } + + /* Ensure that the storage_type field is at least set to a meaningful value */ + if (group_info.storage_type != H5G_STORAGE_TYPE_SYMBOL_TABLE && + group_info.storage_type != H5G_STORAGE_TYPE_COMPACT && + group_info.storage_type != H5G_STORAGE_TYPE_DENSE && + group_info.storage_type != H5G_STORAGE_TYPE_UNKNOWN) { + H5_FAILED(); + HDprintf(" group info's 'storage_type' field wasn't set to a meaningful value\n"); + PART_ERROR(H5Gget_info_by_idx_crt_order_increasing); + } + + /* Assume that mounted should be FALSE in this case */ + if (group_info.mounted != FALSE) { + H5_FAILED(); + HDprintf(" group info's 'mounted' field was TRUE when it should have been FALSE\n"); + PART_ERROR(H5Gget_info_by_idx_crt_order_increasing); + } + } + + PASSED(); + } + PART_END(H5Gget_info_by_idx_crt_order_increasing); + + PART_BEGIN(H5Gget_info_by_idx_crt_order_decreasing) + { + TESTING_2("H5Gget_info_by_idx by creation order in decreasing order"); + + for (i = 0; i < GROUP_GET_INFO_TEST_GROUP_NUMB; i++) { + memset(&group_info, 0, sizeof(group_info)); + + /* Retrieve information about each group under the parent group */ + if (H5Gget_info_by_idx(container_group, GROUP_GET_INFO_TEST_GROUP_NAME, H5_INDEX_CRT_ORDER, + H5_ITER_DEC, (hsize_t)i, &group_info, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get group info for group at index %u\n", i); + PART_ERROR(H5Gget_info_by_idx_crt_order_decreasing); + } + + if (group_info.nlinks != 0) { + H5_FAILED(); + HDprintf(" group's number of links '%lu' doesn't match expected value '%d'\n", + group_info.nlinks, 0); + PART_ERROR(H5Gget_info_by_idx_crt_order_decreasing); + } + + if (group_info.max_corder != 0) { + H5_FAILED(); + HDprintf(" group's max creation order '%lld' doesn't match expected value '%d'\n", + (long long)group_info.max_corder, 0); + PART_ERROR(H5Gget_info_by_idx_crt_order_decreasing); + } + + /* Ensure that the storage_type field is at least set to a meaningful value */ + if (group_info.storage_type != H5G_STORAGE_TYPE_SYMBOL_TABLE && + group_info.storage_type != H5G_STORAGE_TYPE_COMPACT && + group_info.storage_type != H5G_STORAGE_TYPE_DENSE && + group_info.storage_type != H5G_STORAGE_TYPE_UNKNOWN) { + H5_FAILED(); + HDprintf(" group info's 'storage_type' field wasn't set to a meaningful value\n"); + PART_ERROR(H5Gget_info_by_idx_crt_order_decreasing); + } + + /* Assume that mounted should be FALSE in this case */ + if (group_info.mounted != FALSE) { + H5_FAILED(); + HDprintf(" group info's 'mounted' field was TRUE when it should have been FALSE\n"); + PART_ERROR(H5Gget_info_by_idx_crt_order_decreasing); + } + } + + PASSED(); + } + PART_END(H5Gget_info_by_idx_crt_order_decreasing); + + PART_BEGIN(H5Gget_info_by_idx_name_order_increasing) + { + TESTING_2("H5Gget_info_by_idx by alphabetical order in increasing order"); + + for (i = 0; i < GROUP_GET_INFO_TEST_GROUP_NUMB; i++) { + memset(&group_info, 0, sizeof(group_info)); + + /* Retrieve information about each group under the parent group */ + if (H5Gget_info_by_idx(container_group, GROUP_GET_INFO_TEST_GROUP_NAME, H5_INDEX_NAME, + H5_ITER_INC, (hsize_t)i, &group_info, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get group info for group at index %u\n", i); + PART_ERROR(H5Gget_info_by_idx_name_order_increasing); + } + + if (group_info.nlinks != 0) { + H5_FAILED(); + HDprintf(" group's number of links '%lu' doesn't match expected value '%d'\n", + group_info.nlinks, 0); + PART_ERROR(H5Gget_info_by_idx_name_order_increasing); + } + + if (group_info.max_corder != 0) { + H5_FAILED(); + HDprintf(" group's max creation order '%lld' doesn't match expected value '%d'\n", + (long long)group_info.max_corder, 0); + PART_ERROR(H5Gget_info_by_idx_name_order_increasing); + } + + /* Ensure that the storage_type field is at least set to a meaningful value */ + if (group_info.storage_type != H5G_STORAGE_TYPE_SYMBOL_TABLE && + group_info.storage_type != H5G_STORAGE_TYPE_COMPACT && + group_info.storage_type != H5G_STORAGE_TYPE_DENSE && + group_info.storage_type != H5G_STORAGE_TYPE_UNKNOWN) { + H5_FAILED(); + HDprintf(" group info's 'storage_type' field wasn't set to a meaningful value\n"); + PART_ERROR(H5Gget_info_by_idx_name_order_increasing); + } + + /* Assume that mounted should be FALSE in this case */ + if (group_info.mounted != FALSE) { + H5_FAILED(); + HDprintf(" group info's 'mounted' field was TRUE when it should have been FALSE\n"); + PART_ERROR(H5Gget_info_by_idx_name_order_increasing); + } + } + + PASSED(); + } + PART_END(H5Gget_info_by_idx_name_order_increasing); + + PART_BEGIN(H5Gget_info_by_idx_name_order_decreasing) + { + TESTING_2("H5Gget_info_by_idx by alphabetical order in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + for (i = 0; i < GROUP_GET_INFO_TEST_GROUP_NUMB; i++) { + memset(&group_info, 0, sizeof(group_info)); + + /* Retrieve information about each group under the parent group */ + if (H5Gget_info_by_idx(container_group, GROUP_GET_INFO_TEST_GROUP_NAME, H5_INDEX_NAME, + H5_ITER_DEC, (hsize_t)i, &group_info, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get group info for group at index %u\n", i); + PART_ERROR(H5Gget_info_by_idx_name_order_decreasing); + } + + if (group_info.nlinks != 0) { + H5_FAILED(); + HDprintf(" group's number of links '%lld' doesn't match expected value '%lld'\n", + group_info.nlinks, 0); + PART_ERROR(H5Gget_info_by_idx_name_order_decreasing); + } + + if (group_info.max_corder != 0) { + H5_FAILED(); + HDprintf(" group's max creation order '%lld' doesn't match expected value '%lld'\n", + (long long)group_info.max_corder, 0); + PART_ERROR(H5Gget_info_by_idx_name_order_decreasing); + } + + /* Ensure that the storage_type field is at least set to a meaningful value */ + if (group_info.storage_type != H5G_STORAGE_TYPE_SYMBOL_TABLE && + group_info.storage_type != H5G_STORAGE_TYPE_COMPACT && + group_info.storage_type != H5G_STORAGE_TYPE_DENSE && + group_info.storage_type != H5G_STORAGE_TYPE_UNKNOWN) { + H5_FAILED(); + HDprintf(" group info's 'storage_type' field wasn't set to a meaningful value\n"); + PART_ERROR(H5Gget_info_by_idx_name_order_decreasing); + } + + /* Assume that mounted should be FALSE in this case */ + if (group_info.mounted != FALSE) { + H5_FAILED(); + HDprintf(" group info's 'mounted' field was TRUE when it should have been FALSE\n"); + PART_ERROR(H5Gget_info_by_idx_name_order_decreasing); + } + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Gget_info_by_idx_name_order_decreasing); +#endif + } + PART_END(H5Gget_info_by_idx_name_order_decreasing); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(parent_group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(gcpl_id); + H5Gclose(parent_group_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a group's info can't be retrieved when + * H5Gget_info(_by_name/_by_idx) is passed invalid parameters. + */ +static int +test_get_group_info_invalid_params(void) +{ + H5G_info_t group_info; + herr_t err_ret = -1; + hid_t file_id = H5I_INVALID_HID; + + TESTING_MULTIPART("retrieval of group info with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, more group, creation order aren't supported with this " + "connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Gget_info_invalid_loc_id) + { + TESTING_2("H5Gget_info with an invalid loc_id"); + + H5E_BEGIN_TRY + { + err_ret = H5Gget_info(H5I_INVALID_HID, &group_info); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved info of group using H5Gget_info with an invalid loc_id!\n"); + PART_ERROR(H5Gget_info_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Gget_info_invalid_loc_id); + + PART_BEGIN(H5Gget_info_invalid_grp_info_pointer) + { + TESTING_2("H5Gget_info with an invalid group info pointer"); + + H5E_BEGIN_TRY + { + err_ret = H5Gget_info(file_id, NULL); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved info of group using H5Gget_info with invalid group info pointer!\n"); + PART_ERROR(H5Gget_info_invalid_grp_info_pointer); + } + + PASSED(); + } + PART_END(H5Gget_info_invalid_grp_info_pointer); + + PART_BEGIN(H5Gget_info_by_name_invalid_loc_id) + { + TESTING_2("H5Gget_info_by_name with an invalid loc_id"); + + H5E_BEGIN_TRY + { + err_ret = H5Gget_info_by_name(H5I_INVALID_HID, ".", &group_info, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved info of group using H5Gget_info_by_name with an invalid loc_id!\n"); + PART_ERROR(H5Gget_info_by_name_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Gget_info_by_name_invalid_loc_id); + + PART_BEGIN(H5Gget_info_by_name_invalid_grp_name) + { + TESTING_2("H5Gget_info_by_name with an invalid group name"); + + H5E_BEGIN_TRY + { + err_ret = H5Gget_info_by_name(file_id, NULL, &group_info, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved info of group using H5Gget_info_by_name with a NULL name!\n"); + PART_ERROR(H5Gget_info_by_name_invalid_grp_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Gget_info_by_name(file_id, "", &group_info, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf( + " retrieved info of group using H5Gget_info_by_name with an invalid name of ''!\n"); + PART_ERROR(H5Gget_info_by_name_invalid_grp_name); + } + + PASSED(); + } + PART_END(H5Gget_info_by_name_invalid_grp_name); + + PART_BEGIN(H5Gget_info_by_name_invalid_grp_info_pointer) + { + TESTING_2("H5Gget_info_by_name with an invalid group info pointer"); + + H5E_BEGIN_TRY + { + err_ret = H5Gget_info_by_name(file_id, ".", NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved info of group using H5Gget_info_by_name with an invalid group info " + "pointer!\n"); + PART_ERROR(H5Gget_info_by_name_invalid_grp_info_pointer); + } + + PASSED(); + } + PART_END(H5Gget_info_by_name_invalid_grp_info_pointer); + + PART_BEGIN(H5Gget_info_by_name_invalid_lapl) + { + TESTING_2("H5Gget_info_by_name with an invalid LAPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Gget_info_by_name(file_id, ".", &group_info, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved info of group using H5Gget_info_by_name with an invalid LAPL!\n"); + PART_ERROR(H5Gget_info_by_name_invalid_lapl); + } + + PASSED(); + } + PART_END(H5Gget_info_by_name_invalid_lapl); + + PART_BEGIN(H5Gget_info_by_idx_invalid_loc_id) + { + TESTING_2("H5Gget_info_by_idx with an invalid loc_id"); + + H5E_BEGIN_TRY + { + err_ret = H5Gget_info_by_idx(H5I_INVALID_HID, ".", H5_INDEX_NAME, H5_ITER_INC, 0, &group_info, + H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved info of group using H5Gget_info_by_idx with an invalid loc_id!\n"); + PART_ERROR(H5Gget_info_by_idx_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Gget_info_by_idx_invalid_loc_id); + + PART_BEGIN(H5Gget_info_by_idx_invalid_grp_name) + { + TESTING_2("H5Gget_info_by_idx with an invalid group name"); + + H5E_BEGIN_TRY + { + err_ret = H5Gget_info_by_idx(file_id, NULL, H5_INDEX_NAME, H5_ITER_INC, 0, &group_info, + H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved info of group using H5Gget_info_by_idx with a NULL group name!\n"); + PART_ERROR(H5Gget_info_by_idx_invalid_grp_name); + } + + H5E_BEGIN_TRY + { + err_ret = + H5Gget_info_by_idx(file_id, "", H5_INDEX_NAME, H5_ITER_INC, 0, &group_info, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved info of group using H5Gget_info_by_idx with an invalid group name of " + "''!\n"); + PART_ERROR(H5Gget_info_by_idx_invalid_grp_name); + } + + PASSED(); + } + PART_END(H5Gget_info_by_idx_invalid_grp_name); + + PART_BEGIN(H5Gget_info_by_idx_invalid_index_type) + { + TESTING_2("H5Gget_info_by_idx with an invalid index type"); + + H5E_BEGIN_TRY + { + err_ret = H5Gget_info_by_idx(file_id, ".", H5_INDEX_UNKNOWN, H5_ITER_INC, 0, &group_info, + H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved info of group using H5Gget_info_by_idx with invalid index type " + "H5_INDEX_UNKNOWN!\n"); + PART_ERROR(H5Gget_info_by_idx_invalid_index_type); + } + + H5E_BEGIN_TRY + { + err_ret = + H5Gget_info_by_idx(file_id, ".", H5_INDEX_N, H5_ITER_INC, 0, &group_info, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved info of group using H5Gget_info_by_idx with invalid index type " + "H5_INDEX_N!\n"); + PART_ERROR(H5Gget_info_by_idx_invalid_index_type); + } + + PASSED(); + } + PART_END(H5Gget_info_by_idx_invalid_index_type); + + PART_BEGIN(H5Gget_info_by_idx_invalid_iter_order) + { + TESTING_2("H5Gget_info_by_idx with an invalid iteration order"); + + H5E_BEGIN_TRY + { + err_ret = H5Gget_info_by_idx(file_id, ".", H5_INDEX_NAME, H5_ITER_UNKNOWN, 0, &group_info, + H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved info of group using H5Gget_info_by_idx with invalid iteration order " + "H5_ITER_UNKNOWN!\n"); + PART_ERROR(H5Gget_info_by_idx_invalid_iter_order); + } + + H5E_BEGIN_TRY + { + err_ret = + H5Gget_info_by_idx(file_id, ".", H5_INDEX_NAME, H5_ITER_N, 0, &group_info, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved info of group using H5Gget_info_by_idx with invalid iteration order " + "H5_ITER_N!\n"); + PART_ERROR(H5Gget_info_by_idx_invalid_iter_order); + } + + PASSED(); + } + PART_END(H5Gget_info_by_idx_invalid_iter_order); + + PART_BEGIN(H5Gget_info_by_idx_invalid_grp_info_pointer) + { + TESTING_2("H5Gget_info_by_idx with an invalid group info pointer"); + + H5E_BEGIN_TRY + { + err_ret = H5Gget_info_by_idx(file_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved info of group using H5Gget_info_by_idx with an invalid group info " + "pointer!\n"); + PART_ERROR(H5Gget_info_by_idx_invalid_grp_info_pointer); + } + + PASSED(); + } + PART_END(H5Gget_info_by_idx_invalid_grp_info_pointer); + + PART_BEGIN(H5Gget_info_by_idx_invalid_lapl) + { + TESTING_2("H5Gget_info_by_idx with an invalid LAPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Gget_info_by_idx(file_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, &group_info, + H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" retrieved info of group using H5Gget_info_by_idx with an invalid LAPL!\n"); + PART_ERROR(H5Gget_info_by_idx_invalid_lapl); + } + + PASSED(); + } + PART_END(H5Gget_info_by_idx_invalid_lapl); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test for H5Gflush. + */ +static int +test_flush_group(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + + TESTING("H5Gflush"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH)) { + SKIPPED(); + HDprintf(" API functions for basic file, more group, creation order aren't supported with this " + "connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, GROUP_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, GROUP_FLUSH_GNAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", GROUP_FLUSH_GNAME); + goto error; + } + + /* Flush the group */ + if (H5Gflush(group_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't flush the group '%s'\n", GROUP_FLUSH_GNAME); + goto error; + } + + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that H5Gflush fails when it + * is passed invalid parameters. + */ +static int +test_flush_group_invalid_params(void) +{ + herr_t status; + + TESTING("H5Gflush with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH)) { + SKIPPED(); + HDprintf(" API functions for group flush aren't supported with this connector\n"); + return 0; + } + + H5E_BEGIN_TRY + { + status = H5Gflush(H5I_INVALID_HID); + } + H5E_END_TRY; + + if (status >= 0) { + H5_FAILED(); + HDprintf(" flushed group with invalid ID!\n"); + goto error; + } + + PASSED(); + + return 0; + +error: + return 1; +} + +/* + * A test for H5Grefresh. + */ +static int +test_refresh_group(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + + TESTING("H5Grefresh"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or refresh aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, GROUP_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, GROUP_REFRESH_GNAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", GROUP_REFRESH_GNAME); + goto error; + } + + /* Refresh the group */ + if (H5Grefresh(group_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't refresh the group '%s'\n", GROUP_REFRESH_GNAME); + goto error; + } + + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that H5Grefresh fails when it + * is passed invalid parameters. + */ +static int +test_refresh_group_invalid_params(void) +{ + herr_t status; + + TESTING("H5Grefresh with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH)) { + SKIPPED(); + HDprintf(" API functions for group refresh aren't supported with this connector\n"); + return 0; + } + + H5E_BEGIN_TRY + { + status = H5Grefresh(H5I_INVALID_HID); + } + H5E_END_TRY; + + if (status >= 0) { + H5_FAILED(); + HDprintf(" refreshed group with invalid ID!\n"); + goto error; + } + + PASSED(); + + return 0; + +error: + return 1; +} + +int +H5_api_group_test(void) +{ + size_t i; + int nerrors; + + HDprintf("**********************************************\n"); + HDprintf("* *\n"); + HDprintf("* API Group Tests *\n"); + HDprintf("* *\n"); + HDprintf("**********************************************\n\n"); + + for (i = 0, nerrors = 0; i < ARRAY_LENGTH(group_tests); i++) { + nerrors += (*group_tests[i])() ? 1 : 0; + } + + HDprintf("\n"); + + return nerrors; +} diff --git a/test/API/H5_api_group_test.h b/test/API/H5_api_group_test.h new file mode 100644 index 0000000..baf14c8 --- /dev/null +++ b/test/API/H5_api_group_test.h @@ -0,0 +1,65 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef H5_API_GROUP_TEST_H +#define H5_API_GROUP_TEST_H + +#include "H5_api_test.h" + +int H5_api_group_test(void); + +/********************************************** + * * + * API Group test defines * + * * + **********************************************/ + +#define GROUP_CREATE_UNDER_ROOT_GNAME "/group_under_root" + +#define GROUP_CREATE_UNDER_GROUP_REL_GNAME "child_group" +#define GROUP_CREATE_UNDER_GROUP_ABS_GNAME "child_group/grandchild_group" + +#define GROUP_CREATE_INVALID_PARAMS_GROUP_NAME "/invalid_params_group" + +#define GROUP_CREATE_ANONYMOUS_GROUP_NAME "anon_group" + +#define GROUP_CREATE_INTMD_REL_INTMD_NAME "rel_intmd" +#define GROUP_CREATE_INTMD_REL_END_NAME "rel_end" +#define GROUP_CREATE_INTMD_ABS_INTMD_NAME "abs_intmd" +#define GROUP_CREATE_INTMD_ABS_END_NAME "abs_end" +#define GROUP_CREATE_INTMD_MULT_INTMD1_NAME "mult_intmd1" +#define GROUP_CREATE_INTMD_MULT_INTMD2_NAME "mult_intmd2" +#define GROUP_CREATE_INTMD_MULT_END_NAME "mult_end" + +#define OPEN_NONEXISTENT_GROUP_TEST_GNAME "/nonexistent_group" + +#define GROUP_PROPERTY_LIST_TEST_GROUP_NAME1 "property_list_test_group1" +#define GROUP_PROPERTY_LIST_TEST_GROUP_NAME2 "property_list_test_group2" +#define GROUP_PROPERTY_LIST_TEST_DUMMY_VAL H5P_CRT_ORDER_TRACKED + +#define GROUP_GET_INFO_TEST_GROUP_NAME "group_info_test" +#define GROUP_GET_INFO_TEST_GROUP_NUMB 16 + +#define GROUP_FLUSH_GNAME "group_flush_test" + +#define GROUP_REFRESH_GNAME "group_refresh_test" + +#define NAME_BUF_SIZE 64 +#define GROUP_NUMB 16 + +#define MANY_GROUP_CREATIONS_GNAME "home_for_many_groups" +#define GROUP_NUMB_MANY 100u + +#define DEEP_GROUP_CREATIONS_GNAME "home_for_deep_groups" +#define GROUP_DEPTH 100u + +#endif diff --git a/test/API/H5_api_link_test.c b/test/API/H5_api_link_test.c new file mode 100644 index 0000000..9a8c65a --- /dev/null +++ b/test/API/H5_api_link_test.c @@ -0,0 +1,27072 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "H5_api_link_test.h" + +/* + * TODO: add link tests for short-circuit success in operator callback + */ + +static int test_create_hard_link(void); +static int test_create_hard_link_long_name(void); +static int test_create_hard_link_many(void); +static int test_create_hard_link_same_loc(void); +static int test_create_hard_link_invalid_params(void); +static int test_create_soft_link_existing_relative(void); +static int test_create_soft_link_existing_absolute(void); +static int test_create_soft_link_dangling_relative(void); +static int test_create_soft_link_dangling_absolute(void); +static int test_create_soft_link_long_name(void); +static int test_create_soft_link_many(void); +static int test_create_soft_link_invalid_params(void); +static int test_create_external_link(void); +static int test_create_external_link_dangling(void); +static int test_create_external_link_multi(void); +static int test_create_external_link_ping_pong(void); +static int test_create_external_link_invalid_params(void); +static int test_create_user_defined_link(void); +static int test_create_user_defined_link_invalid_params(void); +static int test_delete_link(void); +static int test_delete_link_reset_grp_max_crt_order(void); +static int test_delete_link_invalid_params(void); +static int test_copy_link(void); +static int test_copy_links_into_group_with_links(void); +static int test_copy_link_across_files(void); +static int test_copy_link_invalid_params(void); +static int test_move_link(void); +static int test_move_links_into_group_with_links(void); +static int test_move_link_across_files(void); +static int test_move_link_reset_grp_max_crt_order(void); +static int test_move_link_invalid_params(void); +static int test_get_link_val(void); +static int test_get_link_val_invalid_params(void); +static int test_get_link_info(void); +static int test_get_link_info_invalid_params(void); +static int test_get_link_name(void); +static int test_get_link_name_invalid_params(void); +static int test_link_iterate_hard_links(void); +static int test_link_iterate_soft_links(void); +static int test_link_iterate_external_links(void); +static int test_link_iterate_ud_links(void); +static int test_link_iterate_mixed_links(void); +static int test_link_iterate_invalid_params(void); +static int test_link_iterate_0_links(void); +static int test_link_visit_hard_links_no_cycles(void); +static int test_link_visit_soft_links_no_cycles(void); +static int test_link_visit_external_links_no_cycles(void); +static int test_link_visit_ud_links_no_cycles(void); +static int test_link_visit_mixed_links_no_cycles(void); +static int test_link_visit_hard_links_cycles(void); +static int test_link_visit_soft_links_cycles(void); +static int test_link_visit_external_links_cycles(void); +static int test_link_visit_ud_links_cycles(void); +static int test_link_visit_mixed_links_cycles(void); +static int test_link_visit_invalid_params(void); +static int test_link_visit_0_links(void); + +static herr_t link_iter_hard_links_cb(hid_t group_id, const char *name, const H5L_info2_t *info, + void *op_data); +static herr_t link_iter_soft_links_cb(hid_t group_id, const char *name, const H5L_info2_t *info, + void *op_data); +#ifndef NO_EXTERNAL_LINKS +static herr_t link_iter_external_links_cb(hid_t group_id, const char *name, const H5L_info2_t *info, + void *op_data); +#endif +#ifndef NO_USER_DEFINED_LINKS +static herr_t link_iter_ud_links_cb(hid_t group_id, const char *name, const H5L_info2_t *info, void *op_data); +#endif +#if !defined(NO_EXTERNAL_LINKS) && !defined(NO_USER_DEFINED_LINKS) +static herr_t link_iter_mixed_links_cb(hid_t group_id, const char *name, const H5L_info2_t *info, + void *op_data); +#endif +static herr_t link_iter_invalid_params_cb(hid_t group_id, const char *name, const H5L_info2_t *info, + void *op_data); +static herr_t link_iter_0_links_cb(hid_t group_id, const char *name, const H5L_info2_t *info, void *op_data); +#if !defined(NO_EXTERNAL_LINKS) && !defined(NO_USER_DEFINED_LINKS) +static herr_t link_iter_idx_saving_cb(hid_t group_id, const char *name, const H5L_info2_t *info, + void *op_data); +#endif + +static herr_t link_visit_hard_links_no_cycles_cb(hid_t group_id, const char *name, const H5L_info2_t *info, + void *op_data); +static herr_t link_visit_soft_links_no_cycles_cb(hid_t group_id, const char *name, const H5L_info2_t *info, + void *op_data); +#ifndef NO_EXTERNAL_LINKS +static herr_t link_visit_external_links_no_cycles_cb(hid_t group_id, const char *name, + const H5L_info2_t *info, void *op_data); +#endif +#ifndef NO_USER_DEFINED_LINKS +static herr_t link_visit_ud_links_no_cycles_cb(hid_t group_id, const char *name, const H5L_info2_t *info, + void *op_data); +#endif +#if !defined(NO_EXTERNAL_LINKS) && !defined(NO_USER_DEFINED_LINKS) +static herr_t link_visit_mixed_links_no_cycles_cb(hid_t group_id, const char *name, const H5L_info2_t *info, + void *op_data); +#endif +static herr_t link_visit_hard_links_cycles_cb(hid_t group_id, const char *name, const H5L_info2_t *info, + void *op_data); +static herr_t link_visit_soft_links_cycles_cb(hid_t group_id, const char *name, const H5L_info2_t *info, + void *op_data); +#ifndef NO_EXTERNAL_LINKS +static herr_t link_visit_external_links_cycles_cb(hid_t group_id, const char *name, const H5L_info2_t *info, + void *op_data); +#endif +#ifndef NO_USER_DEFINED_LINKS +static herr_t link_visit_ud_links_cycles_cb(hid_t group_id, const char *name, const H5L_info2_t *info, + void *op_data); +#endif +#if !defined(NO_EXTERNAL_LINKS) && !defined(NO_USER_DEFINED_LINKS) +static herr_t link_visit_mixed_links_cycles_cb(hid_t group_id, const char *name, const H5L_info2_t *info, + void *op_data); +#endif +static herr_t link_visit_invalid_params_cb(hid_t group_id, const char *name, const H5L_info2_t *info, + void *op_data); +static herr_t link_visit_0_links_cb(hid_t group_id, const char *name, const H5L_info2_t *info, void *op_data); + +/* + * The array of link tests to be performed. + */ +static int (*link_tests[])(void) = { + test_create_hard_link, + test_create_hard_link_long_name, + test_create_hard_link_many, + test_create_hard_link_same_loc, + test_create_hard_link_invalid_params, + test_create_soft_link_existing_relative, + test_create_soft_link_existing_absolute, + test_create_soft_link_dangling_relative, + test_create_soft_link_dangling_absolute, + test_create_soft_link_long_name, + test_create_soft_link_many, + test_create_soft_link_invalid_params, + test_create_external_link, + test_create_external_link_dangling, + test_create_external_link_multi, + test_create_external_link_ping_pong, + test_create_external_link_invalid_params, + test_create_user_defined_link, + test_create_user_defined_link_invalid_params, + test_delete_link, + test_delete_link_reset_grp_max_crt_order, + test_delete_link_invalid_params, + test_copy_link, + test_copy_links_into_group_with_links, + test_copy_link_across_files, + test_copy_link_invalid_params, + test_move_link, + test_move_links_into_group_with_links, + test_move_link_across_files, + test_move_link_reset_grp_max_crt_order, + test_move_link_invalid_params, + test_get_link_val, + test_get_link_val_invalid_params, + test_get_link_info, + test_get_link_info_invalid_params, + test_get_link_name, + test_get_link_name_invalid_params, + test_link_iterate_hard_links, + test_link_iterate_soft_links, + test_link_iterate_external_links, + test_link_iterate_ud_links, + test_link_iterate_mixed_links, + test_link_iterate_invalid_params, + test_link_iterate_0_links, + test_link_visit_hard_links_no_cycles, + test_link_visit_soft_links_no_cycles, + test_link_visit_external_links_no_cycles, + test_link_visit_ud_links_no_cycles, + test_link_visit_mixed_links_no_cycles, + test_link_visit_hard_links_cycles, + test_link_visit_soft_links_cycles, + test_link_visit_external_links_cycles, + test_link_visit_ud_links_cycles, + test_link_visit_mixed_links_cycles, + test_link_visit_invalid_params, + test_link_visit_0_links, +}; + +/* + * A test to check that a hard link can be created + * using H5Lcreate_hard. + */ +static int +test_create_hard_link(void) +{ + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + + TESTING("hard link creation"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_HARD_LINKS)) { + SKIPPED(); + HDprintf(" API functions for basic file or group, basic or hard link aren't supported with this " + "connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, HARD_LINK_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", HARD_LINK_TEST_GROUP_NAME); + goto error; + } + + if (H5Lcreate_hard(file_id, "/", group_id, HARD_LINK_TEST_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", HARD_LINK_TEST_LINK_NAME); + goto error; + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(group_id, HARD_LINK_TEST_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", HARD_LINK_TEST_LINK_NAME); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link did not exist\n"); + goto error; + } + + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a hard link with a long name can be created + * using H5Lcreate_hard. + */ +static int +test_create_hard_link_long_name(void) +{ + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + char vol_name[5]; + size_t name_len = MAX_NAME_LEN; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + char *objname = NULL; /* Name of object [Long] */ + size_t u; /* Local index variable */ + + TESTING("hard link creation with a long name"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_HARD_LINKS)) { + SKIPPED(); + HDprintf(" API functions for basic file or group, basic or hard link aren't supported with this " + "connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, HARD_LINK_TEST_GROUP_LONG_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", HARD_LINK_TEST_GROUP_NAME); + goto error; + } + + if (H5VLget_connector_name(file_id, vol_name, 5) < 0) { + H5_FAILED(); + HDprintf(" couldn't get VOL connector name\n"); + goto error; + } + + /** for DAOS VOL, max link name supported is 99 (Lexical key) */ + if (strcmp(vol_name, "daos") == 0) + name_len = 99; + + /* Construct very long file name */ + if ((objname = (char *)HDmalloc((size_t)(name_len + 1))) == NULL) + TEST_ERROR; + + for (u = 0; u < name_len; u++) + objname[u] = 'a'; + objname[name_len] = '\0'; + + if (H5Lcreate_hard(file_id, "/", group_id, objname, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link with a long name\n"); + goto error; + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(group_id, objname, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if the link with a long name exists\n"); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link did not exist\n"); + goto error; + } + + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + /* Release memory */ + if (objname) + HDfree(objname); + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + if (objname) + HDfree(objname); + + return 1; +} + +/* + * A test to check that many hard links can be created + * using H5Lcreate_hard. + */ +static int +test_create_hard_link_many(void) +{ + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID, group_id2 = H5I_INVALID_HID; +#ifndef NO_OBJECT_GET_NAME + char objname[HARD_LINK_TEST_GROUP_MANY_NAME_BUF_SIZE]; /* Object name */ +#endif + + TESTING("hard link creation of many links"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_HARD_LINKS)) { + SKIPPED(); + HDprintf( + " API functions for basic file or group, or hard link aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, HARD_LINK_TEST_GROUP_MANY_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", HARD_LINK_TEST_GROUP_NAME); + goto error; + } + + if ((group_id2 = H5Gcreate2(group_id, HARD_LINK_TEST_GROUP_MANY_FINAL_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", HARD_LINK_TEST_GROUP_MANY_FINAL_NAME); + goto error; + } + + if (H5Lcreate_hard(group_id, HARD_LINK_TEST_GROUP_MANY_FINAL_NAME, group_id, "hard1", H5P_DEFAULT, + H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_hard(group_id, "hard1", group_id, "hard2", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_hard(group_id, "hard2", group_id, "hard3", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_hard(group_id, "hard3", group_id, "hard4", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_hard(group_id, "hard4", group_id, "hard5", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_hard(group_id, "hard5", group_id, "hard6", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_hard(group_id, "hard6", group_id, "hard7", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_hard(group_id, "hard7", group_id, "hard8", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_hard(group_id, "hard8", group_id, "hard9", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_hard(group_id, "hard9", group_id, "hard10", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_hard(group_id, "hard10", group_id, "hard11", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_hard(group_id, "hard11", group_id, "hard12", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_hard(group_id, "hard12", group_id, "hard13", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_hard(group_id, "hard13", group_id, "hard14", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_hard(group_id, "hard14", group_id, "hard15", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_hard(group_id, "hard15", group_id, "hard16", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_hard(group_id, "hard16", group_id, "hard17", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_hard(group_id, "hard17", group_id, "hard18", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_hard(group_id, "hard18", group_id, "hard19", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_hard(group_id, "hard19", group_id, "hard20", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_hard(group_id, "hard20", group_id, "hard21", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(group_id, "hard21", H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link 'hard21' exists\n"); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link 'hard21' did not exist\n"); + goto error; + } + + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id2) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + /* Reopen the file and group and verify the hard link */ + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gopen2(container_group, HARD_LINK_TEST_GROUP_MANY_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container sub-group '%s'\n", HARD_LINK_TEST_GROUP_NAME); + goto error; + } + + /* Open the object through last hard link */ + if ((group_id2 = H5Gopen2(group_id, "hard21", H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open the group '%s' with the last hard link 'hard21'\n", + HARD_LINK_TEST_GROUP_MANY_FINAL_NAME); + goto error; + } +#ifndef NO_OBJECT_GET_NAME + /* Check name */ + if (H5Iget_name(group_id2, objname, (size_t)HARD_LINK_TEST_GROUP_MANY_NAME_BUF_SIZE) < 0) { + H5_FAILED(); + HDprintf(" couldn't get the name of the object '%s'\n", HARD_LINK_TEST_GROUP_MANY_FINAL_NAME); + goto error; + } + + if (HDstrcmp(objname, "/" LINK_TEST_GROUP_NAME "/" HARD_LINK_TEST_GROUP_MANY_NAME "/hard21")) { + H5_FAILED(); + HDprintf(" wrong name of the object '%s'\n", objname); + goto error; + } +#endif + + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id2) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(group_id); + H5Gclose(group_id2); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that behavior is correct when using + * the H5L_SAME_LOC macro for H5Lcreate_hard(). + */ +static int +test_create_hard_link_same_loc(void) +{ + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + + TESTING_MULTIPART("hard link creation with H5L_SAME_LOC"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_HARD_LINKS)) { + SKIPPED(); + HDprintf(" API functions for basic file or group, basic or hard link aren't supported with this " + "connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, H5L_SAME_LOC_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", H5L_SAME_LOC_TEST_GROUP_NAME); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5L_SAME_LOC_first_param) + { + TESTING_2("usage of H5L_SAME_LOC for first parameter of H5Lcreate_hard"); + + /* Library functionality for this part of the test is broken */ + if (H5Lcreate_hard(H5L_SAME_LOC, ".", group_id, H5L_SAME_LOC_TEST_LINK_NAME1, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create first link '%s'\n", H5L_SAME_LOC_TEST_LINK_NAME1); + PART_ERROR(H5L_SAME_LOC_first_param); + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(group_id, H5L_SAME_LOC_TEST_LINK_NAME1, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link exists\n"); + PART_ERROR(H5L_SAME_LOC_first_param); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link did not exist\n"); + PART_ERROR(H5L_SAME_LOC_first_param); + } + + PASSED(); + } + PART_END(H5L_SAME_LOC_first_param); + + PART_BEGIN(H5L_SAME_LOC_third_param) + { + TESTING_2("usage of H5L_SAME_LOC for third parameter of H5Lcreate_hard"); + + if (H5Lcreate_hard(group_id, ".", H5L_SAME_LOC, H5L_SAME_LOC_TEST_LINK_NAME2, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create second link '%s'\n", H5L_SAME_LOC_TEST_LINK_NAME2); + PART_ERROR(H5L_SAME_LOC_third_param); + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(group_id, H5L_SAME_LOC_TEST_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", H5L_SAME_LOC_TEST_LINK_NAME2); + PART_ERROR(H5L_SAME_LOC_third_param); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link did not exist\n"); + PART_ERROR(H5L_SAME_LOC_third_param); + } + + PASSED(); + } + PART_END(H5L_SAME_LOC_third_param); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a hard link can't be created when + * H5Lcreate_hard is passed invalid parameters. + */ +static int +test_create_hard_link_invalid_params(void) +{ + herr_t err_ret = -1; + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; +#ifndef NO_PREVENT_HARD_LINKS_ACROSS_FILES + char ext_link_filename[H5_API_TEST_FILENAME_MAX_LENGTH]; +#endif + hid_t ext_file_id = H5I_INVALID_HID; + + TESTING_MULTIPART("hard link creation with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_HARD_LINKS)) { + SKIPPED(); + HDprintf(" API functions for basic file or group, basic or hard link aren't supported with this " + "connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, HARD_LINK_INVALID_PARAMS_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", HARD_LINK_INVALID_PARAMS_TEST_GROUP_NAME); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Lcreate_hard_invalid_cur_loc_id) + { + TESTING_2("H5Lcreate_hard with an invalid cur_loc_id"); + + H5E_BEGIN_TRY + { + err_ret = H5Lcreate_hard(H5I_INVALID_HID, "/", group_id, + HARD_LINK_INVALID_PARAMS_TEST_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created hard link with an invalid cur_loc_id!\n"); + PART_ERROR(H5Lcreate_hard_invalid_cur_loc_id); + } + + PASSED(); + } + PART_END(H5Lcreate_hard_invalid_cur_loc_id); + + PART_BEGIN(H5Lcreate_hard_invalid_cur_name) + { + TESTING_2("H5Lcreate_hard with an invalid cur_name"); + + H5E_BEGIN_TRY + { + err_ret = H5Lcreate_hard(file_id, NULL, group_id, HARD_LINK_INVALID_PARAMS_TEST_LINK_NAME, + H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created hard link with a NULL cur_name!\n"); + PART_ERROR(H5Lcreate_hard_invalid_cur_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Lcreate_hard(file_id, "", group_id, HARD_LINK_INVALID_PARAMS_TEST_LINK_NAME, + H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created hard link with an invalid cur_name of ''!\n"); + PART_ERROR(H5Lcreate_hard_invalid_cur_name); + } + + PASSED(); + } + PART_END(H5Lcreate_hard_invalid_cur_name); + + PART_BEGIN(H5Lcreate_hard_invalid_new_loc_id) + { + TESTING_2("H5Lcreate_hard with an invalid new_loc_id"); + + H5E_BEGIN_TRY + { + err_ret = H5Lcreate_hard(file_id, "/", H5I_INVALID_HID, + HARD_LINK_INVALID_PARAMS_TEST_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created hard link with an invalid new_loc_id!\n"); + PART_ERROR(H5Lcreate_hard_invalid_new_loc_id); + } + + PASSED(); + } + PART_END(H5Lcreate_hard_invalid_new_loc_id); + + PART_BEGIN(H5Lcreate_hard_invalid_new_name) + { + TESTING_2("H5Lcreate_hard with an invalid new_name"); + + H5E_BEGIN_TRY + { + err_ret = H5Lcreate_hard(file_id, "/", group_id, NULL, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created hard link with a NULL new_name!\n"); + PART_ERROR(H5Lcreate_hard_invalid_new_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Lcreate_hard(file_id, "/", group_id, "", H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created hard link with an invalid new_name of ''!\n"); + PART_ERROR(H5Lcreate_hard_invalid_new_name); + } + + PASSED(); + } + PART_END(H5Lcreate_hard_invalid_new_name); + + PART_BEGIN(H5Lcreate_hard_invalid_lcpl) + { + TESTING_2("H5Lcreate_hard with an invalid LCPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Lcreate_hard(file_id, "/", group_id, HARD_LINK_INVALID_PARAMS_TEST_LINK_NAME, + H5I_INVALID_HID, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created hard link with an invalid LCPL!\n"); + PART_ERROR(H5Lcreate_hard_invalid_lcpl); + } + + PASSED(); + } + PART_END(H5Lcreate_hard_invalid_lcpl); + + PART_BEGIN(H5Lcreate_hard_invalid_lapl) + { + TESTING_2("H5Lcreate_hard with an invalid LAPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Lcreate_hard(file_id, "/", group_id, HARD_LINK_INVALID_PARAMS_TEST_LINK_NAME, + H5P_DEFAULT, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created hard link with an invalid LAPL!\n"); + PART_ERROR(H5Lcreate_hard_invalid_lapl); + } + + PASSED(); + } + PART_END(H5Lcreate_hard_invalid_lapl); + + PART_BEGIN(H5Lcreate_hard_invalid_same_loc) + { + TESTING_2("H5Lcreate_hard with the invalid same location"); + + H5E_BEGIN_TRY + { + err_ret = H5Lcreate_hard(H5L_SAME_LOC, "/", H5L_SAME_LOC, + HARD_LINK_INVALID_PARAMS_TEST_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created hard link with the invalid same location!\n"); + PART_ERROR(H5Lcreate_hard_invalid_same_loc); + } + + PASSED(); + } + PART_END(H5Lcreate_hard_invalid_same_loc); + + PART_BEGIN(H5Lcreate_hard_across_files) + { + TESTING_2("H5Lcreate_hard across files"); +#ifndef NO_PREVENT_HARD_LINKS_ACROSS_FILES + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME); + + if ((ext_file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + PART_ERROR(H5Lcreate_hard_across_files); + } + + H5E_BEGIN_TRY + { + err_ret = H5Lcreate_hard(file_id, "/", ext_file_id, HARD_LINK_INVALID_PARAMS_TEST_LINK_NAME, + H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created hard link across files!\n"); + PART_ERROR(H5Lcreate_hard_across_files); + } + + H5E_BEGIN_TRY + { + err_ret = H5Lcreate_hard(ext_file_id, "/", group_id, HARD_LINK_INVALID_PARAMS_TEST_LINK_NAME, + H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created hard link across files!\n"); + PART_ERROR(H5Lcreate_hard_across_files); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lcreate_hard_across_files); +#endif + } + PART_END(H5Lcreate_hard_across_files); + + PART_BEGIN(H5Lcreate_hard_invalid_existence) + { + TESTING_2("invalid link existence after previous invalid H5Lcreate_hard calls"); + + /* Verify the link hasn't been created */ + if ((link_exists = H5Lexists(group_id, HARD_LINK_INVALID_PARAMS_TEST_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", + HARD_LINK_INVALID_PARAMS_TEST_LINK_NAME); + PART_ERROR(H5Lcreate_hard_invalid_existence); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" link existed!\n"); + PART_ERROR(H5Lcreate_hard_invalid_existence); + } + + PASSED(); + } + PART_END(H5Lcreate_hard_invalid_existence); + } + END_MULTIPART; + + TESTING_2("test cleanup"); +#ifndef NO_PREVENT_HARD_LINKS_ACROSS_FILES + if (H5Fclose(ext_file_id) < 0) + TEST_ERROR; +#endif + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(ext_file_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} /* test_create_hard_link_invalid_params */ + +/* + * A test to check that a soft link, which points to an + * existing object with a relative path, can be created. + */ +static int +test_create_soft_link_existing_relative(void) +{ + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t object_id = H5I_INVALID_HID; + + TESTING("soft link creation to existing object by relative path"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_SOFT_LINKS)) { + SKIPPED(); + HDprintf(" API functions for basic file or group, basic or soft link aren't supported with this " + "connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, SOFT_LINK_EXISTING_RELATIVE_TEST_SUBGROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + SOFT_LINK_EXISTING_RELATIVE_TEST_SUBGROUP_NAME); + goto error; + } + + if ((object_id = H5Gcreate2(group_id, SOFT_LINK_EXISTING_RELATIVE_TEST_OBJECT_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to create object '%s' for soft link's target\n", + SOFT_LINK_EXISTING_RELATIVE_TEST_OBJECT_NAME); + goto error; + } + + if (H5Gclose(object_id) < 0) + TEST_ERROR; + + if (H5Lcreate_soft(SOFT_LINK_EXISTING_RELATIVE_TEST_OBJECT_NAME, group_id, + SOFT_LINK_EXISTING_RELATIVE_TEST_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", SOFT_LINK_EXISTING_RELATIVE_TEST_LINK_NAME); + goto error; + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(group_id, SOFT_LINK_EXISTING_RELATIVE_TEST_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", SOFT_LINK_EXISTING_RELATIVE_TEST_LINK_NAME); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link did not exist\n"); + goto error; + } + + if ((object_id = H5Gopen2(group_id, SOFT_LINK_EXISTING_RELATIVE_TEST_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open object '%s' through the soft link\n", + SOFT_LINK_EXISTING_RELATIVE_TEST_OBJECT_NAME); + goto error; + } + + if (H5Gclose(object_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(object_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a soft link, which points to an + * existing object using an absolute path, can be created. + */ +static int +test_create_soft_link_existing_absolute(void) +{ + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID, root_id = H5I_INVALID_HID; + + TESTING("soft link creation to existing object by absolute path"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_SOFT_LINKS)) { + SKIPPED(); + HDprintf(" API functions for basic file or group, basic or soft link aren't supported with this " + "connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, SOFT_LINK_EXISTING_ABSOLUTE_TEST_SUBGROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + SOFT_LINK_EXISTING_ABSOLUTE_TEST_SUBGROUP_NAME); + goto error; + } + + if (H5Lcreate_soft("/", group_id, SOFT_LINK_EXISTING_ABSOLUTE_TEST_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < + 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", SOFT_LINK_EXISTING_ABSOLUTE_TEST_LINK_NAME); + goto error; + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(group_id, SOFT_LINK_EXISTING_ABSOLUTE_TEST_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", SOFT_LINK_EXISTING_ABSOLUTE_TEST_LINK_NAME); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link did not exist\n"); + goto error; + } + + if ((root_id = H5Gopen2(group_id, SOFT_LINK_EXISTING_ABSOLUTE_TEST_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open object pointed to by soft link '%s'\n", + SOFT_LINK_EXISTING_ABSOLUTE_TEST_LINK_NAME); + goto error; + } + + if (H5Gclose(root_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(root_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a soft link, which points to + * an object that doesn't exist by using a relative + * path, can be created. + */ +static int +test_create_soft_link_dangling_relative(void) +{ + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t object_id = H5I_INVALID_HID; + + TESTING("dangling soft link creation to object by relative path"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_SOFT_LINKS)) { + SKIPPED(); + HDprintf(" API functions for basic file or group, basic or soft link aren't supported with this " + "connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, SOFT_LINK_DANGLING_RELATIVE_TEST_SUBGROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + SOFT_LINK_DANGLING_RELATIVE_TEST_SUBGROUP_NAME); + goto error; + } + + if (H5Lcreate_soft(SOFT_LINK_DANGLING_RELATIVE_TEST_OBJECT_NAME, group_id, + SOFT_LINK_DANGLING_RELATIVE_TEST_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", SOFT_LINK_DANGLING_RELATIVE_TEST_LINK_NAME); + goto error; + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(group_id, SOFT_LINK_DANGLING_RELATIVE_TEST_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", SOFT_LINK_DANGLING_RELATIVE_TEST_LINK_NAME); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link did not exist\n"); + goto error; + } + + H5E_BEGIN_TRY + { + object_id = H5Gopen2(group_id, SOFT_LINK_DANGLING_RELATIVE_TEST_LINK_NAME, H5P_DEFAULT); + } + H5E_END_TRY; + + if (object_id >= 0) { + H5_FAILED(); + HDprintf(" opened target of dangling link '%s'!\n", SOFT_LINK_DANGLING_RELATIVE_TEST_LINK_NAME); + H5Gclose(object_id); + goto error; + } + + if ((object_id = H5Gcreate2(group_id, SOFT_LINK_DANGLING_RELATIVE_TEST_OBJECT_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to create object '%s' for soft link's target\n", + SOFT_LINK_DANGLING_RELATIVE_TEST_OBJECT_NAME); + goto error; + } + + if (H5Gclose(object_id) < 0) + TEST_ERROR; + + if ((object_id = H5Gopen2(group_id, SOFT_LINK_DANGLING_RELATIVE_TEST_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to open object pointed to by soft link '%s'\n", + SOFT_LINK_DANGLING_RELATIVE_TEST_LINK_NAME); + goto error; + } + + if (H5Gclose(object_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(object_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a soft link, which points to an + * object that doesn't exist by using an absolute path, + * can be created. + */ +static int +test_create_soft_link_dangling_absolute(void) +{ + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t object_id = H5I_INVALID_HID; + + TESTING("dangling soft link creation to object by absolute path"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_SOFT_LINKS)) { + SKIPPED(); + HDprintf(" API functions for basic file or group, basic or soft link aren't supported with this " + "connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, SOFT_LINK_DANGLING_ABSOLUTE_TEST_SUBGROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + SOFT_LINK_DANGLING_ABSOLUTE_TEST_SUBGROUP_NAME); + goto error; + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" SOFT_LINK_DANGLING_ABSOLUTE_TEST_SUBGROUP_NAME + "/" SOFT_LINK_DANGLING_ABSOLUTE_TEST_OBJECT_NAME, + group_id, SOFT_LINK_DANGLING_ABSOLUTE_TEST_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", SOFT_LINK_DANGLING_ABSOLUTE_TEST_LINK_NAME); + goto error; + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(group_id, SOFT_LINK_DANGLING_ABSOLUTE_TEST_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", SOFT_LINK_DANGLING_ABSOLUTE_TEST_LINK_NAME); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link did not exist\n"); + goto error; + } + + H5E_BEGIN_TRY + { + object_id = H5Gopen2(group_id, SOFT_LINK_DANGLING_ABSOLUTE_TEST_LINK_NAME, H5P_DEFAULT); + } + H5E_END_TRY; + + if (object_id >= 0) { + H5_FAILED(); + HDprintf(" opened target of dangling link '%s'!\n", SOFT_LINK_DANGLING_ABSOLUTE_TEST_LINK_NAME); + H5Gclose(object_id); + goto error; + } + + if ((object_id = H5Gcreate2(group_id, SOFT_LINK_DANGLING_ABSOLUTE_TEST_OBJECT_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to create object '%s' for soft link's target\n", + SOFT_LINK_DANGLING_ABSOLUTE_TEST_OBJECT_NAME); + goto error; + } + + if (H5Gclose(object_id) < 0) + TEST_ERROR; + + if ((object_id = H5Gopen2(group_id, SOFT_LINK_DANGLING_ABSOLUTE_TEST_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to open object pointed to by soft link '%s'\n", + SOFT_LINK_DANGLING_ABSOLUTE_TEST_LINK_NAME); + goto error; + } + + if (H5Gclose(object_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(object_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a soft link with a long name can be created + * using H5Lcreate_soft. + */ +static int +test_create_soft_link_long_name(void) +{ + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + char vol_name[5]; + size_t name_len = MAX_NAME_LEN; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + char *objname = NULL; /* Name of object [Long] */ + size_t u; /* Local index variable */ + + TESTING("soft link creation with a long name"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_SOFT_LINKS)) { + SKIPPED(); + HDprintf(" API functions for basic file or group, basic or soft link aren't supported with this " + "connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, SOFT_LINK_TEST_GROUP_LONG_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", SOFT_LINK_TEST_GROUP_LONG_NAME); + goto error; + } + + if (H5VLget_connector_name(file_id, vol_name, 5) < 0) { + H5_FAILED(); + HDprintf(" couldn't get VOL connector name\n"); + goto error; + } + + /** for DAOS VOL, max link name supported is 99 (Lexical key) */ + if (strcmp(vol_name, "daos") == 0) + name_len = 99; + + /* Construct very long file name */ + if ((objname = (char *)HDmalloc((size_t)(name_len + 1))) == NULL) + TEST_ERROR; + + for (u = 0; u < name_len; u++) + objname[u] = 'b'; + objname[name_len] = '\0'; + + if (H5Lcreate_soft(SOFT_LINK_TEST_LONG_OBJECT_NAME, group_id, objname, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link with a long name\n"); + goto error; + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(group_id, objname, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if the link with a long name exists\n"); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link did not exist\n"); + goto error; + } + + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + /* Release memory */ + if (objname) + HDfree(objname); + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + if (objname) + HDfree(objname); + + return 1; +} + +/* + * A test to check that many soft links can be created + * using H5Lcreate_soft. + */ +static int +test_create_soft_link_many(void) +{ +#ifndef NO_SOFT_LINK_MANY_DANGLING + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t object_id = H5I_INVALID_HID; +#ifndef NO_OBJECT_GET_NAME + char objname[SOFT_LINK_TEST_GROUP_MANY_NAME_BUF_SIZE]; /* Object name */ +#endif +#endif + + TESTING("soft link creation of many links"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_SOFT_LINKS)) { + SKIPPED(); + HDprintf(" API functions for basic file or group, basic or soft link aren't supported with this " + "connector\n"); + return 0; + } + +#ifndef NO_SOFT_LINK_MANY_DANGLING + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, SOFT_LINK_TEST_GROUP_MANY_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", SOFT_LINK_TEST_GROUP_MANY_NAME); + goto error; + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" SOFT_LINK_TEST_GROUP_MANY_NAME + "/" SOFT_LINK_TEST_GROUP_MANY_FINAL_NAME, + group_id, "soft1", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_soft("soft1", group_id, "soft2", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_soft("soft2", group_id, "soft3", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_soft("soft3", group_id, "soft4", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_soft("soft4", group_id, "soft5", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_soft("soft5", group_id, "soft6", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_soft("soft6", group_id, "soft7", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_soft("soft7", group_id, "soft8", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_soft("soft8", group_id, "soft9", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_soft("soft9", group_id, "soft10", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_soft("soft10", group_id, "soft11", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_soft("soft11", group_id, "soft12", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_soft("soft12", group_id, "soft13", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_soft("soft13", group_id, "soft14", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_soft("soft14", group_id, "soft15", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + if (H5Lcreate_soft("soft15", group_id, "soft16", H5P_DEFAULT, H5P_DEFAULT) < 0) + TEST_ERROR; + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(group_id, "soft16", H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link 'soft16' exists\n"); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link 'soft16' did not exist\n"); + goto error; + } + + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + /* Reopen the file and group and verify the hard link */ + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gopen2(container_group, SOFT_LINK_TEST_GROUP_MANY_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container sub-group '%s'\n", SOFT_LINK_TEST_GROUP_MANY_NAME); + goto error; + } + + /* + * XXX: Try to open the object through last soft link. If should fail because it doesn't exist. If + * H5Oopen is available, use that. + */ + H5E_BEGIN_TRY + { + object_id = H5Gopen2(group_id, "soft16", H5P_DEFAULT); + } + H5E_END_TRY; + + if (object_id >= 0) { + H5_FAILED(); + HDprintf(" opened target of dangling soft link '%s'!\n", SOFT_LINK_TEST_GROUP_MANY_NAME); + H5Gclose(object_id); + goto error; + } + + if ((object_id = H5Gcreate2(group_id, SOFT_LINK_TEST_GROUP_MANY_FINAL_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to create object '%s' for soft link's target\n", SOFT_LINK_TEST_GROUP_MANY_NAME); + goto error; + } + + if (H5Gclose(object_id) < 0) + TEST_ERROR; + + /* + * XXX: Open the object through last soft link. It should work this time. If H5Oopen is available, use + * that. + */ + if ((object_id = H5Gopen2(group_id, "soft16", H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to open object pointed to by soft link '%s'\n", SOFT_LINK_TEST_GROUP_MANY_NAME); + goto error; + } +#ifndef NO_OBJECT_GET_NAME + /* Check name */ + if (H5Iget_name(object_id, objname, (size_t)SOFT_LINK_TEST_GROUP_MANY_NAME_BUF_SIZE) < 0) { + H5_FAILED(); + HDprintf(" couldn't get the name of the object 'soft16'\n"); + goto error; + } + + if (HDstrcmp(objname, "/" LINK_TEST_GROUP_NAME "/" SOFT_LINK_TEST_GROUP_MANY_NAME "/soft16")) { + H5_FAILED(); + HDprintf(" wrong name of the object '%s'\n", objname); + goto error; + } +#endif + + if (H5Gclose(object_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(object_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +#else + SKIPPED(); + return 0; +#endif +} + +/* + * A test to check that a soft link can't be created + * when H5Lcreate_soft is passed invalid parameters. + */ +static int +test_create_soft_link_invalid_params(void) +{ + herr_t err_ret = -1; + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + + TESTING_MULTIPART("soft link creation with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_SOFT_LINKS)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, or link aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, SOFT_LINK_INVALID_PARAMS_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", SOFT_LINK_INVALID_PARAMS_TEST_GROUP_NAME); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Lcreate_soft_invalid_link_target) + { + TESTING_2("H5Lcreate_soft with an invalid link target"); + + H5E_BEGIN_TRY + { + err_ret = H5Lcreate_soft(NULL, group_id, SOFT_LINK_INVALID_PARAMS_TEST_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created soft link '%s' with an invalid link target!\n", + SOFT_LINK_INVALID_PARAMS_TEST_LINK_NAME); + PART_ERROR(H5Lcreate_soft_invalid_link_target); + } + + H5E_BEGIN_TRY + { + err_ret = H5Lcreate_soft("", group_id, SOFT_LINK_INVALID_PARAMS_TEST_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created soft link '%s' with an invalid link target!\n", + SOFT_LINK_INVALID_PARAMS_TEST_LINK_NAME); + PART_ERROR(H5Lcreate_soft_invalid_link_target); + } + + PASSED(); + } + PART_END(H5Lcreate_soft_invalid_link_target); + + PART_BEGIN(H5Lcreate_soft_invalid_link_loc_id) + { + TESTING_2("H5Lcreate_soft with an invalid link_loc_id"); + + H5E_BEGIN_TRY + { + err_ret = H5Lcreate_soft("/", H5I_INVALID_HID, SOFT_LINK_INVALID_PARAMS_TEST_LINK_NAME, + H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created soft link '%s' with an invalid link_loc_id!\n", + SOFT_LINK_INVALID_PARAMS_TEST_LINK_NAME); + PART_ERROR(H5Lcreate_soft_invalid_link_loc_id); + } + + PASSED(); + } + PART_END(H5Lcreate_soft_invalid_link_loc_id); + + PART_BEGIN(H5Lcreate_soft_invalid_link_name) + { + TESTING_2("H5Lcreate_soft with an invalid link name"); + + H5E_BEGIN_TRY + { + err_ret = H5Lcreate_soft("/", group_id, NULL, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created soft link '%s' with a NULL link name!\n", + SOFT_LINK_INVALID_PARAMS_TEST_LINK_NAME); + PART_ERROR(H5Lcreate_soft_invalid_link_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Lcreate_soft("/", group_id, "", H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created soft link '%s' with an invalid link name of ''!\n", + SOFT_LINK_INVALID_PARAMS_TEST_LINK_NAME); + PART_ERROR(H5Lcreate_soft_invalid_link_name); + } + + PASSED(); + } + PART_END(H5Lcreate_soft_invalid_link_name); + + PART_BEGIN(H5Lcreate_soft_invalid_lcpl) + { + TESTING_2("H5Lcreate_soft with an invalid LCPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Lcreate_soft("/", group_id, SOFT_LINK_INVALID_PARAMS_TEST_LINK_NAME, + H5I_INVALID_HID, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created soft link '%s' with an invalid LCPL!\n", + SOFT_LINK_INVALID_PARAMS_TEST_LINK_NAME); + PART_ERROR(H5Lcreate_soft_invalid_lcpl); + } + + PASSED(); + } + PART_END(H5Lcreate_soft_invalid_lcpl); + + PART_BEGIN(H5Lcreate_soft_invalid_lapl) + { + TESTING_2("H5Lcreate_soft with an invalid LAPL"); +#ifndef NO_INVALID_PROPERTY_LIST_TESTS + H5E_BEGIN_TRY + { + err_ret = H5Lcreate_soft("/", group_id, SOFT_LINK_INVALID_PARAMS_TEST_LINK_NAME, H5P_DEFAULT, + H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created soft link '%s' with an invalid LAPL!\n", + SOFT_LINK_INVALID_PARAMS_TEST_LINK_NAME); + PART_ERROR(H5Lcreate_soft_invalid_lapl); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lcreate_soft_invalid_lapl); +#endif + } + PART_END(H5Lcreate_soft_invalid_lapl); + + PART_BEGIN(H5Lcreate_soft_invalid_existence) + { + TESTING_2("invalid link existence after previous invalid H5Lcreate_soft calls"); + + /* Verify the link hasn't been created */ + if ((link_exists = H5Lexists(group_id, SOFT_LINK_INVALID_PARAMS_TEST_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", + SOFT_LINK_INVALID_PARAMS_TEST_LINK_NAME); + PART_ERROR(H5Lcreate_soft_invalid_existence); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" link '%s' existed!\n", SOFT_LINK_INVALID_PARAMS_TEST_LINK_NAME); + PART_ERROR(H5Lcreate_soft_invalid_existence); + } + + PASSED(); + } + PART_END(H5Lcreate_soft_invalid_existence); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that an external link can be created + * using H5Lcreate_external. + */ +static int +test_create_external_link(void) +{ +#ifndef NO_EXTERNAL_LINKS + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t root_id = H5I_INVALID_HID; + char ext_link_filename[H5_API_TEST_FILENAME_MAX_LENGTH]; +#endif + + TESTING("external link creation to existing object"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_EXTERNAL_LINKS)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, basic link, or external link aren't supported " + "with this connector\n"); + return 0; + } + +#ifndef NO_EXTERNAL_LINKS + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", EXTERNAL_LINK_TEST_FILE_NAME); + + if ((file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + goto error; + } + + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, EXTERNAL_LINK_TEST_SUBGROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", EXTERNAL_LINK_TEST_SUBGROUP_NAME); + goto error; + } + + if (H5Lcreate_external(ext_link_filename, "/", group_id, EXTERNAL_LINK_TEST_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", EXTERNAL_LINK_TEST_LINK_NAME); + goto error; + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(group_id, EXTERNAL_LINK_TEST_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", EXTERNAL_LINK_TEST_LINK_NAME); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link did not exist\n"); + goto error; + } + + if ((root_id = H5Gopen2(group_id, EXTERNAL_LINK_TEST_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open root group of other file using external link '%s'\n", + EXTERNAL_LINK_TEST_LINK_NAME); + goto error; + } + + if (H5Gclose(root_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(root_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +#else + SKIPPED(); + return 0; +#endif +} + +/* + * A test to check that an external link, which points to an + * object that doesn't exist by using an absolute path, can + * be created. + */ +static int +test_create_external_link_dangling(void) +{ +#ifndef NO_EXTERNAL_LINKS + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID, ext_file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t object_id = H5I_INVALID_HID; + char ext_link_filename[H5_API_TEST_FILENAME_MAX_LENGTH]; +#endif + + TESTING("dangling external link creation"); + +#ifndef NO_EXTERNAL_LINKS + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_EXTERNAL_LINKS)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, basic link, or external link aren't supported " + "with this connector\n"); + return 0; + } + + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", EXTERNAL_LINK_TEST_FILE_NAME); + + if ((ext_file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + goto error; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, EXTERNAL_LINK_TEST_DANGLING_SUBGROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", EXTERNAL_LINK_TEST_DANGLING_SUBGROUP_NAME); + goto error; + } + + if (H5Lcreate_external(ext_link_filename, "/" EXTERNAL_LINK_TEST_DANGLING_OBJECT_NAME, group_id, + EXTERNAL_LINK_TEST_DANGLING_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dangling external link '%s'\n", EXTERNAL_LINK_TEST_DANGLING_LINK_NAME); + goto error; + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(group_id, EXTERNAL_LINK_TEST_DANGLING_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", EXTERNAL_LINK_TEST_DANGLING_LINK_NAME); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link did not exist\n"); + goto error; + } + + H5E_BEGIN_TRY + { + object_id = H5Gopen2(group_id, EXTERNAL_LINK_TEST_DANGLING_LINK_NAME, H5P_DEFAULT); + } + H5E_END_TRY; + + if (object_id >= 0) { + H5_FAILED(); + HDprintf(" opened non-existent object in other file using dangling external link '%s'!\n", + EXTERNAL_LINK_TEST_DANGLING_LINK_NAME); + H5Gclose(object_id); + goto error; + } + + if ((object_id = H5Gcreate2(ext_file_id, EXTERNAL_LINK_TEST_DANGLING_OBJECT_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to create object '%s' for external link's target\n", + EXTERNAL_LINK_TEST_DANGLING_OBJECT_NAME); + goto error; + } + + if (H5Gclose(object_id) < 0) + TEST_ERROR; + + if ((object_id = H5Gopen2(group_id, EXTERNAL_LINK_TEST_DANGLING_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to open object pointed to by external link '%s'\n", + EXTERNAL_LINK_TEST_DANGLING_LINK_NAME); + goto error; + } + + if (H5Gclose(object_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + if (H5Fclose(ext_file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(object_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + H5Fclose(ext_file_id); + } + H5E_END_TRY; + + return 1; +#else + SKIPPED(); + return 0; +#endif +} + +/* + * A test to check that an external link to an object + * that crosses several files using H5Lcreate_external. + */ +static int +test_create_external_link_multi(void) +{ +#ifndef NO_EXTERNAL_LINKS + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t group_id2 = H5I_INVALID_HID, group_id3 = H5I_INVALID_HID; + hid_t root_id = H5I_INVALID_HID; + char ext_link_filename1[H5_API_TEST_FILENAME_MAX_LENGTH]; + char ext_link_filename2[H5_API_TEST_FILENAME_MAX_LENGTH]; + char ext_link_filename3[H5_API_TEST_FILENAME_MAX_LENGTH]; + char objname[EXTERNAL_LINK_TEST_MULTI_NAME_BUF_SIZE]; +#endif + + TESTING_MULTIPART("external link creation to an object across several files"); + +#ifndef NO_EXTERNAL_LINKS + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_EXTERNAL_LINKS)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, or external link aren't supported with this " + "connector\n"); + return 0; + } + + BEGIN_MULTIPART + { + PART_BEGIN(H5Lcreate_external_first_file) + { + TESTING_2("Create the first external file to be pointed to"); + + HDsnprintf(ext_link_filename1, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME); + + if ((file_id = H5Fcreate(ext_link_filename1, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", + ext_link_filename1); + PART_ERROR(H5Lcreate_external_first_file); + } + + /* Create object down a path */ + if ((group_id = H5Gcreate2(file_id, "A", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create a group\n"); + PART_ERROR(H5Lcreate_external_first_file); + } + + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close a group\n"); + PART_ERROR(H5Lcreate_external_first_file); + } + + if ((group_id = H5Gcreate2(file_id, "A/B", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create a group\n"); + PART_ERROR(H5Lcreate_external_first_file); + } + + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close a group\n"); + PART_ERROR(H5Lcreate_external_first_file); + } + + if ((group_id = H5Gcreate2(file_id, "A/B/C", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create a group\n"); + PART_ERROR(H5Lcreate_external_first_file); + } + + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close a group\n"); + PART_ERROR(H5Lcreate_external_first_file); + } + + /* Close file */ + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close a group\n"); + PART_ERROR(H5Lcreate_external_first_file); + } + + PASSED(); + } + PART_END(H5Lcreate_external_first_file); + + PART_BEGIN(H5Lcreate_external_second_file) + { + TESTING_2("Create the second external file to be pointed to"); + + HDsnprintf(ext_link_filename2, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME2); + + if ((file_id = H5Fcreate(ext_link_filename2, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", + ext_link_filename2); + PART_ERROR(H5Lcreate_external_second_file); + } + + /* Create object down a path */ + if ((group_id = H5Gcreate2(file_id, "D", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create a group\n"); + PART_ERROR(H5Lcreate_external_second_file); + } + + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close a group\n"); + PART_ERROR(H5Lcreate_external_second_file); + } + + if ((group_id = H5Gcreate2(file_id, "D/E", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create a group\n"); + PART_ERROR(H5Lcreate_external_second_file); + } + + /* Create external link to object in first file */ + if (H5Lcreate_external(ext_link_filename1, "/A/B/C", group_id, "F", H5P_DEFAULT, H5P_DEFAULT) < + 0) { + H5_FAILED(); + HDprintf(" couldn't create external link 'F'\n"); + PART_ERROR(H5Lcreate_external_second_file); + } + + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close a group\n"); + PART_ERROR(H5Lcreate_external_second_file); + } + + /* Close file */ + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close a file\n"); + PART_ERROR(H5Lcreate_external_second_file); + } + + PASSED(); + } + PART_END(H5Lcreate_external_second_file); + + PART_BEGIN(H5Lcreate_external_third_file) + { + TESTING_2("Create the third external file to be pointed to"); + + HDsnprintf(ext_link_filename3, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME3); + + if ((file_id = H5Fcreate(ext_link_filename3, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", + ext_link_filename3); + PART_ERROR(H5Lcreate_external_third_file); + } + + /* Create object down a path */ + if ((group_id = H5Gcreate2(file_id, "G", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create a group\n"); + PART_ERROR(H5Lcreate_external_third_file); + } + + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close a group\n"); + PART_ERROR(H5Lcreate_external_third_file); + } + + if ((group_id = H5Gcreate2(file_id, "G/H", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create a group\n"); + PART_ERROR(H5Lcreate_external_third_file); + } + + /* Create external link to object in second file */ + if (H5Lcreate_external(ext_link_filename2, "/D/E/F", group_id, "I", H5P_DEFAULT, H5P_DEFAULT) < + 0) { + H5_FAILED(); + HDprintf(" couldn't create external link 'I'\n"); + PART_ERROR(H5Lcreate_external_third_file); + } + + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close a group\n"); + PART_ERROR(H5Lcreate_external_third_file); + } + + /* Close file */ + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close a file\n"); + PART_ERROR(H5Lcreate_external_third_file); + } + + PASSED(); + } + PART_END(H5Lcreate_external_third_file); + + PART_BEGIN(H5Lcreate_external_final_file) + { + TESTING_2("Open the file and create the final external link"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + PART_ERROR(H5Lcreate_external_final_file); + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + PART_ERROR(H5Lcreate_external_final_file); + } + + if ((group_id = H5Gcreate2(container_group, EXTERNAL_LINK_TEST_MULTI_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", EXTERNAL_LINK_TEST_MULTI_NAME); + PART_ERROR(H5Lcreate_external_final_file); + } + + if (H5Lcreate_external(ext_link_filename3, "/G/H/I", group_id, "ext_link", H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link 'ext_link'\n"); + PART_ERROR(H5Lcreate_external_final_file); + } + + if ((group_id2 = H5Gopen2(group_id, "ext_link", H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open the group that is the external link\n"); + PART_ERROR(H5Lcreate_external_final_file); + } + + /* Check name */ + if (H5Iget_name(group_id2, objname, (size_t)EXTERNAL_LINK_TEST_MULTI_NAME_BUF_SIZE) < 0) { + H5_FAILED(); + HDprintf(" couldn't get the name of the object '%s'\n", + HARD_LINK_TEST_GROUP_MANY_FINAL_NAME); + PART_ERROR(H5Lcreate_external_final_file); + } + + if (HDstrcmp(objname, "/A/B/C")) { + H5_FAILED(); + HDprintf(" wrong name of the object '%s'\n", objname); + PART_ERROR(H5Lcreate_external_final_file); + } + + /* Create an object in the external file */ + if ((group_id3 = H5Gcreate2(group_id2, "new_group", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create a group 'new_group' in the external file\n"); + PART_ERROR(H5Lcreate_external_final_file); + } + + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close a group\n"); + PART_ERROR(H5Lcreate_external_final_file); + } + + if (H5Gclose(group_id2) < 0) { + H5_FAILED(); + HDprintf(" couldn't close a group\n"); + PART_ERROR(H5Lcreate_external_final_file); + } + + if (H5Gclose(group_id3) < 0) { + H5_FAILED(); + HDprintf(" couldn't close a group\n"); + PART_ERROR(H5Lcreate_external_final_file); + } + + if (H5Gclose(container_group) < 0) { + H5_FAILED(); + HDprintf(" couldn't close a group\n"); + PART_ERROR(H5Lcreate_external_final_file); + } + + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close a file\n"); + PART_ERROR(H5Lcreate_external_final_file); + } + + PASSED(); + } + PART_END(H5Lcreate_external_final_file); + + PART_BEGIN(H5Lcreate_external_object_created) + { + TESTING_2("Check the group being created through the external link"); + + if ((file_id = H5Fopen(ext_link_filename1, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", ext_link_filename1); + PART_ERROR(H5Lcreate_external_object_created); + } + + if ((group_id = H5Gopen2(file_id, "/A/B/C/new_group", H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open a group 'new_group' in the external file\n"); + PART_ERROR(H5Lcreate_external_object_created); + } + + /* Check name */ + if (H5Iget_name(group_id, objname, (size_t)EXTERNAL_LINK_TEST_MULTI_NAME_BUF_SIZE) < 0) { + H5_FAILED(); + HDprintf(" couldn't get the name of the object '/A/B/C/new_group'\n"); + PART_ERROR(H5Lcreate_external_object_created); + } + + if (HDstrcmp(objname, "/A/B/C/new_group")) { + H5_FAILED(); + HDprintf(" wrong name of the object '%s'\n", objname); + PART_ERROR(H5Lcreate_external_object_created); + } + + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close the group\n"); + PART_ERROR(H5Lcreate_external_object_created); + } + + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close the file\n"); + PART_ERROR(H5Lcreate_external_object_created); + } + + PASSED(); + } + PART_END(H5Lcreate_external_object_created); + } + END_MULTIPART; + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(root_id); + H5Gclose(group_id); + H5Gclose(group_id2); + H5Gclose(group_id3); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +#else + SKIPPED(); + return 0; +#endif +} + +/* + * A test to build a file with external link to object that + * goes back and forth between two files a couple of times: + * + * file1:/link1 -> file2: /link2 + * file2:/link2 -> file1: /link3 + * file1:/link3 -> file2: /link4 + * file2:/link4 -> file1: /link5 + * file1:/link5 -> file2: /link6 + * file2:/link6 -> file1: /final + */ +static int +test_create_external_link_ping_pong(void) +{ +#ifndef NO_EXTERNAL_LINKS + hid_t file_id = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t group_id2 = H5I_INVALID_HID; + char ext_link_filename1[H5_API_TEST_FILENAME_MAX_LENGTH]; + char ext_link_filename2[H5_API_TEST_FILENAME_MAX_LENGTH]; + char objname[EXTERNAL_LINK_TEST_MULTI_NAME_BUF_SIZE]; +#endif + + TESTING_MULTIPART("external link creation to an object in ping pong style"); + +#ifndef NO_EXTERNAL_LINKS + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_EXTERNAL_LINKS)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, or external link aren't supported with this " + "connector\n"); + return 0; + } + + HDsnprintf(ext_link_filename1, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", EXTERNAL_LINK_TEST_PING_PONG_NAME1); + HDsnprintf(ext_link_filename2, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", EXTERNAL_LINK_TEST_PING_PONG_NAME2); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Lcreate_external_first_file) + { + TESTING_2("Create the first external file"); + + /* Create the first file */ + if ((file_id = H5Fcreate(ext_link_filename1, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", + ext_link_filename1); + PART_ERROR(H5Lcreate_external_first_file); + } + + /* Create external links for chain */ + if (H5Lcreate_external(ext_link_filename2, "/link2", file_id, "link1", H5P_DEFAULT, H5P_DEFAULT) < + 0) { + H5_FAILED(); + HDprintf(" couldn't create external link\n"); + PART_ERROR(H5Lcreate_external_first_file); + } + + if (H5Lcreate_external(ext_link_filename2, "/link4", file_id, "link3", H5P_DEFAULT, H5P_DEFAULT) < + 0) { + H5_FAILED(); + HDprintf(" couldn't create external link\n"); + PART_ERROR(H5Lcreate_external_first_file); + } + + if (H5Lcreate_external(ext_link_filename2, "/link6", file_id, "link5", H5P_DEFAULT, H5P_DEFAULT) < + 0) { + H5_FAILED(); + HDprintf(" couldn't create external link\n"); + PART_ERROR(H5Lcreate_external_first_file); + } + + /* Create final object */ + if ((group_id = H5Gcreate2(file_id, "final", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create a group\n"); + PART_ERROR(H5Lcreate_external_first_file); + } + + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close a group\n"); + PART_ERROR(H5Lcreate_external_first_file); + } + + /* Close file */ + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close a group\n"); + PART_ERROR(H5Lcreate_external_first_file); + } + + PASSED(); + } + PART_END(H5Lcreate_external_first_file); + + PART_BEGIN(H5Lcreate_external_second_file) + { + TESTING_2("Create the second external file"); + + /* Create the second file */ + if ((file_id = H5Fcreate(ext_link_filename2, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link\n", ext_link_filename2); + PART_ERROR(H5Lcreate_external_second_file); + } + + /* Create external links for chain */ + if (H5Lcreate_external(ext_link_filename1, "/link3", file_id, "link2", H5P_DEFAULT, H5P_DEFAULT) < + 0) { + H5_FAILED(); + HDprintf(" couldn't create external link\n"); + PART_ERROR(H5Lcreate_external_second_file); + } + + if (H5Lcreate_external(ext_link_filename1, "/link5", file_id, "link4", H5P_DEFAULT, H5P_DEFAULT) < + 0) { + H5_FAILED(); + HDprintf(" couldn't create external link\n"); + PART_ERROR(H5Lcreate_external_second_file); + } + + if (H5Lcreate_external(ext_link_filename1, "/final", file_id, "link6", H5P_DEFAULT, H5P_DEFAULT) < + 0) { + H5_FAILED(); + HDprintf(" couldn't create external link\n"); + PART_ERROR(H5Lcreate_external_second_file); + } + + /* Close file */ + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close the file\n"); + PART_ERROR(H5Lcreate_external_second_file); + } + + PASSED(); + } + PART_END(H5Lcreate_external_second_file); + + PART_BEGIN(H5Lcreate_external_verify) + { + TESTING_2("Open the first file to verify the object being pointed to"); + + if ((file_id = H5Fopen(ext_link_filename1, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", ext_link_filename1); + PART_ERROR(H5Lcreate_external_verify); + } + + /* Open object through external link */ + if ((group_id = H5Gopen2(file_id, "link1", H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open the group that is the external link 'link1'\n"); + PART_ERROR(H5Lcreate_external_verify); + } + + /* Check the name of the object being pointed to */ + if (H5Iget_name(group_id, objname, (size_t)EXTERNAL_LINK_TEST_PING_PONG_NAME_BUF_SIZE) < 0) { + H5_FAILED(); + HDprintf(" couldn't get the name of the object\n"); + PART_ERROR(H5Lcreate_external_verify); + } + + if (HDstrcmp(objname, "/final")) { + H5_FAILED(); + HDprintf(" wrong name of the object '%s'\n", objname); + PART_ERROR(H5Lcreate_external_verify); + } + + /* Create an object in the external file */ + if ((group_id2 = H5Gcreate2(group_id, "new_group", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create a new group 'new_group'\n"); + PART_ERROR(H5Lcreate_external_verify); + } + + if (H5Gclose(group_id2) < 0) { + H5_FAILED(); + HDprintf(" couldn't close a group\n"); + PART_ERROR(H5Lcreate_external_verify); + } + + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close a group\n"); + PART_ERROR(H5Lcreate_external_verify); + } + + /* Close file */ + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close the file\n"); + PART_ERROR(H5Lcreate_external_verify); + } + + PASSED(); + } + PART_END(H5Lcreate_external_verify); + + PART_BEGIN(H5Lcreate_external_verify_again) + { + TESTING_2("Open the first file to verify the object being created"); + + if ((file_id = H5Fopen(ext_link_filename1, H5F_ACC_RDONLY, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", ext_link_filename1); + PART_ERROR(H5Lcreate_external_verify_again); + } + + /* Open object through external link */ + if ((group_id = H5Gopen2(file_id, "/final/new_group", H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open the group that is the external link\n"); + PART_ERROR(H5Lcreate_external_verify_again); + } + + /* Check the name of the object being pointed to */ + if (H5Iget_name(group_id, objname, (size_t)EXTERNAL_LINK_TEST_PING_PONG_NAME_BUF_SIZE) < 0) { + H5_FAILED(); + HDprintf(" couldn't get the name of the object\n"); + PART_ERROR(H5Lcreate_external_verify_again); + } + + if (HDstrcmp(objname, "/final/new_group")) { + H5_FAILED(); + HDprintf(" wrong name of the object '%s'\n", objname); + PART_ERROR(H5Lcreate_external_verify_again); + } + + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close a group\n"); + PART_ERROR(H5Lcreate_external_verify_again); + } + + /* Close file */ + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close the file\n"); + PART_ERROR(H5Lcreate_external_verify_again); + } + + PASSED(); + } + PART_END(H5Lcreate_external_verify_again); + } + END_MULTIPART; + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(group_id); + H5Gclose(group_id2); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +#else + SKIPPED(); + return 0; +#endif +} + +/* + * A test to check that an external link can't be created + * when H5Lcreate_external is passed invalid parameters. + */ +static int +test_create_external_link_invalid_params(void) +{ + herr_t err_ret = -1; + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + char ext_link_filename[H5_API_TEST_FILENAME_MAX_LENGTH]; + + TESTING_MULTIPART("H5Lcreate_external with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_EXTERNAL_LINKS)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, or basic link or external link aren't supported " + "with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_INVALID_PARAMS_TEST_FILE_NAME); + + if ((file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + goto error; + } + + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, EXTERNAL_LINK_INVALID_PARAMS_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + EXTERNAL_LINK_INVALID_PARAMS_TEST_GROUP_NAME); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Lcreate_external_invalid_file_name) + { + TESTING_2("H5Lcreate_external with an invalid file name"); + + H5E_BEGIN_TRY + { + err_ret = H5Lcreate_external(NULL, "/", group_id, EXTERNAL_LINK_INVALID_PARAMS_TEST_LINK_NAME, + H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created external link '%s' using a NULL file name!\n", + EXTERNAL_LINK_INVALID_PARAMS_TEST_LINK_NAME); + PART_ERROR(H5Lcreate_external_invalid_file_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Lcreate_external("", "/", group_id, EXTERNAL_LINK_INVALID_PARAMS_TEST_LINK_NAME, + H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created external link '%s' using an invalid file name of ''!\n", + EXTERNAL_LINK_INVALID_PARAMS_TEST_LINK_NAME); + PART_ERROR(H5Lcreate_external_invalid_file_name); + } + + PASSED(); + } + PART_END(H5Lcreate_external_invalid_file_name); + + PART_BEGIN(H5Lcreate_external_invalid_ext_obj_name) + { + TESTING_2("H5Lcreate_external with an invalid external object name"); + + H5E_BEGIN_TRY + { + err_ret = + H5Lcreate_external(ext_link_filename, NULL, group_id, + EXTERNAL_LINK_INVALID_PARAMS_TEST_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created external link '%s' using a NULL external object name!\n", + EXTERNAL_LINK_INVALID_PARAMS_TEST_LINK_NAME); + PART_ERROR(H5Lcreate_external_invalid_ext_obj_name); + } + + H5E_BEGIN_TRY + { + err_ret = + H5Lcreate_external(ext_link_filename, "", group_id, + EXTERNAL_LINK_INVALID_PARAMS_TEST_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created external link '%s' using an invalid external object name of ''!\n", + EXTERNAL_LINK_INVALID_PARAMS_TEST_LINK_NAME); + PART_ERROR(H5Lcreate_external_invalid_ext_obj_name); + } + + PASSED(); + } + PART_END(H5Lcreate_external_invalid_ext_obj_name); + + PART_BEGIN(H5Lcreate_external_invalid_link_loc_id) + { + TESTING_2("H5Lcreate_external with an invalid link_loc_id"); + + H5E_BEGIN_TRY + { + err_ret = + H5Lcreate_external(ext_link_filename, "/", H5I_INVALID_HID, + EXTERNAL_LINK_INVALID_PARAMS_TEST_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created external link '%s' using an invalid link_loc_id!\n", + EXTERNAL_LINK_INVALID_PARAMS_TEST_LINK_NAME); + PART_ERROR(H5Lcreate_external_invalid_link_loc_id); + } + + PASSED(); + } + PART_END(H5Lcreate_external_invalid_link_loc_id); + + PART_BEGIN(H5Lcreate_external_invalid_link_name) + { + TESTING_2("H5Lcreate_external with an invalid link name"); + + H5E_BEGIN_TRY + { + err_ret = + H5Lcreate_external(ext_link_filename, "/", group_id, NULL, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created external link '%s' using a NULL link_loc_id!\n", + EXTERNAL_LINK_INVALID_PARAMS_TEST_LINK_NAME); + PART_ERROR(H5Lcreate_external_invalid_link_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Lcreate_external(ext_link_filename, "/", group_id, "", H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created external link '%s' using an invalid link name of ''!\n", + EXTERNAL_LINK_INVALID_PARAMS_TEST_LINK_NAME); + PART_ERROR(H5Lcreate_external_invalid_link_name); + } + + PASSED(); + } + PART_END(H5Lcreate_external_invalid_link_name); + + PART_BEGIN(H5Lcreate_external_invalid_lcpl) + { + TESTING_2("H5Lcreate_external with an invalid LCPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Lcreate_external(ext_link_filename, "/", group_id, + EXTERNAL_LINK_INVALID_PARAMS_TEST_LINK_NAME, H5I_INVALID_HID, + H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created external link '%s' using an invalid LCPL!\n", + EXTERNAL_LINK_INVALID_PARAMS_TEST_LINK_NAME); + PART_ERROR(H5Lcreate_external_invalid_lcpl); + } + + PASSED(); + } + PART_END(H5Lcreate_external_invalid_lcpl); + + PART_BEGIN(H5Lcreate_external_invalid_lapl) + { + TESTING_2("H5Lcreate_external with an invalid LAPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Lcreate_external(ext_link_filename, "/", group_id, + EXTERNAL_LINK_INVALID_PARAMS_TEST_LINK_NAME, H5P_DEFAULT, + H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created external link '%s' using an invalid LAPL!\n", + EXTERNAL_LINK_INVALID_PARAMS_TEST_LINK_NAME); + PART_ERROR(H5Lcreate_external_invalid_lapl); + } + + PASSED(); + } + PART_END(H5Lcreate_external_invalid_lapl); + + PART_BEGIN(H5Lcreate_external_invalid_existence) + { + TESTING_2("invalid link existence after previous invalid H5Lcreate_external calls"); + + /* Verify the link hasn't been created */ + if ((link_exists = + H5Lexists(group_id, EXTERNAL_LINK_INVALID_PARAMS_TEST_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", + EXTERNAL_LINK_INVALID_PARAMS_TEST_LINK_NAME); + PART_ERROR(H5Lcreate_external_invalid_existence); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" link '%s' existed!\n", EXTERNAL_LINK_INVALID_PARAMS_TEST_LINK_NAME); + PART_ERROR(H5Lcreate_external_invalid_existence); + } + + PASSED(); + } + PART_END(H5Lcreate_external_invalid_existence); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a user-defined link can be created. + */ +static int +test_create_user_defined_link(void) +{ +#ifndef NO_USER_DEFINED_LINKS + ssize_t udata_size; + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + char udata[UD_LINK_TEST_UDATA_MAX_SIZE]; +#endif + + TESTING("user-defined link creation"); + +#ifndef NO_USER_DEFINED_LINKS + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_UD_LINKS)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, or user-defined link aren't supported with this " + "connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, UD_LINK_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", UD_LINK_TEST_GROUP_NAME); + goto error; + } + + if ((udata_size = HDsnprintf(udata, UD_LINK_TEST_UDATA_MAX_SIZE, "udata")) < 0) + TEST_ERROR; + + if (H5Lcreate_ud(group_id, UD_LINK_TEST_LINK_NAME, H5L_TYPE_EXTERNAL, udata, (size_t)udata_size, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create user-defined link '%s'\n", UD_LINK_TEST_LINK_NAME); + goto error; + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(group_id, UD_LINK_TEST_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", UD_LINK_TEST_LINK_NAME); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' didn't exist!\n", UD_LINK_TEST_LINK_NAME); + goto error; + } + + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +#else + SKIPPED(); + return 0; +#endif +} + +/* + * A test to check that H5Lcreate_ud fails when + * it is given invalid parameters. + */ +static int +test_create_user_defined_link_invalid_params(void) +{ + ssize_t udata_size; + htri_t link_exists; + herr_t err_ret = -1; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + char udata[UD_LINK_INVALID_PARAMS_TEST_UDATA_MAX_SIZE]; + + TESTING_MULTIPART("H5Lcreate_ud with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_UD_LINKS)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, or link aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, UD_LINK_INVALID_PARAMS_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", UD_LINK_INVALID_PARAMS_TEST_GROUP_NAME); + goto error; + } + + if ((udata_size = HDsnprintf(udata, UD_LINK_INVALID_PARAMS_TEST_UDATA_MAX_SIZE, "udata")) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Lcreate_ud_invalid_link_loc_id) + { + TESTING_2("H5Lcreate_ud with an invalid link location ID"); + + H5E_BEGIN_TRY + { + err_ret = + H5Lcreate_ud(H5I_INVALID_HID, UD_LINK_INVALID_PARAMS_TEST_LINK_NAME, H5L_TYPE_EXTERNAL, + udata, (size_t)udata_size, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created user-defined link '%s' with an invalid link location ID!\n", + UD_LINK_INVALID_PARAMS_TEST_LINK_NAME); + PART_ERROR(H5Lcreate_ud_invalid_link_loc_id); + } + + PASSED(); + } + PART_END(H5Lcreate_ud_invalid_link_loc_id); + + PART_BEGIN(H5Lcreate_ud_invalid_link_name) + { + TESTING_2("H5Lcreate_ud with an invalid link name"); + + H5E_BEGIN_TRY + { + err_ret = H5Lcreate_ud(group_id, NULL, H5L_TYPE_EXTERNAL, udata, (size_t)udata_size, + H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created user-defined link '%s' with a NULL link name!\n", + UD_LINK_INVALID_PARAMS_TEST_LINK_NAME); + PART_ERROR(H5Lcreate_ud_invalid_link_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Lcreate_ud(group_id, "", H5L_TYPE_EXTERNAL, udata, (size_t)udata_size, + H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created user-defined link '%s' with an invalid link name of ''!\n", + UD_LINK_INVALID_PARAMS_TEST_LINK_NAME); + PART_ERROR(H5Lcreate_ud_invalid_link_name); + } + + PASSED(); + } + PART_END(H5Lcreate_ud_invalid_link_name); + + PART_BEGIN(H5Lcreate_ud_invalid_link_type) + { + TESTING_2("H5Lcreate_ud with an invalid link type"); + + H5E_BEGIN_TRY + { + err_ret = H5Lcreate_ud(group_id, UD_LINK_INVALID_PARAMS_TEST_LINK_NAME, H5L_TYPE_HARD, udata, + (size_t)udata_size, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created user-defined link '%s' with an invalid link type!\n", + UD_LINK_INVALID_PARAMS_TEST_LINK_NAME); + PART_ERROR(H5Lcreate_ud_invalid_link_type); + } + + PASSED(); + } + PART_END(H5Lcreate_ud_invalid_link_type); + + PART_BEGIN(H5Lcreate_ud_invalid_udata_pointer) + { + TESTING_2("H5Lcreate_ud with an invalid udata pointer"); + + H5E_BEGIN_TRY + { + err_ret = H5Lcreate_ud(group_id, UD_LINK_INVALID_PARAMS_TEST_LINK_NAME, H5L_TYPE_EXTERNAL, + NULL, (size_t)udata_size, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created user-defined link '%s' with an invalid udata pointer!\n", + UD_LINK_INVALID_PARAMS_TEST_LINK_NAME); + PART_ERROR(H5Lcreate_ud_invalid_udata_pointer); + } + + PASSED(); + } + PART_END(H5Lcreate_ud_invalid_udata_pointer); + + PART_BEGIN(H5Lcreate_ud_invalid_lcpl) + { + TESTING_2("H5Lcreate_ud with an invalid LCPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Lcreate_ud(group_id, UD_LINK_INVALID_PARAMS_TEST_LINK_NAME, H5L_TYPE_EXTERNAL, + udata, (size_t)udata_size, H5I_INVALID_HID, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created user-defined link '%s' with an invalid LCPL!\n", + UD_LINK_INVALID_PARAMS_TEST_LINK_NAME); + PART_ERROR(H5Lcreate_ud_invalid_lcpl); + } + + PASSED(); + } + PART_END(H5Lcreate_ud_invalid_lcpl); + + PART_BEGIN(H5Lcreate_ud_invalid_lapl) + { + TESTING_2("H5Lcreate_ud with an invalid LAPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Lcreate_ud(group_id, UD_LINK_INVALID_PARAMS_TEST_LINK_NAME, H5L_TYPE_EXTERNAL, + udata, (size_t)udata_size, H5P_DEFAULT, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" created user-defined link '%s' with an invalid LAPL!\n", + UD_LINK_INVALID_PARAMS_TEST_LINK_NAME); + PART_ERROR(H5Lcreate_ud_invalid_lapl); + } + + PASSED(); + } + PART_END(H5Lcreate_ud_invalid_lapl); + + PART_BEGIN(H5Lcreate_ud_invalid_existence) + { + TESTING_2("invalid link existence after previous invalid H5Lcreate_ud calls"); + + /* Verify the link hasn't been created */ + if ((link_exists = H5Lexists(group_id, UD_LINK_INVALID_PARAMS_TEST_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", + UD_LINK_INVALID_PARAMS_TEST_LINK_NAME); + PART_ERROR(H5Lcreate_ud_invalid_existence); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" link '%s' existed!\n", UD_LINK_INVALID_PARAMS_TEST_LINK_NAME); + PART_ERROR(H5Lcreate_ud_invalid_existence); + } + + PASSED(); + } + PART_END(H5Lcreate_ud_invalid_existence); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a link can be deleted + * using H5Ldelete and H5Ldelete_by_idx. + */ +static int +test_delete_link(void) +{ + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID, ext_file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t subgroup_id = H5I_INVALID_HID; + hid_t nested_grp_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; +#ifndef NO_EXTERNAL_LINKS + char ext_link_filename[H5_API_TEST_FILENAME_MAX_LENGTH]; +#endif + + TESTING_MULTIPART("link deletion"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_HARD_LINKS) || !(vol_cap_flags_g & H5VL_CAP_FLAG_EXTERNAL_LINKS) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_SOFT_LINKS) || !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, or link, hard, soft, or external link aren't " + "supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create GCPL for link creation order tracking\n"); + goto error; + } + + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED) < 0) { + H5_FAILED(); + HDprintf(" couldn't set link creation order tracking\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, LINK_DELETE_TEST_SUBGROUP_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", LINK_DELETE_TEST_SUBGROUP_NAME); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Ldelete_hard) + { + TESTING_2("H5Ldelete on hard link"); + + if ((subgroup_id = H5Gcreate2(group_id, LINK_DELETE_TEST_SUBGROUP1_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", LINK_DELETE_TEST_SUBGROUP1_NAME); + PART_ERROR(H5Ldelete_hard); + } + + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create first hard link '%s'\n", LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_hard); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if first hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_hard); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" first hard link did not exist\n"); + PART_ERROR(H5Ldelete_hard); + } + + if (H5Ldelete(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete hard link '%s' using H5Ldelete\n", + LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_hard); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if first hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_hard); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" first hard link exists!\n"); + PART_ERROR(H5Ldelete_hard); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", LINK_DELETE_TEST_SUBGROUP1_NAME); + PART_ERROR(H5Ldelete_hard); + } + + PASSED(); + } + PART_END(H5Ldelete_hard); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Ldelete_hard_indirect) + { + TESTING_2("H5Ldelete on nested hard link"); + + if ((subgroup_id = H5Gcreate2(group_id, LINK_DELETE_TEST_NESTED_SUBGROUP_NAME1, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", LINK_DELETE_TEST_NESTED_SUBGROUP_NAME1); + PART_ERROR(H5Ldelete_hard_indirect); + } + + if ((nested_grp_id = H5Gcreate2(subgroup_id, LINK_DELETE_TEST_NESTED_GRP_NAME, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", LINK_DELETE_TEST_NESTED_GRP_NAME); + PART_ERROR(H5Ldelete_hard_indirect); + } + + if (H5Lcreate_hard(nested_grp_id, ".", nested_grp_id, LINK_DELETE_TEST_HARD_LINK_NAME, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create first hard link '%s'\n", LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_hard_indirect); + } + + if ((link_exists = H5Lexists(nested_grp_id, LINK_DELETE_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if first hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_hard_indirect); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" first hard link did not exist\n"); + PART_ERROR(H5Ldelete_hard_indirect); + } + + if (H5Ldelete(subgroup_id, LINK_DELETE_TEST_NESTED_HARD_LINK_NAME, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete hard link '%s' using H5Ldelete\n", + LINK_DELETE_TEST_NESTED_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_hard_indirect); + } + + if ((link_exists = H5Lexists(nested_grp_id, LINK_DELETE_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if first hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_hard_indirect); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" first hard link exists!\n"); + PART_ERROR(H5Ldelete_hard_indirect); + } + + if (H5Gclose(nested_grp_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", LINK_DELETE_TEST_NESTED_GRP_NAME); + PART_ERROR(H5Ldelete_hard_indirect); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", LINK_DELETE_TEST_SUBGROUP1_NAME); + PART_ERROR(H5Ldelete_hard_indirect); + } + + PASSED(); + } + PART_END(H5Ldelete_hard_indirect); + + H5E_BEGIN_TRY + { + H5Gclose(nested_grp_id); + nested_grp_id = H5I_INVALID_HID; + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Ldelete_soft) + { + TESTING_2("H5Ldelete on soft link"); + + if ((subgroup_id = H5Gcreate2(group_id, LINK_DELETE_TEST_SUBGROUP2_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", LINK_DELETE_TEST_SUBGROUP2_NAME); + PART_ERROR(H5Ldelete_soft); + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" LINK_DELETE_TEST_SUBGROUP_NAME + "/" LINK_DELETE_TEST_SUBGROUP2_NAME, + subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create first soft link '%s'\n", LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_soft); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if first soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_soft); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" first soft link did not exist\n"); + PART_ERROR(H5Ldelete_soft); + } + + if (H5Ldelete(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete soft link '%s' using H5Ldelete\n", + LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_soft); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if first soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_soft); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" first soft link exists!\n"); + PART_ERROR(H5Ldelete_soft); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", LINK_DELETE_TEST_SUBGROUP2_NAME); + PART_ERROR(H5Ldelete_soft); + } + + PASSED(); + } + PART_END(H5Ldelete_soft); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Ldelete_external) + { + TESTING_2("H5Ldelete on external link"); +#ifndef NO_EXTERNAL_LINKS + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME); + + if ((ext_file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + PART_ERROR(H5Ldelete_external); + } + + if (H5Fclose(ext_file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close file '%s'\n", ext_link_filename); + PART_ERROR(H5Ldelete_external); + } + + if ((subgroup_id = H5Gcreate2(group_id, LINK_DELETE_TEST_SUBGROUP3_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", LINK_DELETE_TEST_SUBGROUP3_NAME); + PART_ERROR(H5Ldelete_external); + } + + if (H5Lcreate_external(ext_link_filename, "/", subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create first external link '%s'\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_external); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if first external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_external); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" first external link did not exist\n"); + PART_ERROR(H5Ldelete_external); + } + + if (H5Ldelete(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete external link '%s' using H5Ldelete\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_external); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if first external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_external); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" first external link exists!\n"); + PART_ERROR(H5Ldelete_external); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", LINK_DELETE_TEST_SUBGROUP3_NAME); + PART_ERROR(H5Ldelete_external); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Ldelete_external); +#endif + } + PART_END(H5Ldelete_external); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + H5Fclose(ext_file_id); + ext_file_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Ldelete_ud) + { + TESTING_2("H5Ldelete on user-defined link"); + + /* TODO */ + + SKIPPED(); + PART_EMPTY(H5Ldelete_ud); + } + PART_END(H5Ldelete_ud); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Ldelete_by_idx_hard_crt_order_increasing) + { + TESTING_2("H5Ldelete_by_idx on hard link by creation order in increasing order"); + + if ((subgroup_id = H5Gcreate2(group_id, LINK_DELETE_TEST_SUBGROUP5_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", LINK_DELETE_TEST_SUBGROUP5_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + /* Create several hard links */ + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME2, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME3, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + /* Delete a link */ + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete hard link '%s' using H5Ldelete_by_idx by creation order in " + "increasing order\n", + LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + /* Ensure that the link is gone and others remain */ + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' exists after deletion!\n", LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + /* Repeat until all links have been deleted */ + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete hard link '%s' using H5Ldelete_by_idx by creation order in " + "increasing order\n", + LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' exists after deletion!\n", LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' exists after deletion!\n", LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete hard link '%s' using H5Ldelete_by_idx by creation order in " + "increasing order\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' exists after deletion!\n", LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' exists after deletion!\n", LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' exists after deletion!\n", LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", LINK_DELETE_TEST_SUBGROUP5_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_increasing); + } + + PASSED(); + } + PART_END(H5Ldelete_by_idx_hard_crt_order_increasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Ldelete_by_idx_hard_crt_order_decreasing) + { + TESTING_2("H5Ldelete_by_idx on hard link by creation order in decreasing order"); + + if ((subgroup_id = H5Gcreate2(group_id, LINK_DELETE_TEST_SUBGROUP6_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", LINK_DELETE_TEST_SUBGROUP6_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + /* Create several hard links */ + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME2, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME3, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + /* Delete a link */ + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 2, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete hard link '%s' using H5Ldelete_by_idx by creation order in " + "decreasing order\n", + LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + /* Ensure that the link is gone and others remain */ + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' exists after deletion!\n", LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + /* Repeat until all links have been deleted */ + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete hard link '%s' using H5Ldelete_by_idx by creation order in " + "decreasing order\n", + LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' exists after deletion!\n", LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' exists after deletion!\n", LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete hard link '%s' using H5Ldelete_by_idx by creation order in " + "decreasing order\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' exists after deletion!\n", LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' exists after deletion!\n", LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' exists after deletion!\n", LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", LINK_DELETE_TEST_SUBGROUP6_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_crt_order_decreasing); + } + + PASSED(); + } + PART_END(H5Ldelete_by_idx_hard_crt_order_decreasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Ldelete_by_idx_hard_name_order_increasing) + { + TESTING_2("H5Ldelete_by_idx on hard link by alphabetical order in increasing order"); + + if ((subgroup_id = H5Gcreate2(group_id, LINK_DELETE_TEST_SUBGROUP7_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", LINK_DELETE_TEST_SUBGROUP7_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + /* Create several hard links */ + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME2, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME3, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + /* Delete a link */ + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete hard link '%s' using H5Ldelete_by_idx by alphabetical order in " + "increasing order\n", + LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + /* Ensure that the link is gone and others remain */ + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' exists after deletion!\n", LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + /* Repeat until all links have been deleted */ + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete hard link '%s' using H5Ldelete_by_idx by alphabetical order in " + "increasing order\n", + LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' exists after deletion!\n", LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' exists after deletion!\n", LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete hard link '%s' using H5Ldelete_by_idx by alphabetical order in " + "increasing order\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' exists after deletion!\n", LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' exists after deletion!\n", LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' exists after deletion!\n", LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", LINK_DELETE_TEST_SUBGROUP7_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_increasing); + } + + PASSED(); + } + PART_END(H5Ldelete_by_idx_hard_name_order_increasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Ldelete_by_idx_hard_name_order_decreasing) + { + TESTING_2("H5Ldelete_by_idx on hard link by alphabetical order in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + if ((subgroup_id = H5Gcreate2(group_id, LINK_DELETE_TEST_SUBGROUP8_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", LINK_DELETE_TEST_SUBGROUP8_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + /* Create several hard links */ + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME2, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME3, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + /* Delete a link */ + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 2, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete hard link '%s' using H5Ldelete_by_idx by alphabetical order in " + "decreasing order\n", + LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + /* Ensure that the link is gone and others remain */ + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' exists after deletion!\n", LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + /* Repeat until all links have been deleted */ + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete hard link '%s' using H5Ldelete_by_idx by alphabetical order in " + "decreasing order\n", + LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' exists after deletion!\n", LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' exists after deletion!\n", LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete hard link '%s' using H5Ldelete_by_idx by alphabetical order in " + "decreasing order\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' exists after deletion!\n", LINK_DELETE_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' exists after deletion!\n", LINK_DELETE_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_HARD_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' exists after deletion!\n", LINK_DELETE_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", LINK_DELETE_TEST_SUBGROUP8_NAME); + PART_ERROR(H5Ldelete_by_idx_hard_name_order_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Ldelete_by_idx_hard_name_order_decreasing); +#endif + } + PART_END(H5Ldelete_by_idx_hard_name_order_decreasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Ldelete_by_idx_soft_crt_order_increasing) + { + TESTING_2("H5Ldelete_by_idx on soft link by creation order in increasing order"); + + if ((subgroup_id = H5Gcreate2(group_id, LINK_DELETE_TEST_SUBGROUP9_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", LINK_DELETE_TEST_SUBGROUP9_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + /* Create several soft links */ + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" LINK_DELETE_TEST_SUBGROUP_NAME + "/" LINK_DELETE_TEST_SUBGROUP9_NAME, + subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" LINK_DELETE_TEST_SUBGROUP_NAME + "/" LINK_DELETE_TEST_SUBGROUP9_NAME, + subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" LINK_DELETE_TEST_SUBGROUP_NAME + "/" LINK_DELETE_TEST_SUBGROUP9_NAME, + subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME3, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + /* Delete a link */ + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete soft link '%s' using H5Ldelete_by_idx by creation order in " + "increasing order\n", + LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + /* Ensure that the link is gone and others remain */ + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' exists after deletion!\n", LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + /* Repeat until all links have been deleted */ + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete soft link '%s' using H5Ldelete_by_idx by creation order in " + "increasing order\n", + LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' exists after deletion!\n", LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' exists after deletion!\n", LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete soft link '%s' using H5Ldelete_by_idx by creation order in " + "increasing order\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' exists after deletion!\n", LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' exists after deletion!\n", LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' exists after deletion!\n", LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", LINK_DELETE_TEST_SUBGROUP9_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_increasing); + } + + PASSED(); + } + PART_END(H5Ldelete_by_idx_soft_crt_order_increasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Ldelete_by_idx_soft_crt_order_decreasing) + { + TESTING_2("H5Ldelete_by_idx on soft link by creation order in decreasing order"); + + if ((subgroup_id = H5Gcreate2(group_id, LINK_DELETE_TEST_SUBGROUP10_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", LINK_DELETE_TEST_SUBGROUP10_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + /* Create several soft links */ + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" LINK_DELETE_TEST_SUBGROUP_NAME + "/" LINK_DELETE_TEST_SUBGROUP10_NAME, + subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" LINK_DELETE_TEST_SUBGROUP_NAME + "/" LINK_DELETE_TEST_SUBGROUP10_NAME, + subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" LINK_DELETE_TEST_SUBGROUP_NAME + "/" LINK_DELETE_TEST_SUBGROUP10_NAME, + subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME3, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + /* Delete a link */ + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 2, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete soft link '%s' using H5Ldelete_by_idx by creation order in " + "decreasing order\n", + LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + /* Ensure that the link is gone and others remain */ + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' exists after deletion!\n", LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + /* Repeat until all links have been deleted */ + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete soft link '%s' using H5Ldelete_by_idx by creation order in " + "decreasing order\n", + LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' exists after deletion!\n", LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' exists after deletion!\n", LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete soft link '%s' using H5Ldelete_by_idx by creation order in " + "decreasing order\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' exists after deletion!\n", LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' exists after deletion!\n", LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' exists after deletion!\n", LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", LINK_DELETE_TEST_SUBGROUP10_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_crt_order_decreasing); + } + + PASSED(); + } + PART_END(H5Ldelete_by_idx_soft_crt_order_decreasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Ldelete_by_idx_soft_name_order_increasing) + { + TESTING_2("H5Ldelete_by_idx on soft link by alphabetical order in increasing order"); + + if ((subgroup_id = H5Gcreate2(group_id, LINK_DELETE_TEST_SUBGROUP11_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", LINK_DELETE_TEST_SUBGROUP11_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + /* Create several soft links */ + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" LINK_DELETE_TEST_SUBGROUP_NAME + "/" LINK_DELETE_TEST_SUBGROUP11_NAME, + subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" LINK_DELETE_TEST_SUBGROUP_NAME + "/" LINK_DELETE_TEST_SUBGROUP11_NAME, + subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" LINK_DELETE_TEST_SUBGROUP_NAME + "/" LINK_DELETE_TEST_SUBGROUP11_NAME, + subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME3, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + /* Delete a link */ + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete soft link '%s' using H5Ldelete_by_idx by alphabetical order in " + "increasing order\n", + LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + /* Ensure that the link is gone and others remain */ + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' exists after deletion!\n", LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + /* Repeat until all links have been deleted */ + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete soft link '%s' using H5Ldelete_by_idx by alphabetical order in " + "increasing order\n", + LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' exists after deletion!\n", LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' exists after deletion!\n", LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete soft link '%s' using H5Ldelete_by_idx by alphabetical order in " + "increasing order\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' exists after deletion!\n", LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' exists after deletion!\n", LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' exists after deletion!\n", LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", LINK_DELETE_TEST_SUBGROUP11_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_increasing); + } + + PASSED(); + } + PART_END(H5Ldelete_by_idx_soft_name_order_increasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Ldelete_by_idx_soft_name_order_decreasing) + { + TESTING_2("H5Ldelete_by_idx on soft link by alphabetical order in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + if ((subgroup_id = H5Gcreate2(group_id, LINK_DELETE_TEST_SUBGROUP12_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", LINK_DELETE_TEST_SUBGROUP12_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + /* Create several soft links */ + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" LINK_DELETE_TEST_SUBGROUP_NAME + "/" LINK_DELETE_TEST_SUBGROUP12_NAME, + subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" LINK_DELETE_TEST_SUBGROUP_NAME + "/" LINK_DELETE_TEST_SUBGROUP12_NAME, + subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" LINK_DELETE_TEST_SUBGROUP_NAME + "/" LINK_DELETE_TEST_SUBGROUP12_NAME, + subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME3, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + /* Delete a link */ + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 2, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete soft link '%s' using H5Ldelete_by_idx by alphabetical order in " + "decreasing order\n", + LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + /* Ensure that the link is gone and others remain */ + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' exists after deletion!\n", LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + /* Repeat until all links have been deleted */ + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete soft link '%s' using H5Ldelete_by_idx by alphabetical order in " + "decreasing order\n", + LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' exists after deletion!\n", LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' exists after deletion!\n", LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete soft link '%s' using H5Ldelete_by_idx by alphabetical order in " + "decreasing order\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' exists after deletion!\n", LINK_DELETE_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' exists after deletion!\n", LINK_DELETE_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' exists after deletion!\n", LINK_DELETE_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", LINK_DELETE_TEST_SUBGROUP12_NAME); + PART_ERROR(H5Ldelete_by_idx_soft_name_order_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Ldelete_by_idx_soft_name_order_decreasing); +#endif + } + PART_END(H5Ldelete_by_idx_soft_name_order_decreasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Ldelete_by_idx_external_crt_order_increasing) + { + TESTING_2("H5Ldelete_by_idx on external link by creation order in increasing order"); +#ifndef NO_EXTERNAL_LINKS + /* Create file for external link to reference */ + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME); + + if ((ext_file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + if (H5Fclose(ext_file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close file '%s'\n", ext_link_filename); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + if ((subgroup_id = H5Gcreate2(group_id, LINK_DELETE_TEST_SUBGROUP13_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", LINK_DELETE_TEST_SUBGROUP13_NAME); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + /* Create several external links */ + if (H5Lcreate_external(ext_link_filename, "/", subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + if (H5Lcreate_external(ext_link_filename, "/", subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME2, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + if (H5Lcreate_external(ext_link_filename, "/", subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME3, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME3, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + /* Delete a link */ + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete external link '%s' using H5Ldelete_by_idx by creation order in " + "increasing order\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + /* Ensure that the link is gone and others remain */ + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' exists after deletion!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME3, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + /* Repeat until all links have been deleted */ + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete external link '%s' using H5Ldelete_by_idx by creation order in " + "increasing order\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' exists after deletion!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' exists after deletion!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME3, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete external link '%s' using H5Ldelete_by_idx by creation order in " + "increasing order\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' exists after deletion!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' exists after deletion!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME3, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' exists after deletion!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", LINK_DELETE_TEST_SUBGROUP13_NAME); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_increasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Ldelete_by_idx_external_crt_order_increasing); +#endif + } + PART_END(H5Ldelete_by_idx_external_crt_order_increasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + H5Fclose(ext_file_id); + ext_file_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Ldelete_by_idx_external_crt_order_decreasing) + { + TESTING_2("H5Ldelete_by_idx on external link by creation order in decreasing order"); +#ifndef NO_EXTERNAL_LINKS + /* Create file for external link to reference */ + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME); + + if ((ext_file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + if (H5Fclose(ext_file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close file '%s'\n", ext_link_filename); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + if ((subgroup_id = H5Gcreate2(group_id, LINK_DELETE_TEST_SUBGROUP14_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", LINK_DELETE_TEST_SUBGROUP14_NAME); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + /* Create several external links */ + if (H5Lcreate_external(ext_link_filename, "/", subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + if (H5Lcreate_external(ext_link_filename, "/", subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME2, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + if (H5Lcreate_external(ext_link_filename, "/", subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME3, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME3, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + /* Delete a link */ + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 2, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete external link '%s' using H5Ldelete_by_idx by creation order in " + "decreasing order\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + /* Ensure that the link is gone and others remain */ + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' exists after deletion!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME3, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + /* Repeat until all links have been deleted */ + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete external link '%s' using H5Ldelete_by_idx by creation order in " + "decreasing order\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' exists after deletion!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' exists after deletion!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME3, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete external link '%s' using H5Ldelete_by_idx by creation order in " + "decreasing order\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' exists after deletion!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' exists after deletion!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME3, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' exists after deletion!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", LINK_DELETE_TEST_SUBGROUP14_NAME); + PART_ERROR(H5Ldelete_by_idx_external_crt_order_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Ldelete_by_idx_external_crt_order_decreasing); +#endif + } + PART_END(H5Ldelete_by_idx_external_crt_order_decreasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + H5Fclose(ext_file_id); + ext_file_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Ldelete_by_idx_external_name_order_increasing) + { + TESTING_2("H5Ldelete_by_idx on external link by alphabetical order in increasing order"); +#ifndef NO_EXTERNAL_LINKS + /* Create file for external link to reference */ + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME); + + if ((ext_file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + if (H5Fclose(ext_file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close file '%s'\n", ext_link_filename); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + if ((subgroup_id = H5Gcreate2(group_id, LINK_DELETE_TEST_SUBGROUP15_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", LINK_DELETE_TEST_SUBGROUP15_NAME); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + /* Create several external links */ + if (H5Lcreate_external(ext_link_filename, "/", subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + if (H5Lcreate_external(ext_link_filename, "/", subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME2, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + if (H5Lcreate_external(ext_link_filename, "/", subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME3, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME3, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + /* Delete a link */ + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete external link '%s' using H5Ldelete_by_idx by alphabetical " + "order in increasing order\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + /* Ensure that the link is gone and others remain */ + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' exists after deletion!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME3, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + /* Repeat until all links have been deleted */ + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete external link '%s' using H5Ldelete_by_idx by alphabetical " + "order in increasing order\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' exists after deletion!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' exists after deletion!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME3, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete external link '%s' using H5Ldelete_by_idx by alphabetical " + "order in increasing order\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' exists after deletion!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' exists after deletion!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME3, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' exists after deletion!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", LINK_DELETE_TEST_SUBGROUP15_NAME); + PART_ERROR(H5Ldelete_by_idx_external_name_order_increasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Ldelete_by_idx_external_name_order_increasing); +#endif + } + PART_END(H5Ldelete_by_idx_external_name_order_increasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + H5Fclose(ext_file_id); + ext_file_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Ldelete_by_idx_external_name_order_decreasing) + { + TESTING_2("H5Ldelete_by_idx on external link by alphabetical order in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Create file for external link to reference */ + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME); + + if ((ext_file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + if (H5Fclose(ext_file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close file '%s'\n", ext_link_filename); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + if ((subgroup_id = H5Gcreate2(group_id, LINK_DELETE_TEST_SUBGROUP16_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", LINK_DELETE_TEST_SUBGROUP16_NAME); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + /* Create several external links */ + if (H5Lcreate_external(ext_link_filename, "/", subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + if (H5Lcreate_external(ext_link_filename, "/", subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME2, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + if (H5Lcreate_external(ext_link_filename, "/", subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME3, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME3, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before deletion\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + /* Delete a link */ + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 2, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete external link '%s' using H5Ldelete_by_idx by alphabetical " + "order in decreasing order\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + /* Ensure that the link is gone and others remain */ + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' exists after deletion!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME3, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + /* Repeat until all links have been deleted */ + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete external link '%s' using H5Ldelete_by_idx by alphabetical " + "order in decreasing order\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' exists after deletion!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' exists after deletion!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME3, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist after deletion of a different link!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + if (H5Ldelete_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 0, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't delete external link '%s' using H5Ldelete_by_idx by alphabetical " + "order in decreasing order\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' exists after deletion!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' exists after deletion!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, LINK_DELETE_TEST_EXTERNAL_LINK_NAME3, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' exists after deletion!\n", + LINK_DELETE_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", LINK_DELETE_TEST_SUBGROUP16_NAME); + PART_ERROR(H5Ldelete_by_idx_external_name_order_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Ldelete_by_idx_external_name_order_decreasing); +#endif + } + PART_END(H5Ldelete_by_idx_external_name_order_decreasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + H5Fclose(ext_file_id); + ext_file_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Ldelete_by_idx_ud_crt_order_increasing) + { + TESTING_2("H5Ldelete_by_idx on user-defined link by creation order in increasing order"); + + /* TODO */ + + SKIPPED(); + PART_EMPTY(H5Ldelete_by_idx_ud_crt_order_increasing); + } + PART_END(H5Ldelete_by_idx_ud_crt_order_increasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Ldelete_by_idx_ud_crt_order_decreasing) + { + TESTING_2("H5Ldelete_by_idx on user-defined link by creation order in decreasing order"); + + /* TODO */ + + SKIPPED(); + PART_EMPTY(H5Ldelete_by_idx_ud_crt_order_decreasing); + } + PART_END(H5Ldelete_by_idx_ud_crt_order_decreasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Ldelete_by_idx_ud_name_order_increasing) + { + TESTING_2("H5Ldelete_by_idx on user-defined link by alphabetical order in increasing order"); + + /* TODO */ + + SKIPPED(); + PART_EMPTY(H5Ldelete_by_idx_ud_name_order_increasing); + } + PART_END(H5Ldelete_by_idx_ud_name_order_increasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Ldelete_by_idx_ud_name_order_decreasing) + { + TESTING_2("H5Ldelete_by_idx on user-defined link by alphabetical order in decreasing order"); + + /* TODO */ + + SKIPPED(); + PART_EMPTY(H5Ldelete_by_idx_ud_name_order_decreasing); + } + PART_END(H5Ldelete_by_idx_ud_name_order_decreasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(gcpl_id); + H5Gclose(subgroup_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(ext_file_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a group's always-increasing + * maximum link creation order value gets reset once + * all the links have been deleted from the group. + */ +static int +test_delete_link_reset_grp_max_crt_order(void) +{ +#ifndef NO_MAX_LINK_CRT_ORDER_RESET + H5G_info_t grp_info; + size_t i; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t subgroup_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + char link_name[LINK_DELETE_RESET_MAX_CRT_ORDER_TEST_BUF_SIZE]; +#endif + + TESTING_MULTIPART("H5Ldelete of all links in group resets group's maximum link creation order value"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_MORE)) { + SKIPPED(); + HDprintf(" API functions for basic file, basic and more group, or basic link aren't supported " + "with this connector\n"); + return 0; + } + +#ifndef NO_MAX_LINK_CRT_ORDER_RESET + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create GCPL for link creation order tracking\n"); + goto error; + } + + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED) < 0) { + H5_FAILED(); + HDprintf(" couldn't set link creation order tracking\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, LINK_DELETE_RESET_MAX_CRT_ORDER_TEST_SUBGROUP_NAME, + H5P_DEFAULT, gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + LINK_DELETE_RESET_MAX_CRT_ORDER_TEST_SUBGROUP_NAME); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Ldelete_links_bottom_up) + { + TESTING_2("H5Ldelete from least-recently created link to most-recently created link"); + + if ((subgroup_id = H5Gcreate2(group_id, LINK_DELETE_RESET_MAX_CRT_ORDER_TEST_SUBGROUP1_NAME, + H5P_DEFAULT, gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", + LINK_DELETE_RESET_MAX_CRT_ORDER_TEST_SUBGROUP1_NAME); + PART_ERROR(H5Ldelete_links_bottom_up); + } + + /* Create several links inside the group */ + for (i = 0; i < LINK_DELETE_RESET_MAX_CRT_ORDER_TEST_NUM_LINKS; i++) { + snprintf(link_name, LINK_DELETE_RESET_MAX_CRT_ORDER_TEST_BUF_SIZE, "link%d", (int)i); + + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, link_name, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", link_name); + PART_ERROR(H5Ldelete_links_bottom_up); + } + } + + /* Delete the links, checking the group's maximum creation order value each time */ + for (i = 0; i < LINK_DELETE_RESET_MAX_CRT_ORDER_TEST_NUM_LINKS; i++) { + memset(&grp_info, 0, sizeof(grp_info)); + + if (H5Gget_info(subgroup_id, &grp_info) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve group's info\n"); + PART_ERROR(H5Ldelete_links_bottom_up); + } + + if (grp_info.max_corder != LINK_DELETE_RESET_MAX_CRT_ORDER_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" group's maximum creation order value got adjusted to %lld during link " + "deletion; value should have remained at %lld\n", + (long long)grp_info.max_corder, LINK_DELETE_RESET_MAX_CRT_ORDER_TEST_NUM_LINKS); + PART_ERROR(H5Ldelete_links_bottom_up); + } + + snprintf(link_name, LINK_DELETE_RESET_MAX_CRT_ORDER_TEST_BUF_SIZE, "link%d", (int)i); + + if (H5Ldelete(subgroup_id, link_name, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to delete link '%s'\n", link_name); + PART_ERROR(H5Ldelete_links_bottom_up); + } + } + + /* Ensure the group's maximum creation order value has now reset to 0 after all the links are gone + */ + memset(&grp_info, 0, sizeof(grp_info)); + + if (H5Gget_info(subgroup_id, &grp_info) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve group's info\n"); + PART_ERROR(H5Ldelete_links_bottom_up); + } + + if (grp_info.max_corder != 0) { + H5_FAILED(); + HDprintf(" group's maximum creation order value didn't reset to 0 after deleting all " + "links from group; value is still %lld\n", + (long long)grp_info.max_corder); + PART_ERROR(H5Ldelete_links_bottom_up); + } + + PASSED(); + } + PART_END(H5Ldelete_links_bottom_up); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Ldelete_links_top_down) + { + TESTING_2("H5Ldelete from most-recently created link to least-recently created link"); + + if ((subgroup_id = H5Gcreate2(group_id, LINK_DELETE_RESET_MAX_CRT_ORDER_TEST_SUBGROUP2_NAME, + H5P_DEFAULT, gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", + LINK_DELETE_RESET_MAX_CRT_ORDER_TEST_SUBGROUP2_NAME); + PART_ERROR(H5Ldelete_links_top_down); + } + + /* Create several links inside the group */ + for (i = 0; i < LINK_DELETE_RESET_MAX_CRT_ORDER_TEST_NUM_LINKS; i++) { + snprintf(link_name, LINK_DELETE_RESET_MAX_CRT_ORDER_TEST_BUF_SIZE, "link%d", (int)i); + + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, link_name, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", link_name); + PART_ERROR(H5Ldelete_links_top_down); + } + } + + /* Delete the links, checking the group's maximum creation order value each time */ + for (i = 0; i < LINK_DELETE_RESET_MAX_CRT_ORDER_TEST_NUM_LINKS; i++) { + memset(&grp_info, 0, sizeof(grp_info)); + + if (H5Gget_info(subgroup_id, &grp_info) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve group's info\n"); + PART_ERROR(H5Ldelete_links_top_down); + } + + if (grp_info.max_corder != LINK_DELETE_RESET_MAX_CRT_ORDER_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" group's maximum creation order value got adjusted to %lld during link " + "deletion; value should have remained at %lld\n", + (long long)grp_info.max_corder, LINK_DELETE_RESET_MAX_CRT_ORDER_TEST_NUM_LINKS); + PART_ERROR(H5Ldelete_links_top_down); + } + + snprintf(link_name, LINK_DELETE_RESET_MAX_CRT_ORDER_TEST_BUF_SIZE, "link%d", + (int)(LINK_DELETE_RESET_MAX_CRT_ORDER_TEST_NUM_LINKS - i - 1)); + + if (H5Ldelete(subgroup_id, link_name, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to delete link '%s'\n", link_name); + PART_ERROR(H5Ldelete_links_top_down); + } + } + + /* Ensure the group's maximum creation order value has now reset to 0 after all the links are gone + */ + memset(&grp_info, 0, sizeof(grp_info)); + + if (H5Gget_info(subgroup_id, &grp_info) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve group's info\n"); + PART_ERROR(H5Ldelete_links_top_down); + } + + if (grp_info.max_corder != 0) { + H5_FAILED(); + HDprintf(" group's maximum creation order value didn't reset to 0 after deleting all " + "links from group; value is still %lld\n", + (long long)grp_info.max_corder); + PART_ERROR(H5Ldelete_links_top_down); + } + + PASSED(); + } + PART_END(H5Ldelete_links_top_down); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(gcpl_id); + H5Gclose(subgroup_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +#else + SKIPPED(); + return 0; +#endif +} + +static int +test_delete_link_invalid_params(void) +{ + htri_t link_exists; + herr_t err_ret = -1; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + + TESTING_MULTIPART("H5Ldelete with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_BY_IDX) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_HARD_LINKS)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, or link aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, LINK_DELETE_INVALID_PARAMS_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", LINK_DELETE_INVALID_PARAMS_TEST_GROUP_NAME); + goto error; + } + + if (H5Lcreate_hard(group_id, ".", group_id, LINK_DELETE_INVALID_PARAMS_TEST_HARD_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", LINK_DELETE_INVALID_PARAMS_TEST_HARD_LINK_NAME); + goto error; + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(group_id, LINK_DELETE_INVALID_PARAMS_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if first hard link '%s' exists\n", + LINK_DELETE_INVALID_PARAMS_TEST_HARD_LINK_NAME); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" first hard link did not exist\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Ldelete_invalid_loc_id) + { + TESTING_2("H5Ldelete with an invalid location ID"); + + H5E_BEGIN_TRY + { + err_ret = + H5Ldelete(H5I_INVALID_HID, LINK_DELETE_INVALID_PARAMS_TEST_HARD_LINK_NAME, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ldelete succeeded with an invalid location ID!\n"); + PART_ERROR(H5Ldelete_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Ldelete_invalid_loc_id); + + PART_BEGIN(H5Ldelete_invalid_link_name) + { + TESTING_2("H5Ldelete with an invalid link name"); + + H5E_BEGIN_TRY + { + err_ret = H5Ldelete(group_id, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ldelete succeeded with a NULL link name!\n"); + PART_ERROR(H5Ldelete_invalid_link_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Ldelete(group_id, "", H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ldelete succeeded with an invalid link name of ''!\n"); + PART_ERROR(H5Ldelete_invalid_link_name); + } + + PASSED(); + } + PART_END(H5Ldelete_invalid_link_name); + + PART_BEGIN(H5Ldelete_invalid_lapl) + { + TESTING_2("H5Ldelete with an invalid LAPL"); +#ifndef NO_INVALID_PROPERTY_LIST_TESTS + H5E_BEGIN_TRY + { + err_ret = + H5Ldelete(group_id, LINK_DELETE_INVALID_PARAMS_TEST_HARD_LINK_NAME, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ldelete succeeded with an invalid LAPL!\n"); + PART_ERROR(H5Ldelete_invalid_lapl); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Ldelete_invalid_lapl); +#endif + } + PART_END(H5Ldelete_invalid_lapl); + + PART_BEGIN(H5Ldelete_by_idx_invalid_loc_id) + { + TESTING_2("H5Ldelete_by_idx with an invalid location ID"); + + H5E_BEGIN_TRY + { + err_ret = H5Ldelete_by_idx(H5I_INVALID_HID, ".", H5_INDEX_NAME, H5_ITER_INC, 0, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ldelete_by_idx succeeded with an invalid location ID!\n"); + PART_ERROR(H5Ldelete_by_idx_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Ldelete_by_idx_invalid_loc_id); + + PART_BEGIN(H5Ldelete_by_idx_invalid_grp_name) + { + TESTING_2("H5Ldelete_by_idx with an invalid group name"); + + H5E_BEGIN_TRY + { + err_ret = H5Ldelete_by_idx(group_id, NULL, H5_INDEX_NAME, H5_ITER_INC, 0, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ldelete_by_idx succeeded with a NULL group name!\n"); + PART_ERROR(H5Ldelete_by_idx_invalid_grp_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Ldelete_by_idx(group_id, "", H5_INDEX_NAME, H5_ITER_INC, 0, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ldelete_by_idx succeeded with an invalid group name of ''!\n"); + PART_ERROR(H5Ldelete_by_idx_invalid_grp_name); + } + + PASSED(); + } + PART_END(H5Ldelete_by_idx_invalid_grp_name); + + PART_BEGIN(H5Ldelete_by_idx_invalid_index_type) + { + TESTING_2("H5Ldelete_by_idx with an invalid index type"); + + H5E_BEGIN_TRY + { + err_ret = H5Ldelete_by_idx(group_id, ".", H5_INDEX_UNKNOWN, H5_ITER_INC, 0, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ldelete_by_idx succeeded with invalid index type H5_INDEX_UNKNOWN!\n"); + PART_ERROR(H5Ldelete_by_idx_invalid_index_type); + } + + H5E_BEGIN_TRY + { + err_ret = H5Ldelete_by_idx(group_id, ".", H5_INDEX_N, H5_ITER_INC, 0, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ldelete_by_idx succeeded with invalid index type H5_INDEX_N!\n"); + PART_ERROR(H5Ldelete_by_idx_invalid_index_type); + } + + PASSED(); + } + PART_END(H5Ldelete_by_idx_invalid_index_type); + + PART_BEGIN(H5Ldelete_by_idx_invalid_index_order) + { + TESTING_2("H5Ldelete_by_idx with an invalid iteration ordering"); + + H5E_BEGIN_TRY + { + err_ret = H5Ldelete_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_UNKNOWN, 0, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ldelete_by_idx succeeded with invalid iteration ordering H5_ITER_UNKNOWN!\n"); + PART_ERROR(H5Ldelete_by_idx_invalid_index_order); + } + + H5E_BEGIN_TRY + { + err_ret = H5Ldelete_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_N, 0, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ldelete_by_idx succeeded with invalid iteration ordering H5_ITER_N!\n"); + PART_ERROR(H5Ldelete_by_idx_invalid_index_order); + } + + PASSED(); + } + PART_END(H5Ldelete_by_idx_invalid_index_order); + + PART_BEGIN(H5Ldelete_by_idx_invalid_lapl) + { + TESTING_2("H5Ldelete_by_idx with an invalid LAPL"); +#ifndef NO_INVALID_PROPERTY_LIST_TESTS + H5E_BEGIN_TRY + { + err_ret = H5Ldelete_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ldelete_by_idx succeeded with an invalid LAPL!\n"); + PART_ERROR(H5Ldelete_by_idx_invalid_lapl); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Ldelete_by_idx_invalid_lapl); +#endif + } + PART_END(H5Ldelete_by_idx_invalid_lapl); + + PART_BEGIN(H5Ldelete_by_idx_link_existence) + { + TESTING_2("valid link existence after previous invalid H5Ldelete(_by_idx) calls"); + + /* Verify that the link hasn't been deleted */ + if ((link_exists = + H5Lexists(group_id, LINK_DELETE_INVALID_PARAMS_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + LINK_DELETE_INVALID_PARAMS_TEST_HARD_LINK_NAME); + PART_ERROR(H5Ldelete_by_idx_link_existence); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link didn't exist!\n"); + PART_ERROR(H5Ldelete_by_idx_link_existence); + } + + PASSED(); + } + PART_END(H5Ldelete_by_idx_link_existence); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a link can be copied using H5Lcopy. + */ +static int +test_copy_link(void) +{ + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID, ext_file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t src_grp_id = H5I_INVALID_HID, dst_grp_id = H5I_INVALID_HID; +#ifndef NO_EXTERNAL_LINKS + char ext_link_filename[H5_API_TEST_FILENAME_MAX_LENGTH]; +#endif + + TESTING_MULTIPART("link copying"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_HARD_LINKS) || !(vol_cap_flags_g & H5VL_CAP_FLAG_EXTERNAL_LINKS) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_SOFT_LINKS)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, or link, hard, soft, or external link aren't " + "supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't opewn container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, COPY_LINK_TEST_SUBGROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", COPY_LINK_TEST_SUBGROUP_NAME); + goto error; + } + + if ((src_grp_id = H5Gcreate2(group_id, COPY_LINK_TEST_SRC_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", COPY_LINK_TEST_SRC_GROUP_NAME); + goto error; + } + + if ((dst_grp_id = H5Gcreate2(group_id, COPY_LINK_TEST_DST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", COPY_LINK_TEST_DST_GROUP_NAME); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Lcopy_hard_no_check) + { + TESTING_2("H5Lcopy on hard link (copied link's properties not checked)"); + + /* Try to copy a hard link */ + if (H5Lcreate_hard(group_id, ".", src_grp_id, COPY_LINK_TEST_HARD_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", COPY_LINK_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lcopy_hard_no_check); + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(src_grp_id, COPY_LINK_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", COPY_LINK_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lcopy_hard_no_check); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link did not exist\n"); + PART_ERROR(H5Lcopy_hard_no_check); + } + + /* Verify the link doesn't currently exist in the target group */ + if ((link_exists = H5Lexists(dst_grp_id, COPY_LINK_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", COPY_LINK_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lcopy_hard_no_check); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link existed in target group before copy!\n"); + PART_ERROR(H5Lcopy_hard_no_check); + } + + /* Copy the link */ + if (H5Lcopy(src_grp_id, COPY_LINK_TEST_HARD_LINK_NAME, dst_grp_id, + COPY_LINK_TEST_HARD_LINK_COPY_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to copy hard link '%s'\n", COPY_LINK_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lcopy_hard_no_check); + } + + /* Verify the link has been copied and still exists in the source group */ + if ((link_exists = H5Lexists(dst_grp_id, COPY_LINK_TEST_HARD_LINK_COPY_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link copy '%s' exists\n", + COPY_LINK_TEST_HARD_LINK_COPY_NAME); + PART_ERROR(H5Lcopy_hard_no_check); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link copy did not exist\n"); + PART_ERROR(H5Lcopy_hard_no_check); + } + + if ((link_exists = H5Lexists(src_grp_id, COPY_LINK_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if original hard link '%s' exists\n", + COPY_LINK_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lcopy_hard_no_check); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" original hard link did not exist\n"); + PART_ERROR(H5Lcopy_hard_no_check); + } + + PASSED(); + } + PART_END(H5Lcopy_hard_no_check); + + PART_BEGIN(H5Lcopy_hard_check) + { + H5L_info2_t orig_info, new_info; + int cmp_value; + + TESTING_2("H5Lcopy on hard link (copied link's properties checked)"); + + /* Try to copy a hard link */ + if (H5Lcreate_hard(group_id, ".", src_grp_id, COPY_LINK_TEST_HARD_LINK_NAME2, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", COPY_LINK_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lcopy_hard_check); + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(src_grp_id, COPY_LINK_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", COPY_LINK_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lcopy_hard_check); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link did not exist\n"); + PART_ERROR(H5Lcopy_hard_check); + } + + /* Retrieve the link's info */ + if (H5Lget_info2(src_grp_id, COPY_LINK_TEST_HARD_LINK_NAME2, &orig_info, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve info for link '%s'\n", COPY_LINK_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lcopy_hard_check); + } + + /* Verify the link doesn't currently exist in the target group */ + if ((link_exists = H5Lexists(dst_grp_id, COPY_LINK_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", COPY_LINK_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lcopy_hard_check); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link existed in target group before copy!\n"); + PART_ERROR(H5Lcopy_hard_check); + } + + /* Copy the link */ + if (H5Lcopy(src_grp_id, COPY_LINK_TEST_HARD_LINK_NAME2, dst_grp_id, + COPY_LINK_TEST_HARD_LINK_COPY_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to copy hard link '%s'\n", COPY_LINK_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lcopy_hard_check); + } + + /* Verify the link has been copied and still exists in the source group */ + if ((link_exists = H5Lexists(dst_grp_id, COPY_LINK_TEST_HARD_LINK_COPY_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link copy '%s' exists\n", + COPY_LINK_TEST_HARD_LINK_COPY_NAME2); + PART_ERROR(H5Lcopy_hard_check); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link copy did not exist\n"); + PART_ERROR(H5Lcopy_hard_check); + } + + if ((link_exists = H5Lexists(src_grp_id, COPY_LINK_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if original hard link '%s' exists\n", + COPY_LINK_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lcopy_hard_check); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" original hard link did not exist\n"); + PART_ERROR(H5Lcopy_hard_check); + } + + /* Retrieve the new link's info */ + if (H5Lget_info2(dst_grp_id, COPY_LINK_TEST_HARD_LINK_COPY_NAME2, &new_info, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve info for link '%s'\n", COPY_LINK_TEST_HARD_LINK_COPY_NAME2); + PART_ERROR(H5Lcopy_hard_check); + } + + if (new_info.type != orig_info.type) { + H5_FAILED(); + HDprintf(" copied link's link type doesn't match original link's type\n"); + PART_ERROR(H5Lcopy_hard_check); + } + + if (H5Otoken_cmp(dst_grp_id, &new_info.u.token, &orig_info.u.token, &cmp_value) < 0) { + H5_FAILED(); + HDprintf(" failed to compare link target tokens\n"); + PART_ERROR(H5Lcopy_hard_check); + } + + if (cmp_value != 0) { + H5_FAILED(); + HDprintf(" copied hard link's object token doesn't match original link's object token\n"); + PART_ERROR(H5Lcopy_hard_check); + } + + if (new_info.corder_valid != orig_info.corder_valid) { + H5_FAILED(); + HDprintf(" copied link's 'corder_valid' field doesn't match original link's " + "'corder_valid' field\n"); + PART_ERROR(H5Lcopy_hard_check); + } + + if (new_info.corder_valid && orig_info.corder_valid && (new_info.corder != orig_info.corder)) { + H5_FAILED(); + HDprintf(" copied link's creation order value %" PRId64 + " doesn't match original link's creation order value %" PRId64 "\n", + new_info.corder, orig_info.corder); + PART_ERROR(H5Lcopy_hard_check); + } + + if (new_info.cset != orig_info.cset) { + H5_FAILED(); + HDprintf(" copied link's character set doesn't match original link's character set\n"); + PART_ERROR(H5Lcopy_hard_check); + } + + PASSED(); + } + PART_END(H5Lcopy_hard_check); + + PART_BEGIN(H5Lcopy_hard_same_loc) + { + TESTING_2("H5Lcopy on hard link using H5L_SAME_LOC"); + + /* Try to copy a hard link */ + if (H5Lcreate_hard(group_id, ".", src_grp_id, COPY_LINK_TEST_HARD_LINK_NAME3, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", COPY_LINK_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lcopy_hard_same_loc); + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(src_grp_id, COPY_LINK_TEST_HARD_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", COPY_LINK_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lcopy_hard_same_loc); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link did not exist\n"); + PART_ERROR(H5Lcopy_hard_same_loc); + } + + /* Verify the links don't currently exist in the target group */ + if ((link_exists = H5Lexists(src_grp_id, COPY_LINK_TEST_HARD_LINK_SAME_LOC_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + COPY_LINK_TEST_HARD_LINK_SAME_LOC_NAME); + PART_ERROR(H5Lcopy_hard_same_loc); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link existed in target group before copy!\n"); + PART_ERROR(H5Lcopy_hard_same_loc); + } + + if ((link_exists = H5Lexists(src_grp_id, COPY_LINK_TEST_HARD_LINK_SAME_LOC_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + COPY_LINK_TEST_HARD_LINK_SAME_LOC_NAME2); + PART_ERROR(H5Lcopy_hard_same_loc); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link existed in target group before copy!\n"); + PART_ERROR(H5Lcopy_hard_same_loc); + } + + /* Copy the link using H5L_SAME_LOC as the first parameter to H5Lcopy */ + if (H5Lcopy(H5L_SAME_LOC, COPY_LINK_TEST_HARD_LINK_NAME3, src_grp_id, + COPY_LINK_TEST_HARD_LINK_SAME_LOC_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf( + " failed to copy hard link '%s' using H5L_SAME_LOC as first parameter to H5Lcopy\n", + COPY_LINK_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lcopy_hard_same_loc); + } + + /* Copy the link using H5L_SAME_LOC as the third parameter to H5Lcopy */ + if (H5Lcopy(src_grp_id, COPY_LINK_TEST_HARD_LINK_NAME3, H5L_SAME_LOC, + COPY_LINK_TEST_HARD_LINK_SAME_LOC_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf( + " failed to copy hard link '%s' using H5L_SAME_LOC as third parameter to H5Lcopy\n", + COPY_LINK_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lcopy_hard_same_loc); + } + + /* Verify the links have been copied and the original still exist in the source group */ + if ((link_exists = H5Lexists(src_grp_id, COPY_LINK_TEST_HARD_LINK_SAME_LOC_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link copy '%s' exists\n", + COPY_LINK_TEST_HARD_LINK_SAME_LOC_NAME); + PART_ERROR(H5Lcopy_hard_same_loc); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link copy did not exist\n"); + PART_ERROR(H5Lcopy_hard_same_loc); + } + + if ((link_exists = H5Lexists(src_grp_id, COPY_LINK_TEST_HARD_LINK_SAME_LOC_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link copy '%s' exists\n", + COPY_LINK_TEST_HARD_LINK_SAME_LOC_NAME2); + PART_ERROR(H5Lcopy_hard_same_loc); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link copy did not exist\n"); + PART_ERROR(H5Lcopy_hard_same_loc); + } + + if ((link_exists = H5Lexists(src_grp_id, COPY_LINK_TEST_HARD_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if original hard link '%s' exists\n", + COPY_LINK_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lcopy_hard_same_loc); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" original hard link did not exist\n"); + PART_ERROR(H5Lcopy_hard_same_loc); + } + + PASSED(); + } + PART_END(H5Lcopy_hard_same_loc); + + PART_BEGIN(H5Lcopy_soft_no_check) + { + TESTING_2("H5Lcopy on soft link (copied link's properties not checked)"); + + /* Try to copy a soft link */ + if (H5Lcreate_soft(COPY_LINK_TEST_SOFT_LINK_TARGET_PATH, src_grp_id, + COPY_LINK_TEST_SOFT_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", COPY_LINK_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lcopy_soft_no_check); + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(src_grp_id, COPY_LINK_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", COPY_LINK_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lcopy_soft_no_check); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link did not exist\n"); + PART_ERROR(H5Lcopy_soft_no_check); + } + + /* Verify the link doesn't currently exist in the target group */ + if ((link_exists = H5Lexists(dst_grp_id, COPY_LINK_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", COPY_LINK_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lcopy_soft_no_check); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link existed in target group before copy!\n"); + PART_ERROR(H5Lcopy_soft_no_check); + } + + /* Copy the link */ + if (H5Lcopy(src_grp_id, COPY_LINK_TEST_SOFT_LINK_NAME, dst_grp_id, + COPY_LINK_TEST_SOFT_LINK_COPY_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to copy soft link '%s'\n", COPY_LINK_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lcopy_soft_no_check); + } + + /* Verify the link has been copied and still exists in the source group */ + if ((link_exists = H5Lexists(dst_grp_id, COPY_LINK_TEST_SOFT_LINK_COPY_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' copy exists\n", + COPY_LINK_TEST_SOFT_LINK_COPY_NAME); + PART_ERROR(H5Lcopy_soft_no_check); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link copy did not exist\n"); + PART_ERROR(H5Lcopy_soft_no_check); + } + + if ((link_exists = H5Lexists(src_grp_id, COPY_LINK_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if original soft link '%s' exists\n", + COPY_LINK_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lcopy_soft_no_check); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" original soft link did not exist\n"); + PART_ERROR(H5Lcopy_soft_no_check); + } + + PASSED(); + } + PART_END(H5Lcopy_soft_no_check); + + PART_BEGIN(H5Lcopy_soft_check) + { + H5L_info2_t orig_info, new_info; + char orig_link_val[COPY_LINK_TEST_LINK_VAL_BUF_SIZE]; + char new_link_val[COPY_LINK_TEST_LINK_VAL_BUF_SIZE]; + + TESTING_2("H5Lcopy on soft link (copied link's properties checked)"); + + /* Try to copy a soft link */ + if (H5Lcreate_soft(COPY_LINK_TEST_SOFT_LINK_TARGET_PATH, src_grp_id, + COPY_LINK_TEST_SOFT_LINK_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", COPY_LINK_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lcopy_soft_check); + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(src_grp_id, COPY_LINK_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", COPY_LINK_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lcopy_soft_check); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link did not exist\n"); + PART_ERROR(H5Lcopy_soft_check); + } + + /* Retrieve the link's info */ + if (H5Lget_info2(src_grp_id, COPY_LINK_TEST_SOFT_LINK_NAME2, &orig_info, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve info for link '%s'\n", COPY_LINK_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lcopy_soft_check); + } + + /* Retrieve the link's value */ + if (H5Lget_val(src_grp_id, COPY_LINK_TEST_SOFT_LINK_NAME2, orig_link_val, + COPY_LINK_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve value for soft link '%s'\n", COPY_LINK_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lcopy_soft_check); + } + + /* Verify the link doesn't currently exist in the target group */ + if ((link_exists = H5Lexists(dst_grp_id, COPY_LINK_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", COPY_LINK_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lcopy_soft_check); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link existed in target group before copy!\n"); + PART_ERROR(H5Lcopy_soft_check); + } + + /* Copy the link */ + if (H5Lcopy(src_grp_id, COPY_LINK_TEST_SOFT_LINK_NAME2, dst_grp_id, + COPY_LINK_TEST_SOFT_LINK_COPY_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to copy soft link '%s'\n", COPY_LINK_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lcopy_soft_check); + } + + /* Verify the link has been copied and still exists in the source group */ + if ((link_exists = H5Lexists(dst_grp_id, COPY_LINK_TEST_SOFT_LINK_COPY_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' copy exists\n", + COPY_LINK_TEST_SOFT_LINK_COPY_NAME2); + PART_ERROR(H5Lcopy_soft_check); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link copy did not exist\n"); + PART_ERROR(H5Lcopy_soft_check); + } + + if ((link_exists = H5Lexists(src_grp_id, COPY_LINK_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if original soft link '%s' exists\n", + COPY_LINK_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lcopy_soft_check); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" original soft link did not exist\n"); + PART_ERROR(H5Lcopy_soft_check); + } + + /* Retrieve the new link's info */ + if (H5Lget_info2(dst_grp_id, COPY_LINK_TEST_SOFT_LINK_COPY_NAME2, &new_info, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve info for link '%s'\n", COPY_LINK_TEST_SOFT_LINK_COPY_NAME2); + PART_ERROR(H5Lcopy_soft_check); + } + + if (new_info.type != orig_info.type) { + H5_FAILED(); + HDprintf(" copied link's link type doesn't match original link's type\n"); + PART_ERROR(H5Lcopy_soft_check); + } + + if (new_info.u.val_size != orig_info.u.val_size) { + H5_FAILED(); + HDprintf(" copied soft link's value size of %llu doesn't match original link's value size " + "of %llu\n", + (unsigned long long)new_info.u.val_size, (unsigned long long)orig_info.u.val_size); + PART_ERROR(H5Lcopy_soft_check); + } + + if (new_info.corder_valid != orig_info.corder_valid) { + H5_FAILED(); + HDprintf(" copied link's 'corder_valid' field doesn't match original link's " + "'corder_valid' field\n"); + PART_ERROR(H5Lcopy_soft_check); + } + + if (new_info.corder_valid && orig_info.corder_valid && (new_info.corder != orig_info.corder)) { + H5_FAILED(); + HDprintf(" copied link's creation order value %" PRId64 + " doesn't match original link's creation order value %" PRId64 "\n", + new_info.corder, orig_info.corder); + PART_ERROR(H5Lcopy_soft_check); + } + + if (new_info.cset != orig_info.cset) { + H5_FAILED(); + HDprintf(" copied link's character set doesn't match original link's character set\n"); + PART_ERROR(H5Lcopy_soft_check); + } + + /* Check the soft link's value */ + if (H5Lget_val(dst_grp_id, COPY_LINK_TEST_SOFT_LINK_COPY_NAME2, new_link_val, + COPY_LINK_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve value for soft link '%s'\n", + COPY_LINK_TEST_SOFT_LINK_COPY_NAME2); + PART_ERROR(H5Lcopy_soft_check); + } + + if (HDstrncmp(orig_link_val, new_link_val, COPY_LINK_TEST_LINK_VAL_BUF_SIZE)) { + H5_FAILED(); + HDprintf(" copied soft link's value '%s' doesn't match original link's value '%s'\n", + new_link_val, orig_link_val); + PART_ERROR(H5Lcopy_soft_check); + } + + PASSED(); + } + PART_END(H5Lcopy_soft_check); + + PART_BEGIN(H5Lcopy_soft_same_loc) + { + TESTING_2("H5Lcopy on soft link using H5L_SAME_LOC"); + + /* Try to copy a soft link */ + if (H5Lcreate_soft(COPY_LINK_TEST_SOFT_LINK_TARGET_PATH, src_grp_id, + COPY_LINK_TEST_SOFT_LINK_NAME3, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", COPY_LINK_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lcopy_soft_same_loc); + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(src_grp_id, COPY_LINK_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", COPY_LINK_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lcopy_soft_same_loc); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link did not exist\n"); + PART_ERROR(H5Lcopy_soft_same_loc); + } + + /* Verify the links don't currently exist in the target group */ + if ((link_exists = H5Lexists(src_grp_id, COPY_LINK_TEST_SOFT_LINK_SAME_LOC_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + COPY_LINK_TEST_SOFT_LINK_SAME_LOC_NAME); + PART_ERROR(H5Lcopy_soft_same_loc); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link existed in target group before copy!\n"); + PART_ERROR(H5Lcopy_soft_same_loc); + } + + if ((link_exists = H5Lexists(src_grp_id, COPY_LINK_TEST_SOFT_LINK_SAME_LOC_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + COPY_LINK_TEST_SOFT_LINK_SAME_LOC_NAME2); + PART_ERROR(H5Lcopy_soft_same_loc); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link existed in target group before copy!\n"); + PART_ERROR(H5Lcopy_soft_same_loc); + } + + /* Copy the link using H5L_SAME_LOC as the first parameter to H5Lcopy */ + if (H5Lcopy(H5L_SAME_LOC, COPY_LINK_TEST_SOFT_LINK_NAME3, src_grp_id, + COPY_LINK_TEST_SOFT_LINK_SAME_LOC_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf( + " failed to copy soft link '%s' using H5L_SAME_LOC as first parameter to H5Lcopy\n", + COPY_LINK_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lcopy_soft_same_loc); + } + + /* Copy the link using H5L_SAME_LOC as the third parameter to H5Lcopy */ + if (H5Lcopy(src_grp_id, COPY_LINK_TEST_SOFT_LINK_NAME3, H5L_SAME_LOC, + COPY_LINK_TEST_SOFT_LINK_SAME_LOC_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf( + " failed to copy soft link '%s' using H5L_SAME_LOC as third parameter to H5Lcopy\n", + COPY_LINK_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lcopy_soft_same_loc); + } + + /* Verify the links have been copied and the original still exists in the source group */ + if ((link_exists = H5Lexists(src_grp_id, COPY_LINK_TEST_SOFT_LINK_SAME_LOC_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' copy exists\n", + COPY_LINK_TEST_SOFT_LINK_SAME_LOC_NAME); + PART_ERROR(H5Lcopy_soft_same_loc); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link copy did not exist\n"); + PART_ERROR(H5Lcopy_soft_same_loc); + } + + if ((link_exists = H5Lexists(src_grp_id, COPY_LINK_TEST_SOFT_LINK_SAME_LOC_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' copy exists\n", + COPY_LINK_TEST_SOFT_LINK_SAME_LOC_NAME2); + PART_ERROR(H5Lcopy_soft_same_loc); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link copy did not exist\n"); + PART_ERROR(H5Lcopy_soft_same_loc); + } + + if ((link_exists = H5Lexists(src_grp_id, COPY_LINK_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if original soft link '%s' exists\n", + COPY_LINK_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lcopy_soft_same_loc); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" original soft link did not exist\n"); + PART_ERROR(H5Lcopy_soft_same_loc); + } + + PASSED(); + } + PART_END(H5Lcopy_soft_same_loc); + + PART_BEGIN(H5Lcopy_external_no_check) + { + TESTING_2("H5Lcopy on external link (copied link's properties not checked)"); +#ifndef NO_EXTERNAL_LINKS + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME); + + if ((ext_file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + PART_ERROR(H5Lcopy_external_no_check); + } + + if (H5Fclose(ext_file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close file '%s'\n", ext_link_filename); + PART_ERROR(H5Lcopy_external_no_check); + } + + /* Try to copy an external link */ + if (H5Lcreate_external(ext_link_filename, "/", src_grp_id, COPY_LINK_TEST_EXTERNAL_LINK_NAME, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", COPY_LINK_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Lcopy_external_no_check); + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(src_grp_id, COPY_LINK_TEST_EXTERNAL_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + COPY_LINK_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Lcopy_external_no_check); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link did not exist\n"); + PART_ERROR(H5Lcopy_external_no_check); + } + + /* Verify the link doesn't currently exist in the target group */ + if ((link_exists = H5Lexists(dst_grp_id, COPY_LINK_TEST_EXTERNAL_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + COPY_LINK_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Lcopy_external_no_check); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link existed in target group before copy!\n"); + PART_ERROR(H5Lcopy_external_no_check); + } + + /* Copy the link */ + if (H5Lcopy(src_grp_id, COPY_LINK_TEST_EXTERNAL_LINK_NAME, dst_grp_id, + COPY_LINK_TEST_EXTERNAL_LINK_COPY_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to copy external link '%s'\n", COPY_LINK_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Lcopy_external_no_check); + } + + /* Verify the link has been copied and still exists in the source group */ + if ((link_exists = H5Lexists(dst_grp_id, COPY_LINK_TEST_EXTERNAL_LINK_COPY_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link copy '%s' exists\n", + COPY_LINK_TEST_EXTERNAL_LINK_COPY_NAME); + PART_ERROR(H5Lcopy_external_no_check); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link copy did not exist\n"); + PART_ERROR(H5Lcopy_external_no_check); + } + + if ((link_exists = H5Lexists(src_grp_id, COPY_LINK_TEST_EXTERNAL_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if original external link '%s' exists\n", + COPY_LINK_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Lcopy_external_no_check); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" original external link did not exist\n"); + PART_ERROR(H5Lcopy_external_no_check); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lcopy_external_no_check); +#endif + } + PART_END(H5Lcopy_external_no_check); + + H5E_BEGIN_TRY + { + H5Fclose(ext_file_id); + ext_file_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lcopy_external_check) + { +#ifndef NO_EXTERNAL_LINKS + H5L_info2_t orig_info, new_info; + const char *orig_filename, *new_filename; + const char *orig_objname, *new_objname; + unsigned unpack_flags = 0; + char orig_link_val[COPY_LINK_TEST_LINK_VAL_BUF_SIZE]; + char new_link_val[COPY_LINK_TEST_LINK_VAL_BUF_SIZE]; +#endif + + TESTING_2("H5Lcopy on external link (copied link's properties checked)"); +#ifndef NO_EXTERNAL_LINKS + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME); + + if ((ext_file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + PART_ERROR(H5Lcopy_external_check); + } + + if (H5Fclose(ext_file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close file '%s'\n", ext_link_filename); + PART_ERROR(H5Lcopy_external_check); + } + + /* Try to copy an external link */ + if (H5Lcreate_external(ext_link_filename, "/", src_grp_id, COPY_LINK_TEST_EXTERNAL_LINK_NAME2, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", COPY_LINK_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Lcopy_external_check); + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(src_grp_id, COPY_LINK_TEST_EXTERNAL_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + COPY_LINK_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Lcopy_external_check); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link did not exist\n"); + PART_ERROR(H5Lcopy_external_check); + } + + /* Retrieve the link's info */ + if (H5Lget_info2(src_grp_id, COPY_LINK_TEST_EXTERNAL_LINK_NAME2, &orig_info, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve info for link '%s'\n", COPY_LINK_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Lcopy_external_check); + } + + /* Retrieve the link's value */ + if (H5Lget_val(src_grp_id, COPY_LINK_TEST_EXTERNAL_LINK_NAME2, orig_link_val, + COPY_LINK_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve value for external link '%s'\n", + COPY_LINK_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Lcopy_external_check); + } + + if (H5Lunpack_elink_val(orig_link_val, orig_info.u.val_size, &unpack_flags, &orig_filename, + &orig_objname) < 0) { + H5_FAILED(); + HDprintf(" couldn't unpack original external link's value buffer\n"); + PART_ERROR(H5Lcopy_external_check); + } + + /* Verify the link doesn't currently exist in the target group */ + if ((link_exists = H5Lexists(dst_grp_id, COPY_LINK_TEST_EXTERNAL_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + COPY_LINK_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Lcopy_external_check); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link existed in target group before copy!\n"); + PART_ERROR(H5Lcopy_external_check); + } + + /* Copy the link */ + if (H5Lcopy(src_grp_id, COPY_LINK_TEST_EXTERNAL_LINK_NAME2, dst_grp_id, + COPY_LINK_TEST_EXTERNAL_LINK_COPY_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to copy external link '%s'\n", COPY_LINK_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Lcopy_external_check); + } + + /* Verify the link has been copied and still exists in the source group */ + if ((link_exists = H5Lexists(dst_grp_id, COPY_LINK_TEST_EXTERNAL_LINK_COPY_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link copy '%s' exists\n", + COPY_LINK_TEST_EXTERNAL_LINK_COPY_NAME2); + PART_ERROR(H5Lcopy_external_check); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link copy did not exist\n"); + PART_ERROR(H5Lcopy_external_check); + } + + if ((link_exists = H5Lexists(src_grp_id, COPY_LINK_TEST_EXTERNAL_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if original external link '%s' exists\n", + COPY_LINK_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Lcopy_external_check); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" original external link did not exist\n"); + PART_ERROR(H5Lcopy_external_check); + } + + /* Retrieve the new link's info */ + if (H5Lget_info2(dst_grp_id, COPY_LINK_TEST_EXTERNAL_LINK_COPY_NAME2, &new_info, H5P_DEFAULT) < + 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve info for link '%s'\n", + COPY_LINK_TEST_EXTERNAL_LINK_COPY_NAME2); + PART_ERROR(H5Lcopy_external_check); + } + + if (new_info.type != orig_info.type) { + H5_FAILED(); + HDprintf(" copied link's link type doesn't match original link's type\n"); + PART_ERROR(H5Lcopy_external_check); + } + + if (new_info.u.val_size != orig_info.u.val_size) { + H5_FAILED(); + HDprintf(" copied external link's value size of %llu doesn't match original link's value " + "size of %llu\n", + (unsigned long long)new_info.u.val_size, (unsigned long long)orig_info.u.val_size); + PART_ERROR(H5Lcopy_external_check); + } + + if (new_info.corder_valid != orig_info.corder_valid) { + H5_FAILED(); + HDprintf(" copied link's 'corder_valid' field doesn't match original link's " + "'corder_valid' field\n"); + PART_ERROR(H5Lcopy_external_check); + } + + if (new_info.corder_valid && orig_info.corder_valid && (new_info.corder != orig_info.corder)) { + H5_FAILED(); + HDprintf(" copied link's creation order value %lld doesn't match original link's creation " + "order value %lld\n", + new_info.corder, orig_info.corder); + PART_ERROR(H5Lcopy_external_check); + } + + if (new_info.cset != orig_info.cset) { + H5_FAILED(); + HDprintf(" copied link's character set doesn't match original link's character set\n"); + PART_ERROR(H5Lcopy_external_check); + } + + /* Check the external link's value */ + if (H5Lget_val(dst_grp_id, COPY_LINK_TEST_EXTERNAL_LINK_COPY_NAME2, new_link_val, + COPY_LINK_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve value for external link '%s'\n", + COPY_LINK_TEST_EXTERNAL_LINK_COPY_NAME2); + PART_ERROR(H5Lcopy_external_check); + } + + if (H5Lunpack_elink_val(new_link_val, new_info.u.val_size, &unpack_flags, &new_filename, + &new_objname) < 0) { + H5_FAILED(); + HDprintf(" couldn't unpack copied external link's value buffer\n"); + PART_ERROR(H5Lcopy_external_check); + } + + if (HDstrncmp(new_filename, orig_filename, strlen(orig_filename)) < 0) { + H5_FAILED(); + HDprintf(" copied external link's filename '%s' doesn't match original external link's " + "filename '%s'\n", + new_filename, orig_filename); + PART_ERROR(H5Lcopy_external_check); + } + + if (HDstrncmp(new_objname, orig_objname, strlen(orig_objname)) < 0) { + H5_FAILED(); + HDprintf(" copied external link's object name '%s' doesn't match original external link's " + "object name '%s'\n", + new_objname, orig_objname); + PART_ERROR(H5Lcopy_external_check); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lcopy_external_check); +#endif + } + PART_END(H5Lcopy_external_check); + + H5E_BEGIN_TRY + { + H5Fclose(ext_file_id); + ext_file_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lcopy_external_same_loc) + { + TESTING_2("H5Lcopy on external link using H5L_SAME_LOC"); +#ifndef NO_EXTERNAL_LINKS + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME); + + if ((ext_file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + PART_ERROR(H5Lcopy_external_same_loc); + } + + if (H5Fclose(ext_file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close file '%s'\n", ext_link_filename); + PART_ERROR(H5Lcopy_external_same_loc); + } + + /* Try to copy an external link */ + if (H5Lcreate_external(ext_link_filename, "/", src_grp_id, COPY_LINK_TEST_EXTERNAL_LINK_NAME3, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", COPY_LINK_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Lcopy_external_same_loc); + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(src_grp_id, COPY_LINK_TEST_EXTERNAL_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + COPY_LINK_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Lcopy_external_same_loc); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link did not exist\n"); + PART_ERROR(H5Lcopy_external_same_loc); + } + + /* Verify the links don't currently exist in the target group */ + if ((link_exists = + H5Lexists(src_grp_id, COPY_LINK_TEST_EXTERNAL_LINK_SAME_LOC_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + COPY_LINK_TEST_EXTERNAL_LINK_SAME_LOC_NAME); + PART_ERROR(H5Lcopy_external_same_loc); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link existed in target group before copy!\n"); + PART_ERROR(H5Lcopy_external_same_loc); + } + + if ((link_exists = + H5Lexists(src_grp_id, COPY_LINK_TEST_EXTERNAL_LINK_SAME_LOC_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + COPY_LINK_TEST_EXTERNAL_LINK_SAME_LOC_NAME2); + PART_ERROR(H5Lcopy_external_same_loc); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link existed in target group before copy!\n"); + PART_ERROR(H5Lcopy_external_same_loc); + } + + /* Copy the link using H5L_SAME_LOC as the first parameter to H5Lcopy */ + if (H5Lcopy(H5L_SAME_LOC, COPY_LINK_TEST_EXTERNAL_LINK_NAME3, src_grp_id, + COPY_LINK_TEST_EXTERNAL_LINK_SAME_LOC_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to copy external link '%s' using H5L_SAME_LOC as first parameter to " + "H5Lcopy\n", + COPY_LINK_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Lcopy_external_same_loc); + } + + /* Copy the link using H5L_SAME_LOC as the third parameter to H5Lcopy */ + if (H5Lcopy(src_grp_id, COPY_LINK_TEST_EXTERNAL_LINK_NAME3, H5L_SAME_LOC, + COPY_LINK_TEST_EXTERNAL_LINK_SAME_LOC_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to copy external link '%s' using H5L_SAME_LOC as third parameter to " + "H5Lcopy\n", + COPY_LINK_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Lcopy_external_same_loc); + } + + /* Verify the links have been copied and the original still exists in the source group */ + if ((link_exists = + H5Lexists(src_grp_id, COPY_LINK_TEST_EXTERNAL_LINK_SAME_LOC_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link copy '%s' exists\n", + COPY_LINK_TEST_EXTERNAL_LINK_SAME_LOC_NAME); + PART_ERROR(H5Lcopy_external_same_loc); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link copy did not exist\n"); + PART_ERROR(H5Lcopy_external_same_loc); + } + + if ((link_exists = + H5Lexists(src_grp_id, COPY_LINK_TEST_EXTERNAL_LINK_SAME_LOC_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link copy '%s' exists\n", + COPY_LINK_TEST_EXTERNAL_LINK_SAME_LOC_NAME2); + PART_ERROR(H5Lcopy_external_same_loc); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link copy did not exist\n"); + PART_ERROR(H5Lcopy_external_same_loc); + } + + if ((link_exists = H5Lexists(src_grp_id, COPY_LINK_TEST_EXTERNAL_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if original external link '%s' exists\n", + COPY_LINK_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Lcopy_external_same_loc); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" original external link did not exist\n"); + PART_ERROR(H5Lcopy_external_same_loc); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lcopy_external_same_loc); +#endif + } + PART_END(H5Lcopy_external_same_loc); + + H5E_BEGIN_TRY + { + H5Fclose(ext_file_id); + ext_file_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lcopy_ud_no_check) + { + TESTING_2("H5Lcopy on user-defined link (copied link's properties not checked)"); + + /* TODO */ + + SKIPPED(); + PART_EMPTY(H5Lcopy_ud_no_check); + } + PART_END(H5Lcopy_ud_no_check); + + PART_BEGIN(H5Lcopy_ud_check) + { + TESTING_2("H5Lcopy on user-defined link (copied link's properties checked)"); + + /* TODO */ + + SKIPPED(); + PART_EMPTY(H5Lcopy_ud_check); + } + PART_END(H5Lcopy_ud_check); + + PART_BEGIN(H5Lcopy_ud_same_loc) + { + TESTING_2("H5Lcopy on user-defined link using H5L_SAME_LOC"); + + /* TODO */ + + SKIPPED(); + PART_EMPTY(H5Lcopy_ud_same_loc); + } + PART_END(H5Lcopy_ud_same_loc); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Gclose(dst_grp_id) < 0) + TEST_ERROR; + if (H5Gclose(src_grp_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(dst_grp_id); + H5Gclose(src_grp_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(ext_file_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that using H5Lcopy to copy links into a + * group which already contains links will cause the new links + * to have creation order values ranging from the target group's + * maximum link creation order value and upwards. This is to + * check that it is not possible to run into the situation where + * H5Lcopy might cause a group to have two links with the same + * creation order values. + */ +static int +test_copy_links_into_group_with_links(void) +{ + TESTING("H5Lcopy adjusting creation order values for copied links"); + + SKIPPED(); + + return 1; +} + +/* + * A test to check the behavior of copying a link across files. + * This should fail for hard links but succeed for soft and + * external links (and user-defined links of those types). + * + * TODO: Ideally, tests should be written to verify that the + * copied links retain the properties of the original + * links. + */ +static int +test_copy_link_across_files(void) +{ + TESTING("link copying across files"); + + /* TODO */ + + SKIPPED(); + + return 0; +} + +/* + * A test to check that a link can't be copied + * when H5Lcopy is passed invalid parameters. + */ +static int +test_copy_link_invalid_params(void) +{ + herr_t err_ret = -1; + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t src_grp_id = H5I_INVALID_HID, dst_grp_id = H5I_INVALID_HID; + char ext_link_filename[H5_API_TEST_FILENAME_MAX_LENGTH]; + hid_t ext_file_id = H5I_INVALID_HID; + + TESTING_MULTIPART("H5Lcopy with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_HARD_LINKS)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, or basic and more link aren't supported with this " + "connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, COPY_LINK_INVALID_PARAMS_TEST_SUBGROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", COPY_LINK_INVALID_PARAMS_TEST_SUBGROUP_NAME); + goto error; + } + + if ((src_grp_id = H5Gcreate2(group_id, COPY_LINK_INVALID_PARAMS_TEST_SRC_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", COPY_LINK_INVALID_PARAMS_TEST_SRC_GROUP_NAME); + goto error; + } + + if ((dst_grp_id = H5Gcreate2(group_id, COPY_LINK_INVALID_PARAMS_TEST_DST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", COPY_LINK_INVALID_PARAMS_TEST_DST_GROUP_NAME); + goto error; + } + + if (H5Lcreate_hard(group_id, ".", src_grp_id, COPY_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", COPY_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME); + goto error; + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(src_grp_id, COPY_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + COPY_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link did not exist\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Lcopy_invalid_src_loc_id) + { + TESTING_2("H5Lcopy with an invalid source location ID"); + + H5E_BEGIN_TRY + { + err_ret = + H5Lcopy(H5I_INVALID_HID, COPY_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, dst_grp_id, + COPY_LINK_INVALID_PARAMS_TEST_HARD_LINK_COPY_NAME, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lcopy succeeded with an invalid source location ID\n"); + PART_ERROR(H5Lcopy_invalid_src_loc_id); + } + + PASSED(); + } + PART_END(H5Lcopy_invalid_src_loc_id); + + PART_BEGIN(H5Lcopy_invalid_src_name) + { + TESTING_2("H5Lcopy with an invalid source name"); + + H5E_BEGIN_TRY + { + err_ret = + H5Lcopy(src_grp_id, NULL, dst_grp_id, COPY_LINK_INVALID_PARAMS_TEST_HARD_LINK_COPY_NAME, + H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lcopy succeeded with a NULL source name\n"); + PART_ERROR(H5Lcopy_invalid_src_name); + } + + H5E_BEGIN_TRY + { + err_ret = + H5Lcopy(src_grp_id, "", dst_grp_id, COPY_LINK_INVALID_PARAMS_TEST_HARD_LINK_COPY_NAME, + H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lcopy succeeded with an invalid source name of ''\n"); + PART_ERROR(H5Lcopy_invalid_src_name); + } + + PASSED(); + } + PART_END(H5Lcopy_invalid_src_name); + + PART_BEGIN(H5Lcopy_invalid_dst_loc_id) + { + TESTING_2("H5Lcopy with an invalid destination location ID"); + + H5E_BEGIN_TRY + { + err_ret = + H5Lcopy(src_grp_id, COPY_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, H5I_INVALID_HID, + COPY_LINK_INVALID_PARAMS_TEST_HARD_LINK_COPY_NAME, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lcopy succeeded with an invalid destination location ID\n"); + PART_ERROR(H5Lcopy_invalid_dst_loc_id); + } + + PASSED(); + } + PART_END(H5Lcopy_invalid_dst_loc_id); + + PART_BEGIN(H5Lcopy_invalid_dst_name) + { + TESTING_2("H5Lcopy with an invalid destination name"); + + H5E_BEGIN_TRY + { + err_ret = H5Lcopy(src_grp_id, COPY_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, dst_grp_id, NULL, + H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lcopy succeeded with a NULL destination name\n"); + PART_ERROR(H5Lcopy_invalid_dst_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Lcopy(src_grp_id, COPY_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, dst_grp_id, "", + H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lcopy succeeded with an invalid destination name of ''\n"); + PART_ERROR(H5Lcopy_invalid_dst_name); + } + + PASSED(); + } + PART_END(H5Lcopy_invalid_dst_name); + + PART_BEGIN(H5Lcopy_invalid_lcpl) + { + TESTING_2("H5Lcopy with an invalid LCPL"); + + H5E_BEGIN_TRY + { + err_ret = + H5Lcopy(src_grp_id, COPY_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, dst_grp_id, + COPY_LINK_INVALID_PARAMS_TEST_HARD_LINK_COPY_NAME, H5I_INVALID_HID, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lcopy succeeded with an invalid LCPL\n"); + PART_ERROR(H5Lcopy_invalid_lcpl); + } + + PASSED(); + } + PART_END(H5Lcopy_invalid_lcpl); + + PART_BEGIN(H5Lcopy_invalid_lapl) + { + TESTING_2("H5Lcopy with an invalid LAPL"); +#ifndef NO_INVALID_PROPERTY_LIST_TESTS + H5E_BEGIN_TRY + { + err_ret = + H5Lcopy(src_grp_id, COPY_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, dst_grp_id, + COPY_LINK_INVALID_PARAMS_TEST_HARD_LINK_COPY_NAME, H5P_DEFAULT, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lcopy succeeded with an invalid LAPL\n"); + PART_ERROR(H5Lcopy_invalid_lapl); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lcopy_invalid_lapl); +#endif + } + PART_END(H5Lcopy_invalid_lapl); + + PART_BEGIN(H5Lcopy_invalid_same_location) + { + TESTING_2("H5Lcopy with an invalid same location"); + + H5E_BEGIN_TRY + { + err_ret = + H5Lcopy(H5L_SAME_LOC, COPY_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, H5L_SAME_LOC, + COPY_LINK_INVALID_PARAMS_TEST_HARD_LINK_COPY_NAME, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lcopy succeeded with an invalid same location\n"); + PART_ERROR(H5Lcopy_invalid_same_location); + } + + PASSED(); + } + PART_END(H5Lcopy_invalid_same_location); + + PART_BEGIN(H5Lcopy_invalid_across_files) + { + TESTING_2("H5Lcopy invalid across files"); + + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME); + + if ((ext_file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + PART_ERROR(H5Lcopy_invalid_across_files); + } + + H5E_BEGIN_TRY + { + err_ret = + H5Lcopy(src_grp_id, COPY_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, ext_file_id, + COPY_LINK_INVALID_PARAMS_TEST_HARD_LINK_COPY_NAME, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lcopy succeeded in copying a hard link across files!\n"); + PART_ERROR(H5Lcopy_invalid_across_files); + } + + if (H5Fclose(ext_file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close file '%s'\n", ext_link_filename); + PART_ERROR(H5Lcopy_invalid_across_files); + } + + PASSED(); + } + PART_END(H5Lcopy_invalid_across_files); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Gclose(dst_grp_id) < 0) + TEST_ERROR; + if (H5Gclose(src_grp_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(dst_grp_id); + H5Gclose(src_grp_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(ext_file_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a link can be moved with H5Lmove. + */ +static int +test_move_link(void) +{ + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t src_grp_id = H5I_INVALID_HID, dst_grp_id = H5I_INVALID_HID; + char ext_link_filename[H5_API_TEST_FILENAME_MAX_LENGTH]; + hid_t ext_file_id = H5I_INVALID_HID; + + TESTING_MULTIPART("link moving"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_HARD_LINKS) || !(vol_cap_flags_g & H5VL_CAP_FLAG_EXTERNAL_LINKS) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_SOFT_LINKS)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, or link, hard, soft, or external link aren't " + "supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", EXTERNAL_LINK_TEST_FILE_NAME); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, MOVE_LINK_TEST_SUBGROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", MOVE_LINK_TEST_SUBGROUP_NAME); + goto error; + } + + if ((src_grp_id = H5Gcreate2(group_id, MOVE_LINK_TEST_SRC_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", MOVE_LINK_TEST_SRC_GROUP_NAME); + goto error; + } + + if ((dst_grp_id = H5Gcreate2(group_id, MOVE_LINK_TEST_DST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", MOVE_LINK_TEST_DST_GROUP_NAME); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Lmove_hard_no_check) + { + TESTING_2("H5Lmove on hard link (moved link's properties not checked)"); + + /* Try to move a hard link */ + if (H5Lcreate_hard(group_id, ".", src_grp_id, MOVE_LINK_TEST_HARD_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", MOVE_LINK_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lmove_hard_no_check); + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", MOVE_LINK_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lmove_hard_no_check); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link did not exist\n"); + PART_ERROR(H5Lmove_hard_no_check); + } + + /* Verify the link doesn't currently exist in the target group */ + if ((link_exists = H5Lexists(dst_grp_id, MOVE_LINK_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", MOVE_LINK_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lmove_hard_no_check); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link existed in target group before move!\n"); + PART_ERROR(H5Lmove_hard_no_check); + } + + /* Move the link */ + if (H5Lmove(src_grp_id, MOVE_LINK_TEST_HARD_LINK_NAME, dst_grp_id, MOVE_LINK_TEST_HARD_LINK_NAME, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to move link '%s'\n", MOVE_LINK_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lmove_hard_no_check); + } + + /* Verify the link has been moved */ + if ((link_exists = H5Lexists(dst_grp_id, MOVE_LINK_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", MOVE_LINK_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lmove_hard_no_check); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link did not exist\n"); + PART_ERROR(H5Lmove_hard_no_check); + } + + /* Verify the old link is gone */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if old hard link '%s' exists\n", + MOVE_LINK_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lmove_hard_no_check); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" old hard link exists\n"); + PART_ERROR(H5Lmove_hard_no_check); + } + + PASSED(); + } + PART_END(H5Lmove_hard_no_check); + + PART_BEGIN(H5Lmove_hard_check) + { + H5L_info2_t orig_info, new_info; + int cmp_value; + + TESTING_2("H5Lmove on hard link (moved link's properties checked)"); + + /* Try to move a hard link */ + if (H5Lcreate_hard(group_id, ".", src_grp_id, MOVE_LINK_TEST_HARD_LINK_NAME2, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", MOVE_LINK_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lmove_hard_check); + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", MOVE_LINK_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lmove_hard_check); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link did not exist\n"); + PART_ERROR(H5Lmove_hard_check); + } + + /* Retrieve the link's info */ + if (H5Lget_info2(src_grp_id, MOVE_LINK_TEST_HARD_LINK_NAME2, &orig_info, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve info for link '%s'\n", MOVE_LINK_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lmove_hard_check); + } + + /* Verify the link doesn't currently exist in the target group */ + if ((link_exists = H5Lexists(dst_grp_id, MOVE_LINK_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", MOVE_LINK_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lmove_hard_check); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link existed in target group before move!\n"); + PART_ERROR(H5Lmove_hard_check); + } + + /* Move the link */ + if (H5Lmove(src_grp_id, MOVE_LINK_TEST_HARD_LINK_NAME2, dst_grp_id, + MOVE_LINK_TEST_HARD_LINK_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to move link '%s'\n", MOVE_LINK_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lmove_hard_check); + } + + /* Verify the link has been moved */ + if ((link_exists = H5Lexists(dst_grp_id, MOVE_LINK_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", MOVE_LINK_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lmove_hard_check); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link did not exist\n"); + PART_ERROR(H5Lmove_hard_check); + } + + /* Verify the old link is gone */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if old hard link '%s' exists\n", + MOVE_LINK_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lmove_hard_check); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" old hard link exists\n"); + PART_ERROR(H5Lmove_hard_check); + } + + /* Retrieve the moved link's info */ + if (H5Lget_info2(dst_grp_id, MOVE_LINK_TEST_HARD_LINK_NAME2, &new_info, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve info for link '%s'\n", MOVE_LINK_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lmove_hard_check); + } + + if (new_info.type != orig_info.type) { + H5_FAILED(); + HDprintf(" moved link's link type doesn't match original link's type\n"); + PART_ERROR(H5Lmove_hard_check); + } + + if (H5Otoken_cmp(dst_grp_id, &new_info.u.token, &orig_info.u.token, &cmp_value) < 0) { + H5_FAILED(); + HDprintf(" failed to compare link target tokens\n"); + PART_ERROR(H5Lmove_hard_check); + } + + if (cmp_value != 0) { + H5_FAILED(); + HDprintf(" moved hard link's object token doesn't match original link's object token\n"); + PART_ERROR(H5Lmove_hard_check); + } + + if (new_info.corder_valid != orig_info.corder_valid) { + H5_FAILED(); + HDprintf(" moved link's 'corder_valid' field doesn't match original link's 'corder_valid' " + "field\n"); + PART_ERROR(H5Lmove_hard_check); + } + + if (new_info.corder_valid && orig_info.corder_valid && (new_info.corder != orig_info.corder)) { + H5_FAILED(); + HDprintf(" moved link's creation order value %" PRId64 + " doesn't match original link's creation order value %" PRId64 "\n", + new_info.corder, orig_info.corder); + PART_ERROR(H5Lmove_hard_check); + } + + if (new_info.cset != orig_info.cset) { + H5_FAILED(); + HDprintf(" moved link's character set doesn't match original link's character set\n"); + PART_ERROR(H5Lmove_hard_check); + } + + PASSED(); + } + PART_END(H5Lmove_hard_check); + + PART_BEGIN(H5Lmove_hard_same_loc) + { + TESTING_2("H5Lmove on hard link using H5L_SAME_LOC"); + + /* Try to move a hard link */ + if (H5Lcreate_hard(group_id, ".", src_grp_id, MOVE_LINK_TEST_HARD_LINK_NAME3, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", MOVE_LINK_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lmove_hard_same_loc); + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_HARD_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", MOVE_LINK_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lmove_hard_same_loc); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link did not exist\n"); + PART_ERROR(H5Lmove_hard_same_loc); + } + + /* Verify the link doesn't currently exist in the target group */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_HARD_LINK_SAME_LOC_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + MOVE_LINK_TEST_HARD_LINK_SAME_LOC_NAME); + PART_ERROR(H5Lmove_hard_same_loc); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link existed in target group before move!\n"); + PART_ERROR(H5Lmove_hard_same_loc); + } + + /* Rename the link using H5L_SAME_LOC as the first parameter to H5Lmove */ + if (H5Lmove(H5L_SAME_LOC, MOVE_LINK_TEST_HARD_LINK_NAME3, src_grp_id, + MOVE_LINK_TEST_HARD_LINK_SAME_LOC_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to move link '%s' using H5L_SAME_LOC as first parameter to H5Lmove\n", + MOVE_LINK_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lmove_hard_same_loc); + } + + /* Ensure the link has been renamed */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_HARD_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", MOVE_LINK_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lmove_hard_same_loc); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" original hard link existed in target group after move!\n"); + PART_ERROR(H5Lmove_hard_same_loc); + } + + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_HARD_LINK_SAME_LOC_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + MOVE_LINK_TEST_HARD_LINK_SAME_LOC_NAME); + PART_ERROR(H5Lmove_hard_same_loc); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link did not exist after move!\n"); + PART_ERROR(H5Lmove_hard_same_loc); + } + + /* Rename the link back using H5L_SAME_LOC as the third parameter to H5Lmove */ + if (H5Lmove(src_grp_id, MOVE_LINK_TEST_HARD_LINK_SAME_LOC_NAME, H5L_SAME_LOC, + MOVE_LINK_TEST_HARD_LINK_NAME3, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to move link '%s' using H5L_SAME_LOC as third parameter to H5Lmove\n", + MOVE_LINK_TEST_HARD_LINK_SAME_LOC_NAME); + PART_ERROR(H5Lmove_hard_same_loc); + } + + /* Verify the link has been renamed back */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_HARD_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", MOVE_LINK_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lmove_hard_same_loc); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" original hard link did not exist after moving the link back!\n"); + PART_ERROR(H5Lmove_hard_same_loc); + } + + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_HARD_LINK_SAME_LOC_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if old hard link '%s' exists\n", + MOVE_LINK_TEST_HARD_LINK_SAME_LOC_NAME); + PART_ERROR(H5Lmove_hard_same_loc); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" renamed hard link exists after moving the link back!\n"); + PART_ERROR(H5Lmove_hard_same_loc); + } + + PASSED(); + } + PART_END(H5Lmove_hard_same_loc); + + PART_BEGIN(H5Lmove_hard_rename) + { + TESTING_2("H5Lmove to rename hard link without moving it"); + + /* Try to rename a hard link */ + if (H5Lcreate_hard(group_id, ".", src_grp_id, MOVE_LINK_TEST_HARD_LINK_NAME4, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", MOVE_LINK_TEST_HARD_LINK_NAME4); + PART_ERROR(H5Lmove_hard_rename); + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_HARD_LINK_NAME4, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", MOVE_LINK_TEST_HARD_LINK_NAME4); + PART_ERROR(H5Lmove_hard_rename); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link did not exist\n"); + PART_ERROR(H5Lmove_hard_rename); + } + + /* Verify the renamed link doesn't currently exist in the source group */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_HARD_LINK_NEW_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if renamed hard link '%s' exists\n", + MOVE_LINK_TEST_HARD_LINK_NEW_NAME); + PART_ERROR(H5Lmove_hard_rename); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" renamed hard link existed in source group before move!\n"); + PART_ERROR(H5Lmove_hard_rename); + } + + /* Rename the link */ + if (H5Lmove(src_grp_id, MOVE_LINK_TEST_HARD_LINK_NAME4, src_grp_id, + MOVE_LINK_TEST_HARD_LINK_NEW_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to rename link '%s'\n", MOVE_LINK_TEST_HARD_LINK_NAME4); + PART_ERROR(H5Lmove_hard_rename); + } + + /* Verify the link has been renamed */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_HARD_LINK_NEW_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if renamed hard link '%s' exists\n", + MOVE_LINK_TEST_HARD_LINK_NEW_NAME); + PART_ERROR(H5Lmove_hard_rename); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" renamed hard link did not exist\n"); + PART_ERROR(H5Lmove_hard_rename); + } + + /* Verify the old link is gone */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_HARD_LINK_NAME4, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if old hard link '%s' exists\n", + MOVE_LINK_TEST_HARD_LINK_NAME4); + PART_ERROR(H5Lmove_hard_rename); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" old hard link exists\n"); + PART_ERROR(H5Lmove_hard_rename); + } + + PASSED(); + } + PART_END(H5Lmove_hard_rename); + + PART_BEGIN(H5Lmove_soft_no_check) + { + TESTING_2("H5Lmove on soft link (moved link's properties not checked)"); + + /* Try to move a soft link */ + if (H5Lcreate_soft(MOVE_LINK_TEST_SOFT_LINK_TARGET_PATH, src_grp_id, + MOVE_LINK_TEST_SOFT_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", MOVE_LINK_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lmove_soft_no_check); + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", MOVE_LINK_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lmove_soft_no_check); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link did not exist\n"); + PART_ERROR(H5Lmove_soft_no_check); + } + + /* Verify the link doesn't currently exist in the target group */ + if ((link_exists = H5Lexists(dst_grp_id, MOVE_LINK_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", MOVE_LINK_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lmove_soft_no_check); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link existed in target group before move!\n"); + PART_ERROR(H5Lmove_soft_no_check); + } + + /* Move the link */ + if (H5Lmove(src_grp_id, MOVE_LINK_TEST_SOFT_LINK_NAME, dst_grp_id, MOVE_LINK_TEST_SOFT_LINK_NAME, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to move link '%s'\n", MOVE_LINK_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lmove_soft_no_check); + } + + /* Verify the link has been moved */ + if ((link_exists = H5Lexists(dst_grp_id, MOVE_LINK_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", MOVE_LINK_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lmove_soft_no_check); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link did not exist\n"); + PART_ERROR(H5Lmove_soft_no_check); + } + + /* Verify the old link is gone */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if old soft link '%s' exists\n", + MOVE_LINK_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lmove_soft_no_check); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" old soft link exists\n"); + PART_ERROR(H5Lmove_soft_no_check); + } + + PASSED(); + } + PART_END(H5Lmove_soft_no_check); + + PART_BEGIN(H5Lmove_soft_check) + { + H5L_info2_t orig_info, new_info; + char orig_link_val[MOVE_LINK_TEST_LINK_VAL_BUF_SIZE]; + char new_link_val[MOVE_LINK_TEST_LINK_VAL_BUF_SIZE]; + + TESTING_2("H5Lmove on soft link (moved link's properties checked)"); + + /* Try to move a soft link */ + if (H5Lcreate_soft(MOVE_LINK_TEST_SOFT_LINK_TARGET_PATH, src_grp_id, + MOVE_LINK_TEST_SOFT_LINK_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", MOVE_LINK_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lmove_soft_check); + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", MOVE_LINK_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lmove_soft_check); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link did not exist\n"); + PART_ERROR(H5Lmove_soft_check); + } + + /* Retrieve the link's info */ + if (H5Lget_info2(src_grp_id, MOVE_LINK_TEST_SOFT_LINK_NAME2, &orig_info, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve info for link '%s'\n", MOVE_LINK_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lmove_soft_check); + } + + /* Retrieve the link's value */ + if (H5Lget_val(src_grp_id, MOVE_LINK_TEST_SOFT_LINK_NAME2, orig_link_val, + MOVE_LINK_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve value for soft link '%s'\n", MOVE_LINK_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lmove_soft_check); + } + + /* Verify the link doesn't currently exist in the target group */ + if ((link_exists = H5Lexists(dst_grp_id, MOVE_LINK_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", MOVE_LINK_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lmove_soft_check); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link existed in target group before move!\n"); + PART_ERROR(H5Lmove_soft_check); + } + + /* Move the link */ + if (H5Lmove(src_grp_id, MOVE_LINK_TEST_SOFT_LINK_NAME2, dst_grp_id, + MOVE_LINK_TEST_SOFT_LINK_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to move link '%s'\n", MOVE_LINK_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lmove_soft_check); + } + + /* Verify the link has been moved */ + if ((link_exists = H5Lexists(dst_grp_id, MOVE_LINK_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", MOVE_LINK_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lmove_soft_check); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link did not exist\n"); + PART_ERROR(H5Lmove_soft_check); + } + + /* Verify the old link is gone */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if old soft link '%s' exists\n", + MOVE_LINK_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lmove_soft_check); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" old soft link exists\n"); + PART_ERROR(H5Lmove_soft_check); + } + + /* Retrieve the moved link's info */ + if (H5Lget_info2(dst_grp_id, MOVE_LINK_TEST_SOFT_LINK_NAME2, &new_info, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve info for link '%s'\n", MOVE_LINK_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lmove_soft_check); + } + + if (new_info.type != orig_info.type) { + H5_FAILED(); + HDprintf(" moved link's link type doesn't match original link's type\n"); + PART_ERROR(H5Lmove_soft_check); + } + + if (new_info.u.val_size != orig_info.u.val_size) { + H5_FAILED(); + HDprintf(" moved soft link's value size of %llu doesn't match original link's value size " + "of %llu\n", + (unsigned long long)new_info.u.val_size, (unsigned long long)orig_info.u.val_size); + PART_ERROR(H5Lmove_soft_check); + } + + if (new_info.corder_valid != orig_info.corder_valid) { + H5_FAILED(); + HDprintf(" moved link's 'corder_valid' field doesn't match original link's 'corder_valid' " + "field\n"); + PART_ERROR(H5Lmove_soft_check); + } + + if (new_info.corder_valid && orig_info.corder_valid && (new_info.corder != orig_info.corder)) { + H5_FAILED(); + HDprintf(" moved link's creation order value %" PRId64 + " doesn't match original link's creation order value %" PRId64 "\n", + new_info.corder, orig_info.corder); + PART_ERROR(H5Lmove_soft_check); + } + + if (new_info.cset != orig_info.cset) { + H5_FAILED(); + HDprintf(" moved link's character set doesn't match original link's character set\n"); + PART_ERROR(H5Lmove_soft_check); + } + + /* Check the soft link's value */ + if (H5Lget_val(dst_grp_id, MOVE_LINK_TEST_SOFT_LINK_NAME2, new_link_val, + MOVE_LINK_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve value for soft link '%s'\n", MOVE_LINK_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lmove_soft_check); + } + + if (HDstrncmp(orig_link_val, new_link_val, MOVE_LINK_TEST_LINK_VAL_BUF_SIZE)) { + H5_FAILED(); + HDprintf(" moved soft link's value '%s' doesn't match original link's value '%s'\n", + new_link_val, orig_link_val); + PART_ERROR(H5Lmove_soft_check); + } + + PASSED(); + } + PART_END(H5Lmove_soft_check); + + PART_BEGIN(H5Lmove_soft_same_loc) + { + TESTING_2("H5Lmove on soft link using H5L_SAME_LOC"); + + /* Try to move a soft link */ + if (H5Lcreate_soft(MOVE_LINK_TEST_SOFT_LINK_TARGET_PATH, src_grp_id, + MOVE_LINK_TEST_SOFT_LINK_NAME3, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", MOVE_LINK_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lmove_soft_same_loc); + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", MOVE_LINK_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lmove_soft_same_loc); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link did not exist\n"); + PART_ERROR(H5Lmove_soft_same_loc); + } + + /* Verify the link doesn't currently exist in the target group */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_SOFT_LINK_SAME_LOC_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + MOVE_LINK_TEST_SOFT_LINK_SAME_LOC_NAME); + PART_ERROR(H5Lmove_soft_same_loc); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" soft link existed in target group before move!\n"); + PART_ERROR(H5Lmove_soft_same_loc); + } + + /* Rename the link using H5L_SAME_LOC as the first parameter to H5Lmove */ + if (H5Lmove(H5L_SAME_LOC, MOVE_LINK_TEST_SOFT_LINK_NAME3, src_grp_id, + MOVE_LINK_TEST_SOFT_LINK_SAME_LOC_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to move link '%s' using H5L_SAME_LOC as first parameter to H5Lmove\n", + MOVE_LINK_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lmove_soft_same_loc); + } + + /* Ensure the link has been renamed */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", MOVE_LINK_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lmove_soft_same_loc); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" original soft link existed in target group after move!\n"); + PART_ERROR(H5Lmove_soft_same_loc); + } + + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_SOFT_LINK_SAME_LOC_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + MOVE_LINK_TEST_SOFT_LINK_SAME_LOC_NAME); + PART_ERROR(H5Lmove_soft_same_loc); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link did not exist after move!\n"); + PART_ERROR(H5Lmove_soft_same_loc); + } + + /* Rename the link back using H5L_SAME_LOC as the third parameter to H5Lmove */ + if (H5Lmove(src_grp_id, MOVE_LINK_TEST_SOFT_LINK_SAME_LOC_NAME, H5L_SAME_LOC, + MOVE_LINK_TEST_SOFT_LINK_NAME3, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to move link '%s' using H5L_SAME_LOC as third parameter to H5Lmove\n", + MOVE_LINK_TEST_SOFT_LINK_SAME_LOC_NAME); + PART_ERROR(H5Lmove_soft_same_loc); + } + + /* Verify the link has been renamed back */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", MOVE_LINK_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lmove_soft_same_loc); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" original hard link did not exist after moving the link back!\n"); + PART_ERROR(H5Lmove_soft_same_loc); + } + + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_SOFT_LINK_SAME_LOC_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if old soft link '%s' exists\n", + MOVE_LINK_TEST_SOFT_LINK_SAME_LOC_NAME); + PART_ERROR(H5Lmove_soft_same_loc); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" renamed soft link exists after moving the link back!\n"); + PART_ERROR(H5Lmove_soft_same_loc); + } + + PASSED(); + } + PART_END(H5Lmove_soft_same_loc); + + PART_BEGIN(H5Lmove_soft_rename) + { + TESTING_2("H5Lmove to rename soft link without moving it"); + + /* Try to rename a soft link */ + if (H5Lcreate_soft(MOVE_LINK_TEST_SOFT_LINK_TARGET_PATH, src_grp_id, + MOVE_LINK_TEST_SOFT_LINK_NAME4, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", MOVE_LINK_TEST_SOFT_LINK_NAME4); + PART_ERROR(H5Lmove_soft_rename); + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_SOFT_LINK_NAME4, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", MOVE_LINK_TEST_SOFT_LINK_NAME4); + PART_ERROR(H5Lmove_soft_rename); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link did not exist\n"); + PART_ERROR(H5Lmove_soft_rename); + } + + /* Verify the renamed link doesn't currently exist in the source group */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_SOFT_LINK_NEW_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if renamed soft link '%s' exists\n", + MOVE_LINK_TEST_SOFT_LINK_NEW_NAME); + PART_ERROR(H5Lmove_soft_rename); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" renamed soft link existed in source group before move!\n"); + PART_ERROR(H5Lmove_soft_rename); + } + + /* Rename the link */ + if (H5Lmove(src_grp_id, MOVE_LINK_TEST_SOFT_LINK_NAME4, src_grp_id, + MOVE_LINK_TEST_SOFT_LINK_NEW_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to rename link '%s'\n", MOVE_LINK_TEST_SOFT_LINK_NAME4); + PART_ERROR(H5Lmove_soft_rename); + } + + /* Verify the link has been renamed */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_SOFT_LINK_NEW_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if renamed soft link '%s' exists\n", + MOVE_LINK_TEST_SOFT_LINK_NEW_NAME); + PART_ERROR(H5Lmove_soft_rename); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" renamed soft link did not exist\n"); + PART_ERROR(H5Lmove_soft_rename); + } + + /* Verify the old link is gone */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_SOFT_LINK_NAME4, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if old soft link '%s' exists\n", + MOVE_LINK_TEST_SOFT_LINK_NAME4); + PART_ERROR(H5Lmove_soft_rename); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" old soft link exists\n"); + PART_ERROR(H5Lmove_soft_rename); + } + + PASSED(); + } + PART_END(H5Lmove_soft_rename); + + PART_BEGIN(H5Lmove_external_no_check) + { + TESTING_2("H5Lmove on external link (moved link's properties not checked)"); +#ifndef NO_EXTERNAL_LINKS + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME); + + if ((ext_file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + PART_ERROR(H5Lmove_external_no_check); + } + + if (H5Fclose(ext_file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close file '%s'\n", ext_link_filename); + PART_ERROR(H5Lmove_external_no_check); + } + + /* Try to move an external link */ + if (H5Lcreate_external(ext_link_filename, "/", src_grp_id, MOVE_LINK_TEST_EXTERN_LINK_NAME, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", MOVE_LINK_TEST_EXTERN_LINK_NAME); + PART_ERROR(H5Lmove_external_no_check); + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_EXTERN_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + MOVE_LINK_TEST_EXTERN_LINK_NAME); + PART_ERROR(H5Lmove_external_no_check); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link did not exist\n"); + PART_ERROR(H5Lmove_external_no_check); + } + + /* Verify the link doesn't currently exist in the target group */ + if ((link_exists = H5Lexists(dst_grp_id, MOVE_LINK_TEST_EXTERN_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + MOVE_LINK_TEST_EXTERN_LINK_NAME); + PART_ERROR(H5Lmove_external_no_check); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link existed in target group before move!\n"); + PART_ERROR(H5Lmove_external_no_check); + } + + /* Move the link */ + if (H5Lmove(src_grp_id, MOVE_LINK_TEST_EXTERN_LINK_NAME, dst_grp_id, + MOVE_LINK_TEST_EXTERN_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to move link '%s'\n", MOVE_LINK_TEST_EXTERN_LINK_NAME); + PART_ERROR(H5Lmove_external_no_check); + } + + /* Verify the link has been moved */ + if ((link_exists = H5Lexists(dst_grp_id, MOVE_LINK_TEST_EXTERN_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + MOVE_LINK_TEST_EXTERN_LINK_NAME); + PART_ERROR(H5Lmove_external_no_check); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link did not exist\n"); + PART_ERROR(H5Lmove_external_no_check); + } + + /* Verify the old link is gone */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_EXTERN_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if old external link '%s' exists\n", + MOVE_LINK_TEST_EXTERN_LINK_NAME); + PART_ERROR(H5Lmove_external_no_check); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" old external link exists\n"); + PART_ERROR(H5Lmove_external_no_check); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lmove_external_no_check); +#endif + } + PART_END(H5Lmove_external_no_check); + + H5E_BEGIN_TRY + { + H5Fclose(ext_file_id); + ext_file_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lmove_external_check) + { +#ifndef NO_EXTERNAL_LINKS + H5L_info2_t orig_info, new_info; + const char *orig_filename, *new_filename; + const char *orig_objname, *new_objname; + unsigned unpack_flags = 0; + char orig_link_val[MOVE_LINK_TEST_LINK_VAL_BUF_SIZE]; + char new_link_val[MOVE_LINK_TEST_LINK_VAL_BUF_SIZE]; +#endif + + TESTING_2("H5Lmove on external link (moved link's properties checked)"); +#ifndef NO_EXTERNAL_LINKS + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME); + + if ((ext_file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + PART_ERROR(H5Lmove_external_check); + } + + if (H5Fclose(ext_file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close file '%s'\n", ext_link_filename); + PART_ERROR(H5Lmove_external_check); + } + + /* Try to move an external link */ + if (H5Lcreate_external(ext_link_filename, "/", src_grp_id, MOVE_LINK_TEST_EXTERN_LINK_NAME2, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", MOVE_LINK_TEST_EXTERN_LINK_NAME2); + PART_ERROR(H5Lmove_external_check); + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_EXTERN_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + MOVE_LINK_TEST_EXTERN_LINK_NAME2); + PART_ERROR(H5Lmove_external_check); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link did not exist\n"); + PART_ERROR(H5Lmove_external_check); + } + + /* Retrieve the link's info */ + if (H5Lget_info2(src_grp_id, MOVE_LINK_TEST_EXTERN_LINK_NAME2, &orig_info, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve info for link '%s'\n", MOVE_LINK_TEST_EXTERN_LINK_NAME2); + PART_ERROR(H5Lmove_external_check); + } + + /* Retrieve the link's value */ + if (H5Lget_val(src_grp_id, MOVE_LINK_TEST_EXTERN_LINK_NAME2, orig_link_val, + MOVE_LINK_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve value for external link '%s'\n", + MOVE_LINK_TEST_EXTERN_LINK_NAME2); + PART_ERROR(H5Lmove_external_check); + } + + if (H5Lunpack_elink_val(orig_link_val, orig_info.u.val_size, &unpack_flags, &orig_filename, + &orig_objname) < 0) { + H5_FAILED(); + HDprintf(" couldn't unpack original external link's value buffer\n"); + PART_ERROR(H5Lmove_external_check); + } + + /* Verify the link doesn't currently exist in the target group */ + if ((link_exists = H5Lexists(dst_grp_id, MOVE_LINK_TEST_EXTERN_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + MOVE_LINK_TEST_EXTERN_LINK_NAME2); + PART_ERROR(H5Lmove_external_check); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link existed in target group before move!\n"); + PART_ERROR(H5Lmove_external_check); + } + + /* Move the link */ + if (H5Lmove(src_grp_id, MOVE_LINK_TEST_EXTERN_LINK_NAME2, dst_grp_id, + MOVE_LINK_TEST_EXTERN_LINK_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to move link '%s'\n", MOVE_LINK_TEST_EXTERN_LINK_NAME2); + PART_ERROR(H5Lmove_external_check); + } + + /* Verify the link has been moved */ + if ((link_exists = H5Lexists(dst_grp_id, MOVE_LINK_TEST_EXTERN_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + MOVE_LINK_TEST_EXTERN_LINK_NAME2); + PART_ERROR(H5Lmove_external_check); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link did not exist\n"); + PART_ERROR(H5Lmove_external_check); + } + + /* Verify the old link is gone */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_EXTERN_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if old external link '%s' exists\n", + MOVE_LINK_TEST_EXTERN_LINK_NAME2); + PART_ERROR(H5Lmove_external_check); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" old external link exists\n"); + PART_ERROR(H5Lmove_external_check); + } + + /* Retrieve the moved link's info */ + if (H5Lget_info2(dst_grp_id, MOVE_LINK_TEST_EXTERN_LINK_NAME2, &new_info, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve info for link '%s'\n", MOVE_LINK_TEST_EXTERN_LINK_NAME2); + PART_ERROR(H5Lmove_external_check); + } + + if (new_info.type != orig_info.type) { + H5_FAILED(); + HDprintf(" moved link's link type doesn't match original link's type\n"); + PART_ERROR(H5Lmove_external_check); + } + + if (new_info.u.val_size != orig_info.u.val_size) { + H5_FAILED(); + HDprintf(" moved external link's value size of %llu doesn't match original link's value " + "size of %llu\n", + (unsigned long long)new_info.u.val_size, (unsigned long long)orig_info.u.val_size); + PART_ERROR(H5Lmove_external_check); + } + + if (new_info.corder_valid != orig_info.corder_valid) { + H5_FAILED(); + HDprintf(" moved link's 'corder_valid' field doesn't match original link's 'corder_valid' " + "field\n"); + PART_ERROR(H5Lmove_external_check); + } + + if (new_info.corder_valid && orig_info.corder_valid && (new_info.corder != orig_info.corder)) { + H5_FAILED(); + HDprintf(" moved link's creation order value %lld doesn't match original link's creation " + "order value %lld\n", + new_info.corder, orig_info.corder); + PART_ERROR(H5Lmove_external_check); + } + + if (new_info.cset != orig_info.cset) { + H5_FAILED(); + HDprintf(" moved link's character set doesn't match original link's character set\n"); + PART_ERROR(H5Lmove_external_check); + } + + /* Check the external link's value */ + if (H5Lget_val(dst_grp_id, MOVE_LINK_TEST_EXTERN_LINK_NAME2, new_link_val, + MOVE_LINK_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't retrieve value for external link '%s'\n", + MOVE_LINK_TEST_EXTERN_LINK_NAME2); + PART_ERROR(H5Lmove_external_check); + } + + if (H5Lunpack_elink_val(new_link_val, new_info.u.val_size, &unpack_flags, &new_filename, + &new_objname) < 0) { + H5_FAILED(); + HDprintf(" couldn't unpack moved external link's value buffer\n"); + PART_ERROR(H5Lmove_external_check); + } + + if (HDstrncmp(new_filename, orig_filename, strlen(orig_filename)) < 0) { + H5_FAILED(); + HDprintf(" moved external link's filename '%s' doesn't match original external link's " + "filename '%s'\n", + new_filename, orig_filename); + PART_ERROR(H5Lmove_external_check); + } + + if (HDstrncmp(new_objname, orig_objname, strlen(orig_objname)) < 0) { + H5_FAILED(); + HDprintf(" moved external link's object name '%s' doesn't match original external link's " + "object name '%s'\n", + new_objname, orig_objname); + PART_ERROR(H5Lmove_external_check); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lmove_external_check); +#endif + } + PART_END(H5Lmove_external_check); + + H5E_BEGIN_TRY + { + H5Fclose(ext_file_id); + ext_file_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lmove_external_same_loc) + { + TESTING_2("H5Lmove on external link using H5L_SAME_LOC"); +#ifndef NO_EXTERNAL_LINKS + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME); + + if ((ext_file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + PART_ERROR(H5Lmove_external_same_loc); + } + + if (H5Fclose(ext_file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close file '%s'\n", ext_link_filename); + PART_ERROR(H5Lmove_external_same_loc); + } + + /* Try to move an external link */ + if (H5Lcreate_external(ext_link_filename, "/", src_grp_id, MOVE_LINK_TEST_EXTERN_LINK_NAME3, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", MOVE_LINK_TEST_EXTERN_LINK_NAME3); + PART_ERROR(H5Lmove_external_same_loc); + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_EXTERN_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + MOVE_LINK_TEST_EXTERN_LINK_NAME3); + PART_ERROR(H5Lmove_external_same_loc); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link did not exist\n"); + PART_ERROR(H5Lmove_external_same_loc); + } + + /* Verify the link doesn't currently exist in the target group */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_EXTERN_LINK_SAME_LOC_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + MOVE_LINK_TEST_EXTERN_LINK_SAME_LOC_NAME); + PART_ERROR(H5Lmove_external_same_loc); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" external link existed in target group before move!\n"); + PART_ERROR(H5Lmove_external_same_loc); + } + + /* Rename the link using H5L_SAME_LOC as the first parameter to H5Lmove */ + if (H5Lmove(H5L_SAME_LOC, MOVE_LINK_TEST_EXTERN_LINK_NAME3, src_grp_id, + MOVE_LINK_TEST_EXTERN_LINK_SAME_LOC_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to move link '%s'\n", MOVE_LINK_TEST_EXTERN_LINK_NAME3); + PART_ERROR(H5Lmove_external_same_loc); + } + + /* Ensure the link has been renamed */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_EXTERN_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + MOVE_LINK_TEST_EXTERN_LINK_NAME3); + PART_ERROR(H5Lmove_external_same_loc); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" original external link existed in target group after move!\n"); + PART_ERROR(H5Lmove_external_same_loc); + } + + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_EXTERN_LINK_SAME_LOC_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + MOVE_LINK_TEST_EXTERN_LINK_SAME_LOC_NAME); + PART_ERROR(H5Lmove_external_same_loc); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link did not exist after move!\n"); + PART_ERROR(H5Lmove_external_same_loc); + } + + /* Rename the link back using H5L_SAME_LOC as the third parameter to H5Lmove */ + if (H5Lmove(src_grp_id, MOVE_LINK_TEST_EXTERN_LINK_SAME_LOC_NAME, H5L_SAME_LOC, + MOVE_LINK_TEST_EXTERN_LINK_NAME3, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to move link '%s'\n", MOVE_LINK_TEST_EXTERN_LINK_SAME_LOC_NAME); + PART_ERROR(H5Lmove_external_same_loc); + } + + /* Verify the link has been renamed back */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_EXTERN_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + MOVE_LINK_TEST_EXTERN_LINK_NAME3); + PART_ERROR(H5Lmove_external_same_loc); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" original external link did not exist after moving the link back!\n"); + PART_ERROR(H5Lmove_external_same_loc); + } + + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_EXTERN_LINK_SAME_LOC_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if old external link '%s' exists\n", + MOVE_LINK_TEST_EXTERN_LINK_SAME_LOC_NAME); + PART_ERROR(H5Lmove_external_same_loc); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" renamed external link exists after moving the link back!\n"); + PART_ERROR(H5Lmove_external_same_loc); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lmove_external_same_loc); +#endif + } + PART_END(H5Lmove_external_same_loc); + + H5E_BEGIN_TRY + { + H5Fclose(ext_file_id); + ext_file_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lmove_external_rename) + { + TESTING_2("H5Lmove to rename external link without moving it"); +#ifndef NO_EXTERNAL_LINKS + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME); + + if ((ext_file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + PART_ERROR(H5Lmove_external_rename); + } + + if (H5Fclose(ext_file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close file '%s'\n", ext_link_filename); + PART_ERROR(H5Lmove_external_rename); + } + + /* Try to move an external link */ + if (H5Lcreate_external(ext_link_filename, "/", src_grp_id, MOVE_LINK_TEST_EXTERN_LINK_NAME4, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", MOVE_LINK_TEST_EXTERN_LINK_NAME4); + PART_ERROR(H5Lmove_external_rename); + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_EXTERN_LINK_NAME4, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + MOVE_LINK_TEST_EXTERN_LINK_NAME4); + PART_ERROR(H5Lmove_external_rename); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link did not exist\n"); + PART_ERROR(H5Lmove_external_rename); + } + + /* Verify the renamed link doesn't currently exist in the source group */ + if ((link_exists = H5Lexists(dst_grp_id, MOVE_LINK_TEST_EXTERN_LINK_NEW_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if renamed external link '%s' exists\n", + MOVE_LINK_TEST_EXTERN_LINK_NEW_NAME); + PART_ERROR(H5Lmove_external_rename); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" renamed external link existed in source group before move!\n"); + PART_ERROR(H5Lmove_external_rename); + } + + /* Rename the link */ + if (H5Lmove(src_grp_id, MOVE_LINK_TEST_EXTERN_LINK_NAME4, src_grp_id, + MOVE_LINK_TEST_EXTERN_LINK_NEW_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to rename link '%s'\n", MOVE_LINK_TEST_EXTERN_LINK_NAME4); + PART_ERROR(H5Lmove_external_rename); + } + + /* Verify the link has been renamed */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_EXTERN_LINK_NEW_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if renamed external link '%s' exists\n", + MOVE_LINK_TEST_EXTERN_LINK_NEW_NAME); + PART_ERROR(H5Lmove_external_rename); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" renamed external link did not exist\n"); + PART_ERROR(H5Lmove_external_rename); + } + + /* Verify the old link is gone */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_TEST_EXTERN_LINK_NAME4, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if old external link '%s' exists\n", + MOVE_LINK_TEST_EXTERN_LINK_NAME4); + PART_ERROR(H5Lmove_external_rename); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" old external link exists\n"); + PART_ERROR(H5Lmove_external_rename); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lmove_external_rename); +#endif + } + PART_END(H5Lmove_external_rename); + + H5E_BEGIN_TRY + { + H5Fclose(ext_file_id); + ext_file_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lmove_ud_no_check) + { + TESTING_2("H5Lmove on user-defined link (moved link's properties not checked)"); + + /* TODO */ + + SKIPPED(); + PART_EMPTY(H5Lmove_ud_no_check); + } + PART_END(H5Lmove_ud_no_check); + + PART_BEGIN(H5Lmove_ud_check) + { + TESTING_2("H5Lmove on user-defined link (moved link's properties checked)"); + + /* TODO */ + + SKIPPED(); + PART_EMPTY(H5Lmove_ud_check); + } + PART_END(H5Lmove_ud_check); + + PART_BEGIN(H5Lmove_ud_same_loc) + { + TESTING_2("H5Lmove on user-defined link using H5L_SAME_LOC"); + + /* TODO */ + + SKIPPED(); + PART_EMPTY(H5Lmove_ud_same_loc); + } + PART_END(H5Lmove_ud_same_loc); + + PART_BEGIN(H5Lmove_ud_rename) + { + TESTING_2("H5Lmove to rename user-defined link without moving it"); + + /* TODO */ + + SKIPPED(); + PART_EMPTY(H5Lmove_ud_rename); + } + PART_END(H5Lmove_ud_rename); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Gclose(dst_grp_id) < 0) + TEST_ERROR; + if (H5Gclose(src_grp_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(dst_grp_id); + H5Gclose(src_grp_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + H5Fclose(ext_file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that using H5Lmove to move links into a + * group which already contains links will cause the new links + * to have creation order values ranging from the target group's + * maximum link creation order value and upwards. This is to + * check that it is not possible to run into the situation where + * H5Lmove might cause a group to have two links with the same + * creation order values. + */ +static int +test_move_links_into_group_with_links(void) +{ + H5L_info2_t link_info; + size_t i; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t src_grp_id = H5I_INVALID_HID, dst_grp_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + char link_name[MOVE_LINK_INTO_GRP_WITH_LINKS_TEST_BUF_SIZE]; + + TESTING("H5Lmove adjusting creation order values for moved links"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_MORE) || !(vol_cap_flags_g & H5VL_CAP_FLAG_HARD_LINKS) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, or basic or hard link, or creation order aren't " + "supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, MOVE_LINK_INTO_GRP_WITH_LINKS_TEST_SUBGROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", MOVE_LINK_INTO_GRP_WITH_LINKS_TEST_SUBGROUP_NAME); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create GCPL for link creation order tracking\n"); + goto error; + } + + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED) < 0) { + H5_FAILED(); + HDprintf(" couldn't set link creation order tracking\n"); + goto error; + } + + if ((src_grp_id = H5Gcreate2(group_id, MOVE_LINK_INTO_GRP_WITH_LINKS_TEST_SRC_GRP_NAME, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", MOVE_LINK_INTO_GRP_WITH_LINKS_TEST_SRC_GRP_NAME); + goto error; + } + + if ((dst_grp_id = H5Gcreate2(group_id, MOVE_LINK_INTO_GRP_WITH_LINKS_TEST_DST_GRP_NAME, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", MOVE_LINK_INTO_GRP_WITH_LINKS_TEST_DST_GRP_NAME); + goto error; + } + + /* Create several links in the source group */ + for (i = 0; i < MOVE_LINK_INTO_GRP_WITH_LINKS_TEST_NUM_LINKS; i++) { + snprintf(link_name, MOVE_LINK_INTO_GRP_WITH_LINKS_TEST_BUF_SIZE, "link_to_move%d", (int)i); + + if (H5Lcreate_hard(src_grp_id, ".", src_grp_id, link_name, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create link '%s' in source group\n", link_name); + goto error; + } + + /* Check the current creation order value for each link */ + memset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info2(src_grp_id, link_name, &link_info, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve info for link '%s'\n", link_name); + goto error; + } + + if (!link_info.corder_valid) { + H5_FAILED(); + HDprintf(" creation order value for newly-created link '%s' was marked as not valid!\n", + link_name); + goto error; + } + + if (link_info.corder != (int64_t)i) { + H5_FAILED(); + HDprintf(" creation order value %lld for link '%s' did not match expected value %lld\n", + (long long)link_info.corder, link_name, (long long)i); + goto error; + } + } + + /* Create several links in the destination group */ + for (i = 0; i < MOVE_LINK_INTO_GRP_WITH_LINKS_TEST_NUM_LINKS; i++) { + snprintf(link_name, MOVE_LINK_INTO_GRP_WITH_LINKS_TEST_BUF_SIZE, "link%d", (int)i); + + if (H5Lcreate_hard(dst_grp_id, ".", dst_grp_id, link_name, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create link '%s' in destination group\n", link_name); + goto error; + } + } + + /* Move all the links from the source group into the destination group */ + for (i = 0; i < MOVE_LINK_INTO_GRP_WITH_LINKS_TEST_NUM_LINKS; i++) { + snprintf(link_name, MOVE_LINK_INTO_GRP_WITH_LINKS_TEST_BUF_SIZE, "link_to_move%d", (int)i); + + if (H5Lmove(src_grp_id, link_name, dst_grp_id, link_name, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to move link '%s' from source group to destination group\n", link_name); + goto error; + } + + /* Check that the creation order value for each moved link has been adjusted */ + memset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info2(dst_grp_id, link_name, &link_info, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve info for link '%s'\n", link_name); + goto error; + } + + if (!link_info.corder_valid) { + H5_FAILED(); + HDprintf(" creation order value for moved link '%s' was marked as not valid!\n", link_name); + goto error; + } + + if (link_info.corder != (int64_t)(i + MOVE_LINK_INTO_GRP_WITH_LINKS_TEST_NUM_LINKS)) { + H5_FAILED(); + HDprintf(" creation order value for moved link '%s' was not adjusted after move! It should " + "have been %lld but was %lld\n", + link_name, (long long)(i + MOVE_LINK_INTO_GRP_WITH_LINKS_TEST_NUM_LINKS), + (long long)link_info.corder); + goto error; + } + } + + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(dst_grp_id) < 0) + TEST_ERROR; + if (H5Gclose(src_grp_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(gcpl_id); + H5Gclose(dst_grp_id); + H5Gclose(src_grp_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check the behavior of moving a link across files. + * This should fail for hard links but succeed for soft and + * external links (and user-defined links of those types). + * + * TODO: Ideally, tests should be written to verify that the + * moved links retain their original properties. + */ +static int +test_move_link_across_files(void) +{ + TESTING("link moving across files"); + + /* TODO */ + + SKIPPED(); + + return 0; +} + +/* + * A test to check that a group's always-increasing + * maximum link creation order value gets reset once + * all the links have been moved out of the group. + */ +static int +test_move_link_reset_grp_max_crt_order(void) +{ +#ifndef NO_MAX_LINK_CRT_ORDER_RESET + H5G_info_t grp_info; + size_t i; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t src_grp_id = H5I_INVALID_HID, dst_grp_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + char link_name[MOVE_LINK_RESET_MAX_CRT_ORDER_TEST_BUF_SIZE]; +#endif + + TESTING("H5Lmove of all links out of group resets group's maximum link creation order value"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_MORE) || !(vol_cap_flags_g & H5VL_CAP_FLAG_HARD_LINKS) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_MORE) || !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, more or hard link, or creation order aren't " + "supported with this connector\n"); + return 0; + } + +#ifndef NO_MAX_LINK_CRT_ORDER_RESET + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create GCPL for link creation order tracking\n"); + goto error; + } + + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED) < 0) { + H5_FAILED(); + HDprintf(" couldn't set link creation order tracking\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, MOVE_LINK_RESET_MAX_CRT_ORDER_TEST_SUBGROUP_NAME, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + MOVE_LINK_RESET_MAX_CRT_ORDER_TEST_SUBGROUP_NAME); + goto error; + } + + if ((src_grp_id = H5Gcreate2(group_id, MOVE_LINK_RESET_MAX_CRT_ORDER_TEST_SRC_GRP_NAME, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", MOVE_LINK_RESET_MAX_CRT_ORDER_TEST_SRC_GRP_NAME); + goto error; + } + + if ((dst_grp_id = H5Gcreate2(group_id, MOVE_LINK_RESET_MAX_CRT_ORDER_TEST_DST_GRP_NAME, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", MOVE_LINK_RESET_MAX_CRT_ORDER_TEST_DST_GRP_NAME); + goto error; + } + + /* Create several links inside the source group */ + for (i = 0; i < MOVE_LINK_RESET_MAX_CRT_ORDER_TEST_NUM_LINKS; i++) { + snprintf(link_name, MOVE_LINK_RESET_MAX_CRT_ORDER_TEST_BUF_SIZE, "link%d", (int)i); + + if (H5Lcreate_hard(src_grp_id, ".", src_grp_id, link_name, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s' in source group\n", link_name); + goto error; + } + } + + /* + * Move links out of the source group and into the destination group, checking the + * source group's maximum creation order value each time. + */ + for (i = 0; i < MOVE_LINK_RESET_MAX_CRT_ORDER_TEST_NUM_LINKS; i++) { + memset(&grp_info, 0, sizeof(grp_info)); + + if (H5Gget_info(src_grp_id, &grp_info) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve source group's info\n"); + goto error; + } + + if (grp_info.max_corder != MOVE_LINK_RESET_MAX_CRT_ORDER_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" source group's maximum creation order value got adjusted to %lld during link " + "moving; value should have remained at %lld\n", + (long long)grp_info.max_corder, MOVE_LINK_RESET_MAX_CRT_ORDER_TEST_NUM_LINKS); + goto error; + } + + snprintf(link_name, MOVE_LINK_RESET_MAX_CRT_ORDER_TEST_BUF_SIZE, "link%d", (int)i); + + if (H5Lmove(src_grp_id, link_name, dst_grp_id, link_name, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to move link '%s' to destination group\n", link_name); + goto error; + } + } + + /* + * Ensure the source group's maximum creation order value has now + * reset to 0 after all the links have been moved out of it. + */ + memset(&grp_info, 0, sizeof(grp_info)); + + if (H5Gget_info(src_grp_id, &grp_info) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve source group's info\n"); + goto error; + } + + if (grp_info.max_corder != 0) { + H5_FAILED(); + HDprintf(" source group's maximum creation order value didn't reset to 0 after moving all links " + "out of it; value is still %lld\n", + (long long)grp_info.max_corder); + goto error; + } + + /* For good measure, check that destination group's max. creation order value is as expected */ + memset(&grp_info, 0, sizeof(grp_info)); + + if (H5Gget_info(dst_grp_id, &grp_info) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve destination group's info\n"); + goto error; + } + + if (grp_info.max_corder != MOVE_LINK_RESET_MAX_CRT_ORDER_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" destination group's maximum creation order value of %lld didn't match expected value " + "of %lld after moving all links into it\n", + (long long)grp_info.max_corder, MOVE_LINK_RESET_MAX_CRT_ORDER_TEST_NUM_LINKS); + goto error; + } + + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(dst_grp_id) < 0) + TEST_ERROR; + if (H5Gclose(src_grp_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(gcpl_id); + H5Gclose(dst_grp_id); + H5Gclose(src_grp_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +#else + SKIPPED(); + return 0; +#endif +} + +/* + * A test to check that H5Lmove fails when it is given + * invalid parameters. + */ +static int +test_move_link_invalid_params(void) +{ + htri_t link_exists; + herr_t err_ret = -1; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t src_grp_id = H5I_INVALID_HID, dst_grp_id = H5I_INVALID_HID; + char ext_link_filename[H5_API_TEST_FILENAME_MAX_LENGTH]; + hid_t ext_file_id = H5I_INVALID_HID; + + TESTING_MULTIPART("H5Lmove with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_MORE) || !(vol_cap_flags_g & H5VL_CAP_FLAG_HARD_LINKS)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, more or hard link aren't supported with this " + "connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, MOVE_LINK_INVALID_PARAMS_TEST_SUBGROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", MOVE_LINK_INVALID_PARAMS_TEST_SUBGROUP_NAME); + goto error; + } + + if ((src_grp_id = H5Gcreate2(group_id, MOVE_LINK_INVALID_PARAMS_TEST_SRC_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", MOVE_LINK_INVALID_PARAMS_TEST_SRC_GROUP_NAME); + goto error; + } + + if ((dst_grp_id = H5Gcreate2(group_id, MOVE_LINK_INVALID_PARAMS_TEST_DST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", MOVE_LINK_INVALID_PARAMS_TEST_DST_GROUP_NAME); + goto error; + } + + if (H5Lcreate_hard(group_id, ".", src_grp_id, MOVE_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", MOVE_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME); + goto error; + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(src_grp_id, MOVE_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + MOVE_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link did not exist\n"); + goto error; + } + + /* Verify the link doesn't currently exist in the target group */ + if ((link_exists = H5Lexists(dst_grp_id, MOVE_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + MOVE_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME); + goto error; + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link existed in target group before move!\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Lmove_invalid_src_loc_id) + { + TESTING_2("H5Lmove with an invalid source location ID"); + + H5E_BEGIN_TRY + { + err_ret = H5Lmove(H5I_INVALID_HID, MOVE_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, dst_grp_id, + MOVE_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lmove succeeded with an invalid source location ID!\n"); + PART_ERROR(H5Lmove_invalid_src_loc_id); + } + + PASSED(); + } + PART_END(H5Lmove_invalid_src_loc_id); + + PART_BEGIN(H5Lmove_invalid_src_name) + { + TESTING_2("H5Lmove with an invalid source name"); + + H5E_BEGIN_TRY + { + err_ret = H5Lmove(src_grp_id, NULL, dst_grp_id, MOVE_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, + H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lmove succeeded with a NULL source name!\n"); + PART_ERROR(H5Lmove_invalid_src_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Lmove(src_grp_id, "", dst_grp_id, MOVE_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, + H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lmove succeeded with an invalid source name of ''!\n"); + PART_ERROR(H5Lmove_invalid_src_name); + } + + PASSED(); + } + PART_END(H5Lmove_invalid_src_name); + + PART_BEGIN(H5Lmove_invalid_dst_loc_id) + { + TESTING_2("H5Lmove with an invalid destination location ID"); + + H5E_BEGIN_TRY + { + err_ret = H5Lmove(src_grp_id, MOVE_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, H5I_INVALID_HID, + MOVE_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lmove succeeded with an invalid destination location ID!\n"); + PART_ERROR(H5Lmove_invalid_dst_loc_id); + } + + PASSED(); + } + PART_END(H5Lmove_invalid_dst_loc_id); + + PART_BEGIN(H5Lmove_invalid_dst_name) + { + TESTING_2("H5Lmove with an invalid destination name"); + + H5E_BEGIN_TRY + { + err_ret = H5Lmove(src_grp_id, MOVE_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, dst_grp_id, NULL, + H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lmove succeeded with a NULL destination name!\n"); + PART_ERROR(H5Lmove_invalid_dst_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Lmove(src_grp_id, MOVE_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, dst_grp_id, "", + H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lmove succeeded with an invalid destination name of ''!\n"); + PART_ERROR(H5Lmove_invalid_dst_name); + } + + PASSED(); + } + PART_END(H5Lmove_invalid_dst_name); + + PART_BEGIN(H5Lmove_invalid_lcpl) + { + TESTING_2("H5Lmove with an invalid LCPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Lmove(src_grp_id, MOVE_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, dst_grp_id, + MOVE_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, H5I_INVALID_HID, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lmove succeeded with an invalid LCPL!\n"); + PART_ERROR(H5Lmove_invalid_lcpl); + } + + PASSED(); + } + PART_END(H5Lmove_invalid_lcpl); + + PART_BEGIN(H5Lmove_invalid_lapl) + { + TESTING_2("H5Lmove with an invalid LAPL"); +#ifndef NO_INVALID_PROPERTY_LIST_TESTS + H5E_BEGIN_TRY + { + err_ret = H5Lmove(src_grp_id, MOVE_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, dst_grp_id, + MOVE_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, H5P_DEFAULT, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lmove succeeded with an invalid LAPL!\n"); + PART_ERROR(H5Lmove_invalid_lapl); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lmove_invalid_lapl); +#endif + } + PART_END(H5Lmove_invalid_lapl); + + PART_BEGIN(H5Lmove_existence) + { + TESTING_2("valid link existence in original group after previous invalid H5Lmove calls"); + + /* Verify the link hasn't been moved */ + if ((link_exists = + H5Lexists(src_grp_id, MOVE_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + MOVE_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lmove_existence); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link didn't exist in source group after invalid move!\n"); + PART_ERROR(H5Lmove_existence); + } + + if ((link_exists = + H5Lexists(dst_grp_id, MOVE_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + MOVE_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lmove_existence); + } + + if (link_exists) { + H5_FAILED(); + HDprintf(" hard link existed in target group after invalid move!\n"); + PART_ERROR(H5Lmove_existence); + } + + PASSED(); + } + PART_END(H5Lmove_existence); + + PART_BEGIN(H5Lmove_same_location) + { + TESTING_2("H5Lmove with an invalid same location"); + + /* Move a group within the file. Both of source and destination use + * H5L_SAME_LOC. Should fail. */ + H5E_BEGIN_TRY + { + err_ret = H5Lmove(H5L_SAME_LOC, MOVE_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, H5L_SAME_LOC, + MOVE_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lmove succeeded with an invalid same location!\n"); + PART_ERROR(H5Lmove_same_location); + } + + PASSED(); + } + PART_END(H5Lmove_same_location); + + PART_BEGIN(H5Lmove_across_files) + { + TESTING_2("H5Lmove into another file"); + + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME); + + if ((ext_file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + PART_ERROR(H5Lmove_across_files); + } + + /* Move a group across files. */ + H5E_BEGIN_TRY + { + err_ret = H5Lmove(src_grp_id, MOVE_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, ext_file_id, + MOVE_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lmove succeeded in moving a hard link across files!\n"); + PART_ERROR(H5Lmove_across_files); + } + + /* Ensure that original link still exists */ + if ((link_exists = + H5Lexists(src_grp_id, MOVE_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if original link '%s' exists after invalid link move\n", + MOVE_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lmove_across_files); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" original link '%s' didn't exist after failed move!\n", + MOVE_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lmove_across_files); + } + + if (H5Fclose(ext_file_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close a file!\n"); + PART_ERROR(H5Lmove_across_files); + } + + PASSED(); + } + PART_END(H5Lmove_across_files); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Gclose(dst_grp_id) < 0) + TEST_ERROR; + if (H5Gclose(src_grp_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(dst_grp_id); + H5Gclose(src_grp_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(ext_file_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a soft or external link's value can + * be retrieved by using H5Lget_val and H5Lget_val_by_idx. + */ +static int +test_get_link_val(void) +{ + H5L_info2_t link_info; +#ifndef NO_EXTERNAL_LINKS + const char *ext_link_filepath; + const char *ext_link_val; + unsigned ext_link_flags; +#endif + htri_t link_exists; + size_t link_val_size; + char link_val_buf[GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE]; + hid_t file_id = H5I_INVALID_HID, ext_file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t subgroup_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; +#ifndef NO_EXTERNAL_LINKS + char ext_link_filename[H5_API_TEST_FILENAME_MAX_LENGTH]; +#endif + + TESTING_MULTIPART("link value retrieval"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_EXTERNAL_LINKS) || !(vol_cap_flags_g & H5VL_CAP_FLAG_SOFT_LINKS)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, basic, more, soft, external link, or creation " + "order aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create GCPL for link creation order tracking\n"); + goto error; + } + + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED) < 0) { + H5_FAILED(); + HDprintf(" couldn't set link creation order tracking\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, GET_LINK_VAL_TEST_SUBGROUP_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", GET_LINK_VAL_TEST_SUBGROUP_NAME); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Lget_val_soft) + { + const char *link_target = "/" LINK_TEST_GROUP_NAME "/" GET_LINK_VAL_TEST_SUBGROUP_NAME; + + TESTING_2("H5Lget_val on soft link"); + + HDmemset(&link_info, 0, sizeof(link_info)); + + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_VAL_TEST_SUBGROUP1_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", GET_LINK_VAL_TEST_SUBGROUP1_NAME); + PART_ERROR(H5Lget_val_soft); + } + + if (H5Lcreate_soft(link_target, subgroup_id, GET_LINK_VAL_TEST_SOFT_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_val_soft); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_VAL_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_val_soft); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_val_soft); + } + + if (H5Lget_info2(subgroup_id, GET_LINK_VAL_TEST_SOFT_LINK_NAME, &link_info, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve soft link's info\n"); + PART_ERROR(H5Lget_val_soft); + } + + link_val_size = strlen(link_target) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link value size %zu did not match expected size of %zu\n", link_info.u.val_size, + link_val_size); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_increasing); + } + + if (H5Lget_val(subgroup_id, GET_LINK_VAL_TEST_SOFT_LINK_NAME, link_val_buf, + GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get soft link value\n"); + PART_ERROR(H5Lget_val_soft); + } + + if (HDstrncmp(link_val_buf, link_target, link_val_size)) { + H5_FAILED(); + HDprintf(" soft link value did not match\n"); + PART_ERROR(H5Lget_val_soft); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", GET_LINK_VAL_TEST_SUBGROUP1_NAME); + PART_ERROR(H5Lget_val_soft); + } + + PASSED(); + } + PART_END(H5Lget_val_soft); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_val_external) + { +#ifndef NO_EXTERNAL_LINKS + const char *ext_obj_name = "/"; +#endif + + TESTING_2("H5Lget_val on external link"); +#ifndef NO_EXTERNAL_LINKS + HDmemset(&link_info, 0, sizeof(link_info)); + + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME); + + if ((ext_file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + PART_ERROR(H5Lget_val_external); + } + + if (H5Fclose(ext_file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close file '%s'\n", ext_link_filename); + PART_ERROR(H5Lget_val_external); + } + + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_VAL_TEST_SUBGROUP2_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", GET_LINK_VAL_TEST_SUBGROUP2_NAME); + PART_ERROR(H5Lget_val_external); + } + + if (H5Lcreate_external(ext_link_filename, ext_obj_name, subgroup_id, + GET_LINK_VAL_TEST_EXT_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", GET_LINK_VAL_TEST_EXT_LINK_NAME); + PART_ERROR(H5Lget_val_external); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_VAL_TEST_EXT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + GET_LINK_VAL_TEST_EXT_LINK_NAME); + PART_ERROR(H5Lget_val_external); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist\n", GET_LINK_VAL_TEST_EXT_LINK_NAME); + PART_ERROR(H5Lget_val_external); + } + + if (H5Lget_info2(subgroup_id, GET_LINK_VAL_TEST_EXT_LINK_NAME, &link_info, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve external link's info\n"); + PART_ERROR(H5Lget_val_external); + } + + link_val_size = 1 + strlen(ext_link_filename) + 1 + strlen(ext_obj_name) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link value size %lld did not match expected size of %lld\n", + link_info.u.val_size, link_val_size); + PART_ERROR(H5Lget_val_external); + } + + if (H5Lget_val(subgroup_id, GET_LINK_VAL_TEST_EXT_LINK_NAME, link_val_buf, + GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get external link value\n"); + PART_ERROR(H5Lget_val_external); + } + + if (H5Lunpack_elink_val(link_val_buf, link_info.u.val_size, &ext_link_flags, &ext_link_filepath, + &ext_link_val) < 0) { + H5_FAILED(); + HDprintf(" couldn't unpack external link value buffer\n"); + PART_ERROR(H5Lget_val_external); + } + + if (HDstrncmp(ext_link_filepath, ext_link_filename, strlen(ext_link_filename) + 1)) { + H5_FAILED(); + HDprintf(" external link target file '%s' did not match expected '%s'\n", + ext_link_filepath, ext_link_filename); + PART_ERROR(H5Lget_val_external); + } + + if (HDstrncmp(ext_link_val, ext_obj_name, strlen(ext_obj_name) + 1)) { + H5_FAILED(); + HDprintf(" external link value '%s' did not match expected '%s'\n", ext_link_val, + ext_obj_name); + PART_ERROR(H5Lget_val_external); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", GET_LINK_VAL_TEST_SUBGROUP2_NAME); + PART_ERROR(H5Lget_val_external); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lget_val_external); +#endif + } + PART_END(H5Lget_val_external); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + H5Fclose(ext_file_id); + ext_file_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_val_ud) + { + TESTING_2("H5Lget_val on user-defined link"); + + /* TODO */ + + SKIPPED(); + PART_EMPTY(H5Lget_val_ud); + } + PART_END(H5Lget_val_ud); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_val_by_idx_soft_crt_order_increasing) + { + const char *link_target_a = "/" LINK_TEST_GROUP_NAME "/" GET_LINK_VAL_TEST_SUBGROUP_NAME + "/" GET_LINK_VAL_TEST_SUBGROUP4_NAME "A"; + const char *link_target_b = "/" LINK_TEST_GROUP_NAME "/" GET_LINK_VAL_TEST_SUBGROUP_NAME + "/" GET_LINK_VAL_TEST_SUBGROUP4_NAME "B"; + const char *link_target_c = "/" LINK_TEST_GROUP_NAME "/" GET_LINK_VAL_TEST_SUBGROUP_NAME + "/" GET_LINK_VAL_TEST_SUBGROUP4_NAME "C"; + + TESTING_2("H5Lget_val_by_idx on soft link by creation order in increasing order"); + + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_VAL_TEST_SUBGROUP4_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", GET_LINK_VAL_TEST_SUBGROUP4_NAME); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_increasing); + } + + /* Create several soft links */ + if (H5Lcreate_soft(link_target_a, subgroup_id, GET_LINK_VAL_TEST_SOFT_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_increasing); + } + + if (H5Lcreate_soft(link_target_b, subgroup_id, GET_LINK_VAL_TEST_SOFT_LINK_NAME2, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_increasing); + } + + if (H5Lcreate_soft(link_target_c, subgroup_id, GET_LINK_VAL_TEST_SOFT_LINK_NAME3, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_increasing); + } + + /* Verify the links exist */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_VAL_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_VAL_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_VAL_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_increasing); + } + + /* Retrieve the info and value of each link in turn */ + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve soft link's info at index %d\n", 0); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_increasing); + } + + link_val_size = strlen(link_target_a) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link value size %zu for link at index %d did not match expected size of %zu\n", + link_info.u.val_size, 0, link_val_size); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_increasing); + } + + HDmemset(link_val_buf, 0, GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE); + if (H5Lget_val_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, link_val_buf, + GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get soft link value at index %d\n", 0); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_increasing); + } + + if (HDstrncmp(link_val_buf, link_target_a, strlen(link_target_a) + 1)) { + H5_FAILED(); + HDprintf(" link value '%s' for link at index %d did not match expected value '%s'\n", + link_val_buf, 0, link_target_a); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_increasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 1, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve soft link's info at index %d\n", 1); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_increasing); + } + + link_val_size = strlen(link_target_b) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link value size %zu for link at index %d did not match expected size of %zu\n", + link_info.u.val_size, 1, link_val_size); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_increasing); + } + + HDmemset(link_val_buf, 0, GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE); + if (H5Lget_val_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 1, link_val_buf, + GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get soft link value at index %d\n", 1); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_increasing); + } + + if (HDstrncmp(link_val_buf, link_target_b, strlen(link_target_b) + 1)) { + H5_FAILED(); + HDprintf(" link value '%s' for link at index %d did not match expected value '%s'\n", + link_val_buf, 1, link_target_b); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_increasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 2, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve soft link's info at index %d\n", 2); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_increasing); + } + + link_val_size = strlen(link_target_c) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link value size %zu for link at index %d did not match expected size of %zu\n", + link_info.u.val_size, 2, link_val_size); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_increasing); + } + + HDmemset(link_val_buf, 0, GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE); + if (H5Lget_val_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 2, link_val_buf, + GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get soft link value at index %d\n", 2); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_increasing); + } + + if (HDstrncmp(link_val_buf, link_target_c, strlen(link_target_c) + 1)) { + H5_FAILED(); + HDprintf(" link value '%s' for link at index %d did not match expected value '%s'\n", + link_val_buf, 2, link_target_c); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_increasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", GET_LINK_VAL_TEST_SUBGROUP4_NAME); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_increasing); + } + + PASSED(); + } + PART_END(H5Lget_val_by_idx_soft_crt_order_increasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_val_by_idx_soft_crt_order_decreasing) + { + const char *link_target_a = "/" LINK_TEST_GROUP_NAME "/" GET_LINK_VAL_TEST_SUBGROUP_NAME + "/" GET_LINK_VAL_TEST_SUBGROUP5_NAME "A"; + const char *link_target_b = "/" LINK_TEST_GROUP_NAME "/" GET_LINK_VAL_TEST_SUBGROUP_NAME + "/" GET_LINK_VAL_TEST_SUBGROUP5_NAME "B"; + const char *link_target_c = "/" LINK_TEST_GROUP_NAME "/" GET_LINK_VAL_TEST_SUBGROUP_NAME + "/" GET_LINK_VAL_TEST_SUBGROUP5_NAME "C"; + + TESTING_2("H5Lget_val_by_idx on soft link by creation order in decreasing order"); + + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_VAL_TEST_SUBGROUP5_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", GET_LINK_VAL_TEST_SUBGROUP5_NAME); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_decreasing); + } + + /* Create several soft links */ + if (H5Lcreate_soft(link_target_a, subgroup_id, GET_LINK_VAL_TEST_SOFT_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_decreasing); + } + + if (H5Lcreate_soft(link_target_b, subgroup_id, GET_LINK_VAL_TEST_SOFT_LINK_NAME2, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_decreasing); + } + + if (H5Lcreate_soft(link_target_c, subgroup_id, GET_LINK_VAL_TEST_SOFT_LINK_NAME3, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_decreasing); + } + + /* Verify the links exist */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_VAL_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_VAL_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_VAL_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_decreasing); + } + + /* Retrieve the info and value of each link in turn */ + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 2, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve soft link's info at index %d\n", 2); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_decreasing); + } + + link_val_size = strlen(link_target_a) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link value size %zu for link at index %d did not match expected size of %zu\n", + link_info.u.val_size, 2, link_val_size); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_decreasing); + } + + HDmemset(link_val_buf, 0, GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE); + if (H5Lget_val_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 2, link_val_buf, + GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get soft link value at index %d\n", 2); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_decreasing); + } + + if (HDstrncmp(link_val_buf, link_target_a, strlen(link_target_a) + 1)) { + H5_FAILED(); + HDprintf(" link value '%s' for link at index %d did not match expected value '%s'\n", + link_val_buf, 2, link_target_a); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_decreasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 1, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve soft link's info at index %d\n", 1); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_decreasing); + } + + link_val_size = strlen(link_target_b) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link value size %zu for link at index %d did not match expected size of %zu\n", + link_info.u.val_size, 1, link_val_size); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_decreasing); + } + + HDmemset(link_val_buf, 0, GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE); + if (H5Lget_val_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 1, link_val_buf, + GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get soft link value at index %d\n", 1); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_decreasing); + } + + if (HDstrncmp(link_val_buf, link_target_b, strlen(link_target_b) + 1)) { + H5_FAILED(); + HDprintf(" link value '%s' for link at index %d did not match expected value '%s'\n", + link_val_buf, 1, link_target_b); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_decreasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 0, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve soft link's info at index %d\n", 0); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_decreasing); + } + + link_val_size = strlen(link_target_c) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link value size %zu for link at index %d did not match expected size of %zu\n", + link_info.u.val_size, 0, link_val_size); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_decreasing); + } + + HDmemset(link_val_buf, 0, GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE); + if (H5Lget_val_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 0, link_val_buf, + GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get soft link value at index %d\n", 0); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_decreasing); + } + + if (HDstrncmp(link_val_buf, link_target_c, strlen(link_target_c) + 1)) { + H5_FAILED(); + HDprintf(" link value '%s' for link at index %d did not match expected value '%s'\n", + link_val_buf, 0, link_target_c); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_decreasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", GET_LINK_VAL_TEST_SUBGROUP5_NAME); + PART_ERROR(H5Lget_val_by_idx_soft_crt_order_decreasing); + } + + PASSED(); + } + PART_END(H5Lget_val_by_idx_soft_crt_order_decreasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_val_by_idx_soft_name_order_increasing) + { + const char *link_target_a = "/" LINK_TEST_GROUP_NAME "/" GET_LINK_VAL_TEST_SUBGROUP_NAME + "/" GET_LINK_VAL_TEST_SUBGROUP6_NAME "A"; + const char *link_target_b = "/" LINK_TEST_GROUP_NAME "/" GET_LINK_VAL_TEST_SUBGROUP_NAME + "/" GET_LINK_VAL_TEST_SUBGROUP6_NAME "B"; + const char *link_target_c = "/" LINK_TEST_GROUP_NAME "/" GET_LINK_VAL_TEST_SUBGROUP_NAME + "/" GET_LINK_VAL_TEST_SUBGROUP6_NAME "C"; + + TESTING_2("H5Lget_val_by_idx on soft link by alphabetical order in increasing order"); + + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_VAL_TEST_SUBGROUP6_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", GET_LINK_VAL_TEST_SUBGROUP6_NAME); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_increasing); + } + + /* Create several soft links */ + if (H5Lcreate_soft(link_target_a, subgroup_id, GET_LINK_VAL_TEST_SOFT_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_increasing); + } + + if (H5Lcreate_soft(link_target_b, subgroup_id, GET_LINK_VAL_TEST_SOFT_LINK_NAME2, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_increasing); + } + + if (H5Lcreate_soft(link_target_c, subgroup_id, GET_LINK_VAL_TEST_SOFT_LINK_NAME3, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_increasing); + } + + /* Verify the links exist */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_VAL_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_VAL_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_VAL_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_increasing); + } + + /* Retrieve the info and value of each link in turn */ + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve soft link's info at index %d\n", 0); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_increasing); + } + + link_val_size = strlen(link_target_a) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link value size %zu for link at index %d did not match expected size of %zu\n", + link_info.u.val_size, 0, link_val_size); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_increasing); + } + + HDmemset(link_val_buf, 0, GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE); + if (H5Lget_val_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, link_val_buf, + GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get soft link value at index %d\n", 0); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_increasing); + } + + if (HDstrncmp(link_val_buf, link_target_a, strlen(link_target_a) + 1)) { + H5_FAILED(); + HDprintf(" link value '%s' for link at index %d did not match expected value '%s'\n", + link_val_buf, 0, link_target_a); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_increasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 1, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve soft link's info at index %d\n", 1); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_increasing); + } + + link_val_size = strlen(link_target_b) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link value size %zu for link at index %d did not match expected size of %zu\n", + link_info.u.val_size, 1, link_val_size); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_increasing); + } + + HDmemset(link_val_buf, 0, GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE); + if (H5Lget_val_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 1, link_val_buf, + GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get soft link value at index %d\n", 1); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_increasing); + } + + if (HDstrncmp(link_val_buf, link_target_b, strlen(link_target_b) + 1)) { + H5_FAILED(); + HDprintf(" link value '%s' for link at index %d did not match expected value '%s'\n", + link_val_buf, 1, link_target_b); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_increasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 2, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve soft link's info at index %d\n", 2); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_increasing); + } + + link_val_size = strlen(link_target_c) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link value size %zu for link at index %d did not match expected size of %zu\n", + link_info.u.val_size, 2, link_val_size); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_increasing); + } + + HDmemset(link_val_buf, 0, GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE); + if (H5Lget_val_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 2, link_val_buf, + GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get soft link value at index %d\n", 2); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_increasing); + } + + if (HDstrncmp(link_val_buf, link_target_c, strlen(link_target_c) + 1)) { + H5_FAILED(); + HDprintf(" link value '%s' for link at index %d did not match expected value '%s'\n", + link_val_buf, 2, link_target_c); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_increasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", GET_LINK_VAL_TEST_SUBGROUP6_NAME); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_increasing); + } + + PASSED(); + } + PART_END(H5Lget_val_by_idx_soft_name_order_increasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_val_by_idx_soft_name_order_decreasing) + { +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + const char *link_target_a = "/" LINK_TEST_GROUP_NAME "/" GET_LINK_VAL_TEST_SUBGROUP_NAME + "/" GET_LINK_VAL_TEST_SUBGROUP7_NAME "A"; + const char *link_target_b = "/" LINK_TEST_GROUP_NAME "/" GET_LINK_VAL_TEST_SUBGROUP_NAME + "/" GET_LINK_VAL_TEST_SUBGROUP7_NAME "B"; + const char *link_target_c = "/" LINK_TEST_GROUP_NAME "/" GET_LINK_VAL_TEST_SUBGROUP_NAME + "/" GET_LINK_VAL_TEST_SUBGROUP7_NAME "C"; +#endif + + TESTING_2("H5Lget_val_by_idx on soft link by alphabetical order in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_VAL_TEST_SUBGROUP7_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", GET_LINK_VAL_TEST_SUBGROUP7_NAME); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_decreasing); + } + + /* Create several soft links */ + if (H5Lcreate_soft(link_target_a, subgroup_id, GET_LINK_VAL_TEST_SOFT_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_decreasing); + } + + if (H5Lcreate_soft(link_target_b, subgroup_id, GET_LINK_VAL_TEST_SOFT_LINK_NAME2, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_decreasing); + } + + if (H5Lcreate_soft(link_target_c, subgroup_id, GET_LINK_VAL_TEST_SOFT_LINK_NAME3, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_decreasing); + } + + /* Verify the links exist */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_VAL_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_VAL_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_VAL_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", GET_LINK_VAL_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_decreasing); + } + + /* Retrieve the info and value of each link in turn */ + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 2, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve soft link's info at index %lld\n", 2); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_decreasing); + } + + link_val_size = strlen(link_target_a) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf( + " link value size %lld for link at index %lld did not match expected size of %lld\n", + link_info.u.val_size, 2, link_val_size); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_decreasing); + } + + HDmemset(link_val_buf, 0, GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE); + if (H5Lget_val_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 2, link_val_buf, + GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get soft link value at index %lld\n", 2); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_decreasing); + } + + if (HDstrncmp(link_val_buf, link_target_a, strlen(link_target_a) + 1)) { + H5_FAILED(); + HDprintf(" link value '%s' for link at index %lld did not match expected value '%s'\n", + link_val_buf, 2, link_target_a); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_decreasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 1, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve soft link's info at index %lld\n", 1); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_decreasing); + } + + link_val_size = strlen(link_target_b) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf( + " link value size %lld for link at index %lld did not match expected size of %lld\n", + link_info.u.val_size, 1, link_val_size); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_decreasing); + } + + HDmemset(link_val_buf, 0, GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE); + if (H5Lget_val_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 1, link_val_buf, + GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get soft link value at index %lld\n", 1); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_decreasing); + } + + if (HDstrncmp(link_val_buf, link_target_b, strlen(link_target_b) + 1)) { + H5_FAILED(); + HDprintf(" link value '%s' for link at index %lld did not match expected value '%s'\n", + link_val_buf, 1, link_target_b); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_decreasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 0, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve soft link's info at index %lld\n", 0); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_decreasing); + } + + link_val_size = strlen(link_target_c) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf( + " link value size %lld for link at index %lld did not match expected size of %lld\n", + link_info.u.val_size, 0, link_val_size); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_decreasing); + } + + HDmemset(link_val_buf, 0, GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE); + if (H5Lget_val_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 0, link_val_buf, + GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get soft link value at index %lld\n", 0); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_decreasing); + } + + if (HDstrncmp(link_val_buf, link_target_c, strlen(link_target_c) + 1)) { + H5_FAILED(); + HDprintf(" link value '%s' for link at index %lld did not match expected value '%s'\n", + link_val_buf, 0, link_target_c); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_decreasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", GET_LINK_VAL_TEST_SUBGROUP7_NAME); + PART_ERROR(H5Lget_val_by_idx_soft_name_order_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lget_val_by_idx_soft_name_order_decreasing); +#endif + } + PART_END(H5Lget_val_by_idx_soft_name_order_decreasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_val_by_idx_external_crt_order_increasing) + { +#ifndef NO_EXTERNAL_LINKS + const char *ext_obj_name_a = "/A"; + const char *ext_obj_name_b = "/B"; + const char *ext_obj_name_c = "/C"; +#endif + + TESTING_2("H5Lget_val_by_idx on external link by creation order in increasing order"); +#ifndef NO_EXTERNAL_LINKS + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME); + + if ((ext_file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + if (H5Fclose(ext_file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close file '%s'\n", ext_link_filename); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_VAL_TEST_SUBGROUP8_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", GET_LINK_VAL_TEST_SUBGROUP8_NAME); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + /* Create several external links */ + if (H5Lcreate_external(ext_link_filename, ext_obj_name_a, subgroup_id, + GET_LINK_VAL_TEST_EXT_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", GET_LINK_VAL_TEST_EXT_LINK_NAME); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + if (H5Lcreate_external(ext_link_filename, ext_obj_name_b, subgroup_id, + GET_LINK_VAL_TEST_EXT_LINK_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", GET_LINK_VAL_TEST_EXT_LINK_NAME2); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + if (H5Lcreate_external(ext_link_filename, ext_obj_name_c, subgroup_id, + GET_LINK_VAL_TEST_EXT_LINK_NAME3, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", GET_LINK_VAL_TEST_EXT_LINK_NAME3); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + /* Verify the links exist */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_VAL_TEST_EXT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", GET_LINK_VAL_TEST_EXT_LINK_NAME); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", GET_LINK_VAL_TEST_EXT_LINK_NAME); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_VAL_TEST_EXT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", GET_LINK_VAL_TEST_EXT_LINK_NAME2); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", GET_LINK_VAL_TEST_EXT_LINK_NAME2); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_VAL_TEST_EXT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", GET_LINK_VAL_TEST_EXT_LINK_NAME3); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", GET_LINK_VAL_TEST_EXT_LINK_NAME3); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + /* Retrieve the info and value of each link in turn */ + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve external link's info at index %lld\n", 0); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + link_val_size = 1 + strlen(ext_link_filename) + 1 + strlen(ext_obj_name_a) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf( + " link value size %lld for link at index %lld did not match expected size of %lld\n", + link_info.u.val_size, 0, link_val_size); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + HDmemset(link_val_buf, 0, GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE); + if (H5Lget_val_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, link_val_buf, + GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get external link value at index %lld\n", 0); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + if (H5Lunpack_elink_val(link_val_buf, link_info.u.val_size, &ext_link_flags, &ext_link_filepath, + &ext_link_val) < 0) { + H5_FAILED(); + HDprintf(" couldn't unpack external link value buffer\n"); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + if (HDstrncmp(ext_link_filepath, ext_link_filename, strlen(ext_link_filename) + 1)) { + H5_FAILED(); + HDprintf(" external link target file '%s' did not match expected '%s'\n", + ext_link_filepath, ext_link_filename); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + if (HDstrncmp(ext_link_val, ext_obj_name_a, strlen(ext_obj_name_a) + 1)) { + H5_FAILED(); + HDprintf(" external link value '%s' did not match expected '%s'\n", ext_link_val, + ext_obj_name_a); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 1, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve external link's info at index %lld\n", 1); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + link_val_size = 1 + strlen(ext_link_filename) + 1 + strlen(ext_obj_name_b) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf( + " link value size %lld for link at index %lld did not match expected size of %lld\n", + link_info.u.val_size, 1, link_val_size); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + HDmemset(link_val_buf, 0, GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE); + if (H5Lget_val_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 1, link_val_buf, + GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get external link value at index %lld\n", 1); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + if (H5Lunpack_elink_val(link_val_buf, link_info.u.val_size, &ext_link_flags, &ext_link_filepath, + &ext_link_val) < 0) { + H5_FAILED(); + HDprintf(" couldn't unpack external link value buffer\n"); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + if (HDstrncmp(ext_link_filepath, ext_link_filename, strlen(ext_link_filename) + 1)) { + H5_FAILED(); + HDprintf(" external link target file '%s' did not match expected '%s'\n", + ext_link_filepath, ext_link_filename); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + if (HDstrncmp(ext_link_val, ext_obj_name_b, strlen(ext_obj_name_b) + 1)) { + H5_FAILED(); + HDprintf(" external link value '%s' did not match expected '%s'\n", ext_link_val, + ext_obj_name_b); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 2, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve external link's info at index %lld\n", 2); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + link_val_size = 1 + strlen(ext_link_filename) + 1 + strlen(ext_obj_name_c) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf( + " link value size %lld for link at index %lld did not match expected size of %lld\n", + link_info.u.val_size, 2, link_val_size); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + HDmemset(link_val_buf, 0, GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE); + if (H5Lget_val_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 2, link_val_buf, + GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get external link value at index %lld\n", 2); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + if (H5Lunpack_elink_val(link_val_buf, link_info.u.val_size, &ext_link_flags, &ext_link_filepath, + &ext_link_val) < 0) { + H5_FAILED(); + HDprintf(" couldn't unpack external link value buffer\n"); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + if (HDstrncmp(ext_link_filepath, ext_link_filename, strlen(ext_link_filename) + 1)) { + H5_FAILED(); + HDprintf(" external link target file '%s' did not match expected '%s'\n", + ext_link_filepath, ext_link_filename); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + if (HDstrncmp(ext_link_val, ext_obj_name_c, strlen(ext_obj_name_c) + 1)) { + H5_FAILED(); + HDprintf(" external link value '%s' did not match expected '%s'\n", ext_link_val, + ext_obj_name_c); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", GET_LINK_VAL_TEST_SUBGROUP8_NAME); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_increasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lget_val_by_idx_external_crt_order_increasing); +#endif + } + PART_END(H5Lget_val_by_idx_external_crt_order_increasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + H5Fclose(ext_file_id); + ext_file_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_val_by_idx_external_crt_order_decreasing) + { +#ifndef NO_EXTERNAL_LINKS + const char *ext_obj_name_a = "/A"; + const char *ext_obj_name_b = "/B"; + const char *ext_obj_name_c = "/C"; +#endif + + TESTING_2("H5Lget_val_by_idx on external link by creation order in decreasing order"); +#ifndef NO_EXTERNAL_LINKS + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME); + + if ((ext_file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + if (H5Fclose(ext_file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close file '%s'\n", ext_link_filename); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_VAL_TEST_SUBGROUP9_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", GET_LINK_VAL_TEST_SUBGROUP9_NAME); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + /* Create several external links */ + if (H5Lcreate_external(ext_link_filename, ext_obj_name_a, subgroup_id, + GET_LINK_VAL_TEST_EXT_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", GET_LINK_VAL_TEST_EXT_LINK_NAME); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + if (H5Lcreate_external(ext_link_filename, ext_obj_name_b, subgroup_id, + GET_LINK_VAL_TEST_EXT_LINK_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", GET_LINK_VAL_TEST_EXT_LINK_NAME2); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + if (H5Lcreate_external(ext_link_filename, ext_obj_name_c, subgroup_id, + GET_LINK_VAL_TEST_EXT_LINK_NAME3, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", GET_LINK_VAL_TEST_EXT_LINK_NAME3); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + /* Verify the links exist */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_VAL_TEST_EXT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", GET_LINK_VAL_TEST_EXT_LINK_NAME); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", GET_LINK_VAL_TEST_EXT_LINK_NAME); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_VAL_TEST_EXT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", GET_LINK_VAL_TEST_EXT_LINK_NAME2); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", GET_LINK_VAL_TEST_EXT_LINK_NAME2); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_VAL_TEST_EXT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", GET_LINK_VAL_TEST_EXT_LINK_NAME3); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", GET_LINK_VAL_TEST_EXT_LINK_NAME3); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + /* Retrieve the info and value of each link in turn */ + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 2, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve external link's info at index %lld\n", 2); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + link_val_size = 1 + strlen(ext_link_filename) + 1 + strlen(ext_obj_name_a) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf( + " link value size %lld for link at index %lld did not match expected size of %lld\n", + link_info.u.val_size, 2, link_val_size); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + HDmemset(link_val_buf, 0, GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE); + if (H5Lget_val_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 2, link_val_buf, + GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get external link value at index %lld\n", 2); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + if (H5Lunpack_elink_val(link_val_buf, link_info.u.val_size, &ext_link_flags, &ext_link_filepath, + &ext_link_val) < 0) { + H5_FAILED(); + HDprintf(" couldn't unpack external link value buffer\n"); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + if (HDstrncmp(ext_link_filepath, ext_link_filename, strlen(ext_link_filename) + 1)) { + H5_FAILED(); + HDprintf(" external link target file '%s' did not match expected '%s'\n", + ext_link_filepath, ext_link_filename); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + if (HDstrncmp(ext_link_val, ext_obj_name_a, strlen(ext_obj_name_a) + 1)) { + H5_FAILED(); + HDprintf(" external link value '%s' did not match expected '%s'\n", ext_link_val, + ext_obj_name_a); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 1, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve external link's info at index %lld\n", 1); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + link_val_size = 1 + strlen(ext_link_filename) + 1 + strlen(ext_obj_name_b) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf( + " link value size %lld for link at index %lld did not match expected size of %lld\n", + link_info.u.val_size, 1, link_val_size); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + HDmemset(link_val_buf, 0, GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE); + if (H5Lget_val_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 1, link_val_buf, + GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get external link value at index %lld\n", 1); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + if (H5Lunpack_elink_val(link_val_buf, link_info.u.val_size, &ext_link_flags, &ext_link_filepath, + &ext_link_val) < 0) { + H5_FAILED(); + HDprintf(" couldn't unpack external link value buffer\n"); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + if (HDstrncmp(ext_link_filepath, ext_link_filename, strlen(ext_link_filename) + 1)) { + H5_FAILED(); + HDprintf(" external link target file '%s' did not match expected '%s'\n", + ext_link_filepath, ext_link_filename); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + if (HDstrncmp(ext_link_val, ext_obj_name_b, strlen(ext_obj_name_b) + 1)) { + H5_FAILED(); + HDprintf(" external link value '%s' did not match expected '%s'\n", ext_link_val, + ext_obj_name_b); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 0, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve external link's info at index %lld\n", 0); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + link_val_size = 1 + strlen(ext_link_filename) + 1 + strlen(ext_obj_name_c) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf( + " link value size %lld for link at index %lld did not match expected size of %lld\n", + link_info.u.val_size, 0, link_val_size); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + HDmemset(link_val_buf, 0, GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE); + if (H5Lget_val_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 0, link_val_buf, + GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get external link value at index %lld\n", 0); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + if (H5Lunpack_elink_val(link_val_buf, link_info.u.val_size, &ext_link_flags, &ext_link_filepath, + &ext_link_val) < 0) { + H5_FAILED(); + HDprintf(" couldn't unpack external link value buffer\n"); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + if (HDstrncmp(ext_link_filepath, ext_link_filename, strlen(ext_link_filename) + 1)) { + H5_FAILED(); + HDprintf(" external link target file '%s' did not match expected '%s'\n", + ext_link_filepath, ext_link_filename); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + if (HDstrncmp(ext_link_val, ext_obj_name_c, strlen(ext_obj_name_c) + 1)) { + H5_FAILED(); + HDprintf(" external link value '%s' did not match expected '%s'\n", ext_link_val, + ext_obj_name_c); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", GET_LINK_VAL_TEST_SUBGROUP9_NAME); + PART_ERROR(H5Lget_val_by_idx_external_crt_order_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lget_val_by_idx_external_crt_order_decreasing); +#endif + } + PART_END(H5Lget_val_by_idx_external_crt_order_decreasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + H5Fclose(ext_file_id); + ext_file_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_val_by_idx_external_name_order_increasing) + { +#ifndef NO_EXTERNAL_LINKS + const char *ext_obj_name_a = "/A"; + const char *ext_obj_name_b = "/B"; + const char *ext_obj_name_c = "/C"; +#endif + + TESTING_2("H5Lget_val_by_idx on external link by alphabetical order in increasing order"); +#ifndef NO_EXTERNAL_LINKS + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME); + + if ((ext_file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + if (H5Fclose(ext_file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close file '%s'\n", ext_link_filename); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_VAL_TEST_SUBGROUP10_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", GET_LINK_VAL_TEST_SUBGROUP10_NAME); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + /* Create several external links */ + if (H5Lcreate_external(ext_link_filename, ext_obj_name_a, subgroup_id, + GET_LINK_VAL_TEST_EXT_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", GET_LINK_VAL_TEST_EXT_LINK_NAME); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + if (H5Lcreate_external(ext_link_filename, ext_obj_name_b, subgroup_id, + GET_LINK_VAL_TEST_EXT_LINK_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", GET_LINK_VAL_TEST_EXT_LINK_NAME2); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + if (H5Lcreate_external(ext_link_filename, ext_obj_name_c, subgroup_id, + GET_LINK_VAL_TEST_EXT_LINK_NAME3, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", GET_LINK_VAL_TEST_EXT_LINK_NAME3); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + /* Verify the links exist */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_VAL_TEST_EXT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", GET_LINK_VAL_TEST_EXT_LINK_NAME); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", GET_LINK_VAL_TEST_EXT_LINK_NAME); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_VAL_TEST_EXT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", GET_LINK_VAL_TEST_EXT_LINK_NAME2); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", GET_LINK_VAL_TEST_EXT_LINK_NAME2); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_VAL_TEST_EXT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", GET_LINK_VAL_TEST_EXT_LINK_NAME3); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", GET_LINK_VAL_TEST_EXT_LINK_NAME3); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + /* Retrieve the info and value of each link in turn */ + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve external link's info at index %lld\n", 0); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + link_val_size = 1 + strlen(ext_link_filename) + 1 + strlen(ext_obj_name_a) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf( + " link value size %lld for link at index %lld did not match expected size of %lld\n", + link_info.u.val_size, 0, link_val_size); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + HDmemset(link_val_buf, 0, GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE); + if (H5Lget_val_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, link_val_buf, + GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get external link value at index %lld\n", 0); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + if (H5Lunpack_elink_val(link_val_buf, link_info.u.val_size, &ext_link_flags, &ext_link_filepath, + &ext_link_val) < 0) { + H5_FAILED(); + HDprintf(" couldn't unpack external link value buffer\n"); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + if (HDstrncmp(ext_link_filepath, ext_link_filename, strlen(ext_link_filename) + 1)) { + H5_FAILED(); + HDprintf(" external link target file '%s' did not match expected '%s'\n", + ext_link_filepath, ext_link_filename); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + if (HDstrncmp(ext_link_val, ext_obj_name_a, strlen(ext_obj_name_a) + 1)) { + H5_FAILED(); + HDprintf(" external link value '%s' did not match expected '%s'\n", ext_link_val, + ext_obj_name_a); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 1, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve external link's info at index %lld\n", 1); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + link_val_size = 1 + strlen(ext_link_filename) + 1 + strlen(ext_obj_name_b) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf( + " link value size %lld for link at index %lld did not match expected size of %lld\n", + link_info.u.val_size, 1, link_val_size); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + HDmemset(link_val_buf, 0, GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE); + if (H5Lget_val_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 1, link_val_buf, + GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get external link value at index %lld\n", 1); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + if (H5Lunpack_elink_val(link_val_buf, link_info.u.val_size, &ext_link_flags, &ext_link_filepath, + &ext_link_val) < 0) { + H5_FAILED(); + HDprintf(" couldn't unpack external link value buffer\n"); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + if (HDstrncmp(ext_link_filepath, ext_link_filename, strlen(ext_link_filename) + 1)) { + H5_FAILED(); + HDprintf(" external link target file '%s' did not match expected '%s'\n", + ext_link_filepath, ext_link_filename); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + if (HDstrncmp(ext_link_val, ext_obj_name_b, strlen(ext_obj_name_b) + 1)) { + H5_FAILED(); + HDprintf(" external link value '%s' did not match expected '%s'\n", ext_link_val, + ext_obj_name_b); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 2, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve external link's info at index %lld\n", 2); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + link_val_size = 1 + strlen(ext_link_filename) + 1 + strlen(ext_obj_name_c) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf( + " link value size %lld for link at index %lld did not match expected size of %lld\n", + link_info.u.val_size, 2, link_val_size); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + HDmemset(link_val_buf, 0, GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE); + if (H5Lget_val_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 2, link_val_buf, + GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get external link value at index %lld\n", 2); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + if (H5Lunpack_elink_val(link_val_buf, link_info.u.val_size, &ext_link_flags, &ext_link_filepath, + &ext_link_val) < 0) { + H5_FAILED(); + HDprintf(" couldn't unpack external link value buffer\n"); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + if (HDstrncmp(ext_link_filepath, ext_link_filename, strlen(ext_link_filename) + 1)) { + H5_FAILED(); + HDprintf(" external link target file '%s' did not match expected '%s'\n", + ext_link_filepath, ext_link_filename); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + if (HDstrncmp(ext_link_val, ext_obj_name_c, strlen(ext_obj_name_c) + 1)) { + H5_FAILED(); + HDprintf(" external link value '%s' did not match expected '%s'\n", ext_link_val, + ext_obj_name_c); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", GET_LINK_VAL_TEST_SUBGROUP10_NAME); + PART_ERROR(H5Lget_val_by_idx_external_name_order_increasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lget_val_by_idx_external_name_order_increasing); +#endif + } + PART_END(H5Lget_val_by_idx_external_name_order_increasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + H5Fclose(ext_file_id); + ext_file_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_val_by_idx_external_name_order_decreasing) + { +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + const char *ext_obj_name_a = "/A"; + const char *ext_obj_name_b = "/B"; + const char *ext_obj_name_c = "/C"; +#endif + + TESTING_2("H5Lget_val_by_idx on external link by alphabetical order in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME); + + if ((ext_file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + if (H5Fclose(ext_file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close file '%s'\n", ext_link_filename); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_VAL_TEST_SUBGROUP11_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", GET_LINK_VAL_TEST_SUBGROUP11_NAME); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + /* Create several external links */ + if (H5Lcreate_external(ext_link_filename, ext_obj_name_a, subgroup_id, + GET_LINK_VAL_TEST_EXT_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", GET_LINK_VAL_TEST_EXT_LINK_NAME); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + if (H5Lcreate_external(ext_link_filename, ext_obj_name_b, subgroup_id, + GET_LINK_VAL_TEST_EXT_LINK_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", GET_LINK_VAL_TEST_EXT_LINK_NAME2); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + if (H5Lcreate_external(ext_link_filename, ext_obj_name_c, subgroup_id, + GET_LINK_VAL_TEST_EXT_LINK_NAME3, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", GET_LINK_VAL_TEST_EXT_LINK_NAME3); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + /* Verify the links exist */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_VAL_TEST_EXT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", GET_LINK_VAL_TEST_EXT_LINK_NAME); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", GET_LINK_VAL_TEST_EXT_LINK_NAME); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_VAL_TEST_EXT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", GET_LINK_VAL_TEST_EXT_LINK_NAME2); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", GET_LINK_VAL_TEST_EXT_LINK_NAME2); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_VAL_TEST_EXT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", GET_LINK_VAL_TEST_EXT_LINK_NAME3); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", GET_LINK_VAL_TEST_EXT_LINK_NAME3); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + /* Retrieve the info and value of each link in turn */ + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 2, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve external link's info at index %lld\n", 2); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + link_val_size = 1 + strlen(ext_link_filename) + 1 + strlen(ext_obj_name_a) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf( + " link value size %lld for link at index %lld did not match expected size of %lld\n", + link_info.u.val_size, 2, link_val_size); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + HDmemset(link_val_buf, 0, GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE); + if (H5Lget_val_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 2, link_val_buf, + GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get external link value at index %lld\n", 2); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + if (H5Lunpack_elink_val(link_val_buf, link_info.u.val_size, &ext_link_flags, &ext_link_filepath, + &ext_link_val) < 0) { + H5_FAILED(); + HDprintf(" couldn't unpack external link value buffer\n"); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + if (HDstrncmp(ext_link_filepath, ext_link_filename, strlen(ext_link_filename) + 1)) { + H5_FAILED(); + HDprintf(" external link target file '%s' did not match expected '%s'\n", + ext_link_filepath, ext_link_filename); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + if (HDstrncmp(ext_link_val, ext_obj_name_a, strlen(ext_obj_name_a) + 1)) { + H5_FAILED(); + HDprintf(" external link value '%s' did not match expected '%s'\n", ext_link_val, + ext_obj_name_a); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 1, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve external link's info at index %lld\n", 1); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + link_val_size = 1 + strlen(ext_link_filename) + 1 + strlen(ext_obj_name_b) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf( + " link value size %lld for link at index %lld did not match expected size of %lld\n", + link_info.u.val_size, 1, link_val_size); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + HDmemset(link_val_buf, 0, GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE); + if (H5Lget_val_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 1, link_val_buf, + GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get external link value at index %lld\n", 1); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + if (H5Lunpack_elink_val(link_val_buf, link_info.u.val_size, &ext_link_flags, &ext_link_filepath, + &ext_link_val) < 0) { + H5_FAILED(); + HDprintf(" couldn't unpack external link value buffer\n"); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + if (HDstrncmp(ext_link_filepath, ext_link_filename, strlen(ext_link_filename) + 1)) { + H5_FAILED(); + HDprintf(" external link target file '%s' did not match expected '%s'\n", + ext_link_filepath, ext_link_filename); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + if (HDstrncmp(ext_link_val, ext_obj_name_b, strlen(ext_obj_name_b) + 1)) { + H5_FAILED(); + HDprintf(" external link value '%s' did not match expected '%s'\n", ext_link_val, + ext_obj_name_b); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 0, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve external link's info at index %lld\n", 0); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + link_val_size = 1 + strlen(ext_link_filename) + 1 + strlen(ext_obj_name_c) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf( + " link value size %lld for link at index %lld did not match expected size of %lld\n", + link_info.u.val_size, 0, link_val_size); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + HDmemset(link_val_buf, 0, GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE); + if (H5Lget_val_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 0, link_val_buf, + GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get external link value at index %lld\n", 0); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + if (H5Lunpack_elink_val(link_val_buf, link_info.u.val_size, &ext_link_flags, &ext_link_filepath, + &ext_link_val) < 0) { + H5_FAILED(); + HDprintf(" couldn't unpack external link value buffer\n"); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + if (HDstrncmp(ext_link_filepath, ext_link_filename, strlen(ext_link_filename) + 1)) { + H5_FAILED(); + HDprintf(" external link target file '%s' did not match expected '%s'\n", + ext_link_filepath, ext_link_filename); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + if (HDstrncmp(ext_link_val, ext_obj_name_c, strlen(ext_obj_name_c) + 1)) { + H5_FAILED(); + HDprintf(" external link value '%s' did not match expected '%s'\n", ext_link_val, + ext_obj_name_c); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", GET_LINK_VAL_TEST_SUBGROUP11_NAME); + PART_ERROR(H5Lget_val_by_idx_external_name_order_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lget_val_by_idx_external_name_order_decreasing); +#endif + } + PART_END(H5Lget_val_by_idx_external_name_order_decreasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + H5Fclose(ext_file_id); + ext_file_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_val_by_idx_ud_crt_order_increasing) + { + TESTING_2("H5Lget_val_by_idx on user-defined link by creation order in increasing order"); + + SKIPPED(); + PART_EMPTY(H5Lget_val_by_idx_ud_crt_order_increasing); + } + PART_END(H5Lget_val_by_idx_ud_crt_order_increasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_val_by_idx_ud_crt_order_decreasing) + { + TESTING_2("H5Lget_val_by_idx on user-defined link by creation order in decreasing order"); + + SKIPPED(); + PART_EMPTY(H5Lget_val_by_idx_ud_crt_order_decreasing); + } + PART_END(H5Lget_val_by_idx_ud_crt_order_decreasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_val_by_idx_ud_name_order_increasing) + { + TESTING_2("H5Lget_val_by_idx on user-defined link by alphabetical order in increasing order"); + + SKIPPED(); + PART_EMPTY(H5Lget_val_by_idx_ud_name_order_increasing); + } + PART_END(H5Lget_val_by_idx_ud_name_order_increasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_val_by_idx_ud_name_order_decreasing) + { + TESTING_2("H5Lget_val_by_idx on user-defined link by alphabetical order in decreasing order"); + + SKIPPED(); + PART_EMPTY(H5Lget_val_by_idx_ud_name_order_decreasing); + } + PART_END(H5Lget_val_by_idx_ud_name_order_decreasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(gcpl_id); + H5Gclose(subgroup_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(ext_file_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a soft or external link's value can't be + * retrieved when H5Lget_val(_by_idx) is passed invalid parameters. + */ +static int +test_get_link_val_invalid_params(void) +{ + H5L_info2_t link_info; + htri_t link_exists; + herr_t err_ret = -1; + size_t link_val_buf_size = 0; + char *link_val_buf = NULL; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + + TESTING_MULTIPART("link value retrieval with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER) || !(vol_cap_flags_g & H5VL_CAP_FLAG_SOFT_LINKS)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, basic, more, soft, external link, or creation " + "order aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create a GCPL\n"); + goto error; + } + + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0) { + H5_FAILED(); + HDprintf(" couldn't enable link creation order tracking and indexing on GCPL\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, GET_LINK_VAL_INVALID_PARAMS_TEST_GROUP_NAME, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + GET_LINK_VAL_INVALID_PARAMS_TEST_GROUP_NAME); + goto error; + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" GET_LINK_VAL_INVALID_PARAMS_TEST_GROUP_NAME, group_id, + GET_LINK_VAL_INVALID_PARAMS_TEST_SOFT_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", GET_LINK_VAL_INVALID_PARAMS_TEST_SOFT_LINK_NAME); + goto error; + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(group_id, GET_LINK_VAL_INVALID_PARAMS_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", + GET_LINK_VAL_INVALID_PARAMS_TEST_SOFT_LINK_NAME); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link did not exist\n"); + goto error; + } + + link_val_buf_size = 100; + if (NULL == (link_val_buf = (char *)HDmalloc(link_val_buf_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for storing link value\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Lget_val_invalid_loc_id) + { + TESTING_2("H5Lget_val with an invalid location ID"); + + HDmemset(&link_info, 0, sizeof(link_info)); + + H5E_BEGIN_TRY + { + err_ret = H5Lget_val(H5I_INVALID_HID, GET_LINK_VAL_INVALID_PARAMS_TEST_SOFT_LINK_NAME, + link_val_buf, link_val_buf_size, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lget_val succeeded with an invalid location ID\n"); + PART_ERROR(H5Lget_val_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Lget_val_invalid_loc_id); + + PART_BEGIN(H5Lget_val_invalid_link_name) + { + TESTING_2("H5Lget_val with an invalid link name"); + + H5E_BEGIN_TRY + { + err_ret = H5Lget_val(group_id, NULL, link_val_buf, link_val_buf_size, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lget_val succeeded with a NULL link name\n"); + PART_ERROR(H5Lget_val_invalid_link_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Lget_val(group_id, "", link_val_buf, link_val_buf_size, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lget_val succeeded with an invalid link name of ''\n"); + PART_ERROR(H5Lget_val_invalid_link_name); + } + + PASSED(); + } + PART_END(H5Lget_val_invalid_link_name); + + PART_BEGIN(H5Lget_val_invalid_lapl) + { + TESTING_2("H5Lget_val with an invalid LAPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Lget_val(group_id, GET_LINK_VAL_INVALID_PARAMS_TEST_SOFT_LINK_NAME, link_val_buf, + link_val_buf_size, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lget_val succeeded with an invalid LAPL\n"); + PART_ERROR(H5Lget_val_invalid_lapl); + } + + PASSED(); + } + PART_END(H5Lget_val_invalid_lapl); + + PART_BEGIN(H5Lget_val_by_idx_invalid_loc_id) + { + TESTING_2("H5Lget_val_by_idx with an invalid location ID"); + + HDmemset(&link_info, 0, sizeof(link_info)); + + H5E_BEGIN_TRY + { + err_ret = H5Lget_val_by_idx(H5I_INVALID_HID, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, + link_val_buf, link_val_buf_size, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lget_val_by_idx succeeded with an invalid location ID!\n"); + PART_ERROR(H5Lget_val_by_idx_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Lget_val_by_idx_invalid_loc_id); + + PART_BEGIN(H5Lget_val_by_idx_invalid_grp_name) + { + TESTING_2("H5Lget_val_by_idx with an invalid group name"); + + H5E_BEGIN_TRY + { + err_ret = H5Lget_val_by_idx(group_id, NULL, H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, link_val_buf, + link_val_buf_size, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lget_val_by_idx succeeded with a NULL group name!\n"); + PART_ERROR(H5Lget_val_by_idx_invalid_grp_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Lget_val_by_idx(group_id, "", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, link_val_buf, + link_val_buf_size, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lget_val_by_idx succeeded with an invalid group name of ''!\n"); + PART_ERROR(H5Lget_val_by_idx_invalid_grp_name); + } + + PASSED(); + } + PART_END(H5Lget_val_by_idx_invalid_grp_name); + + PART_BEGIN(H5Lget_val_by_idx_invalid_index_type) + { + TESTING_2("H5Lget_val_by_idx with an invalid index type"); + + H5E_BEGIN_TRY + { + err_ret = H5Lget_val_by_idx(group_id, ".", H5_INDEX_UNKNOWN, H5_ITER_INC, 0, link_val_buf, + link_val_buf_size, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lget_val_by_idx succeeded with invalid index type H5_INDEX_UNKNOWN!\n"); + PART_ERROR(H5Lget_val_by_idx_invalid_index_type); + } + + H5E_BEGIN_TRY + { + err_ret = H5Lget_val_by_idx(group_id, ".", H5_INDEX_N, H5_ITER_INC, 0, link_val_buf, + link_val_buf_size, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lget_val_by_idx succeeded with invalid index type H5_INDEX_N!\n"); + PART_ERROR(H5Lget_val_by_idx_invalid_index_type); + } + + PASSED(); + } + PART_END(H5Lget_val_by_idx_invalid_index_type); + + PART_BEGIN(H5Lget_val_by_idx_invalid_iter_order) + { + TESTING_2("H5Lget_val_by_idx with an invalid iteration ordering"); + + H5E_BEGIN_TRY + { + err_ret = H5Lget_val_by_idx(group_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_UNKNOWN, 0, + link_val_buf, link_val_buf_size, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf( + " H5Lget_val_by_idx succeeded with invalid iteration ordering H5_ITER_UNKNOWN!\n"); + PART_ERROR(H5Lget_val_by_idx_invalid_iter_order); + } + + H5E_BEGIN_TRY + { + err_ret = H5Lget_val_by_idx(group_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_N, 0, link_val_buf, + link_val_buf_size, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lget_val_by_idx succeeded with invalid iteration ordering H5_ITER_N!\n"); + PART_ERROR(H5Lget_val_by_idx_invalid_iter_order); + } + + PASSED(); + } + PART_END(H5Lget_val_by_idx_invalid_iter_order); + + PART_BEGIN(H5Lget_val_by_idx_invalid_lapl) + { + TESTING_2("H5Lget_val_by_idx with an invalid LAPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Lget_val_by_idx(group_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, link_val_buf, + link_val_buf_size, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lget_val_by_idx succeeded with an invalid LAPL!\n"); + PART_ERROR(H5Lget_val_by_idx_invalid_lapl); + } + + PASSED(); + } + PART_END(H5Lget_val_by_idx_invalid_lapl); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (link_val_buf) { + HDfree(link_val_buf); + link_val_buf = NULL; + } + + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (link_val_buf) + HDfree(link_val_buf); + H5Pclose(gcpl_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check the functionality of H5Lget_info2 and + * H5Lget_info_by_idx2. + */ +static int +test_get_link_info(void) +{ + H5L_info2_t link_info; + htri_t link_exists; + size_t link_val_size; + hid_t file_id = H5I_INVALID_HID, ext_file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t subgroup_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; +#ifndef NO_EXTERNAL_LINKS + char *ext_objname; + char ext_link_filename[H5_API_TEST_FILENAME_MAX_LENGTH]; +#endif + + TESTING_MULTIPART("link info retrieval"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_HARD_LINKS) || !(vol_cap_flags_g & H5VL_CAP_FLAG_EXTERNAL_LINKS) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_SOFT_LINKS) || !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, basic, more, soft, hard, external link, or " + "creation order aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create GCPL for link creation order tracking\n"); + goto error; + } + + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED) < 0) { + H5_FAILED(); + HDprintf(" couldn't set link creation order tracking\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, GET_LINK_INFO_TEST_GROUP_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", GET_LINK_INFO_TEST_GROUP_NAME); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Lget_info_hard) + { + TESTING_2("H5Lget_info2 on hard link"); + + HDmemset(&link_info, 0, sizeof(link_info)); + + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_INFO_TEST_SUBGROUP1_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", GET_LINK_INFO_TEST_SUBGROUP1_NAME); + PART_ERROR(H5Lget_info_hard); + } + + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, GET_LINK_INFO_TEST_HARD_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", GET_LINK_INFO_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lget_info_hard); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + GET_LINK_INFO_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lget_info_hard); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link did not exist\n"); + PART_ERROR(H5Lget_info_hard); + } + + if (H5Lget_info2(subgroup_id, GET_LINK_INFO_TEST_HARD_LINK_NAME, &link_info, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get hard link info\n"); + PART_ERROR(H5Lget_info_hard); + } + + if (link_info.type != H5L_TYPE_HARD) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_hard); + } + + if (link_info.corder_valid && (link_info.corder != 0)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)0); + PART_ERROR(H5Lget_info_hard); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", GET_LINK_INFO_TEST_SUBGROUP1_NAME); + PART_ERROR(H5Lget_info_hard); + } + + PASSED(); + } + PART_END(H5Lget_info_hard); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_info_soft) + { + TESTING_2("H5Lget_info2 on soft link"); + + HDmemset(&link_info, 0, sizeof(link_info)); + + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_INFO_TEST_SUBGROUP2_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", GET_LINK_INFO_TEST_SUBGROUP2_NAME); + PART_ERROR(H5Lget_info_soft); + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" GET_LINK_INFO_TEST_GROUP_NAME + "/" GET_LINK_INFO_TEST_SUBGROUP2_NAME, + subgroup_id, GET_LINK_INFO_TEST_SOFT_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", GET_LINK_INFO_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_info_soft); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + GET_LINK_INFO_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_info_soft); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link did not exist\n"); + PART_ERROR(H5Lget_info_soft); + } + + if (H5Lget_info2(subgroup_id, GET_LINK_INFO_TEST_SOFT_LINK_NAME, &link_info, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get soft link info\n"); + PART_ERROR(H5Lget_info_soft); + } + + if (link_info.type != H5L_TYPE_SOFT) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_soft); + } + + link_val_size = strlen("/" LINK_TEST_GROUP_NAME "/" GET_LINK_INFO_TEST_GROUP_NAME + "/" GET_LINK_INFO_TEST_SUBGROUP2_NAME) + + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link's value size '%zu' did not match expected value '%zu'\n", + link_info.u.val_size, link_val_size); + PART_ERROR(H5Lget_info_soft); + } + + if (link_info.corder_valid && (link_info.corder != 0)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)0); + PART_ERROR(H5Lget_info_soft); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", GET_LINK_INFO_TEST_SUBGROUP2_NAME); + PART_ERROR(H5Lget_info_soft); + } + + PASSED(); + } + PART_END(H5Lget_info_soft); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_info_external) + { + TESTING_2("H5Lget_info2 on external link"); +#ifndef NO_EXTERNAL_LINKS + HDmemset(&link_info, 0, sizeof(link_info)); + + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME); + + if ((ext_file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + PART_ERROR(H5Lget_info_external); + } + + if (H5Fclose(ext_file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close file '%s'\n", ext_link_filename); + PART_ERROR(H5Lget_info_external); + } + + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_INFO_TEST_SUBGROUP3_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", GET_LINK_INFO_TEST_SUBGROUP3_NAME); + PART_ERROR(H5Lget_info_external); + } + + ext_objname = "/"; + if (H5Lcreate_external(ext_link_filename, ext_objname, subgroup_id, + GET_LINK_INFO_TEST_EXT_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", GET_LINK_INFO_TEST_EXT_LINK_NAME); + PART_ERROR(H5Lget_info_external); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_EXT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + GET_LINK_INFO_TEST_EXT_LINK_NAME); + PART_ERROR(H5Lget_info_external); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link did not exist\n"); + PART_ERROR(H5Lget_info_external); + } + + if (H5Lget_info2(subgroup_id, GET_LINK_INFO_TEST_EXT_LINK_NAME, &link_info, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get external link info\n"); + PART_ERROR(H5Lget_info_external); + } + + if (link_info.type != H5L_TYPE_EXTERNAL) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_external); + } + + link_val_size = 1 + strlen(ext_link_filename) + 1 + strlen(ext_objname) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link's value size '%lld' did not match expected value '%lld'\n", + (long long)link_info.u.val_size, link_val_size); + PART_ERROR(H5Lget_info_external); + } + + if (link_info.corder_valid && (link_info.corder != 0)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)0); + PART_ERROR(H5Lget_info_external); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", GET_LINK_INFO_TEST_SUBGROUP3_NAME); + PART_ERROR(H5Lget_info_external); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lget_info_external); +#endif + } + PART_END(H5Lget_info_external); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + H5Fclose(ext_file_id); + ext_file_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_info_ud) + { + TESTING_2("H5Lget_info2 on user-defined link"); + + /* TODO */ + + SKIPPED(); + PART_EMPTY(H5Lget_info_ud); + } + PART_END(H5Lget_info_ud); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_info_by_idx_hard_crt_order_increasing) + { + TESTING_2("H5Lget_info_by_idx2 on hard link by creation order in increasing order"); + + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_INFO_TEST_SUBGROUP5_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", GET_LINK_INFO_TEST_SUBGROUP5_NAME); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_increasing); + } + + /* Create several hard links */ + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, GET_LINK_INFO_TEST_HARD_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", GET_LINK_INFO_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_increasing); + } + + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, GET_LINK_INFO_TEST_HARD_LINK_NAME2, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", GET_LINK_INFO_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_increasing); + } + + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, GET_LINK_INFO_TEST_HARD_LINK_NAME3, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", GET_LINK_INFO_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_increasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + GET_LINK_INFO_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + GET_LINK_INFO_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_HARD_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + GET_LINK_INFO_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_increasing); + } + + /* Retrieve info of links in turn */ + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get hard link info for index %d\n", 0); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_increasing); + } + + if (link_info.type != H5L_TYPE_HARD) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_increasing); + } + + if (link_info.corder_valid && (link_info.corder != 0)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)0); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_increasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 1, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get hard link info for index %d\n", 1); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_increasing); + } + + if (link_info.type != H5L_TYPE_HARD) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_increasing); + } + + if (link_info.corder_valid && (link_info.corder != 1)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)1); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_increasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 2, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get hard link info for index %d\n", 2); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_increasing); + } + + if (link_info.type != H5L_TYPE_HARD) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_increasing); + } + + if (link_info.corder_valid && (link_info.corder != 2)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)2); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_increasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", GET_LINK_INFO_TEST_SUBGROUP5_NAME); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_increasing); + } + + PASSED(); + } + PART_END(H5Lget_info_by_idx_hard_crt_order_increasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_info_by_idx_hard_crt_order_decreasing) + { + TESTING_2("H5Lget_info_by_idx2 on hard link by creation order in decreasing order"); + + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_INFO_TEST_SUBGROUP6_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", GET_LINK_INFO_TEST_SUBGROUP6_NAME); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_decreasing); + } + + /* Create several hard links */ + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, GET_LINK_INFO_TEST_HARD_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", GET_LINK_INFO_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_decreasing); + } + + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, GET_LINK_INFO_TEST_HARD_LINK_NAME2, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", GET_LINK_INFO_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_decreasing); + } + + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, GET_LINK_INFO_TEST_HARD_LINK_NAME3, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", GET_LINK_INFO_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_decreasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + GET_LINK_INFO_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + GET_LINK_INFO_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_HARD_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + GET_LINK_INFO_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_decreasing); + } + + /* Retrieve info of links in turn */ + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 2, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get hard link info for index %d\n", 2); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_decreasing); + } + + if (link_info.type != H5L_TYPE_HARD) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_decreasing); + } + + if (link_info.corder_valid && (link_info.corder != 0)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)0); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_decreasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 1, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get hard link info for index %d\n", 1); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_decreasing); + } + + if (link_info.type != H5L_TYPE_HARD) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_decreasing); + } + + if (link_info.corder_valid && (link_info.corder != 1)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)1); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_decreasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 0, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get hard link info for index %d\n", 0); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_decreasing); + } + + if (link_info.type != H5L_TYPE_HARD) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_decreasing); + } + + if (link_info.corder_valid && (link_info.corder != 2)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)2); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_decreasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", GET_LINK_INFO_TEST_SUBGROUP6_NAME); + PART_ERROR(H5Lget_info_by_idx_hard_crt_order_decreasing); + } + + PASSED(); + } + PART_END(H5Lget_info_by_idx_hard_crt_order_decreasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_info_by_idx_hard_name_order_increasing) + { + TESTING_2("H5Lget_info_by_idx2 on hard link by alphabetical order in increasing order"); + + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_INFO_TEST_SUBGROUP7_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", GET_LINK_INFO_TEST_SUBGROUP7_NAME); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_increasing); + } + + /* Create several hard links */ + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, GET_LINK_INFO_TEST_HARD_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", GET_LINK_INFO_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_increasing); + } + + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, GET_LINK_INFO_TEST_HARD_LINK_NAME2, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", GET_LINK_INFO_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_increasing); + } + + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, GET_LINK_INFO_TEST_HARD_LINK_NAME3, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", GET_LINK_INFO_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_increasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + GET_LINK_INFO_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + GET_LINK_INFO_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_HARD_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + GET_LINK_INFO_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_increasing); + } + + /* Retrieve info of links in turn */ + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get hard link info for index %d\n", 0); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_increasing); + } + + if (link_info.type != H5L_TYPE_HARD) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_increasing); + } + + if (link_info.corder_valid && (link_info.corder != 0)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)0); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_increasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 1, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get hard link info for index %d\n", 1); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_increasing); + } + + if (link_info.type != H5L_TYPE_HARD) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_increasing); + } + + if (link_info.corder_valid && (link_info.corder != 1)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)1); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_increasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 2, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get hard link info for index %d\n", 2); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_increasing); + } + + if (link_info.type != H5L_TYPE_HARD) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_increasing); + } + + if (link_info.corder_valid && (link_info.corder != 2)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)2); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_increasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", GET_LINK_INFO_TEST_SUBGROUP7_NAME); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_increasing); + } + + PASSED(); + } + PART_END(H5Lget_info_by_idx_hard_name_order_increasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_info_by_idx_hard_name_order_decreasing) + { + TESTING_2("H5Lget_info_by_idx2 on hard link by alphabetical order in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_INFO_TEST_SUBGROUP8_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", GET_LINK_INFO_TEST_SUBGROUP8_NAME); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_decreasing); + } + + /* Create several hard links */ + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, GET_LINK_INFO_TEST_HARD_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", GET_LINK_INFO_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_decreasing); + } + + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, GET_LINK_INFO_TEST_HARD_LINK_NAME2, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", GET_LINK_INFO_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_decreasing); + } + + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, GET_LINK_INFO_TEST_HARD_LINK_NAME3, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", GET_LINK_INFO_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_decreasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + GET_LINK_INFO_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + GET_LINK_INFO_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_HARD_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + GET_LINK_INFO_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_decreasing); + } + + /* Retrieve info of links in turn */ + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 2, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get hard link info for index %lld\n", 2); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_decreasing); + } + + if (link_info.type != H5L_TYPE_HARD) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_decreasing); + } + + if (link_info.corder_valid && (link_info.corder != 0)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)0); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_decreasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 1, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get hard link info for index %lld\n", 1); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_decreasing); + } + + if (link_info.type != H5L_TYPE_HARD) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_decreasing); + } + + if (link_info.corder_valid && (link_info.corder != 1)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)1); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_decreasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 0, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get hard link info for index %lld\n", 0); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_decreasing); + } + + if (link_info.type != H5L_TYPE_HARD) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_decreasing); + } + + if (link_info.corder_valid && (link_info.corder != 2)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)2); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_decreasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", GET_LINK_INFO_TEST_SUBGROUP8_NAME); + PART_ERROR(H5Lget_info_by_idx_hard_name_order_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lget_info_by_idx_hard_name_order_decreasing); +#endif + } + PART_END(H5Lget_info_by_idx_hard_name_order_decreasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_info_by_idx_soft_crt_order_increasing) + { + TESTING_2("H5Lget_info_by_idx2 on soft link by creation order in increasing order"); + + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_INFO_TEST_SUBGROUP9_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", GET_LINK_INFO_TEST_SUBGROUP9_NAME); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_increasing); + } + + /* Create several soft links */ + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" GET_LINK_INFO_TEST_GROUP_NAME + "/" GET_LINK_INFO_TEST_SUBGROUP9_NAME, + subgroup_id, GET_LINK_INFO_TEST_SOFT_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", GET_LINK_INFO_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_increasing); + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" GET_LINK_INFO_TEST_GROUP_NAME + "/" GET_LINK_INFO_TEST_SUBGROUP9_NAME, + subgroup_id, GET_LINK_INFO_TEST_SOFT_LINK_NAME2, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", GET_LINK_INFO_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_increasing); + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" GET_LINK_INFO_TEST_GROUP_NAME + "/" GET_LINK_INFO_TEST_SUBGROUP9_NAME, + subgroup_id, GET_LINK_INFO_TEST_SOFT_LINK_NAME3, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", GET_LINK_INFO_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_increasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + GET_LINK_INFO_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + GET_LINK_INFO_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + GET_LINK_INFO_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_increasing); + } + + /* Retrieve info of links in turn */ + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get soft link info for index %d\n", 0); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_increasing); + } + + if (link_info.type != H5L_TYPE_SOFT) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_increasing); + } + + link_val_size = strlen("/" LINK_TEST_GROUP_NAME "/" GET_LINK_INFO_TEST_GROUP_NAME + "/" GET_LINK_INFO_TEST_SUBGROUP9_NAME) + + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link's value size '%zu' did not match expected value '%zu'\n", + link_info.u.val_size, link_val_size); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_increasing); + } + + if (link_info.corder_valid && (link_info.corder != 0)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)0); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_increasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 1, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get soft link info for index %d\n", 1); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_increasing); + } + + if (link_info.type != H5L_TYPE_SOFT) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_increasing); + } + + link_val_size = strlen("/" LINK_TEST_GROUP_NAME "/" GET_LINK_INFO_TEST_GROUP_NAME + "/" GET_LINK_INFO_TEST_SUBGROUP9_NAME) + + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link's value size '%zu' did not match expected value '%zu'\n", + link_info.u.val_size, link_val_size); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_increasing); + } + + if (link_info.corder_valid && (link_info.corder != 1)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)1); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_increasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 2, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get soft link info for index %d\n", 2); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_increasing); + } + + if (link_info.type != H5L_TYPE_SOFT) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_increasing); + } + + link_val_size = strlen("/" LINK_TEST_GROUP_NAME "/" GET_LINK_INFO_TEST_GROUP_NAME + "/" GET_LINK_INFO_TEST_SUBGROUP9_NAME) + + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link's value size '%zu' did not match expected value '%zu'\n", + link_info.u.val_size, link_val_size); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_increasing); + } + + if (link_info.corder_valid && (link_info.corder != 2)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)2); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_increasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", GET_LINK_INFO_TEST_SUBGROUP9_NAME); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_increasing); + } + + PASSED(); + } + PART_END(H5Lget_info_by_idx_soft_crt_order_increasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_info_by_idx_soft_crt_order_decreasing) + { + TESTING_2("H5Lget_info_by_idx2 on soft link by creation order in decreasing order"); + + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_INFO_TEST_SUBGROUP10_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", GET_LINK_INFO_TEST_SUBGROUP10_NAME); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_decreasing); + } + + /* Create several soft links */ + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" GET_LINK_INFO_TEST_GROUP_NAME + "/" GET_LINK_INFO_TEST_SUBGROUP10_NAME, + subgroup_id, GET_LINK_INFO_TEST_SOFT_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", GET_LINK_INFO_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_decreasing); + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" GET_LINK_INFO_TEST_GROUP_NAME + "/" GET_LINK_INFO_TEST_SUBGROUP10_NAME, + subgroup_id, GET_LINK_INFO_TEST_SOFT_LINK_NAME2, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", GET_LINK_INFO_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_decreasing); + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" GET_LINK_INFO_TEST_GROUP_NAME + "/" GET_LINK_INFO_TEST_SUBGROUP10_NAME, + subgroup_id, GET_LINK_INFO_TEST_SOFT_LINK_NAME3, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", GET_LINK_INFO_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_decreasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + GET_LINK_INFO_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + GET_LINK_INFO_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + GET_LINK_INFO_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_decreasing); + } + + /* Retrieve info of links in turn */ + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 2, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get soft link info for index %d\n", 2); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_decreasing); + } + + if (link_info.type != H5L_TYPE_SOFT) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_decreasing); + } + + link_val_size = strlen("/" LINK_TEST_GROUP_NAME "/" GET_LINK_INFO_TEST_GROUP_NAME + "/" GET_LINK_INFO_TEST_SUBGROUP10_NAME) + + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link's value size '%zu' did not match expected value '%zu'\n", + link_info.u.val_size, link_val_size); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_decreasing); + } + + if (link_info.corder_valid && (link_info.corder != 0)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)0); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_decreasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 1, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get soft link info for index %d\n", 1); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_decreasing); + } + + if (link_info.type != H5L_TYPE_SOFT) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_decreasing); + } + + link_val_size = strlen("/" LINK_TEST_GROUP_NAME "/" GET_LINK_INFO_TEST_GROUP_NAME + "/" GET_LINK_INFO_TEST_SUBGROUP10_NAME) + + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link's value size '%zu' did not match expected value '%zu'\n", + link_info.u.val_size, link_val_size); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_decreasing); + } + + if (link_info.corder_valid && (link_info.corder != 1)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)1); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_decreasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 0, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get soft link info for index %d\n", 0); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_decreasing); + } + + if (link_info.type != H5L_TYPE_SOFT) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_decreasing); + } + + link_val_size = strlen("/" LINK_TEST_GROUP_NAME "/" GET_LINK_INFO_TEST_GROUP_NAME + "/" GET_LINK_INFO_TEST_SUBGROUP10_NAME) + + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link's value size '%zu' did not match expected value '%zu'\n", + link_info.u.val_size, link_val_size); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_decreasing); + } + + if (link_info.corder_valid && (link_info.corder != 2)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)2); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_decreasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", GET_LINK_INFO_TEST_SUBGROUP10_NAME); + PART_ERROR(H5Lget_info_by_idx_soft_crt_order_decreasing); + } + + PASSED(); + } + PART_END(H5Lget_info_by_idx_soft_crt_order_decreasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_info_by_idx_soft_name_order_increasing) + { + TESTING_2("H5Lget_info_by_idx2 on soft link by alphabetical order in increasing order"); + + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_INFO_TEST_SUBGROUP11_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", GET_LINK_INFO_TEST_SUBGROUP11_NAME); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_increasing); + } + + /* Create several soft links */ + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" GET_LINK_INFO_TEST_GROUP_NAME + "/" GET_LINK_INFO_TEST_SUBGROUP11_NAME, + subgroup_id, GET_LINK_INFO_TEST_SOFT_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", GET_LINK_INFO_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_increasing); + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" GET_LINK_INFO_TEST_GROUP_NAME + "/" GET_LINK_INFO_TEST_SUBGROUP11_NAME, + subgroup_id, GET_LINK_INFO_TEST_SOFT_LINK_NAME2, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", GET_LINK_INFO_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_increasing); + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" GET_LINK_INFO_TEST_GROUP_NAME + "/" GET_LINK_INFO_TEST_SUBGROUP11_NAME, + subgroup_id, GET_LINK_INFO_TEST_SOFT_LINK_NAME3, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", GET_LINK_INFO_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_increasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + GET_LINK_INFO_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + GET_LINK_INFO_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + GET_LINK_INFO_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_increasing); + } + + /* Retrieve info of links in turn */ + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get soft link info for index %d\n", 0); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_increasing); + } + + if (link_info.type != H5L_TYPE_SOFT) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_increasing); + } + + link_val_size = strlen("/" LINK_TEST_GROUP_NAME "/" GET_LINK_INFO_TEST_GROUP_NAME + "/" GET_LINK_INFO_TEST_SUBGROUP11_NAME) + + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link's value size '%zu' did not match expected value '%zu'\n", + link_info.u.val_size, link_val_size); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_increasing); + } + + if (link_info.corder_valid && (link_info.corder != 0)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)0); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_increasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 1, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get soft link info for index %d\n", 1); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_increasing); + } + + if (link_info.type != H5L_TYPE_SOFT) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_increasing); + } + + link_val_size = strlen("/" LINK_TEST_GROUP_NAME "/" GET_LINK_INFO_TEST_GROUP_NAME + "/" GET_LINK_INFO_TEST_SUBGROUP11_NAME) + + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link's value size '%zu' did not match expected value '%zu'\n", + link_info.u.val_size, link_val_size); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_increasing); + } + + if (link_info.corder_valid && (link_info.corder != 1)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)1); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_increasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 2, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get soft link info for index %d\n", 2); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_increasing); + } + + if (link_info.type != H5L_TYPE_SOFT) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_increasing); + } + + link_val_size = strlen("/" LINK_TEST_GROUP_NAME "/" GET_LINK_INFO_TEST_GROUP_NAME + "/" GET_LINK_INFO_TEST_SUBGROUP11_NAME) + + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link's value size '%zu' did not match expected value '%zu'\n", + link_info.u.val_size, link_val_size); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_increasing); + } + + if (link_info.corder_valid && (link_info.corder != 2)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)2); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_increasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", GET_LINK_INFO_TEST_SUBGROUP11_NAME); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_increasing); + } + + PASSED(); + } + PART_END(H5Lget_info_by_idx_soft_name_order_increasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_info_by_idx_soft_name_order_decreasing) + { + TESTING_2("H5Lget_info_by_idx2 on soft link by alphabetical order in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_INFO_TEST_SUBGROUP12_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", GET_LINK_INFO_TEST_SUBGROUP12_NAME); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_decreasing); + } + + /* Create several soft links */ + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" GET_LINK_INFO_TEST_GROUP_NAME + "/" GET_LINK_INFO_TEST_SUBGROUP12_NAME, + subgroup_id, GET_LINK_INFO_TEST_SOFT_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", GET_LINK_INFO_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_decreasing); + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" GET_LINK_INFO_TEST_GROUP_NAME + "/" GET_LINK_INFO_TEST_SUBGROUP12_NAME, + subgroup_id, GET_LINK_INFO_TEST_SOFT_LINK_NAME2, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", GET_LINK_INFO_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_decreasing); + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" GET_LINK_INFO_TEST_GROUP_NAME + "/" GET_LINK_INFO_TEST_SUBGROUP12_NAME, + subgroup_id, GET_LINK_INFO_TEST_SOFT_LINK_NAME3, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", GET_LINK_INFO_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_decreasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + GET_LINK_INFO_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + GET_LINK_INFO_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + GET_LINK_INFO_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_decreasing); + } + + /* Retrieve info of links in turn */ + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 2, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get soft link info for index %lld\n", 2); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_decreasing); + } + + if (link_info.type != H5L_TYPE_SOFT) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_decreasing); + } + + link_val_size = strlen("/" LINK_TEST_GROUP_NAME "/" GET_LINK_INFO_TEST_GROUP_NAME + "/" GET_LINK_INFO_TEST_SUBGROUP12_NAME) + + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link's value size '%lld' did not match expected value '%lld'\n", + (long long)link_info.u.val_size, link_val_size); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_decreasing); + } + + if (link_info.corder_valid && (link_info.corder != 0)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)0); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_decreasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 1, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get soft link info for index %lld\n", 1); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_decreasing); + } + + if (link_info.type != H5L_TYPE_SOFT) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_decreasing); + } + + link_val_size = strlen("/" LINK_TEST_GROUP_NAME "/" GET_LINK_INFO_TEST_GROUP_NAME + "/" GET_LINK_INFO_TEST_SUBGROUP12_NAME) + + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link's value size '%lld' did not match expected value '%lld'\n", + (long long)link_info.u.val_size, link_val_size); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_decreasing); + } + + if (link_info.corder_valid && (link_info.corder != 1)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)1); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_decreasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 0, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get soft link info for index %lld\n", 0); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_decreasing); + } + + if (link_info.type != H5L_TYPE_SOFT) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_decreasing); + } + + link_val_size = strlen("/" LINK_TEST_GROUP_NAME "/" GET_LINK_INFO_TEST_GROUP_NAME + "/" GET_LINK_INFO_TEST_SUBGROUP12_NAME) + + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link's value size '%lld' did not match expected value '%lld'\n", + (long long)link_info.u.val_size, link_val_size); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_decreasing); + } + + if (link_info.corder_valid && (link_info.corder != 2)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)2); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_decreasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", GET_LINK_INFO_TEST_SUBGROUP12_NAME); + PART_ERROR(H5Lget_info_by_idx_soft_name_order_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lget_info_by_idx_soft_name_order_decreasing); +#endif + } + PART_END(H5Lget_info_by_idx_soft_name_order_decreasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_info_by_idx_external_crt_order_increasing) + { + TESTING_2("H5Lget_info_by_idx2 on external link by creation order in increasing order"); +#ifndef NO_EXTERNAL_LINKS + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME); + + if ((ext_file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_increasing); + } + + if (H5Fclose(ext_file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close file '%s'\n", ext_link_filename); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_increasing); + } + + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_INFO_TEST_SUBGROUP13_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", GET_LINK_INFO_TEST_SUBGROUP13_NAME); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_increasing); + } + + /* Create several external links */ + ext_objname = "/"; + if (H5Lcreate_external(ext_link_filename, ext_objname, subgroup_id, + GET_LINK_INFO_TEST_EXT_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", GET_LINK_INFO_TEST_EXT_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_increasing); + } + + if (H5Lcreate_external(ext_link_filename, ext_objname, subgroup_id, + GET_LINK_INFO_TEST_EXT_LINK_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", GET_LINK_INFO_TEST_EXT_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_increasing); + } + + if (H5Lcreate_external(ext_link_filename, ext_objname, subgroup_id, + GET_LINK_INFO_TEST_EXT_LINK_NAME3, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", GET_LINK_INFO_TEST_EXT_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_increasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_EXT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + GET_LINK_INFO_TEST_EXT_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_EXT_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_EXT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + GET_LINK_INFO_TEST_EXT_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_EXT_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_EXT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + GET_LINK_INFO_TEST_EXT_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_EXT_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_increasing); + } + + /* Retrieve info of links in turn */ + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get external link info for index %lld\n", 0); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_increasing); + } + + if (link_info.type != H5L_TYPE_EXTERNAL) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_increasing); + } + + link_val_size = 1 + strlen(ext_link_filename) + 1 + strlen(ext_objname) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link's value size '%lld' did not match expected value '%lld'\n", + (long long)link_info.u.val_size, link_val_size); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_increasing); + } + + if (link_info.corder_valid && (link_info.corder != 0)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)0); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_increasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 1, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get external link info for index %lld\n", 1); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_increasing); + } + + if (link_info.type != H5L_TYPE_EXTERNAL) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_increasing); + } + + link_val_size = 1 + strlen(ext_link_filename) + 1 + strlen(ext_objname) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link's value size '%lld' did not match expected value '%lld'\n", + (long long)link_info.u.val_size, link_val_size); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_increasing); + } + + if (link_info.corder_valid && (link_info.corder != 1)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)1); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_increasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 2, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get external link info for index %lld\n", 2); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_increasing); + } + + if (link_info.type != H5L_TYPE_EXTERNAL) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_increasing); + } + + link_val_size = 1 + strlen(ext_link_filename) + 1 + strlen(ext_objname) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link's value size '%lld' did not match expected value '%lld'\n", + (long long)link_info.u.val_size, link_val_size); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_increasing); + } + + if (link_info.corder_valid && (link_info.corder != 2)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)2); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_increasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", GET_LINK_INFO_TEST_SUBGROUP13_NAME); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_increasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lget_info_by_idx_external_crt_order_increasing); +#endif + } + PART_END(H5Lget_info_by_idx_external_crt_order_increasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + H5Fclose(ext_file_id); + ext_file_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_info_by_idx_external_crt_order_decreasing) + { + TESTING_2("H5Lget_info_by_idx2 on external link by creation order in decreasing order"); +#ifndef NO_EXTERNAL_LINKS + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME); + + if ((ext_file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_decreasing); + } + + if (H5Fclose(ext_file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close file '%s'\n", ext_link_filename); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_decreasing); + } + + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_INFO_TEST_SUBGROUP14_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", GET_LINK_INFO_TEST_SUBGROUP14_NAME); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_decreasing); + } + + /* Create several external links */ + ext_objname = "/"; + if (H5Lcreate_external(ext_link_filename, ext_objname, subgroup_id, + GET_LINK_INFO_TEST_EXT_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", GET_LINK_INFO_TEST_EXT_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_decreasing); + } + + if (H5Lcreate_external(ext_link_filename, ext_objname, subgroup_id, + GET_LINK_INFO_TEST_EXT_LINK_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", GET_LINK_INFO_TEST_EXT_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_decreasing); + } + + if (H5Lcreate_external(ext_link_filename, ext_objname, subgroup_id, + GET_LINK_INFO_TEST_EXT_LINK_NAME3, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", GET_LINK_INFO_TEST_EXT_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_decreasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_EXT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + GET_LINK_INFO_TEST_EXT_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_EXT_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_EXT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + GET_LINK_INFO_TEST_EXT_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_EXT_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_EXT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + GET_LINK_INFO_TEST_EXT_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_EXT_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_decreasing); + } + + /* Retrieve info of links in turn */ + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 2, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get external link info for index %lld\n", 2); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_decreasing); + } + + if (link_info.type != H5L_TYPE_EXTERNAL) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_decreasing); + } + + link_val_size = 1 + strlen(ext_link_filename) + 1 + strlen(ext_objname) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link's value size '%lld' did not match expected value '%lld'\n", + (long long)link_info.u.val_size, link_val_size); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_decreasing); + } + + if (link_info.corder_valid && (link_info.corder != 0)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)0); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_decreasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 1, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get external link info for index %lld\n", 1); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_decreasing); + } + + if (link_info.type != H5L_TYPE_EXTERNAL) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_decreasing); + } + + link_val_size = 1 + strlen(ext_link_filename) + 1 + strlen(ext_objname) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link's value size '%lld' did not match expected value '%lld'\n", + (long long)link_info.u.val_size, link_val_size); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_decreasing); + } + + if (link_info.corder_valid && (link_info.corder != 1)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)1); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_decreasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 0, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get external link info for index %lld\n", 0); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_decreasing); + } + + if (link_info.type != H5L_TYPE_EXTERNAL) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_decreasing); + } + + link_val_size = 1 + strlen(ext_link_filename) + 1 + strlen(ext_objname) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link's value size '%lld' did not match expected value '%lld'\n", + (long long)link_info.u.val_size, link_val_size); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_decreasing); + } + + if (link_info.corder_valid && (link_info.corder != 2)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)2); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_decreasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", GET_LINK_INFO_TEST_SUBGROUP14_NAME); + PART_ERROR(H5Lget_info_by_idx_external_crt_order_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lget_info_by_idx_external_crt_order_decreasing); +#endif + } + PART_END(H5Lget_info_by_idx_external_crt_order_decreasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + H5Fclose(ext_file_id); + ext_file_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_info_by_idx_external_name_order_increasing) + { + TESTING_2("H5Lget_info_by_idx2 on external link by alphabetical order in increasing order"); +#ifndef NO_EXTERNAL_LINKS + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME); + + if ((ext_file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + PART_ERROR(H5Lget_info_by_idx_external_name_order_increasing); + } + + if (H5Fclose(ext_file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close file '%s'\n", ext_link_filename); + PART_ERROR(H5Lget_info_by_idx_external_name_order_increasing); + } + + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_INFO_TEST_SUBGROUP15_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", GET_LINK_INFO_TEST_SUBGROUP15_NAME); + PART_ERROR(H5Lget_info_by_idx_external_name_order_increasing); + } + + /* Create several external links */ + ext_objname = "/"; + if (H5Lcreate_external(ext_link_filename, ext_objname, subgroup_id, + GET_LINK_INFO_TEST_EXT_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", GET_LINK_INFO_TEST_EXT_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_external_name_order_increasing); + } + + if (H5Lcreate_external(ext_link_filename, ext_objname, subgroup_id, + GET_LINK_INFO_TEST_EXT_LINK_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", GET_LINK_INFO_TEST_EXT_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_external_name_order_increasing); + } + + if (H5Lcreate_external(ext_link_filename, ext_objname, subgroup_id, + GET_LINK_INFO_TEST_EXT_LINK_NAME3, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", GET_LINK_INFO_TEST_EXT_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_external_name_order_increasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_EXT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + GET_LINK_INFO_TEST_EXT_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_external_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_EXT_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_external_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_EXT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + GET_LINK_INFO_TEST_EXT_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_external_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_EXT_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_external_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_EXT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + GET_LINK_INFO_TEST_EXT_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_external_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_EXT_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_external_name_order_increasing); + } + + /* Retrieve info of links in turn */ + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get external link info for index %lld\n", 0); + PART_ERROR(H5Lget_info_by_idx_external_name_order_increasing); + } + + if (link_info.type != H5L_TYPE_EXTERNAL) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_external_name_order_increasing); + } + + link_val_size = 1 + strlen(ext_link_filename) + 1 + strlen(ext_objname) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link's value size '%lld' did not match expected value '%lld'\n", + (long long)link_info.u.val_size, link_val_size); + PART_ERROR(H5Lget_info_by_idx_external_name_order_increasing); + } + + if (link_info.corder_valid && (link_info.corder != 0)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)0); + PART_ERROR(H5Lget_info_by_idx_external_name_order_increasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 1, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get external link info for index %lld\n", 1); + PART_ERROR(H5Lget_info_by_idx_external_name_order_increasing); + } + + if (link_info.type != H5L_TYPE_EXTERNAL) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_external_name_order_increasing); + } + + link_val_size = 1 + strlen(ext_link_filename) + 1 + strlen(ext_objname) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link's value size '%lld' did not match expected value '%lld'\n", + (long long)link_info.u.val_size, link_val_size); + PART_ERROR(H5Lget_info_by_idx_external_name_order_increasing); + } + + if (link_info.corder_valid && (link_info.corder != 1)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)1); + PART_ERROR(H5Lget_info_by_idx_external_name_order_increasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 2, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get external link info for index %lld\n", 2); + PART_ERROR(H5Lget_info_by_idx_external_name_order_increasing); + } + + if (link_info.type != H5L_TYPE_EXTERNAL) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_external_name_order_increasing); + } + + link_val_size = 1 + strlen(ext_link_filename) + 1 + strlen(ext_objname) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link's value size '%lld' did not match expected value '%lld'\n", + (long long)link_info.u.val_size, link_val_size); + PART_ERROR(H5Lget_info_by_idx_external_name_order_increasing); + } + + if (link_info.corder_valid && (link_info.corder != 2)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)2); + PART_ERROR(H5Lget_info_by_idx_external_name_order_increasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", GET_LINK_INFO_TEST_SUBGROUP15_NAME); + PART_ERROR(H5Lget_info_by_idx_external_name_order_increasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lget_info_by_idx_external_name_order_increasing); +#endif + } + PART_END(H5Lget_info_by_idx_external_name_order_increasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + H5Fclose(ext_file_id); + ext_file_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_info_by_idx_external_name_order_decreasing) + { + TESTING_2("H5Lget_info_by_idx2 on external link by alphabetical order in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME); + + if ((ext_file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + PART_ERROR(H5Lget_info_by_idx_external_name_order_decreasing); + } + + if (H5Fclose(ext_file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close file '%s'\n", ext_link_filename); + PART_ERROR(H5Lget_info_by_idx_external_name_order_decreasing); + } + + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_INFO_TEST_SUBGROUP16_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", GET_LINK_INFO_TEST_SUBGROUP16_NAME); + PART_ERROR(H5Lget_info_by_idx_external_name_order_decreasing); + } + + /* Create several external links */ + ext_objname = "/"; + if (H5Lcreate_external(ext_link_filename, ext_objname, subgroup_id, + GET_LINK_INFO_TEST_EXT_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", GET_LINK_INFO_TEST_EXT_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_external_name_order_decreasing); + } + + if (H5Lcreate_external(ext_link_filename, ext_objname, subgroup_id, + GET_LINK_INFO_TEST_EXT_LINK_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", GET_LINK_INFO_TEST_EXT_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_external_name_order_decreasing); + } + + if (H5Lcreate_external(ext_link_filename, ext_objname, subgroup_id, + GET_LINK_INFO_TEST_EXT_LINK_NAME3, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", GET_LINK_INFO_TEST_EXT_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_external_name_order_decreasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_EXT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + GET_LINK_INFO_TEST_EXT_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_external_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_EXT_LINK_NAME); + PART_ERROR(H5Lget_info_by_idx_external_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_EXT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + GET_LINK_INFO_TEST_EXT_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_external_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_EXT_LINK_NAME2); + PART_ERROR(H5Lget_info_by_idx_external_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_INFO_TEST_EXT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + GET_LINK_INFO_TEST_EXT_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_external_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before deletion\n", + GET_LINK_INFO_TEST_EXT_LINK_NAME3); + PART_ERROR(H5Lget_info_by_idx_external_name_order_decreasing); + } + + /* Retrieve info of links in turn */ + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 2, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get external link info for index %lld\n", 2); + PART_ERROR(H5Lget_info_by_idx_external_name_order_decreasing); + } + + if (link_info.type != H5L_TYPE_EXTERNAL) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_external_name_order_decreasing); + } + + link_val_size = 1 + strlen(ext_link_filename) + 1 + strlen(ext_objname) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link's value size '%lld' did not match expected value '%lld'\n", + (long long)link_info.u.val_size, link_val_size); + PART_ERROR(H5Lget_info_by_idx_external_name_order_decreasing); + } + + if (link_info.corder_valid && (link_info.corder != 0)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)0); + PART_ERROR(H5Lget_info_by_idx_external_name_order_decreasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 1, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get external link info for index %lld\n", 1); + PART_ERROR(H5Lget_info_by_idx_external_name_order_decreasing); + } + + if (link_info.type != H5L_TYPE_EXTERNAL) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_external_name_order_decreasing); + } + + link_val_size = 1 + strlen(ext_link_filename) + 1 + strlen(ext_objname) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link's value size '%lld' did not match expected value '%lld'\n", + (long long)link_info.u.val_size, link_val_size); + PART_ERROR(H5Lget_info_by_idx_external_name_order_decreasing); + } + + if (link_info.corder_valid && (link_info.corder != 1)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)1); + PART_ERROR(H5Lget_info_by_idx_external_name_order_decreasing); + } + + HDmemset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info_by_idx2(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 0, &link_info, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get external link info for index %lld\n", 0); + PART_ERROR(H5Lget_info_by_idx_external_name_order_decreasing); + } + + if (link_info.type != H5L_TYPE_EXTERNAL) { + H5_FAILED(); + HDprintf(" incorrect link type returned\n"); + PART_ERROR(H5Lget_info_by_idx_external_name_order_decreasing); + } + + link_val_size = 1 + strlen(ext_link_filename) + 1 + strlen(ext_objname) + 1; + if (link_info.u.val_size != link_val_size) { + H5_FAILED(); + HDprintf(" link's value size '%lld' did not match expected value '%lld'\n", + (long long)link_info.u.val_size, link_val_size); + PART_ERROR(H5Lget_info_by_idx_external_name_order_decreasing); + } + + if (link_info.corder_valid && (link_info.corder != 2)) { + H5_FAILED(); + HDprintf(" link's creation order value '%lld' did not match expected value '%lld'\n", + (long long)link_info.corder, (long long)2); + PART_ERROR(H5Lget_info_by_idx_external_name_order_decreasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", GET_LINK_INFO_TEST_SUBGROUP16_NAME); + PART_ERROR(H5Lget_info_by_idx_external_name_order_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lget_info_by_idx_external_name_order_decreasing); +#endif + } + PART_END(H5Lget_info_by_idx_external_name_order_decreasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + H5Fclose(ext_file_id); + ext_file_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_info_by_idx_ud_crt_order_increasing) + { + TESTING_2("H5Lget_info_by_idx2 on user-defined link by creation order in increasing order"); + + SKIPPED(); + PART_EMPTY(H5Lget_info_by_idx_ud_crt_order_increasing); + } + PART_END(H5Lget_info_by_idx_ud_crt_order_increasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_info_by_idx_ud_crt_order_decreasing) + { + TESTING_2("H5Lget_info_by_idx2 on user-defined link by creation order in decreasing order"); + + SKIPPED(); + PART_EMPTY(H5Lget_info_by_idx_ud_crt_order_decreasing); + } + PART_END(H5Lget_info_by_idx_ud_crt_order_decreasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_info_by_idx_ud_name_order_increasing) + { + TESTING_2("H5Lget_info_by_idx2 on user-defined link by alphabetical order in increasing order"); + + SKIPPED(); + PART_EMPTY(H5Lget_info_by_idx_ud_name_order_increasing); + } + PART_END(H5Lget_info_by_idx_ud_name_order_increasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_info_by_idx_ud_name_order_decreasing) + { + TESTING_2("H5Lget_info_by_idx2 on user-defined link by alphabetical order in decreasing order"); + + SKIPPED(); + PART_EMPTY(H5Lget_info_by_idx_ud_name_order_decreasing); + } + PART_END(H5Lget_info_by_idx_ud_name_order_decreasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(gcpl_id); + H5Gclose(subgroup_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(ext_file_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a link's info can't be retrieved + * when H5Lget_info(_by_idx)2 is passed invalid parameters. + */ +static int +test_get_link_info_invalid_params(void) +{ + H5L_info2_t link_info; + herr_t err_ret = -1; + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + + TESTING_MULTIPART("link info retrieval with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_HARD_LINKS) || !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, basic, more, soft, hard, external link, or " + "creation order aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create a GCPL\n"); + goto error; + } + + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0) { + H5_FAILED(); + HDprintf(" couldn't enable link creation order tracking and indexing on GCPL\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, GET_LINK_INFO_INVALID_PARAMS_TEST_GROUP_NAME, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + GET_LINK_INFO_INVALID_PARAMS_TEST_GROUP_NAME); + goto error; + } + + if (H5Lcreate_hard(group_id, ".", group_id, GET_LINK_INFO_INVALID_PARAMS_TEST_HARD_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", GET_LINK_INFO_INVALID_PARAMS_TEST_HARD_LINK_NAME); + goto error; + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(group_id, GET_LINK_INFO_INVALID_PARAMS_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + GET_LINK_INFO_INVALID_PARAMS_TEST_HARD_LINK_NAME); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link did not exist\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Lget_info_invalid_loc_id) + { + TESTING_2("H5Lget_info2 with an invalid location ID"); + + HDmemset(&link_info, 0, sizeof(link_info)); + + H5E_BEGIN_TRY + { + err_ret = H5Lget_info2(H5I_INVALID_HID, GET_LINK_INFO_INVALID_PARAMS_TEST_HARD_LINK_NAME, + &link_info, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lget_info2 succeeded with an invalid location ID!\n"); + PART_ERROR(H5Lget_info_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Lget_info_invalid_loc_id); + + PART_BEGIN(H5Lget_info_invalid_link_name) + { + TESTING_2("H5Lget_info2 with an invalid link name"); + + H5E_BEGIN_TRY + { + err_ret = H5Lget_info2(group_id, NULL, &link_info, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lget_info2 succeeded with a NULL link name!\n"); + PART_ERROR(H5Lget_info_invalid_link_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Lget_info2(group_id, "", &link_info, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lget_info2 succeeded with an invalid link name of ''!\n"); + PART_ERROR(H5Lget_info_invalid_link_name); + } + + PASSED(); + } + PART_END(H5Lget_info_invalid_link_name); + + PART_BEGIN(H5Lget_info_invalid_lapl) + { + TESTING_2("H5Lget_info2 with an invalid LAPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Lget_info2(group_id, GET_LINK_INFO_INVALID_PARAMS_TEST_HARD_LINK_NAME, &link_info, + H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lget_info2 succeeded with an invalid LAPL!\n"); + PART_ERROR(H5Lget_info_invalid_lapl); + } + + PASSED(); + } + PART_END(H5Lget_info_invalid_lapl); + + HDmemset(&link_info, 0, sizeof(link_info)); + + PART_BEGIN(H5Lget_info_by_idx_invalid_loc_id) + { + TESTING_2("H5Lget_info_by_idx2 with an invalid location ID"); + + H5E_BEGIN_TRY + { + err_ret = H5Lget_info_by_idx2(H5I_INVALID_HID, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, + &link_info, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lget_info_by_idx2 succeeded with an invalid location ID!\n"); + PART_ERROR(H5Lget_info_by_idx_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Lget_info_by_idx_invalid_loc_id); + + PART_BEGIN(H5Lget_info_by_idx_invalid_grp_name) + { + TESTING_2("H5Lget_info_by_idx2 with an invalid group name"); + + H5E_BEGIN_TRY + { + err_ret = H5Lget_info_by_idx2(group_id, NULL, H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, &link_info, + H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lget_info_by_idx2 succeeded with a NULL group name!\n"); + PART_ERROR(H5Lget_info_by_idx_invalid_grp_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Lget_info_by_idx2(group_id, "", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, &link_info, + H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lget_info_by_idx2 succeeded with an invalid group name of ''!\n"); + PART_ERROR(H5Lget_info_by_idx_invalid_grp_name); + } + + PASSED(); + } + PART_END(H5Lget_info_by_idx_invalid_grp_name); + + PART_BEGIN(H5Lget_info_by_idx_invalid_index_type) + { + TESTING_2("H5Lget_info_by_idx2 with an invalid index type"); + + H5E_BEGIN_TRY + { + err_ret = H5Lget_info_by_idx2(group_id, ".", H5_INDEX_UNKNOWN, H5_ITER_INC, 0, &link_info, + H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lget_info_by_idx2 succeeded with invalid index type H5_INDEX_UNKNOWN!\n"); + PART_ERROR(H5Lget_info_by_idx_invalid_index_type); + } + + H5E_BEGIN_TRY + { + err_ret = + H5Lget_info_by_idx2(group_id, ".", H5_INDEX_N, H5_ITER_INC, 0, &link_info, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lget_info_by_idx2 succeeded with invalid index type H5_INDEX_N!\n"); + PART_ERROR(H5Lget_info_by_idx_invalid_index_type); + } + + PASSED(); + } + PART_END(H5Lget_info_by_idx_invalid_index_type); + + PART_BEGIN(H5Lget_info_by_idx_invalid_iter_order) + { + TESTING_2("H5Lget_info_by_idx2 with an invalid iteration ordering"); + + H5E_BEGIN_TRY + { + err_ret = H5Lget_info_by_idx2(group_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_UNKNOWN, 0, + &link_info, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf( + " H5Lget_info_by_idx2 succeeded with invalid iteration ordering H5_ITER_UNKNOWN!\n"); + PART_ERROR(H5Lget_info_by_idx_invalid_iter_order); + } + + H5E_BEGIN_TRY + { + err_ret = H5Lget_info_by_idx2(group_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_N, 0, &link_info, + H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lget_info_by_idx2 succeeded with invalid iteration ordering H5_ITER_N!\n"); + PART_ERROR(H5Lget_info_by_idx_invalid_iter_order); + } + + PASSED(); + } + PART_END(H5Lget_info_by_idx_invalid_iter_order); + + PART_BEGIN(H5Lget_info_by_idx_invalid_lapl) + { + TESTING_2("H5Lget_info_by_idx2 with an invalid LAPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Lget_info_by_idx2(group_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, &link_info, + H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lget_info_by_idx2 succeeded with an invalid LAPL!\n"); + PART_ERROR(H5Lget_info_by_idx_invalid_lapl); + } + + PASSED(); + } + PART_END(H5Lget_info_by_idx_invalid_lapl); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(gcpl_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a link's name can be correctly + * retrieved by using H5Lget_name_by_idx. + */ +static int +test_get_link_name(void) +{ + ssize_t link_name_buf_size = 0; + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID, ext_file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t subgroup_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + char link_name_buf[GET_LINK_NAME_TEST_BUF_SIZE]; +#ifndef NO_EXTERNAL_LINKS + char ext_link_filename[H5_API_TEST_FILENAME_MAX_LENGTH]; +#endif + + TESTING_MULTIPART("link name retrieval"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_HARD_LINKS) || !(vol_cap_flags_g & H5VL_CAP_FLAG_EXTERNAL_LINKS) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_SOFT_LINKS) || !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, basic, more, soft, hard, external link, or " + "creation order aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create GCPL for link creation order tracking\n"); + goto error; + } + + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED) < 0) { + H5_FAILED(); + HDprintf(" couldn't set link creation order tracking\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, GET_LINK_NAME_TEST_GROUP_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", GET_LINK_NAME_TEST_GROUP_NAME); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Lget_name_by_idx_hard_crt_order_increasing) + { + TESTING_2("H5Lget_name_by_idx on hard link by creation order in increasing order"); + + /* Create group to hold some links */ + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_NAME_TEST_HARD_SUBGROUP_NAME, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + GET_LINK_NAME_TEST_HARD_SUBGROUP_NAME); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_increasing); + } + + /* Create several hard links in reverse order to test creation order */ + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, GET_LINK_NAME_TEST_HARD_LINK_NAME3, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create hard link '%s'\n", GET_LINK_NAME_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_increasing); + } + + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, GET_LINK_NAME_TEST_HARD_LINK_NAME2, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create hard link '%s'\n", GET_LINK_NAME_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_increasing); + } + + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, GET_LINK_NAME_TEST_HARD_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create hard link '%s'\n", GET_LINK_NAME_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_increasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + GET_LINK_NAME_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + GET_LINK_NAME_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_HARD_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + GET_LINK_NAME_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_increasing); + } + + /* Retrieve link names */ + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_increasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_increasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_HARD_LINK_NAME3, + strlen(GET_LINK_NAME_TEST_HARD_LINK_NAME3) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_increasing); + } + + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 1, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_increasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 1, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_increasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_HARD_LINK_NAME2, + strlen(GET_LINK_NAME_TEST_HARD_LINK_NAME2) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_increasing); + } + + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 2, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_increasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 2, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_increasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_HARD_LINK_NAME, + strlen(GET_LINK_NAME_TEST_HARD_LINK_NAME) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_increasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group\n"); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_increasing); + } + + PASSED(); + } + PART_END(H5Lget_name_by_idx_hard_crt_order_increasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_name_by_idx_hard_crt_order_decreasing) + { + TESTING_2("H5Lget_name_by_idx on hard link by creation order in decreasing order"); + + /* Create group to hold some links */ + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_NAME_TEST_HARD_SUBGROUP_NAME2, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + GET_LINK_NAME_TEST_HARD_SUBGROUP_NAME2); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_decreasing); + } + + /* Create several hard links in reverse order to test creation order */ + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, GET_LINK_NAME_TEST_HARD_LINK_NAME3, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create hard link '%s'\n", GET_LINK_NAME_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_decreasing); + } + + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, GET_LINK_NAME_TEST_HARD_LINK_NAME2, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create hard link '%s'\n", GET_LINK_NAME_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_decreasing); + } + + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, GET_LINK_NAME_TEST_HARD_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create hard link '%s'\n", GET_LINK_NAME_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_decreasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + GET_LINK_NAME_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + GET_LINK_NAME_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_HARD_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + GET_LINK_NAME_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_decreasing); + } + + /* Retrieve link names */ + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 0, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_decreasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 0, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_decreasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_HARD_LINK_NAME, + strlen(GET_LINK_NAME_TEST_HARD_LINK_NAME) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_decreasing); + } + + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 1, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_decreasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 1, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_decreasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_HARD_LINK_NAME2, + strlen(GET_LINK_NAME_TEST_HARD_LINK_NAME2) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_decreasing); + } + + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 2, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_decreasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 2, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_decreasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_HARD_LINK_NAME3, + strlen(GET_LINK_NAME_TEST_HARD_LINK_NAME3) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_decreasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group\n"); + PART_ERROR(H5Lget_name_by_idx_hard_crt_order_decreasing); + } + + PASSED(); + } + PART_END(H5Lget_name_by_idx_hard_crt_order_decreasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_name_by_idx_hard_name_order_increasing) + { + TESTING_2("H5Lget_name_by_idx on hard link by alphabetical order in increasing order"); + + /* Create group to hold some links */ + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_NAME_TEST_HARD_SUBGROUP_NAME3, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + GET_LINK_NAME_TEST_HARD_SUBGROUP_NAME3); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_increasing); + } + + /* Create several hard links */ + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, GET_LINK_NAME_TEST_HARD_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create hard link '%s'\n", GET_LINK_NAME_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_increasing); + } + + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, GET_LINK_NAME_TEST_HARD_LINK_NAME2, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create hard link '%s'\n", GET_LINK_NAME_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_increasing); + } + + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, GET_LINK_NAME_TEST_HARD_LINK_NAME3, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create hard link '%s'\n", GET_LINK_NAME_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_increasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + GET_LINK_NAME_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + GET_LINK_NAME_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_HARD_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + GET_LINK_NAME_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_increasing); + } + + /* Retrieve link names */ + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_increasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_increasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_HARD_LINK_NAME, + strlen(GET_LINK_NAME_TEST_HARD_LINK_NAME) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_increasing); + } + + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 1, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_increasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 1, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_increasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_HARD_LINK_NAME2, + strlen(GET_LINK_NAME_TEST_HARD_LINK_NAME2) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_increasing); + } + + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 2, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_increasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 2, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_increasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_HARD_LINK_NAME3, + strlen(GET_LINK_NAME_TEST_HARD_LINK_NAME3) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_increasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group\n"); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_increasing); + } + + PASSED(); + } + PART_END(H5Lget_name_by_idx_hard_name_order_increasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_name_by_idx_hard_name_order_decreasing) + { + TESTING_2("H5Lget_name_by_idx on hard link by alphabetical order in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Create group to hold some links */ + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_NAME_TEST_HARD_SUBGROUP_NAME4, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + GET_LINK_NAME_TEST_HARD_SUBGROUP_NAME4); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_decreasing); + } + + /* Create several hard links */ + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, GET_LINK_NAME_TEST_HARD_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create hard link '%s'\n", GET_LINK_NAME_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_decreasing); + } + + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, GET_LINK_NAME_TEST_HARD_LINK_NAME2, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create hard link '%s'\n", GET_LINK_NAME_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_decreasing); + } + + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, GET_LINK_NAME_TEST_HARD_LINK_NAME3, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create hard link '%s'\n", GET_LINK_NAME_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_decreasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + GET_LINK_NAME_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_HARD_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + GET_LINK_NAME_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_HARD_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if hard link '%s' exists\n", + GET_LINK_NAME_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" hard link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_decreasing); + } + + /* Retrieve link names */ + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 0, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_decreasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 0, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_decreasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_HARD_LINK_NAME3, + strlen(GET_LINK_NAME_TEST_HARD_LINK_NAME3) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_HARD_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_decreasing); + } + + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 1, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_decreasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 1, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_decreasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_HARD_LINK_NAME2, + strlen(GET_LINK_NAME_TEST_HARD_LINK_NAME2) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_HARD_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_decreasing); + } + + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 2, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_decreasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 2, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_decreasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_HARD_LINK_NAME, + strlen(GET_LINK_NAME_TEST_HARD_LINK_NAME) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_HARD_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_decreasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group\n"); + PART_ERROR(H5Lget_name_by_idx_hard_name_order_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lget_name_by_idx_hard_name_order_decreasing); +#endif + } + PART_END(H5Lget_name_by_idx_hard_name_order_decreasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_name_by_idx_soft_crt_order_increasing) + { + TESTING_2("H5Lget_name_by_idx on soft link by creation order in increasing order"); + + /* Create group to hold some links */ + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_NAME_TEST_SOFT_SUBGROUP_NAME, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + GET_LINK_NAME_TEST_SOFT_SUBGROUP_NAME); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_increasing); + } + + /* Create several soft links in reverse order to test creation order */ + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" GET_LINK_NAME_TEST_GROUP_NAME, subgroup_id, + GET_LINK_NAME_TEST_SOFT_LINK_NAME3, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create soft link '%s'\n", GET_LINK_NAME_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_increasing); + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" GET_LINK_NAME_TEST_GROUP_NAME, subgroup_id, + GET_LINK_NAME_TEST_SOFT_LINK_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create soft link '%s'\n", GET_LINK_NAME_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_increasing); + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" GET_LINK_NAME_TEST_GROUP_NAME, subgroup_id, + GET_LINK_NAME_TEST_SOFT_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create soft link '%s'\n", GET_LINK_NAME_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_increasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + GET_LINK_NAME_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + GET_LINK_NAME_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + GET_LINK_NAME_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_increasing); + } + + /* Retrieve link names */ + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_increasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_increasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_SOFT_LINK_NAME3, + strlen(GET_LINK_NAME_TEST_SOFT_LINK_NAME3) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_increasing); + } + + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 1, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_increasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 1, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_increasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_SOFT_LINK_NAME2, + strlen(GET_LINK_NAME_TEST_SOFT_LINK_NAME2) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_increasing); + } + + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 2, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_increasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 2, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_increasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_SOFT_LINK_NAME, + strlen(GET_LINK_NAME_TEST_SOFT_LINK_NAME) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_increasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group\n"); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_increasing); + } + + PASSED(); + } + PART_END(H5Lget_name_by_idx_soft_crt_order_increasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_name_by_idx_soft_crt_order_decreasing) + { + TESTING_2("H5Lget_name_by_idx on soft link by creation order in decreasing order"); + + /* Create group to hold some links */ + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_NAME_TEST_SOFT_SUBGROUP_NAME2, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + GET_LINK_NAME_TEST_SOFT_SUBGROUP_NAME2); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_decreasing); + } + + /* Create several soft links in reverse order to test creation order */ + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" GET_LINK_NAME_TEST_GROUP_NAME, subgroup_id, + GET_LINK_NAME_TEST_SOFT_LINK_NAME3, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create soft link '%s'\n", GET_LINK_NAME_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_decreasing); + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" GET_LINK_NAME_TEST_GROUP_NAME, subgroup_id, + GET_LINK_NAME_TEST_SOFT_LINK_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create soft link '%s'\n", GET_LINK_NAME_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_decreasing); + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" GET_LINK_NAME_TEST_GROUP_NAME, subgroup_id, + GET_LINK_NAME_TEST_SOFT_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create soft link '%s'\n", GET_LINK_NAME_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_decreasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + GET_LINK_NAME_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + GET_LINK_NAME_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + GET_LINK_NAME_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_decreasing); + } + + /* Retrieve link names */ + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 0, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_decreasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 0, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_decreasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_SOFT_LINK_NAME, + strlen(GET_LINK_NAME_TEST_SOFT_LINK_NAME) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_decreasing); + } + + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 1, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_decreasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 1, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_decreasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_SOFT_LINK_NAME2, + strlen(GET_LINK_NAME_TEST_SOFT_LINK_NAME2) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_decreasing); + } + + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 2, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_decreasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 2, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_decreasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_SOFT_LINK_NAME3, + strlen(GET_LINK_NAME_TEST_SOFT_LINK_NAME3) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_decreasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group\n"); + PART_ERROR(H5Lget_name_by_idx_soft_crt_order_decreasing); + } + + PASSED(); + } + PART_END(H5Lget_name_by_idx_soft_crt_order_decreasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_name_by_idx_soft_name_order_increasing) + { + TESTING_2("H5Lget_name_by_idx on soft link by alphabetical order in increasing order"); + + /* Create group to hold some links */ + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_NAME_TEST_SOFT_SUBGROUP_NAME3, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + GET_LINK_NAME_TEST_SOFT_SUBGROUP_NAME3); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_increasing); + } + + /* Create several soft links */ + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" GET_LINK_NAME_TEST_GROUP_NAME, subgroup_id, + GET_LINK_NAME_TEST_SOFT_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create soft link '%s'\n", GET_LINK_NAME_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_increasing); + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" GET_LINK_NAME_TEST_GROUP_NAME, subgroup_id, + GET_LINK_NAME_TEST_SOFT_LINK_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create soft link '%s'\n", GET_LINK_NAME_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_increasing); + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" GET_LINK_NAME_TEST_GROUP_NAME, subgroup_id, + GET_LINK_NAME_TEST_SOFT_LINK_NAME3, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create soft link '%s'\n", GET_LINK_NAME_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_increasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + GET_LINK_NAME_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + GET_LINK_NAME_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + GET_LINK_NAME_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_increasing); + } + + /* Retrieve link names */ + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_increasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_increasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_SOFT_LINK_NAME, + strlen(GET_LINK_NAME_TEST_SOFT_LINK_NAME) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_increasing); + } + + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 1, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_increasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 1, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_increasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_SOFT_LINK_NAME2, + strlen(GET_LINK_NAME_TEST_SOFT_LINK_NAME2) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_increasing); + } + + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 2, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_increasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 2, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_increasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_SOFT_LINK_NAME3, + strlen(GET_LINK_NAME_TEST_SOFT_LINK_NAME3) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_increasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group\n"); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_increasing); + } + + PASSED(); + } + PART_END(H5Lget_name_by_idx_soft_name_order_increasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_name_by_idx_soft_name_order_decreasing) + { + TESTING_2("H5Lget_name_by_idx on soft link by alphabetical order in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Create group to hold some links */ + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_NAME_TEST_SOFT_SUBGROUP_NAME4, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + GET_LINK_NAME_TEST_SOFT_SUBGROUP_NAME4); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_decreasing); + } + + /* Create several soft links */ + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" GET_LINK_NAME_TEST_GROUP_NAME, subgroup_id, + GET_LINK_NAME_TEST_SOFT_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create soft link '%s'\n", GET_LINK_NAME_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_decreasing); + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" GET_LINK_NAME_TEST_GROUP_NAME, subgroup_id, + GET_LINK_NAME_TEST_SOFT_LINK_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create soft link '%s'\n", GET_LINK_NAME_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_decreasing); + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" GET_LINK_NAME_TEST_GROUP_NAME, subgroup_id, + GET_LINK_NAME_TEST_SOFT_LINK_NAME3, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create soft link '%s'\n", GET_LINK_NAME_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_decreasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + GET_LINK_NAME_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_SOFT_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + GET_LINK_NAME_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_SOFT_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if soft link '%s' exists\n", + GET_LINK_NAME_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" soft link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_decreasing); + } + + /* Retrieve link names */ + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 0, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_decreasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 0, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_decreasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_SOFT_LINK_NAME3, + strlen(GET_LINK_NAME_TEST_SOFT_LINK_NAME3) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_SOFT_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_decreasing); + } + + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 1, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_decreasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 1, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_decreasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_SOFT_LINK_NAME2, + strlen(GET_LINK_NAME_TEST_SOFT_LINK_NAME2) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_SOFT_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_decreasing); + } + + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 2, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_decreasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 2, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_decreasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_SOFT_LINK_NAME, + strlen(GET_LINK_NAME_TEST_SOFT_LINK_NAME) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_decreasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group\n"); + PART_ERROR(H5Lget_name_by_idx_soft_name_order_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lget_name_by_idx_soft_name_order_decreasing); +#endif + } + PART_END(H5Lget_name_by_idx_soft_name_order_decreasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_name_by_idx_external_crt_order_increasing) + { + TESTING_2("H5Lget_name_by_idx on external link by creation order in increasing order"); +#ifndef NO_EXTERNAL_LINKS + /* Create file for external link to reference */ + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME); + + if ((ext_file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_increasing); + } + + if (H5Fclose(ext_file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close file '%s'\n", ext_link_filename); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_increasing); + } + + /* Create group to hold some links */ + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_NAME_TEST_EXTERNAL_SUBGROUP_NAME, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + GET_LINK_NAME_TEST_EXTERNAL_SUBGROUP_NAME); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_increasing); + } + + /* Create several external links in reverse order to test creation order */ + if (H5Lcreate_external(ext_link_filename, "/", subgroup_id, + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create external link '%s'\n", GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_increasing); + } + + if (H5Lcreate_external(ext_link_filename, "/", subgroup_id, + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create external link '%s'\n", GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_increasing); + } + + if (H5Lcreate_external(ext_link_filename, "/", subgroup_id, GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create external link '%s'\n", GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_increasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_increasing); + } + + /* Retrieve link names */ + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_increasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 0, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_increasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3, + strlen(GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_increasing); + } + + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 1, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_increasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 1, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_increasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2, + strlen(GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_increasing); + } + + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 2, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_increasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 2, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_increasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME, + strlen(GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_increasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group\n"); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_increasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lget_name_by_idx_external_crt_order_increasing); +#endif + } + PART_END(H5Lget_name_by_idx_external_crt_order_increasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + H5Fclose(ext_file_id); + ext_file_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_name_by_idx_external_crt_order_decreasing) + { + TESTING_2("H5Lget_name_by_idx on external link by creation order in decreasing order"); +#ifndef NO_EXTERNAL_LINKS + /* Create file for external link to reference */ + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME); + + if ((ext_file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_decreasing); + } + + if (H5Fclose(ext_file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close file '%s'\n", ext_link_filename); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_decreasing); + } + + /* Create group to hold some links */ + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_NAME_TEST_EXTERNAL_SUBGROUP_NAME2, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + GET_LINK_NAME_TEST_EXTERNAL_SUBGROUP_NAME2); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_decreasing); + } + + /* Create several external links in reverse order to test creation order */ + if (H5Lcreate_external(ext_link_filename, "/", subgroup_id, + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create external link '%s'\n", GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_decreasing); + } + + if (H5Lcreate_external(ext_link_filename, "/", subgroup_id, + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create external link '%s'\n", GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_decreasing); + } + + if (H5Lcreate_external(ext_link_filename, "/", subgroup_id, GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create external link '%s'\n", GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_decreasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_decreasing); + } + + /* Retrieve link names */ + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 0, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_decreasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 0, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_decreasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME, + strlen(GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_decreasing); + } + + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 1, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_decreasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 1, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_decreasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2, + strlen(GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_decreasing); + } + + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 2, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_decreasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, 2, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_decreasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3, + strlen(GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_decreasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group\n"); + PART_ERROR(H5Lget_name_by_idx_external_crt_order_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lget_name_by_idx_external_crt_order_decreasing); +#endif + } + PART_END(H5Lget_name_by_idx_external_crt_order_decreasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + H5Fclose(ext_file_id); + ext_file_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_name_by_idx_external_name_order_increasing) + { + TESTING_2("H5Lget_name_by_idx on external link by alphabetical order in increasing order"); +#ifndef NO_EXTERNAL_LINKS + /* Create file for external link to reference */ + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME); + + if ((ext_file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + PART_ERROR(H5Lget_name_by_idx_external_name_order_increasing); + } + + if (H5Fclose(ext_file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close file '%s'\n", ext_link_filename); + PART_ERROR(H5Lget_name_by_idx_external_name_order_increasing); + } + + /* Create group to hold some links */ + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_NAME_TEST_EXTERNAL_SUBGROUP_NAME3, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + GET_LINK_NAME_TEST_EXTERNAL_SUBGROUP_NAME3); + PART_ERROR(H5Lget_name_by_idx_external_name_order_increasing); + } + + /* Create several external links */ + if (H5Lcreate_external(ext_link_filename, "/", subgroup_id, GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create external link '%s'\n", GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_external_name_order_increasing); + } + + if (H5Lcreate_external(ext_link_filename, "/", subgroup_id, + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create external link '%s'\n", GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_external_name_order_increasing); + } + + if (H5Lcreate_external(ext_link_filename, "/", subgroup_id, + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create external link '%s'\n", GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_external_name_order_increasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_external_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_external_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_external_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_external_name_order_increasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_external_name_order_increasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_external_name_order_increasing); + } + + /* Retrieve link names */ + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_external_name_order_increasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_external_name_order_increasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME, + strlen(GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_external_name_order_increasing); + } + + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 1, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_external_name_order_increasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 1, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_external_name_order_increasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2, + strlen(GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_external_name_order_increasing); + } + + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 2, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_external_name_order_increasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, 2, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_external_name_order_increasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3, + strlen(GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_external_name_order_increasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group\n"); + PART_ERROR(H5Lget_name_by_idx_external_name_order_increasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lget_name_by_idx_external_name_order_increasing); +#endif + } + PART_END(H5Lget_name_by_idx_external_name_order_increasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + H5Fclose(ext_file_id); + ext_file_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_name_by_idx_external_name_order_decreasing) + { + TESTING_2("H5Lget_name_by_idx on external link by alphabetical order in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Create file for external link to reference */ + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", + EXTERNAL_LINK_TEST_FILE_NAME); + + if ((ext_file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + PART_ERROR(H5Lget_name_by_idx_external_name_order_decreasing); + } + + if (H5Fclose(ext_file_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close file '%s'\n", ext_link_filename); + PART_ERROR(H5Lget_name_by_idx_external_name_order_decreasing); + } + + /* Create group to hold some links */ + if ((subgroup_id = H5Gcreate2(group_id, GET_LINK_NAME_TEST_EXTERNAL_SUBGROUP_NAME4, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + GET_LINK_NAME_TEST_EXTERNAL_SUBGROUP_NAME4); + PART_ERROR(H5Lget_name_by_idx_external_name_order_decreasing); + } + + /* Create several external links */ + if (H5Lcreate_external(ext_link_filename, "/", subgroup_id, GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create external link '%s'\n", GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_external_name_order_decreasing); + } + + if (H5Lcreate_external(ext_link_filename, "/", subgroup_id, + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create external link '%s'\n", GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_external_name_order_decreasing); + } + + if (H5Lcreate_external(ext_link_filename, "/", subgroup_id, + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create external link '%s'\n", GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_external_name_order_decreasing); + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_external_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_external_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_external_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_external_name_order_decreasing); + } + + if ((link_exists = H5Lexists(subgroup_id, GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if external link '%s' exists\n", + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_external_name_order_decreasing); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" external link '%s' did not exist before name retrieval\n", + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_external_name_order_decreasing); + } + + /* Retrieve link names */ + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 0, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_external_name_order_decreasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 0, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_external_name_order_decreasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3, + strlen(GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3); + PART_ERROR(H5Lget_name_by_idx_external_name_order_decreasing); + } + + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 1, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_external_name_order_decreasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 1, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_external_name_order_decreasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2, + strlen(GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2); + PART_ERROR(H5Lget_name_by_idx_external_name_order_decreasing); + } + + if ((link_name_buf_size = H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 2, + NULL, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + PART_ERROR(H5Lget_name_by_idx_external_name_order_decreasing); + } + + if (H5Lget_name_by_idx(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, 2, link_name_buf, + (size_t)link_name_buf_size + 1, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name\n"); + PART_ERROR(H5Lget_name_by_idx_external_name_order_decreasing); + } + + if (HDstrncmp(link_name_buf, GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME, + strlen(GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME) + 1)) { + H5_FAILED(); + HDprintf(" link name '%s' did not match expected name '%s'\n", link_name_buf, + GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME); + PART_ERROR(H5Lget_name_by_idx_external_name_order_decreasing); + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group\n"); + PART_ERROR(H5Lget_name_by_idx_external_name_order_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lget_name_by_idx_external_name_order_decreasing); +#endif + } + PART_END(H5Lget_name_by_idx_external_name_order_decreasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + H5Fclose(ext_file_id); + ext_file_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_name_by_idx_ud_crt_order_increasing) + { + TESTING_2("H5Lget_name_by_idx on user-defined link by creation order in increasing order"); + + /* TODO */ + + SKIPPED(); + PART_EMPTY(H5Lget_name_by_idx_ud_crt_order_increasing); + } + PART_END(H5Lget_name_by_idx_ud_crt_order_increasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_name_by_idx_ud_crt_order_decreasing) + { + TESTING_2("H5Lget_name_by_idx on user-defined link by creation order in decreasing order"); + + /* TODO */ + + SKIPPED(); + PART_EMPTY(H5Lget_name_by_idx_ud_crt_order_decreasing); + } + PART_END(H5Lget_name_by_idx_ud_crt_order_decreasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_name_by_idx_ud_name_order_increasing) + { + TESTING_2("H5Lget_name_by_idx on user-defined link by alphabetical order in increasing order"); + + /* TODO */ + + SKIPPED(); + PART_EMPTY(H5Lget_name_by_idx_ud_name_order_increasing); + } + PART_END(H5Lget_name_by_idx_ud_name_order_increasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + + PART_BEGIN(H5Lget_name_by_idx_ud_name_order_decreasing) + { + TESTING_2("H5Lget_name_by_idx on user-defined link by alphabetical order in decreasing order"); + + /* TODO */ + + SKIPPED(); + PART_EMPTY(H5Lget_name_by_idx_ud_name_order_decreasing); + } + PART_END(H5Lget_name_by_idx_ud_name_order_decreasing); + + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + subgroup_id = H5I_INVALID_HID; + } + H5E_END_TRY; + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(gcpl_id); + H5Gclose(subgroup_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(ext_file_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a link's name can't be retrieved + * when H5Lget_name_by_idx is passed invalid parameters. + */ +static int +test_get_link_name_invalid_params(void) +{ + ssize_t ret; + htri_t link_exists; + size_t link_name_buf_size = 0; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + char *link_name_buf = NULL; + + TESTING_MULTIPART("link name retrieval with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_HARD_LINKS) || !(vol_cap_flags_g & H5VL_CAP_FLAG_EXTERNAL_LINKS) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_SOFT_LINKS) || !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, basic, more, soft, hard, external link, or " + "creation order aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, GET_LINK_NAME_INVALID_PARAMS_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + GET_LINK_NAME_INVALID_PARAMS_TEST_GROUP_NAME); + goto error; + } + + if (H5Lcreate_hard(group_id, ".", group_id, GET_LINK_NAME_INVALID_PARAMS_TEST_HARD_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create hard link '%s'\n", GET_LINK_NAME_INVALID_PARAMS_TEST_HARD_LINK_NAME); + goto error; + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(group_id, GET_LINK_NAME_INVALID_PARAMS_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link exists\n"); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link did not exist\n"); + goto error; + } + + if ((ret = H5Lget_name_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, NULL, link_name_buf_size, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve link name size\n"); + goto error; + } + + link_name_buf_size = (size_t)ret; + if (NULL == (link_name_buf = (char *)HDmalloc(link_name_buf_size + 1))) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Lget_name_by_idx_invalid_loc_id) + { + TESTING_2("H5Lget_name_by_idx with an invalid location ID"); + + H5E_BEGIN_TRY + { + ret = H5Lget_name_by_idx(H5I_INVALID_HID, ".", H5_INDEX_NAME, H5_ITER_INC, 0, link_name_buf, + link_name_buf_size + 1, H5P_DEFAULT); + } + H5E_END_TRY; + + if (ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lget_name_by_idx succeeded with an invalid location ID!\n"); + PART_ERROR(H5Lget_name_by_idx_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Lget_name_by_idx_invalid_loc_id); + + PART_BEGIN(H5Lget_name_by_idx_invalid_grp_name) + { + TESTING_2("H5Lget_name_by_idx with an invalid group name"); + + H5E_BEGIN_TRY + { + ret = H5Lget_name_by_idx(group_id, NULL, H5_INDEX_NAME, H5_ITER_INC, 0, link_name_buf, + link_name_buf_size + 1, H5P_DEFAULT); + } + H5E_END_TRY; + + if (ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lget_name_by_idx succeeded with a NULL group name!\n"); + PART_ERROR(H5Lget_name_by_idx_invalid_grp_name); + } + + H5E_BEGIN_TRY + { + ret = H5Lget_name_by_idx(group_id, "", H5_INDEX_NAME, H5_ITER_INC, 0, link_name_buf, + link_name_buf_size + 1, H5P_DEFAULT); + } + H5E_END_TRY; + + if (ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lget_name_by_idx succeeded with an invalid group name of ''!\n"); + PART_ERROR(H5Lget_name_by_idx_invalid_grp_name); + } + + PASSED(); + } + PART_END(H5Lget_name_by_idx_invalid_grp_name); + + PART_BEGIN(H5Lget_name_by_idx_invalid_index_type) + { + TESTING_2("H5Lget_name_by_idx with an invalid index type"); + + H5E_BEGIN_TRY + { + ret = H5Lget_name_by_idx(group_id, ".", H5_INDEX_UNKNOWN, H5_ITER_INC, 0, link_name_buf, + link_name_buf_size + 1, H5P_DEFAULT); + } + H5E_END_TRY; + + if (ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lget_name_by_idx succeeded with invalid index type H5_INDEX_UNKNOWN!\n"); + PART_ERROR(H5Lget_name_by_idx_invalid_index_type); + } + + H5E_BEGIN_TRY + { + ret = H5Lget_name_by_idx(group_id, ".", H5_INDEX_N, H5_ITER_INC, 0, link_name_buf, + link_name_buf_size + 1, H5P_DEFAULT); + } + H5E_END_TRY; + + if (ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lget_name_by_idx succeeded with invalid index type H5_INDEX_N!\n"); + PART_ERROR(H5Lget_name_by_idx_invalid_index_type); + } + + PASSED(); + } + PART_END(H5Lget_name_by_idx_invalid_index_type); + + PART_BEGIN(H5Lget_name_by_idx_invalid_iter_order) + { + TESTING_2("H5Lget_name_by_idx with an invalid iteration ordering"); + + H5E_BEGIN_TRY + { + ret = H5Lget_name_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_UNKNOWN, 0, link_name_buf, + link_name_buf_size + 1, H5P_DEFAULT); + } + H5E_END_TRY; + + if (ret >= 0) { + H5_FAILED(); + HDprintf( + " H5Lget_name_by_idx succeeded with invalid iteration ordering H5_ITER_UNKNOWN!\n"); + PART_ERROR(H5Lget_name_by_idx_invalid_iter_order); + } + + H5E_BEGIN_TRY + { + ret = H5Lget_name_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_N, 0, link_name_buf, + link_name_buf_size + 1, H5P_DEFAULT); + } + H5E_END_TRY; + + if (ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lget_name_by_idx succeeded with invalid iteration ordering H5_ITER_N!\n"); + PART_ERROR(H5Lget_name_by_idx_invalid_iter_order); + } + + PASSED(); + } + PART_END(H5Lget_name_by_idx_invalid_iter_order); + + PART_BEGIN(H5Lget_name_by_idx_invalid_lapl) + { + TESTING_2("H5Lget_name_by_idx with an invalid LAPL"); + + H5E_BEGIN_TRY + { + ret = H5Lget_name_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, 0, link_name_buf, + link_name_buf_size + 1, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lget_name_by_idx succeeded with an invalid LAPL!\n"); + PART_ERROR(H5Lget_name_by_idx_invalid_lapl); + } + + PASSED(); + } + PART_END(H5Lget_name_by_idx_invalid_lapl); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (link_name_buf) { + HDfree(link_name_buf); + link_name_buf = NULL; + } + + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (link_name_buf) + HDfree(link_name_buf); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check the functionality of link + * iteration using H5Literate(_by_name)2 with + * only hard links. Iteration is done in + * increasing and decreasing order of both link + * name and link creation order. + */ +static int +test_link_iterate_hard_links(void) +{ + size_t i; + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t dset_dspace = H5I_INVALID_HID; + + TESTING_MULTIPART("link iteration (only hard links)"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ITERATE) || !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, link, or iterate aren't supported with " + "this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create GCPL for link creation order tracking\n"); + goto error; + } + + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED) < 0) { + H5_FAILED(); + HDprintf(" couldn't set link creation order tracking\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, LINK_ITER_HARD_LINKS_TEST_SUBGROUP_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", LINK_ITER_HARD_LINKS_TEST_SUBGROUP_NAME); + goto error; + } + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + if ((dset_dspace = + generate_random_dataspace(LINK_ITER_HARD_LINKS_TEST_DSET_SPACE_RANK, NULL, NULL, FALSE)) < 0) + TEST_ERROR; + + for (i = 0; i < LINK_ITER_HARD_LINKS_TEST_NUM_LINKS; i++) { + char dset_name[LINK_ITER_HARD_LINKS_TEST_BUF_SIZE]; + + /* Create the datasets with a reverse-ordering naming scheme to test creation order later */ + HDsnprintf(dset_name, LINK_ITER_HARD_LINKS_TEST_BUF_SIZE, LINK_ITER_HARD_LINKS_TEST_LINK_NAME "%d", + (int)(LINK_ITER_HARD_LINKS_TEST_NUM_LINKS - i - 1)); + + if ((dset_id = H5Dcreate2(group_id, dset_name, dset_dtype, dset_dspace, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", dset_name); + goto error; + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(group_id, dset_name, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", dset_name); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", dset_name); + goto error; + } + + if (H5Dclose(dset_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close dataset '%s'\n", dset_name); + goto error; + } + } + + PASSED(); + + BEGIN_MULTIPART + { + /* + * NOTE: A counter is passed to the iteration callback to try to match up the + * expected links with a given step throughout all of the following + * iterations. This is to try and check that the links are indeed being + * returned in the correct order. + */ + + PART_BEGIN(H5Literate_link_name_increasing) + { + TESTING_2("H5Literate2 by link name in increasing order"); + + i = 0; + + /* Test basic link iteration capability using both index types and both index orders */ + if (H5Literate2(group_id, H5_INDEX_NAME, H5_ITER_INC, NULL, link_iter_hard_links_cb, &i) < 0) { + H5_FAILED(); + HDprintf(" H5Literate2 by index type name in increasing order failed\n"); + PART_ERROR(H5Literate_link_name_increasing); + } + + if (i != LINK_ITER_HARD_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_link_name_increasing); + } + + PASSED(); + } + PART_END(H5Literate_link_name_increasing); + + PART_BEGIN(H5Literate_link_name_decreasing) + { + TESTING_2("H5Literate2 by link name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + i = LINK_ITER_HARD_LINKS_TEST_NUM_LINKS; + + if (H5Literate2(group_id, H5_INDEX_NAME, H5_ITER_DEC, NULL, link_iter_hard_links_cb, &i) < 0) { + H5_FAILED(); + HDprintf(" H5Literate2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Literate_link_name_decreasing); + } + + if (i != 2 * LINK_ITER_HARD_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_link_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Literate_link_name_decreasing); +#endif + } + PART_END(H5Literate_link_name_decreasing); + + PART_BEGIN(H5Literate_link_creation_increasing) + { + TESTING_2("H5Literate2 by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 2 * LINK_ITER_HARD_LINKS_TEST_NUM_LINKS; + + if (H5Literate2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_INC, NULL, link_iter_hard_links_cb, &i) < + 0) { + H5_FAILED(); + HDprintf(" H5Literate2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Literate_link_creation_increasing); + } + + if (i != 3 * LINK_ITER_HARD_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_link_creation_increasing); + } + + PASSED(); + } + PART_END(H5Literate_link_creation_increasing); + + PART_BEGIN(H5Literate_link_creation_decreasing) + { + TESTING_2("H5Literate2 by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 3 * LINK_ITER_HARD_LINKS_TEST_NUM_LINKS; + + if (H5Literate2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_DEC, NULL, link_iter_hard_links_cb, &i) < + 0) { + H5_FAILED(); + HDprintf(" H5Literate2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Literate_link_creation_decreasing); + } + + if (i != 4 * LINK_ITER_HARD_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_link_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Literate_link_creation_decreasing); + + PART_BEGIN(H5Literate_by_name_link_name_increasing) + { + TESTING_2("H5Literate_by_name2 by link name in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 0; + + if (H5Literate_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_ITER_HARD_LINKS_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_INC, NULL, link_iter_hard_links_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Literate_by_name2 by index type name in increasing order failed\n"); + PART_ERROR(H5Literate_by_name_link_name_increasing); + } + + if (i != LINK_ITER_HARD_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_by_name_link_name_increasing); + } + + PASSED(); + } + PART_END(H5Literate_by_name_link_name_increasing); + + PART_BEGIN(H5Literate_by_name_link_name_decreasing) + { + TESTING_2("H5Literate_by_name2 by link name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + i = LINK_ITER_HARD_LINKS_TEST_NUM_LINKS; + + if (H5Literate_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_ITER_HARD_LINKS_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_DEC, NULL, link_iter_hard_links_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Literate_by_name2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Literate_by_name_link_name_decreasing); + } + + if (i != 2 * LINK_ITER_HARD_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_by_name_link_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Literate_by_name_link_name_decreasing); +#endif + } + PART_END(H5Literate_by_name_link_name_decreasing); + + PART_BEGIN(H5Literate_by_name_creation_increasing) + { + TESTING_2("H5Literate_by_name2 by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 2 * LINK_ITER_HARD_LINKS_TEST_NUM_LINKS; + + if (H5Literate_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_ITER_HARD_LINKS_TEST_SUBGROUP_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_INC, NULL, link_iter_hard_links_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Literate_by_name2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Literate_by_name_creation_increasing); + } + + if (i != 3 * LINK_ITER_HARD_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_by_name_creation_increasing); + } + + PASSED(); + } + PART_END(H5Literate_by_name_creation_increasing); + + PART_BEGIN(H5Literate_by_name_creation_decreasing) + { + TESTING_2("H5Literate_by_name2 by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 3 * LINK_ITER_HARD_LINKS_TEST_NUM_LINKS; + + if (H5Literate_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_ITER_HARD_LINKS_TEST_SUBGROUP_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_DEC, NULL, link_iter_hard_links_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Literate_by_name2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Literate_by_name_creation_decreasing); + } + + if (i != 4 * LINK_ITER_HARD_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_by_name_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Literate_by_name_creation_decreasing); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(dset_dspace) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(dset_dspace); + H5Tclose(dset_dtype); + H5Dclose(dset_id); + H5Pclose(gcpl_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check the functionality of link + * iteration using H5Literate(_by_name)2 with + * only soft links. Iteration is done in + * increasing and decreasing order of both link + * name and link creation order. + */ +static int +test_link_iterate_soft_links(void) +{ + size_t i; + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + + TESTING_MULTIPART("link iteration (only soft links)"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_SOFT_LINKS) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ITERATE) || !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, link, or iterate aren't supported with this " + "connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create GCPL for link creation order tracking\n"); + goto error; + } + + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED) < 0) { + H5_FAILED(); + HDprintf(" couldn't set link creation order tracking\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, LINK_ITER_SOFT_LINKS_TEST_SUBGROUP_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", LINK_ITER_SOFT_LINKS_TEST_SUBGROUP_NAME); + goto error; + } + + for (i = 0; i < LINK_ITER_SOFT_LINKS_TEST_NUM_LINKS; i++) { + char link_name[LINK_ITER_SOFT_LINKS_TEST_BUF_SIZE]; + char link_target[LINK_ITER_SOFT_LINKS_TEST_BUF_SIZE]; + + /* Create the links with a reverse-ordering naming scheme to test creation order later */ + HDsnprintf(link_name, LINK_ITER_SOFT_LINKS_TEST_BUF_SIZE, LINK_ITER_SOFT_LINKS_TEST_LINK_NAME "%d", + (int)(LINK_ITER_SOFT_LINKS_TEST_NUM_LINKS - i - 1)); + + HDsnprintf(link_target, LINK_ITER_SOFT_LINKS_TEST_BUF_SIZE, "target%d", + (int)(LINK_ITER_SOFT_LINKS_TEST_NUM_LINKS - i - 1)); + + if (H5Lcreate_soft(link_target, group_id, link_name, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", link_name); + goto error; + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(group_id, link_name, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", link_name); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", link_name); + goto error; + } + } + + PASSED(); + + BEGIN_MULTIPART + { + /* + * NOTE: A counter is passed to the iteration callback to try to match up the + * expected links with a given step throughout all of the following + * iterations. This is to try and check that the links are indeed being + * returned in the correct order. + */ + + PART_BEGIN(H5Literate_link_name_increasing) + { + TESTING_2("H5Literate2 by link name in increasing order"); + + i = 0; + + /* Test basic link iteration capability using both index types and both index orders */ + if (H5Literate2(group_id, H5_INDEX_NAME, H5_ITER_INC, NULL, link_iter_soft_links_cb, &i) < 0) { + H5_FAILED(); + HDprintf(" H5Literate2 by index type name in increasing order failed\n"); + PART_ERROR(H5Literate_link_name_increasing); + } + + if (i != LINK_ITER_SOFT_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_link_name_increasing); + } + + PASSED(); + } + PART_END(H5Literate_link_name_increasing); + + PART_BEGIN(H5Literate_link_name_decreasing) + { + TESTING_2("H5Literate2 by link name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + i = LINK_ITER_SOFT_LINKS_TEST_NUM_LINKS; + + if (H5Literate2(group_id, H5_INDEX_NAME, H5_ITER_DEC, NULL, link_iter_soft_links_cb, &i) < 0) { + H5_FAILED(); + HDprintf(" H5Literate2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Literate_link_name_decreasing); + } + + if (i != 2 * LINK_ITER_SOFT_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_link_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Literate_link_name_decreasing); +#endif + } + PART_END(H5Literate_link_name_decreasing); + + PART_BEGIN(H5Literate_link_creation_increasing) + { + TESTING_2("H5Literate2 by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 2 * LINK_ITER_SOFT_LINKS_TEST_NUM_LINKS; + + if (H5Literate2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_INC, NULL, link_iter_soft_links_cb, &i) < + 0) { + H5_FAILED(); + HDprintf(" H5Literate2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Literate_link_creation_increasing); + } + + if (i != 3 * LINK_ITER_SOFT_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_link_creation_increasing); + } + + PASSED(); + } + PART_END(H5Literate_link_creation_increasing); + + PART_BEGIN(H5Literate_link_creation_decreasing) + { + TESTING_2("H5Literate2 by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 3 * LINK_ITER_SOFT_LINKS_TEST_NUM_LINKS; + + if (H5Literate2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_DEC, NULL, link_iter_soft_links_cb, &i) < + 0) { + H5_FAILED(); + HDprintf(" H5Literate2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Literate_link_creation_decreasing); + } + + if (i != 4 * LINK_ITER_SOFT_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_link_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Literate_link_creation_decreasing); + + PART_BEGIN(H5Literate_by_name_link_name_increasing) + { + TESTING_2("H5Literate_by_name2 by link name in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 0; + + if (H5Literate_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_ITER_SOFT_LINKS_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_INC, NULL, link_iter_soft_links_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Literate_by_name2 by index type name in increasing order failed\n"); + PART_ERROR(H5Literate_by_name_link_name_increasing); + } + + if (i != LINK_ITER_SOFT_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_by_name_link_name_increasing); + } + + PASSED(); + } + PART_END(H5Literate_by_name_link_name_increasing); + + PART_BEGIN(H5Literate_by_name_link_name_decreasing) + { + TESTING_2("H5Literate_by_name2 by link name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + i = LINK_ITER_SOFT_LINKS_TEST_NUM_LINKS; + + if (H5Literate_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_ITER_SOFT_LINKS_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_DEC, NULL, link_iter_soft_links_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Literate_by_name2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Literate_by_name_link_name_decreasing); + } + + if (i != 2 * LINK_ITER_SOFT_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_by_name_link_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Literate_by_name_link_name_decreasing); +#endif + } + PART_END(H5Literate_by_name_link_name_decreasing); + + PART_BEGIN(H5Literate_by_name_creation_increasing) + { + TESTING_2("H5Literate_by_name2 by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 2 * LINK_ITER_SOFT_LINKS_TEST_NUM_LINKS; + + if (H5Literate_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_ITER_SOFT_LINKS_TEST_SUBGROUP_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_INC, NULL, link_iter_soft_links_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Literate_by_name2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Literate_by_name_creation_increasing); + } + + if (i != 3 * LINK_ITER_SOFT_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_by_name_creation_increasing); + } + + PASSED(); + } + PART_END(H5Literate_by_name_creation_increasing); + + PART_BEGIN(H5Literate_by_name_creation_decreasing) + { + TESTING_2("H5Literate_by_name2 by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 3 * LINK_ITER_SOFT_LINKS_TEST_NUM_LINKS; + + if (H5Literate_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_ITER_SOFT_LINKS_TEST_SUBGROUP_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_DEC, NULL, link_iter_soft_links_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Literate_by_name2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Literate_by_name_creation_decreasing); + } + + if (i != 4 * LINK_ITER_SOFT_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_by_name_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Literate_by_name_creation_decreasing); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(gcpl_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check the functionality of link + * iteration using H5Literate(_by_name)2 with + * only external links. Iteration is done in + * increasing and decreasing order of both link + * name and link creation order. + */ +static int +test_link_iterate_external_links(void) +{ +#ifndef NO_EXTERNAL_LINKS + size_t i; + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + char ext_link_filename[H5_API_TEST_FILENAME_MAX_LENGTH]; +#endif + + TESTING_MULTIPART("link iteration (only external links)"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_EXTERNAL_LINKS) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ITERATE) || !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, link, or iterate aren't supported with this " + "connector\n"); + return 0; + } + +#ifndef NO_EXTERNAL_LINKS + TESTING_2("test setup"); + + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", EXTERNAL_LINK_TEST_FILE_NAME); + + if ((file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + goto error; + } + + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create GCPL for link creation order tracking\n"); + goto error; + } + + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED) < 0) { + H5_FAILED(); + HDprintf(" couldn't set link creation order tracking\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, LINK_ITER_EXT_LINKS_TEST_SUBGROUP_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", LINK_ITER_EXT_LINKS_TEST_SUBGROUP_NAME); + goto error; + } + + for (i = 0; i < LINK_ITER_EXT_LINKS_TEST_NUM_LINKS; i++) { + char link_name[LINK_ITER_EXT_LINKS_TEST_BUF_SIZE]; + + /* Create the links with a reverse-ordering naming scheme to test creation order later */ + HDsnprintf(link_name, LINK_ITER_EXT_LINKS_TEST_BUF_SIZE, LINK_ITER_EXT_LINKS_TEST_LINK_NAME "%d", + (int)(LINK_ITER_EXT_LINKS_TEST_NUM_LINKS - i - 1)); + + if (H5Lcreate_external(ext_link_filename, "/", group_id, link_name, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", link_name); + goto error; + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(group_id, link_name, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", link_name); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", link_name); + goto error; + } + } + + PASSED(); + + BEGIN_MULTIPART + { + /* + * NOTE: A counter is passed to the iteration callback to try to match up the + * expected links with a given step throughout all of the following + * iterations. This is to try and check that the links are indeed being + * returned in the correct order. + */ + + PART_BEGIN(H5Literate_link_name_increasing) + { + TESTING_2("H5Literate2 by link name in increasing order"); + + i = 0; + + /* Test basic link iteration capability using both index types and both index orders */ + if (H5Literate2(group_id, H5_INDEX_NAME, H5_ITER_INC, NULL, link_iter_external_links_cb, &i) < + 0) { + H5_FAILED(); + HDprintf(" H5Literate2 by index type name in increasing order failed\n"); + PART_ERROR(H5Literate_link_name_increasing); + } + + if (i != LINK_ITER_EXT_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_link_name_increasing); + } + + PASSED(); + } + PART_END(H5Literate_link_name_increasing); + + PART_BEGIN(H5Literate_link_name_decreasing) + { + TESTING_2("H5Literate2 by link name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + i = LINK_ITER_EXT_LINKS_TEST_NUM_LINKS; + + if (H5Literate2(group_id, H5_INDEX_NAME, H5_ITER_DEC, NULL, link_iter_external_links_cb, &i) < + 0) { + H5_FAILED(); + HDprintf(" H5Literate2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Literate_link_name_decreasing); + } + + if (i != 2 * LINK_ITER_EXT_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_link_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Literate_link_name_decreasing); +#endif + } + PART_END(H5Literate_link_name_decreasing); + + PART_BEGIN(H5Literate_link_creation_increasing) + { + TESTING_2("H5Literate2 by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 2 * LINK_ITER_EXT_LINKS_TEST_NUM_LINKS; + + if (H5Literate2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_INC, NULL, link_iter_external_links_cb, + &i) < 0) { + H5_FAILED(); + HDprintf(" H5Literate2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Literate_link_creation_increasing); + } + + if (i != 3 * LINK_ITER_EXT_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_link_creation_increasing); + } + + PASSED(); + } + PART_END(H5Literate_link_creation_increasing); + + PART_BEGIN(H5Literate_link_creation_decreasing) + { + TESTING_2("H5Literate2 by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 3 * LINK_ITER_EXT_LINKS_TEST_NUM_LINKS; + + if (H5Literate2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_DEC, NULL, link_iter_external_links_cb, + &i) < 0) { + H5_FAILED(); + HDprintf(" H5Literate2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Literate_link_creation_decreasing); + } + + if (i != 4 * LINK_ITER_EXT_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_link_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Literate_link_creation_decreasing); + + PART_BEGIN(H5Literate_by_name_link_name_increasing) + { + TESTING_2("H5Literate_by_name2 by link name in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 0; + + if (H5Literate_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_ITER_EXT_LINKS_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_INC, NULL, link_iter_external_links_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Literate_by_name2 by index type name in increasing order failed\n"); + PART_ERROR(H5Literate_by_name_link_name_increasing); + } + + if (i != LINK_ITER_EXT_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_by_name_link_name_increasing); + } + + PASSED(); + } + PART_END(H5Literate_by_name_link_name_increasing); + + PART_BEGIN(H5Literate_by_name_link_name_decreasing) + { + TESTING_2("H5Literate_by_name2 by link name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + i = LINK_ITER_EXT_LINKS_TEST_NUM_LINKS; + + if (H5Literate_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_ITER_EXT_LINKS_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_DEC, NULL, link_iter_external_links_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Literate_by_name2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Literate_by_name_link_name_decreasing); + } + + if (i != 2 * LINK_ITER_EXT_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_by_name_link_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Literate_by_name_link_name_decreasing); +#endif + } + PART_END(H5Literate_by_name_link_name_decreasing); + + PART_BEGIN(H5Literate_by_name_creation_increasing) + { + TESTING_2("H5Literate_by_name2 by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 2 * LINK_ITER_EXT_LINKS_TEST_NUM_LINKS; + + if (H5Literate_by_name2(file_id, + "/" LINK_TEST_GROUP_NAME "/" LINK_ITER_EXT_LINKS_TEST_SUBGROUP_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_INC, NULL, link_iter_external_links_cb, &i, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Literate_by_name2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Literate_by_name_creation_increasing); + } + + if (i != 3 * LINK_ITER_EXT_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_by_name_creation_increasing); + } + + PASSED(); + } + PART_END(H5Literate_by_name_creation_increasing); + + PART_BEGIN(H5Literate_by_name_creation_decreasing) + { + TESTING_2("H5Literate_by_name2 by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 3 * LINK_ITER_EXT_LINKS_TEST_NUM_LINKS; + + if (H5Literate_by_name2(file_id, + "/" LINK_TEST_GROUP_NAME "/" LINK_ITER_EXT_LINKS_TEST_SUBGROUP_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_DEC, NULL, link_iter_external_links_cb, &i, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Literate_by_name2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Literate_by_name_creation_decreasing); + } + + if (i != 4 * LINK_ITER_EXT_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_by_name_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Literate_by_name_creation_decreasing); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(gcpl_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +#else + SKIPPED(); + return 0; +#endif +} + +/* + * A test to check the functionality of link + * iteration using H5Literate(_by_name)2 with + * only user-defined links. Iteration is done + * in increasing and decreasing order of both + * link name and link creation order. + * + * TODO refactor test so that creation order tests + * actually test the order that objects were created in. + */ +static int +test_link_iterate_ud_links(void) +{ + TESTING("link iteration (only user-defined links)"); + + SKIPPED(); + + return 1; +} + +/* + * A test to check the functionality of link + * iteration using H5Literate(_by_name)2 with + * mixed link types. Iteration is done in + * increasing and decreasing order of both link + * name and link creation order. + * + * TODO refactor test so that creation order tests + * actually test the order that objects were created in. + * + * TODO add UD links + * + * TODO refactor link saving portion into its own test + */ +static int +test_link_iterate_mixed_links(void) +{ +#if !defined(NO_EXTERNAL_LINKS) && !defined(NO_USER_DEFINED_LINKS) + hsize_t saved_idx; + size_t i; + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t dset_dspace = H5I_INVALID_HID; + int halted; + char ext_link_filename[H5_API_TEST_FILENAME_MAX_LENGTH]; +#endif + + TESTING_MULTIPART("link iteration (mixed link types)"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_EXTERNAL_LINKS) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_SOFT_LINKS) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ITERATE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, link, soft or external link, iterate, or creation " + "order aren't supported with this connector\n"); + return 0; + } + +#if !defined(NO_EXTERNAL_LINKS) && !defined(NO_USER_DEFINED_LINKS) + TESTING_2("test setup"); + + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", EXTERNAL_LINK_TEST_FILE_NAME); + + if ((file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + goto error; + } + + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create GCPL for link creation order tracking\n"); + goto error; + } + + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED) < 0) { + H5_FAILED(); + HDprintf(" couldn't set link creation order tracking\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, LINK_ITER_MIXED_LINKS_TEST_SUBGROUP_NAME, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", LINK_ITER_MIXED_LINKS_TEST_SUBGROUP_NAME); + goto error; + } + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + if ((dset_dspace = + generate_random_dataspace(LINK_ITER_MIXED_LINKS_TEST_DSET_SPACE_RANK, NULL, NULL, FALSE)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, LINK_ITER_MIXED_LINKS_TEST_HARD_LINK_NAME, dset_dtype, dset_dspace, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", LINK_ITER_MIXED_LINKS_TEST_HARD_LINK_NAME); + goto error; + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" LINK_ITER_MIXED_LINKS_TEST_SUBGROUP_NAME + "/" LINK_ITER_MIXED_LINKS_TEST_HARD_LINK_NAME, + group_id, LINK_ITER_MIXED_LINKS_TEST_SOFT_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", LINK_ITER_MIXED_LINKS_TEST_SOFT_LINK_NAME); + goto error; + } + + if (H5Lcreate_external(ext_link_filename, "/", group_id, LINK_ITER_MIXED_LINKS_TEST_EXT_LINK_NAME, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", LINK_ITER_MIXED_LINKS_TEST_EXT_LINK_NAME); + goto error; + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(group_id, LINK_ITER_MIXED_LINKS_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", LINK_ITER_MIXED_LINKS_TEST_HARD_LINK_NAME); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" first link did not exist\n"); + goto error; + } + + if ((link_exists = H5Lexists(group_id, LINK_ITER_MIXED_LINKS_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", LINK_ITER_MIXED_LINKS_TEST_SOFT_LINK_NAME); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" second link did not exist\n"); + goto error; + } + + if ((link_exists = H5Lexists(group_id, LINK_ITER_MIXED_LINKS_TEST_EXT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", LINK_ITER_MIXED_LINKS_TEST_EXT_LINK_NAME); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" third link did not exist\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + /* + * NOTE: A counter is passed to the iteration callback to try to match up the + * expected links with a given step throughout all of the following + * iterations. This is to try and check that the links are indeed being + * returned in the correct order. + */ + + PART_BEGIN(H5Literate_link_name_increasing) + { + TESTING_2("H5Literate2 by link name in increasing order"); + + i = 0; + + /* Test basic link iteration capability using both index types and both index orders */ + if (H5Literate2(group_id, H5_INDEX_NAME, H5_ITER_INC, NULL, link_iter_mixed_links_cb, &i) < 0) { + H5_FAILED(); + HDprintf(" H5Literate2 by index type name in increasing order failed\n"); + PART_ERROR(H5Literate_link_name_increasing); + } + + if (i != LINK_ITER_MIXED_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_link_name_increasing); + } + + PASSED(); + } + PART_END(H5Literate_link_name_increasing); + + PART_BEGIN(H5Literate_link_name_decreasing) + { + TESTING_2("H5Literate2 by link name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + i = LINK_ITER_MIXED_LINKS_TEST_NUM_LINKS; + + if (H5Literate2(group_id, H5_INDEX_NAME, H5_ITER_DEC, NULL, link_iter_mixed_links_cb, &i) < 0) { + H5_FAILED(); + HDprintf(" H5Literate2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Literate_link_name_decreasing); + } + + if (i != 2 * LINK_ITER_MIXED_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_link_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Literate_link_name_decreasing); +#endif + } + PART_END(H5Literate_link_name_decreasing); + + PART_BEGIN(H5Literate_link_creation_increasing) + { + TESTING_2("H5Literate2 by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 2 * LINK_ITER_MIXED_LINKS_TEST_NUM_LINKS; + + if (H5Literate2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_INC, NULL, link_iter_mixed_links_cb, &i) < + 0) { + H5_FAILED(); + HDprintf(" H5Literate2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Literate_link_creation_increasing); + } + + if (i != 3 * LINK_ITER_MIXED_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_link_creation_increasing); + } + + PASSED(); + } + PART_END(H5Literate_link_creation_increasing); + + PART_BEGIN(H5Literate_link_creation_decreasing) + { + TESTING_2("H5Literate2 by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 3 * LINK_ITER_MIXED_LINKS_TEST_NUM_LINKS; + + if (H5Literate2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_DEC, NULL, link_iter_mixed_links_cb, &i) < + 0) { + H5_FAILED(); + HDprintf(" H5Literate2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Literate_link_creation_decreasing); + } + + if (i != 4 * LINK_ITER_MIXED_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_link_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Literate_link_creation_decreasing); + + PART_BEGIN(H5Literate_by_name_link_name_increasing) + { + TESTING_2("H5Literate_by_name2 by link name in increasing order"); + + i = 0; + + if (H5Literate_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_ITER_MIXED_LINKS_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_INC, NULL, link_iter_mixed_links_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Literate_by_name2 by index type name in increasing order failed\n"); + PART_ERROR(H5Literate_by_name_link_name_increasing); + } + + if (i != LINK_ITER_MIXED_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_by_name_link_name_increasing); + } + + PASSED(); + } + PART_END(H5Literate_by_name_link_name_increasing); + + PART_BEGIN(H5Literate_by_name_link_name_decreasing) + { + TESTING_2("H5Literate_by_name2 by link name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + i = LINK_ITER_MIXED_LINKS_TEST_NUM_LINKS; + + if (H5Literate_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_ITER_MIXED_LINKS_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_DEC, NULL, link_iter_mixed_links_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Literate_by_name2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Literate_by_name_link_name_decreasing); + } + + if (i != 2 * LINK_ITER_MIXED_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_by_name_link_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Literate_by_name_link_name_decreasing); +#endif + } + PART_END(H5Literate_by_name_link_name_decreasing); + + PART_BEGIN(H5Literate_by_name_creation_increasing) + { + TESTING_2("H5Literate_by_name2 by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 2 * LINK_ITER_MIXED_LINKS_TEST_NUM_LINKS; + + if (H5Literate_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_ITER_MIXED_LINKS_TEST_SUBGROUP_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_INC, NULL, link_iter_mixed_links_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Literate_by_name2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Literate_by_name_creation_increasing); + } + + if (i != 3 * LINK_ITER_MIXED_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_by_name_creation_increasing); + } + + PASSED(); + } + PART_END(H5Literate_by_name_creation_increasing); + + PART_BEGIN(H5Literate_by_name_creation_decreasing) + { + TESTING_2("H5Literate_by_name2 by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 3 * LINK_ITER_MIXED_LINKS_TEST_NUM_LINKS; + + if (H5Literate_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_ITER_MIXED_LINKS_TEST_SUBGROUP_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_DEC, NULL, link_iter_mixed_links_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Literate_by_name2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Literate_by_name_creation_decreasing); + } + + if (i != 4 * LINK_ITER_MIXED_LINKS_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not iterated over!\n"); + PART_ERROR(H5Literate_by_name_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Literate_by_name_creation_decreasing); + + PART_BEGIN(H5Literate_index_saving_increasing) + { + TESTING_2("H5Literate2 index-saving capabilities in increasing order"); + + /* Test the H5Literate2 index-saving capabilities */ + saved_idx = 0; + halted = 0; + + if (H5Literate2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_INC, &saved_idx, link_iter_idx_saving_cb, + &halted) < 0) { + H5_FAILED(); + HDprintf(" H5Literate2 index-saving capability test failed\n"); + PART_ERROR(H5Literate_index_saving_increasing); + } + + if (saved_idx != 2) { + H5_FAILED(); + HDprintf(" saved index after iteration was wrong\n"); + PART_ERROR(H5Literate_index_saving_increasing); + } + + if (H5Literate2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_INC, &saved_idx, link_iter_idx_saving_cb, + &halted) < 0) { + H5_FAILED(); + HDprintf(" couldn't finish iterating when beginning from saved index\n"); + PART_ERROR(H5Literate_index_saving_increasing); + } + + PASSED(); + } + PART_END(H5Literate_index_saving_increasing); + + PART_BEGIN(H5Literate_index_saving_decreasing) + { + TESTING_2("H5Literate2 index-saving capabilities in decreasing order"); + + saved_idx = LINK_ITER_MIXED_LINKS_TEST_NUM_LINKS - 1; + halted = 0; + + if (H5Literate2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_DEC, &saved_idx, link_iter_idx_saving_cb, + &halted) < 0) { + H5_FAILED(); + HDprintf(" H5Literate2 index-saving capability test failed\n"); + PART_ERROR(H5Literate_index_saving_decreasing); + } + + if (saved_idx != 2) { + H5_FAILED(); + HDprintf(" saved index after iteration was wrong\n"); + PART_ERROR(H5Literate_index_saving_decreasing); + } + + if (H5Literate2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_DEC, &saved_idx, link_iter_idx_saving_cb, + &halted) < 0) { + H5_FAILED(); + HDprintf(" couldn't finish iterating when beginning from saved index\n"); + PART_ERROR(H5Literate_index_saving_decreasing); + } + + PASSED(); + } + PART_END(H5Literate_index_saving_decreasing); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(dset_dspace) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(dset_dspace); + H5Tclose(dset_dtype); + H5Dclose(dset_id); + H5Pclose(gcpl_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +#else + SKIPPED(); + return 0; +#endif +} + +/* + * A test to check that H5Literate(_by_name)2 fails + * when given invalid parameters. + */ +static int +test_link_iterate_invalid_params(void) +{ + herr_t err_ret = -1; + size_t i; + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t dset_dspace = H5I_INVALID_HID; + char ext_link_filename[H5_API_TEST_FILENAME_MAX_LENGTH]; + + TESTING_MULTIPART("link iteration with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_EXTERNAL_LINKS) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_SOFT_LINKS) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ITERATE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, link, soft or external link, iterate, or " + "creation order aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", EXTERNAL_LINK_TEST_FILE_NAME); + + if ((file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + goto error; + } + + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create GCPL for link creation order tracking\n"); + goto error; + } + + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED) < 0) { + H5_FAILED(); + HDprintf(" couldn't set link creation order tracking\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, LINK_ITER_INVALID_PARAMS_TEST_SUBGROUP_NAME, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + LINK_ITER_INVALID_PARAMS_TEST_SUBGROUP_NAME); + goto error; + } + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + if ((dset_dspace = + generate_random_dataspace(LINK_ITER_INVALID_PARAMS_TEST_DSET_SPACE_RANK, NULL, NULL, FALSE)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, LINK_ITER_INVALID_PARAMS_TEST_HARD_LINK_NAME, dset_dtype, dset_dspace, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", LINK_ITER_INVALID_PARAMS_TEST_HARD_LINK_NAME); + goto error; + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" LINK_ITER_INVALID_PARAMS_TEST_SUBGROUP_NAME + "/" LINK_ITER_INVALID_PARAMS_TEST_HARD_LINK_NAME, + group_id, LINK_ITER_INVALID_PARAMS_TEST_SOFT_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", LINK_ITER_INVALID_PARAMS_TEST_SOFT_LINK_NAME); + goto error; + } +#ifndef NO_EXTERNAL_LINKS + if (H5Lcreate_external(ext_link_filename, "/", group_id, LINK_ITER_INVALID_PARAMS_TEST_EXT_LINK_NAME, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", LINK_ITER_INVALID_PARAMS_TEST_EXT_LINK_NAME); + goto error; + } +#endif + /* Verify the links have been created */ + if ((link_exists = H5Lexists(group_id, LINK_ITER_INVALID_PARAMS_TEST_HARD_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", + LINK_ITER_INVALID_PARAMS_TEST_HARD_LINK_NAME); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" first link did not exist\n"); + goto error; + } + + if ((link_exists = H5Lexists(group_id, LINK_ITER_INVALID_PARAMS_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", + LINK_ITER_INVALID_PARAMS_TEST_SOFT_LINK_NAME); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" second link did not exist\n"); + goto error; + } +#ifndef NO_EXTERNAL_LINKS + if ((link_exists = H5Lexists(group_id, LINK_ITER_INVALID_PARAMS_TEST_EXT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", LINK_ITER_INVALID_PARAMS_TEST_EXT_LINK_NAME); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" third link did not exist\n"); + goto error; + } +#endif + + PASSED(); + + BEGIN_MULTIPART + { + i = 0; + + PART_BEGIN(H5Literate_invalid_grp_id) + { + TESTING_2("H5Literate2 with an invalid group ID"); + + H5E_BEGIN_TRY + { + err_ret = H5Literate2(H5I_INVALID_HID, H5_INDEX_NAME, H5_ITER_INC, NULL, + link_iter_invalid_params_cb, NULL); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Literate2 succeeded with an invalid group ID!\n"); + PART_ERROR(H5Literate_invalid_grp_id); + } + + PASSED(); + } + PART_END(H5Literate_invalid_grp_id); + + PART_BEGIN(H5Literate_invalid_index_type) + { + TESTING_2("H5Literate2 with an invalid index type"); + + H5E_BEGIN_TRY + { + err_ret = H5Literate2(group_id, H5_INDEX_UNKNOWN, H5_ITER_INC, NULL, + link_iter_invalid_params_cb, NULL); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Literate2 succeeded with invalid index type H5_INDEX_UNKNOWN!\n"); + PART_ERROR(H5Literate_invalid_index_type); + } + + H5E_BEGIN_TRY + { + err_ret = + H5Literate2(group_id, H5_INDEX_N, H5_ITER_INC, NULL, link_iter_invalid_params_cb, NULL); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Literate2 succeeded with invalid index type H5_INDEX_N!\n"); + PART_ERROR(H5Literate_invalid_index_type); + } + + PASSED(); + } + PART_END(H5Literate_invalid_index_type); + + PART_BEGIN(H5Literate_invalid_iter_order) + { + TESTING_2("H5Literate2 with an invalid iteration ordering"); + + H5E_BEGIN_TRY + { + err_ret = H5Literate2(group_id, H5_INDEX_NAME, H5_ITER_UNKNOWN, NULL, + link_iter_invalid_params_cb, NULL); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Literate2 succeeded with invalid iteration ordering H5_ITER_UNKNOWN!\n"); + PART_ERROR(H5Literate_invalid_iter_order); + } + + H5E_BEGIN_TRY + { + err_ret = + H5Literate2(group_id, H5_INDEX_NAME, H5_ITER_N, NULL, link_iter_invalid_params_cb, NULL); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Literate2 succeeded with invalid iteration ordering H5_ITER_N!\n"); + PART_ERROR(H5Literate_invalid_iter_order); + } + + PASSED(); + } + PART_END(H5Literate_invalid_iter_order); + + PART_BEGIN(H5Literate_by_name_invalid_loc_id) + { + TESTING_2("H5Literate_by_name2 with an invalid location ID"); + + H5E_BEGIN_TRY + { + err_ret = H5Literate_by_name2( + H5I_INVALID_HID, "/" LINK_TEST_GROUP_NAME "/" LINK_ITER_INVALID_PARAMS_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_INC, NULL, link_iter_invalid_params_cb, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Literate_by_name2 succeeded with an invalid location ID!\n"); + PART_ERROR(H5Literate_by_name_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Literate_by_name_invalid_loc_id); + + PART_BEGIN(H5Literate_by_name_invalid_grp_name) + { + TESTING_2("H5Literate_by_name2 with an invalid group name"); + + H5E_BEGIN_TRY + { + err_ret = H5Literate_by_name2(file_id, NULL, H5_INDEX_NAME, H5_ITER_INC, NULL, + link_iter_invalid_params_cb, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Literate_by_name2 succeeded with a NULL group name!\n"); + PART_ERROR(H5Literate_by_name_invalid_grp_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Literate_by_name2(file_id, "", H5_INDEX_NAME, H5_ITER_INC, NULL, + link_iter_invalid_params_cb, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Literate_by_name2 succeeded with an invalid group name of ''!\n"); + PART_ERROR(H5Literate_by_name_invalid_grp_name); + } + + PASSED(); + } + PART_END(H5Literate_by_name_invalid_grp_name); + + PART_BEGIN(H5Literate_by_name_invalid_index_type) + { + TESTING_2("H5Literate_by_name2 with an invalid index type"); + + H5E_BEGIN_TRY + { + err_ret = H5Literate_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_ITER_INVALID_PARAMS_TEST_SUBGROUP_NAME, + H5_INDEX_UNKNOWN, H5_ITER_INC, NULL, link_iter_invalid_params_cb, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Literate_by_name2 succeeded with invalid index type H5_INDEX_UNKNOWN!\n"); + PART_ERROR(H5Literate_by_name_invalid_index_type); + } + + H5E_BEGIN_TRY + { + err_ret = H5Literate_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_ITER_INVALID_PARAMS_TEST_SUBGROUP_NAME, + H5_INDEX_N, H5_ITER_INC, NULL, link_iter_invalid_params_cb, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Literate_by_name2 succeeded with invalid index type H5_INDEX_N!\n"); + PART_ERROR(H5Literate_by_name_invalid_index_type); + } + + PASSED(); + } + PART_END(H5Literate_by_name_invalid_index_type); + + PART_BEGIN(H5Literate_by_name_invalid_iter_order) + { + TESTING_2("H5Literate_by_name2 with an invalid iteration ordering"); + + H5E_BEGIN_TRY + { + err_ret = H5Literate_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_ITER_INVALID_PARAMS_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_UNKNOWN, NULL, link_iter_invalid_params_cb, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf( + " H5Literate_by_name2 succeeded with invalid iteration ordering H5_ITER_UNKNOWN!\n"); + PART_ERROR(H5Literate_by_name_invalid_iter_order); + } + + H5E_BEGIN_TRY + { + err_ret = H5Literate_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_ITER_INVALID_PARAMS_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_N, NULL, link_iter_invalid_params_cb, &i, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Literate_by_name2 succeeded with invalid iteration ordering H5_ITER_N!\n"); + PART_ERROR(H5Literate_by_name_invalid_iter_order); + } + + PASSED(); + } + PART_END(H5Literate_by_name_invalid_iter_order); + + PART_BEGIN(H5Literate_by_name_invalid_lapl) + { + TESTING_2("H5Literate_by_name2 with an invalid LAPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Literate_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_ITER_INVALID_PARAMS_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_INC, NULL, link_iter_invalid_params_cb, NULL, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Literate_by_name2 succeeded with an invalid LAPL!\n"); + PART_ERROR(H5Literate_by_name_invalid_lapl); + } + + PASSED(); + } + PART_END(H5Literate_by_name_invalid_lapl); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(dset_dspace) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(dset_dspace); + H5Tclose(dset_dtype); + H5Dclose(dset_id); + H5Pclose(gcpl_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that link iteration performed on a + * group with no links in it is not problematic. + */ +static int +test_link_iterate_0_links(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + + TESTING_MULTIPART("link iteration on group with 0 links"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ITERATE) || !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, link iterate, or creation order aren't supported " + "with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create GCPL for link creation order tracking\n"); + goto error; + } + + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED) < 0) { + H5_FAILED(); + HDprintf(" couldn't set link creation order tracking\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, LINK_ITER_0_LINKS_TEST_SUBGROUP_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", LINK_ITER_0_LINKS_TEST_SUBGROUP_NAME); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Literate_0_links_name_increasing) + { + TESTING_2("H5Literate2 by link name in increasing order"); + + /* Test basic link iteration capability using both index types and both index orders */ + if (H5Literate2(group_id, H5_INDEX_NAME, H5_ITER_INC, NULL, link_iter_0_links_cb, NULL) < 0) { + H5_FAILED(); + HDprintf(" H5Literate2 by index type name in increasing order failed\n"); + PART_ERROR(H5Literate_0_links_name_increasing); + } + + PASSED(); + } + PART_END(H5Literate_0_links_name_increasing); + + PART_BEGIN(H5Literate_0_links_name_decreasing) + { + TESTING_2("H5Literate2 by link name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + if (H5Literate2(group_id, H5_INDEX_NAME, H5_ITER_DEC, NULL, link_iter_0_links_cb, NULL) < 0) { + H5_FAILED(); + HDprintf(" H5Literate2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Literate_0_links_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Literate_0_links_name_decreasing); +#endif + } + PART_END(H5Literate_0_links_name_decreasing); + + PART_BEGIN(H5Literate_0_links_creation_increasing) + { + TESTING_2("H5Literate2 by creation order in increasing order"); + + if (H5Literate2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_INC, NULL, link_iter_0_links_cb, NULL) < + 0) { + H5_FAILED(); + HDprintf(" H5Literate2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Literate_0_links_creation_increasing); + } + + PASSED(); + } + PART_END(H5Literate_0_links_creation_increasing); + + PART_BEGIN(H5Literate_0_links_creation_decreasing) + { + TESTING_2("H5Literate2 by creation order in decreasing order"); + + if (H5Literate2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_DEC, NULL, link_iter_0_links_cb, NULL) < + 0) { + H5_FAILED(); + HDprintf(" H5Literate2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Literate_0_links_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Literate_0_links_creation_decreasing); + + PART_BEGIN(H5Literate_by_name_0_links_name_increasing) + { + TESTING_2("H5Literate_by_name2 by link name in increasing order"); + + if (H5Literate_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_ITER_0_LINKS_TEST_SUBGROUP_NAME, H5_INDEX_NAME, + H5_ITER_INC, NULL, link_iter_0_links_cb, NULL, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Literate_by_name2 by index type name in increasing order failed\n"); + PART_ERROR(H5Literate_by_name_0_links_name_increasing); + } + + PASSED(); + } + PART_END(H5Literate_by_name_0_links_name_increasing); + + PART_BEGIN(H5Literate_by_name_0_links_name_decreasing) + { + TESTING_2("H5Literate_by_name2 by link name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + if (H5Literate_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_ITER_0_LINKS_TEST_SUBGROUP_NAME, H5_INDEX_NAME, + H5_ITER_DEC, NULL, link_iter_0_links_cb, NULL, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Literate_by_name2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Literate_by_name_0_links_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Literate_by_name_0_links_name_decreasing); +#endif + } + PART_END(H5Literate_by_name_0_links_name_decreasing); + + PART_BEGIN(H5Literate_by_name_0_links_creation_increasing) + { + TESTING_2("H5Literate_by_name2 by creation order in increasing order"); + + if (H5Literate_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_ITER_0_LINKS_TEST_SUBGROUP_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_INC, NULL, link_iter_0_links_cb, NULL, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Literate_by_name2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Literate_by_name_0_links_creation_increasing); + } + + PASSED(); + } + PART_END(H5Literate_by_name_0_links_creation_increasing); + + PART_BEGIN(H5Literate_by_name_0_links_creation_decreasing) + { + TESTING_2("H5Literate_by_name2 by creation order in decreasing order"); + + if (H5Literate_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_ITER_0_LINKS_TEST_SUBGROUP_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_DEC, NULL, link_iter_0_links_cb, NULL, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Literate_by_name2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Literate_by_name_0_links_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Literate_by_name_0_links_creation_decreasing); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(gcpl_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check the functionality of recursive + * link iteration using H5Lvisit(_by_name)2 with + * only hard links and where there are no cyclic + * links. Iteration is done in increasing and + * decreasing order of both link name and link + * creation order. + */ +static int +test_link_visit_hard_links_no_cycles(void) +{ + size_t i; + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t subgroup_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t dset_dspace = H5I_INVALID_HID; + + TESTING_MULTIPART("link visiting without cycles (only hard links)"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ITERATE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, link iterate, or creation order aren't supported " + "with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create a GCPL\n"); + goto error; + } + + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0) { + H5_FAILED(); + HDprintf(" couldn't enable link creation order tracking and indexing on GCPL\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME, + H5P_DEFAULT, gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME); + goto error; + } + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + if ((dset_dspace = generate_random_dataspace(LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_DSET_SPACE_RANK, NULL, + NULL, FALSE)) < 0) + TEST_ERROR; + + for (i = 0; i < LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_SUBGROUPS; i++) { + size_t j; + char grp_name[LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_BUF_SIZE]; + + /* Create the groups with a reverse-ordering naming scheme to test creation order later */ + HDsnprintf(grp_name, LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NESTED_GRP_NAME "%d", + (int)(LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_SUBGROUPS - i - 1)); + + if ((subgroup_id = H5Gcreate2(group_id, grp_name, H5P_DEFAULT, gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", grp_name); + goto error; + } + + for (j = 0; j < LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_GROUP; j++) { + char dset_name[LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_BUF_SIZE]; + + /* Create the datasets with a reverse-ordering naming scheme to test creation order later */ + HDsnprintf(dset_name, LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_LINK_NAME "%d", + (int)(LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_GROUP - j - 1)); + + if ((dset_id = H5Dcreate2(subgroup_id, dset_name, dset_dtype, dset_dspace, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", dset_name); + goto error; + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(subgroup_id, dset_name, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", dset_name); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", dset_name); + goto error; + } + + if (H5Dclose(dset_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close dataset '%s'\n", dset_name); + goto error; + } + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close subgroup '%s'\n", grp_name); + goto error; + } + } + + PASSED(); + + BEGIN_MULTIPART + { + /* + * NOTE: A counter is passed to the iteration callback to try to match up the + * expected links with a given step throughout all of the following + * iterations. This is to try and check that the links are indeed being + * returned in the correct order. + */ + + PART_BEGIN(H5Lvisit_no_cycles_link_name_increasing) + { + TESTING_2("H5Lvisit2 by link name in increasing order"); + + i = 0; + + if (H5Lvisit2(group_id, H5_INDEX_NAME, H5_ITER_INC, link_visit_hard_links_no_cycles_cb, &i) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type name in increasing order failed\n"); + PART_ERROR(H5Lvisit_no_cycles_link_name_increasing); + } + + if (i != LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_no_cycles_link_name_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_no_cycles_link_name_increasing); + + PART_BEGIN(H5Lvisit_no_cycles_link_name_decreasing) + { + TESTING_2("H5Lvisit2 by link name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + i = LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit2(group_id, H5_INDEX_NAME, H5_ITER_DEC, link_visit_hard_links_no_cycles_cb, &i) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Lvisit_no_cycles_link_name_decreasing); + } + + if (i != 2 * LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_no_cycles_link_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lvisit_no_cycles_link_name_decreasing); +#endif + } + PART_END(H5Lvisit_no_cycles_link_name_decreasing); + + PART_BEGIN(H5Lvisit_no_cycles_link_creation_increasing) + { + TESTING_2("H5Lvisit2 by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 2 * LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_INC, link_visit_hard_links_no_cycles_cb, &i) < + 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Lvisit_no_cycles_link_creation_increasing); + } + + if (i != 3 * LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_no_cycles_link_creation_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_no_cycles_link_creation_increasing); + + PART_BEGIN(H5Lvisit_no_cycles_link_creation_decreasing) + { + TESTING_2("H5Lvisit2 by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 3 * LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_DEC, link_visit_hard_links_no_cycles_cb, &i) < + 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Lvisit_no_cycles_link_creation_decreasing); + } + + if (i != 4 * LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_no_cycles_link_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Lvisit_no_cycles_link_creation_decreasing); + + PART_BEGIN(H5Lvisit_by_name_no_cycles_link_name_increasing) + { + TESTING_2("H5Lvisit_by_name2 by link name in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 0; + + if (H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_INC, link_visit_hard_links_no_cycles_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type name in increasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_name_increasing); + } + + if (i != LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_name_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_no_cycles_link_name_increasing); + + PART_BEGIN(H5Lvisit_by_name_no_cycles_link_name_decreasing) + { + TESTING_2("H5Lvisit_by_name2 by link name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + i = LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_DEC, link_visit_hard_links_no_cycles_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_name_decreasing); + } + + if (i != 2 * LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lvisit_by_name_no_cycles_link_name_decreasing); +#endif + } + PART_END(H5Lvisit_by_name_no_cycles_link_name_decreasing); + + PART_BEGIN(H5Lvisit_by_name_no_cycles_link_creation_increasing) + { + TESTING_2("H5Lvisit_by_name2 by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 2 * LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_INC, link_visit_hard_links_no_cycles_cb, &i, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_creation_increasing); + } + + if (i != 3 * LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_creation_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_no_cycles_link_creation_increasing); + + PART_BEGIN(H5Lvisit_by_name_no_cycles_link_creation_decreasing) + { + TESTING_2("H5Lvisit_by_name2 by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 3 * LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_DEC, link_visit_hard_links_no_cycles_cb, &i, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_creation_decreasing); + } + + if (i != 4 * LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_no_cycles_link_creation_decreasing); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(dset_dspace) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(dset_dspace); + H5Tclose(dset_dtype); + H5Dclose(dset_id); + H5Pclose(gcpl_id); + H5Gclose(subgroup_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check the functionality of recursive + * link iteration using H5Lvisit(_by_name)2 with + * only soft links and where there are no cyclic + * links. Iteration is done in increasing and + * decreasing order of both link name and link + * creation order. + */ +static int +test_link_visit_soft_links_no_cycles(void) +{ + size_t i; + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t subgroup_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + + TESTING_MULTIPART("link visiting without cycles (only soft links)"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_SOFT_LINKS) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ITERATE) || !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, link, soft link, iterate, or creation order " + "aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create a GCPL\n"); + goto error; + } + + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0) { + H5_FAILED(); + HDprintf(" couldn't enable link creation order tracking and indexing on GCPL\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME, + H5P_DEFAULT, gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME); + goto error; + } + + for (i = 0; i < LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_SUBGROUPS; i++) { + size_t j; + char grp_name[LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_BUF_SIZE]; + + /* Create the groups with a reverse-ordering naming scheme to test creation order later */ + HDsnprintf(grp_name, LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NESTED_GRP_NAME "%d", + (int)(LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_SUBGROUPS - i - 1)); + + if ((subgroup_id = H5Gcreate2(group_id, grp_name, H5P_DEFAULT, gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", grp_name); + goto error; + } + + for (j = 0; j < LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_GROUP; j++) { + char link_name[LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_BUF_SIZE]; + char link_target[LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_BUF_SIZE]; + + /* Create the links with a reverse-ordering naming scheme to test creation order later */ + HDsnprintf(link_name, LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_LINK_NAME "%d", + (int)(LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_GROUP - j - 1)); + + HDsnprintf(link_target, LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_BUF_SIZE, "target%d", + (int)(LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_GROUP - j - 1)); + + if (H5Lcreate_soft(link_target, subgroup_id, link_name, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", link_name); + goto error; + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(subgroup_id, link_name, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", link_name); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", link_name); + goto error; + } + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close subgroup '%s'\n", grp_name); + goto error; + } + } + + PASSED(); + + BEGIN_MULTIPART + { + /* + * NOTE: A counter is passed to the iteration callback to try to match up the + * expected links with a given step throughout all of the following + * iterations. This is to try and check that the links are indeed being + * returned in the correct order. + */ + + PART_BEGIN(H5Lvisit_no_cycles_link_name_increasing) + { + TESTING_2("H5Lvisit2 by link name in increasing order"); + + i = 0; + + if (H5Lvisit2(group_id, H5_INDEX_NAME, H5_ITER_INC, link_visit_soft_links_no_cycles_cb, &i) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type name in increasing order failed\n"); + PART_ERROR(H5Lvisit_no_cycles_link_name_increasing); + } + + if (i != LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_no_cycles_link_name_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_no_cycles_link_name_increasing); + + PART_BEGIN(H5Lvisit_no_cycles_link_name_decreasing) + { + TESTING_2("H5Lvisit2 by link name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + i = LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit2(group_id, H5_INDEX_NAME, H5_ITER_DEC, link_visit_soft_links_no_cycles_cb, &i) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Lvisit_no_cycles_link_name_decreasing); + } + + if (i != 2 * LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_no_cycles_link_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lvisit_no_cycles_link_name_decreasing); +#endif + } + PART_END(H5Lvisit_no_cycles_link_name_decreasing); + + PART_BEGIN(H5Lvisit_no_cycles_link_creation_increasing) + { + TESTING_2("H5Lvisit2 by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 2 * LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_INC, link_visit_soft_links_no_cycles_cb, &i) < + 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Lvisit_no_cycles_link_creation_increasing); + } + + if (i != 3 * LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_no_cycles_link_creation_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_no_cycles_link_creation_increasing); + + PART_BEGIN(H5Lvisit_no_cycles_link_creation_decreasing) + { + TESTING_2("H5Lvisit2 by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 3 * LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_DEC, link_visit_soft_links_no_cycles_cb, &i) < + 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Lvisit_no_cycles_link_creation_decreasing); + } + + if (i != 4 * LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_no_cycles_link_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Lvisit_no_cycles_link_creation_decreasing); + + PART_BEGIN(H5Lvisit_by_name_no_cycles_link_name_increasing) + { + TESTING_2("H5Lvisit_by_name2 by link name in increasing order"); + + i = 0; + + if (H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_INC, link_visit_soft_links_no_cycles_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type name in increasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_name_increasing); + } + + if (i != LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_name_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_no_cycles_link_name_increasing); + + PART_BEGIN(H5Lvisit_by_name_no_cycles_link_name_decreasing) + { + TESTING_2("H5Lvisit_by_name2 by link name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + i = LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_DEC, link_visit_soft_links_no_cycles_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_name_decreasing); + } + + if (i != 2 * LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lvisit_by_name_no_cycles_link_name_decreasing); +#endif + } + PART_END(H5Lvisit_by_name_no_cycles_link_name_decreasing); + + PART_BEGIN(H5Lvisit_by_name_no_cycles_link_creation_increasing) + { + TESTING_2("H5Lvisit_by_name2 by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 2 * LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_INC, link_visit_soft_links_no_cycles_cb, &i, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_creation_increasing); + } + + if (i != 3 * LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_creation_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_no_cycles_link_creation_increasing); + + PART_BEGIN(H5Lvisit_by_name_no_cycles_link_creation_decreasing) + { + TESTING_2("H5Lvisit_by_name2 by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 3 * LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_DEC, link_visit_soft_links_no_cycles_cb, &i, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_creation_decreasing); + } + + if (i != 4 * LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_no_cycles_link_creation_decreasing); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(gcpl_id); + H5Gclose(subgroup_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check the functionality of recursive + * link iteration using H5Lvisit(_by_name)2 with + * only external links and where there are no cyclic + * links. Iteration is done in increasing and + * decreasing order of both link name and link + * creation order. + */ +static int +test_link_visit_external_links_no_cycles(void) +{ +#ifndef NO_EXTERNAL_LINKS + size_t i; + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t subgroup_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + char ext_link_filename[H5_API_TEST_FILENAME_MAX_LENGTH]; +#endif + + TESTING_MULTIPART("link visiting without cycles (only external links)"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_EXTERNAL_LINKS) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ITERATE) || !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, link, external link, iterate, or creation order " + "aren't supported with this connector\n"); + return 0; + } + +#ifndef NO_EXTERNAL_LINKS + TESTING_2("test setup"); + + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", EXTERNAL_LINK_TEST_FILE_NAME); + + if ((file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + goto error; + } + + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create a GCPL\n"); + goto error; + } + + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0) { + H5_FAILED(); + HDprintf(" couldn't enable link creation order tracking and indexing on GCPL\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME); + goto error; + } + + for (i = 0; i < LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_SUBGROUPS; i++) { + size_t j; + char grp_name[LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_BUF_SIZE]; + + /* Create the groups with a reverse-ordering naming scheme to test creation order later */ + HDsnprintf(grp_name, LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NESTED_GRP_NAME "%d", + (int)(LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_SUBGROUPS - i - 1)); + + if ((subgroup_id = H5Gcreate2(group_id, grp_name, H5P_DEFAULT, gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", grp_name); + goto error; + } + + for (j = 0; j < LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_GROUP; j++) { + char link_name[LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_BUF_SIZE]; + + /* Create the links with a reverse-ordering naming scheme to test creation order later */ + HDsnprintf(link_name, LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_LINK_NAME "%d", + (int)(LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_GROUP - j - 1)); + + if (H5Lcreate_external(ext_link_filename, "/", subgroup_id, link_name, H5P_DEFAULT, H5P_DEFAULT) < + 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", link_name); + goto error; + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(subgroup_id, link_name, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", link_name); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", link_name); + goto error; + } + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close subgroup '%s'\n", grp_name); + goto error; + } + } + + PASSED(); + + BEGIN_MULTIPART + { + /* + * NOTE: A counter is passed to the iteration callback to try to match up the + * expected links with a given step throughout all of the following + * iterations. This is to try and check that the links are indeed being + * returned in the correct order. + */ + + PART_BEGIN(H5Lvisit_no_cycles_link_name_increasing) + { + TESTING_2("H5Lvisit2 by link name in increasing order"); + + i = 0; + + if (H5Lvisit2(group_id, H5_INDEX_NAME, H5_ITER_INC, link_visit_external_links_no_cycles_cb, &i) < + 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type name in increasing order failed\n"); + PART_ERROR(H5Lvisit_no_cycles_link_name_increasing); + } + + if (i != LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_no_cycles_link_name_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_no_cycles_link_name_increasing); + + PART_BEGIN(H5Lvisit_no_cycles_link_name_decreasing) + { + TESTING_2("H5Lvisit2 by link name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + i = LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit2(group_id, H5_INDEX_NAME, H5_ITER_DEC, link_visit_external_links_no_cycles_cb, &i) < + 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Lvisit_no_cycles_link_name_decreasing); + } + + if (i != 2 * LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_no_cycles_link_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lvisit_no_cycles_link_name_decreasing); +#endif + } + PART_END(H5Lvisit_no_cycles_link_name_decreasing); + + PART_BEGIN(H5Lvisit_no_cycles_link_creation_increasing) + { + TESTING_2("H5Lvisit2 by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 2 * LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_INC, link_visit_external_links_no_cycles_cb, + &i) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Lvisit_no_cycles_link_creation_increasing); + } + + if (i != 3 * LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_no_cycles_link_creation_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_no_cycles_link_creation_increasing); + + PART_BEGIN(H5Lvisit_no_cycles_link_creation_decreasing) + { + TESTING_2("H5Lvisit2 by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 3 * LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_DEC, link_visit_external_links_no_cycles_cb, + &i) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Lvisit_no_cycles_link_creation_decreasing); + } + + if (i != 4 * LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_no_cycles_link_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Lvisit_no_cycles_link_creation_decreasing); + + PART_BEGIN(H5Lvisit_by_name_no_cycles_link_name_increasing) + { + TESTING_2("H5Lvisit_by_name2 by link name in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 0; + + if (H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_INC, link_visit_external_links_no_cycles_cb, &i, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type name in increasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_name_increasing); + } + + if (i != LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_name_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_no_cycles_link_name_increasing); + + PART_BEGIN(H5Lvisit_by_name_no_cycles_link_name_decreasing) + { + TESTING_2("H5Lvisit_by_name2 by link name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + i = LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_DEC, link_visit_external_links_no_cycles_cb, &i, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_name_decreasing); + } + + if (i != 2 * LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lvisit_by_name_no_cycles_link_name_decreasing); +#endif + } + PART_END(H5Lvisit_by_name_no_cycles_link_name_decreasing); + + PART_BEGIN(H5Lvisit_by_name_no_cycles_link_creation_increasing) + { + TESTING_2("H5Lvisit_by_name2 by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 2 * LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_INC, link_visit_external_links_no_cycles_cb, &i, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_creation_increasing); + } + + if (i != 3 * LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_creation_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_no_cycles_link_creation_increasing); + + PART_BEGIN(H5Lvisit_by_name_no_cycles_link_creation_decreasing) + { + TESTING_2("H5Lvisit_by_name2 by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 3 * LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_DEC, link_visit_external_links_no_cycles_cb, &i, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_creation_decreasing); + } + + if (i != 4 * LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_no_cycles_link_creation_decreasing); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(gcpl_id); + H5Gclose(subgroup_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +#else + SKIPPED(); + return 0; +#endif +} + +/* + * A test to check the functionality of recursive + * link iteration using H5Lvisit(_by_name)2 with + * only user-defined links and where there are no + * cyclic links. Iteration is done in increasing + * and decreasing order of both link name and link + * creation order. + * + * TODO refactor test so that creation order tests + * actually test the order that objects were created in. + */ +static int +test_link_visit_ud_links_no_cycles(void) +{ + TESTING("link visiting without cycles (only user-defined links)"); + + SKIPPED(); + + return 1; +} + +/* + * A test to check the functionality of recursive + * link iteration using H5Lvisit(_by_name)2 with + * mixed link types and where there are no cyclic + * links. Iteration is done in increasing and + * decreasing order of both link name and link + * creation order. + * + * TODO refactor test so that creation order tests + * actually test the order that objects were created in. + * + * TODO add UD links + * + * TODO refactor test to create a macroed number of subgroups + */ +static int +test_link_visit_mixed_links_no_cycles(void) +{ +#if !defined(NO_EXTERNAL_LINKS) && !defined(NO_USER_DEFINED_LINKS) + size_t i; + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t subgroup1 = H5I_INVALID_HID, subgroup2 = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + char ext_link_filename[H5_API_TEST_FILENAME_MAX_LENGTH]; +#endif + + TESTING_MULTIPART("link visiting without cycles (mixed link types)"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_EXTERNAL_LINKS) || !(vol_cap_flags_g & H5VL_CAP_FLAG_SOFT_LINKS) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_HARD_LINKS) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ITERATE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, link, hard, soft, external link, iterate, or " + "creation order aren't supported with this connector\n"); + return 0; + } + +#if !defined(NO_EXTERNAL_LINKS) && !defined(NO_USER_DEFINED_LINKS) + TESTING_2("test setup"); + + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", EXTERNAL_LINK_TEST_FILE_NAME); + + if ((file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + goto error; + } + + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create a GCPL\n"); + goto error; + } + + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0) { + H5_FAILED(); + HDprintf(" couldn't enable link creation order tracking and indexing on GCPL\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME, + H5P_DEFAULT, gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME); + goto error; + } + + if ((subgroup1 = H5Gcreate2(group_id, LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME2, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create first subgroup '%s'\n", + LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME2); + goto error; + } + + if ((subgroup2 = H5Gcreate2(group_id, LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME3, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create second subgroup '%s'\n", + LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME3); + goto error; + } + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + if ((fspace_id = generate_random_dataspace(LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_DSET_SPACE_RANK, NULL, + NULL, FALSE)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(subgroup1, LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_DSET_NAME, dset_dtype, + fspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create first dataset '%s'\n", LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_DSET_NAME); + } + + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(subgroup2, LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_DSET_NAME2, dset_dtype, + fspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create second dataset '%s'\n", LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_DSET_NAME); + } + + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + + if (H5Lcreate_hard(subgroup1, LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_DSET_NAME, subgroup1, + LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME1, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create first hard link '%s'\n", + LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME1); + goto error; + } + + if (H5Lcreate_soft(LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_DSET_NAME, subgroup1, + LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME2); + goto error; + } + + if (H5Lcreate_external(ext_link_filename, "/", subgroup2, LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME3, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME3); + goto error; + } + + if (H5Lcreate_hard(subgroup2, LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_DSET_NAME2, subgroup2, + LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME4, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create second hard link '%s'\n", + LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME4); + goto error; + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup1, LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME1, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if first link '%s' exists\n", + LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME1); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link 1 did not exist\n"); + goto error; + } + + if ((link_exists = H5Lexists(subgroup1, LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME2, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if second link '%s' exists\n", + LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME2); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link 2 did not exist\n"); + goto error; + } + + if ((link_exists = H5Lexists(subgroup2, LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME3, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if third link '%s' exists\n", + LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME3); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link 3 did not exist\n"); + goto error; + } + + if ((link_exists = H5Lexists(subgroup2, LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME4, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if fourth link '%s' exists\n", + LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME4); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link 4 did not exist\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + /* + * NOTE: A counter is passed to the iteration callback to try to match up the + * expected links with a given step throughout all of the following + * iterations. This is to try and check that the links are indeed being + * returned in the correct order. + */ + + PART_BEGIN(H5Lvisit_no_cycles_link_name_increasing) + { + TESTING_2("H5Lvisit2 by link name in increasing order"); + + i = 0; + + if (H5Lvisit2(group_id, H5_INDEX_NAME, H5_ITER_INC, link_visit_mixed_links_no_cycles_cb, &i) < + 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type name in increasing order failed\n"); + PART_ERROR(H5Lvisit_no_cycles_link_name_increasing); + } + + if (i != LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_no_cycles_link_name_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_no_cycles_link_name_increasing); + + PART_BEGIN(H5Lvisit_no_cycles_link_name_decreasing) + { + TESTING_2("H5Lvisit2 by link name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + i = LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_NUM_LINKS; + + if (H5Lvisit2(group_id, H5_INDEX_NAME, H5_ITER_DEC, link_visit_mixed_links_no_cycles_cb, &i) < + 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Lvisit_no_cycles_link_name_decreasing); + } + + if (i != 2 * LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_no_cycles_link_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lvisit_no_cycles_link_name_decreasing); +#endif + } + PART_END(H5Lvisit_no_cycles_link_name_decreasing); + + PART_BEGIN(H5Lvisit_no_cycles_link_creation_increasing) + { + TESTING_2("H5Lvisit2 by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 2 * LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_NUM_LINKS; + + if (H5Lvisit2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_INC, link_visit_mixed_links_no_cycles_cb, + &i) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Lvisit_no_cycles_link_creation_increasing); + } + + if (i != 3 * LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_no_cycles_link_creation_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_no_cycles_link_creation_increasing); + + PART_BEGIN(H5Lvisit_no_cycles_link_creation_decreasing) + { + TESTING_2("H5Lvisit2 by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 3 * LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_NUM_LINKS; + + if (H5Lvisit2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_DEC, link_visit_mixed_links_no_cycles_cb, + &i) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Lvisit_no_cycles_link_creation_decreasing); + } + + if (i != 4 * LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_no_cycles_link_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Lvisit_no_cycles_link_creation_decreasing); + + PART_BEGIN(H5Lvisit_by_name_no_cycles_link_name_increasing) + { + TESTING_2("H5Lvisit_by_name2 by link name in increasing order"); + + i = 0; + + if (H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_INC, link_visit_mixed_links_no_cycles_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type name in increasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_name_increasing); + } + + if (i != LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_name_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_no_cycles_link_name_increasing); + + PART_BEGIN(H5Lvisit_by_name_no_cycles_link_name_decreasing) + { + TESTING_2("H5Lvisit_by_name2 by link name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + i = LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_NUM_LINKS; + + if (H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_DEC, link_visit_mixed_links_no_cycles_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_name_decreasing); + } + + if (i != 2 * LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lvisit_by_name_no_cycles_link_name_decreasing); +#endif + } + PART_END(H5Lvisit_by_name_no_cycles_link_name_decreasing); + + PART_BEGIN(H5Lvisit_by_name_no_cycles_link_creation_increasing) + { + TESTING_2("H5Lvisit_by_name2 by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 2 * LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_NUM_LINKS; + + if (H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_INC, link_visit_mixed_links_no_cycles_cb, &i, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_creation_increasing); + } + + if (i != 3 * LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_creation_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_no_cycles_link_creation_increasing); + + PART_BEGIN(H5Lvisit_by_name_no_cycles_link_creation_decreasing) + { + TESTING_2("H5Lvisit_by_name2 by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 3 * LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_NUM_LINKS; + + if (H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_DEC, link_visit_mixed_links_no_cycles_cb, &i, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_creation_decreasing); + } + + if (i != 4 * LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_no_cycles_link_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_no_cycles_link_creation_decreasing); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(subgroup1) < 0) + TEST_ERROR; + if (H5Gclose(subgroup2) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + H5Tclose(dset_dtype); + H5Dclose(dset_id); + H5Pclose(gcpl_id); + H5Gclose(subgroup1); + H5Gclose(subgroup2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +#else + SKIPPED(); + return 0; +#endif +} + +/* + * A test to check the functionality of recursive + * link iteration using H5Lvisit(_by_name)2 with + * only hard links and where there are cyclic links. + * Iteration is done in increasing and decreasing + * order of both link name and link creation order. + */ +static int +test_link_visit_hard_links_cycles(void) +{ + size_t i; + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t subgroup_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + + TESTING_MULTIPART("link visiting with cycles (only hard links)"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_HARD_LINKS) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ITERATE) || !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, link, hard link, iterate, or creation order " + "aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create a GCPL\n"); + goto error; + } + + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0) { + H5_FAILED(); + HDprintf(" couldn't enable link creation order tracking and indexing on GCPL\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, LINK_VISIT_HARD_LINKS_CYCLE_TEST_SUBGROUP_NAME, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + LINK_VISIT_HARD_LINKS_CYCLE_TEST_SUBGROUP_NAME); + goto error; + } + + for (i = 0; i < LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_SUBGROUPS; i++) { + size_t j; + char grp_name[LINK_VISIT_HARD_LINKS_CYCLE_TEST_BUF_SIZE]; + + /* Create the groups with a reverse-ordering naming scheme to test creation order later */ + HDsnprintf(grp_name, LINK_VISIT_HARD_LINKS_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_HARD_LINKS_CYCLE_TEST_NESTED_GRP_NAME "%d", + (int)(LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_SUBGROUPS - i - 1)); + + if ((subgroup_id = H5Gcreate2(group_id, grp_name, H5P_DEFAULT, gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", grp_name); + goto error; + } + + for (j = 0; j < LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_LINKS_PER_GROUP; j++) { + char link_name[LINK_VISIT_HARD_LINKS_CYCLE_TEST_BUF_SIZE]; + + /* Create the links with a reverse-ordering naming scheme to test creation order later */ + HDsnprintf(link_name, LINK_VISIT_HARD_LINKS_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_HARD_LINKS_CYCLE_TEST_LINK_NAME "%d", + (int)(LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_LINKS_PER_GROUP - j - 1)); + + if (H5Lcreate_hard(subgroup_id, ".", subgroup_id, link_name, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create hard link '%s'\n", link_name); + goto error; + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(subgroup_id, link_name, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", link_name); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", link_name); + goto error; + } + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close subgroup '%s'\n", grp_name); + goto error; + } + } + + PASSED(); + + BEGIN_MULTIPART + { + /* + * NOTE: A counter is passed to the iteration callback to try to match up the + * expected links with a given step throughout all of the following + * iterations. This is to try and check that the links are indeed being + * returned in the correct order. + */ + + PART_BEGIN(H5Lvisit_cycles_link_name_increasing) + { + TESTING_2("H5Lvisit2 by link name in increasing order"); + + i = 0; + + if (H5Lvisit2(group_id, H5_INDEX_NAME, H5_ITER_INC, link_visit_hard_links_cycles_cb, &i) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type name in increasing order failed\n"); + PART_ERROR(H5Lvisit_cycles_link_name_increasing); + } + + if (i != LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_cycles_link_name_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_cycles_link_name_increasing); + + PART_BEGIN(H5Lvisit_cycles_link_name_decreasing) + { + TESTING_2("H5Lvisit2 by link name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + i = LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit2(group_id, H5_INDEX_NAME, H5_ITER_DEC, link_visit_hard_links_cycles_cb, &i) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Lvisit_cycles_link_name_decreasing); + } + + if (i != 2 * LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_cycles_link_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lvisit_cycles_link_name_decreasing); +#endif + } + PART_END(H5Lvisit_cycles_link_name_decreasing); + + PART_BEGIN(H5Lvisit_cycles_link_creation_increasing) + { + TESTING_2("H5Lvisit2 by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 2 * LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_INC, link_visit_hard_links_cycles_cb, &i) < + 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Lvisit_cycles_link_creation_increasing); + } + + if (i != 3 * LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_cycles_link_creation_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_cycles_link_creation_increasing); + + PART_BEGIN(H5Lvisit_cycles_link_creation_decreasing) + { + TESTING_2("H5Lvisit2 by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 3 * LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_DEC, link_visit_hard_links_cycles_cb, &i) < + 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Lvisit_cycles_link_creation_decreasing); + } + + if (i != 4 * LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_cycles_link_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Lvisit_cycles_link_creation_decreasing); + + PART_BEGIN(H5Lvisit_by_name_cycles_link_name_increasing) + { + TESTING_2("H5Lvisit_by_name2 by link name in increasing order"); + + i = 0; + + if (H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_HARD_LINKS_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_INC, link_visit_hard_links_cycles_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type name in increasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_name_increasing); + } + + if (i != LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_name_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_cycles_link_name_increasing); + + PART_BEGIN(H5Lvisit_by_name_cycles_link_name_decreasing) + { + TESTING_2("H5Lvisit_by_name2 by link name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + i = LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_HARD_LINKS_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_DEC, link_visit_hard_links_cycles_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_name_decreasing); + } + + if (i != 2 * LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lvisit_by_name_cycles_link_name_decreasing); +#endif + } + PART_END(H5Lvisit_by_name_cycles_link_name_decreasing); + + PART_BEGIN(H5Lvisit_by_name_cycles_link_creation_increasing) + { + TESTING_2("H5Lvisit_by_name2 by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 2 * LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_HARD_LINKS_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_INC, link_visit_hard_links_cycles_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_creation_increasing); + } + + if (i != 3 * LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_creation_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_cycles_link_creation_increasing); + + PART_BEGIN(H5Lvisit_by_name_cycles_link_creation_decreasing) + { + TESTING_2("H5Lvisit_by_name2 by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 3 * LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_HARD_LINKS_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_DEC, link_visit_hard_links_cycles_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_creation_decreasing); + } + + if (i != 4 * LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_cycles_link_creation_decreasing); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(gcpl_id); + H5Gclose(subgroup_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check the functionality of recursive + * link iteration using H5Lvisit(_by_name)2 with + * only soft links and where there are cyclic links. + * Iteration is done in increasing and decreasing + * order of both link name and link creation order. + */ +static int +test_link_visit_soft_links_cycles(void) +{ + size_t i; + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t subgroup_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + + TESTING_MULTIPART("link visiting with cycles (only soft links)"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_SOFT_LINKS) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ITERATE) || !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, link, soft link, iterate, or creation order " + "aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create a GCPL\n"); + goto error; + } + + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0) { + H5_FAILED(); + HDprintf(" couldn't enable link creation order tracking and indexing on GCPL\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, LINK_VISIT_SOFT_LINKS_CYCLE_TEST_SUBGROUP_NAME, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + LINK_VISIT_SOFT_LINKS_CYCLE_TEST_SUBGROUP_NAME); + goto error; + } + + for (i = 0; i < LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_SUBGROUPS; i++) { + size_t j; + char grp_name[LINK_VISIT_SOFT_LINKS_CYCLE_TEST_BUF_SIZE]; + + /* Create the groups with a reverse-ordering naming scheme to test creation order later */ + HDsnprintf(grp_name, LINK_VISIT_SOFT_LINKS_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NESTED_GRP_NAME "%d", + (int)(LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_SUBGROUPS - i - 1)); + + if ((subgroup_id = H5Gcreate2(group_id, grp_name, H5P_DEFAULT, gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", grp_name); + goto error; + } + + for (j = 0; j < LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_LINKS_PER_GROUP; j++) { + char link_name[LINK_VISIT_SOFT_LINKS_CYCLE_TEST_BUF_SIZE]; + char link_target[2 * LINK_VISIT_SOFT_LINKS_CYCLE_TEST_BUF_SIZE]; + + /* Create the links with a reverse-ordering naming scheme to test creation order later */ + HDsnprintf(link_name, LINK_VISIT_SOFT_LINKS_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_SOFT_LINKS_CYCLE_TEST_LINK_NAME "%d", + (int)(LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_LINKS_PER_GROUP - j - 1)); + + HDsnprintf(link_target, 2 * LINK_VISIT_SOFT_LINKS_CYCLE_TEST_BUF_SIZE, + "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_SOFT_LINKS_CYCLE_TEST_SUBGROUP_NAME "/%s", + grp_name); + + if (H5Lcreate_soft(link_target, subgroup_id, link_name, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", link_name); + goto error; + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(subgroup_id, link_name, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", link_name); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", link_name); + goto error; + } + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close subgroup '%s'\n", grp_name); + goto error; + } + } + + PASSED(); + + BEGIN_MULTIPART + { + /* + * NOTE: A counter is passed to the iteration callback to try to match up the + * expected links with a given step throughout all of the following + * iterations. This is to try and check that the links are indeed being + * returned in the correct order. + */ + + PART_BEGIN(H5Lvisit_cycles_link_name_increasing) + { + TESTING_2("H5Lvisit2 by link name in increasing order"); + + i = 0; + + if (H5Lvisit2(group_id, H5_INDEX_NAME, H5_ITER_INC, link_visit_soft_links_cycles_cb, &i) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type name in increasing order failed\n"); + PART_ERROR(H5Lvisit_cycles_link_name_increasing); + } + + if (i != LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_cycles_link_name_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_cycles_link_name_increasing); + + PART_BEGIN(H5Lvisit_cycles_link_name_decreasing) + { + TESTING_2("H5Lvisit2 by link name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + i = LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit2(group_id, H5_INDEX_NAME, H5_ITER_DEC, link_visit_soft_links_cycles_cb, &i) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Lvisit_cycles_link_name_decreasing); + } + + if (i != 2 * LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_cycles_link_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lvisit_cycles_link_name_decreasing); +#endif + } + PART_END(H5Lvisit_cycles_link_name_decreasing); + + PART_BEGIN(H5Lvisit_cycles_link_creation_increasing) + { + TESTING_2("H5Lvisit2 by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 2 * LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_INC, link_visit_soft_links_cycles_cb, &i) < + 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Lvisit_cycles_link_creation_increasing); + } + + if (i != 3 * LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_cycles_link_creation_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_cycles_link_creation_increasing); + + PART_BEGIN(H5Lvisit_cycles_link_creation_decreasing) + { + TESTING_2("H5Lvisit2 by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 3 * LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_DEC, link_visit_soft_links_cycles_cb, &i) < + 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Lvisit_cycles_link_creation_decreasing); + } + + if (i != 4 * LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_cycles_link_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Lvisit_cycles_link_creation_decreasing); + + PART_BEGIN(H5Lvisit_by_name_cycles_link_name_increasing) + { + TESTING_2("H5Lvisit_by_name2 by link name in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 0; + + if (H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_SOFT_LINKS_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_INC, link_visit_soft_links_cycles_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type name in increasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_name_increasing); + } + + if (i != LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_name_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_cycles_link_name_increasing); + + PART_BEGIN(H5Lvisit_by_name_cycles_link_name_decreasing) + { + TESTING_2("H5Lvisit_by_name2 by link name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + i = LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_SOFT_LINKS_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_DEC, link_visit_soft_links_cycles_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_name_decreasing); + } + + if (i != 2 * LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lvisit_by_name_cycles_link_name_decreasing); +#endif + } + PART_END(H5Lvisit_by_name_cycles_link_name_decreasing); + + PART_BEGIN(H5Lvisit_by_name_cycles_link_creation_increasing) + { + TESTING_2("H5Lvisit_by_name2 by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 2 * LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_SOFT_LINKS_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_INC, link_visit_soft_links_cycles_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_creation_increasing); + } + + if (i != 3 * LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_creation_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_cycles_link_creation_increasing); + + PART_BEGIN(H5Lvisit_by_name_cycles_link_creation_decreasing) + { + TESTING_2("H5Lvisit_by_name2 by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 3 * LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_SOFT_LINKS_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_DEC, link_visit_soft_links_cycles_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_creation_decreasing); + } + + if (i != 4 * LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_cycles_link_creation_decreasing); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(gcpl_id); + H5Gclose(subgroup_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check the functionality of recursive + * link iteration using H5Lvisit(_by_name)2 with + * only external links and where there are cyclic + * links. Iteration is done in increasing and + * decreasing order of both link name and link + * creation order. + */ +static int +test_link_visit_external_links_cycles(void) +{ +#ifndef NO_EXTERNAL_LINKS + size_t i; + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t subgroup_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; +#endif + + TESTING_MULTIPART("link visiting with cycles (only external links)"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_EXTERNAL_LINKS) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ITERATE) || !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, link, external link, iterate, or creation order " + "aren't supported with this connector\n"); + return 0; + } + +#ifndef NO_EXTERNAL_LINKS + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create a GCPL\n"); + goto error; + } + + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0) { + H5_FAILED(); + HDprintf(" couldn't enable link creation order tracking and indexing on GCPL\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, LINK_VISIT_EXT_LINKS_CYCLE_TEST_SUBGROUP_NAME, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + LINK_VISIT_EXT_LINKS_CYCLE_TEST_SUBGROUP_NAME); + goto error; + } + + for (i = 0; i < LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_SUBGROUPS; i++) { + size_t j; + char grp_name[LINK_VISIT_EXT_LINKS_CYCLE_TEST_BUF_SIZE]; + + /* Create the groups with a reverse-ordering naming scheme to test creation order later */ + HDsnprintf(grp_name, LINK_VISIT_EXT_LINKS_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_EXT_LINKS_CYCLE_TEST_NESTED_GRP_NAME "%d", + (int)(LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_SUBGROUPS - i - 1)); + + if ((subgroup_id = H5Gcreate2(group_id, grp_name, H5P_DEFAULT, gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup '%s'\n", grp_name); + goto error; + } + + for (j = 0; j < LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_LINKS_PER_GROUP; j++) { + char link_name[LINK_VISIT_EXT_LINKS_CYCLE_TEST_BUF_SIZE]; + char link_target_obj[2 * LINK_VISIT_EXT_LINKS_CYCLE_TEST_BUF_SIZE]; + + /* Create the links with a reverse-ordering naming scheme to test creation order later */ + HDsnprintf(link_name, LINK_VISIT_EXT_LINKS_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_EXT_LINKS_CYCLE_TEST_LINK_NAME "%d", + (int)(LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_LINKS_PER_GROUP - j - 1)); + + HDsnprintf(link_target_obj, 2 * LINK_VISIT_EXT_LINKS_CYCLE_TEST_BUF_SIZE, + "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_EXT_LINKS_CYCLE_TEST_SUBGROUP_NAME "/%s", + grp_name); + + if (H5Lcreate_external(H5_api_test_filename, link_target_obj, subgroup_id, link_name, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", link_name); + goto error; + } + + /* Verify the link has been created */ + if ((link_exists = H5Lexists(subgroup_id, link_name, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' exists\n", link_name); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link '%s' did not exist\n", link_name); + goto error; + } + } + + if (H5Gclose(subgroup_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close subgroup '%s'\n", grp_name); + goto error; + } + } + + PASSED(); + + BEGIN_MULTIPART + { + /* + * NOTE: A counter is passed to the iteration callback to try to match up the + * expected links with a given step throughout all of the following + * iterations. This is to try and check that the links are indeed being + * returned in the correct order. + */ + + PART_BEGIN(H5Lvisit_cycles_link_name_increasing) + { + TESTING_2("H5Lvisit2 by link name in increasing order"); + + i = 0; + + if (H5Lvisit2(group_id, H5_INDEX_NAME, H5_ITER_INC, link_visit_external_links_cycles_cb, &i) < + 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type name in increasing order failed\n"); + PART_ERROR(H5Lvisit_cycles_link_name_increasing); + } + + if (i != LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_cycles_link_name_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_cycles_link_name_increasing); + + PART_BEGIN(H5Lvisit_cycles_link_name_decreasing) + { + TESTING_2("H5Lvisit2 by link name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + i = LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit2(group_id, H5_INDEX_NAME, H5_ITER_DEC, link_visit_external_links_cycles_cb, &i) < + 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Lvisit_cycles_link_name_decreasing); + } + + if (i != 2 * LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_cycles_link_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lvisit_cycles_link_name_decreasing); +#endif + } + PART_END(H5Lvisit_cycles_link_name_decreasing); + + PART_BEGIN(H5Lvisit_cycles_link_creation_increasing) + { + TESTING_2("H5Lvisit2 by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 2 * LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_INC, link_visit_external_links_cycles_cb, + &i) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Lvisit_cycles_link_creation_increasing); + } + + if (i != 3 * LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_cycles_link_creation_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_cycles_link_creation_increasing); + + PART_BEGIN(H5Lvisit_cycles_link_creation_decreasing) + { + TESTING_2("H5Lvisit2 by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 3 * LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_DEC, link_visit_external_links_cycles_cb, + &i) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Lvisit_cycles_link_creation_decreasing); + } + + if (i != 4 * LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_cycles_link_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Lvisit_cycles_link_creation_decreasing); + + PART_BEGIN(H5Lvisit_by_name_cycles_link_name_increasing) + { + TESTING_2("H5Lvisit_by_name2 by link name in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 0; + + if (H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_EXT_LINKS_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_INC, link_visit_external_links_cycles_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type name in increasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_name_increasing); + } + + if (i != LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_name_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_cycles_link_name_increasing); + + PART_BEGIN(H5Lvisit_by_name_cycles_link_name_decreasing) + { + TESTING_2("H5Lvisit_by_name2 by link name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + i = LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_EXT_LINKS_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_DEC, link_visit_external_links_cycles_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_name_decreasing); + } + + if (i != 2 * LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lvisit_by_name_cycles_link_name_decreasing); +#endif + } + PART_END(H5Lvisit_by_name_cycles_link_name_decreasing); + + PART_BEGIN(H5Lvisit_by_name_cycles_link_creation_increasing) + { + TESTING_2("H5Lvisit_by_name2 by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 2 * LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit_by_name2(file_id, + "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_EXT_LINKS_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_INC, link_visit_external_links_cycles_cb, &i, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_creation_increasing); + } + + if (i != 3 * LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_creation_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_cycles_link_creation_increasing); + + PART_BEGIN(H5Lvisit_by_name_cycles_link_creation_decreasing) + { + TESTING_2("H5Lvisit_by_name2 by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 3 * LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST; + + if (H5Lvisit_by_name2(file_id, + "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_EXT_LINKS_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_DEC, link_visit_external_links_cycles_cb, &i, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_creation_decreasing); + } + + if (i != 4 * LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_cycles_link_creation_decreasing); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(gcpl_id); + H5Gclose(subgroup_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +#else + SKIPPED(); + return 0; +#endif +} + +/* + * A test to check the functionality of recursive + * link iteration using H5Lvisit(_by_name)2 with + * only user-defined links and where there are + * cyclic links. Iteration is done in increasing + * and decreasing order of both link name and link + * creation order. + * + * TODO refactor test so that creation order tests + * actually test the order that objects were created in. + */ +static int +test_link_visit_ud_links_cycles(void) +{ + TESTING("link visiting with cycles (only user-defined links)"); + + SKIPPED(); + + return 1; +} + +/* + * A test to check the functionality of recursive + * link iteration using H5Lvisit(_by_name)2 with + * mixed link types and where there are cyclic links. + * Iteration is done in increasing and decreasing + * order of both link name and link creation order. + * + * TODO refactor test so that creation order tests + * actually test the order that objects were created in. + */ +static int +test_link_visit_mixed_links_cycles(void) +{ +#if !defined(NO_EXTERNAL_LINKS) && !defined(NO_USER_DEFINED_LINKS) + htri_t link_exists; + size_t i; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t subgroup1 = H5I_INVALID_HID, subgroup2 = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + char ext_link_filename[H5_API_TEST_FILENAME_MAX_LENGTH]; +#endif + + TESTING_MULTIPART("link visiting with cycles (mixed link types)"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_EXTERNAL_LINKS) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_HARD_LINKS) || !(vol_cap_flags_g & H5VL_CAP_FLAG_SOFT_LINKS) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ITERATE) || !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, link, hard, soft, external link, iterate, or " + "creation order aren't supported with this connector\n"); + return 0; + } + +#if !defined(NO_EXTERNAL_LINKS) && !defined(NO_USER_DEFINED_LINKS) + TESTING_2("test setup"); + + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", EXTERNAL_LINK_TEST_FILE_NAME); + + if ((file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + goto error; + } + + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create a GCPL\n"); + goto error; + } + + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0) { + H5_FAILED(); + HDprintf(" couldn't enable link creation order tracking and indexing on GCPL\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME); + goto error; + } + + if ((subgroup1 = H5Gcreate2(group_id, LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME2, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create first subgroup '%s'\n", + LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME2); + goto error; + } + + if ((subgroup2 = H5Gcreate2(group_id, LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME3, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create second subgroup '%s'\n", + LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME3); + goto error; + } + + if (H5Lcreate_hard(group_id, LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME2, subgroup1, + LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME1, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create first hard link '%s'\n", LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME1); + goto error; + } + + if (H5Lcreate_soft("/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME + "/" LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME2, + subgroup1, LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME2, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME2); + goto error; + } + + if (H5Lcreate_external(ext_link_filename, "/", subgroup2, LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME3, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME3); + goto error; + } + + if (H5Lcreate_hard(group_id, LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME3, subgroup2, + LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME4, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create second hard link '%s'\n", LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME4); + goto error; + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup1, LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME1, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if first link '%s' exists\n", + LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME1); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" first link '%s' did not exist\n", LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME1); + goto error; + } + + if ((link_exists = H5Lexists(subgroup1, LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if second link '%s' exists\n", + LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME2); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" second link '%s' did not exist\n", LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME2); + goto error; + } + + if ((link_exists = H5Lexists(subgroup2, LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if third link '%s' exists\n", + LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME3); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" third link '%s' did not exist\n", LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME3); + goto error; + } + + if ((link_exists = H5Lexists(subgroup2, LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME4, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if fourth link '%s' exists\n", + LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME4); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" fourth link '%s' did not exist\n", LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME4); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + /* + * NOTE: A counter is passed to the iteration callback to try to match up the + * expected links with a given step throughout all of the following + * iterations. This is to try and check that the links are indeed being + * returned in the correct order. + */ + + PART_BEGIN(H5Lvisit_cycles_link_name_increasing) + { + TESTING_2("H5Lvisit2 by link name in increasing order"); + + i = 0; + + if (H5Lvisit2(group_id, H5_INDEX_NAME, H5_ITER_INC, link_visit_mixed_links_cycles_cb, &i) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type name in increasing order failed\n"); + PART_ERROR(H5Lvisit_cycles_link_name_increasing); + } + + if (i != LINK_VISIT_MIXED_LINKS_CYCLE_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_cycles_link_name_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_cycles_link_name_increasing); + + PART_BEGIN(H5Lvisit_cycles_link_name_decreasing) + { + TESTING_2("H5Lvisit2 by link name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + i = LINK_VISIT_MIXED_LINKS_CYCLE_TEST_NUM_LINKS; + + if (H5Lvisit2(group_id, H5_INDEX_NAME, H5_ITER_DEC, link_visit_mixed_links_cycles_cb, &i) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Lvisit_cycles_link_name_decreasing); + } + + if (i != 2 * LINK_VISIT_MIXED_LINKS_CYCLE_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_cycles_link_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lvisit_cycles_link_name_decreasing); +#endif + } + PART_END(H5Lvisit_cycles_link_name_decreasing); + + PART_BEGIN(H5Lvisit_cycles_link_creation_increasing) + { + TESTING_2("H5Lvisit2 by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 2 * LINK_VISIT_MIXED_LINKS_CYCLE_TEST_NUM_LINKS; + + if (H5Lvisit2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_INC, link_visit_mixed_links_cycles_cb, &i) < + 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Lvisit_cycles_link_creation_increasing); + } + + if (i != 3 * LINK_VISIT_MIXED_LINKS_CYCLE_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_cycles_link_creation_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_cycles_link_creation_increasing); + + PART_BEGIN(H5Lvisit_cycles_link_creation_decreasing) + { + TESTING_2("H5Lvisit2 by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 3 * LINK_VISIT_MIXED_LINKS_CYCLE_TEST_NUM_LINKS; + + if (H5Lvisit2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_DEC, link_visit_mixed_links_cycles_cb, &i) < + 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Lvisit_cycles_link_creation_decreasing); + } + + if (i != 4 * LINK_VISIT_MIXED_LINKS_CYCLE_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_cycles_link_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Lvisit_cycles_link_creation_decreasing); + + PART_BEGIN(H5Lvisit_by_name_cycles_link_name_increasing) + { + TESTING_2("H5Lvisit_by_name2 by link name in increasing order"); + + i = 0; + + if (H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_INC, link_visit_mixed_links_cycles_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type name in increasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_name_increasing); + } + + if (i != LINK_VISIT_MIXED_LINKS_CYCLE_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_name_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_cycles_link_name_increasing); + + PART_BEGIN(H5Lvisit_by_name_cycles_link_name_decreasing) + { + TESTING_2("H5Lvisit_by_name2 by link name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + i = LINK_VISIT_MIXED_LINKS_CYCLE_TEST_NUM_LINKS; + + if (H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_DEC, link_visit_mixed_links_cycles_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_name_decreasing); + } + + if (i != 2 * LINK_VISIT_MIXED_LINKS_CYCLE_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lvisit_by_name_cycles_link_name_decreasing); +#endif + } + PART_END(H5Lvisit_by_name_cycles_link_name_decreasing); + + PART_BEGIN(H5Lvisit_by_name_cycles_link_creation_increasing) + { + TESTING_2("H5Lvisit_by_name2 by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 2 * LINK_VISIT_MIXED_LINKS_CYCLE_TEST_NUM_LINKS; + + if (H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_INC, link_visit_mixed_links_cycles_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_creation_increasing); + } + + if (i != 3 * LINK_VISIT_MIXED_LINKS_CYCLE_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_creation_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_cycles_link_creation_increasing); + + PART_BEGIN(H5Lvisit_by_name_cycles_link_creation_decreasing) + { + TESTING_2("H5Lvisit_by_name2 by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 3 * LINK_VISIT_MIXED_LINKS_CYCLE_TEST_NUM_LINKS; + + if (H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_DEC, link_visit_mixed_links_cycles_cb, &i, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_creation_decreasing); + } + + if (i != 4 * LINK_VISIT_MIXED_LINKS_CYCLE_TEST_NUM_LINKS) { + H5_FAILED(); + HDprintf(" some links were not visited!\n"); + PART_ERROR(H5Lvisit_by_name_cycles_link_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_cycles_link_creation_decreasing); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(subgroup1) < 0) + TEST_ERROR; + if (H5Gclose(subgroup2) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(gcpl_id); + H5Gclose(subgroup1); + H5Gclose(subgroup2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +#else + SKIPPED(); + return 0; +#endif +} + +/* + * A test to check that H5Lvisit(_by_name)2 fails when + * it is given invalid parameters. + */ +static int +test_link_visit_invalid_params(void) +{ + herr_t err_ret = -1; + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t subgroup1 = H5I_INVALID_HID, subgroup2 = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + char ext_link_filename[H5_API_TEST_FILENAME_MAX_LENGTH]; + + TESTING_MULTIPART("link visiting with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_EXTERNAL_LINKS) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ITERATE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, link, external link, iterate, or " + "creation order aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + HDsnprintf(ext_link_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s", EXTERNAL_LINK_TEST_FILE_NAME); + + if ((file_id = H5Fcreate(ext_link_filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s' for external link to reference\n", ext_link_filename); + goto error; + } + + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, LINK_VISIT_INVALID_PARAMS_TEST_SUBGROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + LINK_VISIT_INVALID_PARAMS_TEST_SUBGROUP_NAME); + goto error; + } + + if ((subgroup1 = H5Gcreate2(group_id, LINK_VISIT_INVALID_PARAMS_TEST_SUBGROUP_NAME2, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create first subgroup '%s'\n", LINK_VISIT_INVALID_PARAMS_TEST_SUBGROUP_NAME2); + goto error; + } + + if ((subgroup2 = H5Gcreate2(group_id, LINK_VISIT_INVALID_PARAMS_TEST_SUBGROUP_NAME3, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create second subgroup '%s'\n", LINK_VISIT_INVALID_PARAMS_TEST_SUBGROUP_NAME3); + goto error; + } + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + if ((fspace_id = generate_random_dataspace(LINK_VISIT_INVALID_PARAMS_TEST_DSET_SPACE_RANK, NULL, NULL, + FALSE)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(subgroup1, LINK_VISIT_INVALID_PARAMS_TEST_DSET_NAME, dset_dtype, fspace_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create first dataset '%s'\n", LINK_VISIT_INVALID_PARAMS_TEST_DSET_NAME); + } + + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(subgroup2, LINK_VISIT_INVALID_PARAMS_TEST_DSET_NAME, dset_dtype, fspace_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create second dataset '%s'\n", LINK_VISIT_INVALID_PARAMS_TEST_DSET_NAME); + } + + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + + if (H5Lcreate_hard(subgroup1, LINK_VISIT_INVALID_PARAMS_TEST_DSET_NAME, subgroup1, + LINK_VISIT_INVALID_PARAMS_TEST_LINK_NAME1, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create first hard link '%s'\n", LINK_VISIT_INVALID_PARAMS_TEST_LINK_NAME1); + goto error; + } + + if (H5Lcreate_soft(LINK_VISIT_INVALID_PARAMS_TEST_DSET_NAME, subgroup1, + LINK_VISIT_INVALID_PARAMS_TEST_LINK_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", LINK_VISIT_INVALID_PARAMS_TEST_LINK_NAME2); + goto error; + } +#ifndef NO_EXTERNAL_LINKS + if (H5Lcreate_external(ext_link_filename, "/", subgroup2, LINK_VISIT_INVALID_PARAMS_TEST_LINK_NAME3, + H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create external link '%s'\n", LINK_VISIT_INVALID_PARAMS_TEST_LINK_NAME3); + goto error; + } +#endif + if (H5Lcreate_hard(subgroup2, LINK_VISIT_INVALID_PARAMS_TEST_DSET_NAME, subgroup2, + LINK_VISIT_INVALID_PARAMS_TEST_LINK_NAME4, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create second hard link '%s'\n", LINK_VISIT_INVALID_PARAMS_TEST_LINK_NAME4); + goto error; + } + + /* Verify the links have been created */ + if ((link_exists = H5Lexists(subgroup1, LINK_VISIT_INVALID_PARAMS_TEST_LINK_NAME1, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if first link '%s' exists\n", + LINK_VISIT_INVALID_PARAMS_TEST_LINK_NAME1); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link 1 did not exist\n"); + goto error; + } + + if ((link_exists = H5Lexists(subgroup1, LINK_VISIT_INVALID_PARAMS_TEST_LINK_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if second link '%s' exists\n", + LINK_VISIT_INVALID_PARAMS_TEST_LINK_NAME2); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link 2 did not exist\n"); + goto error; + } +#ifndef NO_EXTERNAL_LINKS + if ((link_exists = H5Lexists(subgroup2, LINK_VISIT_INVALID_PARAMS_TEST_LINK_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if third link '%s' exists\n", + LINK_VISIT_INVALID_PARAMS_TEST_LINK_NAME3); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link 3 did not exist\n"); + goto error; + } +#endif + if ((link_exists = H5Lexists(subgroup2, LINK_VISIT_INVALID_PARAMS_TEST_LINK_NAME4, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if fourth link '%s' exists\n", + LINK_VISIT_INVALID_PARAMS_TEST_LINK_NAME4); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" link 4 did not exist\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Lvisit_invalid_grp_id) + { + TESTING_2("H5Lvisit2 with an invalid group ID"); + + H5E_BEGIN_TRY + { + err_ret = H5Lvisit2(H5I_INVALID_HID, H5_INDEX_NAME, H5_ITER_INC, link_visit_invalid_params_cb, + NULL); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 succeeded with an invalid group ID!\n"); + PART_ERROR(H5Lvisit_invalid_grp_id); + } + + PASSED(); + } + PART_END(H5Lvisit_invalid_grp_id); + + PART_BEGIN(H5Lvisit_invalid_index_type) + { + TESTING_2("H5Lvisit2 with an invalid index type"); + + H5E_BEGIN_TRY + { + err_ret = + H5Lvisit2(group_id, H5_INDEX_UNKNOWN, H5_ITER_INC, link_visit_invalid_params_cb, NULL); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 succeeded with invalid index type H5_INDEX_UNKNOWN!\n"); + PART_ERROR(H5Lvisit_invalid_index_type); + } + + H5E_BEGIN_TRY + { + err_ret = H5Lvisit2(group_id, H5_INDEX_N, H5_ITER_INC, link_visit_invalid_params_cb, NULL); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 succeeded with invalid index type H5_INDEX_N!\n"); + PART_ERROR(H5Lvisit_invalid_index_type); + } + + PASSED(); + } + PART_END(H5Lvisit_invalid_index_type); + + PART_BEGIN(H5Lvisit_invalid_iter_order) + { + TESTING_2("H5Lvisit2 with an invalid iteration ordering"); + + H5E_BEGIN_TRY + { + err_ret = + H5Lvisit2(group_id, H5_INDEX_NAME, H5_ITER_UNKNOWN, link_visit_invalid_params_cb, NULL); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 succeeded with invalid iteration ordering H5_ITER_UNKNOWN!\n"); + PART_ERROR(H5Lvisit_invalid_iter_order); + } + + H5E_BEGIN_TRY + { + err_ret = H5Lvisit2(group_id, H5_INDEX_NAME, H5_ITER_N, link_visit_invalid_params_cb, NULL); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 succeeded with invalid iteration ordering H5_ITER_N!\n"); + PART_ERROR(H5Lvisit_invalid_iter_order); + } + + PASSED(); + } + PART_END(H5Lvisit_invalid_iter_order); + + PART_BEGIN(H5Lvisit_by_name_invalid_loc_id) + { + TESTING_2("H5Lvisit_by_name2 with an invalid location ID"); + + H5E_BEGIN_TRY + { + err_ret = H5Lvisit_by_name2( + H5I_INVALID_HID, + "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_INVALID_PARAMS_TEST_SUBGROUP_NAME, H5_INDEX_NAME, + H5_ITER_INC, link_visit_invalid_params_cb, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 succeeded with an invalid location ID!\n"); + PART_ERROR(H5Lvisit_by_name_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_invalid_loc_id); + + PART_BEGIN(H5Lvisit_by_name_invalid_grp_name) + { + TESTING_2("H5Lvisit_by_name2 with an invalid group name"); + + H5E_BEGIN_TRY + { + err_ret = H5Lvisit_by_name2(file_id, NULL, H5_INDEX_NAME, H5_ITER_INC, + link_visit_invalid_params_cb, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 succeeded with a NULL group name!\n"); + PART_ERROR(H5Lvisit_by_name_invalid_grp_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Lvisit_by_name2(file_id, "", H5_INDEX_NAME, H5_ITER_INC, + link_visit_invalid_params_cb, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 succeeded with an invalid group name of ''!\n"); + PART_ERROR(H5Lvisit_by_name_invalid_grp_name); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_invalid_grp_name); + + PART_BEGIN(H5Lvisit_by_name_invalid_index_type) + { + TESTING_2("H5Lvisit_by_name2 with an invalid index type"); + + H5E_BEGIN_TRY + { + err_ret = H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_INVALID_PARAMS_TEST_SUBGROUP_NAME, + H5_INDEX_UNKNOWN, H5_ITER_INC, link_visit_invalid_params_cb, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 succeeded with invalid index type H5_INDEX_UNKNOWN!\n"); + PART_ERROR(H5Lvisit_by_name_invalid_index_type); + } + + H5E_BEGIN_TRY + { + err_ret = H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_INVALID_PARAMS_TEST_SUBGROUP_NAME, + H5_INDEX_N, H5_ITER_INC, link_visit_invalid_params_cb, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 succeeded with invalid index type H5_INDEX_N!\n"); + PART_ERROR(H5Lvisit_by_name_invalid_index_type); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_invalid_index_type); + + PART_BEGIN(H5Lvisit_by_name_invalid_iter_order) + { + TESTING_2("H5Lvisit_by_name2 with an invalid iteration ordering"); + + H5E_BEGIN_TRY + { + err_ret = H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_INVALID_PARAMS_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_UNKNOWN, link_visit_invalid_params_cb, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf( + " H5Lvisit_by_name2 succeeded with invalid iteration ordering H5_ITER_UNKNOWN!\n"); + PART_ERROR(H5Lvisit_by_name_invalid_iter_order); + } + + H5E_BEGIN_TRY + { + err_ret = H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_INVALID_PARAMS_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_N, link_visit_invalid_params_cb, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 succeeded with invalid iteration ordering H5_ITER_N!\n"); + PART_ERROR(H5Lvisit_by_name_invalid_iter_order); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_invalid_iter_order); + + PART_BEGIN(H5Lvisit_by_name_invalid_lapl) + { + TESTING_2("H5Lvisit_by_name2 with an invalid LAPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Lvisit_by_name2( + file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_INVALID_PARAMS_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_INC, link_visit_invalid_params_cb, NULL, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 succeeded with an invalid LAPL!\n"); + PART_ERROR(H5Lvisit_by_name_invalid_lapl); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_invalid_lapl); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Gclose(subgroup1) < 0) + TEST_ERROR; + if (H5Gclose(subgroup2) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + H5Tclose(dset_dtype); + H5Dclose(dset_id); + H5Gclose(subgroup1); + H5Gclose(subgroup2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that recursive link iteration + * performed on a group with no links in it is + * not problematic. + */ +static int +test_link_visit_0_links(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + + TESTING_MULTIPART("link visiting on group with subgroups containing 0 links"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ITERATE) || !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, link iterate, or creation order aren't supported " + "with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", LINK_TEST_GROUP_NAME); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create a GCPL\n"); + goto error; + } + + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0) { + H5_FAILED(); + HDprintf(" couldn't enable link creation order tracking and indexing on GCPL\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, LINK_VISIT_0_LINKS_TEST_SUBGROUP_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", LINK_VISIT_0_LINKS_TEST_SUBGROUP_NAME); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Lvisit_0_links_name_increasing) + { + TESTING_2("H5Lvisit2 by link name in increasing order"); + + if (H5Lvisit2(group_id, H5_INDEX_NAME, H5_ITER_INC, link_visit_0_links_cb, NULL) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type name in increasing order failed\n"); + PART_ERROR(H5Lvisit_0_links_name_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_0_links_name_increasing); + + PART_BEGIN(H5Lvisit_0_links_name_decreasing) + { + TESTING_2("H5Lvisit2 by link name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + if (H5Lvisit2(group_id, H5_INDEX_NAME, H5_ITER_DEC, link_visit_0_links_cb, NULL) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Lvisit_0_links_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lvisit_0_links_name_decreasing); +#endif + } + PART_END(H5Lvisit_0_links_name_decreasing); + + PART_BEGIN(H5Lvisit_0_links_creation_increasing) + { + TESTING_2("H5Lvisit2 by creation order in increasing order"); + + if (H5Lvisit2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_INC, link_visit_0_links_cb, NULL) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Lvisit_0_links_creation_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_0_links_creation_increasing); + + PART_BEGIN(H5Lvisit_0_links_creation_decreasing) + { + TESTING_2("H5Lvisit2 by creation order in decreasing order"); + + if (H5Lvisit2(group_id, H5_INDEX_CRT_ORDER, H5_ITER_DEC, link_visit_0_links_cb, NULL) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Lvisit_0_links_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Lvisit_0_links_creation_decreasing); + + PART_BEGIN(H5Lvisit_by_name_0_links_name_increasing) + { + TESTING_2("H5Lvisit_by_name2 by link name in increasing order"); + + if (H5Lvisit_by_name2(file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_0_LINKS_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_INC, link_visit_0_links_cb, NULL, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type name in increasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_0_links_name_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_0_links_name_increasing); + + PART_BEGIN(H5Lvisit_by_name_0_links_name_decreasing) + { + TESTING_2("H5Lvisit_by_name2 by link name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + if (H5Lvisit_by_name2(file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_0_LINKS_TEST_SUBGROUP_NAME, + H5_INDEX_NAME, H5_ITER_DEC, link_visit_0_links_cb, NULL, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type name in decreasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_0_links_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Lvisit_by_name_0_links_name_decreasing); +#endif + } + PART_END(H5Lvisit_by_name_0_links_name_decreasing); + + PART_BEGIN(H5Lvisit_by_name_0_links_creation_increasing) + { + TESTING_2("H5Lvisit_by_name2 by creation order in increasing order"); + + if (H5Lvisit_by_name2(file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_0_LINKS_TEST_SUBGROUP_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_INC, link_visit_0_links_cb, NULL, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type creation order in increasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_0_links_creation_increasing); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_0_links_creation_increasing); + + PART_BEGIN(H5Lvisit_by_name_0_links_creation_decreasing) + { + TESTING_2("H5Lvisit_by_name2 by creation order in decreasing order"); + + if (H5Lvisit_by_name2(file_id, "/" LINK_TEST_GROUP_NAME "/" LINK_VISIT_0_LINKS_TEST_SUBGROUP_NAME, + H5_INDEX_CRT_ORDER, H5_ITER_DEC, link_visit_0_links_cb, NULL, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Lvisit_by_name2 by index type creation order in decreasing order failed\n"); + PART_ERROR(H5Lvisit_by_name_0_links_creation_decreasing); + } + + PASSED(); + } + PART_END(H5Lvisit_by_name_0_links_creation_decreasing); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(gcpl_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * Link iteration callback for the hard links test which iterates + * through all of the links in the test group and checks to make sure + * their names and link classes match what is expected. + */ +static herr_t +link_iter_hard_links_cb(hid_t group_id, const char *name, const H5L_info2_t *info, void *op_data) +{ + size_t *i = (size_t *)op_data; + size_t counter_val = *((size_t *)op_data); + size_t test_iteration; + char expected_link_name[LINK_ITER_HARD_LINKS_TEST_BUF_SIZE]; + herr_t ret_val = H5_ITER_CONT; + + UNUSED(group_id); + UNUSED(op_data); + + if (H5L_TYPE_HARD != info->type) { + ret_val = H5_ITER_ERROR; + HDprintf(" link type for link '%s' was not H5L_TYPE_HARD!\n", name); + goto done; + } + + /* + * Four tests are run in the following order per link iteration API call: + * + * - iteration by link name in increasing order + * - iteration by link name in decreasing order + * - iteration by link creation order in increasing order + * - iteration by link creation order in decreasing order + * + * Based on how the test is written, this will mean that the dataset names + * will run in increasing order on the first and fourth tests and decreasing + * order on the second and third tests. + */ + test_iteration = (counter_val / LINK_ITER_HARD_LINKS_TEST_NUM_LINKS); + if (test_iteration == 0 || test_iteration == 3) { + HDsnprintf(expected_link_name, LINK_ITER_HARD_LINKS_TEST_BUF_SIZE, + LINK_ITER_HARD_LINKS_TEST_LINK_NAME "%d", + (int)(counter_val % LINK_ITER_HARD_LINKS_TEST_NUM_LINKS)); + } + else { + HDsnprintf(expected_link_name, LINK_ITER_HARD_LINKS_TEST_BUF_SIZE, + LINK_ITER_HARD_LINKS_TEST_LINK_NAME "%d", + (int)(LINK_ITER_HARD_LINKS_TEST_NUM_LINKS - + (counter_val % LINK_ITER_HARD_LINKS_TEST_NUM_LINKS) - 1)); + } + + if (HDstrncmp(name, expected_link_name, LINK_ITER_HARD_LINKS_TEST_BUF_SIZE)) { + HDprintf(" link name '%s' didn't match expected name '%s'\n", name, expected_link_name); + ret_val = H5_ITER_ERROR; + goto done; + } + +done: + (*i)++; + + return ret_val; +} + +/* + * Link iteration callback for the soft links test which iterates + * through all of the links in the test group and checks to make sure + * their names and link classes match what is expected. + */ +static herr_t +link_iter_soft_links_cb(hid_t group_id, const char *name, const H5L_info2_t *info, void *op_data) +{ + size_t *i = (size_t *)op_data; + size_t counter_val = *((size_t *)op_data); + size_t test_iteration; + char expected_link_name[LINK_ITER_SOFT_LINKS_TEST_BUF_SIZE]; + herr_t ret_val = H5_ITER_CONT; + + UNUSED(group_id); + UNUSED(op_data); + + if (H5L_TYPE_SOFT != info->type) { + ret_val = H5_ITER_ERROR; + HDprintf(" link type for link '%s' was not H5L_TYPE_SOFT!\n", name); + goto done; + } + + /* + * Four tests are run in the following order per link iteration API call: + * + * - iteration by link name in increasing order + * - iteration by link name in decreasing order + * - iteration by link creation order in increasing order + * - iteration by link creation order in decreasing order + * + * Based on how the test is written, this will mean that the link names + * will run in increasing order on the first and fourth tests and decreasing + * order on the second and third tests. + */ + test_iteration = (counter_val / LINK_ITER_SOFT_LINKS_TEST_NUM_LINKS); + if (test_iteration == 0 || test_iteration == 3) { + HDsnprintf(expected_link_name, LINK_ITER_SOFT_LINKS_TEST_BUF_SIZE, + LINK_ITER_SOFT_LINKS_TEST_LINK_NAME "%d", + (int)(counter_val % LINK_ITER_SOFT_LINKS_TEST_NUM_LINKS)); + } + else { + HDsnprintf(expected_link_name, LINK_ITER_SOFT_LINKS_TEST_BUF_SIZE, + LINK_ITER_SOFT_LINKS_TEST_LINK_NAME "%d", + (int)(LINK_ITER_SOFT_LINKS_TEST_NUM_LINKS - + (counter_val % LINK_ITER_SOFT_LINKS_TEST_NUM_LINKS) - 1)); + } + + if (HDstrncmp(name, expected_link_name, LINK_ITER_SOFT_LINKS_TEST_BUF_SIZE)) { + HDprintf(" link name '%s' didn't match expected name '%s'\n", name, expected_link_name); + ret_val = H5_ITER_ERROR; + goto done; + } + +done: + (*i)++; + + return ret_val; +} + +/* + * Link iteration callback for the external links test which iterates + * through all of the links in the test group and checks to make sure + * their names and link classes match what is expected. + */ +#ifndef NO_EXTERNAL_LINKS +static herr_t +link_iter_external_links_cb(hid_t group_id, const char *name, const H5L_info2_t *info, void *op_data) +{ + size_t *i = (size_t *)op_data; + size_t counter_val = *((size_t *)op_data); + size_t test_iteration; + char expected_link_name[LINK_ITER_EXT_LINKS_TEST_BUF_SIZE]; + herr_t ret_val = H5_ITER_CONT; + + UNUSED(group_id); + UNUSED(op_data); + + if (H5L_TYPE_EXTERNAL != info->type) { + ret_val = H5_ITER_ERROR; + HDprintf(" link type for link '%s' was not H5L_TYPE_EXTERNAL!\n", name); + goto done; + } + + /* + * Four tests are run in the following order per link iteration API call: + * + * - iteration by link name in increasing order + * - iteration by link name in decreasing order + * - iteration by link creation order in increasing order + * - iteration by link creation order in decreasing order + * + * Based on how the test is written, this will mean that the link names + * will run in increasing order on the first and fourth tests and decreasing + * order on the second and third tests. + */ + test_iteration = (counter_val / LINK_ITER_EXT_LINKS_TEST_NUM_LINKS); + if (test_iteration == 0 || test_iteration == 3) { + HDsnprintf(expected_link_name, LINK_ITER_EXT_LINKS_TEST_BUF_SIZE, + LINK_ITER_EXT_LINKS_TEST_LINK_NAME "%d", + (int)(counter_val % LINK_ITER_EXT_LINKS_TEST_NUM_LINKS)); + } + else { + HDsnprintf(expected_link_name, LINK_ITER_EXT_LINKS_TEST_BUF_SIZE, + LINK_ITER_EXT_LINKS_TEST_LINK_NAME "%d", + (int)(LINK_ITER_EXT_LINKS_TEST_NUM_LINKS - + (counter_val % LINK_ITER_EXT_LINKS_TEST_NUM_LINKS) - 1)); + } + + if (HDstrncmp(name, expected_link_name, LINK_ITER_EXT_LINKS_TEST_BUF_SIZE)) { + HDprintf(" link name '%s' didn't match expected name '%s'\n", name, expected_link_name); + ret_val = H5_ITER_ERROR; + goto done; + } + +done: + (*i)++; + + return ret_val; +} +#endif +#ifndef NO_USER_DEFINED_LINKS +static herr_t link_iter_ud_links_cb(hid_t group_id, const char *name, const H5L_info2_t *info, void *op_data); +#endif +/* + * Link iteration callback for the mixed link types test which iterates + * through all of the links in the test group and checks to make sure + * their names and link classes match what is expected. + */ +#if !defined(NO_EXTERNAL_LINKS) && !defined(NO_USER_DEFINED_LINKS) +static herr_t +link_iter_mixed_links_cb(hid_t group_id, const char *name, const H5L_info2_t *info, void *op_data) +{ + size_t *i = (size_t *)op_data; + size_t counter_val = *((size_t *)op_data); + herr_t ret_val = 0; + + UNUSED(group_id); + + if (!HDstrncmp(name, LINK_ITER_MIXED_LINKS_TEST_HARD_LINK_NAME, + strlen(LINK_ITER_MIXED_LINKS_TEST_HARD_LINK_NAME) + 1) && + (counter_val == 1 || counter_val == 4 || counter_val == 6 || counter_val == 11)) { + if (H5L_TYPE_HARD != info->type) { + ret_val = -1; + HDprintf(" link type for link '%s' was not H5L_TYPE_HARD!\n", name); + } + + goto done; + } + else if (!HDstrncmp(name, LINK_ITER_MIXED_LINKS_TEST_SOFT_LINK_NAME, + strlen(LINK_ITER_MIXED_LINKS_TEST_SOFT_LINK_NAME) + 1) && + (counter_val == 2 || counter_val == 3 || counter_val == 7 || counter_val == 10)) { + if (H5L_TYPE_SOFT != info->type) { + ret_val = -1; + HDprintf(" link type for link '%s' was not H5L_TYPE_SOFT!\n", name); + } + + goto done; + } + else if (!HDstrncmp(name, LINK_ITER_MIXED_LINKS_TEST_EXT_LINK_NAME, + strlen(LINK_ITER_MIXED_LINKS_TEST_EXT_LINK_NAME) + 1) && + (counter_val == 0 || counter_val == 5 || counter_val == 8 || counter_val == 9)) { + if (H5L_TYPE_EXTERNAL != info->type) { + ret_val = -1; + HDprintf(" link type for link '%s' was not H5L_TYPE_EXTERNAL!\n", name); + } + + goto done; + } + + HDprintf(" link name '%s' didn't match known names or came in an incorrect order\n", name); + + ret_val = -1; + +done: + (*i)++; + + return ret_val; +} +#endif + +/* + * Link iteration callback for the H5Literate(_by_name)2 invalid + * parameters test which simply does nothing. + */ +static herr_t +link_iter_invalid_params_cb(hid_t group_id, const char *name, const H5L_info2_t *info, void *op_data) +{ + UNUSED(group_id); + UNUSED(name); + UNUSED(info); + UNUSED(op_data); + + return 0; +} + +/* + * Link iteration callback for the 0 links iteration test which + * simply does nothing. + */ +static herr_t +link_iter_0_links_cb(hid_t group_id, const char *name, const H5L_info2_t *info, void *op_data) +{ + UNUSED(group_id); + UNUSED(name); + UNUSED(info); + UNUSED(op_data); + + return 0; +} + +/* + * Link iteration callback to test that the index-saving behavior of H5Literate2 + * works correctly. + */ +#if !defined(NO_EXTERNAL_LINKS) && !defined(NO_USER_DEFINED_LINKS) +static herr_t +link_iter_idx_saving_cb(hid_t group_id, const char *name, const H5L_info2_t *info, void *op_data) +{ + int *broken = (int *)op_data; + + UNUSED(group_id); + + if (broken && !*broken && + !HDstrncmp(name, LINK_ITER_MIXED_LINKS_TEST_SOFT_LINK_NAME, + strlen(LINK_ITER_MIXED_LINKS_TEST_SOFT_LINK_NAME) + 1)) { + return (*broken = 1); + } + + if (!HDstrncmp(name, LINK_ITER_MIXED_LINKS_TEST_HARD_LINK_NAME, + strlen(LINK_ITER_MIXED_LINKS_TEST_HARD_LINK_NAME) + 1)) { + if (H5L_TYPE_HARD != info->type) { + H5_FAILED(); + HDprintf(" link type did not match\n"); + goto error; + } + } + else if (!HDstrncmp(name, LINK_ITER_MIXED_LINKS_TEST_SOFT_LINK_NAME, + strlen(LINK_ITER_MIXED_LINKS_TEST_SOFT_LINK_NAME) + 1)) { + if (H5L_TYPE_SOFT != info->type) { + H5_FAILED(); + HDprintf(" link type did not match\n"); + goto error; + } + } + else if (!HDstrncmp(name, LINK_ITER_MIXED_LINKS_TEST_EXT_LINK_NAME, + strlen(LINK_ITER_MIXED_LINKS_TEST_EXT_LINK_NAME) + 1)) { + if (H5L_TYPE_EXTERNAL != info->type) { + H5_FAILED(); + HDprintf(" link type did not match\n"); + goto error; + } + } + else { + H5_FAILED(); + HDprintf(" link name didn't match known names\n"); + goto error; + } + + return 0; + +error: + return -1; +} +#endif + +/* + * Link visiting callback for the hard links + no cycles test which + * iterates recursively through all of the links in the test group and + * checks to make sure their names and link classes match what is expected. + */ +static herr_t +link_visit_hard_links_no_cycles_cb(hid_t group_id, const char *name, const H5L_info2_t *info, void *op_data) +{ + hbool_t is_subgroup_link; + size_t *i = (size_t *)op_data; + size_t counter_val = *((size_t *)op_data); + size_t test_iteration; + size_t subgroup_number; + size_t link_idx_val; + char expected_link_name[LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_BUF_SIZE]; + herr_t ret_val = H5_ITER_CONT; + + UNUSED(group_id); + UNUSED(op_data); + + if (H5L_TYPE_HARD != info->type) { + ret_val = H5_ITER_ERROR; + HDprintf(" link type for link '%s' was not H5L_TYPE_HARD!\n", name); + goto done; + } + + /* + * Four tests are run in the following order per link visiting API call: + * + * - visitation by link name in increasing order + * - visitation by link name in decreasing order + * - visitation by link creation order in increasing order + * - visitation by link creation order in decreasing order + * + * Based on how the test is written, this will mean that the dataset and group + * names will run in increasing order on the first and fourth tests and decreasing + * order on the second and third tests. + */ + test_iteration = counter_val / LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST; + + /* Determine which subgroup is currently being processed */ + subgroup_number = + /* Take the current counter value modulo the total number of links per test iteration (datasets + + subgroups) */ + (counter_val % LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST) + /* and divide it by the number of links per subgroup + 1 to get the subgroup's index number. */ + / (LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_GROUP + 1); + + /* Determine whether the current link points to the current subgroup itself */ + is_subgroup_link = (counter_val % (LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_GROUP + 1) == 0); + if (!is_subgroup_link) { + /* Determine the index number of this link within its containing subgroup */ + link_idx_val = + /* Take the current counter value modulo the total number of links per test iteration (datasets + + subgroups) */ + (counter_val % LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST) + /* and take it modulo the number of links per subgroup + 1, finally subtracting 1 to get the + link's index number. */ + % (LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_GROUP + 1) - + 1; + } + + if (test_iteration == 0 || test_iteration == 3) { + if (is_subgroup_link) { + HDsnprintf(expected_link_name, LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NESTED_GRP_NAME "%d", (int)subgroup_number); + } + else { + HDsnprintf(expected_link_name, LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NESTED_GRP_NAME + "%d" + "/" LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_LINK_NAME "%d", + (int)subgroup_number, (int)link_idx_val); + } + } + else { + if (is_subgroup_link) { + HDsnprintf(expected_link_name, LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NESTED_GRP_NAME "%d", + (int)(LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_SUBGROUPS - subgroup_number - 1)); + } + else { + HDsnprintf(expected_link_name, LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NESTED_GRP_NAME + "%d" + "/" LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_LINK_NAME "%d", + (int)(LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_SUBGROUPS - subgroup_number - 1), + (int)(LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_GROUP - link_idx_val - 1)); + } + } + + if (HDstrncmp(name, expected_link_name, LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_BUF_SIZE)) { + HDprintf(" link name '%s' didn't match expected name '%s'\n", name, expected_link_name); + ret_val = H5_ITER_ERROR; + goto done; + } + +done: + (*i)++; + + return ret_val; +} + +/* + * Link visiting callback for the soft links + no cycles test which + * iterates recursively through all of the links in the test group and + * checks to make sure their names and link classes match what is expected. + */ +static herr_t +link_visit_soft_links_no_cycles_cb(hid_t group_id, const char *name, const H5L_info2_t *info, void *op_data) +{ + hbool_t is_subgroup_link; + size_t *i = (size_t *)op_data; + size_t counter_val = *((size_t *)op_data); + size_t test_iteration; + size_t subgroup_number; + size_t link_idx_val; + char expected_link_name[LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_BUF_SIZE]; + herr_t ret_val = H5_ITER_CONT; + + UNUSED(group_id); + UNUSED(op_data); + + /* Determine whether the current link points to the current subgroup itself */ + is_subgroup_link = (counter_val % (LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_GROUP + 1) == 0); + + if (is_subgroup_link) { + if (H5L_TYPE_HARD != info->type) { + ret_val = H5_ITER_ERROR; + HDprintf(" link type for link '%s' was not H5L_TYPE_HARD!\n", name); + goto done; + } + } + else { + if (H5L_TYPE_SOFT != info->type) { + ret_val = H5_ITER_ERROR; + HDprintf(" link type for link '%s' was not H5L_TYPE_SOFT!\n", name); + goto done; + } + } + + /* + * Four tests are run in the following order per link visiting API call: + * + * - visitation by link name in increasing order + * - visitation by link name in decreasing order + * - visitation by link creation order in increasing order + * - visitation by link creation order in decreasing order + * + * Based on how the test is written, this will mean that the link names will + * run in increasing order on the first and fourth tests and decreasing + * order on the second and third tests. + */ + test_iteration = counter_val / LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST; + + /* Determine which subgroup is currently being processed */ + subgroup_number = + /* Take the current counter value modulo the total number of links per test iteration (links + + subgroups) */ + (counter_val % LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST) + /* and divide it by the number of links per subgroup + 1 to get the subgroup's index number. */ + / (LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_GROUP + 1); + + if (!is_subgroup_link) { + /* Determine the index number of this link within its containing subgroup */ + link_idx_val = + /* Take the current counter value modulo the total number of links per test iteration (links + + subgroups) */ + (counter_val % LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST) + /* and take it modulo the number of links per subgroup + 1, finally subtracting 1 to get the + link's index number. */ + % (LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_GROUP + 1) - + 1; + } + + if (test_iteration == 0 || test_iteration == 3) { + if (is_subgroup_link) { + HDsnprintf(expected_link_name, LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NESTED_GRP_NAME "%d", (int)subgroup_number); + } + else { + HDsnprintf(expected_link_name, LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NESTED_GRP_NAME + "%d" + "/" LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_LINK_NAME "%d", + (int)subgroup_number, (int)link_idx_val); + } + } + else { + if (is_subgroup_link) { + HDsnprintf(expected_link_name, LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NESTED_GRP_NAME "%d", + (int)(LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_SUBGROUPS - subgroup_number - 1)); + } + else { + HDsnprintf(expected_link_name, LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NESTED_GRP_NAME + "%d" + "/" LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_LINK_NAME "%d", + (int)(LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_SUBGROUPS - subgroup_number - 1), + (int)(LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_GROUP - link_idx_val - 1)); + } + } + + if (HDstrncmp(name, expected_link_name, LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_BUF_SIZE)) { + HDprintf(" link name '%s' didn't match expected name '%s'\n", name, expected_link_name); + ret_val = H5_ITER_ERROR; + goto done; + } + +done: + (*i)++; + + return ret_val; +} + +/* + * Link visiting callback for the external links + no cycles test which + * iterates recursively through all of the links in the test group and + * checks to make sure their names and link classes match what is expected. + */ +#ifndef NO_EXTERNAL_LINKS +static herr_t +link_visit_external_links_no_cycles_cb(hid_t group_id, const char *name, const H5L_info2_t *info, + void *op_data) +{ + hbool_t is_subgroup_link; + size_t *i = (size_t *)op_data; + size_t counter_val = *((size_t *)op_data); + size_t test_iteration; + size_t subgroup_number; + size_t link_idx_val; + char expected_link_name[LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_BUF_SIZE]; + herr_t ret_val = H5_ITER_CONT; + + UNUSED(group_id); + UNUSED(op_data); + + /* Determine whether the current link points to the current subgroup itself */ + is_subgroup_link = (counter_val % (LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_GROUP + 1) == 0); + + if (is_subgroup_link) { + if (H5L_TYPE_HARD != info->type) { + ret_val = H5_ITER_ERROR; + HDprintf(" link type for link '%s' was not H5L_TYPE_HARD!\n", name); + goto done; + } + } + else { + if (H5L_TYPE_EXTERNAL != info->type) { + ret_val = H5_ITER_ERROR; + HDprintf(" link type for link '%s' was not H5L_TYPE_EXTERNAL!\n", name); + goto done; + } + } + + /* + * Four tests are run in the following order per link visiting API call: + * + * - visitation by link name in increasing order + * - visitation by link name in decreasing order + * - visitation by link creation order in increasing order + * - visitation by link creation order in decreasing order + * + * Based on how the test is written, this will mean that the link names will + * run in increasing order on the first and fourth tests and decreasing + * order on the second and third tests. + */ + test_iteration = counter_val / LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST; + + /* Determine which subgroup is currently being processed */ + subgroup_number = + /* Take the current counter value modulo the total number of links per test iteration (links + + subgroups) */ + (counter_val % LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST) + /* and divide it by the number of links per subgroup + 1 to get the subgroup's index number. */ + / (LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_GROUP + 1); + + if (!is_subgroup_link) { + /* Determine the index number of this link within its containing subgroup */ + link_idx_val = + /* Take the current counter value modulo the total number of links per test iteration (links + + subgroups) */ + (counter_val % LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST) + /* and take it modulo the number of links per subgroup + 1, finally subtracting 1 to get the + link's index number. */ + % (LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_GROUP + 1) - + 1; + } + + if (test_iteration == 0 || test_iteration == 3) { + if (is_subgroup_link) { + HDsnprintf(expected_link_name, LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NESTED_GRP_NAME "%d", (int)subgroup_number); + } + else { + HDsnprintf(expected_link_name, LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NESTED_GRP_NAME + "%d" + "/" LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_LINK_NAME "%d", + (int)subgroup_number, (int)link_idx_val); + } + } + else { + if (is_subgroup_link) { + HDsnprintf(expected_link_name, LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NESTED_GRP_NAME "%d", + (int)(LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_SUBGROUPS - subgroup_number - 1)); + } + else { + HDsnprintf(expected_link_name, LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NESTED_GRP_NAME + "%d" + "/" LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_LINK_NAME "%d", + (int)(LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_SUBGROUPS - subgroup_number - 1), + (int)(LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_GROUP - link_idx_val - 1)); + } + } + + if (HDstrncmp(name, expected_link_name, LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_BUF_SIZE)) { + HDprintf(" link name '%s' didn't match expected name '%s'\n", name, expected_link_name); + ret_val = H5_ITER_ERROR; + goto done; + } + +done: + (*i)++; + + return ret_val; +} +#endif +#ifndef NO_USER_DEFINED_LINKS +static herr_t link_visit_ud_links_no_cycles_cb(hid_t group_id, const char *name, const H5L_info2_t *info, + void *op_data); +#endif +/* + * Link visiting callback for the mixed link types + no cycles test which + * iterates recursively through all of the links in the test group and + * checks to make sure their names and link classes match what is expected. + */ +#if !defined(NO_EXTERNAL_LINKS) && !defined(NO_USER_DEFINED_LINKS) +static herr_t +link_visit_mixed_links_no_cycles_cb(hid_t group_id, const char *name, const H5L_info2_t *info, void *op_data) +{ + size_t *i = (size_t *)op_data; + size_t counter_val = *((size_t *)op_data); + herr_t ret_val = 0; + + UNUSED(group_id); + UNUSED(op_data); + + if (!HDstrncmp(name, + LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME2 + "/" LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME1, + strlen(LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME2 + "/" LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME1) + + 1) && + (counter_val == 2 || counter_val == 14 || counter_val == 18 || counter_val == 30)) { + if (H5L_TYPE_HARD != info->type) { + ret_val = -1; + HDprintf(" link type for link '%s' was not H5L_TYPE_HARD!\n", + LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME2 + "/" LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME1); + } + + goto done; + } + else if (!HDstrncmp(name, + LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME2 + "/" LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME2, + strlen(LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME2 + "/" LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME2) + + 1) && + (counter_val == 3 || counter_val == 13 || counter_val == 19 || counter_val == 29)) { + if (H5L_TYPE_SOFT != info->type) { + ret_val = -1; + HDprintf(" link type for link '%s' was not H5L_TYPE_SOFT!\n", + LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME2 + "/" LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME2); + } + + goto done; + } + else if (!HDstrncmp(name, + LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME3 + "/" LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME3, + strlen(LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME3 + "/" LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME3) + + 1) && + (counter_val == 6 || counter_val == 10 || counter_val == 22 || counter_val == 26)) { + if (H5L_TYPE_EXTERNAL != info->type) { + ret_val = -1; + HDprintf(" link type for link '%s' was not H5L_TYPE_EXTERNAL!\n", + LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME3 + "/" LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME3); + } + + goto done; + } + else if (!HDstrncmp(name, + LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME3 + "/" LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME4, + strlen(LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME3 + "/" LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME4) + + 1) && + (counter_val == 7 || counter_val == 9 || counter_val == 23 || counter_val == 25)) { + if (H5L_TYPE_HARD != info->type) { + ret_val = -1; + HDprintf(" link type for link '%s' was not H5L_TYPE_HARD!\n", + LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME3 + "/" LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME4); + } + + goto done; + } + else if (!HDstrncmp(name, + LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME2 + "/" LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_DSET_NAME, + strlen(LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME2 + "/" LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_DSET_NAME) + + 1) && + (counter_val == 1 || counter_val == 15 || counter_val == 17 || counter_val == 31)) { + if (H5L_TYPE_HARD != info->type) { + ret_val = -1; + HDprintf(" link type for link '%s' was not H5L_TYPE_HARD!\n", + LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME2 + "/" LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_DSET_NAME); + } + + goto done; + } + else if (!HDstrncmp(name, + LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME3 + "/" LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_DSET_NAME2, + strlen(LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME3 + "/" LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_DSET_NAME2) + + 1) && + (counter_val == 5 || counter_val == 11 || counter_val == 21 || counter_val == 27)) { + if (H5L_TYPE_HARD != info->type) { + ret_val = -1; + HDprintf(" link type for link '%s' was not H5L_TYPE_HARD!\n", + LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME3 + "/" LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_DSET_NAME2); + } + + goto done; + } + else if (!HDstrncmp(name, LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME2, + strlen(LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME2) + 1) && + (counter_val == 0 || counter_val == 12 || counter_val == 16 || counter_val == 28)) { + if (H5L_TYPE_HARD != info->type) { + ret_val = -1; + HDprintf(" link type for link '%s' was not H5L_TYPE_HARD!\n", + LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME2); + } + + goto done; + } + else if (!HDstrncmp(name, LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME3, + strlen(LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME3) + 1) && + (counter_val == 4 || counter_val == 8 || counter_val == 20 || counter_val == 24)) { + if (H5L_TYPE_HARD != info->type) { + ret_val = -1; + HDprintf(" link type for link '%s' was not H5L_TYPE_HARD!\n", + LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME3); + } + + goto done; + } + + HDprintf(" link name '%s' didn't match known names or came in an incorrect order\n", name); + + ret_val = -1; + +done: + (*i)++; + + return ret_val; +} +#endif + +/* + * Link visiting callback for the hard links + cycles test which + * iterates recursively through all of the links in the test group and + * checks to make sure their names and link classes match what is expected. + */ +static herr_t +link_visit_hard_links_cycles_cb(hid_t group_id, const char *name, const H5L_info2_t *info, void *op_data) +{ + hbool_t is_subgroup_link; + size_t *i = (size_t *)op_data; + size_t counter_val = *((size_t *)op_data); + size_t test_iteration; + size_t subgroup_number; + size_t link_idx_val; + char expected_link_name[LINK_VISIT_HARD_LINKS_CYCLE_TEST_BUF_SIZE]; + herr_t ret_val = H5_ITER_CONT; + + UNUSED(group_id); + UNUSED(op_data); + + if (H5L_TYPE_HARD != info->type) { + ret_val = H5_ITER_ERROR; + HDprintf(" link type for link '%s' was not H5L_TYPE_HARD!\n", name); + goto done; + } + + /* + * Four tests are run in the following order per link visiting API call: + * + * - visitation by link name in increasing order + * - visitation by link name in decreasing order + * - visitation by link creation order in increasing order + * - visitation by link creation order in decreasing order + * + * Based on how the test is written, this will mean that the link and group + * names will run in increasing order on the first and fourth tests and decreasing + * order on the second and third tests. + */ + test_iteration = counter_val / LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST; + + /* Determine which subgroup is currently being processed */ + subgroup_number = + /* Take the current counter value modulo the total number of links per test iteration (links + + subgroups) */ + (counter_val % LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST) + /* and divide it by the number of links per subgroup + 1 to get the subgroup's index number. */ + / (LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_LINKS_PER_GROUP + 1); + + /* Determine whether the current link points to the current subgroup itself */ + is_subgroup_link = (counter_val % (LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_LINKS_PER_GROUP + 1) == 0); + if (!is_subgroup_link) { + /* Determine the index number of this link within its containing subgroup */ + link_idx_val = + /* Take the current counter value modulo the total number of links per test iteration (links + + subgroups) */ + (counter_val % LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST) + /* and take it modulo the number of links per subgroup + 1, finally subtracting 1 to get the + link's index number. */ + % (LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_LINKS_PER_GROUP + 1) - + 1; + } + + if (test_iteration == 0 || test_iteration == 3) { + if (is_subgroup_link) { + HDsnprintf(expected_link_name, LINK_VISIT_HARD_LINKS_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_HARD_LINKS_CYCLE_TEST_NESTED_GRP_NAME "%d", (int)subgroup_number); + } + else { + HDsnprintf(expected_link_name, LINK_VISIT_HARD_LINKS_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_HARD_LINKS_CYCLE_TEST_NESTED_GRP_NAME + "%d" + "/" LINK_VISIT_HARD_LINKS_CYCLE_TEST_LINK_NAME "%d", + (int)subgroup_number, (int)link_idx_val); + } + } + else { + if (is_subgroup_link) { + HDsnprintf(expected_link_name, LINK_VISIT_HARD_LINKS_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_HARD_LINKS_CYCLE_TEST_NESTED_GRP_NAME "%d", + (int)(LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_SUBGROUPS - subgroup_number - 1)); + } + else { + HDsnprintf(expected_link_name, LINK_VISIT_HARD_LINKS_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_HARD_LINKS_CYCLE_TEST_NESTED_GRP_NAME + "%d" + "/" LINK_VISIT_HARD_LINKS_CYCLE_TEST_LINK_NAME "%d", + (int)(LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_SUBGROUPS - subgroup_number - 1), + (int)(LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_LINKS_PER_GROUP - link_idx_val - 1)); + } + } + + if (HDstrncmp(name, expected_link_name, LINK_VISIT_HARD_LINKS_CYCLE_TEST_BUF_SIZE)) { + HDprintf(" link name '%s' didn't match expected name '%s'\n", name, expected_link_name); + ret_val = H5_ITER_ERROR; + goto done; + } + +done: + (*i)++; + + return ret_val; +} + +/* + * Link visiting callback for the soft links + cycles test which + * iterates recursively through all of the links in the test group and + * checks to make sure their names and link classes match what is expected. + */ +static herr_t +link_visit_soft_links_cycles_cb(hid_t group_id, const char *name, const H5L_info2_t *info, void *op_data) +{ + hbool_t is_subgroup_link; + size_t *i = (size_t *)op_data; + size_t counter_val = *((size_t *)op_data); + size_t test_iteration; + size_t subgroup_number; + size_t link_idx_val; + char expected_link_name[LINK_VISIT_SOFT_LINKS_CYCLE_TEST_BUF_SIZE]; + herr_t ret_val = H5_ITER_CONT; + + UNUSED(group_id); + UNUSED(op_data); + + /* Determine whether the current link points to the current subgroup itself */ + is_subgroup_link = (counter_val % (LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_LINKS_PER_GROUP + 1) == 0); + + if (is_subgroup_link) { + if (H5L_TYPE_HARD != info->type) { + ret_val = H5_ITER_ERROR; + HDprintf(" link type for link '%s' was not H5L_TYPE_HARD!\n", name); + goto done; + } + } + else { + if (H5L_TYPE_SOFT != info->type) { + ret_val = H5_ITER_ERROR; + HDprintf(" link type for link '%s' was not H5L_TYPE_SOFT!\n", name); + goto done; + } + } + + /* + * Four tests are run in the following order per link visiting API call: + * + * - visitation by link name in increasing order + * - visitation by link name in decreasing order + * - visitation by link creation order in increasing order + * - visitation by link creation order in decreasing order + * + * Based on how the test is written, this will mean that the link and group + * names will run in increasing order on the first and fourth tests and decreasing + * order on the second and third tests. + */ + test_iteration = counter_val / LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST; + + /* Determine which subgroup is currently being processed */ + subgroup_number = + /* Take the current counter value modulo the total number of links per test iteration (links + + subgroups) */ + (counter_val % LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST) + /* and divide it by the number of links per subgroup + 1 to get the subgroup's index number. */ + / (LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_LINKS_PER_GROUP + 1); + + if (!is_subgroup_link) { + /* Determine the index number of this link within its containing subgroup */ + link_idx_val = + /* Take the current counter value modulo the total number of links per test iteration (links + + subgroups) */ + (counter_val % LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST) + /* and take it modulo the number of links per subgroup + 1, finally subtracting 1 to get the + link's index number. */ + % (LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_LINKS_PER_GROUP + 1) - + 1; + } + + if (test_iteration == 0 || test_iteration == 3) { + if (is_subgroup_link) { + HDsnprintf(expected_link_name, LINK_VISIT_SOFT_LINKS_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NESTED_GRP_NAME "%d", (int)subgroup_number); + } + else { + HDsnprintf(expected_link_name, LINK_VISIT_SOFT_LINKS_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NESTED_GRP_NAME + "%d" + "/" LINK_VISIT_SOFT_LINKS_CYCLE_TEST_LINK_NAME "%d", + (int)subgroup_number, (int)link_idx_val); + } + } + else { + if (is_subgroup_link) { + HDsnprintf(expected_link_name, LINK_VISIT_SOFT_LINKS_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NESTED_GRP_NAME "%d", + (int)(LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_SUBGROUPS - subgroup_number - 1)); + } + else { + HDsnprintf(expected_link_name, LINK_VISIT_SOFT_LINKS_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NESTED_GRP_NAME + "%d" + "/" LINK_VISIT_SOFT_LINKS_CYCLE_TEST_LINK_NAME "%d", + (int)(LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_SUBGROUPS - subgroup_number - 1), + (int)(LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_LINKS_PER_GROUP - link_idx_val - 1)); + } + } + + if (HDstrncmp(name, expected_link_name, LINK_VISIT_SOFT_LINKS_CYCLE_TEST_BUF_SIZE)) { + HDprintf(" link name '%s' didn't match expected name '%s'\n", name, expected_link_name); + ret_val = H5_ITER_ERROR; + goto done; + } + +done: + (*i)++; + + return ret_val; +} + +/* + * Link visiting callback for the external links + cycles test which + * iterates recursively through all of the links in the test group and + * checks to make sure their names and link classes match what is expected. + */ +#ifndef NO_EXTERNAL_LINKS +static herr_t +link_visit_external_links_cycles_cb(hid_t group_id, const char *name, const H5L_info2_t *info, void *op_data) +{ + hbool_t is_subgroup_link; + size_t *i = (size_t *)op_data; + size_t counter_val = *((size_t *)op_data); + size_t test_iteration; + size_t subgroup_number; + size_t link_idx_val; + char expected_link_name[LINK_VISIT_EXT_LINKS_CYCLE_TEST_BUF_SIZE]; + herr_t ret_val = H5_ITER_CONT; + + UNUSED(group_id); + UNUSED(op_data); + + /* Determine whether the current link points to the current subgroup itself */ + is_subgroup_link = (counter_val % (LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_LINKS_PER_GROUP + 1) == 0); + + if (is_subgroup_link) { + if (H5L_TYPE_HARD != info->type) { + ret_val = H5_ITER_ERROR; + HDprintf(" link type for link '%s' was not H5L_TYPE_HARD!\n", name); + goto done; + } + } + else { + if (H5L_TYPE_EXTERNAL != info->type) { + ret_val = H5_ITER_ERROR; + HDprintf(" link type for link '%s' was not H5L_TYPE_EXTERNAL!\n", name); + goto done; + } + } + + /* + * Four tests are run in the following order per link visiting API call: + * + * - visitation by link name in increasing order + * - visitation by link name in decreasing order + * - visitation by link creation order in increasing order + * - visitation by link creation order in decreasing order + * + * Based on how the test is written, this will mean that the link and group + * names will run in increasing order on the first and fourth tests and decreasing + * order on the second and third tests. + */ + test_iteration = counter_val / LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST; + + /* Determine which subgroup is currently being processed */ + subgroup_number = + /* Take the current counter value modulo the total number of links per test iteration (links + + subgroups) */ + (counter_val % LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST) + /* and divide it by the number of links per subgroup + 1 to get the subgroup's index number. */ + / (LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_LINKS_PER_GROUP + 1); + + if (!is_subgroup_link) { + /* Determine the index number of this link within its containing subgroup */ + link_idx_val = + /* Take the current counter value modulo the total number of links per test iteration (links + + subgroups) */ + (counter_val % LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST) + /* and take it modulo the number of links per subgroup + 1, finally subtracting 1 to get the + link's index number. */ + % (LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_LINKS_PER_GROUP + 1) - + 1; + } + + if (test_iteration == 0 || test_iteration == 3) { + if (is_subgroup_link) { + HDsnprintf(expected_link_name, LINK_VISIT_EXT_LINKS_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_EXT_LINKS_CYCLE_TEST_NESTED_GRP_NAME "%d", (int)subgroup_number); + } + else { + HDsnprintf(expected_link_name, LINK_VISIT_EXT_LINKS_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_EXT_LINKS_CYCLE_TEST_NESTED_GRP_NAME + "%d" + "/" LINK_VISIT_EXT_LINKS_CYCLE_TEST_LINK_NAME "%d", + (int)subgroup_number, (int)link_idx_val); + } + } + else { + if (is_subgroup_link) { + HDsnprintf(expected_link_name, LINK_VISIT_EXT_LINKS_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_EXT_LINKS_CYCLE_TEST_NESTED_GRP_NAME "%d", + (int)(LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_SUBGROUPS - subgroup_number - 1)); + } + else { + HDsnprintf(expected_link_name, LINK_VISIT_EXT_LINKS_CYCLE_TEST_BUF_SIZE, + LINK_VISIT_EXT_LINKS_CYCLE_TEST_NESTED_GRP_NAME + "%d" + "/" LINK_VISIT_EXT_LINKS_CYCLE_TEST_LINK_NAME "%d", + (int)(LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_SUBGROUPS - subgroup_number - 1), + (int)(LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_LINKS_PER_GROUP - link_idx_val - 1)); + } + } + + if (HDstrncmp(name, expected_link_name, LINK_VISIT_EXT_LINKS_CYCLE_TEST_BUF_SIZE)) { + HDprintf(" link name '%s' didn't match expected name '%s'\n", name, expected_link_name); + ret_val = H5_ITER_ERROR; + goto done; + } + +done: + (*i)++; + + return ret_val; +} +#endif +#ifndef NO_USER_DEFINED_LINKS +static herr_t link_visit_ud_links_cycles_cb(hid_t group_id, const char *name, const H5L_info2_t *info, + void *op_data); +#endif +/* + * Link visiting callback for the mixed link types + cycles test which + * iterates recursively through all of the links in the test group and + * checks to make sure their names and link classes match what is expected. + */ +#if !defined(NO_EXTERNAL_LINKS) && !defined(NO_USER_DEFINED_LINKS) +static herr_t +link_visit_mixed_links_cycles_cb(hid_t group_id, const char *name, const H5L_info2_t *info, void *op_data) +{ + size_t *i = (size_t *)op_data; + size_t counter_val = *((size_t *)op_data); + herr_t ret_val = 0; + + UNUSED(group_id); + UNUSED(op_data); + + if (!HDstrncmp(name, + LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME2 + "/" LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME1, + strlen(LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME2 + "/" LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME1) + + 1) && + (counter_val == 1 || counter_val == 11 || counter_val == 13 || counter_val == 23)) { + if (H5L_TYPE_HARD != info->type) { + ret_val = -1; + HDprintf(" link type for link '%s' was not H5L_TYPE_HARD!\n", + LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME2 + "/" LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME1); + } + + goto done; + } + else if (!HDstrncmp(name, + LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME2 + "/" LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME2, + strlen(LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME2 + "/" LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME2) + + 1) && + (counter_val == 2 || counter_val == 10 || counter_val == 14 || counter_val == 22)) { + if (H5L_TYPE_SOFT != info->type) { + ret_val = -1; + HDprintf(" link type for link '%s' was not H5L_TYPE_SOFT!\n", + LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME2 + "/" LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME2); + } + + goto done; + } + else if (!HDstrncmp(name, + LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME3 + "/" LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME3, + strlen(LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME3 + "/" LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME3) + + 1) && + (counter_val == 4 || counter_val == 8 || counter_val == 16 || counter_val == 20)) { + if (H5L_TYPE_EXTERNAL != info->type) { + ret_val = -1; + HDprintf(" link type for link '%s' was not H5L_TYPE_EXTERNAL!\n", + LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME3 + "/" LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME3); + } + + goto done; + } + else if (!HDstrncmp(name, + LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME3 + "/" LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME4, + strlen(LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME3 + "/" LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME4) + + 1) && + (counter_val == 5 || counter_val == 7 || counter_val == 17 || counter_val == 19)) { + if (H5L_TYPE_HARD != info->type) { + ret_val = -1; + HDprintf(" link type for link '%s' was not H5L_TYPE_HARD!\n", + LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME3 + "/" LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME4); + } + + goto done; + } + else if (!HDstrncmp(name, LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME2, + strlen(LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME2) + 1) && + (counter_val == 0 || counter_val == 9 || counter_val == 12 || counter_val == 21)) { + if (H5L_TYPE_HARD != info->type) { + ret_val = -1; + HDprintf(" link type for link '%s' was not H5L_TYPE_HARD!\n", + LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME2); + } + + goto done; + } + else if (!HDstrncmp(name, LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME3, + strlen(LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME3) + 1) && + (counter_val == 3 || counter_val == 6 || counter_val == 15 || counter_val == 18)) { + if (H5L_TYPE_HARD != info->type) { + ret_val = -1; + HDprintf(" link type for link '%s' was not H5L_TYPE_HARD!\n", + LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME3); + } + + goto done; + } + + HDprintf(" link name '%s' didn't match known names or came in an incorrect order\n", name); + + ret_val = -1; + +done: + (*i)++; + + return ret_val; +} +#endif + +/* + * Link visiting callback for the H5Lvisit(_by_name)2 invalid + * parameters test which simply does nothing. + */ +static herr_t +link_visit_invalid_params_cb(hid_t group_id, const char *name, const H5L_info2_t *info, void *op_data) +{ + UNUSED(group_id); + UNUSED(name); + UNUSED(info); + UNUSED(op_data); + + return 0; +} + +/* + * Link visiting callback for the 0 links visiting test which + * simply does nothing. + */ +static herr_t +link_visit_0_links_cb(hid_t group_id, const char *name, const H5L_info2_t *info, void *op_data) +{ + UNUSED(group_id); + UNUSED(name); + UNUSED(info); + UNUSED(op_data); + + return 0; +} + +/* + * Cleanup temporary test files + */ +static void +cleanup_files(void) +{ + H5Fdelete(EXTERNAL_LINK_TEST_FILE_NAME, H5P_DEFAULT); + H5Fdelete(EXTERNAL_LINK_INVALID_PARAMS_TEST_FILE_NAME, H5P_DEFAULT); +} + +int +H5_api_link_test(void) +{ + size_t i; + int nerrors; + + HDprintf("**********************************************\n"); + HDprintf("* *\n"); + HDprintf("* API Link Tests *\n"); + HDprintf("* *\n"); + HDprintf("**********************************************\n\n"); + + for (i = 0, nerrors = 0; i < ARRAY_LENGTH(link_tests); i++) { + nerrors += (*link_tests[i])() ? 1 : 0; + } + + HDprintf("\n"); + + HDprintf("Cleaning up testing files\n"); + cleanup_files(); + + return nerrors; +} diff --git a/test/API/H5_api_link_test.h b/test/API/H5_api_link_test.h new file mode 100644 index 0000000..e161517 --- /dev/null +++ b/test/API/H5_api_link_test.h @@ -0,0 +1,437 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef H5_API_LINK_TEST_H +#define H5_API_LINK_TEST_H + +#include "H5_api_test.h" + +int H5_api_link_test(void); + +/********************************************* + * * + * API Link test defines * + * * + *********************************************/ + +#define HARD_LINK_TEST_GROUP_NAME "hard_link_creation_test" +#define HARD_LINK_TEST_LINK_NAME "hard_link" + +#define HARD_LINK_TEST_GROUP_LONG_NAME "hard_link_long_name" +#define MAX_NAME_LEN ((64 * 1024) + 1024) + +#define HARD_LINK_TEST_GROUP_MANY_NAME "hard_link_many_name" +#define HARD_LINK_TEST_GROUP_MANY_FINAL_NAME "hard_link_final" +#define HARD_LINK_TEST_GROUP_MANY_NAME_BUF_SIZE 1024 + +#define H5L_SAME_LOC_TEST_GROUP_NAME "h5l_same_loc_test_group" +#define H5L_SAME_LOC_TEST_LINK_NAME1 "h5l_same_loc_test_link1" +#define H5L_SAME_LOC_TEST_LINK_NAME2 "h5l_same_loc_test_link2" + +#define HARD_LINK_INVALID_PARAMS_TEST_GROUP_NAME "hard_link_creation_invalid_params_test" +#define HARD_LINK_INVALID_PARAMS_TEST_LINK_NAME "hard_link" + +#define SOFT_LINK_EXISTING_RELATIVE_TEST_SUBGROUP_NAME "soft_link_to_existing_relative_path_test" +#define SOFT_LINK_EXISTING_RELATIVE_TEST_OBJECT_NAME "group" +#define SOFT_LINK_EXISTING_RELATIVE_TEST_LINK_NAME "soft_link_to_existing_relative_path" + +#define SOFT_LINK_EXISTING_ABSOLUTE_TEST_SUBGROUP_NAME "soft_link_to_existing_absolute_path_test" +#define SOFT_LINK_EXISTING_ABSOLUTE_TEST_LINK_NAME "soft_link_to_existing_absolute_path" + +#define SOFT_LINK_DANGLING_RELATIVE_TEST_SUBGROUP_NAME "soft_link_dangling_relative_path_test" +#define SOFT_LINK_DANGLING_RELATIVE_TEST_OBJECT_NAME "group" +#define SOFT_LINK_DANGLING_RELATIVE_TEST_LINK_NAME "soft_link_dangling_relative_path" + +#define SOFT_LINK_DANGLING_ABSOLUTE_TEST_SUBGROUP_NAME "soft_link_dangling_absolute_path_test" +#define SOFT_LINK_DANGLING_ABSOLUTE_TEST_OBJECT_NAME "group" +#define SOFT_LINK_DANGLING_ABSOLUTE_TEST_LINK_NAME "soft_link_dangling_absolute_path" + +#define SOFT_LINK_TEST_GROUP_LONG_NAME "soft_link_long_name" +#define SOFT_LINK_TEST_LONG_OBJECT_NAME "soft_link_object_name" + +#define SOFT_LINK_TEST_GROUP_MANY_NAME "soft_link_many_name" +#define SOFT_LINK_TEST_GROUP_MANY_FINAL_NAME "soft_link_final" +#define SOFT_LINK_TEST_GROUP_MANY_NAME_BUF_SIZE 1024 + +#define SOFT_LINK_INVALID_PARAMS_TEST_GROUP_NAME "soft_link_creation_invalid_params_test" +#define SOFT_LINK_INVALID_PARAMS_TEST_LINK_NAME "soft_link_to_root" + +#define EXTERNAL_LINK_TEST_SUBGROUP_NAME "external_link_test" +#define EXTERNAL_LINK_TEST_FILE_NAME "ext_link_file.h5" +#define EXTERNAL_LINK_TEST_LINK_NAME "ext_link" + +#define EXTERNAL_LINK_TEST_DANGLING_SUBGROUP_NAME "external_link_dangling_test" +#define EXTERNAL_LINK_TEST_DANGLING_LINK_NAME "dangling_ext_link" +#define EXTERNAL_LINK_TEST_DANGLING_OBJECT_NAME "external_group" + +#define EXTERNAL_LINK_TEST_MULTI_NAME "external_link_multi_test" +#define EXTERNAL_LINK_TEST_MULTI_NAME_BUF_SIZE 1024 +#define EXTERNAL_LINK_TEST_FILE_NAME2 "ext_link_file_2.h5" +#define EXTERNAL_LINK_TEST_FILE_NAME3 "ext_link_file_3.h5" +#define EXTERNAL_LINK_TEST_FILE_NAME4 "ext_link_file_4.h5" + +#define EXTERNAL_LINK_TEST_PING_PONG_NAME1 "ext_link_file_ping_pong_1.h5" +#define EXTERNAL_LINK_TEST_PING_PONG_NAME2 "ext_link_file_ping_pong_2.h5" +#define EXTERNAL_LINK_TEST_PING_PONG_NAME_BUF_SIZE 1024 + +#define EXTERNAL_LINK_INVALID_PARAMS_TEST_GROUP_NAME "external_link_creation_invalid_params_test" +#define EXTERNAL_LINK_INVALID_PARAMS_TEST_FILE_NAME "ext_link_invalid_params_file.h5" +#define EXTERNAL_LINK_INVALID_PARAMS_TEST_LINK_NAME "external_link" + +#define UD_LINK_TEST_UDATA_MAX_SIZE 256 +#define UD_LINK_TEST_GROUP_NAME "ud_link_creation_test" +#define UD_LINK_TEST_LINK_NAME "ud_link" + +#define UD_LINK_INVALID_PARAMS_TEST_UDATA_MAX_SIZE 256 +#define UD_LINK_INVALID_PARAMS_TEST_GROUP_NAME "ud_link_creation_invalid_params_test" +#define UD_LINK_INVALID_PARAMS_TEST_LINK_NAME "ud_link" + +#define LINK_DELETE_TEST_NESTED_GRP_NAME "nested_grp" +#define LINK_DELETE_TEST_HARD_LINK_NAME "hard_link" +#define LINK_DELETE_TEST_NESTED_HARD_LINK_NAME \ + LINK_DELETE_TEST_NESTED_GRP_NAME "/" LINK_DELETE_TEST_HARD_LINK_NAME +#define LINK_DELETE_TEST_HARD_LINK_NAME2 LINK_DELETE_TEST_HARD_LINK_NAME "2" +#define LINK_DELETE_TEST_HARD_LINK_NAME3 LINK_DELETE_TEST_HARD_LINK_NAME "3" +#define LINK_DELETE_TEST_SOFT_LINK_NAME "soft_link" +#define LINK_DELETE_TEST_SOFT_LINK_NAME2 LINK_DELETE_TEST_SOFT_LINK_NAME "2" +#define LINK_DELETE_TEST_SOFT_LINK_NAME3 LINK_DELETE_TEST_SOFT_LINK_NAME "3" +#define LINK_DELETE_TEST_EXTERNAL_LINK_NAME "external_link" +#define LINK_DELETE_TEST_EXTERNAL_LINK_NAME2 LINK_DELETE_TEST_EXTERNAL_LINK_NAME "2" +#define LINK_DELETE_TEST_EXTERNAL_LINK_NAME3 LINK_DELETE_TEST_EXTERNAL_LINK_NAME "3" +#define LINK_DELETE_TEST_SUBGROUP_NAME "link_delete_test" +#define LINK_DELETE_TEST_SUBGROUP1_NAME "H5Ldelete_hard_link" +#define LINK_DELETE_TEST_NESTED_SUBGROUP_NAME1 "H5Ldelete_nested_hard_link" +#define LINK_DELETE_TEST_SUBGROUP2_NAME "H5Ldelete_soft_link" +#define LINK_DELETE_TEST_SUBGROUP3_NAME "H5Ldelete_external_link" +#define LINK_DELETE_TEST_SUBGROUP4_NAME "H5Ldelete_ud_link" +#define LINK_DELETE_TEST_SUBGROUP5_NAME "H5Ldelete_by_idx_hard_link_crt_order_increasing" +#define LINK_DELETE_TEST_SUBGROUP6_NAME "H5Ldelete_by_idx_hard_link_crt_order_decreasing" +#define LINK_DELETE_TEST_SUBGROUP7_NAME "H5Ldelete_by_idx_hard_link_name_order_increasing" +#define LINK_DELETE_TEST_SUBGROUP8_NAME "H5Ldelete_by_idx_hard_link_name_order_decreasing" +#define LINK_DELETE_TEST_SUBGROUP9_NAME "H5Ldelete_by_idx_soft_link_crt_order_increasing" +#define LINK_DELETE_TEST_SUBGROUP10_NAME "H5Ldelete_by_idx_soft_link_crt_order_decreasing" +#define LINK_DELETE_TEST_SUBGROUP11_NAME "H5Ldelete_by_idx_soft_link_name_order_increasing" +#define LINK_DELETE_TEST_SUBGROUP12_NAME "H5Ldelete_by_idx_soft_link_name_order_decreasing" +#define LINK_DELETE_TEST_SUBGROUP13_NAME "H5Ldelete_by_idx_external_link_crt_order_increasing" +#define LINK_DELETE_TEST_SUBGROUP14_NAME "H5Ldelete_by_idx_external_link_crt_order_decreasing" +#define LINK_DELETE_TEST_SUBGROUP15_NAME "H5Ldelete_by_idx_external_link_name_order_increasing" +#define LINK_DELETE_TEST_SUBGROUP16_NAME "H5Ldelete_by_idx_external_link_name_order_decreasing" +#define LINK_DELETE_TEST_SUBGROUP17_NAME "H5Ldelete_by_idx_ud_link_crt_order_increasing" +#define LINK_DELETE_TEST_SUBGROUP18_NAME "H5Ldelete_by_idx_ud_link_crt_order_decreasing" +#define LINK_DELETE_TEST_SUBGROUP19_NAME "H5Ldelete_by_idx_ud_link_name_order_increasing" +#define LINK_DELETE_TEST_SUBGROUP20_NAME "H5Ldelete_by_idx_ud_link_name_order_decreasing" + +#define LINK_DELETE_RESET_MAX_CRT_ORDER_TEST_SUBGROUP_NAME "H5Ldelete_reset_grp_max_crt_order_test" +#define LINK_DELETE_RESET_MAX_CRT_ORDER_TEST_SUBGROUP1_NAME "H5Ldelete_bottom_up" +#define LINK_DELETE_RESET_MAX_CRT_ORDER_TEST_SUBGROUP2_NAME "H5Ldelete_top_down" +#define LINK_DELETE_RESET_MAX_CRT_ORDER_TEST_NUM_LINKS 5 +#define LINK_DELETE_RESET_MAX_CRT_ORDER_TEST_BUF_SIZE 1024 + +#define LINK_DELETE_INVALID_PARAMS_TEST_HARD_LINK_NAME "hard_link" +#define LINK_DELETE_INVALID_PARAMS_TEST_GROUP_NAME "link_deletion_invalid_params_test" + +#define COPY_LINK_TEST_LINK_VAL_BUF_SIZE 1024 +#define COPY_LINK_TEST_EXTERNAL_LINK_NAME "external_link" +#define COPY_LINK_TEST_EXTERNAL_LINK_NAME2 COPY_LINK_TEST_EXTERNAL_LINK_NAME "2" +#define COPY_LINK_TEST_EXTERNAL_LINK_NAME3 COPY_LINK_TEST_EXTERNAL_LINK_NAME "3" +#define COPY_LINK_TEST_EXTERNAL_LINK_COPY_NAME "external_link_copy" +#define COPY_LINK_TEST_EXTERNAL_LINK_COPY_NAME2 COPY_LINK_TEST_EXTERNAL_LINK_COPY_NAME "2" +#define COPY_LINK_TEST_EXTERNAL_LINK_SAME_LOC_NAME "external_link_same_loc" +#define COPY_LINK_TEST_EXTERNAL_LINK_SAME_LOC_NAME2 COPY_LINK_TEST_EXTERNAL_LINK_SAME_LOC_NAME "2" +#define COPY_LINK_TEST_HARD_LINK_NAME "hard_link" +#define COPY_LINK_TEST_HARD_LINK_NAME2 COPY_LINK_TEST_HARD_LINK_NAME "2" +#define COPY_LINK_TEST_HARD_LINK_NAME3 COPY_LINK_TEST_HARD_LINK_NAME "3" +#define COPY_LINK_TEST_HARD_LINK_COPY_NAME "hard_link_copy" +#define COPY_LINK_TEST_HARD_LINK_COPY_NAME2 COPY_LINK_TEST_HARD_LINK_COPY_NAME "2" +#define COPY_LINK_TEST_HARD_LINK_SAME_LOC_NAME "hard_link_same_loc" +#define COPY_LINK_TEST_HARD_LINK_SAME_LOC_NAME2 COPY_LINK_TEST_HARD_LINK_SAME_LOC_NAME "2" +#define COPY_LINK_TEST_SOFT_LINK_TARGET_PATH "/" LINK_TEST_GROUP_NAME "/" COPY_LINK_TEST_SUBGROUP_NAME +#define COPY_LINK_TEST_SOFT_LINK_NAME "soft_link" +#define COPY_LINK_TEST_SOFT_LINK_NAME2 COPY_LINK_TEST_SOFT_LINK_NAME "2" +#define COPY_LINK_TEST_SOFT_LINK_NAME3 COPY_LINK_TEST_SOFT_LINK_NAME "3" +#define COPY_LINK_TEST_SOFT_LINK_COPY_NAME "soft_link_copy" +#define COPY_LINK_TEST_SOFT_LINK_COPY_NAME2 COPY_LINK_TEST_SOFT_LINK_COPY_NAME "2" +#define COPY_LINK_TEST_SOFT_LINK_SAME_LOC_NAME "soft_link_same_loc" +#define COPY_LINK_TEST_SOFT_LINK_SAME_LOC_NAME2 COPY_LINK_TEST_SOFT_LINK_SAME_LOC_NAME "2" +#define COPY_LINK_TEST_SRC_GROUP_NAME "src_group" +#define COPY_LINK_TEST_DST_GROUP_NAME "dst_group" +#define COPY_LINK_TEST_SUBGROUP_NAME "link_copy_test" + +#define COPY_LINK_INVALID_PARAMS_TEST_HARD_LINK_COPY_NAME "hard_link_copy" +#define COPY_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME "hard_link" +#define COPY_LINK_INVALID_PARAMS_TEST_HARD_LINK_NEW_NAME "hard_link_new" +#define COPY_LINK_INVALID_PARAMS_TEST_SRC_GROUP_NAME "src_group" +#define COPY_LINK_INVALID_PARAMS_TEST_DST_GROUP_NAME "dst_group" +#define COPY_LINK_INVALID_PARAMS_TEST_SUBGROUP_NAME "link_copy_invalid_params_test" + +#define MOVE_LINK_TEST_LINK_VAL_BUF_SIZE 1024 +#define MOVE_LINK_TEST_EXTERN_LINK_NAME "extern_link" +#define MOVE_LINK_TEST_EXTERN_LINK_NAME2 MOVE_LINK_TEST_EXTERN_LINK_NAME "2" +#define MOVE_LINK_TEST_EXTERN_LINK_NAME3 MOVE_LINK_TEST_EXTERN_LINK_NAME "3" +#define MOVE_LINK_TEST_EXTERN_LINK_NAME4 MOVE_LINK_TEST_EXTERN_LINK_NAME "4" +#define MOVE_LINK_TEST_EXTERN_LINK_NEW_NAME "extern_link_renamed" +#define MOVE_LINK_TEST_EXTERN_LINK_SAME_LOC_NAME "extern_link_same_loc" +#define MOVE_LINK_TEST_HARD_LINK_NAME "hard_link" +#define MOVE_LINK_TEST_HARD_LINK_NAME2 MOVE_LINK_TEST_HARD_LINK_NAME "2" +#define MOVE_LINK_TEST_HARD_LINK_NAME3 MOVE_LINK_TEST_HARD_LINK_NAME "3" +#define MOVE_LINK_TEST_HARD_LINK_NAME4 MOVE_LINK_TEST_HARD_LINK_NAME "4" +#define MOVE_LINK_TEST_HARD_LINK_NEW_NAME "hard_link_renamed" +#define MOVE_LINK_TEST_HARD_LINK_SAME_LOC_NAME "hard_link_same_loc" +#define MOVE_LINK_TEST_SOFT_LINK_TARGET_PATH "/" LINK_TEST_GROUP_NAME "/" MOVE_LINK_TEST_SUBGROUP_NAME +#define MOVE_LINK_TEST_SOFT_LINK_NAME "soft_link" +#define MOVE_LINK_TEST_SOFT_LINK_NAME2 MOVE_LINK_TEST_SOFT_LINK_NAME "2" +#define MOVE_LINK_TEST_SOFT_LINK_NAME3 MOVE_LINK_TEST_SOFT_LINK_NAME "3" +#define MOVE_LINK_TEST_SOFT_LINK_NAME4 MOVE_LINK_TEST_SOFT_LINK_NAME "4" +#define MOVE_LINK_TEST_SOFT_LINK_NEW_NAME "soft_link_renamed" +#define MOVE_LINK_TEST_SOFT_LINK_SAME_LOC_NAME "soft_link_same_loc" +#define MOVE_LINK_TEST_SRC_GROUP_NAME "src_group" +#define MOVE_LINK_TEST_DST_GROUP_NAME "dst_group" +#define MOVE_LINK_TEST_SUBGROUP_NAME "link_move_test" + +#define MOVE_LINK_INTO_GRP_WITH_LINKS_TEST_SUBGROUP_NAME "link_move_into_group_with_links_test" +#define MOVE_LINK_INTO_GRP_WITH_LINKS_TEST_SRC_GRP_NAME "source_group" +#define MOVE_LINK_INTO_GRP_WITH_LINKS_TEST_DST_GRP_NAME "dest_group" +#define MOVE_LINK_INTO_GRP_WITH_LINKS_TEST_NUM_LINKS 5 +#define MOVE_LINK_INTO_GRP_WITH_LINKS_TEST_BUF_SIZE 1024 + +#define MOVE_LINK_RESET_MAX_CRT_ORDER_TEST_SUBGROUP_NAME "H5Lmove_reset_grp_max_crt_order_test" +#define MOVE_LINK_RESET_MAX_CRT_ORDER_TEST_SRC_GRP_NAME "source_group" +#define MOVE_LINK_RESET_MAX_CRT_ORDER_TEST_DST_GRP_NAME "dest_group" +#define MOVE_LINK_RESET_MAX_CRT_ORDER_TEST_NUM_LINKS 5 +#define MOVE_LINK_RESET_MAX_CRT_ORDER_TEST_BUF_SIZE 1024 + +#define MOVE_LINK_INVALID_PARAMS_TEST_HARD_LINK_NAME "hard_link" +#define MOVE_LINK_INVALID_PARAMS_TEST_SRC_GROUP_NAME "src_grp" +#define MOVE_LINK_INVALID_PARAMS_TEST_DST_GROUP_NAME "dst_grp" +#define MOVE_LINK_INVALID_PARAMS_TEST_SUBGROUP_NAME "link_move_invalid_params_test" + +#define GET_LINK_VAL_TEST_LINK_VAL_BUF_SIZE 1024 +#define GET_LINK_VAL_TEST_SUBGROUP_NAME "get_link_val_test" +#define GET_LINK_VAL_TEST_SOFT_LINK_NAME "soft_link" +#define GET_LINK_VAL_TEST_SOFT_LINK_NAME2 GET_LINK_VAL_TEST_SOFT_LINK_NAME "2" +#define GET_LINK_VAL_TEST_SOFT_LINK_NAME3 GET_LINK_VAL_TEST_SOFT_LINK_NAME "3" +#define GET_LINK_VAL_TEST_EXT_LINK_NAME "ext_link" +#define GET_LINK_VAL_TEST_EXT_LINK_NAME2 GET_LINK_VAL_TEST_EXT_LINK_NAME "2" +#define GET_LINK_VAL_TEST_EXT_LINK_NAME3 GET_LINK_VAL_TEST_EXT_LINK_NAME "3" +#define GET_LINK_VAL_TEST_SUBGROUP1_NAME "H5Lget_val_soft_link" +#define GET_LINK_VAL_TEST_SUBGROUP2_NAME "H5Lget_val_external_link" +#define GET_LINK_VAL_TEST_SUBGROUP3_NAME "H5Lget_val_ud_link" +#define GET_LINK_VAL_TEST_SUBGROUP4_NAME "H5Lget_val_by_idx_soft_link_crt_order_increasing" +#define GET_LINK_VAL_TEST_SUBGROUP5_NAME "H5Lget_val_by_idx_soft_link_crt_order_decreasing" +#define GET_LINK_VAL_TEST_SUBGROUP6_NAME "H5Lget_val_by_idx_soft_link_name_order_increasing" +#define GET_LINK_VAL_TEST_SUBGROUP7_NAME "H5Lget_val_by_idx_soft_link_name_order_decreasing" +#define GET_LINK_VAL_TEST_SUBGROUP8_NAME "H5Lget_val_by_idx_external_link_crt_order_increasing" +#define GET_LINK_VAL_TEST_SUBGROUP9_NAME "H5Lget_val_by_idx_external_link_crt_order_decreasing" +#define GET_LINK_VAL_TEST_SUBGROUP10_NAME "H5Lget_val_by_idx_external_link_name_order_increasing" +#define GET_LINK_VAL_TEST_SUBGROUP11_NAME "H5Lget_val_by_idx_external_link_name_order_decreasing" +#define GET_LINK_VAL_TEST_SUBGROUP12_NAME "H5Lget_val_by_idx_ud_link_crt_order_increasing" +#define GET_LINK_VAL_TEST_SUBGROUP13_NAME "H5Lget_val_by_idx_ud_link_crt_order_decreasing" +#define GET_LINK_VAL_TEST_SUBGROUP14_NAME "H5Lget_val_by_idx_ud_link_name_order_increasing" +#define GET_LINK_VAL_TEST_SUBGROUP15_NAME "H5Lget_val_by_idx_ud_link_name_order_decreasing" + +#define GET_LINK_VAL_INVALID_PARAMS_TEST_SOFT_LINK_NAME "soft_link" +#define GET_LINK_VAL_INVALID_PARAMS_TEST_GROUP_NAME "get_link_val_invalid_params_test" + +#define GET_LINK_INFO_TEST_HARD_LINK_NAME "hard_link" +#define GET_LINK_INFO_TEST_HARD_LINK_NAME2 GET_LINK_INFO_TEST_HARD_LINK_NAME "2" +#define GET_LINK_INFO_TEST_HARD_LINK_NAME3 GET_LINK_INFO_TEST_HARD_LINK_NAME "3" +#define GET_LINK_INFO_TEST_SOFT_LINK_NAME "soft_link" +#define GET_LINK_INFO_TEST_SOFT_LINK_NAME2 GET_LINK_INFO_TEST_SOFT_LINK_NAME "2" +#define GET_LINK_INFO_TEST_SOFT_LINK_NAME3 GET_LINK_INFO_TEST_SOFT_LINK_NAME "3" +#define GET_LINK_INFO_TEST_EXT_LINK_NAME "ext_link" +#define GET_LINK_INFO_TEST_EXT_LINK_NAME2 GET_LINK_INFO_TEST_EXT_LINK_NAME "2" +#define GET_LINK_INFO_TEST_EXT_LINK_NAME3 GET_LINK_INFO_TEST_EXT_LINK_NAME "3" +#define GET_LINK_INFO_TEST_GROUP_NAME "get_link_info_test" +#define GET_LINK_INFO_TEST_SUBGROUP1_NAME "H5Lget_info_hard_link" +#define GET_LINK_INFO_TEST_SUBGROUP2_NAME "H5Lget_info_soft_link" +#define GET_LINK_INFO_TEST_SUBGROUP3_NAME "H5Lget_info_external_link" +#define GET_LINK_INFO_TEST_SUBGROUP4_NAME "H5Lget_info_ud_link" +#define GET_LINK_INFO_TEST_SUBGROUP5_NAME "H5Lget_info_by_idx_hard_link_crt_order_increasing" +#define GET_LINK_INFO_TEST_SUBGROUP6_NAME "H5Lget_info_by_idx_hard_link_crt_order_decreasing" +#define GET_LINK_INFO_TEST_SUBGROUP7_NAME "H5Lget_info_by_idx_hard_link_name_order_increasing" +#define GET_LINK_INFO_TEST_SUBGROUP8_NAME "H5Lget_info_by_idx_hard_link_name_order_decreasing" +#define GET_LINK_INFO_TEST_SUBGROUP9_NAME "H5Lget_info_by_idx_soft_link_crt_order_increasing" +#define GET_LINK_INFO_TEST_SUBGROUP10_NAME "H5Lget_info_by_idx_soft_link_crt_order_decreasing" +#define GET_LINK_INFO_TEST_SUBGROUP11_NAME "H5Lget_info_by_idx_soft_link_name_order_increasing" +#define GET_LINK_INFO_TEST_SUBGROUP12_NAME "H5Lget_info_by_idx_soft_link_name_order_decreasing" +#define GET_LINK_INFO_TEST_SUBGROUP13_NAME "H5Lget_info_by_idx_external_link_crt_order_increasing" +#define GET_LINK_INFO_TEST_SUBGROUP14_NAME "H5Lget_info_by_idx_external_link_crt_order_decreasing" +#define GET_LINK_INFO_TEST_SUBGROUP15_NAME "H5Lget_info_by_idx_external_link_name_order_increasing" +#define GET_LINK_INFO_TEST_SUBGROUP16_NAME "H5Lget_info_by_idx_external_link_name_order_decreasing" +#define GET_LINK_INFO_TEST_SUBGROUP17_NAME "H5Lget_info_by_idx_ud_link_crt_order_increasing" +#define GET_LINK_INFO_TEST_SUBGROUP18_NAME "H5Lget_info_by_idx_ud_link_crt_order_decreasing" +#define GET_LINK_INFO_TEST_SUBGROUP19_NAME "H5Lget_info_by_idx_ud_link_name_order_increasing" +#define GET_LINK_INFO_TEST_SUBGROUP20_NAME "H5Lget_info_by_idx_ud_link_name_order_decreasing" + +#define GET_LINK_INFO_INVALID_PARAMS_TEST_HARD_LINK_NAME "hard_link" +#define GET_LINK_INFO_INVALID_PARAMS_TEST_GROUP_NAME "get_link_info_invalid_params_test" + +#define GET_LINK_NAME_TEST_EXTERNAL_SUBGROUP_NAME "get_external_link_name_crt_order_increasing" +#define GET_LINK_NAME_TEST_EXTERNAL_SUBGROUP_NAME2 "get_external_link_name_crt_order_decreasing" +#define GET_LINK_NAME_TEST_EXTERNAL_SUBGROUP_NAME3 "get_external_link_name_alpha_order_increasing" +#define GET_LINK_NAME_TEST_EXTERNAL_SUBGROUP_NAME4 "get_external_link_name_alpha_order_decreasing" +#define GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME "external_link" +#define GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME2 GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME "2" +#define GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME3 GET_LINK_NAME_TEST_EXTERNAL_LINK_NAME "3" +#define GET_LINK_NAME_TEST_HARD_SUBGROUP_NAME "get_hard_link_name_crt_order_increasing" +#define GET_LINK_NAME_TEST_HARD_SUBGROUP_NAME2 "get_hard_link_name_crt_order_decreasing" +#define GET_LINK_NAME_TEST_HARD_SUBGROUP_NAME3 "get_hard_link_name_alpha_order_increasing" +#define GET_LINK_NAME_TEST_HARD_SUBGROUP_NAME4 "get_hard_link_name_alpha_order_decreasing" +#define GET_LINK_NAME_TEST_HARD_LINK_NAME "hard_link" +#define GET_LINK_NAME_TEST_HARD_LINK_NAME2 GET_LINK_NAME_TEST_HARD_LINK_NAME "2" +#define GET_LINK_NAME_TEST_HARD_LINK_NAME3 GET_LINK_NAME_TEST_HARD_LINK_NAME "3" +#define GET_LINK_NAME_TEST_SOFT_SUBGROUP_NAME "get_soft_link_name_crt_order_increasing" +#define GET_LINK_NAME_TEST_SOFT_SUBGROUP_NAME2 "get_soft_link_name_crt_order_decreasing" +#define GET_LINK_NAME_TEST_SOFT_SUBGROUP_NAME3 "get_soft_link_name_alpha_order_increasing" +#define GET_LINK_NAME_TEST_SOFT_SUBGROUP_NAME4 "get_soft_link_name_alpha_order_decreasing" +#define GET_LINK_NAME_TEST_SOFT_LINK_NAME "soft_link" +#define GET_LINK_NAME_TEST_SOFT_LINK_NAME2 GET_LINK_NAME_TEST_SOFT_LINK_NAME "2" +#define GET_LINK_NAME_TEST_SOFT_LINK_NAME3 GET_LINK_NAME_TEST_SOFT_LINK_NAME "3" +#define GET_LINK_NAME_TEST_GROUP_NAME "get_link_name_test" +#define GET_LINK_NAME_TEST_BUF_SIZE 256 + +#define GET_LINK_NAME_INVALID_PARAMS_TEST_HARD_LINK_NAME "test_link1" +#define GET_LINK_NAME_INVALID_PARAMS_TEST_GROUP_NAME "get_link_name_invalid_params_test" + +#define LINK_ITER_HARD_LINKS_TEST_DSET_SPACE_RANK 2 +#define LINK_ITER_HARD_LINKS_TEST_SUBGROUP_NAME "link_iter_hard_links_test" +#define LINK_ITER_HARD_LINKS_TEST_LINK_NAME "hard_link" +#define LINK_ITER_HARD_LINKS_TEST_NUM_LINKS 10 +#define LINK_ITER_HARD_LINKS_TEST_BUF_SIZE 64 + +#define LINK_ITER_SOFT_LINKS_TEST_SUBGROUP_NAME "link_iter_soft_links_test" +#define LINK_ITER_SOFT_LINKS_TEST_LINK_NAME "soft_link" +#define LINK_ITER_SOFT_LINKS_TEST_NUM_LINKS 10 +#define LINK_ITER_SOFT_LINKS_TEST_BUF_SIZE 64 + +#define LINK_ITER_EXT_LINKS_TEST_SUBGROUP_NAME "link_iter_ext_links_test" +#define LINK_ITER_EXT_LINKS_TEST_LINK_NAME "external_link" +#define LINK_ITER_EXT_LINKS_TEST_NUM_LINKS 10 +#define LINK_ITER_EXT_LINKS_TEST_BUF_SIZE 64 + +#define LINK_ITER_MIXED_LINKS_TEST_DSET_SPACE_RANK 2 +#define LINK_ITER_MIXED_LINKS_TEST_HARD_LINK_NAME "hard_link1" +#define LINK_ITER_MIXED_LINKS_TEST_SOFT_LINK_NAME "soft_link1" +#define LINK_ITER_MIXED_LINKS_TEST_EXT_LINK_NAME "ext_link1" +#define LINK_ITER_MIXED_LINKS_TEST_SUBGROUP_NAME "link_iter_mixed_links_test" +#define LINK_ITER_MIXED_LINKS_TEST_NUM_LINKS 3 + +#define LINK_ITER_INVALID_PARAMS_TEST_DSET_SPACE_RANK 2 +#define LINK_ITER_INVALID_PARAMS_TEST_HARD_LINK_NAME "hard_link1" +#define LINK_ITER_INVALID_PARAMS_TEST_SOFT_LINK_NAME "soft_link1" +#define LINK_ITER_INVALID_PARAMS_TEST_EXT_LINK_NAME "ext_link1" +#define LINK_ITER_INVALID_PARAMS_TEST_SUBGROUP_NAME "link_iter_invalid_params_test" + +#define LINK_ITER_0_LINKS_TEST_SUBGROUP_NAME "link_iter_0_links_test" + +#define LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST \ + ((LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_GROUP * \ + LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_SUBGROUPS) + \ + LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_SUBGROUPS) +#define LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_GROUP 10 +#define LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_DSET_SPACE_RANK 2 +#define LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NUM_SUBGROUPS 5 +#define LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_NESTED_GRP_NAME "subgroup" +#define LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME "link_visit_hard_links_no_cycle_test" +#define LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_LINK_NAME "hard_link" +#define LINK_VISIT_HARD_LINKS_NO_CYCLE_TEST_BUF_SIZE 256 + +#define LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST \ + ((LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_GROUP * \ + LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_SUBGROUPS) + \ + LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_SUBGROUPS) +#define LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_GROUP 10 +#define LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NUM_SUBGROUPS 5 +#define LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_NESTED_GRP_NAME "subgroup" +#define LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME "link_visit_soft_links_no_cycle_test" +#define LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_LINK_NAME "soft_link" +#define LINK_VISIT_SOFT_LINKS_NO_CYCLE_TEST_BUF_SIZE 256 + +#define LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_TEST \ + ((LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_GROUP * \ + LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_SUBGROUPS) + \ + LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_SUBGROUPS) +#define LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_LINKS_PER_GROUP 10 +#define LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NUM_SUBGROUPS 5 +#define LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_NESTED_GRP_NAME "subgroup" +#define LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME "link_visit_ext_links_no_cycle_test" +#define LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_LINK_NAME "external_link" +#define LINK_VISIT_EXT_LINKS_NO_CYCLE_TEST_BUF_SIZE 256 + +#define LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_DSET_SPACE_RANK 2 +#define LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_DSET_NAME "dset" +#define LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_DSET_NAME2 "dset2" +#define LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME "link_visit_mixed_links_no_cycle_test" +#define LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME2 "link_visit_subgroup1" +#define LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_SUBGROUP_NAME3 "link_visit_subgroup2" +#define LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME1 "hard_link1" +#define LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME2 "soft_link1" +#define LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME3 "ext_link1" +#define LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_LINK_NAME4 "hard_link2" +#define LINK_VISIT_MIXED_LINKS_NO_CYCLE_TEST_NUM_LINKS 8 + +#define LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST \ + ((LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_LINKS_PER_GROUP * \ + LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_SUBGROUPS) + \ + LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_SUBGROUPS) +#define LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_LINKS_PER_GROUP 10 +#define LINK_VISIT_HARD_LINKS_CYCLE_TEST_NUM_SUBGROUPS 5 +#define LINK_VISIT_HARD_LINKS_CYCLE_TEST_NESTED_GRP_NAME "subgroup" +#define LINK_VISIT_HARD_LINKS_CYCLE_TEST_SUBGROUP_NAME "link_visit_hard_links_cycle_test" +#define LINK_VISIT_HARD_LINKS_CYCLE_TEST_LINK_NAME "hard_link" +#define LINK_VISIT_HARD_LINKS_CYCLE_TEST_BUF_SIZE 256 + +#define LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST \ + ((LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_LINKS_PER_GROUP * \ + LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_SUBGROUPS) + \ + LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_SUBGROUPS) +#define LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_LINKS_PER_GROUP 10 +#define LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NUM_SUBGROUPS 5 +#define LINK_VISIT_SOFT_LINKS_CYCLE_TEST_NESTED_GRP_NAME "subgroup" +#define LINK_VISIT_SOFT_LINKS_CYCLE_TEST_SUBGROUP_NAME "link_visit_soft_links_cycle_test" +#define LINK_VISIT_SOFT_LINKS_CYCLE_TEST_LINK_NAME "soft_link" +#define LINK_VISIT_SOFT_LINKS_CYCLE_TEST_BUF_SIZE 256 + +#define LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_LINKS_PER_TEST \ + ((LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_LINKS_PER_GROUP * LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_SUBGROUPS) + \ + LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_SUBGROUPS) +#define LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_LINKS_PER_GROUP 10 +#define LINK_VISIT_EXT_LINKS_CYCLE_TEST_NUM_SUBGROUPS 5 +#define LINK_VISIT_EXT_LINKS_CYCLE_TEST_NESTED_GRP_NAME "subgroup" +#define LINK_VISIT_EXT_LINKS_CYCLE_TEST_SUBGROUP_NAME "link_visit_ext_links_cycle_test" +#define LINK_VISIT_EXT_LINKS_CYCLE_TEST_LINK_NAME "external_link" +#define LINK_VISIT_EXT_LINKS_CYCLE_TEST_BUF_SIZE 256 + +#define LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME "link_visit_mixed_links_cycle_test" +#define LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME2 "link_visit_subgroup1" +#define LINK_VISIT_MIXED_LINKS_CYCLE_TEST_SUBGROUP_NAME3 "link_visit_subgroup2" +#define LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME1 "hard_link1" +#define LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME2 "soft_link1" +#define LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME3 "ext_link1" +#define LINK_VISIT_MIXED_LINKS_CYCLE_TEST_LINK_NAME4 "hard_link2" +#define LINK_VISIT_MIXED_LINKS_CYCLE_TEST_NUM_LINKS 6 + +#define LINK_VISIT_INVALID_PARAMS_TEST_DSET_SPACE_RANK 2 +#define LINK_VISIT_INVALID_PARAMS_TEST_DSET_NAME "dset" +#define LINK_VISIT_INVALID_PARAMS_TEST_SUBGROUP_NAME "link_visit_invalid_params_test" +#define LINK_VISIT_INVALID_PARAMS_TEST_SUBGROUP_NAME2 "link_visit_subgroup1" +#define LINK_VISIT_INVALID_PARAMS_TEST_SUBGROUP_NAME3 "link_visit_subgroup2" +#define LINK_VISIT_INVALID_PARAMS_TEST_LINK_NAME1 "hard_link1" +#define LINK_VISIT_INVALID_PARAMS_TEST_LINK_NAME2 "soft_link1" +#define LINK_VISIT_INVALID_PARAMS_TEST_LINK_NAME3 "ext_link1" +#define LINK_VISIT_INVALID_PARAMS_TEST_LINK_NAME4 "hard_link2" + +#define LINK_VISIT_0_LINKS_TEST_SUBGROUP_NAME "link_visit_0_links_test" +#define LINK_VISIT_0_LINKS_TEST_SUBGROUP_NAME2 "link_visit_0_links_test_subgroup1" +#define LINK_VISIT_0_LINKS_TEST_SUBGROUP_NAME3 "link_visit_0_links_test_subgroup2" + +#endif diff --git a/test/API/H5_api_misc_test.c b/test/API/H5_api_misc_test.c new file mode 100644 index 0000000..256550b --- /dev/null +++ b/test/API/H5_api_misc_test.c @@ -0,0 +1,1060 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "H5_api_misc_test.h" + +static int test_open_link_without_leading_slash(void); +static int test_object_creation_by_absolute_path(void); +static int test_absolute_vs_relative_path(void); +static int test_dot_for_object_name(void); +static int test_symbols_in_compound_field_name(void); +static int test_double_init_term(void); + +/* + * The array of miscellaneous tests to be performed. + */ +static int (*misc_tests[])(void) = { + test_open_link_without_leading_slash, test_object_creation_by_absolute_path, + test_absolute_vs_relative_path, test_dot_for_object_name, + test_symbols_in_compound_field_name, test_double_init_term, +}; + +static int +test_open_link_without_leading_slash(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + + TESTING("opening a link without a leading slash"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file\n"); + goto error; + } + + if ((container_group = H5Gopen2(file_id, MISCELLANEOUS_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group\n"); + goto error; + } + + if ((space_id = generate_random_dataspace(OPEN_LINK_WITHOUT_SLASH_DSET_SPACE_RANK, NULL, NULL, FALSE)) < + 0) + TEST_ERROR; + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(container_group, OPEN_LINK_WITHOUT_SLASH_DSET_NAME, dset_dtype, space_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset\n"); + goto error; + } + + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file\n"); + goto error; + } + + if ((group_id = H5Gopen2(file_id, "/", H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open root group\n"); + goto error; + } + + if ((dset_id = H5Dopen2(group_id, MISCELLANEOUS_TEST_GROUP_NAME "/" OPEN_LINK_WITHOUT_SLASH_DSET_NAME, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset\n"); + goto error; + } + + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(space_id); + H5Tclose(dset_dtype); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +static int +test_object_creation_by_absolute_path(void) +{ + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID, sub_group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t dtype_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + + TESTING_MULTIPART("object creation by absolute path"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, link, or stored datatype aren't " + "supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file\n"); + goto error; + } + + if ((container_group = H5Gopen2(file_id, MISCELLANEOUS_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group\n"); + goto error; + } + + /* Start by creating a group to hold all the objects for this test */ + if ((group_id = H5Gcreate2(container_group, OBJECT_CREATE_BY_ABSOLUTE_PATH_TEST_CONTAINER_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group\n"); + goto error; + } + + if ((link_exists = H5Lexists(file_id, + "/" MISCELLANEOUS_TEST_GROUP_NAME + "/" OBJECT_CREATE_BY_ABSOLUTE_PATH_TEST_CONTAINER_GROUP_NAME, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link exists\n"); + goto error; + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" container group didn't exist at the correct location\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Gcreate_using_absolute_path) + { + TESTING_2("creation of group using absolute pathname"); + + /* Try to create a group under the container group by using an absolute pathname */ + if ((sub_group_id = H5Gcreate2(file_id, + "/" MISCELLANEOUS_TEST_GROUP_NAME + "/" OBJECT_CREATE_BY_ABSOLUTE_PATH_TEST_CONTAINER_GROUP_NAME + "/" OBJECT_CREATE_BY_ABSOLUTE_PATH_TEST_SUBGROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create subgroup by absolute pathname\n"); + PART_ERROR(H5Gcreate_using_absolute_path); + } + + if ((link_exists = H5Lexists(file_id, + "/" MISCELLANEOUS_TEST_GROUP_NAME + "/" OBJECT_CREATE_BY_ABSOLUTE_PATH_TEST_CONTAINER_GROUP_NAME + "/" OBJECT_CREATE_BY_ABSOLUTE_PATH_TEST_SUBGROUP_NAME, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link exists\n"); + PART_ERROR(H5Gcreate_using_absolute_path); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" subgroup didn't exist at the correct location\n"); + PART_ERROR(H5Gcreate_using_absolute_path); + } + + PASSED(); + } + PART_END(H5Gcreate_using_absolute_path); + + PART_BEGIN(H5Dcreate_using_absolute_path) + { + TESTING_2("creation of dataset using absolute pathname"); + + /* Try to create a dataset nested at the end of this group chain by using an absolute pathname */ + if ((fspace_id = generate_random_dataspace(OBJECT_CREATE_BY_ABSOLUTE_PATH_TEST_DSET_SPACE_RANK, + NULL, NULL, FALSE)) < 0) { + H5_FAILED(); + HDprintf(" failed to generate dataspace\n"); + PART_ERROR(H5Dcreate_using_absolute_path); + } + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) { + H5_FAILED(); + HDprintf(" failed to generate datatype\n"); + PART_ERROR(H5Dcreate_using_absolute_path); + } + + if ((dset_id = H5Dcreate2(file_id, + "/" MISCELLANEOUS_TEST_GROUP_NAME + "/" OBJECT_CREATE_BY_ABSOLUTE_PATH_TEST_CONTAINER_GROUP_NAME + "/" OBJECT_CREATE_BY_ABSOLUTE_PATH_TEST_SUBGROUP_NAME + "/" OBJECT_CREATE_BY_ABSOLUTE_PATH_TEST_DSET_NAME, + dset_dtype, fspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset\n"); + PART_ERROR(H5Dcreate_using_absolute_path); + } + + if ((link_exists = H5Lexists(file_id, + "/" MISCELLANEOUS_TEST_GROUP_NAME + "/" OBJECT_CREATE_BY_ABSOLUTE_PATH_TEST_CONTAINER_GROUP_NAME + "/" OBJECT_CREATE_BY_ABSOLUTE_PATH_TEST_SUBGROUP_NAME + "/" OBJECT_CREATE_BY_ABSOLUTE_PATH_TEST_DSET_NAME, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link exists\n"); + PART_ERROR(H5Dcreate_using_absolute_path); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" dataset didn't exist at the correct location\n"); + PART_ERROR(H5Dcreate_using_absolute_path); + } + + PASSED(); + } + PART_END(H5Dcreate_using_absolute_path); + + PART_BEGIN(H5Tcommit_using_absolute_path) + { + TESTING_2("creation of committed datatype using absolute pathname"); + + /* Try to create a committed datatype in the same fashion as the preceding dataset */ + if ((dtype_id = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create datatype\n"); + PART_ERROR(H5Tcommit_using_absolute_path); + } + + if (H5Tcommit2(file_id, + "/" MISCELLANEOUS_TEST_GROUP_NAME + "/" OBJECT_CREATE_BY_ABSOLUTE_PATH_TEST_CONTAINER_GROUP_NAME + "/" OBJECT_CREATE_BY_ABSOLUTE_PATH_TEST_SUBGROUP_NAME + "/" OBJECT_CREATE_BY_ABSOLUTE_PATH_TEST_DTYPE_NAME, + dtype_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't commit datatype\n"); + PART_ERROR(H5Tcommit_using_absolute_path); + } + + if ((link_exists = H5Lexists(file_id, + "/" MISCELLANEOUS_TEST_GROUP_NAME + "/" OBJECT_CREATE_BY_ABSOLUTE_PATH_TEST_CONTAINER_GROUP_NAME + "/" OBJECT_CREATE_BY_ABSOLUTE_PATH_TEST_SUBGROUP_NAME + "/" OBJECT_CREATE_BY_ABSOLUTE_PATH_TEST_DTYPE_NAME, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link exists\n"); + PART_ERROR(H5Tcommit_using_absolute_path); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" datatype didn't exist at the correct location\n"); + PART_ERROR(H5Tcommit_using_absolute_path); + } + + PASSED(); + } + PART_END(H5Tcommit_using_absolute_path); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Tclose(dtype_id) < 0) + TEST_ERROR; + if (H5Gclose(sub_group_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + H5Tclose(dset_dtype); + H5Dclose(dset_id); + H5Tclose(dtype_id); + H5Gclose(sub_group_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* XXX: Add testing for groups */ +static int +test_absolute_vs_relative_path(void) +{ + htri_t link_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id1 = H5I_INVALID_HID, dset_id2 = H5I_INVALID_HID, dset_id3 = H5I_INVALID_HID, + dset_id4 = H5I_INVALID_HID, dset_id5 = H5I_INVALID_HID, dset_id6 = H5I_INVALID_HID; + hid_t dset_dtype1 = H5I_INVALID_HID, dset_dtype2 = H5I_INVALID_HID, dset_dtype3 = H5I_INVALID_HID, + dset_dtype4 = H5I_INVALID_HID, dset_dtype5 = H5I_INVALID_HID, dset_dtype6 = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + + TESTING_MULTIPART("absolute vs. relative pathnames"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, or link aren't supported with this " + "connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file\n"); + goto error; + } + + if ((container_group = H5Gopen2(file_id, MISCELLANEOUS_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group\n"); + goto error; + } + + /* Start by creating a group to be used during some of the dataset creation operations */ + if ((group_id = H5Gcreate2(container_group, ABSOLUTE_VS_RELATIVE_PATH_TEST_CONTAINER_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container group\n"); + goto error; + } + + if ((fspace_id = generate_random_dataspace(ABSOLUTE_VS_RELATIVE_PATH_TEST_DSET_SPACE_RANK, NULL, NULL, + FALSE)) < 0) + TEST_ERROR; + + if ((dset_dtype1 = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + if ((dset_dtype2 = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + if ((dset_dtype3 = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + if ((dset_dtype4 = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + if ((dset_dtype5 = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + if ((dset_dtype6 = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Dcreate_absolute_from_root) + { + TESTING_2("dataset creation by absolute path from root group"); + + /* Create a dataset by absolute path in the form "/group/dataset" starting from the root group */ + if ((dset_id1 = H5Dcreate2(file_id, + "/" MISCELLANEOUS_TEST_GROUP_NAME + "/" ABSOLUTE_VS_RELATIVE_PATH_TEST_CONTAINER_GROUP_NAME + "/" ABSOLUTE_VS_RELATIVE_PATH_TEST_DSET1_NAME, + dset_dtype1, fspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset by absolute path from root\n"); + PART_ERROR(H5Dcreate_absolute_from_root); + } + + if ((link_exists = H5Lexists(file_id, + "/" MISCELLANEOUS_TEST_GROUP_NAME + "/" ABSOLUTE_VS_RELATIVE_PATH_TEST_CONTAINER_GROUP_NAME + "/" ABSOLUTE_VS_RELATIVE_PATH_TEST_DSET1_NAME, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link exists\n"); + PART_ERROR(H5Dcreate_absolute_from_root); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" didn't exist at the correct location\n"); + PART_ERROR(H5Dcreate_absolute_from_root); + } + + PASSED(); + } + PART_END(H5Dcreate_absolute_from_root); + + PART_BEGIN(H5Dcreate_absolute_from_nonroot) + { + TESTING_2("dataset creation by absolute path from non-root group"); + + /* Create a dataset by absolute path in the form "/group/dataset" starting from the container + * group */ + if ((dset_id4 = H5Dcreate2(container_group, + "/" MISCELLANEOUS_TEST_GROUP_NAME + "/" ABSOLUTE_VS_RELATIVE_PATH_TEST_CONTAINER_GROUP_NAME + "/" ABSOLUTE_VS_RELATIVE_PATH_TEST_DSET4_NAME, + dset_dtype4, fspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset by absolute path from container group\n"); + PART_ERROR(H5Dcreate_absolute_from_nonroot); + } + + if ((link_exists = H5Lexists(file_id, + "/" MISCELLANEOUS_TEST_GROUP_NAME + "/" ABSOLUTE_VS_RELATIVE_PATH_TEST_CONTAINER_GROUP_NAME + "/" ABSOLUTE_VS_RELATIVE_PATH_TEST_DSET4_NAME, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link exists\n"); + PART_ERROR(H5Dcreate_absolute_from_nonroot); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" didn't exist at the correct location\n"); + PART_ERROR(H5Dcreate_absolute_from_nonroot); + } + + PASSED(); + } + PART_END(H5Dcreate_absolute_from_nonroot); + + PART_BEGIN(H5Dcreate_relative_from_root) + { + TESTING_2("dataset creation by relative path from root group"); + + /* TODO: */ + + SKIPPED(); + PART_EMPTY(H5Dcreate_relative_from_root); + } + PART_END(H5Dcreate_relative_from_root); + + PART_BEGIN(H5Dcreate_relative_from_nonroot) + { + TESTING_2("dataset creation by relative path from non-root group"); + + /* Create a dataset by relative path in the form "dataset" starting from the test container group + */ + if ((dset_id5 = H5Dcreate2(group_id, ABSOLUTE_VS_RELATIVE_PATH_TEST_DSET5_NAME, dset_dtype5, + fspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset by relative path from container group\n"); + PART_ERROR(H5Dcreate_relative_from_nonroot); + } + + /* Create a dataset by relative path in the form "group/dataset" starting from the top-level + * container group */ + if ((dset_id2 = H5Dcreate2(container_group, + ABSOLUTE_VS_RELATIVE_PATH_TEST_CONTAINER_GROUP_NAME + "/" ABSOLUTE_VS_RELATIVE_PATH_TEST_DSET2_NAME, + dset_dtype2, fspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset by relative path from container group\n"); + PART_ERROR(H5Dcreate_relative_from_nonroot); + } + + if ((link_exists = H5Lexists(file_id, + "/" MISCELLANEOUS_TEST_GROUP_NAME + "/" ABSOLUTE_VS_RELATIVE_PATH_TEST_CONTAINER_GROUP_NAME + "/" ABSOLUTE_VS_RELATIVE_PATH_TEST_DSET2_NAME, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link exists\n"); + PART_ERROR(H5Dcreate_relative_from_nonroot); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" didn't exist at the correct location\n"); + PART_ERROR(H5Dcreate_relative_from_nonroot); + } + + if ((link_exists = H5Lexists(file_id, + "/" MISCELLANEOUS_TEST_GROUP_NAME + "/" ABSOLUTE_VS_RELATIVE_PATH_TEST_CONTAINER_GROUP_NAME + "/" ABSOLUTE_VS_RELATIVE_PATH_TEST_DSET5_NAME, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link exists\n"); + PART_ERROR(H5Dcreate_relative_from_nonroot); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" didn't exist at the correct location\n"); + PART_ERROR(H5Dcreate_relative_from_nonroot); + } + + PASSED(); + } + PART_END(H5Dcreate_relative_from_nonroot); + + PART_BEGIN(H5Dcreate_relative_leading_dot_root) + { + TESTING_2("dataset creation by path with leading '.' from root group"); + + /* Create a dataset by relative path in the form "./group/dataset" starting from the root group */ + if ((dset_id3 = H5Dcreate2(file_id, + "./" MISCELLANEOUS_TEST_GROUP_NAME + "/" ABSOLUTE_VS_RELATIVE_PATH_TEST_CONTAINER_GROUP_NAME + "/" ABSOLUTE_VS_RELATIVE_PATH_TEST_DSET3_NAME, + dset_dtype3, fspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset by relative path from root with leading '.'\n"); + PART_ERROR(H5Dcreate_relative_leading_dot_root); + } + + if ((link_exists = H5Lexists(file_id, + "/" MISCELLANEOUS_TEST_GROUP_NAME + "/" ABSOLUTE_VS_RELATIVE_PATH_TEST_CONTAINER_GROUP_NAME + "/" ABSOLUTE_VS_RELATIVE_PATH_TEST_DSET3_NAME, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link exists\n"); + PART_ERROR(H5Dcreate_relative_leading_dot_root); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" didn't exist at the correct location\n"); + PART_ERROR(H5Dcreate_relative_leading_dot_root); + } + + PASSED(); + } + PART_END(H5Dcreate_relative_leading_dot_root); + + PART_BEGIN(H5Dcreate_relative_leading_dot_nonroot) + { + TESTING_2("dataset creation by path with leading '.' from non-root group"); + + /* Create a dataset by relative path in the form "./dataset" starting from the container group */ + if ((dset_id6 = H5Dcreate2(group_id, "./" ABSOLUTE_VS_RELATIVE_PATH_TEST_DSET6_NAME, dset_dtype6, + fspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf( + " couldn't create dataset by relative path from container group with leading '.'\n"); + PART_ERROR(H5Dcreate_relative_leading_dot_nonroot); + } + + if ((link_exists = H5Lexists(file_id, + "/" MISCELLANEOUS_TEST_GROUP_NAME + "/" ABSOLUTE_VS_RELATIVE_PATH_TEST_CONTAINER_GROUP_NAME + "/" ABSOLUTE_VS_RELATIVE_PATH_TEST_DSET6_NAME, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link exists\n"); + PART_ERROR(H5Dcreate_relative_leading_dot_nonroot); + } + + if (!link_exists) { + H5_FAILED(); + HDprintf(" didn't exist at the correct location\n"); + PART_ERROR(H5Dcreate_relative_leading_dot_nonroot); + } + + PASSED(); + } + PART_END(H5Dcreate_relative_leading_dot_nonroot); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype1) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype2) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype3) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype4) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype5) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype6) < 0) + TEST_ERROR; + if (H5Dclose(dset_id1) < 0) + TEST_ERROR; + if (H5Dclose(dset_id2) < 0) + TEST_ERROR; + if (H5Dclose(dset_id3) < 0) + TEST_ERROR; + if (H5Dclose(dset_id4) < 0) + TEST_ERROR; + if (H5Dclose(dset_id5) < 0) + TEST_ERROR; + if (H5Dclose(dset_id6) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + H5Tclose(dset_dtype1); + H5Tclose(dset_dtype2); + H5Tclose(dset_dtype3); + H5Tclose(dset_dtype4); + H5Tclose(dset_dtype5); + H5Tclose(dset_dtype6); + H5Dclose(dset_id1); + H5Dclose(dset_id2); + H5Dclose(dset_id3); + H5Dclose(dset_id4); + H5Dclose(dset_id5); + H5Dclose(dset_id6); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check creating/opening objects with the "." as the name + */ +static int +test_dot_for_object_name(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, subgroup_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID, dspace_id = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t dtype_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + herr_t ret = -1; + + TESTING_MULTIPART("creating objects with \".\" as the name"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, or stored datatype aren't supported with " + "this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, MISCELLANEOUS_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", MISCELLANEOUS_TEST_GROUP_NAME); + goto error; + } + + if ((subgroup_id = H5Gcreate2(container_group, DOT_AS_OBJECT_NAME_TEST_SUBGROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", DOT_AS_OBJECT_NAME_TEST_SUBGROUP_NAME); + goto error; + } + + if ((dspace_id = H5Screate(H5S_SCALAR)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create data space\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Gcreate_dot_as_name) + { + TESTING_2("invalid creation of group with '.' as name"); + + /* Create a group with the "." as the name. It should fail. */ + H5E_BEGIN_TRY + { + group_id = H5Gcreate2(subgroup_id, ".", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (group_id >= 0) { + H5_FAILED(); + HDprintf(" a group was created with '.' as the name!\n"); + PART_ERROR(H5Gcreate_dot_as_name); + } + + PASSED(); + } + PART_END(H5Gcreate_dot_as_name); + + PART_BEGIN(H5Dcreate_dot_as_name) + { + TESTING_2("invalid creation of dataset with '.' as name"); + + /* Create a dataset with the "." as the name. It should fail. */ + H5E_BEGIN_TRY + { + dset_id = H5Dcreate2(subgroup_id, ".", H5T_NATIVE_INT, dspace_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT); + } + H5E_END_TRY; + + if (dset_id >= 0) { + H5_FAILED(); + HDprintf(" a dataset was created with '.' as the name!\n"); + PART_ERROR(H5Dcreate_dot_as_name); + } + + PASSED(); + } + PART_END(H5Dcreate_dot_as_name); + + PART_BEGIN(H5Tcommit_dot_as_name) + { + TESTING_2("invalid creation of committed datatype with '.' as name"); + + if ((dtype_id = H5Tcopy(H5T_NATIVE_INT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't copy a native datatype\n"); + PART_ERROR(H5Tcommit_dot_as_name); + } + + /* Commit a datatype with "." as the name. It should fail. */ + H5E_BEGIN_TRY + { + ret = H5Tcommit2(subgroup_id, ".", dtype_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (ret >= 0) { + H5_FAILED(); + HDprintf(" a named datatype was committed with '.' as the name!\n"); + PART_ERROR(H5Tcommit_dot_as_name); + } + + if (H5Tclose(dtype_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close datatype\n"); + PART_ERROR(H5Tcommit_dot_as_name); + } + + PASSED(); + } + PART_END(H5Tcommit_dot_as_name); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(dspace_id) < 0) + TEST_ERROR; + if (H5Gclose(subgroup_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(dspace_id); + H5Aclose(attr_id); + H5Dclose(dset_id); + H5Tclose(dtype_id); + H5Gclose(group_id); + H5Gclose(subgroup_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that the initialization and termination + * functions of a VOL connector can be called multiple times + * in a row. + * + * TODO: Not sure if this test can be done from public APIs + * at the moment. + */ +static int +test_double_init_term(void) +{ + TESTING("double init/term correctness"); + + SKIPPED(); + + return 0; + +#if 0 +error: + return 1; +#endif +} + +static int +test_symbols_in_compound_field_name(void) +{ + size_t i; + size_t total_type_size; + size_t next_offset; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t compound_type = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t type_pool[COMPOUND_WITH_SYMBOLS_IN_MEMBER_NAMES_TEST_NUM_SUBTYPES]; + char member_names[COMPOUND_WITH_SYMBOLS_IN_MEMBER_NAMES_TEST_NUM_SUBTYPES][256]; + + TESTING("usage of '{', '}' and '\\\"' symbols in compound field name"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + for (i = 0; i < COMPOUND_WITH_SYMBOLS_IN_MEMBER_NAMES_TEST_NUM_SUBTYPES; i++) + type_pool[i] = H5I_INVALID_HID; + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file\n"); + goto error; + } + + if ((container_group = H5Gopen2(file_id, MISCELLANEOUS_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, COMPOUND_WITH_SYMBOLS_IN_MEMBER_NAMES_TEST_SUBGROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group\n"); + goto error; + } + + for (i = 0, total_type_size = 0; i < COMPOUND_WITH_SYMBOLS_IN_MEMBER_NAMES_TEST_NUM_SUBTYPES; i++) { + type_pool[i] = generate_random_datatype(H5T_NO_CLASS, FALSE); + total_type_size += H5Tget_size(type_pool[i]); + } + + HDsnprintf(member_names[0], 256, "{{{ member0"); + HDsnprintf(member_names[1], 256, "member1 }}}"); + HDsnprintf(member_names[2], 256, "{{{ member2 }}"); + HDsnprintf(member_names[3], 256, "{{ member3 }}}"); + HDsnprintf(member_names[4], 256, "\\\"member4"); + HDsnprintf(member_names[5], 256, "member5\\\""); + HDsnprintf(member_names[6], 256, "mem\\\"ber6"); + HDsnprintf(member_names[7], 256, "{{ member7\\\" }"); + HDsnprintf(member_names[8], 256, "{{ member8\\\\"); + + if ((compound_type = H5Tcreate(H5T_COMPOUND, total_type_size)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create compound datatype\n"); + goto error; + } + + for (i = 0, next_offset = 0; i < COMPOUND_WITH_SYMBOLS_IN_MEMBER_NAMES_TEST_NUM_SUBTYPES; i++) { + if (H5Tinsert(compound_type, member_names[i], next_offset, type_pool[i]) < 0) { + H5_FAILED(); + HDprintf(" couldn't insert compound member %zu\n", i); + goto error; + } + + next_offset += H5Tget_size(type_pool[i]); + } + + if (H5Tpack(compound_type) < 0) + TEST_ERROR; + + if ((fspace_id = generate_random_dataspace(COMPOUND_WITH_SYMBOLS_IN_MEMBER_NAMES_TEST_DSET_RANK, NULL, + NULL, FALSE)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, COMPOUND_WITH_SYMBOLS_IN_MEMBER_NAMES_TEST_DSET_NAME, compound_type, + fspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset\n"); + goto error; + } + + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + + if ((dset_id = H5Dopen2(group_id, COMPOUND_WITH_SYMBOLS_IN_MEMBER_NAMES_TEST_DSET_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" failed to open dataset\n"); + goto error; + } + + for (i = 0; i < COMPOUND_WITH_SYMBOLS_IN_MEMBER_NAMES_TEST_NUM_SUBTYPES; i++) + if (type_pool[i] >= 0 && H5Tclose(type_pool[i]) < 0) + TEST_ERROR; + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Tclose(compound_type) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + for (i = 0; i < COMPOUND_WITH_SYMBOLS_IN_MEMBER_NAMES_TEST_NUM_SUBTYPES; i++) + H5Tclose(type_pool[i]); + H5Sclose(fspace_id); + H5Tclose(compound_type); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +int +H5_api_misc_test(void) +{ + size_t i; + int nerrors; + + HDprintf("**********************************************\n"); + HDprintf("* *\n"); + HDprintf("* API Miscellaneous Tests *\n"); + HDprintf("* *\n"); + HDprintf("**********************************************\n\n"); + + for (i = 0, nerrors = 0; i < ARRAY_LENGTH(misc_tests); i++) { + nerrors += (*misc_tests[i])() ? 1 : 0; + } + + HDprintf("\n"); + + return nerrors; +} diff --git a/test/API/H5_api_misc_test.h b/test/API/H5_api_misc_test.h new file mode 100644 index 0000000..8729db7 --- /dev/null +++ b/test/API/H5_api_misc_test.h @@ -0,0 +1,52 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef H5_API_MISC_TEST_H +#define H5_API_MISC_TEST_H + +#include "H5_api_test.h" + +int H5_api_misc_test(void); + +/****************************************************** + * * + * API Miscellaneous test defines * + * * + ******************************************************/ + +#define OPEN_LINK_WITHOUT_SLASH_DSET_SPACE_RANK 2 +#define OPEN_LINK_WITHOUT_SLASH_DSET_NAME "link_without_slash_test_dset" + +#define OBJECT_CREATE_BY_ABSOLUTE_PATH_TEST_CONTAINER_GROUP_NAME "absolute_path_test_container_group" +#define OBJECT_CREATE_BY_ABSOLUTE_PATH_TEST_SUBGROUP_NAME "absolute_path_test_subgroup" +#define OBJECT_CREATE_BY_ABSOLUTE_PATH_TEST_DTYPE_NAME "absolute_path_test_dtype" +#define OBJECT_CREATE_BY_ABSOLUTE_PATH_TEST_DSET_NAME "absolute_path_test_dset" +#define OBJECT_CREATE_BY_ABSOLUTE_PATH_TEST_DSET_SPACE_RANK 3 + +#define ABSOLUTE_VS_RELATIVE_PATH_TEST_CONTAINER_GROUP_NAME "absolute_vs_relative_test_container_group" +#define ABSOLUTE_VS_RELATIVE_PATH_TEST_DSET1_NAME "absolute_vs_relative_test_dset1" +#define ABSOLUTE_VS_RELATIVE_PATH_TEST_DSET2_NAME "absolute_vs_relative_test_dset2" +#define ABSOLUTE_VS_RELATIVE_PATH_TEST_DSET3_NAME "absolute_vs_relative_test_dset3" +#define ABSOLUTE_VS_RELATIVE_PATH_TEST_DSET4_NAME "absolute_vs_relative_test_dset4" +#define ABSOLUTE_VS_RELATIVE_PATH_TEST_DSET5_NAME "absolute_vs_relative_test_dset5" +#define ABSOLUTE_VS_RELATIVE_PATH_TEST_DSET6_NAME "absolute_vs_relative_test_dset6" +#define ABSOLUTE_VS_RELATIVE_PATH_TEST_DSET_SPACE_RANK 3 + +#define DOT_AS_OBJECT_NAME_TEST_SUBGROUP_NAME "dot_as_object_name_test" + +#define COMPOUND_WITH_SYMBOLS_IN_MEMBER_NAMES_TEST_SUBGROUP_NAME \ + "compound_type_with_symbols_in_member_names_test" +#define COMPOUND_WITH_SYMBOLS_IN_MEMBER_NAMES_TEST_NUM_SUBTYPES 9 +#define COMPOUND_WITH_SYMBOLS_IN_MEMBER_NAMES_TEST_DSET_RANK 2 +#define COMPOUND_WITH_SYMBOLS_IN_MEMBER_NAMES_TEST_DSET_NAME "dset" + +#endif diff --git a/test/API/H5_api_object_test.c b/test/API/H5_api_object_test.c new file mode 100644 index 0000000..e054356 --- /dev/null +++ b/test/API/H5_api_object_test.c @@ -0,0 +1,7172 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "H5_api_object_test.h" + +static int test_open_object(void); +static int test_open_object_invalid_params(void); +static int test_object_exists(void); +static int test_object_exists_invalid_params(void); +static int test_get_object_info(void); +static int test_get_object_info_invalid_params(void); +static int test_link_object(void); +static int test_link_object_invalid_params(void); +static int test_incr_decr_object_refcount(void); +static int test_incr_decr_object_refcount_invalid_params(void); +static int test_object_copy_basic(void); +static int test_object_copy_already_existing(void); +static int test_object_copy_shallow_group_copy(void); +static int test_object_copy_no_attributes(void); +static int test_object_copy_by_soft_link(void); +static int test_object_copy_group_with_soft_links(void); +static int test_object_copy_between_files(void); +static int test_object_copy_invalid_params(void); +static int test_object_comments(void); +static int test_object_comments_invalid_params(void); +static int test_object_visit(void); +static int test_object_visit_soft_link(void); +static int test_object_visit_invalid_params(void); +static int test_close_object(void); +static int test_close_object_invalid_params(void); +static int test_close_invalid_objects(void); +static int test_flush_object(void); +static int test_flush_object_invalid_params(void); +static int test_refresh_object(void); +static int test_refresh_object_invalid_params(void); + +static herr_t object_copy_attribute_iter_callback(hid_t location_id, const char *attr_name, + const H5A_info_t *ainfo, void *op_data); +static herr_t object_copy_soft_link_non_expand_callback(hid_t group, const char *name, + const H5L_info2_t *info, void *op_data); +static herr_t object_copy_soft_link_expand_callback(hid_t group, const char *name, const H5L_info2_t *info, + void *op_data); +static herr_t object_visit_callback(hid_t o_id, const char *name, const H5O_info2_t *object_info, + void *op_data); +static herr_t object_visit_dset_callback(hid_t o_id, const char *name, const H5O_info2_t *object_info, + void *op_data); +static herr_t object_visit_dtype_callback(hid_t o_id, const char *name, const H5O_info2_t *object_info, + void *op_data); +static herr_t object_visit_soft_link_callback(hid_t o_id, const char *name, const H5O_info2_t *object_info, + void *op_data); +static herr_t object_visit_noop_callback(hid_t o_id, const char *name, const H5O_info2_t *object_info, + void *op_data); + +/* + * The array of object tests to be performed. + */ +static int (*object_tests[])(void) = { + test_open_object, + test_open_object_invalid_params, + test_object_exists, + test_object_exists_invalid_params, + test_get_object_info, + test_get_object_info_invalid_params, + test_link_object, + test_link_object_invalid_params, + test_incr_decr_object_refcount, + test_incr_decr_object_refcount_invalid_params, + test_object_copy_basic, + test_object_copy_already_existing, + test_object_copy_shallow_group_copy, + test_object_copy_no_attributes, + test_object_copy_by_soft_link, + test_object_copy_group_with_soft_links, + test_object_copy_between_files, + test_object_copy_invalid_params, + test_object_comments, + test_object_comments_invalid_params, + test_object_visit, + test_object_visit_soft_link, + test_object_visit_invalid_params, + test_close_object, + test_close_object_invalid_params, + test_close_invalid_objects, + test_flush_object, + test_flush_object_invalid_params, + test_refresh_object, + test_refresh_object_invalid_params, +}; + +/* + * A test to check that various objects (group, dataset, datatype) + * can be opened by using H5Oopen, H5Oopen_by_idx and H5Oopen_by_addr. + * + * XXX: create separate objects for each test part. + * + * XXX: Add more open by idx tests + * + * XXX: test opening through dangling and resolving soft links. + */ +static int +test_open_object(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t group_id2 = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t type_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + + TESTING_MULTIPART("object opening"); + + TESTING_2("test setup"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, object, dataset, or stored datatype aren't " + "supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, OBJECT_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", OBJECT_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, OBJECT_OPEN_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", OBJECT_OPEN_TEST_GROUP_NAME); + goto error; + } + + if ((fspace_id = generate_random_dataspace(OBJECT_OPEN_TEST_SPACE_RANK, NULL, NULL, FALSE)) < 0) + TEST_ERROR; + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Oopen_group) + { + TESTING_2("H5Oopen on a group"); + + if ((group_id2 = H5Gcreate2(group_id, OBJECT_OPEN_TEST_GRP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", OBJECT_OPEN_TEST_GRP_NAME); + PART_ERROR(H5Oopen_group); + } + + H5E_BEGIN_TRY + { + H5Gclose(group_id2); + } + H5E_END_TRY; + + if ((group_id2 = H5Oopen(group_id, OBJECT_OPEN_TEST_GRP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open group '%s' with H5Oopen\n", OBJECT_OPEN_TEST_GRP_NAME); + PART_ERROR(H5Oopen_group); + } + + if (H5Iget_type(group_id2) != H5I_GROUP) { + H5_FAILED(); + HDprintf(" ID is not a group\n"); + PART_ERROR(H5Oopen_group); + } + + if (H5Gclose(group_id2) < 0) { + H5_FAILED(); + HDprintf(" couldn't close group opened with H5Oopen\n"); + PART_ERROR(H5Oopen_group); + } + + PASSED(); + } + PART_END(H5Oopen_group); + + PART_BEGIN(H5Oopen_dset) + { + TESTING_2("H5Oopen on a dataset"); + + if ((dset_id = H5Dcreate2(group_id, OBJECT_OPEN_TEST_DSET_NAME, dset_dtype, fspace_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", OBJECT_OPEN_TEST_DSET_NAME); + PART_ERROR(H5Oopen_dset); + } + + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + + if ((dset_id = H5Oopen(group_id, OBJECT_OPEN_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s' with H5Oopen\n", OBJECT_OPEN_TEST_DSET_NAME); + PART_ERROR(H5Oopen_dset); + } + + if (H5Iget_type(dset_id) != H5I_DATASET) { + H5_FAILED(); + HDprintf(" ID is not a dataset\n"); + PART_ERROR(H5Oopen_dset); + } + + if (H5Dclose(dset_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close dataset opened with H5Oopen\n"); + PART_ERROR(H5Oopen_dset); + } + + PASSED(); + } + PART_END(H5Oopen_dset); + + PART_BEGIN(H5Oopen_dtype) + { + TESTING_2("H5Oopen on a committed datatype"); + + if ((type_id = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create datatype '%s'\n", OBJECT_OPEN_TEST_TYPE_NAME); + PART_ERROR(H5Oopen_dtype); + } + + if (H5Tcommit2(group_id, OBJECT_OPEN_TEST_TYPE_NAME, type_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't commit datatype '%s'\n", OBJECT_OPEN_TEST_TYPE_NAME); + PART_ERROR(H5Oopen_dtype); + } + + H5E_BEGIN_TRY + { + H5Tclose(type_id); + } + H5E_END_TRY; + + if ((type_id = H5Oopen(group_id, OBJECT_OPEN_TEST_TYPE_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open datatype '%s' with H5Oopen\n", OBJECT_OPEN_TEST_TYPE_NAME); + PART_ERROR(H5Oopen_dtype); + } + + if (H5Iget_type(type_id) != H5I_DATATYPE) { + H5_FAILED(); + HDprintf(" ID is not a dataset\n"); + PART_ERROR(H5Oopen_dtype); + } + + if (H5Tclose(type_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close committed datatype opened with H5Oopen\n"); + PART_ERROR(H5Oopen_dtype); + } + + PASSED(); + } + PART_END(H5Oopen_dtype); + + if (group_id2 >= 0) { + H5E_BEGIN_TRY + { + H5Gclose(group_id2); + } + H5E_END_TRY; + group_id2 = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + if (type_id >= 0) { + H5E_BEGIN_TRY + { + H5Tclose(type_id); + } + H5E_END_TRY; + type_id = H5I_INVALID_HID; + } + + PART_BEGIN(H5Oopen_by_idx_group) + { + TESTING_2("H5Oopen_by_idx on a group"); + + if ((group_id2 = H5Oopen_by_idx(container_group, OBJECT_OPEN_TEST_GROUP_NAME, H5_INDEX_NAME, + H5_ITER_INC, 1, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open group '%s' with H5Oopen_by_idx\n", OBJECT_OPEN_TEST_GRP_NAME); + PART_ERROR(H5Oopen_by_idx_group); + } + + PASSED(); + } + PART_END(H5Oopen_by_idx_group); + + PART_BEGIN(H5Oopen_by_idx_dset) + { + TESTING_2("H5Oopen_by_idx on a dataset"); + + if ((dset_id = H5Oopen_by_idx(container_group, OBJECT_OPEN_TEST_GROUP_NAME, H5_INDEX_NAME, + H5_ITER_INC, 0, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s' with H5Oopen_by_idx\n", OBJECT_OPEN_TEST_DSET_NAME); + PART_ERROR(H5Oopen_by_idx_dset); + } + + PASSED(); + } + PART_END(H5Oopen_by_idx_dset); + + PART_BEGIN(H5Oopen_by_idx_dtype) + { + TESTING_2("H5Oopen_by_idx on a committed datatype"); + + if ((type_id = H5Oopen_by_idx(container_group, OBJECT_OPEN_TEST_GROUP_NAME, H5_INDEX_NAME, + H5_ITER_INC, 2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open committed datatype '%s' with H5Oopen_by_idx\n", + OBJECT_OPEN_TEST_TYPE_NAME); + PART_ERROR(H5Oopen_by_idx_dtype); + } + + PASSED(); + } + PART_END(H5Oopen_by_idx_dtype); + + if (group_id2 >= 0) { + H5E_BEGIN_TRY + { + H5Gclose(group_id2); + } + H5E_END_TRY; + group_id2 = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + if (type_id >= 0) { + H5E_BEGIN_TRY + { + H5Tclose(type_id); + } + H5E_END_TRY; + type_id = H5I_INVALID_HID; + } + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + H5Tclose(dset_dtype); + H5Tclose(type_id); + H5Dclose(dset_id); + H5Gclose(group_id2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that various objects (group, dataset, datatype) + * can't be opened when H5Oopen, H5Oopen_by_idx and H5Oopen_by_addr + * are passed invalid parameters. + */ +static int +test_open_object_invalid_params(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t group_id2 = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + + TESTING_MULTIPART("object opening with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, object, or creation order aren't supported with " + "this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, OBJECT_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", OBJECT_TEST_GROUP_NAME); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create a GCPL\n"); + goto error; + } + + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0) { + H5_FAILED(); + HDprintf(" couldn't enable link creation order tracking and indexing on GCPL\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, OBJECT_OPEN_INVALID_PARAMS_TEST_GROUP_NAME, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + OBJECT_OPEN_INVALID_PARAMS_TEST_GROUP_NAME); + goto error; + } + + if ((group_id2 = H5Gcreate2(group_id, OBJECT_OPEN_INVALID_PARAMS_TEST_GRP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", OBJECT_OPEN_INVALID_PARAMS_TEST_GRP_NAME); + goto error; + } + + if (H5Gclose(group_id2) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Oopen_invalid_loc_id) + { + TESTING_2("H5Oopen with an invalid location ID"); + + H5E_BEGIN_TRY + { + group_id2 = H5Oopen(H5I_INVALID_HID, OBJECT_OPEN_INVALID_PARAMS_TEST_GRP_NAME, H5P_DEFAULT); + } + H5E_END_TRY; + + if (group_id2 >= 0) { + H5_FAILED(); + HDprintf(" H5Oopen succeeded with an invalid location ID!\n"); + H5Gclose(group_id2); + PART_ERROR(H5Oopen_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Oopen_invalid_loc_id); + + PART_BEGIN(H5Oopen_invalid_obj_name) + { + TESTING_2("H5Oopen with an invalid object name"); + + H5E_BEGIN_TRY + { + group_id2 = H5Oopen(group_id, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (group_id2 >= 0) { + H5_FAILED(); + HDprintf(" H5Oopen succeeded with a NULL object name!\n"); + H5Gclose(group_id2); + PART_ERROR(H5Oopen_invalid_obj_name); + } + + H5E_BEGIN_TRY + { + group_id2 = H5Oopen(group_id, "", H5P_DEFAULT); + } + H5E_END_TRY; + + if (group_id2 >= 0) { + H5_FAILED(); + HDprintf(" H5Oopen succeeded with an invalid object name of ''!\n"); + H5Gclose(group_id2); + PART_ERROR(H5Oopen_invalid_obj_name); + } + + PASSED(); + } + PART_END(H5Oopen_invalid_obj_name); + + PART_BEGIN(H5Oopen_invalid_lapl) + { + TESTING_2("H5Oopen with an invalid LAPL"); + + H5E_BEGIN_TRY + { + group_id2 = H5Oopen(group_id, OBJECT_OPEN_INVALID_PARAMS_TEST_GRP_NAME, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (group_id2 >= 0) { + H5_FAILED(); + HDprintf(" H5Oopen succeeded with an invalid LAPL!\n"); + H5Gclose(group_id2); + PART_ERROR(H5Oopen_invalid_lapl); + } + + PASSED(); + } + PART_END(H5Oopen_invalid_lapl); + + PART_BEGIN(H5Oopen_by_idx_invalid_loc_id) + { + TESTING_2("H5Oopen_by_idx with an invalid location ID"); + + H5E_BEGIN_TRY + { + group_id2 = H5Oopen_by_idx(H5I_INVALID_HID, OBJECT_OPEN_INVALID_PARAMS_TEST_GROUP_NAME, + H5_INDEX_NAME, H5_ITER_INC, 0, H5P_DEFAULT); + } + H5E_END_TRY; + + if (group_id2 >= 0) { + H5_FAILED(); + HDprintf(" H5Oopen_by_idx succeeded with an invalid location ID!\n"); + H5Gclose(group_id2); + PART_ERROR(H5Oopen_by_idx_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Oopen_by_idx_invalid_loc_id); + + PART_BEGIN(H5Oopen_by_idx_invalid_grp_name) + { + TESTING_2("H5Oopen_by_idx with an invalid group name"); + + H5E_BEGIN_TRY + { + group_id2 = H5Oopen_by_idx(container_group, NULL, H5_INDEX_NAME, H5_ITER_INC, 0, H5P_DEFAULT); + } + H5E_END_TRY; + + if (group_id2 >= 0) { + H5_FAILED(); + HDprintf(" H5Oopen_by_idx succeeded with a NULL group name!\n"); + H5Gclose(group_id2); + PART_ERROR(H5Oopen_by_idx_invalid_grp_name); + } + + H5E_BEGIN_TRY + { + group_id2 = H5Oopen_by_idx(container_group, "", H5_INDEX_NAME, H5_ITER_INC, 0, H5P_DEFAULT); + } + H5E_END_TRY; + + if (group_id2 >= 0) { + H5_FAILED(); + HDprintf(" H5Oopen_by_idx succeeded with an invalid group name of ''!\n"); + H5Gclose(group_id2); + PART_ERROR(H5Oopen_by_idx_invalid_grp_name); + } + + PASSED(); + } + PART_END(H5Oopen_by_idx_invalid_grp_name); + + PART_BEGIN(H5Oopen_by_idx_invalid_index_type) + { + TESTING_2("H5Oopen_by_idx with an invalid index type"); + + H5E_BEGIN_TRY + { + group_id2 = H5Oopen_by_idx(container_group, OBJECT_OPEN_INVALID_PARAMS_TEST_GROUP_NAME, + H5_INDEX_UNKNOWN, H5_ITER_INC, 0, H5P_DEFAULT); + } + H5E_END_TRY; + + if (group_id2 >= 0) { + H5_FAILED(); + HDprintf(" H5Oopen_by_idx succeeded with invalid index type H5_INDEX_UNKNOWN!\n"); + H5Gclose(group_id2); + PART_ERROR(H5Oopen_by_idx_invalid_index_type); + } + + H5E_BEGIN_TRY + { + group_id2 = H5Oopen_by_idx(container_group, OBJECT_OPEN_INVALID_PARAMS_TEST_GROUP_NAME, + H5_INDEX_N, H5_ITER_INC, 0, H5P_DEFAULT); + } + H5E_END_TRY; + + if (group_id2 >= 0) { + H5_FAILED(); + HDprintf(" H5Oopen_by_idx succeeded with invalid index type H5_INDEX_N!\n"); + H5Gclose(group_id2); + PART_ERROR(H5Oopen_by_idx_invalid_index_type); + } + + PASSED(); + } + PART_END(H5Oopen_by_idx_invalid_index_type); + + PART_BEGIN(H5Oopen_by_idx_invalid_iter_order) + { + TESTING_2("H5Oopen_by_idx with an invalid iteration order"); + + H5E_BEGIN_TRY + { + group_id2 = H5Oopen_by_idx(container_group, OBJECT_OPEN_INVALID_PARAMS_TEST_GROUP_NAME, + H5_INDEX_NAME, H5_ITER_UNKNOWN, 0, H5P_DEFAULT); + } + H5E_END_TRY; + + if (group_id2 >= 0) { + H5_FAILED(); + HDprintf( + " H5Oopen_by_idx succeeded with an invalid iteration ordering H5_ITER_UNKNOWN!\n"); + H5Gclose(group_id2); + PART_ERROR(H5Oopen_by_idx_invalid_iter_order); + } + + H5E_BEGIN_TRY + { + group_id2 = H5Oopen_by_idx(container_group, OBJECT_OPEN_INVALID_PARAMS_TEST_GROUP_NAME, + H5_INDEX_NAME, H5_ITER_N, 0, H5P_DEFAULT); + } + H5E_END_TRY; + + if (group_id2 >= 0) { + H5_FAILED(); + HDprintf(" H5Oopen_by_idx succeeded with an invalid iteration ordering H5_ITER_N!\n"); + H5Gclose(group_id2); + PART_ERROR(H5Oopen_by_idx_invalid_iter_order); + } + + PASSED(); + } + PART_END(H5Oopen_by_idx_invalid_iter_order); + + PART_BEGIN(H5Oopen_by_idx_invalid_lapl) + { + TESTING_2("H5Oopen_by_idx with an invalid LAPL"); + + H5E_BEGIN_TRY + { + group_id2 = H5Oopen_by_idx(container_group, OBJECT_OPEN_INVALID_PARAMS_TEST_GROUP_NAME, + H5_INDEX_NAME, H5_ITER_INC, 0, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (group_id2 >= 0) { + H5_FAILED(); + HDprintf(" H5Oopen_by_idx succeeded with an invalid LAPL!\n"); + H5Gclose(group_id2); + PART_ERROR(H5Oopen_by_idx_invalid_lapl); + } + + PASSED(); + } + PART_END(H5Oopen_by_idx_invalid_lapl); + + PART_BEGIN(H5Oopen_by_token_invalid_loc_id) + { + TESTING_2("H5Oopen_by_token with an invalid location ID"); + + H5E_BEGIN_TRY + { + group_id2 = H5Oopen_by_token(H5I_INVALID_HID, H5O_TOKEN_UNDEF); + } + H5E_END_TRY; + + if (group_id2 >= 0) { + H5_FAILED(); + HDprintf(" H5Oopen_by_token succeeded with an invalid location ID!\n"); + H5Gclose(group_id2); + PART_ERROR(H5Oopen_by_token_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Oopen_by_token_invalid_loc_id); + + PART_BEGIN(H5Oopen_by_token_invalid_token) + { + TESTING_2("H5Oopen_by_token with an invalid token"); + + H5E_BEGIN_TRY + { + group_id2 = H5Oopen_by_token(file_id, H5O_TOKEN_UNDEF); + } + H5E_END_TRY; + + if (group_id2 >= 0) { + H5_FAILED(); + HDprintf(" H5Oopen_by_token succeeded with an invalid token!\n"); + H5Gclose(group_id2); + PART_ERROR(H5Oopen_by_token_invalid_token); + } + + PASSED(); + } + PART_END(H5Oopen_by_token_invalid_token); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(gcpl_id); + H5Gclose(group_id2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test for H5Oexists_by_name. + */ +static int +test_object_exists(void) +{ + htri_t object_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t group_id2 = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dtype_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + + TESTING_MULTIPART("object existence"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_SOFT_LINKS)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, object, dataset, stored datatype or soft link " + "aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, OBJECT_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", OBJECT_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, OBJECT_EXISTS_TEST_SUBGROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", OBJECT_EXISTS_TEST_SUBGROUP_NAME); + goto error; + } + + if ((fspace_id = generate_random_dataspace(OBJECT_EXISTS_TEST_DSET_SPACE_RANK, NULL, NULL, FALSE)) < 0) + TEST_ERROR; + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + PASSED(); + + /* + * NOTE: H5Oexists_by_name for hard links should always succeed. + * H5Oexists_by_name for a soft link may fail if the link doesn't resolve. + */ + BEGIN_MULTIPART + { + PART_BEGIN(H5Oexists_by_name_group) + { + TESTING_2("H5Oexists_by_name on a group"); + + if ((group_id2 = H5Gcreate2(group_id, OBJECT_EXISTS_TEST_GRP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", OBJECT_EXISTS_TEST_GRP_NAME); + PART_ERROR(H5Oexists_by_name_group); + } + + if ((object_exists = H5Oexists_by_name(group_id, OBJECT_EXISTS_TEST_GRP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if object '%s' exists\n", OBJECT_EXISTS_TEST_GRP_NAME); + PART_ERROR(H5Oexists_by_name_group); + } + + if (!object_exists) { + H5_FAILED(); + HDprintf(" object '%s' didn't exist!\n", OBJECT_EXISTS_TEST_GRP_NAME); + PART_ERROR(H5Oexists_by_name_group); + } + + if (H5Gclose(group_id2) < 0) { + H5_FAILED(); + HDprintf(" couldn't close group\n"); + PART_ERROR(H5Oexists_by_name_group); + } + + PASSED(); + } + PART_END(H5Oexists_by_name_group); + + PART_BEGIN(H5Oexists_by_name_dset) + { + TESTING_2("H5Oexists_by_name on a dataset"); + + if ((dset_id = H5Dcreate2(group_id, OBJECT_EXISTS_TEST_DSET_NAME, dset_dtype, fspace_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", OBJECT_EXISTS_TEST_DSET_NAME); + PART_ERROR(H5Oexists_by_name_dset); + } + + if ((object_exists = H5Oexists_by_name(group_id, OBJECT_EXISTS_TEST_DSET_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if object '%s' exists\n", OBJECT_EXISTS_TEST_DSET_NAME); + PART_ERROR(H5Oexists_by_name_dset); + } + + if (!object_exists) { + H5_FAILED(); + HDprintf(" object '%s' didn't exist!\n", OBJECT_EXISTS_TEST_DSET_NAME); + PART_ERROR(H5Oexists_by_name_dset); + } + + if (H5Dclose(dset_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close dataset\n"); + PART_ERROR(H5Oexists_by_name_dset); + } + + PASSED(); + } + PART_END(H5Oexists_by_name_dset); + + PART_BEGIN(H5Oexists_by_name_dtype) + { + TESTING_2("H5Oexists_by_name on a committed datatype"); + + if ((dtype_id = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create datatype '%s'\n", OBJECT_EXISTS_TEST_TYPE_NAME); + PART_ERROR(H5Oexists_by_name_dtype); + } + + if (H5Tcommit2(group_id, OBJECT_EXISTS_TEST_TYPE_NAME, dtype_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't commit datatype '%s'\n", OBJECT_EXISTS_TEST_TYPE_NAME); + PART_ERROR(H5Oexists_by_name_dtype); + } + + if ((object_exists = H5Oexists_by_name(group_id, OBJECT_EXISTS_TEST_TYPE_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if object '%s' exists\n", OBJECT_EXISTS_TEST_TYPE_NAME); + PART_ERROR(H5Oexists_by_name_dtype); + } + + if (!object_exists) { + H5_FAILED(); + HDprintf(" object '%s' didn't exist!\n", OBJECT_EXISTS_TEST_TYPE_NAME); + PART_ERROR(H5Oexists_by_name_dtype); + } + + if (H5Tclose(dtype_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close datatype\n"); + PART_ERROR(H5Oexists_by_name_dtype); + } + + PASSED(); + } + PART_END(H5Oexists_by_name_dtype); + + PART_BEGIN(H5Oexists_by_name_soft_link) + { + TESTING_2("H5Oexists_by_name for a soft link"); + + if (H5Lcreate_soft("/" OBJECT_TEST_GROUP_NAME "/" OBJECT_EXISTS_TEST_SUBGROUP_NAME, group_id, + OBJECT_EXISTS_TEST_SOFT_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", OBJECT_EXISTS_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Oexists_by_name_soft_link); + } + + if ((object_exists = + H5Oexists_by_name(group_id, OBJECT_EXISTS_TEST_SOFT_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if object '%s' exists\n", OBJECT_EXISTS_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Oexists_by_name_soft_link); + } + + if (!object_exists) { + H5_FAILED(); + HDprintf(" object '%s' didn't exist!\n", OBJECT_EXISTS_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Oexists_by_name_soft_link); + } + + PASSED(); + } + PART_END(H5Oexists_by_name_soft_link); + + PART_BEGIN(H5Oexists_by_name_dangling_soft_link) + { + TESTING_2("H5Oexists_by_name for a dangling soft link"); + + if (H5Lcreate_soft( + "/" OBJECT_TEST_GROUP_NAME "/" OBJECT_EXISTS_TEST_SUBGROUP_NAME "/non_existent_object", + group_id, OBJECT_EXISTS_TEST_DANGLING_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", OBJECT_EXISTS_TEST_DANGLING_LINK_NAME); + PART_ERROR(H5Oexists_by_name_dangling_soft_link); + } + + if ((object_exists = + H5Oexists_by_name(group_id, OBJECT_EXISTS_TEST_DANGLING_LINK_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if object '%s' exists\n", + "/" OBJECT_TEST_GROUP_NAME "/" OBJECT_EXISTS_TEST_SUBGROUP_NAME + "/non_existent_object"); + PART_ERROR(H5Oexists_by_name_dangling_soft_link); + } + + if (object_exists) { + H5_FAILED(); + HDprintf(" object pointed to by dangling soft link should not have existed!\n"); + PART_ERROR(H5Oexists_by_name_dangling_soft_link); + } + + PASSED(); + } + PART_END(H5Oexists_by_name_dangling_soft_link); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + H5Tclose(dset_dtype); + H5Tclose(dtype_id); + H5Dclose(dset_id); + H5Gclose(group_id2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that H5Oexists_by_name fails + * when it is passed invalid parameters. + */ +static int +test_object_exists_invalid_params(void) +{ + htri_t object_exists; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t group_id2 = H5I_INVALID_HID; + + TESTING_MULTIPART("object existence with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, or object aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, OBJECT_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", OBJECT_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, OBJECT_EXISTS_INVALID_PARAMS_TEST_SUBGROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + OBJECT_EXISTS_INVALID_PARAMS_TEST_SUBGROUP_NAME); + goto error; + } + + if ((group_id2 = H5Gcreate2(group_id, OBJECT_EXISTS_INVALID_PARAMS_TEST_GRP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", OBJECT_EXISTS_INVALID_PARAMS_TEST_GRP_NAME); + goto error; + } + + if (H5Gclose(group_id2) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Oexists_by_name_invalid_loc_id) + { + TESTING_2("H5Oexists_by_name with an invalid location ID"); + + H5E_BEGIN_TRY + { + object_exists = H5Oexists_by_name(H5I_INVALID_HID, OBJECT_EXISTS_INVALID_PARAMS_TEST_GRP_NAME, + H5P_DEFAULT); + } + H5E_END_TRY; + + if (object_exists >= 0) { + H5_FAILED(); + HDprintf(" H5Oexists_by_name succeeded with an invalid location ID!\n"); + PART_ERROR(H5Oexists_by_name_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Oexists_by_name_invalid_loc_id); + + PART_BEGIN(H5Oexists_by_name_invalid_obj_name) + { + TESTING_2("H5Oexists_by_name with an invalid object name"); + + H5E_BEGIN_TRY + { + object_exists = H5Oexists_by_name(group_id, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (object_exists >= 0) { + H5_FAILED(); + HDprintf(" H5Oexists_by_name succeeded with a NULL object name!\n"); + PART_ERROR(H5Oexists_by_name_invalid_obj_name); + } + + H5E_BEGIN_TRY + { + object_exists = H5Oexists_by_name(group_id, "", H5P_DEFAULT); + } + H5E_END_TRY; + + if (object_exists >= 0) { + H5_FAILED(); + HDprintf(" H5Oexists_by_name succeeded with an invalid object name of ''!\n"); + PART_ERROR(H5Oexists_by_name_invalid_obj_name); + } + + PASSED(); + } + PART_END(H5Oexists_by_name_invalid_obj_name); + + PART_BEGIN(H5Oexists_by_name_invalid_lapl) + { + TESTING_2("H5Oexists_by_name with an invalid LAPL"); + + H5E_BEGIN_TRY + { + object_exists = + H5Oexists_by_name(group_id, OBJECT_EXISTS_INVALID_PARAMS_TEST_GRP_NAME, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (object_exists >= 0) { + H5_FAILED(); + HDprintf(" H5Oexists_by_name succeeded with an invalid LAPL!\n"); + PART_ERROR(H5Oexists_by_name_invalid_lapl); + } + + PASSED(); + } + PART_END(H5Oexists_by_name_invalid_lapl); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(group_id2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test for H5Oget_info(_by_name/_by_idx). + */ +static int +test_get_object_info(void) +{ + TESTING("object info retrieval"); + + SKIPPED(); + + return 0; +} + +/* + * A test to check that an object's info can't be retrieved + * when H5Oget_info(_by_name/_by_idx) are passed invalid + * parameters. + */ +static int +test_get_object_info_invalid_params(void) +{ + TESTING("object info retrieval with invalid parameters"); + + SKIPPED(); + + return 0; +} + +/* + * A test for H5Olink. + */ +static int +test_link_object(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t group_id2 = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t type_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + + TESTING_MULTIPART("object linking"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, object, dataset, or stored datatype aren't " + "supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, OBJECT_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", OBJECT_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, OBJECT_LINK_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", OBJECT_LINK_TEST_GROUP_NAME); + goto error; + } + + if ((fspace_id = generate_random_dataspace(OBJECT_LINK_TEST_SPACE_RANK, NULL, NULL, FALSE)) < 0) + TEST_ERROR; + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Olink_group) + { + TESTING_2("H5Olink an anonymous group"); + + if ((group_id2 = H5Gcreate_anon(group_id, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create an anonymous group\n"); + PART_ERROR(H5Olink_group); + } + + if (H5Olink(group_id2, group_id, OBJECT_LINK_TEST_GROUP_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't link the anonymous group\n"); + PART_ERROR(H5Olink_group); + } + + PASSED(); + } + PART_END(H5Olink_group); + + PART_BEGIN(H5Olink_dataset) + { + TESTING_2("H5Olink an anonymous dataset"); + + if ((dset_id = H5Dcreate_anon(group_id, dset_dtype, fspace_id, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create an anonymous dataset\n"); + PART_ERROR(H5Olink_dataset); + } + + if (H5Olink(dset_id, group_id, OBJECT_LINK_TEST_DSET_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't link the anonymous dataset\n"); + PART_ERROR(H5Olink_dataset); + } + + PASSED(); + } + PART_END(H5Olink_dataset); + + PART_BEGIN(H5Olink_datatype) + { + TESTING_2("H5Olink an anonymous datatype"); + + if (H5Tcommit_anon(group_id, dset_dtype, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create an anonymous datatype\n"); + PART_ERROR(H5Olink_datatype); + } + + if (H5Olink(dset_dtype, group_id, OBJECT_LINK_TEST_DTYPE_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't link the anonymous datatype\n"); + PART_ERROR(H5Olink_datatype); + } + + PASSED(); + } + PART_END(H5Olink_datatype); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id2) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + H5Tclose(dset_dtype); + H5Tclose(type_id); + H5Dclose(dset_id); + H5Gclose(group_id2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that an object can't be linked into + * the file structure when H5Olink is passed invalid + * parameters. + */ +static int +test_link_object_invalid_params(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t group_id2 = H5I_INVALID_HID; + herr_t status; + + TESTING_MULTIPART("object linking with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, or object aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, OBJECT_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", OBJECT_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, OBJECT_LINK_INVALID_PARAMS_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", OBJECT_LINK_TEST_GROUP_NAME); + goto error; + } + + if ((group_id2 = H5Gcreate_anon(group_id, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create an anonymous group\n"); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Olink_invalid_object_id) + { + TESTING_2("H5Olink with an invalid object ID"); + + H5E_BEGIN_TRY + { + status = H5Olink(H5I_INVALID_HID, group_id, OBJECT_LINK_TEST_GROUP_NAME2, H5P_DEFAULT, + H5P_DEFAULT); + } + H5E_END_TRY; + + if (status >= 0) { + H5_FAILED(); + HDprintf(" H5Olink succeeded with an invalid object ID!\n"); + PART_ERROR(H5Olink_invalid_object_id); + } + + PASSED(); + } + PART_END(H5Olink_invalid_object_id); + + PART_BEGIN(H5Olink_invalid_location) + { + TESTING_2("H5Olink with an invalid location ID"); + + H5E_BEGIN_TRY + { + status = H5Olink(group_id2, H5I_INVALID_HID, OBJECT_LINK_TEST_GROUP_NAME2, H5P_DEFAULT, + H5P_DEFAULT); + } + H5E_END_TRY; + + if (status >= 0) { + H5_FAILED(); + HDprintf(" H5Olink succeeded with an invalid location ID!\n"); + PART_ERROR(H5Olink_invalid_location); + } + + PASSED(); + } + PART_END(H5Olink_invalid_location); + + PART_BEGIN(H5Olink_invalid_name) + { + TESTING_2("H5Olink with an invalid name"); + + H5E_BEGIN_TRY + { + status = H5Olink(group_id2, group_id, NULL, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (status >= 0) { + H5_FAILED(); + HDprintf(" H5Olink succeeded with NULL as the object name!\n"); + PART_ERROR(H5Olink_invalid_name); + } + + H5E_BEGIN_TRY + { + status = H5Olink(group_id2, group_id, "", H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (status >= 0) { + H5_FAILED(); + HDprintf(" H5Olink succeeded with an invalid object name of ''!\n"); + PART_ERROR(H5Olink_invalid_name); + } + + PASSED(); + } + PART_END(H5Olink_invalid_name); + + PART_BEGIN(H5Olink_invalid_lcpl) + { + TESTING_2("H5Olink with an invalid LCPL"); + + H5E_BEGIN_TRY + { + status = + H5Olink(group_id2, group_id, OBJECT_LINK_TEST_GROUP_NAME2, H5I_INVALID_HID, H5P_DEFAULT); + } + H5E_END_TRY; + + if (status >= 0) { + H5_FAILED(); + HDprintf(" H5Olink succeeded with an invalid LCPL!\n"); + PART_ERROR(H5Olink_invalid_lcpl); + } + + PASSED(); + } + PART_END(H5Olink_invalid_lcpl); + + PART_BEGIN(H5Olink_invalid_lapl) + { + TESTING_2("H5Olink with an invalid LAPL"); +#ifndef NO_INVALID_PROPERTY_LIST_TESTS + H5E_BEGIN_TRY + { + status = + H5Olink(group_id2, group_id, OBJECT_LINK_TEST_GROUP_NAME2, H5P_DEFAULT, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (status >= 0) { + H5_FAILED(); + HDprintf(" H5Olink succeeded with an invalid LAPL!\n"); + PART_ERROR(H5Olink_invalid_lapl); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Olink_invalid_lapl); +#endif + } + PART_END(H5Olink_invalid_lapl); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id2) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(group_id2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test for H5Oincr_refcount/H5Odecr_refcount. + */ +static int +test_incr_decr_object_refcount(void) +{ + H5O_info2_t oinfo; /* Object info struct */ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t group_id2 = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + + TESTING_MULTIPART("increment/decrement the reference count of object"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, stored datatype, basic or more object " + "aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, OBJECT_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", OBJECT_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, OBJECT_REF_COUNT_TEST_SUBGROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", OBJECT_REF_COUNT_TEST_SUBGROUP_NAME); + goto error; + } + + if ((fspace_id = generate_random_dataspace(OBJECT_REF_COUNT_TEST_DSET_SPACE_RANK, NULL, NULL, FALSE)) < 0) + TEST_ERROR; + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Oincr_decr_refcount_group) + { + TESTING_2("H5Oincr_refcount/H5Odecr_refcount on a group"); + + if ((group_id2 = H5Gcreate2(group_id, OBJECT_REF_COUNT_TEST_GRP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", OBJECT_REF_COUNT_TEST_GRP_NAME); + PART_ERROR(H5Oincr_decr_refcount_group); + } + + /* Increment the reference count */ + if (H5Oincr_refcount(group_id2) < 0) { + H5_FAILED(); + HDprintf(" couldn't increment reference count for the group '%s' \n", + OBJECT_REF_COUNT_TEST_GRP_NAME); + PART_ERROR(H5Oincr_decr_refcount_group); + } + + /* Verify that reference count is 2 now */ + if (H5Oget_info_by_name3(group_id, OBJECT_REF_COUNT_TEST_GRP_NAME, &oinfo, H5O_INFO_BASIC, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get reference count for the group '%s' \n", + OBJECT_REF_COUNT_TEST_GRP_NAME); + PART_ERROR(H5Oincr_decr_refcount_group); + } + + if (oinfo.rc != 2) { + H5_FAILED(); + HDprintf(" the reference count for the group '%s' isn't 2: %d\n", + OBJECT_REF_COUNT_TEST_GRP_NAME, oinfo.rc); + PART_ERROR(H5Oincr_decr_refcount_group); + } + + /* Decrement the reference count */ + if (H5Odecr_refcount(group_id2) < 0) { + H5_FAILED(); + HDprintf(" couldn't decrement reference count for the group '%s' \n", + OBJECT_REF_COUNT_TEST_GRP_NAME); + PART_ERROR(H5Oincr_decr_refcount_group); + } + + /* Verify that reference count is 1 now */ + if (H5Oget_info_by_name3(group_id, OBJECT_REF_COUNT_TEST_GRP_NAME, &oinfo, H5O_INFO_BASIC, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get reference count for the group '%s' \n", + OBJECT_REF_COUNT_TEST_GRP_NAME); + PART_ERROR(H5Oincr_decr_refcount_group); + } + + if (oinfo.rc != 1) { + H5_FAILED(); + HDprintf(" the reference count for the group '%s' isn't 1: %d\n", + OBJECT_REF_COUNT_TEST_GRP_NAME, oinfo.rc); + PART_ERROR(H5Oincr_decr_refcount_group); + } + + if (H5Gclose(group_id2) < 0) { + H5_FAILED(); + HDprintf(" couldn't close group\n"); + PART_ERROR(H5Oincr_decr_refcount_group); + } + + PASSED(); + } + PART_END(H5Oincr_decr_refcount_group); + + PART_BEGIN(H5Oincr_decr_refcount_dset) + { + TESTING_2("H5Oincr_refcount/H5Odecr_refcount on a dataset"); + + if ((dset_id = H5Dcreate2(group_id, OBJECT_REF_COUNT_TEST_DSET_NAME, dset_dtype, fspace_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", OBJECT_REF_COUNT_TEST_DSET_NAME); + PART_ERROR(H5Oincr_decr_refcount_dset); + } + + /* Increment the reference count */ + if (H5Oincr_refcount(dset_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't increment reference count for the dataset '%s' \n", + OBJECT_REF_COUNT_TEST_DSET_NAME); + PART_ERROR(H5Oincr_decr_refcount_dset); + } + + /* Verify that reference count is 2 now */ + if (H5Oget_info_by_name3(group_id, OBJECT_REF_COUNT_TEST_DSET_NAME, &oinfo, H5O_INFO_BASIC, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get reference count for the dataset '%s' \n", + OBJECT_REF_COUNT_TEST_DSET_NAME); + PART_ERROR(H5Oincr_decr_refcount_dset); + } + + if (oinfo.rc != 2) { + H5_FAILED(); + HDprintf(" the reference count for the dataset '%s' isn't 2: %d\n", + OBJECT_REF_COUNT_TEST_DSET_NAME, oinfo.rc); + PART_ERROR(H5Oincr_decr_refcount_dset); + } + + /* Decrement the reference count */ + if (H5Odecr_refcount(dset_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't decrement reference count for the dataset '%s' \n", + OBJECT_REF_COUNT_TEST_DSET_NAME); + PART_ERROR(H5Oincr_decr_refcount_dset); + } + + /* Verify that reference count is 1 now */ + if (H5Oget_info_by_name3(group_id, OBJECT_REF_COUNT_TEST_DSET_NAME, &oinfo, H5O_INFO_BASIC, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get reference count for the dataset '%s' \n", + OBJECT_REF_COUNT_TEST_DSET_NAME); + PART_ERROR(H5Oincr_decr_refcount_dset); + } + + if (oinfo.rc != 1) { + H5_FAILED(); + HDprintf(" the reference count for the dataset '%s' isn't 1: %d\n", + OBJECT_REF_COUNT_TEST_DSET_NAME, oinfo.rc); + PART_ERROR(H5Oincr_decr_refcount_dset); + } + + if (H5Dclose(dset_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close dataset\n"); + PART_ERROR(H5Oincr_decr_refcount_dset); + } + + PASSED(); + } + PART_END(H5Oincr_decr_refcount_dset); + + PART_BEGIN(H5Oincr / decr_refcount_dtype) + { + TESTING_2("H5Oincr_refcount/H5Odecr_refcount on a committed datatype"); + + if (H5Tcommit2(group_id, OBJECT_REF_COUNT_TEST_TYPE_NAME, dset_dtype, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't commit datatype '%s'\n", OBJECT_REF_COUNT_TEST_TYPE_NAME); + PART_ERROR(H5Oincr_decr_refcount_dtype); + } + + /* Increment the reference count */ + if (H5Oincr_refcount(dset_dtype) < 0) { + H5_FAILED(); + HDprintf(" couldn't increment reference count for the datatype '%s' \n", + OBJECT_REF_COUNT_TEST_TYPE_NAME); + PART_ERROR(H5Oincr_decr_refcount_dtype); + } + + /* Verify that reference count is 2 now */ + if (H5Oget_info_by_name3(group_id, OBJECT_REF_COUNT_TEST_TYPE_NAME, &oinfo, H5O_INFO_BASIC, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get reference count for the datatype '%s' \n", + OBJECT_REF_COUNT_TEST_TYPE_NAME); + PART_ERROR(H5Oincr_decr_refcount_dtype); + } + + if (oinfo.rc != 2) { + H5_FAILED(); + HDprintf(" the reference count for the datatype '%s' isn't 2: %d\n", + OBJECT_REF_COUNT_TEST_TYPE_NAME, oinfo.rc); + PART_ERROR(H5Oincr_decr_refcount_dtype); + } + + /* Decrement the reference count */ + if (H5Odecr_refcount(dset_dtype) < 0) { + H5_FAILED(); + HDprintf(" couldn't decrement reference count for the datatype '%s' \n", + OBJECT_REF_COUNT_TEST_TYPE_NAME); + PART_ERROR(H5Oincr_decr_refcount_dtype); + } + + /* Verify that reference count is 1 now */ + if (H5Oget_info_by_name3(group_id, OBJECT_REF_COUNT_TEST_TYPE_NAME, &oinfo, H5O_INFO_BASIC, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't get reference count for the datatype '%s' \n", + OBJECT_REF_COUNT_TEST_TYPE_NAME); + PART_ERROR(H5Oincr_decr_refcount_dtype); + } + + if (oinfo.rc != 1) { + H5_FAILED(); + HDprintf(" the reference count for the datatype '%s' isn't 1: %d\n", + OBJECT_REF_COUNT_TEST_TYPE_NAME, oinfo.rc); + PART_ERROR(H5Oincr_decr_refcount_dtype); + } + + if (H5Tclose(dset_dtype) < 0) { + H5_FAILED(); + HDprintf(" couldn't close datatype\n"); + PART_ERROR(H5Oincr_decr_refcount_dtype); + } + + PASSED(); + } + PART_END(H5Oincr_decr_refcount_dtype); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + H5Tclose(dset_dtype); + H5Dclose(dset_id); + H5Gclose(group_id2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} /* test_incr_decr_object_refcount */ + +/* + * A test to check that H5Oincr_refcount/H5Odecr_refcount + * fail when passed invalid parameters. + */ +static int +test_incr_decr_object_refcount_invalid_params(void) +{ + herr_t status; + + TESTING_MULTIPART("object reference count incr./decr. with an invalid parameter"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_MORE)) { + SKIPPED(); + HDprintf(" API functions for more object aren't supported with this connector\n"); + return 0; + } + + BEGIN_MULTIPART + { + PART_BEGIN(H5Oincr_refcount_invalid_param) + { + TESTING_2("H5Oincr_refcount with invalid object ID"); + + H5E_BEGIN_TRY + { + status = H5Oincr_refcount(H5I_INVALID_HID); + } + H5E_END_TRY; + + if (status >= 0) { + H5_FAILED(); + HDprintf(" incremented the reference count for an invalid object ID\n"); + PART_ERROR(H5Oincr_refcount_invalid_param); + } + + PASSED(); + } + PART_END(H5Oincr_refcount_invalid_param); + + PART_BEGIN(H5Odecr_refcount_invalid_param) + { + TESTING_2("H5Odecr_refcount with invalid object ID"); + + H5E_BEGIN_TRY + { + status = H5Odecr_refcount(H5I_INVALID_HID); + } + H5E_END_TRY; + + if (status >= 0) { + H5_FAILED(); + HDprintf(" decremented the reference count for an invalid object ID\n"); + PART_ERROR(H5Odecr_refcount_invalid_param); + } + + PASSED(); + } + PART_END(H5Odecr_refcount_invalid_param); + } + END_MULTIPART; + + return 0; + +error: + return 1; +} + +/* + * Basic tests for H5Ocopy. + */ +static int +test_object_copy_basic(void) +{ + H5O_info2_t object_info; + H5G_info_t group_info; + htri_t object_link_exists; + size_t i; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t group_id2 = H5I_INVALID_HID; + hid_t tmp_group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t tmp_dset_id = H5I_INVALID_HID; + hid_t dtype_id = H5I_INVALID_HID; + hid_t tmp_dtype_id = H5I_INVALID_HID; + hid_t tmp_attr_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t attr_space_id = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + + TESTING_MULTIPART("basic object copying"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_MORE) || !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ITERATE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, object, link, dataset, attribute, iterate, or " + "stored datatype aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, OBJECT_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", OBJECT_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, OBJECT_COPY_BASIC_TEST_SUBGROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", OBJECT_COPY_BASIC_TEST_SUBGROUP_NAME); + goto error; + } + + if ((space_id = generate_random_dataspace(OBJECT_COPY_BASIC_TEST_SPACE_RANK, NULL, NULL, FALSE)) < 0) + TEST_ERROR; + if ((attr_space_id = generate_random_dataspace(OBJECT_COPY_BASIC_TEST_SPACE_RANK, NULL, NULL, TRUE)) < 0) + TEST_ERROR; + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + /* Create the test group object, along with its nested members and the attributes attached to it. */ + if ((group_id2 = H5Gcreate2(group_id, OBJECT_COPY_BASIC_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", OBJECT_COPY_BASIC_TEST_GROUP_NAME); + goto error; + } + + for (i = 0; i < (size_t)OBJECT_COPY_BASIC_TEST_NUM_NESTED_OBJS; i++) { + char grp_name[OBJECT_COPY_BASIC_TEST_BUF_SIZE]; + + snprintf(grp_name, OBJECT_COPY_BASIC_TEST_BUF_SIZE, "grp%d", (int)i); + + if ((tmp_group_id = H5Gcreate2(group_id2, grp_name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s' under group '%s'\n", grp_name, + OBJECT_COPY_BASIC_TEST_GROUP_NAME); + goto error; + } + + /* Create a further nested group under the last group added */ + if (i == (OBJECT_COPY_BASIC_TEST_NUM_NESTED_OBJS - 1)) { + if (H5Gclose(H5Gcreate2(tmp_group_id, OBJECT_COPY_BASIC_TEST_DEEP_NESTED_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create nested group '%s' under group '%s'\n", + OBJECT_COPY_BASIC_TEST_DEEP_NESTED_GROUP_NAME, grp_name); + goto error; + } + } + + if (H5Gclose(tmp_group_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close group '%s'\n", grp_name); + goto error; + } + } + + for (i = 0; i < (size_t)OBJECT_COPY_BASIC_TEST_NUM_ATTRS; i++) { + char attr_name[OBJECT_COPY_BASIC_TEST_BUF_SIZE]; + + snprintf(attr_name, OBJECT_COPY_BASIC_TEST_BUF_SIZE, "attr%d", (int)i); + + if ((tmp_attr_id = H5Acreate2(group_id2, attr_name, H5T_NATIVE_INT, attr_space_id, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s' on group '%s'\n", attr_name, + OBJECT_COPY_BASIC_TEST_GROUP_NAME); + goto error; + } + + if (H5Aclose(tmp_attr_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close attribute '%s'\n", attr_name); + goto error; + } + } + + /* Create the test dataset object, along with the attributes attached to it. */ + if ((dset_id = H5Dcreate2(group_id, OBJECT_COPY_BASIC_TEST_DSET_NAME, dset_dtype, space_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", OBJECT_COPY_BASIC_TEST_DSET_NAME); + goto error; + } + + for (i = 0; i < (size_t)OBJECT_COPY_BASIC_TEST_NUM_ATTRS; i++) { + char attr_name[OBJECT_COPY_BASIC_TEST_BUF_SIZE]; + + snprintf(attr_name, OBJECT_COPY_BASIC_TEST_BUF_SIZE, "attr%d", (int)i); + + if ((tmp_attr_id = H5Acreate2(dset_id, attr_name, H5T_NATIVE_INT, attr_space_id, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s' on dataset '%s'\n", attr_name, + OBJECT_COPY_BASIC_TEST_DSET_NAME); + goto error; + } + + if (H5Aclose(tmp_attr_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close attribute '%s'\n", attr_name); + goto error; + } + } + + /* Create the test committed datatype object, along with the attributes attached to it. */ + if ((dtype_id = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create datatype\n"); + goto error; + } + + if (H5Tcommit2(group_id, OBJECT_COPY_BASIC_TEST_DTYPE_NAME, dtype_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't commit datatype '%s'\n", OBJECT_COPY_BASIC_TEST_DTYPE_NAME); + goto error; + } + + for (i = 0; i < (size_t)OBJECT_COPY_BASIC_TEST_NUM_ATTRS; i++) { + char attr_name[OBJECT_COPY_BASIC_TEST_BUF_SIZE]; + + snprintf(attr_name, OBJECT_COPY_BASIC_TEST_BUF_SIZE, "attr%d", (int)i); + + if ((tmp_attr_id = H5Acreate2(dtype_id, attr_name, H5T_NATIVE_INT, attr_space_id, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s' on committed datatype '%s'\n", attr_name, + OBJECT_COPY_BASIC_TEST_DTYPE_NAME); + goto error; + } + + if (H5Aclose(tmp_attr_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close attribute '%s'\n", attr_name); + goto error; + } + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Ocopy_group) + { + TESTING_2("H5Ocopy on a group (default copy options)"); + + if (H5Ocopy(group_id, OBJECT_COPY_BASIC_TEST_GROUP_NAME, group_id, + OBJECT_COPY_BASIC_TEST_NEW_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to copy group '%s' to '%s'\n", OBJECT_COPY_BASIC_TEST_GROUP_NAME, + OBJECT_COPY_BASIC_TEST_NEW_GROUP_NAME); + PART_ERROR(H5Ocopy_group); + } + + if ((object_link_exists = + H5Lexists(group_id, OBJECT_COPY_BASIC_TEST_NEW_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' to copied group exists\n", + OBJECT_COPY_BASIC_TEST_NEW_GROUP_NAME); + PART_ERROR(H5Ocopy_group); + } + + if (!object_link_exists) { + H5_FAILED(); + HDprintf(" link '%s' to copied group didn't exist!\n", + OBJECT_COPY_BASIC_TEST_NEW_GROUP_NAME); + PART_ERROR(H5Ocopy_group); + } + + /* Ensure that the new group has all the members of the copied group, and all its attributes */ + if ((tmp_group_id = H5Gopen2(group_id, OBJECT_COPY_BASIC_TEST_NEW_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to open group copy '%s'\n", OBJECT_COPY_BASIC_TEST_NEW_GROUP_NAME); + PART_ERROR(H5Ocopy_group); + } + + memset(&group_info, 0, sizeof(group_info)); + + /* + * Set link count to zero in case the connector doesn't support + * retrieval of group info. + */ + group_info.nlinks = 0; + + if (H5Gget_info(tmp_group_id, &group_info) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve group info\n"); + PART_ERROR(H5Ocopy_group); + } + + if (group_info.nlinks != OBJECT_COPY_BASIC_TEST_NUM_NESTED_OBJS) { + H5_FAILED(); + HDprintf(" copied group contained %d members instead of %d members after a deep copy!\n", + (int)group_info.nlinks, OBJECT_COPY_BASIC_TEST_NUM_NESTED_OBJS); + PART_ERROR(H5Ocopy_group); + } + + memset(&object_info, 0, sizeof(object_info)); + + /* + * Set attribute count to zero in case the connector doesn't + * support retrieval of object info. + */ + object_info.num_attrs = 0; + + if (H5Oget_info3(tmp_group_id, &object_info, H5O_INFO_ALL) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve object info\n"); + PART_ERROR(H5Ocopy_group); + } + + if (object_info.num_attrs == 0) { + H5_FAILED(); + HDprintf(" copied group didn't contain any attributes after copy operation!\n"); + PART_ERROR(H5Ocopy_group); + } + + /* Check the attribute names, types, etc. */ + i = 0; + if (H5Aiterate2(tmp_group_id, H5_INDEX_NAME, H5_ITER_INC, NULL, + object_copy_attribute_iter_callback, &i) < 0) { + H5_FAILED(); + HDprintf(" failed to iterate over copied group's attributes\n"); + PART_ERROR(H5Ocopy_group); + } + + if (i != OBJECT_COPY_BASIC_TEST_NUM_ATTRS) { + H5_FAILED(); + HDprintf( + " number of attributes on copied group (%llu) didn't match expected number (%llu)!\n", + (unsigned long long)i, (unsigned long long)OBJECT_COPY_BASIC_TEST_NUM_ATTRS); + PART_ERROR(H5Ocopy_group); + } + + if (H5Gclose(tmp_group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group copy\n"); + PART_ERROR(H5Ocopy_group); + } + + /* + * Ensure that the last immediate member of the copied group + * contains its single member after the deep copy. + */ + { + char grp_name[OBJECT_COPY_BASIC_TEST_BUF_SIZE]; + + snprintf(grp_name, OBJECT_COPY_BASIC_TEST_BUF_SIZE, + OBJECT_COPY_BASIC_TEST_NEW_GROUP_NAME "/grp%d", + OBJECT_COPY_BASIC_TEST_NUM_NESTED_OBJS - 1); + + if ((tmp_group_id = H5Gopen2(group_id, grp_name, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to open group '%s'\n", + OBJECT_COPY_BASIC_TEST_DEEP_NESTED_GROUP_NAME); + PART_ERROR(H5Ocopy_group); + } + + memset(&group_info, 0, sizeof(group_info)); + + /* + * Set link count to zero in case the connector doesn't support + * retrieval of group info. + */ + group_info.nlinks = 0; + + if (H5Gget_info(tmp_group_id, &group_info) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve group info\n"); + PART_ERROR(H5Ocopy_group); + } + + if (group_info.nlinks != 1) { + H5_FAILED(); + HDprintf(" copied group's immediate members didn't contain nested members after a " + "deep copy!\n"); + PART_ERROR(H5Ocopy_group); + } + + if (H5Gclose(tmp_group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", + OBJECT_COPY_BASIC_TEST_DEEP_NESTED_GROUP_NAME); + PART_ERROR(H5Ocopy_group); + } + } + + PASSED(); + } + PART_END(H5Ocopy_group); + + if (tmp_group_id >= 0) { + H5E_BEGIN_TRY + { + H5Gclose(tmp_group_id); + } + H5E_END_TRY; + tmp_group_id = H5I_INVALID_HID; + } + + PART_BEGIN(H5Ocopy_dset) + { + TESTING_2("H5Ocopy on a dataset (default copy options)"); + + if (H5Ocopy(group_id, OBJECT_COPY_BASIC_TEST_DSET_NAME, group_id, + OBJECT_COPY_BASIC_TEST_NEW_DSET_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to copy dataset '%s' to '%s'\n", OBJECT_COPY_BASIC_TEST_DSET_NAME, + OBJECT_COPY_BASIC_TEST_NEW_DSET_NAME); + PART_ERROR(H5Ocopy_dset); + } + + if ((object_link_exists = + H5Lexists(group_id, OBJECT_COPY_BASIC_TEST_NEW_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' to copied dataset exists\n", + OBJECT_COPY_BASIC_TEST_NEW_DSET_NAME); + PART_ERROR(H5Ocopy_dset); + } + + if (!object_link_exists) { + H5_FAILED(); + HDprintf(" link '%s' to copied dataset didn't exist!\n", + OBJECT_COPY_BASIC_TEST_NEW_DSET_NAME); + PART_ERROR(H5Ocopy_dset); + } + + /* Ensure that the new dataset has all of the attributes of the copied dataset */ + if ((tmp_dset_id = H5Dopen2(group_id, OBJECT_COPY_BASIC_TEST_NEW_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to open dataset copy '%s'\n", OBJECT_COPY_BASIC_TEST_NEW_DSET_NAME); + PART_ERROR(H5Ocopy_dset); + } + + memset(&object_info, 0, sizeof(object_info)); + + /* + * Set attribute count to zero in case the connector doesn't + * support retrieval of object info. + */ + object_info.num_attrs = 0; + + if (H5Oget_info3(tmp_dset_id, &object_info, H5O_INFO_ALL) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve object info\n"); + PART_ERROR(H5Ocopy_dset); + } + + if (object_info.num_attrs == 0) { + H5_FAILED(); + HDprintf(" copied dataset didn't contain any attributes after copy operation!\n"); + PART_ERROR(H5Ocopy_dset); + } + + /* Check the attribute names, types, etc. */ + i = 0; + if (H5Aiterate2(tmp_dset_id, H5_INDEX_NAME, H5_ITER_INC, NULL, + object_copy_attribute_iter_callback, &i) < 0) { + H5_FAILED(); + HDprintf(" failed to iterate over copied dataset's attributes\n"); + PART_ERROR(H5Ocopy_dset); + } + + if (i != OBJECT_COPY_BASIC_TEST_NUM_ATTRS) { + H5_FAILED(); + HDprintf(" number of attributes on copied dataset (%llu) didn't match expected number " + "(%llu)!\n", + (unsigned long long)i, (unsigned long long)OBJECT_COPY_BASIC_TEST_NUM_ATTRS); + PART_ERROR(H5Ocopy_dset); + } + + if (H5Dclose(tmp_dset_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close dataset copy\n"); + PART_ERROR(H5Ocopy_dset); + } + + PASSED(); + } + PART_END(H5Ocopy_dset); + + if (tmp_dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(tmp_dset_id); + } + H5E_END_TRY; + tmp_dset_id = H5I_INVALID_HID; + } + + PART_BEGIN(H5Ocopy_dtype) + { + TESTING_2("H5Ocopy on a committed datatype (default copy options)"); + + if (H5Ocopy(group_id, OBJECT_COPY_BASIC_TEST_DTYPE_NAME, group_id, + OBJECT_COPY_BASIC_TEST_NEW_DTYPE_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to copy datatype '%s' to '%s'\n", OBJECT_COPY_BASIC_TEST_DTYPE_NAME, + OBJECT_COPY_BASIC_TEST_NEW_DTYPE_NAME); + PART_ERROR(H5Ocopy_dtype); + } + + if ((object_link_exists = + H5Lexists(group_id, OBJECT_COPY_BASIC_TEST_NEW_DTYPE_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' to copied datatype exists\n", + OBJECT_COPY_BASIC_TEST_NEW_DTYPE_NAME); + PART_ERROR(H5Ocopy_dtype); + } + + if (!object_link_exists) { + H5_FAILED(); + HDprintf(" link '%s' to copied datatype didn't exist!\n", + OBJECT_COPY_BASIC_TEST_NEW_DTYPE_NAME); + PART_ERROR(H5Ocopy_dtype); + } + + /* Ensure that the new committed datatype has all the attributes of the copied datatype */ + if ((tmp_dtype_id = H5Topen2(group_id, OBJECT_COPY_BASIC_TEST_NEW_DTYPE_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to open datatype copy '%s'\n", OBJECT_COPY_BASIC_TEST_NEW_DTYPE_NAME); + PART_ERROR(H5Ocopy_dtype); + } + + memset(&object_info, 0, sizeof(object_info)); + + /* + * Set attribute count to zero in case the connector doesn't + * support retrieval of object info. + */ + object_info.num_attrs = 0; + + if (H5Oget_info3(tmp_dtype_id, &object_info, H5O_INFO_ALL) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve object info\n"); + PART_ERROR(H5Ocopy_dtype); + } + + if (object_info.num_attrs == 0) { + H5_FAILED(); + HDprintf( + " copied committed datatype didn't contain any attributes after copy operation!\n"); + PART_ERROR(H5Ocopy_dtype); + } + + /* Check the attribute names, types, etc. */ + i = 0; + if (H5Aiterate2(tmp_dtype_id, H5_INDEX_NAME, H5_ITER_INC, NULL, + object_copy_attribute_iter_callback, &i) < 0) { + H5_FAILED(); + HDprintf(" failed to iterate over copied datatype's attributes\n"); + PART_ERROR(H5Ocopy_dtype); + } + + if (i != OBJECT_COPY_BASIC_TEST_NUM_ATTRS) { + H5_FAILED(); + HDprintf(" number of attributes on copied datatype (%llu) didn't match expected number " + "(%llu)!\n", + (unsigned long long)i, (unsigned long long)OBJECT_COPY_BASIC_TEST_NUM_ATTRS); + PART_ERROR(H5Ocopy_dtype); + } + + if (H5Tclose(tmp_dtype_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close datatype copy\n"); + PART_ERROR(H5Ocopy_dtype); + } + + PASSED(); + } + PART_END(H5Ocopy_dtype); + + if (tmp_dtype_id >= 0) { + H5E_BEGIN_TRY + { + H5Tclose(tmp_dtype_id); + } + H5E_END_TRY; + tmp_dtype_id = H5I_INVALID_HID; + } + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(attr_space_id) < 0) + TEST_ERROR; + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Tclose(dtype_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id2) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(attr_space_id); + H5Sclose(space_id); + H5Aclose(tmp_attr_id); + H5Tclose(dset_dtype); + H5Tclose(tmp_dtype_id); + H5Tclose(dtype_id); + H5Dclose(tmp_dset_id); + H5Dclose(dset_id); + H5Gclose(tmp_group_id); + H5Gclose(group_id2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * Tests to ensure that H5Ocopy fails when attempting to copy + * an object to a destination where the object already exists. + */ +static int +test_object_copy_already_existing(void) +{ + herr_t err_ret; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t group_id2 = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dtype_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + + TESTING_MULTIPART("object copying to location where objects already exist"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, object, dataset, or stored datatype aren't " + "supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, OBJECT_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", OBJECT_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, OBJECT_COPY_ALREADY_EXISTING_TEST_SUBGROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + OBJECT_COPY_ALREADY_EXISTING_TEST_SUBGROUP_NAME); + goto error; + } + + if ((space_id = + generate_random_dataspace(OBJECT_COPY_ALREADY_EXISTING_TEST_SPACE_RANK, NULL, NULL, FALSE)) < 0) + TEST_ERROR; + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + /* Create the test group object */ + if ((group_id2 = H5Gcreate2(group_id, OBJECT_COPY_ALREADY_EXISTING_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", OBJECT_COPY_ALREADY_EXISTING_TEST_GROUP_NAME); + goto error; + } + + /* Create the test dataset object */ + if ((dset_id = H5Dcreate2(group_id, OBJECT_COPY_ALREADY_EXISTING_TEST_DSET_NAME, dset_dtype, space_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", OBJECT_COPY_ALREADY_EXISTING_TEST_DSET_NAME); + goto error; + } + + /* Create the test committed datatype object */ + if ((dtype_id = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create datatype\n"); + goto error; + } + + if (H5Tcommit2(group_id, OBJECT_COPY_ALREADY_EXISTING_TEST_DTYPE_NAME, dtype_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't commit datatype '%s'\n", OBJECT_COPY_ALREADY_EXISTING_TEST_DTYPE_NAME); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Ocopy_already_existing_group) + { + TESTING_2("H5Ocopy group to location where group already exists"); + + H5E_BEGIN_TRY + { + err_ret = H5Ocopy(group_id, OBJECT_COPY_ALREADY_EXISTING_TEST_GROUP_NAME, group_id, + OBJECT_COPY_ALREADY_EXISTING_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" group copy succeeded in location where group already exists!\n"); + PART_ERROR(H5Ocopy_already_existing_group); + } + + PASSED(); + } + PART_END(H5Ocopy_already_existing_group); + + PART_BEGIN(H5Ocopy_already_existing_dset) + { + TESTING_2("H5Ocopy dataset to location where dataset already exists"); + + H5E_BEGIN_TRY + { + err_ret = H5Ocopy(group_id, OBJECT_COPY_ALREADY_EXISTING_TEST_DSET_NAME, group_id, + OBJECT_COPY_ALREADY_EXISTING_TEST_DSET_NAME, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" dataset copy succeeded in location where dataset already exists!\n"); + PART_ERROR(H5Ocopy_already_existing_dset); + } + + PASSED(); + } + PART_END(H5Ocopy_already_existing_dset); + + PART_BEGIN(H5Ocopy_already_existing_dtype) + { + TESTING_2("H5Ocopy committed datatype to location where committed datatype already exists"); + + H5E_BEGIN_TRY + { + err_ret = H5Ocopy(group_id, OBJECT_COPY_ALREADY_EXISTING_TEST_DTYPE_NAME, group_id, + OBJECT_COPY_ALREADY_EXISTING_TEST_DTYPE_NAME, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" committed datatype copy succeeded in location where committed datatype already " + "exists!\n"); + PART_ERROR(H5Ocopy_already_existing_dtype); + } + + PASSED(); + } + PART_END(H5Ocopy_already_existing_dtype); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Tclose(dtype_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id2) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(space_id); + H5Tclose(dset_dtype); + H5Tclose(dtype_id); + H5Dclose(dset_id); + H5Gclose(group_id2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to exercise the H5O_COPY_SHALLOW_HIERARCHY_FLAG flag + * for H5Ocopy. + */ +static int +test_object_copy_shallow_group_copy(void) +{ + H5G_info_t group_info; + htri_t object_link_exists; + size_t i; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t group_id2 = H5I_INVALID_HID; + hid_t tmp_group_id = H5I_INVALID_HID; + hid_t ocpypl_id = H5I_INVALID_HID; + + TESTING("object copying with H5O_COPY_SHALLOW_HIERARCHY_FLAG flag"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_MORE) || !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, object, or link aren't supported with this " + "connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, OBJECT_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", OBJECT_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, OBJECT_COPY_SHALLOW_TEST_SUBGROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", OBJECT_COPY_SHALLOW_TEST_SUBGROUP_NAME); + goto error; + } + + /* Create the test group object, along with its nested members. */ + if ((group_id2 = H5Gcreate2(group_id, OBJECT_COPY_SHALLOW_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", OBJECT_COPY_SHALLOW_TEST_GROUP_NAME); + goto error; + } + + for (i = 0; i < (size_t)OBJECT_COPY_SHALLOW_TEST_NUM_NESTED_OBJS; i++) { + char grp_name[OBJECT_COPY_SHALLOW_TEST_BUF_SIZE]; + + snprintf(grp_name, OBJECT_COPY_SHALLOW_TEST_BUF_SIZE, "grp%d", (int)i); + + if ((tmp_group_id = H5Gcreate2(group_id2, grp_name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s' under group '%s'\n", grp_name, + OBJECT_COPY_SHALLOW_TEST_GROUP_NAME); + goto error; + } + + /* Create a further nested group under the last group added */ + if (i == (OBJECT_COPY_SHALLOW_TEST_NUM_NESTED_OBJS - 1)) { + if (H5Gclose(H5Gcreate2(tmp_group_id, OBJECT_COPY_SHALLOW_TEST_DEEP_NESTED_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create nested group '%s' under group '%s'\n", + OBJECT_COPY_SHALLOW_TEST_DEEP_NESTED_GROUP_NAME, grp_name); + goto error; + } + } + + if (H5Gclose(tmp_group_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close group '%s'\n", grp_name); + goto error; + } + } + + if ((ocpypl_id = H5Pcreate(H5P_OBJECT_COPY)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create OCopyPL\n"); + goto error; + } + + if (H5Pset_copy_object(ocpypl_id, H5O_COPY_SHALLOW_HIERARCHY_FLAG) < 0) { + H5_FAILED(); + HDprintf(" couldn't set object copying options\n"); + goto error; + } + + if (H5Ocopy(group_id, OBJECT_COPY_SHALLOW_TEST_GROUP_NAME, group_id, + OBJECT_COPY_SHALLOW_TEST_NEW_GROUP_NAME, ocpypl_id, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to copy group '%s' to '%s'\n", OBJECT_COPY_SHALLOW_TEST_GROUP_NAME, + OBJECT_COPY_SHALLOW_TEST_NEW_GROUP_NAME); + goto error; + } + + if ((object_link_exists = H5Lexists(group_id, OBJECT_COPY_SHALLOW_TEST_NEW_GROUP_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' to copied group exists\n", + OBJECT_COPY_SHALLOW_TEST_NEW_GROUP_NAME); + goto error; + } + + if (!object_link_exists) { + H5_FAILED(); + HDprintf(" link '%s' to copied group didn't exist!\n", OBJECT_COPY_SHALLOW_TEST_NEW_GROUP_NAME); + goto error; + } + + /* + * Ensure that the new group has only the immediate members of the copied group. + */ + if ((tmp_group_id = H5Gopen2(group_id, OBJECT_COPY_SHALLOW_TEST_NEW_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to open group copy '%s'\n", OBJECT_COPY_SHALLOW_TEST_NEW_GROUP_NAME); + goto error; + } + + memset(&group_info, 0, sizeof(group_info)); + + /* + * Set link count to zero in case the connector doesn't support + * retrieval of group info. + */ + group_info.nlinks = 0; + + if (H5Gget_info(tmp_group_id, &group_info) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve group info\n"); + goto error; + } + + if (group_info.nlinks != OBJECT_COPY_SHALLOW_TEST_NUM_NESTED_OBJS) { + H5_FAILED(); + HDprintf(" copied group contained %d members instead of %d members after a shallow copy!\n", + (int)group_info.nlinks, OBJECT_COPY_SHALLOW_TEST_NUM_NESTED_OBJS); + goto error; + } + + if (H5Gclose(tmp_group_id) < 0) + TEST_ERROR; + + /* + * Ensure that the last immediate member of the copied group doesn't + * contain any members after the shallow copy. + */ + { + char grp_name[OBJECT_COPY_SHALLOW_TEST_BUF_SIZE]; + + snprintf(grp_name, OBJECT_COPY_SHALLOW_TEST_BUF_SIZE, + OBJECT_COPY_SHALLOW_TEST_NEW_GROUP_NAME "/grp%d", + OBJECT_COPY_SHALLOW_TEST_NUM_NESTED_OBJS - 1); + + if ((tmp_group_id = H5Gopen2(group_id, grp_name, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to open group '%s'\n", grp_name); + goto error; + } + + memset(&group_info, 0, sizeof(group_info)); + + /* + * Set link count to non-zero in case the connector doesn't support + * retrieval of group info. + */ + group_info.nlinks = 1; + + if (H5Gget_info(tmp_group_id, &group_info) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve group info\n"); + goto error; + } + + if (group_info.nlinks != 0) { + H5_FAILED(); + HDprintf(" copied group's immediate members contained nested members after a shallow copy!\n"); + goto error; + } + + if (H5Gclose(tmp_group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", grp_name); + goto error; + } + } + + if (H5Pclose(ocpypl_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id2) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(ocpypl_id); + H5Gclose(tmp_group_id); + H5Gclose(group_id2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * Tests to exercise the H5O_COPY_WITHOUT_ATTR_FLAG flag + * of H5Ocopy. + */ +static int +test_object_copy_no_attributes(void) +{ + H5O_info2_t object_info; + htri_t object_link_exists; + size_t i; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t group_id2 = H5I_INVALID_HID; + hid_t tmp_group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t tmp_dset_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t dtype_id = H5I_INVALID_HID; + hid_t tmp_dtype_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t attr_space_id = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + hid_t ocpypl_id = H5I_INVALID_HID; + + TESTING_MULTIPART("object copying with H5O_COPY_WITHOUT_ATTR_FLAG flag"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_MORE) || !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, object, link, dataset, attribute, or stored " + "datatype aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, OBJECT_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", OBJECT_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, OBJECT_COPY_NO_ATTRS_TEST_SUBGROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", OBJECT_COPY_NO_ATTRS_TEST_SUBGROUP_NAME); + goto error; + } + + if ((space_id = generate_random_dataspace(OBJECT_COPY_NO_ATTRS_TEST_SPACE_RANK, NULL, NULL, FALSE)) < 0) + TEST_ERROR; + if ((attr_space_id = generate_random_dataspace(OBJECT_COPY_NO_ATTRS_TEST_SPACE_RANK, NULL, NULL, TRUE)) < + 0) + TEST_ERROR; + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + /* Create the test group object, along with the attributes attached to it. */ + if ((group_id2 = H5Gcreate2(group_id, OBJECT_COPY_NO_ATTRS_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", OBJECT_COPY_NO_ATTRS_TEST_GROUP_NAME); + goto error; + } + + for (i = 0; i < (size_t)OBJECT_COPY_NO_ATTRS_TEST_NUM_ATTRS; i++) { + char attr_name[OBJECT_COPY_NO_ATTRS_TEST_BUF_SIZE]; + + snprintf(attr_name, OBJECT_COPY_NO_ATTRS_TEST_BUF_SIZE, "attr%d", (int)i); + + if ((attr_id = H5Acreate2(group_id2, attr_name, H5T_NATIVE_INT, attr_space_id, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s' on group '%s'\n", attr_name, + OBJECT_COPY_NO_ATTRS_TEST_GROUP_NAME); + goto error; + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close attribute '%s'\n", attr_name); + goto error; + } + } + + /* Create the test dataset object, along with the attributes attached to it. */ + if ((dset_id = H5Dcreate2(group_id, OBJECT_COPY_NO_ATTRS_TEST_DSET_NAME, dset_dtype, space_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", OBJECT_COPY_NO_ATTRS_TEST_DSET_NAME); + goto error; + } + + for (i = 0; i < (size_t)OBJECT_COPY_NO_ATTRS_TEST_NUM_ATTRS; i++) { + char attr_name[OBJECT_COPY_NO_ATTRS_TEST_BUF_SIZE]; + + snprintf(attr_name, OBJECT_COPY_NO_ATTRS_TEST_BUF_SIZE, "attr%d", (int)i); + + if ((attr_id = H5Acreate2(dset_id, attr_name, H5T_NATIVE_INT, attr_space_id, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s' on dataset '%s'\n", attr_name, + OBJECT_COPY_NO_ATTRS_TEST_DSET_NAME); + goto error; + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close attribute '%s'\n", attr_name); + goto error; + } + } + + /* Create the test committed datatype object, along with the attributes attached to it. */ + if ((dtype_id = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create datatype\n"); + goto error; + } + + if (H5Tcommit2(group_id, OBJECT_COPY_NO_ATTRS_TEST_DTYPE_NAME, dtype_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't commit datatype '%s'\n", OBJECT_COPY_NO_ATTRS_TEST_DTYPE_NAME); + goto error; + } + + for (i = 0; i < (size_t)OBJECT_COPY_NO_ATTRS_TEST_NUM_ATTRS; i++) { + char attr_name[OBJECT_COPY_NO_ATTRS_TEST_BUF_SIZE]; + + snprintf(attr_name, OBJECT_COPY_NO_ATTRS_TEST_BUF_SIZE, "attr%d", (int)i); + + if ((attr_id = H5Acreate2(dtype_id, attr_name, H5T_NATIVE_INT, attr_space_id, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s' on committed datatype '%s'\n", attr_name, + OBJECT_COPY_NO_ATTRS_TEST_DTYPE_NAME); + goto error; + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close attribute '%s'\n", attr_name); + goto error; + } + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Ocopy_group_no_attributes) + { + TESTING_2("H5Ocopy on a group (without attributes)"); + + if ((ocpypl_id = H5Pcreate(H5P_OBJECT_COPY)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create OCopyPL\n"); + PART_ERROR(H5Ocopy_group_no_attributes); + } + + if (H5Pset_copy_object(ocpypl_id, H5O_COPY_WITHOUT_ATTR_FLAG) < 0) { + H5_FAILED(); + HDprintf(" couldn't set object copying options\n"); + PART_ERROR(H5Ocopy_group_no_attributes); + } + + if (H5Ocopy(group_id, OBJECT_COPY_NO_ATTRS_TEST_GROUP_NAME, group_id, + OBJECT_COPY_NO_ATTRS_TEST_NEW_GROUP_NAME, ocpypl_id, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to copy group '%s' to '%s'\n", OBJECT_COPY_NO_ATTRS_TEST_GROUP_NAME, + OBJECT_COPY_NO_ATTRS_TEST_NEW_GROUP_NAME); + PART_ERROR(H5Ocopy_group_no_attributes); + } + + if ((object_link_exists = + H5Lexists(group_id, OBJECT_COPY_NO_ATTRS_TEST_NEW_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' to copied group exists\n", + OBJECT_COPY_NO_ATTRS_TEST_NEW_GROUP_NAME); + PART_ERROR(H5Ocopy_group_no_attributes); + } + + if (!object_link_exists) { + H5_FAILED(); + HDprintf(" link '%s' to copied group didn't exist!\n", + OBJECT_COPY_NO_ATTRS_TEST_NEW_GROUP_NAME); + PART_ERROR(H5Ocopy_group_no_attributes); + } + + /* Ensure that the new group has no attributes */ + if ((tmp_group_id = H5Gopen2(group_id, OBJECT_COPY_NO_ATTRS_TEST_NEW_GROUP_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" failed to open group copy '%s'\n", OBJECT_COPY_NO_ATTRS_TEST_NEW_GROUP_NAME); + PART_ERROR(H5Ocopy_group_no_attributes); + } + + memset(&object_info, 0, sizeof(object_info)); + + /* + * Set attribute count to non-zero in case the connector doesn't + * support retrieval of object info. + */ + object_info.num_attrs = 1; + + if (H5Oget_info3(tmp_group_id, &object_info, H5O_INFO_ALL) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve object info\n"); + PART_ERROR(H5Ocopy_group_no_attributes); + } + + if (object_info.num_attrs != 0) { + H5_FAILED(); + HDprintf(" copied group contained attributes after a non-attribute copy!\n"); + PART_ERROR(H5Ocopy_group_no_attributes); + } + + if (H5Pclose(ocpypl_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close OCopyPL\n"); + PART_ERROR(H5Ocopy_group_no_attributes); + } + + if (H5Gclose(tmp_group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group copy\n"); + PART_ERROR(H5Ocopy_group_no_attributes); + } + + PASSED(); + } + PART_END(H5Ocopy_group_no_attributes); + + if (ocpypl_id >= 0) { + H5E_BEGIN_TRY + { + H5Pclose(ocpypl_id); + } + H5E_END_TRY; + ocpypl_id = H5I_INVALID_HID; + } + if (tmp_group_id >= 0) { + H5E_BEGIN_TRY + { + H5Gclose(tmp_group_id); + } + H5E_END_TRY; + tmp_group_id = H5I_INVALID_HID; + } + + PART_BEGIN(H5Ocopy_dset_no_attributes) + { + TESTING_2("H5Ocopy on a dataset (without attributes)"); + + if ((ocpypl_id = H5Pcreate(H5P_OBJECT_COPY)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create OCopyPL\n"); + PART_ERROR(H5Ocopy_dset_no_attributes); + } + + if (H5Pset_copy_object(ocpypl_id, H5O_COPY_WITHOUT_ATTR_FLAG) < 0) { + H5_FAILED(); + HDprintf(" couldn't set object copying options\n"); + PART_ERROR(H5Ocopy_dset_no_attributes); + } + + if (H5Ocopy(group_id, OBJECT_COPY_NO_ATTRS_TEST_DSET_NAME, group_id, + OBJECT_COPY_NO_ATTRS_TEST_NEW_DSET_NAME, ocpypl_id, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to copy dataset '%s' to '%s'\n", OBJECT_COPY_NO_ATTRS_TEST_DSET_NAME, + OBJECT_COPY_NO_ATTRS_TEST_NEW_DSET_NAME); + PART_ERROR(H5Ocopy_dset_no_attributes); + } + + if ((object_link_exists = + H5Lexists(group_id, OBJECT_COPY_NO_ATTRS_TEST_NEW_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' to copied dataset exists\n", + OBJECT_COPY_NO_ATTRS_TEST_NEW_DSET_NAME); + PART_ERROR(H5Ocopy_dset_no_attributes); + } + + if (!object_link_exists) { + H5_FAILED(); + HDprintf(" link '%s' to copied dataset didn't exist!\n", + OBJECT_COPY_NO_ATTRS_TEST_NEW_DSET_NAME); + PART_ERROR(H5Ocopy_dset_no_attributes); + } + + /* Ensure that the new dataset doesn't have any attributes */ + if ((tmp_dset_id = H5Dopen2(group_id, OBJECT_COPY_NO_ATTRS_TEST_NEW_DSET_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" failed to open dataset copy '%s'\n", OBJECT_COPY_NO_ATTRS_TEST_NEW_DSET_NAME); + PART_ERROR(H5Ocopy_dset_no_attributes); + } + + memset(&object_info, 0, sizeof(object_info)); + + /* + * Set attribute count to non-zero in case the connector doesn't + * support retrieval of object info. + */ + object_info.num_attrs = 1; + + if (H5Oget_info3(tmp_dset_id, &object_info, H5O_INFO_ALL) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve object info\n"); + PART_ERROR(H5Ocopy_dset_no_attributes); + } + + if (object_info.num_attrs != 0) { + H5_FAILED(); + HDprintf(" copied dataset contained attributes after a non-attribute copy!\n"); + PART_ERROR(H5Ocopy_dset_no_attributes); + } + + if (H5Pclose(ocpypl_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close OCopyPL\n"); + PART_ERROR(H5Ocopy_dset_no_attributes); + } + + if (H5Dclose(tmp_dset_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close dataset copy\n"); + PART_ERROR(H5Ocopy_dset_no_attributes); + } + + PASSED(); + } + PART_END(H5Ocopy_dset_no_attributes); + + if (ocpypl_id >= 0) { + H5E_BEGIN_TRY + { + H5Pclose(ocpypl_id); + } + H5E_END_TRY; + ocpypl_id = H5I_INVALID_HID; + } + if (tmp_dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(tmp_dset_id); + } + H5E_END_TRY; + tmp_dset_id = H5I_INVALID_HID; + } + + PART_BEGIN(H5Ocopy_dtype_no_attributes) + { + TESTING_2("H5Ocopy on a committed datatype (without attributes)"); + + if ((ocpypl_id = H5Pcreate(H5P_OBJECT_COPY)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create OCopyPL\n"); + PART_ERROR(H5Ocopy_dtype_no_attributes); + } + + if (H5Pset_copy_object(ocpypl_id, H5O_COPY_WITHOUT_ATTR_FLAG) < 0) { + H5_FAILED(); + HDprintf(" couldn't set object copying options\n"); + PART_ERROR(H5Ocopy_dtype_no_attributes); + } + + if (H5Ocopy(group_id, OBJECT_COPY_NO_ATTRS_TEST_DTYPE_NAME, group_id, + OBJECT_COPY_NO_ATTRS_TEST_NEW_DTYPE_NAME, ocpypl_id, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to copy datatype '%s' to '%s'\n", OBJECT_COPY_NO_ATTRS_TEST_DTYPE_NAME, + OBJECT_COPY_NO_ATTRS_TEST_NEW_DTYPE_NAME); + PART_ERROR(H5Ocopy_dtype_no_attributes); + } + + if ((object_link_exists = + H5Lexists(group_id, OBJECT_COPY_NO_ATTRS_TEST_NEW_DTYPE_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' to copied datatype exists\n", + OBJECT_COPY_NO_ATTRS_TEST_NEW_DTYPE_NAME); + PART_ERROR(H5Ocopy_dtype_no_attributes); + } + + if (!object_link_exists) { + H5_FAILED(); + HDprintf(" link '%s' to copied datatype didn't exist!\n", + OBJECT_COPY_NO_ATTRS_TEST_NEW_DTYPE_NAME); + PART_ERROR(H5Ocopy_dtype_no_attributes); + } + + /* Ensure that the new committed datatype doesn't have any attributes */ + if ((tmp_dtype_id = H5Topen2(group_id, OBJECT_COPY_NO_ATTRS_TEST_NEW_DTYPE_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" failed to open dataset copy '%s'\n", OBJECT_COPY_NO_ATTRS_TEST_NEW_DTYPE_NAME); + PART_ERROR(H5Ocopy_dtype_no_attributes); + } + + memset(&object_info, 0, sizeof(object_info)); + + /* + * Set attribute count to non-zero in case the connector doesn't + * support retrieval of object info. + */ + object_info.num_attrs = 1; + + if (H5Oget_info3(tmp_dtype_id, &object_info, H5O_INFO_ALL) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve object info\n"); + PART_ERROR(H5Ocopy_dtype_no_attributes); + } + + if (object_info.num_attrs != 0) { + H5_FAILED(); + HDprintf(" copied committed datatype contained attributes after a non-attribute copy!\n"); + PART_ERROR(H5Ocopy_dtype_no_attributes); + } + + if (H5Pclose(ocpypl_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close OCopyPL\n"); + PART_ERROR(H5Ocopy_dtype_no_attributes); + } + + if (H5Tclose(tmp_dtype_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close datatype copy\n"); + PART_ERROR(H5Ocopy_dtype_no_attributes); + } + + PASSED(); + } + PART_END(H5Ocopy_dtype_no_attributes); + + if (ocpypl_id >= 0) { + H5E_BEGIN_TRY + { + H5Pclose(ocpypl_id); + } + H5E_END_TRY; + ocpypl_id = H5I_INVALID_HID; + } + if (tmp_dtype_id >= 0) { + H5E_BEGIN_TRY + { + H5Tclose(tmp_dtype_id); + } + H5E_END_TRY; + tmp_dtype_id = H5I_INVALID_HID; + } + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(attr_space_id) < 0) + TEST_ERROR; + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Tclose(dtype_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id2) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(ocpypl_id); + H5Sclose(attr_space_id); + H5Sclose(space_id); + H5Aclose(attr_id); + H5Tclose(dset_dtype); + H5Tclose(tmp_dtype_id); + H5Tclose(dtype_id); + H5Dclose(tmp_dset_id); + H5Dclose(dset_id); + H5Gclose(tmp_group_id); + H5Gclose(group_id2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * Tests to exercise the behavior of H5Ocopy when the source + * object specified is a soft link or dangling soft link. + */ +static int +test_object_copy_by_soft_link(void) +{ + H5O_info2_t object_info; + H5G_info_t group_info; + H5L_info2_t link_info; + htri_t object_link_exists; + size_t i; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t group_id2 = H5I_INVALID_HID; + hid_t tmp_group_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t attr_space_id = H5I_INVALID_HID; + + TESTING_MULTIPART("object copying through use of soft links"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ITERATE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_SOFT_LINKS)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, object, link, dataset, attribute, iterate, or " + "soft link aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, OBJECT_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", OBJECT_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, OBJECT_COPY_SOFT_LINK_TEST_SUBGROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", OBJECT_COPY_SOFT_LINK_TEST_SUBGROUP_NAME); + goto error; + } + + if ((attr_space_id = generate_random_dataspace(OBJECT_COPY_SOFT_LINK_TEST_SPACE_RANK, NULL, NULL, TRUE)) < + 0) + TEST_ERROR; + + /* Create the test group object, along with its nested members and the attributes attached to it. */ + if ((group_id2 = H5Gcreate2(group_id, OBJECT_COPY_SOFT_LINK_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", OBJECT_COPY_SOFT_LINK_TEST_GROUP_NAME); + goto error; + } + + for (i = 0; i < (size_t)OBJECT_COPY_SOFT_LINK_TEST_NUM_NESTED_OBJS; i++) { + char grp_name[OBJECT_COPY_SOFT_LINK_TEST_BUF_SIZE]; + + snprintf(grp_name, OBJECT_COPY_SOFT_LINK_TEST_BUF_SIZE, "grp%d", (int)i); + + if ((tmp_group_id = H5Gcreate2(group_id2, grp_name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s' under group '%s'\n", grp_name, + OBJECT_COPY_SOFT_LINK_TEST_GROUP_NAME); + goto error; + } + + /* Create a further nested group under the last group added */ + if (i == (OBJECT_COPY_SOFT_LINK_TEST_NUM_NESTED_OBJS - 1)) { + if (H5Gclose(H5Gcreate2(tmp_group_id, OBJECT_COPY_SOFT_LINK_TEST_DEEP_NESTED_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create nested group '%s' under group '%s'\n", + OBJECT_COPY_SOFT_LINK_TEST_DEEP_NESTED_GROUP_NAME, grp_name); + goto error; + } + } + + if (H5Gclose(tmp_group_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close group '%s'\n", grp_name); + goto error; + } + } + + for (i = 0; i < (size_t)OBJECT_COPY_SOFT_LINK_TEST_NUM_ATTRS; i++) { + char attr_name[OBJECT_COPY_SOFT_LINK_TEST_BUF_SIZE]; + + snprintf(attr_name, OBJECT_COPY_SOFT_LINK_TEST_BUF_SIZE, "attr%d", (int)i); + + if ((attr_id = H5Acreate2(group_id2, attr_name, H5T_NATIVE_INT, attr_space_id, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s' on group '%s'\n", attr_name, + OBJECT_COPY_SOFT_LINK_TEST_GROUP_NAME); + goto error; + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close attribute '%s'\n", attr_name); + goto error; + } + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Ocopy_through_soft_link) + { + TESTING_2("H5Ocopy through use of a soft link"); + + if (H5Lcreate_soft("/" OBJECT_TEST_GROUP_NAME "/" OBJECT_COPY_SOFT_LINK_TEST_SUBGROUP_NAME + "/" OBJECT_COPY_SOFT_LINK_TEST_GROUP_NAME, + group_id, OBJECT_COPY_SOFT_LINK_TEST_SOFT_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create soft link '%s' to group for copying\n", + OBJECT_COPY_SOFT_LINK_TEST_SOFT_LINK_NAME); + PART_ERROR(H5Ocopy_through_soft_link); + } + + if (H5Ocopy(group_id, OBJECT_COPY_SOFT_LINK_TEST_SOFT_LINK_NAME, group_id, + OBJECT_COPY_SOFT_LINK_TEST_NEW_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to copy group '%s' to '%s'\n", OBJECT_COPY_SOFT_LINK_TEST_GROUP_NAME, + OBJECT_COPY_SOFT_LINK_TEST_NEW_GROUP_NAME); + PART_ERROR(H5Ocopy_through_soft_link); + } + + if ((object_link_exists = + H5Lexists(group_id, OBJECT_COPY_SOFT_LINK_TEST_NEW_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' to copied group exists\n", + OBJECT_COPY_SOFT_LINK_TEST_NEW_GROUP_NAME); + PART_ERROR(H5Ocopy_through_soft_link); + } + + if (!object_link_exists) { + H5_FAILED(); + HDprintf(" link '%s' to copied group didn't exist!\n", + OBJECT_COPY_SOFT_LINK_TEST_NEW_GROUP_NAME); + PART_ERROR(H5Ocopy_through_soft_link); + } + + /* Make sure the new object is an actual group and not another soft link */ + memset(&link_info, 0, sizeof(link_info)); + if (H5Lget_info2(group_id, OBJECT_COPY_SOFT_LINK_TEST_NEW_GROUP_NAME, &link_info, H5P_DEFAULT) < + 0) { + H5_FAILED(); + HDprintf(" failed to retrieve info for link '%s'\n", + OBJECT_COPY_SOFT_LINK_TEST_NEW_GROUP_NAME); + PART_ERROR(H5Ocopy_through_soft_link); + } + + if (link_info.type != H5L_TYPE_HARD) { + H5_FAILED(); + HDprintf( + " after group copy through soft link, group's new link type wasn't H5L_TYPE_HARD!\n"); + PART_ERROR(H5Ocopy_through_soft_link); + } + + /* + * Ensure that the new group doesn't have any attributes and only the + * immediate members of the copied group. + */ + if ((tmp_group_id = H5Gopen2(group_id, OBJECT_COPY_SOFT_LINK_TEST_NEW_GROUP_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" failed to open group copy '%s'\n", OBJECT_COPY_SOFT_LINK_TEST_NEW_GROUP_NAME); + PART_ERROR(H5Ocopy_through_soft_link); + } + + memset(&group_info, 0, sizeof(group_info)); + + /* + * Set link count to zero in case the connector doesn't support + * retrieval of group info. + */ + group_info.nlinks = 0; + + if (H5Gget_info(tmp_group_id, &group_info) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve group info\n"); + PART_ERROR(H5Ocopy_through_soft_link); + } + + if (group_info.nlinks != OBJECT_COPY_SOFT_LINK_TEST_NUM_NESTED_OBJS) { + H5_FAILED(); + HDprintf( + " copied group contained %d members instead of %d members after a shallow copy!\n", + (int)group_info.nlinks, OBJECT_COPY_SOFT_LINK_TEST_NUM_NESTED_OBJS); + PART_ERROR(H5Ocopy_through_soft_link); + } + + memset(&object_info, 0, sizeof(object_info)); + + /* + * Set attribute count to zero in case the connector doesn't + * support retrieval of object info. + */ + object_info.num_attrs = 0; + + if (H5Oget_info3(tmp_group_id, &object_info, H5O_INFO_ALL) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve object info\n"); + PART_ERROR(H5Ocopy_through_soft_link); + } + + if (object_info.num_attrs == 0) { + H5_FAILED(); + HDprintf(" copied group didn't contain any attributes after copy operation!\n"); + PART_ERROR(H5Ocopy_through_soft_link); + } + + /* Check the attribute names, types, etc. */ + i = 0; + if (H5Aiterate2(tmp_group_id, H5_INDEX_NAME, H5_ITER_INC, NULL, + object_copy_attribute_iter_callback, &i) < 0) { + H5_FAILED(); + HDprintf(" failed to iterate over copied group's attributes\n"); + PART_ERROR(H5Ocopy_through_soft_link); + } + + if (i != OBJECT_COPY_SOFT_LINK_TEST_NUM_ATTRS) { + H5_FAILED(); + HDprintf( + " number of attributes on copied group (%llu) didn't match expected number (%llu)!\n", + (unsigned long long)i, (unsigned long long)OBJECT_COPY_SOFT_LINK_TEST_NUM_ATTRS); + PART_ERROR(H5Ocopy_through_soft_link); + } + + if (H5Gclose(tmp_group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group copy\n"); + PART_ERROR(H5Ocopy_through_soft_link); + } + + PASSED(); + } + PART_END(H5Ocopy_through_soft_link); + + if (tmp_group_id >= 0) { + H5E_BEGIN_TRY + { + H5Gclose(tmp_group_id); + } + H5E_END_TRY; + tmp_group_id = H5I_INVALID_HID; + } + + PART_BEGIN(H5Ocopy_through_dangling_soft_link) + { + herr_t err_ret; + + TESTING_2("H5Ocopy through use of a dangling soft link"); + + if (H5Lcreate_soft("/" OBJECT_TEST_GROUP_NAME "/" OBJECT_COPY_SOFT_LINK_TEST_SUBGROUP_NAME + "/nonexistent_object", + group_id, OBJECT_COPY_SOFT_LINK_TEST_DANGLING_LINK_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create dangling soft link '%s'\n", + OBJECT_COPY_SOFT_LINK_TEST_DANGLING_LINK_NAME); + PART_ERROR(H5Ocopy_through_dangling_soft_link); + } + + H5E_BEGIN_TRY + { + err_ret = + H5Ocopy(group_id, OBJECT_COPY_SOFT_LINK_TEST_DANGLING_LINK_NAME, group_id, + OBJECT_COPY_SOFT_LINK_TEST_DANGLING_LINK_NAME "2", H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" copied non-existent object through use of a dangling soft link!\n"); + PART_ERROR(H5Ocopy_through_dangling_soft_link); + } + + PASSED(); + } + PART_END(H5Ocopy_through_dangling_soft_link); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(attr_space_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id2) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(attr_space_id); + H5Aclose(attr_id); + H5Gclose(tmp_group_id); + H5Gclose(group_id2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * Tests for copying groups that contain soft links with + * H5Ocopy. Also tested is the H5O_COPY_EXPAND_SOFT_LINK_FLAG + * flag. + */ +static int +test_object_copy_group_with_soft_links(void) +{ + H5G_info_t group_info; + htri_t object_link_exists; + size_t i; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t group_id2 = H5I_INVALID_HID; + hid_t tmp_group_id = H5I_INVALID_HID; + hid_t ocpypl_id = H5I_INVALID_HID; + + TESTING_MULTIPART("group copying when group contains soft links"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ITERATE) || !(vol_cap_flags_g & H5VL_CAP_FLAG_SOFT_LINKS)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, object, link, or soft link aren't supported with " + "this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, OBJECT_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", OBJECT_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_SUBGROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_SUBGROUP_NAME); + goto error; + } + + /* Create the test group object. */ + if ((group_id2 = H5Gcreate2(group_id, OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_GROUP_NAME); + goto error; + } + + /* Create several groups at the root level and add soft links pointing to them inside + * the test group object. + */ + for (i = 0; i < (size_t)OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_NUM_NESTED_OBJS; i++) { + char grp_name[OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_BUF_SIZE]; + char lnk_name[OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_BUF_SIZE]; + char lnk_target[2 * OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_BUF_SIZE]; + + snprintf(grp_name, OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_BUF_SIZE, "grp%d", (int)i); + snprintf(lnk_name, OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_BUF_SIZE, "link%d", (int)i); + snprintf(lnk_target, 2 * OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_BUF_SIZE, + "/" OBJECT_TEST_GROUP_NAME "/" OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_SUBGROUP_NAME "/%s", + grp_name); + + if ((tmp_group_id = H5Gcreate2(group_id, grp_name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s' under group '%s'\n", grp_name, + OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_SUBGROUP_NAME); + goto error; + } + + if (H5Lcreate_soft(lnk_target, group_id2, lnk_name, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to create soft link '%s'\n", lnk_name); + goto error; + } + + if (H5Gclose(tmp_group_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close group '%s'\n", grp_name); + goto error; + } + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Ocopy_dont_expand_soft_links) + { + TESTING_2("H5Ocopy on group with soft links (soft links not expanded)"); + + if (H5Ocopy(group_id, OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_GROUP_NAME, group_id, + OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_NON_EXPAND_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to copy group '%s' to '%s'\n", + OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_GROUP_NAME, + OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_NON_EXPAND_GROUP_NAME); + PART_ERROR(H5Ocopy_dont_expand_soft_links); + } + + if ((object_link_exists = + H5Lexists(group_id, OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_NON_EXPAND_GROUP_NAME, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' to copied group exists\n", + OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_NON_EXPAND_GROUP_NAME); + PART_ERROR(H5Ocopy_dont_expand_soft_links); + } + + if (!object_link_exists) { + H5_FAILED(); + HDprintf(" link '%s' to copied group didn't exist!\n", + OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_NON_EXPAND_GROUP_NAME); + PART_ERROR(H5Ocopy_dont_expand_soft_links); + } + + /* Ensure that the number of links is the same */ + if ((tmp_group_id = + H5Gopen2(group_id, OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_NON_EXPAND_GROUP_NAME, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to open group copy '%s'\n", + OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_NON_EXPAND_GROUP_NAME); + PART_ERROR(H5Ocopy_dont_expand_soft_links); + } + + memset(&group_info, 0, sizeof(group_info)); + + /* + * Set link count to zero in case the connector doesn't support + * retrieval of group info. + */ + group_info.nlinks = 0; + + if (H5Gget_info(tmp_group_id, &group_info) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve group info\n"); + PART_ERROR(H5Ocopy_dont_expand_soft_links); + } + + if (group_info.nlinks != OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_NUM_NESTED_OBJS) { + H5_FAILED(); + HDprintf(" copied group contained %d members instead of %d members after copy!\n", + (int)group_info.nlinks, OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_NUM_NESTED_OBJS); + PART_ERROR(H5Ocopy_dont_expand_soft_links); + } + + /* + * Iterate over the links in the copied group and ensure that they're all + * still soft links with their original values. + */ + i = 0; + if (H5Literate2(tmp_group_id, H5_INDEX_NAME, H5_ITER_INC, NULL, + object_copy_soft_link_non_expand_callback, &i) < 0) { + H5_FAILED(); + HDprintf(" failed to iterate over links in group '%s'\n", + OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_NON_EXPAND_GROUP_NAME); + PART_ERROR(H5Ocopy_dont_expand_soft_links); + } + + if (i != OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_NUM_NESTED_OBJS) { + H5_FAILED(); + HDprintf(" number of links in copied group (%llu) didn't match expected number (%llu)!\n", + (unsigned long long)i, + (unsigned long long)OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_NUM_NESTED_OBJS); + PART_ERROR(H5Ocopy_dont_expand_soft_links); + } + + if (H5Gclose(tmp_group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group copy\n"); + PART_ERROR(H5Ocopy_dont_expand_soft_links); + } + + PASSED(); + } + PART_END(H5Ocopy_dont_expand_soft_links); + + if (tmp_group_id >= 0) { + H5E_BEGIN_TRY + { + H5Gclose(tmp_group_id); + } + H5E_END_TRY; + tmp_group_id = H5I_INVALID_HID; + } + + PART_BEGIN(H5Ocopy_expand_soft_links) + { + TESTING_2("H5Ocopy on group with soft links (soft links expanded)"); + + if ((ocpypl_id = H5Pcreate(H5P_OBJECT_COPY)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create OCopyPL\n"); + PART_ERROR(H5Ocopy_expand_soft_links); + } + + if (H5Pset_copy_object(ocpypl_id, H5O_COPY_EXPAND_SOFT_LINK_FLAG) < 0) { + H5_FAILED(); + HDprintf(" couldn't set object copying options\n"); + PART_ERROR(H5Ocopy_expand_soft_links); + } + + if (H5Ocopy(group_id, OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_GROUP_NAME, group_id, + OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_EXPAND_GROUP_NAME, ocpypl_id, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to copy group '%s' to '%s'\n", + OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_GROUP_NAME, + OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_EXPAND_GROUP_NAME); + PART_ERROR(H5Ocopy_expand_soft_links); + } + + if ((object_link_exists = H5Lexists( + group_id, OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_EXPAND_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' to copied group exists\n", + OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_EXPAND_GROUP_NAME); + PART_ERROR(H5Ocopy_expand_soft_links); + } + + if (!object_link_exists) { + H5_FAILED(); + HDprintf(" link '%s' to copied group didn't exist!\n", + OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_EXPAND_GROUP_NAME); + PART_ERROR(H5Ocopy_expand_soft_links); + } + + /* Ensure that the number of links is the same */ + if ((tmp_group_id = H5Gopen2(group_id, OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_EXPAND_GROUP_NAME, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to open group copy '%s'\n", + OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_EXPAND_GROUP_NAME); + PART_ERROR(H5Ocopy_expand_soft_links); + } + + memset(&group_info, 0, sizeof(group_info)); + + /* + * Set link count to zero in case the connector doesn't support + * retrieval of group info. + */ + group_info.nlinks = 0; + + if (H5Gget_info(tmp_group_id, &group_info) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve group info\n"); + PART_ERROR(H5Ocopy_expand_soft_links); + } + + if (group_info.nlinks != OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_NUM_NESTED_OBJS) { + H5_FAILED(); + HDprintf(" copied group contained %d members instead of %d members after copy!\n", + (int)group_info.nlinks, OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_NUM_NESTED_OBJS); + PART_ERROR(H5Ocopy_expand_soft_links); + } + + /* + * Iterate over the links in the copied group and ensure that they've all + * been expanded into hard links corresponding to the top-level groups + * created. + */ + i = 0; + if (H5Literate2(tmp_group_id, H5_INDEX_NAME, H5_ITER_INC, NULL, + object_copy_soft_link_expand_callback, &i) < 0) { + H5_FAILED(); + HDprintf(" failed to iterate over links in group '%s'\n", + OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_EXPAND_GROUP_NAME); + PART_ERROR(H5Ocopy_expand_soft_links); + } + + if (i != OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_NUM_NESTED_OBJS) { + H5_FAILED(); + HDprintf(" number of links in copied group (%llu) didn't match expected number (%llu)!\n", + (unsigned long long)i, + (unsigned long long)OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_NUM_NESTED_OBJS); + PART_ERROR(H5Ocopy_expand_soft_links); + } + + if (H5Pclose(ocpypl_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close OCopyPL\n"); + PART_ERROR(H5Ocopy_expand_soft_links); + } + + if (H5Gclose(tmp_group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group copy\n"); + PART_ERROR(H5Ocopy_expand_soft_links); + } + + PASSED(); + } + PART_END(H5Ocopy_expand_soft_links); + + if (ocpypl_id >= 0) { + H5E_BEGIN_TRY + { + H5Gclose(ocpypl_id); + } + H5E_END_TRY; + ocpypl_id = H5I_INVALID_HID; + } + if (tmp_group_id >= 0) { + H5E_BEGIN_TRY + { + H5Gclose(tmp_group_id); + } + H5E_END_TRY; + tmp_group_id = H5I_INVALID_HID; + } + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Gclose(group_id2) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(ocpypl_id); + H5Gclose(tmp_group_id); + H5Gclose(group_id2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * Tests for copying objects between two different files using + * H5Ocopy. + */ +static int +test_object_copy_between_files(void) +{ + H5O_info2_t object_info; + H5G_info_t group_info; + htri_t object_link_exists; + size_t i; + hid_t file_id = H5I_INVALID_HID; + hid_t file_id2 = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t group_id2 = H5I_INVALID_HID; + hid_t tmp_group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t tmp_dset_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t dtype_id = H5I_INVALID_HID; + hid_t tmp_dtype_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t attr_space_id = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + hid_t ocpypl_id = H5I_INVALID_HID; + + TESTING_MULTIPART("object copying between files"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, object, link, dataset, attribute, stored " + "datatype, or iterate aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + /* + * Create the second file for the between file copying tests. + */ + if ((file_id2 = H5Fcreate(OBJECT_COPY_BETWEEN_FILES_TEST_FILE_NAME, H5F_ACC_TRUNC, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, OBJECT_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", OBJECT_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, OBJECT_COPY_BETWEEN_FILES_TEST_SUBGROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + OBJECT_COPY_BETWEEN_FILES_TEST_SUBGROUP_NAME); + goto error; + } + + if ((space_id = generate_random_dataspace(OBJECT_COPY_BETWEEN_FILES_TEST_SPACE_RANK, NULL, NULL, FALSE)) < + 0) + TEST_ERROR; + if ((attr_space_id = + generate_random_dataspace(OBJECT_COPY_BETWEEN_FILES_TEST_SPACE_RANK, NULL, NULL, TRUE)) < 0) + TEST_ERROR; + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + /* Create the test group object, along with its nested members and the attributes attached to it. */ + if ((group_id2 = H5Gcreate2(group_id, OBJECT_COPY_BETWEEN_FILES_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", OBJECT_COPY_BETWEEN_FILES_TEST_GROUP_NAME); + goto error; + } + + for (i = 0; i < (size_t)OBJECT_COPY_BETWEEN_FILES_TEST_NUM_NESTED_OBJS; i++) { + char grp_name[OBJECT_COPY_BETWEEN_FILES_TEST_BUF_SIZE]; + + snprintf(grp_name, OBJECT_COPY_BETWEEN_FILES_TEST_BUF_SIZE, "grp%d", (int)i); + + if ((tmp_group_id = H5Gcreate2(group_id2, grp_name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s' under group '%s'\n", grp_name, + OBJECT_COPY_BETWEEN_FILES_TEST_GROUP_NAME); + goto error; + } + + /* Create a further nested group under the last group added */ + if (i == (OBJECT_COPY_BETWEEN_FILES_TEST_NUM_NESTED_OBJS - 1)) { + if (H5Gclose(H5Gcreate2(tmp_group_id, OBJECT_COPY_BETWEEN_FILES_TEST_DEEP_NESTED_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create nested group '%s' under group '%s'\n", + OBJECT_COPY_BETWEEN_FILES_TEST_DEEP_NESTED_GROUP_NAME, grp_name); + goto error; + } + } + + if (H5Gclose(tmp_group_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close group '%s'\n", grp_name); + goto error; + } + } + + for (i = 0; i < (size_t)OBJECT_COPY_BETWEEN_FILES_TEST_NUM_ATTRS; i++) { + char attr_name[OBJECT_COPY_BETWEEN_FILES_TEST_BUF_SIZE]; + + snprintf(attr_name, OBJECT_COPY_BETWEEN_FILES_TEST_BUF_SIZE, "attr%d", (int)i); + + if ((attr_id = H5Acreate2(group_id2, attr_name, H5T_NATIVE_INT, attr_space_id, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s' on group '%s'\n", attr_name, + OBJECT_COPY_BETWEEN_FILES_TEST_GROUP_NAME); + goto error; + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close attribute '%s'\n", attr_name); + goto error; + } + } + + /* Create the test dataset object, along with the attributes attached to it. */ + if ((dset_id = H5Dcreate2(group_id, OBJECT_COPY_BETWEEN_FILES_TEST_DSET_NAME, dset_dtype, space_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", OBJECT_COPY_BETWEEN_FILES_TEST_DSET_NAME); + goto error; + } + + for (i = 0; i < (size_t)OBJECT_COPY_BETWEEN_FILES_TEST_NUM_ATTRS; i++) { + char attr_name[OBJECT_COPY_BETWEEN_FILES_TEST_BUF_SIZE]; + + snprintf(attr_name, OBJECT_COPY_BETWEEN_FILES_TEST_BUF_SIZE, "attr%d", (int)i); + + if ((attr_id = H5Acreate2(dset_id, attr_name, H5T_NATIVE_INT, attr_space_id, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s' on dataset '%s'\n", attr_name, + OBJECT_COPY_BETWEEN_FILES_TEST_DSET_NAME); + goto error; + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close attribute '%s'\n", attr_name); + goto error; + } + } + + /* Create the test committed datatype object, along with the attributes attached to it. */ + if ((dtype_id = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create datatype\n"); + goto error; + } + + if (H5Tcommit2(group_id, OBJECT_COPY_BETWEEN_FILES_TEST_DTYPE_NAME, dtype_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't commit datatype '%s'\n", OBJECT_COPY_BETWEEN_FILES_TEST_DTYPE_NAME); + goto error; + } + + for (i = 0; i < (size_t)OBJECT_COPY_BETWEEN_FILES_TEST_NUM_ATTRS; i++) { + char attr_name[OBJECT_COPY_BETWEEN_FILES_TEST_BUF_SIZE]; + + snprintf(attr_name, OBJECT_COPY_BETWEEN_FILES_TEST_BUF_SIZE, "attr%d", (int)i); + + if ((attr_id = H5Acreate2(dtype_id, attr_name, H5T_NATIVE_INT, attr_space_id, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create attribute '%s' on committed datatype '%s'\n", attr_name, + OBJECT_COPY_BETWEEN_FILES_TEST_DTYPE_NAME); + goto error; + } + + if (H5Aclose(attr_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close attribute '%s'\n", attr_name); + goto error; + } + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Ocopy_group_between_files) + { + TESTING_2("H5Ocopy on group between different files"); + + if (H5Ocopy(group_id, OBJECT_COPY_BETWEEN_FILES_TEST_GROUP_NAME, file_id2, + OBJECT_COPY_BETWEEN_FILES_TEST_NEW_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to copy group '%s' to second file '%s'\n", + OBJECT_COPY_BETWEEN_FILES_TEST_GROUP_NAME, + OBJECT_COPY_BETWEEN_FILES_TEST_NEW_GROUP_NAME); + PART_ERROR(H5Ocopy_group_between_files); + } + + if ((object_link_exists = + H5Lexists(file_id2, OBJECT_COPY_BETWEEN_FILES_TEST_NEW_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' to copied group exists\n", + OBJECT_COPY_BETWEEN_FILES_TEST_NEW_GROUP_NAME); + PART_ERROR(H5Ocopy_group_between_files); + } + + if (!object_link_exists) { + H5_FAILED(); + HDprintf(" link '%s' to copied group in second file '%s' didn't exist!\n", + OBJECT_COPY_BETWEEN_FILES_TEST_NEW_GROUP_NAME, + OBJECT_COPY_BETWEEN_FILES_TEST_FILE_NAME); + PART_ERROR(H5Ocopy_group_between_files); + } + + /* Ensure that the new group has all the members of the copied group, and all its attributes */ + if ((tmp_group_id = + H5Gopen2(file_id2, OBJECT_COPY_BETWEEN_FILES_TEST_NEW_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to open group copy '%s'\n", + OBJECT_COPY_BETWEEN_FILES_TEST_NEW_GROUP_NAME); + PART_ERROR(H5Ocopy_group_between_files); + } + + memset(&group_info, 0, sizeof(group_info)); + + /* + * Set link count to zero in case the connector doesn't support + * retrieval of group info. + */ + group_info.nlinks = 0; + + if (H5Gget_info(tmp_group_id, &group_info) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve group info\n"); + PART_ERROR(H5Ocopy_group_between_files); + } + + if (group_info.nlinks != OBJECT_COPY_BETWEEN_FILES_TEST_NUM_NESTED_OBJS) { + H5_FAILED(); + HDprintf(" copied group contained %d members instead of %d members after a deep copy!\n", + (int)group_info.nlinks, OBJECT_COPY_BETWEEN_FILES_TEST_NUM_NESTED_OBJS); + PART_ERROR(H5Ocopy_group_between_files); + } + + memset(&object_info, 0, sizeof(object_info)); + + /* + * Set attribute count to zero in case the connector doesn't + * support retrieval of object info. + */ + object_info.num_attrs = 0; + + if (H5Oget_info3(tmp_group_id, &object_info, H5O_INFO_ALL) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve object info\n"); + PART_ERROR(H5Ocopy_group_between_files); + } + + if (object_info.num_attrs == 0) { + H5_FAILED(); + HDprintf(" copied group didn't contain any attributes after copy operation!\n"); + PART_ERROR(H5Ocopy_group_between_files); + } + + /* Check the attribute names, types, etc. */ + i = 0; + if (H5Aiterate2(tmp_group_id, H5_INDEX_NAME, H5_ITER_INC, NULL, + object_copy_attribute_iter_callback, &i) < 0) { + H5_FAILED(); + HDprintf(" failed to iterate over copied group's attributes\n"); + PART_ERROR(H5Ocopy_group_between_files); + } + + if (i != OBJECT_COPY_BETWEEN_FILES_TEST_NUM_ATTRS) { + H5_FAILED(); + HDprintf( + " number of attributes on copied group (%llu) didn't match expected number (%llu)!\n", + (unsigned long long)i, (unsigned long long)OBJECT_COPY_BETWEEN_FILES_TEST_NUM_ATTRS); + PART_ERROR(H5Ocopy_group_between_files); + } + + if (H5Gclose(tmp_group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group copy\n"); + PART_ERROR(H5Ocopy_group_between_files); + } + + /* + * Ensure that the last immediate member of the copied group + * contains its single member after the deep copy. + */ + { + char grp_name[OBJECT_COPY_BETWEEN_FILES_TEST_BUF_SIZE]; + + snprintf(grp_name, OBJECT_COPY_BETWEEN_FILES_TEST_BUF_SIZE, + "/" OBJECT_COPY_BETWEEN_FILES_TEST_NEW_GROUP_NAME "/grp%d", + OBJECT_COPY_BETWEEN_FILES_TEST_NUM_NESTED_OBJS - 1); + + if ((tmp_group_id = H5Gopen2(file_id2, grp_name, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to open group '%s'\n", grp_name); + PART_ERROR(H5Ocopy_group_between_files); + } + + memset(&group_info, 0, sizeof(group_info)); + + /* + * Set link count to zero in case the connector doesn't support + * retrieval of group info. + */ + group_info.nlinks = 0; + + if (H5Gget_info(tmp_group_id, &group_info) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve group info\n"); + PART_ERROR(H5Ocopy_group_between_files); + } + + if (group_info.nlinks != 1) { + H5_FAILED(); + HDprintf(" copied group's immediate members didn't contain nested members after a " + "deep copy!\n"); + PART_ERROR(H5Ocopy_group_between_files); + } + + if (H5Gclose(tmp_group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close group '%s'\n", grp_name); + PART_ERROR(H5Ocopy_group_between_files); + } + } + + PASSED(); + } + PART_END(H5Ocopy_group_between_files); + + if (tmp_group_id >= 0) { + H5E_BEGIN_TRY + { + H5Gclose(tmp_group_id); + } + H5E_END_TRY; + tmp_group_id = H5I_INVALID_HID; + } + + PART_BEGIN(H5Ocopy_dset_between_files) + { + TESTING_2("H5Ocopy on dataset between different files"); + + if (H5Ocopy(group_id, OBJECT_COPY_BETWEEN_FILES_TEST_DSET_NAME, file_id2, + OBJECT_COPY_BETWEEN_FILES_TEST_NEW_DSET_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to copy dataset '%s' to second file '%s'\n", + OBJECT_COPY_BETWEEN_FILES_TEST_DSET_NAME, + OBJECT_COPY_BETWEEN_FILES_TEST_NEW_DSET_NAME); + PART_ERROR(H5Ocopy_dset_between_files); + } + + if ((object_link_exists = + H5Lexists(file_id2, OBJECT_COPY_BETWEEN_FILES_TEST_NEW_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' to copied dataset exists\n", + OBJECT_COPY_BETWEEN_FILES_TEST_NEW_DSET_NAME); + PART_ERROR(H5Ocopy_dset_between_files); + } + + if (!object_link_exists) { + H5_FAILED(); + HDprintf(" link '%s' to copied dataset in second file '%s' didn't exist!\n", + OBJECT_COPY_BETWEEN_FILES_TEST_NEW_DSET_NAME, + OBJECT_COPY_BETWEEN_FILES_TEST_FILE_NAME); + PART_ERROR(H5Ocopy_dset_between_files); + } + + /* Ensure that the new dataset has all the attributes of the copied dataset */ + if ((tmp_dset_id = + H5Dopen2(file_id2, OBJECT_COPY_BETWEEN_FILES_TEST_NEW_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to open dataset copy '%s'\n", + OBJECT_COPY_BETWEEN_FILES_TEST_NEW_DSET_NAME); + PART_ERROR(H5Ocopy_dset_between_files); + } + + memset(&object_info, 0, sizeof(object_info)); + + /* + * Set attribute count to zero in case the connector doesn't + * support retrieval of object info. + */ + object_info.num_attrs = 0; + + if (H5Oget_info3(tmp_dset_id, &object_info, H5O_INFO_ALL) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve object info\n"); + PART_ERROR(H5Ocopy_dset_between_files); + } + + if (object_info.num_attrs == 0) { + H5_FAILED(); + HDprintf(" copied dataset didn't contain any attributes after copy operation!\n"); + PART_ERROR(H5Ocopy_dset_between_files); + } + + /* Check the attribute names, types, etc. */ + i = 0; + if (H5Aiterate2(tmp_dset_id, H5_INDEX_NAME, H5_ITER_INC, NULL, + object_copy_attribute_iter_callback, &i) < 0) { + H5_FAILED(); + HDprintf(" failed to iterate over copied dataset's attributes\n"); + PART_ERROR(H5Ocopy_dset_between_files); + } + + if (i != OBJECT_COPY_BETWEEN_FILES_TEST_NUM_ATTRS) { + H5_FAILED(); + HDprintf(" number of attributes on copied dataset (%llu) didn't match expected number " + "(%llu)!\n", + (unsigned long long)i, (unsigned long long)OBJECT_COPY_BETWEEN_FILES_TEST_NUM_ATTRS); + PART_ERROR(H5Ocopy_dset_between_files); + } + + if (H5Dclose(tmp_dset_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close dataset copy\n"); + PART_ERROR(H5Ocopy_dset_between_files); + } + + PASSED(); + } + PART_END(H5Ocopy_dset_between_files); + + if (tmp_dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(tmp_dset_id); + } + H5E_END_TRY; + tmp_dset_id = H5I_INVALID_HID; + } + + PART_BEGIN(H5Ocopy_dtype_between_files) + { + TESTING_2("H5Ocopy on committed datatype between different files"); + + if (H5Ocopy(group_id, OBJECT_COPY_BETWEEN_FILES_TEST_DTYPE_NAME, file_id2, + OBJECT_COPY_BETWEEN_FILES_TEST_NEW_DTYPE_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" failed to copy committed datatype '%s' to second file '%s'\n", + OBJECT_COPY_BETWEEN_FILES_TEST_DTYPE_NAME, + OBJECT_COPY_BETWEEN_FILES_TEST_NEW_DTYPE_NAME); + PART_ERROR(H5Ocopy_dtype_between_files); + } + + if ((object_link_exists = + H5Lexists(file_id2, OBJECT_COPY_BETWEEN_FILES_TEST_NEW_DTYPE_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't determine if link '%s' to copied committed datatype exists\n", + OBJECT_COPY_BETWEEN_FILES_TEST_NEW_DTYPE_NAME); + PART_ERROR(H5Ocopy_dtype_between_files); + } + + if (!object_link_exists) { + H5_FAILED(); + HDprintf(" link '%s' to copied committed datatype in second file '%s' didn't exist!\n", + OBJECT_COPY_BETWEEN_FILES_TEST_NEW_DTYPE_NAME, + OBJECT_COPY_BETWEEN_FILES_TEST_FILE_NAME); + PART_ERROR(H5Ocopy_dtype_between_files); + } + + /* Ensure that the new committed datatype has all the attributes of the copied committed datatype + */ + if ((tmp_dtype_id = + H5Topen2(file_id2, OBJECT_COPY_BETWEEN_FILES_TEST_NEW_DTYPE_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to open committed datatype copy '%s'\n", + OBJECT_COPY_BETWEEN_FILES_TEST_NEW_DTYPE_NAME); + PART_ERROR(H5Ocopy_dtype_between_files); + } + + memset(&object_info, 0, sizeof(object_info)); + + /* + * Set attribute count to zero in case the connector doesn't + * support retrieval of object info. + */ + object_info.num_attrs = 0; + + if (H5Oget_info3(tmp_dtype_id, &object_info, H5O_INFO_ALL) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve object info\n"); + PART_ERROR(H5Ocopy_dtype_between_files); + } + + if (object_info.num_attrs == 0) { + H5_FAILED(); + HDprintf( + " copied committed datatype didn't contain any attributes after copy operation!\n"); + PART_ERROR(H5Ocopy_dtype_between_files); + } + + /* Check the attribute names, types, etc. */ + i = 0; + if (H5Aiterate2(tmp_dtype_id, H5_INDEX_NAME, H5_ITER_INC, NULL, + object_copy_attribute_iter_callback, &i) < 0) { + H5_FAILED(); + HDprintf(" failed to iterate over copied datatype's attributes\n"); + PART_ERROR(H5Ocopy_dtype_between_files); + } + + if (i != OBJECT_COPY_BETWEEN_FILES_TEST_NUM_ATTRS) { + H5_FAILED(); + HDprintf(" number of attributes on copied datatype (%llu) didn't match expected number " + "(%llu)!\n", + (unsigned long long)i, (unsigned long long)OBJECT_COPY_BETWEEN_FILES_TEST_NUM_ATTRS); + PART_ERROR(H5Ocopy_dtype_between_files); + } + + if (H5Tclose(tmp_dtype_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close committed datatype copy\n"); + PART_ERROR(H5Ocopy_dtype_between_files); + } + + PASSED(); + } + PART_END(H5Ocopy_dtype_between_files); + + if (tmp_dtype_id >= 0) { + H5E_BEGIN_TRY + { + H5Tclose(tmp_dtype_id); + } + H5E_END_TRY; + tmp_dtype_id = H5I_INVALID_HID; + } + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(attr_space_id) < 0) + TEST_ERROR; + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Tclose(dtype_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id2) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id2) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(ocpypl_id); + H5Sclose(attr_space_id); + H5Sclose(space_id); + H5Aclose(attr_id); + H5Tclose(dset_dtype); + H5Tclose(tmp_dtype_id); + H5Tclose(dtype_id); + H5Dclose(tmp_dset_id); + H5Dclose(dset_id); + H5Gclose(tmp_group_id); + H5Gclose(group_id2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id2); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that H5Ocopy fails when it + * is passed invalid parameters. + */ +static int +test_object_copy_invalid_params(void) +{ + herr_t err_ret = -1; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t group_id2 = H5I_INVALID_HID; + + TESTING_MULTIPART("object copying with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_MORE)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, or object aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, OBJECT_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", OBJECT_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, OBJECT_COPY_INVALID_PARAMS_TEST_SUBGROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", + OBJECT_COPY_INVALID_PARAMS_TEST_SUBGROUP_NAME); + goto error; + } + + if ((group_id2 = H5Gcreate2(group_id, OBJECT_COPY_INVALID_PARAMS_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", OBJECT_COPY_INVALID_PARAMS_TEST_GROUP_NAME); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Ocopy_invalid_src_loc_id) + { + TESTING_2("H5Ocopy with an invalid source location ID"); + + H5E_BEGIN_TRY + { + err_ret = H5Ocopy(H5I_INVALID_HID, OBJECT_COPY_INVALID_PARAMS_TEST_GROUP_NAME, group_id, + OBJECT_COPY_INVALID_PARAMS_TEST_GROUP_NAME2, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ocopy succeeded with an invalid source location ID!\n"); + PART_ERROR(H5Ocopy_invalid_src_loc_id); + } + + PASSED(); + } + PART_END(H5Ocopy_invalid_src_loc_id); + + PART_BEGIN(H5Ocopy_invalid_src_obj_name) + { + TESTING_2("H5Ocopy with an invalid source object name"); + + H5E_BEGIN_TRY + { + err_ret = H5Ocopy(group_id, NULL, group_id, OBJECT_COPY_INVALID_PARAMS_TEST_GROUP_NAME2, + H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ocopy succeeded with a NULL source object name!\n"); + PART_ERROR(H5Ocopy_invalid_src_obj_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Ocopy(group_id, "", group_id, OBJECT_COPY_INVALID_PARAMS_TEST_GROUP_NAME2, + H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ocopy succeeded with an invalid source object name of ''!\n"); + PART_ERROR(H5Ocopy_invalid_src_obj_name); + } + + PASSED(); + } + PART_END(H5Ocopy_invalid_src_obj_name); + + PART_BEGIN(H5Ocopy_invalid_dst_loc_id) + { + TESTING_2("H5Ocopy with an invalid destination location ID"); + + H5E_BEGIN_TRY + { + err_ret = H5Ocopy(group_id, OBJECT_COPY_INVALID_PARAMS_TEST_GROUP_NAME, H5I_INVALID_HID, + OBJECT_COPY_INVALID_PARAMS_TEST_GROUP_NAME2, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ocopy succeeded with an invalid destination location ID!\n"); + PART_ERROR(H5Ocopy_invalid_dst_loc_id); + } + + PASSED(); + } + PART_END(H5Ocopy_invalid_dst_loc_id); + + PART_BEGIN(H5Ocopy_invalid_dst_obj_name) + { + TESTING_2("H5Ocopy with an invalid destination object name"); + + H5E_BEGIN_TRY + { + err_ret = H5Ocopy(group_id, OBJECT_COPY_INVALID_PARAMS_TEST_GROUP_NAME, group_id, NULL, + H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ocopy succeeded with a NULL destination object name!\n"); + PART_ERROR(H5Ocopy_invalid_dst_obj_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Ocopy(group_id, OBJECT_COPY_INVALID_PARAMS_TEST_GROUP_NAME, group_id, "", + H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ocopy succeeded with an invalid destination object name of ''!\n"); + PART_ERROR(H5Ocopy_invalid_dst_obj_name); + } + + PASSED(); + } + PART_END(H5Ocopy_invalid_dst_obj_name); + + PART_BEGIN(H5Ocopy_invalid_ocpypl) + { + TESTING_2("H5Ocopy with an invalid OcpyPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Ocopy(group_id, OBJECT_COPY_INVALID_PARAMS_TEST_GROUP_NAME, group_id, + OBJECT_COPY_INVALID_PARAMS_TEST_GROUP_NAME2, H5I_INVALID_HID, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ocopy succeeded with an invalid OcpyPL!\n"); + PART_ERROR(H5Ocopy_invalid_ocpypl); + } + + PASSED(); + } + PART_END(H5Ocopy_invalid_ocpypl); + + PART_BEGIN(H5Ocopy_invalid_lcpl) + { + TESTING_2("H5Ocopy with an invalid LCPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Ocopy(group_id, OBJECT_COPY_INVALID_PARAMS_TEST_GROUP_NAME, group_id, + OBJECT_COPY_INVALID_PARAMS_TEST_GROUP_NAME2, H5P_DEFAULT, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ocopy succeeded with an invalid LCPL!\n"); + PART_ERROR(H5Ocopy_invalid_lcpl); + } + + PASSED(); + } + PART_END(H5Ocopy_invalid_lcpl); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Gclose(group_id2) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(group_id2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test for H5Oset_comment(_by_name)/H5Oget_comment(_by_name). + */ +static int +test_object_comments(void) +{ + TESTING("object comments"); + + SKIPPED(); + + return 0; +} + +/* + * A test to check that H5Oset_comment(_by_name)/H5Oget_comment(_by_name) + * fail when passed invalid parameters. + */ +static int +test_object_comments_invalid_params(void) +{ + TESTING("object comment "); + + SKIPPED(); + + return 0; +} + +/* + * A test for H5Ovisit(_by_name). + * + * XXX: Should have test for checking nested object's names/paths. + */ +static int +test_object_visit(void) +{ + size_t i; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t group_id2 = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + hid_t type_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + + TESTING_MULTIPART("object visiting"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ITERATE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, object, dataset, attribute, stored datatype, " + "iterate, or creation order aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, OBJECT_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", OBJECT_TEST_GROUP_NAME); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create a GCPL\n"); + goto error; + } + + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0) { + H5_FAILED(); + HDprintf(" couldn't enable link creation order tracking and indexing on GCPL\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, OBJECT_VISIT_TEST_SUBGROUP_NAME, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", OBJECT_VISIT_TEST_SUBGROUP_NAME); + goto error; + } + + if ((fspace_id = generate_random_dataspace(OBJECT_VISIT_TEST_SPACE_RANK, NULL, NULL, FALSE)) < 0) + TEST_ERROR; + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + if ((type_id = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create datatype '%s'\n", OBJECT_VISIT_TEST_TYPE_NAME); + goto error; + } + + if ((group_id2 = H5Gcreate2(group_id, OBJECT_VISIT_TEST_GROUP_NAME, H5P_DEFAULT, gcpl_id, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", OBJECT_VISIT_TEST_GROUP_NAME); + goto error; + } + + if ((dset_id = H5Dcreate2(group_id, OBJECT_VISIT_TEST_DSET_NAME, dset_dtype, fspace_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", OBJECT_VISIT_TEST_DSET_NAME); + goto error; + } + + if (H5Tcommit2(group_id, OBJECT_VISIT_TEST_TYPE_NAME, type_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT) < + 0) { + H5_FAILED(); + HDprintf(" couldn't commit datatype '%s'\n", OBJECT_VISIT_TEST_TYPE_NAME); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + /* + * NOTE: A counter is passed to the iteration callback to try to match up + * the expected objects with a given step throughout all of the following + * iterations. This is to try and check that the objects are indeed being + * returned in the correct order. + */ + + PART_BEGIN(H5Ovisit_obj_name_increasing) + { + TESTING_2("H5Ovisit by object name in increasing order"); + + i = 0; + + if (H5Ovisit3(group_id, H5_INDEX_NAME, H5_ITER_INC, object_visit_callback, &i, H5O_INFO_ALL) < + 0) { + H5_FAILED(); + HDprintf(" H5Ovisit by object name in increasing order failed\n"); + PART_ERROR(H5Ovisit_obj_name_increasing); + } + + if (i != OBJECT_VISIT_TEST_NUM_OBJS_VISITED) { + H5_FAILED(); + HDprintf(" some objects were not visited!\n"); + PART_ERROR(H5Ovisit_obj_name_increasing); + } + + PASSED(); + } + PART_END(H5Ovisit_obj_name_increasing); + + PART_BEGIN(H5Ovisit_obj_name_decreasing) + { + TESTING_2("H5Ovisit by object name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + i = OBJECT_VISIT_TEST_NUM_OBJS_VISITED; + + if (H5Ovisit3(group_id, H5_INDEX_NAME, H5_ITER_DEC, object_visit_callback, &i, H5O_INFO_ALL) < + 0) { + H5_FAILED(); + HDprintf(" H5Ovisit by object name in decreasing order failed\n"); + PART_ERROR(H5Ovisit_obj_name_decreasing); + } + + if (i != 2 * OBJECT_VISIT_TEST_NUM_OBJS_VISITED) { + H5_FAILED(); + HDprintf(" some objects were not visited!\n"); + PART_ERROR(H5Ovisit_obj_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Ovisit_obj_name_decreasing); +#endif + } + PART_END(H5Ovisit_obj_name_decreasing); + + PART_BEGIN(H5Ovisit_create_order_increasing) + { + TESTING_2("H5Ovisit by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 2 * OBJECT_VISIT_TEST_NUM_OBJS_VISITED; + + if (H5Ovisit3(group_id, H5_INDEX_CRT_ORDER, H5_ITER_INC, object_visit_callback, &i, + H5O_INFO_ALL) < 0) { + H5_FAILED(); + HDprintf(" H5Ovisit by creation order in increasing order failed\n"); + PART_ERROR(H5Ovisit_create_order_increasing); + } + + if (i != 3 * OBJECT_VISIT_TEST_NUM_OBJS_VISITED) { + H5_FAILED(); + HDprintf(" some objects were not visited!\n"); + PART_ERROR(H5Ovisit_create_order_increasing); + } + + PASSED(); + } + PART_END(H5Ovisit_create_order_increasing); + + PART_BEGIN(H5Ovisit_create_order_decreasing) + { + TESTING_2("H5Ovisit by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 3 * OBJECT_VISIT_TEST_NUM_OBJS_VISITED; + + if (H5Ovisit3(group_id, H5_INDEX_CRT_ORDER, H5_ITER_DEC, object_visit_callback, &i, + H5O_INFO_ALL) < 0) { + H5_FAILED(); + HDprintf(" H5Ovisit by creation order in decreasing order failed\n"); + PART_ERROR(H5Ovisit_create_order_decreasing); + } + + if (i != 4 * OBJECT_VISIT_TEST_NUM_OBJS_VISITED) { + H5_FAILED(); + HDprintf(" some objects were not visited!\n"); + PART_ERROR(H5Ovisit_create_order_decreasing); + } + + PASSED(); + } + PART_END(H5Ovisit_create_order_decreasing); + + PART_BEGIN(H5Ovisit_file) + { + TESTING_2("H5Ovisit on a file ID"); + + /* + * XXX: + */ + + SKIPPED(); + PART_EMPTY(H5Ovisit_file); + } + PART_END(H5Ovisit_file); + + PART_BEGIN(H5Ovisit_dset) + { + TESTING_2("H5Ovisit on a dataset ID"); + + if (H5Ovisit3(dset_id, H5_INDEX_NAME, H5_ITER_INC, object_visit_dset_callback, NULL, + H5O_INFO_ALL) < 0) { + H5_FAILED(); + HDprintf(" H5Ovisit failed\n"); + PART_ERROR(H5Ovisit_dset); + } + + PASSED(); + } + PART_END(H5Ovisit_dset); + + PART_BEGIN(H5Ovisit_dtype) + { + TESTING_2("H5Ovisit on a committed datatype ID"); + + if (H5Ovisit3(type_id, H5_INDEX_NAME, H5_ITER_INC, object_visit_dtype_callback, NULL, + H5O_INFO_ALL) < 0) { + H5_FAILED(); + HDprintf(" H5Ovisit failed\n"); + PART_ERROR(H5Ovisit_dtype); + } + + PASSED(); + } + PART_END(H5Ovisit_dtype); + + PART_BEGIN(H5Ovisit_by_name_obj_name_increasing) + { + TESTING_2("H5Ovisit_by_name by object name in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 0; + + /* First, test visiting using "." for the object name */ + if (H5Ovisit_by_name3(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, object_visit_callback, &i, + H5O_INFO_ALL, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Ovisit_by_name by object name in increasing order failed\n"); + PART_ERROR(H5Ovisit_by_name_obj_name_increasing); + } + + if (i != OBJECT_VISIT_TEST_NUM_OBJS_VISITED) { + H5_FAILED(); + HDprintf(" some objects were not visited!\n"); + PART_ERROR(H5Ovisit_by_name_obj_name_increasing); + } + + /* Reset the special counter and repeat the test using an indirect object name. */ + i = 0; + + if (H5Ovisit_by_name3(container_group, OBJECT_VISIT_TEST_SUBGROUP_NAME, H5_INDEX_NAME, + H5_ITER_INC, object_visit_callback, &i, H5O_INFO_ALL, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Ovisit_by_name by object name in increasing order failed\n"); + PART_ERROR(H5Ovisit_by_name_obj_name_increasing); + } + + if (i != OBJECT_VISIT_TEST_NUM_OBJS_VISITED) { + H5_FAILED(); + HDprintf(" some objects were not visited!\n"); + PART_ERROR(H5Ovisit_by_name_obj_name_increasing); + } + + PASSED(); + } + PART_END(H5Ovisit_by_name_obj_name_increasing); + + PART_BEGIN(H5Ovisit_by_name_obj_name_decreasing) + { + TESTING_2("H5Ovisit_by_name by object name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + i = OBJECT_VISIT_TEST_NUM_OBJS_VISITED; + + /* First, test visiting using "." for the object name */ + if (H5Ovisit_by_name3(group_id, ".", H5_INDEX_NAME, H5_ITER_DEC, object_visit_callback, &i, + H5O_INFO_ALL, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Ovisit_by_name by object name in decreasing order failed\n"); + PART_ERROR(H5Ovisit_by_name_obj_name_decreasing); + } + + if (i != 2 * OBJECT_VISIT_TEST_NUM_OBJS_VISITED) { + H5_FAILED(); + HDprintf(" some objects were not visited!\n"); + PART_ERROR(H5Ovisit_by_name_obj_name_decreasing); + } + + /* Reset the special counter and repeat the test using an indirect object name. */ + i = OBJECT_VISIT_TEST_NUM_OBJS_VISITED; + + if (H5Ovisit_by_name3(container_group, OBJECT_VISIT_TEST_SUBGROUP_NAME, H5_INDEX_NAME, + H5_ITER_DEC, object_visit_callback, &i, H5O_INFO_ALL, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Ovisit_by_name by object name in decreasing order failed\n"); + PART_ERROR(H5Ovisit_by_name_obj_name_decreasing); + } + + if (i != 2 * OBJECT_VISIT_TEST_NUM_OBJS_VISITED) { + H5_FAILED(); + HDprintf(" some objects were not visited!\n"); + PART_ERROR(H5Ovisit_by_name_obj_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Ovisit_by_name_obj_name_decreasing); +#endif + } + PART_END(H5Ovisit_by_name_obj_name_decreasing); + + PART_BEGIN(H5Ovisit_by_name_create_order_increasing) + { + TESTING_2("H5Ovisit_by_name by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 2 * OBJECT_VISIT_TEST_NUM_OBJS_VISITED; + + /* First, test visiting using "." for the object name */ + if (H5Ovisit_by_name3(group_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, object_visit_callback, &i, + H5O_INFO_ALL, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Ovisit_by_name by creation order in increasing order failed\n"); + PART_ERROR(H5Ovisit_by_name_create_order_increasing); + } + + if (i != 3 * OBJECT_VISIT_TEST_NUM_OBJS_VISITED) { + H5_FAILED(); + HDprintf(" some objects were not visited!\n"); + PART_ERROR(H5Ovisit_by_name_create_order_increasing); + } + + /* Reset the special counter and repeat the test using an indirect object name. */ + i = 2 * OBJECT_VISIT_TEST_NUM_OBJS_VISITED; + + if (H5Ovisit_by_name3(container_group, OBJECT_VISIT_TEST_SUBGROUP_NAME, H5_INDEX_CRT_ORDER, + H5_ITER_INC, object_visit_callback, &i, H5O_INFO_ALL, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Ovisit_by_name by creation order in increasing order failed\n"); + PART_ERROR(H5Ovisit_by_name_create_order_increasing); + } + + if (i != 3 * OBJECT_VISIT_TEST_NUM_OBJS_VISITED) { + H5_FAILED(); + HDprintf(" some objects were not visited!\n"); + PART_ERROR(H5Ovisit_by_name_create_order_increasing); + } + + PASSED(); + } + PART_END(H5Ovisit_by_name_create_order_increasing); + + PART_BEGIN(H5Ovisit_by_name_create_order_decreasing) + { + TESTING_2("H5Ovisit_by_name by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 3 * OBJECT_VISIT_TEST_NUM_OBJS_VISITED; + + /* First, test visiting using "." for the object name */ + if (H5Ovisit_by_name3(group_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, object_visit_callback, &i, + H5O_INFO_ALL, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Ovisit_by_name by creation order in decreasing order failed\n"); + PART_ERROR(H5Ovisit_by_name_create_order_decreasing); + } + + if (i != 4 * OBJECT_VISIT_TEST_NUM_OBJS_VISITED) { + H5_FAILED(); + HDprintf(" some objects were not visited!\n"); + PART_ERROR(H5Ovisit_by_name_create_order_decreasing); + } + + /* Reset the special counter and repeat the test using an indirect object name. */ + i = 3 * OBJECT_VISIT_TEST_NUM_OBJS_VISITED; + + if (H5Ovisit_by_name3(container_group, OBJECT_VISIT_TEST_SUBGROUP_NAME, H5_INDEX_CRT_ORDER, + H5_ITER_DEC, object_visit_callback, &i, H5O_INFO_ALL, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Ovisit_by_name by creation order in decreasing order failed\n"); + PART_ERROR(H5Ovisit_by_name_create_order_decreasing); + } + + if (i != 4 * OBJECT_VISIT_TEST_NUM_OBJS_VISITED) { + H5_FAILED(); + HDprintf(" some objects were not visited!\n"); + PART_ERROR(H5Ovisit_by_name_create_order_decreasing); + } + + PASSED(); + } + PART_END(H5Ovisit_by_name_create_order_decreasing); + + PART_BEGIN(H5Ovisit_by_name_file) + { + TESTING_2("H5Ovisit_by_name on a file ID"); + + /* + * XXX: + */ + + SKIPPED(); + PART_EMPTY(H5Ovisit_by_name_file); + } + PART_END(H5Ovisit_by_name_file); + + PART_BEGIN(H5Ovisit_by_name_dset) + { + TESTING_2("H5Ovisit_by_name on a dataset ID"); + + if (H5Ovisit_by_name3(group_id, OBJECT_VISIT_TEST_DSET_NAME, H5_INDEX_NAME, H5_ITER_INC, + object_visit_dset_callback, NULL, H5O_INFO_ALL, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Ovisit_by_name failed\n"); + PART_ERROR(H5Ovisit_by_name_dset); + } + + PASSED(); + } + PART_END(H5Ovisit_by_name_dset); + + PART_BEGIN(H5Ovisit_by_name_dtype) + { + TESTING_2("H5Ovisit_by_name on a committed datatype ID"); + + if (H5Ovisit_by_name3(group_id, OBJECT_VISIT_TEST_TYPE_NAME, H5_INDEX_NAME, H5_ITER_INC, + object_visit_dtype_callback, NULL, H5O_INFO_ALL, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Ovisit_by_name failed\n"); + PART_ERROR(H5Ovisit_by_name_dtype); + } + + PASSED(); + } + PART_END(H5Ovisit_by_name_dtype); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Tclose(type_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id2) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + H5Tclose(dset_dtype); + H5Tclose(type_id); + H5Dclose(dset_id); + H5Pclose(gcpl_id); + H5Gclose(group_id2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test for H5Ovisit(_by_name) on soft links. Since + * H5Ovisit(_by_name) ignores soft links, this test is + * meant to verify that behavior by placing objects and + * the soft links pointing to those objects in separate + * groups. Visiting is done only on the group containing + * the links to ensure that the objects in the other group + * do not get visited. + */ +static int +test_object_visit_soft_link(void) +{ + size_t i; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t subgroup_id = H5I_INVALID_HID, subgroup_id2 = H5I_INVALID_HID; + hid_t linked_group_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + + TESTING_MULTIPART("object visiting with soft links"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ITERATE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER) || !(vol_cap_flags_g & H5VL_CAP_FLAG_SOFT_LINKS)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, object, soft link, iterate, or creation order " + "aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, OBJECT_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", OBJECT_TEST_GROUP_NAME); + goto error; + } + + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create a GCPL\n"); + goto error; + } + + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0) { + H5_FAILED(); + HDprintf(" couldn't enable link creation order tracking and indexing on GCPL\n"); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, OBJECT_VISIT_SOFT_LINK_TEST_SUBGROUP_NAME, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", OBJECT_VISIT_SOFT_LINK_TEST_SUBGROUP_NAME); + goto error; + } + + /* Create group to hold soft links */ + if ((subgroup_id = H5Gcreate2(group_id, OBJECT_VISIT_SOFT_LINK_TEST_GROUP_NAME1, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", OBJECT_VISIT_SOFT_LINK_TEST_GROUP_NAME1); + goto error; + } + + /* Create group to hold objects pointed to by soft links */ + if ((subgroup_id2 = H5Gcreate2(group_id, OBJECT_VISIT_SOFT_LINK_TEST_GROUP_NAME2, H5P_DEFAULT, gcpl_id, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", OBJECT_VISIT_SOFT_LINK_TEST_GROUP_NAME2); + goto error; + } + + /* Create objects under subgroup 2 */ + if ((linked_group_id = H5Gcreate2(subgroup_id2, OBJECT_VISIT_SOFT_LINK_TEST_OBJ_NAME1, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", OBJECT_VISIT_SOFT_LINK_TEST_OBJ_NAME1); + goto error; + } + + if (H5Gclose(linked_group_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close group '%s'\n", OBJECT_VISIT_SOFT_LINK_TEST_OBJ_NAME1); + goto error; + } + + if ((linked_group_id = H5Gcreate2(subgroup_id2, OBJECT_VISIT_SOFT_LINK_TEST_OBJ_NAME2, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", OBJECT_VISIT_SOFT_LINK_TEST_OBJ_NAME2); + goto error; + } + + if (H5Gclose(linked_group_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close group '%s'\n", OBJECT_VISIT_SOFT_LINK_TEST_OBJ_NAME2); + goto error; + } + + if ((linked_group_id = H5Gcreate2(subgroup_id2, OBJECT_VISIT_SOFT_LINK_TEST_OBJ_NAME3, H5P_DEFAULT, + gcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", OBJECT_VISIT_SOFT_LINK_TEST_OBJ_NAME3); + goto error; + } + + if (H5Gclose(linked_group_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close group '%s'\n", OBJECT_VISIT_SOFT_LINK_TEST_OBJ_NAME3); + goto error; + } + + if (H5Gclose(subgroup_id2) < 0) { + H5_FAILED(); + HDprintf(" couldn't close group '%s'\n", OBJECT_VISIT_SOFT_LINK_TEST_GROUP_NAME2); + goto error; + } + + /* Create soft links under subgroup 1 to point to the previously-created objects */ + if (H5Lcreate_soft("/" OBJECT_TEST_GROUP_NAME "/" OBJECT_VISIT_SOFT_LINK_TEST_SUBGROUP_NAME + "/" OBJECT_VISIT_SOFT_LINK_TEST_GROUP_NAME2 "/" OBJECT_VISIT_SOFT_LINK_TEST_OBJ_NAME1, + subgroup_id, OBJECT_VISIT_SOFT_LINK_TEST_LINK_NAME1, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", OBJECT_VISIT_SOFT_LINK_TEST_LINK_NAME1); + goto error; + } + + if (H5Lcreate_soft("/" OBJECT_TEST_GROUP_NAME "/" OBJECT_VISIT_SOFT_LINK_TEST_SUBGROUP_NAME + "/" OBJECT_VISIT_SOFT_LINK_TEST_GROUP_NAME2 "/" OBJECT_VISIT_SOFT_LINK_TEST_OBJ_NAME2, + subgroup_id, OBJECT_VISIT_SOFT_LINK_TEST_LINK_NAME2, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", OBJECT_VISIT_SOFT_LINK_TEST_LINK_NAME2); + goto error; + } + + if (H5Lcreate_soft("/" OBJECT_TEST_GROUP_NAME "/" OBJECT_VISIT_SOFT_LINK_TEST_SUBGROUP_NAME + "/" OBJECT_VISIT_SOFT_LINK_TEST_GROUP_NAME2 "/" OBJECT_VISIT_SOFT_LINK_TEST_OBJ_NAME3, + subgroup_id, OBJECT_VISIT_SOFT_LINK_TEST_LINK_NAME3, H5P_DEFAULT, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't create soft link '%s'\n", OBJECT_VISIT_SOFT_LINK_TEST_LINK_NAME3); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + /* + * NOTE: A counter is passed to the iteration callback to try to match up + * the expected objects with a given step throughout all of the following + * iterations. This is to try and check that the objects are indeed being + * returned in the correct order. + */ + + PART_BEGIN(H5Ovisit_obj_name_increasing) + { + TESTING_2("H5Ovisit by object name in increasing order"); + + i = 0; + + if (H5Ovisit3(subgroup_id, H5_INDEX_NAME, H5_ITER_INC, object_visit_soft_link_callback, &i, + H5O_INFO_ALL) < 0) { + H5_FAILED(); + HDprintf(" H5Ovisit by object name in increasing order failed\n"); + PART_ERROR(H5Ovisit_obj_name_increasing); + } + + if (i != OBJECT_VISIT_SOFT_LINK_TEST_NUM_OBJS_VISITED) { + H5_FAILED(); + HDprintf(" some objects were not visited!\n"); + PART_ERROR(H5Ovisit_obj_name_increasing); + } + + PASSED(); + } + PART_END(H5Ovisit_obj_name_increasing); + + PART_BEGIN(H5Ovisit_obj_name_decreasing) + { + TESTING_2("H5Ovisit by object name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + i = OBJECT_VISIT_SOFT_LINK_TEST_NUM_OBJS_VISITED; + + if (H5Ovisit3(subgroup_id, H5_INDEX_NAME, H5_ITER_DEC, object_visit_soft_link_callback, &i, + H5O_INFO_ALL) < 0) { + H5_FAILED(); + HDprintf(" H5Ovisit by object name in decreasing order failed\n"); + PART_ERROR(H5Ovisit_obj_name_decreasing); + } + + if (i != 2 * OBJECT_VISIT_SOFT_LINK_TEST_NUM_OBJS_VISITED) { + H5_FAILED(); + HDprintf(" some objects were not visited!\n"); + PART_ERROR(H5Ovisit_obj_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Ovisit_obj_name_decreasing); +#endif + } + PART_END(H5Ovisit_obj_name_decreasing); + + PART_BEGIN(H5Ovisit_create_order_increasing) + { + TESTING_2("H5Ovisit by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 2 * OBJECT_VISIT_SOFT_LINK_TEST_NUM_OBJS_VISITED; + + if (H5Ovisit3(subgroup_id, H5_INDEX_CRT_ORDER, H5_ITER_INC, object_visit_soft_link_callback, &i, + H5O_INFO_ALL) < 0) { + H5_FAILED(); + HDprintf(" H5Ovisit by creation order in increasing order failed\n"); + PART_ERROR(H5Ovisit_create_order_increasing); + } + + if (i != 3 * OBJECT_VISIT_SOFT_LINK_TEST_NUM_OBJS_VISITED) { + H5_FAILED(); + HDprintf(" some objects were not visited!\n"); + PART_ERROR(H5Ovisit_create_order_increasing); + } + + PASSED(); + } + PART_END(H5Ovisit_create_order_increasing); + + PART_BEGIN(H5Ovisit_create_order_decreasing) + { + TESTING_2("H5Ovisit by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 3 * OBJECT_VISIT_SOFT_LINK_TEST_NUM_OBJS_VISITED; + + if (H5Ovisit3(subgroup_id, H5_INDEX_CRT_ORDER, H5_ITER_DEC, object_visit_soft_link_callback, &i, + H5O_INFO_ALL) < 0) { + H5_FAILED(); + HDprintf(" H5Ovisit by creation order in decreasing order failed\n"); + PART_ERROR(H5Ovisit_create_order_decreasing); + } + + if (i != 4 * OBJECT_VISIT_SOFT_LINK_TEST_NUM_OBJS_VISITED) { + H5_FAILED(); + HDprintf(" some objects were not visited!\n"); + PART_ERROR(H5Ovisit_create_order_decreasing); + } + + PASSED(); + } + PART_END(H5Ovisit_create_order_decreasing); + + PART_BEGIN(H5Ovisit_by_name_obj_name_increasing) + { + TESTING_2("H5Ovisit_by_name by object name in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 0; + + /* First, test visiting using "." for the object name */ + if (H5Ovisit_by_name3(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_INC, + object_visit_soft_link_callback, &i, H5O_INFO_ALL, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Ovisit_by_name by object name in increasing order failed\n"); + PART_ERROR(H5Ovisit_by_name_obj_name_increasing); + } + + if (i != OBJECT_VISIT_SOFT_LINK_TEST_NUM_OBJS_VISITED) { + H5_FAILED(); + HDprintf(" some objects were not visited!\n"); + PART_ERROR(H5Ovisit_by_name_obj_name_increasing); + } + + /* Reset the special counter and repeat the test using an indirect object name. */ + i = 0; + + /* Repeat the test using an indirect object name */ + if (H5Ovisit_by_name3(group_id, OBJECT_VISIT_SOFT_LINK_TEST_GROUP_NAME1, H5_INDEX_NAME, + H5_ITER_INC, object_visit_soft_link_callback, &i, H5O_INFO_ALL, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Ovisit_by_name by object name in increasing order failed\n"); + PART_ERROR(H5Ovisit_by_name_obj_name_increasing); + } + + if (i != OBJECT_VISIT_SOFT_LINK_TEST_NUM_OBJS_VISITED) { + H5_FAILED(); + HDprintf(" some objects were not visited!\n"); + PART_ERROR(H5Ovisit_by_name_obj_name_increasing); + } + + PASSED(); + } + PART_END(H5Ovisit_by_name_obj_name_increasing); + + PART_BEGIN(H5Ovisit_by_name_obj_name_decreasing) + { + TESTING_2("H5Ovisit_by_name by object name in decreasing order"); +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Reset the counter to the appropriate value for the next test */ + i = OBJECT_VISIT_SOFT_LINK_TEST_NUM_OBJS_VISITED; + + /* First, test visiting using "." for the object name */ + if (H5Ovisit_by_name3(subgroup_id, ".", H5_INDEX_NAME, H5_ITER_DEC, + object_visit_soft_link_callback, &i, H5O_INFO_ALL, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Ovisit_by_name by object name in decreasing order failed\n"); + PART_ERROR(H5Ovisit_by_name_obj_name_decreasing); + } + + if (i != 2 * OBJECT_VISIT_SOFT_LINK_TEST_NUM_OBJS_VISITED) { + H5_FAILED(); + HDprintf(" some objects were not visited!\n"); + PART_ERROR(H5Ovisit_by_name_obj_name_decreasing); + } + + /* Reset the special counter and repeat the test using an indirect object name. */ + i = OBJECT_VISIT_SOFT_LINK_TEST_NUM_OBJS_VISITED; + + /* Repeat the test using an indirect object name */ + if (H5Ovisit_by_name3(group_id, OBJECT_VISIT_SOFT_LINK_TEST_GROUP_NAME1, H5_INDEX_NAME, + H5_ITER_DEC, object_visit_soft_link_callback, &i, H5O_INFO_ALL, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Ovisit_by_name by object name in decreasing order failed\n"); + PART_ERROR(H5Ovisit_by_name_obj_name_decreasing); + } + + if (i != 2 * OBJECT_VISIT_SOFT_LINK_TEST_NUM_OBJS_VISITED) { + H5_FAILED(); + HDprintf(" some objects were not visited!\n"); + PART_ERROR(H5Ovisit_by_name_obj_name_decreasing); + } + + PASSED(); +#else + SKIPPED(); + PART_EMPTY(H5Ovisit_by_name_obj_name_decreasing); +#endif + } + PART_END(H5Ovisit_by_name_obj_name_decreasing); + + PART_BEGIN(H5Ovisit_by_name_create_order_increasing) + { + TESTING_2("H5Ovisit_by_name by creation order in increasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 2 * OBJECT_VISIT_SOFT_LINK_TEST_NUM_OBJS_VISITED; + + /* First, test visiting using "." for the object name */ + if (H5Ovisit_by_name3(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, + object_visit_soft_link_callback, &i, H5O_INFO_ALL, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Ovisit_by_name by creation order in increasing order failed\n"); + PART_ERROR(H5Ovisit_by_name_create_order_increasing); + } + + if (i != 3 * OBJECT_VISIT_SOFT_LINK_TEST_NUM_OBJS_VISITED) { + H5_FAILED(); + HDprintf(" some objects were not visited!\n"); + PART_ERROR(H5Ovisit_by_name_create_order_increasing); + } + + /* Reset the special counter and repeat the test using an indirect object name. */ + i = 2 * OBJECT_VISIT_SOFT_LINK_TEST_NUM_OBJS_VISITED; + + /* Repeat the test using an indirect object name */ + if (H5Ovisit_by_name3(group_id, OBJECT_VISIT_SOFT_LINK_TEST_GROUP_NAME1, H5_INDEX_CRT_ORDER, + H5_ITER_INC, object_visit_soft_link_callback, &i, H5O_INFO_ALL, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Ovisit_by_name by creation order in increasing order failed\n"); + PART_ERROR(H5Ovisit_by_name_create_order_increasing); + } + + if (i != 3 * OBJECT_VISIT_SOFT_LINK_TEST_NUM_OBJS_VISITED) { + H5_FAILED(); + HDprintf(" some objects were not visited!\n"); + PART_ERROR(H5Ovisit_by_name_create_order_increasing); + } + + PASSED(); + } + PART_END(H5Ovisit_by_name_create_order_increasing); + + PART_BEGIN(H5Ovisit_by_name_create_order_decreasing) + { + TESTING_2("H5Ovisit_by_name by creation order in decreasing order"); + + /* Reset the counter to the appropriate value for the next test */ + i = 3 * OBJECT_VISIT_SOFT_LINK_TEST_NUM_OBJS_VISITED; + + /* First, test visiting using "." for the object name */ + if (H5Ovisit_by_name3(subgroup_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, + object_visit_soft_link_callback, &i, H5O_INFO_ALL, H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Ovisit_by_name by creation order in decreasing order failed\n"); + PART_ERROR(H5Ovisit_by_name_create_order_decreasing); + } + + if (i != 4 * OBJECT_VISIT_SOFT_LINK_TEST_NUM_OBJS_VISITED) { + H5_FAILED(); + HDprintf(" some objects were not visited!\n"); + PART_ERROR(H5Ovisit_by_name_create_order_decreasing); + } + + /* Reset the special counter and repeat the test using an indirect object name. */ + i = 3 * OBJECT_VISIT_SOFT_LINK_TEST_NUM_OBJS_VISITED; + + /* Repeat the test using an indirect object name */ + if (H5Ovisit_by_name3(group_id, OBJECT_VISIT_SOFT_LINK_TEST_GROUP_NAME1, H5_INDEX_CRT_ORDER, + H5_ITER_DEC, object_visit_soft_link_callback, &i, H5O_INFO_ALL, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" H5Ovisit_by_name by creation order in decreasing order failed\n"); + PART_ERROR(H5Ovisit_by_name_create_order_decreasing); + } + + if (i != 4 * OBJECT_VISIT_SOFT_LINK_TEST_NUM_OBJS_VISITED) { + H5_FAILED(); + HDprintf(" some objects were not visited!\n"); + PART_ERROR(H5Ovisit_by_name_create_order_decreasing); + } + + PASSED(); + } + PART_END(H5Ovisit_by_name_create_order_decreasing); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + if (H5Gclose(subgroup_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(gcpl_id); + H5Gclose(linked_group_id); + H5Gclose(subgroup_id); + H5Gclose(subgroup_id2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that H5Ovisit(_by_name) fails when + * it is passed invalid parameters. + */ +static int +test_object_visit_invalid_params(void) +{ + herr_t err_ret = -1; + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t group_id2 = H5I_INVALID_HID; + + TESTING_MULTIPART("object visiting with invalid parameters"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ITERATE)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or iterate aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, OBJECT_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", OBJECT_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, OBJECT_VISIT_INVALID_PARAMS_TEST_SUBGROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + OBJECT_VISIT_INVALID_PARAMS_TEST_SUBGROUP_NAME); + goto error; + } + + if ((group_id2 = H5Gcreate2(group_id, OBJECT_VISIT_INVALID_PARAMS_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", OBJECT_VISIT_INVALID_PARAMS_TEST_GROUP_NAME); + goto error; + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Ovisit_invalid_obj_id) + { + TESTING_2("H5Ovisit with an invalid object ID"); + + H5E_BEGIN_TRY + { + err_ret = H5Ovisit3(H5I_INVALID_HID, H5_INDEX_NAME, H5_ITER_INC, object_visit_noop_callback, + NULL, H5O_INFO_ALL); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ovisit succeeded with an invalid object ID!\n"); + PART_ERROR(H5Ovisit_invalid_obj_id); + } + + PASSED(); + } + PART_END(H5Ovisit_invalid_obj_id); + + PART_BEGIN(H5Ovisit_invalid_index_type) + { + TESTING_2("H5Ovisit with an invalid index type"); + + H5E_BEGIN_TRY + { + err_ret = H5Ovisit3(group_id, H5_INDEX_UNKNOWN, H5_ITER_INC, object_visit_noop_callback, NULL, + H5O_INFO_ALL); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ovisit succeeded with invalid index type H5_INDEX_UNKNOWN!\n"); + PART_ERROR(H5Ovisit_invalid_index_type); + } + + H5E_BEGIN_TRY + { + err_ret = H5Ovisit3(group_id, H5_INDEX_N, H5_ITER_INC, object_visit_noop_callback, NULL, + H5O_INFO_ALL); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ovisit succeeded with invalid index type H5_INDEX_N!\n"); + PART_ERROR(H5Ovisit_invalid_index_type); + } + + PASSED(); + } + PART_END(H5Ovisit_invalid_index_type); + + PART_BEGIN(H5Ovisit_invalid_iter_order) + { + TESTING_2("H5Ovisit with an invalid iteration ordering"); + + H5E_BEGIN_TRY + { + err_ret = H5Ovisit3(group_id, H5_INDEX_NAME, H5_ITER_UNKNOWN, object_visit_noop_callback, + NULL, H5O_INFO_ALL); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ovisit succeeded with invalid iteration ordering H5_ITER_UNKNOWN!\n"); + PART_ERROR(H5Ovisit_invalid_iter_order); + } + + H5E_BEGIN_TRY + { + err_ret = H5Ovisit3(group_id, H5_INDEX_NAME, H5_ITER_N, object_visit_noop_callback, NULL, + H5O_INFO_ALL); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ovisit succeeded with invalid iteration ordering H5_ITER_N!\n"); + PART_ERROR(H5Ovisit_invalid_iter_order); + } + + PASSED(); + } + PART_END(H5Ovisit_invalid_iter_order); + + PART_BEGIN(H5Ovisit_by_name_invalid_loc_id) + { + TESTING_2("H5Ovisit_by_name with an invalid location ID"); + + H5E_BEGIN_TRY + { + err_ret = H5Ovisit_by_name3(H5I_INVALID_HID, ".", H5_INDEX_NAME, H5_ITER_N, + object_visit_noop_callback, NULL, H5O_INFO_ALL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ovisit_by_name succeeded with an invalid location ID!\n"); + PART_ERROR(H5Ovisit_by_name_invalid_loc_id); + } + + PASSED(); + } + PART_END(H5Ovisit_by_name_invalid_loc_id); + + PART_BEGIN(H5Ovisit_by_name_invalid_obj_name) + { + TESTING_2("H5Ovisit_by_name with an invalid object name"); + + H5E_BEGIN_TRY + { + err_ret = H5Ovisit_by_name3(group_id, NULL, H5_INDEX_NAME, H5_ITER_N, + object_visit_noop_callback, NULL, H5O_INFO_ALL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ovisit_by_name succeeded with a NULL object name!\n"); + PART_ERROR(H5Ovisit_by_name_invalid_obj_name); + } + + H5E_BEGIN_TRY + { + err_ret = H5Ovisit_by_name3(group_id, "", H5_INDEX_NAME, H5_ITER_N, + object_visit_noop_callback, NULL, H5O_INFO_ALL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ovisit_by_name succeeded with an invalid object name of ''!\n"); + PART_ERROR(H5Ovisit_by_name_invalid_obj_name); + } + + PASSED(); + } + PART_END(H5Ovisit_by_name_invalid_obj_name); + + PART_BEGIN(H5Ovisit_by_name_invalid_index_type) + { + TESTING_2("H5Ovisit_by_name with an invalid index type"); + + H5E_BEGIN_TRY + { + err_ret = H5Ovisit_by_name3(group_id, ".", H5_INDEX_UNKNOWN, H5_ITER_N, + object_visit_noop_callback, NULL, H5O_INFO_ALL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ovisit_by_name succeeded with invalid index type H5_INDEX_UNKNOWN!\n"); + PART_ERROR(H5Ovisit_by_name_invalid_index_type); + } + + H5E_BEGIN_TRY + { + err_ret = H5Ovisit_by_name3(group_id, ".", H5_INDEX_N, H5_ITER_N, object_visit_noop_callback, + NULL, H5O_INFO_ALL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ovisit_by_name succeeded with invalid index type H5_INDEX_N!\n"); + PART_ERROR(H5Ovisit_by_name_invalid_index_type); + } + + PASSED(); + } + PART_END(H5Ovisit_by_name_invalid_index_type); + + PART_BEGIN(H5Ovisit_by_name_invalid_iter_order) + { + TESTING_2("H5Ovisit_by_name with an invalid iteration ordering"); + + H5E_BEGIN_TRY + { + err_ret = H5Ovisit_by_name3(group_id, ".", H5_INDEX_NAME, H5_ITER_UNKNOWN, + object_visit_noop_callback, NULL, H5O_INFO_ALL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ovisit_by_name succeeded with invalid iteration ordering H5_ITER_UNKNOWN!\n"); + PART_ERROR(H5Ovisit_by_name_invalid_iter_order); + } + + H5E_BEGIN_TRY + { + err_ret = H5Ovisit_by_name3(group_id, ".", H5_INDEX_NAME, H5_ITER_N, + object_visit_noop_callback, NULL, H5O_INFO_ALL, H5P_DEFAULT); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ovisit_by_name succeeded with invalid iteration ordering H5_ITER_N!\n"); + PART_ERROR(H5Ovisit_by_name_invalid_iter_order); + } + + PASSED(); + } + PART_END(H5Ovisit_by_name_invalid_iter_order); + + PART_BEGIN(H5Ovisit_by_name_invalid_lapl) + { + TESTING_2("H5Ovisit_by_name with an invalid LAPL"); + + H5E_BEGIN_TRY + { + err_ret = H5Ovisit_by_name3(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, + object_visit_noop_callback, NULL, H5O_INFO_ALL, H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Ovisit_by_name succeeded with an invalid LAPL!\n"); + PART_ERROR(H5Ovisit_by_name_invalid_lapl); + } + + PASSED(); + } + PART_END(H5Ovisit_by_name_invalid_lapl); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Gclose(group_id2) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(group_id2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test for H5Oclose. + */ +static int +test_close_object(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t group_id2 = H5I_INVALID_HID; + hid_t dtype_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dset_dtype = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + + TESTING_MULTIPART("H5Oclose"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_STORED_DATATYPES)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, object, dataset, attribute, or stored datatype " + "aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, OBJECT_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", OBJECT_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, OBJECT_CLOSE_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container subgroup '%s'\n", OBJECT_CLOSE_TEST_GROUP_NAME); + goto error; + } + + if ((fspace_id = generate_random_dataspace(OBJECT_CLOSE_TEST_SPACE_RANK, NULL, NULL, FALSE)) < 0) + TEST_ERROR; + + if ((dset_dtype = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Oclose_group) + { + TESTING_2("H5Oclose on a group"); + + if ((group_id2 = H5Gcreate2(group_id, OBJECT_CLOSE_TEST_GRP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create group '%s'\n", OBJECT_CLOSE_TEST_GRP_NAME); + PART_ERROR(H5Oclose_group); + } + + H5E_BEGIN_TRY + { + H5Gclose(group_id2); + } + H5E_END_TRY; + + if ((group_id2 = H5Oopen(group_id, OBJECT_CLOSE_TEST_GRP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open group '%s' with H5Oopen\n", OBJECT_CLOSE_TEST_GRP_NAME); + PART_ERROR(H5Oclose_group); + } + + if (H5Oclose(group_id2) < 0) { + H5_FAILED(); + HDprintf(" couldn't close group '%s' with H5Oclose\n", OBJECT_CLOSE_TEST_GRP_NAME); + PART_ERROR(H5Oclose_group); + } + + PASSED(); + } + PART_END(H5Oclose_group); + + PART_BEGIN(H5Oclose_dset) + { + TESTING_2("H5Oclose on a dataset"); + + if ((dset_id = H5Dcreate2(group_id, OBJECT_CLOSE_TEST_DSET_NAME, dset_dtype, fspace_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", OBJECT_CLOSE_TEST_DSET_NAME); + PART_ERROR(H5Oclose_dset); + } + + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + + if ((dset_id = H5Oopen(group_id, OBJECT_CLOSE_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s' with H5Oopen\n", OBJECT_CLOSE_TEST_DSET_NAME); + PART_ERROR(H5Oclose_dset); + } + + if (H5Oclose(dset_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close dataset '%s' with H5Oclose\n", OBJECT_CLOSE_TEST_DSET_NAME); + PART_ERROR(H5Oclose_dset); + } + + PASSED(); + } + PART_END(H5Oclose_dset); + + PART_BEGIN(H5Oclose_dtype) + { + TESTING_2("H5Oclose on a committed datatype"); + + if ((dtype_id = generate_random_datatype(H5T_NO_CLASS, FALSE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create datatype '%s'\n", OBJECT_CLOSE_TEST_TYPE_NAME); + PART_ERROR(H5Oclose_dtype); + } + + if (H5Tcommit2(group_id, OBJECT_CLOSE_TEST_TYPE_NAME, dtype_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT) < 0) { + H5_FAILED(); + HDprintf(" couldn't commit datatype '%s'\n", OBJECT_CLOSE_TEST_TYPE_NAME); + PART_ERROR(H5Oclose_dtype); + } + + H5E_BEGIN_TRY + { + H5Tclose(dtype_id); + } + H5E_END_TRY; + + if ((dtype_id = H5Oopen(group_id, OBJECT_CLOSE_TEST_TYPE_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open datatype '%s' with H5Oopen\n", OBJECT_CLOSE_TEST_TYPE_NAME); + PART_ERROR(H5Oclose_dtype); + } + + if (H5Oclose(dtype_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't close datatype '%s' with H5Oclose\n", OBJECT_CLOSE_TEST_TYPE_NAME); + PART_ERROR(H5Oclose_dtype); + } + + PASSED(); + } + PART_END(H5Oclose_dtype); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Tclose(dset_dtype) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + H5Tclose(dset_dtype); + H5Tclose(dtype_id); + H5Dclose(dset_id); + H5Gclose(group_id2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that H5Oclose fails when it + * is passed invalid parameters. + */ +static int +test_close_object_invalid_params(void) +{ + herr_t err_ret = -1; + hid_t file_id = H5I_INVALID_HID; + + TESTING("H5Oclose with an invalid object ID"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file or object aren't supported with this connector\n"); + return 0; + } + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + H5E_BEGIN_TRY + { + err_ret = H5Oclose(H5I_INVALID_HID); + } + H5E_END_TRY; + + if (err_ret >= 0) { + H5_FAILED(); + HDprintf(" H5Oclose succeeded with an invalid object ID!\n"); + goto error; + } + + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that various objects (file, dataspace, property list, + * and attribute) can't be closed with H5Oclose. + */ +static int +test_close_invalid_objects(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t attr_dtype = H5I_INVALID_HID; + hid_t attr_space_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + herr_t status; + + TESTING_MULTIPART("H5Oclose invalid objects"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & (H5VL_CAP_FLAG_FILE_BASIC)) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, object, dataset, attribute, or stored datatype " + "aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) + TEST_ERROR; + + if ((file_id = H5Fopen(H5_api_test_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, OBJECT_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", OBJECT_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, OBJECT_CLOSE_INVALID_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", OBJECT_OPEN_TEST_GROUP_NAME); + goto error; + } + + if ((attr_space_id = generate_random_dataspace(OBJECT_CLOSE_INVALID_TEST_SPACE_RANK, NULL, NULL, TRUE)) < + 0) + TEST_ERROR; + + if ((attr_dtype = generate_random_datatype(H5T_NO_CLASS, TRUE)) < 0) + TEST_ERROR; + + if ((attr_id = H5Acreate2(group_id, OBJECT_CLOSE_INVALID_TEST_ATTRIBUTE_NAME, attr_dtype, attr_space_id, + H5P_DEFAULT, H5P_DEFAULT)) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Oclose_file) + { + TESTING_2("H5Oclose with an invalid object - file"); + + H5E_BEGIN_TRY + { + status = H5Oclose(file_id); + } + H5E_END_TRY; + + if (status >= 0) { + H5_FAILED(); + HDprintf(" H5Oclose succeeded with an invalid object (file)!\n"); + PART_ERROR(H5Oclose_file); + } + + PASSED(); + } + PART_END(H5Oclose_file); + + PART_BEGIN(H5Oclose_plist) + { + TESTING_2("H5Oclose with an invalid object - property list"); + + H5E_BEGIN_TRY + { + status = H5Oclose(fapl_id); + } + H5E_END_TRY; + + if (status >= 0) { + H5_FAILED(); + HDprintf(" H5Oclose succeeded with an invalid object (property list)!\n"); + PART_ERROR(H5Oclose_plist); + } + + PASSED(); + } + PART_END(H5Oclose_plist); + + PART_BEGIN(H5Oclose_dspace) + { + TESTING_2("H5Oclose with an invalid object - data space"); + + H5E_BEGIN_TRY + { + status = H5Oclose(attr_space_id); + } + H5E_END_TRY; + + if (status >= 0) { + H5_FAILED(); + HDprintf(" H5Oclose succeeded with an invalid object (data space)!\n"); + PART_ERROR(H5Oclose_dspace); + } + + PASSED(); + } + PART_END(H5Oclose_dspace); + + PART_BEGIN(H5Oclose_attribute) + { + TESTING_2("H5Oclose with an invalid object - attribute"); + + H5E_BEGIN_TRY + { + status = H5Oclose(attr_id); + } + H5E_END_TRY; + + if (status >= 0) { + H5_FAILED(); + HDprintf(" H5Oclose succeeded with an invalid object (attribute)!\n"); + PART_ERROR(H5Oclose_attribute); + } + + PASSED(); + } + PART_END(H5Oclose_attribute); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Tclose(attr_dtype) < 0) + TEST_ERROR; + if (H5Aclose(attr_id) < 0) + TEST_ERROR; + if (H5Sclose(attr_space_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Tclose(attr_dtype); + H5Sclose(attr_space_id); + H5Aclose(attr_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Fclose(file_id); + H5Pclose(fapl_id); + } + H5E_END_TRY; + + return 1; +} /* test_close_invalid_objects */ + +/* + * A test for H5Oflush. + */ +static int +test_flush_object(void) +{ + TESTING("H5Oflush"); + + SKIPPED(); + + return 0; +} + +/* + * A test to check that H5Oflush fails when + * it is passed invalid parameters. + */ +static int +test_flush_object_invalid_params(void) +{ + TESTING("H5Oflush with invalid parameters"); + + SKIPPED(); + + return 0; +} + +/* + * A test for H5Orefresh. + */ +static int +test_refresh_object(void) +{ + TESTING("H5Orefresh"); + + SKIPPED(); + + return 0; +} + +/* + * A test to check that H5Orefresh fails when + * it is passed invalid parameters. + */ +static int +test_refresh_object_invalid_params(void) +{ + TESTING("H5Orefresh with invalid parameters"); + + SKIPPED(); + + return 0; +} + +/* + * H5Ocopy test callback to check that an object's attributes got copied + * over successfully to the new object. + */ +static herr_t +object_copy_attribute_iter_callback(hid_t location_id, const char *attr_name, const H5A_info_t *ainfo, + void *op_data) +{ + size_t *counter = (size_t *)op_data; + htri_t types_equal; + char expected_name[256]; + hid_t attr_id = H5I_INVALID_HID; + hid_t attr_type = H5I_INVALID_HID; + herr_t ret_value = H5_ITER_CONT; + + UNUSED(ainfo); + UNUSED(op_data); + + snprintf(expected_name, 256, "attr%d", (int)(*counter)); + + if (HDstrncmp(attr_name, expected_name, 256)) { + HDprintf(" attribute name '%s' did not match expected name '%s'\n", attr_name, expected_name); + ret_value = H5_ITER_ERROR; + goto done; + } + + if ((attr_id = H5Aopen(location_id, attr_name, H5P_DEFAULT)) < 0) { + HDprintf(" failed to open attribute '%s'\n", attr_name); + ret_value = H5_ITER_ERROR; + goto done; + } + + if ((attr_type = H5Aget_type(attr_id)) < 0) { + HDprintf(" failed to retrieve attribute's datatype\n"); + ret_value = H5_ITER_ERROR; + goto done; + } + + if ((types_equal = H5Tequal(attr_type, H5T_NATIVE_INT)) < 0) { + HDprintf(" failed to determine if attribute's datatype matched what is expected\n"); + ret_value = H5_ITER_ERROR; + goto done; + } + + if (!types_equal) { + HDprintf(" attribute datatype did not match expected H5T_NATIVE_INT\n"); + ret_value = H5_ITER_ERROR; + goto done; + } + +done: + if (attr_type >= 0) + H5Tclose(attr_type); + if (attr_id >= 0) + H5Aclose(attr_id); + + (*counter)++; + + return ret_value; +} + +/* + * H5Ocopy callback to check that a copied group's soft links + * have not been expanded when the default copy options are + * used. + */ +static herr_t +object_copy_soft_link_non_expand_callback(hid_t group, const char *name, const H5L_info2_t *info, + void *op_data) +{ + size_t *counter = (size_t *)op_data; + void *link_val_buf = NULL; + char expected_link_val[OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_BUF_SIZE]; + herr_t ret_value = H5_ITER_CONT; + + /* Make sure the link type is soft */ + if (H5L_TYPE_SOFT != info->type) { + HDprintf(" link type was not H5L_TYPE_SOFT; link must have been expanded!\n"); + ret_value = H5_ITER_ERROR; + goto done; + } + + if (NULL == (link_val_buf = calloc(1, info->u.val_size))) { + HDprintf(" failed to allocate buffer for link value\n"); + ret_value = H5_ITER_ERROR; + goto done; + } + + /* Retrieve the link's value */ + if (H5Lget_val(group, name, link_val_buf, info->u.val_size, H5P_DEFAULT) < 0) { + HDprintf(" failed to retrieve value of link '%s'\n", name); + ret_value = H5_ITER_ERROR; + goto done; + } + + /* Make sure link's value matches what is expected */ + snprintf(expected_link_val, OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_BUF_SIZE, + "/" OBJECT_TEST_GROUP_NAME "/" OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_SUBGROUP_NAME "/grp%d", + (int)(*counter)); + + if (strncmp(link_val_buf, expected_link_val, OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_BUF_SIZE)) { + HDprintf(" value '%s' for link '%s' did not match expected value '%s'\n", (char *)link_val_buf, + name, expected_link_val); + ret_value = H5_ITER_ERROR; + goto done; + } + +done: + if (link_val_buf) + free(link_val_buf); + + (*counter)++; + + return ret_value; +} + +/* + * H5Ocopy callback to check that a copied group's soft links + * have been expanded when the H5O_COPY_EXPAND_SOFT_LINK_FLAG + * flag is specified. + */ +static herr_t +object_copy_soft_link_expand_callback(hid_t group, const char *name, const H5L_info2_t *info, void *op_data) +{ + size_t *counter = (size_t *)op_data; + char expected_link_name[OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_BUF_SIZE]; + herr_t ret_value = H5_ITER_CONT; + + UNUSED(group); + + /* Make sure the link type is hard */ + if (H5L_TYPE_HARD != info->type) { + HDprintf(" link type was not H5L_TYPE_HARD; link must not have been expanded!\n"); + ret_value = H5_ITER_ERROR; + goto done; + } + + /* Ensure that the link's name still follows the 'link1', 'link2', etc. pattern */ + snprintf(expected_link_name, OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_BUF_SIZE, "link%d", (int)(*counter)); + + if (strncmp(name, expected_link_name, OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_BUF_SIZE)) { + HDprintf(" link name '%s' did not match expected name '%s'\n", name, expected_link_name); + ret_value = H5_ITER_ERROR; + goto done; + } + +done: + (*counter)++; + + return ret_value; +} + +/* + * H5Ovisit callback to simply iterate recursively through all of the objects in a + * group and check to make sure their names match what is expected. + */ +static herr_t +object_visit_callback(hid_t o_id, const char *name, const H5O_info2_t *object_info, void *op_data) +{ + size_t *i = (size_t *)op_data; + size_t counter_val = *((size_t *)op_data); + herr_t ret_val = 0; + + UNUSED(o_id); + + if (!HDstrncmp(name, ".", strlen(".") + 1) && + (counter_val == 0 || counter_val == 4 || counter_val == 8 || counter_val == 12)) { + if (H5O_TYPE_GROUP == object_info->type) + goto done; + else + HDprintf(" type for object '%s' was not H5O_TYPE_GROUP\n", name); + } + else if (!HDstrncmp(name, OBJECT_VISIT_TEST_GROUP_NAME, strlen(OBJECT_VISIT_TEST_GROUP_NAME) + 1) && + (counter_val == 2 || counter_val == 6 || counter_val == 9 || counter_val == 15)) { + if (H5O_TYPE_GROUP == object_info->type) + goto done; + else + HDprintf(" type for object '%s' was not H5O_TYPE_GROUP\n", name); + } + else if (!HDstrncmp(name, OBJECT_VISIT_TEST_DSET_NAME, strlen(OBJECT_VISIT_TEST_DSET_NAME) + 1) && + (counter_val == 1 || counter_val == 7 || counter_val == 10 || counter_val == 14)) { + if (H5O_TYPE_DATASET == object_info->type) + goto done; + else + HDprintf(" type for object '%s' was not H5O_TYPE_DATASET\n", name); + } + else if (!HDstrncmp(name, OBJECT_VISIT_TEST_TYPE_NAME, strlen(OBJECT_VISIT_TEST_TYPE_NAME) + 1) && + (counter_val == 3 || counter_val == 5 || counter_val == 11 || counter_val == 13)) { + if (H5O_TYPE_NAMED_DATATYPE == object_info->type) + goto done; + else + HDprintf(" type for object '%s' was not H5O_TYPE_NAMED_DATATYPE\n", name); + } + else + HDprintf(" object '%s' didn't match known names or came in an incorrect order\n", name); + + ret_val = -1; + +done: + (*i)++; + + return ret_val; +} + +/* + * H5Ovisit callback for visiting a singular dataset. + */ +static herr_t +object_visit_dset_callback(hid_t o_id, const char *name, const H5O_info2_t *object_info, void *op_data) +{ + herr_t ret_val = 0; + + UNUSED(o_id); + UNUSED(op_data); + + if (HDstrncmp(name, ".", strlen(".") + 1)) { + HDprintf(" object '%s' didn't match known names\n", name); + return -1; + } + + if (H5O_TYPE_DATASET != object_info->type) { + HDprintf(" object type was not H5O_TYPE_DATASET\n"); + return -1; + } + + return ret_val; +} + +/* + * H5Ovisit callback for visiting a singular committed datatype. + */ +static herr_t +object_visit_dtype_callback(hid_t o_id, const char *name, const H5O_info2_t *object_info, void *op_data) +{ + herr_t ret_val = 0; + + UNUSED(o_id); + UNUSED(op_data); + + if (HDstrncmp(name, ".", strlen(".") + 1)) { + HDprintf(" object '%s' didn't match known names\n", name); + return -1; + } + + if (H5O_TYPE_NAMED_DATATYPE != object_info->type) { + HDprintf(" object type was not H5O_TYPE_NAMED_DATATYPE\n"); + return -1; + } + + return ret_val; +} + +/* + * H5Ovisit callback for testing ignoring of + * soft links during object visiting. + */ +static herr_t +object_visit_soft_link_callback(hid_t o_id, const char *name, const H5O_info2_t *object_info, void *op_data) +{ + size_t *i = (size_t *)op_data; + size_t counter_val = *((size_t *)op_data); + herr_t ret_val = 0; + + UNUSED(o_id); + + if (!HDstrncmp(name, ".", strlen(".") + 1) && (counter_val <= 5)) { + if (H5O_TYPE_GROUP == object_info->type) + goto done; + else + HDprintf(" type for object '%s' was not H5O_TYPE_GROUP\n", name); + } + else + HDprintf(" object '%s' didn't match known names or came in an incorrect order\n", name); + + ret_val = -1; + +done: + (*i)++; + + return ret_val; +} + +/* + * H5Ovisit callback to simply iterate through all of the objects in a given + * group. + */ +static herr_t +object_visit_noop_callback(hid_t o_id, const char *name, const H5O_info2_t *object_info, void *op_data) +{ + UNUSED(o_id); + UNUSED(name); + UNUSED(object_info); + UNUSED(op_data); + + return 0; +} + +/* + * Cleanup temporary test files + */ +static void +cleanup_files(void) +{ + H5Fdelete(OBJECT_COPY_BETWEEN_FILES_TEST_FILE_NAME, H5P_DEFAULT); +} + +int +H5_api_object_test(void) +{ + size_t i; + int nerrors; + + HDprintf("**********************************************\n"); + HDprintf("* *\n"); + HDprintf("* API Object Tests *\n"); + HDprintf("* *\n"); + HDprintf("**********************************************\n\n"); + + for (i = 0, nerrors = 0; i < ARRAY_LENGTH(object_tests); i++) { + nerrors += (*object_tests[i])() ? 1 : 0; + } + + HDprintf("\n"); + + HDprintf("Cleaning up testing files\n"); + cleanup_files(); + + return nerrors; +} diff --git a/test/API/H5_api_object_test.h b/test/API/H5_api_object_test.h new file mode 100644 index 0000000..5470843 --- /dev/null +++ b/test/API/H5_api_object_test.h @@ -0,0 +1,191 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef H5_API_OBJECT_TEST_H +#define H5_API_OBJECT_TEST_H + +#include "H5_api_test.h" + +int H5_api_object_test(void); + +/*********************************************** + * * + * API Object test defines * + * * + ***********************************************/ + +#define OBJECT_OPEN_TEST_SPACE_RANK 2 +#define OBJECT_OPEN_TEST_GROUP_NAME "object_open_test" +#define OBJECT_OPEN_TEST_GRP_NAME "object_open_test_group" +#define OBJECT_OPEN_TEST_DSET_NAME "object_open_test_dset" +#define OBJECT_OPEN_TEST_TYPE_NAME "object_open_test_type" + +#define OBJECT_OPEN_INVALID_PARAMS_TEST_GROUP_NAME "object_open_invalid_params_test" +#define OBJECT_OPEN_INVALID_PARAMS_TEST_GRP_NAME "object_open_invalid_params_test_group" + +#define OBJECT_CLOSE_INVALID_TEST_GROUP_NAME "object_close_invalid_params_test" +#define OBJECT_CLOSE_INVALID_TEST_ATTRIBUTE_NAME "object_close_invalid_test_attribute" +#define OBJECT_CLOSE_INVALID_TEST_SPACE_RANK 2 + +#define OBJECT_EXISTS_TEST_DSET_SPACE_RANK 2 +#define OBJECT_EXISTS_TEST_SUBGROUP_NAME "object_exists_test" +#define OBJECT_EXISTS_TEST_DANGLING_LINK_NAME "object_exists_test_dangling_soft_link" +#define OBJECT_EXISTS_TEST_SOFT_LINK_NAME "object_exists_test_soft_link" +#define OBJECT_EXISTS_TEST_GRP_NAME "object_exists_test_group" +#define OBJECT_EXISTS_TEST_TYPE_NAME "object_exists_test_type" +#define OBJECT_EXISTS_TEST_DSET_NAME "object_exists_test_dset" + +#define OBJECT_EXISTS_INVALID_PARAMS_TEST_SUBGROUP_NAME "object_exists_invalid_params_test" +#define OBJECT_EXISTS_INVALID_PARAMS_TEST_GRP_NAME "object_exists_invalid_params_test_group" + +#define OBJECT_COPY_BASIC_TEST_DEEP_NESTED_GROUP_NAME "deep_nested_group" +#define OBJECT_COPY_BASIC_TEST_NUM_NESTED_OBJS 3 +#define OBJECT_COPY_BASIC_TEST_NEW_GROUP_NAME "copied_group" +#define OBJECT_COPY_BASIC_TEST_NEW_DSET_NAME "copied_dset" +#define OBJECT_COPY_BASIC_TEST_NEW_DTYPE_NAME "copied_dtype" +#define OBJECT_COPY_BASIC_TEST_SUBGROUP_NAME "object_copy_basic_test" +#define OBJECT_COPY_BASIC_TEST_GROUP_NAME "group_to_copy" +#define OBJECT_COPY_BASIC_TEST_DSET_NAME "dset_to_copy" +#define OBJECT_COPY_BASIC_TEST_DTYPE_NAME "dtype_to_copy" +#define OBJECT_COPY_BASIC_TEST_SPACE_RANK 2 +#define OBJECT_COPY_BASIC_TEST_NUM_ATTRS 3 +#define OBJECT_COPY_BASIC_TEST_BUF_SIZE 256 + +#define OBJECT_COPY_ALREADY_EXISTING_TEST_SUBGROUP_NAME "object_copy_existing_objects_test" +#define OBJECT_COPY_ALREADY_EXISTING_TEST_GROUP_NAME "group_to_copy" +#define OBJECT_COPY_ALREADY_EXISTING_TEST_DSET_NAME "dset_to_copy" +#define OBJECT_COPY_ALREADY_EXISTING_TEST_DTYPE_NAME "dtype_to_copy" +#define OBJECT_COPY_ALREADY_EXISTING_TEST_SPACE_RANK 2 + +#define OBJECT_COPY_SHALLOW_TEST_DEEP_NESTED_GROUP_NAME "deep_nested_group" +#define OBJECT_COPY_SHALLOW_TEST_NUM_NESTED_OBJS 3 +#define OBJECT_COPY_SHALLOW_TEST_SUBGROUP_NAME "object_copy_shallow_group_copy_test" +#define OBJECT_COPY_SHALLOW_TEST_NEW_GROUP_NAME "copied_group" +#define OBJECT_COPY_SHALLOW_TEST_GROUP_NAME "group_to_copy" +#define OBJECT_COPY_SHALLOW_TEST_BUF_SIZE 256 + +#define OBJECT_COPY_NO_ATTRS_TEST_SUBGROUP_NAME "object_copy_no_attributes_test" +#define OBJECT_COPY_NO_ATTRS_TEST_NEW_GROUP_NAME "copied_group" +#define OBJECT_COPY_NO_ATTRS_TEST_NEW_DSET_NAME "copied_dset" +#define OBJECT_COPY_NO_ATTRS_TEST_NEW_DTYPE_NAME "copied_dtype" +#define OBJECT_COPY_NO_ATTRS_TEST_GROUP_NAME "group_to_copy" +#define OBJECT_COPY_NO_ATTRS_TEST_DSET_NAME "dset_to_copy" +#define OBJECT_COPY_NO_ATTRS_TEST_DTYPE_NAME "dtype_to_copy" +#define OBJECT_COPY_NO_ATTRS_TEST_SPACE_RANK 2 +#define OBJECT_COPY_NO_ATTRS_TEST_NUM_ATTRS 3 +#define OBJECT_COPY_NO_ATTRS_TEST_BUF_SIZE 256 + +#define OBJECT_COPY_SOFT_LINK_TEST_DEEP_NESTED_GROUP_NAME "deep_nested_group" +#define OBJECT_COPY_SOFT_LINK_TEST_DANGLING_LINK_NAME "dangling_link" +#define OBJECT_COPY_SOFT_LINK_TEST_NUM_NESTED_OBJS 3 +#define OBJECT_COPY_SOFT_LINK_TEST_SUBGROUP_NAME "object_copy_soft_link_test" +#define OBJECT_COPY_SOFT_LINK_TEST_SOFT_LINK_NAME "soft_link_to_group_to_copy" +#define OBJECT_COPY_SOFT_LINK_TEST_NEW_GROUP_NAME "copied_group" +#define OBJECT_COPY_SOFT_LINK_TEST_GROUP_NAME "group_to_copy" +#define OBJECT_COPY_SOFT_LINK_TEST_SPACE_RANK 2 +#define OBJECT_COPY_SOFT_LINK_TEST_NUM_ATTRS 3 +#define OBJECT_COPY_SOFT_LINK_TEST_BUF_SIZE 256 + +#define OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_EXPAND_DANGLING_GROUP_NAME "expanded_dangling_soft_links_group" +#define OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_NON_EXPAND_GROUP_NAME "non_expanded_soft_links_group" +#define OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_EXPAND_GROUP_NAME "expanded_soft_links_group" +#define OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_NUM_NESTED_OBJS 3 +#define OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_SUBGROUP_NAME "object_copy_group_with_soft_links_test" +#define OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_GROUP_NAME "group_to_copy" +#define OBJECT_COPY_GROUP_WITH_SOFT_LINKS_TEST_BUF_SIZE 256 + +#define OBJECT_COPY_BETWEEN_FILES_TEST_DEEP_NESTED_GROUP_NAME "deep_nested_group" +#define OBJECT_COPY_BETWEEN_FILES_TEST_NUM_NESTED_OBJS 3 +#define OBJECT_COPY_BETWEEN_FILES_TEST_SUBGROUP_NAME "object_copy_between_files_test" +#define OBJECT_COPY_BETWEEN_FILES_TEST_NEW_GROUP_NAME "copied_group" +#define OBJECT_COPY_BETWEEN_FILES_TEST_NEW_DSET_NAME "copied_dset" +#define OBJECT_COPY_BETWEEN_FILES_TEST_NEW_DTYPE_NAME "copied_dtype" +#define OBJECT_COPY_BETWEEN_FILES_TEST_FILE_NAME "object_copy_test_file.h5" +#define OBJECT_COPY_BETWEEN_FILES_TEST_GROUP_NAME "group_to_copy" +#define OBJECT_COPY_BETWEEN_FILES_TEST_DSET_NAME "dset_to_copy" +#define OBJECT_COPY_BETWEEN_FILES_TEST_DTYPE_NAME "dtype_to_copy" +#define OBJECT_COPY_BETWEEN_FILES_TEST_SPACE_RANK 2 +#define OBJECT_COPY_BETWEEN_FILES_TEST_NUM_ATTRS 3 +#define OBJECT_COPY_BETWEEN_FILES_TEST_BUF_SIZE 256 + +#define OBJECT_COPY_INVALID_PARAMS_TEST_SUBGROUP_NAME "object_copy_invalid_params_test" +#define OBJECT_COPY_INVALID_PARAMS_TEST_GROUP_NAME "object_copy_invalid_params_group" +#define OBJECT_COPY_INVALID_PARAMS_TEST_GROUP_NAME2 "object_copy_invalid_params_group_copy" + +#define OBJECT_VISIT_TEST_NUM_OBJS_VISITED 4 +#define OBJECT_VISIT_TEST_SUBGROUP_NAME "object_visit_test" +#define OBJECT_VISIT_TEST_SPACE_RANK 2 +#define OBJECT_VISIT_TEST_GROUP_NAME "object_visit_test_group" +#define OBJECT_VISIT_TEST_DSET_NAME "object_visit_test_dset" +#define OBJECT_VISIT_TEST_TYPE_NAME "object_visit_test_type" + +#define OBJECT_VISIT_SOFT_LINK_TEST_NUM_OBJS_VISITED 1 +#define OBJECT_VISIT_SOFT_LINK_TEST_SUBGROUP_NAME "object_visit_soft_link" +#define OBJECT_VISIT_SOFT_LINK_TEST_GROUP_NAME1 "links_group" +#define OBJECT_VISIT_SOFT_LINK_TEST_GROUP_NAME2 "objects_group" +#define OBJECT_VISIT_SOFT_LINK_TEST_LINK_NAME1 "soft_link1" +#define OBJECT_VISIT_SOFT_LINK_TEST_LINK_NAME2 "soft_link2" +#define OBJECT_VISIT_SOFT_LINK_TEST_LINK_NAME3 "soft_link3" +#define OBJECT_VISIT_SOFT_LINK_TEST_OBJ_NAME1 "group1" +#define OBJECT_VISIT_SOFT_LINK_TEST_OBJ_NAME2 "group2" +#define OBJECT_VISIT_SOFT_LINK_TEST_OBJ_NAME3 "group3" + +#define OBJECT_VISIT_DANGLING_LINK_TEST_SUBGROUP_NAME "object_visit_dangling_link_test" +#define OBJECT_VISIT_DANGLING_LINK_TEST_LINK_NAME1 "dangling_link1" +#define OBJECT_VISIT_DANGLING_LINK_TEST_LINK_NAME2 "dangling_link2" +#define OBJECT_VISIT_DANGLING_LINK_TEST_LINK_NAME3 "dangling_link3" + +#define OBJECT_VISIT_INVALID_PARAMS_TEST_SUBGROUP_NAME "object_visit_invalid_params_test" +#define OBJECT_VISIT_INVALID_PARAMS_TEST_GROUP_NAME "object_visit_invalid_params_group" + +#define OBJECT_CLOSE_TEST_SPACE_RANK 2 +#define OBJECT_CLOSE_TEST_GROUP_NAME "object_close_test" +#define OBJECT_CLOSE_TEST_GRP_NAME "object_close_test_group" +#define OBJECT_CLOSE_TEST_DSET_NAME "object_close_test_dset" +#define OBJECT_CLOSE_TEST_TYPE_NAME "object_close_test_type" + +#define OBJECT_LINK_TEST_GROUP_NAME "object_link_test_group" +#define OBJECT_LINK_TEST_GROUP_NAME2 "object_link_test_group_link" +#define OBJECT_LINK_TEST_DSET_NAME "object_link_test_dataset" +#define OBJECT_LINK_TEST_DTYPE_NAME "object_link_test_datatype" +#define OBJECT_LINK_TEST_SPACE_RANK 2 + +#define OBJECT_LINK_INVALID_PARAMS_TEST_GROUP_NAME "object_link_invalid_params_test_group" + +#define OBJ_REF_GET_TYPE_TEST_SUBGROUP_NAME "obj_ref_get_obj_type_test" +#define OBJ_REF_GET_TYPE_TEST_DSET_NAME "ref_dset" +#define OBJ_REF_GET_TYPE_TEST_TYPE_NAME "ref_dtype" +#define OBJ_REF_GET_TYPE_TEST_SPACE_RANK 2 + +#define OBJ_REF_DATASET_WRITE_TEST_SUBGROUP_NAME "obj_ref_write_test" +#define OBJ_REF_DATASET_WRITE_TEST_REF_DSET_NAME "ref_dset" +#define OBJ_REF_DATASET_WRITE_TEST_REF_TYPE_NAME "ref_dtype" +#define OBJ_REF_DATASET_WRITE_TEST_SPACE_RANK 1 +#define OBJ_REF_DATASET_WRITE_TEST_DSET_NAME "obj_ref_dset" + +#define OBJ_REF_DATASET_READ_TEST_SUBGROUP_NAME "obj_ref_read_test" +#define OBJ_REF_DATASET_READ_TEST_REF_DSET_NAME "ref_dset" +#define OBJ_REF_DATASET_READ_TEST_REF_TYPE_NAME "ref_dtype" +#define OBJ_REF_DATASET_READ_TEST_SPACE_RANK 1 +#define OBJ_REF_DATASET_READ_TEST_DSET_NAME "obj_ref_dset" + +#define OBJ_REF_DATASET_EMPTY_WRITE_TEST_SUBGROUP_NAME "obj_ref_empty_write_test" +#define OBJ_REF_DATASET_EMPTY_WRITE_TEST_SPACE_RANK 1 +#define OBJ_REF_DATASET_EMPTY_WRITE_TEST_DSET_NAME "obj_ref_dset" + +#define OBJECT_REF_COUNT_TEST_SUBGROUP_NAME "ref_count_test" +#define OBJECT_REF_COUNT_TEST_GRP_NAME "ref_count_test_group" +#define OBJECT_REF_COUNT_TEST_DSET_NAME "ref_count_dset" +#define OBJECT_REF_COUNT_TEST_TYPE_NAME "ref_count_dtype" +#define OBJECT_REF_COUNT_TEST_DSET_SPACE_RANK 2 + +#endif diff --git a/test/API/H5_api_test.c b/test/API/H5_api_test.c new file mode 100644 index 0000000..6d61b75 --- /dev/null +++ b/test/API/H5_api_test.c @@ -0,0 +1,227 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * A test suite which only makes public HDF5 API calls and which is meant + * to test the native VOL connector or a specified HDF5 VOL connector (or + * set of connectors stacked with each other). This test suite must assume + * that a VOL connector could only implement the File interface. Therefore, + * the suite should check that a particular piece of functionality is supported + * by the VOL connector before actually testing it. If the functionality is + * not supported, the test should simply be skipped, perhaps with a note as + * to why the test was skipped, if possible. + * + * If the VOL connector being used supports the creation of groups, this + * test suite will attempt to organize the output of these various tests + * into groups based on their respective HDF5 interface. + */ + +#include "H5_api_test.h" + +#include "H5_api_attribute_test.h" +#include "H5_api_dataset_test.h" +#include "H5_api_datatype_test.h" +#include "H5_api_file_test.h" +#include "H5_api_group_test.h" +#include "H5_api_link_test.h" +#include "H5_api_misc_test.h" +#include "H5_api_object_test.h" +#include "H5_api_test_util.h" +#ifdef H5_API_TEST_HAVE_ASYNC +#include "H5_api_async_test.h" +#endif + +char H5_api_test_filename[H5_API_TEST_FILENAME_MAX_LENGTH]; + +const char *test_path_prefix; + +/* X-macro to define the following for each test: + * - enum type + * - name + * - test function + * - enabled by default + */ +#ifdef H5_API_TEST_HAVE_ASYNC +#define H5_API_TESTS \ + X(H5_API_TEST_NULL, "", NULL, 0) \ + X(H5_API_TEST_FILE, "file", H5_api_file_test, 1) \ + X(H5_API_TEST_GROUP, "group", H5_api_group_test, 1) \ + X(H5_API_TEST_DATASET, "dataset", H5_api_dataset_test, 1) \ + X(H5_API_TEST_DATATYPE, "datatype", H5_api_datatype_test, 1) \ + X(H5_API_TEST_ATTRIBUTE, "attribute", H5_api_attribute_test, 1) \ + X(H5_API_TEST_LINK, "link", H5_api_link_test, 1) \ + X(H5_API_TEST_OBJECT, "object", H5_api_object_test, 1) \ + X(H5_API_TEST_MISC, "misc", H5_api_misc_test, 1) \ + X(H5_API_TEST_ASYNC, "async", H5_api_async_test, 1) \ + X(H5_API_TEST_MAX, "", NULL, 0) +#else +#define H5_API_TESTS \ + X(H5_API_TEST_NULL, "", NULL, 0) \ + X(H5_API_TEST_FILE, "file", H5_api_file_test, 1) \ + X(H5_API_TEST_GROUP, "group", H5_api_group_test, 1) \ + X(H5_API_TEST_DATASET, "dataset", H5_api_dataset_test, 1) \ + X(H5_API_TEST_DATATYPE, "datatype", H5_api_datatype_test, 1) \ + X(H5_API_TEST_ATTRIBUTE, "attribute", H5_api_attribute_test, 1) \ + X(H5_API_TEST_LINK, "link", H5_api_link_test, 1) \ + X(H5_API_TEST_OBJECT, "object", H5_api_object_test, 1) \ + X(H5_API_TEST_MISC, "misc", H5_api_misc_test, 1) \ + X(H5_API_TEST_MAX, "", NULL, 0) +#endif + +#define X(a, b, c, d) a, +enum H5_api_test_type { H5_API_TESTS }; +#undef X +#define X(a, b, c, d) b, +static const char *const H5_api_test_name[] = {H5_API_TESTS}; +#undef X +#define X(a, b, c, d) c, +static int (*H5_api_test_func[])(void) = {H5_API_TESTS}; +#undef X +#define X(a, b, c, d) d, +static int H5_api_test_enabled[] = {H5_API_TESTS}; +#undef X + +static enum H5_api_test_type +H5_api_test_name_to_type(const char *test_name) +{ + enum H5_api_test_type i = 0; + + while (strcmp(H5_api_test_name[i], test_name) && i != H5_API_TEST_MAX) + i++; + + return ((i == H5_API_TEST_MAX) ? H5_API_TEST_NULL : i); +} + +static void +H5_api_test_run(void) +{ + enum H5_api_test_type i; + + for (i = H5_API_TEST_FILE; i < H5_API_TEST_MAX; i++) + if (H5_api_test_enabled[i]) + (void)H5_api_test_func[i](); +} + +/******************************************************************************/ + +int +main(int argc, char **argv) +{ + const char *vol_connector_name; + unsigned seed; + hid_t fapl_id = H5I_INVALID_HID; + hbool_t err_occurred = FALSE; + + /* Simple argument checking, TODO can improve that later */ + if (argc > 1) { + enum H5_api_test_type i = H5_api_test_name_to_type(argv[1]); + if (i != H5_API_TEST_NULL) { + /* Run only specific API test */ + memset(H5_api_test_enabled, 0, sizeof(H5_api_test_enabled)); + H5_api_test_enabled[i] = 1; + } + } + +#ifdef H5_HAVE_PARALLEL + /* If HDF5 was built with parallel enabled, go ahead and call MPI_Init before + * running these tests. Even though these are meant to be serial tests, they will + * likely be run using mpirun (or similar) and we cannot necessarily expect HDF5 or + * an HDF5 VOL connector to call MPI_Init. + */ + MPI_Init(&argc, &argv); +#endif + + /* h5_reset(); */ + + n_tests_run_g = 0; + n_tests_passed_g = 0; + n_tests_failed_g = 0; + n_tests_skipped_g = 0; + + seed = (unsigned)HDtime(NULL); + srand(seed); + + if (NULL == (test_path_prefix = HDgetenv(HDF5_API_TEST_PATH_PREFIX))) + test_path_prefix = ""; + + HDsnprintf(H5_api_test_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s%s", test_path_prefix, + TEST_FILE_NAME); + + if (NULL == (vol_connector_name = HDgetenv(HDF5_VOL_CONNECTOR))) { + HDprintf("No VOL connector selected; using native VOL connector\n"); + vol_connector_name = "native"; + } + + HDprintf("Running API tests with VOL connector '%s'\n\n", vol_connector_name); + HDprintf("Test parameters:\n"); + HDprintf(" - Test file name: '%s'\n", H5_api_test_filename); + HDprintf(" - Test seed: %u\n", seed); + HDprintf("\n\n"); + + /* Retrieve the VOL cap flags - work around an HDF5 + * library issue by creating a FAPL + */ + if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) { + HDfprintf(stderr, "Unable to create FAPL\n"); + err_occurred = TRUE; + goto done; + } + + vol_cap_flags_g = H5VL_CAP_FLAG_NONE; + if (H5Pget_vol_cap_flags(fapl_id, &vol_cap_flags_g) < 0) { + HDfprintf(stderr, "Unable to retrieve VOL connector capability flags\n"); + err_occurred = TRUE; + goto done; + } + + /* + * Create the file that will be used for all of the tests, + * except for those which test file creation. + */ + if (create_test_container(H5_api_test_filename, vol_cap_flags_g) < 0) { + HDfprintf(stderr, "Unable to create testing container file '%s'\n", H5_api_test_filename); + err_occurred = TRUE; + goto done; + } + + /* Run all the tests that are enabled */ + H5_api_test_run(); + + HDprintf("Cleaning up testing files\n"); + H5Fdelete(H5_api_test_filename, fapl_id); + + if (n_tests_run_g > 0) { + HDprintf("%zu/%zu (%.2f%%) API tests passed with VOL connector '%s'\n", n_tests_passed_g, + n_tests_run_g, ((double)n_tests_passed_g / (double)n_tests_run_g * 100.0), + vol_connector_name); + HDprintf("%zu/%zu (%.2f%%) API tests did not pass with VOL connector '%s'\n", n_tests_failed_g, + n_tests_run_g, ((double)n_tests_failed_g / (double)n_tests_run_g * 100.0), + vol_connector_name); + HDprintf("%zu/%zu (%.2f%%) API tests were skipped with VOL connector '%s'\n", n_tests_skipped_g, + n_tests_run_g, ((double)n_tests_skipped_g / (double)n_tests_run_g * 100.0), + vol_connector_name); + } + +done: + if (fapl_id >= 0 && H5Pclose(fapl_id) < 0) { + HDfprintf(stderr, "Unable to close FAPL\n"); + err_occurred = TRUE; + } + + H5close(); + +#ifdef H5_HAVE_PARALLEL + MPI_Finalize(); +#endif + + HDexit(((err_occurred || n_tests_failed_g > 0) ? EXIT_FAILURE : EXIT_SUCCESS)); +} diff --git a/test/API/H5_api_test.h b/test/API/H5_api_test.h new file mode 100644 index 0000000..296d296 --- /dev/null +++ b/test/API/H5_api_test.h @@ -0,0 +1,73 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef H5_API_TEST_H +#define H5_API_TEST_H + +#include +#include + +#include "h5test.h" + +#include "H5_api_test_config.h" +#include "H5_api_test_util.h" +#include "H5_api_tests_disabled.h" + +/* Define H5VL_VERSION if not already defined */ +#ifndef H5VL_VERSION +#define H5VL_VERSION 0 +#endif + +/* Define macro to wait forever depending on version */ +#if H5VL_VERSION >= 2 +#define H5_API_TEST_WAIT_FOREVER H5ES_WAIT_FOREVER +#else +#define H5_API_TEST_WAIT_FOREVER UINT64_MAX +#endif + +/******************************************************************************/ + +/* The name of the file that all of the tests will operate on */ +#define TEST_FILE_NAME "H5_api_test.h5" +extern char H5_api_test_filename[]; + +extern const char *test_path_prefix; + +/* + * Environment variable specifying a prefix string to add to + * filenames generated by the API tests + */ +#define HDF5_API_TEST_PATH_PREFIX "HDF5_API_TEST_PATH_PREFIX" + +/* The names of a set of container groups which hold objects + * created by each of the different types of tests. + */ +#define GROUP_TEST_GROUP_NAME "group_tests" +#define ATTRIBUTE_TEST_GROUP_NAME "attribute_tests" +#define DATASET_TEST_GROUP_NAME "dataset_tests" +#define DATATYPE_TEST_GROUP_NAME "datatype_tests" +#define LINK_TEST_GROUP_NAME "link_tests" +#define OBJECT_TEST_GROUP_NAME "object_tests" +#define MISCELLANEOUS_TEST_GROUP_NAME "miscellaneous_tests" + +#define ARRAY_LENGTH(array) sizeof(array) / sizeof(array[0]) + +#define UNUSED(o) (void)(o); + +#define H5_API_TEST_FILENAME_MAX_LENGTH 1024 + +/* The maximum size of a dimension in an HDF5 dataspace as allowed + * for this testing suite so as not to try to create too large + * of a dataspace/datatype. */ +#define MAX_DIM_SIZE 16 + +#endif diff --git a/test/API/H5_api_test_config.h.in b/test/API/H5_api_test_config.h.in new file mode 100644 index 0000000..c1833fa --- /dev/null +++ b/test/API/H5_api_test_config.h.in @@ -0,0 +1,66 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef H5_API_TEST_CONFIG_H +#define H5_API_TEST_CONFIG_H + +#include "hdf5.h" + +#cmakedefine H5_API_TEST_HAVE_ASYNC + +#ifdef H5_HAVE_PARALLEL +#cmakedefine MPIEXEC_EXECUTABLE "@MPIEXEC_EXECUTABLE@" +#cmakedefine MPIEXEC "@MPIEXEC@" /* For compatibility */ +#ifndef MPIEXEC_EXECUTABLE +# define MPIEXEC_EXECUTABLE MPIEXEC +#endif +#cmakedefine MPIEXEC_NUMPROC_FLAG "@MPIEXEC_NUMPROC_FLAG@" +#cmakedefine MPIEXEC_PREFLAGS "@MPIEXEC_PREFLAGS@" +#cmakedefine MPIEXEC_POSTFLAGS "@MPIEXEC_POSTFLAGS@" +/* Server-specific flags if different */ +#cmakedefine MPIEXEC_SERVER_PREFLAGS "@MPIEXEC_SERVER_PREFLAGS@" +#cmakedefine MPIEXEC_SERVER_POSTFLAGS "@MPIEXEC_SERVER_POSTFLAGS@" +#cmakedefine MPIEXEC_MAX_NUMPROCS @MPIEXEC_MAX_NUMPROCS@ +#endif /* H5_HAVE_PARALLEL */ + +#cmakedefine DART_TESTING_TIMEOUT @DART_TESTING_TIMEOUT@ +#ifndef DART_TESTING_TIMEOUT +# define DART_TESTING_TIMEOUT 1500 +#endif + +#cmakedefine H5_API_TEST_ENV_VARS "@H5_API_TEST_ENV_VARS@" + +#cmakedefine H5_API_TEST_INIT_COMMAND "@H5_API_TEST_INIT_COMMAND@" + +#cmakedefine H5_API_TEST_SERVER_START_MSG "@H5_API_TEST_SERVER_START_MSG@" +#ifndef H5_API_TEST_SERVER_START_MSG +# define H5_API_TEST_SERVER_START_MSG "Waiting" +#endif +#cmakedefine H5_API_TEST_SERVER_EXIT_COMMAND "@H5_API_TEST_SERVER_EXIT_COMMAND@" + +#cmakedefine H5_API_TEST_CLIENT_HELPER_START_MSG "@H5_API_TEST_CLIENT_HELPER_START_MSG@" +#ifndef H5_API_TEST_CLIENT_HELPER_START_MSG +# define H5_API_TEST_CLIENT_HELPER_START_MSG "Waiting" +#endif +#cmakedefine H5_API_TEST_CLIENT_HELPER_EXIT_COMMAND "@H5_API_TEST_CLIENT_HELPER_EXIT_COMMAND@" + +#cmakedefine H5_API_TEST_CLIENT_INIT_TOKEN_REGEX "@H5_API_TEST_CLIENT_INIT_TOKEN_REGEX@" +#ifndef H5_API_TEST_CLIENT_INIT_TOKEN_REGEX +# define H5_API_TEST_CLIENT_INIT_TOKEN_REGEX "^token" +#endif +#cmakedefine H5_API_TEST_CLIENT_INIT_TOKEN_VAR "@H5_API_TEST_CLIENT_INIT_TOKEN_VAR@" +#ifndef H5_API_TEST_CLIENT_INIT_TOKEN_VAR +# define H5_API_TEST_CLIENT_INIT_TOKEN_VAR "TOKEN" +#endif + + +#endif /* H5_API_TEST_CONFIG_H */ diff --git a/test/API/H5_api_test_util.c b/test/API/H5_api_test_util.c new file mode 100644 index 0000000..7fec2b6 --- /dev/null +++ b/test/API/H5_api_test_util.c @@ -0,0 +1,819 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "H5_api_test.h" +#include "H5_api_test_util.h" + +/* + * The maximum allowable size of a generated datatype. + * + * NOTE: HDF5 currently has limits on the maximum size of + * a datatype of an object, as this information is stored + * in the object header. In order to provide maximum + * compatibility between the native VOL connector and others + * for this test suite, we limit the size of a datatype here. + * This value should be adjusted as future HDF5 development + * allows. + */ +#define GENERATED_DATATYPE_MAX_SIZE 65536 + +/* + * The maximum size of a datatype for compact objects that + * must fit within the size of a native HDF5 object header message. + * This is typically used for attributes and compact datasets. + */ +#define COMPACT_DATATYPE_MAX_SIZE 1024 + +/* The maximum level of recursion that the generate_random_datatype() + * function should go down to, before being forced to choose a base type + * in order to not cause a stack overflow. + */ +#define TYPE_GEN_RECURSION_MAX_DEPTH 3 + +/* The maximum number of members allowed in an HDF5 compound type, as + * generated by the generate_random_datatype() function, for ease of + * development. + */ +#define COMPOUND_TYPE_MAX_MEMBERS 4 + +/* The maximum number and size of the dimensions of an HDF5 array + * datatype, as generated by the generate_random_datatype() function. + */ +#define ARRAY_TYPE_MAX_DIMS 4 + +/* The maximum number of members and the maximum size of those + * members' names for an HDF5 enum type, as generated by the + * generate_random_datatype() function. + */ +#define ENUM_TYPE_MAX_MEMBER_NAME_LENGTH 256 +#define ENUM_TYPE_MAX_MEMBERS 16 + +/* The maximum size of an HDF5 string datatype, as created by the + * generate_random_datatype() function. + */ +#define STRING_TYPE_MAX_SIZE 1024 + +/* + * The maximum dimensionality and dimension size of a dataspace + * generated for an attribute or compact dataset. + */ +#define COMPACT_SPACE_MAX_DIM_SIZE 4 +#define COMPACT_SPACE_MAX_DIMS 3 + +/* + * Helper function to generate a random HDF5 datatype in order to thoroughly + * test support for datatypes. The parent_class parameter is to support + * recursive generation of datatypes. In most cases, this function should be + * called with H5T_NO_CLASS for the parent_class parameter. + */ +/* + * XXX: limit size of datatype generated + */ +hid_t +generate_random_datatype(H5T_class_t parent_class, hbool_t is_compact) +{ + static int depth = 0; + hsize_t *array_dims = NULL; + size_t i; + hid_t compound_members[COMPOUND_TYPE_MAX_MEMBERS]; + hid_t datatype = H5I_INVALID_HID; + + depth++; + + for (i = 0; i < COMPOUND_TYPE_MAX_MEMBERS; i++) + compound_members[i] = H5I_INVALID_HID; + + switch (rand() % H5T_NCLASSES) { +case_integer: + case H5T_INTEGER: { + switch (rand() % 16) { + case 0: + if ((datatype = H5Tcopy(H5T_STD_I8BE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't copy predefined integer type\n"); + goto done; + } + + break; + + case 1: + if ((datatype = H5Tcopy(H5T_STD_I8LE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't copy predefined integer type\n"); + goto done; + } + + break; + + case 2: + if ((datatype = H5Tcopy(H5T_STD_I16BE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't copy predefined integer type\n"); + goto done; + } + + break; + + case 3: + if ((datatype = H5Tcopy(H5T_STD_I16LE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't copy predefined integer type\n"); + goto done; + } + + break; + + case 4: + if ((datatype = H5Tcopy(H5T_STD_I32BE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't copy predefined integer type\n"); + goto done; + } + + break; + + case 5: + if ((datatype = H5Tcopy(H5T_STD_I32LE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't copy predefined integer type\n"); + goto done; + } + + break; + + case 6: + if ((datatype = H5Tcopy(H5T_STD_I64BE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't copy predefined integer type\n"); + goto done; + } + + break; + + case 7: + if ((datatype = H5Tcopy(H5T_STD_I64LE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't copy predefined integer type\n"); + goto done; + } + + break; + + case 8: + if ((datatype = H5Tcopy(H5T_STD_U8BE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't copy predefined integer type\n"); + goto done; + } + + break; + + case 9: + if ((datatype = H5Tcopy(H5T_STD_U8LE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't copy predefined integer type\n"); + goto done; + } + + break; + + case 10: + if ((datatype = H5Tcopy(H5T_STD_U16BE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't copy predefined integer type\n"); + goto done; + } + + break; + + case 11: + if ((datatype = H5Tcopy(H5T_STD_U16LE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't copy predefined integer type\n"); + goto done; + } + + break; + + case 12: + if ((datatype = H5Tcopy(H5T_STD_U32BE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't copy predefined integer type\n"); + goto done; + } + + break; + + case 13: + if ((datatype = H5Tcopy(H5T_STD_U32LE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't copy predefined integer type\n"); + goto done; + } + + break; + + case 14: + if ((datatype = H5Tcopy(H5T_STD_U64BE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't copy predefined integer type\n"); + goto done; + } + + break; + + case 15: + if ((datatype = H5Tcopy(H5T_STD_U64LE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't copy predefined integer type\n"); + goto done; + } + + break; + + default: + H5_FAILED(); + HDprintf(" invalid value for predefined integer type; should not happen\n"); + goto done; + } + + break; + } + +case_float: + case H5T_FLOAT: { + switch (rand() % 4) { + case 0: + if ((datatype = H5Tcopy(H5T_IEEE_F32BE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't copy predefined floating-point type\n"); + goto done; + } + + break; + + case 1: + if ((datatype = H5Tcopy(H5T_IEEE_F32LE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't copy predefined floating-point type\n"); + goto done; + } + + break; + + case 2: + if ((datatype = H5Tcopy(H5T_IEEE_F64BE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't copy predefined floating-point type\n"); + goto done; + } + + break; + + case 3: + if ((datatype = H5Tcopy(H5T_IEEE_F64LE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't copy predefined floating-point type\n"); + goto done; + } + + break; + + default: + H5_FAILED(); + HDprintf(" invalid value for floating point type; should not happen\n"); + goto done; + } + + break; + } + +case_time: + case H5T_TIME: { + /* Time datatype is unsupported, try again */ + goto reroll; + break; + } + +case_string: + case H5T_STRING: { + /* Note: currently only H5T_CSET_ASCII is supported for the character set and + * only H5T_STR_NULLTERM is supported for string padding for variable-length + * strings and only H5T_STR_NULLPAD is supported for string padding for + * fixed-length strings, but these may change in the future. + */ + if (0 == (rand() % 2)) { + if ((datatype = H5Tcreate(H5T_STRING, (size_t)(rand() % STRING_TYPE_MAX_SIZE) + 1)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create fixed-length string datatype\n"); + goto done; + } + + if (H5Tset_strpad(datatype, H5T_STR_NULLPAD) < 0) { + H5_FAILED(); + HDprintf(" couldn't set H5T_STR_NULLPAD for fixed-length string type\n"); + goto done; + } + } + else { + /* + * Currently, all VL datatypes are disabled. + */ + goto reroll; + +#if 0 + if ((datatype = H5Tcreate(H5T_STRING, H5T_VARIABLE)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create variable-length string datatype\n"); + goto done; + } + + if (H5Tset_strpad(datatype, H5T_STR_NULLTERM) < 0) { + H5_FAILED(); + HDprintf(" couldn't set H5T_STR_NULLTERM for variable-length string type\n"); + goto done; + } +#endif + } + + if (H5Tset_cset(datatype, H5T_CSET_ASCII) < 0) { + H5_FAILED(); + HDprintf(" couldn't set string datatype character set\n"); + goto done; + } + + break; + } + +case_bitfield: + case H5T_BITFIELD: { + /* Bitfield datatype is unsupported, try again */ + goto reroll; + break; + } + +case_opaque: + case H5T_OPAQUE: { + /* Opaque datatype is unsupported, try again */ + goto reroll; + break; + } + +case_compound: + case H5T_COMPOUND: { + size_t num_members; + size_t next_offset = 0; + size_t compound_size = 0; + + /* Currently only allows arrays of integer, float or string. Pick another type if we + * are creating an array of something other than these. Also don't allow recursion + * to go too deep. Pick another type that doesn't recursively call this function. */ + if (H5T_ARRAY == parent_class || depth > TYPE_GEN_RECURSION_MAX_DEPTH) + goto reroll; + + if ((datatype = H5Tcreate(H5T_COMPOUND, 1)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create compound datatype\n"); + goto done; + } + + num_members = (size_t)(rand() % COMPOUND_TYPE_MAX_MEMBERS + 1); + + for (i = 0; i < num_members; i++) { + size_t member_size; + char member_name[256]; + + HDsnprintf(member_name, 256, "compound_member%zu", i); + + if ((compound_members[i] = generate_random_datatype(H5T_NO_CLASS, is_compact)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create compound datatype member %zu\n", i); + goto done; + } + + if (!(member_size = H5Tget_size(compound_members[i]))) { + H5_FAILED(); + HDprintf(" couldn't get compound member %zu size\n", i); + goto done; + } + + compound_size += member_size; + + if (H5Tset_size(datatype, compound_size) < 0) { + H5_FAILED(); + HDprintf(" couldn't set size for compound datatype\n"); + goto done; + } + + if (H5Tinsert(datatype, member_name, next_offset, compound_members[i]) < 0) { + H5_FAILED(); + HDprintf(" couldn't insert compound datatype member %zu\n", i); + goto done; + } + + next_offset += member_size; + } + + break; + } + +case_reference: + case H5T_REFERENCE: { + /* Temporarily disable generation of reference datatypes */ + goto reroll; + + /* Currently only allows arrays of integer, float or string. Pick another type if we + * are creating an array of something other than these. */ + if (H5T_ARRAY == parent_class) + goto reroll; + + if (0 == (rand() % 2)) { + if ((datatype = H5Tcopy(H5T_STD_REF_OBJ)) < 0) { + H5_FAILED(); + HDprintf(" couldn't copy object reference datatype\n"); + goto done; + } + } + else { + /* Region references are currently unsupported */ + goto reroll; + + if ((datatype = H5Tcopy(H5T_STD_REF_DSETREG)) < 0) { + H5_FAILED(); + HDprintf(" couldn't copy region reference datatype\n"); + goto done; + } + } + + break; + } + +case_enum: + case H5T_ENUM: { + /* Currently doesn't currently support ARRAY of ENUM, so try another type + * if this happens. */ + if (H5T_ARRAY == parent_class) + goto reroll; + + if ((datatype = H5Tenum_create(H5T_NATIVE_INT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create enum datatype\n"); + goto done; + } + + for (i = 0; i < (size_t)(rand() % ENUM_TYPE_MAX_MEMBERS + 1); i++) { + char name[ENUM_TYPE_MAX_MEMBER_NAME_LENGTH]; + int value = rand(); + + HDsnprintf(name, ENUM_TYPE_MAX_MEMBER_NAME_LENGTH, "enum_val%zu", i); + + if (H5Tenum_insert(datatype, name, &value) < 0) { + H5_FAILED(); + HDprintf(" couldn't insert member into enum datatype\n"); + goto done; + } + } + + break; + } + +case_vlen: + case H5T_VLEN: { + /* Variable-length datatypes are unsupported, try again */ + goto reroll; + break; + } + +case_array: + case H5T_ARRAY: { + unsigned ndims; + hid_t base_datatype = H5I_INVALID_HID; + + /* Currently doesn't currently support ARRAY of ARRAY, so try another type + * if this happens. Also check for too much recursion. */ + if (H5T_ARRAY == parent_class || depth > TYPE_GEN_RECURSION_MAX_DEPTH) + goto reroll; + + ndims = (unsigned)(rand() % ARRAY_TYPE_MAX_DIMS + 1); + + if (NULL == (array_dims = (hsize_t *)HDmalloc(ndims * sizeof(*array_dims)))) + goto done; + + for (i = 0; i < ndims; i++) + array_dims[i] = (hsize_t)(rand() % MAX_DIM_SIZE + 1); + + if ((base_datatype = generate_random_datatype(H5T_ARRAY, is_compact)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create array base datatype\n"); + goto done; + } + + if ((datatype = H5Tarray_create2(base_datatype, ndims, array_dims)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create array datatype\n"); + goto done; + } + + break; + } + + default: + H5_FAILED(); + HDprintf(" invalid datatype class\n"); + break; + } /* end if */ + +done: + if (depth > 0) + depth--; + + if (datatype < 0) { + for (i = 0; i < COMPOUND_TYPE_MAX_MEMBERS; i++) { + if (compound_members[i] > 0 && H5Tclose(compound_members[i]) < 0) { + H5_FAILED(); + HDprintf(" couldn't close compound member %zu\n", i); + } + } + } + + if (array_dims) { + HDfree(array_dims); + array_dims = NULL; + } + + if (is_compact && (depth == 0)) { + size_t type_size; + + /* + * Check to make sure that the generated datatype does + * not exceed the maximum compact datatype size if a + * compact datatype was requested. + */ + if (0 == (type_size = H5Tget_size(datatype))) { + H5_FAILED(); + HDprintf(" failed to retrieve datatype's size\n"); + H5Tclose(datatype); + datatype = H5I_INVALID_HID; + } + else { + if (type_size > COMPACT_DATATYPE_MAX_SIZE) { + /* + * Generate a new datatype. + */ + H5Tclose(datatype); + datatype = H5I_INVALID_HID; + goto reroll; + } + } + } + + return datatype; + +reroll: + if (depth > 0) + depth--; + + /* + * The datatype generation resulted in a datatype that is currently invalid + * for these tests, try again. + */ + switch (rand() % H5T_NCLASSES) { + case H5T_INTEGER: + goto case_integer; + case H5T_FLOAT: + goto case_float; + case H5T_TIME: + goto case_time; + case H5T_STRING: + goto case_string; + case H5T_BITFIELD: + goto case_bitfield; + case H5T_OPAQUE: + goto case_opaque; + case H5T_COMPOUND: + goto case_compound; + case H5T_REFERENCE: + goto case_reference; + case H5T_ENUM: + goto case_enum; + case H5T_VLEN: + goto case_vlen; + case H5T_ARRAY: + goto case_array; + default: + H5_FAILED(); + HDprintf(" invalid value for goto\n"); + break; + } + + return H5I_INVALID_HID; +} + +/* + * Helper function to generate a random HDF5 dataspace in order to thoroughly + * test support for dataspaces. + */ +hid_t +generate_random_dataspace(int rank, const hsize_t *max_dims, hsize_t *dims_out, hbool_t is_compact) +{ + hsize_t dataspace_dims[H5S_MAX_RANK]; + size_t i; + hid_t dataspace_id = H5I_INVALID_HID; + + if (rank < 0) + TEST_ERROR; + if (is_compact && (rank > COMPACT_SPACE_MAX_DIMS)) { + HDprintf(" current rank of compact dataspace (%lld) exceeds maximum dimensionality (%lld)\n", + (long long)rank, (long long)COMPACT_SPACE_MAX_DIMS); + TEST_ERROR; + } + + /* + * XXX: if max_dims is specified, make sure that the dimensions generated + * are not larger than this. + */ + for (i = 0; i < (size_t)rank; i++) { + if (is_compact) + dataspace_dims[i] = (hsize_t)(rand() % COMPACT_SPACE_MAX_DIM_SIZE + 1); + else + dataspace_dims[i] = (hsize_t)(rand() % MAX_DIM_SIZE + 1); + + if (dims_out) + dims_out[i] = dataspace_dims[i]; + } + + if ((dataspace_id = H5Screate_simple(rank, dataspace_dims, max_dims)) < 0) + TEST_ERROR; + + return dataspace_id; + +error: + return H5I_INVALID_HID; +} + +int +create_test_container(char *filename, uint64_t vol_cap_flags) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + + if (!(vol_cap_flags & H5VL_CAP_FLAG_FILE_BASIC)) { + HDprintf(" VOL connector doesn't support file creation\n"); + goto error; + } + + if ((file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + HDprintf(" couldn't create testing container file '%s'\n", filename); + goto error; + } + + if (vol_cap_flags & H5VL_CAP_FLAG_GROUP_BASIC) { + /* Create container groups for each of the test interfaces + * (group, attribute, dataset, etc.). + */ + if ((group_id = H5Gcreate2(file_id, GROUP_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) >= + 0) { + HDprintf(" created container group for Group tests\n"); + H5Gclose(group_id); + } + + if ((group_id = H5Gcreate2(file_id, ATTRIBUTE_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) >= 0) { + HDprintf(" created container group for Attribute tests\n"); + H5Gclose(group_id); + } + + if ((group_id = + H5Gcreate2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) >= 0) { + HDprintf(" created container group for Dataset tests\n"); + H5Gclose(group_id); + } + + if ((group_id = + H5Gcreate2(file_id, DATATYPE_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) >= 0) { + HDprintf(" created container group for Datatype tests\n"); + H5Gclose(group_id); + } + + if ((group_id = H5Gcreate2(file_id, LINK_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) >= + 0) { + HDprintf(" created container group for Link tests\n"); + H5Gclose(group_id); + } + + if ((group_id = H5Gcreate2(file_id, OBJECT_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) >= + 0) { + HDprintf(" created container group for Object tests\n"); + H5Gclose(group_id); + } + + if ((group_id = H5Gcreate2(file_id, MISCELLANEOUS_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) >= 0) { + HDprintf(" created container group for Miscellaneous tests\n"); + H5Gclose(group_id); + } + } + + if (H5Fclose(file_id) < 0) { + HDprintf(" failed to close testing container\n"); + goto error; + } + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(group_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return -1; +} + +/* + * Add a prefix to the given filename. The caller + * is responsible for freeing the returned filename + * pointer with HDfree(). + */ +herr_t +prefix_filename(const char *prefix, const char *filename, char **filename_out) +{ + char *out_buf = NULL; + herr_t ret_value = SUCCEED; + + if (!prefix) { + HDprintf(" invalid file prefix\n"); + ret_value = FAIL; + goto done; + } + if (!filename || (*filename == '\0')) { + HDprintf(" invalid filename\n"); + ret_value = FAIL; + goto done; + } + if (!filename_out) { + HDprintf(" invalid filename_out buffer\n"); + ret_value = FAIL; + goto done; + } + + if (NULL == (out_buf = HDmalloc(H5_API_TEST_FILENAME_MAX_LENGTH))) { + HDprintf(" couldn't allocated filename buffer\n"); + ret_value = FAIL; + goto done; + } + + HDsnprintf(out_buf, H5_API_TEST_FILENAME_MAX_LENGTH, "%s%s", prefix, filename); + + *filename_out = out_buf; + +done: + return ret_value; +} + +/* + * Calls H5Fdelete on the given filename. If a prefix string + * is given, adds that prefix string to the filename before + * calling H5Fdelete + */ +herr_t +remove_test_file(const char *prefix, const char *filename) +{ + const char *test_file; + char *prefixed_filename = NULL; + herr_t ret_value = SUCCEED; + + if (prefix) { + if (prefix_filename(prefix, filename, &prefixed_filename) < 0) { + HDprintf(" couldn't prefix filename\n"); + ret_value = FAIL; + goto done; + } + + test_file = prefixed_filename; + } + else + test_file = filename; + + if (H5Fdelete(test_file, H5P_DEFAULT) < 0) { + HDprintf(" couldn't remove file '%s'\n", test_file); + ret_value = FAIL; + goto done; + } + +done: + HDfree(prefixed_filename); + + return ret_value; +} diff --git a/test/API/H5_api_test_util.h b/test/API/H5_api_test_util.h new file mode 100644 index 0000000..86b0e3e --- /dev/null +++ b/test/API/H5_api_test_util.h @@ -0,0 +1,24 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef H5_API_TEST_UTIL_H_ +#define H5_API_TEST_UTIL_H_ + +#include "hdf5.h" + +hid_t generate_random_datatype(H5T_class_t parent_class, hbool_t is_compact); +hid_t generate_random_dataspace(int rank, const hsize_t *max_dims, hsize_t *dims_out, hbool_t is_compact); +int create_test_container(char *filename, uint64_t vol_cap_flags); +herr_t prefix_filename(const char *prefix, const char *filename, char **filename_out); +herr_t remove_test_file(const char *prefix, const char *filename); + +#endif /* H5_API_TEST_UTIL_H_ */ diff --git a/test/API/H5_api_tests_disabled.h b/test/API/H5_api_tests_disabled.h new file mode 100644 index 0000000..672d2d9 --- /dev/null +++ b/test/API/H5_api_tests_disabled.h @@ -0,0 +1,46 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef H5_API_TESTS_DISABLED_H +#define H5_API_TESTS_DISABLED_H + +#include "H5_api_test_config.h" + +/* Contains #defines to temporarily disable API tests based + * on problematic or unsupported functionality */ + +#define NO_LARGE_TESTS +#define NO_ATTR_FILL_VALUE_SUPPORT +#define NO_DECREASING_ALPHA_ITER_ORDER +#define NO_USER_DEFINED_LINKS +#define NO_EXTERNAL_LINKS +#define NO_ITERATION_RESTART +#define NO_FILE_MOUNTS +#define NO_CLEAR_ON_SHRINK +#define NO_DOUBLE_OBJECT_OPENS +#define NO_OBJECT_GET_NAME +#define WRONG_DATATYPE_OBJ_COUNT +#define NO_SHARED_DATATYPES +#define NO_INVALID_PROPERTY_LIST_TESTS +#define NO_MAX_LINK_CRT_ORDER_RESET +#define NO_PREVENT_HARD_LINKS_ACROSS_FILES +#define NO_SOFT_LINK_MANY_DANGLING +#define NO_ID_PREVENTS_OBJ_DELETE +#define NO_WRITE_SAME_ELEMENT_TWICE +#define NO_PREVENT_CREATE_SAME_ATTRIBUTE_TWICE +#define NO_DELETE_NONEXISTENT_ATTRIBUTE +#define NO_TRUNCATE_OPEN_FILE +#define NO_CHECK_SELECTION_BOUNDS +#define NO_VALIDATE_DATASPACE +#define NO_REFERENCE_TO_DELETED + +#endif /* H5_API_TESTS_DISABLED_H */ diff --git a/test/API/README.md b/test/API/README.md new file mode 100644 index 0000000..d57472d --- /dev/null +++ b/test/API/README.md @@ -0,0 +1,86 @@ +# HDF5 API Tests + +This directory contains several test applications that exercise [HDF5](https://github.com/HDFGroup/hdf5)'s +public API and serve as regression tests for HDF5 [VOL Connectors](https://portal.hdfgroup.org/display/HDF5/Virtual+Object+Layer). + +## Build Process and options + +These HDF5 API tests are enabled and built by default, but can be disabled if desired. +The following build options are available to influence how the API tests get built: + +### CMake + +To set an option, it should be prepended with `-D` when passed to the `cmake` command. +For example, + + cmake -DHDF5_TEST_API=OFF .. + +`HDF5_TEST_API` (Default: `ON`) - Determines whether the API tests will be built. + +`HDF5_TEST_API_INSTALL` (Default: `ON`) - Determines whether the API tests should be installed +on the system. + +`HDF5_TEST_API_ENABLE_ASYNC` (Default: `OFF`) - Determines whether tests for HDF5's asynchronous +I/O capabilities should be enabled. Note that the "native" HDF5 VOL connector doesn't support +this functionality, so these tests are directed towards VOL connectors that do. + +`HDF5_TEST_ENABLE_DRIVER` (Default: `OFF`) - Determines whether the API test driver program should +be built. This driver program is useful when a VOL connector relies upon a server executable +(as well as possible additional executables) in order to function. The driver program can be +supplied with a server executable and + +`HDF5_TEST_API_SERVER` (Default: empty string) - If `HDF5_TEST_ENABLE_DRIVER` is set to `ON`, this +option should be edited to point to the server executable that the driver program should attempt +to launch before running the API tests. + +### Autotools + +Currently unsupported + +### Usage + +These API tests currently only support usage with HDF5 VOL connectors that can be loaded dynamically +as a plugin. For information on how to build a VOL connector in this manner, refer to section 2.3 of +the [HDF5 VOL Connector Author Guide](https://portal.hdfgroup.org/display/HDF5/HDF5+VOL+Connector+Authors+Guide?preview=/53610813/59903039/vol_connector_author_guide.pdf). + +TODO: section on building VOL connectors alongside HDF5 for use with tests + +These API tests can also be used to test an HDF5 VOL connector that is external to the library. +For convenience, the `HDF5_TEST_API_INSTALL` option can be used to install these tests on the +system where other HDF5 executables (such as `h5dump`) are installed. + +To run these tests with your VOL connector, set the following two environment variables: + +`HDF5_VOL_CONNECTOR` - This environment variable should be set to the name chosen for the VOL connector +to be used. For example, HDF5's DAOS VOL connector uses the name "[daos](https://github.com/HDFGroup/vol-daos/blob/v1.2.0/src/daos_vol.h#L30)" and would therefore set: + + HDF5_VOL_CONNECTOR=daos + +`HDF5_PLUGIN_PATH` - This environment variable should be set to the directory that contains the built +library for the VOL connector to be used. + +Once these are set, the HDF5 API tests will attempt to automatically load the specified VOL connector +and use it when running tests. If HDF5 is unable to locate or load the VOL connector specified, it +will fall back to running the tests with the native HDF5 VOL connector and an error similar to the +following will appear in the test output: + + HDF5-DIAG: Error detected in HDF5 (1.13.0) MPI-process 0: + #000: /home/user/git/hdf5/src/H5.c line 1010 in H5open(): library initialization failed + major: Function entry/exit + minor: Unable to initialize object + #001: /home/user/git/hdf5/src/H5.c line 277 in H5_init_library(): unable to initialize vol interface + major: Function entry/exit + minor: Unable to initialize object + #002: /home/user/git/hdf5/src/H5VLint.c line 199 in H5VL_init_phase2(): unable to set default VOL connector + major: Virtual Object Layer + minor: Can't set value + #003: /home/user/git/hdf5/src/H5VLint.c line 429 in H5VL__set_def_conn(): can't register connector + major: Virtual Object Layer + minor: Unable to register new ID + #004: /home/user/git/hdf5/src/H5VLint.c line 1321 in H5VL__register_connector_by_name(): unable to load VOL connector + major: Virtual Object Layer + minor: Unable to initialize object + +### Help and Support + +For help with building or using the HDF5 API tests, please contact the [HDF Help Desk](https://portal.hdfgroup.org/display/support/The+HDF+Help+Desk). diff --git a/test/API/driver/CMakeLists.txt b/test/API/driver/CMakeLists.txt new file mode 100644 index 0000000..2210068 --- /dev/null +++ b/test/API/driver/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 2.8.12.2 FATAL_ERROR) +project(H5_API_TEST_DRIVER CXX) + +include(CheckAsan) +include(CheckUbsan) + +set(CMAKE_CXX_STANDARD 11) + +set(KWSYS_NAMESPACE h5_api_test_sys) +set(KWSYS_USE_SystemTools 1) +set(KWSYS_USE_Process 1) +set(KWSYS_USE_RegularExpression 1) +add_subdirectory(kwsys) +include_directories(${CMAKE_CURRENT_BINARY_DIR}/kwsys) + +add_executable(h5_api_test_driver h5_api_test_driver.cxx) +target_link_libraries(h5_api_test_driver h5_api_test_sys) diff --git a/test/API/driver/h5_api_test_driver.cxx b/test/API/driver/h5_api_test_driver.cxx new file mode 100644 index 0000000..b5d9821 --- /dev/null +++ b/test/API/driver/h5_api_test_driver.cxx @@ -0,0 +1,910 @@ +#include "h5_api_test_driver.hxx" + +#include "H5_api_test_config.h" + +#include +#include +#include +#include +#include + +#if !defined(_WIN32) || defined(__CYGWIN__) +# include +# include +#endif + +#include +#include + +using std::vector; +using std::string; +using std::cerr; + +// The main function as this class should only be used by this program +int +main(int argc, char *argv[]) +{ + H5APITestDriver d; + return d.Main(argc, argv); +} + +//---------------------------------------------------------------------------- +H5APITestDriver::H5APITestDriver() +{ + this->ClientArgStart = 0; + this->ClientArgCount = 0; + this->ClientHelperArgStart = 0; + this->ClientHelperArgCount = 0; + this->ClientInitArgStart = 0; + this->ClientInitArgCount = 0; + this->ServerArgStart = 0; + this->ServerArgCount = 0; + this->AllowErrorInOutput = false; + // try to make sure that this times out before dart so it can kill all the processes + this->TimeOut = DART_TESTING_TIMEOUT - 10.0; + this->ServerExitTimeOut = 2; /* 2 seconds timeout for server to exit */ + this->ClientHelper = false; + this->ClientInit = false; + this->TestServer = false; + this->TestSerial = false; + this->IgnoreServerResult = false; +} + +//---------------------------------------------------------------------------- +H5APITestDriver::~H5APITestDriver() +{ +} + +//---------------------------------------------------------------------------- +void +H5APITestDriver::SeparateArguments(const char *str, vector &flags) +{ + string arg = str; + string::size_type pos1 = 0; + string::size_type pos2 = arg.find_first_of(" ;"); + if (pos2 == arg.npos) { + flags.push_back(str); + return; + } + while (pos2 != arg.npos) { + flags.push_back(arg.substr(pos1, pos2 - pos1)); + pos1 = pos2 + 1; + pos2 = arg.find_first_of(" ;", pos1 + 1); + } + flags.push_back(arg.substr(pos1, pos2 - pos1)); +} + +//---------------------------------------------------------------------------- +void +H5APITestDriver::CollectConfiguredOptions() +{ + if (this->TimeOut < 0) + this->TimeOut = 1500; + +#ifdef H5_API_TEST_ENV_VARS + this->SeparateArguments(H5_API_TEST_ENV_VARS, this->ClientEnvVars); +#endif + + // now find all the mpi information if mpi run is set +#ifdef MPIEXEC_EXECUTABLE + this->MPIRun = MPIEXEC_EXECUTABLE; +#else + return; +#endif + int maxNumProc = 1; + +# ifdef MPIEXEC_MAX_NUMPROCS + if (!this->TestSerial) + maxNumProc = MPIEXEC_MAX_NUMPROCS; +# endif +# ifdef MPIEXEC_NUMPROC_FLAG + this->MPINumProcessFlag = MPIEXEC_NUMPROC_FLAG; +# endif +# ifdef MPIEXEC_PREFLAGS + this->SeparateArguments(MPIEXEC_PREFLAGS, this->MPIClientPreFlags); +# endif +# ifdef MPIEXEC_POSTFLAGS + this->SeparateArguments(MPIEXEC_POSTFLAGS, this->MPIClientPostFlags); +# endif +# ifdef MPIEXEC_SERVER_PREFLAGS + this->SeparateArguments(MPIEXEC_SERVER_PREFLAGS, this->MPIServerPreFlags); +#else + this->MPIServerPreFlags = this->MPIClientPreFlags; +# endif +# ifdef MPIEXEC_SERVER_POSTFLAGS + this->SeparateArguments(MPIEXEC_SERVER_POSTFLAGS, this->MPIServerPostFlags); +#else + this->MPIServerPostFlags = this->MPIClientPostFlags; +# endif + std::stringstream ss; + ss << maxNumProc; + this->MPIServerNumProcessFlag = "1"; + this->MPIClientNumProcessFlag = ss.str(); +} + +//---------------------------------------------------------------------------- +/// This adds the debug/build configuration crap for the executable on windows. +static string +FixExecutablePath(const string &path) +{ +#ifdef CMAKE_INTDIR + string parent_dir = + h5_api_test_sys::SystemTools::GetFilenamePath(path.c_str()); + + string filename = + h5_api_test_sys::SystemTools::GetFilenameName(path); + + if (!h5_api_test_sys::SystemTools::StringEndsWith(parent_dir.c_str(), CMAKE_INTDIR)) { + parent_dir += "/" CMAKE_INTDIR; + } + return parent_dir + "/" + filename; +#endif + + return path; +} + +//---------------------------------------------------------------------------- +int +H5APITestDriver::ProcessCommandLine(int argc, char *argv[]) +{ + int *ArgCountP = NULL; + int i; + for (i = 1; i < argc; ++i) { + if (strcmp(argv[i], "--client") == 0) { + this->ClientExecutable = ::FixExecutablePath(argv[i + 1]); + ++i; /* Skip executable */ + this->ClientArgStart = i + 1; + this->ClientArgCount = this->ClientArgStart; + ArgCountP = &this->ClientArgCount; + continue; + } + if (strcmp(argv[i], "--client-helper") == 0) { + std::cerr << "Client Helper" << std::endl; + this->ClientHelper = true; + this->ClientHelperExecutable = ::FixExecutablePath(argv[i + 1]); + ++i; /* Skip executable */ + this->ClientHelperArgStart = i + 1; + this->ClientHelperArgCount = this->ClientHelperArgStart; + ArgCountP = &this->ClientHelperArgCount; + continue; + } + if (strcmp(argv[i], "--client-init") == 0) { + std::cerr << "Client Init" << std::endl; + this->ClientInit = true; + this->ClientInitExecutable = ::FixExecutablePath(argv[i + 1]); + ++i; /* Skip executable */ + this->ClientInitArgStart = i + 1; + this->ClientInitArgCount = this->ClientInitArgStart; + ArgCountP = &this->ClientInitArgCount; + continue; + } + if (strcmp(argv[i], "--server") == 0) { + std::cerr << "Test Server" << std::endl; + this->TestServer = true; + this->ServerExecutable = ::FixExecutablePath(argv[i + 1]); + ++i; /* Skip executable */ + this->ServerArgStart = i + 1; + this->ServerArgCount = this->ServerArgStart; + ArgCountP = &this->ServerArgCount; + continue; + } + if (strcmp(argv[i], "--timeout") == 0) { + this->TimeOut = atoi(argv[i + 1]); + std::cerr << "The timeout was set to " << this->TimeOut << std::endl; + ArgCountP = NULL; + continue; + } + if (strncmp(argv[i], "--allow-errors", strlen("--allow-errors")) == 0) { + this->AllowErrorInOutput = true; + std::cerr << "The allow errors in output flag was set to " << + this->AllowErrorInOutput << std::endl; + ArgCountP = NULL; + continue; + } + if (strncmp(argv[i], "--allow-server-errors", strlen("--allow-server-errors")) == 0) { + this->IgnoreServerResult = true; + std::cerr << "The allow server errors in output flag was set to " << + this->IgnoreServerResult << std::endl; + ArgCountP = NULL; + continue; + } + if (strcmp(argv[i], "--serial") == 0) { + this->TestSerial = true; + std::cerr << "This is a serial test" << std::endl; + ArgCountP = NULL; + continue; + } + if (ArgCountP) + (*ArgCountP)++; + } + + return 1; +} + +//---------------------------------------------------------------------------- +void +H5APITestDriver::CreateCommandLine(vector &commandLine, + const char *cmd, int isServer, int isHelper, const char *numProc, int argStart, + int argCount, char *argv[]) +{ + if (!isServer && this->ClientEnvVars.size()) { + for (unsigned int i = 0; i < this->ClientEnvVars.size(); ++i) + commandLine.push_back(this->ClientEnvVars[i].c_str()); +#ifdef H5_API_TEST_CLIENT_INIT_TOKEN_VAR + if (this->ClientTokenVar.size()) + commandLine.push_back(this->ClientTokenVar.c_str()); +#endif + } + + if (!isHelper && this->MPIRun.size()) { + commandLine.push_back(this->MPIRun.c_str()); + commandLine.push_back(this->MPINumProcessFlag.c_str()); + commandLine.push_back(numProc); + + if (isServer) + for (unsigned int i = 0; i < this->MPIServerPreFlags.size(); ++i) + commandLine.push_back(this->MPIServerPreFlags[i].c_str()); + else + for (unsigned int i = 0; i < this->MPIClientPreFlags.size(); ++i) + commandLine.push_back(this->MPIClientPreFlags[i].c_str()); + } + + commandLine.push_back(cmd); + + if (isServer) + for (unsigned int i = 0; i < this->MPIServerPostFlags.size(); ++i) + commandLine.push_back(MPIServerPostFlags[i].c_str()); + else + for (unsigned int i = 0; i < this->MPIClientPostFlags.size(); ++i) + commandLine.push_back(MPIClientPostFlags[i].c_str()); + + // remaining flags for the test + for (int ii = argStart; ii < argCount; ++ii) { + commandLine.push_back(argv[ii]); + } + + commandLine.push_back(0); +} + +//---------------------------------------------------------------------------- +int +H5APITestDriver::StartServer(h5_api_test_sysProcess *server, const char *name, + vector &out, vector &err) +{ + if (!server) + return 1; + + cerr << "H5APITestDriver: starting process " << name << "\n"; + h5_api_test_sysProcess_SetTimeout(server, this->TimeOut); + h5_api_test_sysProcess_Execute(server); + int foundWaiting = 0; + string output; + while (!foundWaiting) { + int pipe = this->WaitForAndPrintLine(name, server, output, 100.0, out, + err, H5_API_TEST_SERVER_START_MSG, &foundWaiting); + if (pipe == h5_api_test_sysProcess_Pipe_None + || pipe == h5_api_test_sysProcess_Pipe_Timeout) { + break; + } + } + if (foundWaiting) { + cerr << "H5APITestDriver: " << name << " successfully started.\n"; + return 1; + } else { + cerr << "H5APITestDriver: " << name << " never started.\n"; + h5_api_test_sysProcess_Kill(server); + return 0; + } +} + +//---------------------------------------------------------------------------- +int +H5APITestDriver::StartClientHelper(h5_api_test_sysProcess *client, + const char *name, vector &out, vector &err) +{ + if (!client) + return 1; + + cerr << "H5APITestDriver: starting process " << name << "\n"; + h5_api_test_sysProcess_SetTimeout(client, this->TimeOut); + h5_api_test_sysProcess_Execute(client); + int foundWaiting = 0; + string output; + while (!foundWaiting) { + int pipe = this->WaitForAndPrintLine(name, client, output, 100.0, out, + err, H5_API_TEST_CLIENT_HELPER_START_MSG, &foundWaiting); + if (pipe == h5_api_test_sysProcess_Pipe_None + || pipe == h5_api_test_sysProcess_Pipe_Timeout) { + break; + } + } + if (foundWaiting) { + cerr << "H5APITestDriver: " << name << " successfully started.\n"; + return 1; + } else { + cerr << "H5APITestDriver: " << name << " never started.\n"; + h5_api_test_sysProcess_Kill(client); + return 0; + } +} + +//---------------------------------------------------------------------------- +int +H5APITestDriver::StartClientInit(h5_api_test_sysProcess *client, + const char *name, vector &out, vector &err) +{ + if (!client) + return 1; + + cerr << "H5APITestDriver: starting process " << name << "\n"; + h5_api_test_sysProcess_SetTimeout(client, this->TimeOut); + h5_api_test_sysProcess_Execute(client); + int foundToken = 0; + string output, token; + while (!foundToken) { + int pipe = this->WaitForAndPrintLine(name, client, output, 100.0, out, + err, NULL, NULL); + if (pipe == h5_api_test_sysProcess_Pipe_None + || pipe == h5_api_test_sysProcess_Pipe_Timeout) { + break; + } + if (this->OutputStringHasToken(name, H5_API_TEST_CLIENT_INIT_TOKEN_REGEX, output, token)) { + foundToken = 1; + this->ClientTokenVar = std::string(H5_API_TEST_CLIENT_INIT_TOKEN_VAR) + + std::string("=") + std::string(token); + break; + } + } + + if (foundToken) { + cerr << "H5APITestDriver: " << name << " token: " << token << " was found.\n"; + return 1; + } else { + cerr << "H5APITestDriver: " << name << " token was not found.\n"; + return 0; + } +} + +//---------------------------------------------------------------------------- +int +H5APITestDriver::StartClient(h5_api_test_sysProcess *client, const char *name) +{ + if (!client) + return 1; + + cerr << "H5APITestDriver: starting process " << name << "\n"; + h5_api_test_sysProcess_SetTimeout(client, this->TimeOut); + h5_api_test_sysProcess_Execute(client); + if (h5_api_test_sysProcess_GetState(client) + == h5_api_test_sysProcess_State_Executing) { + cerr << "H5APITestDriver: " << name << " successfully started.\n"; + return 1; + } else { + this->ReportStatus(client, name); + h5_api_test_sysProcess_Kill(client); + return 0; + } +} + +//---------------------------------------------------------------------------- +void +H5APITestDriver::Stop(h5_api_test_sysProcess *p, const char *name) +{ + if (p) { + cerr << "H5APITestDriver: killing process " << name << "\n"; + h5_api_test_sysProcess_Kill(p); + h5_api_test_sysProcess_WaitForExit(p, 0); + } +} + +//---------------------------------------------------------------------------- +int +H5APITestDriver::OutputStringHasError(const char *pname, string &output) +{ + const char* possibleMPIErrors[] = {"error", "Error", "Missing:", + "core dumped", "process in local group is dead", "Segmentation fault", + "erroneous", "ERROR:", "Error:", + "mpirun can *only* be used with MPI programs", "due to signal", + "failure", "abnormal termination", "failed", "FAILED", "Failed", 0}; + + const char* nonErrors[] = { + "Memcheck, a memory error detector", //valgrind + 0}; + + if (this->AllowErrorInOutput) + return 0; + + vector lines; + vector::iterator it; + h5_api_test_sys::SystemTools::Split(output.c_str(), lines); + + int i, j; + + for (it = lines.begin(); it != lines.end(); ++it) { + for (i = 0; possibleMPIErrors[i]; ++i) { + if (it->find(possibleMPIErrors[i]) != it->npos) { + int found = 1; + for (j = 0; nonErrors[j]; ++j) { + if (it->find(nonErrors[j]) != it->npos) { + found = 0; + cerr << "Non error \"" << it->c_str() + << "\" suppressed " << std::endl; + } + } + if (found) { + cerr + << "H5APITestDriver: ***** Test will fail, because the string: \"" + << possibleMPIErrors[i] + << "\"\nH5APITestDriver: ***** was found in the following output from the " + << pname << ":\n\"" << it->c_str() << "\"\n"; + return 1; + } + } + } + } + return 0; +} + +//---------------------------------------------------------------------------- +int +H5APITestDriver::OutputStringHasToken(const char *pname, const char *regex, + string &output, string &token) +{ + vector lines; + vector::iterator it; + h5_api_test_sys::SystemTools::Split(output.c_str(), lines); + h5_api_test_sys::RegularExpression re(regex); + + for (it = lines.begin(); it != lines.end(); ++it) { + if (re.find(*it)) { + token = re.match(1); + return 1; + } + } + + return 0; +} + +//---------------------------------------------------------------------------- +#define H5_API_CLEAN_PROCESSES do { \ + h5_api_test_sysProcess_Delete(client); \ + h5_api_test_sysProcess_Delete(client_helper); \ + h5_api_test_sysProcess_Delete(client_init); \ + h5_api_test_sysProcess_Delete(server); \ +} while (0) + +#define H5_API_EXECUTE_CMD(cmd) do { \ + if (strlen(cmd) > 0) { \ + std::vector commands = \ + h5_api_test_sys::SystemTools::SplitString(cmd, ';'); \ + for (unsigned int cc = 0; cc < commands.size(); cc++) { \ + std::string command = commands[cc]; \ + if (command.size() > 0) { \ + std::cout << command.c_str() << std::endl; \ + system(command.c_str()); \ + } \ + } \ + } \ +} while (0) + +//---------------------------------------------------------------------------- +int +H5APITestDriver::Main(int argc, char* argv[]) +{ +#ifdef H5_API_TEST_INIT_COMMAND + // run user-specified commands before initialization. + // For example: "killall -9 rsh test;" + H5_API_EXECUTE_CMD(H5_API_TEST_INIT_COMMAND); +#endif + + if (!this->ProcessCommandLine(argc, argv)) + return 1; + this->CollectConfiguredOptions(); + + // mpi code + // Allocate process managers. + h5_api_test_sysProcess *server = 0; + h5_api_test_sysProcess *client = 0; + h5_api_test_sysProcess *client_helper = 0; + h5_api_test_sysProcess *client_init = 0; + + if (this->TestServer) { + server = h5_api_test_sysProcess_New(); + if (!server) { + H5_API_CLEAN_PROCESSES; + cerr << "H5APITestDriver: Cannot allocate h5_api_test_sysProcess to " + "run the server.\n"; + return 1; + } + } + if (this->ClientHelper) { + client_helper = h5_api_test_sysProcess_New(); + if (!client_helper) { + H5API_CLEAN_PROCESSES; + cerr << "H5APITestDriver: Cannot allocate h5_api_test_sysProcess to " + "run the client helper.\n"; + return 1; + } + } + if (this->ClientInit) { + client_init = h5_api_test_sysProcess_New(); + if (!client_init) { + H5_API_CLEAN_PROCESSES; + cerr << "H5APITestDriver: Cannot allocate h5_api_test_sysProcess to " + "run the client init.\n"; + return 1; + } + } + client = h5_api_test_sysProcess_New(); + if (!client) { + H5_API_CLEAN_PROCESSES; + cerr << "H5APITestDriver: Cannot allocate h5_api_test_sysProcess to " + "run the client.\n"; + return 1; + } + + vector ClientStdOut; + vector ClientStdErr; + vector ClientHelperStdOut; + vector ClientHelperStdErr; + vector ClientInitStdOut; + vector ClientInitStdErr; + vector ServerStdOut; + vector ServerStdErr; + + vector serverCommand; + if (server) { + const char* serverExe = this->ServerExecutable.c_str(); + + this->CreateCommandLine(serverCommand, serverExe, 1, 0, + this->MPIServerNumProcessFlag.c_str(), this->ServerArgStart, + this->ServerArgCount, argv); + this->ReportCommand(&serverCommand[0], "server"); + h5_api_test_sysProcess_SetCommand(server, &serverCommand[0]); + h5_api_test_sysProcess_SetWorkingDirectory(server, + this->GetDirectory(serverExe).c_str()); + } + + vector clientHelperCommand; + if (client_helper) { + // Construct the client helper process command line. + const char *clientHelperExe = this->ClientHelperExecutable.c_str(); + this->CreateCommandLine(clientHelperCommand, clientHelperExe, 0, 1, + "1", this->ClientHelperArgStart, + this->ClientHelperArgCount, argv); + this->ReportCommand(&clientHelperCommand[0], "client_helper"); + h5_api_test_sysProcess_SetCommand(client_helper, &clientHelperCommand[0]); + h5_api_test_sysProcess_SetWorkingDirectory(client_helper, + this->GetDirectory(clientHelperExe).c_str()); + } + + vector clientInitCommand; + if (client_init) { + // Construct the client helper process command line. + const char *clientInitExe = this->ClientInitExecutable.c_str(); + this->CreateCommandLine(clientInitCommand, clientInitExe, 0, 1, + "1", this->ClientInitArgStart, this->ClientInitArgCount, argv); + this->ReportCommand(&clientInitCommand[0], "client_init"); + h5_api_test_sysProcess_SetCommand(client_init, &clientInitCommand[0]); + h5_api_test_sysProcess_SetWorkingDirectory(client_init, + this->GetDirectory(clientInitExe).c_str()); + } + + // Start the server if there is one + if (!this->StartServer(server, "server", ServerStdOut, ServerStdErr)) { + cerr << "H5APITestDriver: Server never started.\n"; + H5_API_CLEAN_PROCESSES; + return -1; + } + + // Start the client helper here if there is one + if (!this->StartClientHelper(client_helper, "client_helper", + ClientHelperStdOut, ClientHelperStdErr)) { + cerr << "H5APITestDriver: Client Helper never started.\n"; + this->Stop(server, "server"); +#ifdef H5_API_TEST_SERVER_EXIT_COMMAND + H5_API_EXECUTE_CMD(H5_API_TEST_SERVER_EXIT_COMMAND); +#endif + H5_API_CLEAN_PROCESSES; + return -1; + } + + // Start the client init here if there is one + if (!this->StartClientInit(client_init, "client_init", + ClientInitStdOut, ClientInitStdErr)) { + cerr << "H5APITestDriver: Client Init never started.\n"; + this->Stop(server, "server"); +#ifdef H5_API_TEST_SERVER_EXIT_COMMAND + H5_API_EXECUTE_CMD(H5_API_TEST_SERVER_EXIT_COMMAND); +#endif + this->Stop(client_helper, "client_helper"); +#ifdef H5_API_TEST_CLIENT_HELPER_EXIT_COMMAND + H5_API_EXECUTE_CMD(H5_API_TEST_CLIENT_HELPER_EXIT_COMMAND); +#endif + H5_API_CLEAN_PROCESSES; + return -1; + } + + // Construct the client process command line. + vector clientCommand; + const char *clientExe = this->ClientExecutable.c_str(); + this->CreateCommandLine(clientCommand, clientExe, 0, 0, + this->MPIClientNumProcessFlag.c_str(), this->ClientArgStart, + this->ClientArgCount, argv); + this->ReportCommand(&clientCommand[0], "client"); + h5_api_test_sysProcess_SetCommand(client, &clientCommand[0]); + h5_api_test_sysProcess_SetWorkingDirectory(client, + this->GetDirectory(clientExe).c_str()); + + // Now run the client + if (!this->StartClient(client, "client")) { + this->Stop(server, "server"); + this->Stop(client_helper, "client_helper"); + this->Stop(client_init, "client_init"); + H5_API_CLEAN_PROCESSES; + return -1; + } + + // Report the output of the processes. + int clientPipe = 1; + + string output; + int mpiError = 0; + while (clientPipe) { + clientPipe = this->WaitForAndPrintLine("client", client, output, 0.1, + ClientStdOut, ClientStdErr, NULL, NULL); + if (!mpiError && this->OutputStringHasError("client", output)) { + mpiError = 1; + } + // If client has died, we wait for output from the server processes + // for this->ServerExitTimeOut, then we'll kill the servers, if needed. + double timeout = (clientPipe) ? 0 : this->ServerExitTimeOut; + output = ""; + this->WaitForAndPrintLine("server", server, output, timeout, + ServerStdOut, ServerStdErr, NULL, NULL); + if (!mpiError && this->OutputStringHasError("server", output)) { + mpiError = 1; + } + output = ""; + } + + // Wait for the client and server to exit. + h5_api_test_sysProcess_WaitForExit(client, 0); + + // Once client is finished, the servers + // must finish quickly. If not, it usually is a sign that + // the client crashed/exited before it attempted to connect to + // the server. + if (server) { +#ifdef H5_API_TEST_SERVER_EXIT_COMMAND + H5_API_EXECUTE_CMD(H5_API_TEST_SERVER_EXIT_COMMAND); +#endif + h5_api_test_sysProcess_WaitForExit(server, &this->ServerExitTimeOut); + } + + if (client_helper) { +#ifdef H5_API_TEST_CLIENT_HELPER_EXIT_COMMAND + H5_API_EXECUTE_CMD(H5_API_TEST_CLIENT_HELPER_EXIT_COMMAND); +#endif + h5_api_test_sysProcess_WaitForExit(client_helper, 0); + } + + // Get the results. + int clientResult = this->ReportStatus(client, "client"); + int serverResult = 0; + if (server) { + serverResult = this->ReportStatus(server, "server"); + h5_api_test_sysProcess_Kill(server); + } + + // Free process managers. + H5_API_CLEAN_PROCESSES; + + // Report the server return code if it is nonzero. Otherwise report + // the client return code. + if (serverResult && !this->IgnoreServerResult) + return serverResult; + + if (mpiError) { + cerr + << "H5VLTestDriver: Error string found in output, H5APITestDriver returning " + << mpiError << "\n"; + return mpiError; + } + + // if server is fine return the client result + return clientResult; +} + +//---------------------------------------------------------------------------- +void +H5APITestDriver::ReportCommand(const char * const *command, const char *name) +{ + cerr << "H5APITestDriver: " << name << " command is:\n"; + for (const char * const *c = command; *c; ++c) + cerr << " \"" << *c << "\""; + cerr << "\n"; +} + +//---------------------------------------------------------------------------- +int +H5APITestDriver::ReportStatus(h5_api_test_sysProcess *process, const char *name) +{ + int result = 1; + switch (h5_api_test_sysProcess_GetState(process)) { + case h5_api_test_sysProcess_State_Starting: { + cerr << "H5APITestDriver: Never started " << name << " process.\n"; + } + break; + case h5_api_test_sysProcess_State_Error: { + cerr << "H5APITestDriver: Error executing " << name << " process: " + << h5_api_test_sysProcess_GetErrorString(process) << "\n"; + } + break; + case h5_api_test_sysProcess_State_Exception: { + cerr << "H5APITestDriver: " << name + << " process exited with an exception: "; + switch (h5_api_test_sysProcess_GetExitException(process)) { + case h5_api_test_sysProcess_Exception_None: { + cerr << "None"; + } + break; + case h5_api_test_sysProcess_Exception_Fault: { + cerr << "Segmentation fault"; + } + break; + case h5_api_test_sysProcess_Exception_Illegal: { + cerr << "Illegal instruction"; + } + break; + case h5_api_test_sysProcess_Exception_Interrupt: { + cerr << "Interrupted by user"; + } + break; + case h5_api_test_sysProcess_Exception_Numerical: { + cerr << "Numerical exception"; + } + break; + case h5_api_test_sysProcess_Exception_Other: { + cerr << "Unknown"; + } + break; + } + cerr << "\n"; + } + break; + case h5_api_test_sysProcess_State_Executing: { + cerr << "H5APITestDriver: Never terminated " << name + << " process.\n"; + } + break; + case h5_api_test_sysProcess_State_Exited: { + result = h5_api_test_sysProcess_GetExitValue(process); + cerr << "H5APITestDriver: " << name << " process exited with code " + << result << "\n"; + } + break; + case h5_api_test_sysProcess_State_Expired: { + cerr << "H5APITestDriver: killed " << name + << " process due to timeout.\n"; + } + break; + case h5_api_test_sysProcess_State_Killed: { + cerr << "H5APITestDriver: killed " << name << " process.\n"; + } + break; + } + return result; +} + +//---------------------------------------------------------------------------- +int +H5APITestDriver::WaitForLine(h5_api_test_sysProcess *process, string &line, + double timeout, vector &out, vector &err) +{ + line = ""; + vector::iterator outiter = out.begin(); + vector::iterator erriter = err.begin(); + while (1) { + // Check for a newline in stdout. + for (; outiter != out.end(); ++outiter) { + if ((*outiter == '\r') && ((outiter + 1) == out.end())) { + break; + } else if (*outiter == '\n' || *outiter == '\0') { + int length = outiter - out.begin(); + if (length > 1 && *(outiter - 1) == '\r') + --length; + if (length > 0) + line.append(&out[0], length); + out.erase(out.begin(), outiter + 1); + return h5_api_test_sysProcess_Pipe_STDOUT; + } + } + + // Check for a newline in stderr. + for (; erriter != err.end(); ++erriter) { + if ((*erriter == '\r') && ((erriter + 1) == err.end())) { + break; + } else if (*erriter == '\n' || *erriter == '\0') { + int length = erriter - err.begin(); + if (length > 1 && *(erriter - 1) == '\r') + --length; + if (length > 0) + line.append(&err[0], length); + err.erase(err.begin(), erriter + 1); + return h5_api_test_sysProcess_Pipe_STDERR; + } + } + + // No newlines found. Wait for more data from the process. + int length; + char *data; + int pipe = h5_api_test_sysProcess_WaitForData(process, &data, &length, + &timeout); + if (pipe == h5_api_test_sysProcess_Pipe_Timeout) { + // Timeout has been exceeded. + return pipe; + } else if (pipe == h5_api_test_sysProcess_Pipe_STDOUT) { + // Append to the stdout buffer. + vector::size_type size = out.size(); + out.insert(out.end(), data, data + length); + outiter = out.begin() + size; + } else if (pipe == h5_api_test_sysProcess_Pipe_STDERR) { + // Append to the stderr buffer. + vector::size_type size = err.size(); + err.insert(err.end(), data, data + length); + erriter = err.begin() + size; + } else if (pipe == h5_api_test_sysProcess_Pipe_None) { + // Both stdout and stderr pipes have broken. Return leftover data. + if (!out.empty()) { + line.append(&out[0], outiter - out.begin()); + out.erase(out.begin(), out.end()); + return h5_api_test_sysProcess_Pipe_STDOUT; + } else if (!err.empty()) { + line.append(&err[0], erriter - err.begin()); + err.erase(err.begin(), err.end()); + return h5_api_test_sysProcess_Pipe_STDERR; + } else { + return h5_api_test_sysProcess_Pipe_None; + } + } + } +} + +//---------------------------------------------------------------------------- +void +H5APITestDriver::PrintLine(const char *pname, const char *line) +{ + // if the name changed then the line is output from a different process + if (this->CurrentPrintLineName != pname) { + cerr << "-------------- " << pname << " output --------------\n"; + // save the current pname + this->CurrentPrintLineName = pname; + } + cerr << line << "\n"; + cerr.flush(); +} + +//---------------------------------------------------------------------------- +int +H5APITestDriver::WaitForAndPrintLine(const char *pname, + h5_api_test_sysProcess *process, string &line, double timeout, + vector &out, vector &err, const char *waitMsg, + int *foundWaiting) +{ + int pipe = this->WaitForLine(process, line, timeout, out, err); + if (pipe == h5_api_test_sysProcess_Pipe_STDOUT + || pipe == h5_api_test_sysProcess_Pipe_STDERR) { + this->PrintLine(pname, line.c_str()); + if (foundWaiting && (line.find(waitMsg) != line.npos)) + *foundWaiting = 1; + } + return pipe; +} + +//---------------------------------------------------------------------------- +string +H5APITestDriver::GetDirectory(string location) +{ + return h5_api_test_sys::SystemTools::GetParentDirectory(location.c_str()); +} diff --git a/test/API/driver/h5_api_test_driver.hxx b/test/API/driver/h5_api_test_driver.hxx new file mode 100644 index 0000000..b8e05e7 --- /dev/null +++ b/test/API/driver/h5_api_test_driver.hxx @@ -0,0 +1,93 @@ +#ifndef H5_API_TEST_DRIVER_H +#define H5_API_TEST_DRIVER_H + +#include +#include + +#include + +class H5APITestDriver { +public: + int Main(int argc, char *argv[]); + H5APITestDriver(); + ~H5APITestDriver(); + +protected: + void SeparateArguments(const char* str, std::vector &flags); + + void ReportCommand(const char * const *command, const char *name); + int ReportStatus(h5_api_test_sysProcess *process, const char *name); + int ProcessCommandLine(int argc, char *argv[]); + void CollectConfiguredOptions(); + void CreateCommandLine(std::vector &commandLine, + const char *cmd, int isServer, int isHelper, const char *numProc, + int argStart = 0, int argCount = 0, char *argv[] = 0); + + int StartServer(h5_api_test_sysProcess *server, const char *name, + std::vector &out, std::vector &err); + int StartClientHelper(h5_api_test_sysProcess *client, const char *name, + std::vector &out, std::vector &err); + int StartClientInit(h5_api_test_sysProcess *client, const char *name, + std::vector &out, std::vector &err); + int StartClient(h5_api_test_sysProcess *client, const char *name); + void Stop(h5_api_test_sysProcess *p, const char *name); + int OutputStringHasError(const char *pname, std::string &output); + int OutputStringHasToken(const char *pname, const char *regex, + std::string &output, std::string &token); + + int WaitForLine(h5_api_test_sysProcess *process, std::string &line, + double timeout, std::vector &out, std::vector &err); + void PrintLine(const char *pname, const char *line); + int WaitForAndPrintLine(const char *pname, h5_api_test_sysProcess *process, + std::string &line, double timeout, std::vector &out, + std::vector &err, const char *waitMsg, int *foundWaiting); + + std::string GetDirectory(std::string location); + +private: + std::string ClientExecutable; // fullpath to client executable + std::string ClientHelperExecutable; // fullpath to client helper executable + std::string ClientInitExecutable; // fullpath to client init executable + std::string ServerExecutable; // fullpath to server executable + std::string MPIRun; // fullpath to mpirun executable + + // This specify the preflags and post flags that can be set using: + // VTK_MPI_PRENUMPROC_FLAGS VTK_MPI_PREFLAGS / VTK_MPI_POSTFLAGS at config time + // std::vector MPIPreNumProcFlags; + std::vector ClientEnvVars; + std::vector MPIClientPreFlags; + std::vector MPIClientPostFlags; + std::vector MPIServerPreFlags; + std::vector MPIServerPostFlags; + + // Specify the number of process flag, this can be set using: VTK_MPI_NUMPROC_FLAG. + // This is then split into : + // MPIServerNumProcessFlag & MPIRenderServerNumProcessFlag + std::string MPINumProcessFlag; + std::string MPIServerNumProcessFlag; + std::string MPIClientNumProcessFlag; + + std::string ClientTokenVar; // use token to launch client if requested + + std::string CurrentPrintLineName; + + double TimeOut; + double ServerExitTimeOut; // time to wait for servers to finish. + bool ClientHelper; + bool ClientInit; + bool TestServer; + + int ClientArgStart; + int ClientArgCount; + int ClientHelperArgStart; + int ClientHelperArgCount; + int ClientInitArgStart; + int ClientInitArgCount; + int ServerArgStart; + int ServerArgCount; + bool AllowErrorInOutput; + bool TestSerial; + bool IgnoreServerResult; +}; + +#endif //H5_API_TEST_DRIVER_H diff --git a/test/API/driver/kwsys/.clang-format b/test/API/driver/kwsys/.clang-format new file mode 100644 index 0000000..588b790 --- /dev/null +++ b/test/API/driver/kwsys/.clang-format @@ -0,0 +1,22 @@ +--- +# This configuration requires clang-format version 6.0 exactly. +BasedOnStyle: Mozilla +AlignOperands: false +AllowShortFunctionsOnASingleLine: InlineOnly +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: true + AfterEnum: true + AfterFunction: true + AfterStruct: true + AfterUnion: true +BreakBeforeBraces: Custom +ColumnLimit: 79 +IndentPPDirectives: AfterHash +SortUsingDeclarations: false +SpaceAfterTemplateKeyword: true +Standard: Cpp03 +... diff --git a/test/API/driver/kwsys/.hooks-config b/test/API/driver/kwsys/.hooks-config new file mode 100644 index 0000000..739cdd2 --- /dev/null +++ b/test/API/driver/kwsys/.hooks-config @@ -0,0 +1,2 @@ +[hooks "chain"] + pre-commit = GitSetup/pre-commit diff --git a/test/API/driver/kwsys/Base64.c b/test/API/driver/kwsys/Base64.c new file mode 100644 index 0000000..bf876f2 --- /dev/null +++ b/test/API/driver/kwsys/Base64.c @@ -0,0 +1,225 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(Base64.h) + +/* Work-around CMake dependency scanning limitation. This must + duplicate the above list of headers. */ +#if 0 +# include "Base64.h.in" +#endif + +static const unsigned char kwsysBase64EncodeTable[65] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + +static const unsigned char kwsysBase64DecodeTable[256] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xFF, 0xFF, 0x3F, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, + 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + /*------------------------------------*/ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +static unsigned char kwsysBase64EncodeChar(int c) +{ + return kwsysBase64EncodeTable[(unsigned char)c]; +} + +static unsigned char kwsysBase64DecodeChar(unsigned char c) +{ + return kwsysBase64DecodeTable[c]; +} + +/* Encode 3 bytes into a 4 byte string. */ +void kwsysBase64_Encode3(const unsigned char* src, unsigned char* dest) +{ + dest[0] = kwsysBase64EncodeChar((src[0] >> 2) & 0x3F); + dest[1] = + kwsysBase64EncodeChar(((src[0] << 4) & 0x30) | ((src[1] >> 4) & 0x0F)); + dest[2] = + kwsysBase64EncodeChar(((src[1] << 2) & 0x3C) | ((src[2] >> 6) & 0x03)); + dest[3] = kwsysBase64EncodeChar(src[2] & 0x3F); +} + +/* Encode 2 bytes into a 4 byte string. */ +void kwsysBase64_Encode2(const unsigned char* src, unsigned char* dest) +{ + dest[0] = kwsysBase64EncodeChar((src[0] >> 2) & 0x3F); + dest[1] = + kwsysBase64EncodeChar(((src[0] << 4) & 0x30) | ((src[1] >> 4) & 0x0F)); + dest[2] = kwsysBase64EncodeChar(((src[1] << 2) & 0x3C)); + dest[3] = '='; +} + +/* Encode 1 bytes into a 4 byte string. */ +void kwsysBase64_Encode1(const unsigned char* src, unsigned char* dest) +{ + dest[0] = kwsysBase64EncodeChar((src[0] >> 2) & 0x3F); + dest[1] = kwsysBase64EncodeChar(((src[0] << 4) & 0x30)); + dest[2] = '='; + dest[3] = '='; +} + +/* Encode 'length' bytes from the input buffer and store the + encoded stream into the output buffer. Return the length of the encoded + buffer (output). Note that the output buffer must be allocated by the caller + (length * 1.5 should be a safe estimate). If 'mark_end' is true than an + extra set of 4 bytes is added to the end of the stream if the input is a + multiple of 3 bytes. These bytes are invalid chars and therefore they will + stop the decoder thus enabling the caller to decode a stream without + actually knowing how much data to expect (if the input is not a multiple of + 3 bytes then the extra padding needed to complete the encode 4 bytes will + stop the decoding anyway). */ +size_t kwsysBase64_Encode(const unsigned char* input, size_t length, + unsigned char* output, int mark_end) +{ + const unsigned char* ptr = input; + const unsigned char* end = input + length; + unsigned char* optr = output; + + /* Encode complete triplet */ + + while ((end - ptr) >= 3) { + kwsysBase64_Encode3(ptr, optr); + ptr += 3; + optr += 4; + } + + /* Encodes a 2-byte ending into 3 bytes and 1 pad byte and writes. */ + + if (end - ptr == 2) { + kwsysBase64_Encode2(ptr, optr); + optr += 4; + } + + /* Encodes a 1-byte ending into 2 bytes and 2 pad bytes */ + + else if (end - ptr == 1) { + kwsysBase64_Encode1(ptr, optr); + optr += 4; + } + + /* Do we need to mark the end */ + + else if (mark_end) { + optr[0] = optr[1] = optr[2] = optr[3] = '='; + optr += 4; + } + + return (size_t)(optr - output); +} + +/* Decode 4 bytes into a 3 byte string. */ +int kwsysBase64_Decode3(const unsigned char* src, unsigned char* dest) +{ + unsigned char d0, d1, d2, d3; + + d0 = kwsysBase64DecodeChar(src[0]); + d1 = kwsysBase64DecodeChar(src[1]); + d2 = kwsysBase64DecodeChar(src[2]); + d3 = kwsysBase64DecodeChar(src[3]); + + /* Make sure all characters were valid */ + + if (d0 == 0xFF || d1 == 0xFF || d2 == 0xFF || d3 == 0xFF) { + return 0; + } + + /* Decode the 3 bytes */ + + dest[0] = (unsigned char)(((d0 << 2) & 0xFC) | ((d1 >> 4) & 0x03)); + dest[1] = (unsigned char)(((d1 << 4) & 0xF0) | ((d2 >> 2) & 0x0F)); + dest[2] = (unsigned char)(((d2 << 6) & 0xC0) | ((d3 >> 0) & 0x3F)); + + /* Return the number of bytes actually decoded */ + + if (src[2] == '=') { + return 1; + } + if (src[3] == '=') { + return 2; + } + return 3; +} + +/* Decode bytes from the input buffer and store the decoded stream + into the output buffer until 'length' bytes have been decoded. Return the + real length of the decoded stream (which should be equal to 'length'). Note + that the output buffer must be allocated by the caller. If + 'max_input_length' is not null, then it specifies the number of encoded + bytes that should be at most read from the input buffer. In that case the + 'length' parameter is ignored. This enables the caller to decode a stream + without actually knowing how much decoded data to expect (of course, the + buffer must be large enough). */ +size_t kwsysBase64_Decode(const unsigned char* input, size_t length, + unsigned char* output, size_t max_input_length) +{ + const unsigned char* ptr = input; + unsigned char* optr = output; + + /* Decode complete triplet */ + + if (max_input_length) { + const unsigned char* end = input + max_input_length; + while (ptr < end) { + int len = kwsysBase64_Decode3(ptr, optr); + optr += len; + if (len < 3) { + return (size_t)(optr - output); + } + ptr += 4; + } + } else { + unsigned char* oend = output + length; + while ((oend - optr) >= 3) { + int len = kwsysBase64_Decode3(ptr, optr); + optr += len; + if (len < 3) { + return (size_t)(optr - output); + } + ptr += 4; + } + + /* Decode the last triplet */ + + if (oend - optr == 2) { + unsigned char temp[3]; + int len = kwsysBase64_Decode3(ptr, temp); + if (len >= 2) { + optr[0] = temp[0]; + optr[1] = temp[1]; + optr += 2; + } else if (len > 0) { + optr[0] = temp[0]; + optr += 1; + } + } else if (oend - optr == 1) { + unsigned char temp[3]; + int len = kwsysBase64_Decode3(ptr, temp); + if (len > 0) { + optr[0] = temp[0]; + optr += 1; + } + } + } + + return (size_t)(optr - output); +} diff --git a/test/API/driver/kwsys/Base64.h.in b/test/API/driver/kwsys/Base64.h.in new file mode 100644 index 0000000..729f972 --- /dev/null +++ b/test/API/driver/kwsys/Base64.h.in @@ -0,0 +1,110 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_Base64_h +#define @KWSYS_NAMESPACE@_Base64_h + +#include <@KWSYS_NAMESPACE@/Configure.h> + +#include /* size_t */ + +/* Redefine all public interface symbol names to be in the proper + namespace. These macros are used internally to kwsys only, and are + not visible to user code. Use kwsysHeaderDump.pl to reproduce + these macros after making changes to the interface. */ +#if !defined(KWSYS_NAMESPACE) +# define kwsys_ns(x) @KWSYS_NAMESPACE@##x +# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT +#endif +#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# define kwsysBase64 kwsys_ns(Base64) +# define kwsysBase64_Decode kwsys_ns(Base64_Decode) +# define kwsysBase64_Decode3 kwsys_ns(Base64_Decode3) +# define kwsysBase64_Encode kwsys_ns(Base64_Encode) +# define kwsysBase64_Encode1 kwsys_ns(Base64_Encode1) +# define kwsysBase64_Encode2 kwsys_ns(Base64_Encode2) +# define kwsysBase64_Encode3 kwsys_ns(Base64_Encode3) +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * Encode 3 bytes into a 4 byte string. + */ +kwsysEXPORT void kwsysBase64_Encode3(const unsigned char* src, + unsigned char* dest); + +/** + * Encode 2 bytes into a 4 byte string. + */ +kwsysEXPORT void kwsysBase64_Encode2(const unsigned char* src, + unsigned char* dest); + +/** + * Encode 1 bytes into a 4 byte string. + */ +kwsysEXPORT void kwsysBase64_Encode1(const unsigned char* src, + unsigned char* dest); + +/** + * Encode 'length' bytes from the input buffer and store the encoded + * stream into the output buffer. Return the length of the encoded + * buffer (output). Note that the output buffer must be allocated by + * the caller (length * 1.5 should be a safe estimate). If 'mark_end' + * is true than an extra set of 4 bytes is added to the end of the + * stream if the input is a multiple of 3 bytes. These bytes are + * invalid chars and therefore they will stop the decoder thus + * enabling the caller to decode a stream without actually knowing how + * much data to expect (if the input is not a multiple of 3 bytes then + * the extra padding needed to complete the encode 4 bytes will stop + * the decoding anyway). + */ +kwsysEXPORT size_t kwsysBase64_Encode(const unsigned char* input, + size_t length, unsigned char* output, + int mark_end); + +/** + * Decode 4 bytes into a 3 byte string. Returns the number of bytes + * actually decoded. + */ +kwsysEXPORT int kwsysBase64_Decode3(const unsigned char* src, + unsigned char* dest); + +/** + * Decode bytes from the input buffer and store the decoded stream + * into the output buffer until 'length' bytes have been decoded. + * Return the real length of the decoded stream (which should be equal + * to 'length'). Note that the output buffer must be allocated by the + * caller. If 'max_input_length' is not null, then it specifies the + * number of encoded bytes that should be at most read from the input + * buffer. In that case the 'length' parameter is ignored. This + * enables the caller to decode a stream without actually knowing how + * much decoded data to expect (of course, the buffer must be large + * enough). + */ +kwsysEXPORT size_t kwsysBase64_Decode(const unsigned char* input, + size_t length, unsigned char* output, + size_t max_input_length); + +#if defined(__cplusplus) +} /* extern "C" */ +#endif + +/* If we are building a kwsys .c or .cxx file, let it use these macros. + Otherwise, undefine them to keep the namespace clean. */ +#if !defined(KWSYS_NAMESPACE) +# undef kwsys_ns +# undef kwsysEXPORT +# if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# undef kwsysBase64 +# undef kwsysBase64_Decode +# undef kwsysBase64_Decode3 +# undef kwsysBase64_Encode +# undef kwsysBase64_Encode1 +# undef kwsysBase64_Encode2 +# undef kwsysBase64_Encode3 +# endif +#endif + +#endif diff --git a/test/API/driver/kwsys/CMakeLists.txt b/test/API/driver/kwsys/CMakeLists.txt new file mode 100644 index 0000000..09bcdb9 --- /dev/null +++ b/test/API/driver/kwsys/CMakeLists.txt @@ -0,0 +1,1260 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing#kwsys for details. + +# The Kitware System Library is intended to be included in other +# projects. It is completely configurable in that the library's +# namespace can be configured and the components that are included can +# be selected invididually. + +# Typical usage is to import the kwsys directory tree into a +# subdirectory under a parent project and enable the classes that will +# be used. All classes are disabled by default. The CMake listfile +# above this one configures the library as follows: +# +# SET(KWSYS_NAMESPACE foosys) +# SET(KWSYS_USE_Directory 1) # Enable Directory class. +# SUBDIRS(kwsys) +# +# Optional settings are as follows: +# +# KWSYS_HEADER_ROOT = The directory into which to generate the kwsys headers. +# A directory called "${KWSYS_NAMESPACE}" will be +# created under this root directory to hold the files. +# KWSYS_SPLIT_OBJECTS_FROM_INTERFACE +# = Instead of creating a single ${KWSYS_NAMESPACE} library +# target, create three separate targets: +# ${KWSYS_NAMESPACE} +# - An INTERFACE library only containing usage +# requirements. +# ${KWSYS_NAMESPACE}_objects +# - An OBJECT library for the built kwsys objects. +# Note: This is omitted from the install rules +# ${KWSYS_NAMESPACE}_private +# - An INTERFACE library combining both that is +# appropriate for use with PRIVATE linking in +# target_link_libraries. Because of how interface +# properties propagate, this target is not suitable +# for use with PUBLIC or INTERFACE linking. +# KWSYS_ALIAS_TARGET = The name of an alias target to create to the actual target. +# +# Example: +# +# SET(KWSYS_HEADER_ROOT ${PROJECT_BINARY_DIR}) +# INCLUDE_DIRECTORIES(${PROJECT_BINARY_DIR}) +# +# KWSYS_CXX_STANDARD = A value for CMAKE_CXX_STANDARD within KWSys. +# Set to empty string to use no default value. +# KWSYS_CXX_COMPILE_FEATURES = target_compile_features arguments for KWSys. +# +# Optional settings to setup install rules are as follows: +# +# KWSYS_INSTALL_BIN_DIR = The installation target directories into +# KWSYS_INSTALL_LIB_DIR which the libraries and headers from +# KWSYS_INSTALL_INCLUDE_DIR kwsys should be installed by a "make install". +# The values should be specified relative to +# the installation prefix and NOT start with '/'. +# KWSYS_INSTALL_DOC_DIR = The installation target directory for documentation +# such as copyright information. +# +# KWSYS_INSTALL_COMPONENT_NAME_RUNTIME = Name of runtime and development +# KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT installation components. +# If not given the install rules +# will not be in any component. +# +# KWSYS_INSTALL_EXPORT_NAME = The EXPORT option value for install(TARGETS) calls. +# +# Example: +# +# SET(KWSYS_INSTALL_BIN_DIR bin) +# SET(KWSYS_INSTALL_LIB_DIR lib) +# SET(KWSYS_INSTALL_INCLUDE_DIR include) +# SET(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME Runtime) +# SET(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT Development) + +# Once configured, kwsys should be used as follows from C or C++ code: +# +# #include +# ... +# foosys::Directory directory; +# + +# NOTE: This library is intended for internal use by Kitware-driven +# projects. In order to keep it simple no attempt will be made to +# maintain backward compatibility when changes are made to KWSys. +# When an incompatible change is made Kitware's projects that use +# KWSys will be fixed, but no notification will necessarily be sent to +# any outside mailing list and no documentation of the change will be +# written. + +CMAKE_MINIMUM_REQUIRED(VERSION 3.1 FATAL_ERROR) +FOREACH(p + CMP0056 # CMake 3.2, Honor link flags in try_compile() source-file signature. + CMP0063 # CMake 3.3, Honor visibility properties for all target types. + CMP0067 # CMake 3.8, Honor language standard in try_compile source-file signature. + CMP0069 # CMake 3.9, INTERPROCEDURAL_OPTIMIZATION is enforced when enabled. + ) + IF(POLICY ${p}) + CMAKE_POLICY(SET ${p} NEW) + ENDIF() +ENDFOREACH() + +#----------------------------------------------------------------------------- +# If a namespace is not specified, use "kwsys" and enable testing. +# This should be the case only when kwsys is not included inside +# another project and is being tested. +IF(NOT KWSYS_NAMESPACE) + SET(KWSYS_NAMESPACE "kwsys") + SET(KWSYS_STANDALONE 1) +ENDIF() + +#----------------------------------------------------------------------------- +# The project name is that of the specified namespace. +PROJECT(${KWSYS_NAMESPACE}) + +# Tell CMake how to follow dependencies of sources in this directory. +SET_PROPERTY(DIRECTORY + PROPERTY IMPLICIT_DEPENDS_INCLUDE_TRANSFORM + "KWSYS_HEADER(%)=<${KWSYS_NAMESPACE}/%>" + ) + +if(KWSYS_CXX_STANDARD) + set(CMAKE_CXX_STANDARD "${KWSYS_CXX_STANDARD}") +elseif(NOT DEFINED CMAKE_CXX_STANDARD AND NOT DEFINED KWSYS_CXX_STANDARD) + if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" + AND CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC" + AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU" + ) + set(CMAKE_CXX_STANDARD 14) + else() + set(CMAKE_CXX_STANDARD 11) + endif() +endif() + +# Select library components. +IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) + SET(KWSYS_ENABLE_C 1) + # Enable all components. + SET(KWSYS_USE_Base64 1) + SET(KWSYS_USE_Directory 1) + SET(KWSYS_USE_DynamicLoader 1) + SET(KWSYS_USE_Encoding 1) + SET(KWSYS_USE_Glob 1) + SET(KWSYS_USE_MD5 1) + SET(KWSYS_USE_Process 1) + SET(KWSYS_USE_RegularExpression 1) + SET(KWSYS_USE_System 1) + SET(KWSYS_USE_SystemTools 1) + SET(KWSYS_USE_CommandLineArguments 1) + SET(KWSYS_USE_Terminal 1) + SET(KWSYS_USE_IOStream 1) + SET(KWSYS_USE_FStream 1) + SET(KWSYS_USE_String 1) + SET(KWSYS_USE_SystemInformation 1) + SET(KWSYS_USE_ConsoleBuf 1) +ENDIF() + +# Enforce component dependencies. +IF(KWSYS_USE_SystemTools) + SET(KWSYS_USE_Directory 1) + SET(KWSYS_USE_FStream 1) + SET(KWSYS_USE_Encoding 1) +ENDIF() +IF(KWSYS_USE_Glob) + SET(KWSYS_USE_Directory 1) + SET(KWSYS_USE_SystemTools 1) + SET(KWSYS_USE_RegularExpression 1) + SET(KWSYS_USE_FStream 1) + SET(KWSYS_USE_Encoding 1) +ENDIF() +IF(KWSYS_USE_Process) + SET(KWSYS_USE_System 1) + SET(KWSYS_USE_Encoding 1) +ENDIF() +IF(KWSYS_USE_SystemInformation) + SET(KWSYS_USE_Process 1) +ENDIF() +IF(KWSYS_USE_System) + SET(KWSYS_USE_Encoding 1) +ENDIF() +IF(KWSYS_USE_Directory) + SET(KWSYS_USE_Encoding 1) +ENDIF() +IF(KWSYS_USE_DynamicLoader) + SET(KWSYS_USE_Encoding 1) +ENDIF() +IF(KWSYS_USE_FStream) + SET(KWSYS_USE_Encoding 1) +ENDIF() +IF(KWSYS_USE_ConsoleBuf) + SET(KWSYS_USE_Encoding 1) +ENDIF() + +# Specify default 8 bit encoding for Windows +IF(NOT KWSYS_ENCODING_DEFAULT_CODEPAGE) + SET(KWSYS_ENCODING_DEFAULT_CODEPAGE CP_ACP) +ENDIF() + +# Enable testing if building standalone. +IF(KWSYS_STANDALONE) + INCLUDE(Dart) + MARK_AS_ADVANCED(BUILD_TESTING DART_ROOT TCL_TCLSH) + IF(BUILD_TESTING) + ENABLE_TESTING() + ENDIF() +ENDIF() + +# Choose default shared/static build if not specified. +IF(NOT DEFINED KWSYS_BUILD_SHARED) + SET(KWSYS_BUILD_SHARED ${BUILD_SHARED_LIBS}) +ENDIF() + +# Include helper macros. +INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/kwsysPlatformTests.cmake) +INCLUDE(CheckTypeSize) + +# Do full dependency headers. +INCLUDE_REGULAR_EXPRESSION("^.*$") + +# Use new KWSYS_INSTALL_*_DIR variable names to control installation. +# Take defaults from the old names. Note that there was no old name +# for the bin dir, so we take the old lib dir name so DLLs will be +# installed in a compatible way for old code. +IF(NOT KWSYS_INSTALL_INCLUDE_DIR) + STRING(REGEX REPLACE "^/" "" KWSYS_INSTALL_INCLUDE_DIR + "${KWSYS_HEADER_INSTALL_DIR}") +ENDIF() +IF(NOT KWSYS_INSTALL_LIB_DIR) + STRING(REGEX REPLACE "^/" "" KWSYS_INSTALL_LIB_DIR + "${KWSYS_LIBRARY_INSTALL_DIR}") +ENDIF() +IF(NOT KWSYS_INSTALL_BIN_DIR) + STRING(REGEX REPLACE "^/" "" KWSYS_INSTALL_BIN_DIR + "${KWSYS_LIBRARY_INSTALL_DIR}") +ENDIF() + +# Setup header install rules. +SET(KWSYS_INSTALL_INCLUDE_OPTIONS) +IF(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT) + SET(KWSYS_INSTALL_INCLUDE_OPTIONS ${KWSYS_INSTALL_INCLUDE_OPTIONS} + COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT} + ) +ENDIF() + +# Setup library install rules. +SET(KWSYS_INSTALL_LIBRARY_RULE) +SET(KWSYS_INSTALL_NAMELINK_RULE) +IF(KWSYS_INSTALL_LIB_DIR) + IF(KWSYS_INSTALL_EXPORT_NAME) + LIST(APPEND KWSYS_INSTALL_LIBRARY_RULE EXPORT ${KWSYS_INSTALL_EXPORT_NAME}) + ENDIF() + # Install the shared library to the lib directory. + SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE} + LIBRARY DESTINATION ${KWSYS_INSTALL_LIB_DIR} NAMELINK_SKIP + ) + # Assign the shared library to the runtime component. + IF(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME) + SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE} + COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_RUNTIME} + ) + ENDIF() + IF(KWSYS_BUILD_SHARED) + SET(KWSYS_INSTALL_NAMELINK_RULE ${KWSYS_INSTALL_NAMELINK_RULE} + LIBRARY DESTINATION ${KWSYS_INSTALL_LIB_DIR} NAMELINK_ONLY + ) + # Assign the namelink to the development component. + IF(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT) + SET(KWSYS_INSTALL_NAMELINK_RULE ${KWSYS_INSTALL_NAMELINK_RULE} + COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT} + ) + ENDIF() + ENDIF() + + # Install the archive to the lib directory. + SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE} + ARCHIVE DESTINATION ${KWSYS_INSTALL_LIB_DIR} + ) + # Assign the archive to the development component. + IF(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT) + SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE} + COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT} + ) + ENDIF() +ENDIF() +IF(KWSYS_INSTALL_BIN_DIR) + # Install the runtime library to the bin directory. + SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE} + RUNTIME DESTINATION ${KWSYS_INSTALL_BIN_DIR} + ) + # Assign the runtime library to the runtime component. + IF(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME) + SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE} + COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_RUNTIME} + ) + ENDIF() +ENDIF() + +# Do not support old KWSYS_*a_INSTALL_DIR variable names. +SET(KWSYS_HEADER_INSTALL_DIR) +SET(KWSYS_LIBRARY_INSTALL_DIR) + +# Generated source files will need this header. +STRING(COMPARE EQUAL "${PROJECT_SOURCE_DIR}" "${PROJECT_BINARY_DIR}" + KWSYS_IN_SOURCE_BUILD) +IF(NOT KWSYS_IN_SOURCE_BUILD) + CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/kwsysPrivate.h + ${PROJECT_BINARY_DIR}/kwsysPrivate.h COPYONLY IMMEDIATE) +ENDIF() + +# Select plugin module file name convention. +IF(NOT KWSYS_DynamicLoader_PREFIX) + SET(KWSYS_DynamicLoader_PREFIX ${CMAKE_SHARED_MODULE_PREFIX}) +ENDIF() +IF(NOT KWSYS_DynamicLoader_SUFFIX) + SET(KWSYS_DynamicLoader_SUFFIX ${CMAKE_SHARED_MODULE_SUFFIX}) +ENDIF() + +#----------------------------------------------------------------------------- +# We require ANSI support from the C compiler. Add any needed flags. +IF(CMAKE_ANSI_CFLAGS) + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_ANSI_CFLAGS}") +ENDIF() + +#----------------------------------------------------------------------------- +# Adjust compiler flags for some platforms. +IF(NOT CMAKE_COMPILER_IS_GNUCXX) + IF(CMAKE_SYSTEM MATCHES "OSF1-V.*") + STRING(REGEX MATCH "-timplicit_local" + KWSYS_CXX_FLAGS_HAVE_IMPLICIT_LOCAL "${CMAKE_CXX_FLAGS}") + STRING(REGEX MATCH "-no_implicit_include" + KWSYS_CXX_FLAGS_HAVE_NO_IMPLICIT_INCLUDE "${CMAKE_CXX_FLAGS}") + IF(NOT KWSYS_CXX_FLAGS_HAVE_IMPLICIT_LOCAL) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -timplicit_local") + ENDIF() + IF(NOT KWSYS_CXX_FLAGS_HAVE_NO_IMPLICIT_INCLUDE) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -no_implicit_include") + ENDIF() + ENDIF() + IF(CMAKE_SYSTEM MATCHES "HP-UX") + SET(KWSYS_PLATFORM_CXX_TEST_EXTRA_FLAGS "+p") + IF(CMAKE_CXX_COMPILER_ID MATCHES "HP") + # it is known that version 3.85 fails and 6.25 works without these flags + IF(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4) + # use new C++ library and improved template support + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -AA +hpxstd98") + ENDIF() + ENDIF() + ENDIF() +ENDIF() +IF(KWSYS_STANDALONE) + IF(CMAKE_CXX_COMPILER_ID STREQUAL SunPro) + IF(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.13) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++03") + ELSE() + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -library=stlport4") + ENDIF() + ENDIF() +ENDIF() + +#----------------------------------------------------------------------------- +# Configure the standard library header wrappers based on compiler's +# capabilities and parent project's request. Enforce 0/1 as only +# possible values for configuration into Configure.hxx. + +# Check existence and uniqueness of long long and __int64. +KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_LONG_LONG + "Checking whether C++ compiler has 'long long'" DIRECT) +KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS___INT64 + "Checking whether C++ compiler has '__int64'" DIRECT) +IF(KWSYS_CXX_HAS___INT64) + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_SAME_LONG_AND___INT64 + "Checking whether long and __int64 are the same type" DIRECT) + IF(KWSYS_CXX_HAS_LONG_LONG) + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_SAME_LONG_LONG_AND___INT64 + "Checking whether long long and __int64 are the same type" DIRECT) + ENDIF() +ENDIF() + +# Enable the "long long" type if it is available. It is standard in +# C99 and C++03 but not in earlier standards. +IF(KWSYS_CXX_HAS_LONG_LONG) + SET(KWSYS_USE_LONG_LONG 1) +ELSE() + SET(KWSYS_USE_LONG_LONG 0) +ENDIF() + +# Enable the "__int64" type if it is available and unique. It is not +# standard. +SET(KWSYS_USE___INT64 0) +IF(KWSYS_CXX_HAS___INT64) + IF(NOT KWSYS_CXX_SAME_LONG_AND___INT64) + IF(NOT KWSYS_CXX_SAME_LONG_LONG_AND___INT64) + SET(KWSYS_USE___INT64 1) + ENDIF() + ENDIF() +ENDIF() + +IF(KWSYS_USE_Encoding) + # Look for type size helper macros. + KWSYS_PLATFORM_CXX_TEST(KWSYS_STL_HAS_WSTRING + "Checking whether wstring is available" DIRECT) +ENDIF() + +IF(KWSYS_USE_IOStream) + # Determine whether iostreams support long long. + IF(KWSYS_CXX_HAS_LONG_LONG) + KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_ISTREAM_LONG_LONG + "Checking if istream supports long long" DIRECT) + KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_OSTREAM_LONG_LONG + "Checking if ostream supports long long" DIRECT) + ELSE() + SET(KWSYS_IOS_HAS_ISTREAM_LONG_LONG 0) + SET(KWSYS_IOS_HAS_OSTREAM_LONG_LONG 0) + ENDIF() + IF(KWSYS_CXX_HAS___INT64) + KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_ISTREAM___INT64 + "Checking if istream supports __int64" DIRECT) + KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_OSTREAM___INT64 + "Checking if ostream supports __int64" DIRECT) + ELSE() + SET(KWSYS_IOS_HAS_ISTREAM___INT64 0) + SET(KWSYS_IOS_HAS_OSTREAM___INT64 0) + ENDIF() +ENDIF() + +IF(KWSYS_NAMESPACE MATCHES "^kwsys$") + SET(KWSYS_NAME_IS_KWSYS 1) +ELSE() + SET(KWSYS_NAME_IS_KWSYS 0) +ENDIF() + +IF(KWSYS_BUILD_SHARED) + SET(KWSYS_BUILD_SHARED 1) + SET(KWSYS_LIBRARY_TYPE SHARED) +ELSE() + SET(KWSYS_BUILD_SHARED 0) + SET(KWSYS_LIBRARY_TYPE STATIC) +ENDIF() + +if(NOT DEFINED KWSYS_BUILD_PIC) + set(KWSYS_BUILD_PIC 0) +endif() + +#----------------------------------------------------------------------------- +# Configure some implementation details. + +KWSYS_PLATFORM_C_TEST(KWSYS_C_HAS_PTRDIFF_T + "Checking whether C compiler has ptrdiff_t in stddef.h" DIRECT) +KWSYS_PLATFORM_C_TEST(KWSYS_C_HAS_SSIZE_T + "Checking whether C compiler has ssize_t in unistd.h" DIRECT) +IF(KWSYS_USE_Process) + KWSYS_PLATFORM_C_TEST(KWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC + "Checking whether C compiler has clock_gettime" DIRECT) +ENDIF() + +SET_SOURCE_FILES_PROPERTIES(ProcessUNIX.c System.c PROPERTIES + COMPILE_FLAGS "-DKWSYS_C_HAS_PTRDIFF_T=${KWSYS_C_HAS_PTRDIFF_T} -DKWSYS_C_HAS_SSIZE_T=${KWSYS_C_HAS_SSIZE_T} -DKWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC=${KWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC}" + ) + +IF(DEFINED KWSYS_PROCESS_USE_SELECT) + GET_PROPERTY(ProcessUNIX_FLAGS SOURCE ProcessUNIX.c PROPERTY COMPILE_FLAGS) + SET_PROPERTY(SOURCE ProcessUNIX.c PROPERTY COMPILE_FLAGS "${ProcessUNIX_FLAGS} -DKWSYSPE_USE_SELECT=${KWSYSPE_USE_SELECT}") +ENDIF() + +IF(KWSYS_USE_DynamicLoader) + GET_PROPERTY(KWSYS_SUPPORTS_SHARED_LIBS GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS) + IF(KWSYS_SUPPORTS_SHARED_LIBS) + SET(KWSYS_SUPPORTS_SHARED_LIBS 1) + ELSE() + SET(KWSYS_SUPPORTS_SHARED_LIBS 0) + ENDIF() + SET_PROPERTY(SOURCE DynamicLoader.cxx APPEND PROPERTY COMPILE_DEFINITIONS + KWSYS_SUPPORTS_SHARED_LIBS=${KWSYS_SUPPORTS_SHARED_LIBS}) +ENDIF() + +IF(KWSYS_USE_SystemTools) + if (NOT DEFINED KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP) + set(KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP 1) + endif () + if (KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP) + set(KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP 1) + else () + set(KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP 0) + endif () + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_SETENV + "Checking whether CXX compiler has setenv" DIRECT) + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_UNSETENV + "Checking whether CXX compiler has unsetenv" DIRECT) + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H + "Checking whether CXX compiler has environ in stdlib.h" DIRECT) + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_UTIMES + "Checking whether CXX compiler has utimes" DIRECT) + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_UTIMENSAT + "Checking whether CXX compiler has utimensat" DIRECT) + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_STAT_HAS_ST_MTIM + "Checking whether CXX compiler struct stat has st_mtim member" DIRECT) + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_STAT_HAS_ST_MTIMESPEC + "Checking whether CXX compiler struct stat has st_mtimespec member" DIRECT) + SET_PROPERTY(SOURCE SystemTools.cxx APPEND PROPERTY COMPILE_DEFINITIONS + KWSYS_CXX_HAS_SETENV=${KWSYS_CXX_HAS_SETENV} + KWSYS_CXX_HAS_UNSETENV=${KWSYS_CXX_HAS_UNSETENV} + KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H=${KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H} + KWSYS_CXX_HAS_UTIMES=${KWSYS_CXX_HAS_UTIMES} + KWSYS_CXX_HAS_UTIMENSAT=${KWSYS_CXX_HAS_UTIMENSAT} + KWSYS_CXX_STAT_HAS_ST_MTIM=${KWSYS_CXX_STAT_HAS_ST_MTIM} + KWSYS_CXX_STAT_HAS_ST_MTIMESPEC=${KWSYS_CXX_STAT_HAS_ST_MTIMESPEC} + ) + IF(NOT WIN32) + IF(KWSYS_STANDALONE) + OPTION(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES "If true, Windows paths will be supported on Unix as well" ON) + ENDIF() + IF(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES) + SET_PROPERTY(SOURCE SystemTools.cxx testSystemTools.cxx APPEND PROPERTY COMPILE_DEFINITIONS + KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES + ) + ENDIF() + ENDIF() + + # Disable getpwnam for static linux builds since it depends on shared glibc + GET_PROPERTY(SHARED_LIBS_SUPPORTED GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS) + IF(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT SHARED_LIBS_SUPPORTED) + SET_PROPERTY(SOURCE SystemTools.cxx APPEND PROPERTY COMPILE_DEFINITIONS + HAVE_GETPWNAM=0 + ) + ENDIF() +ENDIF() + +IF(KWSYS_USE_SystemInformation) + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS SIZEOF_VOID_P=${CMAKE_SIZEOF_VOID_P}) + IF(NOT CYGWIN) + INCLUDE(CheckIncludeFiles) + CHECK_INCLUDE_FILES("sys/types.h;ifaddrs.h" KWSYS_SYS_HAS_IFADDRS_H) + IF(KWSYS_SYS_HAS_IFADDRS_H) + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_SYS_HAS_IFADDRS_H=1) + ENDIF() + ENDIF() + IF(WIN32) + INCLUDE(CheckSymbolExists) + SET(CMAKE_REQUIRED_LIBRARIES Psapi) + CHECK_SYMBOL_EXISTS(GetProcessMemoryInfo "windows.h;psapi.h" KWSYS_SYS_HAS_PSAPI) + UNSET(CMAKE_REQUIRED_LIBRARIES) + IF(KWSYS_SYS_HAS_PSAPI) + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_SYS_HAS_PSAPI=1) + IF(MSVC70 OR MSVC71) + # Suppress LNK4089: all references to 'PSAPI.DLL' discarded by /OPT:REF + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /IGNORE:4089") + ENDIF() + ENDIF() + ENDIF() + IF(CMAKE_SYSTEM MATCHES "HP-UX") + CHECK_INCLUDE_FILES("sys/mpctl.h" KWSYS_SYS_HAS_MPCTL_H) + IF(KWSYS_SYS_HAS_MPCTL_H) + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_SYS_HAS_MPCTL_H=1) + ENDIF() + ENDIF() + IF(CMAKE_SYSTEM MATCHES "BSD") + CHECK_INCLUDE_FILES("machine/cpu.h" KWSYS_SYS_HAS_MACHINE_CPU_H) + IF(KWSYS_SYS_HAS_MACHINE_CPU_H) + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_SYS_HAS_MACHINE_CPU_H=1) + ENDIF() + ENDIF() + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_RLIMIT64 + "Checking whether CXX compiler has rlimit64" DIRECT) + SET(KWSYS_PLATFORM_CXX_TEST_DEFINES) + IF(KWSYS_CXX_HAS_RLIMIT64) + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_CXX_HAS_RLIMIT64=1) + ENDIF() + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_ATOL + "Checking whether CXX compiler has atol" DIRECT) + IF(KWSYS_CXX_HAS_ATOL) + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_CXX_HAS_ATOL=1) + ENDIF() + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_ATOLL + "Checking whether CXX compiler has atoll" DIRECT) + IF(KWSYS_CXX_HAS_ATOLL) + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_CXX_HAS_ATOLL=1) + ENDIF() + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS__ATOI64 + "Checking whether CXX compiler has _atoi64" DIRECT) + IF(KWSYS_CXX_HAS__ATOI64) + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_CXX_HAS__ATOI64=1) + ENDIF() + IF(UNIX) + INCLUDE(CheckIncludeFileCXX) + # check for simple stack trace + # usually it's in libc but on FreeBSD + # it's in libexecinfo + FIND_LIBRARY(EXECINFO_LIB "execinfo") + MARK_AS_ADVANCED(EXECINFO_LIB) + IF (NOT EXECINFO_LIB) + SET(EXECINFO_LIB "") + ENDIF() + CHECK_INCLUDE_FILE_CXX("execinfo.h" KWSYS_CXX_HAS_EXECINFOH) + IF (KWSYS_CXX_HAS_EXECINFOH) + # we have the backtrace header check if it + # can be used with this compiler + SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES ${EXECINFO_LIB}) + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_BACKTRACE + "Checking whether backtrace works with this C++ compiler" DIRECT) + SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES) + IF (KWSYS_CXX_HAS_BACKTRACE) + # backtrace is supported by this system and compiler. + # now check for the more advanced capabilities. + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE=1) + # check for symbol lookup using dladdr + CHECK_INCLUDE_FILE_CXX("dlfcn.h" KWSYS_CXX_HAS_DLFCNH) + IF (KWSYS_CXX_HAS_DLFCNH) + # we have symbol lookup libraries and headers + # check if they can be used with this compiler + SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES ${CMAKE_DL_LIBS}) + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_DLADDR + "Checking whether dladdr works with this C++ compiler" DIRECT) + SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES) + IF (KWSYS_CXX_HAS_DLADDR) + # symbol lookup is supported by this system + # and compiler. + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP=1) + ENDIF() + ENDIF() + # c++ demangling support + # check for cxxabi headers + CHECK_INCLUDE_FILE_CXX("cxxabi.h" KWSYS_CXX_HAS_CXXABIH) + IF (KWSYS_CXX_HAS_CXXABIH) + # check if cxxabi can be used with this + # system and compiler. + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_CXXABI + "Checking whether cxxabi works with this C++ compiler" DIRECT) + IF (KWSYS_CXX_HAS_CXXABI) + # c++ demangle using cxxabi is supported with + # this system and compiler + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE=1) + ENDIF() + ENDIF() + # basic backtrace works better with release build + # don't bother with advanced features for release + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS_DEBUG KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD=1) + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS_RELWITHDEBINFO KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD=1) + ENDIF() + ENDIF() + ENDIF() + IF(BORLAND) + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_BORLAND_ASM + "Checking whether Borland CXX compiler supports assembler instructions" DIRECT) + IF(KWSYS_CXX_HAS_BORLAND_ASM) + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_CXX_HAS_BORLAND_ASM=1) + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_BORLAND_ASM_CPUID + "Checking whether Borland CXX compiler supports CPUID assembler instruction" DIRECT) + IF(KWSYS_CXX_HAS_BORLAND_ASM_CPUID) + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_CXX_HAS_BORLAND_ASM_CPUID=1) + ENDIF() + ENDIF() + ENDIF() + IF(KWSYS_USE___INT64) + SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_USE___INT64=1) + ENDIF() + IF(KWSYS_USE_LONG_LONG) + SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_USE_LONG_LONG=1) + ENDIF() + IF(KWSYS_IOS_HAS_OSTREAM_LONG_LONG) + SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_IOS_HAS_OSTREAM_LONG_LONG=1) + ENDIF() + IF(KWSYS_IOS_HAS_OSTREAM___INT64) + SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_IOS_HAS_OSTREAM___INT64=1) + ENDIF() + IF(KWSYS_BUILD_SHARED) + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_BUILD_SHARED=1) + ENDIF() + + IF(UNIX AND NOT CYGWIN) + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_GETLOADAVG + "Checking whether CXX compiler has getloadavg" DIRECT) + IF(KWSYS_CXX_HAS_GETLOADAVG) + SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY + COMPILE_DEFINITIONS KWSYS_CXX_HAS_GETLOADAVG=1) + ENDIF() + ENDIF() +ENDIF() + +IF(KWSYS_USE_FStream) + KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H + "Checking whether is available" DIRECT) +ENDIF() + +#----------------------------------------------------------------------------- +# Choose a directory for the generated headers. +IF(NOT KWSYS_HEADER_ROOT) + SET(KWSYS_HEADER_ROOT "${PROJECT_BINARY_DIR}") +ENDIF() +SET(KWSYS_HEADER_DIR "${KWSYS_HEADER_ROOT}/${KWSYS_NAMESPACE}") +INCLUDE_DIRECTORIES(${KWSYS_HEADER_ROOT}) + +#----------------------------------------------------------------------------- +IF(KWSYS_INSTALL_DOC_DIR) + # Assign the license to the runtime component since it must be + # distributed with binary forms of this software. + IF(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME) + SET(KWSYS_INSTALL_LICENSE_OPTIONS ${KWSYS_INSTALL_LICENSE_OPTIONS} + COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_RUNTIME} + ) + ENDIF() + + # Install the license under the documentation directory. + INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/Copyright.txt + DESTINATION ${KWSYS_INSTALL_DOC_DIR}/${KWSYS_NAMESPACE} + ${KWSYS_INSTALL_LICENSE_OPTIONS}) +ENDIF() + +#----------------------------------------------------------------------------- +# Build a list of classes and headers we need to implement the +# selected components. Initialize with required components. +SET(KWSYS_CLASSES) +SET(KWSYS_H_FILES Configure SharedForward) +SET(KWSYS_HXX_FILES Configure String) + +IF(NOT CMake_SOURCE_DIR) + SET(KWSYS_HXX_FILES ${KWSYS_HXX_FILES} + hashtable hash_fun hash_map hash_set + ) +ENDIF() + +# Add selected C++ classes. +SET(cppclasses + Directory DynamicLoader Encoding Glob RegularExpression SystemTools + CommandLineArguments IOStream FStream SystemInformation ConsoleBuf + ) +FOREACH(cpp ${cppclasses}) + IF(KWSYS_USE_${cpp}) + # Use the corresponding class. + SET(KWSYS_CLASSES ${KWSYS_CLASSES} ${cpp}) + + # Load component-specific CMake code. + IF(EXISTS ${PROJECT_SOURCE_DIR}/kwsys${cpp}.cmake) + INCLUDE(${PROJECT_SOURCE_DIR}/kwsys${cpp}.cmake) + ENDIF() + ENDIF() +ENDFOREACH() + +# Add selected C components. +FOREACH(c + Process Base64 Encoding MD5 Terminal System String + ) + IF(KWSYS_USE_${c}) + # Use the corresponding header file. + SET(KWSYS_H_FILES ${KWSYS_H_FILES} ${c}) + + # Load component-specific CMake code. + IF(EXISTS ${PROJECT_SOURCE_DIR}/kwsys${c}.cmake) + INCLUDE(${PROJECT_SOURCE_DIR}/kwsys${c}.cmake) + ENDIF() + ENDIF() +ENDFOREACH() + +#----------------------------------------------------------------------------- +# Build a list of sources for the library based on components that are +# included. +SET(KWSYS_C_SRCS) +SET(KWSYS_CXX_SRCS) + +# Add the proper sources for this platform's Process implementation. +IF(KWSYS_USE_Process) + IF(NOT UNIX) + # Use the Windows implementation. + SET(KWSYS_C_SRCS ${KWSYS_C_SRCS} ProcessWin32.c) + ELSE() + # Use the UNIX implementation. + SET(KWSYS_C_SRCS ${KWSYS_C_SRCS} ProcessUNIX.c) + ENDIF() +ENDIF() + +# Add selected C sources. +FOREACH(c Base64 Encoding MD5 Terminal System String) + IF(KWSYS_USE_${c}) + IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${c}C.c) + LIST(APPEND KWSYS_C_SRCS ${c}C.c) + ELSE() + LIST(APPEND KWSYS_C_SRCS ${c}.c) + ENDIF() + ENDIF() +ENDFOREACH() + +# Configure headers of C++ classes and construct the list of sources. +FOREACH(c ${KWSYS_CLASSES}) + # Add this source to the list of source files for the library. + IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${c}CXX.cxx) + LIST(APPEND KWSYS_CXX_SRCS ${c}CXX.cxx) + ELSEIF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${c}.cxx) + LIST(APPEND KWSYS_CXX_SRCS ${c}.cxx) + ENDIF() + + # Configure the header for this class. + CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/${c}.hxx.in ${KWSYS_HEADER_DIR}/${c}.hxx + @ONLY IMMEDIATE) + SET(KWSYS_CXX_SRCS ${KWSYS_CXX_SRCS} ${KWSYS_HEADER_DIR}/${c}.hxx) + + # Create an install target for the header. + IF(KWSYS_INSTALL_INCLUDE_DIR) + INSTALL(FILES ${KWSYS_HEADER_DIR}/${c}.hxx + DESTINATION ${KWSYS_INSTALL_INCLUDE_DIR}/${KWSYS_NAMESPACE} + ${KWSYS_INSTALL_INCLUDE_OPTIONS}) + ENDIF() +ENDFOREACH() + +# Configure C headers. +FOREACH(h ${KWSYS_H_FILES}) + # Configure the header into the given directory. + CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/${h}.h.in ${KWSYS_HEADER_DIR}/${h}.h + @ONLY IMMEDIATE) + SET(KWSYS_C_SRCS ${KWSYS_C_SRCS} ${KWSYS_HEADER_DIR}/${h}.h) + + # Create an install target for the header. + IF(KWSYS_INSTALL_INCLUDE_DIR) + INSTALL(FILES ${KWSYS_HEADER_DIR}/${h}.h + DESTINATION ${KWSYS_INSTALL_INCLUDE_DIR}/${KWSYS_NAMESPACE} + ${KWSYS_INSTALL_INCLUDE_OPTIONS}) + ENDIF() +ENDFOREACH() + +# Configure other C++ headers. +FOREACH(h ${KWSYS_HXX_FILES}) + # Configure the header into the given directory. + CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/${h}.hxx.in ${KWSYS_HEADER_DIR}/${h}.hxx + @ONLY IMMEDIATE) + SET(KWSYS_CXX_SRCS ${KWSYS_CXX_SRCS} ${KWSYS_HEADER_DIR}/${h}.hxx) + + # Create an install target for the header. + IF(KWSYS_INSTALL_INCLUDE_DIR) + INSTALL(FILES ${KWSYS_HEADER_DIR}/${h}.hxx + DESTINATION ${KWSYS_INSTALL_INCLUDE_DIR}/${KWSYS_NAMESPACE} + ${KWSYS_INSTALL_INCLUDE_OPTIONS}) + ENDIF() +ENDFOREACH() + +#----------------------------------------------------------------------------- +# Add the library with the configured name and list of sources. +IF(KWSYS_C_SRCS OR KWSYS_CXX_SRCS) + IF(KWSYS_SPLIT_OBJECTS_FROM_INTERFACE) + SET(KWSYS_TARGET_INTERFACE ${KWSYS_NAMESPACE}) + SET(KWSYS_TARGET_OBJECT ${KWSYS_NAMESPACE}_objects) + SET(KWSYS_TARGET_LINK ${KWSYS_NAMESPACE}_private) + SET(KWSYS_TARGET_INSTALL ${KWSYS_TARGET_INTERFACE} ${KWSYS_TARGET_LINK}) + SET(KWSYS_LINK_DEPENDENCY INTERFACE) + ADD_LIBRARY(${KWSYS_TARGET_OBJECT} OBJECT + ${KWSYS_C_SRCS} ${KWSYS_CXX_SRCS}) + IF(KWSYS_BUILD_SHARED OR KWSYS_BUILD_PIC) + SET_PROPERTY(TARGET ${KWSYS_TARGET_OBJECT} PROPERTY + POSITION_INDEPENDENT_CODE TRUE) + ENDIF() + ADD_LIBRARY(${KWSYS_TARGET_INTERFACE} INTERFACE) + ADD_LIBRARY(${KWSYS_TARGET_LINK} INTERFACE) + TARGET_LINK_LIBRARIES(${KWSYS_TARGET_LINK} INTERFACE + ${KWSYS_TARGET_INTERFACE}) + TARGET_SOURCES(${KWSYS_TARGET_LINK} INTERFACE + $) + target_compile_features(${KWSYS_TARGET_OBJECT} PRIVATE ${KWSYS_CXX_COMPILE_FEATURES}) + target_compile_features(${KWSYS_TARGET_INTERFACE} INTERFACE ${KWSYS_CXX_COMPILE_FEATURES}) + ELSE() + SET(KWSYS_TARGET_INTERFACE ${KWSYS_NAMESPACE}) + SET(KWSYS_TARGET_OBJECT ${KWSYS_NAMESPACE}) + SET(KWSYS_TARGET_LINK ${KWSYS_NAMESPACE}) + set(KWSYS_TARGET_INSTALL ${KWSYS_TARGET_LINK}) + SET(KWSYS_LINK_DEPENDENCY PUBLIC) + ADD_LIBRARY(${KWSYS_TARGET_INTERFACE} ${KWSYS_LIBRARY_TYPE} + ${KWSYS_C_SRCS} ${KWSYS_CXX_SRCS}) + target_compile_features(${KWSYS_TARGET_INTERFACE} PUBLIC ${KWSYS_CXX_COMPILE_FEATURES}) + ENDIF() + if (KWSYS_ALIAS_TARGET) + add_library(${KWSYS_ALIAS_TARGET} ALIAS ${KWSYS_TARGET_INTERFACE}) + endif () + SET_TARGET_PROPERTIES(${KWSYS_TARGET_OBJECT} PROPERTIES + C_CLANG_TIDY "" + CXX_CLANG_TIDY "" + C_INCLUDE_WHAT_YOU_USE "" + CXX_INCLUDE_WHAT_YOU_USE "" + LABELS "${KWSYS_LABELS_LIB}") + IF(KWSYS_USE_DynamicLoader) + IF(UNIX) + TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} + ${CMAKE_DL_LIBS}) + ENDIF() + ENDIF() + + IF(KWSYS_USE_SystemInformation) + IF(WIN32) + TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} ws2_32) + # link in dbghelp.dll for symbol lookup if MSVC 1800 or later + # Note that the dbghelp runtime is part of MS Windows OS + IF(MSVC_VERSION AND NOT MSVC_VERSION VERSION_LESS 1800) + TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} dbghelp) + ENDIF() + IF(KWSYS_SYS_HAS_PSAPI) + TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} + Psapi) + ENDIF() + ELSEIF(UNIX) + IF (EXECINFO_LIB AND KWSYS_CXX_HAS_BACKTRACE) + # backtrace on FreeBSD is not in libc + TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} + ${EXECINFO_LIB}) + ENDIF() + IF (KWSYS_CXX_HAS_DLADDR) + # for symbol lookup using dladdr + TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} + ${CMAKE_DL_LIBS}) + ENDIF() + IF (CMAKE_SYSTEM_NAME STREQUAL "SunOS") + TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} + socket) + ENDIF() + ENDIF() + ENDIF() + + # Apply user-defined target properties to the library. + IF(KWSYS_PROPERTIES_CXX) + SET_TARGET_PROPERTIES(${KWSYS_TARGET_INTERFACE} PROPERTIES + ${KWSYS_PROPERTIES_CXX}) + ENDIF() + + # Set up include usage requirement + IF(COMMAND TARGET_INCLUDE_DIRECTORIES) + TARGET_INCLUDE_DIRECTORIES(${KWSYS_TARGET_INTERFACE} INTERFACE + $) + IF(KWSYS_INSTALL_INCLUDE_DIR) + TARGET_INCLUDE_DIRECTORIES(${KWSYS_TARGET_INTERFACE} INTERFACE + $) + ENDIF() + ENDIF() + + # Create an install target for the library. + IF(KWSYS_INSTALL_LIBRARY_RULE) + INSTALL(TARGETS ${KWSYS_TARGET_INSTALL} ${KWSYS_INSTALL_LIBRARY_RULE}) + ENDIF() + IF(KWSYS_INSTALL_NAMELINK_RULE) + INSTALL(TARGETS ${KWSYS_TARGET_INSTALL} ${KWSYS_INSTALL_NAMELINK_RULE}) + ENDIF() +ENDIF() + +# Add a C-only library if requested. +IF(KWSYS_ENABLE_C AND KWSYS_C_SRCS) + IF(KWSYS_SPLIT_OBJECTS_FROM_INTERFACE) + SET(KWSYS_TARGET_C_INTERFACE ${KWSYS_NAMESPACE}_c) + SET(KWSYS_TARGET_C_OBJECT ${KWSYS_NAMESPACE}_c_objects) + SET(KWSYS_TARGET_C_LINK ${KWSYS_NAMESPACE}_c_private) + SET(KWSYS_TARGET_C_INSTALL + ${KWSYS_TARGET_C_INTERFACE} ${KWSYS_TARGET_C_LINK}) + SET(KWSYS_LINK_DEPENDENCY INTERFACE) + ADD_LIBRARY(${KWSYS_TARGET_C_OBJECT} OBJECT ${KWSYS_C_SRCS}) + IF(KWSYS_BUILD_SHARED OR KWSYS_BUILD_PIC) + SET_PROPERTY(TARGET ${KWSYS_TARGET_C_OBJECT} PROPERTY + POSITION_INDEPENDENT_CODE TRUE) + ENDIF() + ADD_LIBRARY(${KWSYS_TARGET_C_INTERFACE} INTERFACE) + ADD_LIBRARY(${KWSYS_TARGET_C_LINK} INTERFACE) + TARGET_LINK_LIBRARIES(${KWSYS_TARGET_C_LINK} INTERFACE + ${KWSYS_TARGET_C_INTERFACE}) + TARGET_SOURCES(${KWSYS_TARGET_C_LINK} INTERFACE + $) + ELSE() + SET(KWSYS_TARGET_C_INTERFACE ${KWSYS_NAMESPACE}_c) + SET(KWSYS_TARGET_C_OBJECT ${KWSYS_NAMESPACE}_c) + SET(KWSYS_TARGET_C_LINK ${KWSYS_NAMESPACE}_c) + SET(KWSYS_TARGET_C_INSTALL ${KWSYS_TARGET_C_LINK}) + SET(KWSYS_LINK_DEPENDENCY PUBLIC) + ADD_LIBRARY(${KWSYS_TARGET_C_INTERFACE} ${KWSYS_LIBRARY_TYPE} + ${KWSYS_C_SRCS}) + ENDIF() + SET_TARGET_PROPERTIES(${KWSYS_TARGET_C_OBJECT} PROPERTIES + LABELS "${KWSYS_LABELS_LIB}") + + # Apply user-defined target properties to the library. + IF(KWSYS_PROPERTIES_C) + SET_TARGET_PROPERTIES(${KWSYS_TARGET_C_INTERFACE} PROPERTIES + ${KWSYS_PROPERTIES_C}) + ENDIF() + + # Set up include usage requirement + IF(COMMAND TARGET_INCLUDE_DIRECTORIES) + TARGET_INCLUDE_DIRECTORIES(${KWSYS_TARGET_C_INTERFACE} INTERFACE + $) + IF(KWSYS_INSTALL_INCLUDE_DIR) + TARGET_INCLUDE_DIRECTORIES(${KWSYS_TARGET_C_INTERFACE} INTERFACE + $) + ENDIF() + ENDIF() + + # Create an install target for the library. + IF(KWSYS_INSTALL_LIBRARY_RULE) + INSTALL(TARGETS ${KWSYS_TARGET_C_INSTALL}) + ENDIF() +ENDIF() + +# For building kwsys itself, we use a macro defined on the command +# line to configure the namespace in the C and C++ source files. +ADD_DEFINITIONS("-DKWSYS_NAMESPACE=${KWSYS_NAMESPACE}") + +# Disable deprecation warnings for standard C functions. +IF(MSVC OR (WIN32 AND (CMAKE_C_COMPILER_ID STREQUAL "Intel" OR + (CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")))) + ADD_DEFINITIONS( + -D_CRT_NONSTDC_NO_DEPRECATE + -D_CRT_SECURE_NO_DEPRECATE + -D_CRT_SECURE_NO_WARNINGS + -D_SCL_SECURE_NO_DEPRECATE + ) +ENDIF() + +IF(WIN32) + # Help enforce the use of wide Windows apis. + ADD_DEFINITIONS(-DUNICODE -D_UNICODE) +ENDIF() + +IF(KWSYS_USE_String) + # Activate code in "String.c". See the comment in the source. + SET_SOURCE_FILES_PROPERTIES(String.c PROPERTIES + COMPILE_FLAGS "-DKWSYS_STRING_C") +ENDIF() + +IF(KWSYS_USE_Encoding) + # Set default 8 bit encoding in "EndcodingC.c". + SET_PROPERTY(SOURCE EncodingC.c EncodingCXX.cxx APPEND PROPERTY COMPILE_DEFINITIONS + KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE}) +ENDIF() + +#----------------------------------------------------------------------------- +# Setup testing if not being built as part of another project. +IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) + IF(BUILD_TESTING) + # Compute the location of executables. + SET(EXEC_DIR "${CMAKE_CURRENT_BINARY_DIR}") + IF(EXECUTABLE_OUTPUT_PATH) + SET(EXEC_DIR "${EXECUTABLE_OUTPUT_PATH}") + ENDIF() + + # C tests + SET(KWSYS_C_TESTS + testEncode.c + testTerminal.c + ) + IF(KWSYS_STANDALONE) + SET(KWSYS_C_TESTS ${KWSYS_C_TESTS} testFail.c) + ENDIF() + CREATE_TEST_SOURCELIST( + KWSYS_C_TEST_SRCS ${KWSYS_NAMESPACE}TestsC.c + ${KWSYS_C_TESTS} + ) + ADD_EXECUTABLE(${KWSYS_NAMESPACE}TestsC ${KWSYS_C_TEST_SRCS}) + SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsC PROPERTY LABELS ${KWSYS_LABELS_EXE}) + TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE}TestsC ${KWSYS_TARGET_C_LINK}) + FOREACH(testfile ${KWSYS_C_TESTS}) + get_filename_component(test "${testfile}" NAME_WE) + ADD_TEST(kwsys.${test} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestsC ${test} ${KWSYS_TEST_ARGS_${test}}) + SET_PROPERTY(TEST kwsys.${test} PROPERTY LABELS ${KWSYS_LABELS_TEST}) + ENDFOREACH() + + # C++ tests + IF(NOT WATCOM AND NOT CMake_SOURCE_DIR) + SET(KWSYS_CXX_TESTS + testHashSTL.cxx + ) + ENDIF() + SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} + testConfigure.cxx + testSystemTools.cxx + testCommandLineArguments.cxx + testCommandLineArguments1.cxx + testDirectory.cxx + ) + IF(KWSYS_STL_HAS_WSTRING) + SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} + testEncoding.cxx + ) + ENDIF() + IF(KWSYS_USE_FStream) + SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} + testFStream.cxx + ) + ENDIF() + IF(KWSYS_USE_ConsoleBuf) + ADD_EXECUTABLE(testConsoleBufChild testConsoleBufChild.cxx) + SET_PROPERTY(TARGET testConsoleBufChild PROPERTY C_CLANG_TIDY "") + SET_PROPERTY(TARGET testConsoleBufChild PROPERTY CXX_CLANG_TIDY "") + SET_PROPERTY(TARGET testConsoleBufChild PROPERTY C_INCLUDE_WHAT_YOU_USE "") + SET_PROPERTY(TARGET testConsoleBufChild PROPERTY CXX_INCLUDE_WHAT_YOU_USE "") + SET_PROPERTY(TARGET testConsoleBufChild PROPERTY LABELS ${KWSYS_LABELS_EXE}) + TARGET_LINK_LIBRARIES(testConsoleBufChild ${KWSYS_TARGET_LINK}) + SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} + testConsoleBuf.cxx + ) + IF(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND + CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "19.0.23506") + set_property(SOURCE testConsoleBuf.cxx testConsoleBufChild.cxx PROPERTY COMPILE_FLAGS /utf-8) + ENDIF() + SET_PROPERTY(SOURCE testConsoleBuf.cxx APPEND PROPERTY COMPILE_DEFINITIONS + KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE}) + ENDIF() + IF(KWSYS_USE_SystemInformation) + SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testSystemInformation.cxx) + ENDIF() + IF(KWSYS_USE_DynamicLoader) + SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testDynamicLoader.cxx) + # If kwsys contains the DynamicLoader, need extra library + ADD_LIBRARY(${KWSYS_NAMESPACE}TestDynload MODULE testDynload.c) + SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestDynload PROPERTY LABELS ${KWSYS_LABELS_LIB}) + ADD_DEPENDENCIES(${KWSYS_NAMESPACE}TestDynload ${KWSYS_TARGET_INTERFACE}) + + if (WIN32) + # Windows tests supported flags. + add_library(${KWSYS_NAMESPACE}TestDynloadImpl SHARED testDynloadImpl.c) + set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadImpl PROPERTY LABELS ${KWSYS_LABELS_LIB}) + set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadImpl PROPERTY DEFINE_SYMBOL BUILDING_TestDynloadImpl) + set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadImpl PROPERTY RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynloaddir") + add_dependencies(${KWSYS_NAMESPACE}TestDynloadImpl ${KWSYS_TARGET_INTERFACE}) + add_library(${KWSYS_NAMESPACE}TestDynloadUse MODULE testDynloadUse.c) + set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadUse PROPERTY LABELS ${KWSYS_LABELS_LIB}) + set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadUse PROPERTY LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynloaddir") + add_dependencies(${KWSYS_NAMESPACE}TestDynloadUse ${KWSYS_TARGET_INTERFACE}) + target_link_libraries(${KWSYS_NAMESPACE}TestDynloadUse PRIVATE ${KWSYS_NAMESPACE}TestDynloadImpl) + endif () + ENDIF() + CREATE_TEST_SOURCELIST( + KWSYS_CXX_TEST_SRCS ${KWSYS_NAMESPACE}TestsCxx.cxx + ${KWSYS_CXX_TESTS} + ) + ADD_EXECUTABLE(${KWSYS_NAMESPACE}TestsCxx ${KWSYS_CXX_TEST_SRCS}) + SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY C_CLANG_TIDY "") + SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY CXX_CLANG_TIDY "") + SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY C_INCLUDE_WHAT_YOU_USE "") + SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY CXX_INCLUDE_WHAT_YOU_USE "") + SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY LABELS ${KWSYS_LABELS_EXE}) + TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE}TestsCxx ${KWSYS_TARGET_LINK}) + + SET(TEST_SYSTEMTOOLS_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + SET(TEST_SYSTEMTOOLS_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}") + CONFIGURE_FILE( + ${PROJECT_SOURCE_DIR}/testSystemTools.h.in + ${PROJECT_BINARY_DIR}/testSystemTools.h) + INCLUDE_DIRECTORIES(${PROJECT_BINARY_DIR}) + + IF(CTEST_TEST_KWSYS) + CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/ExtraTest.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/ExtraTest.cmake") + SET_DIRECTORY_PROPERTIES(PROPERTIES TEST_INCLUDE_FILE "${CMAKE_CURRENT_BINARY_DIR}/ExtraTest.cmake") + ENDIF() + + SET(KWSYS_TEST_ARGS_testCommandLineArguments + --another-bool-variable + --long3=opt + --set-bool-arg1 + -SSS ken brad bill andy + --some-bool-variable=true + --some-double-variable12.5 + --some-int-variable 14 + "--some-string-variable=test string with space" + --some-multi-argument 5 1 8 3 7 1 3 9 7 1 + -N 12.5 -SS=andy -N 1.31 -N 22 + -SS=bill -BBtrue -SS=brad + -BBtrue + -BBfalse + -SS=ken + -A + -C=test + --long2 hello + ) + SET(KWSYS_TEST_ARGS_testCommandLineArguments1 + --ignored + -n 24 + --second-ignored + "-m=test value" + third-ignored + -p + some junk at the end + ) + FOREACH(testfile ${KWSYS_CXX_TESTS}) + get_filename_component(test "${testfile}" NAME_WE) + ADD_TEST(kwsys.${test} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestsCxx ${test} ${KWSYS_TEST_ARGS_${test}}) + SET_PROPERTY(TEST kwsys.${test} PROPERTY LABELS ${KWSYS_LABELS_TEST}) + ENDFOREACH() + + # Process tests. + ADD_EXECUTABLE(${KWSYS_NAMESPACE}TestProcess testProcess.c) + SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestProcess PROPERTY LABELS ${KWSYS_LABELS_EXE}) + TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE}TestProcess ${KWSYS_TARGET_C_LINK}) + IF(NOT CYGWIN) + SET(KWSYS_TEST_PROCESS_7 7) + ENDIF() + FOREACH(n 1 2 3 4 5 6 ${KWSYS_TEST_PROCESS_7} 9 10) + ADD_TEST(kwsys.testProcess-${n} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestProcess ${n}) + SET_PROPERTY(TEST kwsys.testProcess-${n} PROPERTY LABELS ${KWSYS_LABELS_TEST}) + SET_TESTS_PROPERTIES(kwsys.testProcess-${n} PROPERTIES TIMEOUT 120) + ENDFOREACH() + + SET(testProcess_COMPILE_FLAGS "") + # Some Apple compilers produce bad optimizations in this source. + IF(APPLE AND CMAKE_C_COMPILER_ID MATCHES "^(GNU|LLVM)$") + SET(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -O0") + ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "XL") + # Tell IBM XL not to warn about our test infinite loop + IF(CMAKE_SYSTEM MATCHES "Linux.*ppc64le" + AND CMAKE_C_COMPILER_VERSION VERSION_LESS "16.1.0" + AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS "13.1.1") + # v13.1.[1-6] on Linux ppc64le is clang based and does not accept + # the -qsuppress option, so just suppress all warnings. + SET(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -w") + ELSE() + SET(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -qsuppress=1500-010") + ENDIF() + ENDIF() + IF(CMAKE_C_FLAGS MATCHES "-fsanitize=") + SET(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -DCRASH_USING_ABORT") + ENDIF() + SET_PROPERTY(SOURCE testProcess.c PROPERTY COMPILE_FLAGS "${testProcess_COMPILE_FLAGS}") + + # Test SharedForward + CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/testSharedForward.c.in + ${PROJECT_BINARY_DIR}/testSharedForward.c @ONLY IMMEDIATE) + ADD_EXECUTABLE(${KWSYS_NAMESPACE}TestSharedForward + ${PROJECT_BINARY_DIR}/testSharedForward.c) + SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestSharedForward PROPERTY LABELS ${KWSYS_LABELS_EXE}) + ADD_DEPENDENCIES(${KWSYS_NAMESPACE}TestSharedForward ${KWSYS_TARGET_C_LINK}) + ADD_TEST(kwsys.testSharedForward ${EXEC_DIR}/${KWSYS_NAMESPACE}TestSharedForward 1) + SET_PROPERTY(TEST kwsys.testSharedForward PROPERTY LABELS ${KWSYS_LABELS_TEST}) + + # Configure some test properties. + IF(KWSYS_STANDALONE) + # We expect test to fail + SET_TESTS_PROPERTIES(kwsys.testFail PROPERTIES WILL_FAIL ON) + GET_TEST_PROPERTY(kwsys.testFail WILL_FAIL wfv) + SET_TESTS_PROPERTIES(kwsys.testFail PROPERTIES MEASUREMENT "Some Key=Some Value") + MESSAGE(STATUS "GET_TEST_PROPERTY returned: ${wfv}") + ENDIF() + + # Set up ctest custom configuration file. + CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/CTestCustom.cmake.in + ${PROJECT_BINARY_DIR}/CTestCustom.cmake @ONLY) + + # Suppress known consistent failures on buggy systems. + IF(KWSYS_TEST_BOGUS_FAILURES) + SET_TESTS_PROPERTIES(${KWSYS_TEST_BOGUS_FAILURES} PROPERTIES WILL_FAIL ON) + ENDIF() + + ENDIF() +ENDIF() diff --git a/test/API/driver/kwsys/CONTRIBUTING.rst b/test/API/driver/kwsys/CONTRIBUTING.rst new file mode 100644 index 0000000..32e7b83 --- /dev/null +++ b/test/API/driver/kwsys/CONTRIBUTING.rst @@ -0,0 +1,49 @@ +Contributing to KWSys +********************* + +Patches +======= + +KWSys is kept in its own Git repository and shared by several projects +via copies in their source trees. Changes to KWSys should not be made +directly in a host project, except perhaps in maintenance branches. + +KWSys uses `Kitware's GitLab Instance`_ to manage development and code review. +To contribute patches: + +#. Fork the upstream `KWSys Repository`_ into a personal account. +#. Base all new work on the upstream ``master`` branch. +#. Run ``./SetupForDevelopment.sh`` in new local work trees. +#. Create commits making incremental, distinct, logically complete changes. +#. Push a topic branch to a personal repository fork on GitLab. +#. Create a GitLab Merge Request targeting the upstream ``master`` branch. + +Once changes are reviewed, tested, and integrated to KWSys upstream then +copies of KWSys within dependent projects can be updated to get the changes. + +.. _`Kitware's GitLab Instance`: https://gitlab.kitware.com +.. _`KWSys Repository`: https://gitlab.kitware.com/utils/kwsys + +Code Style +========== + +We use `clang-format`_ version **6.0** to define our style for C++ code in +the KWSys source tree. See the `.clang-format`_ configuration file for +our style settings. Use the `clang-format.bash`_ script to format source +code. It automatically runs ``clang-format`` on the set of source files +for which we enforce style. The script also has options to format only +a subset of files, such as those that are locally modified. + +.. _`clang-format`: http://clang.llvm.org/docs/ClangFormat.html +.. _`.clang-format`: .clang-format +.. _`clang-format.bash`: clang-format.bash + +License +======= + +We do not require any formal copyright assignment or contributor license +agreement. Any contributions intentionally sent upstream are presumed +to be offered under terms of the OSI-approved BSD 3-clause License. +See `Copyright.txt`_ for details. + +.. _`Copyright.txt`: Copyright.txt diff --git a/test/API/driver/kwsys/CTestConfig.cmake b/test/API/driver/kwsys/CTestConfig.cmake new file mode 100644 index 0000000..1339ffc --- /dev/null +++ b/test/API/driver/kwsys/CTestConfig.cmake @@ -0,0 +1,9 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing#kwsys for details. + +set(CTEST_PROJECT_NAME "KWSys") +set(CTEST_NIGHTLY_START_TIME "21:00:00 EDT") +set(CTEST_DROP_METHOD "http") +set(CTEST_DROP_SITE "open.cdash.org") +set(CTEST_DROP_LOCATION "/submit.php?project=KWSys") +set(CTEST_DROP_SITE_CDASH TRUE) diff --git a/test/API/driver/kwsys/CTestCustom.cmake.in b/test/API/driver/kwsys/CTestCustom.cmake.in new file mode 100644 index 0000000..760221b --- /dev/null +++ b/test/API/driver/kwsys/CTestCustom.cmake.in @@ -0,0 +1,14 @@ +# kwsys.testProcess-10 involves sending SIGINT to a child process, which then +# exits abnormally via a call to _exit(). (On Windows, a call to ExitProcess). +# Naturally, this results in plenty of memory being "leaked" by this child +# process - the memory check results are not meaningful in this case. +# +# kwsys.testProcess-9 also tests sending SIGINT to a child process. However, +# normal operation of that test involves the child process timing out, and the +# host process kills (SIGKILL) it as a result. Since it was SIGKILL'ed, the +# resulting memory leaks are not logged by valgrind anyway. Therefore, we +# don't have to exclude it. + +list(APPEND CTEST_CUSTOM_MEMCHECK_IGNORE + kwsys.testProcess-10 + ) diff --git a/test/API/driver/kwsys/CommandLineArguments.cxx b/test/API/driver/kwsys/CommandLineArguments.cxx new file mode 100644 index 0000000..3fd1955 --- /dev/null +++ b/test/API/driver/kwsys/CommandLineArguments.cxx @@ -0,0 +1,768 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(CommandLineArguments.hxx) + +#include KWSYS_HEADER(Configure.hxx) +#include KWSYS_HEADER(String.hxx) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "CommandLineArguments.hxx.in" +# include "Configure.hxx.in" +# include "String.hxx.in" +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef _MSC_VER +# pragma warning(disable : 4786) +#endif + +#if defined(__sgi) && !defined(__GNUC__) +# pragma set woff 1375 /* base class destructor not virtual */ +#endif + +#if 0 +# define CommandLineArguments_DEBUG(x) \ + std::cout << __LINE__ << " CLA: " << x << std::endl +#else +# define CommandLineArguments_DEBUG(x) +#endif + +namespace KWSYS_NAMESPACE { + +struct CommandLineArgumentsCallbackStructure +{ + const char* Argument; + int ArgumentType; + CommandLineArguments::CallbackType Callback; + void* CallData; + void* Variable; + int VariableType; + const char* Help; +}; + +class CommandLineArgumentsVectorOfStrings : public std::vector +{ +}; +class CommandLineArgumentsSetOfStrings : public std::set +{ +}; +class CommandLineArgumentsMapOfStrucs + : public std::map +{ +}; + +class CommandLineArgumentsInternal +{ +public: + CommandLineArgumentsInternal() + : UnknownArgumentCallback{ nullptr } + , ClientData{ nullptr } + , LastArgument{ 0 } + { + } + + typedef CommandLineArgumentsVectorOfStrings VectorOfStrings; + typedef CommandLineArgumentsMapOfStrucs CallbacksMap; + typedef kwsys::String String; + typedef CommandLineArgumentsSetOfStrings SetOfStrings; + + VectorOfStrings Argv; + String Argv0; + CallbacksMap Callbacks; + + CommandLineArguments::ErrorCallbackType UnknownArgumentCallback; + void* ClientData; + + VectorOfStrings::size_type LastArgument; + + VectorOfStrings UnusedArguments; +}; + +CommandLineArguments::CommandLineArguments() +{ + this->Internals = new CommandLineArguments::Internal; + this->Help = ""; + this->LineLength = 80; + this->StoreUnusedArgumentsFlag = false; +} + +CommandLineArguments::~CommandLineArguments() +{ + delete this->Internals; +} + +void CommandLineArguments::Initialize(int argc, const char* const argv[]) +{ + int cc; + + this->Initialize(); + this->Internals->Argv0 = argv[0]; + for (cc = 1; cc < argc; cc++) { + this->ProcessArgument(argv[cc]); + } +} + +void CommandLineArguments::Initialize(int argc, char* argv[]) +{ + this->Initialize(argc, static_cast(argv)); +} + +void CommandLineArguments::Initialize() +{ + this->Internals->Argv.clear(); + this->Internals->LastArgument = 0; +} + +void CommandLineArguments::ProcessArgument(const char* arg) +{ + this->Internals->Argv.push_back(arg); +} + +bool CommandLineArguments::GetMatchedArguments( + std::vector* matches, const std::string& arg) +{ + matches->clear(); + CommandLineArguments::Internal::CallbacksMap::iterator it; + + // Does the argument match to any we know about? + for (it = this->Internals->Callbacks.begin(); + it != this->Internals->Callbacks.end(); it++) { + const CommandLineArguments::Internal::String& parg = it->first; + CommandLineArgumentsCallbackStructure* cs = &it->second; + if (cs->ArgumentType == CommandLineArguments::NO_ARGUMENT || + cs->ArgumentType == CommandLineArguments::SPACE_ARGUMENT) { + if (arg == parg) { + matches->push_back(parg); + } + } else if (arg.find(parg) == 0) { + matches->push_back(parg); + } + } + return !matches->empty(); +} + +int CommandLineArguments::Parse() +{ + std::vector::size_type cc; + std::vector matches; + if (this->StoreUnusedArgumentsFlag) { + this->Internals->UnusedArguments.clear(); + } + for (cc = 0; cc < this->Internals->Argv.size(); cc++) { + const std::string& arg = this->Internals->Argv[cc]; + CommandLineArguments_DEBUG("Process argument: " << arg); + this->Internals->LastArgument = cc; + if (this->GetMatchedArguments(&matches, arg)) { + // Ok, we found one or more arguments that match what user specified. + // Let's find the longest one. + CommandLineArguments::Internal::VectorOfStrings::size_type kk; + CommandLineArguments::Internal::VectorOfStrings::size_type maxidx = 0; + CommandLineArguments::Internal::String::size_type maxlen = 0; + for (kk = 0; kk < matches.size(); kk++) { + if (matches[kk].size() > maxlen) { + maxlen = matches[kk].size(); + maxidx = kk; + } + } + // So, the longest one is probably the right one. Now see if it has any + // additional value + CommandLineArgumentsCallbackStructure* cs = + &this->Internals->Callbacks[matches[maxidx]]; + const std::string& sarg = matches[maxidx]; + if (cs->Argument != sarg) { + abort(); + } + switch (cs->ArgumentType) { + case NO_ARGUMENT: + // No value + if (!this->PopulateVariable(cs, nullptr)) { + return 0; + } + break; + case SPACE_ARGUMENT: + if (cc == this->Internals->Argv.size() - 1) { + this->Internals->LastArgument--; + return 0; + } + CommandLineArguments_DEBUG("This is a space argument: " + << arg << " value: " + << this->Internals->Argv[cc + 1]); + // Value is the next argument + if (!this->PopulateVariable(cs, + this->Internals->Argv[cc + 1].c_str())) { + return 0; + } + cc++; + break; + case EQUAL_ARGUMENT: + if (arg.size() == sarg.size() || arg.at(sarg.size()) != '=') { + this->Internals->LastArgument--; + return 0; + } + // Value is everythng followed the '=' sign + if (!this->PopulateVariable(cs, arg.c_str() + sarg.size() + 1)) { + return 0; + } + break; + case CONCAT_ARGUMENT: + // Value is whatever follows the argument + if (!this->PopulateVariable(cs, arg.c_str() + sarg.size())) { + return 0; + } + break; + case MULTI_ARGUMENT: + // Suck in all the rest of the arguments + CommandLineArguments_DEBUG("This is a multi argument: " << arg); + for (cc++; cc < this->Internals->Argv.size(); ++cc) { + const std::string& marg = this->Internals->Argv[cc]; + CommandLineArguments_DEBUG( + " check multi argument value: " << marg); + if (this->GetMatchedArguments(&matches, marg)) { + CommandLineArguments_DEBUG("End of multi argument " + << arg << " with value: " << marg); + break; + } + CommandLineArguments_DEBUG( + " populate multi argument value: " << marg); + if (!this->PopulateVariable(cs, marg.c_str())) { + return 0; + } + } + if (cc != this->Internals->Argv.size()) { + CommandLineArguments_DEBUG("Again End of multi argument " << arg); + cc--; + continue; + } + break; + default: + std::cerr << "Got unknown argument type: \"" << cs->ArgumentType + << "\"" << std::endl; + this->Internals->LastArgument--; + return 0; + } + } else { + // Handle unknown arguments + if (this->Internals->UnknownArgumentCallback) { + if (!this->Internals->UnknownArgumentCallback( + arg.c_str(), this->Internals->ClientData)) { + this->Internals->LastArgument--; + return 0; + } + return 1; + } else if (this->StoreUnusedArgumentsFlag) { + CommandLineArguments_DEBUG("Store unused argument " << arg); + this->Internals->UnusedArguments.push_back(arg); + } else { + std::cerr << "Got unknown argument: \"" << arg << "\"" << std::endl; + this->Internals->LastArgument--; + return 0; + } + } + } + return 1; +} + +void CommandLineArguments::GetRemainingArguments(int* argc, char*** argv) +{ + CommandLineArguments::Internal::VectorOfStrings::size_type size = + this->Internals->Argv.size() - this->Internals->LastArgument + 1; + CommandLineArguments::Internal::VectorOfStrings::size_type cc; + + // Copy Argv0 as the first argument + char** args = new char*[size]; + args[0] = new char[this->Internals->Argv0.size() + 1]; + strcpy(args[0], this->Internals->Argv0.c_str()); + int cnt = 1; + + // Copy everything after the LastArgument, since that was not parsed. + for (cc = this->Internals->LastArgument + 1; + cc < this->Internals->Argv.size(); cc++) { + args[cnt] = new char[this->Internals->Argv[cc].size() + 1]; + strcpy(args[cnt], this->Internals->Argv[cc].c_str()); + cnt++; + } + *argc = cnt; + *argv = args; +} + +void CommandLineArguments::GetUnusedArguments(int* argc, char*** argv) +{ + CommandLineArguments::Internal::VectorOfStrings::size_type size = + this->Internals->UnusedArguments.size() + 1; + CommandLineArguments::Internal::VectorOfStrings::size_type cc; + + // Copy Argv0 as the first argument + char** args = new char*[size]; + args[0] = new char[this->Internals->Argv0.size() + 1]; + strcpy(args[0], this->Internals->Argv0.c_str()); + int cnt = 1; + + // Copy everything after the LastArgument, since that was not parsed. + for (cc = 0; cc < this->Internals->UnusedArguments.size(); cc++) { + kwsys::String& str = this->Internals->UnusedArguments[cc]; + args[cnt] = new char[str.size() + 1]; + strcpy(args[cnt], str.c_str()); + cnt++; + } + *argc = cnt; + *argv = args; +} + +void CommandLineArguments::DeleteRemainingArguments(int argc, char*** argv) +{ + int cc; + for (cc = 0; cc < argc; ++cc) { + delete[](*argv)[cc]; + } + delete[] * argv; +} + +void CommandLineArguments::AddCallback(const char* argument, + ArgumentTypeEnum type, + CallbackType callback, void* call_data, + const char* help) +{ + CommandLineArgumentsCallbackStructure s; + s.Argument = argument; + s.ArgumentType = type; + s.Callback = callback; + s.CallData = call_data; + s.VariableType = CommandLineArguments::NO_VARIABLE_TYPE; + s.Variable = nullptr; + s.Help = help; + + this->Internals->Callbacks[argument] = s; + this->GenerateHelp(); +} + +void CommandLineArguments::AddArgument(const char* argument, + ArgumentTypeEnum type, + VariableTypeEnum vtype, void* variable, + const char* help) +{ + CommandLineArgumentsCallbackStructure s; + s.Argument = argument; + s.ArgumentType = type; + s.Callback = nullptr; + s.CallData = nullptr; + s.VariableType = vtype; + s.Variable = variable; + s.Help = help; + + this->Internals->Callbacks[argument] = s; + this->GenerateHelp(); +} + +#define CommandLineArgumentsAddArgumentMacro(type, ctype) \ + void CommandLineArguments::AddArgument(const char* argument, \ + ArgumentTypeEnum type, \ + ctype* variable, const char* help) \ + { \ + this->AddArgument(argument, type, CommandLineArguments::type##_TYPE, \ + variable, help); \ + } + +/* clang-format off */ +CommandLineArgumentsAddArgumentMacro(BOOL, bool) +CommandLineArgumentsAddArgumentMacro(INT, int) +CommandLineArgumentsAddArgumentMacro(DOUBLE, double) +CommandLineArgumentsAddArgumentMacro(STRING, char*) +CommandLineArgumentsAddArgumentMacro(STL_STRING, std::string) + +CommandLineArgumentsAddArgumentMacro(VECTOR_BOOL, std::vector) +CommandLineArgumentsAddArgumentMacro(VECTOR_INT, std::vector) +CommandLineArgumentsAddArgumentMacro(VECTOR_DOUBLE, std::vector) +CommandLineArgumentsAddArgumentMacro(VECTOR_STRING, std::vector) +CommandLineArgumentsAddArgumentMacro(VECTOR_STL_STRING, + std::vector) +#ifdef HELP_CLANG_FORMAT +; +#endif +/* clang-format on */ + +#define CommandLineArgumentsAddBooleanArgumentMacro(type, ctype) \ + void CommandLineArguments::AddBooleanArgument( \ + const char* argument, ctype* variable, const char* help) \ + { \ + this->AddArgument(argument, CommandLineArguments::NO_ARGUMENT, \ + CommandLineArguments::type##_TYPE, variable, help); \ + } + +/* clang-format off */ +CommandLineArgumentsAddBooleanArgumentMacro(BOOL, bool) +CommandLineArgumentsAddBooleanArgumentMacro(INT, int) +CommandLineArgumentsAddBooleanArgumentMacro(DOUBLE, double) +CommandLineArgumentsAddBooleanArgumentMacro(STRING, char*) +CommandLineArgumentsAddBooleanArgumentMacro(STL_STRING, std::string) +#ifdef HELP_CLANG_FORMAT +; +#endif +/* clang-format on */ + +void CommandLineArguments::SetClientData(void* client_data) +{ + this->Internals->ClientData = client_data; +} + +void CommandLineArguments::SetUnknownArgumentCallback( + CommandLineArguments::ErrorCallbackType callback) +{ + this->Internals->UnknownArgumentCallback = callback; +} + +const char* CommandLineArguments::GetHelp(const char* arg) +{ + CommandLineArguments::Internal::CallbacksMap::iterator it = + this->Internals->Callbacks.find(arg); + if (it == this->Internals->Callbacks.end()) { + return nullptr; + } + + // Since several arguments may point to the same argument, find the one this + // one point to if this one is pointing to another argument. + CommandLineArgumentsCallbackStructure* cs = &(it->second); + for (;;) { + CommandLineArguments::Internal::CallbacksMap::iterator hit = + this->Internals->Callbacks.find(cs->Help); + if (hit == this->Internals->Callbacks.end()) { + break; + } + cs = &(hit->second); + } + return cs->Help; +} + +void CommandLineArguments::SetLineLength(unsigned int ll) +{ + if (ll < 9 || ll > 1000) { + return; + } + this->LineLength = ll; + this->GenerateHelp(); +} + +const char* CommandLineArguments::GetArgv0() +{ + return this->Internals->Argv0.c_str(); +} + +unsigned int CommandLineArguments::GetLastArgument() +{ + return static_cast(this->Internals->LastArgument + 1); +} + +void CommandLineArguments::GenerateHelp() +{ + std::ostringstream str; + + // Collapse all arguments into the map of vectors of all arguments that do + // the same thing. + CommandLineArguments::Internal::CallbacksMap::iterator it; + typedef std::map + MapArgs; + MapArgs mp; + MapArgs::iterator mpit, smpit; + for (it = this->Internals->Callbacks.begin(); + it != this->Internals->Callbacks.end(); it++) { + CommandLineArgumentsCallbackStructure* cs = &(it->second); + mpit = mp.find(cs->Help); + if (mpit != mp.end()) { + mpit->second.insert(it->first); + mp[it->first].insert(it->first); + } else { + mp[it->first].insert(it->first); + } + } + for (it = this->Internals->Callbacks.begin(); + it != this->Internals->Callbacks.end(); it++) { + CommandLineArgumentsCallbackStructure* cs = &(it->second); + mpit = mp.find(cs->Help); + if (mpit != mp.end()) { + mpit->second.insert(it->first); + smpit = mp.find(it->first); + CommandLineArguments::Internal::SetOfStrings::iterator sit; + for (sit = smpit->second.begin(); sit != smpit->second.end(); sit++) { + mpit->second.insert(*sit); + } + mp.erase(smpit); + } else { + mp[it->first].insert(it->first); + } + } + + // Find the length of the longest string + CommandLineArguments::Internal::String::size_type maxlen = 0; + for (mpit = mp.begin(); mpit != mp.end(); mpit++) { + CommandLineArguments::Internal::SetOfStrings::iterator sit; + for (sit = mpit->second.begin(); sit != mpit->second.end(); sit++) { + CommandLineArguments::Internal::String::size_type clen = sit->size(); + switch (this->Internals->Callbacks[*sit].ArgumentType) { + case CommandLineArguments::NO_ARGUMENT: + clen += 0; + break; + case CommandLineArguments::CONCAT_ARGUMENT: + clen += 3; + break; + case CommandLineArguments::SPACE_ARGUMENT: + clen += 4; + break; + case CommandLineArguments::EQUAL_ARGUMENT: + clen += 4; + break; + } + if (clen > maxlen) { + maxlen = clen; + } + } + } + + CommandLineArguments::Internal::String::size_type maxstrlen = maxlen; + maxlen += 4; // For the space before and after the option + + // Print help for each option + for (mpit = mp.begin(); mpit != mp.end(); mpit++) { + CommandLineArguments::Internal::SetOfStrings::iterator sit; + for (sit = mpit->second.begin(); sit != mpit->second.end(); sit++) { + str << std::endl; + std::string argument = *sit; + switch (this->Internals->Callbacks[*sit].ArgumentType) { + case CommandLineArguments::NO_ARGUMENT: + break; + case CommandLineArguments::CONCAT_ARGUMENT: + argument += "opt"; + break; + case CommandLineArguments::SPACE_ARGUMENT: + argument += " opt"; + break; + case CommandLineArguments::EQUAL_ARGUMENT: + argument += "=opt"; + break; + case CommandLineArguments::MULTI_ARGUMENT: + argument += " opt opt ..."; + break; + } + str << " " << argument.substr(0, maxstrlen) << " "; + } + const char* ptr = this->Internals->Callbacks[mpit->first].Help; + size_t len = strlen(ptr); + int cnt = 0; + while (len > 0) { + // If argument with help is longer than line length, split it on previous + // space (or tab) and continue on the next line + CommandLineArguments::Internal::String::size_type cc; + for (cc = 0; ptr[cc]; cc++) { + if (*ptr == ' ' || *ptr == '\t') { + ptr++; + len--; + } + } + if (cnt > 0) { + for (cc = 0; cc < maxlen; cc++) { + str << " "; + } + } + CommandLineArguments::Internal::String::size_type skip = len; + if (skip > this->LineLength - maxlen) { + skip = this->LineLength - maxlen; + for (cc = skip - 1; cc > 0; cc--) { + if (ptr[cc] == ' ' || ptr[cc] == '\t') { + break; + } + } + if (cc != 0) { + skip = cc; + } + } + str.write(ptr, static_cast(skip)); + str << std::endl; + ptr += skip; + len -= skip; + cnt++; + } + } + /* + // This can help debugging help string + str << endl; + unsigned int cc; + for ( cc = 0; cc < this->LineLength; cc ++ ) + { + str << cc % 10; + } + str << endl; + */ + this->Help = str.str(); +} + +void CommandLineArguments::PopulateVariable(bool* variable, + const std::string& value) +{ + if (value == "1" || value == "ON" || value == "on" || value == "On" || + value == "TRUE" || value == "true" || value == "True" || + value == "yes" || value == "Yes" || value == "YES") { + *variable = true; + } else { + *variable = false; + } +} + +void CommandLineArguments::PopulateVariable(int* variable, + const std::string& value) +{ + char* res = nullptr; + *variable = static_cast(strtol(value.c_str(), &res, 10)); + // if ( res && *res ) + // { + // Can handle non-int + // } +} + +void CommandLineArguments::PopulateVariable(double* variable, + const std::string& value) +{ + char* res = nullptr; + *variable = strtod(value.c_str(), &res); + // if ( res && *res ) + // { + // Can handle non-double + // } +} + +void CommandLineArguments::PopulateVariable(char** variable, + const std::string& value) +{ + delete[] * variable; + *variable = new char[value.size() + 1]; + strcpy(*variable, value.c_str()); +} + +void CommandLineArguments::PopulateVariable(std::string* variable, + const std::string& value) +{ + *variable = value; +} + +void CommandLineArguments::PopulateVariable(std::vector* variable, + const std::string& value) +{ + bool val = false; + if (value == "1" || value == "ON" || value == "on" || value == "On" || + value == "TRUE" || value == "true" || value == "True" || + value == "yes" || value == "Yes" || value == "YES") { + val = true; + } + variable->push_back(val); +} + +void CommandLineArguments::PopulateVariable(std::vector* variable, + const std::string& value) +{ + char* res = nullptr; + variable->push_back(static_cast(strtol(value.c_str(), &res, 10))); + // if ( res && *res ) + // { + // Can handle non-int + // } +} + +void CommandLineArguments::PopulateVariable(std::vector* variable, + const std::string& value) +{ + char* res = nullptr; + variable->push_back(strtod(value.c_str(), &res)); + // if ( res && *res ) + // { + // Can handle non-int + // } +} + +void CommandLineArguments::PopulateVariable(std::vector* variable, + const std::string& value) +{ + char* var = new char[value.size() + 1]; + strcpy(var, value.c_str()); + variable->push_back(var); +} + +void CommandLineArguments::PopulateVariable(std::vector* variable, + const std::string& value) +{ + variable->push_back(value); +} + +bool CommandLineArguments::PopulateVariable( + CommandLineArgumentsCallbackStructure* cs, const char* value) +{ + // Call the callback + if (cs->Callback) { + if (!cs->Callback(cs->Argument, value, cs->CallData)) { + this->Internals->LastArgument--; + return 0; + } + } + CommandLineArguments_DEBUG("Set argument: " << cs->Argument << " to " + << value); + if (cs->Variable) { + std::string var = "1"; + if (value) { + var = value; + } + switch (cs->VariableType) { + case CommandLineArguments::INT_TYPE: + this->PopulateVariable(static_cast(cs->Variable), var); + break; + case CommandLineArguments::DOUBLE_TYPE: + this->PopulateVariable(static_cast(cs->Variable), var); + break; + case CommandLineArguments::STRING_TYPE: + this->PopulateVariable(static_cast(cs->Variable), var); + break; + case CommandLineArguments::STL_STRING_TYPE: + this->PopulateVariable(static_cast(cs->Variable), var); + break; + case CommandLineArguments::BOOL_TYPE: + this->PopulateVariable(static_cast(cs->Variable), var); + break; + case CommandLineArguments::VECTOR_BOOL_TYPE: + this->PopulateVariable(static_cast*>(cs->Variable), + var); + break; + case CommandLineArguments::VECTOR_INT_TYPE: + this->PopulateVariable(static_cast*>(cs->Variable), + var); + break; + case CommandLineArguments::VECTOR_DOUBLE_TYPE: + this->PopulateVariable(static_cast*>(cs->Variable), + var); + break; + case CommandLineArguments::VECTOR_STRING_TYPE: + this->PopulateVariable(static_cast*>(cs->Variable), + var); + break; + case CommandLineArguments::VECTOR_STL_STRING_TYPE: + this->PopulateVariable( + static_cast*>(cs->Variable), var); + break; + default: + std::cerr << "Got unknown variable type: \"" << cs->VariableType + << "\"" << std::endl; + this->Internals->LastArgument--; + return 0; + } + } + return 1; +} + +} // namespace KWSYS_NAMESPACE diff --git a/test/API/driver/kwsys/CommandLineArguments.hxx.in b/test/API/driver/kwsys/CommandLineArguments.hxx.in new file mode 100644 index 0000000..7db9015 --- /dev/null +++ b/test/API/driver/kwsys/CommandLineArguments.hxx.in @@ -0,0 +1,270 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_CommandLineArguments_hxx +#define @KWSYS_NAMESPACE@_CommandLineArguments_hxx + +#include <@KWSYS_NAMESPACE@/Configure.h> +#include <@KWSYS_NAMESPACE@/Configure.hxx> + +#include +#include + +namespace @KWSYS_NAMESPACE@ { + +class CommandLineArgumentsInternal; +struct CommandLineArgumentsCallbackStructure; + +/** \class CommandLineArguments + * \brief Command line arguments processing code. + * + * Find specified arguments with optional options and execute specified methods + * or set given variables. + * + * The two interfaces it knows are callback based and variable based. For + * callback based, you have to register callback for particular argument using + * AddCallback method. When that argument is passed, the callback will be + * called with argument, value, and call data. For boolean (NO_ARGUMENT) + * arguments, the value is "1". If the callback returns 0 the argument parsing + * will stop with an error. + * + * For the variable interface you associate variable with each argument. When + * the argument is specified, the variable is set to the specified value casted + * to the appropriate type. For boolean (NO_ARGUMENT), the value is "1". + * + * Both interfaces can be used at the same time. + * + * Possible argument types are: + * NO_ARGUMENT - The argument takes no value : --A + * CONCAT_ARGUMENT - The argument takes value after no space : --Aval + * SPACE_ARGUMENT - The argument takes value after space : --A val + * EQUAL_ARGUMENT - The argument takes value after equal : --A=val + * MULTI_ARGUMENT - The argument takes values after space : --A val1 val2 + * val3 ... + * + * Example use: + * + * kwsys::CommandLineArguments arg; + * arg.Initialize(argc, argv); + * typedef kwsys::CommandLineArguments argT; + * arg.AddArgument("--something", argT::EQUAL_ARGUMENT, &some_variable, + * "This is help string for --something"); + * if ( !arg.Parse() ) + * { + * std::cerr << "Problem parsing arguments" << std::endl; + * res = 1; + * } + * + */ + +class @KWSYS_NAMESPACE@_EXPORT CommandLineArguments +{ +public: + CommandLineArguments(); + ~CommandLineArguments(); + + CommandLineArguments(const CommandLineArguments&) = delete; + CommandLineArguments& operator=(const CommandLineArguments&) = delete; + + /** + * Various argument types. + */ + enum ArgumentTypeEnum + { + NO_ARGUMENT, + CONCAT_ARGUMENT, + SPACE_ARGUMENT, + EQUAL_ARGUMENT, + MULTI_ARGUMENT + }; + + /** + * Various variable types. When using the variable interface, this specifies + * what type the variable is. + */ + enum VariableTypeEnum + { + NO_VARIABLE_TYPE = 0, // The variable is not specified + INT_TYPE, // The variable is integer (int) + BOOL_TYPE, // The variable is boolean (bool) + DOUBLE_TYPE, // The variable is float (double) + STRING_TYPE, // The variable is string (char*) + STL_STRING_TYPE, // The variable is string (char*) + VECTOR_INT_TYPE, // The variable is integer (int) + VECTOR_BOOL_TYPE, // The variable is boolean (bool) + VECTOR_DOUBLE_TYPE, // The variable is float (double) + VECTOR_STRING_TYPE, // The variable is string (char*) + VECTOR_STL_STRING_TYPE, // The variable is string (char*) + LAST_VARIABLE_TYPE + }; + + /** + * Prototypes for callbacks for callback interface. + */ + typedef int (*CallbackType)(const char* argument, const char* value, + void* call_data); + typedef int (*ErrorCallbackType)(const char* argument, void* client_data); + + /** + * Initialize internal data structures. This should be called before parsing. + */ + void Initialize(int argc, const char* const argv[]); + void Initialize(int argc, char* argv[]); + + /** + * Initialize internal data structure and pass arguments one by one. This is + * convenience method for use from scripting languages where argc and argv + * are not available. + */ + void Initialize(); + void ProcessArgument(const char* arg); + + /** + * This method will parse arguments and call appropriate methods. + */ + int Parse(); + + /** + * This method will add a callback for a specific argument. The arguments to + * it are argument, argument type, callback method, and call data. The + * argument help specifies the help string used with this option. The + * callback and call_data can be skipped. + */ + void AddCallback(const char* argument, ArgumentTypeEnum type, + CallbackType callback, void* call_data, const char* help); + + /** + * Add handler for argument which is going to set the variable to the + * specified value. If the argument is specified, the option is casted to the + * appropriate type. + */ + void AddArgument(const char* argument, ArgumentTypeEnum type, bool* variable, + const char* help); + void AddArgument(const char* argument, ArgumentTypeEnum type, int* variable, + const char* help); + void AddArgument(const char* argument, ArgumentTypeEnum type, + double* variable, const char* help); + void AddArgument(const char* argument, ArgumentTypeEnum type, + char** variable, const char* help); + void AddArgument(const char* argument, ArgumentTypeEnum type, + std::string* variable, const char* help); + + /** + * Add handler for argument which is going to set the variable to the + * specified value. If the argument is specified, the option is casted to the + * appropriate type. This will handle the multi argument values. + */ + void AddArgument(const char* argument, ArgumentTypeEnum type, + std::vector* variable, const char* help); + void AddArgument(const char* argument, ArgumentTypeEnum type, + std::vector* variable, const char* help); + void AddArgument(const char* argument, ArgumentTypeEnum type, + std::vector* variable, const char* help); + void AddArgument(const char* argument, ArgumentTypeEnum type, + std::vector* variable, const char* help); + void AddArgument(const char* argument, ArgumentTypeEnum type, + std::vector* variable, const char* help); + + /** + * Add handler for boolean argument. The argument does not take any option + * and if it is specified, the value of the variable is true/1, otherwise it + * is false/0. + */ + void AddBooleanArgument(const char* argument, bool* variable, + const char* help); + void AddBooleanArgument(const char* argument, int* variable, + const char* help); + void AddBooleanArgument(const char* argument, double* variable, + const char* help); + void AddBooleanArgument(const char* argument, char** variable, + const char* help); + void AddBooleanArgument(const char* argument, std::string* variable, + const char* help); + + /** + * Set the callbacks for error handling. + */ + void SetClientData(void* client_data); + void SetUnknownArgumentCallback(ErrorCallbackType callback); + + /** + * Get remaining arguments. It allocates space for argv, so you have to call + * delete[] on it. + */ + void GetRemainingArguments(int* argc, char*** argv); + void DeleteRemainingArguments(int argc, char*** argv); + + /** + * If StoreUnusedArguments is set to true, then all unknown arguments will be + * stored and the user can access the modified argc, argv without known + * arguments. + */ + void StoreUnusedArguments(bool val) { this->StoreUnusedArgumentsFlag = val; } + void GetUnusedArguments(int* argc, char*** argv); + + /** + * Return string containing help. If the argument is specified, only return + * help for that argument. + */ + const char* GetHelp() { return this->Help.c_str(); } + const char* GetHelp(const char* arg); + + /** + * Get / Set the help line length. This length is used when generating the + * help page. Default length is 80. + */ + void SetLineLength(unsigned int); + unsigned int GetLineLength(); + + /** + * Get the executable name (argv0). This is only available when using + * Initialize with argc/argv. + */ + const char* GetArgv0(); + + /** + * Get index of the last argument parsed. This is the last argument that was + * parsed ok in the original argc/argv list. + */ + unsigned int GetLastArgument(); + +protected: + void GenerateHelp(); + + //! This is internal method that registers variable with argument + void AddArgument(const char* argument, ArgumentTypeEnum type, + VariableTypeEnum vtype, void* variable, const char* help); + + bool GetMatchedArguments(std::vector* matches, + const std::string& arg); + + //! Populate individual variables + bool PopulateVariable(CommandLineArgumentsCallbackStructure* cs, + const char* value); + + //! Populate individual variables of type ... + void PopulateVariable(bool* variable, const std::string& value); + void PopulateVariable(int* variable, const std::string& value); + void PopulateVariable(double* variable, const std::string& value); + void PopulateVariable(char** variable, const std::string& value); + void PopulateVariable(std::string* variable, const std::string& value); + void PopulateVariable(std::vector* variable, const std::string& value); + void PopulateVariable(std::vector* variable, const std::string& value); + void PopulateVariable(std::vector* variable, + const std::string& value); + void PopulateVariable(std::vector* variable, + const std::string& value); + void PopulateVariable(std::vector* variable, + const std::string& value); + + typedef CommandLineArgumentsInternal Internal; + Internal* Internals; + std::string Help; + + unsigned int LineLength; + + bool StoreUnusedArgumentsFlag; +}; + +} // namespace @KWSYS_NAMESPACE@ + +#endif diff --git a/test/API/driver/kwsys/Configure.h.in b/test/API/driver/kwsys/Configure.h.in new file mode 100644 index 0000000..5323c57 --- /dev/null +++ b/test/API/driver/kwsys/Configure.h.in @@ -0,0 +1,89 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_Configure_h +#define @KWSYS_NAMESPACE@_Configure_h + +/* If we are building a kwsys .c or .cxx file, let it use the kwsys + namespace. When not building a kwsys source file these macros are + temporarily defined inside the headers that use them. */ +#if defined(KWSYS_NAMESPACE) +# define kwsys_ns(x) @KWSYS_NAMESPACE@##x +# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT +#endif + +/* Disable some warnings inside kwsys source files. */ +#if defined(KWSYS_NAMESPACE) +# if defined(__BORLANDC__) +# pragma warn - 8027 /* function not inlined. */ +# endif +# if defined(__INTEL_COMPILER) +# pragma warning(disable : 1572) /* floating-point equality test */ +# endif +# if defined(__sgi) && !defined(__GNUC__) +# pragma set woff 3970 /* pointer to int conversion */ +# pragma set woff 3968 /* 64 bit conversion */ +# endif +#endif + +/* Whether kwsys namespace is "kwsys". */ +#define @KWSYS_NAMESPACE@_NAME_IS_KWSYS @KWSYS_NAME_IS_KWSYS@ + +/* Setup the export macro. */ +#if @KWSYS_BUILD_SHARED@ +# if defined(_WIN32) || defined(__CYGWIN__) +# if defined(@KWSYS_NAMESPACE@_EXPORTS) +# define @KWSYS_NAMESPACE@_EXPORT __declspec(dllexport) +# else +# define @KWSYS_NAMESPACE@_EXPORT __declspec(dllimport) +# endif +# elif __GNUC__ >= 4 +# define @KWSYS_NAMESPACE@_EXPORT __attribute__((visibility("default"))) +# else +# define @KWSYS_NAMESPACE@_EXPORT +# endif +#else +# define @KWSYS_NAMESPACE@_EXPORT +#endif + +/* Enable warnings that are off by default but are useful. */ +#if !defined(@KWSYS_NAMESPACE@_NO_WARNING_ENABLE) +# if defined(_MSC_VER) +# pragma warning(default : 4263) /* no override, call convention differs \ + */ +# endif +#endif + +/* Disable warnings that are on by default but occur in valid code. */ +#if !defined(@KWSYS_NAMESPACE@_NO_WARNING_DISABLE) +# if defined(_MSC_VER) +# pragma warning(disable : 4097) /* typedef is synonym for class */ +# pragma warning(disable : 4127) /* conditional expression is constant */ +# pragma warning(disable : 4244) /* possible loss in conversion */ +# pragma warning(disable : 4251) /* missing DLL-interface */ +# pragma warning(disable : 4305) /* truncation from type1 to type2 */ +# pragma warning(disable : 4309) /* truncation of constant value */ +# pragma warning(disable : 4514) /* unreferenced inline function */ +# pragma warning(disable : 4706) /* assignment in conditional expression \ + */ +# pragma warning(disable : 4710) /* function not inlined */ +# pragma warning(disable : 4786) /* identifier truncated in debug info */ +# endif +# if defined(__BORLANDC__) && !defined(__cplusplus) +/* Code has no effect; raised by winnt.h in C (not C++) when ignoring an + unused parameter using "(param)" syntax (i.e. no cast to void). */ +# pragma warn - 8019 +# endif +#endif + +/* MSVC 6.0 in release mode will warn about code it produces with its + optimizer. Disable the warnings specifically for this + configuration. Real warnings will be revealed by a debug build or + by other compilers. */ +#if !defined(@KWSYS_NAMESPACE@_NO_WARNING_DISABLE_BOGUS) +# if defined(_MSC_VER) && (_MSC_VER < 1300) && defined(NDEBUG) +# pragma warning(disable : 4701) /* Variable may be used uninitialized. */ +# pragma warning(disable : 4702) /* Unreachable code. */ +# endif +#endif + +#endif diff --git a/test/API/driver/kwsys/Configure.hxx.in b/test/API/driver/kwsys/Configure.hxx.in new file mode 100644 index 0000000..29a2dd1 --- /dev/null +++ b/test/API/driver/kwsys/Configure.hxx.in @@ -0,0 +1,65 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_Configure_hxx +#define @KWSYS_NAMESPACE@_Configure_hxx + +/* Include C configuration. */ +#include <@KWSYS_NAMESPACE@/Configure.h> + +/* Whether wstring is available. */ +#define @KWSYS_NAMESPACE@_STL_HAS_WSTRING @KWSYS_STL_HAS_WSTRING@ +/* Whether is available. */ +#define @KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H \ + @KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H@ +/* Whether the translation map is available or not. */ +#define @KWSYS_NAMESPACE@_SYSTEMTOOLS_USE_TRANSLATION_MAP \ + @KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP@ + +#if defined(__SUNPRO_CC) && __SUNPRO_CC > 0x5130 && defined(__has_attribute) +# define @KWSYS_NAMESPACE@__has_cpp_attribute(x) __has_attribute(x) +#elif defined(__has_cpp_attribute) +# define @KWSYS_NAMESPACE@__has_cpp_attribute(x) __has_cpp_attribute(x) +#else +# define @KWSYS_NAMESPACE@__has_cpp_attribute(x) 0 +#endif + +#if __cplusplus >= 201103L +# define @KWSYS_NAMESPACE@_NULLPTR nullptr +#else +# define @KWSYS_NAMESPACE@_NULLPTR 0 +#endif + +#ifndef @KWSYS_NAMESPACE@_FALLTHROUGH +# if __cplusplus >= 201703L && \ + @KWSYS_NAMESPACE@__has_cpp_attribute(fallthrough) +# define @KWSYS_NAMESPACE@_FALLTHROUGH [[fallthrough]] +# elif __cplusplus >= 201103L && \ + @KWSYS_NAMESPACE@__has_cpp_attribute(gnu::fallthrough) +# define @KWSYS_NAMESPACE@_FALLTHROUGH [[gnu::fallthrough]] +# elif __cplusplus >= 201103L && \ + @KWSYS_NAMESPACE@__has_cpp_attribute(clang::fallthrough) +# define @KWSYS_NAMESPACE@_FALLTHROUGH [[clang::fallthrough]] +# endif +#endif +#ifndef @KWSYS_NAMESPACE@_FALLTHROUGH +# define @KWSYS_NAMESPACE@_FALLTHROUGH static_cast(0) +#endif + +#undef @KWSYS_NAMESPACE@__has_cpp_attribute + +/* If building a C++ file in kwsys itself, give the source file + access to the macros without a configured namespace. */ +#if defined(KWSYS_NAMESPACE) +# if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# define kwsys @KWSYS_NAMESPACE@ +# endif +# define KWSYS_NAME_IS_KWSYS @KWSYS_NAMESPACE@_NAME_IS_KWSYS +# define KWSYS_STL_HAS_WSTRING @KWSYS_NAMESPACE@_STL_HAS_WSTRING +# define KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H \ + @KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H +# define KWSYS_FALLTHROUGH @KWSYS_NAMESPACE@_FALLTHROUGH +# define KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP \ + @KWSYS_NAMESPACE@_SYSTEMTOOLS_USE_TRANSLATION_MAP +#endif + +#endif diff --git a/test/API/driver/kwsys/ConsoleBuf.hxx.in b/test/API/driver/kwsys/ConsoleBuf.hxx.in new file mode 100644 index 0000000..49dbdf7 --- /dev/null +++ b/test/API/driver/kwsys/ConsoleBuf.hxx.in @@ -0,0 +1,398 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_ConsoleBuf_hxx +#define @KWSYS_NAMESPACE@_ConsoleBuf_hxx + +#include <@KWSYS_NAMESPACE@/Configure.hxx> + +#include <@KWSYS_NAMESPACE@/Encoding.hxx> + +#include +#include +#include +#include +#include +#include + +#if defined(_WIN32) +# include +# if __cplusplus >= 201103L +# include +# endif +#endif + +namespace @KWSYS_NAMESPACE@ { +#if defined(_WIN32) + +template > +class BasicConsoleBuf : public std::basic_streambuf +{ +public: + typedef typename Traits::int_type int_type; + typedef typename Traits::char_type char_type; + + class Manager + { + public: + Manager(std::basic_ios& ios, const bool err = false) + : m_consolebuf(0) + { + m_ios = &ios; + try { + m_consolebuf = new BasicConsoleBuf(err); + m_streambuf = m_ios->rdbuf(m_consolebuf); + } catch (const std::runtime_error& ex) { + std::cerr << "Failed to create ConsoleBuf!" << std::endl + << ex.what() << std::endl; + }; + } + + BasicConsoleBuf* GetConsoleBuf() { return m_consolebuf; } + + void SetUTF8Pipes() + { + if (m_consolebuf) { + m_consolebuf->input_pipe_codepage = CP_UTF8; + m_consolebuf->output_pipe_codepage = CP_UTF8; + m_consolebuf->activateCodepageChange(); + } + } + + ~Manager() + { + if (m_consolebuf) { + delete m_consolebuf; + m_ios->rdbuf(m_streambuf); + } + } + + private: + std::basic_ios* m_ios; + std::basic_streambuf* m_streambuf; + BasicConsoleBuf* m_consolebuf; + }; + + BasicConsoleBuf(const bool err = false) + : flush_on_newline(true) + , input_pipe_codepage(0) + , output_pipe_codepage(0) + , input_file_codepage(CP_UTF8) + , output_file_codepage(CP_UTF8) + , m_consolesCodepage(0) + { + m_hInput = ::GetStdHandle(STD_INPUT_HANDLE); + checkHandle(true, "STD_INPUT_HANDLE"); + if (!setActiveInputCodepage()) { + throw std::runtime_error("setActiveInputCodepage failed!"); + } + m_hOutput = err ? ::GetStdHandle(STD_ERROR_HANDLE) + : ::GetStdHandle(STD_OUTPUT_HANDLE); + checkHandle(false, err ? "STD_ERROR_HANDLE" : "STD_OUTPUT_HANDLE"); + if (!setActiveOutputCodepage()) { + throw std::runtime_error("setActiveOutputCodepage failed!"); + } + _setg(); + _setp(); + } + + ~BasicConsoleBuf() throw() { sync(); } + + bool activateCodepageChange() + { + return setActiveInputCodepage() && setActiveOutputCodepage(); + } + +protected: + virtual int sync() + { + bool success = true; + if (m_hInput && m_isConsoleInput && + ::FlushConsoleInputBuffer(m_hInput) == 0) { + success = false; + } + if (m_hOutput && !m_obuffer.empty()) { + const std::wstring wbuffer = getBuffer(m_obuffer); + if (m_isConsoleOutput) { + DWORD charsWritten; + success = + ::WriteConsoleW(m_hOutput, wbuffer.c_str(), (DWORD)wbuffer.size(), + &charsWritten, nullptr) == 0 + ? false + : true; + } else { + DWORD bytesWritten; + std::string buffer; + success = encodeOutputBuffer(wbuffer, buffer); + if (success) { + success = + ::WriteFile(m_hOutput, buffer.c_str(), (DWORD)buffer.size(), + &bytesWritten, nullptr) == 0 + ? false + : true; + } + } + } + m_ibuffer.clear(); + m_obuffer.clear(); + _setg(); + _setp(); + return success ? 0 : -1; + } + + virtual int_type underflow() + { + if (this->gptr() >= this->egptr()) { + if (!m_hInput) { + _setg(true); + return Traits::eof(); + } + if (m_isConsoleInput) { + // ReadConsole doesn't tell if there's more input available + // don't support reading more characters than this + wchar_t wbuffer[8192]; + DWORD charsRead; + if (ReadConsoleW(m_hInput, wbuffer, + (sizeof(wbuffer) / sizeof(wbuffer[0])), &charsRead, + nullptr) == 0 || + charsRead == 0) { + _setg(true); + return Traits::eof(); + } + setBuffer(std::wstring(wbuffer, charsRead), m_ibuffer); + } else { + std::wstring wbuffer; + std::string strbuffer; + DWORD bytesRead; + LARGE_INTEGER size; + if (GetFileSizeEx(m_hInput, &size) == 0) { + _setg(true); + return Traits::eof(); + } + char* buffer = new char[size.LowPart]; + while (ReadFile(m_hInput, buffer, size.LowPart, &bytesRead, nullptr) == + 0) { + if (GetLastError() == ERROR_MORE_DATA) { + strbuffer += std::string(buffer, bytesRead); + continue; + } + _setg(true); + delete[] buffer; + return Traits::eof(); + } + if (bytesRead > 0) { + strbuffer += std::string(buffer, bytesRead); + } + delete[] buffer; + if (!decodeInputBuffer(strbuffer, wbuffer)) { + _setg(true); + return Traits::eof(); + } + setBuffer(wbuffer, m_ibuffer); + } + _setg(); + } + return Traits::to_int_type(*this->gptr()); + } + + virtual int_type overflow(int_type ch = Traits::eof()) + { + if (!Traits::eq_int_type(ch, Traits::eof())) { + char_type chr = Traits::to_char_type(ch); + m_obuffer += chr; + if ((flush_on_newline && Traits::eq(chr, '\n')) || + Traits::eq_int_type(ch, 0x00)) { + sync(); + } + return ch; + } + sync(); + return Traits::eof(); + } + +public: + bool flush_on_newline; + UINT input_pipe_codepage; + UINT output_pipe_codepage; + UINT input_file_codepage; + UINT output_file_codepage; + +private: + HANDLE m_hInput; + HANDLE m_hOutput; + std::basic_string m_ibuffer; + std::basic_string m_obuffer; + bool m_isConsoleInput; + bool m_isConsoleOutput; + UINT m_activeInputCodepage; + UINT m_activeOutputCodepage; + UINT m_consolesCodepage; + void checkHandle(bool input, std::string handleName) + { + if ((input && m_hInput == INVALID_HANDLE_VALUE) || + (!input && m_hOutput == INVALID_HANDLE_VALUE)) { + std::string errmsg = + "GetStdHandle(" + handleName + ") returned INVALID_HANDLE_VALUE"; +# if __cplusplus >= 201103L + throw std::system_error(::GetLastError(), std::system_category(), + errmsg); +# else + throw std::runtime_error(errmsg); +# endif + } + } + UINT getConsolesCodepage() + { + if (!m_consolesCodepage) { + m_consolesCodepage = GetConsoleCP(); + if (!m_consolesCodepage) { + m_consolesCodepage = GetACP(); + } + } + return m_consolesCodepage; + } + bool setActiveInputCodepage() + { + m_isConsoleInput = false; + switch (GetFileType(m_hInput)) { + case FILE_TYPE_DISK: + m_activeInputCodepage = input_file_codepage; + break; + case FILE_TYPE_CHAR: + // Check for actual console. + DWORD consoleMode; + m_isConsoleInput = + GetConsoleMode(m_hInput, &consoleMode) == 0 ? false : true; + if (m_isConsoleInput) { + break; + } + @KWSYS_NAMESPACE@_FALLTHROUGH; + case FILE_TYPE_PIPE: + m_activeInputCodepage = input_pipe_codepage; + break; + default: + return false; + } + if (!m_isConsoleInput && m_activeInputCodepage == 0) { + m_activeInputCodepage = getConsolesCodepage(); + } + return true; + } + bool setActiveOutputCodepage() + { + m_isConsoleOutput = false; + switch (GetFileType(m_hOutput)) { + case FILE_TYPE_DISK: + m_activeOutputCodepage = output_file_codepage; + break; + case FILE_TYPE_CHAR: + // Check for actual console. + DWORD consoleMode; + m_isConsoleOutput = + GetConsoleMode(m_hOutput, &consoleMode) == 0 ? false : true; + if (m_isConsoleOutput) { + break; + } + @KWSYS_NAMESPACE@_FALLTHROUGH; + case FILE_TYPE_PIPE: + m_activeOutputCodepage = output_pipe_codepage; + break; + default: + return false; + } + if (!m_isConsoleOutput && m_activeOutputCodepage == 0) { + m_activeOutputCodepage = getConsolesCodepage(); + } + return true; + } + void _setg(bool empty = false) + { + if (!empty) { + this->setg((char_type*)m_ibuffer.data(), (char_type*)m_ibuffer.data(), + (char_type*)m_ibuffer.data() + m_ibuffer.size()); + } else { + this->setg((char_type*)m_ibuffer.data(), + (char_type*)m_ibuffer.data() + m_ibuffer.size(), + (char_type*)m_ibuffer.data() + m_ibuffer.size()); + } + } + void _setp() + { + this->setp((char_type*)m_obuffer.data(), + (char_type*)m_obuffer.data() + m_obuffer.size()); + } + bool encodeOutputBuffer(const std::wstring wbuffer, std::string& buffer) + { + if (wbuffer.size() == 0) { + buffer = std::string(); + return true; + } + const int length = + WideCharToMultiByte(m_activeOutputCodepage, 0, wbuffer.c_str(), + (int)wbuffer.size(), nullptr, 0, nullptr, nullptr); + char* buf = new char[length]; + const bool success = + WideCharToMultiByte(m_activeOutputCodepage, 0, wbuffer.c_str(), + (int)wbuffer.size(), buf, length, nullptr, + nullptr) > 0 + ? true + : false; + buffer = std::string(buf, length); + delete[] buf; + return success; + } + bool decodeInputBuffer(const std::string buffer, std::wstring& wbuffer) + { + size_t length = buffer.length(); + if (length == 0) { + wbuffer = std::wstring(); + return true; + } + int actualCodepage = m_activeInputCodepage; + const char BOM_UTF8[] = { char(0xEF), char(0xBB), char(0xBF) }; + const char* data = buffer.data(); + const size_t BOMsize = sizeof(BOM_UTF8); + if (length >= BOMsize && std::memcmp(data, BOM_UTF8, BOMsize) == 0) { + // PowerShell uses UTF-8 with BOM for pipes + actualCodepage = CP_UTF8; + data += BOMsize; + length -= BOMsize; + } + const size_t wlength = static_cast(MultiByteToWideChar( + actualCodepage, 0, data, static_cast(length), nullptr, 0)); + wchar_t* wbuf = new wchar_t[wlength]; + const bool success = + MultiByteToWideChar(actualCodepage, 0, data, static_cast(length), + wbuf, static_cast(wlength)) > 0 + ? true + : false; + wbuffer = std::wstring(wbuf, wlength); + delete[] wbuf; + return success; + } + std::wstring getBuffer(const std::basic_string buffer) + { + return Encoding::ToWide(buffer); + } + std::wstring getBuffer(const std::basic_string buffer) + { + return buffer; + } + void setBuffer(const std::wstring wbuffer, std::basic_string& target) + { + target = Encoding::ToNarrow(wbuffer); + } + void setBuffer(const std::wstring wbuffer, + std::basic_string& target) + { + target = wbuffer; + } + +}; // BasicConsoleBuf class + +typedef BasicConsoleBuf ConsoleBuf; +typedef BasicConsoleBuf WConsoleBuf; + +#endif +} // KWSYS_NAMESPACE + +#endif diff --git a/test/API/driver/kwsys/Copyright.txt b/test/API/driver/kwsys/Copyright.txt new file mode 100644 index 0000000..33d7fb4 --- /dev/null +++ b/test/API/driver/kwsys/Copyright.txt @@ -0,0 +1,38 @@ +KWSys - Kitware System Library +Copyright 2000-2016 Kitware, Inc. and Contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of Kitware, Inc. nor the names of Contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +------------------------------------------------------------------------------ + +The following individuals and institutions are among the Contributors: + +* Insight Software Consortium + +See version control history for details of individual contributions. diff --git a/test/API/driver/kwsys/Directory.cxx b/test/API/driver/kwsys/Directory.cxx new file mode 100644 index 0000000..e379182 --- /dev/null +++ b/test/API/driver/kwsys/Directory.cxx @@ -0,0 +1,236 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(Directory.hxx) + +#include KWSYS_HEADER(Configure.hxx) + +#include KWSYS_HEADER(Encoding.hxx) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "Configure.hxx.in" +# include "Directory.hxx.in" +# include "Encoding.hxx.in" +#endif + +#include +#include + +namespace KWSYS_NAMESPACE { + +class DirectoryInternals +{ +public: + // Array of Files + std::vector Files; + + // Path to Open'ed directory + std::string Path; +}; + +Directory::Directory() +{ + this->Internal = new DirectoryInternals; +} + +Directory::~Directory() +{ + delete this->Internal; +} + +unsigned long Directory::GetNumberOfFiles() const +{ + return static_cast(this->Internal->Files.size()); +} + +const char* Directory::GetFile(unsigned long dindex) const +{ + if (dindex >= this->Internal->Files.size()) { + return nullptr; + } + return this->Internal->Files[dindex].c_str(); +} + +const char* Directory::GetPath() const +{ + return this->Internal->Path.c_str(); +} + +void Directory::Clear() +{ + this->Internal->Path.resize(0); + this->Internal->Files.clear(); +} + +} // namespace KWSYS_NAMESPACE + +// First Windows platforms + +#if defined(_WIN32) && !defined(__CYGWIN__) +# include + +# include +# include +# include +# include +# include +# include +# include +# include + +// Wide function names can vary depending on compiler: +# ifdef __BORLANDC__ +# define _wfindfirst_func __wfindfirst +# define _wfindnext_func __wfindnext +# else +# define _wfindfirst_func _wfindfirst +# define _wfindnext_func _wfindnext +# endif + +namespace KWSYS_NAMESPACE { + +bool Directory::Load(const std::string& name) +{ + this->Clear(); +# if (defined(_MSC_VER) && _MSC_VER < 1300) || defined(__BORLANDC__) + // Older Visual C++ and Embarcadero compilers. + long srchHandle; +# else // Newer Visual C++ + intptr_t srchHandle; +# endif + char* buf; + size_t n = name.size(); + if (name.back() == '/' || name.back() == '\\') { + buf = new char[n + 1 + 1]; + sprintf(buf, "%s*", name.c_str()); + } else { + // Make sure the slashes in the wildcard suffix are consistent with the + // rest of the path + buf = new char[n + 2 + 1]; + if (name.find('\\') != std::string::npos) { + sprintf(buf, "%s\\*", name.c_str()); + } else { + sprintf(buf, "%s/*", name.c_str()); + } + } + struct _wfinddata_t data; // data of current file + + // Now put them into the file array + srchHandle = _wfindfirst_func( + (wchar_t*)Encoding::ToWindowsExtendedPath(buf).c_str(), &data); + delete[] buf; + + if (srchHandle == -1) { + return 0; + } + + // Loop through names + do { + this->Internal->Files.push_back(Encoding::ToNarrow(data.name)); + } while (_wfindnext_func(srchHandle, &data) != -1); + this->Internal->Path = name; + return _findclose(srchHandle) != -1; +} + +unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name) +{ +# if (defined(_MSC_VER) && _MSC_VER < 1300) || defined(__BORLANDC__) + // Older Visual C++ and Embarcadero compilers. + long srchHandle; +# else // Newer Visual C++ + intptr_t srchHandle; +# endif + char* buf; + size_t n = name.size(); + if (name.back() == '/') { + buf = new char[n + 1 + 1]; + sprintf(buf, "%s*", name.c_str()); + } else { + buf = new char[n + 2 + 1]; + sprintf(buf, "%s/*", name.c_str()); + } + struct _wfinddata_t data; // data of current file + + // Now put them into the file array + srchHandle = + _wfindfirst_func((wchar_t*)Encoding::ToWide(buf).c_str(), &data); + delete[] buf; + + if (srchHandle == -1) { + return 0; + } + + // Loop through names + unsigned long count = 0; + do { + count++; + } while (_wfindnext_func(srchHandle, &data) != -1); + _findclose(srchHandle); + return count; +} + +} // namespace KWSYS_NAMESPACE + +#else + +// Now the POSIX style directory access + +# include + +# include + +// PGI with glibc has trouble with dirent and large file support: +// http://www.pgroup.com/userforum/viewtopic.php? +// p=1992&sid=f16167f51964f1a68fe5041b8eb213b6 +// Work around the problem by mapping dirent the same way as readdir. +# if defined(__PGI) && defined(__GLIBC__) +# define kwsys_dirent_readdir dirent +# define kwsys_dirent_readdir64 dirent64 +# define kwsys_dirent kwsys_dirent_lookup(readdir) +# define kwsys_dirent_lookup(x) kwsys_dirent_lookup_delay(x) +# define kwsys_dirent_lookup_delay(x) kwsys_dirent_##x +# else +# define kwsys_dirent dirent +# endif + +namespace KWSYS_NAMESPACE { + +bool Directory::Load(const std::string& name) +{ + this->Clear(); + + DIR* dir = opendir(name.c_str()); + + if (!dir) { + return 0; + } + + for (kwsys_dirent* d = readdir(dir); d; d = readdir(dir)) { + this->Internal->Files.push_back(d->d_name); + } + this->Internal->Path = name; + closedir(dir); + return 1; +} + +unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name) +{ + DIR* dir = opendir(name.c_str()); + + if (!dir) { + return 0; + } + + unsigned long count = 0; + for (kwsys_dirent* d = readdir(dir); d; d = readdir(dir)) { + count++; + } + closedir(dir); + return count; +} + +} // namespace KWSYS_NAMESPACE + +#endif diff --git a/test/API/driver/kwsys/Directory.hxx.in b/test/API/driver/kwsys/Directory.hxx.in new file mode 100644 index 0000000..ad8c51b --- /dev/null +++ b/test/API/driver/kwsys/Directory.hxx.in @@ -0,0 +1,72 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_Directory_hxx +#define @KWSYS_NAMESPACE@_Directory_hxx + +#include <@KWSYS_NAMESPACE@/Configure.h> + +#include + +namespace @KWSYS_NAMESPACE@ { + +class DirectoryInternals; + +/** \class Directory + * \brief Portable directory/filename traversal. + * + * Directory provides a portable way of finding the names of the files + * in a system directory. + * + * Directory currently works with Windows and Unix operating systems. + */ +class @KWSYS_NAMESPACE@_EXPORT Directory +{ +public: + Directory(); + ~Directory(); + + /** + * Load the specified directory and load the names of the files + * in that directory. 0 is returned if the directory can not be + * opened, 1 if it is opened. + */ + bool Load(const std::string&); + + /** + * Return the number of files in the current directory. + */ + unsigned long GetNumberOfFiles() const; + + /** + * Return the number of files in the specified directory. + * A higher performance static method. + */ + static unsigned long GetNumberOfFilesInDirectory(const std::string&); + + /** + * Return the file at the given index, the indexing is 0 based + */ + const char* GetFile(unsigned long) const; + + /** + * Return the path to Open'ed directory + */ + const char* GetPath() const; + + /** + * Clear the internal structure. Used internally at beginning of Load(...) + * to clear the cache. + */ + void Clear(); + +private: + // Private implementation details. + DirectoryInternals* Internal; + + Directory(const Directory&); // Not implemented. + void operator=(const Directory&); // Not implemented. +}; // End Class: Directory + +} // namespace @KWSYS_NAMESPACE@ + +#endif diff --git a/test/API/driver/kwsys/DynamicLoader.cxx b/test/API/driver/kwsys/DynamicLoader.cxx new file mode 100644 index 0000000..a4b8641 --- /dev/null +++ b/test/API/driver/kwsys/DynamicLoader.cxx @@ -0,0 +1,495 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#if defined(_WIN32) +# define NOMINMAX // hide min,max to not conflict with +#endif + +#include "kwsysPrivate.h" +#include KWSYS_HEADER(DynamicLoader.hxx) + +#include KWSYS_HEADER(Configure.hxx) +#include KWSYS_HEADER(Encoding.hxx) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "Configure.hxx.in" +# include "DynamicLoader.hxx.in" +#endif + +// This file actually contains several different implementations: +// * NOOP for environments without dynamic libs +// * HP machines which uses shl_load +// * Mac OS X 10.2.x and earlier which uses NSLinkModule +// * Windows which uses LoadLibrary +// * BeOS / Haiku +// * FreeMiNT for Atari +// * Default implementation for *NIX systems (including Mac OS X 10.3 and +// later) which use dlopen +// +// Each part of the ifdef contains a complete implementation for +// the static methods of DynamicLoader. + +#define CHECK_OPEN_FLAGS(var, supported, ret) \ + do { \ + /* Check for unknown flags. */ \ + if ((var & AllOpenFlags) != var) { \ + return ret; \ + } \ + \ + /* Check for unsupported flags. */ \ + if ((var & (supported)) != var) { \ + return ret; \ + } \ + } while (0) + +namespace KWSYS_NAMESPACE { + +DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( + const std::string& libname) +{ + return DynamicLoader::OpenLibrary(libname, 0); +} +} + +#if !KWSYS_SUPPORTS_SHARED_LIBS +// Implementation for environments without dynamic libs +# include // for strerror() + +namespace KWSYS_NAMESPACE { + +DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( + const std::string& libname, int flags) +{ + return 0; +} + +int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) +{ + if (!lib) { + return 0; + } + + return 1; +} + +DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( + DynamicLoader::LibraryHandle lib, const std::string& sym) +{ + return 0; +} + +const char* DynamicLoader::LastError() +{ + return "General error"; +} + +} // namespace KWSYS_NAMESPACE + +#elif defined(__hpux) +// Implementation for HPUX machines +# include +# include + +namespace KWSYS_NAMESPACE { + +DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( + const std::string& libname, int flags) +{ + CHECK_OPEN_FLAGS(flags, 0, 0); + + return shl_load(libname.c_str(), BIND_DEFERRED | DYNAMIC_PATH, 0L); +} + +int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) +{ + if (!lib) { + return 0; + } + return !shl_unload(lib); +} + +DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( + DynamicLoader::LibraryHandle lib, const std::string& sym) +{ + void* addr; + int status; + + /* TYPE_PROCEDURE Look for a function or procedure. (This used to be default) + * TYPE_DATA Look for a symbol in the data segment (for example, + * variables). + * TYPE_UNDEFINED Look for any symbol. + */ + status = shl_findsym(&lib, sym.c_str(), TYPE_UNDEFINED, &addr); + void* result = (status < 0) ? (void*)0 : addr; + + // Hack to cast pointer-to-data to pointer-to-function. + return *reinterpret_cast(&result); +} + +const char* DynamicLoader::LastError() +{ + // TODO: Need implementation with errno/strerror + /* If successful, shl_findsym returns an integer (int) value zero. If + * shl_findsym cannot find sym, it returns -1 and sets errno to zero. + * If any other errors occur, shl_findsym returns -1 and sets errno to one + * of these values (defined in ): + * ENOEXEC + * A format error was detected in the specified library. + * ENOSYM + * A symbol on which sym depends could not be found. + * EINVAL + * The specified handle is invalid. + */ + + if (errno == ENOEXEC || errno == ENOSYM || errno == EINVAL) { + return strerror(errno); + } + // else + return 0; +} + +} // namespace KWSYS_NAMESPACE + +#elif defined(__APPLE__) && (MAC_OS_X_VERSION_MAX_ALLOWED < 1030) +// Implementation for Mac OS X 10.2.x and earlier +# include +# include // for strlen + +namespace KWSYS_NAMESPACE { + +DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( + const std::string& libname, int flags) +{ + CHECK_OPEN_FLAGS(flags, 0, 0); + + NSObjectFileImageReturnCode rc; + NSObjectFileImage image = 0; + + rc = NSCreateObjectFileImageFromFile(libname.c_str(), &image); + // rc == NSObjectFileImageInappropriateFile when trying to load a dylib file + if (rc != NSObjectFileImageSuccess) { + return 0; + } + NSModule handle = NSLinkModule(image, libname.c_str(), + NSLINKMODULE_OPTION_BINDNOW | + NSLINKMODULE_OPTION_RETURN_ON_ERROR); + NSDestroyObjectFileImage(image); + return handle; +} + +int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) +{ + // NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED + // With this option the memory for the module is not deallocated + // allowing pointers into the module to still be valid. + // You should use this option instead if your code experience some problems + // reported against Panther 10.3.9 (fixed in Tiger 10.4.2 and up) + bool success = NSUnLinkModule(lib, NSUNLINKMODULE_OPTION_NONE); + return success; +} + +DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( + DynamicLoader::LibraryHandle lib, const std::string& sym) +{ + void* result = 0; + // Need to prepend symbols with '_' on Apple-gcc compilers + std::string rsym = '_' + sym; + + NSSymbol symbol = NSLookupSymbolInModule(lib, rsym.c_str()); + if (symbol) { + result = NSAddressOfSymbol(symbol); + } + + // Hack to cast pointer-to-data to pointer-to-function. + return *reinterpret_cast(&result); +} + +const char* DynamicLoader::LastError() +{ + return 0; +} + +} // namespace KWSYS_NAMESPACE + +#elif defined(_WIN32) && !defined(__CYGWIN__) +// Implementation for Windows win32 code but not cygwin +# include + +# include + +namespace KWSYS_NAMESPACE { + +DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( + const std::string& libname, int flags) +{ + CHECK_OPEN_FLAGS(flags, SearchBesideLibrary, nullptr); + + DWORD llFlags = 0; + if (flags & SearchBesideLibrary) { + llFlags |= LOAD_WITH_ALTERED_SEARCH_PATH; + } + + return LoadLibraryExW(Encoding::ToWindowsExtendedPath(libname).c_str(), + nullptr, llFlags); +} + +int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) +{ + return (int)FreeLibrary(lib); +} + +DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( + DynamicLoader::LibraryHandle lib, const std::string& sym) +{ + // TODO: The calling convention affects the name of the symbol. We + // should have a tool to help get the symbol with the desired + // calling convention. Currently we assume cdecl. + // + // Borland: + // __cdecl = "_func" (default) + // __fastcall = "@_func" + // __stdcall = "func" + // + // Watcom: + // __cdecl = "_func" + // __fastcall = "@_func@X" + // __stdcall = "_func@X" + // __watcall = "func_" (default) + // + // MSVC: + // __cdecl = "func" (default) + // __fastcall = "@_func@X" + // __stdcall = "_func@X" + // + // Note that the "@X" part of the name above is the total size (in + // bytes) of the arguments on the stack. + void* result; +# if defined(__BORLANDC__) || defined(__WATCOMC__) + // Need to prepend symbols with '_' + std::string ssym = '_' + sym; + const char* rsym = ssym.c_str(); +# else + const char* rsym = sym.c_str(); +# endif + result = (void*)GetProcAddress(lib, rsym); +// Hack to cast pointer-to-data to pointer-to-function. +# ifdef __WATCOMC__ + return *(DynamicLoader::SymbolPointer*)(&result); +# else + return *reinterpret_cast(&result); +# endif +} + +# define DYNLOAD_ERROR_BUFFER_SIZE 1024 + +const char* DynamicLoader::LastError() +{ + wchar_t lpMsgBuf[DYNLOAD_ERROR_BUFFER_SIZE + 1]; + + DWORD error = GetLastError(); + DWORD length = FormatMessageW( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, error, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + lpMsgBuf, DYNLOAD_ERROR_BUFFER_SIZE, nullptr); + + static char str[DYNLOAD_ERROR_BUFFER_SIZE + 1]; + + if (length < 1) { + /* FormatMessage failed. Use a default message. */ + _snprintf(str, DYNLOAD_ERROR_BUFFER_SIZE, + "DynamicLoader encountered error 0x%X. " + "FormatMessage failed with error 0x%X", + error, GetLastError()); + return str; + } + + if (!WideCharToMultiByte(CP_UTF8, 0, lpMsgBuf, -1, str, + DYNLOAD_ERROR_BUFFER_SIZE, nullptr, nullptr)) { + /* WideCharToMultiByte failed. Use a default message. */ + _snprintf(str, DYNLOAD_ERROR_BUFFER_SIZE, + "DynamicLoader encountered error 0x%X. " + "WideCharToMultiByte failed with error 0x%X", + error, GetLastError()); + } + + return str; +} + +} // namespace KWSYS_NAMESPACE + +#elif defined(__BEOS__) +// Implementation for BeOS / Haiku +# include // for strerror() + +# include +# include + +namespace KWSYS_NAMESPACE { + +static image_id last_dynamic_err = B_OK; + +DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( + const std::string& libname, int flags) +{ + CHECK_OPEN_FLAGS(flags, 0, 0); + + // image_id's are integers, errors are negative. Add one just in case we + // get a valid image_id of zero (is that even possible?). + image_id rc = load_add_on(libname.c_str()); + if (rc < 0) { + last_dynamic_err = rc; + return 0; + } + + return rc + 1; +} + +int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) +{ + if (!lib) { + last_dynamic_err = B_BAD_VALUE; + return 0; + } else { + // The function dlclose() returns 0 on success, and non-zero on error. + status_t rc = unload_add_on(lib - 1); + if (rc != B_OK) { + last_dynamic_err = rc; + return 0; + } + } + + return 1; +} + +DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( + DynamicLoader::LibraryHandle lib, const std::string& sym) +{ + // Hack to cast pointer-to-data to pointer-to-function. + union + { + void* pvoid; + DynamicLoader::SymbolPointer psym; + } result; + + result.psym = nullptr; + + if (!lib) { + last_dynamic_err = B_BAD_VALUE; + } else { + // !!! FIXME: BeOS can do function-only lookups...does this ever + // !!! FIXME: actually _want_ a data symbol lookup, or was this union + // !!! FIXME: a leftover of dlsym()? (s/ANY/TEXT for functions only). + status_t rc = + get_image_symbol(lib - 1, sym.c_str(), B_SYMBOL_TYPE_ANY, &result.pvoid); + if (rc != B_OK) { + last_dynamic_err = rc; + result.psym = nullptr; + } + } + return result.psym; +} + +const char* DynamicLoader::LastError() +{ + const char* retval = strerror(last_dynamic_err); + last_dynamic_err = B_OK; + return retval; +} + +} // namespace KWSYS_NAMESPACE + +#elif defined(__MINT__) +// Implementation for FreeMiNT on Atari +# define _GNU_SOURCE /* for program_invocation_name */ +# include +# include +# include +# include + +namespace KWSYS_NAMESPACE { + +DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( + const std::string& libname, int flags) +{ + CHECK_OPEN_FLAGS(flags, 0, nullptr); + + char* name = (char*)calloc(1, libname.size() + 1); + dld_init(program_invocation_name); + strncpy(name, libname.c_str(), libname.size()); + dld_link(libname.c_str()); + return (void*)name; +} + +int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) +{ + dld_unlink_by_file((char*)lib, 0); + free(lib); + return 0; +} + +DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( + DynamicLoader::LibraryHandle lib, const std::string& sym) +{ + // Hack to cast pointer-to-data to pointer-to-function. + union + { + void* pvoid; + DynamicLoader::SymbolPointer psym; + } result; + result.pvoid = dld_get_symbol(sym.c_str()); + return result.psym; +} + +const char* DynamicLoader::LastError() +{ + return dld_strerror(dld_errno); +} + +} // namespace KWSYS_NAMESPACE + +#else +// Default implementation for *NIX systems (including Mac OS X 10.3 and +// later) which use dlopen +# include + +namespace KWSYS_NAMESPACE { + +DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( + const std::string& libname, int flags) +{ + CHECK_OPEN_FLAGS(flags, 0, nullptr); + + return dlopen(libname.c_str(), RTLD_LAZY); +} + +int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) +{ + if (lib) { + // The function dlclose() returns 0 on success, and non-zero on error. + return !dlclose(lib); + } + // else + return 0; +} + +DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( + DynamicLoader::LibraryHandle lib, const std::string& sym) +{ + // Hack to cast pointer-to-data to pointer-to-function. + union + { + void* pvoid; + DynamicLoader::SymbolPointer psym; + } result; + result.pvoid = dlsym(lib, sym.c_str()); + return result.psym; +} + +const char* DynamicLoader::LastError() +{ + return dlerror(); +} + +} // namespace KWSYS_NAMESPACE +#endif diff --git a/test/API/driver/kwsys/DynamicLoader.hxx.in b/test/API/driver/kwsys/DynamicLoader.hxx.in new file mode 100644 index 0000000..539c742 --- /dev/null +++ b/test/API/driver/kwsys/DynamicLoader.hxx.in @@ -0,0 +1,106 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_DynamicLoader_hxx +#define @KWSYS_NAMESPACE@_DynamicLoader_hxx + +#include <@KWSYS_NAMESPACE@/Configure.hxx> + +#include + +#if defined(__hpux) +# include +#elif defined(_WIN32) && !defined(__CYGWIN__) +# include +#elif defined(__APPLE__) +# include +# if MAC_OS_X_VERSION_MAX_ALLOWED < 1030 +# include +# endif +#elif defined(__BEOS__) +# include +#endif + +namespace @KWSYS_NAMESPACE@ { +/** \class DynamicLoader + * \brief Portable loading of dynamic libraries or dll's. + * + * DynamicLoader provides a portable interface to loading dynamic + * libraries or dll's into a process. + * + * Directory currently works with Windows, Apple, HP-UX and Unix (POSIX) + * operating systems + * + * \warning dlopen on *nix system works the following way: + * If filename contains a slash ("/"), then it is interpreted as a (relative + * or absolute) pathname. Otherwise, the dynamic linker searches for the + * library as follows : see ld.so(8) for further details): + * Whereas this distinction does not exist on Win32. Therefore ideally you + * should be doing full path to guarantee to have a consistent way of dealing + * with dynamic loading of shared library. + * + * \warning the Cygwin implementation do not use the Win32 HMODULE. Put extra + * condition so that we can include the correct declaration (POSIX) + */ + +class @KWSYS_NAMESPACE@_EXPORT DynamicLoader +{ +public: +// Ugly stuff for library handles +// They are different on several different OS's +#if defined(__hpux) + typedef shl_t LibraryHandle; +#elif defined(_WIN32) && !defined(__CYGWIN__) + typedef HMODULE LibraryHandle; +#elif defined(__APPLE__) +# if MAC_OS_X_VERSION_MAX_ALLOWED < 1030 + typedef NSModule LibraryHandle; +# else + typedef void* LibraryHandle; +# endif +#elif defined(__BEOS__) + typedef image_id LibraryHandle; +#else // POSIX + typedef void* LibraryHandle; +#endif + + // Return type from DynamicLoader::GetSymbolAddress. + typedef void (*SymbolPointer)(); + + enum OpenFlags + { + // Search for dependent libraries beside the library being loaded. + // + // This is currently only supported on Windows. + SearchBesideLibrary = 0x00000001, + + AllOpenFlags = SearchBesideLibrary + }; + + /** Load a dynamic library into the current process. + * The returned LibraryHandle can be used to access the symbols in the + * library. The optional second argument is a set of flags to use when + * opening the library. If unrecognized or unsupported flags are specified, + * the library is not opened. */ + static LibraryHandle OpenLibrary(const std::string&); + static LibraryHandle OpenLibrary(const std::string&, int); + + /** Attempt to detach a dynamic library from the + * process. A value of true is returned if it is successful. */ + static int CloseLibrary(LibraryHandle); + + /** Find the address of the symbol in the given library. */ + static SymbolPointer GetSymbolAddress(LibraryHandle, const std::string&); + + /** Return the default module prefix for the current platform. */ + static const char* LibPrefix() { return "@KWSYS_DynamicLoader_PREFIX@"; } + + /** Return the default module suffix for the current platform. */ + static const char* LibExtension() { return "@KWSYS_DynamicLoader_SUFFIX@"; } + + /** Return the last error produced from a calls made on this class. */ + static const char* LastError(); +}; // End Class: DynamicLoader + +} // namespace @KWSYS_NAMESPACE@ + +#endif diff --git a/test/API/driver/kwsys/Encoding.h.in b/test/API/driver/kwsys/Encoding.h.in new file mode 100644 index 0000000..86a2669 --- /dev/null +++ b/test/API/driver/kwsys/Encoding.h.in @@ -0,0 +1,69 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_Encoding_h +#define @KWSYS_NAMESPACE@_Encoding_h + +#include <@KWSYS_NAMESPACE@/Configure.h> + +#include + +/* Redefine all public interface symbol names to be in the proper + namespace. These macros are used internally to kwsys only, and are + not visible to user code. Use kwsysHeaderDump.pl to reproduce + these macros after making changes to the interface. */ +#if !defined(KWSYS_NAMESPACE) +# define kwsys_ns(x) @KWSYS_NAMESPACE@##x +# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT +#endif +#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# define kwsysEncoding kwsys_ns(Encoding) +# define kwsysEncoding_mbstowcs kwsys_ns(Encoding_mbstowcs) +# define kwsysEncoding_DupToWide kwsys_ns(Encoding_DupToWide) +# define kwsysEncoding_wcstombs kwsys_ns(Encoding_wcstombs) +# define kwsysEncoding_DupToNarrow kwsys_ns(Encoding_DupToNarrow) +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +/* Convert a narrow string to a wide string. + On Windows, UTF-8 is assumed, and on other platforms, + the current locale is assumed. + */ +kwsysEXPORT size_t kwsysEncoding_mbstowcs(wchar_t* dest, const char* src, + size_t n); + +/* Convert a narrow string to a wide string. + This can return NULL if the conversion fails. */ +kwsysEXPORT wchar_t* kwsysEncoding_DupToWide(const char* src); + +/* Convert a wide string to a narrow string. + On Windows, UTF-8 is assumed, and on other platforms, + the current locale is assumed. */ +kwsysEXPORT size_t kwsysEncoding_wcstombs(char* dest, const wchar_t* src, + size_t n); + +/* Convert a wide string to a narrow string. + This can return NULL if the conversion fails. */ +kwsysEXPORT char* kwsysEncoding_DupToNarrow(const wchar_t* str); + +#if defined(__cplusplus) +} /* extern "C" */ +#endif + +/* If we are building a kwsys .c or .cxx file, let it use these macros. + Otherwise, undefine them to keep the namespace clean. */ +#if !defined(KWSYS_NAMESPACE) +# undef kwsys_ns +# undef kwsysEXPORT +# if !defined(KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# undef kwsysEncoding +# undef kwsysEncoding_mbstowcs +# undef kwsysEncoding_DupToWide +# undef kwsysEncoding_wcstombs +# undef kwsysEncoding_DupToNarrow +# endif +#endif + +#endif diff --git a/test/API/driver/kwsys/Encoding.hxx.in b/test/API/driver/kwsys/Encoding.hxx.in new file mode 100644 index 0000000..75a2d4d --- /dev/null +++ b/test/API/driver/kwsys/Encoding.hxx.in @@ -0,0 +1,80 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_Encoding_hxx +#define @KWSYS_NAMESPACE@_Encoding_hxx + +#include <@KWSYS_NAMESPACE@/Configure.hxx> + +#include +#include + +namespace @KWSYS_NAMESPACE@ { +class @KWSYS_NAMESPACE@_EXPORT Encoding +{ +public: + // Container class for argc/argv. + class @KWSYS_NAMESPACE@_EXPORT CommandLineArguments + { + public: + // On Windows, get the program command line arguments + // in this Encoding module's 8 bit encoding. + // On other platforms the given argc/argv is used, and + // to be consistent, should be the argc/argv from main(). + static CommandLineArguments Main(int argc, char const* const* argv); + + // Construct CommandLineArguments with the given + // argc/argv. It is assumed that the string is already + // in the encoding used by this module. + CommandLineArguments(int argc, char const* const* argv); + + // Construct CommandLineArguments with the given + // argc and wide argv. This is useful if wmain() is used. + CommandLineArguments(int argc, wchar_t const* const* argv); + ~CommandLineArguments(); + CommandLineArguments(const CommandLineArguments&); + CommandLineArguments& operator=(const CommandLineArguments&); + + int argc() const; + char const* const* argv() const; + + protected: + std::vector argv_; + }; + + /** + * Convert between char and wchar_t + */ + +#if @KWSYS_NAMESPACE@_STL_HAS_WSTRING + + // Convert a narrow string to a wide string. + // On Windows, UTF-8 is assumed, and on other platforms, + // the current locale is assumed. + static std::wstring ToWide(const std::string& str); + static std::wstring ToWide(const char* str); + + // Convert a wide string to a narrow string. + // On Windows, UTF-8 is assumed, and on other platforms, + // the current locale is assumed. + static std::string ToNarrow(const std::wstring& str); + static std::string ToNarrow(const wchar_t* str); + +# if defined(_WIN32) + /** + * Convert the path to an extended length path to avoid MAX_PATH length + * limitations on Windows. If the input is a local path the result will be + * prefixed with \\?\; if the input is instead a network path, the result + * will be prefixed with \\?\UNC\. All output will also be converted to + * absolute paths with Windows-style backslashes. + **/ + static std::wstring ToWindowsExtendedPath(std::string const&); + static std::wstring ToWindowsExtendedPath(const char* source); + static std::wstring ToWindowsExtendedPath(std::wstring const& wsource); +# endif + +#endif // @KWSYS_NAMESPACE@_STL_HAS_WSTRING + +}; // class Encoding +} // namespace @KWSYS_NAMESPACE@ + +#endif diff --git a/test/API/driver/kwsys/EncodingC.c b/test/API/driver/kwsys/EncodingC.c new file mode 100644 index 0000000..e12236a --- /dev/null +++ b/test/API/driver/kwsys/EncodingC.c @@ -0,0 +1,72 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(Encoding.h) + +/* Work-around CMake dependency scanning limitation. This must + duplicate the above list of headers. */ +#if 0 +# include "Encoding.h.in" +#endif + +#include + +#ifdef _WIN32 +# include +#endif + +size_t kwsysEncoding_mbstowcs(wchar_t* dest, const char* str, size_t n) +{ + if (str == 0) { + return (size_t)-1; + } +#ifdef _WIN32 + return MultiByteToWideChar(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str, -1, dest, + (int)n) - + 1; +#else + return mbstowcs(dest, str, n); +#endif +} + +wchar_t* kwsysEncoding_DupToWide(const char* str) +{ + wchar_t* ret = NULL; + size_t length = kwsysEncoding_mbstowcs(NULL, str, 0) + 1; + if (length > 0) { + ret = (wchar_t*)malloc((length) * sizeof(wchar_t)); + if (ret) { + ret[0] = 0; + kwsysEncoding_mbstowcs(ret, str, length); + } + } + return ret; +} + +size_t kwsysEncoding_wcstombs(char* dest, const wchar_t* str, size_t n) +{ + if (str == 0) { + return (size_t)-1; + } +#ifdef _WIN32 + return WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str, -1, dest, + (int)n, NULL, NULL) - + 1; +#else + return wcstombs(dest, str, n); +#endif +} + +char* kwsysEncoding_DupToNarrow(const wchar_t* str) +{ + char* ret = NULL; + size_t length = kwsysEncoding_wcstombs(0, str, 0) + 1; + if (length > 0) { + ret = (char*)malloc(length); + if (ret) { + ret[0] = 0; + kwsysEncoding_wcstombs(ret, str, length); + } + } + return ret; +} diff --git a/test/API/driver/kwsys/EncodingCXX.cxx b/test/API/driver/kwsys/EncodingCXX.cxx new file mode 100644 index 0000000..5cad934 --- /dev/null +++ b/test/API/driver/kwsys/EncodingCXX.cxx @@ -0,0 +1,288 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifdef __osf__ +# define _OSF_SOURCE +# define _POSIX_C_SOURCE 199506L +# define _XOPEN_SOURCE_EXTENDED +#endif + +#include "kwsysPrivate.h" +#include KWSYS_HEADER(Encoding.hxx) +#include KWSYS_HEADER(Encoding.h) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "Encoding.h.in" +# include "Encoding.hxx.in" +#endif + +#include +#include +#include + +#ifdef _MSC_VER +# pragma warning(disable : 4786) +#endif + +// Windows API. +#if defined(_WIN32) +# include + +# include +# include +#endif + +namespace KWSYS_NAMESPACE { + +Encoding::CommandLineArguments Encoding::CommandLineArguments::Main( + int argc, char const* const* argv) +{ +#ifdef _WIN32 + (void)argc; + (void)argv; + + int ac; + LPWSTR* w_av = CommandLineToArgvW(GetCommandLineW(), &ac); + + std::vector av1(ac); + std::vector av2(ac); + for (int i = 0; i < ac; i++) { + av1[i] = ToNarrow(w_av[i]); + av2[i] = av1[i].c_str(); + } + LocalFree(w_av); + return CommandLineArguments(ac, &av2[0]); +#else + return CommandLineArguments(argc, argv); +#endif +} + +Encoding::CommandLineArguments::CommandLineArguments(int ac, + char const* const* av) +{ + this->argv_.resize(ac + 1); + for (int i = 0; i < ac; i++) { + this->argv_[i] = strdup(av[i]); + } + this->argv_[ac] = nullptr; +} + +Encoding::CommandLineArguments::CommandLineArguments(int ac, + wchar_t const* const* av) +{ + this->argv_.resize(ac + 1); + for (int i = 0; i < ac; i++) { + this->argv_[i] = kwsysEncoding_DupToNarrow(av[i]); + } + this->argv_[ac] = nullptr; +} + +Encoding::CommandLineArguments::~CommandLineArguments() +{ + for (size_t i = 0; i < this->argv_.size(); i++) { + free(argv_[i]); + } +} + +Encoding::CommandLineArguments::CommandLineArguments( + const CommandLineArguments& other) +{ + this->argv_.resize(other.argv_.size()); + for (size_t i = 0; i < this->argv_.size(); i++) { + this->argv_[i] = other.argv_[i] ? strdup(other.argv_[i]) : nullptr; + } +} + +Encoding::CommandLineArguments& Encoding::CommandLineArguments::operator=( + const CommandLineArguments& other) +{ + if (this != &other) { + size_t i; + for (i = 0; i < this->argv_.size(); i++) { + free(this->argv_[i]); + } + + this->argv_.resize(other.argv_.size()); + for (i = 0; i < this->argv_.size(); i++) { + this->argv_[i] = other.argv_[i] ? strdup(other.argv_[i]) : nullptr; + } + } + + return *this; +} + +int Encoding::CommandLineArguments::argc() const +{ + return static_cast(this->argv_.size() - 1); +} + +char const* const* Encoding::CommandLineArguments::argv() const +{ + return &this->argv_[0]; +} + +#if KWSYS_STL_HAS_WSTRING + +std::wstring Encoding::ToWide(const std::string& str) +{ + std::wstring wstr; +# if defined(_WIN32) + const int wlength = + MultiByteToWideChar(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.data(), + int(str.size()), nullptr, 0); + if (wlength > 0) { + wchar_t* wdata = new wchar_t[wlength]; + int r = MultiByteToWideChar(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.data(), + int(str.size()), wdata, wlength); + if (r > 0) { + wstr = std::wstring(wdata, wlength); + } + delete[] wdata; + } +# else + size_t pos = 0; + size_t nullPos = 0; + do { + if (pos < str.size() && str.at(pos) != '\0') { + wstr += ToWide(str.c_str() + pos); + } + nullPos = str.find('\0', pos); + if (nullPos != std::string::npos) { + pos = nullPos + 1; + wstr += wchar_t('\0'); + } + } while (nullPos != std::string::npos); +# endif + return wstr; +} + +std::string Encoding::ToNarrow(const std::wstring& str) +{ + std::string nstr; +# if defined(_WIN32) + int length = + WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.c_str(), + int(str.size()), nullptr, 0, nullptr, nullptr); + if (length > 0) { + char* data = new char[length]; + int r = + WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.c_str(), + int(str.size()), data, length, nullptr, nullptr); + if (r > 0) { + nstr = std::string(data, length); + } + delete[] data; + } +# else + size_t pos = 0; + size_t nullPos = 0; + do { + if (pos < str.size() && str.at(pos) != '\0') { + nstr += ToNarrow(str.c_str() + pos); + } + nullPos = str.find(wchar_t('\0'), pos); + if (nullPos != std::string::npos) { + pos = nullPos + 1; + nstr += '\0'; + } + } while (nullPos != std::string::npos); +# endif + return nstr; +} + +std::wstring Encoding::ToWide(const char* cstr) +{ + std::wstring wstr; + size_t length = kwsysEncoding_mbstowcs(nullptr, cstr, 0) + 1; + if (length > 0) { + std::vector wchars(length); + if (kwsysEncoding_mbstowcs(&wchars[0], cstr, length) > 0) { + wstr = &wchars[0]; + } + } + return wstr; +} + +std::string Encoding::ToNarrow(const wchar_t* wcstr) +{ + std::string str; + size_t length = kwsysEncoding_wcstombs(nullptr, wcstr, 0) + 1; + if (length > 0) { + std::vector chars(length); + if (kwsysEncoding_wcstombs(&chars[0], wcstr, length) > 0) { + str = &chars[0]; + } + } + return str; +} + +# if defined(_WIN32) +// Convert local paths to UNC style paths +std::wstring Encoding::ToWindowsExtendedPath(std::string const& source) +{ + return ToWindowsExtendedPath(ToWide(source)); +} + +// Convert local paths to UNC style paths +std::wstring Encoding::ToWindowsExtendedPath(const char* source) +{ + return ToWindowsExtendedPath(ToWide(source)); +} + +// Convert local paths to UNC style paths +std::wstring Encoding::ToWindowsExtendedPath(std::wstring const& wsource) +{ + // Resolve any relative paths + DWORD wfull_len; + + /* The +3 is a workaround for a bug in some versions of GetFullPathNameW that + * won't return a large enough buffer size if the input is too small */ + wfull_len = GetFullPathNameW(wsource.c_str(), 0, nullptr, nullptr) + 3; + std::vector wfull(wfull_len); + GetFullPathNameW(wsource.c_str(), wfull_len, &wfull[0], nullptr); + + /* This should get the correct size without any extra padding from the + * previous size workaround. */ + wfull_len = static_cast(wcslen(&wfull[0])); + + if (wfull_len >= 2 && isalpha(wfull[0]) && + wfull[1] == L':') { /* C:\Foo\bar\FooBar.txt */ + return L"\\\\?\\" + std::wstring(&wfull[0]); + } else if (wfull_len >= 2 && wfull[0] == L'\\' && + wfull[1] == L'\\') { /* Starts with \\ */ + if (wfull_len >= 4 && wfull[2] == L'?' && + wfull[3] == L'\\') { /* Starts with \\?\ */ + if (wfull_len >= 8 && wfull[4] == L'U' && wfull[5] == L'N' && + wfull[6] == L'C' && + wfull[7] == L'\\') { /* \\?\UNC\Foo\bar\FooBar.txt */ + return std::wstring(&wfull[0]); + } else if (wfull_len >= 6 && isalpha(wfull[4]) && + wfull[5] == L':') { /* \\?\C:\Foo\bar\FooBar.txt */ + return std::wstring(&wfull[0]); + } else if (wfull_len >= 5) { /* \\?\Foo\bar\FooBar.txt */ + return L"\\\\?\\UNC\\" + std::wstring(&wfull[4]); + } + } else if (wfull_len >= 4 && wfull[2] == L'.' && + wfull[3] == L'\\') { /* Starts with \\.\ a device name */ + if (wfull_len >= 6 && isalpha(wfull[4]) && + wfull[5] == L':') { /* \\.\C:\Foo\bar\FooBar.txt */ + return L"\\\\?\\" + std::wstring(&wfull[4]); + } else if (wfull_len >= + 5) { /* \\.\Foo\bar\ Device name is left unchanged */ + return std::wstring(&wfull[0]); + } + } else if (wfull_len >= 3) { /* \\Foo\bar\FooBar.txt */ + return L"\\\\?\\UNC\\" + std::wstring(&wfull[2]); + } + } + + // If this case has been reached, then the path is invalid. Leave it + // unchanged + return wsource; +} +# endif + +#endif // KWSYS_STL_HAS_WSTRING + +} // namespace KWSYS_NAMESPACE diff --git a/test/API/driver/kwsys/ExtraTest.cmake.in b/test/API/driver/kwsys/ExtraTest.cmake.in new file mode 100644 index 0000000..e8c0a1c --- /dev/null +++ b/test/API/driver/kwsys/ExtraTest.cmake.in @@ -0,0 +1 @@ +MESSAGE("*** This message is generated by message inside a file that is included in DartTestfile.txt ***") diff --git a/test/API/driver/kwsys/FStream.cxx b/test/API/driver/kwsys/FStream.cxx new file mode 100644 index 0000000..5e4133a --- /dev/null +++ b/test/API/driver/kwsys/FStream.cxx @@ -0,0 +1,55 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(FStream.hxx) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "FStream.hxx.in" +#endif + +namespace KWSYS_NAMESPACE { +namespace FStream { + +BOM ReadBOM(std::istream& in) +{ + if (!in.good()) { + return BOM_None; + } + unsigned long orig = in.tellg(); + unsigned char bom[4]; + in.read(reinterpret_cast(bom), 2); + if (!in.good()) { + in.clear(); + in.seekg(orig); + return BOM_None; + } + if (bom[0] == 0xEF && bom[1] == 0xBB) { + in.read(reinterpret_cast(bom + 2), 1); + if (in.good() && bom[2] == 0xBF) { + return BOM_UTF8; + } + } else if (bom[0] == 0xFE && bom[1] == 0xFF) { + return BOM_UTF16BE; + } else if (bom[0] == 0x00 && bom[1] == 0x00) { + in.read(reinterpret_cast(bom + 2), 2); + if (in.good() && bom[2] == 0xFE && bom[3] == 0xFF) { + return BOM_UTF32BE; + } + } else if (bom[0] == 0xFF && bom[1] == 0xFE) { + unsigned long p = in.tellg(); + in.read(reinterpret_cast(bom + 2), 2); + if (in.good() && bom[2] == 0x00 && bom[3] == 0x00) { + return BOM_UTF32LE; + } + in.seekg(p); + return BOM_UTF16LE; + } + in.clear(); + in.seekg(orig); + return BOM_None; +} + +} // FStream namespace +} // KWSYS_NAMESPACE diff --git a/test/API/driver/kwsys/FStream.hxx.in b/test/API/driver/kwsys/FStream.hxx.in new file mode 100644 index 0000000..d79bbdf --- /dev/null +++ b/test/API/driver/kwsys/FStream.hxx.in @@ -0,0 +1,278 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_FStream_hxx +#define @KWSYS_NAMESPACE@_FStream_hxx + +#include <@KWSYS_NAMESPACE@/Configure.hxx> + +#include <@KWSYS_NAMESPACE@/Encoding.hxx> + +#include +#if defined(_WIN32) +# if !defined(_MSC_VER) && @KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H +# include +# endif +#endif + +namespace @KWSYS_NAMESPACE@ { +#if defined(_WIN32) && \ + (defined(_MSC_VER) || @KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H) +# if defined(_NOEXCEPT) +# define @KWSYS_NAMESPACE@_FStream_NOEXCEPT _NOEXCEPT +# else +# define @KWSYS_NAMESPACE@_FStream_NOEXCEPT +# endif + +# if defined(_MSC_VER) + +template +class basic_filebuf : public std::basic_filebuf +{ +# if _MSC_VER >= 1400 +public: + typedef std::basic_filebuf my_base_type; + basic_filebuf* open(char const* s, std::ios_base::openmode mode) + { + const std::wstring wstr = Encoding::ToWindowsExtendedPath(s); + return static_cast(my_base_type::open(wstr.c_str(), mode)); + } +# endif +}; + +# else + +inline std::wstring getcmode(const std::ios_base::openmode mode) +{ + std::wstring cmode; + bool plus = false; + if (mode & std::ios_base::app) { + cmode += L"a"; + plus = mode & std::ios_base::in ? true : false; + } else if (mode & std::ios_base::trunc || + (mode & std::ios_base::out && (mode & std::ios_base::in) == 0)) { + cmode += L"w"; + plus = mode & std::ios_base::in ? true : false; + } else { + cmode += L"r"; + plus = mode & std::ios_base::out ? true : false; + } + if (plus) { + cmode += L"+"; + } + if (mode & std::ios_base::binary) { + cmode += L"b"; + } else { + cmode += L"t"; + } + return cmode; +}; + +# endif + +template > +class basic_efilebuf +{ +public: +# if defined(_MSC_VER) + typedef basic_filebuf internal_buffer_type; +# else + typedef __gnu_cxx::stdio_filebuf internal_buffer_type; +# endif + + basic_efilebuf() + : file_(0) + { + buf_ = 0; + } + + bool _open(char const* file_name, std::ios_base::openmode mode) + { + if (is_open() || file_) { + return false; + } +# if defined(_MSC_VER) + const bool success = buf_->open(file_name, mode) != 0; +# else + const std::wstring wstr = Encoding::ToWindowsExtendedPath(file_name); + bool success = false; + std::wstring cmode = getcmode(mode); + file_ = _wfopen(wstr.c_str(), cmode.c_str()); + if (file_) { + if (buf_) { + delete buf_; + } + buf_ = new internal_buffer_type(file_, mode); + success = true; + } +# endif + return success; + } + + bool is_open() + { + if (!buf_) { + return false; + } + return buf_->is_open(); + } + + bool is_open() const + { + if (!buf_) { + return false; + } + return buf_->is_open(); + } + + bool _close() + { + bool success = false; + if (buf_) { + success = buf_->close() != 0; +# if !defined(_MSC_VER) + if (file_) { + success = fclose(file_) == 0 ? success : false; + file_ = 0; + } +# endif + } + return success; + } + + static void _set_state(bool success, std::basic_ios* ios, + basic_efilebuf* efilebuf) + { +# if !defined(_MSC_VER) + ios->rdbuf(efilebuf->buf_); +# else + static_cast(efilebuf); +# endif + if (!success) { + ios->setstate(std::ios_base::failbit); + } else { + ios->clear(); + } + } + + ~basic_efilebuf() + { + if (buf_) { + delete buf_; + } + } + +protected: + internal_buffer_type* buf_; + FILE* file_; +}; + +template > +class basic_ifstream + : public std::basic_istream + , public basic_efilebuf +{ +public: + typedef typename basic_efilebuf::internal_buffer_type + internal_buffer_type; + typedef std::basic_istream internal_stream_type; + + basic_ifstream() + : internal_stream_type(new internal_buffer_type()) + { + this->buf_ = + static_cast(internal_stream_type::rdbuf()); + } + explicit basic_ifstream(char const* file_name, + std::ios_base::openmode mode = std::ios_base::in) + : internal_stream_type(new internal_buffer_type()) + { + this->buf_ = + static_cast(internal_stream_type::rdbuf()); + open(file_name, mode); + } + + void open(char const* file_name, + std::ios_base::openmode mode = std::ios_base::in) + { + mode = mode | std::ios_base::in; + this->_set_state(this->_open(file_name, mode), this, this); + } + + void close() { this->_set_state(this->_close(), this, this); } + + using basic_efilebuf::is_open; + + internal_buffer_type* rdbuf() const { return this->buf_; } + + ~basic_ifstream() @KWSYS_NAMESPACE@_FStream_NOEXCEPT { close(); } +}; + +template > +class basic_ofstream + : public std::basic_ostream + , public basic_efilebuf +{ + using basic_efilebuf::is_open; + +public: + typedef typename basic_efilebuf::internal_buffer_type + internal_buffer_type; + typedef std::basic_ostream internal_stream_type; + + basic_ofstream() + : internal_stream_type(new internal_buffer_type()) + { + this->buf_ = + static_cast(internal_stream_type::rdbuf()); + } + explicit basic_ofstream(char const* file_name, + std::ios_base::openmode mode = std::ios_base::out) + : internal_stream_type(new internal_buffer_type()) + { + this->buf_ = + static_cast(internal_stream_type::rdbuf()); + open(file_name, mode); + } + void open(char const* file_name, + std::ios_base::openmode mode = std::ios_base::out) + { + mode = mode | std::ios_base::out; + this->_set_state(this->_open(file_name, mode), this, this); + } + + void close() { this->_set_state(this->_close(), this, this); } + + internal_buffer_type* rdbuf() const { return this->buf_; } + + ~basic_ofstream() @KWSYS_NAMESPACE@_FStream_NOEXCEPT { close(); } +}; + +typedef basic_ifstream ifstream; +typedef basic_ofstream ofstream; + +# undef @KWSYS_NAMESPACE@_FStream_NOEXCEPT +#else +using std::ofstream; +using std::ifstream; +#endif + +namespace FStream { +enum BOM +{ + BOM_None, + BOM_UTF8, + BOM_UTF16BE, + BOM_UTF16LE, + BOM_UTF32BE, + BOM_UTF32LE +}; + +// Read a BOM, if one exists. +// If a BOM exists, the stream is advanced to after the BOM. +// This function requires a seekable stream (but not a relative +// seekable stream). +@KWSYS_NAMESPACE@_EXPORT BOM ReadBOM(std::istream& in); +} +} + +#endif diff --git a/test/API/driver/kwsys/GitSetup/.gitattributes b/test/API/driver/kwsys/GitSetup/.gitattributes new file mode 100644 index 0000000..e96d1f8 --- /dev/null +++ b/test/API/driver/kwsys/GitSetup/.gitattributes @@ -0,0 +1,6 @@ +.git* export-ignore + +config* eol=lf whitespace=indent-with-non-tab +git-* eol=lf whitespace=indent-with-non-tab +tips eol=lf whitespace=indent-with-non-tab +setup-* eol=lf whitespace=indent-with-non-tab diff --git a/test/API/driver/kwsys/GitSetup/LICENSE b/test/API/driver/kwsys/GitSetup/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/test/API/driver/kwsys/GitSetup/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/test/API/driver/kwsys/GitSetup/NOTICE b/test/API/driver/kwsys/GitSetup/NOTICE new file mode 100644 index 0000000..0d32c02 --- /dev/null +++ b/test/API/driver/kwsys/GitSetup/NOTICE @@ -0,0 +1,5 @@ +Kitware Local Git Setup Scripts +Copyright 2010-2012 Kitware, Inc. + +This product includes software developed at Kitware, Inc. +(http://www.kitware.com/). diff --git a/test/API/driver/kwsys/GitSetup/README b/test/API/driver/kwsys/GitSetup/README new file mode 100644 index 0000000..2f9f1ec --- /dev/null +++ b/test/API/driver/kwsys/GitSetup/README @@ -0,0 +1,87 @@ +Kitware Local Git Setup Scripts + + +Introduction +------------ + +This is a collection of local Git development setup scripts meant for +inclusion in project source trees to aid their development workflow. +Project-specific information needed by the scripts may be configured +in a "config" file added next to them in the project. + + +Import +------ + +A project may import these scripts into their source tree by +initializing a subtree merge. Bring up a Git prompt and set the +current working directory inside a clone of the target project. +Fetch the "setup" branch from the GitSetup repository: + + $ git fetch ../GitSetup setup:setup + +Prepare to merge the branch but place the content in a subdirectory. +Any prefix (with trailing '/') may be chosen so long as it is used +consistently within a project through the rest of these instructions: + + $ git merge -s ours --no-commit setup + $ git read-tree -u --prefix=Utilities/GitSetup/ setup + +Commit the merge with an informative message: + + $ git commit + ------------------------------------------------------------------------ + Merge branch 'setup' + + Add Utilities/GitSetup/ directory using subtree merge from + the general GitSetup repository "setup" branch. + ------------------------------------------------------------------------ + +Optionally add to the project ".gitattributes" file the line + + /Utilities/GitSetup export-ignore + +to exclude the GitSetup directory from inclusion by "git archive" +since it does not make sense in source tarballs. + + +Configuration +------------- + +Read the "Project configuration instructions" comment in each script. +Add a "config" file next to the scripts with desired configuration +(optionally copy and modify "config.sample"). For example, to +configure the "setup-hooks" script: + + $ git config -f Utilities/GitSetup/config hooks.url "$url" + +where "$url" is the project repository publishing the "hooks" branch. +When finished, add and commit the configuration file: + + $ git add Utilities/GitSetup/config + $ git commit + + +Update +------ + +A project may update these scripts from the GitSetup repository. +Bring up a Git prompt and set the current working directory inside a +clone of the target project. Fetch the "setup" branch from the +GitSetup repository: + + $ git fetch ../GitSetup setup:setup + +Merge the "setup" branch into the subtree: + + $ git merge -X subtree=Utilities/GitSetup setup + +where "Utilities/GitSetup" is the same prefix used during the import +setup, but without a trailing '/'. + + +License +------- + +Distributed under the Apache License 2.0. +See LICENSE and NOTICE for details. diff --git a/test/API/driver/kwsys/GitSetup/config b/test/API/driver/kwsys/GitSetup/config new file mode 100644 index 0000000..cba4c14 --- /dev/null +++ b/test/API/driver/kwsys/GitSetup/config @@ -0,0 +1,4 @@ +[hooks] + url = https://gitlab.kitware.com/utils/gitsetup.git +[upstream] + url = https://gitlab.kitware.com/utils/kwsys.git diff --git a/test/API/driver/kwsys/GitSetup/config.sample b/test/API/driver/kwsys/GitSetup/config.sample new file mode 100644 index 0000000..eeb468b --- /dev/null +++ b/test/API/driver/kwsys/GitSetup/config.sample @@ -0,0 +1,32 @@ +# Kitware Local Git Setup Scripts - Sample Project Configuration +# +# Copy to "config" and edit as necessary. + +[hooks] + url = http://public.kitware.com/GitSetup.git + #branch = hooks + +[ssh] + host = public.kitware.com + key = id_git_public + request-url = https://www.kitware.com/Admin/SendPassword.cgi + +[stage] + #url = git://public.kitware.com/stage/Project.git + #pushurl = git@public.kitware.com:stage/Project.git + +[gerrit] + #project = Project + site = http://review.source.kitware.com + # pushurl placeholder "$username" is literal + pushurl = $username@review.source.kitware.com:Project + +[upstream] + url = git://public.kitware.com/Project.git + +[gitlab] + host = gitlab.kitware.com + group-path = group + group-name = Group + project-path = project + project-name = Project diff --git a/test/API/driver/kwsys/GitSetup/git-gerrit-push b/test/API/driver/kwsys/GitSetup/git-gerrit-push new file mode 100644 index 0000000..b46f753 --- /dev/null +++ b/test/API/driver/kwsys/GitSetup/git-gerrit-push @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +#============================================================================= +# Copyright 2010-2015 Kitware, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============================================================================= + +USAGE="[] [--no-topic] [--dry-run] [--]" +OPTIONS_SPEC= +SUBDIRECTORY_OK=Yes +. "$(git --exec-path)/git-sh-setup" + +#----------------------------------------------------------------------------- + +remote='' +refspecs='' +no_topic='' +dry_run='' + +# Parse the command line options. +while test $# != 0; do + case "$1" in + --no-topic) no_topic=1 ;; + --dry-run) dry_run=--dry-run ;; + --) shift; break ;; + -*) usage ;; + *) test -z "$remote" || usage ; remote="$1" ;; + esac + shift +done +test $# = 0 || usage + +# Default remote. +test -n "$remote" || remote="gerrit" + +if test -z "$no_topic"; then + # Identify and validate the topic branch name. + head="$(git symbolic-ref HEAD)" && topic="${head#refs/heads/}" || topic='' + if test -z "$topic" -o "$topic" = "master"; then + die 'Please name your topic: + git checkout -b descriptive-name' + fi + # The topic branch will be pushed by name. + refspecs="HEAD:refs/for/master/$topic $refspecs" +fi + +# Fetch the current upstream master branch head. +# This helps computation of a minimal pack to push. +echo "Fetching $remote master" +fetch_out=$(git fetch "$remote" master 2>&1) || die "$fetch_out" + +# Exit early if we have nothing to push. +if test -z "$refspecs"; then + echo 'Nothing to push!' + exit 0 +fi + +# Push. Save output and exit code. +echo "Pushing to $remote" +push_stdout=$(git push --porcelain $dry_run "$remote" $refspecs); push_exit=$? +echo "$push_stdout" + +# Reproduce the push exit code. +exit $push_exit diff --git a/test/API/driver/kwsys/GitSetup/git-gitlab-push b/test/API/driver/kwsys/GitSetup/git-gitlab-push new file mode 100644 index 0000000..768f853 --- /dev/null +++ b/test/API/driver/kwsys/GitSetup/git-gitlab-push @@ -0,0 +1,177 @@ +#!/usr/bin/env bash +#============================================================================= +# Copyright 2010-2015 Kitware, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============================================================================= + +USAGE='[] [...] [--] + +OPTIONS + +--dry-run + Show what would be pushed without actually updating the destination + +-f,--force + Force-push the topic HEAD to rewrite the destination branch + +--no-default + Do not push the default branch (e.g. master) + +--no-topic + Do not push the topic HEAD. +' +OPTIONS_SPEC= +SUBDIRECTORY_OK=Yes +. "$(git --exec-path)/git-sh-setup" + +egrep-q() { + egrep "$@" >/dev/null 2>/dev/null +} + +# Load the project configuration. +gitlab_upstream='' && +gitlab_configured='' && +config="${BASH_SOURCE%/*}/config" && +protocol=$(git config -f "$config" --get gitlab.protocol || + echo "https") && +host=$(git config -f "$config" --get gitlab.host) && +site=$(git config -f "$config" --get gitlab.site || + echo "$protocol://$host") && +group_path=$(git config -f "$config" --get gitlab.group-path) && +project_path=$(git config -f "$config" --get gitlab.project-path) && +gitlab_upstream="$site/$group_path/$project_path.git" && +gitlab_pushurl=$(git config --get remote.gitlab.pushurl || + git config --get remote.gitlab.url) && +gitlab_configured=1 + +#----------------------------------------------------------------------------- + +remote='' +refspecs='' +force='' +lease=false +lease_flag='' +no_topic='' +no_default='' +dry_run='' + +# Parse the command line options. +while test $# != 0; do + case "$1" in + -f|--force) force='+'; lease=true ;; + --no-topic) no_topic=1 ;; + --dry-run) dry_run=--dry-run ;; + --no-default) no_default=1 ;; + --) shift; break ;; + -*) usage ;; + *) test -z "$remote" || usage ; remote="$1" ;; + esac + shift +done +test $# = 0 || usage + +# Default remote. +test -n "$remote" || remote="gitlab" + +if test -z "$no_topic"; then + # Identify and validate the topic branch name. + head="$(git symbolic-ref HEAD)" && topic="${head#refs/heads/}" || topic='' + if test -z "$topic" -o "$topic" = "master"; then + die 'Please name your topic: + git checkout -b descriptive-name' + fi + + if $lease; then + have_ref=false + remoteref="refs/remotes/$remote/$topic" + if git rev-parse --verify -q "$remoteref"; then + have_ref=true + else + die "It seems that a local ref for the branch is +missing; forcing a push is dangerous and may overwrite +previous work. Fetch from the $remote remote first or +push without '-f' or '--force'." + fi + + have_lease_flag=false + if git push -h | egrep-q -e '--force-with-lease'; then + have_lease_flag=true + fi + + if $have_lease_flag && $have_ref; then + # Set the lease flag. + lease_flag="--force-with-lease=$topic:$remoteref" + # Clear the force string. + force='' + fi + fi + + # The topic branch will be pushed by name. + refspecs="${force}HEAD:refs/heads/$topic $refspecs" +fi + +# Fetch the current remote master branch head. +# This helps computation of a minimal pack to push. +echo "Fetching $remote master" +fetch_out=$(git fetch "$remote" master 2>&1) || die "$fetch_out" +gitlab_head=$(git rev-parse FETCH_HEAD) || exit + +# Fetch the current upstream master branch head. +if origin_fetchurl=$(git config --get remote.origin.url) && + test "$origin_fetchurl" = "$gitlab_upstream"; then + upstream_remote='origin' +else + upstream_remote="$gitlab_upstream" +fi +echo "Fetching $upstream_remote master" +fetch_out=$(git fetch "$upstream_remote" master 2>&1) || die "$fetch_out" +upstream_head=$(git rev-parse FETCH_HEAD) || exit + +# Add a refspec to keep the remote master up to date if possible. +if test -z "$no_default" && + base=$(git merge-base "$gitlab_head" "$upstream_head") && + test "$base" = "$gitlab_head"; then + refspecs="$upstream_head:refs/heads/master $refspecs" +fi + +# Exit early if we have nothing to push. +if test -z "$refspecs"; then + echo 'Nothing to push!' + exit 0 +fi + +# Push. Save output and exit code. +echo "Pushing to $remote" +push_config='-c advice.pushUpdateRejected=false' +push_stdout=$(git $push_config push $lease_flag --porcelain $dry_run "$remote" $refspecs); push_exit=$? +echo "$push_stdout" + +if test "$push_exit" -ne 0 && test -z "$force"; then + # Advise the user to fetch if needed. + if echo "$push_stdout" | egrep-q 'stale info'; then + echo " +You have pushed to your branch from another machine; you may be overwriting +commits unintentionally. Fetch from the $remote remote and check that you are +not pushing an outdated branch." + fi + + # Advise the user to force-push if needed. + if echo "$push_stdout" | egrep-q 'non-fast-forward'; then + echo ' +Add "-f" or "--force" to push a rewritten topic.' + fi +fi + +# Reproduce the push exit code. +exit $push_exit diff --git a/test/API/driver/kwsys/GitSetup/pre-commit b/test/API/driver/kwsys/GitSetup/pre-commit new file mode 100644 index 0000000..1f1d3f5 --- /dev/null +++ b/test/API/driver/kwsys/GitSetup/pre-commit @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +egrep-q() { + egrep "$@" >/dev/null 2>/dev/null +} + +die() { + echo 'pre-commit hook failure' 1>&2 + echo '-----------------------' 1>&2 + echo '' 1>&2 + echo "$@" 1>&2 + exit 1 +} + +#----------------------------------------------------------------------------- + +# Check that developmer setup is up-to-date. +lastSetupForDevelopment=$(git config --get hooks.SetupForDevelopment || echo 0) +eval $(grep '^SetupForDevelopment_VERSION=' "${BASH_SOURCE%/*}/../SetupForDevelopment.sh") +test -n "$SetupForDevelopment_VERSION" || SetupForDevelopment_VERSION=0 +if test $lastSetupForDevelopment -lt $SetupForDevelopment_VERSION; then + die 'Developer setup in this work tree is out of date. Please re-run + + ./SetupForDevelopment.sh +' +fi diff --git a/test/API/driver/kwsys/GitSetup/setup-aliases b/test/API/driver/kwsys/GitSetup/setup-aliases new file mode 100644 index 0000000..98810ad --- /dev/null +++ b/test/API/driver/kwsys/GitSetup/setup-aliases @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +echo "Adding 'git prepush' alias" && +git config alias.prepush 'log --graph --stat origin/master..' && +gerrit_disabled="KWSys no longer uses Gerrit. Please use GitLab." && +git config alias.gerrit-push '!sh -c "echo '"${gerrit_disabled}"'"' && +true diff --git a/test/API/driver/kwsys/GitSetup/setup-gerrit b/test/API/driver/kwsys/GitSetup/setup-gerrit new file mode 100644 index 0000000..6d46e3c --- /dev/null +++ b/test/API/driver/kwsys/GitSetup/setup-gerrit @@ -0,0 +1,147 @@ +#!/usr/bin/env bash +#============================================================================= +# Copyright 2010-2012 Kitware, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============================================================================= + +# Run this script to set up the local Git repository to push to +# a Gerrit Code Review instance for this project. + +# Project configuration instructions: +# +# - Run a Gerrit Code Review server +# +# - Populate adjacent "config" file with: +# gerrit.site = Top Gerrit URL (not project-specific) +# gerrit.project = Name of project in Gerrit +# gerrit.pushurl = Review site push URL with "$username" placeholder +# gerrit.remote = Gerrit remote name, if not "gerrit" +# gerrit.url = Gerrit project URL, if not "$site/p/$project" +# optionally with "$username" placeholder + +die() { + echo 1>&2 "$@" ; exit 1 +} + +# Make sure we are inside the repository. +cd "${BASH_SOURCE%/*}" && + +# Load the project configuration. +site=$(git config -f config --get gerrit.site) && +project=$(git config -f config --get gerrit.project) && +remote=$(git config -f config --get gerrit.remote || + echo "gerrit") && +fetchurl_=$(git config -f config --get gerrit.url || + echo "$site/p/$project") && +pushurl_=$(git config -f config --get gerrit.pushurl || + git config -f config --get gerrit.url) || +die 'This project is not configured to use Gerrit.' + +# Get current gerrit push URL. +pushurl=$(git config --get remote."$remote".pushurl || + git config --get remote."$remote".url || echo '') && + +# Tell user about current configuration. +if test -n "$pushurl"; then + echo 'Remote "'"$remote"'" is currently configured to push to + + '"$pushurl"' +' && + read -ep 'Reconfigure Gerrit? [y/N]: ' ans && + if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then + setup=1 + else + setup='' + fi +else + echo 'Remote "'"$remote"'" is not yet configured. + +'"$project"' changes must be pushed to our Gerrit Code Review site: + + '"$site/p/$project"' + +Register a Gerrit account and select a username (used below). +You will need an OpenID: + + http://openid.net/get-an-openid/ +' && + read -ep 'Configure Gerrit? [Y/n]: ' ans && + if [ "$ans" == "n" ] || [ "$ans" == "N" ]; then + exit 0 + else + setup=1 + fi +fi && + +# Perform setup if necessary. +if test -n "$setup"; then + echo 'Sign-in to Gerrit to get/set your username at + + '"$site"'/#/settings + +Add your SSH public keys at + + '"$site"'/#/settings/ssh-keys +' && + read -ep "Gerrit username? [$USER]: " gu && + if test -z "$gu"; then + gu="$USER" + fi && + fetchurl="${fetchurl_/\$username/$gu}" && + if test -z "$pushurl"; then + git remote add "$remote" "$fetchurl" + else + git config remote."$remote".url "$fetchurl" + fi && + pushurl="${pushurl_/\$username/$gu}" && + if test "$pushurl" != "$fetchurl"; then + git config remote."$remote".pushurl "$pushurl" + fi && + echo 'Remote "'"$remote"'" is now configured to push to + + '"$pushurl"' +' +fi && + +# Optionally test Gerrit access. +if test -n "$pushurl"; then + read -ep 'Test access to Gerrit (SSH)? [y/N]: ' ans && + if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then + echo -n 'Testing Gerrit access by SSH...' + if git ls-remote --heads "$pushurl" >/dev/null; then + echo 'passed.' + else + echo 'failed.' && + die 'Could not access Gerrit. Add your SSH public keys at + + '"$site"'/#/settings/ssh-keys +' + fi + fi +fi && + +# Set up GerritId hook. +hook=$(git config --get hooks.GerritId || echo '') && +if test -z "$hook"; then + echo ' +Enabling GerritId hook to add a "Change-Id" footer to commit +messages for interaction with Gerrit. Run + + git config hooks.GerritId false + +to disable this feature (but you will be on your own).' && + git config hooks.GerritId true +else + echo 'GerritId hook already configured to "'"$hook"'".' +fi diff --git a/test/API/driver/kwsys/GitSetup/setup-gitlab b/test/API/driver/kwsys/GitSetup/setup-gitlab new file mode 100644 index 0000000..9c7574d --- /dev/null +++ b/test/API/driver/kwsys/GitSetup/setup-gitlab @@ -0,0 +1,140 @@ +#!/usr/bin/env bash +#============================================================================= +# Copyright 2010-2015 Kitware, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============================================================================= + +# Run this script to set up the local Git repository to push to +# a personal fork for this project in GitLab. + +# Project configuration instructions: +# +# - Run a GitLab server +# +# - Populate adjacent "config" file with: +# gitlab.protocol = Top GitLab protocol, if not 'https' +# gitlab.host = Top GitLab fully qualified host name +# gitlab.site = Top GitLab URL, if not "://" +# gitlab.group-name = Name of group containing project in GitLab +# gitlab.group-path = Path of group containing project in GitLab +# gitlab.project-name = Name of project within GitLab group +# gitlab.project-path = Path of project within GitLab group +# gitlab.url = GitLab push URL with "$username" placeholder, +# if not "/$username/.git" +# gitlab.pushurl = GitLab push URL with "$username" placeholder, +# if not "git@:$username/.git" +# gitlab.remote = GitLab remote name, if not "gitlab" + +die() { + echo 1>&2 "$@" ; exit 1 +} + +# Make sure we are inside the repository. +cd "${BASH_SOURCE%/*}" && + +# Load the project configuration. +protocol=$(git config -f config --get gitlab.protocol || + echo "https") && +host=$(git config -f config --get gitlab.host) && +site=$(git config -f config --get gitlab.site || + echo "$protocol://$host") && +group_path=$(git config -f config --get gitlab.group-path) && +group_name=$(git config -f config --get gitlab.group-name) && +project_name=$(git config -f config --get gitlab.project-name) && +project_path=$(git config -f config --get gitlab.project-path) && +pushurl_=$(git config -f config --get gitlab.pushurl || + echo "git@$host:\$username/$project_path.git") && +remote=$(git config -f config --get gitlab.remote || + echo "gitlab") && +fetchurl_=$(git config -f config --get gitlab.url || + echo "$site/\$username/$project_path.git") || +die 'This project is not configured to use GitLab.' + +# Get current gitlab push URL. +pushurl=$(git config --get remote."$remote".pushurl || + git config --get remote."$remote".url || echo '') && + +# Tell user about current configuration. +if test -n "$pushurl"; then + echo 'Remote "'"$remote"'" is currently configured to push to + + '"$pushurl"' +' && + read -ep 'Reconfigure GitLab? [y/N]: ' ans && + if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then + setup=1 + else + setup='' + fi +else + echo 'Remote "'"$remote"'" is not yet configured. +' && + read -ep 'Configure GitLab to contribute to '"$project_name"'? [Y/n]: ' ans && + if [ "$ans" == "n" ] || [ "$ans" == "N" ]; then + exit 0 + else + setup=1 + fi +fi && + +setup_instructions='Add your SSH public keys at + + '"$site"'/profile/keys + +Then visit the main repository at: + + '"$site/$group_path/$project_path"' + +and use the Fork button in the upper right. +' + +# Perform setup if necessary. +if test -n "$setup"; then + echo 'Sign-in to GitLab to get/set your username at + + '"$site/profile/account"' + +'"$setup_instructions" && + read -ep "GitLab username? [$USER]: " gu && + if test -z "$gu"; then + gu="$USER" + fi && + fetchurl="${fetchurl_/\$username/$gu}" && + if test -z "$pushurl"; then + git remote add "$remote" "$fetchurl" + else + git config remote."$remote".url "$fetchurl" + fi && + pushurl="${pushurl_/\$username/$gu}" && + git config remote."$remote".pushurl "$pushurl" && + echo 'Remote "'"$remote"'" is now configured to push to + + '"$pushurl"' +' +fi && + +# Optionally test GitLab access. +if test -n "$pushurl"; then + read -ep 'Test access to GitLab (SSH)? [y/N]: ' ans && + if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then + echo -n 'Testing GitLab access by SSH...' + if git ls-remote --heads "$pushurl" >/dev/null; then + echo 'passed.' + else + echo 'failed.' && + die 'Could not access your GitLab fork of this project. +'"$setup_instructions" + fi + fi +fi diff --git a/test/API/driver/kwsys/GitSetup/setup-hooks b/test/API/driver/kwsys/GitSetup/setup-hooks new file mode 100644 index 0000000..ca07712 --- /dev/null +++ b/test/API/driver/kwsys/GitSetup/setup-hooks @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +#============================================================================= +# Copyright 2010-2012 Kitware, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============================================================================= + +# Run this script to set up local Git hooks for this project. + +# Project configuration instructions: +# +# - Publish a "hooks" branch in the project repository such that +# clones will have "refs/remotes/origin/hooks". +# +# - Populate adjacent "config" file with: +# hooks.url = Repository URL publishing "hooks" branch +# hooks.branch = Repository branch instead of "hooks" + +egrep-q() { + egrep "$@" >/dev/null 2>/dev/null +} + +die() { + echo 1>&2 "$@" ; exit 1 +} + +# Make sure we are inside the repository. +cd "${BASH_SOURCE%/*}" && + +# Select a hooks branch. +if url=$(git config --get hooks.url); then + # Fetch hooks from locally configured repository. + branch=$(git config hooks.branch || echo hooks) +elif git for-each-ref refs/remotes/origin/hooks 2>/dev/null | + egrep-q 'refs/remotes/origin/hooks$'; then + # Use hooks cloned from origin. + url=.. && branch=remotes/origin/hooks +elif url=$(git config -f config --get hooks.url); then + # Fetch hooks from project-configured repository. + branch=$(git config -f config hooks.branch || echo hooks) +else + die 'This project is not configured to install local hooks.' +fi && + +# Populate ".git/hooks". +echo 'Setting up git hooks...' && +git_dir=$(git rev-parse --git-dir) && +mkdir -p "$git_dir/hooks" && +cd "$git_dir/hooks" && +if ! test -e .git; then + git init -q || die 'Could not run git init for hooks.' +fi && +git fetch -q "$url" "$branch" && +git reset -q --hard FETCH_HEAD || die 'Failed to install hooks' diff --git a/test/API/driver/kwsys/GitSetup/setup-ssh b/test/API/driver/kwsys/GitSetup/setup-ssh new file mode 100644 index 0000000..8920a5b --- /dev/null +++ b/test/API/driver/kwsys/GitSetup/setup-ssh @@ -0,0 +1,111 @@ +#!/usr/bin/env bash +#============================================================================= +# Copyright 2010-2012 Kitware, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============================================================================= + +# Run this script to set up ssh push access to the repository host. + +# Project configuration instructions: +# +# - Populate adjacent "config" file with: +# ssh.host = Repository host name +# ssh.user = Username on host, if not "git" +# ssh.key = Local ssh key name +# ssh.request-url = Web page URL to request ssh access + +egrep-q() { + egrep "$@" >/dev/null 2>/dev/null +} + +die() { + echo 1>&2 "$@" ; exit 1 +} + +# Make sure we are inside the repository. +cd "${BASH_SOURCE%/*}" && + +# Load the project configuration. +host=$(git config -f config --get ssh.host) && +user=$(git config -f config --get ssh.user || echo git) && +key=$(git config -f config --get ssh.key) && +request_url=$(git config -f config --get ssh.request-url) || +die 'This project is not configured for ssh push access.' + +# Check for existing configuration. +if test -r ~/.ssh/config && + egrep-q 'Host[= ]'"${host//\./\\.}" ~/.ssh/config; then + echo 'Host "'"$host"'" is already in ~/.ssh/config' && + setup= && + question='Test' +else + echo 'Host "'"$host"'" not found in ~/.ssh/config' && + setup=1 && + question='Setup and test' +fi && + +# Ask the user whether to make changes. +echo '' && +read -ep "${question} push access by ssh to $user@$host? [y/N]: " access && +if test "$access" != "y" -a "$access" != "Y"; then + exit 0 +fi && + +# Setup host configuration if necessary. +if test -n "$setup"; then + if ! test -d ~/.ssh; then + mkdir -p ~/.ssh && + chmod 700 ~/.ssh + fi && + if ! test -f ~/.ssh/config; then + touch ~/.ssh/config && + chmod 600 ~/.ssh/config + fi && + ssh_config='Host='"$host"' + IdentityFile ~/.ssh/'"$key" && + echo "Adding to ~/.ssh/config: + +$ssh_config +" && + echo "$ssh_config" >> ~/.ssh/config && + if ! test -e ~/.ssh/"$key"; then + if test -f ~/.ssh/id_rsa; then + # Take care of the common case. + ln -s id_rsa ~/.ssh/"$key" + echo ' +Assuming ~/.ssh/id_rsa is the private key corresponding to the public key for + + '"$user@$host"' + +If this is incorrect place private key at "~/.ssh/'"$key"'".' + else + echo ' +Place the private key corresponding to the public key registered for + + '"$user@$host"' + +at "~/.ssh/'"$key"'".' + fi + read -e -n 1 -p 'Press any key to continue...' + fi +fi || exit 1 + +# Test access configuration. +echo 'Testing ssh push access to "'"$user@$host"'"...' && +if ! ssh "$user@$host" info; then + die 'No ssh push access to "'"$user@$host"'". You may need to request access at + + '"$request_url"' +' +fi diff --git a/test/API/driver/kwsys/GitSetup/setup-stage b/test/API/driver/kwsys/GitSetup/setup-stage new file mode 100644 index 0000000..ce6ec45 --- /dev/null +++ b/test/API/driver/kwsys/GitSetup/setup-stage @@ -0,0 +1,82 @@ +#!/usr/bin/env bash +#============================================================================= +# Copyright 2010-2012 Kitware, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============================================================================= + +# Run this script to set up the topic stage for pushing changes. + +# Project configuration instructions: +# +# - Run a Topic Stage repository next to the main project repository. +# +# - Populate adjacent "config" file with: +# stage.url = Topic Stage repository URL +# stage.pushurl = Topic Stage push URL if not "$url" + +egrep-q() { + egrep "$@" >/dev/null 2>/dev/null +} + +die() { + echo 1>&2 "$@" ; exit 1 +} + +# Make sure we are inside the repository. +cd "${BASH_SOURCE%/*}" && + +# Load the project configuration. +fetchurl_=$(git config -f config --get stage.url) && +pushurl_=$(git config -f config --get stage.pushurl || echo "$fetchurl_") && +remote=$(git config -f config --get stage.remote || echo 'stage') || +die 'This project is not configured to use a topic stage.' + +# Get current stage push URL. +pushurl=$(git config --get remote."$remote".pushurl || + git config --get remote."$remote".url || echo '') && + +# Tell user about current configuration. +if test -n "$pushurl"; then + echo 'Remote "'"$remote"'" is currently configured to push to + + '"$pushurl"' +' && + read -ep 'Reconfigure Topic Stage? [y/N]: ' ans && + if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then + setup=1 + else + setup='' + fi +else + setup=1 +fi + +# Perform setup if necessary. +if test -n "$setup"; then + echo 'Setting up the topic stage...' && + fetchurl="${fetchurl_}" && + if test -z "$pushurl"; then + git remote add "$remote" "$fetchurl" + else + git config remote."$remote".url "$fetchurl" + fi && + pushurl="${pushurl_}" && + if test "$pushurl" != "$fetchurl"; then + git config remote."$remote".pushurl "$pushurl" + fi && + echo 'Remote "'"$remote"'" is now configured to push to + + '"$pushurl"' +' +fi || die 'Could not configure the topic stage remote.' diff --git a/test/API/driver/kwsys/GitSetup/setup-upstream b/test/API/driver/kwsys/GitSetup/setup-upstream new file mode 100644 index 0000000..92ce1da --- /dev/null +++ b/test/API/driver/kwsys/GitSetup/setup-upstream @@ -0,0 +1,104 @@ +#!/usr/bin/env bash +#============================================================================= +# Copyright 2010-2015 Kitware, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============================================================================= + +# Run this script to set up the local Git repository to use the +# preferred upstream repository URLs. + +# Project configuration instructions: +# +# - Populate adjacent "config" file with: +# upstream.url = Preferred fetch url for upstream remote +# upstream.remote = Preferred name for upstream remote, if not "origin" + +die() { + echo 1>&2 "$@" ; exit 1 +} + +# Make sure we are inside the repository. +cd "${BASH_SOURCE%/*}" && + +# Load the project configuration. +url=$(git config -f config --get upstream.url) && +remote=$(git config -f config --get upstream.remote || + echo 'origin') || +die 'This project is not configured to use a preferred upstream repository.' + +# Get current upstream URLs. +fetchurl=$(git config --get remote."$remote".url || echo '') && +pushurl=$(git config --get remote."$remote".pushurl || echo '') && + +if test "$fetchurl" = "$url"; then + echo 'Remote "'"$remote"'" already uses recommended upstream repository.' + exit 0 +fi + +upstream_recommend=' +We recommended configuring the "'"$remote"'" remote to fetch from upstream at + + '"$url"' +' + +# Tell user about current configuration. +if test -n "$fetchurl"; then + echo 'Remote "'"$remote"'" is currently configured to fetch from + + '"$fetchurl"' +' && + if test -n "$pushurl"; then + echo 'and push to + + '"$pushurl" + fi && + echo "$upstream_recommend" && + if test -n "$pushurl"; then + echo 'and to never push to it directly. +' + fi && + + read -ep 'Reconfigure "'"$remote"'" remote as recommended? [y/N]: ' ans && + if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then + setup=1 + else + setup='' + fi +else + echo 'Remote "'"$remote"'" is not yet configured.' && + echo "$upstream_recommend" && + read -ep 'Configure "'"$remote"'" remote as recommended? [Y/n]: ' ans && + if [ "$ans" == "n" ] || [ "$ans" == "N" ]; then + exit 0 + else + setup=1 + fi +fi && + +# Perform setup if necessary. +if test -n "$setup"; then + if test -z "$fetchurl"; then + git remote add "$remote" "$url" + else + git config remote."$remote".url "$url" && + if old=$(git config --get remote."$remote".pushurl); then + git config --unset remote."$remote".pushurl || + echo 'Warning: failed to unset remote.'"$remote"'.pushurl' + fi + fi && + echo 'Remote "'"$remote"'" is now configured to fetch from + + '"$url"' +' +fi diff --git a/test/API/driver/kwsys/GitSetup/setup-user b/test/API/driver/kwsys/GitSetup/setup-user new file mode 100644 index 0000000..1af439c --- /dev/null +++ b/test/API/driver/kwsys/GitSetup/setup-user @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +#============================================================================= +# Copyright 2010-2012 Kitware, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============================================================================= + +# Run this script to configure Git user info in this repository. + +# Project configuration instructions: NONE + +for (( ; ; )); do + user_name=$(git config user.name || echo '') && + user_email=$(git config user.email || echo '') && + if test -n "$user_name" -a -n "$user_email"; then + echo 'Your commits will record as Author: + + '"$user_name <$user_email>"' +' && + read -ep 'Is the author name and email address above correct? [Y/n] ' correct && + if test "$correct" != "n" -a "$correct" != "N"; then + break + fi + fi && + read -ep 'Enter your full name e.g. "John Doe": ' name && + read -ep 'Enter your email address e.g. "john@gmail.com": ' email && + git config user.name "$name" && + git config user.email "$email" +done diff --git a/test/API/driver/kwsys/GitSetup/tips b/test/API/driver/kwsys/GitSetup/tips new file mode 100644 index 0000000..784e1ed --- /dev/null +++ b/test/API/driver/kwsys/GitSetup/tips @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +#============================================================================= +# Copyright 2010-2012 Kitware, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============================================================================= + +# This script makes optional suggestions for working with Git. + +# Project configuration instructions: NONE + +egrep-q() { + egrep "$@" >/dev/null 2>/dev/null +} + +# Suggest color configuration. +if test -z "$(git config --get color.ui)"; then + echo ' +One may enable color output from Git commands with + + git config --global color.ui auto +' +fi + +# Suggest bash completion. +if ! bash -i -c 'echo $PS1' | egrep-q '__git_ps1'; then + echo ' +A dynamic, informative Git shell prompt can be obtained by sourcing +the git bash-completion script in your "~/.bashrc". Set the PS1 +environmental variable as suggested in the comments at the top of the +bash-completion script. You may need to install the bash-completion +package from your distribution to obtain it. +' +fi + +# Suggest merge tool. +if test -z "$(git config --get merge.tool)"; then + echo ' +One may configure Git to load a merge tool with + + git config merge.tool + +See "git help mergetool" for more information. +' +fi diff --git a/test/API/driver/kwsys/Glob.cxx b/test/API/driver/kwsys/Glob.cxx new file mode 100644 index 0000000..34bb0d0 --- /dev/null +++ b/test/API/driver/kwsys/Glob.cxx @@ -0,0 +1,448 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(Glob.hxx) + +#include KWSYS_HEADER(Configure.hxx) + +#include KWSYS_HEADER(RegularExpression.hxx) +#include KWSYS_HEADER(SystemTools.hxx) +#include KWSYS_HEADER(Directory.hxx) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "Configure.hxx.in" +# include "Directory.hxx.in" +# include "Glob.hxx.in" +# include "RegularExpression.hxx.in" +# include "SystemTools.hxx.in" +#endif + +#include +#include +#include + +#include +#include +#include +namespace KWSYS_NAMESPACE { +#if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__) +// On Windows and Apple, no difference between lower and upper case +# define KWSYS_GLOB_CASE_INDEPENDENT +#endif + +#if defined(_WIN32) || defined(__CYGWIN__) +// Handle network paths +# define KWSYS_GLOB_SUPPORT_NETWORK_PATHS +#endif + +class GlobInternals +{ +public: + std::vector Files; + std::vector Expressions; +}; + +Glob::Glob() +{ + this->Internals = new GlobInternals; + this->Recurse = false; + this->Relative = ""; + + this->RecurseThroughSymlinks = true; + // RecurseThroughSymlinks is true by default for backwards compatibility, + // not because it's a good idea... + this->FollowedSymlinkCount = 0; + + // Keep separate variables for directory listing for back compatibility + this->ListDirs = true; + this->RecurseListDirs = false; +} + +Glob::~Glob() +{ + delete this->Internals; +} + +std::vector& Glob::GetFiles() +{ + return this->Internals->Files; +} + +std::string Glob::PatternToRegex(const std::string& pattern, + bool require_whole_string, bool preserve_case) +{ + // Incrementally build the regular expression from the pattern. + std::string regex = require_whole_string ? "^" : ""; + std::string::const_iterator pattern_first = pattern.begin(); + std::string::const_iterator pattern_last = pattern.end(); + for (std::string::const_iterator i = pattern_first; i != pattern_last; ++i) { + int c = *i; + if (c == '*') { + // A '*' (not between brackets) matches any string. + // We modify this to not match slashes since the original glob + // pattern documentation was meant for matching file name + // components separated by slashes. + regex += "[^/]*"; + } else if (c == '?') { + // A '?' (not between brackets) matches any single character. + // We modify this to not match slashes since the original glob + // pattern documentation was meant for matching file name + // components separated by slashes. + regex += "[^/]"; + } else if (c == '[') { + // Parse out the bracket expression. It begins just after the + // opening character. + std::string::const_iterator bracket_first = i + 1; + std::string::const_iterator bracket_last = bracket_first; + + // The first character may be complementation '!' or '^'. + if (bracket_last != pattern_last && + (*bracket_last == '!' || *bracket_last == '^')) { + ++bracket_last; + } + + // If the next character is a ']' it is included in the brackets + // because the bracket string may not be empty. + if (bracket_last != pattern_last && *bracket_last == ']') { + ++bracket_last; + } + + // Search for the closing ']'. + while (bracket_last != pattern_last && *bracket_last != ']') { + ++bracket_last; + } + + // Check whether we have a complete bracket string. + if (bracket_last == pattern_last) { + // The bracket string did not end, so it was opened simply by + // a '[' that is supposed to be matched literally. + regex += "\\["; + } else { + // Convert the bracket string to its regex equivalent. + std::string::const_iterator k = bracket_first; + + // Open the regex block. + regex += "["; + + // A regex range complement uses '^' instead of '!'. + if (k != bracket_last && *k == '!') { + regex += "^"; + ++k; + } + + // Convert the remaining characters. + for (; k != bracket_last; ++k) { + // Backslashes must be escaped. + if (*k == '\\') { + regex += "\\"; + } + + // Store this character. + regex += *k; + } + + // Close the regex block. + regex += "]"; + + // Jump to the end of the bracket string. + i = bracket_last; + } + } else { + // A single character matches itself. + int ch = c; + if (!(('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || + ('0' <= ch && ch <= '9'))) { + // Escape the non-alphanumeric character. + regex += "\\"; + } +#if defined(KWSYS_GLOB_CASE_INDEPENDENT) + else { + // On case-insensitive systems file names are converted to lower + // case before matching. + if (!preserve_case) { + ch = tolower(ch); + } + } +#endif + (void)preserve_case; + // Store the character. + regex.append(1, static_cast(ch)); + } + } + + if (require_whole_string) { + regex += "$"; + } + return regex; +} + +bool Glob::RecurseDirectory(std::string::size_type start, + const std::string& dir, GlobMessages* messages) +{ + kwsys::Directory d; + if (!d.Load(dir)) { + return true; + } + unsigned long cc; + std::string realname; + std::string fname; + for (cc = 0; cc < d.GetNumberOfFiles(); cc++) { + fname = d.GetFile(cc); + if (fname == "." || fname == "..") { + continue; + } + + if (start == 0) { + realname = dir + fname; + } else { + realname = dir + "/" + fname; + } + +#if defined(KWSYS_GLOB_CASE_INDEPENDENT) + // On Windows and Apple, no difference between lower and upper case + fname = kwsys::SystemTools::LowerCase(fname); +#endif + + bool isDir = kwsys::SystemTools::FileIsDirectory(realname); + bool isSymLink = kwsys::SystemTools::FileIsSymlink(realname); + + if (isDir && (!isSymLink || this->RecurseThroughSymlinks)) { + if (isSymLink) { + ++this->FollowedSymlinkCount; + std::string realPathErrorMessage; + std::string canonicalPath( + SystemTools::GetRealPath(dir, &realPathErrorMessage)); + + if (!realPathErrorMessage.empty()) { + if (messages) { + messages->push_back( + Message(Glob::error, + "Canonical path generation from path '" + dir + + "' failed! Reason: '" + realPathErrorMessage + "'")); + } + return false; + } + + if (std::find(this->VisitedSymlinks.begin(), + this->VisitedSymlinks.end(), + canonicalPath) == this->VisitedSymlinks.end()) { + if (this->RecurseListDirs) { + // symlinks are treated as directories + this->AddFile(this->Internals->Files, realname); + } + + this->VisitedSymlinks.push_back(canonicalPath); + if (!this->RecurseDirectory(start + 1, realname, messages)) { + this->VisitedSymlinks.pop_back(); + + return false; + } + this->VisitedSymlinks.pop_back(); + } + // else we have already visited this symlink - prevent cyclic recursion + else if (messages) { + std::string message; + for (std::vector::const_iterator pathIt = + std::find(this->VisitedSymlinks.begin(), + this->VisitedSymlinks.end(), canonicalPath); + pathIt != this->VisitedSymlinks.end(); ++pathIt) { + message += *pathIt + "\n"; + } + message += canonicalPath + "/" + fname; + messages->push_back(Message(Glob::cyclicRecursion, message)); + } + } else { + if (this->RecurseListDirs) { + this->AddFile(this->Internals->Files, realname); + } + if (!this->RecurseDirectory(start + 1, realname, messages)) { + return false; + } + } + } else { + if (!this->Internals->Expressions.empty() && + this->Internals->Expressions.back().find(fname)) { + this->AddFile(this->Internals->Files, realname); + } + } + } + + return true; +} + +void Glob::ProcessDirectory(std::string::size_type start, + const std::string& dir, GlobMessages* messages) +{ + // std::cout << "ProcessDirectory: " << dir << std::endl; + bool last = (start == this->Internals->Expressions.size() - 1); + if (last && this->Recurse) { + this->RecurseDirectory(start, dir, messages); + return; + } + + if (start >= this->Internals->Expressions.size()) { + return; + } + + kwsys::Directory d; + if (!d.Load(dir)) { + return; + } + unsigned long cc; + std::string realname; + std::string fname; + for (cc = 0; cc < d.GetNumberOfFiles(); cc++) { + fname = d.GetFile(cc); + if (fname == "." || fname == "..") { + continue; + } + + if (start == 0) { + realname = dir + fname; + } else { + realname = dir + "/" + fname; + } + +#if defined(KWSYS_GLOB_CASE_INDEPENDENT) + // On case-insensitive file systems convert to lower case for matching. + fname = kwsys::SystemTools::LowerCase(fname); +#endif + + // std::cout << "Look at file: " << fname << std::endl; + // std::cout << "Match: " + // << this->Internals->TextExpressions[start].c_str() << std::endl; + // std::cout << "Real name: " << realname << std::endl; + + if ((!last && !kwsys::SystemTools::FileIsDirectory(realname)) || + (!this->ListDirs && last && + kwsys::SystemTools::FileIsDirectory(realname))) { + continue; + } + + if (this->Internals->Expressions[start].find(fname)) { + if (last) { + this->AddFile(this->Internals->Files, realname); + } else { + this->ProcessDirectory(start + 1, realname, messages); + } + } + } +} + +bool Glob::FindFiles(const std::string& inexpr, GlobMessages* messages) +{ + std::string cexpr; + std::string::size_type cc; + std::string expr = inexpr; + + this->Internals->Expressions.clear(); + this->Internals->Files.clear(); + + if (!kwsys::SystemTools::FileIsFullPath(expr)) { + expr = kwsys::SystemTools::GetCurrentWorkingDirectory(); + expr += "/" + inexpr; + } + std::string fexpr = expr; + + std::string::size_type skip = 0; + std::string::size_type last_slash = 0; + for (cc = 0; cc < expr.size(); cc++) { + if (cc > 0 && expr[cc] == '/' && expr[cc - 1] != '\\') { + last_slash = cc; + } + if (cc > 0 && (expr[cc] == '[' || expr[cc] == '?' || expr[cc] == '*') && + expr[cc - 1] != '\\') { + break; + } + } + if (last_slash > 0) { + // std::cout << "I can skip: " << fexpr.substr(0, last_slash) + // << std::endl; + skip = last_slash; + } + if (skip == 0) { +#if defined(KWSYS_GLOB_SUPPORT_NETWORK_PATHS) + // Handle network paths + if (expr[0] == '/' && expr[1] == '/') { + int cnt = 0; + for (cc = 2; cc < expr.size(); cc++) { + if (expr[cc] == '/') { + cnt++; + if (cnt == 2) { + break; + } + } + } + skip = int(cc + 1); + } else +#endif + // Handle drive letters on Windows + if (expr[1] == ':' && expr[0] != '/') { + skip = 2; + } + } + + if (skip > 0) { + expr = expr.substr(skip); + } + + cexpr = ""; + for (cc = 0; cc < expr.size(); cc++) { + int ch = expr[cc]; + if (ch == '/') { + if (!cexpr.empty()) { + this->AddExpression(cexpr); + } + cexpr = ""; + } else { + cexpr.append(1, static_cast(ch)); + } + } + if (!cexpr.empty()) { + this->AddExpression(cexpr); + } + + // Handle network paths + if (skip > 0) { + this->ProcessDirectory(0, fexpr.substr(0, skip) + "/", messages); + } else { + this->ProcessDirectory(0, "/", messages); + } + return true; +} + +void Glob::AddExpression(const std::string& expr) +{ + this->Internals->Expressions.push_back( + kwsys::RegularExpression(this->PatternToRegex(expr))); +} + +void Glob::SetRelative(const char* dir) +{ + if (!dir) { + this->Relative = ""; + return; + } + this->Relative = dir; +} + +const char* Glob::GetRelative() +{ + if (this->Relative.empty()) { + return nullptr; + } + return this->Relative.c_str(); +} + +void Glob::AddFile(std::vector& files, const std::string& file) +{ + if (!this->Relative.empty()) { + files.push_back(kwsys::SystemTools::RelativePath(this->Relative, file)); + } else { + files.push_back(file); + } +} + +} // namespace KWSYS_NAMESPACE diff --git a/test/API/driver/kwsys/Glob.hxx.in b/test/API/driver/kwsys/Glob.hxx.in new file mode 100644 index 0000000..170766f --- /dev/null +++ b/test/API/driver/kwsys/Glob.hxx.in @@ -0,0 +1,134 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_Glob_hxx +#define @KWSYS_NAMESPACE@_Glob_hxx + +#include <@KWSYS_NAMESPACE@/Configure.h> +#include <@KWSYS_NAMESPACE@/Configure.hxx> + +#include +#include + +namespace @KWSYS_NAMESPACE@ { + +class GlobInternals; + +/** \class Glob + * \brief Portable globbing searches. + * + * Globbing expressions are much simpler than regular + * expressions. This class will search for files using + * globbing expressions. + * + * Finds all files that match a given globbing expression. + */ +class @KWSYS_NAMESPACE@_EXPORT Glob +{ +public: + enum MessageType + { + error, + cyclicRecursion + }; + + struct Message + { + MessageType type; + std::string content; + + Message(MessageType t, const std::string& c) + : type(t) + , content(c) + { + } + ~Message() = default; + Message(const Message& msg) = default; + Message& operator=(Message const& msg) = default; + }; + + typedef std::vector GlobMessages; + typedef std::vector::iterator GlobMessagesIterator; + +public: + Glob(); + ~Glob(); + + //! Find all files that match the pattern. + bool FindFiles(const std::string& inexpr, GlobMessages* messages = nullptr); + + //! Return the list of files that matched. + std::vector& GetFiles(); + + //! Set recurse to true to match subdirectories. + void RecurseOn() { this->SetRecurse(true); } + void RecurseOff() { this->SetRecurse(false); } + void SetRecurse(bool i) { this->Recurse = i; } + bool GetRecurse() { return this->Recurse; } + + //! Set recurse through symlinks to true if recursion should traverse the + // linked-to directories + void RecurseThroughSymlinksOn() { this->SetRecurseThroughSymlinks(true); } + void RecurseThroughSymlinksOff() { this->SetRecurseThroughSymlinks(false); } + void SetRecurseThroughSymlinks(bool i) { this->RecurseThroughSymlinks = i; } + bool GetRecurseThroughSymlinks() { return this->RecurseThroughSymlinks; } + + //! Get the number of symlinks followed through recursion + unsigned int GetFollowedSymlinkCount() { return this->FollowedSymlinkCount; } + + //! Set relative to true to only show relative path to files. + void SetRelative(const char* dir); + const char* GetRelative(); + + /** Convert the given globbing pattern to a regular expression. + There is no way to quote meta-characters. The + require_whole_string argument specifies whether the regex is + automatically surrounded by "^" and "$" to match the whole + string. This is on by default because patterns always match + whole strings, but may be disabled to support concatenating + expressions more easily (regex1|regex2|etc). */ + static std::string PatternToRegex(const std::string& pattern, + bool require_whole_string = true, + bool preserve_case = false); + + /** Getters and setters for enabling and disabling directory + listing in recursive and non recursive globbing mode. + If listing is enabled in recursive mode it also lists + directory symbolic links even if follow symlinks is enabled. */ + void SetListDirs(bool list) { this->ListDirs = list; } + bool GetListDirs() const { return this->ListDirs; } + void SetRecurseListDirs(bool list) { this->RecurseListDirs = list; } + bool GetRecurseListDirs() const { return this->RecurseListDirs; } + +protected: + //! Process directory + void ProcessDirectory(std::string::size_type start, const std::string& dir, + GlobMessages* messages); + + //! Process last directory, but only when recurse flags is on. That is + // effectively like saying: /path/to/file/**/file + bool RecurseDirectory(std::string::size_type start, const std::string& dir, + GlobMessages* messages); + + //! Add regular expression + void AddExpression(const std::string& expr); + + //! Add a file to the list + void AddFile(std::vector& files, const std::string& file); + + GlobInternals* Internals; + bool Recurse; + std::string Relative; + bool RecurseThroughSymlinks; + unsigned int FollowedSymlinkCount; + std::vector VisitedSymlinks; + bool ListDirs; + bool RecurseListDirs; + +private: + Glob(const Glob&); // Not implemented. + void operator=(const Glob&); // Not implemented. +}; + +} // namespace @KWSYS_NAMESPACE@ + +#endif diff --git a/test/API/driver/kwsys/IOStream.cxx b/test/API/driver/kwsys/IOStream.cxx new file mode 100644 index 0000000..e21f87d --- /dev/null +++ b/test/API/driver/kwsys/IOStream.cxx @@ -0,0 +1,255 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(Configure.hxx) + +// Include the streams library. +#include +#include KWSYS_HEADER(IOStream.hxx) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "Configure.hxx.in" +# include "IOStream.hxx.in" +#endif + +// Implement the rest of this file only if it is needed. +#if KWSYS_IOS_NEED_OPERATORS_LL + +# include // sscanf, sprintf +# include // memchr + +# if defined(_MAX_INT_DIG) +# define KWSYS_IOS_INT64_MAX_DIG _MAX_INT_DIG +# else +# define KWSYS_IOS_INT64_MAX_DIG 32 +# endif + +namespace KWSYS_NAMESPACE { + +// Scan an input stream for an integer value. +static int IOStreamScanStream(std::istream& is, char* buffer) +{ + // Prepare to write to buffer. + char* out = buffer; + char* end = buffer + KWSYS_IOS_INT64_MAX_DIG - 1; + + // Look for leading sign. + if (is.peek() == '+') { + *out++ = '+'; + is.ignore(); + } else if (is.peek() == '-') { + *out++ = '-'; + is.ignore(); + } + + // Determine the base. If not specified in the stream, try to + // detect it from the input. A leading 0x means hex, and a leading + // 0 alone means octal. + int base = 0; + int flags = is.flags() & std::ios_base::basefield; + if (flags == std::ios_base::oct) { + base = 8; + } else if (flags == std::ios_base::dec) { + base = 10; + } else if (flags == std::ios_base::hex) { + base = 16; + } + bool foundDigit = false; + bool foundNonZero = false; + if (is.peek() == '0') { + foundDigit = true; + is.ignore(); + if ((is.peek() == 'x' || is.peek() == 'X') && (base == 0 || base == 16)) { + base = 16; + foundDigit = false; + is.ignore(); + } else if (base == 0) { + base = 8; + } + } + + // Determine the range of digits allowed for this number. + const char* digits = "0123456789abcdefABCDEF"; + int maxDigitIndex = 10; + if (base == 8) { + maxDigitIndex = 8; + } else if (base == 16) { + maxDigitIndex = 10 + 6 + 6; + } + + // Scan until an invalid digit is found. + for (; is.peek() != EOF; is.ignore()) { + if (memchr(digits, *out = (char)is.peek(), maxDigitIndex) != 0) { + if ((foundNonZero || *out != '0') && out < end) { + ++out; + foundNonZero = true; + } + foundDigit = true; + } else { + break; + } + } + + // Correct the buffer contents for degenerate cases. + if (foundDigit && !foundNonZero) { + *out++ = '0'; + } else if (!foundDigit) { + out = buffer; + } + + // Terminate the string in the buffer. + *out = '\0'; + + return base; +} + +// Read an integer value from an input stream. +template +std::istream& IOStreamScanTemplate(std::istream& is, T& value, char type) +{ + int state = std::ios_base::goodbit; + + // Skip leading whitespace. + std::istream::sentry okay(is); + + if (okay) { + try { + // Copy the string to a buffer and construct the format string. + char buffer[KWSYS_IOS_INT64_MAX_DIG]; +# if defined(_MSC_VER) + char format[] = "%I64_"; + const int typeIndex = 4; +# else + char format[] = "%ll_"; + const int typeIndex = 3; +# endif + switch (IOStreamScanStream(is, buffer)) { + case 8: + format[typeIndex] = 'o'; + break; + case 0: // Default to decimal if not told otherwise. + case 10: + format[typeIndex] = type; + break; + case 16: + format[typeIndex] = 'x'; + break; + }; + + // Use sscanf to parse the number from the buffer. + T result; + int success = (sscanf(buffer, format, &result) == 1) ? 1 : 0; + + // Set flags for resulting state. + if (is.peek() == EOF) { + state |= std::ios_base::eofbit; + } + if (!success) { + state |= std::ios_base::failbit; + } else { + value = result; + } + } catch (...) { + state |= std::ios_base::badbit; + } + } + + is.setstate(std::ios_base::iostate(state)); + return is; +} + +// Print an integer value to an output stream. +template +std::ostream& IOStreamPrintTemplate(std::ostream& os, T value, char type) +{ + std::ostream::sentry okay(os); + if (okay) { + try { + // Construct the format string. + char format[8]; + char* f = format; + *f++ = '%'; + if (os.flags() & std::ios_base::showpos) { + *f++ = '+'; + } + if (os.flags() & std::ios_base::showbase) { + *f++ = '#'; + } +# if defined(_MSC_VER) + *f++ = 'I'; + *f++ = '6'; + *f++ = '4'; +# else + *f++ = 'l'; + *f++ = 'l'; +# endif + long bflags = os.flags() & std::ios_base::basefield; + if (bflags == std::ios_base::oct) { + *f++ = 'o'; + } else if (bflags != std::ios_base::hex) { + *f++ = type; + } else if (os.flags() & std::ios_base::uppercase) { + *f++ = 'X'; + } else { + *f++ = 'x'; + } + *f = '\0'; + + // Use sprintf to print to a buffer and then write the + // buffer to the stream. + char buffer[2 * KWSYS_IOS_INT64_MAX_DIG]; + sprintf(buffer, format, value); + os << buffer; + } catch (...) { + os.clear(os.rdstate() | std::ios_base::badbit); + } + } + return os; +} + +# if !KWSYS_IOS_HAS_ISTREAM_LONG_LONG +// Implement input stream operator for IOStreamSLL. +std::istream& IOStreamScan(std::istream& is, IOStreamSLL& value) +{ + return IOStreamScanTemplate(is, value, 'd'); +} + +// Implement input stream operator for IOStreamULL. +std::istream& IOStreamScan(std::istream& is, IOStreamULL& value) +{ + return IOStreamScanTemplate(is, value, 'u'); +} +# endif + +# if !KWSYS_IOS_HAS_OSTREAM_LONG_LONG +// Implement output stream operator for IOStreamSLL. +std::ostream& IOStreamPrint(std::ostream& os, IOStreamSLL value) +{ + return IOStreamPrintTemplate(os, value, 'd'); +} + +// Implement output stream operator for IOStreamULL. +std::ostream& IOStreamPrint(std::ostream& os, IOStreamULL value) +{ + return IOStreamPrintTemplate(os, value, 'u'); +} +# endif + +} // namespace KWSYS_NAMESPACE + +#else + +namespace KWSYS_NAMESPACE { + +// Create one public symbol in this object file to avoid warnings from +// archivers. +void IOStreamSymbolToAvoidWarning(); +void IOStreamSymbolToAvoidWarning() +{ +} + +} // namespace KWSYS_NAMESPACE + +#endif // KWSYS_IOS_NEED_OPERATORS_LL diff --git a/test/API/driver/kwsys/IOStream.hxx.in b/test/API/driver/kwsys/IOStream.hxx.in new file mode 100644 index 0000000..db8a23e --- /dev/null +++ b/test/API/driver/kwsys/IOStream.hxx.in @@ -0,0 +1,126 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_IOStream_hxx +#define @KWSYS_NAMESPACE@_IOStream_hxx + +#include + +/* Define these macros temporarily to keep the code readable. */ +#if !defined(KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT +#endif + +/* Whether istream supports long long. */ +#define @KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG \ + @KWSYS_IOS_HAS_ISTREAM_LONG_LONG@ + +/* Whether ostream supports long long. */ +#define @KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG \ + @KWSYS_IOS_HAS_OSTREAM_LONG_LONG@ + +/* Determine whether we need to define the streaming operators for + long long or __int64. */ +#if @KWSYS_USE_LONG_LONG@ +# if !@KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG || \ + !@KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG +# define @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL 1 +namespace @KWSYS_NAMESPACE@ { +typedef long long IOStreamSLL; +typedef unsigned long long IOStreamULL; +} +# endif +#elif defined(_MSC_VER) && _MSC_VER < 1300 +# define @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL 1 +namespace @KWSYS_NAMESPACE@ { +typedef __int64 IOStreamSLL; +typedef unsigned __int64 IOStreamULL; +} +#endif +#if !defined(@KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL) +# define @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL 0 +#endif + +#if @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL +# if !@KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG + +/* Input stream operator implementation functions. */ +namespace @KWSYS_NAMESPACE@ { +kwsysEXPORT std::istream& IOStreamScan(std::istream&, IOStreamSLL&); +kwsysEXPORT std::istream& IOStreamScan(std::istream&, IOStreamULL&); +} + +/* Provide input stream operator for long long. */ +# if !defined(@KWSYS_NAMESPACE@_IOS_NO_ISTREAM_LONG_LONG) && \ + !defined(KWSYS_IOS_ISTREAM_LONG_LONG_DEFINED) +# define KWSYS_IOS_ISTREAM_LONG_LONG_DEFINED +# define @KWSYS_NAMESPACE@_IOS_ISTREAM_LONG_LONG_DEFINED +inline std::istream& operator>>(std::istream& is, + @KWSYS_NAMESPACE@::IOStreamSLL& value) +{ + return @KWSYS_NAMESPACE@::IOStreamScan(is, value); +} +# endif + +/* Provide input stream operator for unsigned long long. */ +# if !defined(@KWSYS_NAMESPACE@_IOS_NO_ISTREAM_UNSIGNED_LONG_LONG) && \ + !defined(KWSYS_IOS_ISTREAM_UNSIGNED_LONG_LONG_DEFINED) +# define KWSYS_IOS_ISTREAM_UNSIGNED_LONG_LONG_DEFINED +# define @KWSYS_NAMESPACE@_IOS_ISTREAM_UNSIGNED_LONG_LONG_DEFINED +inline std::istream& operator>>(std::istream& is, + @KWSYS_NAMESPACE@::IOStreamULL& value) +{ + return @KWSYS_NAMESPACE@::IOStreamScan(is, value); +} +# endif +# endif /* !@KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG */ + +# if !@KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG + +/* Output stream operator implementation functions. */ +namespace @KWSYS_NAMESPACE@ { +kwsysEXPORT std::ostream& IOStreamPrint(std::ostream&, IOStreamSLL); +kwsysEXPORT std::ostream& IOStreamPrint(std::ostream&, IOStreamULL); +} + +/* Provide output stream operator for long long. */ +# if !defined(@KWSYS_NAMESPACE@_IOS_NO_OSTREAM_LONG_LONG) && \ + !defined(KWSYS_IOS_OSTREAM_LONG_LONG_DEFINED) +# define KWSYS_IOS_OSTREAM_LONG_LONG_DEFINED +# define @KWSYS_NAMESPACE@_IOS_OSTREAM_LONG_LONG_DEFINED +inline std::ostream& operator<<(std::ostream& os, + @KWSYS_NAMESPACE@::IOStreamSLL value) +{ + return @KWSYS_NAMESPACE@::IOStreamPrint(os, value); +} +# endif + +/* Provide output stream operator for unsigned long long. */ +# if !defined(@KWSYS_NAMESPACE@_IOS_NO_OSTREAM_UNSIGNED_LONG_LONG) && \ + !defined(KWSYS_IOS_OSTREAM_UNSIGNED_LONG_LONG_DEFINED) +# define KWSYS_IOS_OSTREAM_UNSIGNED_LONG_LONG_DEFINED +# define @KWSYS_NAMESPACE@_IOS_OSTREAM_UNSIGNED_LONG_LONG_DEFINED +inline std::ostream& operator<<(std::ostream& os, + @KWSYS_NAMESPACE@::IOStreamULL value) +{ + return @KWSYS_NAMESPACE@::IOStreamPrint(os, value); +} +# endif +# endif /* !@KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG */ +#endif /* @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL */ + +/* Undefine temporary macros. */ +#if !defined(KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# undef kwsysEXPORT +#endif + +/* If building a C++ file in kwsys itself, give the source file + access to the macros without a configured namespace. */ +#if defined(KWSYS_NAMESPACE) +# define KWSYS_IOS_HAS_ISTREAM_LONG_LONG \ + @KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG +# define KWSYS_IOS_HAS_OSTREAM_LONG_LONG \ + @KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG +# define KWSYS_IOS_NEED_OPERATORS_LL @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL +#endif + +#endif diff --git a/test/API/driver/kwsys/MD5.c b/test/API/driver/kwsys/MD5.c new file mode 100644 index 0000000..97cf9ba --- /dev/null +++ b/test/API/driver/kwsys/MD5.c @@ -0,0 +1,494 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(MD5.h) + +/* Work-around CMake dependency scanning limitation. This must + duplicate the above list of headers. */ +#if 0 +# include "MD5.h.in" +#endif + +#include /* size_t */ +#include /* malloc, free */ +#include /* memcpy, strlen */ + +/* This MD5 implementation has been taken from a third party. Slight + modifications to the arrangement of the code have been made to put + it in a single source file instead of a separate header and + implementation file. */ + +#if defined(__clang__) && !defined(__INTEL_COMPILER) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wcast-align" +#endif + +/* + Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.c is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order + either statically or dynamically; added missing #include + in library. + 2002-03-11 lpd Corrected argument list for main(), and added int return + type, in test program and T value program. + 2002-02-21 lpd Added missing #include in test program. + 2000-07-03 lpd Patched to eliminate warnings about "constant is + unsigned in ANSI C, signed in traditional"; made test program + self-checking. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). + 1999-05-03 lpd Original version. + */ + +/* + * This package supports both compile-time and run-time determination of CPU + * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be + * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is + * defined as non-zero, the code will be compiled to run only on big-endian + * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to + * run on either big- or little-endian CPUs, but will run slightly less + * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. + */ + +typedef unsigned char md5_byte_t; /* 8-bit byte */ +typedef unsigned int md5_word_t; /* 32-bit word */ + +/* Define the state of the MD5 Algorithm. */ +typedef struct md5_state_s +{ + md5_word_t count[2]; /* message length in bits, lsw first */ + md5_word_t abcd[4]; /* digest buffer */ + md5_byte_t buf[64]; /* accumulate block */ +} md5_state_t; + +#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ +#ifdef ARCH_IS_BIG_ENDIAN +# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) +#else +# define BYTE_ORDER 0 +#endif + +#define T_MASK ((md5_word_t)~0) +#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) +#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) +#define T3 0x242070db +#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) +#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) +#define T6 0x4787c62a +#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) +#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) +#define T9 0x698098d8 +#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) +#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) +#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) +#define T13 0x6b901122 +#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) +#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) +#define T16 0x49b40821 +#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) +#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) +#define T19 0x265e5a51 +#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) +#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) +#define T22 0x02441453 +#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) +#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) +#define T25 0x21e1cde6 +#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) +#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) +#define T28 0x455a14ed +#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) +#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) +#define T31 0x676f02d9 +#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) +#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) +#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) +#define T35 0x6d9d6122 +#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) +#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) +#define T38 0x4bdecfa9 +#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) +#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) +#define T41 0x289b7ec6 +#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) +#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) +#define T44 0x04881d05 +#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) +#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) +#define T47 0x1fa27cf8 +#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) +#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) +#define T50 0x432aff97 +#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) +#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) +#define T53 0x655b59c3 +#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) +#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) +#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) +#define T57 0x6fa87e4f +#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) +#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) +#define T60 0x4e0811a1 +#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) +#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) +#define T63 0x2ad7d2bb +#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) + +static void md5_process(md5_state_t* pms, const md5_byte_t* data /*[64]*/) +{ + md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], + d = pms->abcd[3]; + md5_word_t t; +#if BYTE_ORDER > 0 + /* Define storage only for big-endian CPUs. */ + md5_word_t X[16]; +#else + /* Define storage for little-endian or both types of CPUs. */ + md5_word_t xbuf[16]; + const md5_word_t* X; +#endif + + { +#if BYTE_ORDER == 0 + /* + * Determine dynamically whether this is a big-endian or + * little-endian machine, since we can use a more efficient + * algorithm on the latter. + */ + static const int w = 1; + + if (*((const md5_byte_t*)&w)) /* dynamic little-endian */ +#endif +#if BYTE_ORDER <= 0 /* little-endian */ + { + /* + * On little-endian machines, we can process properly aligned + * data without copying it. + */ + if (!((data - (const md5_byte_t*)0) & 3)) { + /* data are properly aligned */ + X = (const md5_word_t*)data; + } else { + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; + } + } +#endif +#if BYTE_ORDER == 0 + else /* dynamic big-endian */ +#endif +#if BYTE_ORDER >= 0 /* big-endian */ + { + /* + * On big-endian machines, we must arrange the bytes in the + * right order. + */ + const md5_byte_t* xp = data; + int i; + +# if BYTE_ORDER == 0 + X = xbuf; /* (dynamic only) */ +# else +# define xbuf X /* (static only) */ +# endif + for (i = 0; i < 16; ++i, xp += 4) + xbuf[i] = + (md5_word_t)(xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24)); + } +#endif + } + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + +/* Round 1. */ +/* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET(a, b, c, d, k, s, Ti) \ + t = a + F(b, c, d) + X[k] + (Ti); \ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); +#undef SET + +/* Round 2. */ +/* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET(a, b, c, d, k, s, Ti) \ + t = a + G(b, c, d) + X[k] + (Ti); \ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); +#undef SET + +/* Round 3. */ +/* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET(a, b, c, d, k, s, Ti) \ + t = a + H(b, c, d) + X[k] + (Ti); \ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); +#undef SET + +/* Round 4. */ +/* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET(a, b, c, d, k, s, Ti) \ + t = a + I(b, c, d) + X[k] + (Ti); \ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); +#undef SET + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +/* Initialize the algorithm. */ +static void md5_init(md5_state_t* pms) +{ + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; + pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; + pms->abcd[3] = 0x10325476; +} + +/* Append a string to the message. */ +static void md5_append(md5_state_t* pms, const md5_byte_t* data, size_t nbytes) +{ + const md5_byte_t* p = data; + size_t left = nbytes; + size_t offset = (pms->count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t)(nbytes << 3); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += (md5_word_t)(nbytes >> 29); + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) { + size_t copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + memcpy(pms->buf, p, left); +} + +/* Finish the message and return the digest. */ +static void md5_finish(md5_state_t* pms, md5_byte_t digest[16]) +{ + static const md5_byte_t pad[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + md5_byte_t data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); +} + +#if defined(__clang__) && !defined(__INTEL_COMPILER) +# pragma clang diagnostic pop +#endif + +/* Wrap up the MD5 state in our opaque structure. */ +struct kwsysMD5_s +{ + md5_state_t md5_state; +}; + +kwsysMD5* kwsysMD5_New(void) +{ + /* Allocate a process control structure. */ + kwsysMD5* md5 = (kwsysMD5*)malloc(sizeof(kwsysMD5)); + if (!md5) { + return 0; + } + return md5; +} + +void kwsysMD5_Delete(kwsysMD5* md5) +{ + /* Make sure we have an instance. */ + if (!md5) { + return; + } + + /* Free memory. */ + free(md5); +} + +void kwsysMD5_Initialize(kwsysMD5* md5) +{ + md5_init(&md5->md5_state); +} + +void kwsysMD5_Append(kwsysMD5* md5, unsigned char const* data, int length) +{ + size_t dlen; + if (length < 0) { + dlen = strlen((char const*)data); + } else { + dlen = (size_t)length; + } + md5_append(&md5->md5_state, (md5_byte_t const*)data, dlen); +} + +void kwsysMD5_Finalize(kwsysMD5* md5, unsigned char digest[16]) +{ + md5_finish(&md5->md5_state, (md5_byte_t*)digest); +} + +void kwsysMD5_FinalizeHex(kwsysMD5* md5, char buffer[32]) +{ + unsigned char digest[16]; + kwsysMD5_Finalize(md5, digest); + kwsysMD5_DigestToHex(digest, buffer); +} + +void kwsysMD5_DigestToHex(unsigned char const digest[16], char buffer[32]) +{ + /* Map from 4-bit index to hexadecimal representation. */ + static char const hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + + /* Map each 4-bit block separately. */ + char* out = buffer; + int i; + for (i = 0; i < 16; ++i) { + *out++ = hex[digest[i] >> 4]; + *out++ = hex[digest[i] & 0xF]; + } +} diff --git a/test/API/driver/kwsys/MD5.h.in b/test/API/driver/kwsys/MD5.h.in new file mode 100644 index 0000000..7646f12 --- /dev/null +++ b/test/API/driver/kwsys/MD5.h.in @@ -0,0 +1,97 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_MD5_h +#define @KWSYS_NAMESPACE@_MD5_h + +#include <@KWSYS_NAMESPACE@/Configure.h> + +/* Redefine all public interface symbol names to be in the proper + namespace. These macros are used internally to kwsys only, and are + not visible to user code. Use kwsysHeaderDump.pl to reproduce + these macros after making changes to the interface. */ +#if !defined(KWSYS_NAMESPACE) +# define kwsys_ns(x) @KWSYS_NAMESPACE@##x +# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT +#endif +#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# define kwsysMD5 kwsys_ns(MD5) +# define kwsysMD5_s kwsys_ns(MD5_s) +# define kwsysMD5_New kwsys_ns(MD5_New) +# define kwsysMD5_Delete kwsys_ns(MD5_Delete) +# define kwsysMD5_Initialize kwsys_ns(MD5_Initialize) +# define kwsysMD5_Append kwsys_ns(MD5_Append) +# define kwsysMD5_Finalize kwsys_ns(MD5_Finalize) +# define kwsysMD5_FinalizeHex kwsys_ns(MD5_FinalizeHex) +# define kwsysMD5_DigestToHex kwsys_ns(MD5_DigestToHex) +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * MD5 state data structure. + */ +typedef struct kwsysMD5_s kwsysMD5; + +/** + * Create a new MD5 instance. The returned instance is not initialized. + */ +kwsysEXPORT kwsysMD5* kwsysMD5_New(void); + +/** + * Delete an old MD5 instance. + */ +kwsysEXPORT void kwsysMD5_Delete(kwsysMD5* md5); + +/** + * Initialize a new MD5 digest. + */ +kwsysEXPORT void kwsysMD5_Initialize(kwsysMD5* md5); + +/** + * Append data to an MD5 digest. If the given length is negative, + * data will be read up to but not including a terminating null. + */ +kwsysEXPORT void kwsysMD5_Append(kwsysMD5* md5, unsigned char const* data, + int length); + +/** + * Finalize a MD5 digest and get the 16-byte hash value. + */ +kwsysEXPORT void kwsysMD5_Finalize(kwsysMD5* md5, unsigned char digest[16]); + +/** + * Finalize a MD5 digest and get the 32-bit hexadecimal representation. + */ +kwsysEXPORT void kwsysMD5_FinalizeHex(kwsysMD5* md5, char buffer[32]); + +/** + * Convert a MD5 digest 16-byte value to a 32-byte hexadecimal representation. + */ +kwsysEXPORT void kwsysMD5_DigestToHex(unsigned char const digest[16], + char buffer[32]); + +#if defined(__cplusplus) +} /* extern "C" */ +#endif + +/* If we are building a kwsys .c or .cxx file, let it use these macros. + Otherwise, undefine them to keep the namespace clean. */ +#if !defined(KWSYS_NAMESPACE) +# undef kwsys_ns +# undef kwsysEXPORT +# if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# undef kwsysMD5 +# undef kwsysMD5_s +# undef kwsysMD5_New +# undef kwsysMD5_Delete +# undef kwsysMD5_Initialize +# undef kwsysMD5_Append +# undef kwsysMD5_Finalize +# undef kwsysMD5_FinalizeHex +# undef kwsysMD5_DigestToHex +# endif +#endif + +#endif diff --git a/test/API/driver/kwsys/Process.h.in b/test/API/driver/kwsys/Process.h.in new file mode 100644 index 0000000..73ea9db --- /dev/null +++ b/test/API/driver/kwsys/Process.h.in @@ -0,0 +1,544 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_Process_h +#define @KWSYS_NAMESPACE@_Process_h + +#include <@KWSYS_NAMESPACE@/Configure.h> + +/* Redefine all public interface symbol names to be in the proper + namespace. These macros are used internally to kwsys only, and are + not visible to user code. Use kwsysHeaderDump.pl to reproduce + these macros after making changes to the interface. */ +#if !defined(KWSYS_NAMESPACE) +# define kwsys_ns(x) @KWSYS_NAMESPACE@##x +# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT +#endif +#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# define kwsysProcess kwsys_ns(Process) +# define kwsysProcess_s kwsys_ns(Process_s) +# define kwsysProcess_New kwsys_ns(Process_New) +# define kwsysProcess_Delete kwsys_ns(Process_Delete) +# define kwsysProcess_SetCommand kwsys_ns(Process_SetCommand) +# define kwsysProcess_AddCommand kwsys_ns(Process_AddCommand) +# define kwsysProcess_SetTimeout kwsys_ns(Process_SetTimeout) +# define kwsysProcess_SetWorkingDirectory \ + kwsys_ns(Process_SetWorkingDirectory) +# define kwsysProcess_SetPipeFile kwsys_ns(Process_SetPipeFile) +# define kwsysProcess_SetPipeNative kwsys_ns(Process_SetPipeNative) +# define kwsysProcess_SetPipeShared kwsys_ns(Process_SetPipeShared) +# define kwsysProcess_Option_Detach kwsys_ns(Process_Option_Detach) +# define kwsysProcess_Option_HideWindow kwsys_ns(Process_Option_HideWindow) +# define kwsysProcess_Option_MergeOutput kwsys_ns(Process_Option_MergeOutput) +# define kwsysProcess_Option_Verbatim kwsys_ns(Process_Option_Verbatim) +# define kwsysProcess_Option_CreateProcessGroup \ + kwsys_ns(Process_Option_CreateProcessGroup) +# define kwsysProcess_GetOption kwsys_ns(Process_GetOption) +# define kwsysProcess_SetOption kwsys_ns(Process_SetOption) +# define kwsysProcess_Option_e kwsys_ns(Process_Option_e) +# define kwsysProcess_State_Starting kwsys_ns(Process_State_Starting) +# define kwsysProcess_State_Error kwsys_ns(Process_State_Error) +# define kwsysProcess_State_Exception kwsys_ns(Process_State_Exception) +# define kwsysProcess_State_Executing kwsys_ns(Process_State_Executing) +# define kwsysProcess_State_Exited kwsys_ns(Process_State_Exited) +# define kwsysProcess_State_Expired kwsys_ns(Process_State_Expired) +# define kwsysProcess_State_Killed kwsys_ns(Process_State_Killed) +# define kwsysProcess_State_Disowned kwsys_ns(Process_State_Disowned) +# define kwsysProcess_State_e kwsys_ns(Process_State_e) +# define kwsysProcess_Exception_None kwsys_ns(Process_Exception_None) +# define kwsysProcess_Exception_Fault kwsys_ns(Process_Exception_Fault) +# define kwsysProcess_Exception_Illegal kwsys_ns(Process_Exception_Illegal) +# define kwsysProcess_Exception_Interrupt \ + kwsys_ns(Process_Exception_Interrupt) +# define kwsysProcess_Exception_Numerical \ + kwsys_ns(Process_Exception_Numerical) +# define kwsysProcess_Exception_Other kwsys_ns(Process_Exception_Other) +# define kwsysProcess_Exception_e kwsys_ns(Process_Exception_e) +# define kwsysProcess_GetState kwsys_ns(Process_GetState) +# define kwsysProcess_GetExitException kwsys_ns(Process_GetExitException) +# define kwsysProcess_GetExitCode kwsys_ns(Process_GetExitCode) +# define kwsysProcess_GetExitValue kwsys_ns(Process_GetExitValue) +# define kwsysProcess_GetErrorString kwsys_ns(Process_GetErrorString) +# define kwsysProcess_GetExceptionString kwsys_ns(Process_GetExceptionString) +# define kwsysProcess_GetStateByIndex kwsys_ns(Process_GetStateByIndex) +# define kwsysProcess_GetExitExceptionByIndex \ + kwsys_ns(Process_GetExitExceptionByIndex) +# define kwsysProcess_GetExitCodeByIndex kwsys_ns(Process_GetExitCodeByIndex) +# define kwsysProcess_GetExitValueByIndex \ + kwsys_ns(Process_GetExitValueByIndex) +# define kwsysProcess_GetExceptionStringByIndex \ + kwsys_ns(Process_GetExceptionStringByIndex) +# define kwsysProcess_GetExitCodeByIndex kwsys_ns(Process_GetExitCodeByIndex) +# define kwsysProcess_Execute kwsys_ns(Process_Execute) +# define kwsysProcess_Disown kwsys_ns(Process_Disown) +# define kwsysProcess_WaitForData kwsys_ns(Process_WaitForData) +# define kwsysProcess_Pipes_e kwsys_ns(Process_Pipes_e) +# define kwsysProcess_Pipe_None kwsys_ns(Process_Pipe_None) +# define kwsysProcess_Pipe_STDIN kwsys_ns(Process_Pipe_STDIN) +# define kwsysProcess_Pipe_STDOUT kwsys_ns(Process_Pipe_STDOUT) +# define kwsysProcess_Pipe_STDERR kwsys_ns(Process_Pipe_STDERR) +# define kwsysProcess_Pipe_Timeout kwsys_ns(Process_Pipe_Timeout) +# define kwsysProcess_Pipe_Handle kwsys_ns(Process_Pipe_Handle) +# define kwsysProcess_WaitForExit kwsys_ns(Process_WaitForExit) +# define kwsysProcess_Interrupt kwsys_ns(Process_Interrupt) +# define kwsysProcess_Kill kwsys_ns(Process_Kill) +# define kwsysProcess_KillPID kwsys_ns(Process_KillPID) +# define kwsysProcess_ResetStartTime kwsys_ns(Process_ResetStartTime) +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * Process control data structure. + */ +typedef struct kwsysProcess_s kwsysProcess; + +/* Platform-specific pipe handle type. */ +#if defined(_WIN32) && !defined(__CYGWIN__) +typedef void* kwsysProcess_Pipe_Handle; +#else +typedef int kwsysProcess_Pipe_Handle; +#endif + +/** + * Create a new Process instance. + */ +kwsysEXPORT kwsysProcess* kwsysProcess_New(void); + +/** + * Delete an existing Process instance. If the instance is currently + * executing a process, this blocks until the process terminates. + */ +kwsysEXPORT void kwsysProcess_Delete(kwsysProcess* cp); + +/** + * Set the command line to be executed. Argument is an array of + * pointers to the command and each argument. The array must end with + * a NULL pointer. Any previous command lines are removed. Returns + * 1 for success and 0 otherwise. + */ +kwsysEXPORT int kwsysProcess_SetCommand(kwsysProcess* cp, + char const* const* command); + +/** + * Add a command line to be executed. Argument is an array of + * pointers to the command and each argument. The array must end with + * a NULL pointer. If this is not the first command added, its + * standard input will be connected to the standard output of the + * previous command. Returns 1 for success and 0 otherwise. + */ +kwsysEXPORT int kwsysProcess_AddCommand(kwsysProcess* cp, + char const* const* command); + +/** + * Set the timeout in seconds for the child process. The timeout + * period begins when the child is executed. If the child has not + * terminated when the timeout expires, it will be killed. A + * non-positive (<= 0) value will disable the timeout. + */ +kwsysEXPORT void kwsysProcess_SetTimeout(kwsysProcess* cp, double timeout); + +/** + * Set the working directory for the child process. The working + * directory can be absolute or relative to the current directory. + * Returns 1 for success and 0 for failure. + */ +kwsysEXPORT int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, + const char* dir); + +/** + * Set the name of a file to be attached to the given pipe. Returns 1 + * for success and 0 for failure. + */ +kwsysEXPORT int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe, + const char* file); + +/** + * Set whether the given pipe in the child is shared with the parent + * process. The default is no for Pipe_STDOUT and Pipe_STDERR and yes + * for Pipe_STDIN. + */ +kwsysEXPORT void kwsysProcess_SetPipeShared(kwsysProcess* cp, int pipe, + int shared); + +/** + * Specify a platform-specific native pipe for use as one of the child + * interface pipes. The native pipe is specified by an array of two + * descriptors or handles. The first entry in the array (index 0) + * should be the read end of the pipe. The second entry in the array + * (index 1) should be the write end of the pipe. If a null pointer + * is given the option will be disabled. + * + * For Pipe_STDIN the native pipe is connected to the first child in + * the pipeline as its stdin. After the children are created the + * write end of the pipe will be closed in the child process and the + * read end will be closed in the parent process. + * + * For Pipe_STDOUT and Pipe_STDERR the pipe is connected to the last + * child as its stdout or stderr. After the children are created the + * write end of the pipe will be closed in the parent process and the + * read end will be closed in the child process. + */ +kwsysEXPORT void kwsysProcess_SetPipeNative(kwsysProcess* cp, int pipe, + kwsysProcess_Pipe_Handle p[2]); + +/** + * Get/Set a possibly platform-specific option. Possible options are: + * + * kwsysProcess_Option_Detach = Whether to detach the process. + * 0 = No (default) + * 1 = Yes + * + * kwsysProcess_Option_HideWindow = Whether to hide window on Windows. + * 0 = No (default) + * 1 = Yes + * + * kwsysProcess_Option_MergeOutput = Whether to merge stdout/stderr. + * No content will be returned as stderr. + * Any actual stderr will be on stdout. + * 0 = No (default) + * 1 = Yes + * + * kwsysProcess_Option_Verbatim = Whether SetCommand and AddCommand + * should treat the first argument + * as a verbatim command line + * and ignore the rest of the arguments. + * 0 = No (default) + * 1 = Yes + * + * kwsysProcess_Option_CreateProcessGroup = Whether to place the process in a + * new process group. This is + * useful if you want to send Ctrl+C + * to the process. On UNIX, also + * places the process in a new + * session. + * 0 = No (default) + * 1 = Yes + */ +kwsysEXPORT int kwsysProcess_GetOption(kwsysProcess* cp, int optionId); +kwsysEXPORT void kwsysProcess_SetOption(kwsysProcess* cp, int optionId, + int value); +enum kwsysProcess_Option_e +{ + kwsysProcess_Option_HideWindow, + kwsysProcess_Option_Detach, + kwsysProcess_Option_MergeOutput, + kwsysProcess_Option_Verbatim, + kwsysProcess_Option_CreateProcessGroup +}; + +/** + * Get the current state of the Process instance. Possible states are: + * + * kwsysProcess_State_Starting = Execute has not yet been called. + * kwsysProcess_State_Error = Error administrating the child process. + * kwsysProcess_State_Exception = Child process exited abnormally. + * kwsysProcess_State_Executing = Child process is currently running. + * kwsysProcess_State_Exited = Child process exited normally. + * kwsysProcess_State_Expired = Child process's timeout expired. + * kwsysProcess_State_Killed = Child process terminated by Kill method. + * kwsysProcess_State_Disowned = Child is no longer managed by this object. + */ +kwsysEXPORT int kwsysProcess_GetState(kwsysProcess* cp); +enum kwsysProcess_State_e +{ + kwsysProcess_State_Starting, + kwsysProcess_State_Error, + kwsysProcess_State_Exception, + kwsysProcess_State_Executing, + kwsysProcess_State_Exited, + kwsysProcess_State_Expired, + kwsysProcess_State_Killed, + kwsysProcess_State_Disowned +}; + +/** + * When GetState returns "Exception", this method returns a + * platform-independent description of the exceptional behavior that + * caused the child to terminate abnormally. Possible exceptions are: + * + * kwsysProcess_Exception_None = No exceptional behavior occurred. + * kwsysProcess_Exception_Fault = Child crashed with a memory fault. + * kwsysProcess_Exception_Illegal = Child crashed with an illegal + * instruction. + * kwsysProcess_Exception_Interrupt = Child was interrupted by user + * (Cntl-C/Break). + * kwsysProcess_Exception_Numerical = Child crashed with a numerical + * exception. + * kwsysProcess_Exception_Other = Child terminated for another reason. + */ +kwsysEXPORT int kwsysProcess_GetExitException(kwsysProcess* cp); +enum kwsysProcess_Exception_e +{ + kwsysProcess_Exception_None, + kwsysProcess_Exception_Fault, + kwsysProcess_Exception_Illegal, + kwsysProcess_Exception_Interrupt, + kwsysProcess_Exception_Numerical, + kwsysProcess_Exception_Other +}; + +/** + * When GetState returns "Exited" or "Exception", this method returns + * the platform-specific raw exit code of the process. UNIX platforms + * should use WIFEXITED/WEXITSTATUS and WIFSIGNALED/WTERMSIG to access + * this value. Windows users should compare the value to the various + * EXCEPTION_* values. + * + * If GetState returns "Exited", use GetExitValue to get the + * platform-independent child return value. + */ +kwsysEXPORT int kwsysProcess_GetExitCode(kwsysProcess* cp); + +/** + * When GetState returns "Exited", this method returns the child's + * platform-independent exit code (such as the value returned by the + * child's main). + */ +kwsysEXPORT int kwsysProcess_GetExitValue(kwsysProcess* cp); + +/** + * When GetState returns "Error", this method returns a string + * describing the problem. Otherwise, it returns NULL. + */ +kwsysEXPORT const char* kwsysProcess_GetErrorString(kwsysProcess* cp); + +/** + * When GetState returns "Exception", this method returns a string + * describing the problem. Otherwise, it returns NULL. + */ +kwsysEXPORT const char* kwsysProcess_GetExceptionString(kwsysProcess* cp); + +/** + * Get the current state of the Process instance. Possible states are: + * + * kwsysProcess_StateByIndex_Starting = Execute has not yet been called. + * kwsysProcess_StateByIndex_Exception = Child process exited abnormally. + * kwsysProcess_StateByIndex_Exited = Child process exited normally. + * kwsysProcess_StateByIndex_Error = Error getting the child return code. + */ +kwsysEXPORT int kwsysProcess_GetStateByIndex(kwsysProcess* cp, int idx); +enum kwsysProcess_StateByIndex_e +{ + kwsysProcess_StateByIndex_Starting = kwsysProcess_State_Starting, + kwsysProcess_StateByIndex_Exception = kwsysProcess_State_Exception, + kwsysProcess_StateByIndex_Exited = kwsysProcess_State_Exited, + kwsysProcess_StateByIndex_Error = kwsysProcess_State_Error +}; + +/** + * When GetState returns "Exception", this method returns a + * platform-independent description of the exceptional behavior that + * caused the child to terminate abnormally. Possible exceptions are: + * + * kwsysProcess_Exception_None = No exceptional behavior occurred. + * kwsysProcess_Exception_Fault = Child crashed with a memory fault. + * kwsysProcess_Exception_Illegal = Child crashed with an illegal + * instruction. + * kwsysProcess_Exception_Interrupt = Child was interrupted by user + * (Cntl-C/Break). + * kwsysProcess_Exception_Numerical = Child crashed with a numerical + * exception. + * kwsysProcess_Exception_Other = Child terminated for another reason. + */ +kwsysEXPORT int kwsysProcess_GetExitExceptionByIndex(kwsysProcess* cp, + int idx); + +/** + * When GetState returns "Exited" or "Exception", this method returns + * the platform-specific raw exit code of the process. UNIX platforms + * should use WIFEXITED/WEXITSTATUS and WIFSIGNALED/WTERMSIG to access + * this value. Windows users should compare the value to the various + * EXCEPTION_* values. + * + * If GetState returns "Exited", use GetExitValue to get the + * platform-independent child return value. + */ +kwsysEXPORT int kwsysProcess_GetExitCodeByIndex(kwsysProcess* cp, int idx); + +/** + * When GetState returns "Exited", this method returns the child's + * platform-independent exit code (such as the value returned by the + * child's main). + */ +kwsysEXPORT int kwsysProcess_GetExitValueByIndex(kwsysProcess* cp, int idx); + +/** + * When GetState returns "Exception", this method returns a string + * describing the problem. Otherwise, it returns NULL. + */ +kwsysEXPORT const char* kwsysProcess_GetExceptionStringByIndex( + kwsysProcess* cp, int idx); + +/** + * Start executing the child process. + */ +kwsysEXPORT void kwsysProcess_Execute(kwsysProcess* cp); + +/** + * Stop management of a detached child process. This closes any pipes + * being read. If the child was not created with the + * kwsysProcess_Option_Detach option, this method does nothing. This + * is because disowning a non-detached process will cause the child + * exit signal to be left unhandled until this process exits. + */ +kwsysEXPORT void kwsysProcess_Disown(kwsysProcess* cp); + +/** + * Block until data are available on a pipe, a timeout expires, or the + * child process terminates. Arguments are as follows: + * + * data = If data are read, the pointer to which this points is + * set to point to the data. + * length = If data are read, the integer to which this points is + * set to the length of the data read. + * timeout = Specifies the maximum time this call may block. Upon + * return after reading data, the time elapsed is subtracted + * from the timeout value. If this timeout expires, the + * value is set to 0. A NULL pointer passed for this argument + * indicates no timeout for the call. A negative or zero + * value passed for this argument may be used for polling + * and will always return immediately. + * + * Return value will be one of: + * + * Pipe_None = No more data will be available from the child process, + * ( == 0) or no process has been executed. WaitForExit should + * be called to wait for the process to terminate. + * Pipe_STDOUT = Data have been read from the child's stdout pipe. + * Pipe_STDERR = Data have been read from the child's stderr pipe. + * Pipe_Timeout = No data available within timeout specified for the + * call. Time elapsed has been subtracted from timeout + * argument. + */ +kwsysEXPORT int kwsysProcess_WaitForData(kwsysProcess* cp, char** data, + int* length, double* timeout); +enum kwsysProcess_Pipes_e +{ + kwsysProcess_Pipe_None, + kwsysProcess_Pipe_STDIN, + kwsysProcess_Pipe_STDOUT, + kwsysProcess_Pipe_STDERR, + kwsysProcess_Pipe_Timeout = 255 +}; + +/** + * Block until the child process terminates or the given timeout + * expires. If no process is running, returns immediately. The + * argument is: + * + * timeout = Specifies the maximum time this call may block. Upon + * returning due to child termination, the elapsed time + * is subtracted from the given value. A NULL pointer + * passed for this argument indicates no timeout for the + * call. + * + * Return value will be one of: + * + * 0 = Child did not terminate within timeout specified for + * the call. Time elapsed has been subtracted from timeout + * argument. + * 1 = Child has terminated or was not running. + */ +kwsysEXPORT int kwsysProcess_WaitForExit(kwsysProcess* cp, double* timeout); + +/** + * Interrupt the process group for the child process that is currently + * running by sending it the appropriate operating-system specific signal. + * The caller should call WaitForExit after this returns to wait for the + * child to terminate. + * + * WARNING: If you didn't specify kwsysProcess_Option_CreateProcessGroup, + * you will interrupt your own process group. + */ +kwsysEXPORT void kwsysProcess_Interrupt(kwsysProcess* cp); + +/** + * Forcefully terminate the child process that is currently running. + * The caller should call WaitForExit after this returns to wait for + * the child to terminate. + */ +kwsysEXPORT void kwsysProcess_Kill(kwsysProcess* cp); + +/** + * Same as kwsysProcess_Kill using process ID to locate process to + * terminate. + * @see kwsysProcess_Kill(kwsysProcess* cp) + */ +kwsysEXPORT void kwsysProcess_KillPID(unsigned long); + +/** + * Reset the start time of the child process to the current time. + */ +kwsysEXPORT void kwsysProcess_ResetStartTime(kwsysProcess* cp); + +#if defined(__cplusplus) +} /* extern "C" */ +#endif + +/* If we are building a kwsys .c or .cxx file, let it use these macros. + Otherwise, undefine them to keep the namespace clean. */ +#if !defined(KWSYS_NAMESPACE) +# undef kwsys_ns +# undef kwsysEXPORT +# if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# undef kwsysProcess +# undef kwsysProcess_s +# undef kwsysProcess_New +# undef kwsysProcess_Delete +# undef kwsysProcess_SetCommand +# undef kwsysProcess_AddCommand +# undef kwsysProcess_SetTimeout +# undef kwsysProcess_SetWorkingDirectory +# undef kwsysProcess_SetPipeFile +# undef kwsysProcess_SetPipeNative +# undef kwsysProcess_SetPipeShared +# undef kwsysProcess_Option_Detach +# undef kwsysProcess_Option_HideWindow +# undef kwsysProcess_Option_MergeOutput +# undef kwsysProcess_Option_Verbatim +# undef kwsysProcess_Option_CreateProcessGroup +# undef kwsysProcess_GetOption +# undef kwsysProcess_SetOption +# undef kwsysProcess_Option_e +# undef kwsysProcess_State_Starting +# undef kwsysProcess_State_Error +# undef kwsysProcess_State_Exception +# undef kwsysProcess_State_Executing +# undef kwsysProcess_State_Exited +# undef kwsysProcess_State_Expired +# undef kwsysProcess_State_Killed +# undef kwsysProcess_State_Disowned +# undef kwsysProcess_GetState +# undef kwsysProcess_State_e +# undef kwsysProcess_Exception_None +# undef kwsysProcess_Exception_Fault +# undef kwsysProcess_Exception_Illegal +# undef kwsysProcess_Exception_Interrupt +# undef kwsysProcess_Exception_Numerical +# undef kwsysProcess_Exception_Other +# undef kwsysProcess_GetExitException +# undef kwsysProcess_Exception_e +# undef kwsysProcess_GetExitCode +# undef kwsysProcess_GetExitValue +# undef kwsysProcess_GetErrorString +# undef kwsysProcess_GetExceptionString +# undef kwsysProcess_Execute +# undef kwsysProcess_Disown +# undef kwsysProcess_WaitForData +# undef kwsysProcess_Pipes_e +# undef kwsysProcess_Pipe_None +# undef kwsysProcess_Pipe_STDIN +# undef kwsysProcess_Pipe_STDOUT +# undef kwsysProcess_Pipe_STDERR +# undef kwsysProcess_Pipe_Timeout +# undef kwsysProcess_Pipe_Handle +# undef kwsysProcess_WaitForExit +# undef kwsysProcess_Interrupt +# undef kwsysProcess_Kill +# undef kwsysProcess_ResetStartTime +# endif +#endif + +#endif diff --git a/test/API/driver/kwsys/ProcessUNIX.c b/test/API/driver/kwsys/ProcessUNIX.c new file mode 100644 index 0000000..100eddc --- /dev/null +++ b/test/API/driver/kwsys/ProcessUNIX.c @@ -0,0 +1,2920 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(Process.h) +#include KWSYS_HEADER(System.h) + +/* Work-around CMake dependency scanning limitation. This must + duplicate the above list of headers. */ +#if 0 +# include "Process.h.in" +# include "System.h.in" +#endif + +/* + +Implementation for UNIX + +On UNIX, a child process is forked to exec the program. Three output +pipes are read by the parent process using a select call to block +until data are ready. Two of the pipes are stdout and stderr for the +child. The third is a special pipe populated by a signal handler to +indicate that a child has terminated. This is used in conjunction +with the timeout on the select call to implement a timeout for program +even when it closes stdout and stderr and at the same time avoiding +races. + +*/ + +/* + +TODO: + +We cannot create the pipeline of processes in suspended states. How +do we cleanup processes already started when one fails to load? Right +now we are just killing them, which is probably not the right thing to +do. + +*/ + +#if defined(__CYGWIN__) +/* Increase the file descriptor limit for select() before including + related system headers. (Default: 64) */ +# define FD_SETSIZE 16384 +#endif + +#include /* assert */ +#include /* isspace */ +#include /* DIR, dirent */ +#include /* errno */ +#include /* fcntl */ +#include /* sigaction */ +#include /* ptrdiff_t */ +#include /* snprintf */ +#include /* malloc, free */ +#include /* strdup, strerror, memset */ +#include /* open mode */ +#include /* struct timeval */ +#include /* pid_t, fd_set */ +#include /* waitpid */ +#include /* gettimeofday */ +#include /* pipe, close, fork, execvp, select, _exit */ + +#if defined(__VMS) +# define KWSYSPE_VMS_NONBLOCK , O_NONBLOCK +#else +# define KWSYSPE_VMS_NONBLOCK +#endif + +#if defined(KWSYS_C_HAS_PTRDIFF_T) && KWSYS_C_HAS_PTRDIFF_T +typedef ptrdiff_t kwsysProcess_ptrdiff_t; +#else +typedef int kwsysProcess_ptrdiff_t; +#endif + +#if defined(KWSYS_C_HAS_SSIZE_T) && KWSYS_C_HAS_SSIZE_T +typedef ssize_t kwsysProcess_ssize_t; +#else +typedef int kwsysProcess_ssize_t; +#endif + +#if defined(__BEOS__) && !defined(__ZETA__) +/* BeOS 5 doesn't have usleep(), but it has snooze(), which is identical. */ +# include +static inline void kwsysProcess_usleep(unsigned int msec) +{ + snooze(msec); +} +#else +# define kwsysProcess_usleep usleep +#endif + +/* + * BeOS's select() works like WinSock: it's for networking only, and + * doesn't work with Unix file handles...socket and file handles are + * different namespaces (the same descriptor means different things in + * each context!) + * + * So on Unix-like systems where select() is flakey, we'll set the + * pipes' file handles to be non-blocking and just poll them directly + * without select(). + */ +#if !defined(__BEOS__) && !defined(__VMS) && !defined(__MINT__) && \ + !defined(KWSYSPE_USE_SELECT) +# define KWSYSPE_USE_SELECT 1 +#endif + +/* Some platforms do not have siginfo on their signal handlers. */ +#if defined(SA_SIGINFO) && !defined(__BEOS__) +# define KWSYSPE_USE_SIGINFO 1 +#endif + +/* The number of pipes for the child's output. The standard stdout + and stderr pipes are the first two. One more pipe is used to + detect when the child process has terminated. The third pipe is + not given to the child process, so it cannot close it until it + terminates. */ +#define KWSYSPE_PIPE_COUNT 3 +#define KWSYSPE_PIPE_STDOUT 0 +#define KWSYSPE_PIPE_STDERR 1 +#define KWSYSPE_PIPE_SIGNAL 2 + +/* The maximum amount to read from a pipe at a time. */ +#define KWSYSPE_PIPE_BUFFER_SIZE 1024 + +/* Keep track of times using a signed representation. Switch to the + native (possibly unsigned) representation only when calling native + functions. */ +typedef struct timeval kwsysProcessTimeNative; +typedef struct kwsysProcessTime_s kwsysProcessTime; +struct kwsysProcessTime_s +{ + long tv_sec; + long tv_usec; +}; + +typedef struct kwsysProcessCreateInformation_s +{ + int StdIn; + int StdOut; + int StdErr; + int ErrorPipe[2]; +} kwsysProcessCreateInformation; + +static void kwsysProcessVolatileFree(volatile void* p); +static int kwsysProcessInitialize(kwsysProcess* cp); +static void kwsysProcessCleanup(kwsysProcess* cp, int error); +static void kwsysProcessCleanupDescriptor(int* pfd); +static void kwsysProcessClosePipes(kwsysProcess* cp); +static int kwsysProcessSetNonBlocking(int fd); +static int kwsysProcessCreate(kwsysProcess* cp, int prIndex, + kwsysProcessCreateInformation* si); +static void kwsysProcessDestroy(kwsysProcess* cp); +static int kwsysProcessSetupOutputPipeFile(int* p, const char* name); +static int kwsysProcessSetupOutputPipeNative(int* p, int des[2]); +static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout, + kwsysProcessTime* timeoutTime); +static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime, + double* userTimeout, + kwsysProcessTimeNative* timeoutLength, + int zeroIsExpired); +static kwsysProcessTime kwsysProcessTimeGetCurrent(void); +static double kwsysProcessTimeToDouble(kwsysProcessTime t); +static kwsysProcessTime kwsysProcessTimeFromDouble(double d); +static int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2); +static kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1, + kwsysProcessTime in2); +static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, + kwsysProcessTime in2); +static void kwsysProcessSetExitExceptionByIndex(kwsysProcess* cp, int sig, + int idx); +static void kwsysProcessChildErrorExit(int errorPipe); +static void kwsysProcessRestoreDefaultSignalHandlers(void); +static pid_t kwsysProcessFork(kwsysProcess* cp, + kwsysProcessCreateInformation* si); +static void kwsysProcessKill(pid_t process_id); +#if defined(__VMS) +static int kwsysProcessSetVMSFeature(const char* name, int value); +#endif +static int kwsysProcessesAdd(kwsysProcess* cp); +static void kwsysProcessesRemove(kwsysProcess* cp); +#if KWSYSPE_USE_SIGINFO +static void kwsysProcessesSignalHandler(int signum, siginfo_t* info, + void* ucontext); +#else +static void kwsysProcessesSignalHandler(int signum); +#endif + +/* A structure containing results data for each process. */ +typedef struct kwsysProcessResults_s kwsysProcessResults; +struct kwsysProcessResults_s +{ + /* The status of the child process. */ + int State; + + /* The exceptional behavior that terminated the process, if any. */ + int ExitException; + + /* The process exit code. */ + int ExitCode; + + /* The process return code, if any. */ + int ExitValue; + + /* Description for the ExitException. */ + char ExitExceptionString[KWSYSPE_PIPE_BUFFER_SIZE + 1]; +}; + +/* Structure containing data used to implement the child's execution. */ +struct kwsysProcess_s +{ + /* The command lines to execute. */ + char*** Commands; + volatile int NumberOfCommands; + + /* Descriptors for the read ends of the child's output pipes and + the signal pipe. */ + int PipeReadEnds[KWSYSPE_PIPE_COUNT]; + + /* Descriptors for the child's ends of the pipes. + Used temporarily during process creation. */ + int PipeChildStd[3]; + + /* Write descriptor for child termination signal pipe. */ + int SignalPipe; + + /* Buffer for pipe data. */ + char PipeBuffer[KWSYSPE_PIPE_BUFFER_SIZE]; + + /* Process IDs returned by the calls to fork. Everything is volatile + because the signal handler accesses them. You must be very careful + when reaping PIDs or modifying this array to avoid race conditions. */ + volatile pid_t* volatile ForkPIDs; + + /* Flag for whether the children were terminated by a failed select. */ + int SelectError; + + /* The timeout length. */ + double Timeout; + + /* The working directory for the process. */ + char* WorkingDirectory; + + /* Whether to create the child as a detached process. */ + int OptionDetach; + + /* Whether the child was created as a detached process. */ + int Detached; + + /* Whether to treat command lines as verbatim. */ + int Verbatim; + + /* Whether to merge stdout/stderr of the child. */ + int MergeOutput; + + /* Whether to create the process in a new process group. */ + volatile sig_atomic_t CreateProcessGroup; + + /* Time at which the child started. Negative for no timeout. */ + kwsysProcessTime StartTime; + + /* Time at which the child will timeout. Negative for no timeout. */ + kwsysProcessTime TimeoutTime; + + /* Flag for whether the timeout expired. */ + int TimeoutExpired; + + /* The number of pipes left open during execution. */ + int PipesLeft; + +#if KWSYSPE_USE_SELECT + /* File descriptor set for call to select. */ + fd_set PipeSet; +#endif + + /* The number of children still executing. */ + int CommandsLeft; + + /* The status of the process structure. Must be atomic because + the signal handler checks this to avoid a race. */ + volatile sig_atomic_t State; + + /* Whether the process was killed. */ + volatile sig_atomic_t Killed; + + /* Buffer for error message in case of failure. */ + char ErrorMessage[KWSYSPE_PIPE_BUFFER_SIZE + 1]; + + /* process results. */ + kwsysProcessResults* ProcessResults; + + /* The exit codes of each child process in the pipeline. */ + int* CommandExitCodes; + + /* Name of files to which stdin and stdout pipes are attached. */ + char* PipeFileSTDIN; + char* PipeFileSTDOUT; + char* PipeFileSTDERR; + + /* Whether each pipe is shared with the parent process. */ + int PipeSharedSTDIN; + int PipeSharedSTDOUT; + int PipeSharedSTDERR; + + /* Native pipes provided by the user. */ + int PipeNativeSTDIN[2]; + int PipeNativeSTDOUT[2]; + int PipeNativeSTDERR[2]; + + /* The real working directory of this process. */ + int RealWorkingDirectoryLength; + char* RealWorkingDirectory; +}; + +kwsysProcess* kwsysProcess_New(void) +{ + /* Allocate a process control structure. */ + kwsysProcess* cp = (kwsysProcess*)malloc(sizeof(kwsysProcess)); + if (!cp) { + return 0; + } + memset(cp, 0, sizeof(kwsysProcess)); + + /* Share stdin with the parent process by default. */ + cp->PipeSharedSTDIN = 1; + + /* No native pipes by default. */ + cp->PipeNativeSTDIN[0] = -1; + cp->PipeNativeSTDIN[1] = -1; + cp->PipeNativeSTDOUT[0] = -1; + cp->PipeNativeSTDOUT[1] = -1; + cp->PipeNativeSTDERR[0] = -1; + cp->PipeNativeSTDERR[1] = -1; + + /* Set initial status. */ + cp->State = kwsysProcess_State_Starting; + + return cp; +} + +void kwsysProcess_Delete(kwsysProcess* cp) +{ + /* Make sure we have an instance. */ + if (!cp) { + return; + } + + /* If the process is executing, wait for it to finish. */ + if (cp->State == kwsysProcess_State_Executing) { + if (cp->Detached) { + kwsysProcess_Disown(cp); + } else { + kwsysProcess_WaitForExit(cp, 0); + } + } + + /* Free memory. */ + kwsysProcess_SetCommand(cp, 0); + kwsysProcess_SetWorkingDirectory(cp, 0); + kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDIN, 0); + kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDOUT, 0); + kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDERR, 0); + free(cp->CommandExitCodes); + free(cp->ProcessResults); + free(cp); +} + +int kwsysProcess_SetCommand(kwsysProcess* cp, char const* const* command) +{ + int i; + if (!cp) { + return 0; + } + for (i = 0; i < cp->NumberOfCommands; ++i) { + char** c = cp->Commands[i]; + while (*c) { + free(*c++); + } + free(cp->Commands[i]); + } + cp->NumberOfCommands = 0; + if (cp->Commands) { + free(cp->Commands); + cp->Commands = 0; + } + if (command) { + return kwsysProcess_AddCommand(cp, command); + } + return 1; +} + +int kwsysProcess_AddCommand(kwsysProcess* cp, char const* const* command) +{ + int newNumberOfCommands; + char*** newCommands; + + /* Make sure we have a command to add. */ + if (!cp || !command || !*command) { + return 0; + } + + /* Allocate a new array for command pointers. */ + newNumberOfCommands = cp->NumberOfCommands + 1; + if (!(newCommands = + (char***)malloc(sizeof(char**) * (size_t)(newNumberOfCommands)))) { + /* Out of memory. */ + return 0; + } + + /* Copy any existing commands into the new array. */ + { + int i; + for (i = 0; i < cp->NumberOfCommands; ++i) { + newCommands[i] = cp->Commands[i]; + } + } + + /* Add the new command. */ + if (cp->Verbatim) { + /* In order to run the given command line verbatim we need to + parse it. */ + newCommands[cp->NumberOfCommands] = + kwsysSystem_Parse_CommandForUnix(*command, 0); + if (!newCommands[cp->NumberOfCommands] || + !newCommands[cp->NumberOfCommands][0]) { + /* Out of memory or no command parsed. */ + free(newCommands); + return 0; + } + } else { + /* Copy each argument string individually. */ + char const* const* c = command; + kwsysProcess_ptrdiff_t n = 0; + kwsysProcess_ptrdiff_t i = 0; + while (*c++) + ; + n = c - command - 1; + newCommands[cp->NumberOfCommands] = + (char**)malloc((size_t)(n + 1) * sizeof(char*)); + if (!newCommands[cp->NumberOfCommands]) { + /* Out of memory. */ + free(newCommands); + return 0; + } + for (i = 0; i < n; ++i) { + assert(command[i]); /* Quiet Clang scan-build. */ + newCommands[cp->NumberOfCommands][i] = strdup(command[i]); + if (!newCommands[cp->NumberOfCommands][i]) { + break; + } + } + if (i < n) { + /* Out of memory. */ + for (; i > 0; --i) { + free(newCommands[cp->NumberOfCommands][i - 1]); + } + free(newCommands); + return 0; + } + newCommands[cp->NumberOfCommands][n] = 0; + } + + /* Successfully allocated new command array. Free the old array. */ + free(cp->Commands); + cp->Commands = newCommands; + cp->NumberOfCommands = newNumberOfCommands; + + return 1; +} + +void kwsysProcess_SetTimeout(kwsysProcess* cp, double timeout) +{ + if (!cp) { + return; + } + cp->Timeout = timeout; + if (cp->Timeout < 0) { + cp->Timeout = 0; + } + // Force recomputation of TimeoutTime. + cp->TimeoutTime.tv_sec = -1; +} + +int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, const char* dir) +{ + if (!cp) { + return 0; + } + if (cp->WorkingDirectory == dir) { + return 1; + } + if (cp->WorkingDirectory && dir && strcmp(cp->WorkingDirectory, dir) == 0) { + return 1; + } + if (cp->WorkingDirectory) { + free(cp->WorkingDirectory); + cp->WorkingDirectory = 0; + } + if (dir) { + cp->WorkingDirectory = strdup(dir); + if (!cp->WorkingDirectory) { + return 0; + } + } + return 1; +} + +int kwsysProcess_SetPipeFile(kwsysProcess* cp, int prPipe, const char* file) +{ + char** pfile; + if (!cp) { + return 0; + } + switch (prPipe) { + case kwsysProcess_Pipe_STDIN: + pfile = &cp->PipeFileSTDIN; + break; + case kwsysProcess_Pipe_STDOUT: + pfile = &cp->PipeFileSTDOUT; + break; + case kwsysProcess_Pipe_STDERR: + pfile = &cp->PipeFileSTDERR; + break; + default: + return 0; + } + if (*pfile) { + free(*pfile); + *pfile = 0; + } + if (file) { + *pfile = strdup(file); + if (!*pfile) { + return 0; + } + } + + /* If we are redirecting the pipe, do not share it or use a native + pipe. */ + if (*pfile) { + kwsysProcess_SetPipeNative(cp, prPipe, 0); + kwsysProcess_SetPipeShared(cp, prPipe, 0); + } + return 1; +} + +void kwsysProcess_SetPipeShared(kwsysProcess* cp, int prPipe, int shared) +{ + if (!cp) { + return; + } + + switch (prPipe) { + case kwsysProcess_Pipe_STDIN: + cp->PipeSharedSTDIN = shared ? 1 : 0; + break; + case kwsysProcess_Pipe_STDOUT: + cp->PipeSharedSTDOUT = shared ? 1 : 0; + break; + case kwsysProcess_Pipe_STDERR: + cp->PipeSharedSTDERR = shared ? 1 : 0; + break; + default: + return; + } + + /* If we are sharing the pipe, do not redirect it to a file or use a + native pipe. */ + if (shared) { + kwsysProcess_SetPipeFile(cp, prPipe, 0); + kwsysProcess_SetPipeNative(cp, prPipe, 0); + } +} + +void kwsysProcess_SetPipeNative(kwsysProcess* cp, int prPipe, int p[2]) +{ + int* pPipeNative = 0; + + if (!cp) { + return; + } + + switch (prPipe) { + case kwsysProcess_Pipe_STDIN: + pPipeNative = cp->PipeNativeSTDIN; + break; + case kwsysProcess_Pipe_STDOUT: + pPipeNative = cp->PipeNativeSTDOUT; + break; + case kwsysProcess_Pipe_STDERR: + pPipeNative = cp->PipeNativeSTDERR; + break; + default: + return; + } + + /* Copy the native pipe descriptors provided. */ + if (p) { + pPipeNative[0] = p[0]; + pPipeNative[1] = p[1]; + } else { + pPipeNative[0] = -1; + pPipeNative[1] = -1; + } + + /* If we are using a native pipe, do not share it or redirect it to + a file. */ + if (p) { + kwsysProcess_SetPipeFile(cp, prPipe, 0); + kwsysProcess_SetPipeShared(cp, prPipe, 0); + } +} + +int kwsysProcess_GetOption(kwsysProcess* cp, int optionId) +{ + if (!cp) { + return 0; + } + + switch (optionId) { + case kwsysProcess_Option_Detach: + return cp->OptionDetach; + case kwsysProcess_Option_MergeOutput: + return cp->MergeOutput; + case kwsysProcess_Option_Verbatim: + return cp->Verbatim; + case kwsysProcess_Option_CreateProcessGroup: + return cp->CreateProcessGroup; + default: + return 0; + } +} + +void kwsysProcess_SetOption(kwsysProcess* cp, int optionId, int value) +{ + if (!cp) { + return; + } + + switch (optionId) { + case kwsysProcess_Option_Detach: + cp->OptionDetach = value; + break; + case kwsysProcess_Option_MergeOutput: + cp->MergeOutput = value; + break; + case kwsysProcess_Option_Verbatim: + cp->Verbatim = value; + break; + case kwsysProcess_Option_CreateProcessGroup: + cp->CreateProcessGroup = value; + break; + default: + break; + } +} + +int kwsysProcess_GetState(kwsysProcess* cp) +{ + return cp ? cp->State : kwsysProcess_State_Error; +} + +int kwsysProcess_GetExitException(kwsysProcess* cp) +{ + return (cp && cp->ProcessResults && (cp->NumberOfCommands > 0)) + ? cp->ProcessResults[cp->NumberOfCommands - 1].ExitException + : kwsysProcess_Exception_Other; +} + +int kwsysProcess_GetExitCode(kwsysProcess* cp) +{ + return (cp && cp->ProcessResults && (cp->NumberOfCommands > 0)) + ? cp->ProcessResults[cp->NumberOfCommands - 1].ExitCode + : 0; +} + +int kwsysProcess_GetExitValue(kwsysProcess* cp) +{ + return (cp && cp->ProcessResults && (cp->NumberOfCommands > 0)) + ? cp->ProcessResults[cp->NumberOfCommands - 1].ExitValue + : -1; +} + +const char* kwsysProcess_GetErrorString(kwsysProcess* cp) +{ + if (!cp) { + return "Process management structure could not be allocated"; + } else if (cp->State == kwsysProcess_State_Error) { + return cp->ErrorMessage; + } + return "Success"; +} + +const char* kwsysProcess_GetExceptionString(kwsysProcess* cp) +{ + if (!(cp && cp->ProcessResults && (cp->NumberOfCommands > 0))) { + return "GetExceptionString called with NULL process management structure"; + } else if (cp->State == kwsysProcess_State_Exception) { + return cp->ProcessResults[cp->NumberOfCommands - 1].ExitExceptionString; + } + return "No exception"; +} + +/* the index should be in array bound. */ +#define KWSYSPE_IDX_CHK(RET) \ + if (!cp || idx >= cp->NumberOfCommands || idx < 0) { \ + return RET; \ + } + +int kwsysProcess_GetStateByIndex(kwsysProcess* cp, int idx) +{ + KWSYSPE_IDX_CHK(kwsysProcess_State_Error) + return cp->ProcessResults[idx].State; +} + +int kwsysProcess_GetExitExceptionByIndex(kwsysProcess* cp, int idx) +{ + KWSYSPE_IDX_CHK(kwsysProcess_Exception_Other) + return cp->ProcessResults[idx].ExitException; +} + +int kwsysProcess_GetExitValueByIndex(kwsysProcess* cp, int idx) +{ + KWSYSPE_IDX_CHK(-1) + return cp->ProcessResults[idx].ExitValue; +} + +int kwsysProcess_GetExitCodeByIndex(kwsysProcess* cp, int idx) +{ + KWSYSPE_IDX_CHK(-1) + return cp->CommandExitCodes[idx]; +} + +const char* kwsysProcess_GetExceptionStringByIndex(kwsysProcess* cp, int idx) +{ + KWSYSPE_IDX_CHK("GetExceptionString called with NULL process management " + "structure or index out of bound") + if (cp->ProcessResults[idx].State == kwsysProcess_StateByIndex_Exception) { + return cp->ProcessResults[idx].ExitExceptionString; + } + return "No exception"; +} + +#undef KWSYSPE_IDX_CHK + +void kwsysProcess_Execute(kwsysProcess* cp) +{ + int i; + + /* Do not execute a second copy simultaneously. */ + if (!cp || cp->State == kwsysProcess_State_Executing) { + return; + } + + /* Make sure we have something to run. */ + if (cp->NumberOfCommands < 1) { + strcpy(cp->ErrorMessage, "No command"); + cp->State = kwsysProcess_State_Error; + return; + } + + /* Initialize the control structure for a new process. */ + if (!kwsysProcessInitialize(cp)) { + strcpy(cp->ErrorMessage, "Out of memory"); + cp->State = kwsysProcess_State_Error; + return; + } + +#if defined(__VMS) + /* Make sure pipes behave like streams on VMS. */ + if (!kwsysProcessSetVMSFeature("DECC$STREAM_PIPE", 1)) { + kwsysProcessCleanup(cp, 1); + return; + } +#endif + + /* Save the real working directory of this process and change to + the working directory for the child processes. This is needed + to make pipe file paths evaluate correctly. */ + if (cp->WorkingDirectory) { + int r; + if (!getcwd(cp->RealWorkingDirectory, + (size_t)(cp->RealWorkingDirectoryLength))) { + kwsysProcessCleanup(cp, 1); + return; + } + + /* Some platforms specify that the chdir call may be + interrupted. Repeat the call until it finishes. */ + while (((r = chdir(cp->WorkingDirectory)) < 0) && (errno == EINTR)) + ; + if (r < 0) { + kwsysProcessCleanup(cp, 1); + return; + } + } + + /* If not running a detached child, add this object to the global + set of process objects that wish to be notified when a child + exits. */ + if (!cp->OptionDetach) { + if (!kwsysProcessesAdd(cp)) { + kwsysProcessCleanup(cp, 1); + return; + } + } + + /* Setup the stdin pipe for the first process. */ + if (cp->PipeFileSTDIN) { + /* Open a file for the child's stdin to read. */ + cp->PipeChildStd[0] = open(cp->PipeFileSTDIN, O_RDONLY); + if (cp->PipeChildStd[0] < 0) { + kwsysProcessCleanup(cp, 1); + return; + } + + /* Set close-on-exec flag on the pipe's end. */ + if (fcntl(cp->PipeChildStd[0], F_SETFD, FD_CLOEXEC) < 0) { + kwsysProcessCleanup(cp, 1); + return; + } + } else if (cp->PipeSharedSTDIN) { + cp->PipeChildStd[0] = 0; + } else if (cp->PipeNativeSTDIN[0] >= 0) { + cp->PipeChildStd[0] = cp->PipeNativeSTDIN[0]; + + /* Set close-on-exec flag on the pipe's ends. The read end will + be dup2-ed into the stdin descriptor after the fork but before + the exec. */ + if ((fcntl(cp->PipeNativeSTDIN[0], F_SETFD, FD_CLOEXEC) < 0) || + (fcntl(cp->PipeNativeSTDIN[1], F_SETFD, FD_CLOEXEC) < 0)) { + kwsysProcessCleanup(cp, 1); + return; + } + } else { + cp->PipeChildStd[0] = -1; + } + + /* Create the output pipe for the last process. + We always create this so the pipe can be passed to select even if + it will report closed immediately. */ + { + /* Create the pipe. */ + int p[2]; + if (pipe(p KWSYSPE_VMS_NONBLOCK) < 0) { + kwsysProcessCleanup(cp, 1); + return; + } + + /* Store the pipe. */ + cp->PipeReadEnds[KWSYSPE_PIPE_STDOUT] = p[0]; + cp->PipeChildStd[1] = p[1]; + + /* Set close-on-exec flag on the pipe's ends. */ + if ((fcntl(p[0], F_SETFD, FD_CLOEXEC) < 0) || + (fcntl(p[1], F_SETFD, FD_CLOEXEC) < 0)) { + kwsysProcessCleanup(cp, 1); + return; + } + + /* Set to non-blocking in case select lies, or for the polling + implementation. */ + if (!kwsysProcessSetNonBlocking(p[0])) { + kwsysProcessCleanup(cp, 1); + return; + } + } + + if (cp->PipeFileSTDOUT) { + /* Use a file for stdout. */ + if (!kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[1], + cp->PipeFileSTDOUT)) { + kwsysProcessCleanup(cp, 1); + return; + } + } else if (cp->PipeSharedSTDOUT) { + /* Use the parent stdout. */ + kwsysProcessCleanupDescriptor(&cp->PipeChildStd[1]); + cp->PipeChildStd[1] = 1; + } else if (cp->PipeNativeSTDOUT[1] >= 0) { + /* Use the given descriptor for stdout. */ + if (!kwsysProcessSetupOutputPipeNative(&cp->PipeChildStd[1], + cp->PipeNativeSTDOUT)) { + kwsysProcessCleanup(cp, 1); + return; + } + } + + /* Create stderr pipe to be shared by all processes in the pipeline. + We always create this so the pipe can be passed to select even if + it will report closed immediately. */ + { + /* Create the pipe. */ + int p[2]; + if (pipe(p KWSYSPE_VMS_NONBLOCK) < 0) { + kwsysProcessCleanup(cp, 1); + return; + } + + /* Store the pipe. */ + cp->PipeReadEnds[KWSYSPE_PIPE_STDERR] = p[0]; + cp->PipeChildStd[2] = p[1]; + + /* Set close-on-exec flag on the pipe's ends. */ + if ((fcntl(p[0], F_SETFD, FD_CLOEXEC) < 0) || + (fcntl(p[1], F_SETFD, FD_CLOEXEC) < 0)) { + kwsysProcessCleanup(cp, 1); + return; + } + + /* Set to non-blocking in case select lies, or for the polling + implementation. */ + if (!kwsysProcessSetNonBlocking(p[0])) { + kwsysProcessCleanup(cp, 1); + return; + } + } + + if (cp->PipeFileSTDERR) { + /* Use a file for stderr. */ + if (!kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[2], + cp->PipeFileSTDERR)) { + kwsysProcessCleanup(cp, 1); + return; + } + } else if (cp->PipeSharedSTDERR) { + /* Use the parent stderr. */ + kwsysProcessCleanupDescriptor(&cp->PipeChildStd[2]); + cp->PipeChildStd[2] = 2; + } else if (cp->PipeNativeSTDERR[1] >= 0) { + /* Use the given handle for stderr. */ + if (!kwsysProcessSetupOutputPipeNative(&cp->PipeChildStd[2], + cp->PipeNativeSTDERR)) { + kwsysProcessCleanup(cp, 1); + return; + } + } + + /* The timeout period starts now. */ + cp->StartTime = kwsysProcessTimeGetCurrent(); + cp->TimeoutTime.tv_sec = -1; + cp->TimeoutTime.tv_usec = -1; + + /* Create the pipeline of processes. */ + { + kwsysProcessCreateInformation si = { -1, -1, -1, { -1, -1 } }; + int nextStdIn = cp->PipeChildStd[0]; + for (i = 0; i < cp->NumberOfCommands; ++i) { + /* Setup the process's pipes. */ + si.StdIn = nextStdIn; + if (i == cp->NumberOfCommands - 1) { + nextStdIn = -1; + si.StdOut = cp->PipeChildStd[1]; + } else { + /* Create a pipe to sit between the children. */ + int p[2] = { -1, -1 }; + if (pipe(p KWSYSPE_VMS_NONBLOCK) < 0) { + if (nextStdIn != cp->PipeChildStd[0]) { + kwsysProcessCleanupDescriptor(&nextStdIn); + } + kwsysProcessCleanup(cp, 1); + return; + } + + /* Set close-on-exec flag on the pipe's ends. */ + if ((fcntl(p[0], F_SETFD, FD_CLOEXEC) < 0) || + (fcntl(p[1], F_SETFD, FD_CLOEXEC) < 0)) { + close(p[0]); + close(p[1]); + if (nextStdIn != cp->PipeChildStd[0]) { + kwsysProcessCleanupDescriptor(&nextStdIn); + } + kwsysProcessCleanup(cp, 1); + return; + } + nextStdIn = p[0]; + si.StdOut = p[1]; + } + si.StdErr = cp->MergeOutput ? cp->PipeChildStd[1] : cp->PipeChildStd[2]; + + { + int res = kwsysProcessCreate(cp, i, &si); + + /* Close our copies of pipes used between children. */ + if (si.StdIn != cp->PipeChildStd[0]) { + kwsysProcessCleanupDescriptor(&si.StdIn); + } + if (si.StdOut != cp->PipeChildStd[1]) { + kwsysProcessCleanupDescriptor(&si.StdOut); + } + if (si.StdErr != cp->PipeChildStd[2] && !cp->MergeOutput) { + kwsysProcessCleanupDescriptor(&si.StdErr); + } + + if (!res) { + kwsysProcessCleanupDescriptor(&si.ErrorPipe[0]); + kwsysProcessCleanupDescriptor(&si.ErrorPipe[1]); + if (nextStdIn != cp->PipeChildStd[0]) { + kwsysProcessCleanupDescriptor(&nextStdIn); + } + kwsysProcessCleanup(cp, 1); + return; + } + } + } + } + + /* The parent process does not need the child's pipe ends. */ + for (i = 0; i < 3; ++i) { + kwsysProcessCleanupDescriptor(&cp->PipeChildStd[i]); + } + + /* Restore the working directory. */ + if (cp->RealWorkingDirectory) { + /* Some platforms specify that the chdir call may be + interrupted. Repeat the call until it finishes. */ + while ((chdir(cp->RealWorkingDirectory) < 0) && (errno == EINTR)) + ; + free(cp->RealWorkingDirectory); + cp->RealWorkingDirectory = 0; + } + + /* All the pipes are now open. */ + cp->PipesLeft = KWSYSPE_PIPE_COUNT; + + /* The process has now started. */ + cp->State = kwsysProcess_State_Executing; + cp->Detached = cp->OptionDetach; +} + +kwsysEXPORT void kwsysProcess_Disown(kwsysProcess* cp) +{ + /* Make sure a detached child process is running. */ + if (!cp || !cp->Detached || cp->State != kwsysProcess_State_Executing || + cp->TimeoutExpired || cp->Killed) { + return; + } + + /* Close all the pipes safely. */ + kwsysProcessClosePipes(cp); + + /* We will not wait for exit, so cleanup now. */ + kwsysProcessCleanup(cp, 0); + + /* The process has been disowned. */ + cp->State = kwsysProcess_State_Disowned; +} + +typedef struct kwsysProcessWaitData_s +{ + int Expired; + int PipeId; + int User; + double* UserTimeout; + kwsysProcessTime TimeoutTime; +} kwsysProcessWaitData; +static int kwsysProcessWaitForPipe(kwsysProcess* cp, char** data, int* length, + kwsysProcessWaitData* wd); + +int kwsysProcess_WaitForData(kwsysProcess* cp, char** data, int* length, + double* userTimeout) +{ + kwsysProcessTime userStartTime = { 0, 0 }; + kwsysProcessWaitData wd = { 0, kwsysProcess_Pipe_None, 0, 0, { 0, 0 } }; + wd.UserTimeout = userTimeout; + /* Make sure we are executing a process. */ + if (!cp || cp->State != kwsysProcess_State_Executing || cp->Killed || + cp->TimeoutExpired) { + return kwsysProcess_Pipe_None; + } + + /* Record the time at which user timeout period starts. */ + if (userTimeout) { + userStartTime = kwsysProcessTimeGetCurrent(); + } + + /* Calculate the time at which a timeout will expire, and whether it + is the user or process timeout. */ + wd.User = kwsysProcessGetTimeoutTime(cp, userTimeout, &wd.TimeoutTime); + + /* Data can only be available when pipes are open. If the process + is not running, cp->PipesLeft will be 0. */ + while (cp->PipesLeft > 0 && + !kwsysProcessWaitForPipe(cp, data, length, &wd)) { + } + + /* Update the user timeout. */ + if (userTimeout) { + kwsysProcessTime userEndTime = kwsysProcessTimeGetCurrent(); + kwsysProcessTime difference = + kwsysProcessTimeSubtract(userEndTime, userStartTime); + double d = kwsysProcessTimeToDouble(difference); + *userTimeout -= d; + if (*userTimeout < 0) { + *userTimeout = 0; + } + } + + /* Check what happened. */ + if (wd.PipeId) { + /* Data are ready on a pipe. */ + return wd.PipeId; + } else if (wd.Expired) { + /* A timeout has expired. */ + if (wd.User) { + /* The user timeout has expired. It has no time left. */ + return kwsysProcess_Pipe_Timeout; + } else { + /* The process timeout has expired. Kill the children now. */ + kwsysProcess_Kill(cp); + cp->Killed = 0; + cp->TimeoutExpired = 1; + return kwsysProcess_Pipe_None; + } + } else { + /* No pipes are left open. */ + return kwsysProcess_Pipe_None; + } +} + +static int kwsysProcessWaitForPipe(kwsysProcess* cp, char** data, int* length, + kwsysProcessWaitData* wd) +{ + int i; + kwsysProcessTimeNative timeoutLength; + +#if KWSYSPE_USE_SELECT + int numReady = 0; + int max = -1; + kwsysProcessTimeNative* timeout = 0; + + /* Check for any open pipes with data reported ready by the last + call to select. According to "man select_tut" we must deal + with all descriptors reported by a call to select before + passing them to another select call. */ + for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { + if (cp->PipeReadEnds[i] >= 0 && + FD_ISSET(cp->PipeReadEnds[i], &cp->PipeSet)) { + kwsysProcess_ssize_t n; + + /* We are handling this pipe now. Remove it from the set. */ + FD_CLR(cp->PipeReadEnds[i], &cp->PipeSet); + + /* The pipe is ready to read without blocking. Keep trying to + read until the operation is not interrupted. */ + while (((n = read(cp->PipeReadEnds[i], cp->PipeBuffer, + KWSYSPE_PIPE_BUFFER_SIZE)) < 0) && + (errno == EINTR)) + ; + if (n > 0) { + /* We have data on this pipe. */ + if (i == KWSYSPE_PIPE_SIGNAL) { + /* A child process has terminated. */ + kwsysProcessDestroy(cp); + } else if (data && length) { + /* Report this data. */ + *data = cp->PipeBuffer; + *length = (int)(n); + switch (i) { + case KWSYSPE_PIPE_STDOUT: + wd->PipeId = kwsysProcess_Pipe_STDOUT; + break; + case KWSYSPE_PIPE_STDERR: + wd->PipeId = kwsysProcess_Pipe_STDERR; + break; + } + return 1; + } + } else if (n < 0 && errno == EAGAIN) { + /* No data are really ready. The select call lied. See the + "man select" page on Linux for cases when this occurs. */ + } else { + /* We are done reading from this pipe. */ + kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]); + --cp->PipesLeft; + } + } + } + + /* If we have data, break early. */ + if (wd->PipeId) { + return 1; + } + + /* Make sure the set is empty (it should always be empty here + anyway). */ + FD_ZERO(&cp->PipeSet); + + /* Setup a timeout if required. */ + if (wd->TimeoutTime.tv_sec < 0) { + timeout = 0; + } else { + timeout = &timeoutLength; + } + if (kwsysProcessGetTimeoutLeft( + &wd->TimeoutTime, wd->User ? wd->UserTimeout : 0, &timeoutLength, 0)) { + /* Timeout has already expired. */ + wd->Expired = 1; + return 1; + } + + /* Add the pipe reading ends that are still open. */ + max = -1; + for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { + if (cp->PipeReadEnds[i] >= 0) { + FD_SET(cp->PipeReadEnds[i], &cp->PipeSet); + if (cp->PipeReadEnds[i] > max) { + max = cp->PipeReadEnds[i]; + } + } + } + + /* Make sure we have a non-empty set. */ + if (max < 0) { + /* All pipes have closed. Child has terminated. */ + return 1; + } + + /* Run select to block until data are available. Repeat call + until it is not interrupted. */ + while (((numReady = select(max + 1, &cp->PipeSet, 0, 0, timeout)) < 0) && + (errno == EINTR)) + ; + + /* Check result of select. */ + if (numReady == 0) { + /* Select's timeout expired. */ + wd->Expired = 1; + return 1; + } else if (numReady < 0) { + /* Select returned an error. Leave the error description in the + pipe buffer. */ + strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE); + + /* Kill the children now. */ + kwsysProcess_Kill(cp); + cp->Killed = 0; + cp->SelectError = 1; + } + + return 0; +#else + /* Poll pipes for data since we do not have select. */ + for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { + if (cp->PipeReadEnds[i] >= 0) { + const int fd = cp->PipeReadEnds[i]; + int n = read(fd, cp->PipeBuffer, KWSYSPE_PIPE_BUFFER_SIZE); + if (n > 0) { + /* We have data on this pipe. */ + if (i == KWSYSPE_PIPE_SIGNAL) { + /* A child process has terminated. */ + kwsysProcessDestroy(cp); + } else if (data && length) { + /* Report this data. */ + *data = cp->PipeBuffer; + *length = n; + switch (i) { + case KWSYSPE_PIPE_STDOUT: + wd->PipeId = kwsysProcess_Pipe_STDOUT; + break; + case KWSYSPE_PIPE_STDERR: + wd->PipeId = kwsysProcess_Pipe_STDERR; + break; + }; + } + return 1; + } else if (n == 0) /* EOF */ + { +/* We are done reading from this pipe. */ +# if defined(__VMS) + if (!cp->CommandsLeft) +# endif + { + kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]); + --cp->PipesLeft; + } + } else if (n < 0) /* error */ + { +# if defined(__VMS) + if (!cp->CommandsLeft) { + kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]); + --cp->PipesLeft; + } else +# endif + if ((errno != EINTR) && (errno != EAGAIN)) { + strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE); + /* Kill the children now. */ + kwsysProcess_Kill(cp); + cp->Killed = 0; + cp->SelectError = 1; + return 1; + } + } + } + } + + /* If we have data, break early. */ + if (wd->PipeId) { + return 1; + } + + if (kwsysProcessGetTimeoutLeft( + &wd->TimeoutTime, wd->User ? wd->UserTimeout : 0, &timeoutLength, 1)) { + /* Timeout has already expired. */ + wd->Expired = 1; + return 1; + } + + /* Sleep a little, try again. */ + { + unsigned int msec = + ((timeoutLength.tv_sec * 1000) + (timeoutLength.tv_usec / 1000)); + if (msec > 100000) { + msec = 100000; /* do not sleep more than 100 milliseconds at a time */ + } + kwsysProcess_usleep(msec); + } + return 0; +#endif +} + +int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout) +{ + int prPipe = 0; + + /* Make sure we are executing a process. */ + if (!cp || cp->State != kwsysProcess_State_Executing) { + return 1; + } + + /* Wait for all the pipes to close. Ignore all data. */ + while ((prPipe = kwsysProcess_WaitForData(cp, 0, 0, userTimeout)) > 0) { + if (prPipe == kwsysProcess_Pipe_Timeout) { + return 0; + } + } + + /* Check if there was an error in one of the waitpid calls. */ + if (cp->State == kwsysProcess_State_Error) { + /* The error message is already in its buffer. Tell + kwsysProcessCleanup to not create it. */ + kwsysProcessCleanup(cp, 0); + return 1; + } + + /* Check whether the child reported an error invoking the process. */ + if (cp->SelectError) { + /* The error message is already in its buffer. Tell + kwsysProcessCleanup to not create it. */ + kwsysProcessCleanup(cp, 0); + cp->State = kwsysProcess_State_Error; + return 1; + } + /* Determine the outcome. */ + if (cp->Killed) { + /* We killed the child. */ + cp->State = kwsysProcess_State_Killed; + } else if (cp->TimeoutExpired) { + /* The timeout expired. */ + cp->State = kwsysProcess_State_Expired; + } else { + /* The children exited. Report the outcome of the child processes. */ + for (prPipe = 0; prPipe < cp->NumberOfCommands; ++prPipe) { + cp->ProcessResults[prPipe].ExitCode = cp->CommandExitCodes[prPipe]; + if (WIFEXITED(cp->ProcessResults[prPipe].ExitCode)) { + /* The child exited normally. */ + cp->ProcessResults[prPipe].State = kwsysProcess_StateByIndex_Exited; + cp->ProcessResults[prPipe].ExitException = kwsysProcess_Exception_None; + cp->ProcessResults[prPipe].ExitValue = + (int)WEXITSTATUS(cp->ProcessResults[prPipe].ExitCode); + } else if (WIFSIGNALED(cp->ProcessResults[prPipe].ExitCode)) { + /* The child received an unhandled signal. */ + cp->ProcessResults[prPipe].State = kwsysProcess_State_Exception; + kwsysProcessSetExitExceptionByIndex( + cp, (int)WTERMSIG(cp->ProcessResults[prPipe].ExitCode), prPipe); + } else { + /* Error getting the child return code. */ + strcpy(cp->ProcessResults[prPipe].ExitExceptionString, + "Error getting child return code."); + cp->ProcessResults[prPipe].State = kwsysProcess_StateByIndex_Error; + } + } + /* support legacy state status value */ + cp->State = cp->ProcessResults[cp->NumberOfCommands - 1].State; + } + /* Normal cleanup. */ + kwsysProcessCleanup(cp, 0); + return 1; +} + +void kwsysProcess_Interrupt(kwsysProcess* cp) +{ + int i; + /* Make sure we are executing a process. */ + if (!cp || cp->State != kwsysProcess_State_Executing || cp->TimeoutExpired || + cp->Killed) { + return; + } + + /* Interrupt the children. */ + if (cp->CreateProcessGroup) { + if (cp->ForkPIDs) { + for (i = 0; i < cp->NumberOfCommands; ++i) { + /* Make sure the PID is still valid. */ + if (cp->ForkPIDs[i]) { + /* The user created a process group for this process. The group ID + is the process ID for the original process in the group. */ + kill(-cp->ForkPIDs[i], SIGINT); + } + } + } + } else { + /* No process group was created. Kill our own process group. + NOTE: While one could argue that we could call kill(cp->ForkPIDs[i], + SIGINT) as a way to still interrupt the process even though it's not in + a special group, this is not an option on Windows. Therefore, we kill + the current process group for consistency with Windows. */ + kill(0, SIGINT); + } +} + +void kwsysProcess_Kill(kwsysProcess* cp) +{ + int i; + + /* Make sure we are executing a process. */ + if (!cp || cp->State != kwsysProcess_State_Executing) { + return; + } + + /* First close the child exit report pipe write end to avoid causing a + SIGPIPE when the child terminates and our signal handler tries to + report it after we have already closed the read end. */ + kwsysProcessCleanupDescriptor(&cp->SignalPipe); + +#if !defined(__APPLE__) + /* Close all the pipe read ends. Do this before killing the + children because Cygwin has problems killing processes that are + blocking to wait for writing to their output pipes. */ + kwsysProcessClosePipes(cp); +#endif + + /* Kill the children. */ + cp->Killed = 1; + for (i = 0; i < cp->NumberOfCommands; ++i) { + int status; + if (cp->ForkPIDs[i]) { + /* Kill the child. */ + kwsysProcessKill(cp->ForkPIDs[i]); + + /* Reap the child. Keep trying until the call is not + interrupted. */ + while ((waitpid(cp->ForkPIDs[i], &status, 0) < 0) && (errno == EINTR)) + ; + } + } + +#if defined(__APPLE__) + /* Close all the pipe read ends. Do this after killing the + children because OS X has problems closing pipe read ends whose + pipes are full and still have an open write end. */ + kwsysProcessClosePipes(cp); +#endif + + cp->CommandsLeft = 0; +} + +/* Call the free() function with a pointer to volatile without causing + compiler warnings. */ +static void kwsysProcessVolatileFree(volatile void* p) +{ +/* clang has made it impossible to free memory that points to volatile + without first using special pragmas to disable a warning... */ +#if defined(__clang__) && !defined(__INTEL_COMPILER) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wcast-qual" +#endif + free((void*)p); /* The cast will silence most compilers, but not clang. */ +#if defined(__clang__) && !defined(__INTEL_COMPILER) +# pragma clang diagnostic pop +#endif +} + +/* Initialize a process control structure for kwsysProcess_Execute. */ +static int kwsysProcessInitialize(kwsysProcess* cp) +{ + int i; + volatile pid_t* oldForkPIDs; + for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { + cp->PipeReadEnds[i] = -1; + } + for (i = 0; i < 3; ++i) { + cp->PipeChildStd[i] = -1; + } + cp->SignalPipe = -1; + cp->SelectError = 0; + cp->StartTime.tv_sec = -1; + cp->StartTime.tv_usec = -1; + cp->TimeoutTime.tv_sec = -1; + cp->TimeoutTime.tv_usec = -1; + cp->TimeoutExpired = 0; + cp->PipesLeft = 0; + cp->CommandsLeft = 0; +#if KWSYSPE_USE_SELECT + FD_ZERO(&cp->PipeSet); +#endif + cp->State = kwsysProcess_State_Starting; + cp->Killed = 0; + cp->ErrorMessage[0] = 0; + + oldForkPIDs = cp->ForkPIDs; + cp->ForkPIDs = (volatile pid_t*)malloc(sizeof(volatile pid_t) * + (size_t)(cp->NumberOfCommands)); + kwsysProcessVolatileFree(oldForkPIDs); + if (!cp->ForkPIDs) { + return 0; + } + for (i = 0; i < cp->NumberOfCommands; ++i) { + cp->ForkPIDs[i] = 0; /* can't use memset due to volatile */ + } + + free(cp->CommandExitCodes); + cp->CommandExitCodes = + (int*)malloc(sizeof(int) * (size_t)(cp->NumberOfCommands)); + if (!cp->CommandExitCodes) { + return 0; + } + memset(cp->CommandExitCodes, 0, + sizeof(int) * (size_t)(cp->NumberOfCommands)); + + /* Allocate process result information for each process. */ + free(cp->ProcessResults); + cp->ProcessResults = (kwsysProcessResults*)malloc( + sizeof(kwsysProcessResults) * (size_t)(cp->NumberOfCommands)); + if (!cp->ProcessResults) { + return 0; + } + memset(cp->ProcessResults, 0, + sizeof(kwsysProcessResults) * (size_t)(cp->NumberOfCommands)); + for (i = 0; i < cp->NumberOfCommands; i++) { + cp->ProcessResults[i].ExitException = kwsysProcess_Exception_None; + cp->ProcessResults[i].State = kwsysProcess_StateByIndex_Starting; + cp->ProcessResults[i].ExitCode = 1; + cp->ProcessResults[i].ExitValue = 1; + strcpy(cp->ProcessResults[i].ExitExceptionString, "No exception"); + } + + /* Allocate memory to save the real working directory. */ + if (cp->WorkingDirectory) { +#if defined(MAXPATHLEN) + cp->RealWorkingDirectoryLength = MAXPATHLEN; +#elif defined(PATH_MAX) + cp->RealWorkingDirectoryLength = PATH_MAX; +#else + cp->RealWorkingDirectoryLength = 4096; +#endif + cp->RealWorkingDirectory = + (char*)malloc((size_t)(cp->RealWorkingDirectoryLength)); + if (!cp->RealWorkingDirectory) { + return 0; + } + } + + return 1; +} + +/* Free all resources used by the given kwsysProcess instance that were + allocated by kwsysProcess_Execute. */ +static void kwsysProcessCleanup(kwsysProcess* cp, int error) +{ + int i; + + if (error) { + /* We are cleaning up due to an error. Report the error message + if one has not been provided already. */ + if (cp->ErrorMessage[0] == 0) { + strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE); + } + + /* Set the error state. */ + cp->State = kwsysProcess_State_Error; + + /* Kill any children already started. */ + if (cp->ForkPIDs) { + int status; + for (i = 0; i < cp->NumberOfCommands; ++i) { + if (cp->ForkPIDs[i]) { + /* Kill the child. */ + kwsysProcessKill(cp->ForkPIDs[i]); + + /* Reap the child. Keep trying until the call is not + interrupted. */ + while ((waitpid(cp->ForkPIDs[i], &status, 0) < 0) && + (errno == EINTR)) + ; + } + } + } + + /* Restore the working directory. */ + if (cp->RealWorkingDirectory) { + while ((chdir(cp->RealWorkingDirectory) < 0) && (errno == EINTR)) + ; + } + } + + /* If not creating a detached child, remove this object from the + global set of process objects that wish to be notified when a + child exits. */ + if (!cp->OptionDetach) { + kwsysProcessesRemove(cp); + } + + /* Free memory. */ + if (cp->ForkPIDs) { + kwsysProcessVolatileFree(cp->ForkPIDs); + cp->ForkPIDs = 0; + } + if (cp->RealWorkingDirectory) { + free(cp->RealWorkingDirectory); + cp->RealWorkingDirectory = 0; + } + + /* Close pipe handles. */ + for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { + kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]); + } + for (i = 0; i < 3; ++i) { + kwsysProcessCleanupDescriptor(&cp->PipeChildStd[i]); + } +} + +/* Close the given file descriptor if it is open. Reset its value to -1. */ +static void kwsysProcessCleanupDescriptor(int* pfd) +{ + if (pfd && *pfd > 2) { + /* Keep trying to close until it is not interrupted by a + * signal. */ + while ((close(*pfd) < 0) && (errno == EINTR)) + ; + *pfd = -1; + } +} + +static void kwsysProcessClosePipes(kwsysProcess* cp) +{ + int i; + + /* Close any pipes that are still open. */ + for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { + if (cp->PipeReadEnds[i] >= 0) { +#if KWSYSPE_USE_SELECT + /* If the pipe was reported by the last call to select, we must + read from it. This is needed to satisfy the suggestions from + "man select_tut" and is not needed for the polling + implementation. Ignore the data. */ + if (FD_ISSET(cp->PipeReadEnds[i], &cp->PipeSet)) { + /* We are handling this pipe now. Remove it from the set. */ + FD_CLR(cp->PipeReadEnds[i], &cp->PipeSet); + + /* The pipe is ready to read without blocking. Keep trying to + read until the operation is not interrupted. */ + while ((read(cp->PipeReadEnds[i], cp->PipeBuffer, + KWSYSPE_PIPE_BUFFER_SIZE) < 0) && + (errno == EINTR)) + ; + } +#endif + + /* We are done reading from this pipe. */ + kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]); + --cp->PipesLeft; + } + } +} + +static int kwsysProcessSetNonBlocking(int fd) +{ + int flags = fcntl(fd, F_GETFL); + if (flags >= 0) { + flags = fcntl(fd, F_SETFL, flags | O_NONBLOCK); + } + return flags >= 0; +} + +#if defined(__VMS) +int decc$set_child_standard_streams(int fd1, int fd2, int fd3); +#endif + +static int kwsysProcessCreate(kwsysProcess* cp, int prIndex, + kwsysProcessCreateInformation* si) +{ + sigset_t mask, old_mask; + int pgidPipe[2]; + char tmp; + ssize_t readRes; + + /* Create the error reporting pipe. */ + if (pipe(si->ErrorPipe) < 0) { + return 0; + } + + /* Create a pipe for detecting that the child process has created a process + group and session. */ + if (pipe(pgidPipe) < 0) { + kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]); + kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]); + return 0; + } + + /* Set close-on-exec flag on the pipe's write end. */ + if (fcntl(si->ErrorPipe[1], F_SETFD, FD_CLOEXEC) < 0 || + fcntl(pgidPipe[1], F_SETFD, FD_CLOEXEC) < 0) { + kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]); + kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]); + kwsysProcessCleanupDescriptor(&pgidPipe[0]); + kwsysProcessCleanupDescriptor(&pgidPipe[1]); + return 0; + } + + /* Block SIGINT / SIGTERM while we start. The purpose is so that our signal + handler doesn't get called from the child process after the fork and + before the exec, and subsequently start kill()'ing PIDs from ForkPIDs. */ + sigemptyset(&mask); + sigaddset(&mask, SIGINT); + sigaddset(&mask, SIGTERM); + if (sigprocmask(SIG_BLOCK, &mask, &old_mask) < 0) { + kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]); + kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]); + kwsysProcessCleanupDescriptor(&pgidPipe[0]); + kwsysProcessCleanupDescriptor(&pgidPipe[1]); + return 0; + } + +/* Fork off a child process. */ +#if defined(__VMS) + /* VMS needs vfork and execvp to be in the same function because + they use setjmp/longjmp to run the child startup code in the + parent! TODO: OptionDetach. Also + TODO: CreateProcessGroup. */ + cp->ForkPIDs[prIndex] = vfork(); +#else + cp->ForkPIDs[prIndex] = kwsysProcessFork(cp, si); +#endif + if (cp->ForkPIDs[prIndex] < 0) { + sigprocmask(SIG_SETMASK, &old_mask, 0); + kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]); + kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]); + kwsysProcessCleanupDescriptor(&pgidPipe[0]); + kwsysProcessCleanupDescriptor(&pgidPipe[1]); + return 0; + } + + if (cp->ForkPIDs[prIndex] == 0) { +#if defined(__VMS) + /* Specify standard pipes for child process. */ + decc$set_child_standard_streams(si->StdIn, si->StdOut, si->StdErr); +#else + /* Close the read end of the error reporting / process group + setup pipe. */ + close(si->ErrorPipe[0]); + close(pgidPipe[0]); + + /* Setup the stdin, stdout, and stderr pipes. */ + if (si->StdIn > 0) { + dup2(si->StdIn, 0); + } else if (si->StdIn < 0) { + close(0); + } + if (si->StdOut != 1) { + dup2(si->StdOut, 1); + } + if (si->StdErr != 2) { + dup2(si->StdErr, 2); + } + + /* Clear the close-on-exec flag for stdin, stdout, and stderr. + All other pipe handles will be closed when exec succeeds. */ + fcntl(0, F_SETFD, 0); + fcntl(1, F_SETFD, 0); + fcntl(2, F_SETFD, 0); + + /* Restore all default signal handlers. */ + kwsysProcessRestoreDefaultSignalHandlers(); + + /* Now that we have restored default signal handling and created the + process group, restore mask. */ + sigprocmask(SIG_SETMASK, &old_mask, 0); + + /* Create new process group. We use setsid instead of setpgid to avoid + the child getting hung up on signals like SIGTTOU. (In the real world, + this has been observed where "git svn" ends up calling the "resize" + program which opens /dev/tty. */ + if (cp->CreateProcessGroup && setsid() < 0) { + kwsysProcessChildErrorExit(si->ErrorPipe[1]); + } +#endif + + /* Execute the real process. If successful, this does not return. */ + execvp(cp->Commands[prIndex][0], cp->Commands[prIndex]); + /* TODO: What does VMS do if the child fails to start? */ + /* TODO: On VMS, how do we put the process in a new group? */ + + /* Failure. Report error to parent and terminate. */ + kwsysProcessChildErrorExit(si->ErrorPipe[1]); + } + +#if defined(__VMS) + /* Restore the standard pipes of this process. */ + decc$set_child_standard_streams(0, 1, 2); +#endif + + /* We are done with the error reporting pipe and process group setup pipe + write end. */ + kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]); + kwsysProcessCleanupDescriptor(&pgidPipe[1]); + + /* Make sure the child is in the process group before we proceed. This + avoids race conditions with calls to the kill function that we make for + signalling process groups. */ + while ((readRes = read(pgidPipe[0], &tmp, 1)) > 0) + ; + if (readRes < 0) { + sigprocmask(SIG_SETMASK, &old_mask, 0); + kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]); + kwsysProcessCleanupDescriptor(&pgidPipe[0]); + return 0; + } + kwsysProcessCleanupDescriptor(&pgidPipe[0]); + + /* Unmask signals. */ + if (sigprocmask(SIG_SETMASK, &old_mask, 0) < 0) { + kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]); + return 0; + } + + /* A child has been created. */ + ++cp->CommandsLeft; + + /* Block until the child's exec call succeeds and closes the error + pipe or writes data to the pipe to report an error. */ + { + kwsysProcess_ssize_t total = 0; + kwsysProcess_ssize_t n = 1; + /* Read the entire error message up to the length of our buffer. */ + while (total < KWSYSPE_PIPE_BUFFER_SIZE && n > 0) { + /* Keep trying to read until the operation is not interrupted. */ + while (((n = read(si->ErrorPipe[0], cp->ErrorMessage + total, + (size_t)(KWSYSPE_PIPE_BUFFER_SIZE - total))) < 0) && + (errno == EINTR)) + ; + if (n > 0) { + total += n; + } + } + + /* We are done with the error reporting pipe read end. */ + kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]); + + if (total > 0) { + /* The child failed to execute the process. */ + return 0; + } + } + + return 1; +} + +static void kwsysProcessDestroy(kwsysProcess* cp) +{ + /* A child process has terminated. Reap it if it is one handled by + this object. */ + int i; + /* Temporarily disable signals that access ForkPIDs. We don't want them to + read a reaped PID, and writes to ForkPIDs are not atomic. */ + sigset_t mask, old_mask; + sigemptyset(&mask); + sigaddset(&mask, SIGINT); + sigaddset(&mask, SIGTERM); + if (sigprocmask(SIG_BLOCK, &mask, &old_mask) < 0) { + return; + } + + for (i = 0; i < cp->NumberOfCommands; ++i) { + if (cp->ForkPIDs[i]) { + int result; + while (((result = waitpid(cp->ForkPIDs[i], &cp->CommandExitCodes[i], + WNOHANG)) < 0) && + (errno == EINTR)) + ; + if (result > 0) { + /* This child has terminated. */ + cp->ForkPIDs[i] = 0; + if (--cp->CommandsLeft == 0) { + /* All children have terminated. Close the signal pipe + write end so that no more notifications are sent to this + object. */ + kwsysProcessCleanupDescriptor(&cp->SignalPipe); + + /* TODO: Once the children have terminated, switch + WaitForData to use a non-blocking read to get the + rest of the data from the pipe. This is needed when + grandchildren keep the output pipes open. */ + } + } else if (result < 0 && cp->State != kwsysProcess_State_Error) { + /* Unexpected error. Report the first time this happens. */ + strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE); + cp->State = kwsysProcess_State_Error; + } + } + } + + /* Re-enable signals. */ + sigprocmask(SIG_SETMASK, &old_mask, 0); +} + +static int kwsysProcessSetupOutputPipeFile(int* p, const char* name) +{ + int fout; + if (!name) { + return 1; + } + + /* Close the existing descriptor. */ + kwsysProcessCleanupDescriptor(p); + + /* Open a file for the pipe to write. */ + if ((fout = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) { + return 0; + } + + /* Set close-on-exec flag on the pipe's end. */ + if (fcntl(fout, F_SETFD, FD_CLOEXEC) < 0) { + close(fout); + return 0; + } + + /* Assign the replacement descriptor. */ + *p = fout; + return 1; +} + +static int kwsysProcessSetupOutputPipeNative(int* p, int des[2]) +{ + /* Close the existing descriptor. */ + kwsysProcessCleanupDescriptor(p); + + /* Set close-on-exec flag on the pipe's ends. The proper end will + be dup2-ed into the standard descriptor number after fork but + before exec. */ + if ((fcntl(des[0], F_SETFD, FD_CLOEXEC) < 0) || + (fcntl(des[1], F_SETFD, FD_CLOEXEC) < 0)) { + return 0; + } + + /* Assign the replacement descriptor. */ + *p = des[1]; + return 1; +} + +/* Get the time at which either the process or user timeout will + expire. Returns 1 if the user timeout is first, and 0 otherwise. */ +static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout, + kwsysProcessTime* timeoutTime) +{ + /* The first time this is called, we need to calculate the time at + which the child will timeout. */ + if (cp->Timeout > 0 && cp->TimeoutTime.tv_sec < 0) { + kwsysProcessTime length = kwsysProcessTimeFromDouble(cp->Timeout); + cp->TimeoutTime = kwsysProcessTimeAdd(cp->StartTime, length); + } + + /* Start with process timeout. */ + *timeoutTime = cp->TimeoutTime; + + /* Check if the user timeout is earlier. */ + if (userTimeout) { + kwsysProcessTime currentTime = kwsysProcessTimeGetCurrent(); + kwsysProcessTime userTimeoutLength = + kwsysProcessTimeFromDouble(*userTimeout); + kwsysProcessTime userTimeoutTime = + kwsysProcessTimeAdd(currentTime, userTimeoutLength); + if (timeoutTime->tv_sec < 0 || + kwsysProcessTimeLess(userTimeoutTime, *timeoutTime)) { + *timeoutTime = userTimeoutTime; + return 1; + } + } + return 0; +} + +/* Get the length of time before the given timeout time arrives. + Returns 1 if the time has already arrived, and 0 otherwise. */ +static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime, + double* userTimeout, + kwsysProcessTimeNative* timeoutLength, + int zeroIsExpired) +{ + if (timeoutTime->tv_sec < 0) { + /* No timeout time has been requested. */ + return 0; + } else { + /* Calculate the remaining time. */ + kwsysProcessTime currentTime = kwsysProcessTimeGetCurrent(); + kwsysProcessTime timeLeft = + kwsysProcessTimeSubtract(*timeoutTime, currentTime); + if (timeLeft.tv_sec < 0 && userTimeout && *userTimeout <= 0) { + /* Caller has explicitly requested a zero timeout. */ + timeLeft.tv_sec = 0; + timeLeft.tv_usec = 0; + } + + if (timeLeft.tv_sec < 0 || + (timeLeft.tv_sec == 0 && timeLeft.tv_usec == 0 && zeroIsExpired)) { + /* Timeout has already expired. */ + return 1; + } else { + /* There is some time left. */ + timeoutLength->tv_sec = timeLeft.tv_sec; + timeoutLength->tv_usec = timeLeft.tv_usec; + return 0; + } + } +} + +static kwsysProcessTime kwsysProcessTimeGetCurrent(void) +{ + kwsysProcessTime current; + kwsysProcessTimeNative current_native; +#if KWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC + struct timespec current_timespec; + clock_gettime(CLOCK_MONOTONIC, ¤t_timespec); + + current_native.tv_sec = current_timespec.tv_sec; + current_native.tv_usec = current_timespec.tv_nsec / 1000; +#else + gettimeofday(¤t_native, 0); +#endif + current.tv_sec = (long)current_native.tv_sec; + current.tv_usec = (long)current_native.tv_usec; + return current; +} + +static double kwsysProcessTimeToDouble(kwsysProcessTime t) +{ + return (double)t.tv_sec + (double)(t.tv_usec) * 0.000001; +} + +static kwsysProcessTime kwsysProcessTimeFromDouble(double d) +{ + kwsysProcessTime t; + t.tv_sec = (long)d; + t.tv_usec = (long)((d - (double)(t.tv_sec)) * 1000000); + return t; +} + +static int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2) +{ + return ((in1.tv_sec < in2.tv_sec) || + ((in1.tv_sec == in2.tv_sec) && (in1.tv_usec < in2.tv_usec))); +} + +static kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1, + kwsysProcessTime in2) +{ + kwsysProcessTime out; + out.tv_sec = in1.tv_sec + in2.tv_sec; + out.tv_usec = in1.tv_usec + in2.tv_usec; + if (out.tv_usec >= 1000000) { + out.tv_usec -= 1000000; + out.tv_sec += 1; + } + return out; +} + +static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, + kwsysProcessTime in2) +{ + kwsysProcessTime out; + out.tv_sec = in1.tv_sec - in2.tv_sec; + out.tv_usec = in1.tv_usec - in2.tv_usec; + if (out.tv_usec < 0) { + out.tv_usec += 1000000; + out.tv_sec -= 1; + } + return out; +} + +#define KWSYSPE_CASE(type, str) \ + cp->ProcessResults[idx].ExitException = kwsysProcess_Exception_##type; \ + strcpy(cp->ProcessResults[idx].ExitExceptionString, str) +static void kwsysProcessSetExitExceptionByIndex(kwsysProcess* cp, int sig, + int idx) +{ + switch (sig) { +#ifdef SIGSEGV + case SIGSEGV: + KWSYSPE_CASE(Fault, "Segmentation fault"); + break; +#endif +#ifdef SIGBUS +# if !defined(SIGSEGV) || SIGBUS != SIGSEGV + case SIGBUS: + KWSYSPE_CASE(Fault, "Bus error"); + break; +# endif +#endif +#ifdef SIGFPE + case SIGFPE: + KWSYSPE_CASE(Numerical, "Floating-point exception"); + break; +#endif +#ifdef SIGILL + case SIGILL: + KWSYSPE_CASE(Illegal, "Illegal instruction"); + break; +#endif +#ifdef SIGINT + case SIGINT: + KWSYSPE_CASE(Interrupt, "User interrupt"); + break; +#endif +#ifdef SIGABRT + case SIGABRT: + KWSYSPE_CASE(Other, "Child aborted"); + break; +#endif +#ifdef SIGKILL + case SIGKILL: + KWSYSPE_CASE(Other, "Child killed"); + break; +#endif +#ifdef SIGTERM + case SIGTERM: + KWSYSPE_CASE(Other, "Child terminated"); + break; +#endif +#ifdef SIGHUP + case SIGHUP: + KWSYSPE_CASE(Other, "SIGHUP"); + break; +#endif +#ifdef SIGQUIT + case SIGQUIT: + KWSYSPE_CASE(Other, "SIGQUIT"); + break; +#endif +#ifdef SIGTRAP + case SIGTRAP: + KWSYSPE_CASE(Other, "SIGTRAP"); + break; +#endif +#ifdef SIGIOT +# if !defined(SIGABRT) || SIGIOT != SIGABRT + case SIGIOT: + KWSYSPE_CASE(Other, "SIGIOT"); + break; +# endif +#endif +#ifdef SIGUSR1 + case SIGUSR1: + KWSYSPE_CASE(Other, "SIGUSR1"); + break; +#endif +#ifdef SIGUSR2 + case SIGUSR2: + KWSYSPE_CASE(Other, "SIGUSR2"); + break; +#endif +#ifdef SIGPIPE + case SIGPIPE: + KWSYSPE_CASE(Other, "SIGPIPE"); + break; +#endif +#ifdef SIGALRM + case SIGALRM: + KWSYSPE_CASE(Other, "SIGALRM"); + break; +#endif +#ifdef SIGSTKFLT + case SIGSTKFLT: + KWSYSPE_CASE(Other, "SIGSTKFLT"); + break; +#endif +#ifdef SIGCHLD + case SIGCHLD: + KWSYSPE_CASE(Other, "SIGCHLD"); + break; +#elif defined(SIGCLD) + case SIGCLD: + KWSYSPE_CASE(Other, "SIGCLD"); + break; +#endif +#ifdef SIGCONT + case SIGCONT: + KWSYSPE_CASE(Other, "SIGCONT"); + break; +#endif +#ifdef SIGSTOP + case SIGSTOP: + KWSYSPE_CASE(Other, "SIGSTOP"); + break; +#endif +#ifdef SIGTSTP + case SIGTSTP: + KWSYSPE_CASE(Other, "SIGTSTP"); + break; +#endif +#ifdef SIGTTIN + case SIGTTIN: + KWSYSPE_CASE(Other, "SIGTTIN"); + break; +#endif +#ifdef SIGTTOU + case SIGTTOU: + KWSYSPE_CASE(Other, "SIGTTOU"); + break; +#endif +#ifdef SIGURG + case SIGURG: + KWSYSPE_CASE(Other, "SIGURG"); + break; +#endif +#ifdef SIGXCPU + case SIGXCPU: + KWSYSPE_CASE(Other, "SIGXCPU"); + break; +#endif +#ifdef SIGXFSZ + case SIGXFSZ: + KWSYSPE_CASE(Other, "SIGXFSZ"); + break; +#endif +#ifdef SIGVTALRM + case SIGVTALRM: + KWSYSPE_CASE(Other, "SIGVTALRM"); + break; +#endif +#ifdef SIGPROF + case SIGPROF: + KWSYSPE_CASE(Other, "SIGPROF"); + break; +#endif +#ifdef SIGWINCH + case SIGWINCH: + KWSYSPE_CASE(Other, "SIGWINCH"); + break; +#endif +#ifdef SIGPOLL + case SIGPOLL: + KWSYSPE_CASE(Other, "SIGPOLL"); + break; +#endif +#ifdef SIGIO +# if !defined(SIGPOLL) || SIGIO != SIGPOLL + case SIGIO: + KWSYSPE_CASE(Other, "SIGIO"); + break; +# endif +#endif +#ifdef SIGPWR + case SIGPWR: + KWSYSPE_CASE(Other, "SIGPWR"); + break; +#endif +#ifdef SIGSYS + case SIGSYS: + KWSYSPE_CASE(Other, "SIGSYS"); + break; +#endif +#ifdef SIGUNUSED +# if !defined(SIGSYS) || SIGUNUSED != SIGSYS + case SIGUNUSED: + KWSYSPE_CASE(Other, "SIGUNUSED"); + break; +# endif +#endif + default: + cp->ProcessResults[idx].ExitException = kwsysProcess_Exception_Other; + sprintf(cp->ProcessResults[idx].ExitExceptionString, "Signal %d", sig); + break; + } +} +#undef KWSYSPE_CASE + +/* When the child process encounters an error before its program is + invoked, this is called to report the error to the parent and + exit. */ +static void kwsysProcessChildErrorExit(int errorPipe) +{ + /* Construct the error message. */ + char buffer[KWSYSPE_PIPE_BUFFER_SIZE]; + kwsysProcess_ssize_t result; + strncpy(buffer, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE); + buffer[KWSYSPE_PIPE_BUFFER_SIZE - 1] = '\0'; + + /* Report the error to the parent through the special pipe. */ + result = write(errorPipe, buffer, strlen(buffer)); + (void)result; + + /* Terminate without cleanup. */ + _exit(1); +} + +/* Restores all signal handlers to their default values. */ +static void kwsysProcessRestoreDefaultSignalHandlers(void) +{ + struct sigaction act; + memset(&act, 0, sizeof(struct sigaction)); + act.sa_handler = SIG_DFL; +#ifdef SIGHUP + sigaction(SIGHUP, &act, 0); +#endif +#ifdef SIGINT + sigaction(SIGINT, &act, 0); +#endif +#ifdef SIGQUIT + sigaction(SIGQUIT, &act, 0); +#endif +#ifdef SIGILL + sigaction(SIGILL, &act, 0); +#endif +#ifdef SIGTRAP + sigaction(SIGTRAP, &act, 0); +#endif +#ifdef SIGABRT + sigaction(SIGABRT, &act, 0); +#endif +#ifdef SIGIOT + sigaction(SIGIOT, &act, 0); +#endif +#ifdef SIGBUS + sigaction(SIGBUS, &act, 0); +#endif +#ifdef SIGFPE + sigaction(SIGFPE, &act, 0); +#endif +#ifdef SIGUSR1 + sigaction(SIGUSR1, &act, 0); +#endif +#ifdef SIGSEGV + sigaction(SIGSEGV, &act, 0); +#endif +#ifdef SIGUSR2 + sigaction(SIGUSR2, &act, 0); +#endif +#ifdef SIGPIPE + sigaction(SIGPIPE, &act, 0); +#endif +#ifdef SIGALRM + sigaction(SIGALRM, &act, 0); +#endif +#ifdef SIGTERM + sigaction(SIGTERM, &act, 0); +#endif +#ifdef SIGSTKFLT + sigaction(SIGSTKFLT, &act, 0); +#endif +#ifdef SIGCLD + sigaction(SIGCLD, &act, 0); +#endif +#ifdef SIGCHLD + sigaction(SIGCHLD, &act, 0); +#endif +#ifdef SIGCONT + sigaction(SIGCONT, &act, 0); +#endif +#ifdef SIGTSTP + sigaction(SIGTSTP, &act, 0); +#endif +#ifdef SIGTTIN + sigaction(SIGTTIN, &act, 0); +#endif +#ifdef SIGTTOU + sigaction(SIGTTOU, &act, 0); +#endif +#ifdef SIGURG + sigaction(SIGURG, &act, 0); +#endif +#ifdef SIGXCPU + sigaction(SIGXCPU, &act, 0); +#endif +#ifdef SIGXFSZ + sigaction(SIGXFSZ, &act, 0); +#endif +#ifdef SIGVTALRM + sigaction(SIGVTALRM, &act, 0); +#endif +#ifdef SIGPROF + sigaction(SIGPROF, &act, 0); +#endif +#ifdef SIGWINCH + sigaction(SIGWINCH, &act, 0); +#endif +#ifdef SIGPOLL + sigaction(SIGPOLL, &act, 0); +#endif +#ifdef SIGIO + sigaction(SIGIO, &act, 0); +#endif +#ifdef SIGPWR + sigaction(SIGPWR, &act, 0); +#endif +#ifdef SIGSYS + sigaction(SIGSYS, &act, 0); +#endif +#ifdef SIGUNUSED + sigaction(SIGUNUSED, &act, 0); +#endif +} + +static void kwsysProcessExit(void) +{ + _exit(0); +} + +#if !defined(__VMS) +static pid_t kwsysProcessFork(kwsysProcess* cp, + kwsysProcessCreateInformation* si) +{ + /* Create a detached process if requested. */ + if (cp->OptionDetach) { + /* Create an intermediate process. */ + pid_t middle_pid = fork(); + if (middle_pid < 0) { + /* Fork failed. Return as if we were not detaching. */ + return middle_pid; + } else if (middle_pid == 0) { + /* This is the intermediate process. Create the real child. */ + pid_t child_pid = fork(); + if (child_pid == 0) { + /* This is the real child process. There is nothing to do here. */ + return 0; + } else { + /* Use the error pipe to report the pid to the real parent. */ + while ((write(si->ErrorPipe[1], &child_pid, sizeof(child_pid)) < 0) && + (errno == EINTR)) + ; + + /* Exit without cleanup. The parent holds all resources. */ + kwsysProcessExit(); + return 0; /* Never reached, but avoids SunCC warning. */ + } + } else { + /* This is the original parent process. The intermediate + process will use the error pipe to report the pid of the + detached child. */ + pid_t child_pid; + int status; + while ((read(si->ErrorPipe[0], &child_pid, sizeof(child_pid)) < 0) && + (errno == EINTR)) + ; + + /* Wait for the intermediate process to exit and clean it up. */ + while ((waitpid(middle_pid, &status, 0) < 0) && (errno == EINTR)) + ; + return child_pid; + } + } else { + /* Not creating a detached process. Use normal fork. */ + return fork(); + } +} +#endif + +/* We try to obtain process information by invoking the ps command. + Here we define the command to call on each platform and the + corresponding parsing format string. The parsing format should + have two integers to store: the pid and then the ppid. */ +#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \ + defined(__OpenBSD__) || defined(__GLIBC__) || defined(__GNU__) +# define KWSYSPE_PS_COMMAND "ps axo pid,ppid" +# define KWSYSPE_PS_FORMAT "%d %d\n" +#elif defined(__sun) && (defined(__SVR4) || defined(__svr4__)) /* Solaris */ +# define KWSYSPE_PS_COMMAND "ps -e -o pid,ppid" +# define KWSYSPE_PS_FORMAT "%d %d\n" +#elif defined(__hpux) || defined(__sun__) || defined(__sgi) || \ + defined(_AIX) || defined(__sparc) +# define KWSYSPE_PS_COMMAND "ps -ef" +# define KWSYSPE_PS_FORMAT "%*s %d %d %*[^\n]\n" +#elif defined(__QNX__) +# define KWSYSPE_PS_COMMAND "ps -Af" +# define KWSYSPE_PS_FORMAT "%*d %d %d %*[^\n]\n" +#elif defined(__CYGWIN__) +# define KWSYSPE_PS_COMMAND "ps aux" +# define KWSYSPE_PS_FORMAT "%d %d %*[^\n]\n" +#endif + +void kwsysProcess_KillPID(unsigned long process_id) +{ + kwsysProcessKill((pid_t)process_id); +} + +static void kwsysProcessKill(pid_t process_id) +{ +#if defined(__linux__) || defined(__CYGWIN__) + DIR* procdir; +#endif + + /* Suspend the process to be sure it will not create more children. */ + kill(process_id, SIGSTOP); + +#if defined(__CYGWIN__) + /* Some Cygwin versions seem to need help here. Give up our time slice + so that the child can process SIGSTOP before we send SIGKILL. */ + usleep(1); +#endif + +/* Kill all children if we can find them. */ +#if defined(__linux__) || defined(__CYGWIN__) + /* First try using the /proc filesystem. */ + if ((procdir = opendir("/proc")) != NULL) { +# if defined(MAXPATHLEN) + char fname[MAXPATHLEN]; +# elif defined(PATH_MAX) + char fname[PATH_MAX]; +# else + char fname[4096]; +# endif + char buffer[KWSYSPE_PIPE_BUFFER_SIZE + 1]; + struct dirent* d; + + /* Each process has a directory in /proc whose name is the pid. + Within this directory is a file called stat that has the + following format: + + pid (command line) status ppid ... + + We want to get the ppid for all processes. Those that have + process_id as their parent should be recursively killed. */ + for (d = readdir(procdir); d; d = readdir(procdir)) { + int pid; + if (sscanf(d->d_name, "%d", &pid) == 1 && pid != 0) { + struct stat finfo; + sprintf(fname, "/proc/%d/stat", pid); + if (stat(fname, &finfo) == 0) { + FILE* f = fopen(fname, "r"); + if (f) { + size_t nread = fread(buffer, 1, KWSYSPE_PIPE_BUFFER_SIZE, f); + fclose(f); + buffer[nread] = '\0'; + if (nread > 0) { + const char* rparen = strrchr(buffer, ')'); + int ppid; + if (rparen && (sscanf(rparen + 1, "%*s %d", &ppid) == 1)) { + if (ppid == process_id) { + /* Recursively kill this child and its children. */ + kwsysProcessKill(pid); + } + } + } + } + } + } + } + closedir(procdir); + } else +#endif + { +#if defined(KWSYSPE_PS_COMMAND) + /* Try running "ps" to get the process information. */ + FILE* ps = popen(KWSYSPE_PS_COMMAND, "r"); + + /* Make sure the process started and provided a valid header. */ + if (ps && fscanf(ps, "%*[^\n]\n") != EOF) { + /* Look for processes whose parent is the process being killed. */ + int pid, ppid; + while (fscanf(ps, KWSYSPE_PS_FORMAT, &pid, &ppid) == 2) { + if (ppid == process_id) { + /* Recursively kill this child and its children. */ + kwsysProcessKill(pid); + } + } + } + + /* We are done with the ps process. */ + if (ps) { + pclose(ps); + } +#endif + } + + /* Kill the process. */ + kill(process_id, SIGKILL); + +#if defined(__APPLE__) + /* On OS X 10.3 the above SIGSTOP occasionally prevents the SIGKILL + from working. Just in case, we resume the child and kill it + again. There is a small race condition in this obscure case. If + the child manages to fork again between these two signals, we + will not catch its children. */ + kill(process_id, SIGCONT); + kill(process_id, SIGKILL); +#endif +} + +#if defined(__VMS) +int decc$feature_get_index(const char* name); +int decc$feature_set_value(int index, int mode, int value); +static int kwsysProcessSetVMSFeature(const char* name, int value) +{ + int i; + errno = 0; + i = decc$feature_get_index(name); + return i >= 0 && (decc$feature_set_value(i, 1, value) >= 0 || errno == 0); +} +#endif + +/* Global set of executing processes for use by the signal handler. + This global instance will be zero-initialized by the compiler. */ +typedef struct kwsysProcessInstances_s +{ + int Count; + int Size; + kwsysProcess** Processes; +} kwsysProcessInstances; +static kwsysProcessInstances kwsysProcesses; + +/* The old SIGCHLD / SIGINT / SIGTERM handlers. */ +static struct sigaction kwsysProcessesOldSigChldAction; +static struct sigaction kwsysProcessesOldSigIntAction; +static struct sigaction kwsysProcessesOldSigTermAction; + +static void kwsysProcessesUpdate(kwsysProcessInstances* newProcesses) +{ + /* Block signals while we update the set of pipes to check. + TODO: sigprocmask is undefined for threaded apps. See + pthread_sigmask. */ + sigset_t newset; + sigset_t oldset; + sigemptyset(&newset); + sigaddset(&newset, SIGCHLD); + sigaddset(&newset, SIGINT); + sigaddset(&newset, SIGTERM); + sigprocmask(SIG_BLOCK, &newset, &oldset); + + /* Store the new set in that seen by the signal handler. */ + kwsysProcesses = *newProcesses; + + /* Restore the signal mask to the previous setting. */ + sigprocmask(SIG_SETMASK, &oldset, 0); +} + +static int kwsysProcessesAdd(kwsysProcess* cp) +{ + /* Create a pipe through which the signal handler can notify the + given process object that a child has exited. */ + { + /* Create the pipe. */ + int p[2]; + if (pipe(p KWSYSPE_VMS_NONBLOCK) < 0) { + return 0; + } + + /* Store the pipes now to be sure they are cleaned up later. */ + cp->PipeReadEnds[KWSYSPE_PIPE_SIGNAL] = p[0]; + cp->SignalPipe = p[1]; + + /* Switch the pipe to non-blocking mode so that reading a byte can + be an atomic test-and-set. */ + if (!kwsysProcessSetNonBlocking(p[0]) || + !kwsysProcessSetNonBlocking(p[1])) { + return 0; + } + + /* The children do not need this pipe. Set close-on-exec flag on + the pipe's ends. */ + if ((fcntl(p[0], F_SETFD, FD_CLOEXEC) < 0) || + (fcntl(p[1], F_SETFD, FD_CLOEXEC) < 0)) { + return 0; + } + } + + /* Attempt to add the given signal pipe to the signal handler set. */ + { + + /* Make sure there is enough space for the new signal pipe. */ + kwsysProcessInstances oldProcesses = kwsysProcesses; + kwsysProcessInstances newProcesses = oldProcesses; + if (oldProcesses.Count == oldProcesses.Size) { + /* Start with enough space for a small number of process instances + and double the size each time more is needed. */ + newProcesses.Size = oldProcesses.Size ? oldProcesses.Size * 2 : 4; + + /* Try allocating the new block of memory. */ + if ((newProcesses.Processes = ((kwsysProcess**)malloc( + (size_t)(newProcesses.Size) * sizeof(kwsysProcess*))))) { + /* Copy the old pipe set to the new memory. */ + if (oldProcesses.Count > 0) { + memcpy(newProcesses.Processes, oldProcesses.Processes, + ((size_t)(oldProcesses.Count) * sizeof(kwsysProcess*))); + } + } else { + /* Failed to allocate memory for the new signal pipe set. */ + return 0; + } + } + + /* Append the new signal pipe to the set. */ + newProcesses.Processes[newProcesses.Count++] = cp; + + /* Store the new set in that seen by the signal handler. */ + kwsysProcessesUpdate(&newProcesses); + + /* Free the original pipes if new ones were allocated. */ + if (newProcesses.Processes != oldProcesses.Processes) { + free(oldProcesses.Processes); + } + + /* If this is the first process, enable the signal handler. */ + if (newProcesses.Count == 1) { + /* Install our handler for SIGCHLD. Repeat call until it is not + interrupted. */ + struct sigaction newSigAction; + memset(&newSigAction, 0, sizeof(struct sigaction)); +#if KWSYSPE_USE_SIGINFO + newSigAction.sa_sigaction = kwsysProcessesSignalHandler; + newSigAction.sa_flags = SA_NOCLDSTOP | SA_SIGINFO; +# ifdef SA_RESTART + newSigAction.sa_flags |= SA_RESTART; +# endif +#else + newSigAction.sa_handler = kwsysProcessesSignalHandler; + newSigAction.sa_flags = SA_NOCLDSTOP; +#endif + sigemptyset(&newSigAction.sa_mask); + while ((sigaction(SIGCHLD, &newSigAction, + &kwsysProcessesOldSigChldAction) < 0) && + (errno == EINTR)) + ; + + /* Install our handler for SIGINT / SIGTERM. Repeat call until + it is not interrupted. */ + sigemptyset(&newSigAction.sa_mask); + sigaddset(&newSigAction.sa_mask, SIGTERM); + while ((sigaction(SIGINT, &newSigAction, + &kwsysProcessesOldSigIntAction) < 0) && + (errno == EINTR)) + ; + + sigemptyset(&newSigAction.sa_mask); + sigaddset(&newSigAction.sa_mask, SIGINT); + while ((sigaction(SIGTERM, &newSigAction, + &kwsysProcessesOldSigIntAction) < 0) && + (errno == EINTR)) + ; + } + } + + return 1; +} + +static void kwsysProcessesRemove(kwsysProcess* cp) +{ + /* Attempt to remove the given signal pipe from the signal handler set. */ + { + /* Find the given process in the set. */ + kwsysProcessInstances newProcesses = kwsysProcesses; + int i; + for (i = 0; i < newProcesses.Count; ++i) { + if (newProcesses.Processes[i] == cp) { + break; + } + } + if (i < newProcesses.Count) { + /* Remove the process from the set. */ + --newProcesses.Count; + for (; i < newProcesses.Count; ++i) { + newProcesses.Processes[i] = newProcesses.Processes[i + 1]; + } + + /* If this was the last process, disable the signal handler. */ + if (newProcesses.Count == 0) { + /* Restore the signal handlers. Repeat call until it is not + interrupted. */ + while ((sigaction(SIGCHLD, &kwsysProcessesOldSigChldAction, 0) < 0) && + (errno == EINTR)) + ; + while ((sigaction(SIGINT, &kwsysProcessesOldSigIntAction, 0) < 0) && + (errno == EINTR)) + ; + while ((sigaction(SIGTERM, &kwsysProcessesOldSigTermAction, 0) < 0) && + (errno == EINTR)) + ; + + /* Free the table of process pointers since it is now empty. + This is safe because the signal handler has been removed. */ + newProcesses.Size = 0; + free(newProcesses.Processes); + newProcesses.Processes = 0; + } + + /* Store the new set in that seen by the signal handler. */ + kwsysProcessesUpdate(&newProcesses); + } + } + + /* Close the pipe through which the signal handler may have notified + the given process object that a child has exited. */ + kwsysProcessCleanupDescriptor(&cp->SignalPipe); +} + +static void kwsysProcessesSignalHandler(int signum +#if KWSYSPE_USE_SIGINFO + , + siginfo_t* info, void* ucontext +#endif +) +{ + int i, j, procStatus, old_errno = errno; +#if KWSYSPE_USE_SIGINFO + (void)info; + (void)ucontext; +#endif + + /* Signal all process objects that a child has terminated. */ + switch (signum) { + case SIGCHLD: + for (i = 0; i < kwsysProcesses.Count; ++i) { + /* Set the pipe in a signalled state. */ + char buf = 1; + kwsysProcess* cp = kwsysProcesses.Processes[i]; + kwsysProcess_ssize_t pipeStatus = + read(cp->PipeReadEnds[KWSYSPE_PIPE_SIGNAL], &buf, 1); + (void)pipeStatus; + pipeStatus = write(cp->SignalPipe, &buf, 1); + (void)pipeStatus; + } + break; + case SIGINT: + case SIGTERM: + /* Signal child processes that are running in new process groups. */ + for (i = 0; i < kwsysProcesses.Count; ++i) { + kwsysProcess* cp = kwsysProcesses.Processes[i]; + /* Check Killed to avoid data race condition when killing. + Check State to avoid data race condition in kwsysProcessCleanup + when there is an error (it leaves a reaped PID). */ + if (cp->CreateProcessGroup && !cp->Killed && + cp->State != kwsysProcess_State_Error && cp->ForkPIDs) { + for (j = 0; j < cp->NumberOfCommands; ++j) { + /* Make sure the PID is still valid. */ + if (cp->ForkPIDs[j]) { + /* The user created a process group for this process. The group + ID + is the process ID for the original process in the group. */ + kill(-cp->ForkPIDs[j], SIGINT); + } + } + } + } + + /* Wait for all processes to terminate. */ + while (wait(&procStatus) >= 0 || errno != ECHILD) { + } + + /* Terminate the process, which is now in an inconsistent state + because we reaped all the PIDs that it may have been reaping + or may have reaped in the future. Reraise the signal so that + the proper exit code is returned. */ + { + /* Install default signal handler. */ + struct sigaction defSigAction; + sigset_t unblockSet; + memset(&defSigAction, 0, sizeof(defSigAction)); + defSigAction.sa_handler = SIG_DFL; + sigemptyset(&defSigAction.sa_mask); + while ((sigaction(signum, &defSigAction, 0) < 0) && (errno == EINTR)) + ; + /* Unmask the signal. */ + sigemptyset(&unblockSet); + sigaddset(&unblockSet, signum); + sigprocmask(SIG_UNBLOCK, &unblockSet, 0); + /* Raise the signal again. */ + raise(signum); + /* We shouldn't get here... but if we do... */ + _exit(1); + } + /* break omitted to silence unreachable code clang compiler warning. */ + } + +#if !KWSYSPE_USE_SIGINFO + /* Re-Install our handler. Repeat call until it is not interrupted. */ + { + struct sigaction newSigAction; + struct sigaction& oldSigAction; + memset(&newSigAction, 0, sizeof(struct sigaction)); + newSigChldAction.sa_handler = kwsysProcessesSignalHandler; + newSigChldAction.sa_flags = SA_NOCLDSTOP; + sigemptyset(&newSigAction.sa_mask); + switch (signum) { + case SIGCHLD: + oldSigAction = &kwsysProcessesOldSigChldAction; + break; + case SIGINT: + sigaddset(&newSigAction.sa_mask, SIGTERM); + oldSigAction = &kwsysProcessesOldSigIntAction; + break; + case SIGTERM: + sigaddset(&newSigAction.sa_mask, SIGINT); + oldSigAction = &kwsysProcessesOldSigTermAction; + break; + default: + return 0; + } + while ((sigaction(signum, &newSigAction, oldSigAction) < 0) && + (errno == EINTR)) + ; + } +#endif + + errno = old_errno; +} + +void kwsysProcess_ResetStartTime(kwsysProcess* cp) +{ + if (!cp) { + return; + } + /* Reset start time. */ + cp->StartTime = kwsysProcessTimeGetCurrent(); +} diff --git a/test/API/driver/kwsys/ProcessWin32.c b/test/API/driver/kwsys/ProcessWin32.c new file mode 100644 index 0000000..a963862 --- /dev/null +++ b/test/API/driver/kwsys/ProcessWin32.c @@ -0,0 +1,2786 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(Process.h) +#include KWSYS_HEADER(Encoding.h) + +/* Work-around CMake dependency scanning limitation. This must + duplicate the above list of headers. */ +#if 0 +# include "Encoding.h.in" +# include "Process.h.in" +#endif + +/* + +Implementation for Windows + +On windows, a thread is created to wait for data on each pipe. The +threads are synchronized with the main thread to simulate the use of +a UNIX-style select system call. + +*/ + +#ifdef _MSC_VER +# pragma warning(push, 1) +#endif +#include /* Windows API */ +#if defined(_MSC_VER) && _MSC_VER >= 1800 +# define KWSYS_WINDOWS_DEPRECATED_GetVersionEx +#endif +#include /* _unlink */ +#include /* sprintf */ +#include /* strlen, strdup */ +#ifdef __WATCOMC__ +# define _unlink unlink +#endif + +#ifndef _MAX_FNAME +# define _MAX_FNAME 4096 +#endif +#ifndef _MAX_PATH +# define _MAX_PATH 4096 +#endif + +#ifdef _MSC_VER +# pragma warning(pop) +# pragma warning(disable : 4514) +# pragma warning(disable : 4706) +#endif + +#if defined(__BORLANDC__) +# pragma warn - 8004 /* assigned a value that is never used */ +# pragma warn - 8060 /* Assignment inside if() condition. */ +#endif + +/* There are pipes for the process pipeline's stdout and stderr. */ +#define KWSYSPE_PIPE_COUNT 2 +#define KWSYSPE_PIPE_STDOUT 0 +#define KWSYSPE_PIPE_STDERR 1 + +/* The maximum amount to read from a pipe at a time. */ +#define KWSYSPE_PIPE_BUFFER_SIZE 1024 + +/* Debug output macro. */ +#if 0 +# define KWSYSPE_DEBUG(x) \ + ((void*)cp == (void*)0x00226DE0 \ + ? (fprintf(stderr, "%d/%p/%d ", (int)GetCurrentProcessId(), cp, \ + __LINE__), \ + fprintf x, fflush(stderr), 1) \ + : (1)) +#else +# define KWSYSPE_DEBUG(x) (void)1 +#endif + +typedef LARGE_INTEGER kwsysProcessTime; + +typedef struct kwsysProcessCreateInformation_s +{ + /* Windows child startup control data. */ + STARTUPINFOW StartupInfo; + + /* Original handles before making inherited duplicates. */ + HANDLE hStdInput; + HANDLE hStdOutput; + HANDLE hStdError; +} kwsysProcessCreateInformation; + +typedef struct kwsysProcessPipeData_s kwsysProcessPipeData; +static DWORD WINAPI kwsysProcessPipeThreadRead(LPVOID ptd); +static void kwsysProcessPipeThreadReadPipe(kwsysProcess* cp, + kwsysProcessPipeData* td); +static DWORD WINAPI kwsysProcessPipeThreadWake(LPVOID ptd); +static void kwsysProcessPipeThreadWakePipe(kwsysProcess* cp, + kwsysProcessPipeData* td); +static int kwsysProcessInitialize(kwsysProcess* cp); +static DWORD kwsysProcessCreate(kwsysProcess* cp, int index, + kwsysProcessCreateInformation* si); +static void kwsysProcessDestroy(kwsysProcess* cp, int event); +static DWORD kwsysProcessSetupOutputPipeFile(PHANDLE handle, const char* name); +static void kwsysProcessSetupSharedPipe(DWORD nStdHandle, PHANDLE handle); +static void kwsysProcessSetupPipeNative(HANDLE native, PHANDLE handle); +static void kwsysProcessCleanupHandle(PHANDLE h); +static void kwsysProcessCleanup(kwsysProcess* cp, DWORD error); +static void kwsysProcessCleanErrorMessage(kwsysProcess* cp); +static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout, + kwsysProcessTime* timeoutTime); +static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime, + double* userTimeout, + kwsysProcessTime* timeoutLength); +static kwsysProcessTime kwsysProcessTimeGetCurrent(void); +static DWORD kwsysProcessTimeToDWORD(kwsysProcessTime t); +static double kwsysProcessTimeToDouble(kwsysProcessTime t); +static kwsysProcessTime kwsysProcessTimeFromDouble(double d); +static int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2); +static kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1, + kwsysProcessTime in2); +static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, + kwsysProcessTime in2); +static void kwsysProcessSetExitExceptionByIndex(kwsysProcess* cp, int code, + int idx); +static void kwsysProcessKillTree(int pid); +static void kwsysProcessDisablePipeThreads(kwsysProcess* cp); +static int kwsysProcessesInitialize(void); +static int kwsysTryEnterCreateProcessSection(void); +static void kwsysLeaveCreateProcessSection(void); +static int kwsysProcessesAdd(HANDLE hProcess, DWORD dwProcessId, + int newProcessGroup); +static void kwsysProcessesRemove(HANDLE hProcess); +static BOOL WINAPI kwsysCtrlHandler(DWORD dwCtrlType); + +/* A structure containing synchronization data for each thread. */ +typedef struct kwsysProcessPipeSync_s kwsysProcessPipeSync; +struct kwsysProcessPipeSync_s +{ + /* Handle to the thread. */ + HANDLE Thread; + + /* Semaphore indicating to the thread that a process has started. */ + HANDLE Ready; + + /* Semaphore indicating to the thread that it should begin work. */ + HANDLE Go; + + /* Semaphore indicating thread has reset for another process. */ + HANDLE Reset; +}; + +/* A structure containing data for each pipe's threads. */ +struct kwsysProcessPipeData_s +{ + /* ------------- Data managed per instance of kwsysProcess ------------- */ + + /* Synchronization data for reading thread. */ + kwsysProcessPipeSync Reader; + + /* Synchronization data for waking thread. */ + kwsysProcessPipeSync Waker; + + /* Index of this pipe. */ + int Index; + + /* The kwsysProcess instance owning this pipe. */ + kwsysProcess* Process; + + /* ------------- Data managed per call to Execute ------------- */ + + /* Buffer for data read in this pipe's thread. */ + char DataBuffer[KWSYSPE_PIPE_BUFFER_SIZE]; + + /* The length of the data stored in the buffer. */ + DWORD DataLength; + + /* Whether the pipe has been closed. */ + int Closed; + + /* Handle for the read end of this pipe. */ + HANDLE Read; + + /* Handle for the write end of this pipe. */ + HANDLE Write; +}; + +/* A structure containing results data for each process. */ +typedef struct kwsysProcessResults_s kwsysProcessResults; +struct kwsysProcessResults_s +{ + /* The status of the process. */ + int State; + + /* The exceptional behavior that terminated the process, if any. */ + int ExitException; + + /* The process exit code. */ + DWORD ExitCode; + + /* The process return code, if any. */ + int ExitValue; + + /* Description for the ExitException. */ + char ExitExceptionString[KWSYSPE_PIPE_BUFFER_SIZE + 1]; +}; + +/* Structure containing data used to implement the child's execution. */ +struct kwsysProcess_s +{ + /* ------------- Data managed per instance of kwsysProcess ------------- */ + + /* The status of the process structure. */ + int State; + + /* The command lines to execute. */ + wchar_t** Commands; + int NumberOfCommands; + + /* The exit code of each command. */ + DWORD* CommandExitCodes; + + /* The working directory for the child process. */ + wchar_t* WorkingDirectory; + + /* Whether to create the child as a detached process. */ + int OptionDetach; + + /* Whether the child was created as a detached process. */ + int Detached; + + /* Whether to hide the child process's window. */ + int HideWindow; + + /* Whether to treat command lines as verbatim. */ + int Verbatim; + + /* Whether to merge stdout/stderr of the child. */ + int MergeOutput; + + /* Whether to create the process in a new process group. */ + int CreateProcessGroup; + + /* Mutex to protect the shared index used by threads to report data. */ + HANDLE SharedIndexMutex; + + /* Semaphore used by threads to signal data ready. */ + HANDLE Full; + + /* Whether we are currently deleting this kwsysProcess instance. */ + int Deleting; + + /* Data specific to each pipe and its thread. */ + kwsysProcessPipeData Pipe[KWSYSPE_PIPE_COUNT]; + + /* Name of files to which stdin and stdout pipes are attached. */ + char* PipeFileSTDIN; + char* PipeFileSTDOUT; + char* PipeFileSTDERR; + + /* Whether each pipe is shared with the parent process. */ + int PipeSharedSTDIN; + int PipeSharedSTDOUT; + int PipeSharedSTDERR; + + /* Native pipes provided by the user. */ + HANDLE PipeNativeSTDIN[2]; + HANDLE PipeNativeSTDOUT[2]; + HANDLE PipeNativeSTDERR[2]; + + /* ------------- Data managed per call to Execute ------------- */ + + /* Index of last pipe to report data, if any. */ + int CurrentIndex; + + /* Index shared by threads to report data. */ + int SharedIndex; + + /* The timeout length. */ + double Timeout; + + /* Time at which the child started. */ + kwsysProcessTime StartTime; + + /* Time at which the child will timeout. Negative for no timeout. */ + kwsysProcessTime TimeoutTime; + + /* Flag for whether the process was killed. */ + int Killed; + + /* Flag for whether the timeout expired. */ + int TimeoutExpired; + + /* Flag for whether the process has terminated. */ + int Terminated; + + /* The number of pipes still open during execution and while waiting + for pipes to close after process termination. */ + int PipesLeft; + + /* Buffer for error messages. */ + char ErrorMessage[KWSYSPE_PIPE_BUFFER_SIZE + 1]; + + /* process results. */ + kwsysProcessResults* ProcessResults; + + /* Windows process information data. */ + PROCESS_INFORMATION* ProcessInformation; + + /* Data and process termination events for which to wait. */ + PHANDLE ProcessEvents; + int ProcessEventsLength; + + /* Real working directory of our own process. */ + DWORD RealWorkingDirectoryLength; + wchar_t* RealWorkingDirectory; + + /* Own handles for the child's ends of the pipes in the parent process. + Used temporarily during process creation. */ + HANDLE PipeChildStd[3]; +}; + +kwsysProcess* kwsysProcess_New(void) +{ + int i; + + /* Process control structure. */ + kwsysProcess* cp; + + /* Windows version number data. */ + OSVERSIONINFO osv; + + /* Initialize list of processes before we get any farther. It's especially + important that the console Ctrl handler be added BEFORE starting the + first process. This prevents the risk of an orphaned process being + started by the main thread while the default Ctrl handler is in + progress. */ + if (!kwsysProcessesInitialize()) { + return 0; + } + + /* Allocate a process control structure. */ + cp = (kwsysProcess*)malloc(sizeof(kwsysProcess)); + if (!cp) { + /* Could not allocate memory for the control structure. */ + return 0; + } + ZeroMemory(cp, sizeof(*cp)); + + /* Share stdin with the parent process by default. */ + cp->PipeSharedSTDIN = 1; + + /* Set initial status. */ + cp->State = kwsysProcess_State_Starting; + + /* Choose a method of running the child based on version of + windows. */ + ZeroMemory(&osv, sizeof(osv)); + osv.dwOSVersionInfoSize = sizeof(osv); +#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx +# pragma warning(push) +# ifdef __INTEL_COMPILER +# pragma warning(disable : 1478) +# elif defined __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdeprecated-declarations" +# else +# pragma warning(disable : 4996) +# endif +#endif + GetVersionEx(&osv); +#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx +# ifdef __clang__ +# pragma clang diagnostic pop +# else +# pragma warning(pop) +# endif +#endif + if (osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { + /* Win9x no longer supported. */ + kwsysProcess_Delete(cp); + return 0; + } + + /* Initially no thread owns the mutex. Initialize semaphore to 1. */ + if (!(cp->SharedIndexMutex = CreateSemaphore(0, 1, 1, 0))) { + kwsysProcess_Delete(cp); + return 0; + } + + /* Initially no data are available. Initialize semaphore to 0. */ + if (!(cp->Full = CreateSemaphore(0, 0, 1, 0))) { + kwsysProcess_Delete(cp); + return 0; + } + + /* Create the thread to read each pipe. */ + for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { + DWORD dummy = 0; + + /* Assign the thread its index. */ + cp->Pipe[i].Index = i; + + /* Give the thread a pointer back to the kwsysProcess instance. */ + cp->Pipe[i].Process = cp; + + /* No process is yet running. Initialize semaphore to 0. */ + if (!(cp->Pipe[i].Reader.Ready = CreateSemaphore(0, 0, 1, 0))) { + kwsysProcess_Delete(cp); + return 0; + } + + /* The pipe is not yet reset. Initialize semaphore to 0. */ + if (!(cp->Pipe[i].Reader.Reset = CreateSemaphore(0, 0, 1, 0))) { + kwsysProcess_Delete(cp); + return 0; + } + + /* The thread's buffer is initially empty. Initialize semaphore to 1. */ + if (!(cp->Pipe[i].Reader.Go = CreateSemaphore(0, 1, 1, 0))) { + kwsysProcess_Delete(cp); + return 0; + } + + /* Create the reading thread. It will block immediately. The + thread will not make deeply nested calls, so we need only a + small stack. */ + if (!(cp->Pipe[i].Reader.Thread = CreateThread( + 0, 1024, kwsysProcessPipeThreadRead, &cp->Pipe[i], 0, &dummy))) { + kwsysProcess_Delete(cp); + return 0; + } + + /* No process is yet running. Initialize semaphore to 0. */ + if (!(cp->Pipe[i].Waker.Ready = CreateSemaphore(0, 0, 1, 0))) { + kwsysProcess_Delete(cp); + return 0; + } + + /* The pipe is not yet reset. Initialize semaphore to 0. */ + if (!(cp->Pipe[i].Waker.Reset = CreateSemaphore(0, 0, 1, 0))) { + kwsysProcess_Delete(cp); + return 0; + } + + /* The waker should not wake immediately. Initialize semaphore to 0. */ + if (!(cp->Pipe[i].Waker.Go = CreateSemaphore(0, 0, 1, 0))) { + kwsysProcess_Delete(cp); + return 0; + } + + /* Create the waking thread. It will block immediately. The + thread will not make deeply nested calls, so we need only a + small stack. */ + if (!(cp->Pipe[i].Waker.Thread = CreateThread( + 0, 1024, kwsysProcessPipeThreadWake, &cp->Pipe[i], 0, &dummy))) { + kwsysProcess_Delete(cp); + return 0; + } + } + for (i = 0; i < 3; ++i) { + cp->PipeChildStd[i] = INVALID_HANDLE_VALUE; + } + + return cp; +} + +void kwsysProcess_Delete(kwsysProcess* cp) +{ + int i; + + /* Make sure we have an instance. */ + if (!cp) { + return; + } + + /* If the process is executing, wait for it to finish. */ + if (cp->State == kwsysProcess_State_Executing) { + if (cp->Detached) { + kwsysProcess_Disown(cp); + } else { + kwsysProcess_WaitForExit(cp, 0); + } + } + + /* We are deleting the kwsysProcess instance. */ + cp->Deleting = 1; + + /* Terminate each of the threads. */ + for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { + /* Terminate this reading thread. */ + if (cp->Pipe[i].Reader.Thread) { + /* Signal the thread we are ready for it. It will terminate + immediately since Deleting is set. */ + ReleaseSemaphore(cp->Pipe[i].Reader.Ready, 1, 0); + + /* Wait for the thread to exit. */ + WaitForSingleObject(cp->Pipe[i].Reader.Thread, INFINITE); + + /* Close the handle to the thread. */ + kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Thread); + } + + /* Terminate this waking thread. */ + if (cp->Pipe[i].Waker.Thread) { + /* Signal the thread we are ready for it. It will terminate + immediately since Deleting is set. */ + ReleaseSemaphore(cp->Pipe[i].Waker.Ready, 1, 0); + + /* Wait for the thread to exit. */ + WaitForSingleObject(cp->Pipe[i].Waker.Thread, INFINITE); + + /* Close the handle to the thread. */ + kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Thread); + } + + /* Cleanup the pipe's semaphores. */ + kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Ready); + kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Go); + kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Reset); + kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Ready); + kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Go); + kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Reset); + } + + /* Close the shared semaphores. */ + kwsysProcessCleanupHandle(&cp->SharedIndexMutex); + kwsysProcessCleanupHandle(&cp->Full); + + /* Free memory. */ + kwsysProcess_SetCommand(cp, 0); + kwsysProcess_SetWorkingDirectory(cp, 0); + kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDIN, 0); + kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDOUT, 0); + kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDERR, 0); + free(cp->CommandExitCodes); + free(cp->ProcessResults); + free(cp); +} + +int kwsysProcess_SetCommand(kwsysProcess* cp, char const* const* command) +{ + int i; + if (!cp) { + return 0; + } + for (i = 0; i < cp->NumberOfCommands; ++i) { + free(cp->Commands[i]); + } + cp->NumberOfCommands = 0; + if (cp->Commands) { + free(cp->Commands); + cp->Commands = 0; + } + if (command) { + return kwsysProcess_AddCommand(cp, command); + } + return 1; +} + +int kwsysProcess_AddCommand(kwsysProcess* cp, char const* const* command) +{ + int newNumberOfCommands; + wchar_t** newCommands; + + /* Make sure we have a command to add. */ + if (!cp || !command || !*command) { + return 0; + } + + /* Allocate a new array for command pointers. */ + newNumberOfCommands = cp->NumberOfCommands + 1; + if (!(newCommands = + (wchar_t**)malloc(sizeof(wchar_t*) * newNumberOfCommands))) { + /* Out of memory. */ + return 0; + } + + /* Copy any existing commands into the new array. */ + { + int i; + for (i = 0; i < cp->NumberOfCommands; ++i) { + newCommands[i] = cp->Commands[i]; + } + } + + if (cp->Verbatim) { + /* Copy the verbatim command line into the buffer. */ + newCommands[cp->NumberOfCommands] = kwsysEncoding_DupToWide(*command); + } else { + /* Encode the arguments so CommandLineToArgvW can decode + them from the command line string in the child. */ + char buffer[32768]; /* CreateProcess max command-line length. */ + char* end = buffer + sizeof(buffer); + char* out = buffer; + char const* const* a; + for (a = command; *a; ++a) { + int quote = !**a; /* Quote the empty string. */ + int slashes = 0; + char const* c; + if (a != command && out != end) { + *out++ = ' '; + } + for (c = *a; !quote && *c; ++c) { + quote = (*c == ' ' || *c == '\t'); + } + if (quote && out != end) { + *out++ = '"'; + } + for (c = *a; *c; ++c) { + if (*c == '\\') { + ++slashes; + } else { + if (*c == '"') { + // Add n+1 backslashes to total 2n+1 before internal '"'. + while (slashes-- >= 0 && out != end) { + *out++ = '\\'; + } + } + slashes = 0; + } + if (out != end) { + *out++ = *c; + } + } + if (quote) { + // Add n backslashes to total 2n before ending '"'. + while (slashes-- > 0 && out != end) { + *out++ = '\\'; + } + if (out != end) { + *out++ = '"'; + } + } + } + if (out != end) { + *out = '\0'; + newCommands[cp->NumberOfCommands] = kwsysEncoding_DupToWide(buffer); + } else { + newCommands[cp->NumberOfCommands] = 0; + } + } + if (!newCommands[cp->NumberOfCommands]) { + /* Out of memory or command line too long. */ + free(newCommands); + return 0; + } + + /* Save the new array of commands. */ + free(cp->Commands); + cp->Commands = newCommands; + cp->NumberOfCommands = newNumberOfCommands; + return 1; +} + +void kwsysProcess_SetTimeout(kwsysProcess* cp, double timeout) +{ + if (!cp) { + return; + } + cp->Timeout = timeout; + if (cp->Timeout < 0) { + cp->Timeout = 0; + } + // Force recomputation of TimeoutTime. + cp->TimeoutTime.QuadPart = -1; +} + +int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, const char* dir) +{ + if (!cp) { + return 0; + } + if (cp->WorkingDirectory) { + free(cp->WorkingDirectory); + cp->WorkingDirectory = 0; + } + if (dir && dir[0]) { + wchar_t* wdir = kwsysEncoding_DupToWide(dir); + /* We must convert the working directory to a full path. */ + DWORD length = GetFullPathNameW(wdir, 0, 0, 0); + if (length > 0) { + wchar_t* work_dir = malloc(length * sizeof(wchar_t)); + if (!work_dir) { + free(wdir); + return 0; + } + if (!GetFullPathNameW(wdir, length, work_dir, 0)) { + free(work_dir); + free(wdir); + return 0; + } + cp->WorkingDirectory = work_dir; + } + free(wdir); + } + return 1; +} + +int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe, const char* file) +{ + char** pfile; + if (!cp) { + return 0; + } + switch (pipe) { + case kwsysProcess_Pipe_STDIN: + pfile = &cp->PipeFileSTDIN; + break; + case kwsysProcess_Pipe_STDOUT: + pfile = &cp->PipeFileSTDOUT; + break; + case kwsysProcess_Pipe_STDERR: + pfile = &cp->PipeFileSTDERR; + break; + default: + return 0; + } + if (*pfile) { + free(*pfile); + *pfile = 0; + } + if (file) { + *pfile = strdup(file); + if (!*pfile) { + return 0; + } + } + + /* If we are redirecting the pipe, do not share it or use a native + pipe. */ + if (*pfile) { + kwsysProcess_SetPipeNative(cp, pipe, 0); + kwsysProcess_SetPipeShared(cp, pipe, 0); + } + + return 1; +} + +void kwsysProcess_SetPipeShared(kwsysProcess* cp, int pipe, int shared) +{ + if (!cp) { + return; + } + + switch (pipe) { + case kwsysProcess_Pipe_STDIN: + cp->PipeSharedSTDIN = shared ? 1 : 0; + break; + case kwsysProcess_Pipe_STDOUT: + cp->PipeSharedSTDOUT = shared ? 1 : 0; + break; + case kwsysProcess_Pipe_STDERR: + cp->PipeSharedSTDERR = shared ? 1 : 0; + break; + default: + return; + } + + /* If we are sharing the pipe, do not redirect it to a file or use a + native pipe. */ + if (shared) { + kwsysProcess_SetPipeFile(cp, pipe, 0); + kwsysProcess_SetPipeNative(cp, pipe, 0); + } +} + +void kwsysProcess_SetPipeNative(kwsysProcess* cp, int pipe, HANDLE p[2]) +{ + HANDLE* pPipeNative = 0; + + if (!cp) { + return; + } + + switch (pipe) { + case kwsysProcess_Pipe_STDIN: + pPipeNative = cp->PipeNativeSTDIN; + break; + case kwsysProcess_Pipe_STDOUT: + pPipeNative = cp->PipeNativeSTDOUT; + break; + case kwsysProcess_Pipe_STDERR: + pPipeNative = cp->PipeNativeSTDERR; + break; + default: + return; + } + + /* Copy the native pipe handles provided. */ + if (p) { + pPipeNative[0] = p[0]; + pPipeNative[1] = p[1]; + } else { + pPipeNative[0] = 0; + pPipeNative[1] = 0; + } + + /* If we are using a native pipe, do not share it or redirect it to + a file. */ + if (p) { + kwsysProcess_SetPipeFile(cp, pipe, 0); + kwsysProcess_SetPipeShared(cp, pipe, 0); + } +} + +int kwsysProcess_GetOption(kwsysProcess* cp, int optionId) +{ + if (!cp) { + return 0; + } + + switch (optionId) { + case kwsysProcess_Option_Detach: + return cp->OptionDetach; + case kwsysProcess_Option_HideWindow: + return cp->HideWindow; + case kwsysProcess_Option_MergeOutput: + return cp->MergeOutput; + case kwsysProcess_Option_Verbatim: + return cp->Verbatim; + case kwsysProcess_Option_CreateProcessGroup: + return cp->CreateProcessGroup; + default: + return 0; + } +} + +void kwsysProcess_SetOption(kwsysProcess* cp, int optionId, int value) +{ + if (!cp) { + return; + } + + switch (optionId) { + case kwsysProcess_Option_Detach: + cp->OptionDetach = value; + break; + case kwsysProcess_Option_HideWindow: + cp->HideWindow = value; + break; + case kwsysProcess_Option_MergeOutput: + cp->MergeOutput = value; + break; + case kwsysProcess_Option_Verbatim: + cp->Verbatim = value; + break; + case kwsysProcess_Option_CreateProcessGroup: + cp->CreateProcessGroup = value; + break; + default: + break; + } +} + +int kwsysProcess_GetState(kwsysProcess* cp) +{ + return cp ? cp->State : kwsysProcess_State_Error; +} + +int kwsysProcess_GetExitException(kwsysProcess* cp) +{ + return (cp && cp->ProcessResults && (cp->NumberOfCommands > 0)) + ? cp->ProcessResults[cp->NumberOfCommands - 1].ExitException + : kwsysProcess_Exception_Other; +} + +int kwsysProcess_GetExitValue(kwsysProcess* cp) +{ + return (cp && cp->ProcessResults && (cp->NumberOfCommands > 0)) + ? cp->ProcessResults[cp->NumberOfCommands - 1].ExitValue + : -1; +} + +int kwsysProcess_GetExitCode(kwsysProcess* cp) +{ + return (cp && cp->ProcessResults && (cp->NumberOfCommands > 0)) + ? cp->ProcessResults[cp->NumberOfCommands - 1].ExitCode + : 0; +} + +const char* kwsysProcess_GetErrorString(kwsysProcess* cp) +{ + if (!cp) { + return "Process management structure could not be allocated"; + } else if (cp->State == kwsysProcess_State_Error) { + return cp->ErrorMessage; + } + return "Success"; +} + +const char* kwsysProcess_GetExceptionString(kwsysProcess* cp) +{ + if (!(cp && cp->ProcessResults && (cp->NumberOfCommands > 0))) { + return "GetExceptionString called with NULL process management structure"; + } else if (cp->State == kwsysProcess_State_Exception) { + return cp->ProcessResults[cp->NumberOfCommands - 1].ExitExceptionString; + } + return "No exception"; +} + +/* the index should be in array bound. */ +#define KWSYSPE_IDX_CHK(RET) \ + if (!cp || idx >= cp->NumberOfCommands || idx < 0) { \ + KWSYSPE_DEBUG((stderr, "array index out of bound\n")); \ + return RET; \ + } + +int kwsysProcess_GetStateByIndex(kwsysProcess* cp, int idx) +{ + KWSYSPE_IDX_CHK(kwsysProcess_State_Error) + return cp->ProcessResults[idx].State; +} + +int kwsysProcess_GetExitExceptionByIndex(kwsysProcess* cp, int idx) +{ + KWSYSPE_IDX_CHK(kwsysProcess_Exception_Other) + return cp->ProcessResults[idx].ExitException; +} + +int kwsysProcess_GetExitValueByIndex(kwsysProcess* cp, int idx) +{ + KWSYSPE_IDX_CHK(-1) + return cp->ProcessResults[idx].ExitValue; +} + +int kwsysProcess_GetExitCodeByIndex(kwsysProcess* cp, int idx) +{ + KWSYSPE_IDX_CHK(-1) + return cp->CommandExitCodes[idx]; +} + +const char* kwsysProcess_GetExceptionStringByIndex(kwsysProcess* cp, int idx) +{ + KWSYSPE_IDX_CHK("GetExceptionString called with NULL process management " + "structure or index out of bound") + if (cp->ProcessResults[idx].State == kwsysProcess_StateByIndex_Exception) { + return cp->ProcessResults[idx].ExitExceptionString; + } + return "No exception"; +} + +#undef KWSYSPE_IDX_CHK + +void kwsysProcess_Execute(kwsysProcess* cp) +{ + int i; + + /* Do not execute a second time. */ + if (!cp || cp->State == kwsysProcess_State_Executing) { + return; + } + + /* Make sure we have something to run. */ + if (cp->NumberOfCommands < 1) { + strcpy(cp->ErrorMessage, "No command"); + cp->State = kwsysProcess_State_Error; + return; + } + + /* Initialize the control structure for a new process. */ + if (!kwsysProcessInitialize(cp)) { + strcpy(cp->ErrorMessage, "Out of memory"); + cp->State = kwsysProcess_State_Error; + return; + } + + /* Save the real working directory of this process and change to + the working directory for the child processes. This is needed + to make pipe file paths evaluate correctly. */ + if (cp->WorkingDirectory) { + if (!GetCurrentDirectoryW(cp->RealWorkingDirectoryLength, + cp->RealWorkingDirectory)) { + kwsysProcessCleanup(cp, GetLastError()); + return; + } + SetCurrentDirectoryW(cp->WorkingDirectory); + } + + /* Setup the stdin pipe for the first process. */ + if (cp->PipeFileSTDIN) { + /* Create a handle to read a file for stdin. */ + wchar_t* wstdin = kwsysEncoding_DupToWide(cp->PipeFileSTDIN); + DWORD error; + cp->PipeChildStd[0] = + CreateFileW(wstdin, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, + OPEN_EXISTING, 0, 0); + error = GetLastError(); /* Check now in case free changes this. */ + free(wstdin); + if (cp->PipeChildStd[0] == INVALID_HANDLE_VALUE) { + kwsysProcessCleanup(cp, error); + return; + } + } else if (cp->PipeSharedSTDIN) { + /* Share this process's stdin with the child. */ + kwsysProcessSetupSharedPipe(STD_INPUT_HANDLE, &cp->PipeChildStd[0]); + } else if (cp->PipeNativeSTDIN[0]) { + /* Use the provided native pipe. */ + kwsysProcessSetupPipeNative(cp->PipeNativeSTDIN[0], &cp->PipeChildStd[0]); + } else { + /* Explicitly give the child no stdin. */ + cp->PipeChildStd[0] = INVALID_HANDLE_VALUE; + } + + /* Create the output pipe for the last process. + We always create this so the pipe thread can run even if we + do not end up giving the write end to the child below. */ + if (!CreatePipe(&cp->Pipe[KWSYSPE_PIPE_STDOUT].Read, + &cp->Pipe[KWSYSPE_PIPE_STDOUT].Write, 0, 0)) { + kwsysProcessCleanup(cp, GetLastError()); + return; + } + + if (cp->PipeFileSTDOUT) { + /* Use a file for stdout. */ + DWORD error = kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[1], + cp->PipeFileSTDOUT); + if (error) { + kwsysProcessCleanup(cp, error); + return; + } + } else if (cp->PipeSharedSTDOUT) { + /* Use the parent stdout. */ + kwsysProcessSetupSharedPipe(STD_OUTPUT_HANDLE, &cp->PipeChildStd[1]); + } else if (cp->PipeNativeSTDOUT[1]) { + /* Use the given handle for stdout. */ + kwsysProcessSetupPipeNative(cp->PipeNativeSTDOUT[1], &cp->PipeChildStd[1]); + } else { + /* Use our pipe for stdout. Duplicate the handle since our waker + thread will use the original. Do not make it inherited yet. */ + if (!DuplicateHandle(GetCurrentProcess(), + cp->Pipe[KWSYSPE_PIPE_STDOUT].Write, + GetCurrentProcess(), &cp->PipeChildStd[1], 0, FALSE, + DUPLICATE_SAME_ACCESS)) { + kwsysProcessCleanup(cp, GetLastError()); + return; + } + } + + /* Create stderr pipe to be shared by all processes in the pipeline. + We always create this so the pipe thread can run even if we do not + end up giving the write end to the child below. */ + if (!CreatePipe(&cp->Pipe[KWSYSPE_PIPE_STDERR].Read, + &cp->Pipe[KWSYSPE_PIPE_STDERR].Write, 0, 0)) { + kwsysProcessCleanup(cp, GetLastError()); + return; + } + + if (cp->PipeFileSTDERR) { + /* Use a file for stderr. */ + DWORD error = kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[2], + cp->PipeFileSTDERR); + if (error) { + kwsysProcessCleanup(cp, error); + return; + } + } else if (cp->PipeSharedSTDERR) { + /* Use the parent stderr. */ + kwsysProcessSetupSharedPipe(STD_ERROR_HANDLE, &cp->PipeChildStd[2]); + } else if (cp->PipeNativeSTDERR[1]) { + /* Use the given handle for stderr. */ + kwsysProcessSetupPipeNative(cp->PipeNativeSTDERR[1], &cp->PipeChildStd[2]); + } else { + /* Use our pipe for stderr. Duplicate the handle since our waker + thread will use the original. Do not make it inherited yet. */ + if (!DuplicateHandle(GetCurrentProcess(), + cp->Pipe[KWSYSPE_PIPE_STDERR].Write, + GetCurrentProcess(), &cp->PipeChildStd[2], 0, FALSE, + DUPLICATE_SAME_ACCESS)) { + kwsysProcessCleanup(cp, GetLastError()); + return; + } + } + + /* Create the pipeline of processes. */ + { + /* Child startup control data. */ + kwsysProcessCreateInformation si; + HANDLE nextStdInput = cp->PipeChildStd[0]; + + /* Initialize startup info data. */ + ZeroMemory(&si, sizeof(si)); + si.StartupInfo.cb = sizeof(si.StartupInfo); + + /* Decide whether a child window should be shown. */ + si.StartupInfo.dwFlags |= STARTF_USESHOWWINDOW; + si.StartupInfo.wShowWindow = + (unsigned short)(cp->HideWindow ? SW_HIDE : SW_SHOWDEFAULT); + + /* Connect the child's output pipes to the threads. */ + si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES; + + for (i = 0; i < cp->NumberOfCommands; ++i) { + /* Setup the process's pipes. */ + si.hStdInput = nextStdInput; + if (i == cp->NumberOfCommands - 1) { + /* The last child gets the overall stdout. */ + nextStdInput = INVALID_HANDLE_VALUE; + si.hStdOutput = cp->PipeChildStd[1]; + } else { + /* Create a pipe to sit between the children. */ + HANDLE p[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE }; + if (!CreatePipe(&p[0], &p[1], 0, 0)) { + DWORD error = GetLastError(); + if (nextStdInput != cp->PipeChildStd[0]) { + kwsysProcessCleanupHandle(&nextStdInput); + } + kwsysProcessCleanup(cp, error); + return; + } + nextStdInput = p[0]; + si.hStdOutput = p[1]; + } + si.hStdError = + cp->MergeOutput ? cp->PipeChildStd[1] : cp->PipeChildStd[2]; + + { + DWORD error = kwsysProcessCreate(cp, i, &si); + + /* Close our copies of pipes used between children. */ + if (si.hStdInput != cp->PipeChildStd[0]) { + kwsysProcessCleanupHandle(&si.hStdInput); + } + if (si.hStdOutput != cp->PipeChildStd[1]) { + kwsysProcessCleanupHandle(&si.hStdOutput); + } + if (si.hStdError != cp->PipeChildStd[2] && !cp->MergeOutput) { + kwsysProcessCleanupHandle(&si.hStdError); + } + if (!error) { + cp->ProcessEvents[i + 1] = cp->ProcessInformation[i].hProcess; + } else { + if (nextStdInput != cp->PipeChildStd[0]) { + kwsysProcessCleanupHandle(&nextStdInput); + } + kwsysProcessCleanup(cp, error); + return; + } + } + } + } + + /* The parent process does not need the child's pipe ends. */ + for (i = 0; i < 3; ++i) { + kwsysProcessCleanupHandle(&cp->PipeChildStd[i]); + } + + /* Restore the working directory. */ + if (cp->RealWorkingDirectory) { + SetCurrentDirectoryW(cp->RealWorkingDirectory); + free(cp->RealWorkingDirectory); + cp->RealWorkingDirectory = 0; + } + + /* The timeout period starts now. */ + cp->StartTime = kwsysProcessTimeGetCurrent(); + cp->TimeoutTime = kwsysProcessTimeFromDouble(-1); + + /* All processes in the pipeline have been started in suspended + mode. Resume them all now. */ + for (i = 0; i < cp->NumberOfCommands; ++i) { + ResumeThread(cp->ProcessInformation[i].hThread); + } + + /* ---- It is no longer safe to call kwsysProcessCleanup. ----- */ + /* Tell the pipe threads that a process has started. */ + for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { + ReleaseSemaphore(cp->Pipe[i].Reader.Ready, 1, 0); + ReleaseSemaphore(cp->Pipe[i].Waker.Ready, 1, 0); + } + + /* We don't care about the children's main threads. */ + for (i = 0; i < cp->NumberOfCommands; ++i) { + kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread); + } + + /* No pipe has reported data. */ + cp->CurrentIndex = KWSYSPE_PIPE_COUNT; + cp->PipesLeft = KWSYSPE_PIPE_COUNT; + + /* The process has now started. */ + cp->State = kwsysProcess_State_Executing; + cp->Detached = cp->OptionDetach; +} + +void kwsysProcess_Disown(kwsysProcess* cp) +{ + int i; + + /* Make sure we are executing a detached process. */ + if (!cp || !cp->Detached || cp->State != kwsysProcess_State_Executing || + cp->TimeoutExpired || cp->Killed || cp->Terminated) { + return; + } + + /* Disable the reading threads. */ + kwsysProcessDisablePipeThreads(cp); + + /* Wait for all pipe threads to reset. */ + for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { + WaitForSingleObject(cp->Pipe[i].Reader.Reset, INFINITE); + WaitForSingleObject(cp->Pipe[i].Waker.Reset, INFINITE); + } + + /* We will not wait for exit, so cleanup now. */ + kwsysProcessCleanup(cp, 0); + + /* The process has been disowned. */ + cp->State = kwsysProcess_State_Disowned; +} + +int kwsysProcess_WaitForData(kwsysProcess* cp, char** data, int* length, + double* userTimeout) +{ + kwsysProcessTime userStartTime; + kwsysProcessTime timeoutLength; + kwsysProcessTime timeoutTime; + DWORD timeout; + int user; + int done = 0; + int expired = 0; + int pipeId = kwsysProcess_Pipe_None; + DWORD w; + + /* Make sure we are executing a process. */ + if (!cp || cp->State != kwsysProcess_State_Executing || cp->Killed || + cp->TimeoutExpired) { + return kwsysProcess_Pipe_None; + } + + /* Record the time at which user timeout period starts. */ + userStartTime = kwsysProcessTimeGetCurrent(); + + /* Calculate the time at which a timeout will expire, and whether it + is the user or process timeout. */ + user = kwsysProcessGetTimeoutTime(cp, userTimeout, &timeoutTime); + + /* Loop until we have a reason to return. */ + while (!done && cp->PipesLeft > 0) { + /* If we previously got data from a thread, let it know we are + done with the data. */ + if (cp->CurrentIndex < KWSYSPE_PIPE_COUNT) { + KWSYSPE_DEBUG((stderr, "releasing reader %d\n", cp->CurrentIndex)); + ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0); + cp->CurrentIndex = KWSYSPE_PIPE_COUNT; + } + + /* Setup a timeout if required. */ + if (kwsysProcessGetTimeoutLeft(&timeoutTime, user ? userTimeout : 0, + &timeoutLength)) { + /* Timeout has already expired. */ + expired = 1; + break; + } + if (timeoutTime.QuadPart < 0) { + timeout = INFINITE; + } else { + timeout = kwsysProcessTimeToDWORD(timeoutLength); + } + + /* Wait for a pipe's thread to signal or a process to terminate. */ + w = WaitForMultipleObjects(cp->ProcessEventsLength, cp->ProcessEvents, 0, + timeout); + if (w == WAIT_TIMEOUT) { + /* Timeout has expired. */ + expired = 1; + done = 1; + } else if (w == WAIT_OBJECT_0) { + /* Save the index of the reporting thread and release the mutex. + The thread will block until we signal its Empty mutex. */ + cp->CurrentIndex = cp->SharedIndex; + ReleaseSemaphore(cp->SharedIndexMutex, 1, 0); + + /* Data are available or a pipe closed. */ + if (cp->Pipe[cp->CurrentIndex].Closed) { + /* The pipe closed at the write end. Close the read end and + inform the wakeup thread it is done with this process. */ + kwsysProcessCleanupHandle(&cp->Pipe[cp->CurrentIndex].Read); + ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Waker.Go, 1, 0); + KWSYSPE_DEBUG((stderr, "wakeup %d\n", cp->CurrentIndex)); + --cp->PipesLeft; + } else if (data && length) { + /* Report this data. */ + *data = cp->Pipe[cp->CurrentIndex].DataBuffer; + *length = cp->Pipe[cp->CurrentIndex].DataLength; + switch (cp->CurrentIndex) { + case KWSYSPE_PIPE_STDOUT: + pipeId = kwsysProcess_Pipe_STDOUT; + break; + case KWSYSPE_PIPE_STDERR: + pipeId = kwsysProcess_Pipe_STDERR; + break; + } + done = 1; + } + } else { + /* A process has terminated. */ + kwsysProcessDestroy(cp, w - WAIT_OBJECT_0); + } + } + + /* Update the user timeout. */ + if (userTimeout) { + kwsysProcessTime userEndTime = kwsysProcessTimeGetCurrent(); + kwsysProcessTime difference = + kwsysProcessTimeSubtract(userEndTime, userStartTime); + double d = kwsysProcessTimeToDouble(difference); + *userTimeout -= d; + if (*userTimeout < 0) { + *userTimeout = 0; + } + } + + /* Check what happened. */ + if (pipeId) { + /* Data are ready on a pipe. */ + return pipeId; + } else if (expired) { + /* A timeout has expired. */ + if (user) { + /* The user timeout has expired. It has no time left. */ + return kwsysProcess_Pipe_Timeout; + } else { + /* The process timeout has expired. Kill the child now. */ + KWSYSPE_DEBUG((stderr, "killing child because timeout expired\n")); + kwsysProcess_Kill(cp); + cp->TimeoutExpired = 1; + cp->Killed = 0; + return kwsysProcess_Pipe_None; + } + } else { + /* The children have terminated and no more data are available. */ + return kwsysProcess_Pipe_None; + } +} + +int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout) +{ + int i; + int pipe; + + /* Make sure we are executing a process. */ + if (!cp || cp->State != kwsysProcess_State_Executing) { + return 1; + } + + /* Wait for the process to terminate. Ignore all data. */ + while ((pipe = kwsysProcess_WaitForData(cp, 0, 0, userTimeout)) > 0) { + if (pipe == kwsysProcess_Pipe_Timeout) { + /* The user timeout has expired. */ + return 0; + } + } + + KWSYSPE_DEBUG((stderr, "no more data\n")); + + /* When the last pipe closes in WaitForData, the loop terminates + without releasing the pipe's thread. Release it now. */ + if (cp->CurrentIndex < KWSYSPE_PIPE_COUNT) { + KWSYSPE_DEBUG((stderr, "releasing reader %d\n", cp->CurrentIndex)); + ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0); + cp->CurrentIndex = KWSYSPE_PIPE_COUNT; + } + + /* Wait for all pipe threads to reset. */ + for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { + KWSYSPE_DEBUG((stderr, "waiting reader reset %d\n", i)); + WaitForSingleObject(cp->Pipe[i].Reader.Reset, INFINITE); + KWSYSPE_DEBUG((stderr, "waiting waker reset %d\n", i)); + WaitForSingleObject(cp->Pipe[i].Waker.Reset, INFINITE); + } + + /* ---- It is now safe again to call kwsysProcessCleanup. ----- */ + /* Close all the pipes. */ + kwsysProcessCleanup(cp, 0); + + /* Determine the outcome. */ + if (cp->Killed) { + /* We killed the child. */ + cp->State = kwsysProcess_State_Killed; + } else if (cp->TimeoutExpired) { + /* The timeout expired. */ + cp->State = kwsysProcess_State_Expired; + } else { + /* The children exited. Report the outcome of the child processes. */ + for (i = 0; i < cp->NumberOfCommands; ++i) { + cp->ProcessResults[i].ExitCode = cp->CommandExitCodes[i]; + if ((cp->ProcessResults[i].ExitCode & 0xF0000000) == 0xC0000000) { + /* Child terminated due to exceptional behavior. */ + cp->ProcessResults[i].State = kwsysProcess_StateByIndex_Exception; + cp->ProcessResults[i].ExitValue = 1; + kwsysProcessSetExitExceptionByIndex(cp, cp->ProcessResults[i].ExitCode, + i); + } else { + /* Child exited without exception. */ + cp->ProcessResults[i].State = kwsysProcess_StateByIndex_Exited; + cp->ProcessResults[i].ExitException = kwsysProcess_Exception_None; + cp->ProcessResults[i].ExitValue = cp->ProcessResults[i].ExitCode; + } + } + /* support legacy state status value */ + cp->State = cp->ProcessResults[cp->NumberOfCommands - 1].State; + } + + return 1; +} + +void kwsysProcess_Interrupt(kwsysProcess* cp) +{ + int i; + /* Make sure we are executing a process. */ + if (!cp || cp->State != kwsysProcess_State_Executing || cp->TimeoutExpired || + cp->Killed) { + KWSYSPE_DEBUG((stderr, "interrupt: child not executing\n")); + return; + } + + /* Skip actually interrupting the child if it has already terminated. */ + if (cp->Terminated) { + KWSYSPE_DEBUG((stderr, "interrupt: child already terminated\n")); + return; + } + + /* Interrupt the children. */ + if (cp->CreateProcessGroup) { + if (cp->ProcessInformation) { + for (i = 0; i < cp->NumberOfCommands; ++i) { + /* Make sure the process handle isn't closed (e.g. from disowning). */ + if (cp->ProcessInformation[i].hProcess) { + /* The user created a process group for this process. The group ID + is the process ID for the original process in the group. Note + that we have to use Ctrl+Break: Ctrl+C is not allowed for process + groups. */ + GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, + cp->ProcessInformation[i].dwProcessId); + } + } + } + } else { + /* No process group was created. Kill our own process group... */ + GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0); + } +} + +void kwsysProcess_Kill(kwsysProcess* cp) +{ + int i; + /* Make sure we are executing a process. */ + if (!cp || cp->State != kwsysProcess_State_Executing || cp->TimeoutExpired || + cp->Killed) { + KWSYSPE_DEBUG((stderr, "kill: child not executing\n")); + return; + } + + /* Disable the reading threads. */ + KWSYSPE_DEBUG((stderr, "kill: disabling pipe threads\n")); + kwsysProcessDisablePipeThreads(cp); + + /* Skip actually killing the child if it has already terminated. */ + if (cp->Terminated) { + KWSYSPE_DEBUG((stderr, "kill: child already terminated\n")); + return; + } + + /* Kill the children. */ + cp->Killed = 1; + for (i = 0; i < cp->NumberOfCommands; ++i) { + kwsysProcessKillTree(cp->ProcessInformation[i].dwProcessId); + /* Remove from global list of processes and close handles. */ + kwsysProcessesRemove(cp->ProcessInformation[i].hProcess); + kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread); + kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hProcess); + } + + /* We are killing the children and ignoring all data. Do not wait + for them to exit. */ +} + +void kwsysProcess_KillPID(unsigned long process_id) +{ + kwsysProcessKillTree((DWORD)process_id); +} + +/* + Function executed for each pipe's thread. Argument is a pointer to + the kwsysProcessPipeData instance for this thread. +*/ +DWORD WINAPI kwsysProcessPipeThreadRead(LPVOID ptd) +{ + kwsysProcessPipeData* td = (kwsysProcessPipeData*)ptd; + kwsysProcess* cp = td->Process; + + /* Wait for a process to be ready. */ + while ((WaitForSingleObject(td->Reader.Ready, INFINITE), !cp->Deleting)) { + /* Read output from the process for this thread's pipe. */ + kwsysProcessPipeThreadReadPipe(cp, td); + + /* Signal the main thread we have reset for a new process. */ + ReleaseSemaphore(td->Reader.Reset, 1, 0); + } + return 0; +} + +/* + Function called in each pipe's thread to handle data for one + execution of a subprocess. +*/ +void kwsysProcessPipeThreadReadPipe(kwsysProcess* cp, kwsysProcessPipeData* td) +{ + /* Wait for space in the thread's buffer. */ + while ((KWSYSPE_DEBUG((stderr, "wait for read %d\n", td->Index)), + WaitForSingleObject(td->Reader.Go, INFINITE), !td->Closed)) { + KWSYSPE_DEBUG((stderr, "reading %d\n", td->Index)); + + /* Read data from the pipe. This may block until data are available. */ + if (!ReadFile(td->Read, td->DataBuffer, KWSYSPE_PIPE_BUFFER_SIZE, + &td->DataLength, 0)) { + if (GetLastError() != ERROR_BROKEN_PIPE) { + /* UNEXPECTED failure to read the pipe. */ + } + + /* The pipe closed. There are no more data to read. */ + td->Closed = 1; + KWSYSPE_DEBUG((stderr, "read closed %d\n", td->Index)); + } + + KWSYSPE_DEBUG((stderr, "read %d\n", td->Index)); + + /* Wait for our turn to be handled by the main thread. */ + WaitForSingleObject(cp->SharedIndexMutex, INFINITE); + + KWSYSPE_DEBUG((stderr, "reporting read %d\n", td->Index)); + + /* Tell the main thread we have something to report. */ + cp->SharedIndex = td->Index; + ReleaseSemaphore(cp->Full, 1, 0); + } + + /* We were signalled to exit with our buffer empty. Reset the + mutex for a new process. */ + KWSYSPE_DEBUG((stderr, "self releasing reader %d\n", td->Index)); + ReleaseSemaphore(td->Reader.Go, 1, 0); +} + +/* + Function executed for each pipe's thread. Argument is a pointer to + the kwsysProcessPipeData instance for this thread. +*/ +DWORD WINAPI kwsysProcessPipeThreadWake(LPVOID ptd) +{ + kwsysProcessPipeData* td = (kwsysProcessPipeData*)ptd; + kwsysProcess* cp = td->Process; + + /* Wait for a process to be ready. */ + while ((WaitForSingleObject(td->Waker.Ready, INFINITE), !cp->Deleting)) { + /* Wait for a possible wakeup. */ + kwsysProcessPipeThreadWakePipe(cp, td); + + /* Signal the main thread we have reset for a new process. */ + ReleaseSemaphore(td->Waker.Reset, 1, 0); + } + return 0; +} + +/* + Function called in each pipe's thread to handle reading thread + wakeup for one execution of a subprocess. +*/ +void kwsysProcessPipeThreadWakePipe(kwsysProcess* cp, kwsysProcessPipeData* td) +{ + (void)cp; + + /* Wait for a possible wake command. */ + KWSYSPE_DEBUG((stderr, "wait for wake %d\n", td->Index)); + WaitForSingleObject(td->Waker.Go, INFINITE); + KWSYSPE_DEBUG((stderr, "waking %d\n", td->Index)); + + /* If the pipe is not closed, we need to wake up the reading thread. */ + if (!td->Closed) { + DWORD dummy; + KWSYSPE_DEBUG((stderr, "waker %d writing byte\n", td->Index)); + WriteFile(td->Write, "", 1, &dummy, 0); + KWSYSPE_DEBUG((stderr, "waker %d wrote byte\n", td->Index)); + } +} + +/* Initialize a process control structure for kwsysProcess_Execute. */ +int kwsysProcessInitialize(kwsysProcess* cp) +{ + int i; + /* Reset internal status flags. */ + cp->TimeoutExpired = 0; + cp->Terminated = 0; + cp->Killed = 0; + + free(cp->ProcessResults); + /* Allocate process result information for each process. */ + cp->ProcessResults = (kwsysProcessResults*)malloc( + sizeof(kwsysProcessResults) * (cp->NumberOfCommands)); + if (!cp->ProcessResults) { + return 0; + } + ZeroMemory(cp->ProcessResults, + sizeof(kwsysProcessResults) * cp->NumberOfCommands); + for (i = 0; i < cp->NumberOfCommands; i++) { + cp->ProcessResults[i].ExitException = kwsysProcess_Exception_None; + cp->ProcessResults[i].State = kwsysProcess_StateByIndex_Starting; + cp->ProcessResults[i].ExitCode = 1; + cp->ProcessResults[i].ExitValue = 1; + strcpy(cp->ProcessResults[i].ExitExceptionString, "No exception"); + } + + /* Allocate process information for each process. */ + free(cp->ProcessInformation); + cp->ProcessInformation = (PROCESS_INFORMATION*)malloc( + sizeof(PROCESS_INFORMATION) * cp->NumberOfCommands); + if (!cp->ProcessInformation) { + return 0; + } + ZeroMemory(cp->ProcessInformation, + sizeof(PROCESS_INFORMATION) * cp->NumberOfCommands); + free(cp->CommandExitCodes); + cp->CommandExitCodes = (DWORD*)malloc(sizeof(DWORD) * cp->NumberOfCommands); + if (!cp->CommandExitCodes) { + return 0; + } + ZeroMemory(cp->CommandExitCodes, sizeof(DWORD) * cp->NumberOfCommands); + + /* Allocate event wait array. The first event is cp->Full, the rest + are the process termination events. */ + cp->ProcessEvents = + (PHANDLE)malloc(sizeof(HANDLE) * (cp->NumberOfCommands + 1)); + if (!cp->ProcessEvents) { + return 0; + } + ZeroMemory(cp->ProcessEvents, sizeof(HANDLE) * (cp->NumberOfCommands + 1)); + cp->ProcessEvents[0] = cp->Full; + cp->ProcessEventsLength = cp->NumberOfCommands + 1; + + /* Allocate space to save the real working directory of this process. */ + if (cp->WorkingDirectory) { + cp->RealWorkingDirectoryLength = GetCurrentDirectoryW(0, 0); + if (cp->RealWorkingDirectoryLength > 0) { + cp->RealWorkingDirectory = + malloc(cp->RealWorkingDirectoryLength * sizeof(wchar_t)); + if (!cp->RealWorkingDirectory) { + return 0; + } + } + } + { + for (i = 0; i < 3; ++i) { + cp->PipeChildStd[i] = INVALID_HANDLE_VALUE; + } + } + + return 1; +} + +static DWORD kwsysProcessCreateChildHandle(PHANDLE out, HANDLE in, int isStdIn) +{ + DWORD flags; + + /* Check whether the handle is valid for this process. */ + if (in != INVALID_HANDLE_VALUE && GetHandleInformation(in, &flags)) { + /* Use the handle as-is if it is already inherited. */ + if (flags & HANDLE_FLAG_INHERIT) { + *out = in; + return ERROR_SUCCESS; + } + + /* Create an inherited copy of this handle. */ + if (DuplicateHandle(GetCurrentProcess(), in, GetCurrentProcess(), out, 0, + TRUE, DUPLICATE_SAME_ACCESS)) { + return ERROR_SUCCESS; + } else { + return GetLastError(); + } + } else { + /* The given handle is not valid for this process. Some child + processes may break if they do not have a valid standard handle, + so open NUL to give to the child. */ + SECURITY_ATTRIBUTES sa; + ZeroMemory(&sa, sizeof(sa)); + sa.nLength = (DWORD)sizeof(sa); + sa.bInheritHandle = 1; + *out = CreateFileW( + L"NUL", + (isStdIn ? GENERIC_READ : (GENERIC_WRITE | FILE_READ_ATTRIBUTES)), + FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, OPEN_EXISTING, 0, 0); + return (*out != INVALID_HANDLE_VALUE) ? ERROR_SUCCESS : GetLastError(); + } +} + +DWORD kwsysProcessCreate(kwsysProcess* cp, int index, + kwsysProcessCreateInformation* si) +{ + DWORD creationFlags; + DWORD error = ERROR_SUCCESS; + + /* Check if we are currently exiting. */ + if (!kwsysTryEnterCreateProcessSection()) { + /* The Ctrl handler is currently working on exiting our process. Rather + than return an error code, which could cause incorrect conclusions to be + reached by the caller, we simply hang. (For example, a CMake try_run + configure step might cause the project to configure wrong.) */ + Sleep(INFINITE); + } + + /* Create the child in a suspended state so we can wait until all + children have been created before running any one. */ + creationFlags = CREATE_SUSPENDED; + if (cp->CreateProcessGroup) { + creationFlags |= CREATE_NEW_PROCESS_GROUP; + } + + /* Create inherited copies of the handles. */ + (error = kwsysProcessCreateChildHandle(&si->StartupInfo.hStdInput, + si->hStdInput, 1)) || + (error = kwsysProcessCreateChildHandle(&si->StartupInfo.hStdOutput, + si->hStdOutput, 0)) || + (error = kwsysProcessCreateChildHandle(&si->StartupInfo.hStdError, + si->hStdError, 0)) || + /* Create the process. */ + (!CreateProcessW(0, cp->Commands[index], 0, 0, TRUE, creationFlags, 0, 0, + &si->StartupInfo, &cp->ProcessInformation[index]) && + (error = GetLastError())); + + /* Close the inherited copies of the handles. */ + if (si->StartupInfo.hStdInput != si->hStdInput) { + kwsysProcessCleanupHandle(&si->StartupInfo.hStdInput); + } + if (si->StartupInfo.hStdOutput != si->hStdOutput) { + kwsysProcessCleanupHandle(&si->StartupInfo.hStdOutput); + } + if (si->StartupInfo.hStdError != si->hStdError) { + kwsysProcessCleanupHandle(&si->StartupInfo.hStdError); + } + + /* Add the process to the global list of processes. */ + if (!error && + !kwsysProcessesAdd(cp->ProcessInformation[index].hProcess, + cp->ProcessInformation[index].dwProcessId, + cp->CreateProcessGroup)) { + /* This failed for some reason. Kill the suspended process. */ + TerminateProcess(cp->ProcessInformation[index].hProcess, 1); + /* And clean up... */ + kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hProcess); + kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hThread); + strcpy(cp->ErrorMessage, "kwsysProcessesAdd function failed"); + error = ERROR_NOT_ENOUGH_MEMORY; /* Most likely reason. */ + } + + /* If the console Ctrl handler is waiting for us, this will release it... */ + kwsysLeaveCreateProcessSection(); + return error; +} + +void kwsysProcessDestroy(kwsysProcess* cp, int event) +{ + int i; + int index; + + /* Find the process index for the termination event. */ + for (index = 0; index < cp->NumberOfCommands; ++index) { + if (cp->ProcessInformation[index].hProcess == cp->ProcessEvents[event]) { + break; + } + } + + /* Check the exit code of the process. */ + GetExitCodeProcess(cp->ProcessInformation[index].hProcess, + &cp->CommandExitCodes[index]); + + /* Remove from global list of processes. */ + kwsysProcessesRemove(cp->ProcessInformation[index].hProcess); + + /* Close the process handle for the terminated process. */ + kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hProcess); + + /* Remove the process from the available events. */ + cp->ProcessEventsLength -= 1; + for (i = event; i < cp->ProcessEventsLength; ++i) { + cp->ProcessEvents[i] = cp->ProcessEvents[i + 1]; + } + + /* Check if all processes have terminated. */ + if (cp->ProcessEventsLength == 1) { + cp->Terminated = 1; + + /* Close our copies of the pipe write handles so the pipe threads + can detect end-of-data. */ + for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { + /* TODO: If the child created its own child (our grandchild) + which inherited a copy of the pipe write-end then the pipe + may not close and we will still need the waker write pipe. + However we still want to be able to detect end-of-data in the + normal case. The reader thread will have to switch to using + PeekNamedPipe to read the last bit of data from the pipe + without blocking. This is equivalent to using a non-blocking + read on posix. */ + KWSYSPE_DEBUG((stderr, "closing wakeup write %d\n", i)); + kwsysProcessCleanupHandle(&cp->Pipe[i].Write); + } + } +} + +DWORD kwsysProcessSetupOutputPipeFile(PHANDLE phandle, const char* name) +{ + HANDLE fout; + wchar_t* wname; + DWORD error; + if (!name) { + return ERROR_INVALID_PARAMETER; + } + + /* Close the existing handle. */ + kwsysProcessCleanupHandle(phandle); + + /* Create a handle to write a file for the pipe. */ + wname = kwsysEncoding_DupToWide(name); + fout = + CreateFileW(wname, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0); + error = GetLastError(); + free(wname); + if (fout == INVALID_HANDLE_VALUE) { + return error; + } + + /* Assign the replacement handle. */ + *phandle = fout; + return ERROR_SUCCESS; +} + +void kwsysProcessSetupSharedPipe(DWORD nStdHandle, PHANDLE handle) +{ + /* Close the existing handle. */ + kwsysProcessCleanupHandle(handle); + /* Store the new standard handle. */ + *handle = GetStdHandle(nStdHandle); +} + +void kwsysProcessSetupPipeNative(HANDLE native, PHANDLE handle) +{ + /* Close the existing handle. */ + kwsysProcessCleanupHandle(handle); + /* Store the new given handle. */ + *handle = native; +} + +/* Close the given handle if it is open. Reset its value to 0. */ +void kwsysProcessCleanupHandle(PHANDLE h) +{ + if (h && *h && *h != INVALID_HANDLE_VALUE && + *h != GetStdHandle(STD_INPUT_HANDLE) && + *h != GetStdHandle(STD_OUTPUT_HANDLE) && + *h != GetStdHandle(STD_ERROR_HANDLE)) { + CloseHandle(*h); + *h = INVALID_HANDLE_VALUE; + } +} + +/* Close all handles created by kwsysProcess_Execute. */ +void kwsysProcessCleanup(kwsysProcess* cp, DWORD error) +{ + int i; + /* If this is an error case, report the error. */ + if (error) { + /* Construct an error message if one has not been provided already. */ + if (cp->ErrorMessage[0] == 0) { + /* Format the error message. */ + wchar_t err_msg[KWSYSPE_PIPE_BUFFER_SIZE]; + DWORD length = FormatMessageW( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, error, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err_msg, + KWSYSPE_PIPE_BUFFER_SIZE, 0); + if (length < 1) { + /* FormatMessage failed. Use a default message. */ + _snprintf(cp->ErrorMessage, KWSYSPE_PIPE_BUFFER_SIZE, + "Process execution failed with error 0x%X. " + "FormatMessage failed with error 0x%X", + error, GetLastError()); + } + if (!WideCharToMultiByte(CP_UTF8, 0, err_msg, -1, cp->ErrorMessage, + KWSYSPE_PIPE_BUFFER_SIZE, NULL, NULL)) { + /* WideCharToMultiByte failed. Use a default message. */ + _snprintf(cp->ErrorMessage, KWSYSPE_PIPE_BUFFER_SIZE, + "Process execution failed with error 0x%X. " + "WideCharToMultiByte failed with error 0x%X", + error, GetLastError()); + } + } + + /* Remove trailing period and newline, if any. */ + kwsysProcessCleanErrorMessage(cp); + + /* Set the error state. */ + cp->State = kwsysProcess_State_Error; + + /* Cleanup any processes already started in a suspended state. */ + if (cp->ProcessInformation) { + for (i = 0; i < cp->NumberOfCommands; ++i) { + if (cp->ProcessInformation[i].hProcess) { + TerminateProcess(cp->ProcessInformation[i].hProcess, 255); + WaitForSingleObject(cp->ProcessInformation[i].hProcess, INFINITE); + } + } + for (i = 0; i < cp->NumberOfCommands; ++i) { + /* Remove from global list of processes and close handles. */ + kwsysProcessesRemove(cp->ProcessInformation[i].hProcess); + kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread); + kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hProcess); + } + } + + /* Restore the working directory. */ + if (cp->RealWorkingDirectory) { + SetCurrentDirectoryW(cp->RealWorkingDirectory); + } + } + + /* Free memory. */ + if (cp->ProcessInformation) { + free(cp->ProcessInformation); + cp->ProcessInformation = 0; + } + if (cp->ProcessEvents) { + free(cp->ProcessEvents); + cp->ProcessEvents = 0; + } + if (cp->RealWorkingDirectory) { + free(cp->RealWorkingDirectory); + cp->RealWorkingDirectory = 0; + } + + /* Close each pipe. */ + for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { + kwsysProcessCleanupHandle(&cp->Pipe[i].Write); + kwsysProcessCleanupHandle(&cp->Pipe[i].Read); + cp->Pipe[i].Closed = 0; + } + for (i = 0; i < 3; ++i) { + kwsysProcessCleanupHandle(&cp->PipeChildStd[i]); + } +} + +void kwsysProcessCleanErrorMessage(kwsysProcess* cp) +{ + /* Remove trailing period and newline, if any. */ + size_t length = strlen(cp->ErrorMessage); + if (cp->ErrorMessage[length - 1] == '\n') { + cp->ErrorMessage[length - 1] = 0; + --length; + if (length > 0 && cp->ErrorMessage[length - 1] == '\r') { + cp->ErrorMessage[length - 1] = 0; + --length; + } + } + if (length > 0 && cp->ErrorMessage[length - 1] == '.') { + cp->ErrorMessage[length - 1] = 0; + } +} + +/* Get the time at which either the process or user timeout will + expire. Returns 1 if the user timeout is first, and 0 otherwise. */ +int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout, + kwsysProcessTime* timeoutTime) +{ + /* The first time this is called, we need to calculate the time at + which the child will timeout. */ + if (cp->Timeout && cp->TimeoutTime.QuadPart < 0) { + kwsysProcessTime length = kwsysProcessTimeFromDouble(cp->Timeout); + cp->TimeoutTime = kwsysProcessTimeAdd(cp->StartTime, length); + } + + /* Start with process timeout. */ + *timeoutTime = cp->TimeoutTime; + + /* Check if the user timeout is earlier. */ + if (userTimeout) { + kwsysProcessTime currentTime = kwsysProcessTimeGetCurrent(); + kwsysProcessTime userTimeoutLength = + kwsysProcessTimeFromDouble(*userTimeout); + kwsysProcessTime userTimeoutTime = + kwsysProcessTimeAdd(currentTime, userTimeoutLength); + if (timeoutTime->QuadPart < 0 || + kwsysProcessTimeLess(userTimeoutTime, *timeoutTime)) { + *timeoutTime = userTimeoutTime; + return 1; + } + } + return 0; +} + +/* Get the length of time before the given timeout time arrives. + Returns 1 if the time has already arrived, and 0 otherwise. */ +int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime, + double* userTimeout, + kwsysProcessTime* timeoutLength) +{ + if (timeoutTime->QuadPart < 0) { + /* No timeout time has been requested. */ + return 0; + } else { + /* Calculate the remaining time. */ + kwsysProcessTime currentTime = kwsysProcessTimeGetCurrent(); + *timeoutLength = kwsysProcessTimeSubtract(*timeoutTime, currentTime); + + if (timeoutLength->QuadPart < 0 && userTimeout && *userTimeout <= 0) { + /* Caller has explicitly requested a zero timeout. */ + timeoutLength->QuadPart = 0; + } + + if (timeoutLength->QuadPart < 0) { + /* Timeout has already expired. */ + return 1; + } else { + /* There is some time left. */ + return 0; + } + } +} + +kwsysProcessTime kwsysProcessTimeGetCurrent() +{ + kwsysProcessTime current; + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + current.LowPart = ft.dwLowDateTime; + current.HighPart = ft.dwHighDateTime; + return current; +} + +DWORD kwsysProcessTimeToDWORD(kwsysProcessTime t) +{ + return (DWORD)(t.QuadPart * 0.0001); +} + +double kwsysProcessTimeToDouble(kwsysProcessTime t) +{ + return t.QuadPart * 0.0000001; +} + +kwsysProcessTime kwsysProcessTimeFromDouble(double d) +{ + kwsysProcessTime t; + t.QuadPart = (LONGLONG)(d * 10000000); + return t; +} + +int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2) +{ + return in1.QuadPart < in2.QuadPart; +} + +kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1, + kwsysProcessTime in2) +{ + kwsysProcessTime out; + out.QuadPart = in1.QuadPart + in2.QuadPart; + return out; +} + +kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, + kwsysProcessTime in2) +{ + kwsysProcessTime out; + out.QuadPart = in1.QuadPart - in2.QuadPart; + return out; +} + +#define KWSYSPE_CASE(type, str) \ + cp->ProcessResults[idx].ExitException = kwsysProcess_Exception_##type; \ + strcpy(cp->ProcessResults[idx].ExitExceptionString, str) +static void kwsysProcessSetExitExceptionByIndex(kwsysProcess* cp, int code, + int idx) +{ + switch (code) { + case STATUS_CONTROL_C_EXIT: + KWSYSPE_CASE(Interrupt, "User interrupt"); + break; + + case STATUS_FLOAT_DENORMAL_OPERAND: + KWSYSPE_CASE(Numerical, "Floating-point exception (denormal operand)"); + break; + case STATUS_FLOAT_DIVIDE_BY_ZERO: + KWSYSPE_CASE(Numerical, "Divide-by-zero"); + break; + case STATUS_FLOAT_INEXACT_RESULT: + KWSYSPE_CASE(Numerical, "Floating-point exception (inexact result)"); + break; + case STATUS_FLOAT_INVALID_OPERATION: + KWSYSPE_CASE(Numerical, "Invalid floating-point operation"); + break; + case STATUS_FLOAT_OVERFLOW: + KWSYSPE_CASE(Numerical, "Floating-point overflow"); + break; + case STATUS_FLOAT_STACK_CHECK: + KWSYSPE_CASE(Numerical, "Floating-point stack check failed"); + break; + case STATUS_FLOAT_UNDERFLOW: + KWSYSPE_CASE(Numerical, "Floating-point underflow"); + break; +#ifdef STATUS_FLOAT_MULTIPLE_FAULTS + case STATUS_FLOAT_MULTIPLE_FAULTS: + KWSYSPE_CASE(Numerical, "Floating-point exception (multiple faults)"); + break; +#endif +#ifdef STATUS_FLOAT_MULTIPLE_TRAPS + case STATUS_FLOAT_MULTIPLE_TRAPS: + KWSYSPE_CASE(Numerical, "Floating-point exception (multiple traps)"); + break; +#endif + case STATUS_INTEGER_DIVIDE_BY_ZERO: + KWSYSPE_CASE(Numerical, "Integer divide-by-zero"); + break; + case STATUS_INTEGER_OVERFLOW: + KWSYSPE_CASE(Numerical, "Integer overflow"); + break; + + case STATUS_DATATYPE_MISALIGNMENT: + KWSYSPE_CASE(Fault, "Datatype misalignment"); + break; + case STATUS_ACCESS_VIOLATION: + KWSYSPE_CASE(Fault, "Access violation"); + break; + case STATUS_IN_PAGE_ERROR: + KWSYSPE_CASE(Fault, "In-page error"); + break; + case STATUS_INVALID_HANDLE: + KWSYSPE_CASE(Fault, "Invalid hanlde"); + break; + case STATUS_NONCONTINUABLE_EXCEPTION: + KWSYSPE_CASE(Fault, "Noncontinuable exception"); + break; + case STATUS_INVALID_DISPOSITION: + KWSYSPE_CASE(Fault, "Invalid disposition"); + break; + case STATUS_ARRAY_BOUNDS_EXCEEDED: + KWSYSPE_CASE(Fault, "Array bounds exceeded"); + break; + case STATUS_STACK_OVERFLOW: + KWSYSPE_CASE(Fault, "Stack overflow"); + break; + + case STATUS_ILLEGAL_INSTRUCTION: + KWSYSPE_CASE(Illegal, "Illegal instruction"); + break; + case STATUS_PRIVILEGED_INSTRUCTION: + KWSYSPE_CASE(Illegal, "Privileged instruction"); + break; + + case STATUS_NO_MEMORY: + default: + cp->ProcessResults[idx].ExitException = kwsysProcess_Exception_Other; + _snprintf(cp->ProcessResults[idx].ExitExceptionString, + KWSYSPE_PIPE_BUFFER_SIZE, "Exit code 0x%x\n", code); + break; + } +} +#undef KWSYSPE_CASE + +typedef struct kwsysProcess_List_s kwsysProcess_List; +static kwsysProcess_List* kwsysProcess_List_New(void); +static void kwsysProcess_List_Delete(kwsysProcess_List* self); +static int kwsysProcess_List_Update(kwsysProcess_List* self); +static int kwsysProcess_List_NextProcess(kwsysProcess_List* self); +static int kwsysProcess_List_GetCurrentProcessId(kwsysProcess_List* self); +static int kwsysProcess_List_GetCurrentParentId(kwsysProcess_List* self); + +/* Windows NT 4 API definitions. */ +#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) +typedef LONG NTSTATUS; +typedef LONG KPRIORITY; +typedef struct _UNICODE_STRING UNICODE_STRING; +struct _UNICODE_STRING +{ + USHORT Length; + USHORT MaximumLength; + PWSTR Buffer; +}; + +/* The process information structure. Declare only enough to get + process identifiers. The rest may be ignored because we use the + NextEntryDelta to move through an array of instances. */ +typedef struct _SYSTEM_PROCESS_INFORMATION SYSTEM_PROCESS_INFORMATION; +typedef SYSTEM_PROCESS_INFORMATION* PSYSTEM_PROCESS_INFORMATION; +struct _SYSTEM_PROCESS_INFORMATION +{ + ULONG NextEntryDelta; + ULONG ThreadCount; + ULONG Reserved1[6]; + LARGE_INTEGER CreateTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER KernelTime; + UNICODE_STRING ProcessName; + KPRIORITY BasePriority; + ULONG ProcessId; + ULONG InheritedFromProcessId; +}; + +/* Toolhelp32 API definitions. */ +#define TH32CS_SNAPPROCESS 0x00000002 +#if defined(_WIN64) +typedef unsigned __int64 ProcessULONG_PTR; +#else +typedef unsigned long ProcessULONG_PTR; +#endif +typedef struct tagPROCESSENTRY32 PROCESSENTRY32; +typedef PROCESSENTRY32* LPPROCESSENTRY32; +struct tagPROCESSENTRY32 +{ + DWORD dwSize; + DWORD cntUsage; + DWORD th32ProcessID; + ProcessULONG_PTR th32DefaultHeapID; + DWORD th32ModuleID; + DWORD cntThreads; + DWORD th32ParentProcessID; + LONG pcPriClassBase; + DWORD dwFlags; + char szExeFile[MAX_PATH]; +}; + +/* Windows API function types. */ +typedef HANDLE(WINAPI* CreateToolhelp32SnapshotType)(DWORD, DWORD); +typedef BOOL(WINAPI* Process32FirstType)(HANDLE, LPPROCESSENTRY32); +typedef BOOL(WINAPI* Process32NextType)(HANDLE, LPPROCESSENTRY32); +typedef NTSTATUS(WINAPI* ZwQuerySystemInformationType)(ULONG, PVOID, ULONG, + PULONG); + +static int kwsysProcess_List__New_NT4(kwsysProcess_List* self); +static int kwsysProcess_List__New_Snapshot(kwsysProcess_List* self); +static void kwsysProcess_List__Delete_NT4(kwsysProcess_List* self); +static void kwsysProcess_List__Delete_Snapshot(kwsysProcess_List* self); +static int kwsysProcess_List__Update_NT4(kwsysProcess_List* self); +static int kwsysProcess_List__Update_Snapshot(kwsysProcess_List* self); +static int kwsysProcess_List__Next_NT4(kwsysProcess_List* self); +static int kwsysProcess_List__Next_Snapshot(kwsysProcess_List* self); +static int kwsysProcess_List__GetProcessId_NT4(kwsysProcess_List* self); +static int kwsysProcess_List__GetProcessId_Snapshot(kwsysProcess_List* self); +static int kwsysProcess_List__GetParentId_NT4(kwsysProcess_List* self); +static int kwsysProcess_List__GetParentId_Snapshot(kwsysProcess_List* self); + +struct kwsysProcess_List_s +{ + /* Implementation switches at runtime based on version of Windows. */ + int NT4; + + /* Implementation functions and data for NT 4. */ + ZwQuerySystemInformationType P_ZwQuerySystemInformation; + char* Buffer; + int BufferSize; + PSYSTEM_PROCESS_INFORMATION CurrentInfo; + + /* Implementation functions and data for other Windows versions. */ + CreateToolhelp32SnapshotType P_CreateToolhelp32Snapshot; + Process32FirstType P_Process32First; + Process32NextType P_Process32Next; + HANDLE Snapshot; + PROCESSENTRY32 CurrentEntry; +}; + +static kwsysProcess_List* kwsysProcess_List_New(void) +{ + OSVERSIONINFO osv; + kwsysProcess_List* self; + + /* Allocate and initialize the list object. */ + if (!(self = (kwsysProcess_List*)malloc(sizeof(kwsysProcess_List)))) { + return 0; + } + memset(self, 0, sizeof(*self)); + + /* Select an implementation. */ + ZeroMemory(&osv, sizeof(osv)); + osv.dwOSVersionInfoSize = sizeof(osv); +#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx +# pragma warning(push) +# ifdef __INTEL_COMPILER +# pragma warning(disable : 1478) +# elif defined __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdeprecated-declarations" +# else +# pragma warning(disable : 4996) +# endif +#endif + GetVersionEx(&osv); +#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx +# ifdef __clang__ +# pragma clang diagnostic pop +# else +# pragma warning(pop) +# endif +#endif + self->NT4 = + (osv.dwPlatformId == VER_PLATFORM_WIN32_NT && osv.dwMajorVersion < 5) ? 1 + : 0; + + /* Initialize the selected implementation. */ + if (!(self->NT4 ? kwsysProcess_List__New_NT4(self) + : kwsysProcess_List__New_Snapshot(self))) { + kwsysProcess_List_Delete(self); + return 0; + } + + /* Update to the current set of processes. */ + if (!kwsysProcess_List_Update(self)) { + kwsysProcess_List_Delete(self); + return 0; + } + return self; +} + +static void kwsysProcess_List_Delete(kwsysProcess_List* self) +{ + if (self) { + if (self->NT4) { + kwsysProcess_List__Delete_NT4(self); + } else { + kwsysProcess_List__Delete_Snapshot(self); + } + free(self); + } +} + +static int kwsysProcess_List_Update(kwsysProcess_List* self) +{ + return self ? (self->NT4 ? kwsysProcess_List__Update_NT4(self) + : kwsysProcess_List__Update_Snapshot(self)) + : 0; +} + +static int kwsysProcess_List_GetCurrentProcessId(kwsysProcess_List* self) +{ + return self ? (self->NT4 ? kwsysProcess_List__GetProcessId_NT4(self) + : kwsysProcess_List__GetProcessId_Snapshot(self)) + : -1; +} + +static int kwsysProcess_List_GetCurrentParentId(kwsysProcess_List* self) +{ + return self ? (self->NT4 ? kwsysProcess_List__GetParentId_NT4(self) + : kwsysProcess_List__GetParentId_Snapshot(self)) + : -1; +} + +static int kwsysProcess_List_NextProcess(kwsysProcess_List* self) +{ + return (self ? (self->NT4 ? kwsysProcess_List__Next_NT4(self) + : kwsysProcess_List__Next_Snapshot(self)) + : 0); +} + +static int kwsysProcess_List__New_NT4(kwsysProcess_List* self) +{ + /* Get a handle to the NT runtime module that should already be + loaded in this program. This does not actually increment the + reference count to the module so we do not need to close the + handle. */ + HMODULE hNT = GetModuleHandleW(L"ntdll.dll"); + if (hNT) { + /* Get pointers to the needed API functions. */ + self->P_ZwQuerySystemInformation = + ((ZwQuerySystemInformationType)GetProcAddress( + hNT, "ZwQuerySystemInformation")); + } + if (!self->P_ZwQuerySystemInformation) { + return 0; + } + + /* Allocate an initial process information buffer. */ + self->BufferSize = 32768; + self->Buffer = (char*)malloc(self->BufferSize); + return self->Buffer ? 1 : 0; +} + +static void kwsysProcess_List__Delete_NT4(kwsysProcess_List* self) +{ + /* Free the process information buffer. */ + free(self->Buffer); +} + +static int kwsysProcess_List__Update_NT4(kwsysProcess_List* self) +{ + self->CurrentInfo = 0; + for (;;) { + /* Query number 5 is for system process list. */ + NTSTATUS status = + self->P_ZwQuerySystemInformation(5, self->Buffer, self->BufferSize, 0); + if (status == STATUS_INFO_LENGTH_MISMATCH) { + /* The query requires a bigger buffer. */ + int newBufferSize = self->BufferSize * 2; + char* newBuffer = (char*)malloc(newBufferSize); + if (newBuffer) { + free(self->Buffer); + self->Buffer = newBuffer; + self->BufferSize = newBufferSize; + } else { + return 0; + } + } else if (status >= 0) { + /* The query succeeded. Initialize traversal of the process list. */ + self->CurrentInfo = (PSYSTEM_PROCESS_INFORMATION)self->Buffer; + return 1; + } else { + /* The query failed. */ + return 0; + } + } +} + +static int kwsysProcess_List__Next_NT4(kwsysProcess_List* self) +{ + if (self->CurrentInfo) { + if (self->CurrentInfo->NextEntryDelta > 0) { + self->CurrentInfo = + ((PSYSTEM_PROCESS_INFORMATION)((char*)self->CurrentInfo + + self->CurrentInfo->NextEntryDelta)); + return 1; + } + self->CurrentInfo = 0; + } + return 0; +} + +static int kwsysProcess_List__GetProcessId_NT4(kwsysProcess_List* self) +{ + return self->CurrentInfo ? self->CurrentInfo->ProcessId : -1; +} + +static int kwsysProcess_List__GetParentId_NT4(kwsysProcess_List* self) +{ + return self->CurrentInfo ? self->CurrentInfo->InheritedFromProcessId : -1; +} + +static int kwsysProcess_List__New_Snapshot(kwsysProcess_List* self) +{ + /* Get a handle to the Windows runtime module that should already be + loaded in this program. This does not actually increment the + reference count to the module so we do not need to close the + handle. */ + HMODULE hKernel = GetModuleHandleW(L"kernel32.dll"); + if (hKernel) { + self->P_CreateToolhelp32Snapshot = + ((CreateToolhelp32SnapshotType)GetProcAddress( + hKernel, "CreateToolhelp32Snapshot")); + self->P_Process32First = + ((Process32FirstType)GetProcAddress(hKernel, "Process32First")); + self->P_Process32Next = + ((Process32NextType)GetProcAddress(hKernel, "Process32Next")); + } + return (self->P_CreateToolhelp32Snapshot && self->P_Process32First && + self->P_Process32Next) + ? 1 + : 0; +} + +static void kwsysProcess_List__Delete_Snapshot(kwsysProcess_List* self) +{ + if (self->Snapshot) { + CloseHandle(self->Snapshot); + } +} + +static int kwsysProcess_List__Update_Snapshot(kwsysProcess_List* self) +{ + if (self->Snapshot) { + CloseHandle(self->Snapshot); + } + if (!(self->Snapshot = + self->P_CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0))) { + return 0; + } + ZeroMemory(&self->CurrentEntry, sizeof(self->CurrentEntry)); + self->CurrentEntry.dwSize = sizeof(self->CurrentEntry); + if (!self->P_Process32First(self->Snapshot, &self->CurrentEntry)) { + CloseHandle(self->Snapshot); + self->Snapshot = 0; + return 0; + } + return 1; +} + +static int kwsysProcess_List__Next_Snapshot(kwsysProcess_List* self) +{ + if (self->Snapshot) { + if (self->P_Process32Next(self->Snapshot, &self->CurrentEntry)) { + return 1; + } + CloseHandle(self->Snapshot); + self->Snapshot = 0; + } + return 0; +} + +static int kwsysProcess_List__GetProcessId_Snapshot(kwsysProcess_List* self) +{ + return self->Snapshot ? self->CurrentEntry.th32ProcessID : -1; +} + +static int kwsysProcess_List__GetParentId_Snapshot(kwsysProcess_List* self) +{ + return self->Snapshot ? self->CurrentEntry.th32ParentProcessID : -1; +} + +static void kwsysProcessKill(DWORD pid) +{ + HANDLE h = OpenProcess(PROCESS_TERMINATE, 0, pid); + if (h) { + TerminateProcess(h, 255); + WaitForSingleObject(h, INFINITE); + CloseHandle(h); + } +} + +static void kwsysProcessKillTree(int pid) +{ + kwsysProcess_List* plist = kwsysProcess_List_New(); + kwsysProcessKill(pid); + if (plist) { + do { + if (kwsysProcess_List_GetCurrentParentId(plist) == pid) { + int ppid = kwsysProcess_List_GetCurrentProcessId(plist); + kwsysProcessKillTree(ppid); + } + } while (kwsysProcess_List_NextProcess(plist)); + kwsysProcess_List_Delete(plist); + } +} + +static void kwsysProcessDisablePipeThreads(kwsysProcess* cp) +{ + int i; + + /* If data were just reported data, release the pipe's thread. */ + if (cp->CurrentIndex < KWSYSPE_PIPE_COUNT) { + KWSYSPE_DEBUG((stderr, "releasing reader %d\n", cp->CurrentIndex)); + ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0); + cp->CurrentIndex = KWSYSPE_PIPE_COUNT; + } + + /* Wakeup all reading threads that are not on closed pipes. */ + for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { + /* The wakeup threads will write one byte to the pipe write ends. + If there are no data in the pipe then this is enough to wakeup + the reading threads. If there are already data in the pipe + this may block. We cannot use PeekNamedPipe to check whether + there are data because an outside process might still be + writing data if we are disowning it. Also, PeekNamedPipe will + block if checking a pipe on which the reading thread is + currently calling ReadPipe. Therefore we need a separate + thread to call WriteFile. If it blocks, that is okay because + it will unblock when we close the read end and break the pipe + below. */ + if (cp->Pipe[i].Read) { + KWSYSPE_DEBUG((stderr, "releasing waker %d\n", i)); + ReleaseSemaphore(cp->Pipe[i].Waker.Go, 1, 0); + } + } + + /* Tell pipe threads to reset until we run another process. */ + while (cp->PipesLeft > 0) { + /* The waking threads will cause all reading threads to report. + Wait for the next one and save its index. */ + KWSYSPE_DEBUG((stderr, "waiting for reader\n")); + WaitForSingleObject(cp->Full, INFINITE); + cp->CurrentIndex = cp->SharedIndex; + ReleaseSemaphore(cp->SharedIndexMutex, 1, 0); + KWSYSPE_DEBUG((stderr, "got reader %d\n", cp->CurrentIndex)); + + /* We are done reading this pipe. Close its read handle. */ + cp->Pipe[cp->CurrentIndex].Closed = 1; + kwsysProcessCleanupHandle(&cp->Pipe[cp->CurrentIndex].Read); + --cp->PipesLeft; + + /* Tell the reading thread we are done with the data. It will + reset immediately because the pipe is closed. */ + ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0); + } +} + +/* Global set of executing processes for use by the Ctrl handler. + This global instance will be zero-initialized by the compiler. + + Note that the console Ctrl handler runs on a background thread and so + everything it does must be thread safe. Here, we track the hProcess + HANDLEs directly instead of kwsysProcess instances, so that we don't have + to make kwsysProcess thread safe. */ +typedef struct kwsysProcessInstance_s +{ + HANDLE hProcess; + DWORD dwProcessId; + int NewProcessGroup; /* Whether the process was created in a new group. */ +} kwsysProcessInstance; + +typedef struct kwsysProcessInstances_s +{ + /* Whether we have initialized key fields below, like critical sections. */ + int Initialized; + + /* Ctrl handler runs on a different thread, so we must sync access. */ + CRITICAL_SECTION Lock; + + int Exiting; + size_t Count; + size_t Size; + kwsysProcessInstance* Processes; +} kwsysProcessInstances; +static kwsysProcessInstances kwsysProcesses; + +/* Initialize critial section and set up console Ctrl handler. You MUST call + this before using any other kwsysProcesses* functions below. */ +static int kwsysProcessesInitialize(void) +{ + /* Initialize everything if not done already. */ + if (!kwsysProcesses.Initialized) { + InitializeCriticalSection(&kwsysProcesses.Lock); + + /* Set up console ctrl handler. */ + if (!SetConsoleCtrlHandler(kwsysCtrlHandler, TRUE)) { + return 0; + } + + kwsysProcesses.Initialized = 1; + } + return 1; +} + +/* The Ctrl handler waits on the global list of processes. To prevent an + orphaned process, do not create a new process if the Ctrl handler is + already running. Do so by using this function to check if it is ok to + create a process. */ +static int kwsysTryEnterCreateProcessSection(void) +{ + /* Enter main critical section; this means creating a process and the Ctrl + handler are mutually exclusive. */ + EnterCriticalSection(&kwsysProcesses.Lock); + /* Indicate to the caller if they can create a process. */ + if (kwsysProcesses.Exiting) { + LeaveCriticalSection(&kwsysProcesses.Lock); + return 0; + } else { + return 1; + } +} + +/* Matching function on successful kwsysTryEnterCreateProcessSection return. + Make sure you called kwsysProcessesAdd if applicable before calling this.*/ +static void kwsysLeaveCreateProcessSection(void) +{ + LeaveCriticalSection(&kwsysProcesses.Lock); +} + +/* Add new process to global process list. The Ctrl handler will wait for + the process to exit before it returns. Do not close the process handle + until after calling kwsysProcessesRemove. The newProcessGroup parameter + must be set if the process was created with CREATE_NEW_PROCESS_GROUP. */ +static int kwsysProcessesAdd(HANDLE hProcess, DWORD dwProcessid, + int newProcessGroup) +{ + if (!kwsysProcessesInitialize() || !hProcess || + hProcess == INVALID_HANDLE_VALUE) { + return 0; + } + + /* Enter the critical section. */ + EnterCriticalSection(&kwsysProcesses.Lock); + + /* Make sure there is enough space for the new process handle. */ + if (kwsysProcesses.Count == kwsysProcesses.Size) { + size_t newSize; + kwsysProcessInstance* newArray; + /* Start with enough space for a small number of process handles + and double the size each time more is needed. */ + newSize = kwsysProcesses.Size ? kwsysProcesses.Size * 2 : 4; + + /* Try allocating the new block of memory. */ + if ((newArray = (kwsysProcessInstance*)malloc( + newSize * sizeof(kwsysProcessInstance)))) { + /* Copy the old process handles to the new memory. */ + if (kwsysProcesses.Count > 0) { + memcpy(newArray, kwsysProcesses.Processes, + kwsysProcesses.Count * sizeof(kwsysProcessInstance)); + } + } else { + /* Failed to allocate memory for the new process handle set. */ + LeaveCriticalSection(&kwsysProcesses.Lock); + return 0; + } + + /* Free original array. */ + free(kwsysProcesses.Processes); + + /* Update original structure with new allocation. */ + kwsysProcesses.Size = newSize; + kwsysProcesses.Processes = newArray; + } + + /* Append the new process information to the set. */ + kwsysProcesses.Processes[kwsysProcesses.Count].hProcess = hProcess; + kwsysProcesses.Processes[kwsysProcesses.Count].dwProcessId = dwProcessid; + kwsysProcesses.Processes[kwsysProcesses.Count++].NewProcessGroup = + newProcessGroup; + + /* Leave critical section and return success. */ + LeaveCriticalSection(&kwsysProcesses.Lock); + + return 1; +} + +/* Removes process to global process list. */ +static void kwsysProcessesRemove(HANDLE hProcess) +{ + size_t i; + + if (!hProcess || hProcess == INVALID_HANDLE_VALUE) { + return; + } + + EnterCriticalSection(&kwsysProcesses.Lock); + + /* Find the given process in the set. */ + for (i = 0; i < kwsysProcesses.Count; ++i) { + if (kwsysProcesses.Processes[i].hProcess == hProcess) { + break; + } + } + if (i < kwsysProcesses.Count) { + /* Found it! Remove the process from the set. */ + --kwsysProcesses.Count; + for (; i < kwsysProcesses.Count; ++i) { + kwsysProcesses.Processes[i] = kwsysProcesses.Processes[i + 1]; + } + + /* If this was the last process, free the array. */ + if (kwsysProcesses.Count == 0) { + kwsysProcesses.Size = 0; + free(kwsysProcesses.Processes); + kwsysProcesses.Processes = 0; + } + } + + LeaveCriticalSection(&kwsysProcesses.Lock); +} + +static BOOL WINAPI kwsysCtrlHandler(DWORD dwCtrlType) +{ + size_t i; + (void)dwCtrlType; + /* Enter critical section. */ + EnterCriticalSection(&kwsysProcesses.Lock); + + /* Set flag indicating that we are exiting. */ + kwsysProcesses.Exiting = 1; + + /* If some of our processes were created in a new process group, we must + manually interrupt them. They won't otherwise receive a Ctrl+C/Break. */ + for (i = 0; i < kwsysProcesses.Count; ++i) { + if (kwsysProcesses.Processes[i].NewProcessGroup) { + DWORD groupId = kwsysProcesses.Processes[i].dwProcessId; + if (groupId) { + GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, groupId); + } + } + } + + /* Wait for each child process to exit. This is the key step that prevents + us from leaving several orphaned children processes running in the + background when the user presses Ctrl+C. */ + for (i = 0; i < kwsysProcesses.Count; ++i) { + WaitForSingleObject(kwsysProcesses.Processes[i].hProcess, INFINITE); + } + + /* Leave critical section. */ + LeaveCriticalSection(&kwsysProcesses.Lock); + + /* Continue on to default Ctrl handler (which calls ExitProcess). */ + return FALSE; +} + +void kwsysProcess_ResetStartTime(kwsysProcess* cp) +{ + if (!cp) { + return; + } + /* Reset start time. */ + cp->StartTime = kwsysProcessTimeGetCurrent(); +} diff --git a/test/API/driver/kwsys/README.rst b/test/API/driver/kwsys/README.rst new file mode 100644 index 0000000..fc6b590 --- /dev/null +++ b/test/API/driver/kwsys/README.rst @@ -0,0 +1,37 @@ +KWSys +***** + +Introduction +============ + +KWSys is the Kitware System Library. It provides platform-independent +APIs to many common system features that are implemented differently on +every platform. This library is intended to be shared among many +projects at the source level, so it has a configurable namespace. +Each project should configure KWSys to use a namespace unique to itself. +See comments in `CMakeLists.txt`_ for details. + +.. _`CMakeLists.txt`: CMakeLists.txt + +License +======= + +KWSys is distributed under the OSI-approved BSD 3-clause License. +See `Copyright.txt`_ for details. + +.. _`Copyright.txt`: Copyright.txt + +Reporting Bugs +============== + +KWSys has no independent issue tracker. After encountering an issue +(bug) please submit a patch using the instructions for `Contributing`_. +Otherwise please report the issue to the tracker for the project that +hosts the copy of KWSys in which the problem was found. + +Contributing +============ + +See `CONTRIBUTING.rst`_ for instructions to contribute. + +.. _`CONTRIBUTING.rst`: CONTRIBUTING.rst diff --git a/test/API/driver/kwsys/RegularExpression.cxx b/test/API/driver/kwsys/RegularExpression.cxx new file mode 100644 index 0000000..5e6f8da --- /dev/null +++ b/test/API/driver/kwsys/RegularExpression.cxx @@ -0,0 +1,1218 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +// +// Copyright (C) 1991 Texas Instruments Incorporated. +// +// Permission is granted to any individual or institution to use, copy, modify +// and distribute this software, provided that this complete copyright and +// permission notice is maintained, intact, in all copies and supporting +// documentation. +// +// Texas Instruments Incorporated provides this software "as is" without +// express or implied warranty. +// +// +// Created: MNF 06/13/89 Initial Design and Implementation +// Updated: LGO 08/09/89 Inherit from Generic +// Updated: MBN 09/07/89 Added conditional exception handling +// Updated: MBN 12/15/89 Sprinkled "const" qualifiers all over the place! +// Updated: DLS 03/22/91 New lite version +// + +#include "kwsysPrivate.h" +#include KWSYS_HEADER(RegularExpression.hxx) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "RegularExpression.hxx.in" +#endif + +#include +#include + +namespace KWSYS_NAMESPACE { + +// RegularExpression -- Copies the given regular expression. +RegularExpression::RegularExpression(const RegularExpression& rxp) +{ + if (!rxp.program) { + this->program = nullptr; + return; + } + int ind; + this->progsize = rxp.progsize; // Copy regular expression size + this->program = new char[this->progsize]; // Allocate storage + for (ind = this->progsize; ind-- != 0;) // Copy regular expression + this->program[ind] = rxp.program[ind]; + // Copy pointers into last successful "find" operation + this->regmatch = rxp.regmatch; + this->regmust = rxp.regmust; // Copy field + if (rxp.regmust != nullptr) { + char* dum = rxp.program; + ind = 0; + while (dum != rxp.regmust) { + ++dum; + ++ind; + } + this->regmust = this->program + ind; + } + this->regstart = rxp.regstart; // Copy starting index + this->reganch = rxp.reganch; // Copy remaining private data + this->regmlen = rxp.regmlen; // Copy remaining private data +} + +// operator= -- Copies the given regular expression. +RegularExpression& RegularExpression::operator=(const RegularExpression& rxp) +{ + if (this == &rxp) { + return *this; + } + if (!rxp.program) { + this->program = nullptr; + return *this; + } + int ind; + this->progsize = rxp.progsize; // Copy regular expression size + delete[] this->program; + this->program = new char[this->progsize]; // Allocate storage + for (ind = this->progsize; ind-- != 0;) // Copy regular expression + this->program[ind] = rxp.program[ind]; + // Copy pointers into last successful "find" operation + this->regmatch = rxp.regmatch; + this->regmust = rxp.regmust; // Copy field + if (rxp.regmust != nullptr) { + char* dum = rxp.program; + ind = 0; + while (dum != rxp.regmust) { + ++dum; + ++ind; + } + this->regmust = this->program + ind; + } + this->regstart = rxp.regstart; // Copy starting index + this->reganch = rxp.reganch; // Copy remaining private data + this->regmlen = rxp.regmlen; // Copy remaining private data + + return *this; +} + +// operator== -- Returns true if two regular expressions have the same +// compiled program for pattern matching. +bool RegularExpression::operator==(const RegularExpression& rxp) const +{ + if (this != &rxp) { // Same address? + int ind = this->progsize; // Get regular expression size + if (ind != rxp.progsize) // If different size regexp + return false; // Return failure + while (ind-- != 0) // Else while still characters + if (this->program[ind] != rxp.program[ind]) // If regexp are different + return false; // Return failure + } + return true; // Else same, return success +} + +// deep_equal -- Returns true if have the same compiled regular expressions +// and the same start and end pointers. + +bool RegularExpression::deep_equal(const RegularExpression& rxp) const +{ + int ind = this->progsize; // Get regular expression size + if (ind != rxp.progsize) // If different size regexp + return false; // Return failure + while (ind-- != 0) // Else while still characters + if (this->program[ind] != rxp.program[ind]) // If regexp are different + return false; // Return failure + // Else if same start/end ptrs, return true + return (this->regmatch.start() == rxp.regmatch.start() && + this->regmatch.end() == rxp.regmatch.end()); +} + +// The remaining code in this file is derived from the regular expression code +// whose copyright statement appears below. It has been changed to work +// with the class concepts of C++ and COOL. + +/* + * compile and find + * + * Copyright (c) 1986 by University of Toronto. + * Written by Henry Spencer. Not derived from licensed software. + * + * Permission is granted to anyone to use this software for any + * purpose on any computer system, and to redistribute it freely, + * subject to the following restrictions: + * + * 1. The author is not responsible for the consequences of use of + * this software, no matter how awful, even if they arise + * from defects in it. + * + * 2. The origin of this software must not be misrepresented, either + * by explicit claim or by omission. + * + * 3. Altered versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * Beware that some of this code is subtly aware of the way operator + * precedence is structured in regular expressions. Serious changes in + * regular-expression syntax might require a total rethink. + */ + +/* + * The "internal use only" fields in regexp.h are present to pass info from + * compile to execute that permits the execute phase to run lots faster on + * simple cases. They are: + * + * regstart char that must begin a match; '\0' if none obvious + * reganch is the match anchored (at beginning-of-line only)? + * regmust string (pointer into program) that match must include, or + * nullptr regmlen length of regmust string + * + * Regstart and reganch permit very fast decisions on suitable starting points + * for a match, cutting down the work a lot. Regmust permits fast rejection + * of lines that cannot possibly match. The regmust tests are costly enough + * that compile() supplies a regmust only if the r.e. contains something + * potentially expensive (at present, the only such thing detected is * or + + * at the start of the r.e., which can involve a lot of backup). Regmlen is + * supplied because the test in find() needs it and compile() is computing + * it anyway. + */ + +/* + * Structure for regexp "program". This is essentially a linear encoding + * of a nondeterministic finite-state machine (aka syntax charts or + * "railroad normal form" in parsing technology). Each node is an opcode + * plus a "next" pointer, possibly plus an operand. "Next" pointers of + * all nodes except BRANCH implement concatenation; a "next" pointer with + * a BRANCH on both ends of it is connecting two alternatives. (Here we + * have one of the subtle syntax dependencies: an individual BRANCH (as + * opposed to a collection of them) is never concatenated with anything + * because of operator precedence.) The operand of some types of node is + * a literal string; for others, it is a node leading into a sub-FSM. In + * particular, the operand of a BRANCH node is the first node of the branch. + * (NB this is *not* a tree structure: the tail of the branch connects + * to the thing following the set of BRANCHes.) The opcodes are: + */ + +// definition number opnd? meaning +#define END 0 // no End of program. +#define BOL 1 // no Match "" at beginning of line. +#define EOL 2 // no Match "" at end of line. +#define ANY 3 // no Match any one character. +#define ANYOF 4 // str Match any character in this string. +#define ANYBUT \ + 5 // str Match any character not in this + // string. +#define BRANCH \ + 6 // node Match this alternative, or the + // next... +#define BACK 7 // no Match "", "next" ptr points backward. +#define EXACTLY 8 // str Match this string. +#define NOTHING 9 // no Match empty string. +#define STAR \ + 10 // node Match this (simple) thing 0 or more + // times. +#define PLUS \ + 11 // node Match this (simple) thing 1 or more + // times. +#define OPEN \ + 20 // no Mark this point in input as start of + // #n. +// OPEN+1 is number 1, etc. +#define CLOSE 30 // no Analogous to OPEN. + +/* + * Opcode notes: + * + * BRANCH The set of branches constituting a single choice are hooked + * together with their "next" pointers, since precedence prevents + * anything being concatenated to any individual branch. The + * "next" pointer of the last BRANCH in a choice points to the + * thing following the whole choice. This is also where the + * final "next" pointer of each individual branch points; each + * branch starts with the operand node of a BRANCH node. + * + * BACK Normal "next" pointers all implicitly point forward; BACK + * exists to make loop structures possible. + * + * STAR,PLUS '?', and complex '*' and '+', are implemented as circular + * BRANCH structures using BACK. Simple cases (one character + * per match) are implemented with STAR and PLUS for speed + * and to minimize recursive plunges. + * + * OPEN,CLOSE ...are numbered at compile time. + */ + +/* + * A node is one char of opcode followed by two chars of "next" pointer. + * "Next" pointers are stored as two 8-bit pieces, high order first. The + * value is a positive offset from the opcode of the node containing it. + * An operand, if any, simply follows the node. (Note that much of the + * code generation knows about this implicit relationship.) + * + * Using two bytes for the "next" pointer is vast overkill for most things, + * but allows patterns to get big without disasters. + */ + +#define OP(p) (*(p)) +#define NEXT(p) (((*((p) + 1) & 0377) << 8) + (*((p) + 2) & 0377)) +#define OPERAND(p) ((p) + 3) + +const unsigned char MAGIC = 0234; +/* + * Utility definitions. + */ + +#define UCHARAT(p) (reinterpret_cast(p))[0] + +#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?') +#define META "^$.[()|?+*\\" + +/* + * Flags to be passed up and down. + */ +#define HASWIDTH 01 // Known never to match null string. +#define SIMPLE 02 // Simple enough to be STAR/PLUS operand. +#define SPSTART 04 // Starts with * or +. +#define WORST 0 // Worst case. + +///////////////////////////////////////////////////////////////////////// +// +// COMPILE AND ASSOCIATED FUNCTIONS +// +///////////////////////////////////////////////////////////////////////// + +/* + * Read only utility variables. + */ +static char regdummy; +static char* const regdummyptr = ®dummy; + +/* + * Utility class for RegularExpression::compile(). + */ +class RegExpCompile +{ +public: + const char* regparse; // Input-scan pointer. + int regnpar; // () count. + char* regcode; // Code-emit pointer; regdummyptr = don't. + long regsize; // Code size. + + char* reg(int, int*); + char* regbranch(int*); + char* regpiece(int*); + char* regatom(int*); + char* regnode(char); + void regc(char); + void reginsert(char, char*); + static void regtail(char*, const char*); + static void regoptail(char*, const char*); +}; + +static const char* regnext(const char*); +static char* regnext(char*); + +#ifdef STRCSPN +static int strcspn(); +#endif + +/* + * We can't allocate space until we know how big the compiled form will be, + * but we can't compile it (and thus know how big it is) until we've got a + * place to put the code. So we cheat: we compile it twice, once with code + * generation turned off and size counting turned on, and once "for real". + * This also means that we don't allocate space until we are sure that the + * thing really will compile successfully, and we never have to move the + * code and thus invalidate pointers into it. (Note that it has to be in + * one piece because free() must be able to free it all.) + * + * Beware that the optimization-preparation code in here knows about some + * of the structure of the compiled regexp. + */ + +// compile -- compile a regular expression into internal code +// for later pattern matching. + +bool RegularExpression::compile(const char* exp) +{ + const char* scan; + const char* longest; + int flags; + + if (exp == nullptr) { + // RAISE Error, SYM(RegularExpression), SYM(No_Expr), + printf("RegularExpression::compile(): No expression supplied.\n"); + return false; + } + + // First pass: determine size, legality. + RegExpCompile comp; + comp.regparse = exp; + comp.regnpar = 1; + comp.regsize = 0L; + comp.regcode = regdummyptr; + comp.regc(static_cast(MAGIC)); + if (!comp.reg(0, &flags)) { + printf("RegularExpression::compile(): Error in compile.\n"); + return false; + } + this->regmatch.clear(); + + // Small enough for pointer-storage convention? + if (comp.regsize >= 32767L) { // Probably could be 65535L. + // RAISE Error, SYM(RegularExpression), SYM(Expr_Too_Big), + printf("RegularExpression::compile(): Expression too big.\n"); + return false; + } + + // Allocate space. + //#ifndef _WIN32 + if (this->program != nullptr) + delete[] this->program; + //#endif + this->program = new char[comp.regsize]; + this->progsize = static_cast(comp.regsize); + + if (this->program == nullptr) { + // RAISE Error, SYM(RegularExpression), SYM(Out_Of_Memory), + printf("RegularExpression::compile(): Out of memory.\n"); + return false; + } + + // Second pass: emit code. + comp.regparse = exp; + comp.regnpar = 1; + comp.regcode = this->program; + comp.regc(static_cast(MAGIC)); + comp.reg(0, &flags); + + // Dig out information for optimizations. + this->regstart = '\0'; // Worst-case defaults. + this->reganch = 0; + this->regmust = nullptr; + this->regmlen = 0; + scan = this->program + 1; // First BRANCH. + if (OP(regnext(scan)) == END) { // Only one top-level choice. + scan = OPERAND(scan); + + // Starting-point info. + if (OP(scan) == EXACTLY) + this->regstart = *OPERAND(scan); + else if (OP(scan) == BOL) + this->reganch++; + + // + // If there's something expensive in the r.e., find the longest + // literal string that must appear and make it the regmust. Resolve + // ties in favor of later strings, since the regstart check works + // with the beginning of the r.e. and avoiding duplication + // strengthens checking. Not a strong reason, but sufficient in the + // absence of others. + // + if (flags & SPSTART) { + longest = nullptr; + size_t len = 0; + for (; scan != nullptr; scan = regnext(scan)) + if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) { + longest = OPERAND(scan); + len = strlen(OPERAND(scan)); + } + this->regmust = longest; + this->regmlen = len; + } + } + return true; +} + +/* + - reg - regular expression, i.e. main body or parenthesized thing + * + * Caller must absorb opening parenthesis. + * + * Combining parenthesis handling with the base level of regular expression + * is a trifle forced, but the need to tie the tails of the branches to what + * follows makes it hard to avoid. + */ +char* RegExpCompile::reg(int paren, int* flagp) +{ + char* ret; + char* br; + char* ender; + int parno = 0; + int flags; + + *flagp = HASWIDTH; // Tentatively. + + // Make an OPEN node, if parenthesized. + if (paren) { + if (regnpar >= RegularExpressionMatch::NSUBEXP) { + // RAISE Error, SYM(RegularExpression), SYM(Too_Many_Parens), + printf("RegularExpression::compile(): Too many parentheses.\n"); + return nullptr; + } + parno = regnpar; + regnpar++; + ret = regnode(static_cast(OPEN + parno)); + } else + ret = nullptr; + + // Pick up the branches, linking them together. + br = regbranch(&flags); + if (br == nullptr) + return (nullptr); + if (ret != nullptr) + regtail(ret, br); // OPEN -> first. + else + ret = br; + if (!(flags & HASWIDTH)) + *flagp &= ~HASWIDTH; + *flagp |= flags & SPSTART; + while (*regparse == '|') { + regparse++; + br = regbranch(&flags); + if (br == nullptr) + return (nullptr); + regtail(ret, br); // BRANCH -> BRANCH. + if (!(flags & HASWIDTH)) + *flagp &= ~HASWIDTH; + *flagp |= flags & SPSTART; + } + + // Make a closing node, and hook it on the end. + ender = regnode(static_cast((paren) ? CLOSE + parno : END)); + regtail(ret, ender); + + // Hook the tails of the branches to the closing node. + for (br = ret; br != nullptr; br = regnext(br)) + regoptail(br, ender); + + // Check for proper termination. + if (paren && *regparse++ != ')') { + // RAISE Error, SYM(RegularExpression), SYM(Unmatched_Parens), + printf("RegularExpression::compile(): Unmatched parentheses.\n"); + return nullptr; + } else if (!paren && *regparse != '\0') { + if (*regparse == ')') { + // RAISE Error, SYM(RegularExpression), SYM(Unmatched_Parens), + printf("RegularExpression::compile(): Unmatched parentheses.\n"); + return nullptr; + } else { + // RAISE Error, SYM(RegularExpression), SYM(Internal_Error), + printf("RegularExpression::compile(): Internal error.\n"); + return nullptr; + } + // NOTREACHED + } + return (ret); +} + +/* + - regbranch - one alternative of an | operator + * + * Implements the concatenation operator. + */ +char* RegExpCompile::regbranch(int* flagp) +{ + char* ret; + char* chain; + char* latest; + int flags; + + *flagp = WORST; // Tentatively. + + ret = regnode(BRANCH); + chain = nullptr; + while (*regparse != '\0' && *regparse != '|' && *regparse != ')') { + latest = regpiece(&flags); + if (latest == nullptr) + return (nullptr); + *flagp |= flags & HASWIDTH; + if (chain == nullptr) // First piece. + *flagp |= flags & SPSTART; + else + regtail(chain, latest); + chain = latest; + } + if (chain == nullptr) // Loop ran zero times. + regnode(NOTHING); + + return (ret); +} + +/* + - regpiece - something followed by possible [*+?] + * + * Note that the branching code sequences used for ? and the general cases + * of * and + are somewhat optimized: they use the same NOTHING node as + * both the endmarker for their branch list and the body of the last branch. + * It might seem that this node could be dispensed with entirely, but the + * endmarker role is not redundant. + */ +char* RegExpCompile::regpiece(int* flagp) +{ + char* ret; + char op; + char* next; + int flags; + + ret = regatom(&flags); + if (ret == nullptr) + return (nullptr); + + op = *regparse; + if (!ISMULT(op)) { + *flagp = flags; + return (ret); + } + + if (!(flags & HASWIDTH) && op != '?') { + // RAISE Error, SYM(RegularExpression), SYM(Empty_Operand), + printf("RegularExpression::compile() : *+ operand could be empty.\n"); + return nullptr; + } + *flagp = (op != '+') ? (WORST | SPSTART) : (WORST | HASWIDTH); + + if (op == '*' && (flags & SIMPLE)) + reginsert(STAR, ret); + else if (op == '*') { + // Emit x* as (x&|), where & means "self". + reginsert(BRANCH, ret); // Either x + regoptail(ret, regnode(BACK)); // and loop + regoptail(ret, ret); // back + regtail(ret, regnode(BRANCH)); // or + regtail(ret, regnode(NOTHING)); // null. + } else if (op == '+' && (flags & SIMPLE)) + reginsert(PLUS, ret); + else if (op == '+') { + // Emit x+ as x(&|), where & means "self". + next = regnode(BRANCH); // Either + regtail(ret, next); + regtail(regnode(BACK), ret); // loop back + regtail(next, regnode(BRANCH)); // or + regtail(ret, regnode(NOTHING)); // null. + } else if (op == '?') { + // Emit x? as (x|) + reginsert(BRANCH, ret); // Either x + regtail(ret, regnode(BRANCH)); // or + next = regnode(NOTHING); // null. + regtail(ret, next); + regoptail(ret, next); + } + regparse++; + if (ISMULT(*regparse)) { + // RAISE Error, SYM(RegularExpression), SYM(Nested_Operand), + printf("RegularExpression::compile(): Nested *?+.\n"); + return nullptr; + } + return (ret); +} + +/* + - regatom - the lowest level + * + * Optimization: gobbles an entire sequence of ordinary characters so that + * it can turn them into a single node, which is smaller to store and + * faster to run. Backslashed characters are exceptions, each becoming a + * separate node; the code is simpler that way and it's not worth fixing. + */ +char* RegExpCompile::regatom(int* flagp) +{ + char* ret; + int flags; + + *flagp = WORST; // Tentatively. + + switch (*regparse++) { + case '^': + ret = regnode(BOL); + break; + case '$': + ret = regnode(EOL); + break; + case '.': + ret = regnode(ANY); + *flagp |= HASWIDTH | SIMPLE; + break; + case '[': { + int rxpclass; + int rxpclassend; + + if (*regparse == '^') { // Complement of range. + ret = regnode(ANYBUT); + regparse++; + } else + ret = regnode(ANYOF); + if (*regparse == ']' || *regparse == '-') + regc(*regparse++); + while (*regparse != '\0' && *regparse != ']') { + if (*regparse == '-') { + regparse++; + if (*regparse == ']' || *regparse == '\0') + regc('-'); + else { + rxpclass = UCHARAT(regparse - 2) + 1; + rxpclassend = UCHARAT(regparse); + if (rxpclass > rxpclassend + 1) { + // RAISE Error, SYM(RegularExpression), SYM(Invalid_Range), + printf("RegularExpression::compile(): Invalid range in [].\n"); + return nullptr; + } + for (; rxpclass <= rxpclassend; rxpclass++) + regc(static_cast(rxpclass)); + regparse++; + } + } else + regc(*regparse++); + } + regc('\0'); + if (*regparse != ']') { + // RAISE Error, SYM(RegularExpression), SYM(Unmatched_Bracket), + printf("RegularExpression::compile(): Unmatched [].\n"); + return nullptr; + } + regparse++; + *flagp |= HASWIDTH | SIMPLE; + } break; + case '(': + ret = reg(1, &flags); + if (ret == nullptr) + return (nullptr); + *flagp |= flags & (HASWIDTH | SPSTART); + break; + case '\0': + case '|': + case ')': + // RAISE Error, SYM(RegularExpression), SYM(Internal_Error), + printf("RegularExpression::compile(): Internal error.\n"); // Never here + return nullptr; + case '?': + case '+': + case '*': + // RAISE Error, SYM(RegularExpression), SYM(No_Operand), + printf("RegularExpression::compile(): ?+* follows nothing.\n"); + return nullptr; + case '\\': + if (*regparse == '\0') { + // RAISE Error, SYM(RegularExpression), SYM(Trailing_Backslash), + printf("RegularExpression::compile(): Trailing backslash.\n"); + return nullptr; + } + ret = regnode(EXACTLY); + regc(*regparse++); + regc('\0'); + *flagp |= HASWIDTH | SIMPLE; + break; + default: { + int len; + char ender; + + regparse--; + len = int(strcspn(regparse, META)); + if (len <= 0) { + // RAISE Error, SYM(RegularExpression), SYM(Internal_Error), + printf("RegularExpression::compile(): Internal error.\n"); + return nullptr; + } + ender = *(regparse + len); + if (len > 1 && ISMULT(ender)) + len--; // Back off clear of ?+* operand. + *flagp |= HASWIDTH; + if (len == 1) + *flagp |= SIMPLE; + ret = regnode(EXACTLY); + while (len > 0) { + regc(*regparse++); + len--; + } + regc('\0'); + } break; + } + return (ret); +} + +/* + - regnode - emit a node + Location. + */ +char* RegExpCompile::regnode(char op) +{ + char* ret; + char* ptr; + + ret = regcode; + if (ret == regdummyptr) { + regsize += 3; + return (ret); + } + + ptr = ret; + *ptr++ = op; + *ptr++ = '\0'; // Null "next" pointer. + *ptr++ = '\0'; + regcode = ptr; + + return (ret); +} + +/* + - regc - emit (if appropriate) a byte of code + */ +void RegExpCompile::regc(char b) +{ + if (regcode != regdummyptr) + *regcode++ = b; + else + regsize++; +} + +/* + - reginsert - insert an operator in front of already-emitted operand + * + * Means relocating the operand. + */ +void RegExpCompile::reginsert(char op, char* opnd) +{ + char* src; + char* dst; + char* place; + + if (regcode == regdummyptr) { + regsize += 3; + return; + } + + src = regcode; + regcode += 3; + dst = regcode; + while (src > opnd) + *--dst = *--src; + + place = opnd; // Op node, where operand used to be. + *place++ = op; + *place++ = '\0'; + *place = '\0'; +} + +/* + - regtail - set the next-pointer at the end of a node chain + */ +void RegExpCompile::regtail(char* p, const char* val) +{ + char* scan; + char* temp; + int offset; + + if (p == regdummyptr) + return; + + // Find last node. + scan = p; + for (;;) { + temp = regnext(scan); + if (temp == nullptr) + break; + scan = temp; + } + + if (OP(scan) == BACK) + offset = int(scan - val); + else + offset = int(val - scan); + *(scan + 1) = static_cast((offset >> 8) & 0377); + *(scan + 2) = static_cast(offset & 0377); +} + +/* + - regoptail - regtail on operand of first argument; nop if operandless + */ +void RegExpCompile::regoptail(char* p, const char* val) +{ + // "Operandless" and "op != BRANCH" are synonymous in practice. + if (p == nullptr || p == regdummyptr || OP(p) != BRANCH) + return; + regtail(OPERAND(p), val); +} + +//////////////////////////////////////////////////////////////////////// +// +// find and friends +// +//////////////////////////////////////////////////////////////////////// + +/* + * Utility class for RegularExpression::find(). + */ +class RegExpFind +{ +public: + const char* reginput; // String-input pointer. + const char* regbol; // Beginning of input, for ^ check. + const char** regstartp; // Pointer to startp array. + const char** regendp; // Ditto for endp. + + int regtry(const char*, const char**, const char**, const char*); + int regmatch(const char*); + int regrepeat(const char*); +}; + +// find -- Matches the regular expression to the given string. +// Returns true if found, and sets start and end indexes accordingly. +bool RegularExpression::find(char const* string, + RegularExpressionMatch& rmatch) const +{ + const char* s; + + rmatch.clear(); + rmatch.searchstring = string; + + if (!this->program) { + return false; + } + + // Check validity of program. + if (UCHARAT(this->program) != MAGIC) { + // RAISE Error, SYM(RegularExpression), SYM(Internal_Error), + printf( + "RegularExpression::find(): Compiled regular expression corrupted.\n"); + return false; + } + + // If there is a "must appear" string, look for it. + if (this->regmust != nullptr) { + s = string; + while ((s = strchr(s, this->regmust[0])) != nullptr) { + if (strncmp(s, this->regmust, this->regmlen) == 0) + break; // Found it. + s++; + } + if (s == nullptr) // Not present. + return false; + } + + RegExpFind regFind; + + // Mark beginning of line for ^ . + regFind.regbol = string; + + // Simplest case: anchored match need be tried only once. + if (this->reganch) + return ( + regFind.regtry(string, rmatch.startp, rmatch.endp, this->program) != 0); + + // Messy cases: unanchored match. + s = string; + if (this->regstart != '\0') + // We know what char it must start with. + while ((s = strchr(s, this->regstart)) != nullptr) { + if (regFind.regtry(s, rmatch.startp, rmatch.endp, this->program)) + return true; + s++; + } + else + // We don't -- general case. + do { + if (regFind.regtry(s, rmatch.startp, rmatch.endp, this->program)) + return true; + } while (*s++ != '\0'); + + // Failure. + return false; +} + +/* + - regtry - try match at specific point + 0 failure, 1 success + */ +int RegExpFind::regtry(const char* string, const char** start, + const char** end, const char* prog) +{ + int i; + const char** sp1; + const char** ep; + + reginput = string; + regstartp = start; + regendp = end; + + sp1 = start; + ep = end; + for (i = RegularExpressionMatch::NSUBEXP; i > 0; i--) { + *sp1++ = nullptr; + *ep++ = nullptr; + } + if (regmatch(prog + 1)) { + start[0] = string; + end[0] = reginput; + return (1); + } else + return (0); +} + +/* + - regmatch - main matching routine + * + * Conceptually the strategy is simple: check to see whether the current + * node matches, call self recursively to see whether the rest matches, + * and then act accordingly. In practice we make some effort to avoid + * recursion, in particular by going through "ordinary" nodes (that don't + * need to know whether the rest of the match failed) by a loop instead of + * by recursion. + * 0 failure, 1 success + */ +int RegExpFind::regmatch(const char* prog) +{ + const char* scan; // Current node. + const char* next; // Next node. + + scan = prog; + + while (scan != nullptr) { + + next = regnext(scan); + + switch (OP(scan)) { + case BOL: + if (reginput != regbol) + return (0); + break; + case EOL: + if (*reginput != '\0') + return (0); + break; + case ANY: + if (*reginput == '\0') + return (0); + reginput++; + break; + case EXACTLY: { + size_t len; + const char* opnd; + + opnd = OPERAND(scan); + // Inline the first character, for speed. + if (*opnd != *reginput) + return (0); + len = strlen(opnd); + if (len > 1 && strncmp(opnd, reginput, len) != 0) + return (0); + reginput += len; + } break; + case ANYOF: + if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == nullptr) + return (0); + reginput++; + break; + case ANYBUT: + if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != nullptr) + return (0); + reginput++; + break; + case NOTHING: + break; + case BACK: + break; + case OPEN + 1: + case OPEN + 2: + case OPEN + 3: + case OPEN + 4: + case OPEN + 5: + case OPEN + 6: + case OPEN + 7: + case OPEN + 8: + case OPEN + 9: { + int no; + const char* save; + + no = OP(scan) - OPEN; + save = reginput; + + if (regmatch(next)) { + + // + // Don't set startp if some later invocation of the + // same parentheses already has. + // + if (regstartp[no] == nullptr) + regstartp[no] = save; + return (1); + } else + return (0); + } + // break; + case CLOSE + 1: + case CLOSE + 2: + case CLOSE + 3: + case CLOSE + 4: + case CLOSE + 5: + case CLOSE + 6: + case CLOSE + 7: + case CLOSE + 8: + case CLOSE + 9: { + int no; + const char* save; + + no = OP(scan) - CLOSE; + save = reginput; + + if (regmatch(next)) { + + // + // Don't set endp if some later invocation of the + // same parentheses already has. + // + if (regendp[no] == nullptr) + regendp[no] = save; + return (1); + } else + return (0); + } + // break; + case BRANCH: { + + const char* save; + + if (OP(next) != BRANCH) // No choice. + next = OPERAND(scan); // Avoid recursion. + else { + do { + save = reginput; + if (regmatch(OPERAND(scan))) + return (1); + reginput = save; + scan = regnext(scan); + } while (scan != nullptr && OP(scan) == BRANCH); + return (0); + // NOTREACHED + } + } break; + case STAR: + case PLUS: { + char nextch; + int no; + const char* save; + int min_no; + + // + // Lookahead to avoid useless match attempts when we know + // what character comes next. + // + nextch = '\0'; + if (OP(next) == EXACTLY) + nextch = *OPERAND(next); + min_no = (OP(scan) == STAR) ? 0 : 1; + save = reginput; + no = regrepeat(OPERAND(scan)); + while (no >= min_no) { + // If it could work, try it. + if (nextch == '\0' || *reginput == nextch) + if (regmatch(next)) + return (1); + // Couldn't or didn't -- back up. + no--; + reginput = save + no; + } + return (0); + } + // break; + case END: + return (1); // Success! + + default: + // RAISE Error, SYM(RegularExpression), SYM(Internal_Error), + printf( + "RegularExpression::find(): Internal error -- memory corrupted.\n"); + return 0; + } + scan = next; + } + + // + // We get here only if there's trouble -- normally "case END" is the + // terminating point. + // + // RAISE Error, SYM(RegularExpression), SYM(Internal_Error), + printf("RegularExpression::find(): Internal error -- corrupted pointers.\n"); + return (0); +} + +/* + - regrepeat - repeatedly match something simple, report how many + */ +int RegExpFind::regrepeat(const char* p) +{ + int count = 0; + const char* scan; + const char* opnd; + + scan = reginput; + opnd = OPERAND(p); + switch (OP(p)) { + case ANY: + count = int(strlen(scan)); + scan += count; + break; + case EXACTLY: + while (*opnd == *scan) { + count++; + scan++; + } + break; + case ANYOF: + while (*scan != '\0' && strchr(opnd, *scan) != nullptr) { + count++; + scan++; + } + break; + case ANYBUT: + while (*scan != '\0' && strchr(opnd, *scan) == nullptr) { + count++; + scan++; + } + break; + default: // Oh dear. Called inappropriately. + // RAISE Error, SYM(RegularExpression), SYM(Internal_Error), + printf("cm RegularExpression::find(): Internal error.\n"); + return 0; + } + reginput = scan; + return (count); +} + +/* + - regnext - dig the "next" pointer out of a node + */ +static const char* regnext(const char* p) +{ + int offset; + + if (p == regdummyptr) + return (nullptr); + + offset = NEXT(p); + if (offset == 0) + return (nullptr); + + if (OP(p) == BACK) + return (p - offset); + else + return (p + offset); +} + +static char* regnext(char* p) +{ + int offset; + + if (p == regdummyptr) + return (nullptr); + + offset = NEXT(p); + if (offset == 0) + return (nullptr); + + if (OP(p) == BACK) + return (p - offset); + else + return (p + offset); +} + +} // namespace KWSYS_NAMESPACE diff --git a/test/API/driver/kwsys/RegularExpression.hxx.in b/test/API/driver/kwsys/RegularExpression.hxx.in new file mode 100644 index 0000000..0c2366b --- /dev/null +++ b/test/API/driver/kwsys/RegularExpression.hxx.in @@ -0,0 +1,562 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +// Original Copyright notice: +// Copyright (C) 1991 Texas Instruments Incorporated. +// +// Permission is granted to any individual or institution to use, copy, modify, +// and distribute this software, provided that this complete copyright and +// permission notice is maintained, intact, in all copies and supporting +// documentation. +// +// Texas Instruments Incorporated provides this software "as is" without +// express or implied warranty. +// +// Created: MNF 06/13/89 Initial Design and Implementation +// Updated: LGO 08/09/89 Inherit from Generic +// Updated: MBN 09/07/89 Added conditional exception handling +// Updated: MBN 12/15/89 Sprinkled "const" qualifiers all over the place! +// Updated: DLS 03/22/91 New lite version +// + +#ifndef @KWSYS_NAMESPACE@_RegularExpression_hxx +#define @KWSYS_NAMESPACE@_RegularExpression_hxx + +#include <@KWSYS_NAMESPACE@/Configure.h> +#include <@KWSYS_NAMESPACE@/Configure.hxx> + +#include + +/* Disable useless Borland warnings. KWSys tries not to force things + on its includers, but there is no choice here. */ +#if defined(__BORLANDC__) +# pragma warn - 8027 /* function not inlined. */ +#endif + +namespace @KWSYS_NAMESPACE@ { + +// Forward declaration +class RegularExpression; + +/** \class RegularExpressionMatch + * \brief Stores the pattern matches of a RegularExpression + */ +class @KWSYS_NAMESPACE@_EXPORT RegularExpressionMatch +{ +public: + RegularExpressionMatch(); + + bool isValid() const; + void clear(); + + std::string::size_type start() const; + std::string::size_type end() const; + std::string::size_type start(int n) const; + std::string::size_type end(int n) const; + std::string match(int n) const; + + enum + { + NSUBEXP = 10 + }; + +private: + friend class RegularExpression; + const char* startp[NSUBEXP]; + const char* endp[NSUBEXP]; + const char* searchstring; +}; + +/** + * \brief Creates an invalid match object + */ +inline RegularExpressionMatch::RegularExpressionMatch() + : startp{} + , endp{} + , searchstring{} +{ +} + +/** + * \brief Returns true if the match pointers are valid + */ +inline bool RegularExpressionMatch::isValid() const +{ + return (this->startp[0] != nullptr); +} + +/** + * \brief Resets to the (invalid) construction state. + */ +inline void RegularExpressionMatch::clear() +{ + startp[0] = nullptr; + endp[0] = nullptr; + searchstring = nullptr; +} + +/** + * \brief Returns the start index of the full match. + */ +inline std::string::size_type RegularExpressionMatch::start() const +{ + return static_cast(this->startp[0] - searchstring); +} + +/** + * \brief Returns the end index of the full match. + */ +inline std::string::size_type RegularExpressionMatch::end() const +{ + return static_cast(this->endp[0] - searchstring); +} + +/** + * \brief Returns the start index of nth submatch. + * start(0) is the start of the full match. + */ +inline std::string::size_type RegularExpressionMatch::start(int n) const +{ + return static_cast(this->startp[n] - + this->searchstring); +} + +/** + * \brief Returns the end index of nth submatch. + * end(0) is the end of the full match. + */ +inline std::string::size_type RegularExpressionMatch::end(int n) const +{ + return static_cast(this->endp[n] - + this->searchstring); +} + +/** + * \brief Returns the nth submatch as a string. + */ +inline std::string RegularExpressionMatch::match(int n) const +{ + if (this->startp[n] == nullptr) { + return std::string(); + } else { + return std::string( + this->startp[n], + static_cast(this->endp[n] - this->startp[n])); + } +} + +/** \class RegularExpression + * \brief Implements pattern matching with regular expressions. + * + * This is the header file for the regular expression class. An object of + * this class contains a regular expression, in a special "compiled" format. + * This compiled format consists of several slots all kept as the objects + * private data. The RegularExpression class provides a convenient way to + * represent regular expressions. It makes it easy to search for the same + * regular expression in many different strings without having to compile a + * string to regular expression format more than necessary. + * + * This class implements pattern matching via regular expressions. + * A regular expression allows a programmer to specify complex + * patterns that can be searched for and matched against the + * character string of a string object. In its simplest form, a + * regular expression is a sequence of characters used to + * search for exact character matches. However, many times the + * exact sequence to be found is not known, or only a match at + * the beginning or end of a string is desired. The RegularExpression regu- + * lar expression class implements regular expression pattern + * matching as is found and implemented in many UNIX commands + * and utilities. + * + * Example: The perl code + * + * $filename =~ m"([a-z]+)\.cc"; + * print $1; + * + * Is written as follows in C++ + * + * RegularExpression re("([a-z]+)\\.cc"); + * re.find(filename); + * cerr << re.match(1); + * + * + * The regular expression class provides a convenient mechanism + * for specifying and manipulating regular expressions. The + * regular expression object allows specification of such pat- + * terns by using the following regular expression metacharac- + * ters: + * + * ^ Matches at beginning of a line + * + * $ Matches at end of a line + * + * . Matches any single character + * + * [ ] Matches any character(s) inside the brackets + * + * [^ ] Matches any character(s) not inside the brackets + * + * - Matches any character in range on either side of a dash + * + * * Matches preceding pattern zero or more times + * + * + Matches preceding pattern one or more times + * + * ? Matches preceding pattern zero or once only + * + * () Saves a matched expression and uses it in a later match + * + * Note that more than one of these metacharacters can be used + * in a single regular expression in order to create complex + * search patterns. For example, the pattern [^ab1-9] says to + * match any character sequence that does not begin with the + * characters "ab" followed by numbers in the series one + * through nine. + * + * There are three constructors for RegularExpression. One just creates an + * empty RegularExpression object. Another creates a RegularExpression + * object and initializes it with a regular expression that is given in the + * form of a char*. The third takes a reference to a RegularExpression + * object as an argument and creates an object initialized with the + * information from the given RegularExpression object. + * + * The find member function finds the first occurrence of the regular + * expression of that object in the string given to find as an argument. Find + * returns a boolean, and if true, mutates the private data appropriately. + * Find sets pointers to the beginning and end of the thing last found, they + * are pointers into the actual string that was searched. The start and end + * member functions return indices into the searched string that correspond + * to the beginning and end pointers respectively. The compile member + * function takes a char* and puts the compiled version of the char* argument + * into the object's private data fields. The == and != operators only check + * the to see if the compiled regular expression is the same, and the + * deep_equal functions also checks to see if the start and end pointers are + * the same. The is_valid function returns false if program is set to + * nullptr, (i.e. there is no valid compiled expression). The set_invalid + * function sets the program to nullptr (Warning: this deletes the compiled + * expression). The following examples may help clarify regular expression + * usage: + * + * * The regular expression "^hello" matches a "hello" only at the + * beginning of a line. It would match "hello there" but not "hi, + * hello there". + * + * * The regular expression "long$" matches a "long" only at the end + * of a line. It would match "so long\0", but not "long ago". + * + * * The regular expression "t..t..g" will match anything that has a + * "t" then any two characters, another "t", any two characters and + * then a "g". It will match "testing", or "test again" but would + * not match "toasting" + * + * * The regular expression "[1-9ab]" matches any number one through + * nine, and the characters "a" and "b". It would match "hello 1" + * or "begin", but would not match "no-match". + * + * * The regular expression "[^1-9ab]" matches any character that is + * not a number one through nine, or an "a" or "b". It would NOT + * match "hello 1" or "begin", but would match "no-match". + * + * * The regular expression "br* " matches something that begins with + * a "b", is followed by zero or more "r"s, and ends in a space. It + * would match "brrrrr ", and "b ", but would not match "brrh ". + * + * * The regular expression "br+ " matches something that begins with + * a "b", is followed by one or more "r"s, and ends in a space. It + * would match "brrrrr ", and "br ", but would not match "b " or + * "brrh ". + * + * * The regular expression "br? " matches something that begins with + * a "b", is followed by zero or one "r"s, and ends in a space. It + * would match "br ", and "b ", but would not match "brrrr " or + * "brrh ". + * + * * The regular expression "(..p)b" matches something ending with pb + * and beginning with whatever the two characters before the first p + * encountered in the line were. It would find "repb" in "rep drepa + * qrepb". The regular expression "(..p)a" would find "repa qrepb" + * in "rep drepa qrepb" + * + * * The regular expression "d(..p)" matches something ending with p, + * beginning with d, and having two characters in between that are + * the same as the two characters before the first p encountered in + * the line. It would match "drepa qrepb" in "rep drepa qrepb". + * + * All methods of RegularExpression can be called simultaneously from + * different threads but only if each invocation uses an own instance of + * RegularExpression. + */ +class @KWSYS_NAMESPACE@_EXPORT RegularExpression +{ +public: + /** + * Instantiate RegularExpression with program=nullptr. + */ + inline RegularExpression(); + + /** + * Instantiate RegularExpression with compiled char*. + */ + inline RegularExpression(char const*); + + /** + * Instantiate RegularExpression as a copy of another regular expression. + */ + RegularExpression(RegularExpression const&); + + /** + * Instantiate RegularExpression with compiled string. + */ + inline RegularExpression(std::string const&); + + /** + * Destructor. + */ + inline ~RegularExpression(); + + /** + * Compile a regular expression into internal code + * for later pattern matching. + */ + bool compile(char const*); + + /** + * Compile a regular expression into internal code + * for later pattern matching. + */ + inline bool compile(std::string const&); + + /** + * Matches the regular expression to the given string. + * Returns true if found, and sets start and end indexes + * in the RegularExpressionMatch instance accordingly. + * + * This method is thread safe when called with different + * RegularExpressionMatch instances. + */ + bool find(char const*, RegularExpressionMatch&) const; + + /** + * Matches the regular expression to the given string. + * Returns true if found, and sets start and end indexes accordingly. + */ + inline bool find(char const*); + + /** + * Matches the regular expression to the given std string. + * Returns true if found, and sets start and end indexes accordingly. + */ + inline bool find(std::string const&); + + /** + * Match indices + */ + inline RegularExpressionMatch const& regMatch() const; + inline std::string::size_type start() const; + inline std::string::size_type end() const; + inline std::string::size_type start(int n) const; + inline std::string::size_type end(int n) const; + + /** + * Match strings + */ + inline std::string match(int n) const; + + /** + * Copy the given regular expression. + */ + RegularExpression& operator=(const RegularExpression& rxp); + + /** + * Returns true if two regular expressions have the same + * compiled program for pattern matching. + */ + bool operator==(RegularExpression const&) const; + + /** + * Returns true if two regular expressions have different + * compiled program for pattern matching. + */ + inline bool operator!=(RegularExpression const&) const; + + /** + * Returns true if have the same compiled regular expressions + * and the same start and end pointers. + */ + bool deep_equal(RegularExpression const&) const; + + /** + * True if the compiled regexp is valid. + */ + inline bool is_valid() const; + + /** + * Marks the regular expression as invalid. + */ + inline void set_invalid(); + +private: + RegularExpressionMatch regmatch; + char regstart; // Internal use only + char reganch; // Internal use only + const char* regmust; // Internal use only + std::string::size_type regmlen; // Internal use only + char* program; + int progsize; +}; + +/** + * Create an empty regular expression. + */ +inline RegularExpression::RegularExpression() + : regstart{} + , reganch{} + , regmust{} + , program{ nullptr } + , progsize{} +{ +} + +/** + * Creates a regular expression from string s, and + * compiles s. + */ +inline RegularExpression::RegularExpression(const char* s) + : regstart{} + , reganch{} + , regmust{} + , program{ nullptr } + , progsize{} +{ + if (s) { + this->compile(s); + } +} + +/** + * Creates a regular expression from string s, and + * compiles s. + */ +inline RegularExpression::RegularExpression(const std::string& s) + : regstart{} + , reganch{} + , regmust{} + , program{ nullptr } + , progsize{} +{ + this->compile(s); +} + +/** + * Destroys and frees space allocated for the regular expression. + */ +inline RegularExpression::~RegularExpression() +{ + //#ifndef _WIN32 + delete[] this->program; + //#endif +} + +/** + * Compile a regular expression into internal code + * for later pattern matching. + */ +inline bool RegularExpression::compile(std::string const& s) +{ + return this->compile(s.c_str()); +} + +/** + * Matches the regular expression to the given std string. + * Returns true if found, and sets start and end indexes accordingly. + */ +inline bool RegularExpression::find(const char* s) +{ + return this->find(s, this->regmatch); +} + +/** + * Matches the regular expression to the given std string. + * Returns true if found, and sets start and end indexes accordingly. + */ +inline bool RegularExpression::find(std::string const& s) +{ + return this->find(s.c_str()); +} + +/** + * Returns the internal match object + */ +inline RegularExpressionMatch const& RegularExpression::regMatch() const +{ + return this->regmatch; +} + +/** + * Returns the start index of the full match. + */ +inline std::string::size_type RegularExpression::start() const +{ + return regmatch.start(); +} + +/** + * Returns the end index of the full match. + */ +inline std::string::size_type RegularExpression::end() const +{ + return regmatch.end(); +} + +/** + * Return start index of nth submatch. start(0) is the start of the full match. + */ +inline std::string::size_type RegularExpression::start(int n) const +{ + return regmatch.start(n); +} + +/** + * Return end index of nth submatch. end(0) is the end of the full match. + */ +inline std::string::size_type RegularExpression::end(int n) const +{ + return regmatch.end(n); +} + +/** + * Return nth submatch as a string. + */ +inline std::string RegularExpression::match(int n) const +{ + return regmatch.match(n); +} + +/** + * Returns true if two regular expressions have different + * compiled program for pattern matching. + */ +inline bool RegularExpression::operator!=(const RegularExpression& r) const +{ + return (!(*this == r)); +} + +/** + * Returns true if a valid regular expression is compiled + * and ready for pattern matching. + */ +inline bool RegularExpression::is_valid() const +{ + return (this->program != nullptr); +} + +inline void RegularExpression::set_invalid() +{ + //#ifndef _WIN32 + delete[] this->program; + //#endif + this->program = nullptr; +} + +} // namespace @KWSYS_NAMESPACE@ + +#endif diff --git a/test/API/driver/kwsys/SetupForDevelopment.sh b/test/API/driver/kwsys/SetupForDevelopment.sh new file mode 100644 index 0000000..c3a2b16 --- /dev/null +++ b/test/API/driver/kwsys/SetupForDevelopment.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +cd "${BASH_SOURCE%/*}" && +GitSetup/setup-user && echo && +GitSetup/setup-hooks && echo && +GitSetup/setup-aliases && echo && +GitSetup/setup-upstream && echo && +GitSetup/tips + +# Rebase master by default +git config rebase.stat true +git config branch.master.rebase true + +# Disable Gerrit hook explicitly so the commit-msg hook will +# not complain even if some gerrit remotes are still configured. +git config hooks.GerritId false + +# Record the version of this setup so Scripts/pre-commit can check it. +SetupForDevelopment_VERSION=2 +git config hooks.SetupForDevelopment ${SetupForDevelopment_VERSION} diff --git a/test/API/driver/kwsys/SharedForward.h.in b/test/API/driver/kwsys/SharedForward.h.in new file mode 100644 index 0000000..5716cd4 --- /dev/null +++ b/test/API/driver/kwsys/SharedForward.h.in @@ -0,0 +1,879 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_SharedForward_h +# define @KWSYS_NAMESPACE@_SharedForward_h + +/* + This header is used to create a forwarding executable sets up the + shared library search path and replaces itself with a real + executable. This is useful when creating installations on UNIX with + shared libraries that will run from any install directory. Typical + usage: + + #if defined(CMAKE_INTDIR) + # define CONFIG_DIR_PRE CMAKE_INTDIR "/" + # define CONFIG_DIR_POST "/" CMAKE_INTDIR + #else + # define CONFIG_DIR_PRE "" + # define CONFIG_DIR_POST "" + #endif + #define @KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD "/path/to/foo-build/bin" + #define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD "." CONFIG_DIR_POST + #define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL "../lib/foo-1.2" + #define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD CONFIG_DIR_PRE "foo-real" + #define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL + "../lib/foo-1.2/foo-real" + #define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_COMMAND "--command" + #define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_PRINT "--print" + #define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_LDD "--ldd" + #if defined(CMAKE_INTDIR) + # define @KWSYS_NAMESPACE@_SHARED_FORWARD_CONFIG_NAME CMAKE_INTDIR + #endif + #include <@KWSYS_NAMESPACE@/SharedForward.h> + int main(int argc, char** argv) + { + return @KWSYS_NAMESPACE@_shared_forward_to_real(argc, argv); + } + + Specify search and executable paths relative to the forwarding + executable location or as full paths. Include no trailing slash. + In the case of a multi-configuration build, when CMAKE_INTDIR is + defined, the DIR_BUILD setting should point at the directory above + the executable (the one containing the per-configuration + subdirectory specified by CMAKE_INTDIR). Then PATH_BUILD entries + and EXE_BUILD should be specified relative to this location and use + CMAKE_INTDIR as necessary. In the above example imagine appending + the PATH_BUILD or EXE_BUILD setting to the DIR_BUILD setting. The + result should form a valid path with per-configuration subdirectory. + + Additional paths may be specified in the PATH_BUILD and PATH_INSTALL + variables by using comma-separated strings. For example: + + #define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD \ + "." CONFIG_DIR_POST, "/path/to/bar-build" CONFIG_DIR_POST + #define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL \ + "../lib/foo-1.2", "../lib/bar-4.5" + + See the comments below for specific explanations of each macro. +*/ + +/* Disable -Wcast-qual warnings since they are too hard to fix in a + cross-platform way. */ +# if defined(__clang__) && defined(__has_warning) +# if __has_warning("-Wcast-qual") +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wcast-qual" +# endif +# endif + +# if defined(__BORLANDC__) && !defined(__cplusplus) +/* Code has no effect; raised by winnt.h in C (not C++) when ignoring an + unused parameter using "(param)" syntax (i.e. no cast to void). */ +# pragma warn - 8019 +# endif + +/* Full path to the directory in which this executable is built. Do + not include a trailing slash. */ +# if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD) +# error "Must define @KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD" +# endif +# if !defined(KWSYS_SHARED_FORWARD_DIR_BUILD) +# define KWSYS_SHARED_FORWARD_DIR_BUILD \ + @KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD +# endif + +/* Library search path for build tree. */ +# if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD) +# error "Must define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD" +# endif +# if !defined(KWSYS_SHARED_FORWARD_PATH_BUILD) +# define KWSYS_SHARED_FORWARD_PATH_BUILD \ + @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD +# endif + +/* Library search path for install tree. */ +# if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL) +# error "Must define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL" +# endif +# if !defined(KWSYS_SHARED_FORWARD_PATH_INSTALL) +# define KWSYS_SHARED_FORWARD_PATH_INSTALL \ + @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL +# endif + +/* The real executable to which to forward in the build tree. */ +# if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD) +# error "Must define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD" +# endif +# if !defined(KWSYS_SHARED_FORWARD_EXE_BUILD) +# define KWSYS_SHARED_FORWARD_EXE_BUILD \ + @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD +# endif + +/* The real executable to which to forward in the install tree. */ +# if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL) +# error "Must define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL" +# endif +# if !defined(KWSYS_SHARED_FORWARD_EXE_INSTALL) +# define KWSYS_SHARED_FORWARD_EXE_INSTALL \ + @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL +# endif + +/* The configuration name with which this executable was built (Debug/Release). + */ +# if defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_CONFIG_NAME) +# define KWSYS_SHARED_FORWARD_CONFIG_NAME \ + @KWSYS_NAMESPACE@_SHARED_FORWARD_CONFIG_NAME +# else +# undef KWSYS_SHARED_FORWARD_CONFIG_NAME +# endif + +/* Create command line option to replace executable. */ +# if defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_COMMAND) +# if !defined(KWSYS_SHARED_FORWARD_OPTION_COMMAND) +# define KWSYS_SHARED_FORWARD_OPTION_COMMAND \ + @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_COMMAND +# endif +# else +# undef KWSYS_SHARED_FORWARD_OPTION_COMMAND +# endif + +/* Create command line option to print environment setting and exit. */ +# if defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_PRINT) +# if !defined(KWSYS_SHARED_FORWARD_OPTION_PRINT) +# define KWSYS_SHARED_FORWARD_OPTION_PRINT \ + @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_PRINT +# endif +# else +# undef KWSYS_SHARED_FORWARD_OPTION_PRINT +# endif + +/* Create command line option to run ldd or equivalent. */ +# if defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_LDD) +# if !defined(KWSYS_SHARED_FORWARD_OPTION_LDD) +# define KWSYS_SHARED_FORWARD_OPTION_LDD \ + @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_LDD +# endif +# else +# undef KWSYS_SHARED_FORWARD_OPTION_LDD +# endif + +/* Include needed system headers. */ + +# include +# include +# include /* size_t */ +# include +# include +# include + +# if defined(_WIN32) && !defined(__CYGWIN__) +# include + +# include +# include +# define KWSYS_SHARED_FORWARD_ESCAPE_ARGV /* re-escape argv for execvp */ +# else +# include +# include +# endif + +/* Configuration for this platform. */ + +/* The path separator for this platform. */ +# if defined(_WIN32) && !defined(__CYGWIN__) +# define KWSYS_SHARED_FORWARD_PATH_SEP ';' +# define KWSYS_SHARED_FORWARD_PATH_SLASH '\\' +# else +# define KWSYS_SHARED_FORWARD_PATH_SEP ':' +# define KWSYS_SHARED_FORWARD_PATH_SLASH '/' +# endif +static const char kwsys_shared_forward_path_sep[2] = { + KWSYS_SHARED_FORWARD_PATH_SEP, 0 +}; +static const char kwsys_shared_forward_path_slash[2] = { + KWSYS_SHARED_FORWARD_PATH_SLASH, 0 +}; + +/* The maximum length of a file name. */ +# if defined(PATH_MAX) +# define KWSYS_SHARED_FORWARD_MAXPATH PATH_MAX +# elif defined(MAXPATHLEN) +# define KWSYS_SHARED_FORWARD_MAXPATH MAXPATHLEN +# else +# define KWSYS_SHARED_FORWARD_MAXPATH 16384 +# endif + +/* Select the environment variable holding the shared library runtime + search path for this platform and build configuration. Also select + ldd command equivalent. */ + +/* Linux */ +# if defined(__linux) +# define KWSYS_SHARED_FORWARD_LDD "ldd" +# define KWSYS_SHARED_FORWARD_LDD_N 1 +# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" + +/* FreeBSD */ +# elif defined(__FreeBSD__) +# define KWSYS_SHARED_FORWARD_LDD "ldd" +# define KWSYS_SHARED_FORWARD_LDD_N 1 +# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" + +/* OpenBSD */ +# elif defined(__OpenBSD__) +# define KWSYS_SHARED_FORWARD_LDD "ldd" +# define KWSYS_SHARED_FORWARD_LDD_N 1 +# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" + +/* OS X */ +# elif defined(__APPLE__) +# define KWSYS_SHARED_FORWARD_LDD "otool", "-L" +# define KWSYS_SHARED_FORWARD_LDD_N 2 +# define KWSYS_SHARED_FORWARD_LDPATH "DYLD_LIBRARY_PATH" + +/* AIX */ +# elif defined(_AIX) +# define KWSYS_SHARED_FORWARD_LDD "dump", "-H" +# define KWSYS_SHARED_FORWARD_LDD_N 2 +# define KWSYS_SHARED_FORWARD_LDPATH "LIBPATH" + +/* SUN */ +# elif defined(__sun) +# define KWSYS_SHARED_FORWARD_LDD "ldd" +# define KWSYS_SHARED_FORWARD_LDD_N 1 +# include +# if defined(_ILP32) +# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" +# elif defined(_LP64) +# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH_64" +# endif + +/* HP-UX */ +# elif defined(__hpux) +# define KWSYS_SHARED_FORWARD_LDD "chatr" +# define KWSYS_SHARED_FORWARD_LDD_N 1 +# if defined(__LP64__) +# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" +# else +# define KWSYS_SHARED_FORWARD_LDPATH "SHLIB_PATH" +# endif + +/* SGI MIPS */ +# elif defined(__sgi) && defined(_MIPS_SIM) +# define KWSYS_SHARED_FORWARD_LDD "ldd" +# define KWSYS_SHARED_FORWARD_LDD_N 1 +# if _MIPS_SIM == _ABIO32 +# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" +# elif _MIPS_SIM == _ABIN32 +# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARYN32_PATH" +# elif _MIPS_SIM == _ABI64 +# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY64_PATH" +# endif + +/* Cygwin */ +# elif defined(__CYGWIN__) +# define KWSYS_SHARED_FORWARD_LDD \ + "cygcheck" /* TODO: cygwin 1.7 has ldd \ + */ +# define KWSYS_SHARED_FORWARD_LDD_N 1 +# define KWSYS_SHARED_FORWARD_LDPATH "PATH" + +/* Windows */ +# elif defined(_WIN32) +# define KWSYS_SHARED_FORWARD_LDPATH "PATH" + +/* Guess on this unknown system. */ +# else +# define KWSYS_SHARED_FORWARD_LDD "ldd" +# define KWSYS_SHARED_FORWARD_LDD_N 1 +# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" +# endif + +# ifdef KWSYS_SHARED_FORWARD_ESCAPE_ARGV +typedef struct kwsys_sf_arg_info_s +{ + const char* arg; + int size; + int quote; +} kwsys_sf_arg_info; + +static kwsys_sf_arg_info kwsys_sf_get_arg_info(const char* in) +{ + /* Initialize information. */ + kwsys_sf_arg_info info; + + /* String iterator. */ + const char* c; + + /* Keep track of how many backslashes have been encountered in a row. */ + int windows_backslashes = 0; + + /* Start with the length of the original argument, plus one for + either a terminating null or a separating space. */ + info.arg = in; + info.size = (int)strlen(in) + 1; + info.quote = 0; + + /* Scan the string for characters that require escaping or quoting. */ + for (c = in; *c; ++c) { + /* Check whether this character needs quotes. */ + if (strchr(" \t?'#&<>|^", *c)) { + info.quote = 1; + } + + /* On Windows only backslashes and double-quotes need escaping. */ + if (*c == '\\') { + /* Found a backslash. It may need to be escaped later. */ + ++windows_backslashes; + } else if (*c == '"') { + /* Found a double-quote. We need to escape it and all + immediately preceding backslashes. */ + info.size += windows_backslashes + 1; + windows_backslashes = 0; + } else { + /* Found another character. This eliminates the possibility + that any immediately preceding backslashes will be + escaped. */ + windows_backslashes = 0; + } + } + + /* Check whether the argument needs surrounding quotes. */ + if (info.quote) { + /* Surrounding quotes are needed. Allocate space for them. */ + info.size += 2; + + /* We must escape all ending backslashes when quoting on windows. */ + info.size += windows_backslashes; + } + + return info; +} + +static char* kwsys_sf_get_arg(kwsys_sf_arg_info info, char* out) +{ + /* String iterator. */ + const char* c; + + /* Keep track of how many backslashes have been encountered in a row. */ + int windows_backslashes = 0; + + /* Whether the argument must be quoted. */ + if (info.quote) { + /* Add the opening quote for this argument. */ + *out++ = '"'; + } + + /* Scan the string for characters that require escaping or quoting. */ + for (c = info.arg; *c; ++c) { + /* On Windows only backslashes and double-quotes need escaping. */ + if (*c == '\\') { + /* Found a backslash. It may need to be escaped later. */ + ++windows_backslashes; + } else if (*c == '"') { + /* Found a double-quote. Escape all immediately preceding + backslashes. */ + while (windows_backslashes > 0) { + --windows_backslashes; + *out++ = '\\'; + } + + /* Add the backslash to escape the double-quote. */ + *out++ = '\\'; + } else { + /* We encountered a normal character. This eliminates any + escaping needed for preceding backslashes. */ + windows_backslashes = 0; + } + + /* Store this character. */ + *out++ = *c; + } + + if (info.quote) { + /* Add enough backslashes to escape any trailing ones. */ + while (windows_backslashes > 0) { + --windows_backslashes; + *out++ = '\\'; + } + + /* Add the closing quote for this argument. */ + *out++ = '"'; + } + + /* Store a terminating null without incrementing. */ + *out = 0; + + return out; +} +# endif + +/* Function to convert a logical or relative path to a physical full path. */ +static int kwsys_shared_forward_realpath(const char* in_path, char* out_path) +{ +# if defined(_WIN32) && !defined(__CYGWIN__) + /* Implementation for Windows. */ + DWORD n = + GetFullPathNameA(in_path, KWSYS_SHARED_FORWARD_MAXPATH, out_path, 0); + return n > 0 && n <= KWSYS_SHARED_FORWARD_MAXPATH; +# else + /* Implementation for UNIX. */ + return realpath(in_path, out_path) != 0; +# endif +} + +static int kwsys_shared_forward_samepath(const char* file1, const char* file2) +{ +# if defined(_WIN32) + int result = 0; + HANDLE h1 = CreateFileA(file1, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + HANDLE h2 = CreateFileA(file2, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (h1 != INVALID_HANDLE_VALUE && h2 != INVALID_HANDLE_VALUE) { + BY_HANDLE_FILE_INFORMATION fi1; + BY_HANDLE_FILE_INFORMATION fi2; + GetFileInformationByHandle(h1, &fi1); + GetFileInformationByHandle(h2, &fi2); + result = (fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber && + fi1.nFileIndexHigh == fi2.nFileIndexHigh && + fi1.nFileIndexLow == fi2.nFileIndexLow); + } + CloseHandle(h1); + CloseHandle(h2); + return result; +# else + struct stat fs1, fs2; + return (stat(file1, &fs1) == 0 && stat(file2, &fs2) == 0 && + memcmp(&fs2.st_dev, &fs1.st_dev, sizeof(fs1.st_dev)) == 0 && + memcmp(&fs2.st_ino, &fs1.st_ino, sizeof(fs1.st_ino)) == 0 && + fs2.st_size == fs1.st_size); +# endif +} + +/* Function to report a system error message. */ +static void kwsys_shared_forward_strerror(char* message) +{ +# if defined(_WIN32) && !defined(__CYGWIN__) + /* Implementation for Windows. */ + DWORD original = GetLastError(); + DWORD length = + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + 0, original, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + message, KWSYS_SHARED_FORWARD_MAXPATH, 0); + if (length < 1 || length > KWSYS_SHARED_FORWARD_MAXPATH) { + /* FormatMessage failed. Use a default message. */ + _snprintf(message, KWSYS_SHARED_FORWARD_MAXPATH, + "Error 0x%X (FormatMessage failed with error 0x%X)", original, + GetLastError()); + } +# else + /* Implementation for UNIX. */ + strcpy(message, strerror(errno)); +# endif +} + +/* Functions to execute a child process. */ +static void kwsys_shared_forward_execvp(const char* cmd, + char const* const* argv) +{ +# ifdef KWSYS_SHARED_FORWARD_ESCAPE_ARGV + /* Count the number of arguments. */ + int argc = 0; + { + char const* const* argvc; + for (argvc = argv; *argvc; ++argvc, ++argc) { + } + } + + /* Create the escaped arguments. */ + { + char** nargv = (char**)malloc((argc + 1) * sizeof(char*)); + int i; + for (i = 0; i < argc; ++i) { + kwsys_sf_arg_info info = kwsys_sf_get_arg_info(argv[i]); + nargv[i] = (char*)malloc(info.size); + kwsys_sf_get_arg(info, nargv[i]); + } + nargv[argc] = 0; + + /* Replace the command line to be used. */ + argv = (char const* const*)nargv; + } +# endif + +/* Invoke the child process. */ +# if defined(_MSC_VER) + _execvp(cmd, argv); +# elif defined(__MINGW32__) && !defined(__MINGW64__) + execvp(cmd, argv); +# else + execvp(cmd, (char* const*)argv); +# endif +} + +/* Function to get the directory containing the given file or directory. */ +static void kwsys_shared_forward_dirname(const char* begin, char* result) +{ + /* Find the location of the last slash. */ + int last_slash_index = -1; + const char* end = begin + strlen(begin); + for (; begin <= end && last_slash_index < 0; --end) { + if (*end == '/' || *end == '\\') { + last_slash_index = (int)(end - begin); + } + } + + /* Handle each case of the index of the last slash. */ + if (last_slash_index < 0) { + /* No slashes. */ + strcpy(result, "."); + } else if (last_slash_index == 0) { + /* Only one leading slash. */ + strcpy(result, kwsys_shared_forward_path_slash); + } +# if defined(_WIN32) + else if (last_slash_index == 2 && begin[1] == ':') { + /* Only one leading drive letter and slash. */ + strncpy(result, begin, (size_t)last_slash_index); + result[last_slash_index] = KWSYS_SHARED_FORWARD_PATH_SLASH; + result[last_slash_index + 1] = 0; + } +# endif + else { + /* A non-leading slash. */ + strncpy(result, begin, (size_t)last_slash_index); + result[last_slash_index] = 0; + } +} + +/* Function to check if a file exists and is executable. */ +static int kwsys_shared_forward_is_executable(const char* f) +{ +# if defined(_MSC_VER) +# define KWSYS_SHARED_FORWARD_ACCESS _access +# else +# define KWSYS_SHARED_FORWARD_ACCESS access +# endif +# if defined(X_OK) +# define KWSYS_SHARED_FORWARD_ACCESS_OK X_OK +# else +# define KWSYS_SHARED_FORWARD_ACCESS_OK 04 +# endif + if (KWSYS_SHARED_FORWARD_ACCESS(f, KWSYS_SHARED_FORWARD_ACCESS_OK) == 0) { + return 1; + } else { + return 0; + } +} + +/* Function to locate the executable currently running. */ +static int kwsys_shared_forward_self_path(const char* argv0, char* result) +{ + /* Check whether argv0 has a slash. */ + int has_slash = 0; + const char* p = argv0; + for (; *p && !has_slash; ++p) { + if (*p == '/' || *p == '\\') { + has_slash = 1; + } + } + + if (has_slash) { + /* There is a slash. Use the dirname of the given location. */ + kwsys_shared_forward_dirname(argv0, result); + return 1; + } else { + /* There is no slash. Search the PATH for the executable. */ + const char* path = getenv("PATH"); + const char* begin = path; + const char* end = begin + (begin ? strlen(begin) : 0); + const char* first = begin; + while (first != end) { + /* Store the end of this path entry. */ + const char* last; + + /* Skip all path separators. */ + for (; *first && *first == KWSYS_SHARED_FORWARD_PATH_SEP; ++first) + ; + + /* Find the next separator. */ + for (last = first; *last && *last != KWSYS_SHARED_FORWARD_PATH_SEP; + ++last) + ; + + /* If we got a non-empty directory, look for the executable there. */ + if (first < last) { + /* Determine the length without trailing slash. */ + size_t length = (size_t)(last - first); + if (*(last - 1) == '/' || *(last - 1) == '\\') { + --length; + } + + /* Construct the name of the executable in this location. */ + strncpy(result, first, length); + result[length] = KWSYS_SHARED_FORWARD_PATH_SLASH; + strcpy(result + (length) + 1, argv0); + + /* Check if it exists and is executable. */ + if (kwsys_shared_forward_is_executable(result)) { + /* Found it. */ + result[length] = 0; + return 1; + } + } + + /* Move to the next directory in the path. */ + first = last; + } + } + + /* We could not find the executable. */ + return 0; +} + +/* Function to convert a specified path to a full path. If it is not + already full, it is taken relative to the self path. */ +static int kwsys_shared_forward_fullpath(const char* self_path, + const char* in_path, char* result, + const char* desc) +{ + /* Check the specified path type. */ + if (in_path[0] == '/') { + /* Already a full path. */ + strcpy(result, in_path); + } +# if defined(_WIN32) + else if (in_path[0] && in_path[1] == ':') { + /* Already a full path. */ + strcpy(result, in_path); + } +# endif + else { + /* Relative to self path. */ + char temp_path[KWSYS_SHARED_FORWARD_MAXPATH]; + strcpy(temp_path, self_path); + strcat(temp_path, kwsys_shared_forward_path_slash); + strcat(temp_path, in_path); + if (!kwsys_shared_forward_realpath(temp_path, result)) { + if (desc) { + char msgbuf[KWSYS_SHARED_FORWARD_MAXPATH]; + kwsys_shared_forward_strerror(msgbuf); + fprintf(stderr, "Error converting %s \"%s\" to real path: %s\n", desc, + temp_path, msgbuf); + } + return 0; + } + } + return 1; +} + +/* Function to compute the library search path and executable name + based on the self path. */ +static int kwsys_shared_forward_get_settings(const char* self_path, + char* ldpath, char* exe) +{ + /* Possible search paths. */ + static const char* search_path_build[] = { KWSYS_SHARED_FORWARD_PATH_BUILD, + 0 }; + static const char* search_path_install[] = { + KWSYS_SHARED_FORWARD_PATH_INSTALL, 0 + }; + + /* Chosen paths. */ + const char** search_path; + const char* exe_path; + +/* Get the real name of the build and self paths. */ +# if defined(KWSYS_SHARED_FORWARD_CONFIG_NAME) + char build_path[] = + KWSYS_SHARED_FORWARD_DIR_BUILD "/" KWSYS_SHARED_FORWARD_CONFIG_NAME; + char self_path_logical[KWSYS_SHARED_FORWARD_MAXPATH]; +# else + char build_path[] = KWSYS_SHARED_FORWARD_DIR_BUILD; + const char* self_path_logical = self_path; +# endif + char build_path_real[KWSYS_SHARED_FORWARD_MAXPATH]; + char self_path_real[KWSYS_SHARED_FORWARD_MAXPATH]; + if (!kwsys_shared_forward_realpath(self_path, self_path_real)) { + char msgbuf[KWSYS_SHARED_FORWARD_MAXPATH]; + kwsys_shared_forward_strerror(msgbuf); + fprintf(stderr, "Error converting self path \"%s\" to real path: %s\n", + self_path, msgbuf); + return 0; + } + + /* Check whether we are running in the build tree or an install tree. */ + if (kwsys_shared_forward_realpath(build_path, build_path_real) && + kwsys_shared_forward_samepath(self_path_real, build_path_real)) { + /* Running in build tree. Use the build path and exe. */ + search_path = search_path_build; +# if defined(_WIN32) + exe_path = KWSYS_SHARED_FORWARD_EXE_BUILD ".exe"; +# else + exe_path = KWSYS_SHARED_FORWARD_EXE_BUILD; +# endif + +# if defined(KWSYS_SHARED_FORWARD_CONFIG_NAME) + /* Remove the configuration directory from self_path. */ + kwsys_shared_forward_dirname(self_path, self_path_logical); +# endif + } else { + /* Running in install tree. Use the install path and exe. */ + search_path = search_path_install; +# if defined(_WIN32) + exe_path = KWSYS_SHARED_FORWARD_EXE_INSTALL ".exe"; +# else + exe_path = KWSYS_SHARED_FORWARD_EXE_INSTALL; +# endif + +# if defined(KWSYS_SHARED_FORWARD_CONFIG_NAME) + /* Use the original self path directory. */ + strcpy(self_path_logical, self_path); +# endif + } + + /* Construct the runtime search path. */ + { + const char** dir; + for (dir = search_path; *dir; ++dir) { + /* Add separator between path components. */ + if (dir != search_path) { + strcat(ldpath, kwsys_shared_forward_path_sep); + } + + /* Add this path component. */ + if (!kwsys_shared_forward_fullpath(self_path_logical, *dir, + ldpath + strlen(ldpath), + "runtime path entry")) { + return 0; + } + } + } + + /* Construct the executable location. */ + if (!kwsys_shared_forward_fullpath(self_path_logical, exe_path, exe, + "executable file")) { + return 0; + } + return 1; +} + +/* Function to print why execution of a command line failed. */ +static void kwsys_shared_forward_print_failure(char const* const* argv) +{ + char msg[KWSYS_SHARED_FORWARD_MAXPATH]; + char const* const* arg = argv; + kwsys_shared_forward_strerror(msg); + fprintf(stderr, "Error running"); + for (; *arg; ++arg) { + fprintf(stderr, " \"%s\"", *arg); + } + fprintf(stderr, ": %s\n", msg); +} + +/* Static storage space to store the updated environment variable. */ +static char kwsys_shared_forward_ldpath[65535] = + KWSYS_SHARED_FORWARD_LDPATH "="; + +/* Main driver function to be called from main. */ +static int @KWSYS_NAMESPACE@_shared_forward_to_real(int argc, char** argv_in) +{ + char const** argv = (char const**)argv_in; + /* Get the directory containing this executable. */ + char self_path[KWSYS_SHARED_FORWARD_MAXPATH]; + if (kwsys_shared_forward_self_path(argv[0], self_path)) { + /* Found this executable. Use it to get the library directory. */ + char exe[KWSYS_SHARED_FORWARD_MAXPATH]; + if (kwsys_shared_forward_get_settings(self_path, + kwsys_shared_forward_ldpath, exe)) { + /* Append the old runtime search path. */ + const char* old_ldpath = getenv(KWSYS_SHARED_FORWARD_LDPATH); + if (old_ldpath) { + strcat(kwsys_shared_forward_ldpath, kwsys_shared_forward_path_sep); + strcat(kwsys_shared_forward_ldpath, old_ldpath); + } + + /* Store the environment variable. */ + putenv(kwsys_shared_forward_ldpath); + +# if defined(KWSYS_SHARED_FORWARD_OPTION_COMMAND) + /* Look for the command line replacement option. */ + if (argc > 1 && + strcmp(argv[1], KWSYS_SHARED_FORWARD_OPTION_COMMAND) == 0) { + if (argc > 2) { + /* Use the command line given. */ + strcpy(exe, argv[2]); + argv += 2; + argc -= 2; + } else { + /* The option was not given an executable. */ + fprintf(stderr, + "Option " KWSYS_SHARED_FORWARD_OPTION_COMMAND + " must be followed by a command line.\n"); + return 1; + } + } +# endif + +# if defined(KWSYS_SHARED_FORWARD_OPTION_PRINT) + /* Look for the print command line option. */ + if (argc > 1 && + strcmp(argv[1], KWSYS_SHARED_FORWARD_OPTION_PRINT) == 0) { + fprintf(stdout, "%s\n", kwsys_shared_forward_ldpath); + fprintf(stdout, "%s\n", exe); + return 0; + } +# endif + +# if defined(KWSYS_SHARED_FORWARD_OPTION_LDD) + /* Look for the ldd command line option. */ + if (argc > 1 && strcmp(argv[1], KWSYS_SHARED_FORWARD_OPTION_LDD) == 0) { +# if defined(KWSYS_SHARED_FORWARD_LDD) + /* Use the named ldd-like executable and arguments. */ + char const* ldd_argv[] = { KWSYS_SHARED_FORWARD_LDD, 0, 0 }; + ldd_argv[KWSYS_SHARED_FORWARD_LDD_N] = exe; + kwsys_shared_forward_execvp(ldd_argv[0], ldd_argv); + + /* Report why execution failed. */ + kwsys_shared_forward_print_failure(ldd_argv); + return 1; +# else + /* We have no ldd-like executable available on this platform. */ + fprintf(stderr, "No ldd-like tool is known to this executable.\n"); + return 1; +# endif + } +# endif + + /* Replace this process with the real executable. */ + argv[0] = exe; + kwsys_shared_forward_execvp(argv[0], argv); + + /* Report why execution failed. */ + kwsys_shared_forward_print_failure(argv); + } else { + /* Could not convert self path to the library directory. */ + } + } else { + /* Could not find this executable. */ + fprintf(stderr, "Error locating executable \"%s\".\n", argv[0]); + } + + /* Avoid unused argument warning. */ + (void)argc; + + /* Exit with failure. */ + return 1; +} + +/* Restore warning stack. */ +# if defined(__clang__) && defined(__has_warning) +# if __has_warning("-Wcast-qual") +# pragma clang diagnostic pop +# endif +# endif + +#else +# error "@KWSYS_NAMESPACE@/SharedForward.h should be included only once." +#endif diff --git a/test/API/driver/kwsys/String.c b/test/API/driver/kwsys/String.c new file mode 100644 index 0000000..daf7ad1 --- /dev/null +++ b/test/API/driver/kwsys/String.c @@ -0,0 +1,100 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifdef KWSYS_STRING_C +/* +All code in this source file is conditionally compiled to work-around +template definition auto-search on VMS. Other source files in this +directory that use the stl string cause the compiler to load this +source to try to get the definition of the string template. This +condition blocks the compiler from seeing the symbols defined here. +*/ +# include "kwsysPrivate.h" +# include KWSYS_HEADER(String.h) + +/* Work-around CMake dependency scanning limitation. This must + duplicate the above list of headers. */ +# if 0 +# include "String.h.in" +# endif + +/* Select an implementation for strcasecmp. */ +# if defined(_MSC_VER) +# define KWSYS_STRING_USE_STRICMP +# include +# elif defined(__GNUC__) +# define KWSYS_STRING_USE_STRCASECMP +# include +# else +/* Table to convert upper case letters to lower case and leave all + other characters alone. */ +static char kwsysString_strcasecmp_tolower[] = { + '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', '\010', + '\011', '\012', '\013', '\014', '\015', '\016', '\017', '\020', '\021', + '\022', '\023', '\024', '\025', '\026', '\027', '\030', '\031', '\032', + '\033', '\034', '\035', '\036', '\037', '\040', '\041', '\042', '\043', + '\044', '\045', '\046', '\047', '\050', '\051', '\052', '\053', '\054', + '\055', '\056', '\057', '\060', '\061', '\062', '\063', '\064', '\065', + '\066', '\067', '\070', '\071', '\072', '\073', '\074', '\075', '\076', + '\077', '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147', + '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', '\160', + '\161', '\162', '\163', '\164', '\165', '\166', '\167', '\170', '\171', + '\172', '\133', '\134', '\135', '\136', '\137', '\140', '\141', '\142', + '\143', '\144', '\145', '\146', '\147', '\150', '\151', '\152', '\153', + '\154', '\155', '\156', '\157', '\160', '\161', '\162', '\163', '\164', + '\165', '\166', '\167', '\170', '\171', '\172', '\173', '\174', '\175', + '\176', '\177', '\200', '\201', '\202', '\203', '\204', '\205', '\206', + '\207', '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217', + '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', '\230', + '\231', '\232', '\233', '\234', '\235', '\236', '\237', '\240', '\241', + '\242', '\243', '\244', '\245', '\246', '\247', '\250', '\251', '\252', + '\253', '\254', '\255', '\256', '\257', '\260', '\261', '\262', '\263', + '\264', '\265', '\266', '\267', '\270', '\271', '\272', '\273', '\274', + '\275', '\276', '\277', '\300', '\301', '\302', '\303', '\304', '\305', + '\306', '\307', '\310', '\311', '\312', '\313', '\314', '\315', '\316', + '\317', '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327', + '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337', '\340', + '\341', '\342', '\343', '\344', '\345', '\346', '\347', '\350', '\351', + '\352', '\353', '\354', '\355', '\356', '\357', '\360', '\361', '\362', + '\363', '\364', '\365', '\366', '\367', '\370', '\371', '\372', '\373', + '\374', '\375', '\376', '\377' +}; +# endif + +/*--------------------------------------------------------------------------*/ +int kwsysString_strcasecmp(const char* lhs, const char* rhs) +{ +# if defined(KWSYS_STRING_USE_STRICMP) + return _stricmp(lhs, rhs); +# elif defined(KWSYS_STRING_USE_STRCASECMP) + return strcasecmp(lhs, rhs); +# else + const char* const lower = kwsysString_strcasecmp_tolower; + unsigned char const* us1 = (unsigned char const*)lhs; + unsigned char const* us2 = (unsigned char const*)rhs; + int result; + while ((result = lower[*us1] - lower[*us2++], result == 0) && *us1++) { + } + return result; +# endif +} + +/*--------------------------------------------------------------------------*/ +int kwsysString_strncasecmp(const char* lhs, const char* rhs, size_t n) +{ +# if defined(KWSYS_STRING_USE_STRICMP) + return _strnicmp(lhs, rhs, n); +# elif defined(KWSYS_STRING_USE_STRCASECMP) + return strncasecmp(lhs, rhs, n); +# else + const char* const lower = kwsysString_strcasecmp_tolower; + unsigned char const* us1 = (unsigned char const*)lhs; + unsigned char const* us2 = (unsigned char const*)rhs; + int result = 0; + while (n && (result = lower[*us1] - lower[*us2++], result == 0) && *us1++) { + --n; + } + return result; +# endif +} + +#endif /* KWSYS_STRING_C */ diff --git a/test/API/driver/kwsys/String.h.in b/test/API/driver/kwsys/String.h.in new file mode 100644 index 0000000..7c9348a --- /dev/null +++ b/test/API/driver/kwsys/String.h.in @@ -0,0 +1,57 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_String_h +#define @KWSYS_NAMESPACE@_String_h + +#include <@KWSYS_NAMESPACE@/Configure.h> + +#include /* size_t */ + +/* Redefine all public interface symbol names to be in the proper + namespace. These macros are used internally to kwsys only, and are + not visible to user code. Use kwsysHeaderDump.pl to reproduce + these macros after making changes to the interface. */ +#if !defined(KWSYS_NAMESPACE) +# define kwsys_ns(x) @KWSYS_NAMESPACE@##x +# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT +#endif +#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# define kwsysString_strcasecmp kwsys_ns(String_strcasecmp) +# define kwsysString_strncasecmp kwsys_ns(String_strncasecmp) +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * Compare two strings ignoring the case of the characters. The + * integer returned is negative, zero, or positive if the first string + * is found to be less than, equal to, or greater than the second + * string, respectively. + */ +kwsysEXPORT int kwsysString_strcasecmp(const char* lhs, const char* rhs); + +/** + * Identical to String_strcasecmp except that only the first n + * characters are considered. + */ +kwsysEXPORT int kwsysString_strncasecmp(const char* lhs, const char* rhs, + size_t n); + +#if defined(__cplusplus) +} /* extern "C" */ +#endif + +/* If we are building a kwsys .c or .cxx file, let it use these macros. + Otherwise, undefine them to keep the namespace clean. */ +#if !defined(KWSYS_NAMESPACE) +# undef kwsys_ns +# undef kwsysEXPORT +# if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# undef kwsysString_strcasecmp +# undef kwsysString_strncasecmp +# endif +#endif + +#endif diff --git a/test/API/driver/kwsys/String.hxx.in b/test/API/driver/kwsys/String.hxx.in new file mode 100644 index 0000000..db1cf22 --- /dev/null +++ b/test/API/driver/kwsys/String.hxx.in @@ -0,0 +1,65 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_String_hxx +#define @KWSYS_NAMESPACE@_String_hxx + +#include + +namespace @KWSYS_NAMESPACE@ { + +/** \class String + * \brief Short-name version of the STL basic_string class template. + * + * The standard library "string" type is actually a typedef for + * "basic_string<..long argument list..>". This string class is + * simply a subclass of this type with the same interface so that the + * name is shorter in debugging symbols and error messages. + */ +class String : public std::string +{ + /** The original string type. */ + typedef std::string stl_string; + +public: + /** String member types. */ + typedef stl_string::value_type value_type; + typedef stl_string::pointer pointer; + typedef stl_string::reference reference; + typedef stl_string::const_reference const_reference; + typedef stl_string::size_type size_type; + typedef stl_string::difference_type difference_type; + typedef stl_string::iterator iterator; + typedef stl_string::const_iterator const_iterator; + typedef stl_string::reverse_iterator reverse_iterator; + typedef stl_string::const_reverse_iterator const_reverse_iterator; + + /** String constructors. */ + String() + : stl_string() + { + } + String(const value_type* s) + : stl_string(s) + { + } + String(const value_type* s, size_type n) + : stl_string(s, n) + { + } + String(const stl_string& s, size_type pos = 0, size_type n = npos) + : stl_string(s, pos, n) + { + } +}; // End Class: String + +#if defined(__WATCOMC__) +inline bool operator<(String const& l, String const& r) +{ + return (static_cast(l) < + static_cast(r)); +} +#endif + +} // namespace @KWSYS_NAMESPACE@ + +#endif diff --git a/test/API/driver/kwsys/System.c b/test/API/driver/kwsys/System.c new file mode 100644 index 0000000..d43cc6f --- /dev/null +++ b/test/API/driver/kwsys/System.c @@ -0,0 +1,236 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(System.h) + +/* Work-around CMake dependency scanning limitation. This must + duplicate the above list of headers. */ +#if 0 +# include "System.h.in" +#endif + +#include /* isspace */ +#include /* ptrdiff_t */ +#include /* malloc, free */ +#include /* memcpy */ + +#include + +#if defined(KWSYS_C_HAS_PTRDIFF_T) && KWSYS_C_HAS_PTRDIFF_T +typedef ptrdiff_t kwsysSystem_ptrdiff_t; +#else +typedef int kwsysSystem_ptrdiff_t; +#endif + +static int kwsysSystem__AppendByte(char* local, char** begin, char** end, + int* size, char c) +{ + /* Allocate space for the character. */ + if ((*end - *begin) >= *size) { + kwsysSystem_ptrdiff_t length = *end - *begin; + char* newBuffer = (char*)malloc((size_t)(*size * 2)); + if (!newBuffer) { + return 0; + } + memcpy(newBuffer, *begin, (size_t)(length) * sizeof(char)); + if (*begin != local) { + free(*begin); + } + *begin = newBuffer; + *end = *begin + length; + *size *= 2; + } + + /* Store the character. */ + *(*end)++ = c; + return 1; +} + +static int kwsysSystem__AppendArgument(char** local, char*** begin, + char*** end, int* size, char* arg_local, + char** arg_begin, char** arg_end, + int* arg_size) +{ + /* Append a null-terminator to the argument string. */ + if (!kwsysSystem__AppendByte(arg_local, arg_begin, arg_end, arg_size, + '\0')) { + return 0; + } + + /* Allocate space for the argument pointer. */ + if ((*end - *begin) >= *size) { + kwsysSystem_ptrdiff_t length = *end - *begin; + char** newPointers = (char**)malloc((size_t)(*size) * 2 * sizeof(char*)); + if (!newPointers) { + return 0; + } + memcpy(newPointers, *begin, (size_t)(length) * sizeof(char*)); + if (*begin != local) { + free(*begin); + } + *begin = newPointers; + *end = *begin + length; + *size *= 2; + } + + /* Allocate space for the argument string. */ + **end = (char*)malloc((size_t)(*arg_end - *arg_begin)); + if (!**end) { + return 0; + } + + /* Store the argument in the command array. */ + memcpy(**end, *arg_begin, (size_t)(*arg_end - *arg_begin)); + ++(*end); + + /* Reset the argument to be empty. */ + *arg_end = *arg_begin; + + return 1; +} + +#define KWSYSPE_LOCAL_BYTE_COUNT 1024 +#define KWSYSPE_LOCAL_ARGS_COUNT 32 +static char** kwsysSystem__ParseUnixCommand(const char* command, int flags) +{ + /* Create a buffer for argument pointers during parsing. */ + char* local_pointers[KWSYSPE_LOCAL_ARGS_COUNT]; + int pointers_size = KWSYSPE_LOCAL_ARGS_COUNT; + char** pointer_begin = local_pointers; + char** pointer_end = pointer_begin; + + /* Create a buffer for argument strings during parsing. */ + char local_buffer[KWSYSPE_LOCAL_BYTE_COUNT]; + int buffer_size = KWSYSPE_LOCAL_BYTE_COUNT; + char* buffer_begin = local_buffer; + char* buffer_end = buffer_begin; + + /* Parse the command string. Try to behave like a UNIX shell. */ + char** newCommand = 0; + const char* c = command; + int in_argument = 0; + int in_escape = 0; + int in_single = 0; + int in_double = 0; + int failed = 0; + for (; *c; ++c) { + if (in_escape) { + /* This character is escaped so do no special handling. */ + if (!in_argument) { + in_argument = 1; + } + if (!kwsysSystem__AppendByte(local_buffer, &buffer_begin, &buffer_end, + &buffer_size, *c)) { + failed = 1; + break; + } + in_escape = 0; + } else if (*c == '\\') { + /* The next character should be escaped. */ + in_escape = 1; + } else if (*c == '\'' && !in_double) { + /* Enter or exit single-quote state. */ + if (in_single) { + in_single = 0; + } else { + in_single = 1; + if (!in_argument) { + in_argument = 1; + } + } + } else if (*c == '"' && !in_single) { + /* Enter or exit double-quote state. */ + if (in_double) { + in_double = 0; + } else { + in_double = 1; + if (!in_argument) { + in_argument = 1; + } + } + } else if (isspace((unsigned char)*c)) { + if (in_argument) { + if (in_single || in_double) { + /* This space belongs to a quoted argument. */ + if (!kwsysSystem__AppendByte(local_buffer, &buffer_begin, + &buffer_end, &buffer_size, *c)) { + failed = 1; + break; + } + } else { + /* This argument has been terminated by whitespace. */ + if (!kwsysSystem__AppendArgument( + local_pointers, &pointer_begin, &pointer_end, &pointers_size, + local_buffer, &buffer_begin, &buffer_end, &buffer_size)) { + failed = 1; + break; + } + in_argument = 0; + } + } + } else { + /* This character belong to an argument. */ + if (!in_argument) { + in_argument = 1; + } + if (!kwsysSystem__AppendByte(local_buffer, &buffer_begin, &buffer_end, + &buffer_size, *c)) { + failed = 1; + break; + } + } + } + + /* Finish the last argument. */ + if (in_argument) { + if (!kwsysSystem__AppendArgument( + local_pointers, &pointer_begin, &pointer_end, &pointers_size, + local_buffer, &buffer_begin, &buffer_end, &buffer_size)) { + failed = 1; + } + } + + /* If we still have memory allocate space for the new command + buffer. */ + if (!failed) { + kwsysSystem_ptrdiff_t n = pointer_end - pointer_begin; + newCommand = (char**)malloc((size_t)(n + 1) * sizeof(char*)); + } + + if (newCommand) { + /* Copy the arguments into the new command buffer. */ + kwsysSystem_ptrdiff_t n = pointer_end - pointer_begin; + memcpy(newCommand, pointer_begin, sizeof(char*) * (size_t)(n)); + newCommand[n] = 0; + } else { + /* Free arguments already allocated. */ + while (pointer_end != pointer_begin) { + free(*(--pointer_end)); + } + } + + /* Free temporary buffers. */ + if (pointer_begin != local_pointers) { + free(pointer_begin); + } + if (buffer_begin != local_buffer) { + free(buffer_begin); + } + + /* The flags argument is currently unused. */ + (void)flags; + + /* Return the final command buffer. */ + return newCommand; +} + +char** kwsysSystem_Parse_CommandForUnix(const char* command, int flags) +{ + /* Validate the flags. */ + if (flags != 0) { + return 0; + } + + /* Forward to our internal implementation. */ + return kwsysSystem__ParseUnixCommand(command, flags); +} diff --git a/test/API/driver/kwsys/System.h.in b/test/API/driver/kwsys/System.h.in new file mode 100644 index 0000000..a9d4f5e --- /dev/null +++ b/test/API/driver/kwsys/System.h.in @@ -0,0 +1,60 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_System_h +#define @KWSYS_NAMESPACE@_System_h + +#include <@KWSYS_NAMESPACE@/Configure.h> + +/* Redefine all public interface symbol names to be in the proper + namespace. These macros are used internally to kwsys only, and are + not visible to user code. Use kwsysHeaderDump.pl to reproduce + these macros after making changes to the interface. */ +#if !defined(KWSYS_NAMESPACE) +# define kwsys_ns(x) @KWSYS_NAMESPACE@##x +# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT +#endif +#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# define kwsysSystem_Parse_CommandForUnix \ + kwsys_ns(System_Parse_CommandForUnix) +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * Parse a unix-style command line string into separate arguments. + * + * On success, returns a pointer to an array of pointers to individual + * argument strings. Each string is null-terminated and the last + * entry in the array is a NULL pointer (just like argv). It is the + * caller's responsibility to free() the strings and the array of + * pointers to them. + * + * On failure, returns NULL. Failure occurs only on invalid flags or + * when memory cannot be allocated; never due to content of the input + * string. Missing close-quotes are treated as if the necessary + * closing quote appears. + * + * By default single- and double-quoted arguments are supported, and + * any character may be escaped by a backslash. The flags argument is + * reserved for future use, and must be zero (or the call will fail). + */ +kwsysEXPORT char** kwsysSystem_Parse_CommandForUnix(const char* command, + int flags); + +#if defined(__cplusplus) +} /* extern "C" */ +#endif + +/* If we are building a kwsys .c or .cxx file, let it use these macros. + Otherwise, undefine them to keep the namespace clean. */ +#if !defined(KWSYS_NAMESPACE) +# undef kwsys_ns +# undef kwsysEXPORT +# if !defined(KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# undef kwsysSystem_Parse_CommandForUnix +# endif +#endif + +#endif diff --git a/test/API/driver/kwsys/SystemInformation.cxx b/test/API/driver/kwsys/SystemInformation.cxx new file mode 100644 index 0000000..6ec6e48 --- /dev/null +++ b/test/API/driver/kwsys/SystemInformation.cxx @@ -0,0 +1,5466 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#if defined(_WIN32) +# define NOMINMAX // use our min,max +# if !defined(_WIN32_WINNT) && defined(_MSC_VER) && _MSC_VER >= 1800 +# define _WIN32_WINNT 0x0600 // vista +# endif +# if !defined(_WIN32_WINNT) && !(defined(_MSC_VER) && _MSC_VER < 1300) +# define _WIN32_WINNT 0x0501 +# endif +# include // WSADATA, include before sys/types.h +#endif + +#if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE) +# define _GNU_SOURCE +#endif + +// TODO: +// We need an alternative implementation for many functions in this file +// when USE_ASM_INSTRUCTIONS gets defined as 0. +// +// Consider using these on Win32/Win64 for some of them: +// +// IsProcessorFeaturePresent +// http://msdn.microsoft.com/en-us/library/ms724482(VS.85).aspx +// +// GetProcessMemoryInfo +// http://msdn.microsoft.com/en-us/library/ms683219(VS.85).aspx + +#include "kwsysPrivate.h" +#include KWSYS_HEADER(SystemInformation.hxx) +#include KWSYS_HEADER(Process.h) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "Process.h.in" +# include "SystemInformation.hxx.in" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_WIN32) +# include +# if defined(_MSC_VER) && _MSC_VER >= 1800 +# define KWSYS_WINDOWS_DEPRECATED_GetVersionEx +# endif +# include +# if defined(KWSYS_SYS_HAS_PSAPI) +# include +# endif +# if !defined(siginfo_t) +typedef int siginfo_t; +# endif +#else +# include + +# include // extern int errno; +# include +# include +# include // getrlimit +# include +# include // int uname(struct utsname *buf); +# include +#endif + +#if defined(__CYGWIN__) && !defined(_WIN32) +# include +# undef _WIN32 +#endif + +#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ + defined(__DragonFly__) +# include +# include +# include +# include +# include +# if defined(KWSYS_SYS_HAS_IFADDRS_H) +# include +# include +# define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN +# endif +#endif + +#if defined(KWSYS_SYS_HAS_MACHINE_CPU_H) +# include +#endif + +#ifdef __APPLE__ +# include +# include +# include +# include +# include +# include +# include +# include +# if defined(KWSYS_SYS_HAS_IFADDRS_H) +# include +# include +# define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN +# endif +# if !(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ - 0 >= 1050) +# undef KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE +# endif +#endif + +#if defined(__linux) || defined(__sun) || defined(_SCO_DS) || \ + defined(__GLIBC__) || defined(__GNU__) +# include +# include +# include +# if defined(KWSYS_SYS_HAS_IFADDRS_H) +# include +# include +# if defined(__LSB_VERSION__) +/* LSB has no getifaddrs */ +# elif defined(__ANDROID_API__) && __ANDROID_API__ < 24 +/* Android has no getifaddrs prior to API 24. */ +# else +# define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN +# endif +# endif +# if defined(KWSYS_CXX_HAS_RLIMIT64) +typedef struct rlimit64 ResourceLimitType; +# define GetResourceLimit getrlimit64 +# else +typedef struct rlimit ResourceLimitType; +# define GetResourceLimit getrlimit +# endif +#elif defined(__hpux) +# include +# include +# if defined(KWSYS_SYS_HAS_MPCTL_H) +# include +# endif +#endif + +#ifdef __HAIKU__ +# include +#endif + +#if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) +# include +# if defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE) +# include +# endif +# if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP) +# include +# endif +#else +# undef KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE +# undef KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP +#endif + +#include // int isdigit(int c); +#include +#include +#include +#include + +#if defined(KWSYS_USE_LONG_LONG) +# if defined(KWSYS_IOS_HAS_OSTREAM_LONG_LONG) +# define iostreamLongLong(x) (x) +# else +# define iostreamLongLong(x) ((long)(x)) +# endif +#elif defined(KWSYS_USE___INT64) +# if defined(KWSYS_IOS_HAS_OSTREAM___INT64) +# define iostreamLongLong(x) (x) +# else +# define iostreamLongLong(x) ((long)(x)) +# endif +#else +# error "No Long Long" +#endif + +#if defined(KWSYS_CXX_HAS_ATOLL) +# define atoLongLong atoll +#else +# if defined(KWSYS_CXX_HAS__ATOI64) +# define atoLongLong _atoi64 +# elif defined(KWSYS_CXX_HAS_ATOL) +# define atoLongLong atol +# else +# define atoLongLong atoi +# endif +#endif + +#if defined(_MSC_VER) && (_MSC_VER >= 1300) && !defined(_WIN64) && \ + !defined(__clang__) +# define USE_ASM_INSTRUCTIONS 1 +#else +# define USE_ASM_INSTRUCTIONS 0 +#endif + +#if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__clang__) +# include +# define USE_CPUID_INTRINSICS 1 +#else +# define USE_CPUID_INTRINSICS 0 +#endif + +#if USE_ASM_INSTRUCTIONS || USE_CPUID_INTRINSICS || \ + defined(KWSYS_CXX_HAS_BORLAND_ASM_CPUID) +# define USE_CPUID 1 +#else +# define USE_CPUID 0 +#endif + +#if USE_CPUID + +# define CPUID_AWARE_COMPILER + +/** + * call CPUID instruction + * + * Will return false if the instruction failed. + */ +static bool call_cpuid(int select, int result[4]) +{ +# if USE_CPUID_INTRINSICS + __cpuid(result, select); + return true; +# else + int tmp[4]; +# if defined(_MSC_VER) + // Use SEH to determine CPUID presence + __try { + _asm { +# ifdef CPUID_AWARE_COMPILER + ; we must push/pop the registers <> writes to, as the + ; optimiser does not know about <>, and so does not expect + ; these registers to change. + push eax + push ebx + push ecx + push edx +# endif + ; <> + mov eax, select +# ifdef CPUID_AWARE_COMPILER + cpuid +# else + _asm _emit 0x0f + _asm _emit 0xa2 +# endif + mov tmp[0 * TYPE int], eax + mov tmp[1 * TYPE int], ebx + mov tmp[2 * TYPE int], ecx + mov tmp[3 * TYPE int], edx + +# ifdef CPUID_AWARE_COMPILER + pop edx + pop ecx + pop ebx + pop eax +# endif + } + } __except (1) { + return false; + } + + memcpy(result, tmp, sizeof(tmp)); +# elif defined(KWSYS_CXX_HAS_BORLAND_ASM_CPUID) + unsigned int a, b, c, d; + __asm { + mov EAX, select; + cpuid + mov a, EAX; + mov b, EBX; + mov c, ECX; + mov d, EDX; + } + + result[0] = a; + result[1] = b; + result[2] = c; + result[3] = d; +# endif + + // The cpuid instruction succeeded. + return true; +# endif +} +#endif + +namespace KWSYS_NAMESPACE { +template +T min(T a, T b) +{ + return a < b ? a : b; +} + +extern "C" { +typedef void (*SigAction)(int, siginfo_t*, void*); +} + +// Define SystemInformationImplementation class +typedef void (*DELAY_FUNC)(unsigned int uiMS); + +class SystemInformationImplementation +{ +public: + typedef SystemInformation::LongLong LongLong; + SystemInformationImplementation(); + ~SystemInformationImplementation(); + + const char* GetVendorString(); + const char* GetVendorID(); + std::string GetTypeID(); + std::string GetFamilyID(); + std::string GetModelID(); + std::string GetModelName(); + std::string GetSteppingCode(); + const char* GetExtendedProcessorName(); + const char* GetProcessorSerialNumber(); + int GetProcessorCacheSize(); + unsigned int GetLogicalProcessorsPerPhysical(); + float GetProcessorClockFrequency(); + int GetProcessorAPICID(); + int GetProcessorCacheXSize(long int); + bool DoesCPUSupportFeature(long int); + + const char* GetOSName(); + const char* GetHostname(); + int GetFullyQualifiedDomainName(std::string& fqdn); + const char* GetOSRelease(); + const char* GetOSVersion(); + const char* GetOSPlatform(); + + bool Is64Bits(); + + unsigned int GetNumberOfLogicalCPU(); // per physical cpu + unsigned int GetNumberOfPhysicalCPU(); + + bool DoesCPUSupportCPUID(); + + // Retrieve memory information in MiB. + size_t GetTotalVirtualMemory(); + size_t GetAvailableVirtualMemory(); + size_t GetTotalPhysicalMemory(); + size_t GetAvailablePhysicalMemory(); + + LongLong GetProcessId(); + + // Retrieve memory information in KiB. + LongLong GetHostMemoryTotal(); + LongLong GetHostMemoryAvailable(const char* envVarName); + LongLong GetHostMemoryUsed(); + + LongLong GetProcMemoryAvailable(const char* hostLimitEnvVarName, + const char* procLimitEnvVarName); + LongLong GetProcMemoryUsed(); + + double GetLoadAverage(); + + // enable/disable stack trace signal handler. + static void SetStackTraceOnError(int enable); + + // get current stack + static std::string GetProgramStack(int firstFrame, int wholePath); + + /** Run the different checks */ + void RunCPUCheck(); + void RunOSCheck(); + void RunMemoryCheck(); + +public: + typedef struct tagID + { + int Type; + int Family; + int Model; + int Revision; + int ExtendedFamily; + int ExtendedModel; + std::string ProcessorName; + std::string Vendor; + std::string SerialNumber; + std::string ModelName; + } ID; + + typedef struct tagCPUPowerManagement + { + bool HasVoltageID; + bool HasFrequencyID; + bool HasTempSenseDiode; + } CPUPowerManagement; + + typedef struct tagCPUExtendedFeatures + { + bool Has3DNow; + bool Has3DNowPlus; + bool SupportsMP; + bool HasMMXPlus; + bool HasSSEMMX; + unsigned int LogicalProcessorsPerPhysical; + int APIC_ID; + CPUPowerManagement PowerManagement; + } CPUExtendedFeatures; + + typedef struct CPUtagFeatures + { + bool HasFPU; + bool HasTSC; + bool HasMMX; + bool HasSSE; + bool HasSSEFP; + bool HasSSE2; + bool HasIA64; + bool HasAPIC; + bool HasCMOV; + bool HasMTRR; + bool HasACPI; + bool HasSerial; + bool HasThermal; + int CPUSpeed; + int L1CacheSize; + int L2CacheSize; + int L3CacheSize; + CPUExtendedFeatures ExtendedFeatures; + } CPUFeatures; + + enum Manufacturer + { + AMD, + Intel, + NSC, + UMC, + Cyrix, + NexGen, + IDT, + Rise, + Transmeta, + Sun, + IBM, + Motorola, + HP, + Hygon, + UnknownManufacturer + }; + +protected: + // For windows + bool RetrieveCPUFeatures(); + bool RetrieveCPUIdentity(); + bool RetrieveCPUCacheDetails(); + bool RetrieveClassicalCPUCacheDetails(); + bool RetrieveCPUClockSpeed(); + bool RetrieveClassicalCPUClockSpeed(); + bool RetrieveCPUExtendedLevelSupport(int); + bool RetrieveExtendedCPUFeatures(); + bool RetrieveProcessorSerialNumber(); + bool RetrieveCPUPowerManagement(); + bool RetrieveClassicalCPUIdentity(); + bool RetrieveExtendedCPUIdentity(); + + // Processor information + Manufacturer ChipManufacturer; + CPUFeatures Features; + ID ChipID; + float CPUSpeedInMHz; + unsigned int NumberOfLogicalCPU; + unsigned int NumberOfPhysicalCPU; + + void CPUCountWindows(); // For windows + unsigned char GetAPICId(); // For windows + bool IsSMTSupported(); + static LongLong GetCyclesDifference(DELAY_FUNC, unsigned int); // For windows + + // For Linux and Cygwin, /proc/cpuinfo formats are slightly different + bool RetreiveInformationFromCpuInfoFile(); + std::string ExtractValueFromCpuInfoFile(std::string buffer, const char* word, + size_t init = 0); + + bool QueryLinuxMemory(); + bool QueryCygwinMemory(); + + static void Delay(unsigned int); + static void DelayOverhead(unsigned int); + + void FindManufacturer(const std::string& family = ""); + + // For Mac + bool ParseSysCtl(); + int CallSwVers(const char* arg, std::string& ver); + void TrimNewline(std::string&); + std::string ExtractValueFromSysCtl(const char* word); + std::string SysCtlBuffer; + + // For Solaris + bool QuerySolarisMemory(); + bool QuerySolarisProcessor(); + std::string ParseValueFromKStat(const char* arguments); + std::string RunProcess(std::vector args); + + // For Haiku OS + bool QueryHaikuInfo(); + + // For QNX + bool QueryQNXMemory(); + bool QueryQNXProcessor(); + + // For OpenBSD, FreeBSD, NetBSD, DragonFly + bool QueryBSDMemory(); + bool QueryBSDProcessor(); + + // For HP-UX + bool QueryHPUXMemory(); + bool QueryHPUXProcessor(); + + // For Microsoft Windows + bool QueryWindowsMemory(); + + // For AIX + bool QueryAIXMemory(); + + bool QueryProcessorBySysconf(); + bool QueryProcessor(); + + // Evaluate the memory information. + bool QueryMemoryBySysconf(); + bool QueryMemory(); + size_t TotalVirtualMemory; + size_t AvailableVirtualMemory; + size_t TotalPhysicalMemory; + size_t AvailablePhysicalMemory; + + size_t CurrentPositionInFile; + + // Operating System information + bool QueryOSInformation(); + std::string OSName; + std::string Hostname; + std::string OSRelease; + std::string OSVersion; + std::string OSPlatform; + bool OSIs64Bit; +}; + +SystemInformation::SystemInformation() +{ + this->Implementation = new SystemInformationImplementation; +} + +SystemInformation::~SystemInformation() +{ + delete this->Implementation; +} + +const char* SystemInformation::GetVendorString() +{ + return this->Implementation->GetVendorString(); +} + +const char* SystemInformation::GetVendorID() +{ + return this->Implementation->GetVendorID(); +} + +std::string SystemInformation::GetTypeID() +{ + return this->Implementation->GetTypeID(); +} + +std::string SystemInformation::GetFamilyID() +{ + return this->Implementation->GetFamilyID(); +} + +std::string SystemInformation::GetModelID() +{ + return this->Implementation->GetModelID(); +} + +std::string SystemInformation::GetModelName() +{ + return this->Implementation->GetModelName(); +} + +std::string SystemInformation::GetSteppingCode() +{ + return this->Implementation->GetSteppingCode(); +} + +const char* SystemInformation::GetExtendedProcessorName() +{ + return this->Implementation->GetExtendedProcessorName(); +} + +const char* SystemInformation::GetProcessorSerialNumber() +{ + return this->Implementation->GetProcessorSerialNumber(); +} + +int SystemInformation::GetProcessorCacheSize() +{ + return this->Implementation->GetProcessorCacheSize(); +} + +unsigned int SystemInformation::GetLogicalProcessorsPerPhysical() +{ + return this->Implementation->GetLogicalProcessorsPerPhysical(); +} + +float SystemInformation::GetProcessorClockFrequency() +{ + return this->Implementation->GetProcessorClockFrequency(); +} + +int SystemInformation::GetProcessorAPICID() +{ + return this->Implementation->GetProcessorAPICID(); +} + +int SystemInformation::GetProcessorCacheXSize(long int l) +{ + return this->Implementation->GetProcessorCacheXSize(l); +} + +bool SystemInformation::DoesCPUSupportFeature(long int i) +{ + return this->Implementation->DoesCPUSupportFeature(i); +} + +std::string SystemInformation::GetCPUDescription() +{ + std::ostringstream oss; + oss << this->GetNumberOfPhysicalCPU() << " core "; + if (this->GetModelName().empty()) { + oss << this->GetProcessorClockFrequency() << " MHz " + << this->GetVendorString() << " " << this->GetExtendedProcessorName(); + } else { + oss << this->GetModelName(); + } + + // remove extra spaces + std::string tmp = oss.str(); + size_t pos; + while ((pos = tmp.find(" ")) != std::string::npos) { + tmp.replace(pos, 2, " "); + } + + return tmp; +} + +const char* SystemInformation::GetOSName() +{ + return this->Implementation->GetOSName(); +} + +const char* SystemInformation::GetHostname() +{ + return this->Implementation->GetHostname(); +} + +std::string SystemInformation::GetFullyQualifiedDomainName() +{ + std::string fqdn; + this->Implementation->GetFullyQualifiedDomainName(fqdn); + return fqdn; +} + +const char* SystemInformation::GetOSRelease() +{ + return this->Implementation->GetOSRelease(); +} + +const char* SystemInformation::GetOSVersion() +{ + return this->Implementation->GetOSVersion(); +} + +const char* SystemInformation::GetOSPlatform() +{ + return this->Implementation->GetOSPlatform(); +} + +int SystemInformation::GetOSIsWindows() +{ +#if defined(_WIN32) + return 1; +#else + return 0; +#endif +} + +int SystemInformation::GetOSIsLinux() +{ +#if defined(__linux) + return 1; +#else + return 0; +#endif +} + +int SystemInformation::GetOSIsApple() +{ +#if defined(__APPLE__) + return 1; +#else + return 0; +#endif +} + +std::string SystemInformation::GetOSDescription() +{ + std::ostringstream oss; + oss << this->GetOSName() << " " << this->GetOSRelease() << " " + << this->GetOSVersion(); + + return oss.str(); +} + +bool SystemInformation::Is64Bits() +{ + return this->Implementation->Is64Bits(); +} + +unsigned int SystemInformation::GetNumberOfLogicalCPU() // per physical cpu +{ + return this->Implementation->GetNumberOfLogicalCPU(); +} + +unsigned int SystemInformation::GetNumberOfPhysicalCPU() +{ + return this->Implementation->GetNumberOfPhysicalCPU(); +} + +bool SystemInformation::DoesCPUSupportCPUID() +{ + return this->Implementation->DoesCPUSupportCPUID(); +} + +// Retrieve memory information in MiB. +size_t SystemInformation::GetTotalVirtualMemory() +{ + return this->Implementation->GetTotalVirtualMemory(); +} + +size_t SystemInformation::GetAvailableVirtualMemory() +{ + return this->Implementation->GetAvailableVirtualMemory(); +} + +size_t SystemInformation::GetTotalPhysicalMemory() +{ + return this->Implementation->GetTotalPhysicalMemory(); +} + +size_t SystemInformation::GetAvailablePhysicalMemory() +{ + return this->Implementation->GetAvailablePhysicalMemory(); +} + +std::string SystemInformation::GetMemoryDescription( + const char* hostLimitEnvVarName, const char* procLimitEnvVarName) +{ + std::ostringstream oss; + oss << "Host Total: " << iostreamLongLong(this->GetHostMemoryTotal()) + << " KiB, Host Available: " + << iostreamLongLong(this->GetHostMemoryAvailable(hostLimitEnvVarName)) + << " KiB, Process Available: " + << iostreamLongLong(this->GetProcMemoryAvailable(hostLimitEnvVarName, + procLimitEnvVarName)) + << " KiB"; + return oss.str(); +} + +// host memory info in units of KiB. +SystemInformation::LongLong SystemInformation::GetHostMemoryTotal() +{ + return this->Implementation->GetHostMemoryTotal(); +} + +SystemInformation::LongLong SystemInformation::GetHostMemoryAvailable( + const char* hostLimitEnvVarName) +{ + return this->Implementation->GetHostMemoryAvailable(hostLimitEnvVarName); +} + +SystemInformation::LongLong SystemInformation::GetHostMemoryUsed() +{ + return this->Implementation->GetHostMemoryUsed(); +} + +// process memory info in units of KiB. +SystemInformation::LongLong SystemInformation::GetProcMemoryAvailable( + const char* hostLimitEnvVarName, const char* procLimitEnvVarName) +{ + return this->Implementation->GetProcMemoryAvailable(hostLimitEnvVarName, + procLimitEnvVarName); +} + +SystemInformation::LongLong SystemInformation::GetProcMemoryUsed() +{ + return this->Implementation->GetProcMemoryUsed(); +} + +double SystemInformation::GetLoadAverage() +{ + return this->Implementation->GetLoadAverage(); +} + +SystemInformation::LongLong SystemInformation::GetProcessId() +{ + return this->Implementation->GetProcessId(); +} + +void SystemInformation::SetStackTraceOnError(int enable) +{ + SystemInformationImplementation::SetStackTraceOnError(enable); +} + +std::string SystemInformation::GetProgramStack(int firstFrame, int wholePath) +{ + return SystemInformationImplementation::GetProgramStack(firstFrame, + wholePath); +} + +/** Run the different checks */ +void SystemInformation::RunCPUCheck() +{ + this->Implementation->RunCPUCheck(); +} + +void SystemInformation::RunOSCheck() +{ + this->Implementation->RunOSCheck(); +} + +void SystemInformation::RunMemoryCheck() +{ + this->Implementation->RunMemoryCheck(); +} + +// SystemInformationImplementation starts here + +#if USE_CPUID +# define STORE_TLBCACHE_INFO(x, y) x = (x < (y)) ? (y) : x +# define TLBCACHE_INFO_UNITS (15) +#endif + +#if USE_ASM_INSTRUCTIONS +# define CLASSICAL_CPU_FREQ_LOOP 10000000 +# define RDTSC_INSTRUCTION _asm _emit 0x0f _asm _emit 0x31 +#endif + +#define INITIAL_APIC_ID_BITS 0xFF000000 +// initial APIC ID for the processor this code is running on. +// Default value = 0xff if HT is not supported + +// Hide implementation details in an anonymous namespace. +namespace { +// ***************************************************************************** +#if defined(__linux) || defined(__APPLE__) +int LoadLines(FILE* file, std::vector& lines) +{ + // Load each line in the given file into a the vector. + int nRead = 0; + const int bufSize = 1024; + char buf[bufSize] = { '\0' }; + while (!feof(file) && !ferror(file)) { + errno = 0; + if (fgets(buf, bufSize, file) == nullptr) { + if (ferror(file) && (errno == EINTR)) { + clearerr(file); + } + continue; + } + char* pBuf = buf; + while (*pBuf) { + if (*pBuf == '\n') + *pBuf = '\0'; + pBuf += 1; + } + lines.push_back(buf); + ++nRead; + } + if (ferror(file)) { + return 0; + } + return nRead; +} + +# if defined(__linux) +// ***************************************************************************** +int LoadLines(const char* fileName, std::vector& lines) +{ + FILE* file = fopen(fileName, "r"); + if (file == 0) { + return 0; + } + int nRead = LoadLines(file, lines); + fclose(file); + return nRead; +} +# endif + +// **************************************************************************** +template +int NameValue(std::vector const& lines, std::string const& name, + T& value) +{ + size_t nLines = lines.size(); + for (size_t i = 0; i < nLines; ++i) { + size_t at = lines[i].find(name); + if (at == std::string::npos) { + continue; + } + std::istringstream is(lines[i].substr(at + name.size())); + is >> value; + return 0; + } + return -1; +} +#endif + +#if defined(__linux) +// **************************************************************************** +template +int GetFieldsFromFile(const char* fileName, const char** fieldNames, T* values) +{ + std::vector fields; + if (!LoadLines(fileName, fields)) { + return -1; + } + int i = 0; + while (fieldNames[i] != nullptr) { + int ierr = NameValue(fields, fieldNames[i], values[i]); + if (ierr) { + return -(i + 2); + } + i += 1; + } + return 0; +} + +// **************************************************************************** +template +int GetFieldFromFile(const char* fileName, const char* fieldName, T& value) +{ + const char* fieldNames[2] = { fieldName, nullptr }; + T values[1] = { T(0) }; + int ierr = GetFieldsFromFile(fileName, fieldNames, values); + if (ierr) { + return ierr; + } + value = values[0]; + return 0; +} +#endif + +// **************************************************************************** +#if defined(__APPLE__) +template +int GetFieldsFromCommand(const char* command, const char** fieldNames, + T* values) +{ + FILE* file = popen(command, "r"); + if (file == nullptr) { + return -1; + } + std::vector fields; + int nl = LoadLines(file, fields); + pclose(file); + if (nl == 0) { + return -1; + } + int i = 0; + while (fieldNames[i] != nullptr) { + int ierr = NameValue(fields, fieldNames[i], values[i]); + if (ierr) { + return -(i + 2); + } + i += 1; + } + return 0; +} +#endif + +// **************************************************************************** +#if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) +void StacktraceSignalHandler(int sigNo, siginfo_t* sigInfo, + void* /*sigContext*/) +{ +# if defined(__linux) || defined(__APPLE__) + std::ostringstream oss; + oss << std::endl + << "=========================================================" + << std::endl + << "Process id " << getpid() << " "; + switch (sigNo) { + case SIGINT: + oss << "Caught SIGINT"; + break; + + case SIGTERM: + oss << "Caught SIGTERM"; + break; + + case SIGABRT: + oss << "Caught SIGABRT"; + break; + + case SIGFPE: + oss << "Caught SIGFPE at " << (sigInfo->si_addr == nullptr ? "0x" : "") + << sigInfo->si_addr << " "; + switch (sigInfo->si_code) { +# if defined(FPE_INTDIV) + case FPE_INTDIV: + oss << "integer division by zero"; + break; +# endif + +# if defined(FPE_INTOVF) + case FPE_INTOVF: + oss << "integer overflow"; + break; +# endif + + case FPE_FLTDIV: + oss << "floating point divide by zero"; + break; + + case FPE_FLTOVF: + oss << "floating point overflow"; + break; + + case FPE_FLTUND: + oss << "floating point underflow"; + break; + + case FPE_FLTRES: + oss << "floating point inexact result"; + break; + + case FPE_FLTINV: + oss << "floating point invalid operation"; + break; + +# if defined(FPE_FLTSUB) + case FPE_FLTSUB: + oss << "floating point subscript out of range"; + break; +# endif + + default: + oss << "code " << sigInfo->si_code; + break; + } + break; + + case SIGSEGV: + oss << "Caught SIGSEGV at " << (sigInfo->si_addr == nullptr ? "0x" : "") + << sigInfo->si_addr << " "; + switch (sigInfo->si_code) { + case SEGV_MAPERR: + oss << "address not mapped to object"; + break; + + case SEGV_ACCERR: + oss << "invalid permission for mapped object"; + break; + + default: + oss << "code " << sigInfo->si_code; + break; + } + break; + + case SIGBUS: + oss << "Caught SIGBUS at " << (sigInfo->si_addr == nullptr ? "0x" : "") + << sigInfo->si_addr << " "; + switch (sigInfo->si_code) { + case BUS_ADRALN: + oss << "invalid address alignment"; + break; + +# if defined(BUS_ADRERR) + case BUS_ADRERR: + oss << "nonexistent physical address"; + break; +# endif + +# if defined(BUS_OBJERR) + case BUS_OBJERR: + oss << "object-specific hardware error"; + break; +# endif + +# if defined(BUS_MCEERR_AR) + case BUS_MCEERR_AR: + oss << "Hardware memory error consumed on a machine check; action " + "required."; + break; +# endif + +# if defined(BUS_MCEERR_AO) + case BUS_MCEERR_AO: + oss << "Hardware memory error detected in process but not consumed; " + "action optional."; + break; +# endif + + default: + oss << "code " << sigInfo->si_code; + break; + } + break; + + case SIGILL: + oss << "Caught SIGILL at " << (sigInfo->si_addr == nullptr ? "0x" : "") + << sigInfo->si_addr << " "; + switch (sigInfo->si_code) { + case ILL_ILLOPC: + oss << "illegal opcode"; + break; + +# if defined(ILL_ILLOPN) + case ILL_ILLOPN: + oss << "illegal operand"; + break; +# endif + +# if defined(ILL_ILLADR) + case ILL_ILLADR: + oss << "illegal addressing mode."; + break; +# endif + + case ILL_ILLTRP: + oss << "illegal trap"; + break; + + case ILL_PRVOPC: + oss << "privileged opcode"; + break; + +# if defined(ILL_PRVREG) + case ILL_PRVREG: + oss << "privileged register"; + break; +# endif + +# if defined(ILL_COPROC) + case ILL_COPROC: + oss << "co-processor error"; + break; +# endif + +# if defined(ILL_BADSTK) + case ILL_BADSTK: + oss << "internal stack error"; + break; +# endif + + default: + oss << "code " << sigInfo->si_code; + break; + } + break; + + default: + oss << "Caught " << sigNo << " code " << sigInfo->si_code; + break; + } + oss << std::endl + << "Program Stack:" << std::endl + << SystemInformationImplementation::GetProgramStack(2, 0) + << "=========================================================" + << std::endl; + std::cerr << oss.str() << std::endl; + + // restore the previously registered handlers + // and abort + SystemInformationImplementation::SetStackTraceOnError(0); + abort(); +# else + // avoid warning C4100 + (void)sigNo; + (void)sigInfo; +# endif +} +#endif + +#if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) +# define safes(_arg) ((_arg) ? (_arg) : "???") + +// Description: +// A container for symbol properties. Each instance +// must be Initialized. +class SymbolProperties +{ +public: + SymbolProperties(); + + // Description: + // The SymbolProperties instance must be initialized by + // passing a stack address. + void Initialize(void* address); + + // Description: + // Get the symbol's stack address. + void* GetAddress() const { return this->Address; } + + // Description: + // If not set paths will be removed. eg, from a binary + // or source file. + void SetReportPath(int rp) { this->ReportPath = rp; } + + // Description: + // Set/Get the name of the binary file that the symbol + // is found in. + void SetBinary(const char* binary) { this->Binary = safes(binary); } + + std::string GetBinary() const; + + // Description: + // Set the name of the function that the symbol is found in. + // If c++ demangling is supported it will be demangled. + void SetFunction(const char* function) + { + this->Function = this->Demangle(function); + } + + std::string GetFunction() const { return this->Function; } + + // Description: + // Set/Get the name of the source file where the symbol + // is defined. + void SetSourceFile(const char* sourcefile) + { + this->SourceFile = safes(sourcefile); + } + + std::string GetSourceFile() const + { + return this->GetFileName(this->SourceFile); + } + + // Description: + // Set/Get the line number where the symbol is defined + void SetLineNumber(long linenumber) { this->LineNumber = linenumber; } + long GetLineNumber() const { return this->LineNumber; } + + // Description: + // Set the address where the binary image is mapped + // into memory. + void SetBinaryBaseAddress(void* address) + { + this->BinaryBaseAddress = address; + } + +private: + void* GetRealAddress() const + { + return (void*)((char*)this->Address - (char*)this->BinaryBaseAddress); + } + + std::string GetFileName(const std::string& path) const; + std::string Demangle(const char* symbol) const; + +private: + std::string Binary; + void* BinaryBaseAddress; + void* Address; + std::string SourceFile; + std::string Function; + long LineNumber; + int ReportPath; +}; + +std::ostream& operator<<(std::ostream& os, const SymbolProperties& sp) +{ +# if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP) + os << std::hex << sp.GetAddress() << " : " << sp.GetFunction() << " [(" + << sp.GetBinary() << ") " << sp.GetSourceFile() << ":" << std::dec + << sp.GetLineNumber() << "]"; +# elif defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) + void* addr = sp.GetAddress(); + char** syminfo = backtrace_symbols(&addr, 1); + os << safes(syminfo[0]); + free(syminfo); +# else + (void)os; + (void)sp; +# endif + return os; +} + +SymbolProperties::SymbolProperties() +{ + // not using an initializer list + // to avoid some PGI compiler warnings + this->SetBinary("???"); + this->SetBinaryBaseAddress(nullptr); + this->Address = nullptr; + this->SetSourceFile("???"); + this->SetFunction("???"); + this->SetLineNumber(-1); + this->SetReportPath(0); + // avoid PGI compiler warnings + this->GetRealAddress(); + this->GetFunction(); + this->GetSourceFile(); + this->GetLineNumber(); +} + +std::string SymbolProperties::GetFileName(const std::string& path) const +{ + std::string file(path); + if (!this->ReportPath) { + size_t at = file.rfind("/"); + if (at != std::string::npos) { + file = file.substr(at + 1); + } + } + return file; +} + +std::string SymbolProperties::GetBinary() const +{ +// only linux has proc fs +# if defined(__linux__) + if (this->Binary == "/proc/self/exe") { + std::string binary; + char buf[1024] = { '\0' }; + ssize_t ll = 0; + if ((ll = readlink("/proc/self/exe", buf, 1024)) > 0 && ll < 1024) { + buf[ll] = '\0'; + binary = buf; + } else { + binary = "/proc/self/exe"; + } + return this->GetFileName(binary); + } +# endif + return this->GetFileName(this->Binary); +} + +std::string SymbolProperties::Demangle(const char* symbol) const +{ + std::string result = safes(symbol); +# if defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE) + int status = 0; + size_t bufferLen = 1024; + char* buffer = (char*)malloc(1024); + char* demangledSymbol = + abi::__cxa_demangle(symbol, buffer, &bufferLen, &status); + if (!status) { + result = demangledSymbol; + } + free(buffer); +# else + (void)symbol; +# endif + return result; +} + +void SymbolProperties::Initialize(void* address) +{ + this->Address = address; +# if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP) + // first fallback option can demangle c++ functions + Dl_info info; + int ierr = dladdr(this->Address, &info); + if (ierr && info.dli_sname && info.dli_saddr) { + this->SetBinary(info.dli_fname); + this->SetFunction(info.dli_sname); + } +# else +// second fallback use builtin backtrace_symbols +// to decode the bactrace. +# endif +} +#endif // don't define this class if we're not using it + +#if defined(_WIN32) || defined(__CYGWIN__) +# define KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes +#endif +#if defined(_MSC_VER) && _MSC_VER < 1310 +# undef KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes +#endif +#if defined(KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes) +double calculateCPULoad(unsigned __int64 idleTicks, + unsigned __int64 totalTicks) +{ + static double previousLoad = -0.0; + static unsigned __int64 previousIdleTicks = 0; + static unsigned __int64 previousTotalTicks = 0; + + unsigned __int64 const idleTicksSinceLastTime = + idleTicks - previousIdleTicks; + unsigned __int64 const totalTicksSinceLastTime = + totalTicks - previousTotalTicks; + + double load; + if (previousTotalTicks == 0 || totalTicksSinceLastTime == 0) { + // No new information. Use previous result. + load = previousLoad; + } else { + // Calculate load since last time. + load = 1.0 - double(idleTicksSinceLastTime) / totalTicksSinceLastTime; + + // Smooth if possible. + if (previousLoad > 0) { + load = 0.25 * load + 0.75 * previousLoad; + } + } + + previousLoad = load; + previousIdleTicks = idleTicks; + previousTotalTicks = totalTicks; + + return load; +} + +unsigned __int64 fileTimeToUInt64(FILETIME const& ft) +{ + LARGE_INTEGER out; + out.HighPart = ft.dwHighDateTime; + out.LowPart = ft.dwLowDateTime; + return out.QuadPart; +} +#endif + +} // anonymous namespace + +SystemInformationImplementation::SystemInformationImplementation() +{ + this->TotalVirtualMemory = 0; + this->AvailableVirtualMemory = 0; + this->TotalPhysicalMemory = 0; + this->AvailablePhysicalMemory = 0; + this->CurrentPositionInFile = 0; + this->ChipManufacturer = UnknownManufacturer; + memset(&this->Features, 0, sizeof(CPUFeatures)); + this->ChipID.Type = 0; + this->ChipID.Family = 0; + this->ChipID.Model = 0; + this->ChipID.Revision = 0; + this->ChipID.ExtendedFamily = 0; + this->ChipID.ExtendedModel = 0; + this->CPUSpeedInMHz = 0; + this->NumberOfLogicalCPU = 0; + this->NumberOfPhysicalCPU = 0; + this->OSName = ""; + this->Hostname = ""; + this->OSRelease = ""; + this->OSVersion = ""; + this->OSPlatform = ""; + this->OSIs64Bit = (sizeof(void*) == 8); +} + +SystemInformationImplementation::~SystemInformationImplementation() +{ +} + +void SystemInformationImplementation::RunCPUCheck() +{ +#ifdef _WIN32 + // Check to see if this processor supports CPUID. + bool supportsCPUID = DoesCPUSupportCPUID(); + + if (supportsCPUID) { + // Retrieve the CPU details. + RetrieveCPUIdentity(); + this->FindManufacturer(); + RetrieveCPUFeatures(); + } + + // These two may be called without support for the CPUID instruction. + // (But if the instruction is there, they should be called *after* + // the above call to RetrieveCPUIdentity... that's why the two if + // blocks exist with the same "if (supportsCPUID)" logic... + // + if (!RetrieveCPUClockSpeed()) { + RetrieveClassicalCPUClockSpeed(); + } + + if (supportsCPUID) { + // Retrieve cache information. + if (!RetrieveCPUCacheDetails()) { + RetrieveClassicalCPUCacheDetails(); + } + + // Retrieve the extended CPU details. + if (!RetrieveExtendedCPUIdentity()) { + RetrieveClassicalCPUIdentity(); + } + + RetrieveExtendedCPUFeatures(); + RetrieveCPUPowerManagement(); + + // Now attempt to retrieve the serial number (if possible). + RetrieveProcessorSerialNumber(); + } + + this->CPUCountWindows(); + +#elif defined(__APPLE__) + this->ParseSysCtl(); +#elif defined(__SVR4) && defined(__sun) + this->QuerySolarisProcessor(); +#elif defined(__HAIKU__) + this->QueryHaikuInfo(); +#elif defined(__QNX__) + this->QueryQNXProcessor(); +#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ + defined(__DragonFly__) + this->QueryBSDProcessor(); +#elif defined(__hpux) + this->QueryHPUXProcessor(); +#elif defined(__linux) || defined(__CYGWIN__) + this->RetreiveInformationFromCpuInfoFile(); +#else + this->QueryProcessor(); +#endif +} + +void SystemInformationImplementation::RunOSCheck() +{ + this->QueryOSInformation(); +} + +void SystemInformationImplementation::RunMemoryCheck() +{ +#if defined(__APPLE__) + this->ParseSysCtl(); +#elif defined(__SVR4) && defined(__sun) + this->QuerySolarisMemory(); +#elif defined(__HAIKU__) + this->QueryHaikuInfo(); +#elif defined(__QNX__) + this->QueryQNXMemory(); +#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ + defined(__DragonFly__) + this->QueryBSDMemory(); +#elif defined(__CYGWIN__) + this->QueryCygwinMemory(); +#elif defined(_WIN32) + this->QueryWindowsMemory(); +#elif defined(__hpux) + this->QueryHPUXMemory(); +#elif defined(__linux) + this->QueryLinuxMemory(); +#elif defined(_AIX) + this->QueryAIXMemory(); +#else + this->QueryMemory(); +#endif +} + +/** Get the vendor string */ +const char* SystemInformationImplementation::GetVendorString() +{ + return this->ChipID.Vendor.c_str(); +} + +/** Get the OS Name */ +const char* SystemInformationImplementation::GetOSName() +{ + return this->OSName.c_str(); +} + +/** Get the hostname */ +const char* SystemInformationImplementation::GetHostname() +{ + if (this->Hostname.empty()) { + this->Hostname = "localhost"; +#if defined(_WIN32) + WORD wVersionRequested; + WSADATA wsaData; + char name[255]; + wVersionRequested = MAKEWORD(2, 0); + if (WSAStartup(wVersionRequested, &wsaData) == 0) { + gethostname(name, sizeof(name)); + WSACleanup(); + } + this->Hostname = name; +#else + struct utsname unameInfo; + int errorFlag = uname(&unameInfo); + if (errorFlag == 0) { + this->Hostname = unameInfo.nodename; + } +#endif + } + return this->Hostname.c_str(); +} + +/** Get the FQDN */ +int SystemInformationImplementation::GetFullyQualifiedDomainName( + std::string& fqdn) +{ + // in the event of absolute failure return localhost. + fqdn = "localhost"; + +#if defined(_WIN32) + int ierr; + // TODO - a more robust implementation for windows, see comments + // in unix implementation. + WSADATA wsaData; + WORD ver = MAKEWORD(2, 0); + ierr = WSAStartup(ver, &wsaData); + if (ierr) { + return -1; + } + + char base[256] = { '\0' }; + ierr = gethostname(base, 256); + if (ierr) { + WSACleanup(); + return -2; + } + fqdn = base; + + HOSTENT* hent = gethostbyname(base); + if (hent) { + fqdn = hent->h_name; + } + + WSACleanup(); + return 0; + +#elif defined(KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN) + // gethostname typical returns an alias for loopback interface + // we want the fully qualified domain name. Because there are + // any number of interfaces on this system we look for the + // first of these that contains the name returned by gethostname + // and is longer. failing that we return gethostname and indicate + // with a failure code. Return of a failure code is not necessarily + // an indication of an error. for instance gethostname may return + // the fully qualified domain name, or there may not be one if the + // system lives on a private network such as in the case of a cluster + // node. + + int ierr = 0; + char base[NI_MAXHOST]; + ierr = gethostname(base, NI_MAXHOST); + if (ierr) { + return -1; + } + size_t baseSize = strlen(base); + fqdn = base; + + struct ifaddrs* ifas; + struct ifaddrs* ifa; + ierr = getifaddrs(&ifas); + if (ierr) { + return -2; + } + + for (ifa = ifas; ifa != nullptr; ifa = ifa->ifa_next) { + int fam = ifa->ifa_addr ? ifa->ifa_addr->sa_family : -1; + // Skip Loopback interfaces + if (((fam == AF_INET) || (fam == AF_INET6)) && + !(ifa->ifa_flags & IFF_LOOPBACK)) { + char host[NI_MAXHOST] = { '\0' }; + + const size_t addrlen = (fam == AF_INET ? sizeof(struct sockaddr_in) + : sizeof(struct sockaddr_in6)); + + ierr = getnameinfo(ifa->ifa_addr, static_cast(addrlen), host, + NI_MAXHOST, nullptr, 0, NI_NAMEREQD); + if (ierr) { + // don't report the failure now since we may succeed on another + // interface. If all attempts fail then return the failure code. + ierr = -3; + continue; + } + + std::string candidate = host; + if ((candidate.find(base) != std::string::npos) && + baseSize < candidate.size()) { + // success, stop now. + ierr = 0; + fqdn = candidate; + break; + } + } + } + freeifaddrs(ifas); + + return ierr; +#else + /* TODO: Implement on more platforms. */ + fqdn = this->GetHostname(); + return -1; +#endif +} + +/** Get the OS release */ +const char* SystemInformationImplementation::GetOSRelease() +{ + return this->OSRelease.c_str(); +} + +/** Get the OS version */ +const char* SystemInformationImplementation::GetOSVersion() +{ + return this->OSVersion.c_str(); +} + +/** Get the OS platform */ +const char* SystemInformationImplementation::GetOSPlatform() +{ + return this->OSPlatform.c_str(); +} + +/** Get the vendor ID */ +const char* SystemInformationImplementation::GetVendorID() +{ + // Return the vendor ID. + switch (this->ChipManufacturer) { + case Intel: + return "Intel Corporation"; + case AMD: + return "Advanced Micro Devices"; + case NSC: + return "National Semiconductor"; + case Cyrix: + return "Cyrix Corp., VIA Inc."; + case NexGen: + return "NexGen Inc., Advanced Micro Devices"; + case IDT: + return "IDT\\Centaur, Via Inc."; + case UMC: + return "United Microelectronics Corp."; + case Rise: + return "Rise"; + case Transmeta: + return "Transmeta"; + case Sun: + return "Sun Microelectronics"; + case IBM: + return "IBM"; + case Motorola: + return "Motorola"; + case HP: + return "Hewlett-Packard"; + case Hygon: + return "Chengdu Haiguang IC Design Co., Ltd."; + case UnknownManufacturer: + default: + return "Unknown Manufacturer"; + } +} + +/** Return the type ID of the CPU */ +std::string SystemInformationImplementation::GetTypeID() +{ + std::ostringstream str; + str << this->ChipID.Type; + return str.str(); +} + +/** Return the family of the CPU present */ +std::string SystemInformationImplementation::GetFamilyID() +{ + std::ostringstream str; + str << this->ChipID.Family; + return str.str(); +} + +// Return the model of CPU present */ +std::string SystemInformationImplementation::GetModelID() +{ + std::ostringstream str; + str << this->ChipID.Model; + return str.str(); +} + +// Return the model name of CPU present */ +std::string SystemInformationImplementation::GetModelName() +{ + return this->ChipID.ModelName; +} + +/** Return the stepping code of the CPU present. */ +std::string SystemInformationImplementation::GetSteppingCode() +{ + std::ostringstream str; + str << this->ChipID.Revision; + return str.str(); +} + +/** Return the stepping code of the CPU present. */ +const char* SystemInformationImplementation::GetExtendedProcessorName() +{ + return this->ChipID.ProcessorName.c_str(); +} + +/** Return the serial number of the processor + * in hexadecimal: xxxx-xxxx-xxxx-xxxx-xxxx-xxxx. */ +const char* SystemInformationImplementation::GetProcessorSerialNumber() +{ + return this->ChipID.SerialNumber.c_str(); +} + +/** Return the logical processors per physical */ +unsigned int SystemInformationImplementation::GetLogicalProcessorsPerPhysical() +{ + return this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical; +} + +/** Return the processor clock frequency. */ +float SystemInformationImplementation::GetProcessorClockFrequency() +{ + return this->CPUSpeedInMHz; +} + +/** Return the APIC ID. */ +int SystemInformationImplementation::GetProcessorAPICID() +{ + return this->Features.ExtendedFeatures.APIC_ID; +} + +/** Return the L1 cache size. */ +int SystemInformationImplementation::GetProcessorCacheSize() +{ + return this->Features.L1CacheSize; +} + +/** Return the chosen cache size. */ +int SystemInformationImplementation::GetProcessorCacheXSize(long int dwCacheID) +{ + switch (dwCacheID) { + case SystemInformation::CPU_FEATURE_L1CACHE: + return this->Features.L1CacheSize; + case SystemInformation::CPU_FEATURE_L2CACHE: + return this->Features.L2CacheSize; + case SystemInformation::CPU_FEATURE_L3CACHE: + return this->Features.L3CacheSize; + } + return -1; +} + +bool SystemInformationImplementation::DoesCPUSupportFeature(long int dwFeature) +{ + bool bHasFeature = false; + + // Check for MMX instructions. + if (((dwFeature & SystemInformation::CPU_FEATURE_MMX) != 0) && + this->Features.HasMMX) + bHasFeature = true; + + // Check for MMX+ instructions. + if (((dwFeature & SystemInformation::CPU_FEATURE_MMX_PLUS) != 0) && + this->Features.ExtendedFeatures.HasMMXPlus) + bHasFeature = true; + + // Check for SSE FP instructions. + if (((dwFeature & SystemInformation::CPU_FEATURE_SSE) != 0) && + this->Features.HasSSE) + bHasFeature = true; + + // Check for SSE FP instructions. + if (((dwFeature & SystemInformation::CPU_FEATURE_SSE_FP) != 0) && + this->Features.HasSSEFP) + bHasFeature = true; + + // Check for SSE MMX instructions. + if (((dwFeature & SystemInformation::CPU_FEATURE_SSE_MMX) != 0) && + this->Features.ExtendedFeatures.HasSSEMMX) + bHasFeature = true; + + // Check for SSE2 instructions. + if (((dwFeature & SystemInformation::CPU_FEATURE_SSE2) != 0) && + this->Features.HasSSE2) + bHasFeature = true; + + // Check for 3DNow! instructions. + if (((dwFeature & SystemInformation::CPU_FEATURE_AMD_3DNOW) != 0) && + this->Features.ExtendedFeatures.Has3DNow) + bHasFeature = true; + + // Check for 3DNow+ instructions. + if (((dwFeature & SystemInformation::CPU_FEATURE_AMD_3DNOW_PLUS) != 0) && + this->Features.ExtendedFeatures.Has3DNowPlus) + bHasFeature = true; + + // Check for IA64 instructions. + if (((dwFeature & SystemInformation::CPU_FEATURE_IA64) != 0) && + this->Features.HasIA64) + bHasFeature = true; + + // Check for MP capable. + if (((dwFeature & SystemInformation::CPU_FEATURE_MP_CAPABLE) != 0) && + this->Features.ExtendedFeatures.SupportsMP) + bHasFeature = true; + + // Check for a serial number for the processor. + if (((dwFeature & SystemInformation::CPU_FEATURE_SERIALNUMBER) != 0) && + this->Features.HasSerial) + bHasFeature = true; + + // Check for a local APIC in the processor. + if (((dwFeature & SystemInformation::CPU_FEATURE_APIC) != 0) && + this->Features.HasAPIC) + bHasFeature = true; + + // Check for CMOV instructions. + if (((dwFeature & SystemInformation::CPU_FEATURE_CMOV) != 0) && + this->Features.HasCMOV) + bHasFeature = true; + + // Check for MTRR instructions. + if (((dwFeature & SystemInformation::CPU_FEATURE_MTRR) != 0) && + this->Features.HasMTRR) + bHasFeature = true; + + // Check for L1 cache size. + if (((dwFeature & SystemInformation::CPU_FEATURE_L1CACHE) != 0) && + (this->Features.L1CacheSize != -1)) + bHasFeature = true; + + // Check for L2 cache size. + if (((dwFeature & SystemInformation::CPU_FEATURE_L2CACHE) != 0) && + (this->Features.L2CacheSize != -1)) + bHasFeature = true; + + // Check for L3 cache size. + if (((dwFeature & SystemInformation::CPU_FEATURE_L3CACHE) != 0) && + (this->Features.L3CacheSize != -1)) + bHasFeature = true; + + // Check for ACPI capability. + if (((dwFeature & SystemInformation::CPU_FEATURE_ACPI) != 0) && + this->Features.HasACPI) + bHasFeature = true; + + // Check for thermal monitor support. + if (((dwFeature & SystemInformation::CPU_FEATURE_THERMALMONITOR) != 0) && + this->Features.HasThermal) + bHasFeature = true; + + // Check for temperature sensing diode support. + if (((dwFeature & SystemInformation::CPU_FEATURE_TEMPSENSEDIODE) != 0) && + this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode) + bHasFeature = true; + + // Check for frequency ID support. + if (((dwFeature & SystemInformation::CPU_FEATURE_FREQUENCYID) != 0) && + this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID) + bHasFeature = true; + + // Check for voltage ID support. + if (((dwFeature & SystemInformation::CPU_FEATURE_VOLTAGEID_FREQUENCY) != + 0) && + this->Features.ExtendedFeatures.PowerManagement.HasVoltageID) + bHasFeature = true; + + // Check for FPU support. + if (((dwFeature & SystemInformation::CPU_FEATURE_FPU) != 0) && + this->Features.HasFPU) + bHasFeature = true; + + return bHasFeature; +} + +void SystemInformationImplementation::Delay(unsigned int uiMS) +{ +#ifdef _WIN32 + LARGE_INTEGER Frequency, StartCounter, EndCounter; + __int64 x; + + // Get the frequency of the high performance counter. + if (!QueryPerformanceFrequency(&Frequency)) + return; + x = Frequency.QuadPart / 1000 * uiMS; + + // Get the starting position of the counter. + QueryPerformanceCounter(&StartCounter); + + do { + // Get the ending position of the counter. + QueryPerformanceCounter(&EndCounter); + } while (EndCounter.QuadPart - StartCounter.QuadPart < x); +#endif + (void)uiMS; +} + +bool SystemInformationImplementation::DoesCPUSupportCPUID() +{ +#if USE_CPUID + int dummy[4] = { 0, 0, 0, 0 }; + +# if USE_ASM_INSTRUCTIONS + return call_cpuid(0, dummy); +# else + call_cpuid(0, dummy); + return dummy[0] || dummy[1] || dummy[2] || dummy[3]; +# endif +#else + // Assume no cpuid instruction. + return false; +#endif +} + +bool SystemInformationImplementation::RetrieveCPUFeatures() +{ +#if USE_CPUID + int cpuinfo[4] = { 0, 0, 0, 0 }; + + if (!call_cpuid(1, cpuinfo)) { + return false; + } + + // Retrieve the features of CPU present. + this->Features.HasFPU = + ((cpuinfo[3] & 0x00000001) != 0); // FPU Present --> Bit 0 + this->Features.HasTSC = + ((cpuinfo[3] & 0x00000010) != 0); // TSC Present --> Bit 4 + this->Features.HasAPIC = + ((cpuinfo[3] & 0x00000200) != 0); // APIC Present --> Bit 9 + this->Features.HasMTRR = + ((cpuinfo[3] & 0x00001000) != 0); // MTRR Present --> Bit 12 + this->Features.HasCMOV = + ((cpuinfo[3] & 0x00008000) != 0); // CMOV Present --> Bit 15 + this->Features.HasSerial = + ((cpuinfo[3] & 0x00040000) != 0); // Serial Present --> Bit 18 + this->Features.HasACPI = + ((cpuinfo[3] & 0x00400000) != 0); // ACPI Capable --> Bit 22 + this->Features.HasMMX = + ((cpuinfo[3] & 0x00800000) != 0); // MMX Present --> Bit 23 + this->Features.HasSSE = + ((cpuinfo[3] & 0x02000000) != 0); // SSE Present --> Bit 25 + this->Features.HasSSE2 = + ((cpuinfo[3] & 0x04000000) != 0); // SSE2 Present --> Bit 26 + this->Features.HasThermal = + ((cpuinfo[3] & 0x20000000) != 0); // Thermal Monitor Present --> Bit 29 + this->Features.HasIA64 = + ((cpuinfo[3] & 0x40000000) != 0); // IA64 Present --> Bit 30 + +# if USE_ASM_INSTRUCTIONS + // Retrieve extended SSE capabilities if SSE is available. + if (this->Features.HasSSE) { + + // Attempt to __try some SSE FP instructions. + __try { + // Perform: orps xmm0, xmm0 + _asm + { + _emit 0x0f + _emit 0x56 + _emit 0xc0 + } + + // SSE FP capable processor. + this->Features.HasSSEFP = true; + } __except (1) { + // bad instruction - processor or OS cannot handle SSE FP. + this->Features.HasSSEFP = false; + } + } else { + // Set the advanced SSE capabilities to not available. + this->Features.HasSSEFP = false; + } +# else + this->Features.HasSSEFP = false; +# endif + + // Retrieve Intel specific extended features. + if (this->ChipManufacturer == Intel) { + bool SupportsSMT = + ((cpuinfo[3] & 0x10000000) != 0); // Intel specific: SMT --> Bit 28 + + if ((SupportsSMT) && (this->Features.HasAPIC)) { + // Retrieve APIC information if there is one present. + this->Features.ExtendedFeatures.APIC_ID = + ((cpuinfo[1] & 0xFF000000) >> 24); + } + } + + return true; + +#else + return false; +#endif +} + +/** Find the manufacturer given the vendor id */ +void SystemInformationImplementation::FindManufacturer( + const std::string& family) +{ + if (this->ChipID.Vendor == "GenuineIntel") + this->ChipManufacturer = Intel; // Intel Corp. + else if (this->ChipID.Vendor == "UMC UMC UMC ") + this->ChipManufacturer = UMC; // United Microelectronics Corp. + else if (this->ChipID.Vendor == "AuthenticAMD") + this->ChipManufacturer = AMD; // Advanced Micro Devices + else if (this->ChipID.Vendor == "AMD ISBETTER") + this->ChipManufacturer = AMD; // Advanced Micro Devices (1994) + else if (this->ChipID.Vendor == "HygonGenuine") + this->ChipManufacturer = Hygon; // Chengdu Haiguang IC Design Co., Ltd. + else if (this->ChipID.Vendor == "CyrixInstead") + this->ChipManufacturer = Cyrix; // Cyrix Corp., VIA Inc. + else if (this->ChipID.Vendor == "NexGenDriven") + this->ChipManufacturer = NexGen; // NexGen Inc. (now AMD) + else if (this->ChipID.Vendor == "CentaurHauls") + this->ChipManufacturer = IDT; // IDT/Centaur (now VIA) + else if (this->ChipID.Vendor == "RiseRiseRise") + this->ChipManufacturer = Rise; // Rise + else if (this->ChipID.Vendor == "GenuineTMx86") + this->ChipManufacturer = Transmeta; // Transmeta + else if (this->ChipID.Vendor == "TransmetaCPU") + this->ChipManufacturer = Transmeta; // Transmeta + else if (this->ChipID.Vendor == "Geode By NSC") + this->ChipManufacturer = NSC; // National Semiconductor + else if (this->ChipID.Vendor == "Sun") + this->ChipManufacturer = Sun; // Sun Microelectronics + else if (this->ChipID.Vendor == "IBM") + this->ChipManufacturer = IBM; // IBM Microelectronics + else if (this->ChipID.Vendor == "Hewlett-Packard") + this->ChipManufacturer = HP; // Hewlett-Packard + else if (this->ChipID.Vendor == "Motorola") + this->ChipManufacturer = Motorola; // Motorola Microelectronics + else if (family.substr(0, 7) == "PA-RISC") + this->ChipManufacturer = HP; // Hewlett-Packard + else + this->ChipManufacturer = UnknownManufacturer; // Unknown manufacturer +} + +/** */ +bool SystemInformationImplementation::RetrieveCPUIdentity() +{ +#if USE_CPUID + int localCPUVendor[4]; + int localCPUSignature[4]; + + if (!call_cpuid(0, localCPUVendor)) { + return false; + } + if (!call_cpuid(1, localCPUSignature)) { + return false; + } + + // Process the returned information. + // ; eax = 0 --> eax: maximum value of CPUID instruction. + // ; ebx: part 1 of 3; CPU signature. + // ; edx: part 2 of 3; CPU signature. + // ; ecx: part 3 of 3; CPU signature. + char vbuf[13]; + memcpy(&(vbuf[0]), &(localCPUVendor[1]), sizeof(int)); + memcpy(&(vbuf[4]), &(localCPUVendor[3]), sizeof(int)); + memcpy(&(vbuf[8]), &(localCPUVendor[2]), sizeof(int)); + vbuf[12] = '\0'; + this->ChipID.Vendor = vbuf; + + // Retrieve the family of CPU present. + // ; eax = 1 --> eax: CPU ID - bits 31..16 - unused, bits 15..12 - type, + // bits 11..8 - family, bits 7..4 - model, bits 3..0 - mask revision + // ; ebx: 31..24 - default APIC ID, 23..16 - logical processor ID, + // 15..8 - CFLUSH chunk size , 7..0 - brand ID + // ; edx: CPU feature flags + this->ChipID.ExtendedFamily = + ((localCPUSignature[0] & 0x0FF00000) >> 20); // Bits 27..20 Used + this->ChipID.ExtendedModel = + ((localCPUSignature[0] & 0x000F0000) >> 16); // Bits 19..16 Used + this->ChipID.Type = + ((localCPUSignature[0] & 0x0000F000) >> 12); // Bits 15..12 Used + this->ChipID.Family = + ((localCPUSignature[0] & 0x00000F00) >> 8); // Bits 11..8 Used + this->ChipID.Model = + ((localCPUSignature[0] & 0x000000F0) >> 4); // Bits 7..4 Used + this->ChipID.Revision = + ((localCPUSignature[0] & 0x0000000F) >> 0); // Bits 3..0 Used + + return true; + +#else + return false; +#endif +} + +/** */ +bool SystemInformationImplementation::RetrieveCPUCacheDetails() +{ +#if USE_CPUID + int L1Cache[4] = { 0, 0, 0, 0 }; + int L2Cache[4] = { 0, 0, 0, 0 }; + + // Check to see if what we are about to do is supported... + if (RetrieveCPUExtendedLevelSupport(0x80000005)) { + if (!call_cpuid(0x80000005, L1Cache)) { + return false; + } + // Save the L1 data cache size (in KB) from ecx: bits 31..24 as well as + // data cache size from edx: bits 31..24. + this->Features.L1CacheSize = ((L1Cache[2] & 0xFF000000) >> 24); + this->Features.L1CacheSize += ((L1Cache[3] & 0xFF000000) >> 24); + } else { + // Store -1 to indicate the cache could not be queried. + this->Features.L1CacheSize = -1; + } + + // Check to see if what we are about to do is supported... + if (RetrieveCPUExtendedLevelSupport(0x80000006)) { + if (!call_cpuid(0x80000006, L2Cache)) { + return false; + } + // Save the L2 unified cache size (in KB) from ecx: bits 31..16. + this->Features.L2CacheSize = ((L2Cache[2] & 0xFFFF0000) >> 16); + } else { + // Store -1 to indicate the cache could not be queried. + this->Features.L2CacheSize = -1; + } + + // Define L3 as being not present as we cannot test for it. + this->Features.L3CacheSize = -1; + +#endif + + // Return failure if we cannot detect either cache with this method. + return ((this->Features.L1CacheSize == -1) && + (this->Features.L2CacheSize == -1)) + ? false + : true; +} + +/** */ +bool SystemInformationImplementation::RetrieveClassicalCPUCacheDetails() +{ +#if USE_CPUID + int TLBCode = -1, TLBData = -1, L1Code = -1, L1Data = -1, L1Trace = -1, + L2Unified = -1, L3Unified = -1; + int TLBCacheData[4] = { 0, 0, 0, 0 }; + int TLBPassCounter = 0; + int TLBCacheUnit = 0; + + do { + if (!call_cpuid(2, TLBCacheData)) { + return false; + } + + int bob = ((TLBCacheData[0] & 0x00FF0000) >> 16); + (void)bob; + // Process the returned TLB and cache information. + for (int nCounter = 0; nCounter < TLBCACHE_INFO_UNITS; nCounter++) { + // First of all - decide which unit we are dealing with. + switch (nCounter) { + // eax: bits 8..15 : bits 16..23 : bits 24..31 + case 0: + TLBCacheUnit = ((TLBCacheData[0] & 0x0000FF00) >> 8); + break; + case 1: + TLBCacheUnit = ((TLBCacheData[0] & 0x00FF0000) >> 16); + break; + case 2: + TLBCacheUnit = ((TLBCacheData[0] & 0xFF000000) >> 24); + break; + + // ebx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31 + case 3: + TLBCacheUnit = ((TLBCacheData[1] & 0x000000FF) >> 0); + break; + case 4: + TLBCacheUnit = ((TLBCacheData[1] & 0x0000FF00) >> 8); + break; + case 5: + TLBCacheUnit = ((TLBCacheData[1] & 0x00FF0000) >> 16); + break; + case 6: + TLBCacheUnit = ((TLBCacheData[1] & 0xFF000000) >> 24); + break; + + // ecx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31 + case 7: + TLBCacheUnit = ((TLBCacheData[2] & 0x000000FF) >> 0); + break; + case 8: + TLBCacheUnit = ((TLBCacheData[2] & 0x0000FF00) >> 8); + break; + case 9: + TLBCacheUnit = ((TLBCacheData[2] & 0x00FF0000) >> 16); + break; + case 10: + TLBCacheUnit = ((TLBCacheData[2] & 0xFF000000) >> 24); + break; + + // edx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31 + case 11: + TLBCacheUnit = ((TLBCacheData[3] & 0x000000FF) >> 0); + break; + case 12: + TLBCacheUnit = ((TLBCacheData[3] & 0x0000FF00) >> 8); + break; + case 13: + TLBCacheUnit = ((TLBCacheData[3] & 0x00FF0000) >> 16); + break; + case 14: + TLBCacheUnit = ((TLBCacheData[3] & 0xFF000000) >> 24); + break; + + // Default case - an error has occurred. + default: + return false; + } + + // Now process the resulting unit to see what it means.... + switch (TLBCacheUnit) { + case 0x00: + break; + case 0x01: + STORE_TLBCACHE_INFO(TLBCode, 4); + break; + case 0x02: + STORE_TLBCACHE_INFO(TLBCode, 4096); + break; + case 0x03: + STORE_TLBCACHE_INFO(TLBData, 4); + break; + case 0x04: + STORE_TLBCACHE_INFO(TLBData, 4096); + break; + case 0x06: + STORE_TLBCACHE_INFO(L1Code, 8); + break; + case 0x08: + STORE_TLBCACHE_INFO(L1Code, 16); + break; + case 0x0a: + STORE_TLBCACHE_INFO(L1Data, 8); + break; + case 0x0c: + STORE_TLBCACHE_INFO(L1Data, 16); + break; + case 0x10: + STORE_TLBCACHE_INFO(L1Data, 16); + break; // <-- FIXME: IA-64 Only + case 0x15: + STORE_TLBCACHE_INFO(L1Code, 16); + break; // <-- FIXME: IA-64 Only + case 0x1a: + STORE_TLBCACHE_INFO(L2Unified, 96); + break; // <-- FIXME: IA-64 Only + case 0x22: + STORE_TLBCACHE_INFO(L3Unified, 512); + break; + case 0x23: + STORE_TLBCACHE_INFO(L3Unified, 1024); + break; + case 0x25: + STORE_TLBCACHE_INFO(L3Unified, 2048); + break; + case 0x29: + STORE_TLBCACHE_INFO(L3Unified, 4096); + break; + case 0x39: + STORE_TLBCACHE_INFO(L2Unified, 128); + break; + case 0x3c: + STORE_TLBCACHE_INFO(L2Unified, 256); + break; + case 0x40: + STORE_TLBCACHE_INFO(L2Unified, 0); + break; // <-- FIXME: No integrated L2 cache (P6 core) or L3 cache (P4 + // core). + case 0x41: + STORE_TLBCACHE_INFO(L2Unified, 128); + break; + case 0x42: + STORE_TLBCACHE_INFO(L2Unified, 256); + break; + case 0x43: + STORE_TLBCACHE_INFO(L2Unified, 512); + break; + case 0x44: + STORE_TLBCACHE_INFO(L2Unified, 1024); + break; + case 0x45: + STORE_TLBCACHE_INFO(L2Unified, 2048); + break; + case 0x50: + STORE_TLBCACHE_INFO(TLBCode, 4096); + break; + case 0x51: + STORE_TLBCACHE_INFO(TLBCode, 4096); + break; + case 0x52: + STORE_TLBCACHE_INFO(TLBCode, 4096); + break; + case 0x5b: + STORE_TLBCACHE_INFO(TLBData, 4096); + break; + case 0x5c: + STORE_TLBCACHE_INFO(TLBData, 4096); + break; + case 0x5d: + STORE_TLBCACHE_INFO(TLBData, 4096); + break; + case 0x66: + STORE_TLBCACHE_INFO(L1Data, 8); + break; + case 0x67: + STORE_TLBCACHE_INFO(L1Data, 16); + break; + case 0x68: + STORE_TLBCACHE_INFO(L1Data, 32); + break; + case 0x70: + STORE_TLBCACHE_INFO(L1Trace, 12); + break; + case 0x71: + STORE_TLBCACHE_INFO(L1Trace, 16); + break; + case 0x72: + STORE_TLBCACHE_INFO(L1Trace, 32); + break; + case 0x77: + STORE_TLBCACHE_INFO(L1Code, 16); + break; // <-- FIXME: IA-64 Only + case 0x79: + STORE_TLBCACHE_INFO(L2Unified, 128); + break; + case 0x7a: + STORE_TLBCACHE_INFO(L2Unified, 256); + break; + case 0x7b: + STORE_TLBCACHE_INFO(L2Unified, 512); + break; + case 0x7c: + STORE_TLBCACHE_INFO(L2Unified, 1024); + break; + case 0x7e: + STORE_TLBCACHE_INFO(L2Unified, 256); + break; + case 0x81: + STORE_TLBCACHE_INFO(L2Unified, 128); + break; + case 0x82: + STORE_TLBCACHE_INFO(L2Unified, 256); + break; + case 0x83: + STORE_TLBCACHE_INFO(L2Unified, 512); + break; + case 0x84: + STORE_TLBCACHE_INFO(L2Unified, 1024); + break; + case 0x85: + STORE_TLBCACHE_INFO(L2Unified, 2048); + break; + case 0x88: + STORE_TLBCACHE_INFO(L3Unified, 2048); + break; // <-- FIXME: IA-64 Only + case 0x89: + STORE_TLBCACHE_INFO(L3Unified, 4096); + break; // <-- FIXME: IA-64 Only + case 0x8a: + STORE_TLBCACHE_INFO(L3Unified, 8192); + break; // <-- FIXME: IA-64 Only + case 0x8d: + STORE_TLBCACHE_INFO(L3Unified, 3096); + break; // <-- FIXME: IA-64 Only + case 0x90: + STORE_TLBCACHE_INFO(TLBCode, 262144); + break; // <-- FIXME: IA-64 Only + case 0x96: + STORE_TLBCACHE_INFO(TLBCode, 262144); + break; // <-- FIXME: IA-64 Only + case 0x9b: + STORE_TLBCACHE_INFO(TLBCode, 262144); + break; // <-- FIXME: IA-64 Only + + // Default case - an error has occurred. + default: + return false; + } + } + + // Increment the TLB pass counter. + TLBPassCounter++; + } while ((TLBCacheData[0] & 0x000000FF) > TLBPassCounter); + + // Ok - we now have the maximum TLB, L1, L2, and L3 sizes... + if ((L1Code == -1) && (L1Data == -1) && (L1Trace == -1)) { + this->Features.L1CacheSize = -1; + } else if ((L1Code == -1) && (L1Data == -1) && (L1Trace != -1)) { + this->Features.L1CacheSize = L1Trace; + } else if ((L1Code != -1) && (L1Data == -1)) { + this->Features.L1CacheSize = L1Code; + } else if ((L1Code == -1) && (L1Data != -1)) { + this->Features.L1CacheSize = L1Data; + } else if ((L1Code != -1) && (L1Data != -1)) { + this->Features.L1CacheSize = L1Code + L1Data; + } else { + this->Features.L1CacheSize = -1; + } + + // Ok - we now have the maximum TLB, L1, L2, and L3 sizes... + if (L2Unified == -1) { + this->Features.L2CacheSize = -1; + } else { + this->Features.L2CacheSize = L2Unified; + } + + // Ok - we now have the maximum TLB, L1, L2, and L3 sizes... + if (L3Unified == -1) { + this->Features.L3CacheSize = -1; + } else { + this->Features.L3CacheSize = L3Unified; + } + + return true; + +#else + return false; +#endif +} + +/** */ +bool SystemInformationImplementation::RetrieveCPUClockSpeed() +{ + bool retrieved = false; + +#if defined(_WIN32) + unsigned int uiRepetitions = 1; + unsigned int uiMSecPerRepetition = 50; + __int64 i64Total = 0; + __int64 i64Overhead = 0; + + // Check if the TSC implementation works at all + if (this->Features.HasTSC && + GetCyclesDifference(SystemInformationImplementation::Delay, + uiMSecPerRepetition) > 0) { + for (unsigned int nCounter = 0; nCounter < uiRepetitions; nCounter++) { + i64Total += GetCyclesDifference(SystemInformationImplementation::Delay, + uiMSecPerRepetition); + i64Overhead += GetCyclesDifference( + SystemInformationImplementation::DelayOverhead, uiMSecPerRepetition); + } + + // Calculate the MHz speed. + i64Total -= i64Overhead; + i64Total /= uiRepetitions; + i64Total /= uiMSecPerRepetition; + i64Total /= 1000; + + // Save the CPU speed. + this->CPUSpeedInMHz = (float)i64Total; + + retrieved = true; + } + + // If RDTSC is not supported, we fallback to trying to read this value + // from the registry: + if (!retrieved) { + HKEY hKey = nullptr; + LONG err = + RegOpenKeyExW(HKEY_LOCAL_MACHINE, + L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, + KEY_READ, &hKey); + + if (ERROR_SUCCESS == err) { + DWORD dwType = 0; + DWORD data = 0; + DWORD dwSize = sizeof(DWORD); + + err = + RegQueryValueExW(hKey, L"~MHz", 0, &dwType, (LPBYTE)&data, &dwSize); + + if (ERROR_SUCCESS == err) { + this->CPUSpeedInMHz = (float)data; + retrieved = true; + } + + RegCloseKey(hKey); + hKey = nullptr; + } + } +#endif + + return retrieved; +} + +/** */ +bool SystemInformationImplementation::RetrieveClassicalCPUClockSpeed() +{ +#if USE_ASM_INSTRUCTIONS + LARGE_INTEGER liStart, liEnd, liCountsPerSecond; + double dFrequency, dDifference; + + // Attempt to get a starting tick count. + QueryPerformanceCounter(&liStart); + + __try { + _asm { + mov eax, 0x80000000 + mov ebx, CLASSICAL_CPU_FREQ_LOOP + Timer_Loop: + bsf ecx,eax + dec ebx + jnz Timer_Loop + } + } __except (1) { + return false; + } + + // Attempt to get a starting tick count. + QueryPerformanceCounter(&liEnd); + + // Get the difference... NB: This is in seconds.... + QueryPerformanceFrequency(&liCountsPerSecond); + dDifference = (((double)liEnd.QuadPart - (double)liStart.QuadPart) / + (double)liCountsPerSecond.QuadPart); + + // Calculate the clock speed. + if (this->ChipID.Family == 3) { + // 80386 processors.... Loop time is 115 cycles! + dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 115) / dDifference) / 1000000); + } else if (this->ChipID.Family == 4) { + // 80486 processors.... Loop time is 47 cycles! + dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 47) / dDifference) / 1000000); + } else if (this->ChipID.Family == 5) { + // Pentium processors.... Loop time is 43 cycles! + dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 43) / dDifference) / 1000000); + } + + // Save the clock speed. + this->Features.CPUSpeed = (int)dFrequency; + + return true; + +#else + return false; +#endif +} + +/** */ +bool SystemInformationImplementation::RetrieveCPUExtendedLevelSupport( + int CPULevelToCheck) +{ + int cpuinfo[4] = { 0, 0, 0, 0 }; + + // The extended CPUID is supported by various vendors starting with the + // following CPU models: + // + // Manufacturer & Chip Name | Family Model Revision + // + // AMD K6, K6-2 | 5 6 x + // Cyrix GXm, Cyrix III "Joshua" | 5 4 x + // IDT C6-2 | 5 8 x + // VIA Cyrix III | 6 5 x + // Transmeta Crusoe | 5 x x + // Intel Pentium 4 | f x x + // + + // We check to see if a supported processor is present... + if (this->ChipManufacturer == AMD) { + if (this->ChipID.Family < 5) + return false; + if ((this->ChipID.Family == 5) && (this->ChipID.Model < 6)) + return false; + } else if (this->ChipManufacturer == Cyrix) { + if (this->ChipID.Family < 5) + return false; + if ((this->ChipID.Family == 5) && (this->ChipID.Model < 4)) + return false; + if ((this->ChipID.Family == 6) && (this->ChipID.Model < 5)) + return false; + } else if (this->ChipManufacturer == IDT) { + if (this->ChipID.Family < 5) + return false; + if ((this->ChipID.Family == 5) && (this->ChipID.Model < 8)) + return false; + } else if (this->ChipManufacturer == Transmeta) { + if (this->ChipID.Family < 5) + return false; + } else if (this->ChipManufacturer == Intel) { + if (this->ChipID.Family < 0xf) { + return false; + } + } + +#if USE_CPUID + if (!call_cpuid(0x80000000, cpuinfo)) { + return false; + } +#endif + + // Now we have to check the level wanted vs level returned... + int nLevelWanted = (CPULevelToCheck & 0x7FFFFFFF); + int nLevelReturn = (cpuinfo[0] & 0x7FFFFFFF); + + // Check to see if the level provided is supported... + if (nLevelWanted > nLevelReturn) { + return false; + } + + return true; +} + +/** */ +bool SystemInformationImplementation::RetrieveExtendedCPUFeatures() +{ + + // Check that we are not using an Intel processor as it does not support + // this. + if (this->ChipManufacturer == Intel) { + return false; + } + + // Check to see if what we are about to do is supported... + if (!RetrieveCPUExtendedLevelSupport(static_cast(0x80000001))) { + return false; + } + +#if USE_CPUID + int localCPUExtendedFeatures[4] = { 0, 0, 0, 0 }; + + if (!call_cpuid(0x80000001, localCPUExtendedFeatures)) { + return false; + } + + // Retrieve the extended features of CPU present. + this->Features.ExtendedFeatures.Has3DNow = + ((localCPUExtendedFeatures[3] & 0x80000000) != + 0); // 3DNow Present --> Bit 31. + this->Features.ExtendedFeatures.Has3DNowPlus = + ((localCPUExtendedFeatures[3] & 0x40000000) != + 0); // 3DNow+ Present -- > Bit 30. + this->Features.ExtendedFeatures.HasSSEMMX = + ((localCPUExtendedFeatures[3] & 0x00400000) != + 0); // SSE MMX Present --> Bit 22. + this->Features.ExtendedFeatures.SupportsMP = + ((localCPUExtendedFeatures[3] & 0x00080000) != + 0); // MP Capable -- > Bit 19. + + // Retrieve AMD specific extended features. + if (this->ChipManufacturer == AMD || this->ChipManufacturer == Hygon) { + this->Features.ExtendedFeatures.HasMMXPlus = + ((localCPUExtendedFeatures[3] & 0x00400000) != + 0); // AMD specific: MMX-SSE --> Bit 22 + } + + // Retrieve Cyrix specific extended features. + if (this->ChipManufacturer == Cyrix) { + this->Features.ExtendedFeatures.HasMMXPlus = + ((localCPUExtendedFeatures[3] & 0x01000000) != + 0); // Cyrix specific: Extended MMX --> Bit 24 + } + + return true; + +#else + return false; +#endif +} + +/** */ +bool SystemInformationImplementation::RetrieveProcessorSerialNumber() +{ + // Check to see if the processor supports the processor serial number. + if (!this->Features.HasSerial) { + return false; + } + +#if USE_CPUID + int SerialNumber[4]; + + if (!call_cpuid(3, SerialNumber)) { + return false; + } + + // Process the returned information. + // ; eax = 3 --> ebx: top 32 bits are the processor signature bits --> NB: + // Transmeta only ?!? + // ; ecx: middle 32 bits are the processor signature bits + // ; edx: bottom 32 bits are the processor signature bits + char sn[128]; + sprintf(sn, "%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x", + ((SerialNumber[1] & 0xff000000) >> 24), + ((SerialNumber[1] & 0x00ff0000) >> 16), + ((SerialNumber[1] & 0x0000ff00) >> 8), + ((SerialNumber[1] & 0x000000ff) >> 0), + ((SerialNumber[2] & 0xff000000) >> 24), + ((SerialNumber[2] & 0x00ff0000) >> 16), + ((SerialNumber[2] & 0x0000ff00) >> 8), + ((SerialNumber[2] & 0x000000ff) >> 0), + ((SerialNumber[3] & 0xff000000) >> 24), + ((SerialNumber[3] & 0x00ff0000) >> 16), + ((SerialNumber[3] & 0x0000ff00) >> 8), + ((SerialNumber[3] & 0x000000ff) >> 0)); + this->ChipID.SerialNumber = sn; + return true; + +#else + return false; +#endif +} + +/** */ +bool SystemInformationImplementation::RetrieveCPUPowerManagement() +{ + // Check to see if what we are about to do is supported... + if (!RetrieveCPUExtendedLevelSupport(static_cast(0x80000007))) { + this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID = false; + this->Features.ExtendedFeatures.PowerManagement.HasVoltageID = false; + this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode = false; + return false; + } + +#if USE_CPUID + int localCPUPowerManagement[4] = { 0, 0, 0, 0 }; + + if (!call_cpuid(0x80000007, localCPUPowerManagement)) { + return false; + } + + // Check for the power management capabilities of the CPU. + this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode = + ((localCPUPowerManagement[3] & 0x00000001) != 0); + this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID = + ((localCPUPowerManagement[3] & 0x00000002) != 0); + this->Features.ExtendedFeatures.PowerManagement.HasVoltageID = + ((localCPUPowerManagement[3] & 0x00000004) != 0); + + return true; + +#else + return false; +#endif +} + +#if USE_CPUID +// Used only in USE_CPUID implementation below. +static void SystemInformationStripLeadingSpace(std::string& str) +{ + // Because some manufacturers have leading white space - we have to + // post-process the name. + std::string::size_type pos = str.find_first_not_of(" "); + if (pos != std::string::npos) { + str = str.substr(pos); + } +} +#endif + +/** */ +bool SystemInformationImplementation::RetrieveExtendedCPUIdentity() +{ + // Check to see if what we are about to do is supported... + if (!RetrieveCPUExtendedLevelSupport(static_cast(0x80000002))) + return false; + if (!RetrieveCPUExtendedLevelSupport(static_cast(0x80000003))) + return false; + if (!RetrieveCPUExtendedLevelSupport(static_cast(0x80000004))) + return false; + +#if USE_CPUID + int CPUExtendedIdentity[12]; + + if (!call_cpuid(0x80000002, CPUExtendedIdentity)) { + return false; + } + if (!call_cpuid(0x80000003, CPUExtendedIdentity + 4)) { + return false; + } + if (!call_cpuid(0x80000004, CPUExtendedIdentity + 8)) { + return false; + } + + // Process the returned information. + char nbuf[49]; + memcpy(&(nbuf[0]), &(CPUExtendedIdentity[0]), sizeof(int)); + memcpy(&(nbuf[4]), &(CPUExtendedIdentity[1]), sizeof(int)); + memcpy(&(nbuf[8]), &(CPUExtendedIdentity[2]), sizeof(int)); + memcpy(&(nbuf[12]), &(CPUExtendedIdentity[3]), sizeof(int)); + memcpy(&(nbuf[16]), &(CPUExtendedIdentity[4]), sizeof(int)); + memcpy(&(nbuf[20]), &(CPUExtendedIdentity[5]), sizeof(int)); + memcpy(&(nbuf[24]), &(CPUExtendedIdentity[6]), sizeof(int)); + memcpy(&(nbuf[28]), &(CPUExtendedIdentity[7]), sizeof(int)); + memcpy(&(nbuf[32]), &(CPUExtendedIdentity[8]), sizeof(int)); + memcpy(&(nbuf[36]), &(CPUExtendedIdentity[9]), sizeof(int)); + memcpy(&(nbuf[40]), &(CPUExtendedIdentity[10]), sizeof(int)); + memcpy(&(nbuf[44]), &(CPUExtendedIdentity[11]), sizeof(int)); + nbuf[48] = '\0'; + this->ChipID.ProcessorName = nbuf; + this->ChipID.ModelName = nbuf; + + // Because some manufacturers have leading white space - we have to + // post-process the name. + SystemInformationStripLeadingSpace(this->ChipID.ProcessorName); + return true; +#else + return false; +#endif +} + +/** */ +bool SystemInformationImplementation::RetrieveClassicalCPUIdentity() +{ + // Start by decided which manufacturer we are using.... + switch (this->ChipManufacturer) { + case Intel: + // Check the family / model / revision to determine the CPU ID. + switch (this->ChipID.Family) { + case 3: + this->ChipID.ProcessorName = "Newer i80386 family"; + break; + case 4: + switch (this->ChipID.Model) { + case 0: + this->ChipID.ProcessorName = "i80486DX-25/33"; + break; + case 1: + this->ChipID.ProcessorName = "i80486DX-50"; + break; + case 2: + this->ChipID.ProcessorName = "i80486SX"; + break; + case 3: + this->ChipID.ProcessorName = "i80486DX2"; + break; + case 4: + this->ChipID.ProcessorName = "i80486SL"; + break; + case 5: + this->ChipID.ProcessorName = "i80486SX2"; + break; + case 7: + this->ChipID.ProcessorName = "i80486DX2 WriteBack"; + break; + case 8: + this->ChipID.ProcessorName = "i80486DX4"; + break; + case 9: + this->ChipID.ProcessorName = "i80486DX4 WriteBack"; + break; + default: + this->ChipID.ProcessorName = "Unknown 80486 family"; + return false; + } + break; + case 5: + switch (this->ChipID.Model) { + case 0: + this->ChipID.ProcessorName = "P5 A-Step"; + break; + case 1: + this->ChipID.ProcessorName = "P5"; + break; + case 2: + this->ChipID.ProcessorName = "P54C"; + break; + case 3: + this->ChipID.ProcessorName = "P24T OverDrive"; + break; + case 4: + this->ChipID.ProcessorName = "P55C"; + break; + case 7: + this->ChipID.ProcessorName = "P54C"; + break; + case 8: + this->ChipID.ProcessorName = "P55C (0.25micron)"; + break; + default: + this->ChipID.ProcessorName = "Unknown Pentium family"; + return false; + } + break; + case 6: + switch (this->ChipID.Model) { + case 0: + this->ChipID.ProcessorName = "P6 A-Step"; + break; + case 1: + this->ChipID.ProcessorName = "P6"; + break; + case 3: + this->ChipID.ProcessorName = "Pentium II (0.28 micron)"; + break; + case 5: + this->ChipID.ProcessorName = "Pentium II (0.25 micron)"; + break; + case 6: + this->ChipID.ProcessorName = "Pentium II With On-Die L2 Cache"; + break; + case 7: + this->ChipID.ProcessorName = "Pentium III (0.25 micron)"; + break; + case 8: + this->ChipID.ProcessorName = + "Pentium III (0.18 micron) With 256 KB On-Die L2 Cache "; + break; + case 0xa: + this->ChipID.ProcessorName = + "Pentium III (0.18 micron) With 1 Or 2 MB On-Die L2 Cache "; + break; + case 0xb: + this->ChipID.ProcessorName = "Pentium III (0.13 micron) With " + "256 Or 512 KB On-Die L2 Cache "; + break; + case 23: + this->ChipID.ProcessorName = + "Intel(R) Core(TM)2 Duo CPU T9500 @ 2.60GHz"; + break; + default: + this->ChipID.ProcessorName = "Unknown P6 family"; + return false; + } + break; + case 7: + this->ChipID.ProcessorName = "Intel Merced (IA-64)"; + break; + case 0xf: + // Check the extended family bits... + switch (this->ChipID.ExtendedFamily) { + case 0: + switch (this->ChipID.Model) { + case 0: + this->ChipID.ProcessorName = "Pentium IV (0.18 micron)"; + break; + case 1: + this->ChipID.ProcessorName = "Pentium IV (0.18 micron)"; + break; + case 2: + this->ChipID.ProcessorName = "Pentium IV (0.13 micron)"; + break; + default: + this->ChipID.ProcessorName = "Unknown Pentium 4 family"; + return false; + } + break; + case 1: + this->ChipID.ProcessorName = "Intel McKinley (IA-64)"; + break; + default: + this->ChipID.ProcessorName = "Pentium"; + } + break; + default: + this->ChipID.ProcessorName = "Unknown Intel family"; + return false; + } + break; + + case AMD: + // Check the family / model / revision to determine the CPU ID. + switch (this->ChipID.Family) { + case 4: + switch (this->ChipID.Model) { + case 3: + this->ChipID.ProcessorName = "80486DX2"; + break; + case 7: + this->ChipID.ProcessorName = "80486DX2 WriteBack"; + break; + case 8: + this->ChipID.ProcessorName = "80486DX4"; + break; + case 9: + this->ChipID.ProcessorName = "80486DX4 WriteBack"; + break; + case 0xe: + this->ChipID.ProcessorName = "5x86"; + break; + case 0xf: + this->ChipID.ProcessorName = "5x86WB"; + break; + default: + this->ChipID.ProcessorName = "Unknown 80486 family"; + return false; + } + break; + case 5: + switch (this->ChipID.Model) { + case 0: + this->ChipID.ProcessorName = "SSA5 (PR75, PR90 = PR100)"; + break; + case 1: + this->ChipID.ProcessorName = "5k86 (PR120 = PR133)"; + break; + case 2: + this->ChipID.ProcessorName = "5k86 (PR166)"; + break; + case 3: + this->ChipID.ProcessorName = "5k86 (PR200)"; + break; + case 6: + this->ChipID.ProcessorName = "K6 (0.30 micron)"; + break; + case 7: + this->ChipID.ProcessorName = "K6 (0.25 micron)"; + break; + case 8: + this->ChipID.ProcessorName = "K6-2"; + break; + case 9: + this->ChipID.ProcessorName = "K6-III"; + break; + case 0xd: + this->ChipID.ProcessorName = "K6-2+ or K6-III+ (0.18 micron)"; + break; + default: + this->ChipID.ProcessorName = "Unknown 80586 family"; + return false; + } + break; + case 6: + switch (this->ChipID.Model) { + case 1: + this->ChipID.ProcessorName = "Athlon- (0.25 micron)"; + break; + case 2: + this->ChipID.ProcessorName = "Athlon- (0.18 micron)"; + break; + case 3: + this->ChipID.ProcessorName = "Duron- (SF core)"; + break; + case 4: + this->ChipID.ProcessorName = "Athlon- (Thunderbird core)"; + break; + case 6: + this->ChipID.ProcessorName = "Athlon- (Palomino core)"; + break; + case 7: + this->ChipID.ProcessorName = "Duron- (Morgan core)"; + break; + case 8: + if (this->Features.ExtendedFeatures.SupportsMP) + this->ChipID.ProcessorName = "Athlon - MP (Thoroughbred core)"; + else + this->ChipID.ProcessorName = "Athlon - XP (Thoroughbred core)"; + break; + default: + this->ChipID.ProcessorName = "Unknown K7 family"; + return false; + } + break; + default: + this->ChipID.ProcessorName = "Unknown AMD family"; + return false; + } + break; + + case Hygon: + this->ChipID.ProcessorName = "Unknown Hygon family"; + return false; + + case Transmeta: + switch (this->ChipID.Family) { + case 5: + switch (this->ChipID.Model) { + case 4: + this->ChipID.ProcessorName = "Crusoe TM3x00 and TM5x00"; + break; + default: + this->ChipID.ProcessorName = "Unknown Crusoe family"; + return false; + } + break; + default: + this->ChipID.ProcessorName = "Unknown Transmeta family"; + return false; + } + break; + + case Rise: + switch (this->ChipID.Family) { + case 5: + switch (this->ChipID.Model) { + case 0: + this->ChipID.ProcessorName = "mP6 (0.25 micron)"; + break; + case 2: + this->ChipID.ProcessorName = "mP6 (0.18 micron)"; + break; + default: + this->ChipID.ProcessorName = "Unknown Rise family"; + return false; + } + break; + default: + this->ChipID.ProcessorName = "Unknown Rise family"; + return false; + } + break; + + case UMC: + switch (this->ChipID.Family) { + case 4: + switch (this->ChipID.Model) { + case 1: + this->ChipID.ProcessorName = "U5D"; + break; + case 2: + this->ChipID.ProcessorName = "U5S"; + break; + default: + this->ChipID.ProcessorName = "Unknown UMC family"; + return false; + } + break; + default: + this->ChipID.ProcessorName = "Unknown UMC family"; + return false; + } + break; + + case IDT: + switch (this->ChipID.Family) { + case 5: + switch (this->ChipID.Model) { + case 4: + this->ChipID.ProcessorName = "C6"; + break; + case 8: + this->ChipID.ProcessorName = "C2"; + break; + case 9: + this->ChipID.ProcessorName = "C3"; + break; + default: + this->ChipID.ProcessorName = "Unknown IDT\\Centaur family"; + return false; + } + break; + case 6: + switch (this->ChipID.Model) { + case 6: + this->ChipID.ProcessorName = "VIA Cyrix III - Samuel"; + break; + default: + this->ChipID.ProcessorName = "Unknown IDT\\Centaur family"; + return false; + } + break; + default: + this->ChipID.ProcessorName = "Unknown IDT\\Centaur family"; + return false; + } + break; + + case Cyrix: + switch (this->ChipID.Family) { + case 4: + switch (this->ChipID.Model) { + case 4: + this->ChipID.ProcessorName = "MediaGX GX = GXm"; + break; + case 9: + this->ChipID.ProcessorName = "5x86"; + break; + default: + this->ChipID.ProcessorName = "Unknown Cx5x86 family"; + return false; + } + break; + case 5: + switch (this->ChipID.Model) { + case 2: + this->ChipID.ProcessorName = "Cx6x86"; + break; + case 4: + this->ChipID.ProcessorName = "MediaGX GXm"; + break; + default: + this->ChipID.ProcessorName = "Unknown Cx6x86 family"; + return false; + } + break; + case 6: + switch (this->ChipID.Model) { + case 0: + this->ChipID.ProcessorName = "6x86MX"; + break; + case 5: + this->ChipID.ProcessorName = "Cyrix M2 Core"; + break; + case 6: + this->ChipID.ProcessorName = "WinChip C5A Core"; + break; + case 7: + this->ChipID.ProcessorName = "WinChip C5B\\C5C Core"; + break; + case 8: + this->ChipID.ProcessorName = "WinChip C5C-T Core"; + break; + default: + this->ChipID.ProcessorName = "Unknown 6x86MX\\Cyrix III family"; + return false; + } + break; + default: + this->ChipID.ProcessorName = "Unknown Cyrix family"; + return false; + } + break; + + case NexGen: + switch (this->ChipID.Family) { + case 5: + switch (this->ChipID.Model) { + case 0: + this->ChipID.ProcessorName = "Nx586 or Nx586FPU"; + break; + default: + this->ChipID.ProcessorName = "Unknown NexGen family"; + return false; + } + break; + default: + this->ChipID.ProcessorName = "Unknown NexGen family"; + return false; + } + break; + + case NSC: + this->ChipID.ProcessorName = "Cx486SLC \\ DLC \\ Cx486S A-Step"; + break; + + case Sun: + case IBM: + case Motorola: + case HP: + case UnknownManufacturer: + default: + this->ChipID.ProcessorName = + "Unknown family"; // We cannot identify the processor. + return false; + } + + return true; +} + +/** Extract a value from the CPUInfo file */ +std::string SystemInformationImplementation::ExtractValueFromCpuInfoFile( + std::string buffer, const char* word, size_t init) +{ + size_t pos = buffer.find(word, init); + if (pos != std::string::npos) { + this->CurrentPositionInFile = pos; + pos = buffer.find(":", pos); + size_t pos2 = buffer.find("\n", pos); + if (pos != std::string::npos && pos2 != std::string::npos) { + // It may happen that the beginning matches, but this is still not the + // requested key. + // An example is looking for "cpu" when "cpu family" comes first. So we + // check that + // we have only spaces from here to pos, otherwise we search again. + for (size_t i = this->CurrentPositionInFile + strlen(word); i < pos; + ++i) { + if (buffer[i] != ' ' && buffer[i] != '\t') { + return this->ExtractValueFromCpuInfoFile(buffer, word, pos2); + } + } + return buffer.substr(pos + 2, pos2 - pos - 2); + } + } + this->CurrentPositionInFile = std::string::npos; + return ""; +} + +/** Query for the cpu status */ +bool SystemInformationImplementation::RetreiveInformationFromCpuInfoFile() +{ + this->NumberOfLogicalCPU = 0; + this->NumberOfPhysicalCPU = 0; + std::string buffer; + + FILE* fd = fopen("/proc/cpuinfo", "r"); + if (!fd) { + std::cout << "Problem opening /proc/cpuinfo" << std::endl; + return false; + } + + size_t fileSize = 0; + while (!feof(fd)) { + buffer += static_cast(fgetc(fd)); + fileSize++; + } + fclose(fd); + buffer.resize(fileSize - 2); + // Number of logical CPUs (combination of multiple processors, multi-core + // and SMT) + size_t pos = buffer.find("processor\t"); + while (pos != std::string::npos) { + this->NumberOfLogicalCPU++; + pos = buffer.find("processor\t", pos + 1); + } + +#ifdef __linux + // Count sockets. + std::set PhysicalIDs; + std::string idc = this->ExtractValueFromCpuInfoFile(buffer, "physical id"); + while (this->CurrentPositionInFile != std::string::npos) { + int id = atoi(idc.c_str()); + PhysicalIDs.insert(id); + idc = this->ExtractValueFromCpuInfoFile(buffer, "physical id", + this->CurrentPositionInFile + 1); + } + uint64_t NumberOfSockets = PhysicalIDs.size(); + NumberOfSockets = std::max(NumberOfSockets, (uint64_t)1); + // Physical ids returned by Linux don't distinguish cores. + // We want to record the total number of cores in this->NumberOfPhysicalCPU + // (checking only the first proc) + std::string Cores = this->ExtractValueFromCpuInfoFile(buffer, "cpu cores"); + unsigned int NumberOfCoresPerSocket = (unsigned int)atoi(Cores.c_str()); + NumberOfCoresPerSocket = std::max(NumberOfCoresPerSocket, 1u); + this->NumberOfPhysicalCPU = + NumberOfCoresPerSocket * (unsigned int)NumberOfSockets; + +#else // __CYGWIN__ + // does not have "physical id" entries, neither "cpu cores" + // this has to be fixed for hyper-threading. + std::string cpucount = + this->ExtractValueFromCpuInfoFile(buffer, "cpu count"); + this->NumberOfPhysicalCPU = this->NumberOfLogicalCPU = + atoi(cpucount.c_str()); +#endif + // gotta have one, and if this is 0 then we get a / by 0n + // better to have a bad answer than a crash + if (this->NumberOfPhysicalCPU <= 0) { + this->NumberOfPhysicalCPU = 1; + } + // LogicalProcessorsPerPhysical>1 => SMT. + this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = + this->NumberOfLogicalCPU / this->NumberOfPhysicalCPU; + + // CPU speed (checking only the first processor) + std::string CPUSpeed = this->ExtractValueFromCpuInfoFile(buffer, "cpu MHz"); + if (!CPUSpeed.empty()) { + this->CPUSpeedInMHz = static_cast(atof(CPUSpeed.c_str())); + } +#ifdef __linux + else { + // Linux Sparc: CPU speed is in Hz and encoded in hexadecimal + CPUSpeed = this->ExtractValueFromCpuInfoFile(buffer, "Cpu0ClkTck"); + this->CPUSpeedInMHz = + static_cast(strtoull(CPUSpeed.c_str(), 0, 16)) / 1000000.0f; + } +#endif + + // Chip family + std::string familyStr = + this->ExtractValueFromCpuInfoFile(buffer, "cpu family"); + if (familyStr.empty()) { + familyStr = this->ExtractValueFromCpuInfoFile(buffer, "CPU architecture"); + } + this->ChipID.Family = atoi(familyStr.c_str()); + + // Chip Vendor + this->ChipID.Vendor = this->ExtractValueFromCpuInfoFile(buffer, "vendor_id"); + this->FindManufacturer(familyStr); + + // second try for setting family + if (this->ChipID.Family == 0 && this->ChipManufacturer == HP) { + if (familyStr == "PA-RISC 1.1a") + this->ChipID.Family = 0x11a; + else if (familyStr == "PA-RISC 2.0") + this->ChipID.Family = 0x200; + // If you really get CMake to work on a machine not belonging to + // any of those families I owe you a dinner if you get it to + // contribute nightly builds regularly. + } + + // Chip Model + this->ChipID.Model = + atoi(this->ExtractValueFromCpuInfoFile(buffer, "model").c_str()); + if (!this->RetrieveClassicalCPUIdentity()) { + // Some platforms (e.g. PA-RISC) tell us their CPU name here. + // Note: x86 does not. + std::string cpuname = this->ExtractValueFromCpuInfoFile(buffer, "cpu"); + if (!cpuname.empty()) { + this->ChipID.ProcessorName = cpuname; + } + } + + // Chip revision + std::string cpurev = this->ExtractValueFromCpuInfoFile(buffer, "stepping"); + if (cpurev.empty()) { + cpurev = this->ExtractValueFromCpuInfoFile(buffer, "CPU revision"); + } + this->ChipID.Revision = atoi(cpurev.c_str()); + + // Chip Model Name + this->ChipID.ModelName = + this->ExtractValueFromCpuInfoFile(buffer, "model name"); + + // L1 Cache size + // Different architectures may show different names for the caches. + // Sum up everything we find. + std::vector cachename; + cachename.clear(); + + cachename.push_back("cache size"); // e.g. x86 + cachename.push_back("I-cache"); // e.g. PA-RISC + cachename.push_back("D-cache"); // e.g. PA-RISC + + this->Features.L1CacheSize = 0; + for (size_t index = 0; index < cachename.size(); index++) { + std::string cacheSize = + this->ExtractValueFromCpuInfoFile(buffer, cachename[index]); + if (!cacheSize.empty()) { + pos = cacheSize.find(" KB"); + if (pos != std::string::npos) { + cacheSize = cacheSize.substr(0, pos); + } + this->Features.L1CacheSize += atoi(cacheSize.c_str()); + } + } + + // processor feature flags (probably x86 specific) + std::string cpuflags = this->ExtractValueFromCpuInfoFile(buffer, "flags"); + if (!cpurev.empty()) { + // now we can match every flags as space + flag + space + cpuflags = " " + cpuflags + " "; + if ((cpuflags.find(" fpu ") != std::string::npos)) { + this->Features.HasFPU = true; + } + if ((cpuflags.find(" tsc ") != std::string::npos)) { + this->Features.HasTSC = true; + } + if ((cpuflags.find(" mmx ") != std::string::npos)) { + this->Features.HasMMX = true; + } + if ((cpuflags.find(" sse ") != std::string::npos)) { + this->Features.HasSSE = true; + } + if ((cpuflags.find(" sse2 ") != std::string::npos)) { + this->Features.HasSSE2 = true; + } + if ((cpuflags.find(" apic ") != std::string::npos)) { + this->Features.HasAPIC = true; + } + if ((cpuflags.find(" cmov ") != std::string::npos)) { + this->Features.HasCMOV = true; + } + if ((cpuflags.find(" mtrr ") != std::string::npos)) { + this->Features.HasMTRR = true; + } + if ((cpuflags.find(" acpi ") != std::string::npos)) { + this->Features.HasACPI = true; + } + if ((cpuflags.find(" 3dnow ") != std::string::npos)) { + this->Features.ExtendedFeatures.Has3DNow = true; + } + } + + return true; +} + +bool SystemInformationImplementation::QueryProcessorBySysconf() +{ +#if defined(_SC_NPROC_ONLN) && !defined(_SC_NPROCESSORS_ONLN) +// IRIX names this slightly different +# define _SC_NPROCESSORS_ONLN _SC_NPROC_ONLN +#endif + +#ifdef _SC_NPROCESSORS_ONLN + long c = sysconf(_SC_NPROCESSORS_ONLN); + if (c <= 0) { + return false; + } + + this->NumberOfPhysicalCPU = static_cast(c); + this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU; + + return true; +#else + return false; +#endif +} + +bool SystemInformationImplementation::QueryProcessor() +{ + return this->QueryProcessorBySysconf(); +} + +/** +Get total system RAM in units of KiB. +*/ +SystemInformation::LongLong +SystemInformationImplementation::GetHostMemoryTotal() +{ +#if defined(_WIN32) +# if defined(_MSC_VER) && _MSC_VER < 1300 + MEMORYSTATUS stat; + stat.dwLength = sizeof(stat); + GlobalMemoryStatus(&stat); + return stat.dwTotalPhys / 1024; +# else + MEMORYSTATUSEX statex; + statex.dwLength = sizeof(statex); + GlobalMemoryStatusEx(&statex); + return statex.ullTotalPhys / 1024; +# endif +#elif defined(__linux) + SystemInformation::LongLong memTotal = 0; + int ierr = GetFieldFromFile("/proc/meminfo", "MemTotal:", memTotal); + if (ierr) { + return -1; + } + return memTotal; +#elif defined(__APPLE__) + uint64_t mem; + size_t len = sizeof(mem); + int ierr = sysctlbyname("hw.memsize", &mem, &len, nullptr, 0); + if (ierr) { + return -1; + } + return mem / 1024; +#else + return 0; +#endif +} + +/** +Get total system RAM in units of KiB. This may differ from the +host total if a host-wide resource limit is applied. +*/ +SystemInformation::LongLong +SystemInformationImplementation::GetHostMemoryAvailable( + const char* hostLimitEnvVarName) +{ + SystemInformation::LongLong memTotal = this->GetHostMemoryTotal(); + + // the following mechanism is provided for systems that + // apply resource limits across groups of processes. + // this is of use on certain SMP systems (eg. SGI UV) + // where the host has a large amount of ram but a given user's + // access to it is severely restricted. The system will + // apply a limit across a set of processes. Units are in KiB. + if (hostLimitEnvVarName) { + const char* hostLimitEnvVarValue = getenv(hostLimitEnvVarName); + if (hostLimitEnvVarValue) { + SystemInformation::LongLong hostLimit = + atoLongLong(hostLimitEnvVarValue); + if (hostLimit > 0) { + memTotal = min(hostLimit, memTotal); + } + } + } + + return memTotal; +} + +/** +Get total system RAM in units of KiB. This may differ from the +host total if a per-process resource limit is applied. +*/ +SystemInformation::LongLong +SystemInformationImplementation::GetProcMemoryAvailable( + const char* hostLimitEnvVarName, const char* procLimitEnvVarName) +{ + SystemInformation::LongLong memAvail = + this->GetHostMemoryAvailable(hostLimitEnvVarName); + + // the following mechanism is provide for systems where rlimits + // are not employed. Units are in KiB. + if (procLimitEnvVarName) { + const char* procLimitEnvVarValue = getenv(procLimitEnvVarName); + if (procLimitEnvVarValue) { + SystemInformation::LongLong procLimit = + atoLongLong(procLimitEnvVarValue); + if (procLimit > 0) { + memAvail = min(procLimit, memAvail); + } + } + } + +#if defined(__linux) + int ierr; + ResourceLimitType rlim; + ierr = GetResourceLimit(RLIMIT_DATA, &rlim); + if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) { + memAvail = + min((SystemInformation::LongLong)rlim.rlim_cur / 1024, memAvail); + } + + ierr = GetResourceLimit(RLIMIT_AS, &rlim); + if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) { + memAvail = + min((SystemInformation::LongLong)rlim.rlim_cur / 1024, memAvail); + } +#elif defined(__APPLE__) + struct rlimit rlim; + int ierr; + ierr = getrlimit(RLIMIT_DATA, &rlim); + if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) { + memAvail = + min((SystemInformation::LongLong)rlim.rlim_cur / 1024, memAvail); + } + + ierr = getrlimit(RLIMIT_RSS, &rlim); + if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) { + memAvail = + min((SystemInformation::LongLong)rlim.rlim_cur / 1024, memAvail); + } +#endif + + return memAvail; +} + +/** +Get RAM used by all processes in the host, in units of KiB. +*/ +SystemInformation::LongLong +SystemInformationImplementation::GetHostMemoryUsed() +{ +#if defined(_WIN32) +# if defined(_MSC_VER) && _MSC_VER < 1300 + MEMORYSTATUS stat; + stat.dwLength = sizeof(stat); + GlobalMemoryStatus(&stat); + return (stat.dwTotalPhys - stat.dwAvailPhys) / 1024; +# else + MEMORYSTATUSEX statex; + statex.dwLength = sizeof(statex); + GlobalMemoryStatusEx(&statex); + return (statex.ullTotalPhys - statex.ullAvailPhys) / 1024; +# endif +#elif defined(__linux) + // First try to use MemAvailable, but it only works on newer kernels + const char* names2[3] = { "MemTotal:", "MemAvailable:", nullptr }; + SystemInformation::LongLong values2[2] = { SystemInformation::LongLong(0) }; + int ierr = GetFieldsFromFile("/proc/meminfo", names2, values2); + if (ierr) { + const char* names4[5] = { "MemTotal:", "MemFree:", "Buffers:", "Cached:", + nullptr }; + SystemInformation::LongLong values4[4] = { SystemInformation::LongLong( + 0) }; + ierr = GetFieldsFromFile("/proc/meminfo", names4, values4); + if (ierr) { + return ierr; + } + SystemInformation::LongLong& memTotal = values4[0]; + SystemInformation::LongLong& memFree = values4[1]; + SystemInformation::LongLong& memBuffers = values4[2]; + SystemInformation::LongLong& memCached = values4[3]; + return memTotal - memFree - memBuffers - memCached; + } + SystemInformation::LongLong& memTotal = values2[0]; + SystemInformation::LongLong& memAvail = values2[1]; + return memTotal - memAvail; +#elif defined(__APPLE__) + SystemInformation::LongLong psz = getpagesize(); + if (psz < 1) { + return -1; + } + const char* names[3] = { "Pages wired down:", "Pages active:", nullptr }; + SystemInformation::LongLong values[2] = { SystemInformation::LongLong(0) }; + int ierr = GetFieldsFromCommand("vm_stat", names, values); + if (ierr) { + return -1; + } + SystemInformation::LongLong& vmWired = values[0]; + SystemInformation::LongLong& vmActive = values[1]; + return ((vmActive + vmWired) * psz) / 1024; +#else + return 0; +#endif +} + +/** +Get system RAM used by the process associated with the given +process id in units of KiB. +*/ +SystemInformation::LongLong +SystemInformationImplementation::GetProcMemoryUsed() +{ +#if defined(_WIN32) && defined(KWSYS_SYS_HAS_PSAPI) + long pid = GetCurrentProcessId(); + HANDLE hProc; + hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid); + if (hProc == 0) { + return -1; + } + PROCESS_MEMORY_COUNTERS pmc; + int ok = GetProcessMemoryInfo(hProc, &pmc, sizeof(pmc)); + CloseHandle(hProc); + if (!ok) { + return -2; + } + return pmc.WorkingSetSize / 1024; +#elif defined(__linux) + SystemInformation::LongLong memUsed = 0; + int ierr = GetFieldFromFile("/proc/self/status", "VmRSS:", memUsed); + if (ierr) { + return -1; + } + return memUsed; +#elif defined(__APPLE__) + SystemInformation::LongLong memUsed = 0; + pid_t pid = getpid(); + std::ostringstream oss; + oss << "ps -o rss= -p " << pid; + FILE* file = popen(oss.str().c_str(), "r"); + if (file == nullptr) { + return -1; + } + oss.str(""); + while (!feof(file) && !ferror(file)) { + char buf[256] = { '\0' }; + errno = 0; + size_t nRead = fread(buf, 1, 256, file); + if (ferror(file) && (errno == EINTR)) { + clearerr(file); + } + if (nRead) + oss << buf; + } + int ierr = ferror(file); + pclose(file); + if (ierr) { + return -2; + } + std::istringstream iss(oss.str()); + iss >> memUsed; + return memUsed; +#else + return 0; +#endif +} + +double SystemInformationImplementation::GetLoadAverage() +{ +#if defined(KWSYS_CXX_HAS_GETLOADAVG) + double loadavg[3] = { 0.0, 0.0, 0.0 }; + if (getloadavg(loadavg, 3) > 0) { + return loadavg[0]; + } + return -0.0; +#elif defined(KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes) + // Old windows.h headers do not provide GetSystemTimes. + typedef BOOL(WINAPI * GetSystemTimesType)(LPFILETIME, LPFILETIME, + LPFILETIME); + static GetSystemTimesType pGetSystemTimes = + (GetSystemTimesType)GetProcAddress(GetModuleHandleW(L"kernel32"), + "GetSystemTimes"); + FILETIME idleTime, kernelTime, userTime; + if (pGetSystemTimes && pGetSystemTimes(&idleTime, &kernelTime, &userTime)) { + unsigned __int64 const idleTicks = fileTimeToUInt64(idleTime); + unsigned __int64 const totalTicks = + fileTimeToUInt64(kernelTime) + fileTimeToUInt64(userTime); + return calculateCPULoad(idleTicks, totalTicks) * GetNumberOfPhysicalCPU(); + } + return -0.0; +#else + // Not implemented on this platform. + return -0.0; +#endif +} + +/** +Get the process id of the running process. +*/ +SystemInformation::LongLong SystemInformationImplementation::GetProcessId() +{ +#if defined(_WIN32) + return GetCurrentProcessId(); +#elif defined(__linux) || defined(__APPLE__) || defined(__OpenBSD__) || \ + defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) + return getpid(); +#else + return -1; +#endif +} + +/** + * Used in GetProgramStack(...) below + */ +#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600 && defined(_MSC_VER) && \ + _MSC_VER >= 1800 +# define KWSYS_SYSTEMINFORMATION_HAS_DBGHELP +# define TRACE_MAX_STACK_FRAMES 1024 +# define TRACE_MAX_FUNCTION_NAME_LENGTH 1024 +# pragma warning(push) +# pragma warning(disable : 4091) /* 'typedef ': ignored on left of '' */ +# include "dbghelp.h" +# pragma warning(pop) +#endif + +/** +return current program stack in a string +demangle cxx symbols if possible. +*/ +std::string SystemInformationImplementation::GetProgramStack(int firstFrame, + int wholePath) +{ + std::ostringstream oss; + std::string programStack = ""; + +#ifdef KWSYS_SYSTEMINFORMATION_HAS_DBGHELP + (void)wholePath; + + void* stack[TRACE_MAX_STACK_FRAMES]; + HANDLE process = GetCurrentProcess(); + SymInitialize(process, nullptr, TRUE); + WORD numberOfFrames = + CaptureStackBackTrace(firstFrame, TRACE_MAX_STACK_FRAMES, stack, nullptr); + SYMBOL_INFO* symbol = static_cast( + malloc(sizeof(SYMBOL_INFO) + + (TRACE_MAX_FUNCTION_NAME_LENGTH - 1) * sizeof(TCHAR))); + symbol->MaxNameLen = TRACE_MAX_FUNCTION_NAME_LENGTH; + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + DWORD displacement; + IMAGEHLP_LINE64 line; + line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + for (int i = 0; i < numberOfFrames; i++) { + DWORD64 address = reinterpret_cast(stack[i]); + SymFromAddr(process, address, nullptr, symbol); + if (SymGetLineFromAddr64(process, address, &displacement, &line)) { + oss << " at " << symbol->Name << " in " << line.FileName << " line " + << line.LineNumber << std::endl; + } else { + oss << " at " << symbol->Name << std::endl; + } + } + free(symbol); + +#else + programStack += "" +# if !defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) + "WARNING: The stack could not be examined " + "because backtrace is not supported.\n" +# elif !defined(KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD) + "WARNING: The stack trace will not use advanced " + "capabilities because this is a release build.\n" +# else +# if !defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP) + "WARNING: Function names will not be demangled " + "because dladdr is not available.\n" +# endif +# if !defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE) + "WARNING: Function names will not be demangled " + "because cxxabi is not available.\n" +# endif +# endif + ; + +# if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) + void* stackSymbols[256]; + int nFrames = backtrace(stackSymbols, 256); + for (int i = firstFrame; i < nFrames; ++i) { + SymbolProperties symProps; + symProps.SetReportPath(wholePath); + symProps.Initialize(stackSymbols[i]); + oss << symProps << std::endl; + } +# else + (void)firstFrame; + (void)wholePath; +# endif +#endif + + programStack += oss.str(); + + return programStack; +} + +/** +when set print stack trace in response to common signals. +*/ +void SystemInformationImplementation::SetStackTraceOnError(int enable) +{ +#if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) + static int saOrigValid = 0; + static struct sigaction saABRTOrig; + static struct sigaction saSEGVOrig; + static struct sigaction saTERMOrig; + static struct sigaction saINTOrig; + static struct sigaction saILLOrig; + static struct sigaction saBUSOrig; + static struct sigaction saFPEOrig; + + if (enable && !saOrigValid) { + // save the current actions + sigaction(SIGABRT, nullptr, &saABRTOrig); + sigaction(SIGSEGV, nullptr, &saSEGVOrig); + sigaction(SIGTERM, nullptr, &saTERMOrig); + sigaction(SIGINT, nullptr, &saINTOrig); + sigaction(SIGILL, nullptr, &saILLOrig); + sigaction(SIGBUS, nullptr, &saBUSOrig); + sigaction(SIGFPE, nullptr, &saFPEOrig); + + // enable read, disable write + saOrigValid = 1; + + // install ours + struct sigaction sa; + sa.sa_sigaction = (SigAction)StacktraceSignalHandler; + sa.sa_flags = SA_SIGINFO | SA_RESETHAND; +# ifdef SA_RESTART + sa.sa_flags |= SA_RESTART; +# endif + sigemptyset(&sa.sa_mask); + + sigaction(SIGABRT, &sa, nullptr); + sigaction(SIGSEGV, &sa, nullptr); + sigaction(SIGTERM, &sa, nullptr); + sigaction(SIGINT, &sa, nullptr); + sigaction(SIGILL, &sa, nullptr); + sigaction(SIGBUS, &sa, nullptr); + sigaction(SIGFPE, &sa, nullptr); + } else if (!enable && saOrigValid) { + // restore previous actions + sigaction(SIGABRT, &saABRTOrig, nullptr); + sigaction(SIGSEGV, &saSEGVOrig, nullptr); + sigaction(SIGTERM, &saTERMOrig, nullptr); + sigaction(SIGINT, &saINTOrig, nullptr); + sigaction(SIGILL, &saILLOrig, nullptr); + sigaction(SIGBUS, &saBUSOrig, nullptr); + sigaction(SIGFPE, &saFPEOrig, nullptr); + + // enable write, disable read + saOrigValid = 0; + } +#else + // avoid warning C4100 + (void)enable; +#endif +} + +bool SystemInformationImplementation::QueryWindowsMemory() +{ +#if defined(_WIN32) +# if defined(_MSC_VER) && _MSC_VER < 1300 + MEMORYSTATUS ms; + unsigned long tv, tp, av, ap; + ms.dwLength = sizeof(ms); + GlobalMemoryStatus(&ms); +# define MEM_VAL(value) dw##value +# else + MEMORYSTATUSEX ms; + DWORDLONG tv, tp, av, ap; + ms.dwLength = sizeof(ms); + if (0 == GlobalMemoryStatusEx(&ms)) { + return 0; + } +# define MEM_VAL(value) ull##value +# endif + tv = ms.MEM_VAL(TotalPageFile); + tp = ms.MEM_VAL(TotalPhys); + av = ms.MEM_VAL(AvailPageFile); + ap = ms.MEM_VAL(AvailPhys); + this->TotalVirtualMemory = tv >> 10 >> 10; + this->TotalPhysicalMemory = tp >> 10 >> 10; + this->AvailableVirtualMemory = av >> 10 >> 10; + this->AvailablePhysicalMemory = ap >> 10 >> 10; + return true; +#else + return false; +#endif +} + +bool SystemInformationImplementation::QueryLinuxMemory() +{ +#if defined(__linux) + unsigned long tv = 0; + unsigned long tp = 0; + unsigned long av = 0; + unsigned long ap = 0; + + char buffer[1024]; // for reading lines + + int linuxMajor = 0; + int linuxMinor = 0; + + // Find the Linux kernel version first + struct utsname unameInfo; + int errorFlag = uname(&unameInfo); + if (errorFlag != 0) { + std::cout << "Problem calling uname(): " << strerror(errno) << std::endl; + return false; + } + + if (strlen(unameInfo.release) >= 3) { + // release looks like "2.6.3-15mdk-i686-up-4GB" + char majorChar = unameInfo.release[0]; + char minorChar = unameInfo.release[2]; + + if (isdigit(majorChar)) { + linuxMajor = majorChar - '0'; + } + + if (isdigit(minorChar)) { + linuxMinor = minorChar - '0'; + } + } + + FILE* fd = fopen("/proc/meminfo", "r"); + if (!fd) { + std::cout << "Problem opening /proc/meminfo" << std::endl; + return false; + } + + if (linuxMajor >= 3 || ((linuxMajor >= 2) && (linuxMinor >= 6))) { + // new /proc/meminfo format since kernel 2.6.x + // Rigorously, this test should check from the developing version 2.5.x + // that introduced the new format... + + enum + { + mMemTotal, + mMemFree, + mBuffers, + mCached, + mSwapTotal, + mSwapFree + }; + const char* format[6] = { "MemTotal:%lu kB", "MemFree:%lu kB", + "Buffers:%lu kB", "Cached:%lu kB", + "SwapTotal:%lu kB", "SwapFree:%lu kB" }; + bool have[6] = { false, false, false, false, false, false }; + unsigned long value[6]; + int count = 0; + while (fgets(buffer, static_cast(sizeof(buffer)), fd)) { + for (int i = 0; i < 6; ++i) { + if (!have[i] && sscanf(buffer, format[i], &value[i]) == 1) { + have[i] = true; + ++count; + } + } + } + if (count == 6) { + this->TotalPhysicalMemory = value[mMemTotal] / 1024; + this->AvailablePhysicalMemory = + (value[mMemFree] + value[mBuffers] + value[mCached]) / 1024; + this->TotalVirtualMemory = value[mSwapTotal] / 1024; + this->AvailableVirtualMemory = value[mSwapFree] / 1024; + } else { + std::cout << "Problem parsing /proc/meminfo" << std::endl; + fclose(fd); + return false; + } + } else { + // /proc/meminfo format for kernel older than 2.6.x + + unsigned long temp; + unsigned long cachedMem; + unsigned long buffersMem; + // Skip "total: used:..." + char* r = fgets(buffer, static_cast(sizeof(buffer)), fd); + int status = 0; + if (r == buffer) { + status += fscanf(fd, "Mem: %lu %lu %lu %lu %lu %lu\n", &tp, &temp, &ap, + &temp, &buffersMem, &cachedMem); + } + if (status == 6) { + status += fscanf(fd, "Swap: %lu %lu %lu\n", &tv, &temp, &av); + } + if (status == 9) { + this->TotalVirtualMemory = tv >> 10 >> 10; + this->TotalPhysicalMemory = tp >> 10 >> 10; + this->AvailableVirtualMemory = av >> 10 >> 10; + this->AvailablePhysicalMemory = + (ap + buffersMem + cachedMem) >> 10 >> 10; + } else { + std::cout << "Problem parsing /proc/meminfo" << std::endl; + fclose(fd); + return false; + } + } + fclose(fd); + + return true; +#else + return false; +#endif +} + +bool SystemInformationImplementation::QueryCygwinMemory() +{ +#ifdef __CYGWIN__ + // _SC_PAGE_SIZE does return the mmap() granularity on Cygwin, + // see http://cygwin.com/ml/cygwin/2006-06/msg00350.html + // Therefore just use 4096 as the page size of Windows. + long m = sysconf(_SC_PHYS_PAGES); + if (m < 0) { + return false; + } + this->TotalPhysicalMemory = m >> 8; + return true; +#else + return false; +#endif +} + +bool SystemInformationImplementation::QueryAIXMemory() +{ +#if defined(_AIX) && defined(_SC_AIX_REALMEM) + long c = sysconf(_SC_AIX_REALMEM); + if (c <= 0) { + return false; + } + + this->TotalPhysicalMemory = c / 1024; + + return true; +#else + return false; +#endif +} + +bool SystemInformationImplementation::QueryMemoryBySysconf() +{ +#if defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE) + // Assume the mmap() granularity as returned by _SC_PAGESIZE is also + // the system page size. The only known system where this isn't true + // is Cygwin. + long p = sysconf(_SC_PHYS_PAGES); + long m = sysconf(_SC_PAGESIZE); + + if (p < 0 || m < 0) { + return false; + } + + // assume pagesize is a power of 2 and smaller 1 MiB + size_t pagediv = (1024 * 1024 / m); + + this->TotalPhysicalMemory = p; + this->TotalPhysicalMemory /= pagediv; + +# if defined(_SC_AVPHYS_PAGES) + p = sysconf(_SC_AVPHYS_PAGES); + if (p < 0) { + return false; + } + + this->AvailablePhysicalMemory = p; + this->AvailablePhysicalMemory /= pagediv; +# endif + + return true; +#else + return false; +#endif +} + +/** Query for the memory status */ +bool SystemInformationImplementation::QueryMemory() +{ + return this->QueryMemoryBySysconf(); +} + +/** */ +size_t SystemInformationImplementation::GetTotalVirtualMemory() +{ + return this->TotalVirtualMemory; +} + +/** */ +size_t SystemInformationImplementation::GetAvailableVirtualMemory() +{ + return this->AvailableVirtualMemory; +} + +size_t SystemInformationImplementation::GetTotalPhysicalMemory() +{ + return this->TotalPhysicalMemory; +} + +/** */ +size_t SystemInformationImplementation::GetAvailablePhysicalMemory() +{ + return this->AvailablePhysicalMemory; +} + +/** Get Cycle differences */ +SystemInformation::LongLong +SystemInformationImplementation::GetCyclesDifference(DELAY_FUNC DelayFunction, + unsigned int uiParameter) +{ +#if defined(_MSC_VER) && (_MSC_VER >= 1400) + unsigned __int64 stamp1, stamp2; + + stamp1 = __rdtsc(); + DelayFunction(uiParameter); + stamp2 = __rdtsc(); + + return stamp2 - stamp1; +#elif USE_ASM_INSTRUCTIONS + + unsigned int edx1, eax1; + unsigned int edx2, eax2; + + // Calculate the frequency of the CPU instructions. + __try { + _asm { + push uiParameter ; push parameter param + mov ebx, DelayFunction ; store func in ebx + + RDTSC_INSTRUCTION + + mov esi, eax ; esi = eax + mov edi, edx ; edi = edx + + call ebx ; call the delay functions + + RDTSC_INSTRUCTION + + pop ebx + + mov edx2, edx ; edx2 = edx + mov eax2, eax ; eax2 = eax + + mov edx1, edi ; edx2 = edi + mov eax1, esi ; eax2 = esi + } + } __except (1) { + return -1; + } + + return ((((__int64)edx2 << 32) + eax2) - (((__int64)edx1 << 32) + eax1)); + +#else + (void)DelayFunction; + (void)uiParameter; + return -1; +#endif +} + +/** Compute the delay overhead */ +void SystemInformationImplementation::DelayOverhead(unsigned int uiMS) +{ +#if defined(_WIN32) + LARGE_INTEGER Frequency, StartCounter, EndCounter; + __int64 x; + + // Get the frequency of the high performance counter. + if (!QueryPerformanceFrequency(&Frequency)) { + return; + } + x = Frequency.QuadPart / 1000 * uiMS; + + // Get the starting position of the counter. + QueryPerformanceCounter(&StartCounter); + + do { + // Get the ending position of the counter. + QueryPerformanceCounter(&EndCounter); + } while (EndCounter.QuadPart - StartCounter.QuadPart == x); +#endif + (void)uiMS; +} + +/** Works only for windows */ +bool SystemInformationImplementation::IsSMTSupported() +{ + return this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical > 1; +} + +/** Return the APIC Id. Works only for windows. */ +unsigned char SystemInformationImplementation::GetAPICId() +{ + int Regs[4] = { 0, 0, 0, 0 }; + +#if USE_CPUID + if (!this->IsSMTSupported()) { + return static_cast(-1); // HT not supported + } // Logical processor = 1 + call_cpuid(1, Regs); +#endif + + return static_cast((Regs[1] & INITIAL_APIC_ID_BITS) >> 24); +} + +/** Count the number of CPUs. Works only on windows. */ +void SystemInformationImplementation::CPUCountWindows() +{ +#if defined(_WIN32) + this->NumberOfPhysicalCPU = 0; + this->NumberOfLogicalCPU = 0; + + typedef BOOL(WINAPI * GetLogicalProcessorInformationType)( + PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD); + static GetLogicalProcessorInformationType pGetLogicalProcessorInformation = + (GetLogicalProcessorInformationType)GetProcAddress( + GetModuleHandleW(L"kernel32"), "GetLogicalProcessorInformation"); + + if (!pGetLogicalProcessorInformation) { + // Fallback to approximate implementation on ancient Windows versions. + SYSTEM_INFO info; + ZeroMemory(&info, sizeof(info)); + GetSystemInfo(&info); + this->NumberOfPhysicalCPU = + static_cast(info.dwNumberOfProcessors); + this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU; + return; + } + + std::vector ProcInfo; + { + DWORD Length = 0; + DWORD rc = pGetLogicalProcessorInformation(nullptr, &Length); + assert(FALSE == rc); + (void)rc; // Silence unused variable warning in Borland C++ 5.81 + assert(GetLastError() == ERROR_INSUFFICIENT_BUFFER); + ProcInfo.resize(Length / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION)); + rc = pGetLogicalProcessorInformation(&ProcInfo[0], &Length); + assert(rc != FALSE); + (void)rc; // Silence unused variable warning in Borland C++ 5.81 + } + + typedef std::vector::iterator + pinfoIt_t; + for (pinfoIt_t it = ProcInfo.begin(); it != ProcInfo.end(); ++it) { + SYSTEM_LOGICAL_PROCESSOR_INFORMATION PInfo = *it; + if (PInfo.Relationship != RelationProcessorCore) { + continue; + } + + std::bitset::digits> ProcMask( + (unsigned long long)PInfo.ProcessorMask); + unsigned int count = (unsigned int)ProcMask.count(); + if (count == 0) { // I think this should never happen, but just to be safe. + continue; + } + this->NumberOfPhysicalCPU++; + this->NumberOfLogicalCPU += (unsigned int)count; + this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = count; + } + this->NumberOfPhysicalCPU = std::max(1u, this->NumberOfPhysicalCPU); + this->NumberOfLogicalCPU = std::max(1u, this->NumberOfLogicalCPU); +#else +#endif +} + +/** Return the number of logical CPUs on the system */ +unsigned int SystemInformationImplementation::GetNumberOfLogicalCPU() +{ + return this->NumberOfLogicalCPU; +} + +/** Return the number of physical CPUs on the system */ +unsigned int SystemInformationImplementation::GetNumberOfPhysicalCPU() +{ + return this->NumberOfPhysicalCPU; +} + +/** For Mac use sysctlbyname calls to find system info */ +bool SystemInformationImplementation::ParseSysCtl() +{ +#if defined(__APPLE__) + char retBuf[128]; + int err = 0; + uint64_t value = 0; + size_t len = sizeof(value); + sysctlbyname("hw.memsize", &value, &len, nullptr, 0); + this->TotalPhysicalMemory = static_cast(value / 1048576); + + // Parse values for Mac + this->AvailablePhysicalMemory = 0; + vm_statistics_data_t vmstat; + mach_msg_type_number_t count = HOST_VM_INFO_COUNT; + if (host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vmstat, + &count) == KERN_SUCCESS) { + len = sizeof(value); + err = sysctlbyname("hw.pagesize", &value, &len, nullptr, 0); + int64_t available_memory = + (vmstat.free_count + vmstat.inactive_count) * value; + this->AvailablePhysicalMemory = + static_cast(available_memory / 1048576); + } + +# ifdef VM_SWAPUSAGE + // Virtual memory. + int mib[2] = { CTL_VM, VM_SWAPUSAGE }; + unsigned int miblen = + static_cast(sizeof(mib) / sizeof(mib[0])); + struct xsw_usage swap; + len = sizeof(swap); + err = sysctl(mib, miblen, &swap, &len, nullptr, 0); + if (err == 0) { + this->AvailableVirtualMemory = + static_cast(swap.xsu_avail / 1048576); + this->TotalVirtualMemory = static_cast(swap.xsu_total / 1048576); + } +# else + this->AvailableVirtualMemory = 0; + this->TotalVirtualMemory = 0; +# endif + + // CPU Info + len = sizeof(this->NumberOfPhysicalCPU); + sysctlbyname("hw.physicalcpu", &this->NumberOfPhysicalCPU, &len, nullptr, 0); + len = sizeof(this->NumberOfLogicalCPU); + sysctlbyname("hw.logicalcpu", &this->NumberOfLogicalCPU, &len, nullptr, 0); + + int cores_per_package = 0; + len = sizeof(cores_per_package); + err = sysctlbyname("machdep.cpu.cores_per_package", &cores_per_package, &len, + nullptr, 0); + // That name was not found, default to 1 + this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = + err != 0 ? 1 : static_cast(cores_per_package); + + len = sizeof(value); + sysctlbyname("hw.cpufrequency", &value, &len, nullptr, 0); + this->CPUSpeedInMHz = static_cast(value) / 1000000; + + // Chip family + len = sizeof(this->ChipID.Family); + // Seems only the intel chips will have this name so if this fails it is + // probably a PPC machine + err = + sysctlbyname("machdep.cpu.family", &this->ChipID.Family, &len, nullptr, 0); + if (err != 0) // Go back to names we know but are less descriptive + { + this->ChipID.Family = 0; + ::memset(retBuf, 0, 128); + len = 32; + err = sysctlbyname("hw.machine", &retBuf, &len, nullptr, 0); + std::string machineBuf(retBuf); + if (machineBuf.find_first_of("Power") != std::string::npos) { + this->ChipID.Vendor = "IBM"; + len = sizeof(this->ChipID.Family); + err = sysctlbyname("hw.cputype", &this->ChipID.Family, &len, nullptr, 0); + len = sizeof(this->ChipID.Model); + err = + sysctlbyname("hw.cpusubtype", &this->ChipID.Model, &len, nullptr, 0); + this->FindManufacturer(); + } + } else // Should be an Intel Chip. + { + len = sizeof(this->ChipID.Family); + err = sysctlbyname("machdep.cpu.family", &this->ChipID.Family, &len, + nullptr, 0); + + ::memset(retBuf, 0, 128); + len = 128; + err = sysctlbyname("machdep.cpu.vendor", retBuf, &len, nullptr, 0); + // Chip Vendor + this->ChipID.Vendor = retBuf; + this->FindManufacturer(); + + // Chip Model + len = sizeof(value); + err = sysctlbyname("machdep.cpu.model", &value, &len, nullptr, 0); + this->ChipID.Model = static_cast(value); + + // Chip Stepping + len = sizeof(value); + value = 0; + err = sysctlbyname("machdep.cpu.stepping", &value, &len, nullptr, 0); + if (!err) { + this->ChipID.Revision = static_cast(value); + } + + // feature string + char* buf = nullptr; + size_t allocSize = 128; + + err = 0; + len = 0; + + // sysctlbyname() will return with err==0 && len==0 if the buffer is too + // small + while (err == 0 && len == 0) { + delete[] buf; + allocSize *= 2; + buf = new char[allocSize]; + if (!buf) { + break; + } + buf[0] = ' '; + len = allocSize - 2; // keep space for leading and trailing space + err = sysctlbyname("machdep.cpu.features", buf + 1, &len, nullptr, 0); + } + if (!err && buf && len) { + // now we can match every flags as space + flag + space + buf[len + 1] = ' '; + std::string cpuflags(buf, len + 2); + + if ((cpuflags.find(" FPU ") != std::string::npos)) { + this->Features.HasFPU = true; + } + if ((cpuflags.find(" TSC ") != std::string::npos)) { + this->Features.HasTSC = true; + } + if ((cpuflags.find(" MMX ") != std::string::npos)) { + this->Features.HasMMX = true; + } + if ((cpuflags.find(" SSE ") != std::string::npos)) { + this->Features.HasSSE = true; + } + if ((cpuflags.find(" SSE2 ") != std::string::npos)) { + this->Features.HasSSE2 = true; + } + if ((cpuflags.find(" APIC ") != std::string::npos)) { + this->Features.HasAPIC = true; + } + if ((cpuflags.find(" CMOV ") != std::string::npos)) { + this->Features.HasCMOV = true; + } + if ((cpuflags.find(" MTRR ") != std::string::npos)) { + this->Features.HasMTRR = true; + } + if ((cpuflags.find(" ACPI ") != std::string::npos)) { + this->Features.HasACPI = true; + } + } + delete[] buf; + } + + // brand string + ::memset(retBuf, 0, sizeof(retBuf)); + len = sizeof(retBuf); + err = sysctlbyname("machdep.cpu.brand_string", retBuf, &len, nullptr, 0); + if (!err) { + this->ChipID.ProcessorName = retBuf; + this->ChipID.ModelName = retBuf; + } + + // Cache size + len = sizeof(value); + err = sysctlbyname("hw.l1icachesize", &value, &len, nullptr, 0); + this->Features.L1CacheSize = static_cast(value); + len = sizeof(value); + err = sysctlbyname("hw.l2cachesize", &value, &len, nullptr, 0); + this->Features.L2CacheSize = static_cast(value); + + return true; +#else + return false; +#endif +} + +/** Extract a value from sysctl command */ +std::string SystemInformationImplementation::ExtractValueFromSysCtl( + const char* word) +{ + size_t pos = this->SysCtlBuffer.find(word); + if (pos != std::string::npos) { + pos = this->SysCtlBuffer.find(": ", pos); + size_t pos2 = this->SysCtlBuffer.find("\n", pos); + if (pos != std::string::npos && pos2 != std::string::npos) { + return this->SysCtlBuffer.substr(pos + 2, pos2 - pos - 2); + } + } + return ""; +} + +/** Run a given process */ +std::string SystemInformationImplementation::RunProcess( + std::vector args) +{ + std::string buffer; + + // Run the application + kwsysProcess* gp = kwsysProcess_New(); + kwsysProcess_SetCommand(gp, args.data()); + kwsysProcess_SetOption(gp, kwsysProcess_Option_HideWindow, 1); + + kwsysProcess_Execute(gp); + + char* data = nullptr; + int length; + double timeout = 255; + int pipe; // pipe id as returned by kwsysProcess_WaitForData() + + while ((static_cast( + pipe = kwsysProcess_WaitForData(gp, &data, &length, &timeout)), + (pipe == kwsysProcess_Pipe_STDOUT || + pipe == kwsysProcess_Pipe_STDERR))) // wait for 1s + { + buffer.append(data, length); + } + kwsysProcess_WaitForExit(gp, nullptr); + + int result = 0; + switch (kwsysProcess_GetState(gp)) { + case kwsysProcess_State_Exited: { + result = kwsysProcess_GetExitValue(gp); + } break; + case kwsysProcess_State_Error: { + std::cerr << "Error: Could not run " << args[0] << ":\n"; + std::cerr << kwsysProcess_GetErrorString(gp) << "\n"; + } break; + case kwsysProcess_State_Exception: { + std::cerr << "Error: " << args[0] << " terminated with an exception: " + << kwsysProcess_GetExceptionString(gp) << "\n"; + } break; + case kwsysProcess_State_Starting: + case kwsysProcess_State_Executing: + case kwsysProcess_State_Expired: + case kwsysProcess_State_Killed: { + // Should not get here. + std::cerr << "Unexpected ending state after running " << args[0] + << std::endl; + } break; + } + kwsysProcess_Delete(gp); + if (result) { + std::cerr << "Error " << args[0] << " returned :" << result << "\n"; + } + return buffer; +} + +std::string SystemInformationImplementation::ParseValueFromKStat( + const char* arguments) +{ + std::vector args_string; + std::string command = arguments; + size_t start = std::string::npos; + size_t pos = command.find(' ', 0); + while (pos != std::string::npos) { + bool inQuotes = false; + // Check if we are between quotes + size_t b0 = command.find('"', 0); + size_t b1 = command.find('"', b0 + 1); + while (b0 != std::string::npos && b1 != std::string::npos && b1 > b0) { + if (pos > b0 && pos < b1) { + inQuotes = true; + break; + } + b0 = command.find('"', b1 + 1); + b1 = command.find('"', b0 + 1); + } + + if (!inQuotes) { + args_string.push_back(command.substr(start + 1, pos - start - 1)); + std::string& arg = args_string.back(); + + // Remove the quotes if any + arg.erase(std::remove(arg.begin(), arg.end(), '"'), arg.end()); + start = pos; + } + pos = command.find(' ', pos + 1); + } + args_string.push_back(command.substr(start + 1, command.size() - start - 1)); + + std::vector args; + args.reserve(3 + args_string.size()); + args.push_back("kstat"); + args.push_back("-p"); + for (size_t i = 0; i < args_string.size(); ++i) { + args.push_back(args_string[i].c_str()); + } + args.push_back(nullptr); + + std::string buffer = this->RunProcess(args); + + std::string value; + for (size_t i = buffer.size() - 1; i > 0; i--) { + if (buffer[i] == ' ' || buffer[i] == '\t') { + break; + } + if (buffer[i] != '\n' && buffer[i] != '\r') { + value.insert(0u, 1, buffer[i]); + } + } + return value; +} + +/** Querying for system information from Solaris */ +bool SystemInformationImplementation::QuerySolarisMemory() +{ +#if defined(__SVR4) && defined(__sun) +// Solaris allows querying this value by sysconf, but if this is +// a 32 bit process on a 64 bit host the returned memory will be +// limited to 4GiB. So if this is a 32 bit process or if the sysconf +// method fails use the kstat interface. +# if SIZEOF_VOID_P == 8 + if (this->QueryMemoryBySysconf()) { + return true; + } +# endif + + char* tail; + unsigned long totalMemory = + strtoul(this->ParseValueFromKStat("-s physmem").c_str(), &tail, 0); + this->TotalPhysicalMemory = totalMemory / 128; + + return true; +#else + return false; +#endif +} + +bool SystemInformationImplementation::QuerySolarisProcessor() +{ + if (!this->QueryProcessorBySysconf()) { + return false; + } + + // Parse values + this->CPUSpeedInMHz = static_cast( + atoi(this->ParseValueFromKStat("-s clock_MHz").c_str())); + + // Chip family + this->ChipID.Family = 0; + + // Chip Model + this->ChipID.ProcessorName = this->ParseValueFromKStat("-s cpu_type"); + this->ChipID.Model = 0; + + // Chip Vendor + if (this->ChipID.ProcessorName != "i386") { + this->ChipID.Vendor = "Sun"; + this->FindManufacturer(); + } + + return true; +} + +/** Querying for system information from Haiku OS */ +bool SystemInformationImplementation::QueryHaikuInfo() +{ +#if defined(__HAIKU__) + + // CPU count + system_info info; + get_system_info(&info); + this->NumberOfPhysicalCPU = info.cpu_count; + + // CPU speed + uint32 topologyNodeCount = 0; + cpu_topology_node_info* topology = 0; + get_cpu_topology_info(0, &topologyNodeCount); + if (topologyNodeCount != 0) + topology = new cpu_topology_node_info[topologyNodeCount]; + get_cpu_topology_info(topology, &topologyNodeCount); + + for (uint32 i = 0; i < topologyNodeCount; i++) { + if (topology[i].type == B_TOPOLOGY_CORE) { + this->CPUSpeedInMHz = + topology[i].data.core.default_frequency / 1000000.0f; + break; + } + } + + delete[] topology; + + // Physical Memory + this->TotalPhysicalMemory = (info.max_pages * B_PAGE_SIZE) / (1024 * 1024); + this->AvailablePhysicalMemory = this->TotalPhysicalMemory - + ((info.used_pages * B_PAGE_SIZE) / (1024 * 1024)); + + // NOTE: get_system_info_etc is currently a private call so just set to 0 + // until it becomes public + this->TotalVirtualMemory = 0; + this->AvailableVirtualMemory = 0; + + // Retrieve cpuid_info union for cpu 0 + cpuid_info cpu_info; + get_cpuid(&cpu_info, 0, 0); + + // Chip Vendor + // Use a temporary buffer so that we can add NULL termination to the string + char vbuf[13]; + strncpy(vbuf, cpu_info.eax_0.vendor_id, 12); + vbuf[12] = '\0'; + this->ChipID.Vendor = vbuf; + + this->FindManufacturer(); + + // Retrieve cpuid_info union for cpu 0 this time using a register value of 1 + get_cpuid(&cpu_info, 1, 0); + + this->NumberOfLogicalCPU = cpu_info.eax_1.logical_cpus; + + // Chip type + this->ChipID.Type = cpu_info.eax_1.type; + + // Chip family + this->ChipID.Family = cpu_info.eax_1.family; + + // Chip Model + this->ChipID.Model = cpu_info.eax_1.model; + + // Chip Revision + this->ChipID.Revision = cpu_info.eax_1.stepping; + + // Chip Extended Family + this->ChipID.ExtendedFamily = cpu_info.eax_1.extended_family; + + // Chip Extended Model + this->ChipID.ExtendedModel = cpu_info.eax_1.extended_model; + + // Get ChipID.ProcessorName from other information already gathered + this->RetrieveClassicalCPUIdentity(); + + // Cache size + this->Features.L1CacheSize = 0; + this->Features.L2CacheSize = 0; + + return true; + +#else + return false; +#endif +} + +bool SystemInformationImplementation::QueryQNXMemory() +{ +#if defined(__QNX__) + std::string buffer; + std::vector args; + args.clear(); + + args.push_back("showmem"); + args.push_back("-S"); + args.push_back(0); + buffer = this->RunProcess(args); + args.clear(); + + size_t pos = buffer.find("System RAM:"); + if (pos == std::string::npos) + return false; + pos = buffer.find(":", pos); + size_t pos2 = buffer.find("M (", pos); + if (pos2 == std::string::npos) + return false; + + pos++; + while (buffer[pos] == ' ') + pos++; + + this->TotalPhysicalMemory = atoi(buffer.substr(pos, pos2 - pos).c_str()); + return true; +#endif + return false; +} + +bool SystemInformationImplementation::QueryBSDMemory() +{ +#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ + defined(__DragonFly__) + int ctrl[2] = { CTL_HW, HW_PHYSMEM }; +# if defined(HW_PHYSMEM64) + int64_t k; + ctrl[1] = HW_PHYSMEM64; +# else + int k; +# endif + size_t sz = sizeof(k); + + if (sysctl(ctrl, 2, &k, &sz, nullptr, 0) != 0) { + return false; + } + + this->TotalPhysicalMemory = k >> 10 >> 10; + + return true; +#else + return false; +#endif +} + +bool SystemInformationImplementation::QueryQNXProcessor() +{ +#if defined(__QNX__) + // the output on my QNX 6.4.1 looks like this: + // Processor1: 686 Pentium II Stepping 3 2175MHz FPU + std::string buffer; + std::vector args; + args.clear(); + + args.push_back("pidin"); + args.push_back("info"); + args.push_back(0); + buffer = this->RunProcess(args); + args.clear(); + + size_t pos = buffer.find("Processor1:"); + if (pos == std::string::npos) + return false; + + size_t pos2 = buffer.find("MHz", pos); + if (pos2 == std::string::npos) + return false; + + size_t pos3 = pos2; + while (buffer[pos3] != ' ') + --pos3; + + this->CPUSpeedInMHz = atoi(buffer.substr(pos3 + 1, pos2 - pos3 - 1).c_str()); + + pos2 = buffer.find(" Stepping", pos); + if (pos2 != std::string::npos) { + pos2 = buffer.find(" ", pos2 + 1); + if (pos2 != std::string::npos && pos2 < pos3) { + this->ChipID.Revision = + atoi(buffer.substr(pos2 + 1, pos3 - pos2).c_str()); + } + } + + this->NumberOfPhysicalCPU = 0; + do { + pos = buffer.find("\nProcessor", pos + 1); + ++this->NumberOfPhysicalCPU; + } while (pos != std::string::npos); + this->NumberOfLogicalCPU = 1; + + return true; +#else + return false; +#endif +} + +bool SystemInformationImplementation::QueryBSDProcessor() +{ +#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ + defined(__DragonFly__) + int k; + size_t sz = sizeof(k); + int ctrl[2] = { CTL_HW, HW_NCPU }; + + if (sysctl(ctrl, 2, &k, &sz, nullptr, 0) != 0) { + return false; + } + + this->NumberOfPhysicalCPU = k; + this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU; + +# if defined(HW_CPUSPEED) + ctrl[1] = HW_CPUSPEED; + + if (sysctl(ctrl, 2, &k, &sz, nullptr, 0) != 0) { + return false; + } + + this->CPUSpeedInMHz = (float)k; +# endif + +# if defined(CPU_SSE) + ctrl[0] = CTL_MACHDEP; + ctrl[1] = CPU_SSE; + + if (sysctl(ctrl, 2, &k, &sz, nullptr, 0) != 0) { + return false; + } + + this->Features.HasSSE = (k > 0); +# endif + +# if defined(CPU_SSE2) + ctrl[0] = CTL_MACHDEP; + ctrl[1] = CPU_SSE2; + + if (sysctl(ctrl, 2, &k, &sz, nullptr, 0) != 0) { + return false; + } + + this->Features.HasSSE2 = (k > 0); +# endif + +# if defined(CPU_CPUVENDOR) + ctrl[0] = CTL_MACHDEP; + ctrl[1] = CPU_CPUVENDOR; + char vbuf[25]; + ::memset(vbuf, 0, sizeof(vbuf)); + sz = sizeof(vbuf) - 1; + if (sysctl(ctrl, 2, vbuf, &sz, nullptr, 0) != 0) { + return false; + } + + this->ChipID.Vendor = vbuf; + this->FindManufacturer(); +# endif + + return true; +#else + return false; +#endif +} + +bool SystemInformationImplementation::QueryHPUXMemory() +{ +#if defined(__hpux) + unsigned long tv = 0; + unsigned long tp = 0; + unsigned long av = 0; + unsigned long ap = 0; + struct pst_static pst; + struct pst_dynamic pdy; + + unsigned long ps = 0; + if (pstat_getstatic(&pst, sizeof(pst), (size_t)1, 0) == -1) { + return false; + } + + ps = pst.page_size; + tp = pst.physical_memory * ps; + tv = (pst.physical_memory + pst.pst_maxmem) * ps; + if (pstat_getdynamic(&pdy, sizeof(pdy), (size_t)1, 0) == -1) { + return false; + } + + ap = tp - pdy.psd_rm * ps; + av = tv - pdy.psd_vm; + this->TotalVirtualMemory = tv >> 10 >> 10; + this->TotalPhysicalMemory = tp >> 10 >> 10; + this->AvailableVirtualMemory = av >> 10 >> 10; + this->AvailablePhysicalMemory = ap >> 10 >> 10; + return true; +#else + return false; +#endif +} + +bool SystemInformationImplementation::QueryHPUXProcessor() +{ +#if defined(__hpux) +# if defined(KWSYS_SYS_HAS_MPCTL_H) + int c = mpctl(MPC_GETNUMSPUS_SYS, 0, 0); + if (c <= 0) { + return false; + } + + this->NumberOfPhysicalCPU = c; + this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU; + + long t = sysconf(_SC_CPU_VERSION); + + if (t == -1) { + return false; + } + + switch (t) { + case CPU_PA_RISC1_0: + this->ChipID.Vendor = "Hewlett-Packard"; + this->ChipID.Family = 0x100; + break; + case CPU_PA_RISC1_1: + this->ChipID.Vendor = "Hewlett-Packard"; + this->ChipID.Family = 0x110; + break; + case CPU_PA_RISC2_0: + this->ChipID.Vendor = "Hewlett-Packard"; + this->ChipID.Family = 0x200; + break; +# if defined(CPU_HP_INTEL_EM_1_0) || defined(CPU_IA64_ARCHREV_0) +# ifdef CPU_HP_INTEL_EM_1_0 + case CPU_HP_INTEL_EM_1_0: +# endif +# ifdef CPU_IA64_ARCHREV_0 + case CPU_IA64_ARCHREV_0: +# endif + this->ChipID.Vendor = "GenuineIntel"; + this->Features.HasIA64 = true; + break; +# endif + default: + return false; + } + + this->FindManufacturer(); + + return true; +# else + return false; +# endif +#else + return false; +#endif +} + +/** Query the operating system information */ +bool SystemInformationImplementation::QueryOSInformation() +{ +#if defined(_WIN32) + + this->OSName = "Windows"; + + OSVERSIONINFOEXW osvi; + BOOL bIsWindows64Bit; + BOOL bOsVersionInfoEx; + char operatingSystem[256]; + + // Try calling GetVersionEx using the OSVERSIONINFOEX structure. + ZeroMemory(&osvi, sizeof(OSVERSIONINFOEXW)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW); +# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx +# pragma warning(push) +# ifdef __INTEL_COMPILER +# pragma warning(disable : 1478) +# elif defined __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdeprecated-declarations" +# else +# pragma warning(disable : 4996) +# endif +# endif + bOsVersionInfoEx = GetVersionExW((OSVERSIONINFOW*)&osvi); + if (!bOsVersionInfoEx) { + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW); + if (!GetVersionExW((OSVERSIONINFOW*)&osvi)) { + return false; + } + } +# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx +# ifdef __clang__ +# pragma clang diagnostic pop +# else +# pragma warning(pop) +# endif +# endif + + switch (osvi.dwPlatformId) { + case VER_PLATFORM_WIN32_NT: + // Test for the product. + if (osvi.dwMajorVersion <= 4) { + this->OSRelease = "NT"; + } + if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) { + this->OSRelease = "2000"; + } + if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) { + this->OSRelease = "XP"; + } + // XP Professional x64 + if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) { + this->OSRelease = "XP"; + } +# ifdef VER_NT_WORKSTATION + // Test for product type. + if (bOsVersionInfoEx) { + if (osvi.wProductType == VER_NT_WORKSTATION) { + if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0) { + this->OSRelease = "Vista"; + } + if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1) { + this->OSRelease = "7"; + } +// VER_SUITE_PERSONAL may not be defined +# ifdef VER_SUITE_PERSONAL + else { + if (osvi.wSuiteMask & VER_SUITE_PERSONAL) { + this->OSRelease += " Personal"; + } else { + this->OSRelease += " Professional"; + } + } +# endif + } else if (osvi.wProductType == VER_NT_SERVER) { + // Check for .NET Server instead of Windows XP. + if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) { + this->OSRelease = ".NET"; + } + + // Continue with the type detection. + if (osvi.wSuiteMask & VER_SUITE_DATACENTER) { + this->OSRelease += " DataCenter Server"; + } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) { + this->OSRelease += " Advanced Server"; + } else { + this->OSRelease += " Server"; + } + } + + sprintf(operatingSystem, "%ls (Build %ld)", osvi.szCSDVersion, + osvi.dwBuildNumber & 0xFFFF); + this->OSVersion = operatingSystem; + } else +# endif // VER_NT_WORKSTATION + { + HKEY hKey; + wchar_t szProductType[80]; + DWORD dwBufLen; + + // Query the registry to retrieve information. + RegOpenKeyExW(HKEY_LOCAL_MACHINE, + L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions", 0, + KEY_QUERY_VALUE, &hKey); + RegQueryValueExW(hKey, L"ProductType", nullptr, nullptr, + (LPBYTE)szProductType, &dwBufLen); + RegCloseKey(hKey); + + if (lstrcmpiW(L"WINNT", szProductType) == 0) { + this->OSRelease += " Professional"; + } + if (lstrcmpiW(L"LANMANNT", szProductType) == 0) { + // Decide between Windows 2000 Advanced Server and Windows .NET + // Enterprise Server. + if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) { + this->OSRelease += " Standard Server"; + } else { + this->OSRelease += " Server"; + } + } + if (lstrcmpiW(L"SERVERNT", szProductType) == 0) { + // Decide between Windows 2000 Advanced Server and Windows .NET + // Enterprise Server. + if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) { + this->OSRelease += " Enterprise Server"; + } else { + this->OSRelease += " Advanced Server"; + } + } + } + + // Display version, service pack (if any), and build number. + if (osvi.dwMajorVersion <= 4) { + // NB: NT 4.0 and earlier. + sprintf(operatingSystem, "version %ld.%ld %ls (Build %ld)", + osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.szCSDVersion, + osvi.dwBuildNumber & 0xFFFF); + this->OSVersion = operatingSystem; + } else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) { + // Windows XP and .NET server. + typedef BOOL(CALLBACK * LPFNPROC)(HANDLE, BOOL*); + HINSTANCE hKernelDLL; + LPFNPROC DLLProc; + + // Load the Kernel32 DLL. + hKernelDLL = LoadLibraryW(L"kernel32"); + if (hKernelDLL != nullptr) { + // Only XP and .NET Server support IsWOW64Process so... Load + // dynamically! + DLLProc = (LPFNPROC)GetProcAddress(hKernelDLL, "IsWow64Process"); + + // If the function address is valid, call the function. + if (DLLProc != nullptr) + (DLLProc)(GetCurrentProcess(), &bIsWindows64Bit); + else + bIsWindows64Bit = false; + + // Free the DLL module. + FreeLibrary(hKernelDLL); + } + } else { + // Windows 2000 and everything else. + sprintf(operatingSystem, "%ls (Build %ld)", osvi.szCSDVersion, + osvi.dwBuildNumber & 0xFFFF); + this->OSVersion = operatingSystem; + } + break; + + case VER_PLATFORM_WIN32_WINDOWS: + // Test for the product. + if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) { + this->OSRelease = "95"; + if (osvi.szCSDVersion[1] == 'C') { + this->OSRelease += "OSR 2.5"; + } else if (osvi.szCSDVersion[1] == 'B') { + this->OSRelease += "OSR 2"; + } + } + + if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10) { + this->OSRelease = "98"; + if (osvi.szCSDVersion[1] == 'A') { + this->OSRelease += "SE"; + } + } + + if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90) { + this->OSRelease = "Me"; + } + break; + + case VER_PLATFORM_WIN32s: + this->OSRelease = "Win32s"; + break; + + default: + this->OSRelease = "Unknown"; + break; + } + + // Get the hostname + WORD wVersionRequested; + WSADATA wsaData; + char name[255]; + wVersionRequested = MAKEWORD(2, 0); + + if (WSAStartup(wVersionRequested, &wsaData) == 0) { + gethostname(name, sizeof(name)); + WSACleanup(); + } + this->Hostname = name; + + const char* arch = getenv("PROCESSOR_ARCHITECTURE"); + const char* wow64 = getenv("PROCESSOR_ARCHITEW6432"); + if (arch) { + this->OSPlatform = arch; + } + + if (wow64) { + // the PROCESSOR_ARCHITEW6432 is only defined when running 32bit programs + // on 64bit OS + this->OSIs64Bit = true; + } else if (arch) { + // all values other than x86 map to 64bit architectures + this->OSIs64Bit = (strncmp(arch, "x86", 3) != 0); + } + +#else + + struct utsname unameInfo; + int errorFlag = uname(&unameInfo); + if (errorFlag == 0) { + this->OSName = unameInfo.sysname; + this->Hostname = unameInfo.nodename; + this->OSRelease = unameInfo.release; + this->OSVersion = unameInfo.version; + this->OSPlatform = unameInfo.machine; + + // This is still insufficient to capture 64bit architecture such + // powerpc and possible mips and sparc + if (this->OSPlatform.find_first_of("64") != std::string::npos) { + this->OSIs64Bit = true; + } + } + +# ifdef __APPLE__ + this->OSName = "Unknown Apple OS"; + this->OSRelease = "Unknown product version"; + this->OSVersion = "Unknown build version"; + + this->CallSwVers("-productName", this->OSName); + this->CallSwVers("-productVersion", this->OSRelease); + this->CallSwVers("-buildVersion", this->OSVersion); +# endif + +#endif + + return true; +} + +int SystemInformationImplementation::CallSwVers(const char* arg, + std::string& ver) +{ +#ifdef __APPLE__ + std::vector args; + args.push_back("sw_vers"); + args.push_back(arg); + args.push_back(nullptr); + ver = this->RunProcess(args); + this->TrimNewline(ver); +#else + // avoid C4100 + (void)arg; + (void)ver; +#endif + return 0; +} + +void SystemInformationImplementation::TrimNewline(std::string& output) +{ + // remove \r + std::string::size_type pos = 0; + while ((pos = output.find("\r", pos)) != std::string::npos) { + output.erase(pos); + } + + // remove \n + pos = 0; + while ((pos = output.find("\n", pos)) != std::string::npos) { + output.erase(pos); + } +} + +/** Return true if the machine is 64 bits */ +bool SystemInformationImplementation::Is64Bits() +{ + return this->OSIs64Bit; +} +} diff --git a/test/API/driver/kwsys/SystemInformation.hxx.in b/test/API/driver/kwsys/SystemInformation.hxx.in new file mode 100644 index 0000000..fc42e9d --- /dev/null +++ b/test/API/driver/kwsys/SystemInformation.hxx.in @@ -0,0 +1,170 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_SystemInformation_h +#define @KWSYS_NAMESPACE@_SystemInformation_h + +#include <@KWSYS_NAMESPACE@/Configure.hxx> + +#include /* size_t */ +#include + +namespace @KWSYS_NAMESPACE@ { + +// forward declare the implementation class +class SystemInformationImplementation; + +class @KWSYS_NAMESPACE@_EXPORT SystemInformation +{ +#if @KWSYS_USE_LONG_LONG@ + typedef long long LongLong; +#elif @KWSYS_USE___INT64@ + typedef __int64 LongLong; +#else +# error "No Long Long" +#endif + friend class SystemInformationImplementation; + SystemInformationImplementation* Implementation; + +public: + // possible parameter values for DoesCPUSupportFeature() + static const long int CPU_FEATURE_MMX = 1 << 0; + static const long int CPU_FEATURE_MMX_PLUS = 1 << 1; + static const long int CPU_FEATURE_SSE = 1 << 2; + static const long int CPU_FEATURE_SSE2 = 1 << 3; + static const long int CPU_FEATURE_AMD_3DNOW = 1 << 4; + static const long int CPU_FEATURE_AMD_3DNOW_PLUS = 1 << 5; + static const long int CPU_FEATURE_IA64 = 1 << 6; + static const long int CPU_FEATURE_MP_CAPABLE = 1 << 7; + static const long int CPU_FEATURE_HYPERTHREAD = 1 << 8; + static const long int CPU_FEATURE_SERIALNUMBER = 1 << 9; + static const long int CPU_FEATURE_APIC = 1 << 10; + static const long int CPU_FEATURE_SSE_FP = 1 << 11; + static const long int CPU_FEATURE_SSE_MMX = 1 << 12; + static const long int CPU_FEATURE_CMOV = 1 << 13; + static const long int CPU_FEATURE_MTRR = 1 << 14; + static const long int CPU_FEATURE_L1CACHE = 1 << 15; + static const long int CPU_FEATURE_L2CACHE = 1 << 16; + static const long int CPU_FEATURE_L3CACHE = 1 << 17; + static const long int CPU_FEATURE_ACPI = 1 << 18; + static const long int CPU_FEATURE_THERMALMONITOR = 1 << 19; + static const long int CPU_FEATURE_TEMPSENSEDIODE = 1 << 20; + static const long int CPU_FEATURE_FREQUENCYID = 1 << 21; + static const long int CPU_FEATURE_VOLTAGEID_FREQUENCY = 1 << 22; + static const long int CPU_FEATURE_FPU = 1 << 23; + +public: + SystemInformation(); + ~SystemInformation(); + + SystemInformation(const SystemInformation&) = delete; + SystemInformation& operator=(const SystemInformation&) = delete; + + const char* GetVendorString(); + const char* GetVendorID(); + std::string GetTypeID(); + std::string GetFamilyID(); + std::string GetModelID(); + std::string GetModelName(); + std::string GetSteppingCode(); + const char* GetExtendedProcessorName(); + const char* GetProcessorSerialNumber(); + int GetProcessorCacheSize(); + unsigned int GetLogicalProcessorsPerPhysical(); + float GetProcessorClockFrequency(); + int GetProcessorAPICID(); + int GetProcessorCacheXSize(long int); + bool DoesCPUSupportFeature(long int); + + // returns an informative general description of the cpu + // on this system. + std::string GetCPUDescription(); + + const char* GetHostname(); + std::string GetFullyQualifiedDomainName(); + + const char* GetOSName(); + const char* GetOSRelease(); + const char* GetOSVersion(); + const char* GetOSPlatform(); + + int GetOSIsWindows(); + int GetOSIsLinux(); + int GetOSIsApple(); + + // returns an informative general description of the os + // on this system. + std::string GetOSDescription(); + + // returns if the operating system is 64bit or not. + bool Is64Bits(); + + unsigned int GetNumberOfLogicalCPU(); + unsigned int GetNumberOfPhysicalCPU(); + + bool DoesCPUSupportCPUID(); + + // Retrieve id of the current running process + LongLong GetProcessId(); + + // Retrieve memory information in MiB. + size_t GetTotalVirtualMemory(); + size_t GetAvailableVirtualMemory(); + size_t GetTotalPhysicalMemory(); + size_t GetAvailablePhysicalMemory(); + + // returns an informative general description if the installed and + // available ram on this system. See the GetHostMemoryTotal, and + // Get{Host,Proc}MemoryAvailable methods for more information. + std::string GetMemoryDescription(const char* hostLimitEnvVarName = nullptr, + const char* procLimitEnvVarName = nullptr); + + // Retrieve amount of physical memory installed on the system in KiB + // units. + LongLong GetHostMemoryTotal(); + + // Get total system RAM in units of KiB available colectivley to all + // processes in a process group. An example of a process group + // are the processes comprising an mpi program which is running in + // parallel. The amount of memory reported may differ from the host + // total if a host wide resource limit is applied. Such reource limits + // are reported to us via an application specified environment variable. + LongLong GetHostMemoryAvailable(const char* hostLimitEnvVarName = nullptr); + + // Get total system RAM in units of KiB available to this process. + // This may differ from the host available if a per-process resource + // limit is applied. per-process memory limits are applied on unix + // system via rlimit API. Resource limits that are not imposed via + // rlimit API may be reported to us via an application specified + // environment variable. + LongLong GetProcMemoryAvailable(const char* hostLimitEnvVarName = nullptr, + const char* procLimitEnvVarName = nullptr); + + // Get the system RAM used by all processes on the host, in units of KiB. + LongLong GetHostMemoryUsed(); + + // Get system RAM used by this process id in units of KiB. + LongLong GetProcMemoryUsed(); + + // Return the load average of the machine or -0.0 if it cannot + // be determined. + double GetLoadAverage(); + + // enable/disable stack trace signal handler. In order to + // produce an informative stack trace the application should + // be dynamically linked and compiled with debug symbols. + static void SetStackTraceOnError(int enable); + + // format and return the current program stack in a string. In + // order to produce an informative stack trace the application + // should be dynamically linked and compiled with debug symbols. + static std::string GetProgramStack(int firstFrame, int wholePath); + + /** Run the different checks */ + void RunCPUCheck(); + void RunOSCheck(); + void RunMemoryCheck(); +}; + +} // namespace @KWSYS_NAMESPACE@ + +#endif diff --git a/test/API/driver/kwsys/SystemTools.cxx b/test/API/driver/kwsys/SystemTools.cxx new file mode 100644 index 0000000..ce4d6ef --- /dev/null +++ b/test/API/driver/kwsys/SystemTools.cxx @@ -0,0 +1,4703 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifdef __osf__ +# define _OSF_SOURCE +# define _POSIX_C_SOURCE 199506L +# define _XOPEN_SOURCE_EXTENDED +#endif + +#if defined(_WIN32) && \ + (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) || \ + defined(__MINGW32__)) +# define KWSYS_WINDOWS_DIRS +#else +# if defined(__SUNPRO_CC) +# include +# endif +#endif + +#include "kwsysPrivate.h" +#include KWSYS_HEADER(RegularExpression.hxx) +#include KWSYS_HEADER(SystemTools.hxx) +#include KWSYS_HEADER(Directory.hxx) +#include KWSYS_HEADER(FStream.hxx) +#include KWSYS_HEADER(Encoding.h) +#include KWSYS_HEADER(Encoding.hxx) + +#include +#include +#include +#include +#include +#include + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "Directory.hxx.in" +# include "Encoding.hxx.in" +# include "FStream.hxx.in" +# include "RegularExpression.hxx.in" +# include "SystemTools.hxx.in" +#endif + +#ifdef _MSC_VER +# pragma warning(disable : 4786) +#endif + +#if defined(__sgi) && !defined(__GNUC__) +# pragma set woff 1375 /* base class destructor not virtual */ +#endif + +#include +#include +#ifdef __QNX__ +# include /* for malloc/free on QNX */ +#endif +#include +#include +#include +#include + +#if defined(_WIN32) && !defined(_MSC_VER) && defined(__GNUC__) +# include /* for strcasecmp */ +#endif + +#ifdef _MSC_VER +# define umask _umask // Note this is still umask on Borland +#endif + +// support for realpath call +#ifndef _WIN32 +# include +# include +# include +# include +# include +# include +# include +# ifndef __VMS +# include +# include +# endif +# include /* sigprocmask */ +#endif + +#ifdef __linux +# include +#endif + +// Windows API. +#if defined(_WIN32) +# include +# include +# ifndef INVALID_FILE_ATTRIBUTES +# define INVALID_FILE_ATTRIBUTES ((DWORD)-1) +# endif +# if defined(_MSC_VER) && _MSC_VER >= 1800 +# define KWSYS_WINDOWS_DEPRECATED_GetVersionEx +# endif +#elif defined(__CYGWIN__) +# include +# undef _WIN32 +#endif + +#if !KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H +extern char** environ; +#endif + +#ifdef __CYGWIN__ +# include +#endif + +// getpwnam doesn't exist on Windows and Cray Xt3/Catamount +// same for TIOCGWINSZ +#if defined(_WIN32) || defined(__LIBCATAMOUNT__) || \ + (defined(HAVE_GETPWNAM) && HAVE_GETPWNAM == 0) +# undef HAVE_GETPWNAM +# undef HAVE_TTY_INFO +#else +# define HAVE_GETPWNAM 1 +# define HAVE_TTY_INFO 1 +#endif + +#define VTK_URL_PROTOCOL_REGEX "([a-zA-Z0-9]*)://(.*)" +#define VTK_URL_REGEX \ + "([a-zA-Z0-9]*)://(([A-Za-z0-9]+)(:([^:@]+))?@)?([^:@/]+)(:([0-9]+))?/" \ + "(.+)?" + +#ifdef _MSC_VER +# include +#else +# include +#endif + +// This is a hack to prevent warnings about these functions being +// declared but not referenced. +#if defined(__sgi) && !defined(__GNUC__) +# include +namespace KWSYS_NAMESPACE { +class SystemToolsHack +{ +public: + enum + { + Ref1 = sizeof(cfgetospeed(0)), + Ref2 = sizeof(cfgetispeed(0)), + Ref3 = sizeof(tcgetattr(0, 0)), + Ref4 = sizeof(tcsetattr(0, 0, 0)), + Ref5 = sizeof(cfsetospeed(0, 0)), + Ref6 = sizeof(cfsetispeed(0, 0)) + }; +}; +} +#endif + +#if defined(_WIN32) && \ + (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) || \ + defined(__MINGW32__)) +# include +# include +# define _unlink unlink +#endif + +/* The maximum length of a file name. */ +#if defined(PATH_MAX) +# define KWSYS_SYSTEMTOOLS_MAXPATH PATH_MAX +#elif defined(MAXPATHLEN) +# define KWSYS_SYSTEMTOOLS_MAXPATH MAXPATHLEN +#else +# define KWSYS_SYSTEMTOOLS_MAXPATH 16384 +#endif +#if defined(__WATCOMC__) +# include +# define _mkdir mkdir +# define _rmdir rmdir +# define _getcwd getcwd +# define _chdir chdir +#endif + +#if defined(__BEOS__) && !defined(__ZETA__) +# include +# include + +// BeOS 5 doesn't have usleep(), but it has snooze(), which is identical. +static inline void usleep(unsigned int msec) +{ + ::snooze(msec); +} + +// BeOS 5 also doesn't have realpath(), but its C++ API offers something close. +static inline char* realpath(const char* path, char* resolved_path) +{ + const size_t maxlen = KWSYS_SYSTEMTOOLS_MAXPATH; + snprintf(resolved_path, maxlen, "%s", path); + BPath normalized(resolved_path, nullptr, true); + const char* resolved = normalized.Path(); + if (resolved != nullptr) // nullptr == No such file. + { + if (snprintf(resolved_path, maxlen, "%s", resolved) < maxlen) { + return resolved_path; + } + } + return nullptr; // something went wrong. +} +#endif + +#ifdef _WIN32 +static time_t windows_filetime_to_posix_time(const FILETIME& ft) +{ + LARGE_INTEGER date; + date.HighPart = ft.dwHighDateTime; + date.LowPart = ft.dwLowDateTime; + + // removes the diff between 1970 and 1601 + date.QuadPart -= ((LONGLONG)(369 * 365 + 89) * 24 * 3600 * 10000000); + + // converts back from 100-nanoseconds to seconds + return date.QuadPart / 10000000; +} +#endif + +#ifdef KWSYS_WINDOWS_DIRS +# include + +inline int Mkdir(const std::string& dir) +{ + return _wmkdir( + KWSYS_NAMESPACE::Encoding::ToWindowsExtendedPath(dir).c_str()); +} +inline int Rmdir(const std::string& dir) +{ + return _wrmdir( + KWSYS_NAMESPACE::Encoding::ToWindowsExtendedPath(dir).c_str()); +} +inline const char* Getcwd(char* buf, unsigned int len) +{ + std::vector w_buf(len); + if (_wgetcwd(&w_buf[0], len)) { + size_t nlen = kwsysEncoding_wcstombs(buf, &w_buf[0], len); + if (nlen == static_cast(-1)) { + return 0; + } + if (nlen < len) { + // make sure the drive letter is capital + if (nlen > 1 && buf[1] == ':') { + buf[0] = toupper(buf[0]); + } + return buf; + } + } + return 0; +} +inline int Chdir(const std::string& dir) +{ +# if defined(__BORLANDC__) + return chdir(dir.c_str()); +# else + return _wchdir(KWSYS_NAMESPACE::Encoding::ToWide(dir).c_str()); +# endif +} +inline void Realpath(const std::string& path, std::string& resolved_path, + std::string* errorMessage = 0) +{ + std::wstring tmp = KWSYS_NAMESPACE::Encoding::ToWide(path); + wchar_t* ptemp; + wchar_t fullpath[MAX_PATH]; + DWORD bufferLen = GetFullPathNameW( + tmp.c_str(), sizeof(fullpath) / sizeof(fullpath[0]), fullpath, &ptemp); + if (bufferLen < sizeof(fullpath) / sizeof(fullpath[0])) { + resolved_path = KWSYS_NAMESPACE::Encoding::ToNarrow(fullpath); + KWSYS_NAMESPACE::SystemTools::ConvertToUnixSlashes(resolved_path); + } else if (errorMessage) { + if (bufferLen) { + *errorMessage = "Destination path buffer size too small."; + } else if (unsigned int errorId = GetLastError()) { + LPSTR message = nullptr; + DWORD size = FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, errorId, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)&message, 0, nullptr); + *errorMessage = std::string(message, size); + LocalFree(message); + } else { + *errorMessage = "Unknown error."; + } + + resolved_path = ""; + } else { + resolved_path = path; + } +} +#else +# include + +# include +# include +inline int Mkdir(const std::string& dir) +{ + return mkdir(dir.c_str(), 00777); +} +inline int Rmdir(const std::string& dir) +{ + return rmdir(dir.c_str()); +} +inline const char* Getcwd(char* buf, unsigned int len) +{ + return getcwd(buf, len); +} + +inline int Chdir(const std::string& dir) +{ + return chdir(dir.c_str()); +} +inline void Realpath(const std::string& path, std::string& resolved_path, + std::string* errorMessage = nullptr) +{ + char resolved_name[KWSYS_SYSTEMTOOLS_MAXPATH]; + + errno = 0; + char* ret = realpath(path.c_str(), resolved_name); + if (ret) { + resolved_path = ret; + } else if (errorMessage) { + if (errno) { + *errorMessage = strerror(errno); + } else { + *errorMessage = "Unknown error."; + } + + resolved_path = ""; + } else { + // if path resolution fails, return what was passed in + resolved_path = path; + } +} +#endif + +#if !defined(_WIN32) && defined(__COMO__) +// Hack for como strict mode to avoid defining _SVID_SOURCE or _BSD_SOURCE. +extern "C" { +extern FILE* popen(__const char* __command, __const char* __modes) __THROW; +extern int pclose(FILE* __stream) __THROW; +extern char* realpath(__const char* __restrict __name, + char* __restrict __resolved) __THROW; +extern char* strdup(__const char* __s) __THROW; +extern int putenv(char* __string) __THROW; +} +#endif + +namespace KWSYS_NAMESPACE { + +double SystemTools::GetTime(void) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + return (429.4967296 * ft.dwHighDateTime + 0.0000001 * ft.dwLowDateTime - + 11644473600.0); +#else + struct timeval t; + gettimeofday(&t, nullptr); + return 1.0 * double(t.tv_sec) + 0.000001 * double(t.tv_usec); +#endif +} + +/* Type of character storing the environment. */ +#if defined(_WIN32) +typedef wchar_t envchar; +#else +typedef char envchar; +#endif + +/* Order by environment key only (VAR from VAR=VALUE). */ +struct kwsysEnvCompare +{ + bool operator()(const envchar* l, const envchar* r) const + { +#if defined(_WIN32) + const wchar_t* leq = wcschr(l, L'='); + const wchar_t* req = wcschr(r, L'='); + size_t llen = leq ? (leq - l) : wcslen(l); + size_t rlen = req ? (req - r) : wcslen(r); + if (llen == rlen) { + return wcsncmp(l, r, llen) < 0; + } else { + return wcscmp(l, r) < 0; + } +#else + const char* leq = strchr(l, '='); + const char* req = strchr(r, '='); + size_t llen = leq ? static_cast(leq - l) : strlen(l); + size_t rlen = req ? static_cast(req - r) : strlen(r); + if (llen == rlen) { + return strncmp(l, r, llen) < 0; + } else { + return strcmp(l, r) < 0; + } +#endif + } +}; + +class kwsysEnvSet : public std::set +{ +public: + class Free + { + const envchar* Env; + + public: + Free(const envchar* env) + : Env(env) + { + } + ~Free() { free(const_cast(this->Env)); } + + Free(const Free&) = delete; + Free& operator=(const Free&) = delete; + }; + + const envchar* Release(const envchar* env) + { + const envchar* old = nullptr; + iterator i = this->find(env); + if (i != this->end()) { + old = *i; + this->erase(i); + } + return old; + } +}; + +#ifdef _WIN32 +struct SystemToolsPathCaseCmp +{ + bool operator()(std::string const& l, std::string const& r) const + { +# ifdef _MSC_VER + return _stricmp(l.c_str(), r.c_str()) < 0; +# elif defined(__GNUC__) + return strcasecmp(l.c_str(), r.c_str()) < 0; +# else + return SystemTools::Strucmp(l.c_str(), r.c_str()) < 0; +# endif + } +}; +#endif + +/** + * SystemTools static variables singleton class. + */ +class SystemToolsStatic +{ +public: + typedef std::map StringMap; +#if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP + /** + * Path translation table from dir to refdir + * Each time 'dir' will be found it will be replace by 'refdir' + */ + StringMap TranslationMap; +#endif +#ifdef _WIN32 + static std::string GetCasePathName(std::string const& pathIn); + static std::string GetActualCaseForPathCached(std::string const& path); + static const char* GetEnvBuffered(const char* key); + std::map PathCaseMap; + std::map EnvMap; +#endif +#ifdef __CYGWIN__ + StringMap Cyg2Win32Map; +#endif + + /** + * Actual implementation of ReplaceString. + */ + static void ReplaceString(std::string& source, const char* replace, + size_t replaceSize, const std::string& with); + + /** + * Actual implementation of FileIsFullPath. + */ + static bool FileIsFullPath(const char*, size_t); + + /** + * Find a filename (file or directory) in the system PATH, with + * optional extra paths. + */ + static std::string FindName( + const std::string& name, + const std::vector& path = std::vector(), + bool no_system_path = false); +}; + +#ifdef _WIN32 +std::string SystemToolsStatic::GetCasePathName(std::string const& pathIn) +{ + std::string casePath; + + // First check if the file is relative. We don't fix relative paths since the + // real case depends on the root directory and the given path fragment may + // have meaning elsewhere in the project. + if (!SystemTools::FileIsFullPath(pathIn)) { + // This looks unnecessary, but it allows for the return value optimization + // since all return paths return the same local variable. + casePath = pathIn; + return casePath; + } + + std::vector path_components; + SystemTools::SplitPath(pathIn, path_components); + + // Start with root component. + std::vector::size_type idx = 0; + casePath = path_components[idx++]; + // make sure drive letter is always upper case + if (casePath.size() > 1 && casePath[1] == ':') { + casePath[0] = toupper(casePath[0]); + } + const char* sep = ""; + + // If network path, fill casePath with server/share so FindFirstFile + // will work after that. Maybe someday call other APIs to get + // actual case of servers and shares. + if (path_components.size() > 2 && path_components[0] == "//") { + casePath += path_components[idx++]; + casePath += "/"; + casePath += path_components[idx++]; + sep = "/"; + } + + // Convert case of all components that exist. + bool converting = true; + for (; idx < path_components.size(); idx++) { + casePath += sep; + sep = "/"; + + if (converting) { + // If path component contains wildcards, we skip matching + // because these filenames are not allowed on windows, + // and we do not want to match a different file. + if (path_components[idx].find('*') != std::string::npos || + path_components[idx].find('?') != std::string::npos) { + converting = false; + } else { + std::string test_str = casePath; + test_str += path_components[idx]; + WIN32_FIND_DATAW findData; + HANDLE hFind = + ::FindFirstFileW(Encoding::ToWide(test_str).c_str(), &findData); + if (INVALID_HANDLE_VALUE != hFind) { + path_components[idx] = Encoding::ToNarrow(findData.cFileName); + ::FindClose(hFind); + } else { + converting = false; + } + } + } + + casePath += path_components[idx]; + } + return casePath; +} + +std::string SystemToolsStatic::GetActualCaseForPathCached(std::string const& p) +{ + // Check to see if actual case has already been called + // for this path, and the result is stored in the PathCaseMap + auto& pcm = SystemTools::Statics->PathCaseMap; + { + auto itr = pcm.find(p); + if (itr != pcm.end()) { + return itr->second; + } + } + std::string casePath = SystemToolsStatic::GetCasePathName(p); + if (casePath.size() <= MAX_PATH) { + pcm[p] = casePath; + } + return casePath; +} +#endif + +// adds the elements of the env variable path to the arg passed in +void SystemTools::GetPath(std::vector& path, const char* env) +{ + size_t const old_size = path.size(); +#if defined(_WIN32) && !defined(__CYGWIN__) + const char pathSep = ';'; +#else + const char pathSep = ':'; +#endif + if (!env) { + env = "PATH"; + } + std::string pathEnv; + if (!SystemTools::GetEnv(env, pathEnv)) { + return; + } + + // A hack to make the below algorithm work. + if (!pathEnv.empty() && pathEnv.back() != pathSep) { + pathEnv += pathSep; + } + std::string::size_type start = 0; + bool done = false; + while (!done) { + std::string::size_type endpos = pathEnv.find(pathSep, start); + if (endpos != std::string::npos) { + path.push_back(pathEnv.substr(start, endpos - start)); + start = endpos + 1; + } else { + done = true; + } + } + for (std::vector::iterator i = path.begin() + old_size; + i != path.end(); ++i) { + SystemTools::ConvertToUnixSlashes(*i); + } +} + +#if defined(_WIN32) +const char* SystemToolsStatic::GetEnvBuffered(const char* key) +{ + std::string env; + if (SystemTools::GetEnv(key, env)) { + std::string& menv = SystemTools::Statics->EnvMap[key]; + if (menv != env) { + menv = std::move(env); + } + return menv.c_str(); + } + return nullptr; +} +#endif + +const char* SystemTools::GetEnv(const char* key) +{ +#if defined(_WIN32) + return SystemToolsStatic::GetEnvBuffered(key); +#else + return getenv(key); +#endif +} + +const char* SystemTools::GetEnv(const std::string& key) +{ +#if defined(_WIN32) + return SystemToolsStatic::GetEnvBuffered(key.c_str()); +#else + return getenv(key.c_str()); +#endif +} + +bool SystemTools::GetEnv(const char* key, std::string& result) +{ +#if defined(_WIN32) + const std::wstring wkey = Encoding::ToWide(key); + const wchar_t* wv = _wgetenv(wkey.c_str()); + if (wv) { + result = Encoding::ToNarrow(wv); + return true; + } +#else + const char* v = getenv(key); + if (v) { + result = v; + return true; + } +#endif + return false; +} + +bool SystemTools::GetEnv(const std::string& key, std::string& result) +{ + return SystemTools::GetEnv(key.c_str(), result); +} + +bool SystemTools::HasEnv(const char* key) +{ +#if defined(_WIN32) + const std::wstring wkey = Encoding::ToWide(key); + const wchar_t* v = _wgetenv(wkey.c_str()); +#else + const char* v = getenv(key); +#endif + return v != nullptr; +} + +bool SystemTools::HasEnv(const std::string& key) +{ + return SystemTools::HasEnv(key.c_str()); +} + +#if KWSYS_CXX_HAS_UNSETENV +/* unsetenv("A") removes A from the environment. + On older platforms it returns void instead of int. */ +static int kwsysUnPutEnv(const std::string& env) +{ + size_t pos = env.find('='); + if (pos != std::string::npos) { + std::string name = env.substr(0, pos); + unsetenv(name.c_str()); + } else { + unsetenv(env.c_str()); + } + return 0; +} + +#elif defined(__CYGWIN__) || defined(__GLIBC__) +/* putenv("A") removes A from the environment. It must not put the + memory in the environment because it does not have any "=" syntax. */ +static int kwsysUnPutEnv(const std::string& env) +{ + int err = 0; + size_t pos = env.find('='); + size_t const len = pos == std::string::npos ? env.size() : pos; + size_t const sz = len + 1; + char local_buf[256]; + char* buf = sz > sizeof(local_buf) ? (char*)malloc(sz) : local_buf; + if (!buf) { + return -1; + } + strncpy(buf, env.c_str(), len); + buf[len] = 0; + if (putenv(buf) < 0 && errno != EINVAL) { + err = errno; + } + if (buf != local_buf) { + free(buf); + } + if (err) { + errno = err; + return -1; + } + return 0; +} + +#elif defined(_WIN32) +/* putenv("A=") places "A=" in the environment, which is as close to + removal as we can get with the putenv API. We have to leak the + most recent value placed in the environment for each variable name + on program exit in case exit routines access it. */ + +static kwsysEnvSet kwsysUnPutEnvSet; + +static int kwsysUnPutEnv(std::string const& env) +{ + std::wstring wEnv = Encoding::ToWide(env); + size_t const pos = wEnv.find('='); + size_t const len = pos == std::string::npos ? wEnv.size() : pos; + wEnv.resize(len + 1, L'='); + wchar_t* newEnv = _wcsdup(wEnv.c_str()); + if (!newEnv) { + return -1; + } + kwsysEnvSet::Free oldEnv(kwsysUnPutEnvSet.Release(newEnv)); + kwsysUnPutEnvSet.insert(newEnv); + return _wputenv(newEnv); +} + +#else +/* Manipulate the "environ" global directly. */ +static int kwsysUnPutEnv(const std::string& env) +{ + size_t pos = env.find('='); + size_t const len = pos == std::string::npos ? env.size() : pos; + int in = 0; + int out = 0; + while (environ[in]) { + if (strlen(environ[in]) > len && environ[in][len] == '=' && + strncmp(env.c_str(), environ[in], len) == 0) { + ++in; + } else { + environ[out++] = environ[in++]; + } + } + while (out < in) { + environ[out++] = 0; + } + return 0; +} +#endif + +#if KWSYS_CXX_HAS_SETENV + +/* setenv("A", "B", 1) will set A=B in the environment and makes its + own copies of the strings. */ +bool SystemTools::PutEnv(const std::string& env) +{ + size_t pos = env.find('='); + if (pos != std::string::npos) { + std::string name = env.substr(0, pos); + return setenv(name.c_str(), env.c_str() + pos + 1, 1) == 0; + } else { + return kwsysUnPutEnv(env) == 0; + } +} + +bool SystemTools::UnPutEnv(const std::string& env) +{ + return kwsysUnPutEnv(env) == 0; +} + +#else + +/* putenv("A=B") will set A=B in the environment. Most putenv implementations + put their argument directly in the environment. They never free the memory + on program exit. Keep an active set of pointers to memory we allocate and + pass to putenv, one per environment key. At program exit remove any + environment values that may still reference memory we allocated. Then free + the memory. This will not affect any environment values we never set. */ + +# ifdef __INTEL_COMPILER +# pragma warning disable 444 /* base has non-virtual destructor */ +# endif + +class kwsysEnv : public kwsysEnvSet +{ +public: + ~kwsysEnv() + { + for (iterator i = this->begin(); i != this->end(); ++i) { +# if defined(_WIN32) + const std::string s = Encoding::ToNarrow(*i); + kwsysUnPutEnv(s); +# else + kwsysUnPutEnv(*i); +# endif + free(const_cast(*i)); + } + } + bool Put(const char* env) + { +# if defined(_WIN32) + const std::wstring wEnv = Encoding::ToWide(env); + wchar_t* newEnv = _wcsdup(wEnv.c_str()); +# else + char* newEnv = strdup(env); +# endif + Free oldEnv(this->Release(newEnv)); + this->insert(newEnv); +# if defined(_WIN32) + return _wputenv(newEnv) == 0; +# else + return putenv(newEnv) == 0; +# endif + } + bool UnPut(const char* env) + { +# if defined(_WIN32) + const std::wstring wEnv = Encoding::ToWide(env); + Free oldEnv(this->Release(wEnv.c_str())); +# else + Free oldEnv(this->Release(env)); +# endif + return kwsysUnPutEnv(env) == 0; + } +}; + +static kwsysEnv kwsysEnvInstance; + +bool SystemTools::PutEnv(const std::string& env) +{ + return kwsysEnvInstance.Put(env.c_str()); +} + +bool SystemTools::UnPutEnv(const std::string& env) +{ + return kwsysEnvInstance.UnPut(env.c_str()); +} + +#endif + +const char* SystemTools::GetExecutableExtension() +{ +#if defined(_WIN32) || defined(__CYGWIN__) || defined(__VMS) + return ".exe"; +#else + return ""; +#endif +} + +FILE* SystemTools::Fopen(const std::string& file, const char* mode) +{ +#ifdef _WIN32 + return _wfopen(Encoding::ToWindowsExtendedPath(file).c_str(), + Encoding::ToWide(mode).c_str()); +#else + return fopen(file.c_str(), mode); +#endif +} + +bool SystemTools::MakeDirectory(const char* path, const mode_t* mode) +{ + if (!path) { + return false; + } + return SystemTools::MakeDirectory(std::string(path), mode); +} + +bool SystemTools::MakeDirectory(const std::string& path, const mode_t* mode) +{ + if (SystemTools::PathExists(path)) { + return SystemTools::FileIsDirectory(path); + } + if (path.empty()) { + return false; + } + std::string dir = path; + SystemTools::ConvertToUnixSlashes(dir); + + std::string::size_type pos = 0; + std::string topdir; + while ((pos = dir.find('/', pos)) != std::string::npos) { + topdir = dir.substr(0, pos); + + if (Mkdir(topdir) == 0 && mode != nullptr) { + SystemTools::SetPermissions(topdir, *mode); + } + + ++pos; + } + topdir = dir; + if (Mkdir(topdir) != 0) { + // There is a bug in the Borland Run time library which makes MKDIR + // return EACCES when it should return EEXISTS + // if it is some other error besides directory exists + // then return false + if ((errno != EEXIST) +#ifdef __BORLANDC__ + && (errno != EACCES) +#endif + ) { + return false; + } + } else if (mode != nullptr) { + SystemTools::SetPermissions(topdir, *mode); + } + + return true; +} + +// replace replace with with as many times as it shows up in source. +// write the result into source. +void SystemTools::ReplaceString(std::string& source, + const std::string& replace, + const std::string& with) +{ + // do while hangs if replaceSize is 0 + if (replace.empty()) { + return; + } + + SystemToolsStatic::ReplaceString(source, replace.c_str(), replace.size(), + with); +} + +void SystemTools::ReplaceString(std::string& source, const char* replace, + const char* with) +{ + // do while hangs if replaceSize is 0 + if (!*replace) { + return; + } + + SystemToolsStatic::ReplaceString(source, replace, strlen(replace), + with ? with : ""); +} + +void SystemToolsStatic::ReplaceString(std::string& source, const char* replace, + size_t replaceSize, + const std::string& with) +{ + const char* src = source.c_str(); + char* searchPos = const_cast(strstr(src, replace)); + + // get out quick if string is not found + if (!searchPos) { + return; + } + + // perform replacements until done + char* orig = strdup(src); + char* currentPos = orig; + searchPos = searchPos - src + orig; + + // initialize the result + source.erase(source.begin(), source.end()); + do { + *searchPos = '\0'; + source += currentPos; + currentPos = searchPos + replaceSize; + // replace + source += with; + searchPos = strstr(currentPos, replace); + } while (searchPos); + + // copy any trailing text + source += currentPos; + free(orig); +} + +#if defined(_WIN32) && !defined(__CYGWIN__) + +# if defined(KEY_WOW64_32KEY) && defined(KEY_WOW64_64KEY) +# define KWSYS_ST_KEY_WOW64_32KEY KEY_WOW64_32KEY +# define KWSYS_ST_KEY_WOW64_64KEY KEY_WOW64_64KEY +# else +# define KWSYS_ST_KEY_WOW64_32KEY 0x0200 +# define KWSYS_ST_KEY_WOW64_64KEY 0x0100 +# endif + +static bool SystemToolsParseRegistryKey(const std::string& key, + HKEY& primaryKey, std::string& second, + std::string& valuename) +{ + std::string primary = key; + + size_t start = primary.find('\\'); + if (start == std::string::npos) { + return false; + } + + size_t valuenamepos = primary.find(';'); + if (valuenamepos != std::string::npos) { + valuename = primary.substr(valuenamepos + 1); + } + + second = primary.substr(start + 1, valuenamepos - start - 1); + primary = primary.substr(0, start); + + if (primary == "HKEY_CURRENT_USER") { + primaryKey = HKEY_CURRENT_USER; + } + if (primary == "HKEY_CURRENT_CONFIG") { + primaryKey = HKEY_CURRENT_CONFIG; + } + if (primary == "HKEY_CLASSES_ROOT") { + primaryKey = HKEY_CLASSES_ROOT; + } + if (primary == "HKEY_LOCAL_MACHINE") { + primaryKey = HKEY_LOCAL_MACHINE; + } + if (primary == "HKEY_USERS") { + primaryKey = HKEY_USERS; + } + + return true; +} + +static DWORD SystemToolsMakeRegistryMode(DWORD mode, + SystemTools::KeyWOW64 view) +{ + // only add the modes when on a system that supports Wow64. + static FARPROC wow64p = + GetProcAddress(GetModuleHandleW(L"kernel32"), "IsWow64Process"); + if (wow64p == nullptr) { + return mode; + } + + if (view == SystemTools::KeyWOW64_32) { + return mode | KWSYS_ST_KEY_WOW64_32KEY; + } else if (view == SystemTools::KeyWOW64_64) { + return mode | KWSYS_ST_KEY_WOW64_64KEY; + } + return mode; +} +#endif + +#if defined(_WIN32) && !defined(__CYGWIN__) +bool SystemTools::GetRegistrySubKeys(const std::string& key, + std::vector& subkeys, + KeyWOW64 view) +{ + HKEY primaryKey = HKEY_CURRENT_USER; + std::string second; + std::string valuename; + if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) { + return false; + } + + HKEY hKey; + if (RegOpenKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0, + SystemToolsMakeRegistryMode(KEY_READ, view), + &hKey) != ERROR_SUCCESS) { + return false; + } else { + wchar_t name[1024]; + DWORD dwNameSize = sizeof(name) / sizeof(name[0]); + + DWORD i = 0; + while (RegEnumKeyW(hKey, i, name, dwNameSize) == ERROR_SUCCESS) { + subkeys.push_back(Encoding::ToNarrow(name)); + ++i; + } + + RegCloseKey(hKey); + } + + return true; +} +#else +bool SystemTools::GetRegistrySubKeys(const std::string&, + std::vector&, KeyWOW64) +{ + return false; +} +#endif + +// Read a registry value. +// Example : +// HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\2.1\InstallPath +// => will return the data of the "default" value of the key +// HKEY_LOCAL_MACHINE\SOFTWARE\Scriptics\Tcl\8.4;Root +// => will return the data of the "Root" value of the key + +#if defined(_WIN32) && !defined(__CYGWIN__) +bool SystemTools::ReadRegistryValue(const std::string& key, std::string& value, + KeyWOW64 view) +{ + bool valueset = false; + HKEY primaryKey = HKEY_CURRENT_USER; + std::string second; + std::string valuename; + if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) { + return false; + } + + HKEY hKey; + if (RegOpenKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0, + SystemToolsMakeRegistryMode(KEY_READ, view), + &hKey) != ERROR_SUCCESS) { + return false; + } else { + DWORD dwType, dwSize; + dwSize = 1023; + wchar_t data[1024]; + if (RegQueryValueExW(hKey, Encoding::ToWide(valuename).c_str(), nullptr, + &dwType, (BYTE*)data, &dwSize) == ERROR_SUCCESS) { + if (dwType == REG_SZ) { + value = Encoding::ToNarrow(data); + valueset = true; + } else if (dwType == REG_EXPAND_SZ) { + wchar_t expanded[1024]; + DWORD dwExpandedSize = sizeof(expanded) / sizeof(expanded[0]); + if (ExpandEnvironmentStringsW(data, expanded, dwExpandedSize)) { + value = Encoding::ToNarrow(expanded); + valueset = true; + } + } + } + + RegCloseKey(hKey); + } + + return valueset; +} +#else +bool SystemTools::ReadRegistryValue(const std::string&, std::string&, KeyWOW64) +{ + return false; +} +#endif + +// Write a registry value. +// Example : +// HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\2.1\InstallPath +// => will set the data of the "default" value of the key +// HKEY_LOCAL_MACHINE\SOFTWARE\Scriptics\Tcl\8.4;Root +// => will set the data of the "Root" value of the key + +#if defined(_WIN32) && !defined(__CYGWIN__) +bool SystemTools::WriteRegistryValue(const std::string& key, + const std::string& value, KeyWOW64 view) +{ + HKEY primaryKey = HKEY_CURRENT_USER; + std::string second; + std::string valuename; + if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) { + return false; + } + + HKEY hKey; + DWORD dwDummy; + wchar_t lpClass[] = L""; + if (RegCreateKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0, lpClass, + REG_OPTION_NON_VOLATILE, + SystemToolsMakeRegistryMode(KEY_WRITE, view), nullptr, + &hKey, &dwDummy) != ERROR_SUCCESS) { + return false; + } + + std::wstring wvalue = Encoding::ToWide(value); + if (RegSetValueExW(hKey, Encoding::ToWide(valuename).c_str(), 0, REG_SZ, + (CONST BYTE*)wvalue.c_str(), + (DWORD)(sizeof(wchar_t) * (wvalue.size() + 1))) == + ERROR_SUCCESS) { + return true; + } + return false; +} +#else +bool SystemTools::WriteRegistryValue(const std::string&, const std::string&, + KeyWOW64) +{ + return false; +} +#endif + +// Delete a registry value. +// Example : +// HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\2.1\InstallPath +// => will delete the data of the "default" value of the key +// HKEY_LOCAL_MACHINE\SOFTWARE\Scriptics\Tcl\8.4;Root +// => will delete the data of the "Root" value of the key + +#if defined(_WIN32) && !defined(__CYGWIN__) +bool SystemTools::DeleteRegistryValue(const std::string& key, KeyWOW64 view) +{ + HKEY primaryKey = HKEY_CURRENT_USER; + std::string second; + std::string valuename; + if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) { + return false; + } + + HKEY hKey; + if (RegOpenKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0, + SystemToolsMakeRegistryMode(KEY_WRITE, view), + &hKey) != ERROR_SUCCESS) { + return false; + } else { + if (RegDeleteValue(hKey, (LPTSTR)valuename.c_str()) == ERROR_SUCCESS) { + RegCloseKey(hKey); + return true; + } + } + return false; +} +#else +bool SystemTools::DeleteRegistryValue(const std::string&, KeyWOW64) +{ + return false; +} +#endif + +bool SystemTools::SameFile(const std::string& file1, const std::string& file2) +{ +#ifdef _WIN32 + HANDLE hFile1, hFile2; + + hFile1 = + CreateFileW(Encoding::ToWide(file1).c_str(), GENERIC_READ, FILE_SHARE_READ, + nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); + hFile2 = + CreateFileW(Encoding::ToWide(file2).c_str(), GENERIC_READ, FILE_SHARE_READ, + nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); + if (hFile1 == INVALID_HANDLE_VALUE || hFile2 == INVALID_HANDLE_VALUE) { + if (hFile1 != INVALID_HANDLE_VALUE) { + CloseHandle(hFile1); + } + if (hFile2 != INVALID_HANDLE_VALUE) { + CloseHandle(hFile2); + } + return false; + } + + BY_HANDLE_FILE_INFORMATION fiBuf1; + BY_HANDLE_FILE_INFORMATION fiBuf2; + GetFileInformationByHandle(hFile1, &fiBuf1); + GetFileInformationByHandle(hFile2, &fiBuf2); + CloseHandle(hFile1); + CloseHandle(hFile2); + return (fiBuf1.dwVolumeSerialNumber == fiBuf2.dwVolumeSerialNumber && + fiBuf1.nFileIndexHigh == fiBuf2.nFileIndexHigh && + fiBuf1.nFileIndexLow == fiBuf2.nFileIndexLow); +#else + struct stat fileStat1, fileStat2; + if (stat(file1.c_str(), &fileStat1) == 0 && + stat(file2.c_str(), &fileStat2) == 0) { + // see if the files are the same file + // check the device inode and size + if (memcmp(&fileStat2.st_dev, &fileStat1.st_dev, + sizeof(fileStat1.st_dev)) == 0 && + memcmp(&fileStat2.st_ino, &fileStat1.st_ino, + sizeof(fileStat1.st_ino)) == 0 && + fileStat2.st_size == fileStat1.st_size) { + return true; + } + } + return false; +#endif +} + +bool SystemTools::PathExists(const std::string& path) +{ + if (path.empty()) { + return false; + } +#if defined(__CYGWIN__) + // Convert path to native windows path if possible. + char winpath[MAX_PATH]; + if (SystemTools::PathCygwinToWin32(path.c_str(), winpath)) { + return (GetFileAttributesA(winpath) != INVALID_FILE_ATTRIBUTES); + } + struct stat st; + return lstat(path.c_str(), &st) == 0; +#elif defined(_WIN32) + return (GetFileAttributesW(Encoding::ToWindowsExtendedPath(path).c_str()) != + INVALID_FILE_ATTRIBUTES); +#else + struct stat st; + return lstat(path.c_str(), &st) == 0; +#endif +} + +bool SystemTools::FileExists(const char* filename) +{ + if (!filename) { + return false; + } + return SystemTools::FileExists(std::string(filename)); +} + +bool SystemTools::FileExists(const std::string& filename) +{ + if (filename.empty()) { + return false; + } +#if defined(__CYGWIN__) + // Convert filename to native windows path if possible. + char winpath[MAX_PATH]; + if (SystemTools::PathCygwinToWin32(filename.c_str(), winpath)) { + return (GetFileAttributesA(winpath) != INVALID_FILE_ATTRIBUTES); + } + return access(filename.c_str(), R_OK) == 0; +#elif defined(_WIN32) + DWORD attr = + GetFileAttributesW(Encoding::ToWindowsExtendedPath(filename).c_str()); + if (attr == INVALID_FILE_ATTRIBUTES) { + return false; + } + + if (attr & FILE_ATTRIBUTE_REPARSE_POINT) { + // Using 0 instead of GENERIC_READ as it allows reading of file attributes + // even if we do not have permission to read the file itself + HANDLE handle = + CreateFileW(Encoding::ToWindowsExtendedPath(filename).c_str(), 0, 0, + nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); + + if (handle == INVALID_HANDLE_VALUE) { + return false; + } + + CloseHandle(handle); + } + + return true; +#else +// SCO OpenServer 5.0.7/3.2's command has 711 permission. +# if defined(_SCO_DS) + return access(filename.c_str(), F_OK) == 0; +# else + return access(filename.c_str(), R_OK) == 0; +# endif +#endif +} + +bool SystemTools::FileExists(const char* filename, bool isFile) +{ + if (!filename) { + return false; + } + return SystemTools::FileExists(std::string(filename), isFile); +} + +bool SystemTools::FileExists(const std::string& filename, bool isFile) +{ + if (SystemTools::FileExists(filename)) { + // If isFile is set return not FileIsDirectory, + // so this will only be true if it is a file + return !isFile || !SystemTools::FileIsDirectory(filename); + } + return false; +} + +bool SystemTools::TestFileAccess(const char* filename, + TestFilePermissions permissions) +{ + if (!filename) { + return false; + } + return SystemTools::TestFileAccess(std::string(filename), permissions); +} + +bool SystemTools::TestFileAccess(const std::string& filename, + TestFilePermissions permissions) +{ + if (filename.empty()) { + return false; + } +#if defined(_WIN32) && !defined(__CYGWIN__) + // If execute set, change to read permission (all files on Windows + // are executable if they are readable). The CRT will always fail + // if you pass an execute bit. + if (permissions & TEST_FILE_EXECUTE) { + permissions &= ~TEST_FILE_EXECUTE; + permissions |= TEST_FILE_READ; + } + return _waccess(Encoding::ToWindowsExtendedPath(filename).c_str(), + permissions) == 0; +#else + return access(filename.c_str(), permissions) == 0; +#endif +} + +int SystemTools::Stat(const char* path, SystemTools::Stat_t* buf) +{ + if (!path) { + errno = EFAULT; + return -1; + } + return SystemTools::Stat(std::string(path), buf); +} + +int SystemTools::Stat(const std::string& path, SystemTools::Stat_t* buf) +{ + if (path.empty()) { + errno = ENOENT; + return -1; + } +#if defined(_WIN32) && !defined(__CYGWIN__) + // Ideally we should use Encoding::ToWindowsExtendedPath to support + // long paths, but _wstat64 rejects paths with '?' in them, thinking + // they are wildcards. + std::wstring const& wpath = Encoding::ToWide(path); +# if defined(__BORLANDC__) + return _wstati64(wpath.c_str(), buf); +# else + return _wstat64(wpath.c_str(), buf); +# endif +#else + return stat(path.c_str(), buf); +#endif +} + +#ifdef __CYGWIN__ +bool SystemTools::PathCygwinToWin32(const char* path, char* win32_path) +{ + auto itr = SystemTools::Statics->Cyg2Win32Map.find(path); + if (itr != SystemTools::Statics->Cyg2Win32Map.end()) { + strncpy(win32_path, itr->second.c_str(), MAX_PATH); + } else { + if (cygwin_conv_path(CCP_POSIX_TO_WIN_A, path, win32_path, MAX_PATH) != + 0) { + win32_path[0] = 0; + } + SystemTools::Statics->Cyg2Win32Map.insert( + SystemToolsStatic::StringMap::value_type(path, win32_path)); + } + return win32_path[0] != 0; +} +#endif + +bool SystemTools::Touch(const std::string& filename, bool create) +{ + if (!SystemTools::PathExists(filename)) { + if (create) { + FILE* file = Fopen(filename, "a+b"); + if (file) { + fclose(file); + return true; + } + return false; + } else { + return true; + } + } +#if defined(_WIN32) && !defined(__CYGWIN__) + HANDLE h = CreateFileW(Encoding::ToWindowsExtendedPath(filename).c_str(), + FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, 0, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); + if (!h) { + return false; + } + FILETIME mtime; + GetSystemTimeAsFileTime(&mtime); + if (!SetFileTime(h, 0, 0, &mtime)) { + CloseHandle(h); + return false; + } + CloseHandle(h); +#elif KWSYS_CXX_HAS_UTIMENSAT + // utimensat is only available on newer Unixes and macOS 10.13+ + if (utimensat(AT_FDCWD, filename.c_str(), nullptr, 0) < 0) { + return false; + } +#else + // fall back to utimes + if (utimes(filename.c_str(), nullptr) < 0) { + return false; + } +#endif + return true; +} + +bool SystemTools::FileTimeCompare(const std::string& f1, const std::string& f2, + int* result) +{ + // Default to same time. + *result = 0; +#if !defined(_WIN32) || defined(__CYGWIN__) + // POSIX version. Use stat function to get file modification time. + struct stat s1; + if (stat(f1.c_str(), &s1) != 0) { + return false; + } + struct stat s2; + if (stat(f2.c_str(), &s2) != 0) { + return false; + } +# if KWSYS_CXX_STAT_HAS_ST_MTIM + // Compare using nanosecond resolution. + if (s1.st_mtim.tv_sec < s2.st_mtim.tv_sec) { + *result = -1; + } else if (s1.st_mtim.tv_sec > s2.st_mtim.tv_sec) { + *result = 1; + } else if (s1.st_mtim.tv_nsec < s2.st_mtim.tv_nsec) { + *result = -1; + } else if (s1.st_mtim.tv_nsec > s2.st_mtim.tv_nsec) { + *result = 1; + } +# elif KWSYS_CXX_STAT_HAS_ST_MTIMESPEC + // Compare using nanosecond resolution. + if (s1.st_mtimespec.tv_sec < s2.st_mtimespec.tv_sec) { + *result = -1; + } else if (s1.st_mtimespec.tv_sec > s2.st_mtimespec.tv_sec) { + *result = 1; + } else if (s1.st_mtimespec.tv_nsec < s2.st_mtimespec.tv_nsec) { + *result = -1; + } else if (s1.st_mtimespec.tv_nsec > s2.st_mtimespec.tv_nsec) { + *result = 1; + } +# else + // Compare using 1 second resolution. + if (s1.st_mtime < s2.st_mtime) { + *result = -1; + } else if (s1.st_mtime > s2.st_mtime) { + *result = 1; + } +# endif +#else + // Windows version. Get the modification time from extended file attributes. + WIN32_FILE_ATTRIBUTE_DATA f1d; + WIN32_FILE_ATTRIBUTE_DATA f2d; + if (!GetFileAttributesExW(Encoding::ToWindowsExtendedPath(f1).c_str(), + GetFileExInfoStandard, &f1d)) { + return false; + } + if (!GetFileAttributesExW(Encoding::ToWindowsExtendedPath(f2).c_str(), + GetFileExInfoStandard, &f2d)) { + return false; + } + + // Compare the file times using resolution provided by system call. + *result = (int)CompareFileTime(&f1d.ftLastWriteTime, &f2d.ftLastWriteTime); +#endif + return true; +} + +// Return a capitalized string (i.e the first letter is uppercased, all other +// are lowercased) +std::string SystemTools::Capitalized(const std::string& s) +{ + std::string n; + if (s.empty()) { + return n; + } + n.resize(s.size()); + n[0] = static_cast(toupper(s[0])); + for (size_t i = 1; i < s.size(); i++) { + n[i] = static_cast(tolower(s[i])); + } + return n; +} + +// Return capitalized words +std::string SystemTools::CapitalizedWords(const std::string& s) +{ + std::string n(s); + for (size_t i = 0; i < s.size(); i++) { +#if defined(_MSC_VER) && defined(_MT) && defined(_DEBUG) + // MS has an assert that will fail if s[i] < 0; setting + // LC_CTYPE using setlocale() does *not* help. Painful. + if ((int)s[i] >= 0 && isalpha(s[i]) && + (i == 0 || ((int)s[i - 1] >= 0 && isspace(s[i - 1])))) +#else + if (isalpha(s[i]) && (i == 0 || isspace(s[i - 1]))) +#endif + { + n[i] = static_cast(toupper(s[i])); + } + } + return n; +} + +// Return uncapitalized words +std::string SystemTools::UnCapitalizedWords(const std::string& s) +{ + std::string n(s); + for (size_t i = 0; i < s.size(); i++) { +#if defined(_MSC_VER) && defined(_MT) && defined(_DEBUG) + // MS has an assert that will fail if s[i] < 0; setting + // LC_CTYPE using setlocale() does *not* help. Painful. + if ((int)s[i] >= 0 && isalpha(s[i]) && + (i == 0 || ((int)s[i - 1] >= 0 && isspace(s[i - 1])))) +#else + if (isalpha(s[i]) && (i == 0 || isspace(s[i - 1]))) +#endif + { + n[i] = static_cast(tolower(s[i])); + } + } + return n; +} + +// only works for words with at least two letters +std::string SystemTools::AddSpaceBetweenCapitalizedWords(const std::string& s) +{ + std::string n; + if (!s.empty()) { + n.reserve(s.size()); + n += s[0]; + for (size_t i = 1; i < s.size(); i++) { + if (isupper(s[i]) && !isspace(s[i - 1]) && !isupper(s[i - 1])) { + n += ' '; + } + n += s[i]; + } + } + return n; +} + +char* SystemTools::AppendStrings(const char* str1, const char* str2) +{ + if (!str1) { + return SystemTools::DuplicateString(str2); + } + if (!str2) { + return SystemTools::DuplicateString(str1); + } + size_t len1 = strlen(str1); + char* newstr = new char[len1 + strlen(str2) + 1]; + if (!newstr) { + return nullptr; + } + strcpy(newstr, str1); + strcat(newstr + len1, str2); + return newstr; +} + +char* SystemTools::AppendStrings(const char* str1, const char* str2, + const char* str3) +{ + if (!str1) { + return SystemTools::AppendStrings(str2, str3); + } + if (!str2) { + return SystemTools::AppendStrings(str1, str3); + } + if (!str3) { + return SystemTools::AppendStrings(str1, str2); + } + + size_t len1 = strlen(str1), len2 = strlen(str2); + char* newstr = new char[len1 + len2 + strlen(str3) + 1]; + if (!newstr) { + return nullptr; + } + strcpy(newstr, str1); + strcat(newstr + len1, str2); + strcat(newstr + len1 + len2, str3); + return newstr; +} + +// Return a lower case string +std::string SystemTools::LowerCase(const std::string& s) +{ + std::string n; + n.resize(s.size()); + for (size_t i = 0; i < s.size(); i++) { + n[i] = static_cast(tolower(s[i])); + } + return n; +} + +// Return a lower case string +std::string SystemTools::UpperCase(const std::string& s) +{ + std::string n; + n.resize(s.size()); + for (size_t i = 0; i < s.size(); i++) { + n[i] = static_cast(toupper(s[i])); + } + return n; +} + +// Count char in string +size_t SystemTools::CountChar(const char* str, char c) +{ + size_t count = 0; + + if (str) { + while (*str) { + if (*str == c) { + ++count; + } + ++str; + } + } + return count; +} + +// Remove chars in string +char* SystemTools::RemoveChars(const char* str, const char* toremove) +{ + if (!str) { + return nullptr; + } + char* clean_str = new char[strlen(str) + 1]; + char* ptr = clean_str; + while (*str) { + const char* str2 = toremove; + while (*str2 && *str != *str2) { + ++str2; + } + if (!*str2) { + *ptr++ = *str; + } + ++str; + } + *ptr = '\0'; + return clean_str; +} + +// Remove chars in string +char* SystemTools::RemoveCharsButUpperHex(const char* str) +{ + if (!str) { + return nullptr; + } + char* clean_str = new char[strlen(str) + 1]; + char* ptr = clean_str; + while (*str) { + if ((*str >= '0' && *str <= '9') || (*str >= 'A' && *str <= 'F')) { + *ptr++ = *str; + } + ++str; + } + *ptr = '\0'; + return clean_str; +} + +// Replace chars in string +char* SystemTools::ReplaceChars(char* str, const char* toreplace, + char replacement) +{ + if (str) { + char* ptr = str; + while (*ptr) { + const char* ptr2 = toreplace; + while (*ptr2) { + if (*ptr == *ptr2) { + *ptr = replacement; + } + ++ptr2; + } + ++ptr; + } + } + return str; +} + +// Returns if string starts with another string +bool SystemTools::StringStartsWith(const char* str1, const char* str2) +{ + if (!str1 || !str2) { + return false; + } + size_t len1 = strlen(str1), len2 = strlen(str2); + return len1 >= len2 && !strncmp(str1, str2, len2) ? true : false; +} + +// Returns if string starts with another string +bool SystemTools::StringStartsWith(const std::string& str1, const char* str2) +{ + if (!str2) { + return false; + } + size_t len1 = str1.size(), len2 = strlen(str2); + return len1 >= len2 && !strncmp(str1.c_str(), str2, len2) ? true : false; +} + +// Returns if string ends with another string +bool SystemTools::StringEndsWith(const char* str1, const char* str2) +{ + if (!str1 || !str2) { + return false; + } + size_t len1 = strlen(str1), len2 = strlen(str2); + return len1 >= len2 && !strncmp(str1 + (len1 - len2), str2, len2) ? true + : false; +} + +// Returns if string ends with another string +bool SystemTools::StringEndsWith(const std::string& str1, const char* str2) +{ + if (!str2) { + return false; + } + size_t len1 = str1.size(), len2 = strlen(str2); + return len1 >= len2 && !strncmp(str1.c_str() + (len1 - len2), str2, len2) + ? true + : false; +} + +// Returns a pointer to the last occurrence of str2 in str1 +const char* SystemTools::FindLastString(const char* str1, const char* str2) +{ + if (!str1 || !str2) { + return nullptr; + } + + size_t len1 = strlen(str1), len2 = strlen(str2); + if (len1 >= len2) { + const char* ptr = str1 + len1 - len2; + do { + if (!strncmp(ptr, str2, len2)) { + return ptr; + } + } while (ptr-- != str1); + } + + return nullptr; +} + +// Duplicate string +char* SystemTools::DuplicateString(const char* str) +{ + if (str) { + char* newstr = new char[strlen(str) + 1]; + return strcpy(newstr, str); + } + return nullptr; +} + +// Return a cropped string +std::string SystemTools::CropString(const std::string& s, size_t max_len) +{ + if (!s.size() || max_len == 0 || max_len >= s.size()) { + return s; + } + + std::string n; + n.reserve(max_len); + + size_t middle = max_len / 2; + + n += s.substr(0, middle); + n += s.substr(s.size() - (max_len - middle)); + + if (max_len > 2) { + n[middle] = '.'; + if (max_len > 3) { + n[middle - 1] = '.'; + if (max_len > 4) { + n[middle + 1] = '.'; + } + } + } + + return n; +} + +std::vector SystemTools::SplitString(const std::string& p, + char sep, bool isPath) +{ + std::string path = p; + std::vector paths; + if (path.empty()) { + return paths; + } + if (isPath && path[0] == '/') { + path.erase(path.begin()); + paths.push_back("/"); + } + std::string::size_type pos1 = 0; + std::string::size_type pos2 = path.find(sep, pos1 + 1); + while (pos2 != std::string::npos) { + paths.push_back(path.substr(pos1, pos2 - pos1)); + pos1 = pos2 + 1; + pos2 = path.find(sep, pos1 + 1); + } + paths.push_back(path.substr(pos1, pos2 - pos1)); + + return paths; +} + +int SystemTools::EstimateFormatLength(const char* format, va_list ap) +{ + if (!format) { + return 0; + } + + // Quick-hack attempt at estimating the length of the string. + // Should never under-estimate. + + // Start with the length of the format string itself. + + size_t length = strlen(format); + + // Increase the length for every argument in the format. + + const char* cur = format; + while (*cur) { + if (*cur++ == '%') { + // Skip "%%" since it doesn't correspond to a va_arg. + if (*cur != '%') { + while (!int(isalpha(*cur))) { + ++cur; + } + switch (*cur) { + case 's': { + // Check the length of the string. + char* s = va_arg(ap, char*); + if (s) { + length += strlen(s); + } + } break; + case 'e': + case 'f': + case 'g': { + // Assume the argument contributes no more than 64 characters. + length += 64; + + // Eat the argument. + static_cast(va_arg(ap, double)); + } break; + default: { + // Assume the argument contributes no more than 64 characters. + length += 64; + + // Eat the argument. + static_cast(va_arg(ap, int)); + } break; + } + } + + // Move past the characters just tested. + ++cur; + } + } + + return static_cast(length); +} + +std::string SystemTools::EscapeChars(const char* str, + const char* chars_to_escape, + char escape_char) +{ + std::string n; + if (str) { + if (!chars_to_escape || !*chars_to_escape) { + n.append(str); + } else { + n.reserve(strlen(str)); + while (*str) { + const char* ptr = chars_to_escape; + while (*ptr) { + if (*str == *ptr) { + n += escape_char; + break; + } + ++ptr; + } + n += *str; + ++str; + } + } + } + return n; +} + +#ifdef __VMS +static void ConvertVMSToUnix(std::string& path) +{ + std::string::size_type rootEnd = path.find(":["); + std::string::size_type pathEnd = path.find("]"); + if (rootEnd != std::string::npos) { + std::string root = path.substr(0, rootEnd); + std::string pathPart = path.substr(rootEnd + 2, pathEnd - rootEnd - 2); + const char* pathCString = pathPart.c_str(); + const char* pos0 = pathCString; + for (std::string::size_type pos = 0; *pos0; ++pos) { + if (*pos0 == '.') { + pathPart[pos] = '/'; + } + pos0++; + } + path = "/" + root + "/" + pathPart; + } +} +#endif + +// convert windows slashes to unix slashes +void SystemTools::ConvertToUnixSlashes(std::string& path) +{ + if (path.empty()) { + return; + } + + const char* pathCString = path.c_str(); + bool hasDoubleSlash = false; +#ifdef __VMS + ConvertVMSToUnix(path); +#else + const char* pos0 = pathCString; + for (std::string::size_type pos = 0; *pos0; ++pos) { + if (*pos0 == '\\') { + path[pos] = '/'; + } + + // Also, reuse the loop to check for slash followed by another slash + if (!hasDoubleSlash && *(pos0 + 1) == '/' && *(pos0 + 2) == '/') { +# ifdef _WIN32 + // However, on windows if the first characters are both slashes, + // then keep them that way, so that network paths can be handled. + if (pos > 0) { + hasDoubleSlash = true; + } +# else + hasDoubleSlash = true; +# endif + } + + pos0++; + } + + if (hasDoubleSlash) { + SystemTools::ReplaceString(path, "//", "/"); + } +#endif + + // remove any trailing slash + // if there is a tilda ~ then replace it with HOME + pathCString = path.c_str(); + if (pathCString[0] == '~' && + (pathCString[1] == '/' || pathCString[1] == '\0')) { + std::string homeEnv; + if (SystemTools::GetEnv("HOME", homeEnv)) { + path.replace(0, 1, homeEnv); + } + } +#ifdef HAVE_GETPWNAM + else if (pathCString[0] == '~') { + std::string::size_type idx = path.find_first_of("/\0"); + std::string user = path.substr(1, idx - 1); + passwd* pw = getpwnam(user.c_str()); + if (pw) { + path.replace(0, idx, pw->pw_dir); + } + } +#endif + // remove trailing slash if the path is more than + // a single / + pathCString = path.c_str(); + size_t size = path.size(); + if (size > 1 && path.back() == '/') { + // if it is c:/ then do not remove the trailing slash + if (!((size == 3 && pathCString[1] == ':'))) { + path.resize(size - 1); + } + } +} + +#ifdef _WIN32 +std::wstring SystemTools::ConvertToWindowsExtendedPath( + const std::string& source) +{ + return Encoding::ToWindowsExtendedPath(source); +} +#endif + +// change // to /, and escape any spaces in the path +std::string SystemTools::ConvertToUnixOutputPath(const std::string& path) +{ + std::string ret = path; + + // remove // except at the beginning might be a cygwin drive + std::string::size_type pos = 1; + while ((pos = ret.find("//", pos)) != std::string::npos) { + ret.erase(pos, 1); + } + // escape spaces and () in the path + if (ret.find_first_of(" ") != std::string::npos) { + std::string result; + char lastch = 1; + for (const char* ch = ret.c_str(); *ch != '\0'; ++ch) { + // if it is already escaped then don't try to escape it again + if ((*ch == ' ') && lastch != '\\') { + result += '\\'; + } + result += *ch; + lastch = *ch; + } + ret = result; + } + return ret; +} + +std::string SystemTools::ConvertToOutputPath(const std::string& path) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + return SystemTools::ConvertToWindowsOutputPath(path); +#else + return SystemTools::ConvertToUnixOutputPath(path); +#endif +} + +// remove double slashes not at the start +std::string SystemTools::ConvertToWindowsOutputPath(const std::string& path) +{ + std::string ret; + // make it big enough for all of path and double quotes + ret.reserve(path.size() + 3); + // put path into the string + ret = path; + std::string::size_type pos = 0; + // first convert all of the slashes + while ((pos = ret.find('/', pos)) != std::string::npos) { + ret[pos] = '\\'; + pos++; + } + // check for really small paths + if (ret.size() < 2) { + return ret; + } + // now clean up a bit and remove double slashes + // Only if it is not the first position in the path which is a network + // path on windows + pos = 1; // start at position 1 + if (ret[0] == '\"') { + pos = 2; // if the string is already quoted then start at 2 + if (ret.size() < 3) { + return ret; + } + } + while ((pos = ret.find("\\\\", pos)) != std::string::npos) { + ret.erase(pos, 1); + } + // now double quote the path if it has spaces in it + // and is not already double quoted + if (ret.find(' ') != std::string::npos && ret[0] != '\"') { + ret.insert(static_cast(0), + static_cast(1), '\"'); + ret.append(1, '\"'); + } + return ret; +} + +/** + * Append the filename from the path source to the directory name dir. + */ +static std::string FileInDir(const std::string& source, const std::string& dir) +{ + std::string new_destination = dir; + SystemTools::ConvertToUnixSlashes(new_destination); + return new_destination + '/' + SystemTools::GetFilenameName(source); +} + +bool SystemTools::CopyFileIfDifferent(const std::string& source, + const std::string& destination) +{ + // special check for a destination that is a directory + // FilesDiffer does not handle file to directory compare + if (SystemTools::FileIsDirectory(destination)) { + const std::string new_destination = FileInDir(source, destination); + return SystemTools::CopyFileIfDifferent(source, new_destination); + } + // source and destination are files so do a copy if they + // are different + if (SystemTools::FilesDiffer(source, destination)) { + return SystemTools::CopyFileAlways(source, destination); + } + // at this point the files must be the same so return true + return true; +} + +#define KWSYS_ST_BUFFER 4096 + +bool SystemTools::FilesDiffer(const std::string& source, + const std::string& destination) +{ + +#if defined(_WIN32) + WIN32_FILE_ATTRIBUTE_DATA statSource; + if (GetFileAttributesExW(Encoding::ToWindowsExtendedPath(source).c_str(), + GetFileExInfoStandard, &statSource) == 0) { + return true; + } + + WIN32_FILE_ATTRIBUTE_DATA statDestination; + if (GetFileAttributesExW( + Encoding::ToWindowsExtendedPath(destination).c_str(), + GetFileExInfoStandard, &statDestination) == 0) { + return true; + } + + if (statSource.nFileSizeHigh != statDestination.nFileSizeHigh || + statSource.nFileSizeLow != statDestination.nFileSizeLow) { + return true; + } + + if (statSource.nFileSizeHigh == 0 && statSource.nFileSizeLow == 0) { + return false; + } + off_t nleft = + ((__int64)statSource.nFileSizeHigh << 32) + statSource.nFileSizeLow; + +#else + + struct stat statSource; + if (stat(source.c_str(), &statSource) != 0) { + return true; + } + + struct stat statDestination; + if (stat(destination.c_str(), &statDestination) != 0) { + return true; + } + + if (statSource.st_size != statDestination.st_size) { + return true; + } + + if (statSource.st_size == 0) { + return false; + } + off_t nleft = statSource.st_size; +#endif + +#if defined(_WIN32) + kwsys::ifstream finSource(source.c_str(), (std::ios::binary | std::ios::in)); + kwsys::ifstream finDestination(destination.c_str(), + (std::ios::binary | std::ios::in)); +#else + kwsys::ifstream finSource(source.c_str()); + kwsys::ifstream finDestination(destination.c_str()); +#endif + if (!finSource || !finDestination) { + return true; + } + + // Compare the files a block at a time. + char source_buf[KWSYS_ST_BUFFER]; + char dest_buf[KWSYS_ST_BUFFER]; + while (nleft > 0) { + // Read a block from each file. + std::streamsize nnext = (nleft > KWSYS_ST_BUFFER) + ? KWSYS_ST_BUFFER + : static_cast(nleft); + finSource.read(source_buf, nnext); + finDestination.read(dest_buf, nnext); + + // If either failed to read assume they are different. + if (static_cast(finSource.gcount()) != nnext || + static_cast(finDestination.gcount()) != nnext) { + return true; + } + + // If this block differs the file differs. + if (memcmp(static_cast(source_buf), + static_cast(dest_buf), + static_cast(nnext)) != 0) { + return true; + } + + // Update the byte count remaining. + nleft -= nnext; + } + + // No differences found. + return false; +} + +bool SystemTools::TextFilesDiffer(const std::string& path1, + const std::string& path2) +{ + kwsys::ifstream if1(path1.c_str()); + kwsys::ifstream if2(path2.c_str()); + if (!if1 || !if2) { + return true; + } + + for (;;) { + std::string line1, line2; + bool hasData1 = GetLineFromStream(if1, line1); + bool hasData2 = GetLineFromStream(if2, line2); + if (hasData1 != hasData2) { + return true; + } + if (!hasData1) { + break; + } + if (line1 != line2) { + return true; + } + } + return false; +} + +/** + * Blockwise copy source to destination file + */ +static bool CopyFileContentBlockwise(const std::string& source, + const std::string& destination) +{ +// Open files +#if defined(_WIN32) + kwsys::ifstream fin( + Encoding::ToNarrow(Encoding::ToWindowsExtendedPath(source)).c_str(), + std::ios::in | std::ios::binary); +#else + kwsys::ifstream fin(source.c_str(), std::ios::in | std::ios::binary); +#endif + if (!fin) { + return false; + } + + // try and remove the destination file so that read only destination files + // can be written to. + // If the remove fails continue so that files in read only directories + // that do not allow file removal can be modified. + SystemTools::RemoveFile(destination); + +#if defined(_WIN32) + kwsys::ofstream fout( + Encoding::ToNarrow(Encoding::ToWindowsExtendedPath(destination)).c_str(), + std::ios::out | std::ios::trunc | std::ios::binary); +#else + kwsys::ofstream fout(destination.c_str(), + std::ios::out | std::ios::trunc | std::ios::binary); +#endif + if (!fout) { + return false; + } + + // This copy loop is very sensitive on certain platforms with + // slightly broken stream libraries (like HPUX). Normally, it is + // incorrect to not check the error condition on the fin.read() + // before using the data, but the fin.gcount() will be zero if an + // error occurred. Therefore, the loop should be safe everywhere. + while (fin) { + const int bufferSize = 4096; + char buffer[bufferSize]; + + fin.read(buffer, bufferSize); + if (fin.gcount()) { + fout.write(buffer, fin.gcount()); + } else { + break; + } + } + + // Make sure the operating system has finished writing the file + // before closing it. This will ensure the file is finished before + // the check below. + fout.flush(); + + fin.close(); + fout.close(); + + if (!fout) { + return false; + } + + return true; +} + +/** + * Clone the source file to the destination file + * + * If available, the Linux FICLONE ioctl is used to create a check + * copy-on-write clone of the source file. + * + * The method returns false for the following cases: + * - The code has not been compiled on Linux or the ioctl was unknown + * - The source and destination is on different file systems + * - The underlying filesystem does not support file cloning + * - An unspecified error occurred + */ +static bool CloneFileContent(const std::string& source, + const std::string& destination) +{ +#if defined(__linux) && defined(FICLONE) + int in = open(source.c_str(), O_RDONLY); + if (in < 0) { + return false; + } + + SystemTools::RemoveFile(destination); + + int out = + open(destination.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + if (out < 0) { + close(in); + return false; + } + + int result = ioctl(out, FICLONE, in); + close(in); + close(out); + + if (result < 0) { + return false; + } + + return true; +#else + (void)source; + (void)destination; + return false; +#endif +} + +/** + * Copy a file named by "source" to the file named by "destination". + */ +bool SystemTools::CopyFileAlways(const std::string& source, + const std::string& destination) +{ + mode_t perm = 0; + bool perms = SystemTools::GetPermissions(source, perm); + std::string real_destination = destination; + + if (SystemTools::FileIsDirectory(source)) { + SystemTools::MakeDirectory(destination); + } else { + // If destination is a directory, try to create a file with the same + // name as the source in that directory. + + std::string destination_dir; + if (SystemTools::FileIsDirectory(destination)) { + destination_dir = real_destination; + SystemTools::ConvertToUnixSlashes(real_destination); + real_destination += '/'; + std::string source_name = source; + real_destination += SystemTools::GetFilenameName(source_name); + } else { + destination_dir = SystemTools::GetFilenamePath(destination); + } + // If files are the same do not copy + if (SystemTools::SameFile(source, real_destination)) { + return true; + } + + // Create destination directory + + SystemTools::MakeDirectory(destination_dir); + + if (!CloneFileContent(source, real_destination)) { + // if cloning did not succeed, fall back to blockwise copy + if (!CopyFileContentBlockwise(source, real_destination)) { + return false; + } + } + } + if (perms) { + if (!SystemTools::SetPermissions(real_destination, perm)) { + return false; + } + } + return true; +} + +bool SystemTools::CopyAFile(const std::string& source, + const std::string& destination, bool always) +{ + if (always) { + return SystemTools::CopyFileAlways(source, destination); + } else { + return SystemTools::CopyFileIfDifferent(source, destination); + } +} + +/** + * Copy a directory content from "source" directory to the directory named by + * "destination". + */ +bool SystemTools::CopyADirectory(const std::string& source, + const std::string& destination, bool always) +{ + Directory dir; + if (dir.Load(source) == 0) { + return false; + } + size_t fileNum; + if (!SystemTools::MakeDirectory(destination)) { + return false; + } + for (fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum) { + if (strcmp(dir.GetFile(static_cast(fileNum)), ".") && + strcmp(dir.GetFile(static_cast(fileNum)), "..")) { + std::string fullPath = source; + fullPath += "/"; + fullPath += dir.GetFile(static_cast(fileNum)); + if (SystemTools::FileIsDirectory(fullPath)) { + std::string fullDestPath = destination; + fullDestPath += "/"; + fullDestPath += dir.GetFile(static_cast(fileNum)); + if (!SystemTools::CopyADirectory(fullPath, fullDestPath, always)) { + return false; + } + } else { + if (!SystemTools::CopyAFile(fullPath, destination, always)) { + return false; + } + } + } + } + + return true; +} + +// return size of file; also returns zero if no file exists +unsigned long SystemTools::FileLength(const std::string& filename) +{ + unsigned long length = 0; +#ifdef _WIN32 + WIN32_FILE_ATTRIBUTE_DATA fs; + if (GetFileAttributesExW(Encoding::ToWindowsExtendedPath(filename).c_str(), + GetFileExInfoStandard, &fs) != 0) { + /* To support the full 64-bit file size, use fs.nFileSizeHigh + * and fs.nFileSizeLow to construct the 64 bit size + + length = ((__int64)fs.nFileSizeHigh << 32) + fs.nFileSizeLow; + */ + length = static_cast(fs.nFileSizeLow); + } +#else + struct stat fs; + if (stat(filename.c_str(), &fs) == 0) { + length = static_cast(fs.st_size); + } +#endif + return length; +} + +int SystemTools::Strucmp(const char* l, const char* r) +{ + int lc; + int rc; + do { + lc = tolower(*l++); + rc = tolower(*r++); + } while (lc == rc && lc); + return lc - rc; +} + +// return file's modified time +long int SystemTools::ModifiedTime(const std::string& filename) +{ + long int mt = 0; +#ifdef _WIN32 + WIN32_FILE_ATTRIBUTE_DATA fs; + if (GetFileAttributesExW(Encoding::ToWindowsExtendedPath(filename).c_str(), + GetFileExInfoStandard, &fs) != 0) { + mt = windows_filetime_to_posix_time(fs.ftLastWriteTime); + } +#else + struct stat fs; + if (stat(filename.c_str(), &fs) == 0) { + mt = static_cast(fs.st_mtime); + } +#endif + return mt; +} + +// return file's creation time +long int SystemTools::CreationTime(const std::string& filename) +{ + long int ct = 0; +#ifdef _WIN32 + WIN32_FILE_ATTRIBUTE_DATA fs; + if (GetFileAttributesExW(Encoding::ToWindowsExtendedPath(filename).c_str(), + GetFileExInfoStandard, &fs) != 0) { + ct = windows_filetime_to_posix_time(fs.ftCreationTime); + } +#else + struct stat fs; + if (stat(filename.c_str(), &fs) == 0) { + ct = fs.st_ctime >= 0 ? static_cast(fs.st_ctime) : 0; + } +#endif + return ct; +} + +std::string SystemTools::GetLastSystemError() +{ + int e = errno; + return strerror(e); +} + +bool SystemTools::RemoveFile(const std::string& source) +{ +#ifdef _WIN32 + std::wstring const& ws = Encoding::ToWindowsExtendedPath(source); + if (DeleteFileW(ws.c_str())) { + return true; + } + DWORD err = GetLastError(); + if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) { + return true; + } + if (err != ERROR_ACCESS_DENIED) { + return false; + } + /* The file may be read-only. Try adding write permission. */ + mode_t mode; + if (!SystemTools::GetPermissions(source, mode) || + !SystemTools::SetPermissions(source, S_IWRITE)) { + SetLastError(err); + return false; + } + + const DWORD DIRECTORY_SOFT_LINK_ATTRS = + FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT; + DWORD attrs = GetFileAttributesW(ws.c_str()); + if (attrs != INVALID_FILE_ATTRIBUTES && + (attrs & DIRECTORY_SOFT_LINK_ATTRS) == DIRECTORY_SOFT_LINK_ATTRS && + RemoveDirectoryW(ws.c_str())) { + return true; + } + if (DeleteFileW(ws.c_str()) || GetLastError() == ERROR_FILE_NOT_FOUND || + GetLastError() == ERROR_PATH_NOT_FOUND) { + return true; + } + /* Try to restore the original permissions. */ + SystemTools::SetPermissions(source, mode); + SetLastError(err); + return false; +#else + return unlink(source.c_str()) == 0 || errno == ENOENT; +#endif +} + +bool SystemTools::RemoveADirectory(const std::string& source) +{ + // Add write permission to the directory so we can modify its + // content to remove files and directories from it. + mode_t mode; + if (SystemTools::GetPermissions(source, mode)) { +#if defined(_WIN32) && !defined(__CYGWIN__) + mode |= S_IWRITE; +#else + mode |= S_IWUSR; +#endif + SystemTools::SetPermissions(source, mode); + } + + Directory dir; + dir.Load(source); + size_t fileNum; + for (fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum) { + if (strcmp(dir.GetFile(static_cast(fileNum)), ".") && + strcmp(dir.GetFile(static_cast(fileNum)), "..")) { + std::string fullPath = source; + fullPath += "/"; + fullPath += dir.GetFile(static_cast(fileNum)); + if (SystemTools::FileIsDirectory(fullPath) && + !SystemTools::FileIsSymlink(fullPath)) { + if (!SystemTools::RemoveADirectory(fullPath)) { + return false; + } + } else { + if (!SystemTools::RemoveFile(fullPath)) { + return false; + } + } + } + } + + return (Rmdir(source) == 0); +} + +/** + */ +size_t SystemTools::GetMaximumFilePathLength() +{ + return KWSYS_SYSTEMTOOLS_MAXPATH; +} + +/** + * Find the file the given name. Searches the given path and then + * the system search path. Returns the full path to the file if it is + * found. Otherwise, the empty string is returned. + */ +std::string SystemToolsStatic::FindName( + const std::string& name, const std::vector& userPaths, + bool no_system_path) +{ + // Add the system search path to our path first + std::vector path; + if (!no_system_path) { + SystemTools::GetPath(path, "CMAKE_FILE_PATH"); + SystemTools::GetPath(path); + } + // now add the additional paths + path.reserve(path.size() + userPaths.size()); + path.insert(path.end(), userPaths.begin(), userPaths.end()); + // now look for the file + std::string tryPath; + for (std::string const& p : path) { + tryPath = p; + if (tryPath.empty() || tryPath.back() != '/') { + tryPath += '/'; + } + tryPath += name; + if (SystemTools::FileExists(tryPath)) { + return tryPath; + } + } + // Couldn't find the file. + return ""; +} + +/** + * Find the file the given name. Searches the given path and then + * the system search path. Returns the full path to the file if it is + * found. Otherwise, the empty string is returned. + */ +std::string SystemTools::FindFile(const std::string& name, + const std::vector& userPaths, + bool no_system_path) +{ + std::string tryPath = + SystemToolsStatic::FindName(name, userPaths, no_system_path); + if (!tryPath.empty() && !SystemTools::FileIsDirectory(tryPath)) { + return SystemTools::CollapseFullPath(tryPath); + } + // Couldn't find the file. + return ""; +} + +/** + * Find the directory the given name. Searches the given path and then + * the system search path. Returns the full path to the directory if it is + * found. Otherwise, the empty string is returned. + */ +std::string SystemTools::FindDirectory( + const std::string& name, const std::vector& userPaths, + bool no_system_path) +{ + std::string tryPath = + SystemToolsStatic::FindName(name, userPaths, no_system_path); + if (!tryPath.empty() && SystemTools::FileIsDirectory(tryPath)) { + return SystemTools::CollapseFullPath(tryPath); + } + // Couldn't find the file. + return ""; +} + +/** + * Find the executable with the given name. Searches the given path and then + * the system search path. Returns the full path to the executable if it is + * found. Otherwise, the empty string is returned. + */ +std::string SystemTools::FindProgram(const char* nameIn, + const std::vector& userPaths, + bool no_system_path) +{ + if (!nameIn || !*nameIn) { + return ""; + } + return SystemTools::FindProgram(std::string(nameIn), userPaths, + no_system_path); +} + +std::string SystemTools::FindProgram(const std::string& name, + const std::vector& userPaths, + bool no_system_path) +{ + std::string tryPath; + +#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) + std::vector extensions; + // check to see if the name already has a .xxx at + // the end of it + // on windows try .com then .exe + if (name.size() <= 3 || name[name.size() - 4] != '.') { + extensions.emplace_back(".com"); + extensions.emplace_back(".exe"); + + // first try with extensions if the os supports them + for (std::string const& ext : extensions) { + tryPath = name; + tryPath += ext; + if (SystemTools::FileExists(tryPath, true)) { + return SystemTools::CollapseFullPath(tryPath); + } + } + } +#endif + + // now try just the name + if (SystemTools::FileExists(name, true)) { + return SystemTools::CollapseFullPath(name); + } + // now construct the path + std::vector path; + // Add the system search path to our path. + if (!no_system_path) { + SystemTools::GetPath(path); + } + // now add the additional paths + path.reserve(path.size() + userPaths.size()); + path.insert(path.end(), userPaths.begin(), userPaths.end()); + // Add a trailing slash to all paths to aid the search process. + for (std::string& p : path) { + if (p.empty() || p.back() != '/') { + p += '/'; + } + } + // Try each path + for (std::string& p : path) { +#ifdef _WIN32 + // Remove double quotes from the path on windows + SystemTools::ReplaceString(p, "\"", ""); +#endif +#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) + // first try with extensions + for (std::string const& ext : extensions) { + tryPath = p; + tryPath += name; + tryPath += ext; + if (SystemTools::FileExists(tryPath, true)) { + return SystemTools::CollapseFullPath(tryPath); + } + } +#endif + // now try it without them + tryPath = p; + tryPath += name; + if (SystemTools::FileExists(tryPath, true)) { + return SystemTools::CollapseFullPath(tryPath); + } + } + // Couldn't find the program. + return ""; +} + +std::string SystemTools::FindProgram(const std::vector& names, + const std::vector& path, + bool noSystemPath) +{ + for (std::string const& name : names) { + // Try to find the program. + std::string result = SystemTools::FindProgram(name, path, noSystemPath); + if (!result.empty()) { + return result; + } + } + return ""; +} + +/** + * Find the library with the given name. Searches the given path and then + * the system search path. Returns the full path to the library if it is + * found. Otherwise, the empty string is returned. + */ +std::string SystemTools::FindLibrary(const std::string& name, + const std::vector& userPaths) +{ + // See if the executable exists as written. + if (SystemTools::FileExists(name, true)) { + return SystemTools::CollapseFullPath(name); + } + + // Add the system search path to our path. + std::vector path; + SystemTools::GetPath(path); + // now add the additional paths + path.reserve(path.size() + userPaths.size()); + path.insert(path.end(), userPaths.begin(), userPaths.end()); + // Add a trailing slash to all paths to aid the search process. + for (std::string& p : path) { + if (p.empty() || p.back() != '/') { + p += '/'; + } + } + std::string tryPath; + for (std::string const& p : path) { +#if defined(__APPLE__) + tryPath = p; + tryPath += name; + tryPath += ".framework"; + if (SystemTools::FileIsDirectory(tryPath)) { + return SystemTools::CollapseFullPath(tryPath); + } +#endif +#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__) + tryPath = p; + tryPath += name; + tryPath += ".lib"; + if (SystemTools::FileExists(tryPath, true)) { + return SystemTools::CollapseFullPath(tryPath); + } +#else + tryPath = p; + tryPath += "lib"; + tryPath += name; + tryPath += ".so"; + if (SystemTools::FileExists(tryPath, true)) { + return SystemTools::CollapseFullPath(tryPath); + } + tryPath = p; + tryPath += "lib"; + tryPath += name; + tryPath += ".a"; + if (SystemTools::FileExists(tryPath, true)) { + return SystemTools::CollapseFullPath(tryPath); + } + tryPath = p; + tryPath += "lib"; + tryPath += name; + tryPath += ".sl"; + if (SystemTools::FileExists(tryPath, true)) { + return SystemTools::CollapseFullPath(tryPath); + } + tryPath = p; + tryPath += "lib"; + tryPath += name; + tryPath += ".dylib"; + if (SystemTools::FileExists(tryPath, true)) { + return SystemTools::CollapseFullPath(tryPath); + } + tryPath = p; + tryPath += "lib"; + tryPath += name; + tryPath += ".dll"; + if (SystemTools::FileExists(tryPath, true)) { + return SystemTools::CollapseFullPath(tryPath); + } +#endif + } + + // Couldn't find the library. + return ""; +} + +std::string SystemTools::GetRealPath(const std::string& path, + std::string* errorMessage) +{ + std::string ret; + Realpath(path, ret, errorMessage); + return ret; +} + +bool SystemTools::FileIsDirectory(const std::string& inName) +{ + if (inName.empty()) { + return false; + } + size_t length = inName.size(); + const char* name = inName.c_str(); + + // Remove any trailing slash from the name except in a root component. + char local_buffer[KWSYS_SYSTEMTOOLS_MAXPATH]; + std::string string_buffer; + size_t last = length - 1; + if (last > 0 && (name[last] == '/' || name[last] == '\\') && + strcmp(name, "/") != 0 && name[last - 1] != ':') { + if (last < sizeof(local_buffer)) { + memcpy(local_buffer, name, last); + local_buffer[last] = '\0'; + name = local_buffer; + } else { + string_buffer.append(name, last); + name = string_buffer.c_str(); + } + } + +// Now check the file node type. +#if defined(_WIN32) + DWORD attr = + GetFileAttributesW(Encoding::ToWindowsExtendedPath(name).c_str()); + if (attr != INVALID_FILE_ATTRIBUTES) { + return (attr & FILE_ATTRIBUTE_DIRECTORY) != 0; +#else + struct stat fs; + if (stat(name, &fs) == 0) { + return S_ISDIR(fs.st_mode); +#endif + } else { + return false; + } +} + +bool SystemTools::FileIsSymlink(const std::string& name) +{ +#if defined(_WIN32) + std::wstring path = Encoding::ToWindowsExtendedPath(name); + DWORD attr = GetFileAttributesW(path.c_str()); + if (attr != INVALID_FILE_ATTRIBUTES) { + if ((attr & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { + // FILE_ATTRIBUTE_REPARSE_POINT means: + // * a file or directory that has an associated reparse point, or + // * a file that is a symbolic link. + HANDLE hFile = CreateFileW( + path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, nullptr); + if (hFile == INVALID_HANDLE_VALUE) { + return false; + } + byte buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + DWORD bytesReturned = 0; + if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, nullptr, 0, buffer, + MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bytesReturned, + nullptr)) { + CloseHandle(hFile); + // Since FILE_ATTRIBUTE_REPARSE_POINT is set this file must be + // a symbolic link if it is not a reparse point. + return GetLastError() == ERROR_NOT_A_REPARSE_POINT; + } + CloseHandle(hFile); + ULONG reparseTag = + reinterpret_cast(&buffer[0])->ReparseTag; + return (reparseTag == IO_REPARSE_TAG_SYMLINK) || + (reparseTag == IO_REPARSE_TAG_MOUNT_POINT); + } + return false; + } else { + return false; + } +#else + struct stat fs; + if (lstat(name.c_str(), &fs) == 0) { + return S_ISLNK(fs.st_mode); + } else { + return false; + } +#endif +} + +bool SystemTools::FileIsFIFO(const std::string& name) +{ +#if defined(_WIN32) + HANDLE hFile = + CreateFileW(Encoding::ToWide(name).c_str(), GENERIC_READ, FILE_SHARE_READ, + nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); + if (hFile == INVALID_HANDLE_VALUE) { + return false; + } + const DWORD type = GetFileType(hFile); + CloseHandle(hFile); + return type == FILE_TYPE_PIPE; +#else + struct stat fs; + if (lstat(name.c_str(), &fs) == 0) { + return S_ISFIFO(fs.st_mode); + } else { + return false; + } +#endif +} + +#if defined(_WIN32) && !defined(__CYGWIN__) +bool SystemTools::CreateSymlink(const std::string&, const std::string&) +{ + return false; +} +#else +bool SystemTools::CreateSymlink(const std::string& origName, + const std::string& newName) +{ + return symlink(origName.c_str(), newName.c_str()) >= 0; +} +#endif + +#if defined(_WIN32) && !defined(__CYGWIN__) +bool SystemTools::ReadSymlink(const std::string&, std::string&) +{ + return false; +} +#else +bool SystemTools::ReadSymlink(const std::string& newName, + std::string& origName) +{ + char buf[KWSYS_SYSTEMTOOLS_MAXPATH + 1]; + int count = static_cast( + readlink(newName.c_str(), buf, KWSYS_SYSTEMTOOLS_MAXPATH)); + if (count >= 0) { + // Add null-terminator. + buf[count] = 0; + origName = buf; + return true; + } else { + return false; + } +} +#endif + +int SystemTools::ChangeDirectory(const std::string& dir) +{ + return Chdir(dir); +} + +std::string SystemTools::GetCurrentWorkingDirectory(bool collapse) +{ + char buf[2048]; + const char* cwd = Getcwd(buf, 2048); + std::string path; + if (cwd) { + path = cwd; + } + if (collapse) { + return SystemTools::CollapseFullPath(path); + } + return path; +} + +std::string SystemTools::GetProgramPath(const std::string& in_name) +{ + std::string dir, file; + SystemTools::SplitProgramPath(in_name, dir, file); + return dir; +} + +bool SystemTools::SplitProgramPath(const std::string& in_name, + std::string& dir, std::string& file, bool) +{ + dir = in_name; + file = ""; + SystemTools::ConvertToUnixSlashes(dir); + + if (!SystemTools::FileIsDirectory(dir)) { + std::string::size_type slashPos = dir.rfind("/"); + if (slashPos != std::string::npos) { + file = dir.substr(slashPos + 1); + dir = dir.substr(0, slashPos); + } else { + file = dir; + dir = ""; + } + } + if (!(dir.empty()) && !SystemTools::FileIsDirectory(dir)) { + std::string oldDir = in_name; + SystemTools::ConvertToUnixSlashes(oldDir); + dir = in_name; + return false; + } + return true; +} + +bool SystemTools::FindProgramPath(const char* argv0, std::string& pathOut, + std::string& errorMsg, const char* exeName, + const char* buildDir, + const char* installPrefix) +{ + std::vector failures; + std::string self = argv0 ? argv0 : ""; + failures.push_back(self); + SystemTools::ConvertToUnixSlashes(self); + self = SystemTools::FindProgram(self); + if (!SystemTools::FileExists(self)) { + if (buildDir) { + std::string intdir = "."; +#ifdef CMAKE_INTDIR + intdir = CMAKE_INTDIR; +#endif + self = buildDir; + self += "/bin/"; + self += intdir; + self += "/"; + self += exeName; + self += SystemTools::GetExecutableExtension(); + } + } + if (installPrefix) { + if (!SystemTools::FileExists(self)) { + failures.push_back(self); + self = installPrefix; + self += "/bin/"; + self += exeName; + } + } + if (!SystemTools::FileExists(self)) { + failures.push_back(self); + std::ostringstream msg; + msg << "Can not find the command line program "; + if (exeName) { + msg << exeName; + } + msg << "\n"; + if (argv0) { + msg << " argv[0] = \"" << argv0 << "\"\n"; + } + msg << " Attempted paths:\n"; + for (std::string const& ff : failures) { + msg << " \"" << ff << "\"\n"; + } + errorMsg = msg.str(); + return false; + } + pathOut = self; + return true; +} + +std::string SystemTools::CollapseFullPath(const std::string& in_relative) +{ + return SystemTools::CollapseFullPath(in_relative, nullptr); +} + +#if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP +void SystemTools::AddTranslationPath(const std::string& a, + const std::string& b) +{ + std::string path_a = a; + std::string path_b = b; + SystemTools::ConvertToUnixSlashes(path_a); + SystemTools::ConvertToUnixSlashes(path_b); + // First check this is a directory path, since we don't want the table to + // grow too fat + if (SystemTools::FileIsDirectory(path_a)) { + // Make sure the path is a full path and does not contain no '..' + // Ken--the following code is incorrect. .. can be in a valid path + // for example /home/martink/MyHubba...Hubba/Src + if (SystemTools::FileIsFullPath(path_b) && + path_b.find("..") == std::string::npos) { + // Before inserting make sure path ends with '/' + if (!path_a.empty() && path_a.back() != '/') { + path_a += '/'; + } + if (!path_b.empty() && path_b.back() != '/') { + path_b += '/'; + } + if (!(path_a == path_b)) { + SystemTools::Statics->TranslationMap.insert( + SystemToolsStatic::StringMap::value_type(std::move(path_a), + std::move(path_b))); + } + } + } +} + +void SystemTools::AddKeepPath(const std::string& dir) +{ + std::string cdir; + Realpath(SystemTools::CollapseFullPath(dir), cdir); + SystemTools::AddTranslationPath(cdir, dir); +} + +void SystemTools::CheckTranslationPath(std::string& path) +{ + // Do not translate paths that are too short to have meaningful + // translations. + if (path.size() < 2) { + return; + } + + // Always add a trailing slash before translation. It does not + // matter if this adds an extra slash, but we do not want to + // translate part of a directory (like the foo part of foo-dir). + path += '/'; + + // In case a file was specified we still have to go through this: + // Now convert any path found in the table back to the one desired: + for (auto const& pair : SystemTools::Statics->TranslationMap) { + // We need to check of the path is a substring of the other path + if (path.find(pair.first) == 0) { + path = path.replace(0, pair.first.size(), pair.second); + } + } + + // Remove the trailing slash we added before. + path.pop_back(); +} +#endif + +static void SystemToolsAppendComponents( + std::vector& out_components, + std::vector::iterator first, + std::vector::iterator last) +{ + static const std::string up = ".."; + static const std::string cur = "."; + for (std::vector::const_iterator i = first; i != last; ++i) { + if (*i == up) { + // Remove the previous component if possible. Ignore ../ components + // that try to go above the root. Keep ../ components if they are + // at the beginning of a relative path (base path is relative). + if (out_components.size() > 1 && out_components.back() != up) { + out_components.resize(out_components.size() - 1); + } else if (!out_components.empty() && out_components[0].empty()) { + out_components.emplace_back(std::move(*i)); + } + } else if (!i->empty() && *i != cur) { + out_components.emplace_back(std::move(*i)); + } + } +} + +std::string SystemTools::CollapseFullPath(const std::string& in_path, + const char* in_base) +{ + // Use the current working directory as a base path. + char buf[2048]; + const char* res_in_base = in_base; + if (!res_in_base) { + if (const char* cwd = Getcwd(buf, 2048)) { + res_in_base = cwd; + } else { + res_in_base = ""; + } + } + + return SystemTools::CollapseFullPath(in_path, std::string(res_in_base)); +} + +std::string SystemTools::CollapseFullPath(const std::string& in_path, + const std::string& in_base) +{ + // Collect the output path components. + std::vector out_components; + + // Split the input path components. + std::vector path_components; + SystemTools::SplitPath(in_path, path_components); + out_components.reserve(path_components.size()); + + // If the input path is relative, start with a base path. + if (path_components[0].empty()) { + std::vector base_components; + // Use the given base path. + SystemTools::SplitPath(in_base, base_components); + + // Append base path components to the output path. + out_components.push_back(base_components[0]); + SystemToolsAppendComponents(out_components, base_components.begin() + 1, + base_components.end()); + } + + // Append input path components to the output path. + SystemToolsAppendComponents(out_components, path_components.begin(), + path_components.end()); + + // Transform the path back to a string. + std::string newPath = SystemTools::JoinPath(out_components); + +#if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP + // Update the translation table with this potentially new path. I am not + // sure why this line is here, it seems really questionable, but yet I + // would put good money that if I remove it something will break, basically + // from what I can see it created a mapping from the collapsed path, to be + // replaced by the input path, which almost completely does the opposite of + // this function, the only thing preventing this from happening a lot is + // that if the in_path has a .. in it, then it is not added to the + // translation table. So for most calls this either does nothing due to the + // .. or it adds a translation between identical paths as nothing was + // collapsed, so I am going to try to comment it out, and see what hits the + // fan, hopefully quickly. + // Commented out line below: + // SystemTools::AddTranslationPath(newPath, in_path); + + SystemTools::CheckTranslationPath(newPath); +#endif +#ifdef _WIN32 + newPath = SystemTools::Statics->GetActualCaseForPathCached(newPath); + SystemTools::ConvertToUnixSlashes(newPath); +#endif + // Return the reconstructed path. + return newPath; +} + +// compute the relative path from here to there +std::string SystemTools::RelativePath(const std::string& local, + const std::string& remote) +{ + if (!SystemTools::FileIsFullPath(local)) { + return ""; + } + if (!SystemTools::FileIsFullPath(remote)) { + return ""; + } + + std::string l = SystemTools::CollapseFullPath(local); + std::string r = SystemTools::CollapseFullPath(remote); + + // split up both paths into arrays of strings using / as a separator + std::vector localSplit = SystemTools::SplitString(l, '/', true); + std::vector remoteSplit = + SystemTools::SplitString(r, '/', true); + std::vector + commonPath; // store shared parts of path in this array + std::vector finalPath; // store the final relative path here + // count up how many matching directory names there are from the start + unsigned int sameCount = 0; + while (((sameCount <= (localSplit.size() - 1)) && + (sameCount <= (remoteSplit.size() - 1))) && +// for Windows and Apple do a case insensitive string compare +#if defined(_WIN32) || defined(__APPLE__) + SystemTools::Strucmp(localSplit[sameCount].c_str(), + remoteSplit[sameCount].c_str()) == 0 +#else + localSplit[sameCount] == remoteSplit[sameCount] +#endif + ) { + // put the common parts of the path into the commonPath array + commonPath.push_back(localSplit[sameCount]); + // erase the common parts of the path from the original path arrays + localSplit[sameCount] = ""; + remoteSplit[sameCount] = ""; + sameCount++; + } + + // If there is nothing in common at all then just return the full + // path. This is the case only on windows when the paths have + // different drive letters. On unix two full paths always at least + // have the root "/" in common so we will return a relative path + // that passes through the root directory. + if (sameCount == 0) { + return remote; + } + + // for each entry that is not common in the local path + // add a ../ to the finalpath array, this gets us out of the local + // path into the remote dir + for (std::string const& lp : localSplit) { + if (!lp.empty()) { + finalPath.emplace_back("../"); + } + } + // for each entry that is not common in the remote path add it + // to the final path. + for (std::string const& rp : remoteSplit) { + if (!rp.empty()) { + finalPath.push_back(rp); + } + } + std::string relativePath; // result string + // now turn the array of directories into a unix path by puttint / + // between each entry that does not already have one + for (std::string const& fp : finalPath) { + if (!relativePath.empty() && relativePath.back() != '/') { + relativePath += '/'; + } + relativePath += fp; + } + return relativePath; +} + +std::string SystemTools::GetActualCaseForPath(const std::string& p) +{ +#ifdef _WIN32 + return SystemToolsStatic::GetCasePathName(p); +#else + return p; +#endif +} + +const char* SystemTools::SplitPathRootComponent(const std::string& p, + std::string* root) +{ + // Identify the root component. + const char* c = p.c_str(); + if ((c[0] == '/' && c[1] == '/') || (c[0] == '\\' && c[1] == '\\')) { + // Network path. + if (root) { + *root = "//"; + } + c += 2; + } else if (c[0] == '/' || c[0] == '\\') { + // Unix path (or Windows path w/out drive letter). + if (root) { + *root = "/"; + } + c += 1; + } else if (c[0] && c[1] == ':' && (c[2] == '/' || c[2] == '\\')) { + // Windows path. + if (root) { + (*root) = "_:/"; + (*root)[0] = c[0]; + } + c += 3; + } else if (c[0] && c[1] == ':') { + // Path relative to a windows drive working directory. + if (root) { + (*root) = "_:"; + (*root)[0] = c[0]; + } + c += 2; + } else if (c[0] == '~') { + // Home directory. The returned root should always have a + // trailing slash so that appending components as + // c[0]c[1]/c[2]/... works. The remaining path returned should + // skip the first slash if it exists: + // + // "~" : root = "~/" , return "" + // "~/ : root = "~/" , return "" + // "~/x : root = "~/" , return "x" + // "~u" : root = "~u/", return "" + // "~u/" : root = "~u/", return "" + // "~u/x" : root = "~u/", return "x" + size_t n = 1; + while (c[n] && c[n] != '/') { + ++n; + } + if (root) { + root->assign(c, n); + *root += '/'; + } + if (c[n] == '/') { + ++n; + } + c += n; + } else { + // Relative path. + if (root) { + *root = ""; + } + } + + // Return the remaining path. + return c; +} + +void SystemTools::SplitPath(const std::string& p, + std::vector& components, + bool expand_home_dir) +{ + const char* c; + components.clear(); + + // Identify the root component. + { + std::string root; + c = SystemTools::SplitPathRootComponent(p, &root); + + // Expand home directory references if requested. + if (expand_home_dir && !root.empty() && root[0] == '~') { + std::string homedir; + root = root.substr(0, root.size() - 1); + if (root.size() == 1) { +#if defined(_WIN32) && !defined(__CYGWIN__) + if (!SystemTools::GetEnv("USERPROFILE", homedir)) +#endif + SystemTools::GetEnv("HOME", homedir); + } +#ifdef HAVE_GETPWNAM + else if (passwd* pw = getpwnam(root.c_str() + 1)) { + if (pw->pw_dir) { + homedir = pw->pw_dir; + } + } +#endif + if (!homedir.empty() && + (homedir.back() == '/' || homedir.back() == '\\')) { + homedir.resize(homedir.size() - 1); + } + SystemTools::SplitPath(homedir, components); + } else { + components.push_back(root); + } + } + + // Parse the remaining components. + const char* first = c; + const char* last = first; + for (; *last; ++last) { + if (*last == '/' || *last == '\\') { + // End of a component. Save it. + components.push_back(std::string(first, last)); + first = last + 1; + } + } + + // Save the last component unless there were no components. + if (last != c) { + components.push_back(std::string(first, last)); + } +} + +std::string SystemTools::JoinPath(const std::vector& components) +{ + return SystemTools::JoinPath(components.begin(), components.end()); +} + +std::string SystemTools::JoinPath( + std::vector::const_iterator first, + std::vector::const_iterator last) +{ + // Construct result in a single string. + std::string result; + size_t len = 0; + for (std::vector::const_iterator i = first; i != last; ++i) { + len += 1 + i->size(); + } + result.reserve(len); + + // The first two components do not add a slash. + if (first != last) { + result.append(*first++); + } + if (first != last) { + result.append(*first++); + } + + // All remaining components are always separated with a slash. + while (first != last) { + result.push_back('/'); + result.append((*first++)); + } + + // Return the concatenated result. + return result; +} + +bool SystemTools::ComparePath(const std::string& c1, const std::string& c2) +{ +#if defined(_WIN32) || defined(__APPLE__) +# ifdef _MSC_VER + return _stricmp(c1.c_str(), c2.c_str()) == 0; +# elif defined(__APPLE__) || defined(__GNUC__) + return strcasecmp(c1.c_str(), c2.c_str()) == 0; +# else + return SystemTools::Strucmp(c1.c_str(), c2.c_str()) == 0; +# endif +#else + return c1 == c2; +#endif +} + +bool SystemTools::Split(const std::string& str, + std::vector& lines, char separator) +{ + std::string data(str); + std::string::size_type lpos = 0; + while (lpos < data.length()) { + std::string::size_type rpos = data.find_first_of(separator, lpos); + if (rpos == std::string::npos) { + // String ends at end of string without a separator. + lines.push_back(data.substr(lpos)); + return false; + } else { + // String ends in a separator, remove the character. + lines.push_back(data.substr(lpos, rpos - lpos)); + } + lpos = rpos + 1; + } + return true; +} + +bool SystemTools::Split(const std::string& str, + std::vector& lines) +{ + std::string data(str); + std::string::size_type lpos = 0; + while (lpos < data.length()) { + std::string::size_type rpos = data.find_first_of('\n', lpos); + if (rpos == std::string::npos) { + // Line ends at end of string without a newline. + lines.push_back(data.substr(lpos)); + return false; + } + if ((rpos > lpos) && (data[rpos - 1] == '\r')) { + // Line ends in a "\r\n" pair, remove both characters. + lines.push_back(data.substr(lpos, (rpos - 1) - lpos)); + } else { + // Line ends in a "\n", remove the character. + lines.push_back(data.substr(lpos, rpos - lpos)); + } + lpos = rpos + 1; + } + return true; +} + +/** + * Return path of a full filename (no trailing slashes). + * Warning: returned path is converted to Unix slashes format. + */ +std::string SystemTools::GetFilenamePath(const std::string& filename) +{ + std::string fn = filename; + SystemTools::ConvertToUnixSlashes(fn); + + std::string::size_type slash_pos = fn.rfind("/"); + if (slash_pos != std::string::npos) { + std::string ret = fn.substr(0, slash_pos); + if (ret.size() == 2 && ret[1] == ':') { + return ret + '/'; + } + if (ret.empty()) { + return "/"; + } + return ret; + } else { + return ""; + } +} + +/** + * Return file name of a full filename (i.e. file name without path). + */ +std::string SystemTools::GetFilenameName(const std::string& filename) +{ +#if defined(_WIN32) || defined(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES) + const char* separators = "/\\"; +#else + char separators = '/'; +#endif + std::string::size_type slash_pos = filename.find_last_of(separators); + if (slash_pos != std::string::npos) { + return filename.substr(slash_pos + 1); + } else { + return filename; + } +} + +/** + * Return file extension of a full filename (dot included). + * Warning: this is the longest extension (for example: .tar.gz) + */ +std::string SystemTools::GetFilenameExtension(const std::string& filename) +{ + std::string name = SystemTools::GetFilenameName(filename); + std::string::size_type dot_pos = name.find('.'); + if (dot_pos != std::string::npos) { + return name.substr(dot_pos); + } else { + return ""; + } +} + +/** + * Return file extension of a full filename (dot included). + * Warning: this is the shortest extension (for example: .gz of .tar.gz) + */ +std::string SystemTools::GetFilenameLastExtension(const std::string& filename) +{ + std::string name = SystemTools::GetFilenameName(filename); + std::string::size_type dot_pos = name.rfind('.'); + if (dot_pos != std::string::npos) { + return name.substr(dot_pos); + } else { + return ""; + } +} + +/** + * Return file name without extension of a full filename (i.e. without path). + * Warning: it considers the longest extension (for example: .tar.gz) + */ +std::string SystemTools::GetFilenameWithoutExtension( + const std::string& filename) +{ + std::string name = SystemTools::GetFilenameName(filename); + std::string::size_type dot_pos = name.find('.'); + if (dot_pos != std::string::npos) { + return name.substr(0, dot_pos); + } else { + return name; + } +} + +/** + * Return file name without extension of a full filename (i.e. without path). + * Warning: it considers the last extension (for example: removes .gz + * from .tar.gz) + */ +std::string SystemTools::GetFilenameWithoutLastExtension( + const std::string& filename) +{ + std::string name = SystemTools::GetFilenameName(filename); + std::string::size_type dot_pos = name.rfind('.'); + if (dot_pos != std::string::npos) { + return name.substr(0, dot_pos); + } else { + return name; + } +} + +bool SystemTools::FileHasSignature(const char* filename, const char* signature, + long offset) +{ + if (!filename || !signature) { + return false; + } + + FILE* fp = Fopen(filename, "rb"); + if (!fp) { + return false; + } + + fseek(fp, offset, SEEK_SET); + + bool res = false; + size_t signature_len = strlen(signature); + char* buffer = new char[signature_len]; + + if (fread(buffer, 1, signature_len, fp) == signature_len) { + res = (!strncmp(buffer, signature, signature_len) ? true : false); + } + + delete[] buffer; + + fclose(fp); + return res; +} + +SystemTools::FileTypeEnum SystemTools::DetectFileType(const char* filename, + unsigned long length, + double percent_bin) +{ + if (!filename || percent_bin < 0) { + return SystemTools::FileTypeUnknown; + } + + if (SystemTools::FileIsDirectory(filename)) { + return SystemTools::FileTypeUnknown; + } + + FILE* fp = Fopen(filename, "rb"); + if (!fp) { + return SystemTools::FileTypeUnknown; + } + + // Allocate buffer and read bytes + + unsigned char* buffer = new unsigned char[length]; + size_t read_length = fread(buffer, 1, length, fp); + fclose(fp); + if (read_length == 0) { + delete[] buffer; + return SystemTools::FileTypeUnknown; + } + + // Loop over contents and count + + size_t text_count = 0; + + const unsigned char* ptr = buffer; + const unsigned char* buffer_end = buffer + read_length; + + while (ptr != buffer_end) { + if ((*ptr >= 0x20 && *ptr <= 0x7F) || *ptr == '\n' || *ptr == '\r' || + *ptr == '\t') { + text_count++; + } + ptr++; + } + + delete[] buffer; + + double current_percent_bin = (static_cast(read_length - text_count) / + static_cast(read_length)); + + if (current_percent_bin >= percent_bin) { + return SystemTools::FileTypeBinary; + } + + return SystemTools::FileTypeText; +} + +bool SystemTools::LocateFileInDir(const char* filename, const char* dir, + std::string& filename_found, + int try_filename_dirs) +{ + if (!filename || !dir) { + return false; + } + + // Get the basename of 'filename' + + std::string filename_base = SystemTools::GetFilenameName(filename); + + // Check if 'dir' is really a directory + // If win32 and matches something like C:, accept it as a dir + + std::string real_dir; + if (!SystemTools::FileIsDirectory(dir)) { +#if defined(_WIN32) + size_t dir_len = strlen(dir); + if (dir_len < 2 || dir[dir_len - 1] != ':') { +#endif + real_dir = SystemTools::GetFilenamePath(dir); + dir = real_dir.c_str(); +#if defined(_WIN32) + } +#endif + } + + // Try to find the file in 'dir' + + bool res = false; + if (!filename_base.empty() && dir) { + size_t dir_len = strlen(dir); + int need_slash = + (dir_len && dir[dir_len - 1] != '/' && dir[dir_len - 1] != '\\'); + + std::string temp = dir; + if (need_slash) { + temp += "/"; + } + temp += filename_base; + + if (SystemTools::FileExists(temp)) { + res = true; + filename_found = temp; + } + + // If not found, we can try harder by appending part of the file to + // to the directory to look inside. + // Example: if we were looking for /foo/bar/yo.txt in /d1/d2, then + // try to find yo.txt in /d1/d2/bar, then /d1/d2/foo/bar, etc. + + else if (try_filename_dirs) { + std::string filename_dir(filename); + std::string filename_dir_base; + std::string filename_dir_bases; + do { + filename_dir = SystemTools::GetFilenamePath(filename_dir); + filename_dir_base = SystemTools::GetFilenameName(filename_dir); +#if defined(_WIN32) + if (filename_dir_base.empty() || filename_dir_base.back() == ':') +#else + if (filename_dir_base.empty()) +#endif + { + break; + } + + filename_dir_bases = filename_dir_base + "/" + filename_dir_bases; + + temp = dir; + if (need_slash) { + temp += "/"; + } + temp += filename_dir_bases; + + res = SystemTools::LocateFileInDir(filename_base.c_str(), temp.c_str(), + filename_found, 0); + + } while (!res && !filename_dir_base.empty()); + } + } + + return res; +} + +bool SystemTools::FileIsFullPath(const std::string& in_name) +{ + return SystemToolsStatic::FileIsFullPath(in_name.c_str(), in_name.size()); +} + +bool SystemTools::FileIsFullPath(const char* in_name) +{ + return SystemToolsStatic::FileIsFullPath( + in_name, in_name[0] ? (in_name[1] ? 2 : 1) : 0); +} + +bool SystemToolsStatic::FileIsFullPath(const char* in_name, size_t len) +{ +#if defined(_WIN32) || defined(__CYGWIN__) + // On Windows, the name must be at least two characters long. + if (len < 2) { + return false; + } + if (in_name[1] == ':') { + return true; + } + if (in_name[0] == '\\') { + return true; + } +#else + // On UNIX, the name must be at least one character long. + if (len < 1) { + return false; + } +#endif +#if !defined(_WIN32) + if (in_name[0] == '~') { + return true; + } +#endif + // On UNIX, the name must begin in a '/'. + // On Windows, if the name begins in a '/', then it is a full + // network path. + if (in_name[0] == '/') { + return true; + } + return false; +} + +bool SystemTools::GetShortPath(const std::string& path, std::string& shortPath) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + std::string tempPath = path; // create a buffer + + // if the path passed in has quotes around it, first remove the quotes + if (!path.empty() && path[0] == '"' && path.back() == '"') { + tempPath = path.substr(1, path.length() - 2); + } + + std::wstring wtempPath = Encoding::ToWide(tempPath); + DWORD ret = GetShortPathNameW(wtempPath.c_str(), nullptr, 0); + std::vector buffer(ret); + if (ret != 0) { + ret = GetShortPathNameW(wtempPath.c_str(), &buffer[0], + static_cast(buffer.size())); + } + + if (ret == 0) { + return false; + } else { + shortPath = Encoding::ToNarrow(&buffer[0]); + return true; + } +#else + shortPath = path; + return true; +#endif +} + +std::string SystemTools::GetCurrentDateTime(const char* format) +{ + char buf[1024]; + time_t t; + time(&t); + strftime(buf, sizeof(buf), format, localtime(&t)); + return std::string(buf); +} + +std::string SystemTools::MakeCidentifier(const std::string& s) +{ + std::string str(s); + if (str.find_first_of("0123456789") == 0) { + str = "_" + str; + } + + std::string permited_chars("_" + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789"); + std::string::size_type pos = 0; + while ((pos = str.find_first_not_of(permited_chars, pos)) != + std::string::npos) { + str[pos] = '_'; + } + return str; +} + +// Convenience function around std::getline which removes a trailing carriage +// return and can truncate the buffer as needed. Returns true +// if any data were read before the end-of-file was reached. +bool SystemTools::GetLineFromStream(std::istream& is, std::string& line, + bool* has_newline /* = 0 */, + long sizeLimit /* = -1 */) +{ + // Start with an empty line. + line = ""; + + // Early short circuit return if stream is no good. Just return + // false and the empty line. (Probably means caller tried to + // create a file stream with a non-existent file name...) + // + if (!is) { + if (has_newline) { + *has_newline = false; + } + return false; + } + + std::getline(is, line); + bool haveData = !line.empty() || !is.eof(); + if (!line.empty()) { + // Avoid storing a carriage return character. + if (line.back() == '\r') { + line.resize(line.size() - 1); + } + + // if we read too much then truncate the buffer + if (sizeLimit >= 0 && line.size() >= static_cast(sizeLimit)) { + line.resize(sizeLimit); + } + } + + // Return the results. + if (has_newline) { + *has_newline = !is.eof(); + } + return haveData; +} + +int SystemTools::GetTerminalWidth() +{ + int width = -1; +#ifdef HAVE_TTY_INFO + struct winsize ws; + std::string columns; /* Unix98 environment variable */ + if (ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col > 0 && ws.ws_row > 0) { + width = ws.ws_col; + } + if (!isatty(STDOUT_FILENO)) { + width = -1; + } + if (SystemTools::GetEnv("COLUMNS", columns) && !columns.empty()) { + long t; + char* endptr; + t = strtol(columns.c_str(), &endptr, 0); + if (endptr && !*endptr && (t > 0) && (t < 1000)) { + width = static_cast(t); + } + } + if (width < 9) { + width = -1; + } +#endif + return width; +} + +bool SystemTools::GetPermissions(const char* file, mode_t& mode) +{ + if (!file) { + return false; + } + return SystemTools::GetPermissions(std::string(file), mode); +} + +bool SystemTools::GetPermissions(const std::string& file, mode_t& mode) +{ +#if defined(_WIN32) + DWORD attr = + GetFileAttributesW(Encoding::ToWindowsExtendedPath(file).c_str()); + if (attr == INVALID_FILE_ATTRIBUTES) { + return false; + } + if ((attr & FILE_ATTRIBUTE_READONLY) != 0) { + mode = (_S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6)); + } else { + mode = (_S_IWRITE | (_S_IWRITE >> 3) | (_S_IWRITE >> 6)) | + (_S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6)); + } + if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { + mode |= S_IFDIR | (_S_IEXEC | (_S_IEXEC >> 3) | (_S_IEXEC >> 6)); + } else { + mode |= S_IFREG; + } + size_t dotPos = file.rfind('.'); + const char* ext = dotPos == std::string::npos ? 0 : (file.c_str() + dotPos); + if (ext && + (Strucmp(ext, ".exe") == 0 || Strucmp(ext, ".com") == 0 || + Strucmp(ext, ".cmd") == 0 || Strucmp(ext, ".bat") == 0)) { + mode |= (_S_IEXEC | (_S_IEXEC >> 3) | (_S_IEXEC >> 6)); + } +#else + struct stat st; + if (stat(file.c_str(), &st) < 0) { + return false; + } + mode = st.st_mode; +#endif + return true; +} + +bool SystemTools::SetPermissions(const char* file, mode_t mode, + bool honor_umask) +{ + if (!file) { + return false; + } + return SystemTools::SetPermissions(std::string(file), mode, honor_umask); +} + +bool SystemTools::SetPermissions(const std::string& file, mode_t mode, + bool honor_umask) +{ + if (!SystemTools::PathExists(file)) { + return false; + } + if (honor_umask) { + mode_t currentMask = umask(0); + umask(currentMask); + mode &= ~currentMask; + } +#ifdef _WIN32 + if (_wchmod(Encoding::ToWindowsExtendedPath(file).c_str(), mode) < 0) +#else + if (chmod(file.c_str(), mode) < 0) +#endif + { + return false; + } + + return true; +} + +std::string SystemTools::GetParentDirectory(const std::string& fileOrDir) +{ + return SystemTools::GetFilenamePath(fileOrDir); +} + +bool SystemTools::IsSubDirectory(const std::string& cSubdir, + const std::string& cDir) +{ + if (cDir.empty()) { + return false; + } + std::string subdir = cSubdir; + std::string dir = cDir; + SystemTools::ConvertToUnixSlashes(subdir); + SystemTools::ConvertToUnixSlashes(dir); + if (subdir.size() <= dir.size() || dir.empty()) { + return false; + } + bool isRootPath = dir.back() == '/'; // like "/" or "C:/" + size_t expectedSlashPosition = isRootPath ? dir.size() - 1u : dir.size(); + if (subdir[expectedSlashPosition] != '/') { + return false; + } + std::string s = subdir.substr(0, dir.size()); + return SystemTools::ComparePath(s, dir); +} + +void SystemTools::Delay(unsigned int msec) +{ +#ifdef _WIN32 + Sleep(msec); +#else + // The sleep function gives 1 second resolution and the usleep + // function gives 1e-6 second resolution but on some platforms has a + // maximum sleep time of 1 second. This could be re-implemented to + // use select with masked signals or pselect to mask signals + // atomically. If select is given empty sets and zero as the max + // file descriptor but a non-zero timeout it can be used to block + // for a precise amount of time. + if (msec >= 1000) { + sleep(msec / 1000); + usleep((msec % 1000) * 1000); + } else { + usleep(msec * 1000); + } +#endif +} + +std::string SystemTools::GetOperatingSystemNameAndVersion() +{ + std::string res; + +#ifdef _WIN32 + char buffer[256]; + + OSVERSIONINFOEXA osvi; + BOOL bOsVersionInfoEx; + + ZeroMemory(&osvi, sizeof(osvi)); + osvi.dwOSVersionInfoSize = sizeof(osvi); + +# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx +# pragma warning(push) +# ifdef __INTEL_COMPILER +# pragma warning(disable : 1478) +# elif defined __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdeprecated-declarations" +# else +# pragma warning(disable : 4996) +# endif +# endif + bOsVersionInfoEx = GetVersionExA((OSVERSIONINFOA*)&osvi); + if (!bOsVersionInfoEx) { + return 0; + } +# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx +# ifdef __clang__ +# pragma clang diagnostic pop +# else +# pragma warning(pop) +# endif +# endif + + switch (osvi.dwPlatformId) { + // Test for the Windows NT product family. + + case VER_PLATFORM_WIN32_NT: + + // Test for the specific product family. + if (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0) { + if (osvi.wProductType == VER_NT_WORKSTATION) { + res += "Microsoft Windows 10"; + } else { + res += "Microsoft Windows Server 2016 family"; + } + } + + if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 3) { + if (osvi.wProductType == VER_NT_WORKSTATION) { + res += "Microsoft Windows 8.1"; + } else { + res += "Microsoft Windows Server 2012 R2 family"; + } + } + + if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 2) { + if (osvi.wProductType == VER_NT_WORKSTATION) { + res += "Microsoft Windows 8"; + } else { + res += "Microsoft Windows Server 2012 family"; + } + } + + if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1) { + if (osvi.wProductType == VER_NT_WORKSTATION) { + res += "Microsoft Windows 7"; + } else { + res += "Microsoft Windows Server 2008 R2 family"; + } + } + + if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0) { + if (osvi.wProductType == VER_NT_WORKSTATION) { + res += "Microsoft Windows Vista"; + } else { + res += "Microsoft Windows Server 2008 family"; + } + } + + if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) { + res += "Microsoft Windows Server 2003 family"; + } + + if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) { + res += "Microsoft Windows XP"; + } + + if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) { + res += "Microsoft Windows 2000"; + } + + if (osvi.dwMajorVersion <= 4) { + res += "Microsoft Windows NT"; + } + + // Test for specific product on Windows NT 4.0 SP6 and later. + + if (bOsVersionInfoEx) { + // Test for the workstation type. + + if (osvi.wProductType == VER_NT_WORKSTATION) { + if (osvi.dwMajorVersion == 4) { + res += " Workstation 4.0"; + } else if (osvi.dwMajorVersion == 5) { + if (osvi.wSuiteMask & VER_SUITE_PERSONAL) { + res += " Home Edition"; + } else { + res += " Professional"; + } + } + } + + // Test for the server type. + + else if (osvi.wProductType == VER_NT_SERVER) { + if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) { + if (osvi.wSuiteMask & VER_SUITE_DATACENTER) { + res += " Datacenter Edition"; + } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) { + res += " Enterprise Edition"; + } else if (osvi.wSuiteMask == VER_SUITE_BLADE) { + res += " Web Edition"; + } else { + res += " Standard Edition"; + } + } + + else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) { + if (osvi.wSuiteMask & VER_SUITE_DATACENTER) { + res += " Datacenter Server"; + } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) { + res += " Advanced Server"; + } else { + res += " Server"; + } + } + + else if (osvi.dwMajorVersion <= 4) // Windows NT 4.0 + { + if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) { + res += " Server 4.0, Enterprise Edition"; + } else { + res += " Server 4.0"; + } + } + } + } + + // Test for specific product on Windows NT 4.0 SP5 and earlier + + else { + HKEY hKey; +# define BUFSIZE 80 + wchar_t szProductType[BUFSIZE]; + DWORD dwBufLen = BUFSIZE; + LONG lRet; + + lRet = + RegOpenKeyExW(HKEY_LOCAL_MACHINE, + L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions", + 0, KEY_QUERY_VALUE, &hKey); + if (lRet != ERROR_SUCCESS) { + return 0; + } + + lRet = RegQueryValueExW(hKey, L"ProductType", nullptr, nullptr, + (LPBYTE)szProductType, &dwBufLen); + + if ((lRet != ERROR_SUCCESS) || (dwBufLen > BUFSIZE)) { + return 0; + } + + RegCloseKey(hKey); + + if (lstrcmpiW(L"WINNT", szProductType) == 0) { + res += " Workstation"; + } + if (lstrcmpiW(L"LANMANNT", szProductType) == 0) { + res += " Server"; + } + if (lstrcmpiW(L"SERVERNT", szProductType) == 0) { + res += " Advanced Server"; + } + + res += " "; + sprintf(buffer, "%ld", osvi.dwMajorVersion); + res += buffer; + res += "."; + sprintf(buffer, "%ld", osvi.dwMinorVersion); + res += buffer; + } + + // Display service pack (if any) and build number. + + if (osvi.dwMajorVersion == 4 && + lstrcmpiA(osvi.szCSDVersion, "Service Pack 6") == 0) { + HKEY hKey; + LONG lRet; + + // Test for SP6 versus SP6a. + + lRet = RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q246009", + 0, KEY_QUERY_VALUE, &hKey); + + if (lRet == ERROR_SUCCESS) { + res += " Service Pack 6a (Build "; + sprintf(buffer, "%ld", osvi.dwBuildNumber & 0xFFFF); + res += buffer; + res += ")"; + } else // Windows NT 4.0 prior to SP6a + { + res += " "; + res += osvi.szCSDVersion; + res += " (Build "; + sprintf(buffer, "%ld", osvi.dwBuildNumber & 0xFFFF); + res += buffer; + res += ")"; + } + + RegCloseKey(hKey); + } else // Windows NT 3.51 and earlier or Windows 2000 and later + { + res += " "; + res += osvi.szCSDVersion; + res += " (Build "; + sprintf(buffer, "%ld", osvi.dwBuildNumber & 0xFFFF); + res += buffer; + res += ")"; + } + + break; + + // Test for the Windows 95 product family. + + case VER_PLATFORM_WIN32_WINDOWS: + + if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) { + res += "Microsoft Windows 95"; + if (osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B') { + res += " OSR2"; + } + } + + if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10) { + res += "Microsoft Windows 98"; + if (osvi.szCSDVersion[1] == 'A') { + res += " SE"; + } + } + + if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90) { + res += "Microsoft Windows Millennium Edition"; + } + break; + + case VER_PLATFORM_WIN32s: + + res += "Microsoft Win32s"; + break; + } +#endif + + return res; +} + +bool SystemTools::ParseURLProtocol(const std::string& URL, + std::string& protocol, + std::string& dataglom) +{ + // match 0 entire url + // match 1 protocol + // match 2 dataglom following protocol:// + kwsys::RegularExpression urlRe(VTK_URL_PROTOCOL_REGEX); + + if (!urlRe.find(URL)) + return false; + + protocol = urlRe.match(1); + dataglom = urlRe.match(2); + + return true; +} + +bool SystemTools::ParseURL(const std::string& URL, std::string& protocol, + std::string& username, std::string& password, + std::string& hostname, std::string& dataport, + std::string& database) +{ + kwsys::RegularExpression urlRe(VTK_URL_REGEX); + if (!urlRe.find(URL)) + return false; + + // match 0 URL + // match 1 protocol + // match 2 mangled user + // match 3 username + // match 4 mangled password + // match 5 password + // match 6 hostname + // match 7 mangled port + // match 8 dataport + // match 9 database name + + protocol = urlRe.match(1); + username = urlRe.match(3); + password = urlRe.match(5); + hostname = urlRe.match(6); + dataport = urlRe.match(8); + database = urlRe.match(9); + + return true; +} + +// These must NOT be initialized. Default initialization to zero is +// necessary. +static unsigned int SystemToolsManagerCount; +SystemToolsStatic* SystemTools::Statics; + +// SystemToolsManager manages the SystemTools singleton. +// SystemToolsManager should be included in any translation unit +// that will use SystemTools or that implements the singleton +// pattern. It makes sure that the SystemTools singleton is created +// before and destroyed after all other singletons in CMake. + +SystemToolsManager::SystemToolsManager() +{ + if (++SystemToolsManagerCount == 1) { + SystemTools::ClassInitialize(); + } +} + +SystemToolsManager::~SystemToolsManager() +{ + if (--SystemToolsManagerCount == 0) { + SystemTools::ClassFinalize(); + } +} + +#if defined(__VMS) +// On VMS we configure the run time C library to be more UNIX like. +// http://h71000.www7.hp.com/doc/732final/5763/5763pro_004.html +extern "C" int decc$feature_get_index(char* name); +extern "C" int decc$feature_set_value(int index, int mode, int value); +static int SetVMSFeature(char* name, int value) +{ + int i; + errno = 0; + i = decc$feature_get_index(name); + return i >= 0 && (decc$feature_set_value(i, 1, value) >= 0 || errno == 0); +} +#endif + +void SystemTools::ClassInitialize() +{ +#ifdef __VMS + SetVMSFeature("DECC$FILENAME_UNIX_ONLY", 1); +#endif + + // Create statics singleton instance + SystemTools::Statics = new SystemToolsStatic; + +#if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP +// Add some special translation paths for unix. These are not added +// for windows because drive letters need to be maintained. Also, +// there are not sym-links and mount points on windows anyway. +# if !defined(_WIN32) || defined(__CYGWIN__) + // The tmp path is frequently a logical path so always keep it: + SystemTools::AddKeepPath("/tmp/"); + + // If the current working directory is a logical path then keep the + // logical name. + std::string pwd_str; + if (SystemTools::GetEnv("PWD", pwd_str)) { + char buf[2048]; + if (const char* cwd = Getcwd(buf, 2048)) { + // The current working directory may be a logical path. Find + // the shortest logical path that still produces the correct + // physical path. + std::string cwd_changed; + std::string pwd_changed; + + // Test progressively shorter logical-to-physical mappings. + std::string cwd_str = cwd; + std::string pwd_path; + Realpath(pwd_str, pwd_path); + while (cwd_str == pwd_path && cwd_str != pwd_str) { + // The current pair of paths is a working logical mapping. + cwd_changed = cwd_str; + pwd_changed = pwd_str; + + // Strip off one directory level and see if the logical + // mapping still works. + pwd_str = SystemTools::GetFilenamePath(pwd_str); + cwd_str = SystemTools::GetFilenamePath(cwd_str); + Realpath(pwd_str, pwd_path); + } + + // Add the translation to keep the logical path name. + if (!cwd_changed.empty() && !pwd_changed.empty()) { + SystemTools::AddTranslationPath(cwd_changed, pwd_changed); + } + } + } +# endif +#endif +} + +void SystemTools::ClassFinalize() +{ + delete SystemTools::Statics; +} + +} // namespace KWSYS_NAMESPACE + +#if defined(_MSC_VER) && defined(_DEBUG) +# include +# include +# include +namespace KWSYS_NAMESPACE { + +static int SystemToolsDebugReport(int, char* message, int*) +{ + fprintf(stderr, "%s", message); + fflush(stderr); + return 1; // no further reporting required +} + +void SystemTools::EnableMSVCDebugHook() +{ + if (SystemTools::HasEnv("DART_TEST_FROM_DART") || + SystemTools::HasEnv("DASHBOARD_TEST_FROM_CTEST")) { + _CrtSetReportHook(SystemToolsDebugReport); + } +} + +} // namespace KWSYS_NAMESPACE +#else +namespace KWSYS_NAMESPACE { +void SystemTools::EnableMSVCDebugHook() +{ +} +} // namespace KWSYS_NAMESPACE +#endif diff --git a/test/API/driver/kwsys/SystemTools.hxx.in b/test/API/driver/kwsys/SystemTools.hxx.in new file mode 100644 index 0000000..c4ab9d4 --- /dev/null +++ b/test/API/driver/kwsys/SystemTools.hxx.in @@ -0,0 +1,981 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_SystemTools_hxx +#define @KWSYS_NAMESPACE@_SystemTools_hxx + +#include <@KWSYS_NAMESPACE@/Configure.hxx> + +#include +#include +#include +#include + +#include +// include sys/stat.h after sys/types.h +#include + +#if !defined(_WIN32) || defined(__CYGWIN__) +# include // For access permissions for use with access() +#endif + +// Required for va_list +#include +// Required for FILE* +#include +#if !defined(va_list) +// Some compilers move va_list into the std namespace and there is no way to +// tell that this has been done. Playing with things being included before or +// after stdarg.h does not solve things because we do not have control over +// what the user does. This hack solves this problem by moving va_list to our +// own namespace that is local for kwsys. +namespace std { +} // Required for platforms that do not have std namespace +namespace @KWSYS_NAMESPACE@_VA_LIST { +using namespace std; +typedef va_list hack_va_list; +} +namespace @KWSYS_NAMESPACE@ { +typedef @KWSYS_NAMESPACE@_VA_LIST::hack_va_list va_list; +} +#endif // va_list + +namespace @KWSYS_NAMESPACE@ { + +class SystemToolsStatic; + +/** \class SystemToolsManager + * \brief Use to make sure SystemTools is initialized before it is used + * and is the last static object destroyed + */ +class @KWSYS_NAMESPACE@_EXPORT SystemToolsManager +{ +public: + SystemToolsManager(); + ~SystemToolsManager(); + + SystemToolsManager(const SystemToolsManager&) = delete; + SystemToolsManager& operator=(const SystemToolsManager&) = delete; +}; + +// This instance will show up in any translation unit that uses +// SystemTools. It will make sure SystemTools is initialized +// before it is used and is the last static object destroyed. +static SystemToolsManager SystemToolsManagerInstance; + +// Flags for use with TestFileAccess. Use a typedef in case any operating +// system in the future needs a special type. These are flags that may be +// combined using the | operator. +typedef int TestFilePermissions; +#if defined(_WIN32) && !defined(__CYGWIN__) +// On Windows (VC and Borland), no system header defines these constants... +static const TestFilePermissions TEST_FILE_OK = 0; +static const TestFilePermissions TEST_FILE_READ = 4; +static const TestFilePermissions TEST_FILE_WRITE = 2; +static const TestFilePermissions TEST_FILE_EXECUTE = 1; +#else +// Standard POSIX constants +static const TestFilePermissions TEST_FILE_OK = F_OK; +static const TestFilePermissions TEST_FILE_READ = R_OK; +static const TestFilePermissions TEST_FILE_WRITE = W_OK; +static const TestFilePermissions TEST_FILE_EXECUTE = X_OK; +#endif + +/** \class SystemTools + * \brief A collection of useful platform-independent system functions. + */ +class @KWSYS_NAMESPACE@_EXPORT SystemTools +{ +public: + /** ----------------------------------------------------------------- + * String Manipulation Routines + * ----------------------------------------------------------------- + */ + + /** + * Replace symbols in str that are not valid in C identifiers as + * defined by the 1999 standard, ie. anything except [A-Za-z0-9_]. + * They are replaced with `_' and if the first character is a digit + * then an underscore is prepended. Note that this can produce + * identifiers that the standard reserves (_[A-Z].* and __.*). + */ + static std::string MakeCidentifier(const std::string& s); + + static std::string MakeCindentifier(const std::string& s) + { + return MakeCidentifier(s); + } + + /** + * Replace replace all occurrences of the string in the source string. + */ + static void ReplaceString(std::string& source, const char* replace, + const char* with); + static void ReplaceString(std::string& source, const std::string& replace, + const std::string& with); + + /** + * Return a capitalized string (i.e the first letter is uppercased, + * all other are lowercased). + */ + static std::string Capitalized(const std::string&); + + /** + * Return a 'capitalized words' string (i.e the first letter of each word + * is uppercased all other are left untouched though). + */ + static std::string CapitalizedWords(const std::string&); + + /** + * Return a 'uncapitalized words' string (i.e the first letter of each word + * is lowercased all other are left untouched though). + */ + static std::string UnCapitalizedWords(const std::string&); + + /** + * Return a lower case string + */ + static std::string LowerCase(const std::string&); + + /** + * Return a lower case string + */ + static std::string UpperCase(const std::string&); + + /** + * Count char in string + */ + static size_t CountChar(const char* str, char c); + + /** + * Remove some characters from a string. + * Return a pointer to the new resulting string (allocated with 'new') + */ + static char* RemoveChars(const char* str, const char* toremove); + + /** + * Remove remove all but 0->9, A->F characters from a string. + * Return a pointer to the new resulting string (allocated with 'new') + */ + static char* RemoveCharsButUpperHex(const char* str); + + /** + * Replace some characters by another character in a string (in-place) + * Return a pointer to string + */ + static char* ReplaceChars(char* str, const char* toreplace, + char replacement); + + /** + * Returns true if str1 starts (respectively ends) with str2 + */ + static bool StringStartsWith(const char* str1, const char* str2); + static bool StringStartsWith(const std::string& str1, const char* str2); + static bool StringEndsWith(const char* str1, const char* str2); + static bool StringEndsWith(const std::string& str1, const char* str2); + + /** + * Returns a pointer to the last occurrence of str2 in str1 + */ + static const char* FindLastString(const char* str1, const char* str2); + + /** + * Make a duplicate of the string similar to the strdup C function + * but use new to create the 'new' string, so one can use + * 'delete' to remove it. Returns 0 if the input is empty. + */ + static char* DuplicateString(const char* str); + + /** + * Return the string cropped to a given length by removing chars in the + * center of the string and replacing them with an ellipsis (...) + */ + static std::string CropString(const std::string&, size_t max_len); + + /** split a path by separator into an array of strings, default is /. + If isPath is true then the string is treated like a path and if + s starts with a / then the first element of the returned array will + be /, so /foo/bar will be [/, foo, bar] + */ + static std::vector SplitString(const std::string& s, + char separator = '/', + bool isPath = false); + /** + * Perform a case-independent string comparison + */ + static int Strucmp(const char* s1, const char* s2); + + /** + * Split a string on its newlines into multiple lines + * Return false only if the last line stored had no newline + */ + static bool Split(const std::string& s, std::vector& l); + static bool Split(const std::string& s, std::vector& l, + char separator); + + /** + * Return string with space added between capitalized words + * (i.e. EatMyShorts becomes Eat My Shorts ) + * (note that IEatShorts becomes IEat Shorts) + */ + static std::string AddSpaceBetweenCapitalizedWords(const std::string&); + + /** + * Append two or more strings and produce new one. + * Programmer must 'delete []' the resulting string, which was allocated + * with 'new'. + * Return 0 if inputs are empty or there was an error + */ + static char* AppendStrings(const char* str1, const char* str2); + static char* AppendStrings(const char* str1, const char* str2, + const char* str3); + + /** + * Estimate the length of the string that will be produced + * from printing the given format string and arguments. The + * returned length will always be at least as large as the string + * that will result from printing. + * WARNING: since va_arg is called to iterate of the argument list, + * you will not be able to use this 'ap' anymore from the beginning. + * It's up to you to call va_end though. + */ + static int EstimateFormatLength(const char* format, va_list ap); + + /** + * Escape specific characters in 'str'. + */ + static std::string EscapeChars(const char* str, const char* chars_to_escape, + char escape_char = '\\'); + + /** ----------------------------------------------------------------- + * Filename Manipulation Routines + * ----------------------------------------------------------------- + */ + + /** + * Replace Windows file system slashes with Unix-style slashes. + */ + static void ConvertToUnixSlashes(std::string& path); + +#ifdef _WIN32 + /** Calls Encoding::ToWindowsExtendedPath. */ + static std::wstring ConvertToWindowsExtendedPath(const std::string&); +#endif + + /** + * For windows this calls ConvertToWindowsOutputPath and for unix + * it calls ConvertToUnixOutputPath + */ + static std::string ConvertToOutputPath(const std::string&); + + /** + * Convert the path to a string that can be used in a unix makefile. + * double slashes are removed, and spaces are escaped. + */ + static std::string ConvertToUnixOutputPath(const std::string&); + + /** + * Convert the path to string that can be used in a windows project or + * makefile. Double slashes are removed if they are not at the start of + * the string, the slashes are converted to windows style backslashes, and + * if there are spaces in the string it is double quoted. + */ + static std::string ConvertToWindowsOutputPath(const std::string&); + + /** + * Return true if a path with the given name exists in the current directory. + */ + static bool PathExists(const std::string& path); + + /** + * Return true if a file exists in the current directory. + * If isFile = true, then make sure the file is a file and + * not a directory. If isFile = false, then return true + * if it is a file or a directory. Note that the file will + * also be checked for read access. (Currently, this check + * for read access is only done on POSIX systems.) + */ + static bool FileExists(const char* filename, bool isFile); + static bool FileExists(const std::string& filename, bool isFile); + static bool FileExists(const char* filename); + static bool FileExists(const std::string& filename); + + /** + * Test if a file exists and can be accessed with the requested + * permissions. Symbolic links are followed. Returns true if + * the access test was successful. + * + * On POSIX systems (including Cygwin), this maps to the access + * function. On Windows systems, all existing files are + * considered readable, and writable files are considered to + * have the read-only file attribute cleared. + */ + static bool TestFileAccess(const char* filename, + TestFilePermissions permissions); + static bool TestFileAccess(const std::string& filename, + TestFilePermissions permissions); +/** + * Cross platform wrapper for stat struct + */ +#if defined(_WIN32) && !defined(__CYGWIN__) +# if defined(__BORLANDC__) + typedef struct stati64 Stat_t; +# else + typedef struct _stat64 Stat_t; +# endif +#else + typedef struct stat Stat_t; +#endif + + /** + * Cross platform wrapper for stat system call + * + * On Windows this may not work for paths longer than 250 characters + * due to limitations of the underlying '_wstat64' call. + */ + static int Stat(const char* path, Stat_t* buf); + static int Stat(const std::string& path, Stat_t* buf); + +/** + * Converts Cygwin path to Win32 path. Uses dictionary container for + * caching and calls to cygwin_conv_to_win32_path from Cygwin dll + * for actual translation. Returns true on success, else false. + */ +#ifdef __CYGWIN__ + static bool PathCygwinToWin32(const char* path, char* win32_path); +#endif + + /** + * Return file length + */ + static unsigned long FileLength(const std::string& filename); + + /** + Change the modification time or create a file + */ + static bool Touch(const std::string& filename, bool create); + + /** + * Compare file modification times. + * Return true for successful comparison and false for error. + * When true is returned, result has -1, 0, +1 for + * f1 older, same, or newer than f2. + */ + static bool FileTimeCompare(const std::string& f1, const std::string& f2, + int* result); + + /** + * Get the file extension (including ".") needed for an executable + * on the current platform ("" for unix, ".exe" for Windows). + */ + static const char* GetExecutableExtension(); + + /** + * Given a path on a Windows machine, return the actual case of + * the path as it exists on disk. Path components that do not + * exist on disk are returned unchanged. Relative paths are always + * returned unchanged. Drive letters are always made upper case. + * This does nothing on non-Windows systems but return the path. + */ + static std::string GetActualCaseForPath(const std::string& path); + + /** + * Given the path to a program executable, get the directory part of + * the path with the file stripped off. If there is no directory + * part, the empty string is returned. + */ + static std::string GetProgramPath(const std::string&); + static bool SplitProgramPath(const std::string& in_name, std::string& dir, + std::string& file, bool errorReport = true); + + /** + * Given argv[0] for a unix program find the full path to a running + * executable. argv0 can be null for windows WinMain programs + * in this case GetModuleFileName will be used to find the path + * to the running executable. If argv0 is not a full path, + * then this will try to find the full path. If the path is not + * found false is returned, if found true is returned. An error + * message of the attempted paths is stored in errorMsg. + * exeName is the name of the executable. + * buildDir is a possibly null path to the build directory. + * installPrefix is a possibly null pointer to the install directory. + */ + static bool FindProgramPath(const char* argv0, std::string& pathOut, + std::string& errorMsg, + const char* exeName = nullptr, + const char* buildDir = nullptr, + const char* installPrefix = nullptr); + + /** + * Given a path to a file or directory, convert it to a full path. + * This collapses away relative paths relative to the cwd argument + * (which defaults to the current working directory). The full path + * is returned. + */ + static std::string CollapseFullPath(const std::string& in_relative); + static std::string CollapseFullPath(const std::string& in_relative, + const char* in_base); + static std::string CollapseFullPath(const std::string& in_relative, + const std::string& in_base); + + /** + * Get the real path for a given path, removing all symlinks. In + * the event of an error (non-existent path, permissions issue, + * etc.) the original path is returned if errorMessage pointer is + * nullptr. Otherwise empty string is returned and errorMessage + * contains error description. + */ + static std::string GetRealPath(const std::string& path, + std::string* errorMessage = nullptr); + + /** + * Split a path name into its root component and the rest of the + * path. The root component is one of the following: + * "/" = UNIX full path + * "c:/" = Windows full path (can be any drive letter) + * "c:" = Windows drive-letter relative path (can be any drive letter) + * "//" = Network path + * "~/" = Home path for current user + * "~u/" = Home path for user 'u' + * "" = Relative path + * + * A pointer to the rest of the path after the root component is + * returned. The root component is stored in the "root" string if + * given. + */ + static const char* SplitPathRootComponent(const std::string& p, + std::string* root = nullptr); + + /** + * Split a path name into its basic components. The first component + * always exists and is the root returned by SplitPathRootComponent. + * The remaining components form the path. If there is a trailing + * slash then the last component is the empty string. The + * components can be recombined as "c[0]c[1]/c[2]/.../c[n]" to + * produce the original path. Home directory references are + * automatically expanded if expand_home_dir is true and this + * platform supports them. + * + * This does *not* normalize the input path. All components are + * preserved, including empty ones. Typically callers should use + * this only on paths that have already been normalized. + */ + static void SplitPath(const std::string& p, + std::vector& components, + bool expand_home_dir = true); + + /** + * Join components of a path name into a single string. See + * SplitPath for the format of the components. + * + * This does *not* normalize the input path. All components are + * preserved, including empty ones. Typically callers should use + * this only on paths that have already been normalized. + */ + static std::string JoinPath(const std::vector& components); + static std::string JoinPath(std::vector::const_iterator first, + std::vector::const_iterator last); + + /** + * Compare a path or components of a path. + */ + static bool ComparePath(const std::string& c1, const std::string& c2); + + /** + * Return path of a full filename (no trailing slashes) + */ + static std::string GetFilenamePath(const std::string&); + + /** + * Return file name of a full filename (i.e. file name without path) + */ + static std::string GetFilenameName(const std::string&); + + /** + * Return longest file extension of a full filename (dot included) + */ + static std::string GetFilenameExtension(const std::string&); + + /** + * Return shortest file extension of a full filename (dot included) + */ + static std::string GetFilenameLastExtension(const std::string& filename); + + /** + * Return file name without extension of a full filename + */ + static std::string GetFilenameWithoutExtension(const std::string&); + + /** + * Return file name without its last (shortest) extension + */ + static std::string GetFilenameWithoutLastExtension(const std::string&); + + /** + * Return whether the path represents a full path (not relative) + */ + static bool FileIsFullPath(const std::string&); + static bool FileIsFullPath(const char*); + + /** + * For windows return the short path for the given path, + * Unix just a pass through + */ + static bool GetShortPath(const std::string& path, std::string& result); + + /** + * Read line from file. Make sure to read a full line and truncates it if + * requested via sizeLimit. Returns true if any data were read before the + * end-of-file was reached. If the has_newline argument is specified, it will + * be true when the line read had a newline character. + */ + static bool GetLineFromStream(std::istream& istr, std::string& line, + bool* has_newline = nullptr, + long sizeLimit = -1); + + /** + * Get the parent directory of the directory or file + */ + static std::string GetParentDirectory(const std::string& fileOrDir); + + /** + * Check if the given file or directory is in subdirectory of dir + */ + static bool IsSubDirectory(const std::string& fileOrDir, + const std::string& dir); + + /** ----------------------------------------------------------------- + * File Manipulation Routines + * ----------------------------------------------------------------- + */ + + /** + * Open a file considering unicode. + */ + static FILE* Fopen(const std::string& file, const char* mode); + +/** + * Visual C++ does not define mode_t (note that Borland does, however). + */ +#if defined(_MSC_VER) + typedef unsigned short mode_t; +#endif + + /** + * Make a new directory if it is not there. This function + * can make a full path even if none of the directories existed + * prior to calling this function. + */ + static bool MakeDirectory(const char* path, const mode_t* mode = nullptr); + static bool MakeDirectory(const std::string& path, + const mode_t* mode = nullptr); + + /** + * Copy the source file to the destination file only + * if the two files differ. + */ + static bool CopyFileIfDifferent(const std::string& source, + const std::string& destination); + + /** + * Compare the contents of two files. Return true if different + */ + static bool FilesDiffer(const std::string& source, + const std::string& destination); + + /** + * Compare the contents of two files, ignoring line ending differences. + * Return true if different + */ + static bool TextFilesDiffer(const std::string& path1, + const std::string& path2); + + /** + * Return true if the two files are the same file + */ + static bool SameFile(const std::string& file1, const std::string& file2); + + /** + * Copy a file. + */ + static bool CopyFileAlways(const std::string& source, + const std::string& destination); + + /** + * Copy a file. If the "always" argument is true the file is always + * copied. If it is false, the file is copied only if it is new or + * has changed. + */ + static bool CopyAFile(const std::string& source, + const std::string& destination, bool always = true); + + /** + * Copy content directory to another directory with all files and + * subdirectories. If the "always" argument is true all files are + * always copied. If it is false, only files that have changed or + * are new are copied. + */ + static bool CopyADirectory(const std::string& source, + const std::string& destination, + bool always = true); + + /** + * Remove a file + */ + static bool RemoveFile(const std::string& source); + + /** + * Remove a directory + */ + static bool RemoveADirectory(const std::string& source); + + /** + * Get the maximum full file path length + */ + static size_t GetMaximumFilePathLength(); + + /** + * Find a file in the system PATH, with optional extra paths + */ + static std::string FindFile( + const std::string& name, + const std::vector& path = std::vector(), + bool no_system_path = false); + + /** + * Find a directory in the system PATH, with optional extra paths + */ + static std::string FindDirectory( + const std::string& name, + const std::vector& path = std::vector(), + bool no_system_path = false); + + /** + * Find an executable in the system PATH, with optional extra paths + */ + static std::string FindProgram( + const char* name, + const std::vector& path = std::vector(), + bool no_system_path = false); + static std::string FindProgram( + const std::string& name, + const std::vector& path = std::vector(), + bool no_system_path = false); + static std::string FindProgram( + const std::vector& names, + const std::vector& path = std::vector(), + bool no_system_path = false); + + /** + * Find a library in the system PATH, with optional extra paths + */ + static std::string FindLibrary(const std::string& name, + const std::vector& path); + + /** + * Return true if the file is a directory + */ + static bool FileIsDirectory(const std::string& name); + + /** + * Return true if the file is a symlink + */ + static bool FileIsSymlink(const std::string& name); + + /** + * Return true if the file is a FIFO + */ + static bool FileIsFIFO(const std::string& name); + + /** + * Return true if the file has a given signature (first set of bytes) + */ + static bool FileHasSignature(const char* filename, const char* signature, + long offset = 0); + + /** + * Attempt to detect and return the type of a file. + * Up to 'length' bytes are read from the file, if more than 'percent_bin' % + * of the bytes are non-textual elements, the file is considered binary, + * otherwise textual. Textual elements are bytes in the ASCII [0x20, 0x7E] + * range, but also \\n, \\r, \\t. + * The algorithm is simplistic, and should probably check for usual file + * extensions, 'magic' signature, unicode, etc. + */ + enum FileTypeEnum + { + FileTypeUnknown, + FileTypeBinary, + FileTypeText + }; + static SystemTools::FileTypeEnum DetectFileType(const char* filename, + unsigned long length = 256, + double percent_bin = 0.05); + + /** + * Create a symbolic link if the platform supports it. Returns whether + * creation succeeded. + */ + static bool CreateSymlink(const std::string& origName, + const std::string& newName); + + /** + * Read the contents of a symbolic link. Returns whether reading + * succeeded. + */ + static bool ReadSymlink(const std::string& newName, std::string& origName); + + /** + * Try to locate the file 'filename' in the directory 'dir'. + * If 'filename' is a fully qualified filename, the basename of the file is + * used to check for its existence in 'dir'. + * If 'dir' is not a directory, GetFilenamePath() is called on 'dir' to + * get its directory first (thus, you can pass a filename as 'dir', as + * a convenience). + * 'filename_found' is assigned the fully qualified name/path of the file + * if it is found (not touched otherwise). + * If 'try_filename_dirs' is true, try to find the file using the + * components of its path, i.e. if we are looking for c:/foo/bar/bill.txt, + * first look for bill.txt in 'dir', then in 'dir'/bar, then in 'dir'/foo/bar + * etc. + * Return true if the file was found, false otherwise. + */ + static bool LocateFileInDir(const char* filename, const char* dir, + std::string& filename_found, + int try_filename_dirs = 0); + + /** compute the relative path from local to remote. local must + be a directory. remote can be a file or a directory. + Both remote and local must be full paths. Basically, if + you are in directory local and you want to access the file in remote + what is the relative path to do that. For example: + /a/b/c/d to /a/b/c1/d1 -> ../../c1/d1 + from /usr/src to /usr/src/test/blah/foo.cpp -> test/blah/foo.cpp + */ + static std::string RelativePath(const std::string& local, + const std::string& remote); + + /** + * Return file's modified time + */ + static long int ModifiedTime(const std::string& filename); + + /** + * Return file's creation time (Win32: works only for NTFS, not FAT) + */ + static long int CreationTime(const std::string& filename); + + /** + * Get and set permissions of the file. If honor_umask is set, the umask + * is queried and applied to the given permissions. Returns false if + * failure. + * + * WARNING: A non-thread-safe method is currently used to get the umask + * if a honor_umask parameter is set to true. + */ + static bool GetPermissions(const char* file, mode_t& mode); + static bool GetPermissions(const std::string& file, mode_t& mode); + static bool SetPermissions(const char* file, mode_t mode, + bool honor_umask = false); + static bool SetPermissions(const std::string& file, mode_t mode, + bool honor_umask = false); + + /** ----------------------------------------------------------------- + * Time Manipulation Routines + * ----------------------------------------------------------------- + */ + + /** Get current time in seconds since Posix Epoch (Jan 1, 1970). */ + static double GetTime(); + + /** + * Get current date/time + */ + static std::string GetCurrentDateTime(const char* format); + + /** ----------------------------------------------------------------- + * Registry Manipulation Routines + * ----------------------------------------------------------------- + */ + + /** + * Specify access to the 32-bit or 64-bit application view of + * registry values. The default is to match the currently running + * binary type. + */ + enum KeyWOW64 + { + KeyWOW64_Default, + KeyWOW64_32, + KeyWOW64_64 + }; + + /** + * Get a list of subkeys. + */ + static bool GetRegistrySubKeys(const std::string& key, + std::vector& subkeys, + KeyWOW64 view = KeyWOW64_Default); + + /** + * Read a registry value + */ + static bool ReadRegistryValue(const std::string& key, std::string& value, + KeyWOW64 view = KeyWOW64_Default); + + /** + * Write a registry value + */ + static bool WriteRegistryValue(const std::string& key, + const std::string& value, + KeyWOW64 view = KeyWOW64_Default); + + /** + * Delete a registry value + */ + static bool DeleteRegistryValue(const std::string& key, + KeyWOW64 view = KeyWOW64_Default); + + /** ----------------------------------------------------------------- + * Environment Manipulation Routines + * ----------------------------------------------------------------- + */ + + /** + * Add the paths from the environment variable PATH to the + * string vector passed in. If env is set then the value + * of env will be used instead of PATH. + */ + static void GetPath(std::vector& path, + const char* env = nullptr); + + /** + * Read an environment variable + */ + static const char* GetEnv(const char* key); + static const char* GetEnv(const std::string& key); + static bool GetEnv(const char* key, std::string& result); + static bool GetEnv(const std::string& key, std::string& result); + static bool HasEnv(const char* key); + static bool HasEnv(const std::string& key); + + /** Put a string into the environment + of the form var=value */ + static bool PutEnv(const std::string& env); + + /** Remove a string from the environment. + Input is of the form "var" or "var=value" (value is ignored). */ + static bool UnPutEnv(const std::string& env); + + /** + * Get current working directory CWD + */ + static std::string GetCurrentWorkingDirectory(bool collapse = true); + + /** + * Change directory to the directory specified + */ + static int ChangeDirectory(const std::string& dir); + + /** + * Get the result of strerror(errno) + */ + static std::string GetLastSystemError(); + + /** + * When building DEBUG with MSVC, this enables a hook that prevents + * error dialogs from popping up if the program is being run from + * DART. + */ + static void EnableMSVCDebugHook(); + + /** + * Get the width of the terminal window. The code may or may not work, so + * make sure you have some reasonable defaults prepared if the code returns + * some bogus size. + */ + static int GetTerminalWidth(); + +#if @KWSYS_NAMESPACE@_SYSTEMTOOLS_USE_TRANSLATION_MAP + /** + * Add an entry in the path translation table. + */ + static void AddTranslationPath(const std::string& dir, + const std::string& refdir); + + /** + * If dir is different after CollapseFullPath is called, + * Then insert it into the path translation table + */ + static void AddKeepPath(const std::string& dir); + + /** + * Update path by going through the Path Translation table; + */ + static void CheckTranslationPath(std::string& path); +#endif + + /** + * Delay the execution for a specified amount of time specified + * in milliseconds + */ + static void Delay(unsigned int msec); + + /** + * Get the operating system name and version + * This is implemented for Win32 only for the moment + */ + static std::string GetOperatingSystemNameAndVersion(); + + /** ----------------------------------------------------------------- + * URL Manipulation Routines + * ----------------------------------------------------------------- + */ + + /** + * Parse a character string : + * protocol://dataglom + * and fill protocol as appropriate. + * Return false if the URL does not have the required form, true otherwise. + */ + static bool ParseURLProtocol(const std::string& URL, std::string& protocol, + std::string& dataglom); + + /** + * Parse a string (a URL without protocol prefix) with the form: + * protocol://[[username[':'password]'@']hostname[':'dataport]]'/'[datapath] + * and fill protocol, username, password, hostname, dataport, and datapath + * when values are found. + * Return true if the string matches the format; false otherwise. + */ + static bool ParseURL(const std::string& URL, std::string& protocol, + std::string& username, std::string& password, + std::string& hostname, std::string& dataport, + std::string& datapath); + +private: + /** + * Allocate the stl map that serve as the Path Translation table. + */ + static void ClassInitialize(); + + /** + * Deallocate the stl map that serve as the Path Translation table. + */ + static void ClassFinalize(); + + /** + * This method prevents warning on SGI + */ + SystemToolsManager* GetSystemToolsManager() + { + return &SystemToolsManagerInstance; + } + + static SystemToolsStatic* Statics; + friend class SystemToolsStatic; + friend class SystemToolsManager; +}; + +} // namespace @KWSYS_NAMESPACE@ + +#endif diff --git a/test/API/driver/kwsys/Terminal.c b/test/API/driver/kwsys/Terminal.c new file mode 100644 index 0000000..4dd2461 --- /dev/null +++ b/test/API/driver/kwsys/Terminal.c @@ -0,0 +1,414 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(Terminal.h) + +/* Work-around CMake dependency scanning limitation. This must + duplicate the above list of headers. */ +#if 0 +# include "Terminal.h.in" +#endif + +/* Configure support for this platform. */ +#if defined(_WIN32) || defined(__CYGWIN__) +# define KWSYS_TERMINAL_SUPPORT_CONSOLE +#endif +#if !defined(_WIN32) +# define KWSYS_TERMINAL_ISATTY_WORKS +#endif + +/* Include needed system APIs. */ + +#include /* va_list */ +#include /* getenv */ +#include /* strcmp */ + +#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE) +# include /* _get_osfhandle */ +# include /* SetConsoleTextAttribute */ +#endif + +#if defined(KWSYS_TERMINAL_ISATTY_WORKS) +# include /* isatty */ +#else +# include /* fstat */ +#endif + +static int kwsysTerminalStreamIsVT100(FILE* stream, int default_vt100, + int default_tty); +static void kwsysTerminalSetVT100Color(FILE* stream, int color); +#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE) +static HANDLE kwsysTerminalGetStreamHandle(FILE* stream); +static void kwsysTerminalSetConsoleColor(HANDLE hOut, + CONSOLE_SCREEN_BUFFER_INFO* hOutInfo, + FILE* stream, int color); +#endif + +void kwsysTerminal_cfprintf(int color, FILE* stream, const char* format, ...) +{ + /* Setup the stream with the given color if possible. */ + int pipeIsConsole = 0; + int pipeIsVT100 = 0; + int default_vt100 = color & kwsysTerminal_Color_AssumeVT100; + int default_tty = color & kwsysTerminal_Color_AssumeTTY; +#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE) + CONSOLE_SCREEN_BUFFER_INFO hOutInfo; + HANDLE hOut = kwsysTerminalGetStreamHandle(stream); + if (GetConsoleScreenBufferInfo(hOut, &hOutInfo)) { + pipeIsConsole = 1; + kwsysTerminalSetConsoleColor(hOut, &hOutInfo, stream, color); + } +#endif + if (!pipeIsConsole && + kwsysTerminalStreamIsVT100(stream, default_vt100, default_tty)) { + pipeIsVT100 = 1; + kwsysTerminalSetVT100Color(stream, color); + } + + /* Format the text into the stream. */ + { + va_list var_args; + va_start(var_args, format); + vfprintf(stream, format, var_args); + va_end(var_args); + } + +/* Restore the normal color state for the stream. */ +#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE) + if (pipeIsConsole) { + kwsysTerminalSetConsoleColor(hOut, &hOutInfo, stream, + kwsysTerminal_Color_Normal); + } +#endif + if (pipeIsVT100) { + kwsysTerminalSetVT100Color(stream, kwsysTerminal_Color_Normal); + } +} + +/* Detect cases when a stream is definitely not interactive. */ +#if !defined(KWSYS_TERMINAL_ISATTY_WORKS) +static int kwsysTerminalStreamIsNotInteractive(FILE* stream) +{ + /* The given stream is definitely not interactive if it is a regular + file. */ + struct stat stream_stat; + if (fstat(fileno(stream), &stream_stat) == 0) { + if (stream_stat.st_mode & S_IFREG) { + return 1; + } + } + return 0; +} +#endif + +/* List of terminal names known to support VT100 color escape sequences. */ +static const char* kwsysTerminalVT100Names[] = { "Eterm", + "alacritty", + "alacritty-direct", + "ansi", + "color-xterm", + "con132x25", + "con132x30", + "con132x43", + "con132x60", + "con80x25", + "con80x28", + "con80x30", + "con80x43", + "con80x50", + "con80x60", + "cons25", + "console", + "cygwin", + "dtterm", + "eterm-color", + "gnome", + "gnome-256color", + "konsole", + "konsole-256color", + "kterm", + "linux", + "msys", + "linux-c", + "mach-color", + "mlterm", + "putty", + "putty-256color", + "rxvt", + "rxvt-256color", + "rxvt-cygwin", + "rxvt-cygwin-native", + "rxvt-unicode", + "rxvt-unicode-256color", + "screen", + "screen-256color", + "screen-256color-bce", + "screen-bce", + "screen-w", + "screen.linux", + "tmux", + "tmux-256color", + "vt100", + "xterm", + "xterm-16color", + "xterm-256color", + "xterm-88color", + "xterm-color", + "xterm-debian", + "xterm-kitty", + "xterm-termite", + 0 }; + +/* Detect whether a stream is displayed in a VT100-compatible terminal. */ +static int kwsysTerminalStreamIsVT100(FILE* stream, int default_vt100, + int default_tty) +{ + /* Force color according to http://bixense.com/clicolors/ convention. */ + { + const char* clicolor_force = getenv("CLICOLOR_FORCE"); + if (clicolor_force && *clicolor_force && + strcmp(clicolor_force, "0") != 0) { + return 1; + } + } + + /* If running inside emacs the terminal is not VT100. Some emacs + seem to claim the TERM is xterm even though they do not support + VT100 escapes. */ + { + const char* emacs = getenv("EMACS"); + if (emacs && *emacs == 't') { + return 0; + } + } + + /* Check for a valid terminal. */ + if (!default_vt100) { + const char** t = 0; + const char* term = getenv("TERM"); + if (term) { + for (t = kwsysTerminalVT100Names; *t && strcmp(term, *t) != 0; ++t) { + } + } + if (!(t && *t)) { + return 0; + } + } + +#if defined(KWSYS_TERMINAL_ISATTY_WORKS) + /* Make sure the stream is a tty. */ + (void)default_tty; + return isatty(fileno(stream)) ? 1 : 0; +#else + /* Check for cases in which the stream is definitely not a tty. */ + if (kwsysTerminalStreamIsNotInteractive(stream)) { + return 0; + } + + /* Use the provided default for whether this is a tty. */ + return default_tty; +#endif +} + +/* VT100 escape sequence strings. */ +#if defined(__MVS__) +/* if building on z/OS (aka MVS), assume we are using EBCDIC */ +# define ESCAPE_CHAR "\47" +#else +# define ESCAPE_CHAR "\33" +#endif + +#define KWSYS_TERMINAL_VT100_NORMAL ESCAPE_CHAR "[0m" +#define KWSYS_TERMINAL_VT100_BOLD ESCAPE_CHAR "[1m" +#define KWSYS_TERMINAL_VT100_UNDERLINE ESCAPE_CHAR "[4m" +#define KWSYS_TERMINAL_VT100_BLINK ESCAPE_CHAR "[5m" +#define KWSYS_TERMINAL_VT100_INVERSE ESCAPE_CHAR "[7m" +#define KWSYS_TERMINAL_VT100_FOREGROUND_BLACK ESCAPE_CHAR "[30m" +#define KWSYS_TERMINAL_VT100_FOREGROUND_RED ESCAPE_CHAR "[31m" +#define KWSYS_TERMINAL_VT100_FOREGROUND_GREEN ESCAPE_CHAR "[32m" +#define KWSYS_TERMINAL_VT100_FOREGROUND_YELLOW ESCAPE_CHAR "[33m" +#define KWSYS_TERMINAL_VT100_FOREGROUND_BLUE ESCAPE_CHAR "[34m" +#define KWSYS_TERMINAL_VT100_FOREGROUND_MAGENTA ESCAPE_CHAR "[35m" +#define KWSYS_TERMINAL_VT100_FOREGROUND_CYAN ESCAPE_CHAR "[36m" +#define KWSYS_TERMINAL_VT100_FOREGROUND_WHITE ESCAPE_CHAR "[37m" +#define KWSYS_TERMINAL_VT100_BACKGROUND_BLACK ESCAPE_CHAR "[40m" +#define KWSYS_TERMINAL_VT100_BACKGROUND_RED ESCAPE_CHAR "[41m" +#define KWSYS_TERMINAL_VT100_BACKGROUND_GREEN ESCAPE_CHAR "[42m" +#define KWSYS_TERMINAL_VT100_BACKGROUND_YELLOW ESCAPE_CHAR "[43m" +#define KWSYS_TERMINAL_VT100_BACKGROUND_BLUE ESCAPE_CHAR "[44m" +#define KWSYS_TERMINAL_VT100_BACKGROUND_MAGENTA ESCAPE_CHAR "[45m" +#define KWSYS_TERMINAL_VT100_BACKGROUND_CYAN ESCAPE_CHAR "[46m" +#define KWSYS_TERMINAL_VT100_BACKGROUND_WHITE ESCAPE_CHAR "[47m" + +/* Write VT100 escape sequences to the stream for the given color. */ +static void kwsysTerminalSetVT100Color(FILE* stream, int color) +{ + if (color == kwsysTerminal_Color_Normal) { + fprintf(stream, KWSYS_TERMINAL_VT100_NORMAL); + return; + } + + switch (color & kwsysTerminal_Color_ForegroundMask) { + case kwsysTerminal_Color_Normal: + fprintf(stream, KWSYS_TERMINAL_VT100_NORMAL); + break; + case kwsysTerminal_Color_ForegroundBlack: + fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_BLACK); + break; + case kwsysTerminal_Color_ForegroundRed: + fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_RED); + break; + case kwsysTerminal_Color_ForegroundGreen: + fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_GREEN); + break; + case kwsysTerminal_Color_ForegroundYellow: + fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_YELLOW); + break; + case kwsysTerminal_Color_ForegroundBlue: + fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_BLUE); + break; + case kwsysTerminal_Color_ForegroundMagenta: + fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_MAGENTA); + break; + case kwsysTerminal_Color_ForegroundCyan: + fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_CYAN); + break; + case kwsysTerminal_Color_ForegroundWhite: + fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_WHITE); + break; + } + switch (color & kwsysTerminal_Color_BackgroundMask) { + case kwsysTerminal_Color_BackgroundBlack: + fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_BLACK); + break; + case kwsysTerminal_Color_BackgroundRed: + fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_RED); + break; + case kwsysTerminal_Color_BackgroundGreen: + fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_GREEN); + break; + case kwsysTerminal_Color_BackgroundYellow: + fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_YELLOW); + break; + case kwsysTerminal_Color_BackgroundBlue: + fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_BLUE); + break; + case kwsysTerminal_Color_BackgroundMagenta: + fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_MAGENTA); + break; + case kwsysTerminal_Color_BackgroundCyan: + fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_CYAN); + break; + case kwsysTerminal_Color_BackgroundWhite: + fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_WHITE); + break; + } + if (color & kwsysTerminal_Color_ForegroundBold) { + fprintf(stream, KWSYS_TERMINAL_VT100_BOLD); + } +} + +#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE) + +# define KWSYS_TERMINAL_MASK_FOREGROUND \ + (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | \ + FOREGROUND_INTENSITY) +# define KWSYS_TERMINAL_MASK_BACKGROUND \ + (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | \ + BACKGROUND_INTENSITY) + +/* Get the Windows handle for a FILE stream. */ +static HANDLE kwsysTerminalGetStreamHandle(FILE* stream) +{ + /* Get the C-library file descriptor from the stream. */ + int fd = fileno(stream); + +# if defined(__CYGWIN__) + /* Cygwin seems to have an extra pipe level. If the file descriptor + corresponds to stdout or stderr then obtain the matching windows + handle directly. */ + if (fd == fileno(stdout)) { + return GetStdHandle(STD_OUTPUT_HANDLE); + } else if (fd == fileno(stderr)) { + return GetStdHandle(STD_ERROR_HANDLE); + } +# endif + + /* Get the underlying Windows handle for the descriptor. */ + return (HANDLE)_get_osfhandle(fd); +} + +/* Set color attributes in a Windows console. */ +static void kwsysTerminalSetConsoleColor(HANDLE hOut, + CONSOLE_SCREEN_BUFFER_INFO* hOutInfo, + FILE* stream, int color) +{ + WORD attributes = 0; + switch (color & kwsysTerminal_Color_ForegroundMask) { + case kwsysTerminal_Color_Normal: + attributes |= hOutInfo->wAttributes & KWSYS_TERMINAL_MASK_FOREGROUND; + break; + case kwsysTerminal_Color_ForegroundBlack: + attributes |= 0; + break; + case kwsysTerminal_Color_ForegroundRed: + attributes |= FOREGROUND_RED; + break; + case kwsysTerminal_Color_ForegroundGreen: + attributes |= FOREGROUND_GREEN; + break; + case kwsysTerminal_Color_ForegroundYellow: + attributes |= FOREGROUND_RED | FOREGROUND_GREEN; + break; + case kwsysTerminal_Color_ForegroundBlue: + attributes |= FOREGROUND_BLUE; + break; + case kwsysTerminal_Color_ForegroundMagenta: + attributes |= FOREGROUND_RED | FOREGROUND_BLUE; + break; + case kwsysTerminal_Color_ForegroundCyan: + attributes |= FOREGROUND_BLUE | FOREGROUND_GREEN; + break; + case kwsysTerminal_Color_ForegroundWhite: + attributes |= FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; + break; + } + switch (color & kwsysTerminal_Color_BackgroundMask) { + case kwsysTerminal_Color_Normal: + attributes |= hOutInfo->wAttributes & KWSYS_TERMINAL_MASK_BACKGROUND; + break; + case kwsysTerminal_Color_BackgroundBlack: + attributes |= 0; + break; + case kwsysTerminal_Color_BackgroundRed: + attributes |= BACKGROUND_RED; + break; + case kwsysTerminal_Color_BackgroundGreen: + attributes |= BACKGROUND_GREEN; + break; + case kwsysTerminal_Color_BackgroundYellow: + attributes |= BACKGROUND_RED | BACKGROUND_GREEN; + break; + case kwsysTerminal_Color_BackgroundBlue: + attributes |= BACKGROUND_BLUE; + break; + case kwsysTerminal_Color_BackgroundMagenta: + attributes |= BACKGROUND_RED | BACKGROUND_BLUE; + break; + case kwsysTerminal_Color_BackgroundCyan: + attributes |= BACKGROUND_BLUE | BACKGROUND_GREEN; + break; + case kwsysTerminal_Color_BackgroundWhite: + attributes |= BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED; + break; + } + if (color & kwsysTerminal_Color_ForegroundBold) { + attributes |= FOREGROUND_INTENSITY; + } + if (color & kwsysTerminal_Color_BackgroundBold) { + attributes |= BACKGROUND_INTENSITY; + } + fflush(stream); + SetConsoleTextAttribute(hOut, attributes); +} +#endif diff --git a/test/API/driver/kwsys/Terminal.h.in b/test/API/driver/kwsys/Terminal.h.in new file mode 100644 index 0000000..1a2c745 --- /dev/null +++ b/test/API/driver/kwsys/Terminal.h.in @@ -0,0 +1,170 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_Terminal_h +#define @KWSYS_NAMESPACE@_Terminal_h + +#include <@KWSYS_NAMESPACE@/Configure.h> + +#include /* For file stream type FILE. */ + +/* Redefine all public interface symbol names to be in the proper + namespace. These macros are used internally to kwsys only, and are + not visible to user code. Use kwsysHeaderDump.pl to reproduce + these macros after making changes to the interface. */ +#if !defined(KWSYS_NAMESPACE) +# define kwsys_ns(x) @KWSYS_NAMESPACE@##x +# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT +#endif +#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# define kwsysTerminal_cfprintf kwsys_ns(Terminal_cfprintf) +# define kwsysTerminal_Color_e kwsys_ns(Terminal_Color_e) +# define kwsysTerminal_Color_Normal kwsys_ns(Terminal_Color_Normal) +# define kwsysTerminal_Color_ForegroundBlack \ + kwsys_ns(Terminal_Color_ForegroundBlack) +# define kwsysTerminal_Color_ForegroundRed \ + kwsys_ns(Terminal_Color_ForegroundRed) +# define kwsysTerminal_Color_ForegroundGreen \ + kwsys_ns(Terminal_Color_ForegroundGreen) +# define kwsysTerminal_Color_ForegroundYellow \ + kwsys_ns(Terminal_Color_ForegroundYellow) +# define kwsysTerminal_Color_ForegroundBlue \ + kwsys_ns(Terminal_Color_ForegroundBlue) +# define kwsysTerminal_Color_ForegroundMagenta \ + kwsys_ns(Terminal_Color_ForegroundMagenta) +# define kwsysTerminal_Color_ForegroundCyan \ + kwsys_ns(Terminal_Color_ForegroundCyan) +# define kwsysTerminal_Color_ForegroundWhite \ + kwsys_ns(Terminal_Color_ForegroundWhite) +# define kwsysTerminal_Color_ForegroundMask \ + kwsys_ns(Terminal_Color_ForegroundMask) +# define kwsysTerminal_Color_BackgroundBlack \ + kwsys_ns(Terminal_Color_BackgroundBlack) +# define kwsysTerminal_Color_BackgroundRed \ + kwsys_ns(Terminal_Color_BackgroundRed) +# define kwsysTerminal_Color_BackgroundGreen \ + kwsys_ns(Terminal_Color_BackgroundGreen) +# define kwsysTerminal_Color_BackgroundYellow \ + kwsys_ns(Terminal_Color_BackgroundYellow) +# define kwsysTerminal_Color_BackgroundBlue \ + kwsys_ns(Terminal_Color_BackgroundBlue) +# define kwsysTerminal_Color_BackgroundMagenta \ + kwsys_ns(Terminal_Color_BackgroundMagenta) +# define kwsysTerminal_Color_BackgroundCyan \ + kwsys_ns(Terminal_Color_BackgroundCyan) +# define kwsysTerminal_Color_BackgroundWhite \ + kwsys_ns(Terminal_Color_BackgroundWhite) +# define kwsysTerminal_Color_BackgroundMask \ + kwsys_ns(Terminal_Color_BackgroundMask) +# define kwsysTerminal_Color_ForegroundBold \ + kwsys_ns(Terminal_Color_ForegroundBold) +# define kwsysTerminal_Color_BackgroundBold \ + kwsys_ns(Terminal_Color_BackgroundBold) +# define kwsysTerminal_Color_AssumeTTY kwsys_ns(Terminal_Color_AssumeTTY) +# define kwsysTerminal_Color_AssumeVT100 kwsys_ns(Terminal_Color_AssumeVT100) +# define kwsysTerminal_Color_AttributeMask \ + kwsys_ns(Terminal_Color_AttributeMask) +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * Write colored and formatted text to a stream. Color is used only + * for streams supporting it. The color specification is constructed + * by bitwise-OR-ing enumeration values. At most one foreground and + * one background value may be given. + * + * Whether the a stream supports color is usually automatically + * detected, but with two exceptions: + * + * - When the stream is displayed in a terminal supporting VT100 + * color but using an intermediate pipe for communication the + * detection of a tty fails. (This typically occurs for a shell + * running in an rxvt terminal in MSYS.) If the caller knows this + * to be the case, the attribute Color_AssumeTTY may be included in + * the color specification. + * + * - When the stream is displayed in a terminal whose TERM + * environment variable is not set or is set to a value that is not + * known to support VT100 colors. If the caller knows this to be + * the case, the attribute Color_AssumeVT100 may be included in the + * color specification. + */ +kwsysEXPORT void kwsysTerminal_cfprintf(int color, FILE* stream, + const char* format, ...); +enum kwsysTerminal_Color_e +{ + /* Normal Text */ + kwsysTerminal_Color_Normal = 0, + + /* Foreground Color */ + kwsysTerminal_Color_ForegroundBlack = 0x1, + kwsysTerminal_Color_ForegroundRed = 0x2, + kwsysTerminal_Color_ForegroundGreen = 0x3, + kwsysTerminal_Color_ForegroundYellow = 0x4, + kwsysTerminal_Color_ForegroundBlue = 0x5, + kwsysTerminal_Color_ForegroundMagenta = 0x6, + kwsysTerminal_Color_ForegroundCyan = 0x7, + kwsysTerminal_Color_ForegroundWhite = 0x8, + kwsysTerminal_Color_ForegroundMask = 0xF, + + /* Background Color */ + kwsysTerminal_Color_BackgroundBlack = 0x10, + kwsysTerminal_Color_BackgroundRed = 0x20, + kwsysTerminal_Color_BackgroundGreen = 0x30, + kwsysTerminal_Color_BackgroundYellow = 0x40, + kwsysTerminal_Color_BackgroundBlue = 0x50, + kwsysTerminal_Color_BackgroundMagenta = 0x60, + kwsysTerminal_Color_BackgroundCyan = 0x70, + kwsysTerminal_Color_BackgroundWhite = 0x80, + kwsysTerminal_Color_BackgroundMask = 0xF0, + + /* Attributes */ + kwsysTerminal_Color_ForegroundBold = 0x100, + kwsysTerminal_Color_BackgroundBold = 0x200, + kwsysTerminal_Color_AssumeTTY = 0x400, + kwsysTerminal_Color_AssumeVT100 = 0x800, + kwsysTerminal_Color_AttributeMask = 0xF00 +}; + +#if defined(__cplusplus) +} /* extern "C" */ +#endif + +/* If we are building a kwsys .c or .cxx file, let it use these macros. + Otherwise, undefine them to keep the namespace clean. */ +#if !defined(KWSYS_NAMESPACE) +# undef kwsys_ns +# undef kwsysEXPORT +# if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS +# undef kwsysTerminal_cfprintf +# undef kwsysTerminal_Color_e +# undef kwsysTerminal_Color_Normal +# undef kwsysTerminal_Color_ForegroundBlack +# undef kwsysTerminal_Color_ForegroundRed +# undef kwsysTerminal_Color_ForegroundGreen +# undef kwsysTerminal_Color_ForegroundYellow +# undef kwsysTerminal_Color_ForegroundBlue +# undef kwsysTerminal_Color_ForegroundMagenta +# undef kwsysTerminal_Color_ForegroundCyan +# undef kwsysTerminal_Color_ForegroundWhite +# undef kwsysTerminal_Color_ForegroundMask +# undef kwsysTerminal_Color_BackgroundBlack +# undef kwsysTerminal_Color_BackgroundRed +# undef kwsysTerminal_Color_BackgroundGreen +# undef kwsysTerminal_Color_BackgroundYellow +# undef kwsysTerminal_Color_BackgroundBlue +# undef kwsysTerminal_Color_BackgroundMagenta +# undef kwsysTerminal_Color_BackgroundCyan +# undef kwsysTerminal_Color_BackgroundWhite +# undef kwsysTerminal_Color_BackgroundMask +# undef kwsysTerminal_Color_ForegroundBold +# undef kwsysTerminal_Color_BackgroundBold +# undef kwsysTerminal_Color_AssumeTTY +# undef kwsysTerminal_Color_AssumeVT100 +# undef kwsysTerminal_Color_AttributeMask +# endif +#endif + +#endif diff --git a/test/API/driver/kwsys/clang-format.bash b/test/API/driver/kwsys/clang-format.bash new file mode 100644 index 0000000..b0282ab --- /dev/null +++ b/test/API/driver/kwsys/clang-format.bash @@ -0,0 +1,128 @@ +#!/usr/bin/env bash +#============================================================================= +# Copyright 2015-2017 Kitware, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============================================================================= + +usage='usage: clang-format.bash [] [--] + + --help Print usage plus more detailed help. + + --clang-format Use given clang-format tool. + + --amend Filter files changed by HEAD. + --cached Filter files locally staged for commit. + --modified Filter files locally modified from HEAD. + --tracked Filter files tracked by Git. +' + +help="$usage"' +Example to format locally modified files: + + ./clang-format.bash --modified + +Example to format locally modified files staged for commit: + + ./clang-format.bash --cached + +Example to format files modified by the most recent commit: + + ./clang-format.bash --amend + +Example to format all files: + + ./clang-format.bash --tracked + +Example to format the current topic: + + git filter-branch \ + --tree-filter "./clang-format.bash --tracked" \ + master.. +' + +die() { + echo "$@" 1>&2; exit 1 +} + +#----------------------------------------------------------------------------- + +# Parse command-line arguments. +clang_format='' +mode='' +while test "$#" != 0; do + case "$1" in + --amend) mode="amend" ;; + --cached) mode="cached" ;; + --clang-format) shift; clang_format="$1" ;; + --help) echo "$help"; exit 0 ;; + --modified) mode="modified" ;; + --tracked) mode="tracked" ;; + --) shift ; break ;; + -*) die "$usage" ;; + *) break ;; + esac + shift +done +test "$#" = 0 || die "$usage" + +# Find a default tool. +tools=' + clang-format-6.0 + clang-format +' +if test "x$clang_format" = "x"; then + for tool in $tools; do + if type -p "$tool" >/dev/null; then + clang_format="$tool" + break + fi + done +fi + +# Verify that we have a tool. +if ! type -p "$clang_format" >/dev/null; then + echo "Unable to locate a 'clang-format' tool." + exit 1 +fi + +if ! "$clang_format" --version | grep 'clang-format version 6\.0' >/dev/null 2>/dev/null; then + echo "clang-format version 6.0 is required (exactly)" + exit 1 +fi + +# Select listing mode. +case "$mode" in + '') echo "$usage"; exit 0 ;; + amend) git_ls='git diff-tree --diff-filter=AM --name-only HEAD -r --no-commit-id' ;; + cached) git_ls='git diff-index --diff-filter=AM --name-only HEAD --cached' ;; + modified) git_ls='git diff-index --diff-filter=AM --name-only HEAD' ;; + tracked) git_ls='git ls-files' ;; + *) die "invalid mode: $mode" ;; +esac + +# List files as selected above. +list_files() { + $git_ls | + + # Select sources with our attribute. + git check-attr --stdin format.clang-format | + sed -n '/: format\.clang-format: set$/ {s/:[^:]*:[^:]*$//p}' +} + +# Transform configured sources to protect @SYMBOLS@. +list_files | xargs -d '\n' sed -i 's/@\(KWSYS_[A-Z0-9_]\+\)@/x\1x/g' +# Update sources in-place. +list_files | xargs -d '\n' "$clang_format" -i +# Transform configured sources to restore @SYMBOLS@. +list_files | xargs -d '\n' sed -i 's/x\(KWSYS_[A-Z0-9_]\+\)x/@\1@/g' diff --git a/test/API/driver/kwsys/hash_fun.hxx.in b/test/API/driver/kwsys/hash_fun.hxx.in new file mode 100644 index 0000000..8626c2a --- /dev/null +++ b/test/API/driver/kwsys/hash_fun.hxx.in @@ -0,0 +1,166 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +/* + * Copyright (c) 1996 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ +#ifndef @KWSYS_NAMESPACE@_hash_fun_hxx +#define @KWSYS_NAMESPACE@_hash_fun_hxx + +#include <@KWSYS_NAMESPACE@/Configure.hxx> + +#include // size_t +#include + +namespace @KWSYS_NAMESPACE@ { + +template +struct hash +{ +}; + +inline size_t _stl_hash_string(const char* __s) +{ + unsigned long __h = 0; + for (; *__s; ++__s) + __h = 5 * __h + *__s; + + return size_t(__h); +} + +template <> +struct hash +{ + size_t operator()(const char* __s) const { return _stl_hash_string(__s); } +}; + +template <> +struct hash +{ + size_t operator()(const char* __s) const { return _stl_hash_string(__s); } +}; + +template <> +struct hash +{ + size_t operator()(const std::string& __s) const + { + return _stl_hash_string(__s.c_str()); + } +}; + +#if !defined(__BORLANDC__) +template <> +struct hash +{ + size_t operator()(const std::string& __s) const + { + return _stl_hash_string(__s.c_str()); + } +}; +#endif + +template <> +struct hash +{ + size_t operator()(char __x) const { return __x; } +}; + +template <> +struct hash +{ + size_t operator()(unsigned char __x) const { return __x; } +}; + +template <> +struct hash +{ + size_t operator()(unsigned char __x) const { return __x; } +}; + +template <> +struct hash +{ + size_t operator()(short __x) const { return __x; } +}; + +template <> +struct hash +{ + size_t operator()(unsigned short __x) const { return __x; } +}; + +template <> +struct hash +{ + size_t operator()(int __x) const { return __x; } +}; + +template <> +struct hash +{ + size_t operator()(unsigned int __x) const { return __x; } +}; + +template <> +struct hash +{ + size_t operator()(long __x) const { return __x; } +}; + +template <> +struct hash +{ + size_t operator()(unsigned long __x) const { return __x; } +}; + +// use long long or __int64 +#if @KWSYS_USE_LONG_LONG@ +template <> +struct hash +{ + size_t operator()(long long __x) const { return __x; } +}; + +template <> +struct hash +{ + size_t operator()(unsigned long long __x) const { return __x; } +}; +#elif @KWSYS_USE___INT64@ +template <> +struct hash<__int64> +{ + size_t operator()(__int64 __x) const { return __x; } +}; +template <> +struct hash +{ + size_t operator()(unsigned __int64 __x) const { return __x; } +}; +#endif // use long long or __int64 + +} // namespace @KWSYS_NAMESPACE@ + +#endif diff --git a/test/API/driver/kwsys/hash_map.hxx.in b/test/API/driver/kwsys/hash_map.hxx.in new file mode 100644 index 0000000..5f04e9c --- /dev/null +++ b/test/API/driver/kwsys/hash_map.hxx.in @@ -0,0 +1,423 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +/* + * Copyright (c) 1996 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ +#ifndef @KWSYS_NAMESPACE@_hash_map_hxx +#define @KWSYS_NAMESPACE@_hash_map_hxx + +#include <@KWSYS_NAMESPACE@/hashtable.hxx> + +#include <@KWSYS_NAMESPACE@/hash_fun.hxx> + +#include // equal_to + +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable : 4284) +# pragma warning(disable : 4786) +#endif + +#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32) +# pragma set woff 1174 +# pragma set woff 1375 +#endif + +namespace @KWSYS_NAMESPACE@ { + +// select1st is an extension: it is not part of the standard. +template +struct hash_select1st +{ + const T1& operator()(const std::pair& __x) const + { + return __x.first; + } +}; + +// Forward declaration of equality operator; needed for friend declaration. + +template , + class _EqualKey = std::equal_to<_Key>, + class _Alloc = std::allocator > +class hash_map; + +template +bool operator==(const hash_map<_Key, _Tp, _HashFn, _EqKey, _Alloc>&, + const hash_map<_Key, _Tp, _HashFn, _EqKey, _Alloc>&); + +template +class hash_map +{ +private: + typedef hashtable, _Key, _HashFcn, + hash_select1st, _EqualKey, _Alloc> + _Ht; + _Ht _M_ht; + +public: + typedef typename _Ht::key_type key_type; + typedef _Tp data_type; + typedef _Tp mapped_type; + typedef typename _Ht::value_type value_type; + typedef typename _Ht::hasher hasher; + typedef typename _Ht::key_equal key_equal; + + typedef typename _Ht::size_type size_type; + typedef typename _Ht::difference_type difference_type; + typedef typename _Ht::pointer pointer; + typedef typename _Ht::const_pointer const_pointer; + typedef typename _Ht::reference reference; + typedef typename _Ht::const_reference const_reference; + + typedef typename _Ht::iterator iterator; + typedef typename _Ht::const_iterator const_iterator; + + typedef typename _Ht::allocator_type allocator_type; + + hasher hash_funct() const { return _M_ht.hash_funct(); } + key_equal key_eq() const { return _M_ht.key_eq(); } + allocator_type get_allocator() const { return _M_ht.get_allocator(); } + +public: + hash_map() + : _M_ht(100, hasher(), key_equal(), allocator_type()) + { + } + explicit hash_map(size_type __n) + : _M_ht(__n, hasher(), key_equal(), allocator_type()) + { + } + hash_map(size_type __n, const hasher& __hf) + : _M_ht(__n, __hf, key_equal(), allocator_type()) + { + } + hash_map(size_type __n, const hasher& __hf, const key_equal& __eql, + const allocator_type& __a = allocator_type()) + : _M_ht(__n, __hf, __eql, __a) + { + } + + template + hash_map(_InputIterator __f, _InputIterator __l) + : _M_ht(100, hasher(), key_equal(), allocator_type()) + { + _M_ht.insert_unique(__f, __l); + } + template + hash_map(_InputIterator __f, _InputIterator __l, size_type __n) + : _M_ht(__n, hasher(), key_equal(), allocator_type()) + { + _M_ht.insert_unique(__f, __l); + } + template + hash_map(_InputIterator __f, _InputIterator __l, size_type __n, + const hasher& __hf) + : _M_ht(__n, __hf, key_equal(), allocator_type()) + { + _M_ht.insert_unique(__f, __l); + } + template + hash_map(_InputIterator __f, _InputIterator __l, size_type __n, + const hasher& __hf, const key_equal& __eql, + const allocator_type& __a = allocator_type()) + : _M_ht(__n, __hf, __eql, __a) + { + _M_ht.insert_unique(__f, __l); + } + +public: + size_type size() const { return _M_ht.size(); } + size_type max_size() const { return _M_ht.max_size(); } + bool empty() const { return _M_ht.empty(); } + void swap(hash_map& __hs) { _M_ht.swap(__hs._M_ht); } + + friend bool operator==<>(const hash_map&, const hash_map&); + + iterator begin() { return _M_ht.begin(); } + iterator end() { return _M_ht.end(); } + const_iterator begin() const { return _M_ht.begin(); } + const_iterator end() const { return _M_ht.end(); } + +public: + std::pair insert(const value_type& __obj) + { + return _M_ht.insert_unique(__obj); + } + template + void insert(_InputIterator __f, _InputIterator __l) + { + _M_ht.insert_unique(__f, __l); + } + std::pair insert_noresize(const value_type& __obj) + { + return _M_ht.insert_unique_noresize(__obj); + } + + iterator find(const key_type& __key) { return _M_ht.find(__key); } + const_iterator find(const key_type& __key) const + { + return _M_ht.find(__key); + } + + _Tp& operator[](const key_type& __key) + { + return _M_ht.find_or_insert(value_type(__key, _Tp())).second; + } + + size_type count(const key_type& __key) const { return _M_ht.count(__key); } + + std::pair equal_range(const key_type& __key) + { + return _M_ht.equal_range(__key); + } + std::pair equal_range( + const key_type& __key) const + { + return _M_ht.equal_range(__key); + } + + size_type erase(const key_type& __key) { return _M_ht.erase(__key); } + void erase(iterator __it) { _M_ht.erase(__it); } + void erase(iterator __f, iterator __l) { _M_ht.erase(__f, __l); } + void clear() { _M_ht.clear(); } + + void resize(size_type __hint) { _M_ht.resize(__hint); } + size_type bucket_count() const { return _M_ht.bucket_count(); } + size_type max_bucket_count() const { return _M_ht.max_bucket_count(); } + size_type elems_in_bucket(size_type __n) const + { + return _M_ht.elems_in_bucket(__n); + } +}; + +template +bool operator==(const hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm1, + const hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm2) +{ + return __hm1._M_ht == __hm2._M_ht; +} + +template +inline bool operator!=( + const hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm1, + const hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm2) +{ + return !(__hm1 == __hm2); +} + +template +inline void swap(hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm1, + hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm2) +{ + __hm1.swap(__hm2); +} + +// Forward declaration of equality operator; needed for friend declaration. + +template , + class _EqualKey = std::equal_to<_Key>, + class _Alloc = std::allocator > +class hash_multimap; + +template +bool operator==(const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm1, + const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm2); + +template +class hash_multimap +{ +private: + typedef hashtable, _Key, _HashFcn, + hash_select1st, _EqualKey, _Alloc> + _Ht; + _Ht _M_ht; + +public: + typedef typename _Ht::key_type key_type; + typedef _Tp data_type; + typedef _Tp mapped_type; + typedef typename _Ht::value_type value_type; + typedef typename _Ht::hasher hasher; + typedef typename _Ht::key_equal key_equal; + + typedef typename _Ht::size_type size_type; + typedef typename _Ht::difference_type difference_type; + typedef typename _Ht::pointer pointer; + typedef typename _Ht::const_pointer const_pointer; + typedef typename _Ht::reference reference; + typedef typename _Ht::const_reference const_reference; + + typedef typename _Ht::iterator iterator; + typedef typename _Ht::const_iterator const_iterator; + + typedef typename _Ht::allocator_type allocator_type; + + hasher hash_funct() const { return _M_ht.hash_funct(); } + key_equal key_eq() const { return _M_ht.key_eq(); } + allocator_type get_allocator() const { return _M_ht.get_allocator(); } + +public: + hash_multimap() + : _M_ht(100, hasher(), key_equal(), allocator_type()) + { + } + explicit hash_multimap(size_type __n) + : _M_ht(__n, hasher(), key_equal(), allocator_type()) + { + } + hash_multimap(size_type __n, const hasher& __hf) + : _M_ht(__n, __hf, key_equal(), allocator_type()) + { + } + hash_multimap(size_type __n, const hasher& __hf, const key_equal& __eql, + const allocator_type& __a = allocator_type()) + : _M_ht(__n, __hf, __eql, __a) + { + } + + template + hash_multimap(_InputIterator __f, _InputIterator __l) + : _M_ht(100, hasher(), key_equal(), allocator_type()) + { + _M_ht.insert_equal(__f, __l); + } + template + hash_multimap(_InputIterator __f, _InputIterator __l, size_type __n) + : _M_ht(__n, hasher(), key_equal(), allocator_type()) + { + _M_ht.insert_equal(__f, __l); + } + template + hash_multimap(_InputIterator __f, _InputIterator __l, size_type __n, + const hasher& __hf) + : _M_ht(__n, __hf, key_equal(), allocator_type()) + { + _M_ht.insert_equal(__f, __l); + } + template + hash_multimap(_InputIterator __f, _InputIterator __l, size_type __n, + const hasher& __hf, const key_equal& __eql, + const allocator_type& __a = allocator_type()) + : _M_ht(__n, __hf, __eql, __a) + { + _M_ht.insert_equal(__f, __l); + } + +public: + size_type size() const { return _M_ht.size(); } + size_type max_size() const { return _M_ht.max_size(); } + bool empty() const { return _M_ht.empty(); } + void swap(hash_multimap& __hs) { _M_ht.swap(__hs._M_ht); } + + friend bool operator==<>(const hash_multimap&, const hash_multimap&); + + iterator begin() { return _M_ht.begin(); } + iterator end() { return _M_ht.end(); } + const_iterator begin() const { return _M_ht.begin(); } + const_iterator end() const { return _M_ht.end(); } + +public: + iterator insert(const value_type& __obj) + { + return _M_ht.insert_equal(__obj); + } + template + void insert(_InputIterator __f, _InputIterator __l) + { + _M_ht.insert_equal(__f, __l); + } + iterator insert_noresize(const value_type& __obj) + { + return _M_ht.insert_equal_noresize(__obj); + } + + iterator find(const key_type& __key) { return _M_ht.find(__key); } + const_iterator find(const key_type& __key) const + { + return _M_ht.find(__key); + } + + size_type count(const key_type& __key) const { return _M_ht.count(__key); } + + std::pair equal_range(const key_type& __key) + { + return _M_ht.equal_range(__key); + } + std::pair equal_range( + const key_type& __key) const + { + return _M_ht.equal_range(__key); + } + + size_type erase(const key_type& __key) { return _M_ht.erase(__key); } + void erase(iterator __it) { _M_ht.erase(__it); } + void erase(iterator __f, iterator __l) { _M_ht.erase(__f, __l); } + void clear() { _M_ht.clear(); } + +public: + void resize(size_type __hint) { _M_ht.resize(__hint); } + size_type bucket_count() const { return _M_ht.bucket_count(); } + size_type max_bucket_count() const { return _M_ht.max_bucket_count(); } + size_type elems_in_bucket(size_type __n) const + { + return _M_ht.elems_in_bucket(__n); + } +}; + +template +bool operator==(const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm1, + const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm2) +{ + return __hm1._M_ht == __hm2._M_ht; +} + +template +inline bool operator!=( + const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm1, + const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm2) +{ + return !(__hm1 == __hm2); +} + +template +inline void swap(hash_multimap<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm1, + hash_multimap<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm2) +{ + __hm1.swap(__hm2); +} + +} // namespace @KWSYS_NAMESPACE@ + +#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32) +# pragma reset woff 1174 +# pragma reset woff 1375 +#endif + +#if defined(_MSC_VER) +# pragma warning(pop) +#endif + +#endif diff --git a/test/API/driver/kwsys/hash_set.hxx.in b/test/API/driver/kwsys/hash_set.hxx.in new file mode 100644 index 0000000..f4a37ee --- /dev/null +++ b/test/API/driver/kwsys/hash_set.hxx.in @@ -0,0 +1,392 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +/* + * Copyright (c) 1996 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ +#ifndef @KWSYS_NAMESPACE@_hash_set_hxx +#define @KWSYS_NAMESPACE@_hash_set_hxx + +#include <@KWSYS_NAMESPACE@/hashtable.hxx> + +#include <@KWSYS_NAMESPACE@/hash_fun.hxx> + +#include // equal_to + +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable : 4284) +# pragma warning(disable : 4786) +#endif + +#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32) +# pragma set woff 1174 +# pragma set woff 1375 +#endif + +namespace @KWSYS_NAMESPACE@ { + +// identity is an extension: it is not part of the standard. +template +struct _Identity +{ + const _Tp& operator()(const _Tp& __x) const { return __x; } +}; + +// Forward declaration of equality operator; needed for friend declaration. + +template , + class _EqualKey = std::equal_to<_Value>, + class _Alloc = std::allocator > +class hash_set; + +template +bool operator==(const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs1, + const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs2); + +template +class hash_set +{ +private: + typedef hashtable<_Value, _Value, _HashFcn, _Identity<_Value>, _EqualKey, + _Alloc> + _Ht; + _Ht _M_ht; + +public: + typedef typename _Ht::key_type key_type; + typedef typename _Ht::value_type value_type; + typedef typename _Ht::hasher hasher; + typedef typename _Ht::key_equal key_equal; + + typedef typename _Ht::size_type size_type; + typedef typename _Ht::difference_type difference_type; + typedef typename _Ht::const_pointer pointer; + typedef typename _Ht::const_pointer const_pointer; + typedef typename _Ht::const_reference reference; + typedef typename _Ht::const_reference const_reference; + + typedef typename _Ht::const_iterator iterator; + typedef typename _Ht::const_iterator const_iterator; + + typedef typename _Ht::allocator_type allocator_type; + + hasher hash_funct() const { return _M_ht.hash_funct(); } + key_equal key_eq() const { return _M_ht.key_eq(); } + allocator_type get_allocator() const { return _M_ht.get_allocator(); } + +public: + hash_set() + : _M_ht(100, hasher(), key_equal(), allocator_type()) + { + } + explicit hash_set(size_type __n) + : _M_ht(__n, hasher(), key_equal(), allocator_type()) + { + } + hash_set(size_type __n, const hasher& __hf) + : _M_ht(__n, __hf, key_equal(), allocator_type()) + { + } + hash_set(size_type __n, const hasher& __hf, const key_equal& __eql, + const allocator_type& __a = allocator_type()) + : _M_ht(__n, __hf, __eql, __a) + { + } + + template + hash_set(_InputIterator __f, _InputIterator __l) + : _M_ht(100, hasher(), key_equal(), allocator_type()) + { + _M_ht.insert_unique(__f, __l); + } + template + hash_set(_InputIterator __f, _InputIterator __l, size_type __n) + : _M_ht(__n, hasher(), key_equal(), allocator_type()) + { + _M_ht.insert_unique(__f, __l); + } + template + hash_set(_InputIterator __f, _InputIterator __l, size_type __n, + const hasher& __hf) + : _M_ht(__n, __hf, key_equal(), allocator_type()) + { + _M_ht.insert_unique(__f, __l); + } + template + hash_set(_InputIterator __f, _InputIterator __l, size_type __n, + const hasher& __hf, const key_equal& __eql, + const allocator_type& __a = allocator_type()) + : _M_ht(__n, __hf, __eql, __a) + { + _M_ht.insert_unique(__f, __l); + } + +public: + size_type size() const { return _M_ht.size(); } + size_type max_size() const { return _M_ht.max_size(); } + bool empty() const { return _M_ht.empty(); } + void swap(hash_set& __hs) { _M_ht.swap(__hs._M_ht); } + + friend bool operator==<>(const hash_set&, const hash_set&); + + iterator begin() const { return _M_ht.begin(); } + iterator end() const { return _M_ht.end(); } + +public: + std::pair insert(const value_type& __obj) + { + typedef typename _Ht::iterator _Ht_iterator; + std::pair<_Ht_iterator, bool> __p = _M_ht.insert_unique(__obj); + return std::pair(__p.first, __p.second); + } + template + void insert(_InputIterator __f, _InputIterator __l) + { + _M_ht.insert_unique(__f, __l); + } + std::pair insert_noresize(const value_type& __obj) + { + typedef typename _Ht::iterator _Ht_iterator; + std::pair<_Ht_iterator, bool> __p = _M_ht.insert_unique_noresize(__obj); + return std::pair(__p.first, __p.second); + } + + iterator find(const key_type& __key) const { return _M_ht.find(__key); } + + size_type count(const key_type& __key) const { return _M_ht.count(__key); } + + std::pair equal_range(const key_type& __key) const + { + return _M_ht.equal_range(__key); + } + + size_type erase(const key_type& __key) { return _M_ht.erase(__key); } + void erase(iterator __it) { _M_ht.erase(__it); } + void erase(iterator __f, iterator __l) { _M_ht.erase(__f, __l); } + void clear() { _M_ht.clear(); } + +public: + void resize(size_type __hint) { _M_ht.resize(__hint); } + size_type bucket_count() const { return _M_ht.bucket_count(); } + size_type max_bucket_count() const { return _M_ht.max_bucket_count(); } + size_type elems_in_bucket(size_type __n) const + { + return _M_ht.elems_in_bucket(__n); + } +}; + +template +bool operator==(const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs1, + const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs2) +{ + return __hs1._M_ht == __hs2._M_ht; +} + +template +inline bool operator!=( + const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs1, + const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs2) +{ + return !(__hs1 == __hs2); +} + +template +inline void swap(hash_set<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1, + hash_set<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2) +{ + __hs1.swap(__hs2); +} + +template , + class _EqualKey = std::equal_to<_Value>, + class _Alloc = std::allocator > +class hash_multiset; + +template +bool operator==(const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1, + const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2); + +template +class hash_multiset +{ +private: + typedef hashtable<_Value, _Value, _HashFcn, _Identity<_Value>, _EqualKey, + _Alloc> + _Ht; + _Ht _M_ht; + +public: + typedef typename _Ht::key_type key_type; + typedef typename _Ht::value_type value_type; + typedef typename _Ht::hasher hasher; + typedef typename _Ht::key_equal key_equal; + + typedef typename _Ht::size_type size_type; + typedef typename _Ht::difference_type difference_type; + typedef typename _Ht::const_pointer pointer; + typedef typename _Ht::const_pointer const_pointer; + typedef typename _Ht::const_reference reference; + typedef typename _Ht::const_reference const_reference; + + typedef typename _Ht::const_iterator iterator; + typedef typename _Ht::const_iterator const_iterator; + + typedef typename _Ht::allocator_type allocator_type; + + hasher hash_funct() const { return _M_ht.hash_funct(); } + key_equal key_eq() const { return _M_ht.key_eq(); } + allocator_type get_allocator() const { return _M_ht.get_allocator(); } + +public: + hash_multiset() + : _M_ht(100, hasher(), key_equal(), allocator_type()) + { + } + explicit hash_multiset(size_type __n) + : _M_ht(__n, hasher(), key_equal(), allocator_type()) + { + } + hash_multiset(size_type __n, const hasher& __hf) + : _M_ht(__n, __hf, key_equal(), allocator_type()) + { + } + hash_multiset(size_type __n, const hasher& __hf, const key_equal& __eql, + const allocator_type& __a = allocator_type()) + : _M_ht(__n, __hf, __eql, __a) + { + } + + template + hash_multiset(_InputIterator __f, _InputIterator __l) + : _M_ht(100, hasher(), key_equal(), allocator_type()) + { + _M_ht.insert_equal(__f, __l); + } + template + hash_multiset(_InputIterator __f, _InputIterator __l, size_type __n) + : _M_ht(__n, hasher(), key_equal(), allocator_type()) + { + _M_ht.insert_equal(__f, __l); + } + template + hash_multiset(_InputIterator __f, _InputIterator __l, size_type __n, + const hasher& __hf) + : _M_ht(__n, __hf, key_equal(), allocator_type()) + { + _M_ht.insert_equal(__f, __l); + } + template + hash_multiset(_InputIterator __f, _InputIterator __l, size_type __n, + const hasher& __hf, const key_equal& __eql, + const allocator_type& __a = allocator_type()) + : _M_ht(__n, __hf, __eql, __a) + { + _M_ht.insert_equal(__f, __l); + } + +public: + size_type size() const { return _M_ht.size(); } + size_type max_size() const { return _M_ht.max_size(); } + bool empty() const { return _M_ht.empty(); } + void swap(hash_multiset& hs) { _M_ht.swap(hs._M_ht); } + + friend bool operator==<>(const hash_multiset&, const hash_multiset&); + + iterator begin() const { return _M_ht.begin(); } + iterator end() const { return _M_ht.end(); } + +public: + iterator insert(const value_type& __obj) + { + return _M_ht.insert_equal(__obj); + } + template + void insert(_InputIterator __f, _InputIterator __l) + { + _M_ht.insert_equal(__f, __l); + } + iterator insert_noresize(const value_type& __obj) + { + return _M_ht.insert_equal_noresize(__obj); + } + + iterator find(const key_type& __key) const { return _M_ht.find(__key); } + + size_type count(const key_type& __key) const { return _M_ht.count(__key); } + + std::pair equal_range(const key_type& __key) const + { + return _M_ht.equal_range(__key); + } + + size_type erase(const key_type& __key) { return _M_ht.erase(__key); } + void erase(iterator __it) { _M_ht.erase(__it); } + void erase(iterator __f, iterator __l) { _M_ht.erase(__f, __l); } + void clear() { _M_ht.clear(); } + +public: + void resize(size_type __hint) { _M_ht.resize(__hint); } + size_type bucket_count() const { return _M_ht.bucket_count(); } + size_type max_bucket_count() const { return _M_ht.max_bucket_count(); } + size_type elems_in_bucket(size_type __n) const + { + return _M_ht.elems_in_bucket(__n); + } +}; + +template +bool operator==(const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1, + const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2) +{ + return __hs1._M_ht == __hs2._M_ht; +} + +template +inline bool operator!=( + const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1, + const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2) +{ + return !(__hs1 == __hs2); +} + +template +inline void swap(hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1, + hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2) +{ + __hs1.swap(__hs2); +} + +} // namespace @KWSYS_NAMESPACE@ + +#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32) +# pragma reset woff 1174 +# pragma reset woff 1375 +#endif + +#if defined(_MSC_VER) +# pragma warning(pop) +#endif + +#endif diff --git a/test/API/driver/kwsys/hashtable.hxx.in b/test/API/driver/kwsys/hashtable.hxx.in new file mode 100644 index 0000000..8c4b002 --- /dev/null +++ b/test/API/driver/kwsys/hashtable.hxx.in @@ -0,0 +1,995 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +/* + * Copyright (c) 1996 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ +#ifdef __BORLANDC__ +# pragma warn - 8027 /* 'for' not inlined. */ +# pragma warn - 8026 /* 'exception' not inlined. */ +#endif + +#ifndef @KWSYS_NAMESPACE@_hashtable_hxx +# define @KWSYS_NAMESPACE@_hashtable_hxx + +# include <@KWSYS_NAMESPACE@/Configure.hxx> + +# include // lower_bound +# include // iterator_traits +# include // allocator +# include // size_t +# include // pair +# include // vector + +# if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable : 4284) +# pragma warning(disable : 4786) +# pragma warning(disable : 4512) /* no assignment operator for class */ +# endif +# if defined(__sgi) && !defined(__GNUC__) +# pragma set woff 3970 /* pointer to int conversion */ 3321 3968 +# endif + +// In C++11, clang will warn about using dynamic exception specifications +// as they are deprecated. But as this class is trying to faithfully +// mimic unordered_set and unordered_map, we want to keep the 'throw()' +// decorations below. So we suppress the warning. +# if defined(__clang__) && defined(__has_warning) +# if __has_warning("-Wdeprecated") +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdeprecated" +# endif +# endif + +namespace @KWSYS_NAMESPACE@ { + +template +struct _Hashtable_node +{ + _Hashtable_node* _M_next; + _Val _M_val; + void public_method_to_quiet_warning_about_all_methods_private(); + +private: + void operator=(_Hashtable_node<_Val> const&) = delete; +}; + +template > +class hashtable; + +template +struct _Hashtable_iterator; + +template +struct _Hashtable_const_iterator; + +template +struct _Hashtable_iterator +{ + typedef hashtable<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc> + _Hashtable; + typedef _Hashtable_iterator<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, + _Alloc> + iterator; + typedef _Hashtable_const_iterator<_Val, _Key, _HashFcn, _ExtractKey, + _EqualKey, _Alloc> + const_iterator; + typedef _Hashtable_node<_Val> _Node; + + typedef std::forward_iterator_tag iterator_category; + typedef _Val value_type; + typedef ptrdiff_t difference_type; + typedef size_t size_type; + typedef _Val& reference; + typedef _Val* pointer; + + _Node* _M_cur; + _Hashtable* _M_ht; + + _Hashtable_iterator(_Node* __n, _Hashtable* __tab) + : _M_cur(__n) + , _M_ht(__tab) + { + } + _Hashtable_iterator() {} + reference operator*() const { return _M_cur->_M_val; } + pointer operator->() const { return &(operator*()); } + iterator& operator++(); + iterator operator++(int); + bool operator==(const iterator& __it) const { return _M_cur == __it._M_cur; } + bool operator!=(const iterator& __it) const { return _M_cur != __it._M_cur; } +}; + +template +struct _Hashtable_const_iterator +{ + typedef hashtable<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc> + _Hashtable; + typedef _Hashtable_iterator<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, + _Alloc> + iterator; + typedef _Hashtable_const_iterator<_Val, _Key, _HashFcn, _ExtractKey, + _EqualKey, _Alloc> + const_iterator; + typedef _Hashtable_node<_Val> _Node; + + typedef std::forward_iterator_tag iterator_category; + typedef _Val value_type; + typedef ptrdiff_t difference_type; + typedef size_t size_type; + typedef const _Val& reference; + typedef const _Val* pointer; + + const _Node* _M_cur; + const _Hashtable* _M_ht; + + _Hashtable_const_iterator(const _Node* __n, const _Hashtable* __tab) + : _M_cur(__n) + , _M_ht(__tab) + { + } + _Hashtable_const_iterator() {} + _Hashtable_const_iterator(const iterator& __it) + : _M_cur(__it._M_cur) + , _M_ht(__it._M_ht) + { + } + reference operator*() const { return _M_cur->_M_val; } + pointer operator->() const { return &(operator*()); } + const_iterator& operator++(); + const_iterator operator++(int); + bool operator==(const const_iterator& __it) const + { + return _M_cur == __it._M_cur; + } + bool operator!=(const const_iterator& __it) const + { + return _M_cur != __it._M_cur; + } +}; + +// Note: assumes long is at least 32 bits. +enum +{ + _stl_num_primes = 31 +}; + +// create a function with a static local to that function that returns +// the static +static inline const unsigned long* get_stl_prime_list() +{ + + static const unsigned long _stl_prime_list[_stl_num_primes] = { + 5ul, 11ul, 23ul, 53ul, 97ul, + 193ul, 389ul, 769ul, 1543ul, 3079ul, + 6151ul, 12289ul, 24593ul, 49157ul, 98317ul, + 196613ul, 393241ul, 786433ul, 1572869ul, 3145739ul, + 6291469ul, 12582917ul, 25165843ul, 50331653ul, 100663319ul, + 201326611ul, 402653189ul, 805306457ul, 1610612741ul, 3221225473ul, + 4294967291ul + }; + + return &_stl_prime_list[0]; +} + +static inline size_t _stl_next_prime(size_t __n) +{ + const unsigned long* __first = get_stl_prime_list(); + const unsigned long* __last = get_stl_prime_list() + (int)_stl_num_primes; + const unsigned long* pos = std::lower_bound(__first, __last, __n); + return pos == __last ? *(__last - 1) : *pos; +} + +// Forward declaration of operator==. + +template +class hashtable; + +template +bool operator==(const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht1, + const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht2); + +// Hashtables handle allocators a bit differently than other containers +// do. If we're using standard-conforming allocators, then a hashtable +// unconditionally has a member variable to hold its allocator, even if +// it so happens that all instances of the allocator type are identical. +// This is because, for hashtables, this extra storage is negligible. +// Additionally, a base class wouldn't serve any other purposes; it +// wouldn't, for example, simplify the exception-handling code. + +template +class hashtable +{ +public: + typedef _Key key_type; + typedef _Val value_type; + typedef _HashFcn hasher; + typedef _EqualKey key_equal; + + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + + hasher hash_funct() const { return _M_hash; } + key_equal key_eq() const { return _M_equals; } + +private: + typedef _Hashtable_node<_Val> _Node; + +public: + typedef typename _Alloc::template rebind<_Val>::other allocator_type; + allocator_type get_allocator() const { return _M_node_allocator; } + +private: + typedef + typename _Alloc::template rebind<_Node>::other _M_node_allocator_type; + typedef + typename _Alloc::template rebind<_Node*>::other _M_node_ptr_allocator_type; + typedef std::vector<_Node*, _M_node_ptr_allocator_type> _M_buckets_type; + +private: + _M_node_allocator_type _M_node_allocator; + hasher _M_hash; + key_equal _M_equals; + _ExtractKey _M_get_key; + _M_buckets_type _M_buckets; + size_type _M_num_elements; + + _Node* _M_get_node() { return _M_node_allocator.allocate(1); } + void _M_put_node(_Node* __p) { _M_node_allocator.deallocate(__p, 1); } + +public: + typedef _Hashtable_iterator<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, + _Alloc> + iterator; + typedef _Hashtable_const_iterator<_Val, _Key, _HashFcn, _ExtractKey, + _EqualKey, _Alloc> + const_iterator; + + friend struct _Hashtable_iterator<_Val, _Key, _HashFcn, _ExtractKey, + _EqualKey, _Alloc>; + friend struct _Hashtable_const_iterator<_Val, _Key, _HashFcn, _ExtractKey, + _EqualKey, _Alloc>; + +public: + hashtable(size_type __n, const _HashFcn& __hf, const _EqualKey& __eql, + const _ExtractKey& __ext, + const allocator_type& __a = allocator_type()) + : _M_node_allocator(__a) + , _M_hash(__hf) + , _M_equals(__eql) + , _M_get_key(__ext) + , _M_buckets(__a) + , _M_num_elements(0) + { + _M_initialize_buckets(__n); + } + + hashtable(size_type __n, const _HashFcn& __hf, const _EqualKey& __eql, + const allocator_type& __a = allocator_type()) + : _M_node_allocator(__a) + , _M_hash(__hf) + , _M_equals(__eql) + , _M_get_key(_ExtractKey()) + , _M_buckets(__a) + , _M_num_elements(0) + { + _M_initialize_buckets(__n); + } + + hashtable(const hashtable& __ht) + : _M_node_allocator(__ht.get_allocator()) + , _M_hash(__ht._M_hash) + , _M_equals(__ht._M_equals) + , _M_get_key(__ht._M_get_key) + , _M_buckets(__ht.get_allocator()) + , _M_num_elements(0) + { + _M_copy_from(__ht); + } + + hashtable& operator=(const hashtable& __ht) + { + if (&__ht != this) { + clear(); + _M_hash = __ht._M_hash; + _M_equals = __ht._M_equals; + _M_get_key = __ht._M_get_key; + _M_copy_from(__ht); + } + return *this; + } + + ~hashtable() { clear(); } + + size_type size() const { return _M_num_elements; } + size_type max_size() const { return size_type(-1); } + bool empty() const { return size() == 0; } + + void swap(hashtable& __ht) + { + std::swap(_M_hash, __ht._M_hash); + std::swap(_M_equals, __ht._M_equals); + std::swap(_M_get_key, __ht._M_get_key); + _M_buckets.swap(__ht._M_buckets); + std::swap(_M_num_elements, __ht._M_num_elements); + } + + iterator begin() + { + for (size_type __n = 0; __n < _M_buckets.size(); ++__n) + if (_M_buckets[__n]) + return iterator(_M_buckets[__n], this); + return end(); + } + + iterator end() { return iterator(nullptr, this); } + + const_iterator begin() const + { + for (size_type __n = 0; __n < _M_buckets.size(); ++__n) + if (_M_buckets[__n]) + return const_iterator(_M_buckets[__n], this); + return end(); + } + + const_iterator end() const { return const_iterator(nullptr, this); } + + friend bool operator==<>(const hashtable&, const hashtable&); + +public: + size_type bucket_count() const { return _M_buckets.size(); } + + size_type max_bucket_count() const + { + return get_stl_prime_list()[(int)_stl_num_primes - 1]; + } + + size_type elems_in_bucket(size_type __bucket) const + { + size_type __result = 0; + for (_Node* __cur = _M_buckets[__bucket]; __cur; __cur = __cur->_M_next) + __result += 1; + return __result; + } + + std::pair insert_unique(const value_type& __obj) + { + resize(_M_num_elements + 1); + return insert_unique_noresize(__obj); + } + + iterator insert_equal(const value_type& __obj) + { + resize(_M_num_elements + 1); + return insert_equal_noresize(__obj); + } + + std::pair insert_unique_noresize(const value_type& __obj); + iterator insert_equal_noresize(const value_type& __obj); + + template + void insert_unique(_InputIterator __f, _InputIterator __l) + { + insert_unique( + __f, __l, + typename std::iterator_traits<_InputIterator>::iterator_category()); + } + + template + void insert_equal(_InputIterator __f, _InputIterator __l) + { + insert_equal( + __f, __l, + typename std::iterator_traits<_InputIterator>::iterator_category()); + } + + template + void insert_unique(_InputIterator __f, _InputIterator __l, + std::input_iterator_tag) + { + for (; __f != __l; ++__f) + insert_unique(*__f); + } + + template + void insert_equal(_InputIterator __f, _InputIterator __l, + std::input_iterator_tag) + { + for (; __f != __l; ++__f) + insert_equal(*__f); + } + + template + void insert_unique(_ForwardIterator __f, _ForwardIterator __l, + std::forward_iterator_tag) + { + size_type __n = 0; + std::distance(__f, __l, __n); + resize(_M_num_elements + __n); + for (; __n > 0; --__n, ++__f) + insert_unique_noresize(*__f); + } + + template + void insert_equal(_ForwardIterator __f, _ForwardIterator __l, + std::forward_iterator_tag) + { + size_type __n = 0; + std::distance(__f, __l, __n); + resize(_M_num_elements + __n); + for (; __n > 0; --__n, ++__f) + insert_equal_noresize(*__f); + } + + reference find_or_insert(const value_type& __obj); + + iterator find(const key_type& __key) + { + size_type __n = _M_bkt_num_key(__key); + _Node* __first; + for (__first = _M_buckets[__n]; + __first && !_M_equals(_M_get_key(__first->_M_val), __key); + __first = __first->_M_next) { + } + return iterator(__first, this); + } + + const_iterator find(const key_type& __key) const + { + size_type __n = _M_bkt_num_key(__key); + const _Node* __first; + for (__first = _M_buckets[__n]; + __first && !_M_equals(_M_get_key(__first->_M_val), __key); + __first = __first->_M_next) { + } + return const_iterator(__first, this); + } + + size_type count(const key_type& __key) const + { + const size_type __n = _M_bkt_num_key(__key); + size_type __result = 0; + + for (const _Node* __cur = _M_buckets[__n]; __cur; __cur = __cur->_M_next) + if (_M_equals(_M_get_key(__cur->_M_val), __key)) + ++__result; + return __result; + } + + std::pair equal_range(const key_type& __key); + + std::pair equal_range( + const key_type& __key) const; + + size_type erase(const key_type& __key); + void erase(const iterator& __it); + void erase(iterator __first, iterator __last); + + void erase(const const_iterator& __it); + void erase(const_iterator __first, const_iterator __last); + + void resize(size_type __num_elements_hint); + void clear(); + +private: + size_type _M_next_size(size_type __n) const { return _stl_next_prime(__n); } + + void _M_initialize_buckets(size_type __n) + { + const size_type __n_buckets = _M_next_size(__n); + _M_buckets.reserve(__n_buckets); + _M_buckets.insert(_M_buckets.end(), __n_buckets, (_Node*)nullptr); + _M_num_elements = 0; + } + + size_type _M_bkt_num_key(const key_type& __key) const + { + return _M_bkt_num_key(__key, _M_buckets.size()); + } + + size_type _M_bkt_num(const value_type& __obj) const + { + return _M_bkt_num_key(_M_get_key(__obj)); + } + + size_type _M_bkt_num_key(const key_type& __key, size_t __n) const + { + return _M_hash(__key) % __n; + } + + size_type _M_bkt_num(const value_type& __obj, size_t __n) const + { + return _M_bkt_num_key(_M_get_key(__obj), __n); + } + + void construct(_Val* p, const _Val& v) { new (p) _Val(v); } + void destroy(_Val* p) + { + (void)p; + p->~_Val(); + } + + _Node* _M_new_node(const value_type& __obj) + { + _Node* __n = _M_get_node(); + __n->_M_next = nullptr; + try { + construct(&__n->_M_val, __obj); + return __n; + } catch (...) { + _M_put_node(__n); + throw; + } + } + + void _M_delete_node(_Node* __n) + { + destroy(&__n->_M_val); + _M_put_node(__n); + } + + void _M_erase_bucket(const size_type __n, _Node* __first, _Node* __last); + void _M_erase_bucket(const size_type __n, _Node* __last); + + void _M_copy_from(const hashtable& __ht); +}; + +template +_Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>& +_Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>::operator++() +{ + const _Node* __old = _M_cur; + _M_cur = _M_cur->_M_next; + if (!_M_cur) { + size_type __bucket = _M_ht->_M_bkt_num(__old->_M_val); + while (!_M_cur && ++__bucket < _M_ht->_M_buckets.size()) + _M_cur = _M_ht->_M_buckets[__bucket]; + } + return *this; +} + +template +inline _Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All> +_Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>::operator++(int) +{ + iterator __tmp = *this; + ++*this; + return __tmp; +} + +template +_Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>& +_Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>::operator++() +{ + const _Node* __old = _M_cur; + _M_cur = _M_cur->_M_next; + if (!_M_cur) { + size_type __bucket = _M_ht->_M_bkt_num(__old->_M_val); + while (!_M_cur && ++__bucket < _M_ht->_M_buckets.size()) + _M_cur = _M_ht->_M_buckets[__bucket]; + } + return *this; +} + +template +inline _Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All> +_Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>::operator++(int) +{ + const_iterator __tmp = *this; + ++*this; + return __tmp; +} + +template +bool operator==(const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht1, + const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht2) +{ + typedef typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::_Node _Node; + if (__ht1._M_buckets.size() != __ht2._M_buckets.size()) + return false; + for (int __n = 0; __n < __ht1._M_buckets.size(); ++__n) { + _Node* __cur1 = __ht1._M_buckets[__n]; + _Node* __cur2 = __ht2._M_buckets[__n]; + for (; __cur1 && __cur2 && __cur1->_M_val == __cur2->_M_val; + __cur1 = __cur1->_M_next, __cur2 = __cur2->_M_next) { + } + if (__cur1 || __cur2) + return false; + } + return true; +} + +template +inline bool operator!=(const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht1, + const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht2) +{ + return !(__ht1 == __ht2); +} + +template +inline void swap(hashtable<_Val, _Key, _HF, _Extract, _EqKey, _All>& __ht1, + hashtable<_Val, _Key, _HF, _Extract, _EqKey, _All>& __ht2) +{ + __ht1.swap(__ht2); +} + +template +std::pair::iterator, bool> +hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::insert_unique_noresize( + const value_type& __obj) +{ + const size_type __n = _M_bkt_num(__obj); + _Node* __first = _M_buckets[__n]; + + for (_Node* __cur = __first; __cur; __cur = __cur->_M_next) + if (_M_equals(_M_get_key(__cur->_M_val), _M_get_key(__obj))) + return std::pair(iterator(__cur, this), false); + + _Node* __tmp = _M_new_node(__obj); + __tmp->_M_next = __first; + _M_buckets[__n] = __tmp; + ++_M_num_elements; + return std::pair(iterator(__tmp, this), true); +} + +template +typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::iterator +hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::insert_equal_noresize( + const value_type& __obj) +{ + const size_type __n = _M_bkt_num(__obj); + _Node* __first = _M_buckets[__n]; + + for (_Node* __cur = __first; __cur; __cur = __cur->_M_next) + if (_M_equals(_M_get_key(__cur->_M_val), _M_get_key(__obj))) { + _Node* __tmp = _M_new_node(__obj); + __tmp->_M_next = __cur->_M_next; + __cur->_M_next = __tmp; + ++_M_num_elements; + return iterator(__tmp, this); + } + + _Node* __tmp = _M_new_node(__obj); + __tmp->_M_next = __first; + _M_buckets[__n] = __tmp; + ++_M_num_elements; + return iterator(__tmp, this); +} + +template +typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::reference +hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::find_or_insert( + const value_type& __obj) +{ + resize(_M_num_elements + 1); + + size_type __n = _M_bkt_num(__obj); + _Node* __first = _M_buckets[__n]; + + for (_Node* __cur = __first; __cur; __cur = __cur->_M_next) + if (_M_equals(_M_get_key(__cur->_M_val), _M_get_key(__obj))) + return __cur->_M_val; + + _Node* __tmp = _M_new_node(__obj); + __tmp->_M_next = __first; + _M_buckets[__n] = __tmp; + ++_M_num_elements; + return __tmp->_M_val; +} + +template +std::pair::iterator, + typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::iterator> +hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::equal_range(const key_type& __key) +{ + typedef std::pair _Pii; + const size_type __n = _M_bkt_num_key(__key); + + for (_Node* __first = _M_buckets[__n]; __first; __first = __first->_M_next) + if (_M_equals(_M_get_key(__first->_M_val), __key)) { + for (_Node* __cur = __first->_M_next; __cur; __cur = __cur->_M_next) + if (!_M_equals(_M_get_key(__cur->_M_val), __key)) + return _Pii(iterator(__first, this), iterator(__cur, this)); + for (size_type __m = __n + 1; __m < _M_buckets.size(); ++__m) + if (_M_buckets[__m]) + return _Pii(iterator(__first, this), + iterator(_M_buckets[__m], this)); + return _Pii(iterator(__first, this), end()); + } + return _Pii(end(), end()); +} + +template +std::pair::const_iterator, + typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::const_iterator> +hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::equal_range( + const key_type& __key) const +{ + typedef std::pair _Pii; + const size_type __n = _M_bkt_num_key(__key); + + for (const _Node* __first = _M_buckets[__n]; __first; + __first = __first->_M_next) { + if (_M_equals(_M_get_key(__first->_M_val), __key)) { + for (const _Node* __cur = __first->_M_next; __cur; + __cur = __cur->_M_next) + if (!_M_equals(_M_get_key(__cur->_M_val), __key)) + return _Pii(const_iterator(__first, this), + const_iterator(__cur, this)); + for (size_type __m = __n + 1; __m < _M_buckets.size(); ++__m) + if (_M_buckets[__m]) + return _Pii(const_iterator(__first, this), + const_iterator(_M_buckets[__m], this)); + return _Pii(const_iterator(__first, this), end()); + } + } + return _Pii(end(), end()); +} + +template +typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::size_type +hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::erase(const key_type& __key) +{ + const size_type __n = _M_bkt_num_key(__key); + _Node* __first = _M_buckets[__n]; + size_type __erased = 0; + + if (__first) { + _Node* __cur = __first; + _Node* __next = __cur->_M_next; + while (__next) { + if (_M_equals(_M_get_key(__next->_M_val), __key)) { + __cur->_M_next = __next->_M_next; + _M_delete_node(__next); + __next = __cur->_M_next; + ++__erased; + --_M_num_elements; + } else { + __cur = __next; + __next = __cur->_M_next; + } + } + if (_M_equals(_M_get_key(__first->_M_val), __key)) { + _M_buckets[__n] = __first->_M_next; + _M_delete_node(__first); + ++__erased; + --_M_num_elements; + } + } + return __erased; +} + +template +void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::erase(const iterator& __it) +{ + _Node* __p = __it._M_cur; + if (__p) { + const size_type __n = _M_bkt_num(__p->_M_val); + _Node* __cur = _M_buckets[__n]; + + if (__cur == __p) { + _M_buckets[__n] = __cur->_M_next; + _M_delete_node(__cur); + --_M_num_elements; + } else { + _Node* __next = __cur->_M_next; + while (__next) { + if (__next == __p) { + __cur->_M_next = __next->_M_next; + _M_delete_node(__next); + --_M_num_elements; + break; + } else { + __cur = __next; + __next = __cur->_M_next; + } + } + } + } +} + +template +void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::erase(iterator __first, + iterator __last) +{ + size_type __f_bucket = + __first._M_cur ? _M_bkt_num(__first._M_cur->_M_val) : _M_buckets.size(); + size_type __l_bucket = + __last._M_cur ? _M_bkt_num(__last._M_cur->_M_val) : _M_buckets.size(); + + if (__first._M_cur == __last._M_cur) + return; + else if (__f_bucket == __l_bucket) + _M_erase_bucket(__f_bucket, __first._M_cur, __last._M_cur); + else { + _M_erase_bucket(__f_bucket, __first._M_cur, nullptr); + for (size_type __n = __f_bucket + 1; __n < __l_bucket; ++__n) + _M_erase_bucket(__n, nullptr); + if (__l_bucket != _M_buckets.size()) + _M_erase_bucket(__l_bucket, __last._M_cur); + } +} + +template +inline void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::erase( + const_iterator __first, const_iterator __last) +{ + erase(iterator(const_cast<_Node*>(__first._M_cur), + const_cast(__first._M_ht)), + iterator(const_cast<_Node*>(__last._M_cur), + const_cast(__last._M_ht))); +} + +template +inline void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::erase( + const const_iterator& __it) +{ + erase(iterator(const_cast<_Node*>(__it._M_cur), + const_cast(__it._M_ht))); +} + +template +void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::resize( + size_type __num_elements_hint) +{ + const size_type __old_n = _M_buckets.size(); + if (__num_elements_hint > __old_n) { + const size_type __n = _M_next_size(__num_elements_hint); + if (__n > __old_n) { + _M_buckets_type __tmp(__n, (_Node*)(nullptr), + _M_buckets.get_allocator()); + try { + for (size_type __bucket = 0; __bucket < __old_n; ++__bucket) { + _Node* __first = _M_buckets[__bucket]; + while (__first) { + size_type __new_bucket = _M_bkt_num(__first->_M_val, __n); + _M_buckets[__bucket] = __first->_M_next; + __first->_M_next = __tmp[__new_bucket]; + __tmp[__new_bucket] = __first; + __first = _M_buckets[__bucket]; + } + } + _M_buckets.swap(__tmp); + } catch (...) { + for (size_type __bucket = 0; __bucket < __tmp.size(); ++__bucket) { + while (__tmp[__bucket]) { + _Node* __next = __tmp[__bucket]->_M_next; + _M_delete_node(__tmp[__bucket]); + __tmp[__bucket] = __next; + } + } + throw; + } + } + } +} + +template +void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::_M_erase_bucket( + const size_type __n, _Node* __first, _Node* __last) +{ + _Node* __cur = _M_buckets[__n]; + if (__cur == __first) + _M_erase_bucket(__n, __last); + else { + _Node* __next; + for (__next = __cur->_M_next; __next != __first; + __cur = __next, __next = __cur->_M_next) + ; + while (__next != __last) { + __cur->_M_next = __next->_M_next; + _M_delete_node(__next); + __next = __cur->_M_next; + --_M_num_elements; + } + } +} + +template +void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::_M_erase_bucket( + const size_type __n, _Node* __last) +{ + _Node* __cur = _M_buckets[__n]; + while (__cur != __last) { + _Node* __next = __cur->_M_next; + _M_delete_node(__cur); + __cur = __next; + _M_buckets[__n] = __cur; + --_M_num_elements; + } +} + +template +void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::clear() +{ + for (size_type __i = 0; __i < _M_buckets.size(); ++__i) { + _Node* __cur = _M_buckets[__i]; + while (__cur != nullptr) { + _Node* __next = __cur->_M_next; + _M_delete_node(__cur); + __cur = __next; + } + _M_buckets[__i] = nullptr; + } + _M_num_elements = 0; +} + +template +void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::_M_copy_from( + const hashtable& __ht) +{ + _M_buckets.clear(); + _M_buckets.reserve(__ht._M_buckets.size()); + _M_buckets.insert(_M_buckets.end(), __ht._M_buckets.size(), (_Node*)nullptr); + try { + for (size_type __i = 0; __i < __ht._M_buckets.size(); ++__i) { + const _Node* __cur = __ht._M_buckets[__i]; + if (__cur) { + _Node* __copy = _M_new_node(__cur->_M_val); + _M_buckets[__i] = __copy; + + for (_Node* __next = __cur->_M_next; __next; + __cur = __next, __next = __cur->_M_next) { + __copy->_M_next = _M_new_node(__next->_M_val); + __copy = __copy->_M_next; + } + } + } + _M_num_elements = __ht._M_num_elements; + } catch (...) { + clear(); + throw; + } +} + +} // namespace @KWSYS_NAMESPACE@ + +// Undo warning suppression. +# if defined(__clang__) && defined(__has_warning) +# if __has_warning("-Wdeprecated") +# pragma clang diagnostic pop +# endif +# endif + +# if defined(_MSC_VER) +# pragma warning(pop) +# endif + +#endif diff --git a/test/API/driver/kwsys/kwsysHeaderDump.pl b/test/API/driver/kwsys/kwsysHeaderDump.pl new file mode 100644 index 0000000..e3391e7 --- /dev/null +++ b/test/API/driver/kwsys/kwsysHeaderDump.pl @@ -0,0 +1,41 @@ +#!/usr/bin/perl +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing#kwsys for details. + +if ( $#ARGV+1 < 2 ) +{ + print "Usage: ./kwsysHeaderDump.pl
\n"; + exit(1); +} + +$name = $ARGV[0]; +$max = 0; +open(INFILE, $ARGV[1]); +while (chomp ($line = )) +{ + if (($line !~ /^\#/) && + ($line =~ s/.*kwsys${name}_([A-Za-z0-9_]*).*/\1/) && + ($i{$line}++ < 1)) + { + push(@lines, "$line"); + if (length($line) > $max) + { + $max = length($line); + } + } +} +close(INFILE); + +$width = $max + 13; +print sprintf("#define %-${width}s kwsys_ns(${name})\n", "kwsys${name}"); +foreach $l (@lines) +{ + print sprintf("#define %-${width}s kwsys_ns(${name}_$l)\n", + "kwsys${name}_$l"); +} +print "\n"; +print sprintf("# undef kwsys${name}\n"); +foreach $l (@lines) +{ + print sprintf("# undef kwsys${name}_$l\n"); +} diff --git a/test/API/driver/kwsys/kwsysPlatformTests.cmake b/test/API/driver/kwsys/kwsysPlatformTests.cmake new file mode 100644 index 0000000..28d3f68 --- /dev/null +++ b/test/API/driver/kwsys/kwsysPlatformTests.cmake @@ -0,0 +1,216 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing#kwsys for details. + +SET(KWSYS_PLATFORM_TEST_FILE_C kwsysPlatformTestsC.c) +SET(KWSYS_PLATFORM_TEST_FILE_CXX kwsysPlatformTestsCXX.cxx) + +MACRO(KWSYS_PLATFORM_TEST lang var description invert) + IF(NOT DEFINED ${var}_COMPILED) + MESSAGE(STATUS "${description}") + set(maybe_cxx_standard "") + if(CMAKE_VERSION VERSION_LESS 3.8 AND CMAKE_CXX_STANDARD) + set(maybe_cxx_standard "-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}") + endif() + TRY_COMPILE(${var}_COMPILED + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/${KWSYS_PLATFORM_TEST_FILE_${lang}} + COMPILE_DEFINITIONS -DTEST_${var} ${KWSYS_PLATFORM_TEST_DEFINES} ${KWSYS_PLATFORM_TEST_EXTRA_FLAGS} + CMAKE_FLAGS "-DLINK_LIBRARIES:STRING=${KWSYS_PLATFORM_TEST_LINK_LIBRARIES}" + ${maybe_cxx_standard} + OUTPUT_VARIABLE OUTPUT) + IF(${var}_COMPILED) + FILE(APPEND + ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "${description} compiled with the following output:\n${OUTPUT}\n\n") + ELSE() + FILE(APPEND + ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "${description} failed to compile with the following output:\n${OUTPUT}\n\n") + ENDIF() + IF(${invert} MATCHES INVERT) + IF(${var}_COMPILED) + MESSAGE(STATUS "${description} - no") + ELSE() + MESSAGE(STATUS "${description} - yes") + ENDIF() + ELSE() + IF(${var}_COMPILED) + MESSAGE(STATUS "${description} - yes") + ELSE() + MESSAGE(STATUS "${description} - no") + ENDIF() + ENDIF() + ENDIF() + IF(${invert} MATCHES INVERT) + IF(${var}_COMPILED) + SET(${var} 0) + ELSE() + SET(${var} 1) + ENDIF() + ELSE() + IF(${var}_COMPILED) + SET(${var} 1) + ELSE() + SET(${var} 0) + ENDIF() + ENDIF() +ENDMACRO() + +MACRO(KWSYS_PLATFORM_TEST_RUN lang var description invert) + IF(NOT DEFINED ${var}) + MESSAGE(STATUS "${description}") + TRY_RUN(${var} ${var}_COMPILED + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/${KWSYS_PLATFORM_TEST_FILE_${lang}} + COMPILE_DEFINITIONS -DTEST_${var} ${KWSYS_PLATFORM_TEST_DEFINES} ${KWSYS_PLATFORM_TEST_EXTRA_FLAGS} + OUTPUT_VARIABLE OUTPUT) + + # Note that ${var} will be a 0 return value on success. + IF(${var}_COMPILED) + IF(${var}) + FILE(APPEND + ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "${description} compiled but failed to run with the following output:\n${OUTPUT}\n\n") + ELSE() + FILE(APPEND + ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "${description} compiled and ran with the following output:\n${OUTPUT}\n\n") + ENDIF() + ELSE() + FILE(APPEND + ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "${description} failed to compile with the following output:\n${OUTPUT}\n\n") + SET(${var} -1 CACHE INTERNAL "${description} failed to compile.") + ENDIF() + + IF(${invert} MATCHES INVERT) + IF(${var}_COMPILED) + IF(${var}) + MESSAGE(STATUS "${description} - yes") + ELSE() + MESSAGE(STATUS "${description} - no") + ENDIF() + ELSE() + MESSAGE(STATUS "${description} - failed to compile") + ENDIF() + ELSE() + IF(${var}_COMPILED) + IF(${var}) + MESSAGE(STATUS "${description} - no") + ELSE() + MESSAGE(STATUS "${description} - yes") + ENDIF() + ELSE() + MESSAGE(STATUS "${description} - failed to compile") + ENDIF() + ENDIF() + ENDIF() + + IF(${invert} MATCHES INVERT) + IF(${var}_COMPILED) + IF(${var}) + SET(${var} 1) + ELSE() + SET(${var} 0) + ENDIF() + ELSE() + SET(${var} 1) + ENDIF() + ELSE() + IF(${var}_COMPILED) + IF(${var}) + SET(${var} 0) + ELSE() + SET(${var} 1) + ENDIF() + ELSE() + SET(${var} 0) + ENDIF() + ENDIF() +ENDMACRO() + +MACRO(KWSYS_PLATFORM_C_TEST var description invert) + SET(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_C_TEST_DEFINES}) + SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_C_TEST_EXTRA_FLAGS}) + KWSYS_PLATFORM_TEST(C "${var}" "${description}" "${invert}") + SET(KWSYS_PLATFORM_TEST_DEFINES) + SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS) +ENDMACRO() + +MACRO(KWSYS_PLATFORM_C_TEST_RUN var description invert) + SET(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_C_TEST_DEFINES}) + SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_C_TEST_EXTRA_FLAGS}) + KWSYS_PLATFORM_TEST_RUN(C "${var}" "${description}" "${invert}") + SET(KWSYS_PLATFORM_TEST_DEFINES) + SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS) +ENDMACRO() + +MACRO(KWSYS_PLATFORM_CXX_TEST var description invert) + SET(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_CXX_TEST_DEFINES}) + SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_CXX_TEST_EXTRA_FLAGS}) + SET(KWSYS_PLATFORM_TEST_LINK_LIBRARIES ${KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES}) + KWSYS_PLATFORM_TEST(CXX "${var}" "${description}" "${invert}") + SET(KWSYS_PLATFORM_TEST_DEFINES) + SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS) + SET(KWSYS_PLATFORM_TEST_LINK_LIBRARIES) +ENDMACRO() + +MACRO(KWSYS_PLATFORM_CXX_TEST_RUN var description invert) + SET(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_CXX_TEST_DEFINES}) + SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_CXX_TEST_EXTRA_FLAGS}) + KWSYS_PLATFORM_TEST_RUN(CXX "${var}" "${description}" "${invert}") + SET(KWSYS_PLATFORM_TEST_DEFINES) + SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS) +ENDMACRO() + +#----------------------------------------------------------------------------- +# KWSYS_PLATFORM_INFO_TEST(lang var description) +# +# Compile test named by ${var} and store INFO strings extracted from binary. +MACRO(KWSYS_PLATFORM_INFO_TEST lang var description) + # We can implement this macro on CMake 2.6 and above. + IF("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.6) + SET(${var} "") + ELSE() + # Choose a location for the result binary. + SET(KWSYS_PLATFORM_INFO_FILE + ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/${var}.bin) + + # Compile the test binary. + IF(NOT EXISTS ${KWSYS_PLATFORM_INFO_FILE}) + MESSAGE(STATUS "${description}") + TRY_COMPILE(${var}_COMPILED + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/${KWSYS_PLATFORM_TEST_FILE_${lang}} + COMPILE_DEFINITIONS -DTEST_${var} + ${KWSYS_PLATFORM_${lang}_TEST_DEFINES} + ${KWSYS_PLATFORM_${lang}_TEST_EXTRA_FLAGS} + OUTPUT_VARIABLE OUTPUT + COPY_FILE ${KWSYS_PLATFORM_INFO_FILE} + ) + IF(${var}_COMPILED) + FILE(APPEND + ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "${description} compiled with the following output:\n${OUTPUT}\n\n") + ELSE() + FILE(APPEND + ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "${description} failed to compile with the following output:\n${OUTPUT}\n\n") + ENDIF() + IF(${var}_COMPILED) + MESSAGE(STATUS "${description} - compiled") + ELSE() + MESSAGE(STATUS "${description} - failed") + ENDIF() + ENDIF() + + # Parse info strings out of the compiled binary. + IF(${var}_COMPILED) + FILE(STRINGS ${KWSYS_PLATFORM_INFO_FILE} ${var} REGEX "INFO:[A-Za-z0-9]+\\[[^]]*\\]") + ELSE() + SET(${var} "") + ENDIF() + + SET(KWSYS_PLATFORM_INFO_FILE) + ENDIF() +ENDMACRO() diff --git a/test/API/driver/kwsys/kwsysPlatformTestsC.c b/test/API/driver/kwsys/kwsysPlatformTestsC.c new file mode 100644 index 0000000..b0cf7ad --- /dev/null +++ b/test/API/driver/kwsys/kwsysPlatformTestsC.c @@ -0,0 +1,108 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +/* + Macros to define main() in a cross-platform way. + + Usage: + + int KWSYS_PLATFORM_TEST_C_MAIN() + { + return 0; + } + + int KWSYS_PLATFORM_TEST_C_MAIN_ARGS(argc, argv) + { + (void)argc; (void)argv; + return 0; + } +*/ +#if defined(__CLASSIC_C__) +# define KWSYS_PLATFORM_TEST_C_MAIN() main() +# define KWSYS_PLATFORM_TEST_C_MAIN_ARGS(argc, argv) \ + main(argc, argv) int argc; \ + char* argv[]; +#else +# define KWSYS_PLATFORM_TEST_C_MAIN() main(void) +# define KWSYS_PLATFORM_TEST_C_MAIN_ARGS(argc, argv) \ + main(int argc, char* argv[]) +#endif + +#ifdef TEST_KWSYS_C_HAS_PTRDIFF_T +# include +int f(ptrdiff_t n) +{ + return n > 0; +} +int KWSYS_PLATFORM_TEST_C_MAIN() +{ + char* p = 0; + ptrdiff_t d = p - p; + (void)d; + return f(p - p); +} +#endif + +#ifdef TEST_KWSYS_C_HAS_SSIZE_T +# include +int f(ssize_t n) +{ + return (int)n; +} +int KWSYS_PLATFORM_TEST_C_MAIN() +{ + ssize_t n = 0; + return f(n); +} +#endif + +#ifdef TEST_KWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC +# if defined(__APPLE__) +# include +# if MAC_OS_X_VERSION_MIN_REQUIRED < 101200 +# error "clock_gettime not available on macOS < 10.12" +# endif +# endif +# include +int KWSYS_PLATFORM_TEST_C_MAIN() +{ + struct timespec ts; + return clock_gettime(CLOCK_MONOTONIC, &ts); +} +#endif + +#ifdef TEST_KWSYS_C_TYPE_MACROS +char* info_macros = +# if defined(__SIZEOF_SHORT__) + "INFO:macro[__SIZEOF_SHORT__]\n" +# endif +# if defined(__SIZEOF_INT__) + "INFO:macro[__SIZEOF_INT__]\n" +# endif +# if defined(__SIZEOF_LONG__) + "INFO:macro[__SIZEOF_LONG__]\n" +# endif +# if defined(__SIZEOF_LONG_LONG__) + "INFO:macro[__SIZEOF_LONG_LONG__]\n" +# endif +# if defined(__SHORT_MAX__) + "INFO:macro[__SHORT_MAX__]\n" +# endif +# if defined(__INT_MAX__) + "INFO:macro[__INT_MAX__]\n" +# endif +# if defined(__LONG_MAX__) + "INFO:macro[__LONG_MAX__]\n" +# endif +# if defined(__LONG_LONG_MAX__) + "INFO:macro[__LONG_LONG_MAX__]\n" +# endif + ""; + +int KWSYS_PLATFORM_TEST_C_MAIN_ARGS(argc, argv) +{ + int require = 0; + require += info_macros[argc]; + (void)argv; + return require; +} +#endif diff --git a/test/API/driver/kwsys/kwsysPlatformTestsCXX.cxx b/test/API/driver/kwsys/kwsysPlatformTestsCXX.cxx new file mode 100644 index 0000000..cfd5666 --- /dev/null +++ b/test/API/driver/kwsys/kwsysPlatformTestsCXX.cxx @@ -0,0 +1,335 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifdef TEST_KWSYS_CXX_HAS_CSTDIO +# include +int main() +{ + return 0; +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_LONG_LONG +long long f(long long n) +{ + return n; +} +int main() +{ + long long n = 0; + return static_cast(f(n)); +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS___INT64 +__int64 f(__int64 n) +{ + return n; +} +int main() +{ + __int64 n = 0; + return static_cast(f(n)); +} +#endif + +#ifdef TEST_KWSYS_CXX_STAT_HAS_ST_MTIM +# include + +# include +# include +int main() +{ + struct stat stat1; + (void)stat1.st_mtim.tv_sec; + (void)stat1.st_mtim.tv_nsec; + return 0; +} +#endif + +#ifdef TEST_KWSYS_CXX_STAT_HAS_ST_MTIMESPEC +# include + +# include +# include +int main() +{ + struct stat stat1; + (void)stat1.st_mtimespec.tv_sec; + (void)stat1.st_mtimespec.tv_nsec; + return 0; +} +#endif + +#ifdef TEST_KWSYS_CXX_SAME_LONG_AND___INT64 +void function(long**) +{ +} +int main() +{ + __int64** p = 0; + function(p); + return 0; +} +#endif + +#ifdef TEST_KWSYS_CXX_SAME_LONG_LONG_AND___INT64 +void function(long long**) +{ +} +int main() +{ + __int64** p = 0; + function(p); + return 0; +} +#endif + +#ifdef TEST_KWSYS_IOS_HAS_ISTREAM_LONG_LONG +# include +int test_istream(std::istream& is, long long& x) +{ + return (is >> x) ? 1 : 0; +} +int main() +{ + long long x = 0; + return test_istream(std::cin, x); +} +#endif + +#ifdef TEST_KWSYS_IOS_HAS_OSTREAM_LONG_LONG +# include +int test_ostream(std::ostream& os, long long x) +{ + return (os << x) ? 1 : 0; +} +int main() +{ + long long x = 0; + return test_ostream(std::cout, x); +} +#endif + +#ifdef TEST_KWSYS_IOS_HAS_ISTREAM___INT64 +# include +int test_istream(std::istream& is, __int64& x) +{ + return (is >> x) ? 1 : 0; +} +int main() +{ + __int64 x = 0; + return test_istream(std::cin, x); +} +#endif + +#ifdef TEST_KWSYS_IOS_HAS_OSTREAM___INT64 +# include +int test_ostream(std::ostream& os, __int64 x) +{ + return (os << x) ? 1 : 0; +} +int main() +{ + __int64 x = 0; + return test_ostream(std::cout, x); +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_SETENV +# include +int main() +{ + return setenv("A", "B", 1); +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_UNSETENV +# include +int main() +{ + unsetenv("A"); + return 0; +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H +# include +int main() +{ + char* e = environ[0]; + return e ? 0 : 1; +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_GETLOADAVG +// Match feature definitions from SystemInformation.cxx +# if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE) +# define _GNU_SOURCE +# endif +# include +int main() +{ + double loadavg[3] = { 0.0, 0.0, 0.0 }; + return getloadavg(loadavg, 3); +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_RLIMIT64 +# include +int main() +{ + struct rlimit64 rlim; + return getrlimit64(0, &rlim); +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_ATOLL +# include +int main() +{ + const char* str = "1024"; + return static_cast(atoll(str)); +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_ATOL +# include +int main() +{ + const char* str = "1024"; + return static_cast(atol(str)); +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS__ATOI64 +# include +int main() +{ + const char* str = "1024"; + return static_cast(_atoi64(str)); +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_UTIMES +# include +int main() +{ + struct timeval* current_time = 0; + return utimes("/example", current_time); +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_UTIMENSAT +# include +# include +# if defined(__APPLE__) +# include +# if MAC_OS_X_VERSION_MIN_REQUIRED < 101300 +# error "utimensat not available on macOS < 10.13" +# endif +# endif +int main() +{ + struct timespec times[2] = { { 0, UTIME_OMIT }, { 0, UTIME_NOW } }; + return utimensat(AT_FDCWD, "/example", times, AT_SYMLINK_NOFOLLOW); +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_BACKTRACE +# if defined(__PATHSCALE__) || defined(__PATHCC__) || \ + (defined(__LSB_VERSION__) && (__LSB_VERSION__ < 41)) +backtrace does not work with this compiler or os +# endif +# if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE) +# define _GNU_SOURCE +# endif +# include +int main() +{ + void* stackSymbols[256]; + backtrace(stackSymbols, 256); + backtrace_symbols(&stackSymbols[0], 1); + return 0; +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_DLADDR +# if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE) +# define _GNU_SOURCE +# endif +# include +int main() +{ + Dl_info info; + int ierr = dladdr((void*)main, &info); + return 0; +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_CXXABI +# if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE) +# define _GNU_SOURCE +# endif +# if defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5130 && __linux && \ + __SUNPRO_CC_COMPAT == 'G' +# include +# endif +# include +int main() +{ + int status = 0; + size_t bufferLen = 512; + char buffer[512] = { '\0' }; + const char* function = "_ZN5kwsys17SystemInformation15GetProgramStackEii"; + char* demangledFunction = + abi::__cxa_demangle(function, buffer, &bufferLen, &status); + return status; +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_BORLAND_ASM +int main() +{ + int a = 1; + __asm { + xor EBX, EBX; + mov a, EBX; + } + + return a; +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_BORLAND_ASM_CPUID +int main() +{ + int a = 0; + __asm { + xor EAX, EAX; + cpuid; + mov a, EAX; + } + + return a; +} +#endif + +#ifdef TEST_KWSYS_STL_HAS_WSTRING +# include +void f(std::wstring*) +{ +} +int main() +{ + return 0; +} +#endif + +#ifdef TEST_KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H +# include +int main() +{ + return 0; +} +#endif diff --git a/test/API/driver/kwsys/kwsysPrivate.h b/test/API/driver/kwsys/kwsysPrivate.h new file mode 100644 index 0000000..dd9c127 --- /dev/null +++ b/test/API/driver/kwsys/kwsysPrivate.h @@ -0,0 +1,34 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef KWSYS_NAMESPACE +# error "Do not include kwsysPrivate.h outside of kwsys c and cxx files." +#endif + +#ifndef _kwsysPrivate_h +# define _kwsysPrivate_h + +/* + Define KWSYS_HEADER macro to help the c and cxx files include kwsys + headers from the configured namespace directory. The macro can be + used like this: + + #include KWSYS_HEADER(Directory.hxx) + #include KWSYS_HEADER(std/vector) +*/ +/* clang-format off */ +#define KWSYS_HEADER(x) KWSYS_HEADER0(KWSYS_NAMESPACE/x) +/* clang-format on */ +# define KWSYS_HEADER0(x) KWSYS_HEADER1(x) +# define KWSYS_HEADER1(x) + +/* + Define KWSYS_NAMESPACE_STRING to be a string constant containing the + name configured for this instance of the kwsys library. +*/ +# define KWSYS_NAMESPACE_STRING KWSYS_NAMESPACE_STRING0(KWSYS_NAMESPACE) +# define KWSYS_NAMESPACE_STRING0(x) KWSYS_NAMESPACE_STRING1(x) +# define KWSYS_NAMESPACE_STRING1(x) # x + +#else +# error "kwsysPrivate.h included multiple times." +#endif diff --git a/test/API/driver/kwsys/testCommandLineArguments.cxx b/test/API/driver/kwsys/testCommandLineArguments.cxx new file mode 100644 index 0000000..1778a9b --- /dev/null +++ b/test/API/driver/kwsys/testCommandLineArguments.cxx @@ -0,0 +1,209 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(CommandLineArguments.hxx) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "CommandLineArguments.hxx.in" +#endif + +#include +#include + +#include /* size_t */ +#include /* strcmp */ + +static void* random_ptr = reinterpret_cast(0x123); + +static int argument(const char* arg, const char* value, void* call_data) +{ + std::cout << "Got argument: \"" << arg << "\" value: \"" + << (value ? value : "(null)") << "\"" << std::endl; + if (call_data != random_ptr) { + std::cerr << "Problem processing call_data" << std::endl; + return 0; + } + return 1; +} + +static int unknown_argument(const char* argument, void* call_data) +{ + std::cout << "Got unknown argument: \"" << argument << "\"" << std::endl; + if (call_data != random_ptr) { + std::cerr << "Problem processing call_data" << std::endl; + return 0; + } + return 1; +} + +static bool CompareTwoItemsOnList(bool i1, bool i2) +{ + return i1 == i2; +} +static bool CompareTwoItemsOnList(int i1, int i2) +{ + return i1 == i2; +} +static bool CompareTwoItemsOnList(double i1, double i2) +{ + return i1 == i2; +} +static bool CompareTwoItemsOnList(const char* i1, const char* i2) +{ + return strcmp(i1, i2) == 0; +} +static bool CompareTwoItemsOnList(const std::string& i1, const std::string& i2) +{ + return i1 == i2; +} + +int testCommandLineArguments(int argc, char* argv[]) +{ + // Example run: ./testCommandLineArguments --some-int-variable 4 + // --another-bool-variable --some-bool-variable=yes + // --some-stl-string-variable=foobar --set-bool-arg1 --set-bool-arg2 + // --some-string-variable=hello + + int res = 0; + kwsys::CommandLineArguments arg; + arg.Initialize(argc, argv); + + // For error handling + arg.SetClientData(random_ptr); + arg.SetUnknownArgumentCallback(unknown_argument); + + int some_int_variable = 10; + double some_double_variable = 10.10; + char* some_string_variable = nullptr; + std::string some_stl_string_variable; + bool some_bool_variable = false; + bool some_bool_variable1 = false; + bool bool_arg1 = false; + int bool_arg2 = 0; + + std::vector numbers_argument; + int valid_numbers[] = { 5, 1, 8, 3, 7, 1, 3, 9, 7, 1 }; + + std::vector doubles_argument; + double valid_doubles[] = { 12.5, 1.31, 22 }; + + std::vector bools_argument; + bool valid_bools[] = { true, true, false }; + + std::vector strings_argument; + const char* valid_strings[] = { "andy", "bill", "brad", "ken" }; + + std::vector stl_strings_argument; + std::string valid_stl_strings[] = { "ken", "brad", "bill", "andy" }; + + typedef kwsys::CommandLineArguments argT; + + arg.AddArgument("--some-int-variable", argT::SPACE_ARGUMENT, + &some_int_variable, "Set some random int variable"); + arg.AddArgument("--some-double-variable", argT::CONCAT_ARGUMENT, + &some_double_variable, "Set some random double variable"); + arg.AddArgument("--some-string-variable", argT::EQUAL_ARGUMENT, + &some_string_variable, "Set some random string variable"); + arg.AddArgument("--some-stl-string-variable", argT::EQUAL_ARGUMENT, + &some_stl_string_variable, + "Set some random stl string variable"); + arg.AddArgument("--some-bool-variable", argT::EQUAL_ARGUMENT, + &some_bool_variable, "Set some random bool variable"); + arg.AddArgument("--another-bool-variable", argT::NO_ARGUMENT, + &some_bool_variable1, "Set some random bool variable 1"); + arg.AddBooleanArgument("--set-bool-arg1", &bool_arg1, + "Test AddBooleanArgument 1"); + arg.AddBooleanArgument("--set-bool-arg2", &bool_arg2, + "Test AddBooleanArgument 2"); + arg.AddArgument("--some-multi-argument", argT::MULTI_ARGUMENT, + &numbers_argument, "Some multiple values variable"); + arg.AddArgument("-N", argT::SPACE_ARGUMENT, &doubles_argument, + "Some explicit multiple values variable"); + arg.AddArgument("-BB", argT::CONCAT_ARGUMENT, &bools_argument, + "Some explicit multiple values variable"); + arg.AddArgument("-SS", argT::EQUAL_ARGUMENT, &strings_argument, + "Some explicit multiple values variable"); + arg.AddArgument("-SSS", argT::MULTI_ARGUMENT, &stl_strings_argument, + "Some explicit multiple values variable"); + + arg.AddCallback("-A", argT::NO_ARGUMENT, argument, random_ptr, + "Some option -A. This option has a multiline comment. It " + "should demonstrate how the code splits lines."); + arg.AddCallback("-B", argT::SPACE_ARGUMENT, argument, random_ptr, + "Option -B takes argument with space"); + arg.AddCallback("-C", argT::EQUAL_ARGUMENT, argument, random_ptr, + "Option -C takes argument after ="); + arg.AddCallback("-D", argT::CONCAT_ARGUMENT, argument, random_ptr, + "This option takes concatenated argument"); + arg.AddCallback("--long1", argT::NO_ARGUMENT, argument, random_ptr, "-A"); + arg.AddCallback("--long2", argT::SPACE_ARGUMENT, argument, random_ptr, "-B"); + arg.AddCallback("--long3", argT::EQUAL_ARGUMENT, argument, random_ptr, + "Same as -C but a bit different"); + arg.AddCallback("--long4", argT::CONCAT_ARGUMENT, argument, random_ptr, + "-C"); + + if (!arg.Parse()) { + std::cerr << "Problem parsing arguments" << std::endl; + res = 1; + } + std::cout << "Help: " << arg.GetHelp() << std::endl; + + std::cout << "Some int variable was set to: " << some_int_variable + << std::endl; + std::cout << "Some double variable was set to: " << some_double_variable + << std::endl; + if (some_string_variable && + strcmp(some_string_variable, "test string with space") == 0) { + std::cout << "Some string variable was set to: " << some_string_variable + << std::endl; + delete[] some_string_variable; + } else { + std::cerr << "Problem setting string variable" << std::endl; + res = 1; + } + size_t cc; +#define CompareTwoLists(list1, list_valid, lsize) \ + do { \ + if (list1.size() != lsize) { \ + std::cerr << "Problem setting " #list1 ". Size is: " << list1.size() \ + << " should be: " << lsize << std::endl; \ + res = 1; \ + } else { \ + std::cout << #list1 " argument set:"; \ + for (cc = 0; cc < lsize; ++cc) { \ + std::cout << " " << list1[cc]; \ + if (!CompareTwoItemsOnList(list1[cc], list_valid[cc])) { \ + std::cerr << "Problem setting " #list1 ". Value of " << cc \ + << " is: [" << list1[cc] << "] <> [" << list_valid[cc] \ + << "]" << std::endl; \ + res = 1; \ + break; \ + } \ + } \ + std::cout << std::endl; \ + } \ + } while (0) + CompareTwoLists(numbers_argument, valid_numbers, 10); + CompareTwoLists(doubles_argument, valid_doubles, 3); + CompareTwoLists(bools_argument, valid_bools, 3); + CompareTwoLists(strings_argument, valid_strings, 4); + CompareTwoLists(stl_strings_argument, valid_stl_strings, 4); + + std::cout << "Some STL String variable was set to: " + << some_stl_string_variable << std::endl; + std::cout << "Some bool variable was set to: " << some_bool_variable + << std::endl; + std::cout << "Some bool variable was set to: " << some_bool_variable1 + << std::endl; + std::cout << "bool_arg1 variable was set to: " << bool_arg1 << std::endl; + std::cout << "bool_arg2 variable was set to: " << bool_arg2 << std::endl; + std::cout << std::endl; + + for (cc = 0; cc < strings_argument.size(); ++cc) { + delete[] strings_argument[cc]; + strings_argument[cc] = nullptr; + } + return res; +} diff --git a/test/API/driver/kwsys/testCommandLineArguments1.cxx b/test/API/driver/kwsys/testCommandLineArguments1.cxx new file mode 100644 index 0000000..64561b1 --- /dev/null +++ b/test/API/driver/kwsys/testCommandLineArguments1.cxx @@ -0,0 +1,93 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(CommandLineArguments.hxx) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "CommandLineArguments.hxx.in" +#endif + +#include +#include + +#include /* assert */ +#include /* strcmp */ + +int testCommandLineArguments1(int argc, char* argv[]) +{ + kwsys::CommandLineArguments arg; + arg.Initialize(argc, argv); + + int n = 0; + char* m = nullptr; + std::string p; + int res = 0; + + typedef kwsys::CommandLineArguments argT; + arg.AddArgument("-n", argT::SPACE_ARGUMENT, &n, "Argument N"); + arg.AddArgument("-m", argT::EQUAL_ARGUMENT, &m, "Argument M"); + arg.AddBooleanArgument("-p", &p, "Argument P"); + + arg.StoreUnusedArguments(true); + + if (!arg.Parse()) { + std::cerr << "Problem parsing arguments" << std::endl; + res = 1; + } + if (n != 24) { + std::cout << "Problem setting N. Value of N: " << n << std::endl; + res = 1; + } + if (!m || strcmp(m, "test value") != 0) { + std::cout << "Problem setting M. Value of M: " << m << std::endl; + res = 1; + } + if (p != "1") { + std::cout << "Problem setting P. Value of P: " << p << std::endl; + res = 1; + } + std::cout << "Value of N: " << n << std::endl; + std::cout << "Value of M: " << m << std::endl; + std::cout << "Value of P: " << p << std::endl; + if (m) { + delete[] m; + } + + char** newArgv = nullptr; + int newArgc = 0; + arg.GetUnusedArguments(&newArgc, &newArgv); + int cc; + const char* valid_unused_args[9] = { nullptr, + "--ignored", + "--second-ignored", + "third-ignored", + "some", + "junk", + "at", + "the", + "end" }; + if (newArgc != 9) { + std::cerr << "Bad number of unused arguments: " << newArgc << std::endl; + res = 1; + } + for (cc = 0; cc < newArgc; ++cc) { + assert(newArgv[cc]); /* Quiet Clang scan-build. */ + std::cout << "Unused argument[" << cc << "] = [" << newArgv[cc] << "]" + << std::endl; + if (cc >= 9) { + std::cerr << "Too many unused arguments: " << cc << std::endl; + res = 1; + } else if (valid_unused_args[cc] && + strcmp(valid_unused_args[cc], newArgv[cc]) != 0) { + std::cerr << "Bad unused argument [" << cc << "] \"" << newArgv[cc] + << "\" should be: \"" << valid_unused_args[cc] << "\"" + << std::endl; + res = 1; + } + } + arg.DeleteRemainingArguments(newArgc, &newArgv); + + return res; +} diff --git a/test/API/driver/kwsys/testConfigure.cxx b/test/API/driver/kwsys/testConfigure.cxx new file mode 100644 index 0000000..a3c2ed3 --- /dev/null +++ b/test/API/driver/kwsys/testConfigure.cxx @@ -0,0 +1,30 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying +file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(Configure.hxx) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "Configure.hxx.in" +#endif + +static bool testFallthrough(int n) +{ + int r = 0; + switch (n) { + case 1: + ++r; + KWSYS_FALLTHROUGH; + default: + ++r; + } + return r == 2; +} + +int testConfigure(int, char* []) +{ + bool res = true; + res = testFallthrough(1) && res; + return res ? 0 : 1; +} diff --git a/test/API/driver/kwsys/testConsoleBuf.cxx b/test/API/driver/kwsys/testConsoleBuf.cxx new file mode 100644 index 0000000..4b7ddf0 --- /dev/null +++ b/test/API/driver/kwsys/testConsoleBuf.cxx @@ -0,0 +1,782 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" + +// Ignore Windows version levels defined by command-line flags. This +// source needs access to all APIs available on the host in order for +// the test to run properly. The test binary is not installed anyway. +#undef _WIN32_WINNT +#undef NTDDI_VERSION + +#include KWSYS_HEADER(Encoding.hxx) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "Encoding.hxx.in" +#endif + +#if defined(_WIN32) + +# include +# include +# include +# include +# include +# include +# include + +# include "testConsoleBuf.hxx" + +# if defined(_MSC_VER) && _MSC_VER >= 1800 +# define KWSYS_WINDOWS_DEPRECATED_GetVersion +# endif +// يونيكود +static const WCHAR UnicodeInputTestString[] = + L"\u064A\u0648\u0646\u064A\u0643\u0648\u062F!"; +static UINT TestCodepage = KWSYS_ENCODING_DEFAULT_CODEPAGE; + +static const DWORD waitTimeout = 10 * 1000; +static STARTUPINFO startupInfo; +static PROCESS_INFORMATION processInfo; +static HANDLE beforeInputEvent; +static HANDLE afterOutputEvent; +static std::string encodedInputTestString; +static std::string encodedTestString; + +static void displayError(DWORD errorCode) +{ + std::cerr.setf(std::ios::hex, std::ios::basefield); + std::cerr << "Failed with error: 0x" << errorCode << "!" << std::endl; + LPWSTR message; + if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + nullptr, errorCode, 0, (LPWSTR)&message, 0, nullptr)) { + std::cerr << "Error message: " << kwsys::Encoding::ToNarrow(message) + << std::endl; + HeapFree(GetProcessHeap(), 0, message); + } else { + std::cerr << "FormatMessage() failed with error: 0x" << GetLastError() + << "!" << std::endl; + } + std::cerr.unsetf(std::ios::hex); +} + +std::basic_streambuf* errstream(const char* unused) +{ + static_cast(unused); + return std::cerr.rdbuf(); +} + +std::basic_streambuf* errstream(const wchar_t* unused) +{ + static_cast(unused); + return std::wcerr.rdbuf(); +} + +template +static void dumpBuffers(const T* expected, const T* received, size_t size) +{ + std::basic_ostream err(errstream(expected)); + err << "Expected output: '" << std::basic_string(expected, size) << "'" + << std::endl; + if (err.fail()) { + err.clear(); + err << "--- Error while outputting ---" << std::endl; + } + err << "Received output: '" << std::basic_string(received, size) << "'" + << std::endl; + if (err.fail()) { + err.clear(); + err << "--- Error while outputting ---" << std::endl; + } + std::cerr << "Expected output | Received output" << std::endl; + for (size_t i = 0; i < size; i++) { + std::cerr << std::setbase(16) << std::setfill('0') << " " + << "0x" << std::setw(8) << static_cast(expected[i]) + << " | " + << "0x" << std::setw(8) + << static_cast(received[i]); + if (static_cast(expected[i]) != + static_cast(received[i])) { + std::cerr << " MISMATCH!"; + } + std::cerr << std::endl; + } + std::cerr << std::endl; +} + +static bool createProcess(HANDLE hIn, HANDLE hOut, HANDLE hErr) +{ + BOOL bInheritHandles = FALSE; + DWORD dwCreationFlags = 0; + memset(&processInfo, 0, sizeof(processInfo)); + memset(&startupInfo, 0, sizeof(startupInfo)); + startupInfo.cb = sizeof(startupInfo); + startupInfo.dwFlags = STARTF_USESHOWWINDOW; + startupInfo.wShowWindow = SW_HIDE; + if (hIn || hOut || hErr) { + startupInfo.dwFlags |= STARTF_USESTDHANDLES; + startupInfo.hStdInput = hIn; + startupInfo.hStdOutput = hOut; + startupInfo.hStdError = hErr; + bInheritHandles = TRUE; + } + + WCHAR cmd[MAX_PATH]; + if (GetModuleFileNameW(nullptr, cmd, MAX_PATH) == 0) { + std::cerr << "GetModuleFileName failed!" << std::endl; + return false; + } + WCHAR* p = cmd + wcslen(cmd); + while (p > cmd && *p != L'\\') + p--; + *(p + 1) = 0; + wcscat(cmd, cmdConsoleBufChild); + wcscat(cmd, L".exe"); + + bool success = + CreateProcessW(nullptr, // No module name (use command line) + cmd, // Command line + nullptr, // Process handle not inheritable + nullptr, // Thread handle not inheritable + bInheritHandles, // Set handle inheritance + dwCreationFlags, + nullptr, // Use parent's environment block + nullptr, // Use parent's starting directory + &startupInfo, // Pointer to STARTUPINFO structure + &processInfo) != + 0; // Pointer to PROCESS_INFORMATION structure + if (!success) { + DWORD lastError = GetLastError(); + std::cerr << "CreateProcess(" << kwsys::Encoding::ToNarrow(cmd) << ")" + << std::endl; + displayError(lastError); + } + return success; +} + +static void finishProcess(bool success) +{ + if (success) { + success = + WaitForSingleObject(processInfo.hProcess, waitTimeout) == WAIT_OBJECT_0; + }; + if (!success) { + TerminateProcess(processInfo.hProcess, 1); + } + CloseHandle(processInfo.hProcess); + CloseHandle(processInfo.hThread); +} + +static bool createPipe(PHANDLE readPipe, PHANDLE writePipe) +{ + SECURITY_ATTRIBUTES securityAttributes; + securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); + securityAttributes.bInheritHandle = TRUE; + securityAttributes.lpSecurityDescriptor = nullptr; + return CreatePipe(readPipe, writePipe, &securityAttributes, 0) == 0 ? false + : true; +} + +static void finishPipe(HANDLE readPipe, HANDLE writePipe) +{ + if (readPipe != INVALID_HANDLE_VALUE) { + CloseHandle(readPipe); + } + if (writePipe != INVALID_HANDLE_VALUE) { + CloseHandle(writePipe); + } +} + +static HANDLE createFile(LPCWSTR fileName) +{ + SECURITY_ATTRIBUTES securityAttributes; + securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); + securityAttributes.bInheritHandle = TRUE; + securityAttributes.lpSecurityDescriptor = nullptr; + + HANDLE file = + CreateFileW(fileName, GENERIC_READ | GENERIC_WRITE, + 0, // do not share + &securityAttributes, + CREATE_ALWAYS, // overwrite existing + FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, + nullptr); // no template + if (file == INVALID_HANDLE_VALUE) { + DWORD lastError = GetLastError(); + std::cerr << "CreateFile(" << kwsys::Encoding::ToNarrow(fileName) << ")" + << std::endl; + displayError(lastError); + } + return file; +} + +static void finishFile(HANDLE file) +{ + if (file != INVALID_HANDLE_VALUE) { + CloseHandle(file); + } +} + +# ifndef MAPVK_VK_TO_VSC +# define MAPVK_VK_TO_VSC (0) +# endif + +static void writeInputKeyEvent(INPUT_RECORD inputBuffer[], WCHAR chr) +{ + inputBuffer[0].EventType = KEY_EVENT; + inputBuffer[0].Event.KeyEvent.bKeyDown = TRUE; + inputBuffer[0].Event.KeyEvent.wRepeatCount = 1; + SHORT keyCode = VkKeyScanW(chr); + if (keyCode == -1) { + // Character can't be entered with current keyboard layout + // Just set any, it doesn't really matter + keyCode = 'K'; + } + inputBuffer[0].Event.KeyEvent.wVirtualKeyCode = LOBYTE(keyCode); + inputBuffer[0].Event.KeyEvent.wVirtualScanCode = MapVirtualKey( + inputBuffer[0].Event.KeyEvent.wVirtualKeyCode, MAPVK_VK_TO_VSC); + inputBuffer[0].Event.KeyEvent.uChar.UnicodeChar = chr; + inputBuffer[0].Event.KeyEvent.dwControlKeyState = 0; + if ((HIBYTE(keyCode) & 1) == 1) { + inputBuffer[0].Event.KeyEvent.dwControlKeyState |= SHIFT_PRESSED; + } + if ((HIBYTE(keyCode) & 2) == 2) { + inputBuffer[0].Event.KeyEvent.dwControlKeyState |= RIGHT_CTRL_PRESSED; + } + if ((HIBYTE(keyCode) & 4) == 4) { + inputBuffer[0].Event.KeyEvent.dwControlKeyState |= RIGHT_ALT_PRESSED; + } + inputBuffer[1].EventType = inputBuffer[0].EventType; + inputBuffer[1].Event.KeyEvent.bKeyDown = FALSE; + inputBuffer[1].Event.KeyEvent.wRepeatCount = 1; + inputBuffer[1].Event.KeyEvent.wVirtualKeyCode = + inputBuffer[0].Event.KeyEvent.wVirtualKeyCode; + inputBuffer[1].Event.KeyEvent.wVirtualScanCode = + inputBuffer[0].Event.KeyEvent.wVirtualScanCode; + inputBuffer[1].Event.KeyEvent.uChar.UnicodeChar = + inputBuffer[0].Event.KeyEvent.uChar.UnicodeChar; + inputBuffer[1].Event.KeyEvent.dwControlKeyState = 0; +} + +static int testPipe() +{ + int didFail = 1; + HANDLE inPipeRead = INVALID_HANDLE_VALUE; + HANDLE inPipeWrite = INVALID_HANDLE_VALUE; + HANDLE outPipeRead = INVALID_HANDLE_VALUE; + HANDLE outPipeWrite = INVALID_HANDLE_VALUE; + HANDLE errPipeRead = INVALID_HANDLE_VALUE; + HANDLE errPipeWrite = INVALID_HANDLE_VALUE; + UINT currentCodepage = GetConsoleCP(); + char buffer[200]; + char buffer2[200]; + try { + if (!createPipe(&inPipeRead, &inPipeWrite) || + !createPipe(&outPipeRead, &outPipeWrite) || + !createPipe(&errPipeRead, &errPipeWrite)) { + throw std::runtime_error("createFile failed!"); + } + if (TestCodepage == CP_ACP) { + TestCodepage = GetACP(); + } + if (!SetConsoleCP(TestCodepage)) { + throw std::runtime_error("SetConsoleCP failed!"); + } + + DWORD bytesWritten = 0; + if (!WriteFile(inPipeWrite, encodedInputTestString.c_str(), + (DWORD)encodedInputTestString.size(), &bytesWritten, + nullptr) || + bytesWritten == 0) { + throw std::runtime_error("WriteFile failed!"); + } + + if (createProcess(inPipeRead, outPipeWrite, errPipeWrite)) { + try { + DWORD status; + if ((status = WaitForSingleObject(afterOutputEvent, waitTimeout)) != + WAIT_OBJECT_0) { + std::cerr.setf(std::ios::hex, std::ios::basefield); + std::cerr << "WaitForSingleObject returned unexpected status 0x" + << status << std::endl; + std::cerr.unsetf(std::ios::hex); + throw std::runtime_error("WaitForSingleObject failed!"); + } + DWORD bytesRead = 0; + if (!ReadFile(outPipeRead, buffer, sizeof(buffer), &bytesRead, + nullptr) || + bytesRead == 0) { + throw std::runtime_error("ReadFile#1 failed!"); + } + buffer[bytesRead] = 0; + if ((bytesRead < + encodedTestString.size() + 1 + encodedInputTestString.size() && + !ReadFile(outPipeRead, buffer + bytesRead, + sizeof(buffer) - bytesRead, &bytesRead, nullptr)) || + bytesRead == 0) { + throw std::runtime_error("ReadFile#2 failed!"); + } + if (memcmp(buffer, encodedTestString.c_str(), + encodedTestString.size()) == 0 && + memcmp(buffer + encodedTestString.size() + 1, + encodedInputTestString.c_str(), + encodedInputTestString.size()) == 0) { + bytesRead = 0; + if (!ReadFile(errPipeRead, buffer2, sizeof(buffer2), &bytesRead, + nullptr) || + bytesRead == 0) { + throw std::runtime_error("ReadFile#3 failed!"); + } + buffer2[bytesRead] = 0; + didFail = encodedTestString.compare(0, std::string::npos, buffer2, + encodedTestString.size()) == 0 + ? 0 + : 1; + } + if (didFail != 0) { + std::cerr << "Pipe's output didn't match expected output!" + << std::endl; + dumpBuffers(encodedTestString.c_str(), buffer, + encodedTestString.size()); + dumpBuffers(encodedInputTestString.c_str(), + buffer + encodedTestString.size() + 1, + encodedInputTestString.size()); + dumpBuffers(encodedTestString.c_str(), buffer2, + encodedTestString.size()); + } + } catch (const std::runtime_error& ex) { + DWORD lastError = GetLastError(); + std::cerr << "In function testPipe, line " << __LINE__ << ": " + << ex.what() << std::endl; + displayError(lastError); + } + finishProcess(didFail == 0); + } + } catch (const std::runtime_error& ex) { + DWORD lastError = GetLastError(); + std::cerr << "In function testPipe, line " << __LINE__ << ": " << ex.what() + << std::endl; + displayError(lastError); + } + finishPipe(inPipeRead, inPipeWrite); + finishPipe(outPipeRead, outPipeWrite); + finishPipe(errPipeRead, errPipeWrite); + SetConsoleCP(currentCodepage); + return didFail; +} + +static int testFile() +{ + int didFail = 1; + HANDLE inFile = INVALID_HANDLE_VALUE; + HANDLE outFile = INVALID_HANDLE_VALUE; + HANDLE errFile = INVALID_HANDLE_VALUE; + try { + if ((inFile = createFile(L"stdinFile.txt")) == INVALID_HANDLE_VALUE || + (outFile = createFile(L"stdoutFile.txt")) == INVALID_HANDLE_VALUE || + (errFile = createFile(L"stderrFile.txt")) == INVALID_HANDLE_VALUE) { + throw std::runtime_error("createFile failed!"); + } + DWORD bytesWritten = 0; + char buffer[200]; + char buffer2[200]; + + int length; + if ((length = WideCharToMultiByte(TestCodepage, 0, UnicodeInputTestString, + -1, buffer, sizeof(buffer), nullptr, + nullptr)) == 0) { + throw std::runtime_error("WideCharToMultiByte failed!"); + } + buffer[length - 1] = '\n'; + if (!WriteFile(inFile, buffer, length, &bytesWritten, nullptr) || + bytesWritten == 0) { + throw std::runtime_error("WriteFile failed!"); + } + if (SetFilePointer(inFile, 0, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { + throw std::runtime_error("SetFilePointer failed!"); + } + + if (createProcess(inFile, outFile, errFile)) { + DWORD bytesRead = 0; + try { + DWORD status; + if ((status = WaitForSingleObject(afterOutputEvent, waitTimeout)) != + WAIT_OBJECT_0) { + std::cerr.setf(std::ios::hex, std::ios::basefield); + std::cerr << "WaitForSingleObject returned unexpected status 0x" + << status << std::endl; + std::cerr.unsetf(std::ios::hex); + throw std::runtime_error("WaitForSingleObject failed!"); + } + if (SetFilePointer(outFile, 0, 0, FILE_BEGIN) == + INVALID_SET_FILE_POINTER) { + throw std::runtime_error("SetFilePointer#1 failed!"); + } + if (!ReadFile(outFile, buffer, sizeof(buffer), &bytesRead, nullptr) || + bytesRead == 0) { + throw std::runtime_error("ReadFile#1 failed!"); + } + buffer[bytesRead] = 0; + if (memcmp(buffer, encodedTestString.c_str(), + encodedTestString.size()) == 0 && + memcmp(buffer + encodedTestString.size() + 1, + encodedInputTestString.c_str(), + encodedInputTestString.size()) == 0) { + bytesRead = 0; + if (SetFilePointer(errFile, 0, 0, FILE_BEGIN) == + INVALID_SET_FILE_POINTER) { + throw std::runtime_error("SetFilePointer#2 failed!"); + } + + if (!ReadFile(errFile, buffer2, sizeof(buffer2), &bytesRead, + nullptr) || + bytesRead == 0) { + throw std::runtime_error("ReadFile#2 failed!"); + } + buffer2[bytesRead] = 0; + didFail = encodedTestString.compare(0, std::string::npos, buffer2, + encodedTestString.size()) == 0 + ? 0 + : 1; + } + if (didFail != 0) { + std::cerr << "File's output didn't match expected output!" + << std::endl; + dumpBuffers(encodedTestString.c_str(), buffer, + encodedTestString.size()); + dumpBuffers(encodedInputTestString.c_str(), + buffer + encodedTestString.size() + 1, + encodedInputTestString.size()); + dumpBuffers(encodedTestString.c_str(), buffer2, + encodedTestString.size()); + } + } catch (const std::runtime_error& ex) { + DWORD lastError = GetLastError(); + std::cerr << "In function testFile, line " << __LINE__ << ": " + << ex.what() << std::endl; + displayError(lastError); + } + finishProcess(didFail == 0); + } + } catch (const std::runtime_error& ex) { + DWORD lastError = GetLastError(); + std::cerr << "In function testFile, line " << __LINE__ << ": " << ex.what() + << std::endl; + displayError(lastError); + } + finishFile(inFile); + finishFile(outFile); + finishFile(errFile); + return didFail; +} + +# ifndef _WIN32_WINNT_VISTA +# define _WIN32_WINNT_VISTA 0x0600 +# endif + +static int testConsole() +{ + int didFail = 1; + HANDLE parentIn = GetStdHandle(STD_INPUT_HANDLE); + HANDLE parentOut = GetStdHandle(STD_OUTPUT_HANDLE); + HANDLE parentErr = GetStdHandle(STD_ERROR_HANDLE); + HANDLE hIn = parentIn; + HANDLE hOut = parentOut; + DWORD consoleMode; + bool newConsole = false; + bool forceNewConsole = false; + bool restoreConsole = false; + LPCWSTR TestFaceName = L"Lucida Console"; + const DWORD TestFontFamily = 0x00000036; + const DWORD TestFontSize = 0x000c0000; + HKEY hConsoleKey; + WCHAR FaceName[200]; + FaceName[0] = 0; + DWORD FaceNameSize = sizeof(FaceName); + DWORD FontFamily = TestFontFamily; + DWORD FontSize = TestFontSize; +# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersion +# pragma warning(push) +# ifdef __INTEL_COMPILER +# pragma warning(disable : 1478) +# elif defined __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdeprecated-declarations" +# else +# pragma warning(disable : 4996) +# endif +# endif + const bool isVistaOrGreater = + LOBYTE(LOWORD(GetVersion())) >= HIBYTE(_WIN32_WINNT_VISTA); +# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersion +# ifdef __clang__ +# pragma clang diagnostic pop +# else +# pragma warning(pop) +# endif +# endif + if (!isVistaOrGreater) { + if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Console", 0, KEY_READ | KEY_WRITE, + &hConsoleKey) == ERROR_SUCCESS) { + DWORD dwordSize = sizeof(DWORD); + if (RegQueryValueExW(hConsoleKey, L"FontFamily", nullptr, nullptr, + (LPBYTE)&FontFamily, &dwordSize) == ERROR_SUCCESS) { + if (FontFamily != TestFontFamily) { + RegQueryValueExW(hConsoleKey, L"FaceName", nullptr, nullptr, + (LPBYTE)FaceName, &FaceNameSize); + RegQueryValueExW(hConsoleKey, L"FontSize", nullptr, nullptr, + (LPBYTE)&FontSize, &dwordSize); + + RegSetValueExW(hConsoleKey, L"FontFamily", 0, REG_DWORD, + (BYTE*)&TestFontFamily, sizeof(TestFontFamily)); + RegSetValueExW(hConsoleKey, L"FaceName", 0, REG_SZ, + (BYTE*)TestFaceName, + (DWORD)((wcslen(TestFaceName) + 1) * sizeof(WCHAR))); + RegSetValueExW(hConsoleKey, L"FontSize", 0, REG_DWORD, + (BYTE*)&TestFontSize, sizeof(TestFontSize)); + + restoreConsole = true; + forceNewConsole = true; + } + } else { + std::cerr << "RegGetValueW(FontFamily) failed!" << std::endl; + } + RegCloseKey(hConsoleKey); + } else { + std::cerr << "RegOpenKeyExW(HKEY_CURRENT_USER\\Console) failed!" + << std::endl; + } + } + if (forceNewConsole || GetConsoleMode(parentOut, &consoleMode) == 0) { + // Not a real console, let's create new one. + FreeConsole(); + if (!AllocConsole()) { + std::cerr << "AllocConsole failed!" << std::endl; + return didFail; + } + SECURITY_ATTRIBUTES securityAttributes; + securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); + securityAttributes.bInheritHandle = TRUE; + securityAttributes.lpSecurityDescriptor = nullptr; + hIn = CreateFileW(L"CONIN$", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, &securityAttributes, + OPEN_EXISTING, 0, nullptr); + if (hIn == INVALID_HANDLE_VALUE) { + DWORD lastError = GetLastError(); + std::cerr << "CreateFile(CONIN$)" << std::endl; + displayError(lastError); + } + hOut = CreateFileW(L"CONOUT$", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, &securityAttributes, + OPEN_EXISTING, 0, nullptr); + if (hOut == INVALID_HANDLE_VALUE) { + DWORD lastError = GetLastError(); + std::cerr << "CreateFile(CONOUT$)" << std::endl; + displayError(lastError); + } + SetStdHandle(STD_INPUT_HANDLE, hIn); + SetStdHandle(STD_OUTPUT_HANDLE, hOut); + SetStdHandle(STD_ERROR_HANDLE, hOut); + newConsole = true; + } + +# if _WIN32_WINNT >= _WIN32_WINNT_VISTA + if (isVistaOrGreater) { + CONSOLE_FONT_INFOEX consoleFont; + memset(&consoleFont, 0, sizeof(consoleFont)); + consoleFont.cbSize = sizeof(consoleFont); + HMODULE kernel32 = LoadLibraryW(L"kernel32.dll"); + typedef BOOL(WINAPI * GetCurrentConsoleFontExFunc)( + HANDLE hConsoleOutput, BOOL bMaximumWindow, + PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx); + typedef BOOL(WINAPI * SetCurrentConsoleFontExFunc)( + HANDLE hConsoleOutput, BOOL bMaximumWindow, + PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx); + GetCurrentConsoleFontExFunc getConsoleFont = + (GetCurrentConsoleFontExFunc)GetProcAddress(kernel32, + "GetCurrentConsoleFontEx"); + SetCurrentConsoleFontExFunc setConsoleFont = + (SetCurrentConsoleFontExFunc)GetProcAddress(kernel32, + "SetCurrentConsoleFontEx"); + if (getConsoleFont(hOut, FALSE, &consoleFont)) { + if (consoleFont.FontFamily != TestFontFamily) { + consoleFont.FontFamily = TestFontFamily; + wcscpy(consoleFont.FaceName, TestFaceName); + if (!setConsoleFont(hOut, FALSE, &consoleFont)) { + std::cerr << "SetCurrentConsoleFontEx failed!" << std::endl; + } + } + } else { + std::cerr << "GetCurrentConsoleFontEx failed!" << std::endl; + } + } else { +# endif + if (restoreConsole && + RegOpenKeyExW(HKEY_CURRENT_USER, L"Console", 0, KEY_WRITE, + &hConsoleKey) == ERROR_SUCCESS) { + RegSetValueExW(hConsoleKey, L"FontFamily", 0, REG_DWORD, + (BYTE*)&FontFamily, sizeof(FontFamily)); + if (FaceName[0] != 0) { + RegSetValueExW(hConsoleKey, L"FaceName", 0, REG_SZ, (BYTE*)FaceName, + FaceNameSize); + } else { + RegDeleteValueW(hConsoleKey, L"FaceName"); + } + RegSetValueExW(hConsoleKey, L"FontSize", 0, REG_DWORD, (BYTE*)&FontSize, + sizeof(FontSize)); + RegCloseKey(hConsoleKey); + } +# if _WIN32_WINNT >= _WIN32_WINNT_VISTA + } +# endif + + if (createProcess(nullptr, nullptr, nullptr)) { + try { + DWORD status; + if ((status = WaitForSingleObject(beforeInputEvent, waitTimeout)) != + WAIT_OBJECT_0) { + std::cerr.setf(std::ios::hex, std::ios::basefield); + std::cerr << "WaitForSingleObject returned unexpected status 0x" + << status << std::endl; + std::cerr.unsetf(std::ios::hex); + throw std::runtime_error("WaitForSingleObject#1 failed!"); + } + INPUT_RECORD inputBuffer[(sizeof(UnicodeInputTestString) / + sizeof(UnicodeInputTestString[0])) * + 2]; + memset(&inputBuffer, 0, sizeof(inputBuffer)); + unsigned int i; + for (i = 0; i < (sizeof(UnicodeInputTestString) / + sizeof(UnicodeInputTestString[0]) - + 1); + i++) { + writeInputKeyEvent(&inputBuffer[i * 2], UnicodeInputTestString[i]); + } + writeInputKeyEvent(&inputBuffer[i * 2], VK_RETURN); + DWORD eventsWritten = 0; + // We need to wait a bit before writing to console so child process have + // started waiting for input on stdin. + Sleep(300); + if (!WriteConsoleInputW(hIn, inputBuffer, + sizeof(inputBuffer) / sizeof(inputBuffer[0]), + &eventsWritten) || + eventsWritten == 0) { + throw std::runtime_error("WriteConsoleInput failed!"); + } + if ((status = WaitForSingleObject(afterOutputEvent, waitTimeout)) != + WAIT_OBJECT_0) { + std::cerr.setf(std::ios::hex, std::ios::basefield); + std::cerr << "WaitForSingleObject returned unexpected status 0x" + << status << std::endl; + std::cerr.unsetf(std::ios::hex); + throw std::runtime_error("WaitForSingleObject#2 failed!"); + } + CONSOLE_SCREEN_BUFFER_INFO screenBufferInfo; + if (!GetConsoleScreenBufferInfo(hOut, &screenBufferInfo)) { + throw std::runtime_error("GetConsoleScreenBufferInfo failed!"); + } + + COORD coord; + DWORD charsRead = 0; + coord.X = 0; + coord.Y = screenBufferInfo.dwCursorPosition.Y - 4; + WCHAR* outputBuffer = new WCHAR[screenBufferInfo.dwSize.X * 4]; + if (!ReadConsoleOutputCharacterW(hOut, outputBuffer, + screenBufferInfo.dwSize.X * 4, coord, + &charsRead) || + charsRead == 0) { + delete[] outputBuffer; + throw std::runtime_error("ReadConsoleOutputCharacter failed!"); + } + std::wstring wideTestString = kwsys::Encoding::ToWide(encodedTestString); + std::replace(wideTestString.begin(), wideTestString.end(), '\0', ' '); + std::wstring wideInputTestString = + kwsys::Encoding::ToWide(encodedInputTestString); + if (memcmp(outputBuffer, wideTestString.c_str(), + wideTestString.size() * sizeof(wchar_t)) == 0 && + memcmp(outputBuffer + screenBufferInfo.dwSize.X * 1, + wideTestString.c_str(), + wideTestString.size() * sizeof(wchar_t)) == 0 && + memcmp(outputBuffer + screenBufferInfo.dwSize.X * 2, + UnicodeInputTestString, + sizeof(UnicodeInputTestString) - sizeof(WCHAR)) == 0 && + memcmp(outputBuffer + screenBufferInfo.dwSize.X * 3, + wideInputTestString.c_str(), + (wideInputTestString.size() - 1) * sizeof(wchar_t)) == 0) { + didFail = 0; + } else { + std::cerr << "Console's output didn't match expected output!" + << std::endl; + dumpBuffers(wideTestString.c_str(), outputBuffer, + wideTestString.size()); + dumpBuffers(wideTestString.c_str(), + outputBuffer + screenBufferInfo.dwSize.X * 1, + wideTestString.size()); + dumpBuffers( + UnicodeInputTestString, outputBuffer + screenBufferInfo.dwSize.X * 2, + (sizeof(UnicodeInputTestString) - 1) / sizeof(WCHAR)); + dumpBuffers(wideInputTestString.c_str(), + outputBuffer + screenBufferInfo.dwSize.X * 3, + wideInputTestString.size() - 1); + } + delete[] outputBuffer; + } catch (const std::runtime_error& ex) { + DWORD lastError = GetLastError(); + std::cerr << "In function testConsole, line " << __LINE__ << ": " + << ex.what() << std::endl; + displayError(lastError); + } + finishProcess(didFail == 0); + } + if (newConsole) { + SetStdHandle(STD_INPUT_HANDLE, parentIn); + SetStdHandle(STD_OUTPUT_HANDLE, parentOut); + SetStdHandle(STD_ERROR_HANDLE, parentErr); + CloseHandle(hIn); + CloseHandle(hOut); + FreeConsole(); + } + return didFail; +} + +#endif + +int testConsoleBuf(int, char* []) +{ + int ret = 0; + +#if defined(_WIN32) + beforeInputEvent = CreateEventW(nullptr, + FALSE, // auto-reset event + FALSE, // initial state is nonsignaled + BeforeInputEventName); // object name + if (!beforeInputEvent) { + std::cerr << "CreateEvent#1 failed " << GetLastError() << std::endl; + return 1; + } + + afterOutputEvent = CreateEventW(nullptr, FALSE, FALSE, AfterOutputEventName); + if (!afterOutputEvent) { + std::cerr << "CreateEvent#2 failed " << GetLastError() << std::endl; + return 1; + } + + encodedTestString = kwsys::Encoding::ToNarrow(std::wstring( + UnicodeTestString, sizeof(UnicodeTestString) / sizeof(wchar_t) - 1)); + encodedInputTestString = kwsys::Encoding::ToNarrow( + std::wstring(UnicodeInputTestString, + sizeof(UnicodeInputTestString) / sizeof(wchar_t) - 1)); + encodedInputTestString += "\n"; + + ret |= testPipe(); + ret |= testFile(); + ret |= testConsole(); + + CloseHandle(beforeInputEvent); + CloseHandle(afterOutputEvent); +#endif + + return ret; +} diff --git a/test/API/driver/kwsys/testConsoleBuf.hxx b/test/API/driver/kwsys/testConsoleBuf.hxx new file mode 100644 index 0000000..e93cb4f --- /dev/null +++ b/test/API/driver/kwsys/testConsoleBuf.hxx @@ -0,0 +1,17 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef testConsoleBuf_hxx +#define testConsoleBuf_hxx + +static const wchar_t cmdConsoleBufChild[] = L"testConsoleBufChild"; + +static const wchar_t BeforeInputEventName[] = L"BeforeInputEvent"; +static const wchar_t AfterOutputEventName[] = L"AfterOutputEvent"; + +// यूनिकोड είναι здорово! +static const wchar_t UnicodeTestString[] = + L"\u092F\u0942\u0928\u093F\u0915\u094B\u0921 " + L"\u03B5\u03AF\u03BD\0\u03B1\u03B9 " + L"\u0437\u0434\u043E\u0440\u043E\u0432\u043E!"; + +#endif diff --git a/test/API/driver/kwsys/testConsoleBufChild.cxx b/test/API/driver/kwsys/testConsoleBufChild.cxx new file mode 100644 index 0000000..3c8fdc2 --- /dev/null +++ b/test/API/driver/kwsys/testConsoleBufChild.cxx @@ -0,0 +1,55 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" + +#include KWSYS_HEADER(ConsoleBuf.hxx) +#include KWSYS_HEADER(Encoding.hxx) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "ConsoleBuf.hxx.in" +# include "Encoding.hxx.in" +#endif + +#include + +#include "testConsoleBuf.hxx" + +int main(int argc, const char* argv[]) +{ +#if defined(_WIN32) + kwsys::ConsoleBuf::Manager out(std::cout); + kwsys::ConsoleBuf::Manager err(std::cerr, true); + kwsys::ConsoleBuf::Manager in(std::cin); + + if (argc > 1) { + std::cout << argv[1] << std::endl; + std::cerr << argv[1] << std::endl; + } else { + std::string str = kwsys::Encoding::ToNarrow(std::wstring( + UnicodeTestString, sizeof(UnicodeTestString) / sizeof(wchar_t) - 1)); + std::cout << str << std::endl; + std::cerr << str << std::endl; + } + + std::string input; + HANDLE event = OpenEventW(EVENT_MODIFY_STATE, FALSE, BeforeInputEventName); + if (event) { + SetEvent(event); + CloseHandle(event); + } + + std::cin >> input; + std::cout << input << std::endl; + event = OpenEventW(EVENT_MODIFY_STATE, FALSE, AfterOutputEventName); + if (event) { + SetEvent(event); + CloseHandle(event); + } +#else + static_cast(argc); + static_cast(argv); +#endif + return 0; +} diff --git a/test/API/driver/kwsys/testDirectory.cxx b/test/API/driver/kwsys/testDirectory.cxx new file mode 100644 index 0000000..b1ab0c8 --- /dev/null +++ b/test/API/driver/kwsys/testDirectory.cxx @@ -0,0 +1,110 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying +file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(Directory.hxx) +#include KWSYS_HEADER(Encoding.hxx) +#include KWSYS_HEADER(SystemTools.hxx) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "Directory.hxx.in" +# include "Encoding.hxx.in" +# include "SystemTools.hxx.in" +#endif + +#include +#include +#include + +#include + +int _doLongPathTest() +{ + using namespace kwsys; + static const int LONG_PATH_THRESHOLD = 512; + int res = 0; + std::string topdir(TEST_SYSTEMTOOLS_BINARY_DIR "/directory_testing/"); + std::stringstream testpathstrm; + std::string testdirpath; + std::string extendedtestdirpath; + + testpathstrm << topdir; + size_t pathlen = testpathstrm.str().length(); + testpathstrm.seekp(0, std::ios_base::end); + while (pathlen < LONG_PATH_THRESHOLD) { + testpathstrm << "0123456789/"; + pathlen = testpathstrm.str().length(); + } + + testdirpath = testpathstrm.str(); +#ifdef _WIN32 + extendedtestdirpath = + Encoding::ToNarrow(SystemTools::ConvertToWindowsExtendedPath(testdirpath)); +#else + extendedtestdirpath = testdirpath; +#endif + + if (SystemTools::MakeDirectory(extendedtestdirpath)) { + std::ofstream testfile1( + (extendedtestdirpath + "longfilepathtest1.txt").c_str()); + std::ofstream testfile2( + (extendedtestdirpath + "longfilepathtest2.txt").c_str()); + testfile1 << "foo"; + testfile2 << "bar"; + testfile1.close(); + testfile2.close(); + + Directory testdir; + // Set res to failure if the directory doesn't load + res += !testdir.Load(testdirpath); + // Increment res failure if the directory appears empty + res += testdir.GetNumberOfFiles() == 0; + // Increment res failures if the path has changed from + // what was provided. + res += testdirpath != testdir.GetPath(); + + SystemTools::RemoveADirectory(topdir); + } else { + std::cerr << "Failed to create directory with long path: " + << extendedtestdirpath << std::endl; + res += 1; + } + return res; +} + +int _copyDirectoryTest() +{ + using namespace kwsys; + const std::string source(TEST_SYSTEMTOOLS_BINARY_DIR + "/directory_testing/copyDirectoryTestSrc"); + if (SystemTools::PathExists(source)) { + std::cerr << source << " shouldn't exist before test" << std::endl; + return 1; + } + const std::string destination(TEST_SYSTEMTOOLS_BINARY_DIR + "/directory_testing/copyDirectoryTestDst"); + if (SystemTools::PathExists(destination)) { + std::cerr << destination << " shouldn't exist before test" << std::endl; + return 2; + } + const bool copysuccess = SystemTools::CopyADirectory(source, destination); + const bool destinationexists = SystemTools::PathExists(destination); + if (copysuccess) { + std::cerr << "CopyADirectory should have returned false" << std::endl; + SystemTools::RemoveADirectory(destination); + return 3; + } + if (destinationexists) { + std::cerr << "CopyADirectory returned false, but destination directory" + << " has been created" << std::endl; + SystemTools::RemoveADirectory(destination); + return 4; + } + return 0; +} + +int testDirectory(int, char* []) +{ + return _doLongPathTest() + _copyDirectoryTest(); +} diff --git a/test/API/driver/kwsys/testDynamicLoader.cxx b/test/API/driver/kwsys/testDynamicLoader.cxx new file mode 100644 index 0000000..2421ac0 --- /dev/null +++ b/test/API/driver/kwsys/testDynamicLoader.cxx @@ -0,0 +1,133 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" + +#include KWSYS_HEADER(DynamicLoader.hxx) + +#if defined(__BEOS__) || defined(__HAIKU__) +# include /* disable_debugger() API. */ +#endif + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "DynamicLoader.hxx.in" +#endif + +#include +#include + +// Include with <> instead of "" to avoid getting any in-source copy +// left on disk. +#include + +static std::string GetLibName(const char* lname, const char* subdir = nullptr) +{ + // Construct proper name of lib + std::string slname; + slname = EXECUTABLE_OUTPUT_PATH; + if (subdir) { + slname += "/"; + slname += subdir; + } +#ifdef CMAKE_INTDIR + slname += "/"; + slname += CMAKE_INTDIR; +#endif + slname += "/"; + slname += kwsys::DynamicLoader::LibPrefix(); + slname += lname; + slname += kwsys::DynamicLoader::LibExtension(); + + return slname; +} + +/* libname = Library name (proper prefix, proper extension) + * System = symbol to lookup in libname + * r1: should OpenLibrary succeed ? + * r2: should GetSymbolAddress succeed ? + * r3: should CloseLibrary succeed ? + */ +static int TestDynamicLoader(const char* libname, const char* symbol, int r1, + int r2, int r3, int flags = 0) +{ + std::cerr << "Testing: " << libname << std::endl; + kwsys::DynamicLoader::LibraryHandle l = + kwsys::DynamicLoader::OpenLibrary(libname, flags); + // If result is incompatible with expectation just fails (xor): + if ((r1 && !l) || (!r1 && l)) { + std::cerr << "OpenLibrary: " << kwsys::DynamicLoader::LastError() + << std::endl; + return 1; + } + kwsys::DynamicLoader::SymbolPointer f = + kwsys::DynamicLoader::GetSymbolAddress(l, symbol); + if ((r2 && !f) || (!r2 && f)) { + std::cerr << "GetSymbolAddress: " << kwsys::DynamicLoader::LastError() + << std::endl; + return 1; + } +#ifndef __APPLE__ + int s = kwsys::DynamicLoader::CloseLibrary(l); + if ((r3 && !s) || (!r3 && s)) { + std::cerr << "CloseLibrary: " << kwsys::DynamicLoader::LastError() + << std::endl; + return 1; + } +#else + (void)r3; +#endif + return 0; +} + +int testDynamicLoader(int argc, char* argv[]) +{ +#if defined(_WIN32) + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); +#elif defined(__BEOS__) || defined(__HAIKU__) + disable_debugger(1); +#endif + int res = 0; + if (argc == 3) { + // User specify a libname and symbol to check. + res = TestDynamicLoader(argv[1], argv[2], 1, 1, 1); + return res; + } + +// dlopen() on Syllable before 11/22/2007 doesn't return 0 on error +#ifndef __SYLLABLE__ + // Make sure that inexistent lib is giving correct result + res += TestDynamicLoader("azerty_", "foo_bar", 0, 0, 0); + // Make sure that random binary file cannot be assimilated as dylib + res += TestDynamicLoader(TEST_SYSTEMTOOLS_SOURCE_DIR "/testSystemTools.bin", + "wp", 0, 0, 0); +#endif + +#ifdef __linux__ + // This one is actually fun to test, since dlopen is by default + // loaded...wonder why :) + res += TestDynamicLoader("foobar.lib", "dlopen", 0, 1, 0); + res += TestDynamicLoader("libdl.so", "dlopen", 1, 1, 1); + res += TestDynamicLoader("libdl.so", "TestDynamicLoader", 1, 0, 1); +#endif + // Now try on the generated library + std::string libname = GetLibName(KWSYS_NAMESPACE_STRING "TestDynload"); + res += TestDynamicLoader(libname.c_str(), "dummy", 1, 0, 1); + res += TestDynamicLoader(libname.c_str(), "TestDynamicLoaderSymbolPointer", + 1, 1, 1); + res += TestDynamicLoader(libname.c_str(), "_TestDynamicLoaderSymbolPointer", + 1, 0, 1); + res += TestDynamicLoader(libname.c_str(), "TestDynamicLoaderData", 1, 1, 1); + res += TestDynamicLoader(libname.c_str(), "_TestDynamicLoaderData", 1, 0, 1); + +#ifdef _WIN32 + libname = GetLibName(KWSYS_NAMESPACE_STRING "TestDynloadUse", "dynloaddir"); + res += TestDynamicLoader(libname.c_str(), "dummy", 0, 0, 0); + res += TestDynamicLoader(libname.c_str(), "TestLoad", 1, 1, 1, + kwsys::DynamicLoader::SearchBesideLibrary); + res += TestDynamicLoader(libname.c_str(), "_TestLoad", 1, 0, 1, + kwsys::DynamicLoader::SearchBesideLibrary); +#endif + + return res; +} diff --git a/test/API/driver/kwsys/testDynload.c b/test/API/driver/kwsys/testDynload.c new file mode 100644 index 0000000..c49f747 --- /dev/null +++ b/test/API/driver/kwsys/testDynload.c @@ -0,0 +1,13 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifdef _WIN32 +# define DL_EXPORT __declspec(dllexport) +#else +# define DL_EXPORT +#endif + +DL_EXPORT int TestDynamicLoaderData = 0; + +DL_EXPORT void TestDynamicLoaderSymbolPointer() +{ +} diff --git a/test/API/driver/kwsys/testDynloadImpl.c b/test/API/driver/kwsys/testDynloadImpl.c new file mode 100644 index 0000000..2b9069b --- /dev/null +++ b/test/API/driver/kwsys/testDynloadImpl.c @@ -0,0 +1,10 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ + +#include "testDynloadImpl.h" + +int TestDynamicLoaderImplData = 0; + +void TestDynamicLoaderImplSymbolPointer() +{ +} diff --git a/test/API/driver/kwsys/testDynloadImpl.h b/test/API/driver/kwsys/testDynloadImpl.h new file mode 100644 index 0000000..d0c9dfb --- /dev/null +++ b/test/API/driver/kwsys/testDynloadImpl.h @@ -0,0 +1,15 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifdef _WIN32 +# ifdef BUILDING_TestDynloadImpl +# define DLIMPL_EXPORT __declspec(dllexport) +# else +# define DLIMPL_EXPORT __declspec(dllimport) +# endif +#else +# define DLIMPL_EXPORT +#endif + +DLIMPL_EXPORT int TestDynamicLoaderImplData; + +DLIMPL_EXPORT void TestDynamicLoaderImplSymbolPointer(); diff --git a/test/API/driver/kwsys/testDynloadUse.c b/test/API/driver/kwsys/testDynloadUse.c new file mode 100644 index 0000000..5402add --- /dev/null +++ b/test/API/driver/kwsys/testDynloadUse.c @@ -0,0 +1,15 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "testDynloadImpl.h" + +#ifdef _WIN32 +# define DL_EXPORT __declspec(dllexport) +#else +# define DL_EXPORT +#endif + +DL_EXPORT int TestLoad() +{ + TestDynamicLoaderImplSymbolPointer(); + return TestDynamicLoaderImplData; +} diff --git a/test/API/driver/kwsys/testEncode.c b/test/API/driver/kwsys/testEncode.c new file mode 100644 index 0000000..b7b6dd8 --- /dev/null +++ b/test/API/driver/kwsys/testEncode.c @@ -0,0 +1,67 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(MD5.h) + +/* Work-around CMake dependency scanning limitation. This must + duplicate the above list of headers. */ +#if 0 +# include "MD5.h.in" +#endif + +#include +#include + +static const unsigned char testMD5input1[] = + " A quick brown fox jumps over the lazy dog.\n" + " This is sample text for MD5 sum input.\n"; +static const char testMD5output1[] = "8f146af46ed4f267921bb937d4d3500c"; + +static const int testMD5input2len = 28; +static const unsigned char testMD5input2[] = "the cow jumped over the moon"; +static const char testMD5output2[] = "a2ad137b746138fae4e5adca9c85d3ae"; + +static int testMD5_1(kwsysMD5* md5) +{ + char md5out[33]; + kwsysMD5_Initialize(md5); + kwsysMD5_Append(md5, testMD5input1, -1); + kwsysMD5_FinalizeHex(md5, md5out); + md5out[32] = 0; + printf("md5sum 1: expected [%s]\n" + " got [%s]\n", + testMD5output1, md5out); + return (strcmp(md5out, testMD5output1) != 0) ? 1 : 0; +} + +static int testMD5_2(kwsysMD5* md5) +{ + unsigned char digest[16]; + char md5out[33]; + kwsysMD5_Initialize(md5); + kwsysMD5_Append(md5, testMD5input2, testMD5input2len); + kwsysMD5_Finalize(md5, digest); + kwsysMD5_DigestToHex(digest, md5out); + md5out[32] = 0; + printf("md5sum 2: expected [%s]\n" + " got [%s]\n", + testMD5output2, md5out); + return (strcmp(md5out, testMD5output2) != 0) ? 1 : 0; +} + +int testEncode(int argc, char* argv[]) +{ + int result = 0; + (void)argc; + (void)argv; + + /* Test MD5 digest. */ + { + kwsysMD5* md5 = kwsysMD5_New(); + result |= testMD5_1(md5); + result |= testMD5_2(md5); + kwsysMD5_Delete(md5); + } + + return result; +} diff --git a/test/API/driver/kwsys/testEncoding.cxx b/test/API/driver/kwsys/testEncoding.cxx new file mode 100644 index 0000000..988697b --- /dev/null +++ b/test/API/driver/kwsys/testEncoding.cxx @@ -0,0 +1,286 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" + +#if defined(_MSC_VER) +# pragma warning(disable : 4786) +#endif + +#include KWSYS_HEADER(Encoding.hxx) +#include KWSYS_HEADER(Encoding.h) + +#include +#include +#include +#include +#include + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "Encoding.h.in" +# include "Encoding.hxx.in" +#endif + +static const unsigned char helloWorldStrings[][32] = { + // English + { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', 0 }, + // Japanese + { 0xE3, 0x81, 0x93, 0xE3, 0x82, 0x93, 0xE3, 0x81, 0xAB, 0xE3, 0x81, + 0xA1, 0xE3, 0x81, 0xAF, 0xE4, 0xB8, 0x96, 0xE7, 0x95, 0x8C, 0 }, + // Arabic + { 0xD9, 0x85, 0xD8, 0xB1, 0xD8, 0xAD, 0xD8, 0xA8, 0xD8, 0xA7, 0x20, 0xD8, + 0xA7, 0xD9, 0x84, 0xD8, 0xB9, 0xD8, 0xA7, 0xD9, 0x84, 0xD9, 0x85, 0 }, + // Yiddish + { 0xD7, 0x94, 0xD7, 0xA2, 0xD7, 0x9C, 0xD7, 0x90, 0x20, 0xD7, + 0x95, 0xD7, 0x95, 0xD7, 0xA2, 0xD7, 0x9C, 0xD7, 0x98, 0 }, + // Russian + { 0xD0, 0xBF, 0xD1, 0x80, 0xD0, 0xB8, 0xD0, 0xB2, 0xD0, 0xB5, + 0xD1, 0x82, 0x20, 0xD0, 0xBC, 0xD0, 0xB8, 0xD1, 0x80, 0 }, + // Latin + { 0x4D, 0x75, 0x6E, 0x64, 0x75, 0x73, 0x20, 0x73, 0x61, 0x6C, 0x76, 0x65, + 0 }, + // Swahili + { 0x68, 0x75, 0x6A, 0x61, 0x6D, 0x62, 0x6F, 0x20, 0x44, 0x75, 0x6E, 0x69, + 0x61, 0 }, + // Icelandic + { 0x48, 0x61, 0x6C, 0x6C, 0xC3, 0xB3, 0x20, 0x68, 0x65, 0x69, 0x6D, 0x75, + 0x72, 0 }, + { 0 } +}; + +static int testHelloWorldEncoding() +{ + int ret = 0; + for (int i = 0; helloWorldStrings[i][0] != 0; i++) { + std::string str = reinterpret_cast(helloWorldStrings[i]); + std::cout << str << std::endl; + std::wstring wstr = kwsys::Encoding::ToWide(str); + std::string str2 = kwsys::Encoding::ToNarrow(wstr); + wchar_t* c_wstr = kwsysEncoding_DupToWide(str.c_str()); + char* c_str2 = kwsysEncoding_DupToNarrow(c_wstr); + if (!wstr.empty() && (str != str2 || strcmp(c_str2, str.c_str()))) { + std::cout << "converted string was different: " << str2 << std::endl; + std::cout << "converted string was different: " << c_str2 << std::endl; + ret++; + } + free(c_wstr); + free(c_str2); + } + return ret; +} + +static int testRobustEncoding() +{ + // test that the conversion functions handle invalid + // unicode correctly/gracefully + + // we manipulate the format flags of stdout, remember + // the original state here to restore before return + std::ios::fmtflags const& flags = std::cout.flags(); + + int ret = 0; + char cstr[] = { (char)-1, 0 }; + // this conversion could fail + std::wstring wstr = kwsys::Encoding::ToWide(cstr); + + wstr = kwsys::Encoding::ToWide(nullptr); + if (wstr != L"") { + const wchar_t* wcstr = wstr.c_str(); + std::cout << "ToWide(NULL) returned"; + for (size_t i = 0; i < wstr.size(); i++) { + std::cout << " " << std::hex << (int)wcstr[i]; + } + std::cout << std::endl; + ret++; + } + wstr = kwsys::Encoding::ToWide(""); + if (wstr != L"") { + const wchar_t* wcstr = wstr.c_str(); + std::cout << "ToWide(\"\") returned"; + for (size_t i = 0; i < wstr.size(); i++) { + std::cout << " " << std::hex << (int)wcstr[i]; + } + std::cout << std::endl; + ret++; + } + +#ifdef _WIN32 + // 16 bit wchar_t - we make an invalid surrogate pair + wchar_t cwstr[] = { 0xD801, 0xDA00, 0 }; + // this conversion could fail + std::string win_str = kwsys::Encoding::ToNarrow(cwstr); +#endif + + std::string str = kwsys::Encoding::ToNarrow(nullptr); + if (str != "") { + std::cout << "ToNarrow(NULL) returned " << str << std::endl; + ret++; + } + + str = kwsys::Encoding::ToNarrow(L""); + if (wstr != L"") { + std::cout << "ToNarrow(\"\") returned " << str << std::endl; + ret++; + } + + std::cout.flags(flags); + return ret; +} + +static int testWithNulls() +{ + int ret = 0; + std::vector strings; + strings.push_back(std::string("ab") + '\0' + 'c'); + strings.push_back(std::string("d") + '\0' + '\0' + 'e'); + strings.push_back(std::string() + '\0' + 'f'); + strings.push_back(std::string() + '\0' + '\0' + "gh"); + strings.push_back(std::string("ij") + '\0'); + strings.push_back(std::string("k") + '\0' + '\0'); + strings.push_back(std::string("\0\0\0\0", 4) + "lmn" + + std::string("\0\0\0\0", 4)); + for (std::vector::iterator it = strings.begin(); + it != strings.end(); ++it) { + std::wstring wstr = kwsys::Encoding::ToWide(*it); + std::string str = kwsys::Encoding::ToNarrow(wstr); + std::string s(*it); + std::replace(s.begin(), s.end(), '\0', ' '); + std::cout << "'" << s << "' (" << it->size() << ")" << std::endl; + if (str != *it) { + std::replace(str.begin(), str.end(), '\0', ' '); + std::cout << "string with null was different: '" << str << "' (" + << str.size() << ")" << std::endl; + ret++; + } + } + return ret; +} + +static int testCommandLineArguments() +{ + int status = 0; + + char const* argv[2] = { "./app.exe", (char const*)helloWorldStrings[1] }; + + kwsys::Encoding::CommandLineArguments args(2, argv); + kwsys::Encoding::CommandLineArguments arg2 = + kwsys::Encoding::CommandLineArguments(args); + + char const* const* u8_argv = args.argv(); + for (int i = 0; i < args.argc(); i++) { + char const* u8_arg = u8_argv[i]; + if (strcmp(argv[i], u8_arg) != 0) { + std::cout << "argv[" << i << "] " << argv[i] << " != " << u8_arg + << std::endl; + status++; + } + } + + kwsys::Encoding::CommandLineArguments args3 = + kwsys::Encoding::CommandLineArguments::Main(2, argv); + + return status; +} + +static int testToWindowsExtendedPath() +{ +#ifdef _WIN32 + int ret = 0; + if (kwsys::Encoding::ToWindowsExtendedPath( + "L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") != + L"\\\\?\\L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") { + std::cout << "Problem with ToWindowsExtendedPath " + << "\"L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\"" + << std::endl; + ++ret; + } + + if (kwsys::Encoding::ToWindowsExtendedPath( + "L:/Local Mojo/Hex Power Pack/Iffy Voodoo") != + L"\\\\?\\L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") { + std::cout << "Problem with ToWindowsExtendedPath " + << "\"L:/Local Mojo/Hex Power Pack/Iffy Voodoo\"" << std::endl; + ++ret; + } + + if (kwsys::Encoding::ToWindowsExtendedPath( + "\\\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") != + L"\\\\?\\UNC\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") { + std::cout << "Problem with ToWindowsExtendedPath " + << "\"\\\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\"" + << std::endl; + ++ret; + } + + if (kwsys::Encoding::ToWindowsExtendedPath( + "//Foo/Local Mojo/Hex Power Pack/Iffy Voodoo") != + L"\\\\?\\UNC\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") { + std::cout << "Problem with ToWindowsExtendedPath " + << "\"//Foo/Local Mojo/Hex Power Pack/Iffy Voodoo\"" + << std::endl; + ++ret; + } + + if (kwsys::Encoding::ToWindowsExtendedPath("//") != L"//") { + std::cout << "Problem with ToWindowsExtendedPath " + << "\"//\"" << std::endl; + ++ret; + } + + if (kwsys::Encoding::ToWindowsExtendedPath("\\\\.\\") != L"\\\\.\\") { + std::cout << "Problem with ToWindowsExtendedPath " + << "\"\\\\.\\\"" << std::endl; + ++ret; + } + + if (kwsys::Encoding::ToWindowsExtendedPath("\\\\.\\X") != L"\\\\.\\X") { + std::cout << "Problem with ToWindowsExtendedPath " + << "\"\\\\.\\X\"" << std::endl; + ++ret; + } + + if (kwsys::Encoding::ToWindowsExtendedPath("\\\\.\\X:") != L"\\\\?\\X:") { + std::cout << "Problem with ToWindowsExtendedPath " + << "\"\\\\.\\X:\"" << std::endl; + ++ret; + } + + if (kwsys::Encoding::ToWindowsExtendedPath("\\\\.\\X:\\") != + L"\\\\?\\X:\\") { + std::cout << "Problem with ToWindowsExtendedPath " + << "\"\\\\.\\X:\\\"" << std::endl; + ++ret; + } + + if (kwsys::Encoding::ToWindowsExtendedPath("NUL") != L"\\\\.\\NUL") { + std::cout << "Problem with ToWindowsExtendedPath " + << "\"NUL\"" << std::endl; + ++ret; + } + + return ret; +#else + return 0; +#endif +} + +int testEncoding(int, char* []) +{ + const char* loc = setlocale(LC_ALL, ""); + if (loc) { + std::cout << "Locale: " << loc << std::endl; + } else { + std::cout << "Locale: None" << std::endl; + } + + int ret = 0; + + ret |= testHelloWorldEncoding(); + ret |= testRobustEncoding(); + ret |= testCommandLineArguments(); + ret |= testWithNulls(); + ret |= testToWindowsExtendedPath(); + + return ret; +} diff --git a/test/API/driver/kwsys/testFStream.cxx b/test/API/driver/kwsys/testFStream.cxx new file mode 100644 index 0000000..5009e98 --- /dev/null +++ b/test/API/driver/kwsys/testFStream.cxx @@ -0,0 +1,113 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" + +#if defined(_MSC_VER) +# pragma warning(disable : 4786) +#endif + +#include KWSYS_HEADER(FStream.hxx) +#include +#ifdef __BORLANDC__ +# include /* memcmp */ +#endif + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "FStream.hxx.in" +#endif + +#include + +static int testNoFile() +{ + kwsys::ifstream in_file("NoSuchFile.txt"); + if (in_file) { + return 1; + } + + return 0; +} + +static const int num_test_files = 7; +static const int max_test_file_size = 45; + +static kwsys::FStream::BOM expected_bom[num_test_files] = { + kwsys::FStream::BOM_None, kwsys::FStream::BOM_None, + kwsys::FStream::BOM_UTF8, kwsys::FStream::BOM_UTF16LE, + kwsys::FStream::BOM_UTF16BE, kwsys::FStream::BOM_UTF32LE, + kwsys::FStream::BOM_UTF32BE +}; + +static unsigned char expected_bom_data[num_test_files][5] = { + { 0 }, + { 0 }, + { 3, 0xEF, 0xBB, 0xBF }, + { 2, 0xFF, 0xFE }, + { 2, 0xFE, 0xFF }, + { 4, 0xFF, 0xFE, 0x00, 0x00 }, + { 4, 0x00, 0x00, 0xFE, 0xFF }, +}; + +static unsigned char file_data[num_test_files][max_test_file_size] = { + { 1, 'H' }, + { 11, 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd' }, + { 11, 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd' }, + { 22, 0x48, 0x00, 0x65, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6F, 0x00, 0x20, + 0x00, 0x57, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x6C, 0x00, 0x64, 0x00 }, + { 22, 0x00, 0x48, 0x00, 0x65, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6F, 0x00, + 0x20, 0x00, 0x57, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x6C, 0x00, 0x64 }, + { 44, 0x48, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, + 0x00, 0x6C, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x57, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, + 0x00, 0x6C, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00 }, + { 44, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, + 0x6C, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, + 0x72, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x64 }, +}; + +static int testBOM() +{ + // test various encodings in binary mode + for (int i = 0; i < num_test_files; i++) { + { + kwsys::ofstream out("bom.txt", kwsys::ofstream::binary); + out.write(reinterpret_cast(expected_bom_data[i] + 1), + *expected_bom_data[i]); + out.write(reinterpret_cast(file_data[i] + 1), + file_data[i][0]); + } + + kwsys::ifstream in("bom.txt", kwsys::ofstream::binary); + kwsys::FStream::BOM bom = kwsys::FStream::ReadBOM(in); + if (bom != expected_bom[i]) { + std::cout << "Unexpected BOM " << i << std::endl; + return 1; + } + char data[max_test_file_size]; + in.read(data, file_data[i][0]); + if (!in.good()) { + std::cout << "Unable to read data " << i << std::endl; + return 1; + } + + if (memcmp(data, file_data[i] + 1, file_data[i][0]) != 0) { + std::cout << "Incorrect read data " << i << std::endl; + return 1; + } + } + + return 0; +} + +int testFStream(int, char* []) +{ + int ret = 0; + + ret |= testNoFile(); + ret |= testBOM(); + + return ret; +} diff --git a/test/API/driver/kwsys/testFail.c b/test/API/driver/kwsys/testFail.c new file mode 100644 index 0000000..82caeac --- /dev/null +++ b/test/API/driver/kwsys/testFail.c @@ -0,0 +1,24 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include +#include +#include + +int testFail(int argc, char* argv[]) +{ + char* env = getenv("DASHBOARD_TEST_FROM_CTEST"); + int oldCtest = 0; + if (env) { + if (strcmp(env, "1") == 0) { + oldCtest = 1; + } + printf("DASHBOARD_TEST_FROM_CTEST = %s\n", env); + } + printf("%s: This test intentionally fails\n", argv[0]); + if (oldCtest) { + printf("The version of ctest is not able to handle intentionally failing " + "tests, so pass.\n"); + return 0; + } + return argc; +} diff --git a/test/API/driver/kwsys/testHashSTL.cxx b/test/API/driver/kwsys/testHashSTL.cxx new file mode 100644 index 0000000..4ed2f89 --- /dev/null +++ b/test/API/driver/kwsys/testHashSTL.cxx @@ -0,0 +1,64 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(hash_map.hxx) +#include KWSYS_HEADER(hash_set.hxx) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "hash_map.hxx.in" +# include "hash_set.hxx.in" +#endif + +#include + +#if defined(_MSC_VER) +# pragma warning(disable : 4786) +#endif + +#if defined(__sgi) && !defined(__GNUC__) +# pragma set woff 1468 /* inline function cannot be explicitly instantiated \ + */ +#endif + +template class kwsys::hash_map; +template class kwsys::hash_set; + +static bool test_hash_map() +{ + typedef kwsys::hash_map mtype; + mtype m; + const char* keys[] = { "hello", "world" }; + m[keys[0]] = 1; + m.insert(mtype::value_type(keys[1], 2)); + int sum = 0; + for (mtype::iterator mi = m.begin(); mi != m.end(); ++mi) { + std::cout << "Found entry [" << mi->first << "," << mi->second << "]" + << std::endl; + sum += mi->second; + } + return sum == 3; +} + +static bool test_hash_set() +{ + typedef kwsys::hash_set stype; + stype s; + s.insert(1); + s.insert(2); + int sum = 0; + for (stype::iterator si = s.begin(); si != s.end(); ++si) { + std::cout << "Found entry [" << *si << "]" << std::endl; + sum += *si; + } + return sum == 3; +} + +int testHashSTL(int, char* []) +{ + bool result = true; + result = test_hash_map() && result; + result = test_hash_set() && result; + return result ? 0 : 1; +} diff --git a/test/API/driver/kwsys/testProcess.c b/test/API/driver/kwsys/testProcess.c new file mode 100644 index 0000000..39aaa23 --- /dev/null +++ b/test/API/driver/kwsys/testProcess.c @@ -0,0 +1,728 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(Process.h) +#include KWSYS_HEADER(Encoding.h) + +/* Work-around CMake dependency scanning limitation. This must + duplicate the above list of headers. */ +#if 0 +# include "Encoding.h.in" +# include "Process.h.in" +#endif + +#include +#include +#include +#include +#include + +#if defined(_WIN32) +# include +#else +# include +# include +#endif + +#if defined(__BORLANDC__) +# pragma warn - 8060 /* possibly incorrect assignment */ +#endif + +/* Platform-specific sleep functions. */ + +#if defined(__BEOS__) && !defined(__ZETA__) +/* BeOS 5 doesn't have usleep(), but it has snooze(), which is identical. */ +# include +static inline void testProcess_usleep(unsigned int usec) +{ + snooze(usec); +} +#elif defined(_WIN32) +/* Windows can only sleep in millisecond intervals. */ +static void testProcess_usleep(unsigned int usec) +{ + Sleep(usec / 1000); +} +#else +# define testProcess_usleep usleep +#endif + +#if defined(_WIN32) +static void testProcess_sleep(unsigned int sec) +{ + Sleep(sec * 1000); +} +#else +static void testProcess_sleep(unsigned int sec) +{ + sleep(sec); +} +#endif + +int runChild(const char* cmd[], int state, int exception, int value, int share, + int output, int delay, double timeout, int poll, int repeat, + int disown, int createNewGroup, unsigned int interruptDelay); + +static int test1(int argc, const char* argv[]) +{ + /* This is a very basic functional test of kwsysProcess. It is repeated + numerous times to verify that there are no resource leaks in kwsysProcess + that eventually lead to an error. Many versions of OS X will fail after + 256 leaked file handles, so 257 iterations seems to be a good test. On + the other hand, too many iterations will cause the test to time out - + especially if the test is instrumented with e.g. valgrind. + + If you have problems with this test timing out on your system, or want to + run more than 257 iterations, you can change the number of iterations by + setting the KWSYS_TEST_PROCESS_1_COUNT environment variable. */ + (void)argc; + (void)argv; + fprintf(stdout, "Output on stdout from test returning 0.\n"); + fprintf(stderr, "Output on stderr from test returning 0.\n"); + return 0; +} + +static int test2(int argc, const char* argv[]) +{ + (void)argc; + (void)argv; + fprintf(stdout, "Output on stdout from test returning 123.\n"); + fprintf(stderr, "Output on stderr from test returning 123.\n"); + return 123; +} + +static int test3(int argc, const char* argv[]) +{ + (void)argc; + (void)argv; + fprintf(stdout, "Output before sleep on stdout from timeout test.\n"); + fprintf(stderr, "Output before sleep on stderr from timeout test.\n"); + fflush(stdout); + fflush(stderr); + testProcess_sleep(15); + fprintf(stdout, "Output after sleep on stdout from timeout test.\n"); + fprintf(stderr, "Output after sleep on stderr from timeout test.\n"); + return 0; +} + +static int test4(int argc, const char* argv[]) +{ +#ifndef CRASH_USING_ABORT + /* Prepare a pointer to an invalid address. Don't use null, because + dereferencing null is undefined behaviour and compilers are free to + do whatever they want. ex: Clang will warn at compile time, or even + optimize away the write. We hope to 'outsmart' them by using + 'volatile' and a slightly larger address, based on a runtime value. */ + volatile int* invalidAddress = 0; + invalidAddress += argc ? 1 : 2; +#endif + +#if defined(_WIN32) + /* Avoid error diagnostic popups since we are crashing on purpose. */ + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); +#elif defined(__BEOS__) || defined(__HAIKU__) + /* Avoid error diagnostic popups since we are crashing on purpose. */ + disable_debugger(1); +#endif + (void)argc; + (void)argv; + fprintf(stdout, "Output before crash on stdout from crash test.\n"); + fprintf(stderr, "Output before crash on stderr from crash test.\n"); + fflush(stdout); + fflush(stderr); +#ifdef CRASH_USING_ABORT + abort(); +#else + assert(invalidAddress); /* Quiet Clang scan-build. */ + /* Provoke deliberate crash by writing to the invalid address. */ + *invalidAddress = 0; +#endif + fprintf(stdout, "Output after crash on stdout from crash test.\n"); + fprintf(stderr, "Output after crash on stderr from crash test.\n"); + return 0; +} + +static int test5(int argc, const char* argv[]) +{ + int r; + const char* cmd[4]; + (void)argc; + cmd[0] = argv[0]; + cmd[1] = "run"; + cmd[2] = "4"; + cmd[3] = 0; + fprintf(stdout, "Output on stdout before recursive test.\n"); + fprintf(stderr, "Output on stderr before recursive test.\n"); + fflush(stdout); + fflush(stderr); + r = runChild(cmd, kwsysProcess_State_Exception, +#ifdef CRASH_USING_ABORT + kwsysProcess_Exception_Other, +#else + kwsysProcess_Exception_Fault, +#endif + 1, 1, 1, 0, 15, 0, 1, 0, 0, 0); + fprintf(stdout, "Output on stdout after recursive test.\n"); + fprintf(stderr, "Output on stderr after recursive test.\n"); + fflush(stdout); + fflush(stderr); + return r; +} + +#define TEST6_SIZE (4096 * 2) +static void test6(int argc, const char* argv[]) +{ + int i; + char runaway[TEST6_SIZE + 1]; + (void)argc; + (void)argv; + for (i = 0; i < TEST6_SIZE; ++i) { + runaway[i] = '.'; + } + runaway[TEST6_SIZE] = '\n'; + + /* Generate huge amounts of output to test killing. */ + for (;;) { + fwrite(runaway, 1, TEST6_SIZE + 1, stdout); + fflush(stdout); + } +} + +/* Define MINPOLL to be one more than the number of times output is + written. Define MAXPOLL to be the largest number of times a loop + delaying 1/10th of a second should ever have to poll. */ +#define MINPOLL 5 +#define MAXPOLL 20 +static int test7(int argc, const char* argv[]) +{ + (void)argc; + (void)argv; + fprintf(stdout, "Output on stdout before sleep.\n"); + fprintf(stderr, "Output on stderr before sleep.\n"); + fflush(stdout); + fflush(stderr); + /* Sleep for 1 second. */ + testProcess_sleep(1); + fprintf(stdout, "Output on stdout after sleep.\n"); + fprintf(stderr, "Output on stderr after sleep.\n"); + fflush(stdout); + fflush(stderr); + return 0; +} + +static int test8(int argc, const char* argv[]) +{ + /* Create a disowned grandchild to test handling of processes + that exit before their children. */ + int r; + const char* cmd[4]; + (void)argc; + cmd[0] = argv[0]; + cmd[1] = "run"; + cmd[2] = "108"; + cmd[3] = 0; + fprintf(stdout, "Output on stdout before grandchild test.\n"); + fprintf(stderr, "Output on stderr before grandchild test.\n"); + fflush(stdout); + fflush(stderr); + r = runChild(cmd, kwsysProcess_State_Disowned, kwsysProcess_Exception_None, + 1, 1, 1, 0, 10, 0, 1, 1, 0, 0); + fprintf(stdout, "Output on stdout after grandchild test.\n"); + fprintf(stderr, "Output on stderr after grandchild test.\n"); + fflush(stdout); + fflush(stderr); + return r; +} + +static int test8_grandchild(int argc, const char* argv[]) +{ + (void)argc; + (void)argv; + fprintf(stdout, "Output on stdout from grandchild before sleep.\n"); + fprintf(stderr, "Output on stderr from grandchild before sleep.\n"); + fflush(stdout); + fflush(stderr); + /* TODO: Instead of closing pipes here leave them open to make sure + the grandparent can stop listening when the parent exits. This + part of the test cannot be enabled until the feature is + implemented. */ + fclose(stdout); + fclose(stderr); + testProcess_sleep(15); + return 0; +} + +static int test9(int argc, const char* argv[]) +{ + /* Test Ctrl+C behavior: the root test program will send a Ctrl+C to this + process. Here, we start a child process that sleeps for a long time + while ignoring signals. The test is successful if this process waits + for the child to return before exiting from the Ctrl+C handler. + + WARNING: This test will falsely pass if the share parameter of runChild + was set to 0 when invoking the test9 process. */ + int r; + const char* cmd[4]; + (void)argc; + cmd[0] = argv[0]; + cmd[1] = "run"; + cmd[2] = "109"; + cmd[3] = 0; + fprintf(stdout, "Output on stdout before grandchild test.\n"); + fprintf(stderr, "Output on stderr before grandchild test.\n"); + fflush(stdout); + fflush(stderr); + r = runChild(cmd, kwsysProcess_State_Exited, kwsysProcess_Exception_None, 0, + 1, 1, 0, 30, 0, 1, 0, 0, 0); + /* This sleep will avoid a race condition between this function exiting + normally and our Ctrl+C handler exiting abnormally after the process + exits. */ + testProcess_sleep(1); + fprintf(stdout, "Output on stdout after grandchild test.\n"); + fprintf(stderr, "Output on stderr after grandchild test.\n"); + fflush(stdout); + fflush(stderr); + return r; +} + +#if defined(_WIN32) +static BOOL WINAPI test9_grandchild_handler(DWORD dwCtrlType) +{ + /* Ignore all Ctrl+C/Break signals. We must use an actual handler function + instead of using SetConsoleCtrlHandler(NULL, TRUE) so that we can also + ignore Ctrl+Break in addition to Ctrl+C. */ + (void)dwCtrlType; + return TRUE; +} +#endif + +static int test9_grandchild(int argc, const char* argv[]) +{ + /* The grandchild just sleeps for a few seconds while ignoring signals. */ + (void)argc; + (void)argv; +#if defined(_WIN32) + if (!SetConsoleCtrlHandler(test9_grandchild_handler, TRUE)) { + return 1; + } +#else + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_IGN; + sigemptyset(&sa.sa_mask); + if (sigaction(SIGINT, &sa, 0) < 0) { + return 1; + } +#endif + fprintf(stdout, "Output on stdout from grandchild before sleep.\n"); + fprintf(stderr, "Output on stderr from grandchild before sleep.\n"); + fflush(stdout); + fflush(stderr); + /* Sleep for 9 seconds. */ + testProcess_sleep(9); + fprintf(stdout, "Output on stdout from grandchild after sleep.\n"); + fprintf(stderr, "Output on stderr from grandchild after sleep.\n"); + fflush(stdout); + fflush(stderr); + return 0; +} + +static int test10(int argc, const char* argv[]) +{ + /* Test Ctrl+C behavior: the root test program will send a Ctrl+C to this + process. Here, we start a child process that sleeps for a long time and + processes signals normally. However, this grandchild is created in a new + process group - ensuring that Ctrl+C we receive is sent to our process + groups. We make sure it exits anyway. */ + int r; + const char* cmd[4]; + (void)argc; + cmd[0] = argv[0]; + cmd[1] = "run"; + cmd[2] = "110"; + cmd[3] = 0; + fprintf(stdout, "Output on stdout before grandchild test.\n"); + fprintf(stderr, "Output on stderr before grandchild test.\n"); + fflush(stdout); + fflush(stderr); + r = + runChild(cmd, kwsysProcess_State_Exception, + kwsysProcess_Exception_Interrupt, 0, 1, 1, 0, 30, 0, 1, 0, 1, 0); + fprintf(stdout, "Output on stdout after grandchild test.\n"); + fprintf(stderr, "Output on stderr after grandchild test.\n"); + fflush(stdout); + fflush(stderr); + return r; +} + +static int test10_grandchild(int argc, const char* argv[]) +{ + /* The grandchild just sleeps for a few seconds and handles signals. */ + (void)argc; + (void)argv; + fprintf(stdout, "Output on stdout from grandchild before sleep.\n"); + fprintf(stderr, "Output on stderr from grandchild before sleep.\n"); + fflush(stdout); + fflush(stderr); + /* Sleep for 6 seconds. */ + testProcess_sleep(6); + fprintf(stdout, "Output on stdout from grandchild after sleep.\n"); + fprintf(stderr, "Output on stderr from grandchild after sleep.\n"); + fflush(stdout); + fflush(stderr); + return 0; +} + +static int runChild2(kwsysProcess* kp, const char* cmd[], int state, + int exception, int value, int share, int output, + int delay, double timeout, int poll, int disown, + int createNewGroup, unsigned int interruptDelay) +{ + int result = 0; + char* data = 0; + int length = 0; + double userTimeout = 0; + double* pUserTimeout = 0; + kwsysProcess_SetCommand(kp, cmd); + if (timeout >= 0) { + kwsysProcess_SetTimeout(kp, timeout); + } + if (share) { + kwsysProcess_SetPipeShared(kp, kwsysProcess_Pipe_STDOUT, 1); + kwsysProcess_SetPipeShared(kp, kwsysProcess_Pipe_STDERR, 1); + } + if (disown) { + kwsysProcess_SetOption(kp, kwsysProcess_Option_Detach, 1); + } + if (createNewGroup) { + kwsysProcess_SetOption(kp, kwsysProcess_Option_CreateProcessGroup, 1); + } + kwsysProcess_Execute(kp); + + if (poll) { + pUserTimeout = &userTimeout; + } + + if (interruptDelay) { + testProcess_sleep(interruptDelay); + kwsysProcess_Interrupt(kp); + } + + if (!share && !disown) { + int p; + while ((p = kwsysProcess_WaitForData(kp, &data, &length, pUserTimeout))) { + if (output) { + if (poll && p == kwsysProcess_Pipe_Timeout) { + fprintf(stdout, "WaitForData timeout reached.\n"); + fflush(stdout); + + /* Count the number of times we polled without getting data. + If it is excessive then kill the child and fail. */ + if (++poll >= MAXPOLL) { + fprintf(stdout, "Poll count reached limit %d.\n", MAXPOLL); + kwsysProcess_Kill(kp); + } + } else { + fwrite(data, 1, (size_t)length, stdout); + fflush(stdout); + } + } + if (poll) { + /* Delay to avoid busy loop during polling. */ + testProcess_usleep(100000); + } + if (delay) { +/* Purposely sleeping only on Win32 to let pipe fill up. */ +#if defined(_WIN32) + testProcess_usleep(100000); +#endif + } + } + } + + if (disown) { + kwsysProcess_Disown(kp); + } else { + kwsysProcess_WaitForExit(kp, 0); + } + + switch (kwsysProcess_GetState(kp)) { + case kwsysProcess_State_Starting: + printf("No process has been executed.\n"); + break; + case kwsysProcess_State_Executing: + printf("The process is still executing.\n"); + break; + case kwsysProcess_State_Expired: + printf("Child was killed when timeout expired.\n"); + break; + case kwsysProcess_State_Exited: + printf("Child exited with value = %d\n", kwsysProcess_GetExitValue(kp)); + result = ((exception != kwsysProcess_GetExitException(kp)) || + (value != kwsysProcess_GetExitValue(kp))); + break; + case kwsysProcess_State_Killed: + printf("Child was killed by parent.\n"); + break; + case kwsysProcess_State_Exception: + printf("Child terminated abnormally: %s\n", + kwsysProcess_GetExceptionString(kp)); + result = ((exception != kwsysProcess_GetExitException(kp)) || + (value != kwsysProcess_GetExitValue(kp))); + break; + case kwsysProcess_State_Disowned: + printf("Child was disowned.\n"); + break; + case kwsysProcess_State_Error: + printf("Error in administrating child process: [%s]\n", + kwsysProcess_GetErrorString(kp)); + break; + } + + if (result) { + if (exception != kwsysProcess_GetExitException(kp)) { + fprintf(stderr, + "Mismatch in exit exception. " + "Should have been %d, was %d.\n", + exception, kwsysProcess_GetExitException(kp)); + } + if (value != kwsysProcess_GetExitValue(kp)) { + fprintf(stderr, + "Mismatch in exit value. " + "Should have been %d, was %d.\n", + value, kwsysProcess_GetExitValue(kp)); + } + } + + if (kwsysProcess_GetState(kp) != state) { + fprintf(stderr, + "Mismatch in state. " + "Should have been %d, was %d.\n", + state, kwsysProcess_GetState(kp)); + result = 1; + } + + /* We should have polled more times than there were data if polling + was enabled. */ + if (poll && poll < MINPOLL) { + fprintf(stderr, "Poll count is %d, which is less than %d.\n", poll, + MINPOLL); + result = 1; + } + + return result; +} + +/** + * Runs a child process and blocks until it returns. Arguments as follows: + * + * cmd = Command line to run. + * state = Expected return value of kwsysProcess_GetState after exit. + * exception = Expected return value of kwsysProcess_GetExitException. + * value = Expected return value of kwsysProcess_GetExitValue. + * share = Whether to share stdout/stderr child pipes with our pipes + * by way of kwsysProcess_SetPipeShared. If false, new pipes + * are created. + * output = If !share && !disown, whether to write the child's stdout + * and stderr output to our stdout. + * delay = If !share && !disown, adds an additional short delay to + * the pipe loop to allow the pipes to fill up; Windows only. + * timeout = Non-zero to sets a timeout in seconds via + * kwsysProcess_SetTimeout. + * poll = If !share && !disown, we count the number of 0.1 second + * intervals where the child pipes had no new data. We fail + * if not in the bounds of MINPOLL/MAXPOLL. + * repeat = Number of times to run the process. + * disown = If set, the process is disowned. + * createNewGroup = If set, the process is created in a new process group. + * interruptDelay = If non-zero, number of seconds to delay before + * interrupting the process. Note that this delay will occur + * BEFORE any reading/polling of pipes occurs and before any + * detachment occurs. + */ +int runChild(const char* cmd[], int state, int exception, int value, int share, + int output, int delay, double timeout, int poll, int repeat, + int disown, int createNewGroup, unsigned int interruptDelay) +{ + int result = 1; + kwsysProcess* kp = kwsysProcess_New(); + if (!kp) { + fprintf(stderr, "kwsysProcess_New returned NULL!\n"); + return 1; + } + while (repeat-- > 0) { + result = runChild2(kp, cmd, state, exception, value, share, output, delay, + timeout, poll, disown, createNewGroup, interruptDelay); + if (result) { + break; + } + } + kwsysProcess_Delete(kp); + return result; +} + +int main(int argc, const char* argv[]) +{ + int n = 0; + +#ifdef _WIN32 + int i; + char new_args[10][_MAX_PATH]; + LPWSTR* w_av = CommandLineToArgvW(GetCommandLineW(), &argc); + for (i = 0; i < argc; i++) { + kwsysEncoding_wcstombs(new_args[i], w_av[i], _MAX_PATH); + argv[i] = new_args[i]; + } + LocalFree(w_av); +#endif + +#if 0 + { + HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE); + DuplicateHandle(GetCurrentProcess(), out, + GetCurrentProcess(), &out, 0, FALSE, + DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + SetStdHandle(STD_OUTPUT_HANDLE, out); + } + { + HANDLE out = GetStdHandle(STD_ERROR_HANDLE); + DuplicateHandle(GetCurrentProcess(), out, + GetCurrentProcess(), &out, 0, FALSE, + DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + SetStdHandle(STD_ERROR_HANDLE, out); + } +#endif + if (argc == 2) { + n = atoi(argv[1]); + } else if (argc == 3 && strcmp(argv[1], "run") == 0) { + n = atoi(argv[2]); + } + /* Check arguments. */ + if (((n >= 1 && n <= 10) || n == 108 || n == 109 || n == 110) && argc == 3) { + /* This is the child process for a requested test number. */ + switch (n) { + case 1: + return test1(argc, argv); + case 2: + return test2(argc, argv); + case 3: + return test3(argc, argv); + case 4: + return test4(argc, argv); + case 5: + return test5(argc, argv); + case 6: + test6(argc, argv); + return 0; + case 7: + return test7(argc, argv); + case 8: + return test8(argc, argv); + case 9: + return test9(argc, argv); + case 10: + return test10(argc, argv); + case 108: + return test8_grandchild(argc, argv); + case 109: + return test9_grandchild(argc, argv); + case 110: + return test10_grandchild(argc, argv); + } + fprintf(stderr, "Invalid test number %d.\n", n); + return 1; + } else if (n >= 1 && n <= 10) { + /* This is the parent process for a requested test number. */ + int states[10] = { + kwsysProcess_State_Exited, kwsysProcess_State_Exited, + kwsysProcess_State_Expired, kwsysProcess_State_Exception, + kwsysProcess_State_Exited, kwsysProcess_State_Expired, + kwsysProcess_State_Exited, kwsysProcess_State_Exited, + kwsysProcess_State_Expired, /* Ctrl+C handler test */ + kwsysProcess_State_Exception /* Process group test */ + }; + int exceptions[10] = { + kwsysProcess_Exception_None, kwsysProcess_Exception_None, + kwsysProcess_Exception_None, +#ifdef CRASH_USING_ABORT + kwsysProcess_Exception_Other, +#else + kwsysProcess_Exception_Fault, +#endif + kwsysProcess_Exception_None, kwsysProcess_Exception_None, + kwsysProcess_Exception_None, kwsysProcess_Exception_None, + kwsysProcess_Exception_None, kwsysProcess_Exception_Interrupt + }; + int values[10] = { 0, 123, 1, 1, 0, 0, 0, 0, 1, 1 }; + int shares[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 }; + int outputs[10] = { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1 }; + int delays[10] = { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 }; + double timeouts[10] = { 10, 10, 10, 30, 30, 10, -1, 10, 6, 4 }; + int polls[10] = { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }; + int repeat[10] = { 257, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; + int createNewGroups[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 }; + unsigned int interruptDelays[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 3, 2 }; + int r; + const char* cmd[4]; +#ifdef _WIN32 + char* argv0 = 0; +#endif + char* test1IterationsStr = getenv("KWSYS_TEST_PROCESS_1_COUNT"); + if (test1IterationsStr) { + long int test1Iterations = strtol(test1IterationsStr, 0, 10); + if (test1Iterations > 10 && test1Iterations != LONG_MAX) { + repeat[0] = (int)test1Iterations; + } + } +#ifdef _WIN32 + if (n == 0 && (argv0 = strdup(argv[0]))) { + /* Try converting to forward slashes to see if it works. */ + char* c; + for (c = argv0; *c; ++c) { + if (*c == '\\') { + *c = '/'; + } + } + cmd[0] = argv0; + } else { + cmd[0] = argv[0]; + } +#else + cmd[0] = argv[0]; +#endif + cmd[1] = "run"; + cmd[2] = argv[1]; + cmd[3] = 0; + fprintf(stdout, "Output on stdout before test %d.\n", n); + fprintf(stderr, "Output on stderr before test %d.\n", n); + fflush(stdout); + fflush(stderr); + r = runChild(cmd, states[n - 1], exceptions[n - 1], values[n - 1], + shares[n - 1], outputs[n - 1], delays[n - 1], timeouts[n - 1], + polls[n - 1], repeat[n - 1], 0, createNewGroups[n - 1], + interruptDelays[n - 1]); + fprintf(stdout, "Output on stdout after test %d.\n", n); + fprintf(stderr, "Output on stderr after test %d.\n", n); + fflush(stdout); + fflush(stderr); +#if defined(_WIN32) + free(argv0); +#endif + return r; + } else if (argc > 2 && strcmp(argv[1], "0") == 0) { + /* This is the special debugging test to run a given command + line. */ + const char** cmd = argv + 2; + int state = kwsysProcess_State_Exited; + int exception = kwsysProcess_Exception_None; + int value = 0; + double timeout = 0; + int r = + runChild(cmd, state, exception, value, 0, 1, 0, timeout, 0, 1, 0, 0, 0); + return r; + } else { + /* Improper usage. */ + fprintf(stdout, "Usage: %s \n", argv[0]); + return 1; + } +} diff --git a/test/API/driver/kwsys/testSharedForward.c.in b/test/API/driver/kwsys/testSharedForward.c.in new file mode 100644 index 0000000..b3eb413 --- /dev/null +++ b/test/API/driver/kwsys/testSharedForward.c.in @@ -0,0 +1,27 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#if defined(CMAKE_INTDIR) +# define CONFIG_DIR_PRE CMAKE_INTDIR "/" +# define CONFIG_DIR_POST "/" CMAKE_INTDIR +#else +# define CONFIG_DIR_PRE "" +# define CONFIG_DIR_POST "" +#endif +#define @KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD "@EXEC_DIR@" +#define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD "." CONFIG_DIR_POST +#define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL 0 +#define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD \ + CONFIG_DIR_PRE "@KWSYS_NAMESPACE@TestProcess" +#define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL \ + "@KWSYS_NAMESPACE@TestProcess" +#define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_COMMAND "--command" +#define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_PRINT "--print" +#define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_LDD "--ldd" +#if defined(CMAKE_INTDIR) +# define @KWSYS_NAMESPACE@_SHARED_FORWARD_CONFIG_NAME CMAKE_INTDIR +#endif +#include <@KWSYS_NAMESPACE@/SharedForward.h> +int main(int argc, char** argv) +{ + return @KWSYS_NAMESPACE@_shared_forward_to_real(argc, argv); +} diff --git a/test/API/driver/kwsys/testSystemInformation.cxx b/test/API/driver/kwsys/testSystemInformation.cxx new file mode 100644 index 0000000..154517e --- /dev/null +++ b/test/API/driver/kwsys/testSystemInformation.cxx @@ -0,0 +1,106 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(SystemInformation.hxx) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "SystemInformation.hxx.in" +#endif + +#include + +#if defined(KWSYS_USE_LONG_LONG) +# if defined(KWSYS_IOS_HAS_OSTREAM_LONG_LONG) +# define iostreamLongLong(x) (x) +# else +# define iostreamLongLong(x) ((long)x) +# endif +#elif defined(KWSYS_USE___INT64) +# if defined(KWSYS_IOS_HAS_OSTREAM___INT64) +# define iostreamLongLong(x) (x) +# else +# define iostreamLongLong(x) ((long)x) +# endif +#else +# error "No Long Long" +#endif + +#define printMethod(info, m) std::cout << #m << ": " << info.m() << "\n" + +#define printMethod2(info, m, unit) \ + std::cout << #m << ": " << info.m() << " " << unit << "\n" + +#define printMethod3(info, m, unit) \ + std::cout << #m << ": " << iostreamLongLong(info.m) << " " << unit << "\n" + +int testSystemInformation(int, char* []) +{ + std::cout << "CTEST_FULL_OUTPUT\n"; // avoid truncation + + kwsys::SystemInformation info; + info.RunCPUCheck(); + info.RunOSCheck(); + info.RunMemoryCheck(); + printMethod(info, GetOSName); + printMethod(info, GetOSIsLinux); + printMethod(info, GetOSIsApple); + printMethod(info, GetOSIsWindows); + printMethod(info, GetHostname); + printMethod(info, GetFullyQualifiedDomainName); + printMethod(info, GetOSRelease); + printMethod(info, GetOSVersion); + printMethod(info, GetOSPlatform); + printMethod(info, Is64Bits); + printMethod(info, GetVendorString); + printMethod(info, GetVendorID); + printMethod(info, GetTypeID); + printMethod(info, GetFamilyID); + printMethod(info, GetModelID); + printMethod(info, GetExtendedProcessorName); + printMethod(info, GetSteppingCode); + printMethod(info, GetProcessorSerialNumber); + printMethod2(info, GetProcessorCacheSize, "KB"); + printMethod(info, GetLogicalProcessorsPerPhysical); + printMethod2(info, GetProcessorClockFrequency, "MHz"); + printMethod(info, GetNumberOfLogicalCPU); + printMethod(info, GetNumberOfPhysicalCPU); + printMethod(info, DoesCPUSupportCPUID); + printMethod(info, GetProcessorAPICID); + printMethod2(info, GetTotalVirtualMemory, "MB"); + printMethod2(info, GetAvailableVirtualMemory, "MB"); + printMethod2(info, GetTotalPhysicalMemory, "MB"); + printMethod2(info, GetAvailablePhysicalMemory, "MB"); + printMethod3(info, GetHostMemoryTotal(), "KiB"); + printMethod3(info, GetHostMemoryAvailable("KWSHL"), "KiB"); + printMethod3(info, GetProcMemoryAvailable("KWSHL", "KWSPL"), "KiB"); + printMethod3(info, GetHostMemoryUsed(), "KiB"); + printMethod3(info, GetProcMemoryUsed(), "KiB"); + printMethod(info, GetLoadAverage); + + for (long int i = 0; i <= 31; i++) { + if (info.DoesCPUSupportFeature(static_cast(1) << i)) { + std::cout << "CPU feature " << i << "\n"; + } + } + + /* test stack trace + */ + std::cout << "Program Stack:" << std::endl + << kwsys::SystemInformation::GetProgramStack(0, 0) << std::endl + << std::endl; + + /* test segv handler + info.SetStackTraceOnError(1); + double *d = (double*)100; + *d=0; + */ + + /* test abort handler + info.SetStackTraceOnError(1); + abort(); + */ + + return 0; +} diff --git a/test/API/driver/kwsys/testSystemTools.bin b/test/API/driver/kwsys/testSystemTools.bin new file mode 100644 index 0000000..961a404 Binary files /dev/null and b/test/API/driver/kwsys/testSystemTools.bin differ diff --git a/test/API/driver/kwsys/testSystemTools.cxx b/test/API/driver/kwsys/testSystemTools.cxx new file mode 100644 index 0000000..1f3a15b --- /dev/null +++ b/test/API/driver/kwsys/testSystemTools.cxx @@ -0,0 +1,1128 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" + +#if defined(_MSC_VER) +# pragma warning(disable : 4786) +#endif + +#include KWSYS_HEADER(FStream.hxx) +#include KWSYS_HEADER(SystemTools.hxx) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "FStream.hxx.in" +# include "SystemTools.hxx.in" +#endif + +// Include with <> instead of "" to avoid getting any in-source copy +// left on disk. +#include + +#include +#include +#include /* free */ +#include /* strcmp */ +#if defined(_WIN32) && !defined(__CYGWIN__) +# include /* _umask (MSVC) / umask (Borland) */ +# ifdef _MSC_VER +# define umask _umask // Note this is still umask on Borland +# endif +#endif +#include /* umask (POSIX), _S_I* constants (Windows) */ +// Visual C++ does not define mode_t (note that Borland does, however). +#if defined(_MSC_VER) +typedef unsigned short mode_t; +#endif + +static const char* toUnixPaths[][2] = { + { "/usr/local/bin/passwd", "/usr/local/bin/passwd" }, + { "/usr/lo cal/bin/pa sswd", "/usr/lo cal/bin/pa sswd" }, + { "/usr/lo\\ cal/bin/pa\\ sswd", "/usr/lo/ cal/bin/pa/ sswd" }, + { "c:/usr/local/bin/passwd", "c:/usr/local/bin/passwd" }, + { "c:/usr/lo cal/bin/pa sswd", "c:/usr/lo cal/bin/pa sswd" }, + { "c:/usr/lo\\ cal/bin/pa\\ sswd", "c:/usr/lo/ cal/bin/pa/ sswd" }, + { "\\usr\\local\\bin\\passwd", "/usr/local/bin/passwd" }, + { "\\usr\\lo cal\\bin\\pa sswd", "/usr/lo cal/bin/pa sswd" }, + { "\\usr\\lo\\ cal\\bin\\pa\\ sswd", "/usr/lo/ cal/bin/pa/ sswd" }, + { "c:\\usr\\local\\bin\\passwd", "c:/usr/local/bin/passwd" }, + { "c:\\usr\\lo cal\\bin\\pa sswd", "c:/usr/lo cal/bin/pa sswd" }, + { "c:\\usr\\lo\\ cal\\bin\\pa\\ sswd", "c:/usr/lo/ cal/bin/pa/ sswd" }, + { "\\\\usr\\local\\bin\\passwd", "//usr/local/bin/passwd" }, + { "\\\\usr\\lo cal\\bin\\pa sswd", "//usr/lo cal/bin/pa sswd" }, + { "\\\\usr\\lo\\ cal\\bin\\pa\\ sswd", "//usr/lo/ cal/bin/pa/ sswd" }, + { nullptr, nullptr } +}; + +static bool CheckConvertToUnixSlashes(std::string const& input, + std::string const& output) +{ + std::string result = input; + kwsys::SystemTools::ConvertToUnixSlashes(result); + if (result != output) { + std::cerr << "Problem with ConvertToUnixSlashes - input: " << input + << " output: " << result << " expected: " << output << std::endl; + return false; + } + return true; +} + +static const char* checkEscapeChars[][4] = { + { "1 foo 2 bar 2", "12", "\\", "\\1 foo \\2 bar \\2" }, + { " {} ", "{}", "#", " #{#} " }, + { nullptr, nullptr, nullptr, nullptr } +}; + +static bool CheckEscapeChars(std::string const& input, + const char* chars_to_escape, char escape_char, + std::string const& output) +{ + std::string result = kwsys::SystemTools::EscapeChars( + input.c_str(), chars_to_escape, escape_char); + if (result != output) { + std::cerr << "Problem with CheckEscapeChars - input: " << input + << " output: " << result << " expected: " << output << std::endl; + return false; + } + return true; +} + +static bool CheckFileOperations() +{ + bool res = true; + const std::string testNonExistingFile(TEST_SYSTEMTOOLS_SOURCE_DIR + "/testSystemToolsNonExistingFile"); + const std::string testDotFile(TEST_SYSTEMTOOLS_SOURCE_DIR "/."); + const std::string testBinFile(TEST_SYSTEMTOOLS_SOURCE_DIR + "/testSystemTools.bin"); + const std::string testTxtFile(TEST_SYSTEMTOOLS_SOURCE_DIR + "/testSystemTools.cxx"); + const std::string testNewDir(TEST_SYSTEMTOOLS_BINARY_DIR + "/testSystemToolsNewDir"); + const std::string testNewFile(testNewDir + "/testNewFile.txt"); + + if (kwsys::SystemTools::DetectFileType(testNonExistingFile.c_str()) != + kwsys::SystemTools::FileTypeUnknown) { + std::cerr << "Problem with DetectFileType - failed to detect type of: " + << testNonExistingFile << std::endl; + res = false; + } + + if (kwsys::SystemTools::DetectFileType(testDotFile.c_str()) != + kwsys::SystemTools::FileTypeUnknown) { + std::cerr << "Problem with DetectFileType - failed to detect type of: " + << testDotFile << std::endl; + res = false; + } + + if (kwsys::SystemTools::DetectFileType(testBinFile.c_str()) != + kwsys::SystemTools::FileTypeBinary) { + std::cerr << "Problem with DetectFileType - failed to detect type of: " + << testBinFile << std::endl; + res = false; + } + + if (kwsys::SystemTools::DetectFileType(testTxtFile.c_str()) != + kwsys::SystemTools::FileTypeText) { + std::cerr << "Problem with DetectFileType - failed to detect type of: " + << testTxtFile << std::endl; + res = false; + } + + if (kwsys::SystemTools::FileLength(testBinFile) != 766) { + std::cerr << "Problem with FileLength - incorrect length for: " + << testBinFile << std::endl; + res = false; + } + + kwsys::SystemTools::Stat_t buf; + if (kwsys::SystemTools::Stat(testTxtFile.c_str(), &buf) != 0) { + std::cerr << "Problem with Stat - unable to stat text file: " + << testTxtFile << std::endl; + res = false; + } + + if (kwsys::SystemTools::Stat(testBinFile, &buf) != 0) { + std::cerr << "Problem with Stat - unable to stat bin file: " << testBinFile + << std::endl; + res = false; + } + + if (!kwsys::SystemTools::MakeDirectory(testNewDir)) { + std::cerr << "Problem with MakeDirectory for: " << testNewDir << std::endl; + res = false; + } + // calling it again should just return true + if (!kwsys::SystemTools::MakeDirectory(testNewDir)) { + std::cerr << "Problem with second call to MakeDirectory for: " + << testNewDir << std::endl; + res = false; + } + // calling with 0 pointer should return false + if (kwsys::SystemTools::MakeDirectory(nullptr)) { + std::cerr << "Problem with MakeDirectory(0)" << std::endl; + res = false; + } + // calling with an empty string should return false + if (kwsys::SystemTools::MakeDirectory(std::string())) { + std::cerr << "Problem with MakeDirectory(std::string())" << std::endl; + res = false; + } + // check existence + if (!kwsys::SystemTools::FileExists(testNewDir.c_str(), false)) { + std::cerr << "Problem with FileExists as C string and not file for: " + << testNewDir << std::endl; + res = false; + } + // check existence + if (!kwsys::SystemTools::PathExists(testNewDir)) { + std::cerr << "Problem with PathExists for: " << testNewDir << std::endl; + res = false; + } + // remove it + if (!kwsys::SystemTools::RemoveADirectory(testNewDir)) { + std::cerr << "Problem with RemoveADirectory for: " << testNewDir + << std::endl; + res = false; + } + // check existence + if (kwsys::SystemTools::FileExists(testNewDir.c_str(), false)) { + std::cerr << "After RemoveADirectory: " + << "Problem with FileExists as C string and not file for: " + << testNewDir << std::endl; + res = false; + } + // check existence + if (kwsys::SystemTools::PathExists(testNewDir)) { + std::cerr << "After RemoveADirectory: " + << "Problem with PathExists for: " << testNewDir << std::endl; + res = false; + } + // create it using the char* version + if (!kwsys::SystemTools::MakeDirectory(testNewDir.c_str())) { + std::cerr << "Problem with second call to MakeDirectory as C string for: " + << testNewDir << std::endl; + res = false; + } + + if (!kwsys::SystemTools::Touch(testNewFile, true)) { + std::cerr << "Problem with Touch for: " << testNewFile << std::endl; + res = false; + } + // calling MakeDirectory with something that is no file should fail + if (kwsys::SystemTools::MakeDirectory(testNewFile)) { + std::cerr << "Problem with to MakeDirectory for: " << testNewFile + << std::endl; + res = false; + } + + // calling with 0 pointer should return false + if (kwsys::SystemTools::FileExists(nullptr)) { + std::cerr << "Problem with FileExists(0)" << std::endl; + res = false; + } + if (kwsys::SystemTools::FileExists(nullptr, true)) { + std::cerr << "Problem with FileExists(0) as file" << std::endl; + res = false; + } + // calling with an empty string should return false + if (kwsys::SystemTools::FileExists(std::string())) { + std::cerr << "Problem with FileExists(std::string())" << std::endl; + res = false; + } + // FileExists(x, true) should return false on a directory + if (kwsys::SystemTools::FileExists(testNewDir, true)) { + std::cerr << "Problem with FileExists as file for: " << testNewDir + << std::endl; + res = false; + } + if (kwsys::SystemTools::FileExists(testNewDir.c_str(), true)) { + std::cerr << "Problem with FileExists as C string and file for: " + << testNewDir << std::endl; + res = false; + } + // FileExists(x, false) should return true even on a directory + if (!kwsys::SystemTools::FileExists(testNewDir, false)) { + std::cerr << "Problem with FileExists as not file for: " << testNewDir + << std::endl; + res = false; + } + if (!kwsys::SystemTools::FileExists(testNewDir.c_str(), false)) { + std::cerr << "Problem with FileExists as C string and not file for: " + << testNewDir << std::endl; + res = false; + } + // should work, was created as new file before + if (!kwsys::SystemTools::FileExists(testNewFile)) { + std::cerr << "Problem with FileExists for: " << testNewFile << std::endl; + res = false; + } + if (!kwsys::SystemTools::FileExists(testNewFile.c_str())) { + std::cerr << "Problem with FileExists as C string for: " << testNewFile + << std::endl; + res = false; + } + if (!kwsys::SystemTools::FileExists(testNewFile, true)) { + std::cerr << "Problem with FileExists as file for: " << testNewFile + << std::endl; + res = false; + } + if (!kwsys::SystemTools::FileExists(testNewFile.c_str(), true)) { + std::cerr << "Problem with FileExists as C string and file for: " + << testNewFile << std::endl; + res = false; + } + + // calling with an empty string should return false + if (kwsys::SystemTools::PathExists(std::string())) { + std::cerr << "Problem with PathExists(std::string())" << std::endl; + res = false; + } + // PathExists(x) should return true on a directory + if (!kwsys::SystemTools::PathExists(testNewDir)) { + std::cerr << "Problem with PathExists for: " << testNewDir << std::endl; + res = false; + } + // should work, was created as new file before + if (!kwsys::SystemTools::PathExists(testNewFile)) { + std::cerr << "Problem with PathExists for: " << testNewFile << std::endl; + res = false; + } + +// Reset umask +#if defined(_WIN32) && !defined(__CYGWIN__) + // NOTE: Windows doesn't support toggling _S_IREAD. + mode_t fullMask = _S_IWRITE; +#else + // On a normal POSIX platform, we can toggle all permissions. + mode_t fullMask = S_IRWXU | S_IRWXG | S_IRWXO; +#endif + mode_t orig_umask = umask(fullMask); + + // Test file permissions without umask + mode_t origPerm, thisPerm; + if (!kwsys::SystemTools::GetPermissions(testNewFile, origPerm)) { + std::cerr << "Problem with GetPermissions (1) for: " << testNewFile + << std::endl; + res = false; + } + + if (!kwsys::SystemTools::SetPermissions(testNewFile, 0)) { + std::cerr << "Problem with SetPermissions (1) for: " << testNewFile + << std::endl; + res = false; + } + + if (!kwsys::SystemTools::GetPermissions(testNewFile, thisPerm)) { + std::cerr << "Problem with GetPermissions (2) for: " << testNewFile + << std::endl; + res = false; + } + + if ((thisPerm & fullMask) != 0) { + std::cerr << "SetPermissions failed to set permissions (1) for: " + << testNewFile << ": actual = " << thisPerm + << "; expected = " << 0 << std::endl; + res = false; + } + + // While we're at it, check proper TestFileAccess functionality. + if (kwsys::SystemTools::TestFileAccess(testNewFile, + kwsys::TEST_FILE_WRITE)) { + std::cerr + << "TestFileAccess incorrectly indicated that this is a writable file:" + << testNewFile << std::endl; + res = false; + } + + if (!kwsys::SystemTools::TestFileAccess(testNewFile, kwsys::TEST_FILE_OK)) { + std::cerr + << "TestFileAccess incorrectly indicated that this file does not exist:" + << testNewFile << std::endl; + res = false; + } + + // Test restoring/setting full permissions. + if (!kwsys::SystemTools::SetPermissions(testNewFile, fullMask)) { + std::cerr << "Problem with SetPermissions (2) for: " << testNewFile + << std::endl; + res = false; + } + + if (!kwsys::SystemTools::GetPermissions(testNewFile, thisPerm)) { + std::cerr << "Problem with GetPermissions (3) for: " << testNewFile + << std::endl; + res = false; + } + + if ((thisPerm & fullMask) != fullMask) { + std::cerr << "SetPermissions failed to set permissions (2) for: " + << testNewFile << ": actual = " << thisPerm + << "; expected = " << fullMask << std::endl; + res = false; + } + + // Test setting file permissions while honoring umask + if (!kwsys::SystemTools::SetPermissions(testNewFile, fullMask, true)) { + std::cerr << "Problem with SetPermissions (3) for: " << testNewFile + << std::endl; + res = false; + } + + if (!kwsys::SystemTools::GetPermissions(testNewFile, thisPerm)) { + std::cerr << "Problem with GetPermissions (4) for: " << testNewFile + << std::endl; + res = false; + } + + if ((thisPerm & fullMask) != 0) { + std::cerr << "SetPermissions failed to honor umask for: " << testNewFile + << ": actual = " << thisPerm << "; expected = " << 0 + << std::endl; + res = false; + } + + // Restore umask + umask(orig_umask); + + // Restore file permissions + if (!kwsys::SystemTools::SetPermissions(testNewFile, origPerm)) { + std::cerr << "Problem with SetPermissions (4) for: " << testNewFile + << std::endl; + res = false; + } + + // Remove the test file + if (!kwsys::SystemTools::RemoveFile(testNewFile)) { + std::cerr << "Problem with RemoveFile: " << testNewFile << std::endl; + res = false; + } + + std::string const testFileMissing(testNewDir + "/testMissingFile.txt"); + if (!kwsys::SystemTools::RemoveFile(testFileMissing)) { + std::string const& msg = kwsys::SystemTools::GetLastSystemError(); + std::cerr << "RemoveFile(\"" << testFileMissing << "\") failed: " << msg + << "\n"; + res = false; + } + + std::string const testFileMissingDir(testNewDir + "/missing/file.txt"); + if (!kwsys::SystemTools::RemoveFile(testFileMissingDir)) { + std::string const& msg = kwsys::SystemTools::GetLastSystemError(); + std::cerr << "RemoveFile(\"" << testFileMissingDir << "\") failed: " << msg + << "\n"; + res = false; + } + + kwsys::SystemTools::Touch(testNewFile, true); + if (!kwsys::SystemTools::RemoveADirectory(testNewDir)) { + std::cerr << "Problem with RemoveADirectory for: " << testNewDir + << std::endl; + res = false; + } + +#ifdef KWSYS_TEST_SYSTEMTOOLS_LONG_PATHS + // Perform the same file and directory creation and deletion tests but + // with paths > 256 characters in length. + + const std::string testNewLongDir( + TEST_SYSTEMTOOLS_BINARY_DIR + "/" + "012345678901234567890123456789012345678901234567890123456789" + "012345678901234567890123456789012345678901234567890123456789" + "012345678901234567890123456789012345678901234567890123456789" + "012345678901234567890123456789012345678901234567890123456789" + "01234567890123"); + const std::string testNewLongFile( + testNewLongDir + + "/" + "012345678901234567890123456789012345678901234567890123456789" + "012345678901234567890123456789012345678901234567890123456789" + "012345678901234567890123456789012345678901234567890123456789" + "012345678901234567890123456789012345678901234567890123456789" + "0123456789.txt"); + + if (!kwsys::SystemTools::MakeDirectory(testNewLongDir)) { + std::cerr << "Problem with MakeDirectory for: " << testNewLongDir + << std::endl; + res = false; + } + + if (!kwsys::SystemTools::Touch(testNewLongFile.c_str(), true)) { + std::cerr << "Problem with Touch for: " << testNewLongFile << std::endl; + res = false; + } + + if (!kwsys::SystemTools::RemoveFile(testNewLongFile)) { + std::cerr << "Problem with RemoveFile: " << testNewLongFile << std::endl; + res = false; + } + + kwsys::SystemTools::Touch(testNewLongFile.c_str(), true); + if (!kwsys::SystemTools::RemoveADirectory(testNewLongDir)) { + std::cerr << "Problem with RemoveADirectory for: " << testNewLongDir + << std::endl; + res = false; + } +#endif + + return res; +} + +static bool CheckStringOperations() +{ + bool res = true; + + std::string test = "mary had a little lamb."; + if (kwsys::SystemTools::CapitalizedWords(test) != + "Mary Had A Little Lamb.") { + std::cerr << "Problem with CapitalizedWords " << '"' << test << '"' + << std::endl; + res = false; + } + + test = "Mary Had A Little Lamb."; + if (kwsys::SystemTools::UnCapitalizedWords(test) != + "mary had a little lamb.") { + std::cerr << "Problem with UnCapitalizedWords " << '"' << test << '"' + << std::endl; + res = false; + } + + test = "MaryHadTheLittleLamb."; + if (kwsys::SystemTools::AddSpaceBetweenCapitalizedWords(test) != + "Mary Had The Little Lamb.") { + std::cerr << "Problem with AddSpaceBetweenCapitalizedWords " << '"' << test + << '"' << std::endl; + res = false; + } + + char* cres = + kwsys::SystemTools::AppendStrings("Mary Had A", " Little Lamb."); + if (strcmp(cres, "Mary Had A Little Lamb.")) { + std::cerr << "Problem with AppendStrings " + << "\"Mary Had A\" \" Little Lamb.\"" << std::endl; + res = false; + } + delete[] cres; + + cres = kwsys::SystemTools::AppendStrings("Mary Had", " A ", "Little Lamb."); + if (strcmp(cres, "Mary Had A Little Lamb.")) { + std::cerr << "Problem with AppendStrings " + << "\"Mary Had\" \" A \" \"Little Lamb.\"" << std::endl; + res = false; + } + delete[] cres; + + if (kwsys::SystemTools::CountChar("Mary Had A Little Lamb.", 'a') != 3) { + std::cerr << "Problem with CountChar " + << "\"Mary Had A Little Lamb.\"" << std::endl; + res = false; + } + + cres = kwsys::SystemTools::RemoveChars("Mary Had A Little Lamb.", "aeiou"); + if (strcmp(cres, "Mry Hd A Lttl Lmb.")) { + std::cerr << "Problem with RemoveChars " + << "\"Mary Had A Little Lamb.\"" << std::endl; + res = false; + } + delete[] cres; + + cres = kwsys::SystemTools::RemoveCharsButUpperHex("Mary Had A Little Lamb."); + if (strcmp(cres, "A")) { + std::cerr << "Problem with RemoveCharsButUpperHex " + << "\"Mary Had A Little Lamb.\"" << std::endl; + res = false; + } + delete[] cres; + + char* cres2 = strdup("Mary Had A Little Lamb."); + kwsys::SystemTools::ReplaceChars(cres2, "aeiou", 'X'); + if (strcmp(cres2, "MXry HXd A LXttlX LXmb.")) { + std::cerr << "Problem with ReplaceChars " + << "\"Mary Had A Little Lamb.\"" << std::endl; + res = false; + } + free(cres2); + + if (!kwsys::SystemTools::StringStartsWith("Mary Had A Little Lamb.", + "Mary ")) { + std::cerr << "Problem with StringStartsWith " + << "\"Mary Had A Little Lamb.\"" << std::endl; + res = false; + } + + if (!kwsys::SystemTools::StringEndsWith("Mary Had A Little Lamb.", + " Lamb.")) { + std::cerr << "Problem with StringEndsWith " + << "\"Mary Had A Little Lamb.\"" << std::endl; + res = false; + } + + cres = kwsys::SystemTools::DuplicateString("Mary Had A Little Lamb."); + if (strcmp(cres, "Mary Had A Little Lamb.")) { + std::cerr << "Problem with DuplicateString " + << "\"Mary Had A Little Lamb.\"" << std::endl; + res = false; + } + delete[] cres; + + test = "Mary Had A Little Lamb."; + if (kwsys::SystemTools::CropString(test, 13) != "Mary ...Lamb.") { + std::cerr << "Problem with CropString " + << "\"Mary Had A Little Lamb.\"" << std::endl; + res = false; + } + + std::vector lines; + kwsys::SystemTools::Split("Mary Had A Little Lamb.", lines, ' '); + if (lines[0] != "Mary" || lines[1] != "Had" || lines[2] != "A" || + lines[3] != "Little" || lines[4] != "Lamb.") { + std::cerr << "Problem with Split " + << "\"Mary Had A Little Lamb.\"" << std::endl; + res = false; + } + + if (kwsys::SystemTools::ConvertToWindowsOutputPath( + "L://Local Mojo/Hex Power Pack/Iffy Voodoo") != + "\"L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\"") { + std::cerr << "Problem with ConvertToWindowsOutputPath " + << "\"L://Local Mojo/Hex Power Pack/Iffy Voodoo\"" << std::endl; + res = false; + } + + if (kwsys::SystemTools::ConvertToWindowsOutputPath( + "//grayson/Local Mojo/Hex Power Pack/Iffy Voodoo") != + "\"\\\\grayson\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\"") { + std::cerr << "Problem with ConvertToWindowsOutputPath " + << "\"//grayson/Local Mojo/Hex Power Pack/Iffy Voodoo\"" + << std::endl; + res = false; + } + + if (kwsys::SystemTools::ConvertToUnixOutputPath( + "//Local Mojo/Hex Power Pack/Iffy Voodoo") != + "//Local\\ Mojo/Hex\\ Power\\ Pack/Iffy\\ Voodoo") { + std::cerr << "Problem with ConvertToUnixOutputPath " + << "\"//Local Mojo/Hex Power Pack/Iffy Voodoo\"" << std::endl; + res = false; + } + + return res; +} + +static bool CheckPutEnv(const std::string& env, const char* name, + const char* value) +{ + if (!kwsys::SystemTools::PutEnv(env)) { + std::cerr << "PutEnv(\"" << env << "\") failed!" << std::endl; + return false; + } + std::string v = "(null)"; + kwsys::SystemTools::GetEnv(name, v); + if (v != value) { + std::cerr << "GetEnv(\"" << name << "\") returned \"" << v << "\", not \"" + << value << "\"!" << std::endl; + return false; + } + return true; +} + +static bool CheckUnPutEnv(const char* env, const char* name) +{ + if (!kwsys::SystemTools::UnPutEnv(env)) { + std::cerr << "UnPutEnv(\"" << env << "\") failed!" << std::endl; + return false; + } + std::string v; + if (kwsys::SystemTools::GetEnv(name, v)) { + std::cerr << "GetEnv(\"" << name << "\") returned \"" << v + << "\", not (null)!" << std::endl; + return false; + } + return true; +} + +static bool CheckEnvironmentOperations() +{ + bool res = true; + res &= CheckPutEnv("A=B", "A", "B"); + res &= CheckPutEnv("B=C", "B", "C"); + res &= CheckPutEnv("C=D", "C", "D"); + res &= CheckPutEnv("D=E", "D", "E"); + res &= CheckUnPutEnv("A", "A"); + res &= CheckUnPutEnv("B=", "B"); + res &= CheckUnPutEnv("C=D", "C"); + /* Leave "D=E" in environment so a memory checker can test for leaks. */ + return res; +} + +static bool CheckRelativePath(const std::string& local, + const std::string& remote, + const std::string& expected) +{ + std::string result = kwsys::SystemTools::RelativePath(local, remote); + if (!kwsys::SystemTools::ComparePath(expected, result)) { + std::cerr << "RelativePath(" << local << ", " << remote << ") yielded " + << result << " instead of " << expected << std::endl; + return false; + } + return true; +} + +static bool CheckRelativePaths() +{ + bool res = true; + res &= CheckRelativePath("/usr/share", "/bin/bash", "../../bin/bash"); + res &= CheckRelativePath("/usr/./share/", "/bin/bash", "../../bin/bash"); + res &= CheckRelativePath("/usr//share/", "/bin/bash", "../../bin/bash"); + res &= + CheckRelativePath("/usr/share/../bin/", "/bin/bash", "../../bin/bash"); + res &= CheckRelativePath("/usr/share", "/usr/share//bin", "bin"); + return res; +} + +static bool CheckCollapsePath(const std::string& path, + const std::string& expected, + const char* base = nullptr) +{ + std::string result = kwsys::SystemTools::CollapseFullPath(path, base); + if (!kwsys::SystemTools::ComparePath(expected, result)) { + std::cerr << "CollapseFullPath(" << path << ") yielded " << result + << " instead of " << expected << std::endl; + return false; + } + return true; +} + +static bool CheckCollapsePath() +{ + bool res = true; + res &= CheckCollapsePath("/usr/share/*", "/usr/share/*"); + res &= CheckCollapsePath("C:/Windows/*", "C:/Windows/*"); + res &= CheckCollapsePath("/usr/share/../lib", "/usr/lib"); + res &= CheckCollapsePath("/usr/share/./lib", "/usr/share/lib"); + res &= CheckCollapsePath("/usr/share/../../lib", "/lib"); + res &= CheckCollapsePath("/usr/share/.././../lib", "/lib"); + res &= CheckCollapsePath("/../lib", "/lib"); + res &= CheckCollapsePath("/../lib/", "/lib"); + res &= CheckCollapsePath("/", "/"); + res &= CheckCollapsePath("C:/", "C:/"); + res &= CheckCollapsePath("C:/../", "C:/"); + res &= CheckCollapsePath("C:/../../", "C:/"); + res &= CheckCollapsePath("../b", "../../b", "../"); + res &= CheckCollapsePath("../a/../b", "../b", "../rel"); + res &= CheckCollapsePath("a/../b", "../rel/b", "../rel"); + return res; +} + +static std::string StringVectorToString(const std::vector& vec) +{ + std::stringstream ss; + ss << "vector("; + for (std::vector::const_iterator i = vec.begin(); + i != vec.end(); ++i) { + if (i != vec.begin()) { + ss << ", "; + } + ss << *i; + } + ss << ")"; + return ss.str(); +} + +static bool CheckGetPath() +{ + const char* envName = "S"; +#ifdef _WIN32 + const char* envValue = "C:\\Somewhere\\something;D:\\Temp"; +#else + const char* envValue = "/Somewhere/something:/tmp"; +#endif + const char* registryPath = "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MyApp; MyKey]"; + + std::vector originalPaths; + originalPaths.push_back(registryPath); + + std::vector expectedPaths; + expectedPaths.push_back(registryPath); +#ifdef _WIN32 + expectedPaths.push_back("C:/Somewhere/something"); + expectedPaths.push_back("D:/Temp"); +#else + expectedPaths.push_back("/Somewhere/something"); + expectedPaths.push_back("/tmp"); +#endif + + bool res = true; + res &= CheckPutEnv(std::string(envName) + "=" + envValue, envName, envValue); + + std::vector paths = originalPaths; + kwsys::SystemTools::GetPath(paths, envName); + + if (paths != expectedPaths) { + std::cerr << "GetPath(" << StringVectorToString(originalPaths) << ", " + << envName << ") yielded " << StringVectorToString(paths) + << " instead of " << StringVectorToString(expectedPaths) + << std::endl; + res = false; + } + + res &= CheckUnPutEnv(envName, envName); + return res; +} + +static bool CheckGetFilenameName() +{ + const char* windowsFilepath = "C:\\somewhere\\something"; + const char* unixFilepath = "/somewhere/something"; + +#if defined(_WIN32) || defined(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES) + std::string expectedWindowsFilename = "something"; +#else + std::string expectedWindowsFilename = "C:\\somewhere\\something"; +#endif + std::string expectedUnixFilename = "something"; + + bool res = true; + std::string filename = kwsys::SystemTools::GetFilenameName(windowsFilepath); + if (filename != expectedWindowsFilename) { + std::cerr << "GetFilenameName(" << windowsFilepath << ") yielded " + << filename << " instead of " << expectedWindowsFilename + << std::endl; + res = false; + } + + filename = kwsys::SystemTools::GetFilenameName(unixFilepath); + if (filename != expectedUnixFilename) { + std::cerr << "GetFilenameName(" << unixFilepath << ") yielded " << filename + << " instead of " << expectedUnixFilename << std::endl; + res = false; + } + return res; +} + +static bool CheckFind() +{ + bool res = true; + const std::string testFindFileName("testFindFile.txt"); + const std::string testFindFile(TEST_SYSTEMTOOLS_BINARY_DIR "/" + + testFindFileName); + + if (!kwsys::SystemTools::Touch(testFindFile, true)) { + std::cerr << "Problem with Touch for: " << testFindFile << std::endl; + // abort here as the existence of the file only makes the test meaningful + return false; + } + + std::vector searchPaths; + searchPaths.push_back(TEST_SYSTEMTOOLS_BINARY_DIR); + if (kwsys::SystemTools::FindFile(testFindFileName, searchPaths, true) + .empty()) { + std::cerr << "Problem with FindFile without system paths for: " + << testFindFileName << std::endl; + res = false; + } + if (kwsys::SystemTools::FindFile(testFindFileName, searchPaths, false) + .empty()) { + std::cerr << "Problem with FindFile with system paths for: " + << testFindFileName << std::endl; + res = false; + } + + return res; +} + +static bool CheckIsSubDirectory() +{ + bool res = true; + + if (kwsys::SystemTools::IsSubDirectory("/foo", "/") == false) { + std::cerr << "Problem with IsSubDirectory (root - unix): " << std::endl; + res = false; + } + if (kwsys::SystemTools::IsSubDirectory("c:/foo", "c:/") == false) { + std::cerr << "Problem with IsSubDirectory (root - dos): " << std::endl; + res = false; + } + if (kwsys::SystemTools::IsSubDirectory("/foo/bar", "/foo") == false) { + std::cerr << "Problem with IsSubDirectory (deep): " << std::endl; + res = false; + } + if (kwsys::SystemTools::IsSubDirectory("/foo", "/foo") == true) { + std::cerr << "Problem with IsSubDirectory (identity): " << std::endl; + res = false; + } + if (kwsys::SystemTools::IsSubDirectory("/fooo", "/foo") == true) { + std::cerr << "Problem with IsSubDirectory (substring): " << std::endl; + res = false; + } + if (kwsys::SystemTools::IsSubDirectory("/foo/", "/foo") == true) { + std::cerr << "Problem with IsSubDirectory (prepended slash): " + << std::endl; + res = false; + } + + return res; +} + +static bool CheckGetLineFromStream() +{ + const std::string fileWithFiveCharsOnFirstLine(TEST_SYSTEMTOOLS_SOURCE_DIR + "/README.rst"); + + kwsys::ifstream file(fileWithFiveCharsOnFirstLine.c_str(), std::ios::in); + + if (!file) { + std::cerr << "Problem opening: " << fileWithFiveCharsOnFirstLine + << std::endl; + return false; + } + + std::string line; + bool has_newline = false; + bool result; + + file.seekg(0, std::ios::beg); + result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, -1); + if (!result || line.size() != 5) { + std::cerr << "First line does not have five characters: " << line.size() + << std::endl; + return false; + } + + file.seekg(0, std::ios::beg); + result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, -1); + if (!result || line.size() != 5) { + std::cerr << "First line does not have five characters after rewind: " + << line.size() << std::endl; + return false; + } + + bool ret = true; + + for (size_t size = 1; size <= 5; ++size) { + file.seekg(0, std::ios::beg); + result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, + static_cast(size)); + if (!result || line.size() != size) { + std::cerr << "Should have read " << size << " characters but got " + << line.size() << std::endl; + ret = false; + } + } + + return ret; +} + +static bool CheckGetLineFromStreamLongLine() +{ + const std::string fileWithLongLine("longlines.txt"); + std::string firstLine, secondLine; + // First line: large buffer, containing a carriage return for some reason. + firstLine.assign(2050, ' '); + firstLine += "\rfirst"; + secondLine.assign(2050, 'y'); + secondLine += "second"; + + // Create file with long lines. + { + kwsys::ofstream out(fileWithLongLine.c_str(), std::ios::binary); + if (!out) { + std::cerr << "Problem opening for write: " << fileWithLongLine + << std::endl; + return false; + } + out << firstLine << "\r\n\n" << secondLine << "\n"; + } + + kwsys::ifstream file(fileWithLongLine.c_str(), std::ios::binary); + if (!file) { + std::cerr << "Problem opening: " << fileWithLongLine << std::endl; + return false; + } + + std::string line; + bool has_newline = false; + bool result; + + // Read first line. + result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, -1); + if (!result || line != firstLine) { + std::cerr << "First line does not match, expected " << firstLine.size() + << " characters, got " << line.size() << std::endl; + return false; + } + if (!has_newline) { + std::cerr << "Expected new line to be read from first line" << std::endl; + return false; + } + + // Read empty line. + has_newline = false; + result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, -1); + if (!result || !line.empty()) { + std::cerr << "Expected successful read with an empty line, got " + << line.size() << " characters" << std::endl; + return false; + } + if (!has_newline) { + std::cerr << "Expected new line to be read for an empty line" << std::endl; + return false; + } + + // Read second line. + has_newline = false; + result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, -1); + if (!result || line != secondLine) { + std::cerr << "Second line does not match, expected " << secondLine.size() + << " characters, got " << line.size() << std::endl; + return false; + } + if (!has_newline) { + std::cerr << "Expected new line to be read from second line" << std::endl; + return false; + } + + return true; +} + +static bool writeFile(const char* fileName, const char* data) +{ + kwsys::ofstream out(fileName, std::ios::binary); + out << data; + if (!out) { + std::cerr << "Failed to write file: " << fileName << std::endl; + return false; + } + return true; +} + +static std::string readFile(const char* fileName) +{ + kwsys::ifstream in(fileName, std::ios::binary); + std::stringstream sstr; + sstr << in.rdbuf(); + std::string data = sstr.str(); + if (!in) { + std::cerr << "Failed to read file: " << fileName << std::endl; + return std::string(); + } + return data; +} + +struct +{ + const char* a; + const char* b; + bool differ; +} diff_test_cases[] = { { "one", "one", false }, + { "one", "two", true }, + { "", "", false }, + { "\n", "\r\n", false }, + { "one\n", "one\n", false }, + { "one\r\n", "one\n", false }, + { "one\n", "one", false }, + { "one\ntwo", "one\ntwo", false }, + { "one\ntwo", "one\r\ntwo", false } }; + +static bool CheckTextFilesDiffer() +{ + const int num_test_cases = + sizeof(diff_test_cases) / sizeof(diff_test_cases[0]); + for (int i = 0; i < num_test_cases; ++i) { + if (!writeFile("file_a", diff_test_cases[i].a) || + !writeFile("file_b", diff_test_cases[i].b)) { + return false; + } + if (kwsys::SystemTools::TextFilesDiffer("file_a", "file_b") != + diff_test_cases[i].differ) { + std::cerr << "Incorrect TextFilesDiffer result for test case " << i + 1 + << "." << std::endl; + return false; + } + } + + return true; +} + +static bool CheckCopyFileIfDifferent() +{ + bool ret = true; + const int num_test_cases = + sizeof(diff_test_cases) / sizeof(diff_test_cases[0]); + for (int i = 0; i < num_test_cases; ++i) { + if (!writeFile("file_a", diff_test_cases[i].a) || + !writeFile("file_b", diff_test_cases[i].b)) { + return false; + } + const char* cptarget = + i < 4 ? TEST_SYSTEMTOOLS_BINARY_DIR "/file_b" : "file_b"; + if (!kwsys::SystemTools::CopyFileIfDifferent("file_a", cptarget)) { + std::cerr << "CopyFileIfDifferent() returned false for test case " + << i + 1 << "." << std::endl; + ret = false; + continue; + } + std::string bdata = readFile("file_b"); + if (diff_test_cases[i].a != bdata) { + std::cerr << "Incorrect CopyFileIfDifferent file contents in test case " + << i + 1 << "." << std::endl; + ret = false; + continue; + } + } + + return ret; +} + +int testSystemTools(int, char* []) +{ + bool res = true; + + int cc; + for (cc = 0; toUnixPaths[cc][0]; cc++) { + res &= CheckConvertToUnixSlashes(toUnixPaths[cc][0], toUnixPaths[cc][1]); + } + + // Special check for ~ + std::string output; + if (kwsys::SystemTools::GetEnv("HOME", output)) { + output += "/foo bar/lala"; + res &= CheckConvertToUnixSlashes("~/foo bar/lala", output); + } + + for (cc = 0; checkEscapeChars[cc][0]; cc++) { + res &= CheckEscapeChars(checkEscapeChars[cc][0], checkEscapeChars[cc][1], + *checkEscapeChars[cc][2], checkEscapeChars[cc][3]); + } + + res &= CheckFileOperations(); + + res &= CheckStringOperations(); + + res &= CheckEnvironmentOperations(); + + res &= CheckRelativePaths(); + + res &= CheckCollapsePath(); + + res &= CheckGetPath(); + + res &= CheckFind(); + + res &= CheckIsSubDirectory(); + + res &= CheckGetLineFromStream(); + + res &= CheckGetLineFromStreamLongLine(); + + res &= CheckGetFilenameName(); + + res &= CheckTextFilesDiffer(); + + res &= CheckCopyFileIfDifferent(); + + return res ? 0 : 1; +} diff --git a/test/API/driver/kwsys/testSystemTools.h.in b/test/API/driver/kwsys/testSystemTools.h.in new file mode 100644 index 0000000..022e36e --- /dev/null +++ b/test/API/driver/kwsys/testSystemTools.h.in @@ -0,0 +1,12 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifndef @KWSYS_NAMESPACE@_testSystemtools_h +#define @KWSYS_NAMESPACE@_testSystemtools_h + +#define EXECUTABLE_OUTPUT_PATH "@CMAKE_CURRENT_BINARY_DIR@" + +#define TEST_SYSTEMTOOLS_SOURCE_DIR "@TEST_SYSTEMTOOLS_SOURCE_DIR@" +#define TEST_SYSTEMTOOLS_BINARY_DIR "@TEST_SYSTEMTOOLS_BINARY_DIR@" +#cmakedefine KWSYS_TEST_SYSTEMTOOLS_LONG_PATHS + +#endif diff --git a/test/API/driver/kwsys/testTerminal.c b/test/API/driver/kwsys/testTerminal.c new file mode 100644 index 0000000..652830c --- /dev/null +++ b/test/API/driver/kwsys/testTerminal.c @@ -0,0 +1,22 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(Terminal.h) + +/* Work-around CMake dependency scanning limitation. This must + duplicate the above list of headers. */ +#if 0 +# include "Terminal.h.in" +#endif + +int testTerminal(int argc, char* argv[]) +{ + (void)argc; + (void)argv; + kwsysTerminal_cfprintf(kwsysTerminal_Color_ForegroundYellow | + kwsysTerminal_Color_BackgroundBlue | + kwsysTerminal_Color_AssumeTTY, + stdout, "Hello %s!", "World"); + fprintf(stdout, "\n"); + return 0; +} diff --git a/test/API/driver/kwsys/update-gitsetup.bash b/test/API/driver/kwsys/update-gitsetup.bash new file mode 100644 index 0000000..aa83cb8 --- /dev/null +++ b/test/API/driver/kwsys/update-gitsetup.bash @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +set -e +set -x +shopt -s dotglob + +readonly name="GitSetup" +readonly ownership="GitSetup Upstream " +readonly subtree="GitSetup" +readonly repo="https://gitlab.kitware.com/utils/gitsetup.git" +readonly tag="setup" +readonly shortlog=false +readonly paths=" +" + +extract_source () { + git_archive +} + +. "${BASH_SOURCE%/*}/update-third-party.bash" diff --git a/test/API/driver/kwsys/update-third-party.bash b/test/API/driver/kwsys/update-third-party.bash new file mode 100644 index 0000000..3b8358e --- /dev/null +++ b/test/API/driver/kwsys/update-third-party.bash @@ -0,0 +1,169 @@ +#============================================================================= +# Copyright 2015-2016 Kitware, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============================================================================= + +######################################################################## +# Script for updating third party packages. +# +# This script should be sourced in a project-specific script which sets +# the following variables: +# +# name +# The name of the project. +# ownership +# A git author name/email for the commits. +# subtree +# The location of the thirdparty package within the main source +# tree. +# repo +# The git repository to use as upstream. +# tag +# The tag, branch or commit hash to use for upstream. +# shortlog +# Optional. Set to 'true' to get a shortlog in the commit message. +# +# Additionally, an "extract_source" function must be defined. It will be +# run within the checkout of the project on the requested tag. It should +# should place the desired tree into $extractdir/$name-reduced. This +# directory will be used as the newest commit for the project. +# +# 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. +######################################################################## + +######################################################################## +# Utility functions +######################################################################## +git_archive () { + git archive --worktree-attributes --prefix="$name-reduced/" HEAD -- $paths | \ + tar -C "$extractdir" -x +} + +die () { + echo >&2 "$@" + exit 1 +} + +warn () { + echo >&2 "warning: $@" +} + +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 basehash="$( git rev-list --author="$ownership" --grep="$basehash_regex" -n 1 HEAD )" +readonly upstream_old_short="$( git cat-file commit "$basehash" | sed -n '/'"$basehash_regex"'/ {s/.*(//;s/)//;p}' | egrep '^[0-9a-f]+$' )" + +######################################################################## +# Sanity checking +######################################################################## +[ -n "$name" ] || \ + die "'name' is empty" +[ -n "$ownership" ] || \ + die "'ownership' is empty" +[ -n "$subtree" ] || \ + die "'subtree' is empty" +[ -n "$repo" ] || \ + die "'repo' is empty" +[ -n "$tag" ] || \ + die "'tag' is empty" +[ -n "$basehash" ] || \ + warn "'basehash' is empty; performing initial import" +readonly do_shortlog="${shortlog-false}" + +readonly workdir="$PWD/work" +readonly upstreamdir="$workdir/upstream" +readonly extractdir="$workdir/extract" + +[ -d "$workdir" ] && \ + die "error: workdir '$workdir' already exists" + +trap "rm -rf '$workdir'" EXIT + +# Get upstream +git clone "$repo" "$upstreamdir" + +if [ -n "$basehash" ]; then + # Use the existing package's history + git worktree add "$extractdir" "$basehash" + # Clear out the working tree + pushd "$extractdir" + git ls-files | xargs rm -v + find . -type d -empty -delete + popd +else + # Create a repo to hold this package's history + mkdir -p "$extractdir" + git -C "$extractdir" init +fi + +# Extract the subset of upstream we care about +pushd "$upstreamdir" +git checkout "$tag" +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" )" +readonly upstream_date="$( echo "$upstream_datetime" | grep -o -e "$regex_date" )" +if $do_shortlog && [ -n "$basehash" ]; then + readonly commit_shortlog=" + +Upstream Shortlog +----------------- + +$( git shortlog --no-merges --abbrev=8 --format='%h %s' "$upstream_old_short".."$upstream_hash" )" +else + readonly commit_shortlog="" +fi +extract_source || \ + die "failed to extract source" +popd + +[ -d "$extractdir/$name-reduced" ] || \ + die "expected directory to extract does not exist" +readonly commit_summary="$name $upstream_date ($upstream_hash_short)" + +# Commit the subset +pushd "$extractdir" +mv -v "$name-reduced/"* . +rmdir "$name-reduced/" +git add -A . +git commit -n --author="$ownership" --date="$upstream_datetime" -F - <<-EOF +$commit_summary + +Code extracted from: + + $repo + +at commit $upstream_hash ($tag).$commit_shortlog +EOF +git branch -f "upstream-$name" +popd + +# Merge the subset into this repository +if [ -n "$basehash" ]; then + git merge --log -s recursive "-Xsubtree=$subtree/" --no-commit "upstream-$name" +else + unrelated_histories_flag="" + if git merge --help | grep -q -e allow-unrelated-histories; then + unrelated_histories_flag="--allow-unrelated-histories " + fi + readonly unrelated_histories_flag + + git fetch "$extractdir" "upstream-$name:upstream-$name" + git merge --log -s ours --no-commit $unrelated_histories_flag "upstream-$name" + git read-tree -u --prefix="$subtree/" "upstream-$name" +fi +git commit --no-edit +git branch -d "upstream-$name" diff --git a/test/API/tarray.c b/test/API/tarray.c new file mode 100644 index 0000000..214a022 --- /dev/null +++ b/test/API/tarray.c @@ -0,0 +1,2250 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*********************************************************** + * + * Test program: tarray + * + * Test the Array Datatype functionality + * + *************************************************************/ + +#include "testhdf5.h" +/* #include "H5srcdir.h" */ + +#define FILENAME "tarray1.h5" +#define TESTFILE "tarrold.h5" + +/* 1-D array datatype */ +#define ARRAY1_RANK 1 +#define ARRAY1_DIM1 4 + +/* 3-D array datatype */ +#define ARRAY2_RANK 3 +#define ARRAY2_DIM1 3 +#define ARRAY2_DIM2 4 +#define ARRAY2_DIM3 5 + +/* 2-D array datatype */ +#define ARRAY3_RANK 2 +#define ARRAY3_DIM1 6 +#define ARRAY3_DIM2 3 + +/* 1-D dataset with fixed dimensions */ +#define SPACE1_RANK 1 +#define SPACE1_DIM1 4 + +/* Parameters used with the test_array_bkg() test */ +#define FIELDNAME "ArrayofStructures" +#define LENGTH 5 +#define ALEN 10 +#define RANK 1 +#define NMAX 100 + +/* Struct used with test_array_bkg() test */ +typedef struct { + int nsubfields; + char *name[NMAX]; + size_t offset[NMAX]; + hid_t datatype[NMAX]; + +} CmpDTSinfo; + +/* Forward declarations for custom vlen memory manager functions */ +void *test_array_alloc_custom(size_t size, void *info); +void test_array_free_custom(void *mem, void *info); + +/*------------------------------------------------------------------------- + * Function: test_array_atomic_1d + * + * Purpose: Test basic array datatype code. + * Tests 1-D array of atomic datatypes. + * + * Return: void + * + *------------------------------------------------------------------------- + */ +static void +test_array_atomic_1d(void) +{ + int wdata[SPACE1_DIM1][ARRAY1_DIM1]; /* Information to write */ + int rdata[SPACE1_DIM1][ARRAY1_DIM1]; /* Information read in */ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1; /* Dataspace ID */ + hid_t tid1; /* Datatype ID */ + hsize_t sdims1[] = {SPACE1_DIM1}; + hsize_t tdims1[] = {ARRAY1_DIM1}; + int ndims; /* Array rank for reading */ + hsize_t rdims1[H5S_MAX_RANK]; /* Array dimensions for reading */ + int i, j; /* counting variables */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing 1-D Array of Atomic Datatypes Functionality\n")); + + /* Allocate and initialize array data to write */ + for (i = 0; i < SPACE1_DIM1; i++) + for (j = 0; j < ARRAY1_DIM1; j++) + wdata[i][j] = i * 10 + j; + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid1 = H5Screate_simple(SPACE1_RANK, sdims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create a datatype to refer to */ + tid1 = H5Tarray_create2(H5T_NATIVE_INT, ARRAY1_RANK, tdims1); + CHECK(tid1, FAIL, "H5Tarray_create2"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, "Dataset1", tid1, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write dataset to disk */ + ret = H5Dwrite(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open file */ + fid1 = H5Fopen(FILENAME, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Open the dataset */ + dataset = H5Dopen2(fid1, "Dataset1", H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Get the datatype */ + tid1 = H5Dget_type(dataset); + CHECK(tid1, FAIL, "H5Dget_type"); + + /* Check the array rank */ + ndims = H5Tget_array_ndims(tid1); + VERIFY(ndims, ARRAY1_RANK, "H5Tget_array_ndims"); + + /* Get the array dimensions */ + ret = H5Tget_array_dims2(tid1, rdims1); + CHECK(ret, FAIL, "H5Tget_array_dims2"); + + /* Check the array dimensions */ + for (i = 0; i < ndims; i++) + if (rdims1[i] != tdims1[i]) { + TestErrPrintf("Array dimension information doesn't match!, rdims1[%d]=%" PRIuHSIZE + ", tdims1[%d]=%" PRIuHSIZE "\n", + i, rdims1[i], i, tdims1[i]); + continue; + } /* end if */ + + /* Read dataset from disk */ + ret = H5Dread(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < SPACE1_DIM1; i++) + for (j = 0; j < ARRAY1_DIM1; j++) + if (wdata[i][j] != rdata[i][j]) { + TestErrPrintf("Array data information doesn't match!, wdata[%d][%d]=%d, rdata[%d][%d]=%d\n", + (int)i, (int)j, (int)wdata[i][j], (int)i, (int)j, (int)rdata[i][j]); + continue; + } /* end if */ + + /* Close Datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_array_atomic_1d() */ + +/*------------------------------------------------------------------------- + * Function: test_array_funcs + * + * Purpose: Test some type functions that are and aren't supposed to + * work with array type. + * + * Return: void + * + *------------------------------------------------------------------------- + */ +static void +test_array_funcs(void) +{ + hid_t type; /* Datatype ID */ + hsize_t tdims1[] = {ARRAY1_DIM1}; + size_t size; + H5T_pad_t inpad; + H5T_norm_t norm; + H5T_cset_t cset; + H5T_str_t strpad; + herr_t ret; /* Generic return value */ + + /* Create a datatype to refer to */ + type = H5Tarray_create2(H5T_IEEE_F32BE, ARRAY1_RANK, tdims1); + CHECK(type, FAIL, "H5Tarray_create2"); + + size = H5Tget_precision(type); + CHECK(size, 0, "H5Tget_precision"); + + size = H5Tget_size(type); + CHECK(size, 0, "H5Tget_size"); + + size = H5Tget_ebias(type); + CHECK(size, 0, "H5Tget_ebias"); + + ret = H5Tset_pad(type, H5T_PAD_ZERO, H5T_PAD_ONE); + CHECK(ret, FAIL, "H5Tset_pad"); + + inpad = H5Tget_inpad(type); + CHECK(inpad, FAIL, "H5Tget_inpad"); + + norm = H5Tget_norm(type); + CHECK(norm, FAIL, "H5Tget_norm"); + + ret = H5Tset_offset(type, (size_t)16); + CHECK(ret, FAIL, "H5Tset_offset"); + + H5E_BEGIN_TRY + { + cset = H5Tget_cset(type); + } + H5E_END_TRY; + VERIFY(cset, FAIL, "H5Tget_cset"); + + H5E_BEGIN_TRY + { + strpad = H5Tget_strpad(type); + } + H5E_END_TRY; + VERIFY(strpad, FAIL, "H5Tget_strpad"); + + /* Close datatype */ + ret = H5Tclose(type); + CHECK(ret, FAIL, "H5Tclose"); +} /* end test_array_funcs() */ + +/*------------------------------------------------------------------------- + * Function: test_array_atomic_3d + * + * Purpose: Test basic array datatype code. + * Tests 3-D array of atomic datatypes. + * + * Return: void + * + *------------------------------------------------------------------------- + */ +static void +test_array_atomic_3d(void) +{ + int wdata[SPACE1_DIM1][ARRAY2_DIM1][ARRAY2_DIM2][ARRAY2_DIM3]; /* Information to write */ + int rdata[SPACE1_DIM1][ARRAY2_DIM1][ARRAY2_DIM2][ARRAY2_DIM3]; /* Information read in */ + hid_t fid; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t tid; /* Datatype ID */ + hsize_t sdims1[] = {SPACE1_DIM1}; + hsize_t tdims2[] = {ARRAY2_DIM1, ARRAY2_DIM2, ARRAY2_DIM3}; + int ndims; /* Array rank for reading */ + hsize_t rdims2[H5S_MAX_RANK]; /* Array dimensions for reading */ + int i, j, k, l; /* counting variables */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing 3-D Array of Atomic Datatypes Functionality\n")); + + /* Allocate and initialize array data to write */ + for (i = 0; i < SPACE1_DIM1; i++) + for (j = 0; j < ARRAY2_DIM1; j++) + for (k = 0; k < ARRAY2_DIM2; k++) + for (l = 0; l < ARRAY2_DIM3; l++) + wdata[i][j][k][l] = i * 1000 + j * 100 + k * 10 + l; + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid = H5Screate_simple(SPACE1_RANK, sdims1, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Create a datatype to refer to */ + tid = H5Tarray_create2(H5T_NATIVE_INT, ARRAY2_RANK, tdims2); + CHECK(tid, FAIL, "H5Tarray_create2"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid, "Dataset1", tid, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write dataset to disk */ + ret = H5Dwrite(dataset, tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close datatype */ + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* Open the dataset */ + dataset = H5Dopen2(fid, "Dataset1", H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Get the datatype */ + tid = H5Dget_type(dataset); + CHECK(tid, FAIL, "H5Dget_type"); + + /* Check the array rank */ + ndims = H5Tget_array_ndims(tid); + VERIFY(ndims, ARRAY2_RANK, "H5Tget_array_ndims"); + + /* Get the array dimensions */ + ret = H5Tget_array_dims2(tid, rdims2); + CHECK(ret, FAIL, "H5Tget_array_dims2"); + + /* Check the array dimensions */ + for (i = 0; i < ndims; i++) + if (rdims2[i] != tdims2[i]) { + TestErrPrintf("Array dimension information doesn't match!, rdims2[%d]=%d, tdims2[%d]=%d\n", + (int)i, (int)rdims2[i], (int)i, (int)tdims2[i]); + continue; + } /* end if */ + + /* Read dataset from disk */ + ret = H5Dread(dataset, tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < SPACE1_DIM1; i++) + for (j = 0; j < ARRAY2_DIM1; j++) + for (k = 0; k < ARRAY2_DIM2; k++) + for (l = 0; l < ARRAY2_DIM3; l++) + if (wdata[i][j][k][l] != rdata[i][j][k][l]) { + TestErrPrintf("Array data information doesn't match!, wdata[%d][%d][%d][%d]=%d, " + "rdata[%d][%d][%d][%d]=%d\n", + (int)i, (int)j, (int)k, (int)l, (int)wdata[i][j][k][l], (int)i, (int)j, + (int)k, (int)l, (int)rdata[i][j][k][l]); + continue; + } /* end if */ + + /* Close Datatype */ + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + +} /* end test_array_atomic_3d() */ + +/*------------------------------------------------------------------------- + * Function: test_array_array_atomic + * + * Purpose: Test basic array datatype code. + * Tests 1-D array 2-D arrays of atomic datatypes. + * + * Return: void + * + *------------------------------------------------------------------------- + */ +static void +test_array_array_atomic(void) +{ + int wdata[SPACE1_DIM1][ARRAY1_DIM1][ARRAY3_DIM1][ARRAY3_DIM2]; /* Information to write */ + int rdata[SPACE1_DIM1][ARRAY1_DIM1][ARRAY3_DIM1][ARRAY3_DIM2]; /* Information read in */ + hid_t fid; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t tid1; /* 1-D array Datatype ID */ + hid_t tid2; /* 2-D array Datatype ID */ + hsize_t sdims1[] = {SPACE1_DIM1}; + hsize_t tdims1[] = {ARRAY1_DIM1}; + hsize_t tdims2[] = {ARRAY3_DIM1, ARRAY3_DIM2}; + int ndims1; /* Array rank for reading */ + int ndims2; /* Array rank for reading */ + hsize_t rdims1[H5S_MAX_RANK]; /* Array dimensions for reading */ + hsize_t rdims2[H5S_MAX_RANK]; /* Array dimensions for reading */ + int i, j, k, l; /* counting variables */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing 1-D Array 2-D Arrays of Atomic Datatypes Functionality\n")); + + /* Allocate and initialize array data to write */ + for (i = 0; i < SPACE1_DIM1; i++) + for (j = 0; j < ARRAY1_DIM1; j++) + for (k = 0; k < ARRAY3_DIM1; k++) + for (l = 0; l < ARRAY3_DIM2; l++) + wdata[i][j][k][l] = i * 1000 + j * 100 + k * 10 + l; + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid = H5Screate_simple(SPACE1_RANK, sdims1, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Create a 2-D datatype to refer to */ + tid2 = H5Tarray_create2(H5T_NATIVE_INT, ARRAY3_RANK, tdims2); + CHECK(tid2, FAIL, "H5Tarray_create2"); + + /* Create a 1-D datatype to refer to */ + tid1 = H5Tarray_create2(tid2, ARRAY1_RANK, tdims1); + CHECK(tid1, FAIL, "H5Tarray_create2"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid, "Dataset1", tid1, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write dataset to disk */ + ret = H5Dwrite(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close datatypes */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Tclose(tid2); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* Open the dataset */ + dataset = H5Dopen2(fid, "Dataset1", H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Get the 1-D datatype */ + tid1 = H5Dget_type(dataset); + CHECK(tid1, FAIL, "H5Dget_type"); + + /* Check the 1-D array rank */ + ndims1 = H5Tget_array_ndims(tid1); + VERIFY(ndims1, ARRAY1_RANK, "H5Tget_array_ndims"); + + /* Get the 1-D array dimensions */ + ret = H5Tget_array_dims2(tid1, rdims1); + CHECK(ret, FAIL, "H5Tget_array_dims2"); + + /* Check the array dimensions */ + for (i = 0; i < ndims1; i++) + if (rdims1[i] != tdims1[i]) { + TestErrPrintf("Array dimension information doesn't match!, rdims1[%d]=%" PRIuHSIZE + ", tdims1[%d]=%" PRIuHSIZE "\n", + i, rdims1[i], i, tdims1[i]); + continue; + } /* end if */ + + /* Get the 2-D datatype */ + tid2 = H5Tget_super(tid1); + CHECK(tid2, FAIL, "H5Tget_super"); + + /* Check the 2-D array rank */ + ndims2 = H5Tget_array_ndims(tid2); + VERIFY(ndims2, ARRAY3_RANK, "H5Tget_array_ndims"); + + /* Get the 2-D array dimensions */ + ret = H5Tget_array_dims2(tid2, rdims2); + CHECK(ret, FAIL, "H5Tget_array_dims2"); + + /* Check the array dimensions */ + for (i = 0; i < ndims2; i++) + if (rdims2[i] != tdims2[i]) { + TestErrPrintf("Array dimension information doesn't match!, rdims2[%d]=%d, tdims2[%d]=%d\n", + (int)i, (int)rdims2[i], (int)i, (int)tdims2[i]); + continue; + } /* end if */ + + /* Read dataset from disk */ + ret = H5Dread(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < SPACE1_DIM1; i++) + for (j = 0; j < ARRAY1_DIM1; j++) + for (k = 0; k < ARRAY3_DIM1; k++) + for (l = 0; l < ARRAY3_DIM2; l++) + if (wdata[i][j][k][l] != rdata[i][j][k][l]) { + TestErrPrintf("Array data information doesn't match!, wdata[%d][%d][%d][%d]=%d, " + "rdata[%d][%d][%d][%d]=%d\n", + (int)i, (int)j, (int)k, (int)l, (int)wdata[i][j][k][l], (int)i, (int)j, + (int)k, (int)l, (int)rdata[i][j][k][l]); + continue; + } /* end if */ + + /* Close Datatypes */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Tclose(tid2); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_array_array_atomic() */ + +/*------------------------------------------------------------------------- + * Function: test_array_compound_atomic + * + * Purpose: Test basic array datatype code. + * Tests 1-D array of compound datatypes (with no array fields). + * + * Return: void + * + *------------------------------------------------------------------------- + */ +static void +test_array_compound_atomic(void) +{ + typedef struct { /* Typedef for compound datatype */ + int i; + float f; + } s1_t; + + s1_t wdata[SPACE1_DIM1][ARRAY1_DIM1]; /* Information to write */ + s1_t rdata[SPACE1_DIM1][ARRAY1_DIM1]; /* Information read in */ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1; /* Dataspace ID */ + hid_t tid1; /* Array Datatype ID */ + hid_t tid2; /* Compound Datatype ID */ + hsize_t sdims1[] = {SPACE1_DIM1}; + hsize_t tdims1[] = {ARRAY1_DIM1}; + int ndims; /* Array rank for reading */ + hsize_t rdims1[H5S_MAX_RANK]; /* Array dimensions for reading */ + int nmemb; /* Number of compound members */ + char *mname; /* Name of compound field */ + size_t off; /* Offset of compound field */ + hid_t mtid; /* Datatype ID for field */ + int i, j; /* counting variables */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing 1-D Array of Compound Atomic Datatypes Functionality\n")); + + /* Initialize array data to write */ + for (i = 0; i < SPACE1_DIM1; i++) + for (j = 0; j < ARRAY1_DIM1; j++) { + wdata[i][j].i = i * 10 + j; + wdata[i][j].f = (float)i * 2.5F + (float)j; + } /* end for */ + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid1 = H5Screate_simple(SPACE1_RANK, sdims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create a compound datatype to refer to */ + tid2 = H5Tcreate(H5T_COMPOUND, sizeof(s1_t)); + CHECK(tid2, FAIL, "H5Tcreate"); + + /* Insert integer field */ + ret = H5Tinsert(tid2, "i", HOFFSET(s1_t, i), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + /* Insert float field */ + ret = H5Tinsert(tid2, "f", HOFFSET(s1_t, f), H5T_NATIVE_FLOAT); + CHECK(ret, FAIL, "H5Tinsert"); + + /* Create an array datatype to refer to */ + tid1 = H5Tarray_create2(tid2, ARRAY1_RANK, tdims1); + CHECK(tid1, FAIL, "H5Tarray_create2"); + + /* Close compound datatype */ + ret = H5Tclose(tid2); + CHECK(ret, FAIL, "H5Tclose"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, "Dataset1", tid1, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write dataset to disk */ + ret = H5Dwrite(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open file */ + fid1 = H5Fopen(FILENAME, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Open the dataset */ + dataset = H5Dopen2(fid1, "Dataset1", H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Get the datatype */ + tid1 = H5Dget_type(dataset); + CHECK(tid1, FAIL, "H5Dget_type"); + + /* Check the array rank */ + ndims = H5Tget_array_ndims(tid1); + VERIFY(ndims, ARRAY1_RANK, "H5Tget_array_ndims"); + + /* Get the array dimensions */ + ret = H5Tget_array_dims2(tid1, rdims1); + CHECK(ret, FAIL, "H5Tget_array_dims2"); + + /* Check the array dimensions */ + for (i = 0; i < ndims; i++) + if (rdims1[i] != tdims1[i]) { + TestErrPrintf("Array dimension information doesn't match!, rdims1[%d]=%" PRIuHSIZE + ", tdims1[%d]=%" PRIuHSIZE "\n", + i, rdims1[i], i, tdims1[i]); + continue; + } /* end if */ + + /* Get the compound datatype */ + tid2 = H5Tget_super(tid1); + CHECK(tid2, FAIL, "H5Tget_super"); + + /* Check the number of members */ + nmemb = H5Tget_nmembers(tid2); + VERIFY(nmemb, 2, "H5Tget_nmembers"); + + /* Check the 1st field's name */ + mname = H5Tget_member_name(tid2, 0); + CHECK_PTR(mname, "H5Tget_member_name"); + if (HDstrcmp(mname, "i") != 0) + TestErrPrintf("Compound field name doesn't match!, mname=%s\n", mname); + H5free_memory(mname); + + /* Check the 1st field's offset */ + off = H5Tget_member_offset(tid2, 0); + VERIFY(off, HOFFSET(s1_t, i), "H5Tget_member_offset"); + + /* Check the 1st field's datatype */ + mtid = H5Tget_member_type(tid2, 0); + CHECK(mtid, FAIL, "H5Tget_member_type"); + if ((ret = H5Tequal(mtid, H5T_NATIVE_INT)) <= 0) + TestErrPrintf("Compound data type is incorrect!, ret=%d\n", (int)ret); + ret = H5Tclose(mtid); + CHECK(mtid, FAIL, "H5Tclose"); + + /* Check the 2nd field's name */ + mname = H5Tget_member_name(tid2, 1); + CHECK_PTR(mname, "H5Tget_member_name"); + if (HDstrcmp(mname, "f") != 0) + TestErrPrintf("Compound field name doesn't match!, mname=%s\n", mname); + H5free_memory(mname); + + /* Check the 2nd field's offset */ + off = H5Tget_member_offset(tid2, 1); + VERIFY(off, HOFFSET(s1_t, f), "H5Tget_member_offset"); + + /* Check the 2nd field's datatype */ + mtid = H5Tget_member_type(tid2, 1); + CHECK(mtid, FAIL, "H5Tget_member_type"); + if ((ret = H5Tequal(mtid, H5T_NATIVE_FLOAT)) <= 0) + TestErrPrintf("Compound data type is incorrect!, ret=%d\n", (int)ret); + ret = H5Tclose(mtid); + CHECK(mtid, FAIL, "H5Tclose"); + + /* Close Compound Datatype */ + ret = H5Tclose(tid2); + CHECK(ret, FAIL, "H5Tclose"); + + /* Read dataset from disk */ + ret = H5Dread(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < SPACE1_DIM1; i++) + for (j = 0; j < ARRAY1_DIM1; j++) { + if (wdata[i][j].i != rdata[i][j].i) { + TestErrPrintf( + "Array data information doesn't match!, wdata[%d][%d].i=%d, rdata[%d][%d].i=%d\n", (int)i, + (int)j, (int)wdata[i][j].i, (int)i, (int)j, (int)rdata[i][j].i); + continue; + } /* end if */ + if (!H5_FLT_ABS_EQUAL(wdata[i][j].f, rdata[i][j].f)) { + TestErrPrintf( + "Array data information doesn't match!, wdata[%d][%d].f=%f, rdata[%d][%d].f=%f\n", (int)i, + (int)j, (double)wdata[i][j].f, (int)i, (int)j, (double)rdata[i][j].f); + continue; + } /* end if */ + } /* end for */ + + /* Close Datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_array_compound_atomic() */ + +/*------------------------------------------------------------------------- + * Function: test_array_compound_array + * + * Purpose: Test basic array datatype code. + * Tests 1-D array of compound datatypes (with array fields). + * + * Return: void + * + *------------------------------------------------------------------------- + */ +static void +test_array_compound_array(void) +{ + typedef struct { /* Typedef for compound datatype */ + int i; + float f[ARRAY1_DIM1]; + } s1_t; + + s1_t wdata[SPACE1_DIM1][ARRAY1_DIM1]; /* Information to write */ + s1_t rdata[SPACE1_DIM1][ARRAY1_DIM1]; /* Information read in */ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1; /* Dataspace ID */ + hid_t tid1; /* Array Datatype ID */ + hid_t tid2; /* Compound Datatype ID */ + hid_t tid3; /* Nested Array Datatype ID */ + hsize_t sdims1[] = {SPACE1_DIM1}; + hsize_t tdims1[] = {ARRAY1_DIM1}; + int ndims; /* Array rank for reading */ + hsize_t rdims1[H5S_MAX_RANK]; /* Array dimensions for reading */ + int nmemb; /* Number of compound members */ + char *mname; /* Name of compound field */ + size_t off; /* Offset of compound field */ + hid_t mtid; /* Datatype ID for field */ + H5T_class_t mclass; /* Datatype class for field */ + int i, j, k; /* counting variables */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing 1-D Array of Compound Array Datatypes Functionality\n")); + + /* Initialize array data to write */ + for (i = 0; i < SPACE1_DIM1; i++) + for (j = 0; j < ARRAY1_DIM1; j++) { + wdata[i][j].i = i * 10 + j; + for (k = 0; k < ARRAY1_DIM1; k++) + wdata[i][j].f[k] = (float)i * 10.0F + (float)j * 2.5F + (float)k; + } /* end for */ + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid1 = H5Screate_simple(SPACE1_RANK, sdims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create a compound datatype to refer to */ + tid2 = H5Tcreate(H5T_COMPOUND, sizeof(s1_t)); + CHECK(tid2, FAIL, "H5Tcreate"); + + /* Insert integer field */ + ret = H5Tinsert(tid2, "i", HOFFSET(s1_t, i), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + /* Create an array of floats datatype */ + tid3 = H5Tarray_create2(H5T_NATIVE_FLOAT, ARRAY1_RANK, tdims1); + CHECK(tid3, FAIL, "H5Tarray_create2"); + + /* Insert float array field */ + ret = H5Tinsert(tid2, "f", HOFFSET(s1_t, f), tid3); + CHECK(ret, FAIL, "H5Tinsert"); + + /* Close array of floats field datatype */ + ret = H5Tclose(tid3); + CHECK(ret, FAIL, "H5Tclose"); + + /* Create an array datatype to refer to */ + tid1 = H5Tarray_create2(tid2, ARRAY1_RANK, tdims1); + CHECK(tid1, FAIL, "H5Tarray_create2"); + + /* Close compound datatype */ + ret = H5Tclose(tid2); + CHECK(ret, FAIL, "H5Tclose"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, "Dataset1", tid1, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write dataset to disk */ + ret = H5Dwrite(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open file */ + fid1 = H5Fopen(FILENAME, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Open the dataset */ + dataset = H5Dopen2(fid1, "Dataset1", H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Get the datatype */ + tid1 = H5Dget_type(dataset); + CHECK(tid1, FAIL, "H5Dget_type"); + + /* Check the array rank */ + ndims = H5Tget_array_ndims(tid1); + VERIFY(ndims, ARRAY1_RANK, "H5Tget_array_ndims"); + + /* Get the array dimensions */ + ret = H5Tget_array_dims2(tid1, rdims1); + CHECK(ret, FAIL, "H5Tget_array_dims2"); + + /* Check the array dimensions */ + for (i = 0; i < ndims; i++) + if (rdims1[i] != tdims1[i]) { + TestErrPrintf("Array dimension information doesn't match!, rdims1[%d]=%" PRIuHSIZE + ", tdims1[%d]=%" PRIuHSIZE "\n", + i, rdims1[i], i, tdims1[i]); + continue; + } /* end if */ + + /* Get the compound datatype */ + tid2 = H5Tget_super(tid1); + CHECK(tid2, FAIL, "H5Tget_super"); + + /* Check the number of members */ + nmemb = H5Tget_nmembers(tid2); + VERIFY(nmemb, 2, "H5Tget_nmembers"); + + /* Check the 1st field's name */ + mname = H5Tget_member_name(tid2, 0); + CHECK_PTR(mname, "H5Tget_member_name"); + if (HDstrcmp(mname, "i") != 0) + TestErrPrintf("Compound field name doesn't match!, mname=%s\n", mname); + H5free_memory(mname); + + /* Check the 1st field's offset */ + off = H5Tget_member_offset(tid2, 0); + VERIFY(off, HOFFSET(s1_t, i), "H5Tget_member_offset"); + + /* Check the 1st field's datatype */ + mtid = H5Tget_member_type(tid2, 0); + CHECK(mtid, FAIL, "H5Tget_member_type"); + if ((ret = H5Tequal(mtid, H5T_NATIVE_INT)) <= 0) + TestErrPrintf("Compound data type is incorrect!, ret=%d\n", (int)ret); + ret = H5Tclose(mtid); + CHECK(mtid, FAIL, "H5Tclose"); + + /* Check the 2nd field's name */ + mname = H5Tget_member_name(tid2, 1); + CHECK_PTR(mname, "H5Tget_member_name"); + if (HDstrcmp(mname, "f") != 0) + TestErrPrintf("Compound field name doesn't match!, mname=%s\n", mname); + H5free_memory(mname); + + /* Check the 2nd field's offset */ + off = H5Tget_member_offset(tid2, 1); + VERIFY(off, HOFFSET(s1_t, f), "H5Tget_member_offset"); + + /* Check the 2nd field's datatype */ + mtid = H5Tget_member_type(tid2, 1); + CHECK(mtid, FAIL, "H5Tget_member_type"); + + /* Get the 2nd field's class */ + mclass = H5Tget_class(mtid); + VERIFY(mclass, H5T_ARRAY, "H5Tget_class"); + + /* Check the array rank */ + ndims = H5Tget_array_ndims(mtid); + VERIFY(ndims, ARRAY1_RANK, "H5Tget_array_ndims"); + + /* Get the array dimensions */ + ret = H5Tget_array_dims2(mtid, rdims1); + CHECK(ret, FAIL, "H5Tget_array_dims2"); + + /* Check the array dimensions */ + for (i = 0; i < ndims; i++) + if (rdims1[i] != tdims1[i]) { + TestErrPrintf("Nested array dimension information doesn't match!, rdims1[%d]=%" PRIuHSIZE + ", tdims1[%d]=%" PRIuHSIZE "\n", + i, rdims1[i], i, tdims1[i]); + continue; + } /* end if */ + + /* Check the nested array's datatype */ + tid3 = H5Tget_super(mtid); + CHECK(tid3, FAIL, "H5Tget_super"); + + if ((ret = H5Tequal(tid3, H5T_NATIVE_FLOAT)) <= 0) + TestErrPrintf("Compound data type is incorrect!, ret=%d\n", (int)ret); + + /* Close the array's base type datatype */ + ret = H5Tclose(tid3); + CHECK(mtid, FAIL, "H5Tclose"); + + /* Close the member datatype */ + ret = H5Tclose(mtid); + CHECK(mtid, FAIL, "H5Tclose"); + + /* Close Compound Datatype */ + ret = H5Tclose(tid2); + CHECK(ret, FAIL, "H5Tclose"); + + /* Read dataset from disk */ + ret = H5Dread(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < SPACE1_DIM1; i++) { + for (j = 0; j < ARRAY1_DIM1; j++) { + if (wdata[i][j].i != rdata[i][j].i) { + TestErrPrintf( + "Array data information doesn't match!, wdata[%d][%d].i=%d, rdata[%d][%d].i=%d\n", (int)i, + (int)j, (int)wdata[i][j].i, (int)i, (int)j, (int)rdata[i][j].i); + continue; + } /* end if */ + for (k = 0; k < ARRAY1_DIM1; k++) + if (!H5_FLT_ABS_EQUAL(wdata[i][j].f[k], rdata[i][j].f[k])) { + TestErrPrintf("Array data information doesn't match!, wdata[%d][%d].f[%d]=%f, " + "rdata[%d][%d].f[%d]=%f\n", + (int)i, (int)j, (int)k, (double)wdata[i][j].f[k], (int)i, (int)j, (int)k, + (double)rdata[i][j].f[k]); + continue; + } /* end if */ + } /* end for */ + } /* end for */ + + /* Close Datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + +} /* end test_array_compound_array() */ + +/**************************************************************** +** +** test_array_alloc_custom(): Test VL datatype custom memory +** allocation routines. This routine just uses malloc to +** allocate the memory and increments the amount of memory +** allocated. +** +****************************************************************/ + +/*------------------------------------------------------------------------- + * Function: test_array_alloc_custom + * + * Purpose: Memory allocator for testing VL datatype custom memory + * allocation routines. + * + * This routine just uses malloc to allocate the memory and + * increments the amount of memory allocated. + * + * Return: + * + * Success: A memory buffer + * Failure: NULL + * + *------------------------------------------------------------------------- + */ +void * +test_array_alloc_custom(size_t size, void *info) +{ + void *ret_value = NULL; /* Pointer to return */ + size_t *mem_used = (size_t *)info; /* Pointer to the memory used */ + size_t extra; /* Extra space needed */ + + /* + * This weird contortion is required on the DEC Alpha to keep the + * alignment correct - QAK + */ + extra = MAX(sizeof(void *), sizeof(size_t)); + + if ((ret_value = HDmalloc(extra + size)) != NULL) { + *(size_t *)ret_value = size; + *mem_used += size; + } /* end if */ + + ret_value = ((unsigned char *)ret_value) + extra; + return ret_value; +} /* end test_array_alloc_custom() */ + +/*------------------------------------------------------------------------- + * Function: test_array_free_custom + * + * Purpose: Memory free function for testing VL datatype custom memory + * allocation routines. + * + * This routine just uses free to free the memory and + * decrements the amount of memory allocated. + * + * Return: void + * + *------------------------------------------------------------------------- + */ +void +test_array_free_custom(void *_mem, void *info) +{ + unsigned char *mem = NULL; /* Pointer to mem to be freed */ + size_t *mem_used = (size_t *)info; /* Pointer to the memory used */ + size_t extra; /* Extra space needed */ + + /* + * This weird contortion is required on the DEC Alpha to keep the + * alignment correct - QAK + */ + extra = MAX(sizeof(void *), sizeof(size_t)); + + if (_mem != NULL) { + mem = ((unsigned char *)_mem) - extra; + *mem_used -= *(size_t *)((void *)mem); + HDfree(mem); + } /* end if */ + +} /* end test_array_free_custom() */ + +/*------------------------------------------------------------------------- + * Function: test_array_vlen_atomic + * + * Purpose: Test basic array datatype code. + * Tests 1-D array of atomic VL datatypes. + * + * Return: void + * + *------------------------------------------------------------------------- + */ +static void +test_array_vlen_atomic(void) +{ + hvl_t wdata[SPACE1_DIM1][ARRAY1_DIM1]; /* Information to write */ + hvl_t rdata[SPACE1_DIM1][ARRAY1_DIM1]; /* Information read in */ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1; /* Dataspace ID */ + hid_t tid1; /* Array Datatype ID */ + hid_t tid2; /* VL Datatype ID */ + hid_t tid3; /* Atomic Datatype ID */ + hsize_t sdims1[] = {SPACE1_DIM1}; + hsize_t tdims1[] = {ARRAY1_DIM1}; + int ndims; /* Array rank for reading */ + hsize_t rdims1[H5S_MAX_RANK]; /* Array dimensions for reading */ + H5T_class_t mclass; /* Datatype class for VL */ + hid_t xfer_pid; /* Dataset transfer property list ID */ + hsize_t size; /* Number of bytes which will be used */ + size_t mem_used = 0; /* Memory used during allocation */ + int i, j, k; /* counting variables */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing 1-D Array of Atomic Variable-Length Datatypes Functionality\n")); + + /* Initialize array data to write */ + for (i = 0; i < SPACE1_DIM1; i++) + for (j = 0; j < ARRAY1_DIM1; j++) { + wdata[i][j].p = HDmalloc((size_t)(i + j + 1) * sizeof(unsigned int)); + wdata[i][j].len = (size_t)(i + j + 1); + for (k = 0; k < (i + j + 1); k++) + ((unsigned int *)wdata[i][j].p)[k] = (unsigned int)(i * 100 + j * 10 + k); + } /* end for */ + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid1 = H5Screate_simple(SPACE1_RANK, sdims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create a compound datatype to refer to */ + tid2 = H5Tvlen_create(H5T_NATIVE_UINT); + CHECK(tid2, FAIL, "H5Tcreate"); + + /* Create an array datatype to refer to */ + tid1 = H5Tarray_create2(tid2, ARRAY1_RANK, tdims1); + CHECK(tid1, FAIL, "H5Tarray_create2"); + + /* Close VL datatype */ + ret = H5Tclose(tid2); + CHECK(ret, FAIL, "H5Tclose"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, "Dataset1", tid1, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write dataset to disk */ + ret = H5Dwrite(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open file */ + fid1 = H5Fopen(FILENAME, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Open the dataset */ + dataset = H5Dopen2(fid1, "Dataset1", H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Get the dataspace */ + sid1 = H5Dget_space(dataset); + CHECK(sid1, FAIL, "H5Dget_space"); + + /* Get the datatype */ + tid1 = H5Dget_type(dataset); + CHECK(tid1, FAIL, "H5Dget_type"); + + /* Check the array rank */ + ndims = H5Tget_array_ndims(tid1); + VERIFY(ndims, ARRAY1_RANK, "H5Tget_array_ndims"); + + /* Get the array dimensions */ + ret = H5Tget_array_dims2(tid1, rdims1); + CHECK(ret, FAIL, "H5Tget_array_dims2"); + + /* Check the array dimensions */ + for (i = 0; i < ndims; i++) + if (rdims1[i] != tdims1[i]) { + TestErrPrintf("Array dimension information doesn't match!, rdims1[%d]=%" PRIuHSIZE + ", tdims1[%d]=%" PRIuHSIZE "\n", + i, rdims1[i], i, tdims1[i]); + continue; + } /* end if */ + + /* Get the VL datatype */ + tid2 = H5Tget_super(tid1); + CHECK(tid2, FAIL, "H5Tget_super"); + + /* Get the 2nd field's class */ + mclass = H5Tget_class(tid2); + VERIFY(mclass, H5T_VLEN, "H5Tget_class"); + + /* Check the VL datatype's base type */ + tid3 = H5Tget_super(tid2); + CHECK(tid3, FAIL, "H5Tget_super"); + + if ((ret = H5Tequal(tid3, H5T_NATIVE_UINT)) <= 0) + TestErrPrintf("VL base datatype is incorrect!, ret=%d\n", (int)ret); + + /* Close the array's base type datatype */ + ret = H5Tclose(tid3); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close VL Datatype */ + ret = H5Tclose(tid2); + CHECK(ret, FAIL, "H5Tclose"); + + /* Change to the custom memory allocation routines for reading VL data */ + xfer_pid = H5Pcreate(H5P_DATASET_XFER); + CHECK(xfer_pid, FAIL, "H5Pcreate"); + + ret = H5Pset_vlen_mem_manager(xfer_pid, test_array_alloc_custom, &mem_used, test_array_free_custom, + &mem_used); + CHECK(ret, FAIL, "H5Pset_vlen_mem_manager"); + + /* Make certain the correct amount of memory will be used */ + ret = H5Dvlen_get_buf_size(dataset, tid1, sid1, &size); + CHECK(ret, FAIL, "H5Dvlen_get_buf_size"); + + /* # elements allocated = (1 + 2 + 3 + 4) + (2 + 3 + 4 + 5) + + * (3 + 4 + 5 + 6) + (4 + 5 + 6 + 7) = 64 elements + */ + VERIFY(size, 64 * sizeof(unsigned int), "H5Dvlen_get_buf_size"); + + /* Read dataset from disk */ + ret = H5Dread(dataset, tid1, H5S_ALL, H5S_ALL, xfer_pid, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Make certain the correct amount of memory has been used */ + /* # elements allocated = (1 + 2 + 3 + 4) + (2 + 3 + 4 + 5) + + * (3 + 4 + 5 + 6) + (4 + 5 + 6 + 7) = 64 elements + */ + VERIFY(mem_used, 64 * sizeof(unsigned int), "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < SPACE1_DIM1; i++) { + for (j = 0; j < ARRAY1_DIM1; j++) { + if (wdata[i][j].len != rdata[i][j].len) { + TestErrPrintf("VL data length don't match!, wdata[%d][%d].len=%d, rdata[%d][%d].len=%d\n", + (int)i, (int)j, (int)wdata[i][j].len, (int)i, (int)j, (int)rdata[i][j].len); + continue; + } /* end if */ + for (k = 0; k < (int)rdata[i][j].len; k++) { + if (((unsigned int *)wdata[i][j].p)[k] != ((unsigned int *)rdata[i][j].p)[k]) { + TestErrPrintf( + "VL data values don't match!, wdata[%d][%d].p[%d]=%d, rdata[%d][%d].p[%d]=%d\n", + (int)i, (int)j, (int)k, (int)((unsigned int *)wdata[i][j].p)[k], (int)i, (int)j, + (int)k, (int)((unsigned int *)rdata[i][j].p)[k]); + continue; + } /* end if */ + } /* end for */ + } /* end for */ + } /* end for */ + + /* Reclaim the read VL data */ + ret = H5Treclaim(tid1, sid1, xfer_pid, rdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Make certain the VL memory has been freed */ + VERIFY(mem_used, 0, "H5Treclaim"); + + /* Reclaim the write VL data */ + ret = H5Treclaim(tid1, sid1, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Close dataset transfer property list */ + ret = H5Pclose(xfer_pid); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close Datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + +} /* end test_array_vlen_atomic() */ + +/*------------------------------------------------------------------------- + * Function: test_array_vlen_array + * + * Purpose: Test basic array datatype code. + * Tests 1-D array of 1-D array VL datatypes. + * + * Return: void + * + *------------------------------------------------------------------------- + */ +static void +test_array_vlen_array(void) +{ + hvl_t wdata[SPACE1_DIM1][ARRAY1_DIM1]; /* Information to write */ + hvl_t rdata[SPACE1_DIM1][ARRAY1_DIM1]; /* Information read in */ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1; /* Dataspace ID */ + hid_t tid1; /* Array Datatype ID */ + hid_t tid2; /* VL Datatype ID */ + hid_t tid3; /* Nested Array Datatype ID */ + hid_t tid4; /* Atomic Datatype ID */ + hsize_t sdims1[] = {SPACE1_DIM1}; + hsize_t tdims1[] = {ARRAY1_DIM1}; + int ndims; /* Array rank for reading */ + hsize_t rdims1[H5S_MAX_RANK]; /* Array dimensions for reading */ + H5T_class_t mclass; /* Datatype class for VL */ + hid_t xfer_pid; /* Dataset transfer property list ID */ + hsize_t size; /* Number of bytes which will be used */ + size_t mem_used = 0; /* Memory used during allocation */ + int i, j, k, l; /* Index variables */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing 1-D Array of 1-D Array Variable-Length Datatypes Functionality\n")); + + /* Initialize array data to write */ + for (i = 0; i < SPACE1_DIM1; i++) + for (j = 0; j < ARRAY1_DIM1; j++) { + wdata[i][j].p = HDmalloc((size_t)(i + j + 1) * sizeof(unsigned int) * (size_t)ARRAY1_DIM1); + wdata[i][j].len = (size_t)(i + j + 1); + for (k = 0; k < (i + j + 1); k++) + for (l = 0; l < ARRAY1_DIM1; l++) + ((unsigned int *)wdata[i][j].p)[k * ARRAY1_DIM1 + l] = + (unsigned int)(i * 1000 + j * 100 + k * 10 + l); + } + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid1 = H5Screate_simple(SPACE1_RANK, sdims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create the nested array datatype to refer to */ + tid3 = H5Tarray_create2(H5T_NATIVE_UINT, ARRAY1_RANK, tdims1); + CHECK(tid3, FAIL, "H5Tarray_create2"); + + /* Create a VL datatype of 1-D arrays to refer to */ + tid2 = H5Tvlen_create(tid3); + CHECK(tid2, FAIL, "H5Tcreate"); + + /* Close nested array datatype */ + ret = H5Tclose(tid3); + CHECK(ret, FAIL, "H5Tclose"); + + /* Create an array datatype to refer to */ + tid1 = H5Tarray_create2(tid2, ARRAY1_RANK, tdims1); + CHECK(tid1, FAIL, "H5Tarray_create2"); + + /* Close VL datatype */ + ret = H5Tclose(tid2); + CHECK(ret, FAIL, "H5Tclose"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, "Dataset1", tid1, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write dataset to disk */ + ret = H5Dwrite(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open file */ + fid1 = H5Fopen(FILENAME, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Open the dataset */ + dataset = H5Dopen2(fid1, "Dataset1", H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Get the dataspace */ + sid1 = H5Dget_space(dataset); + CHECK(sid1, FAIL, "H5Dget_space"); + + /* Get the datatype */ + tid1 = H5Dget_type(dataset); + CHECK(tid1, FAIL, "H5Dget_type"); + + /* Check the array rank */ + ndims = H5Tget_array_ndims(tid1); + VERIFY(ndims, ARRAY1_RANK, "H5Tget_array_ndims"); + + /* Get the array dimensions */ + ret = H5Tget_array_dims2(tid1, rdims1); + CHECK(ret, FAIL, "H5Tget_array_dims2"); + + /* Check the array dimensions */ + for (i = 0; i < ndims; i++) + if (rdims1[i] != tdims1[i]) { + TestErrPrintf("Array dimension information doesn't match!, rdims1[%d]=%" PRIuHSIZE + ", tdims1[%d]=%" PRIuHSIZE "\n", + i, rdims1[i], i, tdims1[i]); + continue; + } /* end if */ + + /* Get the VL datatype */ + tid2 = H5Tget_super(tid1); + CHECK(tid2, FAIL, "H5Tget_super"); + + /* Get the VL datatype's class */ + mclass = H5Tget_class(tid2); + VERIFY(mclass, H5T_VLEN, "H5Tget_class"); + + /* Check the VL datatype's base type */ + tid3 = H5Tget_super(tid2); + CHECK(tid3, FAIL, "H5Tget_super"); + + /* Get the nested array datatype's class */ + mclass = H5Tget_class(tid3); + VERIFY(mclass, H5T_ARRAY, "H5Tget_class"); + + /* Check the array rank */ + ndims = H5Tget_array_ndims(tid3); + VERIFY(ndims, ARRAY1_RANK, "H5Tget_array_ndims"); + + /* Get the array dimensions */ + ret = H5Tget_array_dims2(tid3, rdims1); + CHECK(ret, FAIL, "H5Tget_array_dims2"); + + /* Check the array dimensions */ + for (i = 0; i < ndims; i++) + if (rdims1[i] != tdims1[i]) { + TestErrPrintf("Array dimension information doesn't match!, rdims1[%d]=%" PRIuHSIZE + ", tdims1[%d]=%" PRIuHSIZE "\n", + i, rdims1[i], i, tdims1[i]); + continue; + } /* end if */ + + /* Check the array's base type */ + tid4 = H5Tget_super(tid3); + CHECK(tid4, FAIL, "H5Tget_super"); + + if ((ret = H5Tequal(tid4, H5T_NATIVE_UINT)) <= 0) + TestErrPrintf("VL base datatype is incorrect!, ret=%d\n", (int)ret); + + /* Close the array's base type datatype */ + ret = H5Tclose(tid4); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close the nested array datatype */ + ret = H5Tclose(tid3); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close VL Datatype */ + ret = H5Tclose(tid2); + CHECK(ret, FAIL, "H5Tclose"); + + /* Change to the custom memory allocation routines for reading VL data */ + xfer_pid = H5Pcreate(H5P_DATASET_XFER); + CHECK(xfer_pid, FAIL, "H5Pcreate"); + + ret = H5Pset_vlen_mem_manager(xfer_pid, test_array_alloc_custom, &mem_used, test_array_free_custom, + &mem_used); + CHECK(ret, FAIL, "H5Pset_vlen_mem_manager"); + + /* Make certain the correct amount of memory will be used */ + ret = H5Dvlen_get_buf_size(dataset, tid1, sid1, &size); + CHECK(ret, FAIL, "H5Dvlen_get_buf_size"); + + /* # elements allocated = (1 + 2 + 3 + 4) + (2 + 3 + 4 + 5) + + * (3 + 4 + 5 + 6) + (4 + 5 + 6 + 7) = 64*ARRAY1_DIM1 elements + */ + VERIFY(size, 64 * (sizeof(unsigned int) * ARRAY1_DIM1), "H5Dvlen_get_buf_size"); + + /* Read dataset from disk */ + ret = H5Dread(dataset, tid1, H5S_ALL, H5S_ALL, xfer_pid, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Make certain the correct amount of memory has been used */ + /* # elements allocated = (1 + 2 + 3 + 4) + (2 + 3 + 4 + 5) + + * (3 + 4 + 5 + 6) + (4 + 5 + 6 + 7) = 64*ARRAY1_DIM1 elements + */ + VERIFY(mem_used, 64 * (sizeof(unsigned int) * ARRAY1_DIM1), "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < SPACE1_DIM1; i++) { + for (j = 0; j < ARRAY1_DIM1; j++) { + if (wdata[i][j].len != rdata[i][j].len) { + TestErrPrintf("VL data length don't match!, wdata[%d][%d].len=%d, rdata[%d][%d].len=%d\n", + (int)i, (int)j, (int)wdata[i][j].len, (int)i, (int)j, (int)rdata[i][j].len); + continue; + } /* end if */ + for (k = 0; k < (int)rdata[i][j].len; k++) { + for (l = 0; l < ARRAY1_DIM1; l++) { + if (((unsigned int *)wdata[i][j].p)[k * ARRAY1_DIM1 + l] != + ((unsigned int *)rdata[i][j].p)[k * ARRAY1_DIM1 + l]) { + TestErrPrintf("VL data values don't match!, wdata[%d][%d].p[%d][%d]=%d, " + "rdata[%d][%d].p[%d][%d]=%d\n", + (int)i, (int)j, (int)k, (int)l, + (int)((unsigned int *)wdata[i][j].p)[k * ARRAY1_DIM1 + l], (int)i, + (int)j, (int)k, (int)l, + (int)((unsigned int *)rdata[i][j].p)[k * ARRAY1_DIM1 + l]); + continue; + } /* end if */ + } /* end for */ + } /* end for */ + } /* end for */ + } /* end for */ + + /* Reclaim the read VL data */ + ret = H5Treclaim(tid1, sid1, xfer_pid, rdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Make certain the VL memory has been freed */ + VERIFY(mem_used, 0, "H5Treclaim"); + + /* Reclaim the write VL data */ + ret = H5Treclaim(tid1, sid1, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Close dataset transfer property list */ + ret = H5Pclose(xfer_pid); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close Datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + +} /* end test_array_vlen_array() */ + +/*------------------------------------------------------------------------- + * Function: test_array_bkg + * + * Purpose: Test basic array datatype code. + * Tests reading compound datatype with array fields and + * writing partial fields. + * + * Return: void + * + *------------------------------------------------------------------------- + */ +static void +test_array_bkg(void) +{ + herr_t status = -1; + + hid_t fid, array_dt; + hid_t space; + hid_t type; + hid_t dataset; + + hsize_t dim[] = {LENGTH}; + hsize_t dima[] = {ALEN}; + + int i, j; + unsigned ndims[3] = {1, 1, 1}; + + typedef struct { + int a[ALEN]; + float b[ALEN]; + double c[ALEN]; + } CmpField; + + CmpField cf[LENGTH]; + CmpField cfr[LENGTH]; + CmpDTSinfo *dtsinfo = NULL; + + typedef struct { + float b[ALEN]; + } fld_t; + + fld_t fld[LENGTH]; + fld_t fldr[LENGTH]; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Partial I/O of Array Fields in Compound Datatype Functionality\n")); + + /* Initialize the data */ + /* ------------------- */ + dtsinfo = (CmpDTSinfo *)HDmalloc(sizeof(CmpDTSinfo)); + CHECK_PTR(dtsinfo, "HDmalloc"); + HDmemset(dtsinfo, 0, sizeof(CmpDTSinfo)); + for (i = 0; i < LENGTH; i++) { + for (j = 0; j < ALEN; j++) { + cf[i].a[j] = 100 * (i + 1) + j; + cf[i].b[j] = 100.0F * ((float)i + 1.0F) + 0.01F * (float)j; + cf[i].c[j] = (double)(100.0F * ((float)i + 1.0F) + 0.02F * (float)j); + } /* end for */ + } /* end for */ + + /* Set the number of data members */ + /* ------------------------------ */ + dtsinfo->nsubfields = 3; + + /* Initialize the offsets */ + /* ----------------------- */ + dtsinfo->offset[0] = HOFFSET(CmpField, a); + dtsinfo->offset[1] = HOFFSET(CmpField, b); + dtsinfo->offset[2] = HOFFSET(CmpField, c); + + /* Initialize the data type IDs */ + /* ---------------------------- */ + dtsinfo->datatype[0] = H5T_NATIVE_INT; + dtsinfo->datatype[1] = H5T_NATIVE_FLOAT; + dtsinfo->datatype[2] = H5T_NATIVE_DOUBLE; + + /* Initialize the names of data members */ + /* ------------------------------------ */ + for (i = 0; i < dtsinfo->nsubfields; i++) + dtsinfo->name[i] = (char *)HDcalloc((size_t)20, sizeof(char)); + + HDstrcpy(dtsinfo->name[0], "One"); + HDstrcpy(dtsinfo->name[1], "Two"); + HDstrcpy(dtsinfo->name[2], "Three"); + + /* Create file */ + /* ----------- */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create data space */ + /* ----------------- */ + space = H5Screate_simple(RANK, dim, NULL); + CHECK(space, FAIL, "H5Screate_simple"); + + /* Create the memory data type */ + /* --------------------------- */ + type = H5Tcreate(H5T_COMPOUND, sizeof(CmpField)); + CHECK(type, FAIL, "H5Tcreate"); + + /* Add members to the compound data type */ + /* -------------------------------------- */ + for (i = 0; i < dtsinfo->nsubfields; i++) { + array_dt = H5Tarray_create2(dtsinfo->datatype[i], ndims[i], dima); + CHECK(array_dt, FAIL, "H5Tarray_create2"); + + status = H5Tinsert(type, dtsinfo->name[i], dtsinfo->offset[i], array_dt); + CHECK(status, FAIL, "H5Tinsert"); + + status = H5Tclose(array_dt); + CHECK(status, FAIL, "H5Tclose"); + } /* end for */ + + /* Create the dataset */ + /* ------------------ */ + dataset = H5Dcreate2(fid, FIELDNAME, type, space, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write data to the dataset */ + /* ------------------------- */ + status = H5Dwrite(dataset, type, H5S_ALL, H5S_ALL, H5P_DEFAULT, cf); + CHECK(status, FAIL, "H5Dwrite"); + + status = H5Dread(dataset, type, H5S_ALL, H5S_ALL, H5P_DEFAULT, cfr); + CHECK(status, FAIL, "H5Dread"); + + /* Verify correct data */ + /* ------------------- */ + for (i = 0; i < LENGTH; i++) { + for (j = 0; j < ALEN; j++) { + if (cf[i].a[j] != cfr[i].a[j]) { + TestErrPrintf("Field a data doesn't match, cf[%d].a[%d]=%d, cfr[%d].a[%d]=%d\n", (int)i, + (int)j, (int)cf[i].a[j], (int)i, (int)j, (int)cfr[i].a[j]); + continue; + } /* end if */ + if (!H5_FLT_ABS_EQUAL(cf[i].b[j], cfr[i].b[j])) { + TestErrPrintf("Field b data doesn't match, cf[%d].b[%d]=%f, cfr[%d].b[%d]=%f\n", (int)i, + (int)j, (double)cf[i].b[j], (int)i, (int)j, (double)cfr[i].b[j]); + continue; + } /* end if */ + if (!H5_DBL_ABS_EQUAL(cf[i].c[j], cfr[i].c[j])) { + TestErrPrintf("Field c data doesn't match, cf[%d].b[%d]=%f, cfr[%d].b[%d]=%f\n", (int)i, + (int)j, (double)cf[i].c[j], (int)i, (int)j, (double)cfr[i].c[j]); + continue; + } /* end if */ + } /* end for */ + } /* end for */ + + /* Release memory resources */ + /* ------------------------ */ + for (i = 0; i < dtsinfo->nsubfields; i++) + HDfree(dtsinfo->name[i]); + + /* Release IDs */ + /* ----------- */ + status = H5Tclose(type); + CHECK(status, FAIL, "H5Tclose"); + + status = H5Sclose(space); + CHECK(status, FAIL, "H5Sclose"); + + status = H5Dclose(dataset); + CHECK(status, FAIL, "H5Dclose"); + + status = H5Fclose(fid); + CHECK(status, FAIL, "H5Fclose"); + + /******************************/ + /* Reopen the file and update */ + /******************************/ + + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + dataset = H5Dopen2(fid, FIELDNAME, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + type = H5Tcreate(H5T_COMPOUND, sizeof(fld_t)); + CHECK(type, FAIL, "H5Tcreate"); + + array_dt = H5Tarray_create2(H5T_NATIVE_FLOAT, 1, dima); + CHECK(array_dt, FAIL, "H5Tarray_create2"); + + status = H5Tinsert(type, "Two", HOFFSET(fld_t, b), array_dt); + CHECK(status, FAIL, "H5Tinsert"); + + /* Initialize the data to overwrite */ + /* -------------------------------- */ + for (i = 0; i < LENGTH; i++) + for (j = 0; j < ALEN; j++) + cf[i].b[j] = fld[i].b[j] = 1.313F; + + status = H5Dwrite(dataset, type, H5S_ALL, H5S_ALL, H5P_DEFAULT, fld); + CHECK(status, FAIL, "H5Dwrite"); + + /* Read just the field changed */ + status = H5Dread(dataset, type, H5S_ALL, H5S_ALL, H5P_DEFAULT, fldr); + CHECK(status, FAIL, "H5Dread"); + + for (i = 0; i < LENGTH; i++) + for (j = 0; j < ALEN; j++) + if (!H5_FLT_ABS_EQUAL(fld[i].b[j], fldr[i].b[j])) { + TestErrPrintf("Field data doesn't match, fld[%d].b[%d]=%f, fldr[%d].b[%d]=%f\n", (int)i, + (int)j, (double)fld[i].b[j], (int)i, (int)j, (double)fldr[i].b[j]); + continue; + } /* end if */ + + status = H5Tclose(type); + CHECK(status, FAIL, "H5Tclose"); + + status = H5Tclose(array_dt); + CHECK(status, FAIL, "H5Tclose"); + + type = H5Dget_type(dataset); + CHECK(type, FAIL, "H5Dget_type"); + + /* Read the entire dataset again */ + status = H5Dread(dataset, type, H5S_ALL, H5S_ALL, H5P_DEFAULT, cfr); + CHECK(status, FAIL, "H5Dread"); + + /* Verify correct data */ + /* ------------------- */ + for (i = 0; i < LENGTH; i++) { + for (j = 0; j < ALEN; j++) { + if (cf[i].a[j] != cfr[i].a[j]) { + TestErrPrintf("Field a data doesn't match, cf[%d].a[%d]=%d, cfr[%d].a[%d]=%d\n", (int)i, + (int)j, (int)cf[i].a[j], (int)i, (int)j, (int)cfr[i].a[j]); + continue; + } /* end if */ + if (!H5_FLT_ABS_EQUAL(cf[i].b[j], cfr[i].b[j])) { + TestErrPrintf("Field b data doesn't match, cf[%d].b[%d]=%f, cfr[%d].b[%d]=%f\n", (int)i, + (int)j, (double)cf[i].b[j], (int)i, (int)j, (double)cfr[i].b[j]); + continue; + } /* end if */ + if (!H5_DBL_ABS_EQUAL(cf[i].c[j], cfr[i].c[j])) { + TestErrPrintf("Field c data doesn't match, cf[%d].b[%d]=%f, cfr[%d].b[%d]=%f\n", (int)i, + (int)j, (double)cf[i].c[j], (int)i, (int)j, (double)cfr[i].c[j]); + continue; + } /* end if */ + } /* end for */ + } /* end for */ + + status = H5Dclose(dataset); + CHECK(status, FAIL, "H5Dclose"); + + status = H5Tclose(type); + CHECK(status, FAIL, "H5Tclose"); + + status = H5Fclose(fid); + CHECK(status, FAIL, "H5Fclose"); + + /****************************************************/ + /* Reopen the file and print out all the data again */ + /****************************************************/ + + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + dataset = H5Dopen2(fid, FIELDNAME, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + type = H5Dget_type(dataset); + CHECK(type, FAIL, "H5Dget_type"); + + /* Reset the data to read in */ + /* ------------------------- */ + HDmemset(cfr, 0, sizeof(CmpField) * LENGTH); + + status = H5Dread(dataset, type, H5S_ALL, H5S_ALL, H5P_DEFAULT, cfr); + CHECK(status, FAIL, "H5Dread"); + + /* Verify correct data */ + /* ------------------- */ + for (i = 0; i < LENGTH; i++) { + for (j = 0; j < ALEN; j++) { + if (cf[i].a[j] != cfr[i].a[j]) { + TestErrPrintf("Field a data doesn't match, cf[%d].a[%d]=%d, cfr[%d].a[%d]=%d\n", (int)i, + (int)j, (int)cf[i].a[j], (int)i, (int)j, (int)cfr[i].a[j]); + continue; + } /* end if */ + if (!H5_FLT_ABS_EQUAL(cf[i].b[j], cfr[i].b[j])) { + TestErrPrintf("Field b data doesn't match, cf[%d].b[%d]=%f, cfr[%d].b[%d]=%f\n", (int)i, + (int)j, (double)cf[i].b[j], (int)i, (int)j, (double)cfr[i].b[j]); + continue; + } /* end if */ + if (!H5_DBL_ABS_EQUAL(cf[i].c[j], cfr[i].c[j])) { + TestErrPrintf("Field c data doesn't match, cf[%d].b[%d]=%f, cfr[%d].b[%d]=%f\n", (int)i, + (int)j, (double)cf[i].c[j], (int)i, (int)j, (double)cfr[i].c[j]); + continue; + } /* end if */ + } /* end for */ + } /* end for */ + + status = H5Dclose(dataset); + CHECK(status, FAIL, "H5Dclose"); + + status = H5Tclose(type); + CHECK(status, FAIL, "H5Tclose"); + + status = H5Fclose(fid); + CHECK(status, FAIL, "H5Fclose"); + + HDfree(dtsinfo); +} /* end test_array_bkg() */ + +/*------------------------------------------------------------------------- + * Function: test_compat + * + * Purpose: Test array datatype compatibility code. + * + * Reads file containing old version of datatype object header + * messages for compound datatypes and verifies reading the older + * version of the is working correctly. + * + * Return: void + * + *------------------------------------------------------------------------- + */ +#if 0 +static void +test_compat(void) +{ + const char *testfile = H5_get_srcdir_filename(TESTFILE); /* Corrected test file name */ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t tid1; /* Array Datatype ID */ + hid_t tid2; /* Datatype ID */ + hsize_t tdims1[] = {ARRAY1_DIM1}; + int ndims; /* Array rank for reading */ + hsize_t rdims1[H5S_MAX_RANK]; /* Array dimensions for reading */ + H5T_class_t mclass; /* Datatype class for VL */ + int nmemb; /* Number of compound members */ + char *mname; /* Name of compound field */ + size_t off; /* Offset of compound field */ + hid_t mtid; /* Datatype ID for field */ + int i; /* Index variables */ + hbool_t driver_is_default_compatible; + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Array Datatypes Compatibility Functionality\n")); + + /* + * Try reading a file that has been prepared that has datasets with + * compound datatypes which use an older version (version 1) of the + * datatype object header message for describing the datatype. + * + * If this test fails and the datatype object header message version has + * changed, follow the instructions in gen_old_array.c for regenerating + * the tarrold.h5 file. + */ + + if (h5_driver_is_default_vfd_compatible(H5P_DEFAULT, &driver_is_default_compatible) < 0) + TestErrPrintf("can't check if VFD is default VFD compatible\n"); + if (!driver_is_default_compatible) { + HDprintf(" -- SKIPPED --\n"); + return; + } + + /* Open the testfile */ + fid1 = H5Fopen(testfile, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK_I(fid1, "H5Fopen"); + + /* Only try to proceed if the file is around */ + if (fid1 >= 0) { + /* Open the first dataset (with no array fields) */ + dataset = H5Dopen2(fid1, "Dataset1", H5P_DEFAULT); + CHECK_I(dataset, "H5Dopen2"); + + /* Get the datatype */ + tid1 = H5Dget_type(dataset); + CHECK_I(tid1, "H5Dget_type"); + + /* Verify datatype class */ + mclass = H5Tget_class(tid1); + VERIFY(mclass, H5T_COMPOUND, "H5Tget_class"); + + /* Get the number of compound datatype fields */ + nmemb = H5Tget_nmembers(tid1); + VERIFY(nmemb, 3, "H5Tget_nmembers"); + + /* Check the 1st field's name */ + mname = H5Tget_member_name(tid1, 0); + CHECK_PTR(mname, "H5Tget_member_name"); + if (HDstrcmp(mname, "i") != 0) + TestErrPrintf("Compound field name doesn't match!, mname=%s\n", mname); + H5free_memory(mname); + + /* Check the 1st field's offset */ + off = H5Tget_member_offset(tid1, 0); + VERIFY(off, 0, "H5Tget_member_offset"); + + /* Check the 1st field's datatype */ + mtid = H5Tget_member_type(tid1, 0); + CHECK(mtid, FAIL, "H5Tget_member_type"); + if ((ret = H5Tequal(mtid, H5T_STD_I16LE)) <= 0) + TestErrPrintf("Compound data type is incorrect!, ret=%d\n", (int)ret); + ret = H5Tclose(mtid); + CHECK(mtid, FAIL, "H5Tclose"); + + /* Check the 2nd field's name */ + mname = H5Tget_member_name(tid1, 1); + CHECK_PTR(mname, "H5Tget_member_name"); + if (HDstrcmp(mname, "f") != 0) + TestErrPrintf("Compound field name doesn't match!, mname=%s\n", mname); + H5free_memory(mname); + + /* Check the 2nd field's offset */ + off = H5Tget_member_offset(tid1, 1); + VERIFY(off, 4, "H5Tget_member_offset"); + + /* Check the 2nd field's datatype */ + mtid = H5Tget_member_type(tid1, 1); + CHECK(mtid, FAIL, "H5Tget_member_type"); + if ((ret = H5Tequal(mtid, H5T_IEEE_F32LE)) <= 0) + TestErrPrintf("Compound data type is incorrect!, ret=%d\n", (int)ret); + ret = H5Tclose(mtid); + CHECK(mtid, FAIL, "H5Tclose"); + + /* Check the 3rd field's name */ + mname = H5Tget_member_name(tid1, 2); + CHECK_PTR(mname, "H5Tget_member_name"); + if (HDstrcmp(mname, "l") != 0) + TestErrPrintf("Compound field name doesn't match!, mname=%s\n", mname); + H5free_memory(mname); + + /* Check the 3rd field's offset */ + off = H5Tget_member_offset(tid1, 2); + VERIFY(off, 8, "H5Tget_member_offset"); + + /* Check the 3rd field's datatype */ + mtid = H5Tget_member_type(tid1, 2); + CHECK(mtid, FAIL, "H5Tget_member_type"); + if ((ret = H5Tequal(mtid, H5T_STD_I32LE)) <= 0) + TestErrPrintf("Compound data type is incorrect!, ret=%d\n", (int)ret); + ret = H5Tclose(mtid); + CHECK(mtid, FAIL, "H5Tclose"); + + /* Close the datatype */ + ret = H5Tclose(tid1); + CHECK_I(ret, "H5Tclose"); + + /* Close the dataset */ + ret = H5Dclose(dataset); + CHECK_I(ret, "H5Dclose"); + + /* Open the second dataset (with array fields) */ + dataset = H5Dopen2(fid1, "Dataset2", H5P_DEFAULT); + CHECK_I(dataset, "H5Dopen2"); + + /* Get the datatype */ + tid1 = H5Dget_type(dataset); + CHECK_I(tid1, "H5Dget_type"); + + /* Verify datatype class */ + mclass = H5Tget_class(tid1); + VERIFY(mclass, H5T_COMPOUND, "H5Tget_class"); + + /* Get the number of compound datatype fields */ + nmemb = H5Tget_nmembers(tid1); + VERIFY(nmemb, 4, "H5Tget_nmembers"); + + /* Check the 1st field's name */ + mname = H5Tget_member_name(tid1, 0); + CHECK_PTR(mname, "H5Tget_member_name"); + if (mname && HDstrcmp(mname, "i") != 0) + TestErrPrintf("Compound field name doesn't match!, mname=%s\n", mname); + if (mname) + H5free_memory(mname); + + /* Check the 1st field's offset */ + off = H5Tget_member_offset(tid1, 0); + VERIFY(off, 0, "H5Tget_member_offset"); + + /* Check the 1st field's datatype */ + mtid = H5Tget_member_type(tid1, 0); + CHECK(mtid, FAIL, "H5Tget_member_type"); + if ((ret = H5Tequal(mtid, H5T_STD_I16LE)) <= 0) + TestErrPrintf("Compound data type is incorrect!, ret=%d\n", (int)ret); + ret = H5Tclose(mtid); + CHECK(mtid, FAIL, "H5Tclose"); + + /* Check the 2nd field's name */ + mname = H5Tget_member_name(tid1, 1); + CHECK_PTR(mname, "H5Tget_member_name"); + if (mname && HDstrcmp(mname, "f") != 0) + TestErrPrintf("Compound field name doesn't match!, mname=%s\n", mname); + if (mname) + H5free_memory(mname); + + /* Check the 2nd field's offset */ + off = H5Tget_member_offset(tid1, 1); + VERIFY(off, 4, "H5Tget_member_offset"); + + /* Check the 2nd field's datatype */ + mtid = H5Tget_member_type(tid1, 1); + CHECK(mtid, FAIL, "H5Tget_member_type"); + + /* Verify datatype class */ + mclass = H5Tget_class(mtid); + VERIFY(mclass, H5T_ARRAY, "H5Tget_class"); + + /* Check the array rank */ + ndims = H5Tget_array_ndims(mtid); + VERIFY(ndims, ARRAY1_RANK, "H5Tget_array_ndims"); + + /* Get the array dimensions */ + ret = H5Tget_array_dims2(mtid, rdims1); + CHECK(ret, FAIL, "H5Tget_array_dims2"); + + /* Check the array dimensions */ + for (i = 0; i < ndims; i++) + if (rdims1[i] != tdims1[i]) { + TestErrPrintf("Array dimension information doesn't match!, rdims1[%d]=%" PRIuHSIZE + ", tdims1[%d]=%" PRIuHSIZE "\n", + i, rdims1[i], i, tdims1[i]); + continue; + } /* end if */ + + /* Check the array's base datatype */ + tid2 = H5Tget_super(mtid); + CHECK(tid2, FAIL, "H5Tget_super"); + + if ((ret = H5Tequal(tid2, H5T_IEEE_F32LE)) <= 0) + TestErrPrintf("Compound data type is incorrect!, ret=%d\n", (int)ret); + ret = H5Tclose(tid2); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Tclose(mtid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Check the 3rd field's name */ + mname = H5Tget_member_name(tid1, 2); + CHECK_PTR(mname, "H5Tget_member_name"); + if (mname && HDstrcmp(mname, "l") != 0) + TestErrPrintf("Compound field name doesn't match!, mname=%s\n", mname); + if (mname) + H5free_memory(mname); + + /* Check the 3rd field's offset */ + off = H5Tget_member_offset(tid1, 2); + VERIFY(off, 20, "H5Tget_member_offset"); + + /* Check the 3rd field's datatype */ + mtid = H5Tget_member_type(tid1, 2); + CHECK(mtid, FAIL, "H5Tget_member_type"); + + /* Verify datatype class */ + mclass = H5Tget_class(mtid); + VERIFY(mclass, H5T_ARRAY, "H5Tget_class"); + + /* Check the array rank */ + ndims = H5Tget_array_ndims(mtid); + VERIFY(ndims, ARRAY1_RANK, "H5Tget_array_ndims"); + + /* Get the array dimensions */ + ret = H5Tget_array_dims2(mtid, rdims1); + CHECK(ret, FAIL, "H5Tget_array_dims2"); + + /* Check the array dimensions */ + for (i = 0; i < ndims; i++) + if (rdims1[i] != tdims1[i]) { + TestErrPrintf("Array dimension information doesn't match!, rdims1[%d]=%" PRIuHSIZE + ", tdims1[%d]=%" PRIuHSIZE "\n", + i, rdims1[i], i, tdims1[i]); + continue; + } /* end if */ + + /* Check the array's base datatype */ + tid2 = H5Tget_super(mtid); + CHECK(tid2, FAIL, "H5Tget_super"); + + if ((ret = H5Tequal(tid2, H5T_STD_I32LE)) <= 0) + TestErrPrintf("Compound data type is incorrect!, ret=%d\n", (int)ret); + ret = H5Tclose(tid2); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Tclose(mtid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Check the 4th field's name */ + mname = H5Tget_member_name(tid1, 3); + CHECK_PTR(mname, "H5Tget_member_name"); + if (mname && HDstrcmp(mname, "d") != 0) + TestErrPrintf("Compound field name doesn't match!, mname=%s\n", mname); + if (mname) + H5free_memory(mname); + + /* Check the 4th field's offset */ + off = H5Tget_member_offset(tid1, 3); + VERIFY(off, 36, "H5Tget_member_offset"); + + /* Check the 4th field's datatype */ + mtid = H5Tget_member_type(tid1, 3); + CHECK(mtid, FAIL, "H5Tget_member_type"); + if ((ret = H5Tequal(mtid, H5T_IEEE_F64LE)) <= 0) + TestErrPrintf("Compound data type is incorrect!, ret=%d\n", (int)ret); + ret = H5Tclose(mtid); + CHECK(mtid, FAIL, "H5Tclose"); + + /* Close the datatype */ + ret = H5Tclose(tid1); + CHECK_I(ret, "H5Tclose"); + + /* Close the dataset */ + ret = H5Dclose(dataset); + CHECK_I(ret, "H5Dclose"); + + /* Close the file */ + ret = H5Fclose(fid1); + CHECK_I(ret, "H5Fclose"); + } /* end if */ + else + HDprintf("***cannot open the pre-created compound datatype test file (%s)\n", testfile); + +} /* end test_compat() */ +#endif + +/*------------------------------------------------------------------------- + * Function: test_array + * + * Purpose: Main array datatype testing routine. + * + * Return: void + * + *------------------------------------------------------------------------- + */ +void +test_array(void) +{ + /* Output message about test being performed */ + MESSAGE(5, ("Testing Array Datatypes\n")); + + /* These tests use the same file... */ + test_array_atomic_1d(); /* Test 1-D array of atomic datatypes */ + test_array_atomic_3d(); /* Test 3-D array of atomic datatypes */ + test_array_array_atomic(); /* Test 1-D array of 2-D arrays of atomic datatypes */ + test_array_compound_atomic(); /* Test 1-D array of compound datatypes (with no array fields) */ + test_array_compound_array(); /* Test 1-D array of compound datatypes (with array fields) */ + test_array_vlen_atomic(); /* Test 1-D array of atomic VL datatypes */ + test_array_vlen_array(); /* Test 1-D array of 1-D array VL datatypes */ + test_array_funcs(); /* Test type functions with array types */ + + test_array_bkg(); /* Read compound datatype with array fields and background fields read */ +#if 0 + /* This test uses a custom file */ + test_compat(); /* Test compatibility changes for compound datatype fields */ +#endif +} /* end test_array() */ + +/*------------------------------------------------------------------------- + * Function: cleanup_array + * + * Purpose: Cleanup temporary test files + * + * Return: void + * + * Programmer: Quincey Koziol + * June 8, 1999 + * + *------------------------------------------------------------------------- + */ +void +cleanup_array(void) +{ + H5Fdelete(FILENAME, H5P_DEFAULT); +} /* end cleanup_array() */ diff --git a/test/API/tattr.c b/test/API/tattr.c new file mode 100644 index 0000000..d006eb8 --- /dev/null +++ b/test/API/tattr.c @@ -0,0 +1,11929 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*********************************************************** + * + * Test program: tattr + * + * Test the attribute functionality + * + *************************************************************/ + +#include "testhdf5.h" + +#if 0 +#include "H5VLnative_private.h" + +/* + * This file needs to access private information from the H5O package. + * This file also needs to access the object header testing code. + */ +#define H5O_FRIEND /*suppress error about including H5Opkg */ +#define H5O_TESTING +#include "H5Opkg.h" /* Object headers */ + +/* + * This file needs to access private information from the H5A package. + * This file also needs to access the attribute testing code. + */ +#define H5A_FRIEND /*suppress error about including H5Apkg */ +#define H5A_TESTING +#include "H5Apkg.h" /* Attributes */ + +/* + * This file needs to access private information from the H5F package. + * This file also needs to access the file testing code. + */ +#define H5F_FRIEND /*suppress error about including H5Fpkg */ +#define H5F_TESTING +#include "H5Fpkg.h" /* File access */ +#endif + +#define FILENAME "tattr.h5" +#define NAME_BUF_SIZE 1024 +#define ATTR_NAME_LEN 16 +#define ATTR_MAX_DIMS 7 +#define ATTR_TMP_NAME "a really long temp_name" +#define CORDER_ITER_STOP 3 + +/* 3-D dataset with fixed dimensions */ +#define SPACE1_RANK 3 +#define SPACE1_DIM1 3 +#define SPACE1_DIM2 15 +#define SPACE1_DIM3 13 + +/* Dataset Information */ +#define DSET1_NAME "Dataset1" +#define DSET2_NAME "Dataset2" +#define DSET3_NAME "Dataset3" +#define NUM_DSETS 3 + +/* Group Information */ +#define GROUP1_NAME "/Group1" +#define GROUP2_NAME "/Group2" +#define GROUP3_NAME "/Group3" + +/* Named Datatype Information */ +#define TYPE1_NAME "/Type" + +/* Attribute Rank & Dimensions */ +#define ATTR1_NAME "Attr1" +#define ATTR1_RANK 1 +#define ATTR1_DIM1 3 +int attr_data1[ATTR1_DIM1] = {512, -234, 98123}; /* Test data for 1st attribute */ + +/* rank & dimensions for another attribute */ +#define ATTR1A_NAME "Attr1_a" +int attr_data1a[ATTR1_DIM1] = {256, 11945, -22107}; + +#define ATTR2_NAME "Attr2" +#define ATTR2_RANK 2 +#define ATTR2_DIM1 2 +#define ATTR2_DIM2 2 +int attr_data2[ATTR2_DIM1][ATTR2_DIM2] = {{7614, -416}, {197814, -3}}; /* Test data for 2nd attribute */ + +#define ATTR3_NAME "Attr3" +#define ATTR3_RANK 3 +#define ATTR3_DIM1 2 +#define ATTR3_DIM2 2 +#define ATTR3_DIM3 2 +double attr_data3[ATTR3_DIM1][ATTR3_DIM2][ATTR3_DIM3] = { + {{2.3, -26.1}, {0.123, -10.0}}, {{973.23, -0.91827}, {2.0, 23.0}}}; /* Test data for 3rd attribute */ + +#define ATTR4_NAME "Attr4" +#define ATTR4_RANK 2 +#define ATTR4_DIM1 2 +#define ATTR4_DIM2 2 +#define ATTR4_FIELDNAME1 "i" +#define ATTR4_FIELDNAME2 "d" +#define ATTR4_FIELDNAME3 "c" +size_t attr4_field1_off = 0; +size_t attr4_field2_off = 0; +size_t attr4_field3_off = 0; +struct attr4_struct { + int i; + double d; + char c; +} attr_data4[ATTR4_DIM1][ATTR4_DIM2] = { + {{3, -26.1, 'd'}, {-100000, 0.123, '3'}}, + {{-23, 981724.2, 'Q'}, {0, 2.0, '\n'}}}; /* Test data for 4th attribute */ + +#define ATTR5_NAME "Attr5" +#define ATTR5_RANK 0 +float attr_data5 = -5.123F; /* Test data for 5th attribute */ + +#define ATTR6_RANK 3 +#define ATTR6_DIM1 100 +#define ATTR6_DIM2 100 +#define ATTR6_DIM3 100 + +#define ATTR7_NAME "attr 1 - 000000" +#define ATTR8_NAME "attr 2" + +#define LINK1_NAME "Link1" + +#define NATTR_MANY_OLD 350 +#define NATTR_MANY_NEW 3500 + +#define BUG2_NATTR 100 +#define BUG2_NATTR2 16 + +#define BUG3_DSET_NAME "dset" +#define BUG3_DT_NAME "dt" +#define BUG3_ATTR_NAME "attr" + +/* Used by test_attr_delete_last_dense() */ +#define GRPNAME "grp" +#define ATTRNAME "attr" +#define DIM0 100 +#define DIM1 100 +#define RANK 2 + +/* Used by test_attr_info_null_info_pointer() */ +#define GET_INFO_NULL_POINTER_ATTR_NAME "NullInfoPointerAttr" + +/* Used by test_attr_rename_invalid_name() */ +#define INVALID_RENAME_TEST_ATTR_NAME "InvalidRenameTestAttr" +#define INVALID_RENAME_TEST_NEW_ATTR_NAME "InvalidRenameTestNewAttr" + +/* Used by test_attr_get_name_invalid_buf() */ +#define GET_NAME_INVALID_BUF_TEST_ATTR_NAME "InvalidNameBufferTestAttr" + +/* Attribute iteration struct */ +typedef struct { + H5_iter_order_t order; /* Direction of iteration */ + unsigned ncalled; /* # of times callback is entered */ + unsigned nskipped; /* # of attributes skipped */ + int stop; /* # of iterations to stop after */ + hsize_t curr; /* Current creation order value */ + size_t max_visit; /* Size of "visited attribute" flag array */ + hbool_t *visited; /* Pointer to array of "visited attribute" flags */ +} attr_iter_info_t; + +static herr_t attr_op1(hid_t loc_id, const char *name, const H5A_info_t *ainfo, void *op_data); + +/* Global dcpl ID, can be re-set as a generated dcpl for various operations + * across multiple tests. + * e.g., minimized dataset object headers + */ +static hid_t dcpl_g = H5P_DEFAULT; + +/**************************************************************** +** +** test_attr_basic_write(): Test basic H5A (attribute) code. +** Tests integer attributes on both datasets and groups +** +****************************************************************/ +static void +test_attr_basic_write(hid_t fapl) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t group; /* Group ID */ + hid_t sid1, sid2; /* Dataspace ID */ + hid_t attr, attr2; /* Attribute ID */ +#if 0 + hsize_t attr_size; /* storage size for attribute */ +#endif + ssize_t attr_name_size; /* size of attribute name */ + char *attr_name = NULL; /* name of attribute */ + hsize_t dims1[] = {SPACE1_DIM1, SPACE1_DIM2, SPACE1_DIM3}; + hsize_t dims2[] = {ATTR1_DIM1}; + hsize_t dims3[] = {ATTR2_DIM1, ATTR2_DIM2}; + int read_data1[ATTR1_DIM1] = {0}; /* Buffer for reading 1st attribute */ + int i; +#ifndef NO_PREVENT_CREATE_SAME_ATTRIBUTE_TWICE + hid_t ret_id; /* Generic hid_t return value */ +#endif + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Basic Scalar Attribute Writing Functions\n")); + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, DSET1_NAME, H5T_NATIVE_UCHAR, sid1, H5P_DEFAULT, dcpl_g, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Create dataspace for attribute */ + sid2 = H5Screate_simple(ATTR1_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Try to create an attribute on the file (should create an attribute on root group) */ + attr = H5Acreate2(fid1, ATTR1_NAME, H5T_NATIVE_INT, sid2, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Open the root group */ + group = H5Gopen2(fid1, "/", H5P_DEFAULT); + CHECK(group, FAIL, "H5Gopen2"); + + /* Open attribute again */ + attr = H5Aopen(group, ATTR1_NAME, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close root group */ + ret = H5Gclose(group); + CHECK(ret, FAIL, "H5Gclose"); + + /* Create an attribute for the dataset */ + attr = H5Acreate2(dataset, ATTR1_NAME, H5T_NATIVE_INT, sid2, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); +#ifndef NO_PREVENT_CREATE_SAME_ATTRIBUTE_TWICE + /* Try to create the same attribute again (should fail) */ + H5E_BEGIN_TRY + { + ret_id = H5Acreate2(dataset, ATTR1_NAME, H5T_NATIVE_INT, sid2, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret_id, FAIL, "H5Acreate2"); +#endif + /* Write attribute information */ + ret = H5Awrite(attr, H5T_NATIVE_INT, attr_data1); + CHECK(ret, FAIL, "H5Awrite"); + + /* Create an another attribute for the dataset */ + attr2 = H5Acreate2(dataset, ATTR1A_NAME, H5T_NATIVE_INT, sid2, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Write attribute information */ + ret = H5Awrite(attr2, H5T_NATIVE_INT, attr_data1a); + CHECK(ret, FAIL, "H5Awrite"); +#if 0 + /* Check storage size for attribute */ + attr_size = H5Aget_storage_size(attr); + VERIFY(attr_size, (ATTR1_DIM1 * sizeof(int)), "H5A_get_storage_size"); +#endif + /* Read attribute information immediately, without closing attribute */ + ret = H5Aread(attr, H5T_NATIVE_INT, read_data1); + CHECK(ret, FAIL, "H5Aread"); + + /* Verify values read in */ + for (i = 0; i < ATTR1_DIM1; i++) + if (attr_data1[i] != read_data1[i]) + TestErrPrintf("%d: attribute data different: attr_data1[%d]=%d, read_data1[%d]=%d\n", __LINE__, i, + attr_data1[i], i, read_data1[i]); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close attribute */ + ret = H5Aclose(attr2); + CHECK(ret, FAIL, "H5Aclose"); + + /* change attribute name */ + ret = H5Arename(dataset, ATTR1_NAME, ATTR_TMP_NAME); + CHECK(ret, FAIL, "H5Arename"); + + /* Open attribute again */ + attr = H5Aopen(dataset, ATTR_TMP_NAME, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); + + /* Verify new attribute name */ + attr_name_size = H5Aget_name(attr, (size_t)0, NULL); + CHECK(attr_name_size, FAIL, "H5Aget_name"); + + if (attr_name_size > 0) { + attr_name = (char *)HDcalloc((size_t)(attr_name_size + 1), sizeof(char)); + CHECK_PTR(attr_name, "HDcalloc"); + + if (attr_name) { + ret = (herr_t)H5Aget_name(attr, (size_t)(attr_name_size + 1), attr_name); + CHECK(ret, FAIL, "H5Aget_name"); + ret = HDstrcmp(attr_name, ATTR_TMP_NAME); + VERIFY(ret, 0, "HDstrcmp"); + + HDfree(attr_name); + attr_name = NULL; + } /* end if */ + } /* end if */ + + /* Read attribute information immediately, without closing attribute */ + ret = H5Aread(attr, H5T_NATIVE_INT, read_data1); + CHECK(ret, FAIL, "H5Aread"); + + /* Verify values read in */ + for (i = 0; i < ATTR1_DIM1; i++) + if (attr_data1[i] != read_data1[i]) + TestErrPrintf("%d: attribute data different: attr_data1[%d]=%d, read_data1[%d]=%d\n", __LINE__, i, + attr_data1[i], i, read_data1[i]); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Open the second attribute again */ + attr2 = H5Aopen(dataset, ATTR1A_NAME, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); + + /* Verify new attribute name */ + attr_name_size = H5Aget_name(attr2, (size_t)0, NULL); + CHECK(attr_name_size, FAIL, "H5Aget_name"); + + if (attr_name_size > 0) { + attr_name = (char *)HDcalloc((size_t)(attr_name_size + 1), sizeof(char)); + CHECK_PTR(attr_name, "HDcalloc"); + + if (attr_name) { + ret = (herr_t)H5Aget_name(attr2, (size_t)(attr_name_size + 1), attr_name); + CHECK(ret, FAIL, "H5Aget_name"); + ret = HDstrcmp(attr_name, ATTR1A_NAME); + VERIFY(ret, 0, "HDstrcmp"); + + HDfree(attr_name); + attr_name = NULL; + } /* end if */ + } /* end if */ + + /* Read attribute information immediately, without closing attribute */ + ret = H5Aread(attr2, H5T_NATIVE_INT, read_data1); + CHECK(ret, FAIL, "H5Aread"); + + /* Verify values read in */ + for (i = 0; i < ATTR1_DIM1; i++) + if (attr_data1a[i] != read_data1[i]) + TestErrPrintf("%d: attribute data different: attr_data1a[%d]=%d, read_data1[%d]=%d\n", __LINE__, + i, attr_data1a[i], i, read_data1[i]); + + /* Close attribute */ + ret = H5Aclose(attr2); + CHECK(ret, FAIL, "H5Aclose"); + + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Create group */ + group = H5Gcreate2(fid1, GROUP1_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(group, FAIL, "H5Gcreate2"); + + /* Create dataspace for attribute */ + sid2 = H5Screate_simple(ATTR2_RANK, dims3, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Create an attribute for the group */ + attr = H5Acreate2(group, ATTR2_NAME, H5T_NATIVE_INT, sid2, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); +#if 0 + /* Check storage size for attribute */ + attr_size = H5Aget_storage_size(attr); + VERIFY(attr_size, (ATTR2_DIM1 * ATTR2_DIM2 * sizeof(int)), "H5Aget_storage_size"); +#endif +#ifndef NO_PREVENT_CREATE_SAME_ATTRIBUTE_TWICE + /* Try to create the same attribute again (should fail) */ + H5E_BEGIN_TRY + { + ret_id = H5Acreate2(group, ATTR2_NAME, H5T_NATIVE_INT, sid2, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret_id, FAIL, "H5Acreate2"); +#endif + /* Write attribute information */ + ret = H5Awrite(attr, H5T_NATIVE_INT, attr_data2); + CHECK(ret, FAIL, "H5Awrite"); +#if 0 + /* Check storage size for attribute */ + attr_size = H5Aget_storage_size(attr); + VERIFY(attr_size, (ATTR2_DIM1 * ATTR2_DIM2 * sizeof(int)), "H5A_get_storage_size"); +#endif + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close Attribute dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Group */ + ret = H5Gclose(group); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_attr_basic_write() */ + +/**************************************************************** +** +** test_attr_basic_read(): Test basic H5A (attribute) code. +** +****************************************************************/ +static void +test_attr_basic_read(hid_t fapl) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t group; /* Group ID */ + hid_t attr; /* Attribute ID */ + H5O_info2_t oinfo; /* Object info */ + int read_data1[ATTR1_DIM1] = {0}; /* Buffer for reading 1st attribute */ + int read_data2[ATTR2_DIM1][ATTR2_DIM2] = {{0}}; /* Buffer for reading 2nd attribute */ + int i, j; /* Local index variables */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Basic Attribute Functions\n")); + + /* Create file */ + fid1 = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Open the dataset */ + dataset = H5Dopen2(fid1, DSET1_NAME, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Verify the correct number of attributes */ + ret = H5Oget_info3(dataset, &oinfo, H5O_INFO_NUM_ATTRS); + CHECK(ret, FAIL, "H5Oget_info3"); + VERIFY(oinfo.num_attrs, 2, "H5Oget_info3"); + + /* Open first attribute for the dataset */ + attr = H5Aopen(dataset, ATTR_TMP_NAME, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); + + /* Read attribute information */ + ret = H5Aread(attr, H5T_NATIVE_INT, read_data1); + CHECK(ret, FAIL, "H5Aread"); + + /* Verify values read in */ + for (i = 0; i < ATTR1_DIM1; i++) + if (attr_data1[i] != read_data1[i]) + TestErrPrintf("%d: attribute data different: attr_data1[%d]=%d, read_data1[%d]=%d\n", __LINE__, i, + attr_data1[i], i, read_data1[i]); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Open the group */ + group = H5Gopen2(fid1, GROUP1_NAME, H5P_DEFAULT); + CHECK(group, FAIL, "H5Gopen2"); + + /* Verify the correct number of attributes */ + ret = H5Oget_info3(group, &oinfo, H5O_INFO_NUM_ATTRS); + CHECK(ret, FAIL, "H5Oget_info3"); + VERIFY(oinfo.num_attrs, 1, "H5Oget_info3"); + + /* Open the attribute for the group */ + attr = H5Aopen(group, ATTR2_NAME, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); + + /* Read attribute information */ + ret = H5Aread(attr, H5T_NATIVE_INT, read_data2); + CHECK(ret, FAIL, "H5Aread"); + + /* Verify values read in */ + for (i = 0; i < ATTR2_DIM1; i++) + for (j = 0; j < ATTR2_DIM2; j++) + if (attr_data2[i][j] != read_data2[i][j]) + TestErrPrintf("%d: attribute data different: attr_data2[%d][%d]=%d, read_data2[%d][%d]=%d\n", + __LINE__, i, j, attr_data2[i][j], i, j, read_data1[i]); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close group */ + ret = H5Gclose(group); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_attr_basic_read() */ + +/**************************************************************** +** +** test_attr_flush(): Test H5A (attribute) code for performing +** I/O when H5Fflush is used. +** +****************************************************************/ +static void +test_attr_flush(hid_t fapl) +{ + hid_t fil, /* File ID */ + att, /* Attribute ID */ + spc, /* Dataspace ID */ + set; /* Dataset ID */ + double wdata = 3.14159; /* Data to write */ + double rdata; /* Data read in */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Attribute Flushing\n")); + + fil = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(fil, FAIL, "H5Fcreate"); + + spc = H5Screate(H5S_SCALAR); + CHECK(spc, FAIL, "H5Screate"); + + set = H5Dcreate2(fil, DSET1_NAME, H5T_NATIVE_DOUBLE, spc, H5P_DEFAULT, dcpl_g, H5P_DEFAULT); + CHECK(set, FAIL, "H5Dcreate2"); + + att = H5Acreate2(set, ATTR1_NAME, H5T_NATIVE_DOUBLE, spc, H5P_DEFAULT, H5P_DEFAULT); + CHECK(att, FAIL, "H5Acreate2"); +#ifndef NO_ATTR_FILL_VALUE_SUPPORT + ret = H5Aread(att, H5T_NATIVE_DOUBLE, &rdata); + CHECK(ret, FAIL, "H5Aread"); + + if (!H5_DBL_ABS_EQUAL(rdata, 0.0)) + TestErrPrintf("attribute value wrong: rdata=%f, should be %f\n", rdata, 0.0); + + ret = H5Fflush(fil, H5F_SCOPE_GLOBAL); + CHECK(ret, FAIL, "H5Fflush"); + + ret = H5Aread(att, H5T_NATIVE_DOUBLE, &rdata); + CHECK(ret, FAIL, "H5Awrite"); + + if (!H5_DBL_ABS_EQUAL(rdata, 0.0)) + TestErrPrintf("attribute value wrong: rdata=%f, should be %f\n", rdata, 0.0); +#else + HDprintf("** SKIPPED attribute pre-read temporarily until attribute fill values supported **\n"); +#endif + ret = H5Awrite(att, H5T_NATIVE_DOUBLE, &wdata); + CHECK(ret, FAIL, "H5Awrite"); + + ret = H5Aread(att, H5T_NATIVE_DOUBLE, &rdata); + CHECK(ret, FAIL, "H5Awrite"); + + if (!H5_DBL_ABS_EQUAL(rdata, wdata)) + TestErrPrintf("attribute value wrong: rdata=%f, should be %f\n", rdata, wdata); + + ret = H5Sclose(spc); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Aclose(att); + CHECK(ret, FAIL, "H5Aclose"); + ret = H5Dclose(set); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Fclose(fil); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_attr_flush() */ + +/**************************************************************** +** +** test_attr_plist(): Test Attribute Creation Property Lists +** +****************************************************************/ +static void +test_attr_plist(hid_t fapl) +{ + hid_t fid = H5I_INVALID_HID; /* File ID */ + hid_t did = H5I_INVALID_HID; /* Dataset ID */ + hid_t dsid = H5I_INVALID_HID; /* Dataspace ID (for dataset) */ + hid_t asid = H5I_INVALID_HID; /* Dataspace ID (for attribute) */ + hid_t aid = H5I_INVALID_HID; /* Attribute ID */ + hid_t acpl_id = H5I_INVALID_HID; /* Attribute creation property list ID */ + hid_t aapl_id = H5I_INVALID_HID; /* Attribute access property list ID */ + hsize_t dims1[] = {SPACE1_DIM1, SPACE1_DIM2, SPACE1_DIM3}; + hsize_t dims2[] = {ATTR1_DIM1}; + H5T_cset_t cset; /* Character set for attributes */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Attribute Property Lists\n")); + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(fid, H5I_INVALID_HID, "H5Fcreate"); + + /* Create dataspace for dataset */ + dsid = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(dsid, H5I_INVALID_HID, "H5Screate_simple"); + + /* Create a dataset */ + did = H5Dcreate2(fid, DSET1_NAME, H5T_NATIVE_UCHAR, dsid, H5P_DEFAULT, dcpl_g, H5P_DEFAULT); + CHECK(did, H5I_INVALID_HID, "H5Dcreate2"); + + /* Create dataspace for attribute */ + asid = H5Screate_simple(ATTR1_RANK, dims2, NULL); + CHECK(asid, H5I_INVALID_HID, "H5Screate_simple"); + + /* Create default creation property list for attribute */ + acpl_id = H5Pcreate(H5P_ATTRIBUTE_CREATE); + CHECK(acpl_id, H5I_INVALID_HID, "H5Pcreate"); + + /* Create default access property list for attribute + * This currently has no properties, but we need to test its creation + * and use. + */ + aapl_id = H5Pcreate(H5P_ATTRIBUTE_ACCESS); + CHECK(aapl_id, H5I_INVALID_HID, "H5Pcreate"); + + /* Get the character encoding and ensure that it is the default (ASCII) */ + ret = H5Pget_char_encoding(acpl_id, &cset); + CHECK(ret, FAIL, "H5Pget_char_encoding"); + VERIFY(cset, H5T_CSET_ASCII, "H5Pget_char_encoding"); + + /* Create an attribute for the dataset using the property list */ + aid = H5Acreate2(did, ATTR1_NAME, H5T_NATIVE_INT, asid, acpl_id, aapl_id); + CHECK(aid, H5I_INVALID_HID, "H5Acreate2"); + + /* Close the property list, and get the attribute's creation property list */ + ret = H5Pclose(acpl_id); + CHECK(ret, FAIL, "H5Pclose"); + acpl_id = H5Aget_create_plist(aid); + CHECK(acpl_id, H5I_INVALID_HID, "H5Aget_create_plist"); + + /* Get the character encoding and ensure that it is the default (ASCII) */ + ret = H5Pget_char_encoding(acpl_id, &cset); + CHECK(ret, FAIL, "H5Pget_char_encoding"); + VERIFY(cset, H5T_CSET_ASCII, "H5Pget_char_encoding"); + + /* Close the property list and attribute */ + ret = H5Pclose(acpl_id); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + + /* Create a new property list and modify it to use a different encoding */ + acpl_id = H5Pcreate(H5P_ATTRIBUTE_CREATE); + CHECK(acpl_id, H5I_INVALID_HID, "H5Pcreate"); + ret = H5Pset_char_encoding(acpl_id, H5T_CSET_UTF8); + CHECK(ret, FAIL, "H5Pset_char_encoding"); + + /* Get the character encoding and ensure that it has been changed */ + ret = H5Pget_char_encoding(acpl_id, &cset); + CHECK(ret, FAIL, "H5Pget_char_encoding"); + VERIFY(cset, H5T_CSET_UTF8, "H5Pget_char_encoding"); + + /* Create an attribute for the dataset using the modified property list */ + aid = H5Acreate2(did, ATTR2_NAME, H5T_NATIVE_INT, asid, acpl_id, aapl_id); + CHECK(aid, H5I_INVALID_HID, "H5Acreate2"); + + /* Close the property list and attribute */ + ret = H5Pclose(acpl_id); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + + /* Re-open the second attribute and ensure that its character encoding is correct */ + aid = H5Aopen(did, ATTR2_NAME, H5P_DEFAULT); + CHECK(aid, H5I_INVALID_HID, "H5Aopen"); + acpl_id = H5Aget_create_plist(aid); + CHECK(acpl_id, H5I_INVALID_HID, "H5Aget_create_plist"); + ret = H5Pget_char_encoding(acpl_id, &cset); + CHECK(ret, FAIL, "H5Pget_char_encoding"); + VERIFY(cset, H5T_CSET_UTF8, "H5Pget_char_encoding"); + + /* Close everything */ + ret = H5Sclose(dsid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(asid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Pclose(aapl_id); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(acpl_id); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_attr_plist() */ + +/**************************************************************** +** +** test_attr_compound_write(): Test H5A (attribute) code. +** Tests compound datatype attributes +** +****************************************************************/ +static void +test_attr_compound_write(hid_t fapl) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t tid1; /* Attribute datatype ID */ + hid_t sid1, sid2; /* Dataspace ID */ + hid_t attr; /* Attribute ID */ + hsize_t dims1[] = {SPACE1_DIM1, SPACE1_DIM2, SPACE1_DIM3}; + hsize_t dims2[] = {ATTR4_DIM1, ATTR4_DIM2}; +#ifndef NO_PREVENT_CREATE_SAME_ATTRIBUTE_TWICE + hid_t ret_id; /* Generic hid_t return value */ +#endif + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Multiple Attribute Functions\n")); + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, DSET1_NAME, H5T_NATIVE_UCHAR, sid1, H5P_DEFAULT, dcpl_g, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Close dataset's dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Create the attribute datatype. */ + tid1 = H5Tcreate(H5T_COMPOUND, sizeof(struct attr4_struct)); + CHECK(tid1, FAIL, "H5Tcreate"); + attr4_field1_off = HOFFSET(struct attr4_struct, i); + ret = H5Tinsert(tid1, ATTR4_FIELDNAME1, attr4_field1_off, H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + attr4_field2_off = HOFFSET(struct attr4_struct, d); + ret = H5Tinsert(tid1, ATTR4_FIELDNAME2, attr4_field2_off, H5T_NATIVE_DOUBLE); + CHECK(ret, FAIL, "H5Tinsert"); + attr4_field3_off = HOFFSET(struct attr4_struct, c); + ret = H5Tinsert(tid1, ATTR4_FIELDNAME3, attr4_field3_off, H5T_NATIVE_SCHAR); + CHECK(ret, FAIL, "H5Tinsert"); + + /* Create dataspace for 1st attribute */ + sid2 = H5Screate_simple(ATTR4_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Create complex attribute for the dataset */ + attr = H5Acreate2(dataset, ATTR4_NAME, tid1, sid2, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); +#ifndef NO_PREVENT_CREATE_SAME_ATTRIBUTE_TWICE + /* Try to create the same attribute again (should fail) */ + H5E_BEGIN_TRY + { + ret_id = H5Acreate2(dataset, ATTR4_NAME, tid1, sid2, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret_id, FAIL, "H5Acreate2"); +#endif + /* Write complex attribute data */ + ret = H5Awrite(attr, tid1, attr_data4); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close attribute's dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close attribute's datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_attr_compound_write() */ + +/**************************************************************** +** +** test_attr_compound_read(): Test basic H5A (attribute) code. +** +****************************************************************/ +static void +test_attr_compound_read(hid_t fapl) +{ + hid_t fid1; /* HDF5 File ID */ + hid_t dataset; /* Dataset ID */ + hid_t space; /* Attribute dataspace */ + hid_t type; /* Attribute datatype */ + hid_t attr; /* Attribute ID */ + char attr_name[ATTR_NAME_LEN]; /* Buffer for attribute names */ + int rank; /* Attribute rank */ + hsize_t dims[ATTR_MAX_DIMS]; /* Attribute dimensions */ + H5T_class_t t_class; /* Attribute datatype class */ + H5T_order_t order; /* Attribute datatype order */ + size_t size; /* Attribute datatype size as stored in file */ + int fields; /* # of Attribute datatype fields */ + char *fieldname; /* Name of a field */ + size_t offset; /* Attribute datatype field offset */ + hid_t field; /* Attribute field datatype */ + struct attr4_struct read_data4[ATTR4_DIM1][ATTR4_DIM2]; /* Buffer for reading 4th attribute */ + ssize_t name_len; /* Length of attribute name */ + H5O_info2_t oinfo; /* Object info */ + int i, j; /* Local index variables */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Basic Attribute Functions\n")); + + /* Open file */ + fid1 = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Open the dataset */ + dataset = H5Dopen2(fid1, DSET1_NAME, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Verify the correct number of attributes */ + ret = H5Oget_info3(dataset, &oinfo, H5O_INFO_NUM_ATTRS); + CHECK(ret, FAIL, "H5Oget_info3"); + VERIFY(oinfo.num_attrs, 1, "H5Oget_info3"); + + /* Open 1st attribute for the dataset */ + attr = + H5Aopen_by_idx(dataset, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, (hsize_t)0, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen_by_idx"); + + /* Verify Dataspace */ + space = H5Aget_space(attr); + CHECK(space, FAIL, "H5Aget_space"); + rank = H5Sget_simple_extent_ndims(space); + VERIFY(rank, ATTR4_RANK, "H5Sget_simple_extent_ndims"); + ret = H5Sget_simple_extent_dims(space, dims, NULL); + CHECK(ret, FAIL, "H5Sget_simple_extent_dims"); + if (dims[0] != ATTR4_DIM1) + TestErrPrintf("attribute dimensions different: dims[0]=%d, should be %d\n", (int)dims[0], ATTR4_DIM1); + if (dims[1] != ATTR4_DIM2) + TestErrPrintf("attribute dimensions different: dims[1]=%d, should be %d\n", (int)dims[1], ATTR4_DIM2); + H5Sclose(space); + + /* Verify Datatype */ + type = H5Aget_type(attr); + CHECK(type, FAIL, "H5Aget_type"); + t_class = H5Tget_class(type); + VERIFY(t_class, H5T_COMPOUND, "H5Tget_class"); + fields = H5Tget_nmembers(type); + VERIFY(fields, 3, "H5Tget_nmembers"); + for (i = 0; i < fields; i++) { + fieldname = H5Tget_member_name(type, (unsigned)i); + if (!(HDstrcmp(fieldname, ATTR4_FIELDNAME1) != 0 || HDstrcmp(fieldname, ATTR4_FIELDNAME2) != 0 || + HDstrcmp(fieldname, ATTR4_FIELDNAME3) != 0)) + TestErrPrintf("invalid field name for field #%d: %s\n", i, fieldname); + H5free_memory(fieldname); + } /* end for */ + offset = H5Tget_member_offset(type, 0); + VERIFY(offset, attr4_field1_off, "H5Tget_member_offset"); + offset = H5Tget_member_offset(type, 1); + VERIFY(offset, attr4_field2_off, "H5Tget_member_offset"); + offset = H5Tget_member_offset(type, 2); + VERIFY(offset, attr4_field3_off, "H5Tget_member_offset"); + + /* Verify each field's type, class & size */ + field = H5Tget_member_type(type, 0); + CHECK(field, FAIL, "H5Tget_member_type"); + t_class = H5Tget_class(field); + VERIFY(t_class, H5T_INTEGER, "H5Tget_class"); + order = H5Tget_order(field); + VERIFY_TYPE(order, H5Tget_order(H5T_NATIVE_INT), H5T_order_t, "%d", "H5Tget_order"); + size = H5Tget_size(field); + VERIFY(size, H5Tget_size(H5T_NATIVE_INT), "H5Tget_size"); + H5Tclose(field); + field = H5Tget_member_type(type, 1); + CHECK(field, FAIL, "H5Tget_member_type"); + t_class = H5Tget_class(field); + VERIFY(t_class, H5T_FLOAT, "H5Tget_class"); + order = H5Tget_order(field); + VERIFY_TYPE(order, H5Tget_order(H5T_NATIVE_DOUBLE), H5T_order_t, "%d", "H5Tget_order"); + size = H5Tget_size(field); + VERIFY(size, H5Tget_size(H5T_NATIVE_DOUBLE), "H5Tget_size"); + H5Tclose(field); + field = H5Tget_member_type(type, 2); + CHECK(field, FAIL, "H5Tget_member_type"); + t_class = H5Tget_class(field); + VERIFY(t_class, H5T_INTEGER, "H5Tget_class"); + order = H5Tget_order(field); + VERIFY_TYPE(order, H5Tget_order(H5T_NATIVE_SCHAR), H5T_order_t, "%d", "H5Tget_order"); + size = H5Tget_size(field); + VERIFY(size, H5Tget_size(H5T_NATIVE_SCHAR), "H5Tget_size"); + H5Tclose(field); + + /* Read attribute information */ + ret = H5Aread(attr, type, read_data4); + CHECK(ret, FAIL, "H5Aread"); + + /* Verify values read in */ + for (i = 0; i < ATTR4_DIM1; i++) + for (j = 0; j < ATTR4_DIM2; j++) + if (HDmemcmp(&attr_data4[i][j], &read_data4[i][j], sizeof(struct attr4_struct)) != 0) { + HDprintf("%d: attribute data different: attr_data4[%d][%d].i=%d, read_data4[%d][%d].i=%d\n", + __LINE__, i, j, attr_data4[i][j].i, i, j, read_data4[i][j].i); + HDprintf("%d: attribute data different: attr_data4[%d][%d].d=%f, read_data4[%d][%d].d=%f\n", + __LINE__, i, j, attr_data4[i][j].d, i, j, read_data4[i][j].d); + TestErrPrintf( + "%d: attribute data different: attr_data4[%d][%d].c=%c, read_data4[%d][%d].c=%c\n", + __LINE__, i, j, attr_data4[i][j].c, i, j, read_data4[i][j].c); + } /* end if */ + + /* Verify Name */ + name_len = H5Aget_name(attr, (size_t)ATTR_NAME_LEN, attr_name); + VERIFY(name_len, HDstrlen(ATTR4_NAME), "H5Aget_name"); + if (HDstrcmp(attr_name, ATTR4_NAME) != 0) + TestErrPrintf("attribute name different: attr_name=%s, should be %s\n", attr_name, ATTR4_NAME); + + /* Close attribute datatype */ + ret = H5Tclose(type); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_attr_compound_read() */ + +/**************************************************************** +** +** test_attr_scalar_write(): Test scalar H5A (attribute) writing code. +** +****************************************************************/ +static void +test_attr_scalar_write(hid_t fapl) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1, sid2; /* Dataspace ID */ + hid_t attr; /* Attribute ID */ + hsize_t dims1[] = {SPACE1_DIM1, SPACE1_DIM2, SPACE1_DIM3}; +#ifndef NO_PREVENT_CREATE_SAME_ATTRIBUTE_TWICE + hid_t ret_id; /* Generic hid_t return value */ +#endif + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Basic Attribute Functions\n")); + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, DSET1_NAME, H5T_NATIVE_UCHAR, sid1, H5P_DEFAULT, dcpl_g, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Create dataspace for attribute */ + sid2 = H5Screate_simple(ATTR5_RANK, NULL, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Create an attribute for the dataset */ + attr = H5Acreate2(dataset, ATTR5_NAME, H5T_NATIVE_FLOAT, sid2, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); +#ifndef NO_PREVENT_CREATE_SAME_ATTRIBUTE_TWICE + /* Try to create the same attribute again (should fail) */ + H5E_BEGIN_TRY + { + ret_id = H5Acreate2(dataset, ATTR5_NAME, H5T_NATIVE_FLOAT, sid2, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret_id, FAIL, "H5Acreate2"); +#endif + /* Write attribute information */ + ret = H5Awrite(attr, H5T_NATIVE_FLOAT, &attr_data5); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_attr_scalar_write() */ + +/**************************************************************** +** +** test_attr_scalar_read(): Test scalar H5A (attribute) reading code. +** +****************************************************************/ +static void +test_attr_scalar_read(hid_t fapl) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t attr; /* Attribute ID */ + H5S_class_t stype; /* Dataspace class */ + float rdata = 0.0F; /* Buffer for reading 1st attribute */ + H5O_info2_t oinfo; /* Object info */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Basic Scalar Attribute Reading Functions\n")); + + /* Create file */ + fid1 = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Open the dataset */ + dataset = H5Dopen2(fid1, DSET1_NAME, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Verify the correct number of attributes */ + ret = H5Oget_info3(dataset, &oinfo, H5O_INFO_NUM_ATTRS); + CHECK(ret, FAIL, "H5Oget_info3"); + VERIFY(oinfo.num_attrs, 1, "H5Oget_info3"); + + /* Open an attribute for the dataset */ + attr = H5Aopen(dataset, ATTR5_NAME, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); + + /* Read attribute information */ + ret = H5Aread(attr, H5T_NATIVE_FLOAT, &rdata); + CHECK(ret, FAIL, "H5Aread"); + + /* Verify the floating-poing value in this way to avoid compiler warning. */ + if (!H5_FLT_ABS_EQUAL(rdata, attr_data5)) + HDprintf("*** UNEXPECTED VALUE from %s should be %f, but is %f at line %4d in %s\n", "H5Aread", + (double)attr_data5, (double)rdata, (int)__LINE__, __FILE__); + + /* Get the attribute's dataspace */ + sid = H5Aget_space(attr); + CHECK(sid, FAIL, "H5Aget_space"); + + /* Make certain the dataspace is scalar */ + stype = H5Sget_simple_extent_type(sid); + VERIFY(stype, H5S_SCALAR, "H5Sget_simple_extent_type"); + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_attr_scalar_read() */ + +/**************************************************************** +** +** test_attr_mult_write(): Test basic H5A (attribute) code. +** Tests integer attributes on both datasets and groups +** +****************************************************************/ +static void +test_attr_mult_write(hid_t fapl) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1, sid2; /* Dataspace ID */ + hid_t attr; /* Attribute ID */ + hsize_t dims1[] = {SPACE1_DIM1, SPACE1_DIM2, SPACE1_DIM3}; + hsize_t dims2[] = {ATTR1_DIM1}; + hsize_t dims3[] = {ATTR2_DIM1, ATTR2_DIM2}; + hsize_t dims4[] = {ATTR3_DIM1, ATTR3_DIM2, ATTR3_DIM3}; +#ifndef NO_PREVENT_CREATE_SAME_ATTRIBUTE_TWICE + hid_t ret_id; /* Generic hid_t return value */ +#endif + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Multiple Attribute Functions\n")); + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, DSET1_NAME, H5T_NATIVE_UCHAR, sid1, H5P_DEFAULT, dcpl_g, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Close dataset's dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Create dataspace for 1st attribute */ + sid2 = H5Screate_simple(ATTR1_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Create 1st attribute for the dataset */ + attr = H5Acreate2(dataset, ATTR1_NAME, H5T_NATIVE_INT, sid2, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); +#ifndef NO_PREVENT_CREATE_SAME_ATTRIBUTE_TWICE + /* Try to create the same attribute again (should fail) */ + H5E_BEGIN_TRY + { + ret_id = H5Acreate2(dataset, ATTR1_NAME, H5T_NATIVE_INT, sid2, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret_id, FAIL, "H5Acreate2"); +#endif + /* Write 1st attribute data */ + ret = H5Awrite(attr, H5T_NATIVE_INT, attr_data1); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close 1st attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close attribute's dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Create dataspace for 2nd attribute */ + sid2 = H5Screate_simple(ATTR2_RANK, dims3, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Create 2nd attribute for the dataset */ + attr = H5Acreate2(dataset, ATTR2_NAME, H5T_NATIVE_INT, sid2, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); +#ifndef NO_PREVENT_CREATE_SAME_ATTRIBUTE_TWICE + /* Try to create the same attribute again (should fail) */ + H5E_BEGIN_TRY + { + ret_id = H5Acreate2(dataset, ATTR2_NAME, H5T_NATIVE_INT, sid2, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret_id, FAIL, "H5Acreate2"); +#endif + /* Write 2nd attribute information */ + ret = H5Awrite(attr, H5T_NATIVE_INT, attr_data2); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close 2nd attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close 2nd attribute's dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Create dataspace for 3rd attribute */ + sid2 = H5Screate_simple(ATTR3_RANK, dims4, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Create 3rd attribute for the dataset */ + attr = H5Acreate2(dataset, ATTR3_NAME, H5T_NATIVE_DOUBLE, sid2, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); +#ifndef NO_PREVENT_CREATE_SAME_ATTRIBUTE_TWICE + /* Try to create the same attribute again (should fail) */ + H5E_BEGIN_TRY + { + ret_id = H5Acreate2(dataset, ATTR3_NAME, H5T_NATIVE_DOUBLE, sid2, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret_id, FAIL, "H5Acreate2"); +#endif + /* Write 3rd attribute information */ + ret = H5Awrite(attr, H5T_NATIVE_DOUBLE, attr_data3); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close 3rd attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close 3rd attribute's dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_attr_mult_write() */ + +/**************************************************************** +** +** test_attr_mult_read(): Test basic H5A (attribute) code. +** +****************************************************************/ +static void +test_attr_mult_read(hid_t fapl) +{ + hid_t fid1; /* HDF5 File ID */ + hid_t dataset; /* Dataset ID */ + hid_t space; /* Attribute dataspace */ + hid_t type; /* Attribute datatype */ + hid_t attr; /* Attribute ID */ + char attr_name[ATTR_NAME_LEN]; /* Buffer for attribute names */ + char temp_name[ATTR_NAME_LEN]; /* Buffer for mangling attribute names */ + int rank; /* Attribute rank */ + hsize_t dims[ATTR_MAX_DIMS]; /* Attribute dimensions */ + H5T_class_t t_class; /* Attribute datatype class */ + H5T_order_t order; /* Attribute datatype order */ + size_t size; /* Attribute datatype size as stored in file */ + int read_data1[ATTR1_DIM1] = {0}; /* Buffer for reading 1st attribute */ + int read_data2[ATTR2_DIM1][ATTR2_DIM2] = {{0}}; /* Buffer for reading 2nd attribute */ + double read_data3[ATTR3_DIM1][ATTR3_DIM2][ATTR3_DIM3] = {{{0}}}; /* Buffer for reading 3rd attribute */ + ssize_t name_len; /* Length of attribute name */ + H5O_info2_t oinfo; /* Object info */ + int i, j, k; /* Local index values */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Basic Attribute Functions\n")); + + /* Open file */ + fid1 = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Open the dataset */ + dataset = H5Dopen2(fid1, DSET1_NAME, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Verify the correct number of attributes */ + ret = H5Oget_info3(dataset, &oinfo, H5O_INFO_NUM_ATTRS); + CHECK(ret, FAIL, "H5Oget_info3"); + VERIFY(oinfo.num_attrs, 3, "H5Oget_info3"); + + /* Open 1st attribute for the dataset */ + attr = + H5Aopen_by_idx(dataset, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, (hsize_t)0, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen_by_idx"); + + /* Verify Dataspace */ + space = H5Aget_space(attr); + CHECK(space, FAIL, "H5Aget_space"); + rank = H5Sget_simple_extent_ndims(space); + VERIFY(rank, ATTR1_RANK, "H5Sget_simple_extent_ndims"); + ret = H5Sget_simple_extent_dims(space, dims, NULL); + CHECK(ret, FAIL, "H5Sget_simple_extent_dims"); + if (dims[0] != ATTR1_DIM1) + TestErrPrintf("attribute dimensions different: dims[0]=%d, should be %d\n", (int)dims[0], ATTR1_DIM1); + H5Sclose(space); + + /* Verify Datatype */ + type = H5Aget_type(attr); + CHECK(type, FAIL, "H5Aget_type"); + t_class = H5Tget_class(type); + VERIFY(t_class, H5T_INTEGER, "H5Tget_class"); + order = H5Tget_order(type); + VERIFY_TYPE(order, H5Tget_order(H5T_NATIVE_INT), H5T_order_t, "%d", "H5Tget_order"); + size = H5Tget_size(type); + VERIFY(size, H5Tget_size(H5T_NATIVE_INT), "H5Tget_size"); + H5Tclose(type); + + /* Read attribute information */ + ret = H5Aread(attr, H5T_NATIVE_INT, read_data1); + CHECK(ret, FAIL, "H5Aread"); + + /* Verify values read in */ + for (i = 0; i < ATTR1_DIM1; i++) + if (attr_data1[i] != read_data1[i]) + TestErrPrintf("%d: attribute data different: attr_data1[%d]=%d, read_data1[%d]=%d\n", __LINE__, i, + attr_data1[i], i, read_data1[i]); + + /* Verify Name */ + name_len = H5Aget_name(attr, (size_t)ATTR_NAME_LEN, attr_name); + VERIFY(name_len, HDstrlen(ATTR1_NAME), "H5Aget_name"); + if (HDstrcmp(attr_name, ATTR1_NAME) != 0) + TestErrPrintf("attribute name different: attr_name=%s, should be %s\n", attr_name, ATTR1_NAME); + + /* Verify Name with too small of a buffer */ + name_len = H5Aget_name(attr, HDstrlen(ATTR1_NAME), attr_name); + VERIFY(name_len, HDstrlen(ATTR1_NAME), "H5Aget_name"); + HDstrcpy(temp_name, ATTR1_NAME); /* make a copy of the name */ + temp_name[HDstrlen(ATTR1_NAME) - 1] = '\0'; /* truncate it to match the one retrieved */ + if (HDstrcmp(attr_name, temp_name) != 0) + TestErrPrintf("attribute name different: attr_name=%s, should be %s\n", attr_name, temp_name); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Open 2nd attribute for the dataset */ + attr = + H5Aopen_by_idx(dataset, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, (hsize_t)1, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen_by_idx"); + + /* Verify Dataspace */ + space = H5Aget_space(attr); + CHECK(space, FAIL, "H5Aget_space"); + rank = H5Sget_simple_extent_ndims(space); + VERIFY(rank, ATTR2_RANK, "H5Sget_simple_extent_ndims"); + ret = H5Sget_simple_extent_dims(space, dims, NULL); + CHECK(ret, FAIL, "H5Sget_simple_extent_dims"); + if (dims[0] != ATTR2_DIM1) + TestErrPrintf("attribute dimensions different: dims[0]=%d, should be %d\n", (int)dims[0], ATTR2_DIM1); + if (dims[1] != ATTR2_DIM2) + TestErrPrintf("attribute dimensions different: dims[1]=%d, should be %d\n", (int)dims[1], ATTR2_DIM2); + H5Sclose(space); + + /* Verify Datatype */ + type = H5Aget_type(attr); + CHECK(type, FAIL, "H5Aget_type"); + t_class = H5Tget_class(type); + VERIFY(t_class, H5T_INTEGER, "H5Tget_class"); + order = H5Tget_order(type); + VERIFY_TYPE(order, H5Tget_order(H5T_NATIVE_INT), H5T_order_t, "%d", "H5Tget_order"); + size = H5Tget_size(type); + VERIFY(size, H5Tget_size(H5T_NATIVE_INT), "H5Tget_size"); + H5Tclose(type); + + /* Read attribute information */ + ret = H5Aread(attr, H5T_NATIVE_INT, read_data2); + CHECK(ret, FAIL, "H5Aread"); + + /* Verify values read in */ + for (i = 0; i < ATTR2_DIM1; i++) + for (j = 0; j < ATTR2_DIM2; j++) + if (attr_data2[i][j] != read_data2[i][j]) + TestErrPrintf("%d: attribute data different: attr_data2[%d][%d]=%d, read_data2[%d][%d]=%d\n", + __LINE__, i, j, attr_data2[i][j], i, j, read_data2[i][j]); + + /* Verify Name */ + name_len = H5Aget_name(attr, (size_t)ATTR_NAME_LEN, attr_name); + VERIFY(name_len, HDstrlen(ATTR2_NAME), "H5Aget_name"); + if (HDstrcmp(attr_name, ATTR2_NAME) != 0) + TestErrPrintf("attribute name different: attr_name=%s, should be %s\n", attr_name, ATTR2_NAME); + + /* Verify Name with too small of a buffer */ + name_len = H5Aget_name(attr, HDstrlen(ATTR2_NAME), attr_name); + VERIFY(name_len, HDstrlen(ATTR2_NAME), "H5Aget_name"); + HDstrcpy(temp_name, ATTR2_NAME); /* make a copy of the name */ + temp_name[HDstrlen(ATTR2_NAME) - 1] = '\0'; /* truncate it to match the one retrieved */ + if (HDstrcmp(attr_name, temp_name) != 0) + TestErrPrintf("attribute name different: attr_name=%s, should be %s\n", attr_name, temp_name); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Open 2nd attribute for the dataset */ + attr = + H5Aopen_by_idx(dataset, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, (hsize_t)2, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen_by_idx"); + + /* Verify Dataspace */ + space = H5Aget_space(attr); + CHECK(space, FAIL, "H5Aget_space"); + rank = H5Sget_simple_extent_ndims(space); + VERIFY(rank, ATTR3_RANK, "H5Sget_simple_extent_ndims"); + ret = H5Sget_simple_extent_dims(space, dims, NULL); + CHECK(ret, FAIL, "H5Sget_simple_extent_dims"); + if (dims[0] != ATTR3_DIM1) + TestErrPrintf("attribute dimensions different: dims[0]=%d, should be %d\n", (int)dims[0], ATTR3_DIM1); + if (dims[1] != ATTR3_DIM2) + TestErrPrintf("attribute dimensions different: dims[1]=%d, should be %d\n", (int)dims[1], ATTR3_DIM2); + if (dims[2] != ATTR3_DIM3) + TestErrPrintf("attribute dimensions different: dims[2]=%d, should be %d\n", (int)dims[2], ATTR3_DIM3); + H5Sclose(space); + + /* Verify Datatype */ + type = H5Aget_type(attr); + CHECK(type, FAIL, "H5Aget_type"); + t_class = H5Tget_class(type); + VERIFY(t_class, H5T_FLOAT, "H5Tget_class"); + order = H5Tget_order(type); + VERIFY_TYPE(order, H5Tget_order(H5T_NATIVE_DOUBLE), H5T_order_t, "%d", "H5Tget_order"); + size = H5Tget_size(type); + VERIFY(size, H5Tget_size(H5T_NATIVE_DOUBLE), "H5Tget_size"); + H5Tclose(type); + + /* Read attribute information */ + ret = H5Aread(attr, H5T_NATIVE_DOUBLE, read_data3); + CHECK(ret, FAIL, "H5Aread"); + + /* Verify values read in */ + for (i = 0; i < ATTR3_DIM1; i++) + for (j = 0; j < ATTR3_DIM2; j++) + for (k = 0; k < ATTR3_DIM3; k++) + if (!H5_DBL_ABS_EQUAL(attr_data3[i][j][k], read_data3[i][j][k])) + TestErrPrintf("%d: attribute data different: attr_data3[%d][%d][%d]=%f, " + "read_data3[%d][%d][%d]=%f\n", + __LINE__, i, j, k, attr_data3[i][j][k], i, j, k, read_data3[i][j][k]); + + /* Verify Name */ + name_len = H5Aget_name(attr, (size_t)ATTR_NAME_LEN, attr_name); + VERIFY(name_len, HDstrlen(ATTR3_NAME), "H5Aget_name"); + if (HDstrcmp(attr_name, ATTR3_NAME) != 0) + TestErrPrintf("attribute name different: attr_name=%s, should be %s\n", attr_name, ATTR3_NAME); + + /* Verify Name with too small of a buffer */ + name_len = H5Aget_name(attr, HDstrlen(ATTR3_NAME), attr_name); + VERIFY(name_len, HDstrlen(ATTR3_NAME), "H5Aget_name"); + HDstrcpy(temp_name, ATTR3_NAME); /* make a copy of the name */ + temp_name[HDstrlen(ATTR3_NAME) - 1] = '\0'; /* truncate it to match the one retrieved */ + if (HDstrcmp(attr_name, temp_name) != 0) + TestErrPrintf("attribute name different: attr_name=%s, should be %s\n", attr_name, temp_name); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_attr_mult_read() */ + +/**************************************************************** +** +** attr_op1(): Attribute operator +** +****************************************************************/ +static herr_t +attr_op1(hid_t H5_ATTR_UNUSED loc_id, const char *name, const H5A_info_t H5_ATTR_UNUSED *ainfo, void *op_data) +{ + int *count = (int *)op_data; + herr_t ret = 0; + + switch (*count) { + case 0: + if (HDstrcmp(name, ATTR1_NAME) != 0) + TestErrPrintf("attribute name different: name=%s, should be %s\n", name, ATTR1_NAME); + (*count)++; + break; + + case 1: + if (HDstrcmp(name, ATTR2_NAME) != 0) + TestErrPrintf("attribute name different: name=%s, should be %s\n", name, ATTR2_NAME); + (*count)++; + break; + + case 2: + if (HDstrcmp(name, ATTR3_NAME) != 0) + TestErrPrintf("attribute name different: name=%s, should be %s\n", name, ATTR3_NAME); + (*count)++; + break; + + default: + ret = -1; + break; + } /* end switch() */ + + return (ret); +} /* end attr_op1() */ + +/**************************************************************** +** +** test_attr_iterate(): Test H5A (attribute) iterator code. +** +****************************************************************/ +static void +test_attr_iterate(hid_t fapl) +{ + hid_t file; /* HDF5 File ID */ + hid_t dataset; /* Dataset ID */ + hid_t sid; /* Dataspace ID */ + int count; /* operator data for the iterator */ + H5O_info2_t oinfo; /* Object info */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Basic Attribute Functions\n")); + + /* Open file */ + file = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(file, FAIL, "H5Fopen"); + + /* Create a dataspace */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create a new dataset */ + dataset = H5Dcreate2(file, DSET2_NAME, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl_g, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Verify the correct number of attributes */ + ret = H5Oget_info3(dataset, &oinfo, H5O_INFO_NUM_ATTRS); + CHECK(ret, FAIL, "H5Oget_info3"); + VERIFY(oinfo.num_attrs, 0, "H5Oget_info3"); + + /* Iterate over attributes on dataset */ + count = 0; + ret = H5Aiterate2(dataset, H5_INDEX_NAME, H5_ITER_INC, NULL, attr_op1, &count); + VERIFY(ret, 0, "H5Aiterate2"); + + /* Close dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Open existing dataset w/attributes */ + dataset = H5Dopen2(file, DSET1_NAME, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Verify the correct number of attributes */ + ret = H5Oget_info3(dataset, &oinfo, H5O_INFO_NUM_ATTRS); + CHECK(ret, FAIL, "H5Oget_info3"); + VERIFY(oinfo.num_attrs, 3, "H5Oget_info3"); + + /* Iterate over attributes on dataset */ + count = 0; + ret = H5Aiterate2(dataset, H5_INDEX_NAME, H5_ITER_INC, NULL, attr_op1, &count); + VERIFY(ret, 0, "H5Aiterate2"); + + /* Close dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_attr_iterate() */ + +/**************************************************************** +** +** test_attr_delete(): Test H5A (attribute) code for deleting objects. +** +****************************************************************/ +static void +test_attr_delete(hid_t fapl) +{ + hid_t fid1; /* HDF5 File ID */ + hid_t dataset; /* Dataset ID */ + hid_t attr; /* Attribute ID */ + char attr_name[ATTR_NAME_LEN]; /* Buffer for attribute names */ + ssize_t name_len; /* Length of attribute name */ + H5O_info2_t oinfo; /* Object info */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Basic Attribute Deletion Functions\n")); + + /* Open file */ + fid1 = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Open the dataset */ + dataset = H5Dopen2(fid1, DSET1_NAME, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Verify the correct number of attributes */ + ret = H5Oget_info3(dataset, &oinfo, H5O_INFO_NUM_ATTRS); + CHECK(ret, FAIL, "H5Oget_info3"); + VERIFY(oinfo.num_attrs, 3, "H5Oget_info3"); +#ifndef NO_DELETE_NONEXISTENT_ATTRIBUTE + /* Try to delete bogus attribute */ + H5E_BEGIN_TRY + { + ret = H5Adelete(dataset, "Bogus"); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Adelete"); +#endif + /* Verify the correct number of attributes */ + ret = H5Oget_info3(dataset, &oinfo, H5O_INFO_NUM_ATTRS); + CHECK(ret, FAIL, "H5Oget_info3"); + VERIFY(oinfo.num_attrs, 3, "H5Oget_info3"); + + /* Delete middle (2nd) attribute */ + ret = H5Adelete(dataset, ATTR2_NAME); + CHECK(ret, FAIL, "H5Adelete"); + + /* Verify the correct number of attributes */ + ret = H5Oget_info3(dataset, &oinfo, H5O_INFO_NUM_ATTRS); + CHECK(ret, FAIL, "H5Oget_info3"); + VERIFY(oinfo.num_attrs, 2, "H5Oget_info3"); + + /* Open 1st attribute for the dataset */ + attr = + H5Aopen_by_idx(dataset, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, (hsize_t)0, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen_by_idx"); + + /* Verify Name */ + name_len = H5Aget_name(attr, (size_t)ATTR_NAME_LEN, attr_name); + VERIFY(name_len, HDstrlen(ATTR1_NAME), "H5Aget_name"); + if (HDstrcmp(attr_name, ATTR1_NAME) != 0) + TestErrPrintf("attribute name different: attr_name=%s, should be %s\n", attr_name, ATTR1_NAME); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Open last (formally 3rd) attribute for the dataset */ + attr = + H5Aopen_by_idx(dataset, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, (hsize_t)1, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen_by_idx"); + + /* Verify Name */ + name_len = H5Aget_name(attr, (size_t)ATTR_NAME_LEN, attr_name); + VERIFY(name_len, HDstrlen(ATTR3_NAME), "H5Aget_name"); + if (HDstrcmp(attr_name, ATTR3_NAME) != 0) + TestErrPrintf("attribute name different: attr_name=%s, should be %s\n", attr_name, ATTR3_NAME); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Delete first attribute */ + ret = H5Adelete(dataset, ATTR1_NAME); + CHECK(ret, FAIL, "H5Adelete"); + + /* Verify the correct number of attributes */ + ret = H5Oget_info3(dataset, &oinfo, H5O_INFO_NUM_ATTRS); + CHECK(ret, FAIL, "H5Oget_info3"); + VERIFY(oinfo.num_attrs, 1, "H5Oget_info3"); + + /* Open last (formally 3rd) attribute for the dataset */ + attr = + H5Aopen_by_idx(dataset, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, (hsize_t)0, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen_by_idx"); + + /* Verify Name */ + name_len = H5Aget_name(attr, (size_t)ATTR_NAME_LEN, attr_name); + VERIFY(name_len, HDstrlen(ATTR3_NAME), "H5Aget_name"); + if (HDstrcmp(attr_name, ATTR3_NAME) != 0) + TestErrPrintf("attribute name different: attr_name=%s, should be %s\n", attr_name, ATTR3_NAME); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Delete first attribute */ + ret = H5Adelete(dataset, ATTR3_NAME); + CHECK(ret, FAIL, "H5Adelete"); + + /* Verify the correct number of attributes */ + ret = H5Oget_info3(dataset, &oinfo, H5O_INFO_NUM_ATTRS); + CHECK(ret, FAIL, "H5Oget_info3"); + VERIFY(oinfo.num_attrs, 0, "H5Oget_info3"); + + /* Close dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_attr_delete() */ + +/**************************************************************** +** +** test_attr_dtype_shared(): Test H5A (attribute) code for using +** shared datatypes in attributes. +** +****************************************************************/ +static void +test_attr_dtype_shared(hid_t fapl) +{ +#ifndef NO_SHARED_DATATYPES + hid_t file_id; /* File ID */ + hid_t dset_id; /* Dataset ID */ + hid_t space_id; /* Dataspace ID for dataset & attribute */ + hid_t type_id; /* Datatype ID for named datatype */ + hid_t attr_id; /* Attribute ID */ + int data = 8; /* Data to write */ + int rdata = 0; /* Read read in */ + H5O_info2_t oinfo; /* Object's information */ +#if 0 + h5_stat_size_t empty_filesize; /* Size of empty file */ + h5_stat_size_t filesize; /* Size of file after modifications */ +#endif + herr_t ret; /* Generic return value */ +#else + (void)fapl; +#endif + /* Output message about test being performed */ + MESSAGE(5, ("Testing Shared Datatypes with Attributes - SKIPPED for now due to no support for shared " + "datatypes\n")); +#ifndef NO_SHARED_DATATYPES + /* Create a file */ + file_id = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(file_id, FAIL, "H5Fopen"); + + /* Close file */ + ret = H5Fclose(file_id); + CHECK(ret, FAIL, "H5Fclose"); +#if 0 + /* Get size of file */ + empty_filesize = h5_get_file_size(FILENAME, fapl); + if (empty_filesize < 0) + TestErrPrintf("Line %d: file size wrong!\n", __LINE__); +#endif + + /* Re-open file */ + file_id = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(file_id, FAIL, "H5Fopen"); + + /* Create a datatype to commit and use */ + type_id = H5Tcopy(H5T_NATIVE_INT); + CHECK(type_id, FAIL, "H5Tcopy"); + + /* Commit datatype to file */ + ret = H5Tcommit2(file_id, TYPE1_NAME, type_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + + /* Check reference count on named datatype */ + ret = H5Oget_info_by_name3(file_id, TYPE1_NAME, &oinfo, H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name3"); + VERIFY(oinfo.rc, 1, "H5Oget_info_by_name3"); + + /* Create dataspace for dataset */ + space_id = H5Screate(H5S_SCALAR); + CHECK(space_id, FAIL, "H5Screate"); + + /* Create dataset */ + dset_id = H5Dcreate2(file_id, DSET1_NAME, type_id, space_id, H5P_DEFAULT, dcpl_g, H5P_DEFAULT); + CHECK(dset_id, FAIL, "H5Dcreate2"); + + /* Check reference count on named datatype */ + ret = H5Oget_info_by_name3(file_id, TYPE1_NAME, &oinfo, H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name3"); + VERIFY(oinfo.rc, 2, "H5Oget_info_by_name3"); + + /* Create attribute on dataset */ + attr_id = H5Acreate2(dset_id, ATTR1_NAME, type_id, space_id, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr_id, FAIL, "H5Acreate2"); + + /* Check reference count on named datatype */ + ret = H5Oget_info_by_name3(file_id, TYPE1_NAME, &oinfo, H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name3"); + VERIFY(oinfo.rc, 3, "H5Oget_info_by_name3"); + + /* Close attribute */ + ret = H5Aclose(attr_id); + CHECK(ret, FAIL, "H5Aclose"); + + /* Delete attribute */ + ret = H5Adelete(dset_id, ATTR1_NAME); + CHECK(ret, FAIL, "H5Adelete"); + + /* Check reference count on named datatype */ + ret = H5Oget_info_by_name3(file_id, TYPE1_NAME, &oinfo, H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name3"); + VERIFY(oinfo.rc, 2, "H5Oget_info_by_name3"); + + /* Create attribute on dataset */ + attr_id = H5Acreate2(dset_id, ATTR1_NAME, type_id, space_id, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr_id, FAIL, "H5Acreate2"); + + /* Check reference count on named datatype */ + ret = H5Oget_info_by_name3(file_id, TYPE1_NAME, &oinfo, H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name3"); + VERIFY(oinfo.rc, 3, "H5Oget_info_by_name3"); + + /* Write data into the attribute */ + ret = H5Awrite(attr_id, H5T_NATIVE_INT, &data); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr_id); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close dataset */ + ret = H5Dclose(dset_id); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close dataspace */ + ret = H5Sclose(space_id); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close datatype */ + ret = H5Tclose(type_id); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close file */ + ret = H5Fclose(file_id); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open file */ + file_id = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(file_id, FAIL, "H5Fopen"); + + /* Open dataset */ + dset_id = H5Dopen2(file_id, DSET1_NAME, H5P_DEFAULT); + CHECK(dset_id, FAIL, "H5Dopen2"); + + /* Open attribute */ + attr_id = H5Aopen(dset_id, ATTR1_NAME, H5P_DEFAULT); + CHECK(attr_id, FAIL, "H5Aopen"); + + /* Read data from the attribute */ + ret = H5Aread(attr_id, H5T_NATIVE_INT, &rdata); + CHECK(ret, FAIL, "H5Aread"); + VERIFY(data, rdata, "H5Aread"); + + /* Close attribute */ + ret = H5Aclose(attr_id); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close dataset */ + ret = H5Dclose(dset_id); + CHECK(ret, FAIL, "H5Dclose"); + + /* Check reference count on named datatype */ + ret = H5Oget_info_by_name3(file_id, TYPE1_NAME, &oinfo, H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name3"); + VERIFY(oinfo.rc, 3, "H5Oget_info_by_name3"); + + /* Unlink the dataset */ + ret = H5Ldelete(file_id, DSET1_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + + /* Check reference count on named datatype */ + ret = H5Oget_info_by_name3(file_id, TYPE1_NAME, &oinfo, H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name3"); + VERIFY(oinfo.rc, 1, "H5Oget_info_by_name3"); + + /* Unlink the named datatype */ + ret = H5Ldelete(file_id, TYPE1_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + + /* Close file */ + ret = H5Fclose(file_id); + CHECK(ret, FAIL, "H5Fclose"); +#if 0 + /* Check size of file */ + filesize = h5_get_file_size(FILENAME, fapl); + VERIFY(filesize, empty_filesize, "h5_get_file_size"); +#endif +#endif +} /* test_attr_dtype_shared() */ + +/**************************************************************** +** +** test_attr_duplicate_ids(): Test operations with more than +** one ID handles. +** +****************************************************************/ +static void +test_attr_duplicate_ids(hid_t fapl) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t gid1, gid2; /* Group ID */ + hid_t sid1, sid2; /* Dataspace ID */ + hid_t attr, attr2; /* Attribute ID */ + hsize_t dims1[] = {SPACE1_DIM1, SPACE1_DIM2, SPACE1_DIM3}; + hsize_t dims2[] = {ATTR1_DIM1}; + int read_data1[ATTR1_DIM1] = {0}; /* Buffer for reading 1st attribute */ + int rewrite_data[ATTR1_DIM1] = {1234, -423, 9907256}; /* Test data for rewrite */ + int i; + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing operations with two ID handles\n")); + + /*----------------------------------------------------------------------------------- + * Create an attribute in a new file and fill it with fill value. + */ + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, DSET1_NAME, H5T_NATIVE_UCHAR, sid1, H5P_DEFAULT, dcpl_g, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Create dataspace for attribute */ + sid2 = H5Screate_simple(ATTR1_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Try to create an attribute on the dataset */ + attr = H5Acreate2(dataset, ATTR1_NAME, H5T_NATIVE_INT, sid2, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Open the attribute just created and get a second ID */ + attr2 = H5Aopen(dataset, ATTR1_NAME, H5P_DEFAULT); + CHECK(attr2, FAIL, "H5Aopen"); + + /* Close attribute */ + ret = H5Aclose(attr2); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /*----------------------------------------------------------------------------------- + * Reopen the file and verify the fill value for attribute. Also write + * some real data. + */ + + /* Open file */ + fid1 = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Open the dataset */ + dataset = H5Dopen2(fid1, DSET1_NAME, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Open first attribute for the dataset */ + attr = H5Aopen(dataset, ATTR1_NAME, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); + + /* Read attribute with fill value */ + ret = H5Aread(attr, H5T_NATIVE_INT, read_data1); + CHECK(ret, FAIL, "H5Aread"); + + /* Verify values read in */ + for (i = 0; i < ATTR1_DIM1; i++) + if (0 != read_data1[i]) + TestErrPrintf("%d: attribute data different: read_data1[%d]=%d\n", __LINE__, i, read_data1[i]); + + /* Open attribute for the second time */ + attr2 = H5Aopen(dataset, ATTR1_NAME, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); + + /* Write attribute information */ + ret = H5Awrite(attr2, H5T_NATIVE_INT, attr_data1); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr2); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /*----------------------------------------------------------------------------------- + * Reopen the file and verify the data. Also rewrite the data and verify it. + */ + + /* Open file */ + fid1 = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Open the dataset */ + dataset = H5Dopen2(fid1, DSET1_NAME, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Open first attribute for the dataset */ + attr = H5Aopen(dataset, ATTR1_NAME, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); + + /* Read attribute information */ + ret = H5Aread(attr, H5T_NATIVE_INT, read_data1); + CHECK(ret, FAIL, "H5Aread"); + + /* Verify values read in */ + for (i = 0; i < ATTR1_DIM1; i++) + if (attr_data1[i] != read_data1[i]) + TestErrPrintf("%d: attribute data different: attr_data1[%d]=%d, read_data1[%d]=%d\n", __LINE__, i, + attr_data1[i], i, read_data1[i]); + + /* Open attribute for the second time */ + attr2 = H5Aopen(dataset, ATTR1_NAME, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); + + /* Write attribute information */ + ret = H5Awrite(attr2, H5T_NATIVE_INT, rewrite_data); + CHECK(ret, FAIL, "H5Awrite"); + + /* Read attribute information */ + ret = H5Aread(attr, H5T_NATIVE_INT, read_data1); + CHECK(ret, FAIL, "H5Aread"); + + /* Verify values read in */ + for (i = 0; i < ATTR1_DIM1; i++) + if (read_data1[i] != rewrite_data[i]) + TestErrPrintf("%d: attribute data different: read_data1[%d]=%d, rewrite_data[%d]=%d\n", __LINE__, + i, read_data1[i], i, rewrite_data[i]); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + ret = H5Aclose(attr2); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /*----------------------------------------------------------------------------------- + * Verify that the attribute being pointed to by different paths shares + * the same data. + */ + /* Open file */ + fid1 = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Create a group */ + gid1 = H5Gcreate2(fid1, GROUP1_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid1, FAIL, "H5Gcreate2"); + + /* Create hard link to the first group */ + ret = H5Lcreate_hard(gid1, GROUP1_NAME, H5L_SAME_LOC, GROUP2_NAME, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lcreate_hard"); + + /* Try to create an attribute on the group */ + attr = H5Acreate2(gid1, ATTR2_NAME, H5T_NATIVE_INT, sid2, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Open the hard link just created */ + gid2 = H5Gopen2(fid1, GROUP2_NAME, H5P_DEFAULT); + CHECK(gid2, FAIL, "H5Gopen2"); + + /* Open the attribute of the group for the second time */ + attr2 = H5Aopen(gid2, ATTR2_NAME, H5P_DEFAULT); + CHECK(attr2, FAIL, "H5Aopen"); + + /* Write attribute information with the first attribute handle */ + ret = H5Awrite(attr, H5T_NATIVE_INT, attr_data1); + CHECK(ret, FAIL, "H5Awrite"); + + /* Read attribute information with the second attribute handle */ + ret = H5Aread(attr2, H5T_NATIVE_INT, read_data1); + CHECK(ret, FAIL, "H5Aread"); + + /* Verify values read in */ + for (i = 0; i < ATTR1_DIM1; i++) + if (attr_data1[i] != read_data1[i]) + TestErrPrintf("%d: attribute data different: attr_data1[%d]=%d, read_data1[%d]=%d\n", __LINE__, i, + attr_data1[i], i, read_data1[i]); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + ret = H5Aclose(attr2); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close group */ + ret = H5Gclose(gid1); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Gclose(gid2); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close Attribute dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_attr_duplicate_ids() */ + +/**************************************************************** +** +** test_attr_dense_verify(): Test basic H5A (attribute) code. +** Verify attributes on object +** +****************************************************************/ +static int +test_attr_dense_verify(hid_t loc_id, unsigned max_attr) +{ + char attrname[NAME_BUF_SIZE]; /* Name of attribute */ + hid_t attr; /* Attribute ID */ + unsigned value; /* Attribute value */ + unsigned u; /* Local index variable */ + int old_nerrs; /* Number of errors when entering this check */ + herr_t ret; /* Generic return value */ + + /* Retrieve the current # of reported errors */ + old_nerrs = nerrors; + + /* Re-open all the attributes by name and verify the data */ + for (u = 0; u < max_attr; u++) { + /* Open attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = H5Aopen(loc_id, attrname, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); + + /* Read data from the attribute */ + ret = H5Aread(attr, H5T_NATIVE_UINT, &value); + CHECK(ret, FAIL, "H5Aread"); + VERIFY(value, u, "H5Aread"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + } /* end for */ + + /* Re-open all the attributes by index and verify the data */ + for (u = 0; u < max_attr; u++) { + ssize_t name_len; /* Length of attribute name */ + char check_name[ATTR_NAME_LEN]; /* Buffer for checking attribute names */ + + /* Open attribute */ + attr = H5Aopen_by_idx(loc_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, (hsize_t)u, H5P_DEFAULT, + H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen_by_idx"); + + /* Verify Name */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + name_len = H5Aget_name(attr, (size_t)ATTR_NAME_LEN, check_name); + VERIFY(name_len, HDstrlen(attrname), "H5Aget_name"); + if (HDstrcmp(check_name, attrname) != 0) + TestErrPrintf("attribute name different: attrname = '%s', should be '%s'\n", check_name, + attrname); + + /* Read data from the attribute */ + ret = H5Aread(attr, H5T_NATIVE_UINT, &value); + CHECK(ret, FAIL, "H5Aread"); + VERIFY(value, u, "H5Aread"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + } /* end for */ + + /* Retrieve current # of errors */ + if (old_nerrs == nerrors) + return (0); + else + return (-1); +} /* test_attr_dense_verify() */ + +/**************************************************************** +** +** test_attr_dense_create(): Test basic H5A (attribute) code. +** Tests "dense" attribute storage creation +** +****************************************************************/ +static void +test_attr_dense_create(hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* HDF5 File ID */ + hid_t dataset; /* Dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t attr; /* Attribute ID */ + hid_t dcpl; /* Dataset creation property list ID */ + char attrname[NAME_BUF_SIZE]; /* Name of attribute */ + unsigned max_compact; /* Maximum # of attributes to store compactly */ + unsigned min_dense; /* Minimum # of attributes to store "densely" */ +#if 0 + htri_t is_dense; /* Are attributes stored densely? */ +#endif + unsigned u; /* Local index variable */ +#if 0 + h5_stat_size_t empty_filesize; /* Size of empty file */ + h5_stat_size_t filesize; /* Size of file after modifications */ +#endif + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Dense Attribute Storage Creation\n")); + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +#if 0 + /* Get size of file */ + empty_filesize = h5_get_file_size(FILENAME, fapl); + if (empty_filesize < 0) + TestErrPrintf("Line %d: file size wrong!\n", __LINE__); +#endif + /* Re-open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Create dataspace for dataset */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* need DCPL to query the group creation properties */ + if (dcpl_g == H5P_DEFAULT) { + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + } + else { + dcpl = H5Pcopy(dcpl_g); + CHECK(dcpl, FAIL, "H5Pcopy"); + } + + /* Create a dataset */ + dataset = H5Dcreate2(fid, DSET1_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Retrieve limits for compact/dense attribute storage */ + ret = H5Pget_attr_phase_change(dcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + + /* Close property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Add attributes, until just before converting to dense storage */ + for (u = 0; u < max_compact; u++) { + /* Create attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = H5Acreate2(dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + } /* end for */ +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Add one more attribute, to push into "dense" storage */ + /* Create attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = H5Acreate2(dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); +#endif + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); +#ifndef NO_PREVENT_CREATE_SAME_ATTRIBUTE_TWICE + /* Attempt to add attribute again, which should fail */ + H5E_BEGIN_TRY + { + attr = H5Acreate2(dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(attr, FAIL, "H5Acreate2"); +#endif + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Unlink dataset with attributes */ + ret = H5Ldelete(fid, DSET1_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +#if 0 + if (h5_using_default_driver(NULL)) { + /* Check size of file */ + filesize = h5_get_file_size(FILENAME, fapl); + VERIFY(filesize, empty_filesize, "h5_get_file_size"); + } +#endif +} /* test_attr_dense_create() */ + +/**************************************************************** +** +** test_attr_dense_open(): Test basic H5A (attribute) code. +** Tests opening attributes in "dense" storage +** +****************************************************************/ +static void +test_attr_dense_open(hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* HDF5 File ID */ + hid_t dataset; /* Dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t attr; /* Attribute ID */ + hid_t dcpl; /* Dataset creation property list ID */ + char attrname[NAME_BUF_SIZE]; /* Name of attribute */ + unsigned max_compact; /* Maximum # of attributes to store compactly */ + unsigned min_dense; /* Minimum # of attributes to store "densely" */ +#if 0 + htri_t is_dense; /* Are attributes stored densely? */ +#endif + unsigned u; /* Local index variable */ +#if 0 + h5_stat_size_t empty_filesize; /* Size of empty file */ + h5_stat_size_t filesize; /* Size of file after modifications */ +#endif + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Opening Attributes in Dense Storage\n")); + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +#if 0 + /* Get size of file */ + empty_filesize = h5_get_file_size(FILENAME, fapl); + if (empty_filesize < 0) + TestErrPrintf("Line %d: file size wrong!\n", __LINE__); +#endif + /* Re-open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Create dataspace for dataset */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* need DCPL to query the group creation properties */ + if (dcpl_g == H5P_DEFAULT) { + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + } + else { + dcpl = H5Pcopy(dcpl_g); + CHECK(dcpl, FAIL, "H5Pcopy"); + } + + /* Enable creation order tracking on attributes, so creation order tests work */ + ret = H5Pset_attr_creation_order(dcpl, H5P_CRT_ORDER_TRACKED); + CHECK(ret, FAIL, "H5Pset_attr_creation_order"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid, DSET1_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Retrieve limits for compact/dense attribute storage */ + ret = H5Pget_attr_phase_change(dcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + + /* Close property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Add attributes, until just before converting to dense storage */ + for (u = 0; u < max_compact; u++) { + /* Create attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = H5Acreate2(dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Verify attributes written so far */ + ret = test_attr_dense_verify(dataset, u); + CHECK(ret, FAIL, "test_attr_dense_verify"); + } /* end for */ +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Add one more attribute, to push into "dense" storage */ + /* Create attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = H5Acreate2(dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); +#endif + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Verify all the attributes written */ + ret = test_attr_dense_verify(dataset, (u + 1)); + CHECK(ret, FAIL, "test_attr_dense_verify"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Unlink dataset with attributes */ + ret = H5Ldelete(fid, DSET1_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +#if 0 + if (h5_using_default_driver(NULL)) { + /* Check size of file */ + filesize = h5_get_file_size(FILENAME, fapl); + VERIFY(filesize, empty_filesize, "h5_get_file_size"); + } +#endif +} /* test_attr_dense_open() */ + +/**************************************************************** +** +** test_attr_dense_delete(): Test basic H5A (attribute) code. +** Tests deleting attributes in "dense" storage +** +****************************************************************/ +static void +test_attr_dense_delete(hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* HDF5 File ID */ + hid_t dataset; /* Dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t attr; /* Attribute ID */ + hid_t dcpl; /* Dataset creation property list ID */ + char attrname[NAME_BUF_SIZE]; /* Name of attribute */ + unsigned max_compact; /* Maximum # of attributes to store compactly */ + unsigned min_dense; /* Minimum # of attributes to store "densely" */ +#if 0 + htri_t is_dense; /* Are attributes stored densely? */ +#endif + unsigned u; /* Local index variable */ +#if 0 + h5_stat_size_t empty_filesize; /* Size of empty file */ + h5_stat_size_t filesize; /* Size of file after modifications */ +#endif + H5O_info2_t oinfo; /* Object info */ + int use_min_dset_oh = (dcpl_g != H5P_DEFAULT); + herr_t ret; /* Generic return value */ + + /* Only run this test for sec2/default driver */ + if (!h5_using_default_driver(NULL)) + return; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Deleting Attributes in Dense Storage\n")); + + if (use_min_dset_oh) { /* using minimized dataset headers */ + /* modify fcpl... + * sidestep "bug" where file space is lost with minimized dset ohdrs + */ + fcpl = H5Pcopy(fcpl); + CHECK(fcpl, FAIL, "H5Pcopy"); + ret = H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_FSM_AGGR, TRUE, 1); + CHECK(ret, FAIL, "H5Pset_file_space_strategy"); + } + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + if (use_min_dset_oh) + CHECK(H5Pclose(fcpl), FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +#if 0 + /* Get size of file */ + empty_filesize = h5_get_file_size(FILENAME, fapl); + if (empty_filesize < 0) + TestErrPrintf("Line %d: file size wrong!\n", __LINE__); +#endif + /* Re-open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Create dataspace for dataset */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* need DCPL to query the group creation properties */ + if (use_min_dset_oh) { + dcpl = H5Pcopy(dcpl_g); + CHECK(dcpl, FAIL, "H5Pcopy"); + } + else { + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + } + + /* Enable creation order tracking on attributes, so creation order tests work */ + ret = H5Pset_attr_creation_order(dcpl, H5P_CRT_ORDER_TRACKED); + CHECK(ret, FAIL, "H5Pset_attr_creation_order"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid, DSET1_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Retrieve limits for compact/dense attribute storage */ + ret = H5Pget_attr_phase_change(dcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + + /* Close property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Add attributes, until well into dense storage */ + for (u = 0; u < (max_compact * 2); u++) { + /* Create attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = H5Acreate2(dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Check # of attributes */ + ret = H5Oget_info3(dataset, &oinfo, H5O_INFO_NUM_ATTRS); + CHECK(ret, FAIL, "H5Oget_info3"); + VERIFY(oinfo.num_attrs, (u + 1), "H5Oget_info3"); + } /* end for */ +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); +#endif + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Open dataset */ + dataset = H5Dopen2(fid, DSET1_NAME, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Delete attributes until the attributes revert to compact storage again */ + for (u--; u >= min_dense; u--) { + /* Delete attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + ret = H5Adelete(dataset, attrname); + CHECK(ret, FAIL, "H5Adelete"); + + /* Verify attributes still left */ + ret = test_attr_dense_verify(dataset, u); + CHECK(ret, FAIL, "test_attr_dense_verify"); + } /* end for */ +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); +#endif + /* Delete one more attribute, which should cause reversion to compact storage */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + ret = H5Adelete(dataset, attrname); + CHECK(ret, FAIL, "H5Adelete"); +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Verify attributes still left */ + ret = test_attr_dense_verify(dataset, (u - 1)); + CHECK(ret, FAIL, "test_attr_dense_verify"); + + /* Delete another attribute, to verify deletion in compact storage */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", (u - 1)); + ret = H5Adelete(dataset, attrname); + CHECK(ret, FAIL, "H5Adelete"); +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Verify attributes still left */ + ret = test_attr_dense_verify(dataset, (u - 2)); + CHECK(ret, FAIL, "test_attr_dense_verify"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Unlink dataset with attributes */ + ret = H5Ldelete(fid, DSET1_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +#if 0 + if (h5_using_default_driver(NULL)) { + /* Check size of file */ + filesize = h5_get_file_size(FILENAME, fapl); + VERIFY(filesize, empty_filesize, "h5_get_file_size"); + } +#endif +} /* test_attr_dense_delete() */ + +/**************************************************************** +** +** test_attr_dense_rename(): Test basic H5A (attribute) code. +** Tests renaming attributes in "dense" storage +** +****************************************************************/ +static void +test_attr_dense_rename(hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* HDF5 File ID */ + hid_t dataset; /* Dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t attr; /* Attribute ID */ + hid_t dcpl; /* Dataset creation property list ID */ + char attrname[NAME_BUF_SIZE]; /* Name of attribute */ + char new_attrname[NAME_BUF_SIZE]; /* New name of attribute */ + unsigned max_compact; /* Maximum # of attributes to store compactly */ + unsigned min_dense; /* Minimum # of attributes to store "densely" */ +#if 0 + htri_t is_dense; /* Are attributes stored densely? */ + h5_stat_size_t empty_filesize; /* Size of empty file */ + h5_stat_size_t filesize; /* Size of file after modifications */ +#endif + H5O_info2_t oinfo; /* Object info */ + unsigned u; /* Local index variable */ + int use_min_dset_oh = (dcpl_g != H5P_DEFAULT); + unsigned use_corder; /* Track creation order or not */ + herr_t ret; /* Generic return value */ + + /* Only run this test for sec2/default driver */ + if (!h5_using_default_driver(NULL)) + return; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Renaming Attributes in Dense Storage\n")); + + if (use_min_dset_oh) { /* using minimized dataset headers */ + /* modify fcpl... + * sidestep "bug" where file space is lost with minimized dset ohdrs + */ + fcpl = H5Pcopy(fcpl); + CHECK(fcpl, FAIL, "H5Pcopy"); + ret = H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_FSM_AGGR, TRUE, 1); + CHECK(ret, FAIL, "H5Pset_file_space_strategy"); + } + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, H5I_INVALID_HID, "H5Fcreate"); + if (use_min_dset_oh) + CHECK(H5Pclose(fcpl), FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +#if 0 + /* Get size of file */ + empty_filesize = h5_get_file_size(FILENAME, fapl); + if (empty_filesize < 0) + TestErrPrintf("Line %d: file size wrong!\n", __LINE__); +#endif + /* Re-open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, H5I_INVALID_HID, "H5Fopen"); + + /* Create dataspace for dataset */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, H5I_INVALID_HID, "H5Screate"); + + /* need DCPL to query the group creation properties */ + if (use_min_dset_oh) { + dcpl = H5Pcopy(dcpl_g); + CHECK(dcpl, H5I_INVALID_HID, "H5Pcopy"); + } + else { + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, H5I_INVALID_HID, "H5Pcreate"); + } + + /* Retrieve limits for compact/dense attribute storage */ + ret = H5Pget_attr_phase_change(dcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + + /* Using creation order or not */ + for (use_corder = FALSE; use_corder <= TRUE; use_corder++) { + + if (use_corder) { + ret = H5Pset_attr_creation_order(dcpl, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED); + CHECK(ret, FAIL, "H5Pset_attr_creation_order"); + } + + /* Create a dataset */ + dataset = H5Dcreate2(fid, DSET1_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dcreate2"); +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Add attributes, until well into dense storage */ + for (u = 0; u < (max_compact * 2); u++) { + /* Create attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = H5Acreate2(dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, H5I_INVALID_HID, "H5Acreate2"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Rename attribute */ + HDsnprintf(new_attrname, sizeof(new_attrname), "new attr %02u", u); + + /* Rename attribute */ + ret = H5Arename_by_name(fid, DSET1_NAME, attrname, new_attrname, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Arename_by_name"); + + /* Check # of attributes */ + ret = H5Oget_info3(dataset, &oinfo, H5O_INFO_NUM_ATTRS); + CHECK(ret, FAIL, "H5Oget_info3"); + VERIFY(oinfo.num_attrs, (u + 1), "H5Oget_info3"); + } /* end for */ +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); +#endif + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + if (!use_corder) { + /* Unlink dataset with attributes */ + ret = H5Ldelete(fid, DSET1_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + } + + } /* end for use_corder */ + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, H5I_INVALID_HID, "H5Fopen"); + + /* Open dataset */ + dataset = H5Dopen2(fid, DSET1_NAME, H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dopen2"); + + /* Verify renamed attributes */ + for (u = 0; u < (max_compact * 2); u++) { + unsigned value; /* Attribute value */ + + /* Open attribute */ + HDsnprintf(attrname, sizeof(attrname), "new attr %02u", u); + attr = H5Aopen(dataset, attrname, H5P_DEFAULT); + CHECK(attr, H5I_INVALID_HID, "H5Aopen"); + + /* Read data from the attribute */ + ret = H5Aread(attr, H5T_NATIVE_UINT, &value); + CHECK(ret, FAIL, "H5Aread"); + VERIFY(value, u, "H5Aread"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + } /* end for */ + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Unlink dataset with attributes */ + ret = H5Ldelete(fid, DSET1_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +#if 0 + if (h5_using_default_driver(NULL)) { + /* Check size of file */ + filesize = h5_get_file_size(FILENAME, fapl); + VERIFY(filesize, empty_filesize, "h5_get_file_size"); + } +#endif +} /* test_attr_dense_rename() */ + +/**************************************************************** +** +** test_attr_dense_unlink(): Test basic H5A (attribute) code. +** Tests unlinking object with attributes in "dense" storage +** +****************************************************************/ +static void +test_attr_dense_unlink(hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* HDF5 File ID */ + hid_t dataset; /* Dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t attr; /* Attribute ID */ + hid_t dcpl; /* Dataset creation property list ID */ + char attrname[NAME_BUF_SIZE]; /* Name of attribute */ + unsigned max_compact; /* Maximum # of attributes to store compactly */ + unsigned min_dense; /* Minimum # of attributes to store "densely" */ +#if 0 + htri_t is_dense; /* Are attributes stored densely? */ + size_t mesg_count; /* # of shared messages */ + h5_stat_size_t empty_filesize; /* Size of empty file */ + h5_stat_size_t filesize; /* Size of file after modifications */ +#endif + H5O_info2_t oinfo; /* Object info */ + unsigned u; /* Local index variable */ + int use_min_dset_oh = (dcpl_g != H5P_DEFAULT); + herr_t ret; /* Generic return value */ + + /* Only run this test for sec2/default driver */ + if (!h5_using_default_driver(NULL)) + return; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Unlinking Object with Attributes in Dense Storage\n")); + + if (use_min_dset_oh) { /* using minimized dataset headers */ + /* modify fcpl... + * sidestep "bug" where file space is lost with minimized dset ohdrs + */ + fcpl = H5Pcopy(fcpl); + CHECK(fcpl, FAIL, "H5Pcopy"); + ret = H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_FSM_AGGR, TRUE, 1); + CHECK(ret, FAIL, "H5Pset_file_space_strategy"); + } + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + if (use_min_dset_oh) + CHECK(H5Pclose(fcpl), FAIL, "H5Pclose"); + + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +#if 0 + empty_filesize = h5_get_file_size(FILENAME, fapl); + if (empty_filesize < 0) + TestErrPrintf("Line %d: file size wrong!\n", __LINE__); +#endif + /* Re-open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Create dataspace for dataset */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* need DCPL to query the group creation properties */ + if (use_min_dset_oh) { + dcpl = H5Pcopy(dcpl_g); + CHECK(dcpl, FAIL, "H5Pcopy"); + } + else { + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + } + + /* Create a dataset */ + dataset = H5Dcreate2(fid, DSET1_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Retrieve limits for compact/dense attribute storage */ + ret = H5Pget_attr_phase_change(dcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + + /* Close property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Add attributes, until well into dense storage */ + for (u = 0; u < (max_compact * 2); u++) { + /* Create attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = H5Acreate2(dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Check # of attributes */ + ret = H5Oget_info3(dataset, &oinfo, H5O_INFO_NUM_ATTRS); + CHECK(ret, FAIL, "H5Oget_info3"); + VERIFY(oinfo.num_attrs, (u + 1), "H5Oget_info3"); + } /* end for */ +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); +#endif + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Unlink dataset */ + ret = H5Ldelete(fid, DSET1_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); +#if 0 + /* Check on dataset's attribute storage status */ + ret = H5F__get_sohm_mesg_count_test(fid, H5O_ATTR_ID, &mesg_count); + CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); + VERIFY(mesg_count, 0, "H5F__get_sohm_mesg_count_test"); +#endif + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +#if 0 + if (h5_using_default_driver(NULL)) { + /* Check size of file */ + filesize = h5_get_file_size(FILENAME, fapl); + VERIFY(filesize, empty_filesize, "h5_get_file_size"); + } +#endif +} /* test_attr_dense_unlink() */ + +/**************************************************************** +** +** test_attr_dense_limits(): Test basic H5A (attribute) code. +** Tests attribute in "dense" storage limits +** +****************************************************************/ +static void +test_attr_dense_limits(hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* HDF5 File ID */ + hid_t dataset; /* Dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t attr; /* Attribute ID */ + hid_t dcpl; /* Dataset creation property list ID */ + char attrname[NAME_BUF_SIZE]; /* Name of attribute */ + unsigned max_compact, rmax_compact; /* Maximum # of attributes to store compactly */ + unsigned min_dense, rmin_dense; /* Minimum # of attributes to store "densely" */ +#if 0 + htri_t is_dense; /* Are attributes stored densely? */ +#endif + unsigned u; /* Local index variable */ +#if 0 + h5_stat_size_t empty_filesize; /* Size of empty file */ + h5_stat_size_t filesize; /* Size of file after modifications */ +#endif + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Phase Change Limits For Attributes in Dense Storage\n")); + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +#if 0 + /* Get size of file */ + empty_filesize = h5_get_file_size(FILENAME, fapl); + if (empty_filesize < 0) + TestErrPrintf("Line %d: file size wrong!\n", __LINE__); +#endif + /* Re-open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Create dataspace for dataset */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* need DCPL to query the group creation properties */ + if (dcpl_g == H5P_DEFAULT) { + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + } + else { + dcpl = H5Pcopy(dcpl_g); + CHECK(dcpl, FAIL, "H5Pcopy"); + } + + /* Change limits on compact/dense attribute storage */ + max_compact = 0; + min_dense = 0; + ret = H5Pset_attr_phase_change(dcpl, max_compact, min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid, DSET1_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Retrieve limits for compact/dense attribute storage */ + ret = H5Pget_attr_phase_change(dcpl, &rmax_compact, &rmin_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + VERIFY(rmax_compact, max_compact, "H5Pget_attr_phase_change"); + VERIFY(rmin_dense, min_dense, "H5Pget_attr_phase_change"); + + /* Close property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + + /* Add first attribute, which should be immediately in dense storage */ + + /* Create attribute */ + u = 0; + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = H5Acreate2(dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); +#endif + + /* Add second attribute, to allow deletions to be checked easily */ + + /* Create attribute */ + u = 1; + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = H5Acreate2(dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); +#endif + + /* Delete second attribute, attributes should still be stored densely */ + + /* Delete attribute */ + ret = H5Adelete(dataset, attrname); + CHECK(ret, FAIL, "H5Adelete"); +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); +#endif + + /* Delete first attribute, attributes should not be stored densely */ + + /* Delete attribute */ + u = 0; + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + ret = H5Adelete(dataset, attrname); + CHECK(ret, FAIL, "H5Adelete"); +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Unlink dataset */ + ret = H5Ldelete(fid, DSET1_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +#if 0 + if (h5_using_default_driver(NULL)) { + /* Check size of file */ + filesize = h5_get_file_size(FILENAME, fapl); + VERIFY(filesize, empty_filesize, "h5_get_file_size"); + } +#endif +} /* test_attr_dense_limits() */ + +/**************************************************************** +** +** test_attr_dense_dup_ids(): Test operations with multiple ID +** handles with "dense" attribute storage creation +** +****************************************************************/ +static void +test_attr_dense_dup_ids(hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* HDF5 File ID */ + hid_t dataset; /* Dataset ID */ + hid_t gid1, gid2; /* Group ID */ + hid_t sid, sid2; /* Dataspace ID */ + hid_t attr, attr2, add_attr; /* Attribute ID */ + hid_t dcpl; /* Dataset creation property list ID */ + char attrname[NAME_BUF_SIZE]; /* Name of attribute */ + hsize_t dims[] = {ATTR1_DIM1}; + int read_data1[ATTR1_DIM1] = {0}; /* Buffer for reading attribute */ + int rewrite_data[ATTR1_DIM1] = {1234, -423, 9907256}; /* Test data for rewrite */ + unsigned scalar_data = 1317; /* scalar data for attribute */ + unsigned read_scalar; /* variable for reading attribute*/ + unsigned max_compact; /* Maximum # of attributes to store compactly */ + unsigned min_dense; /* Minimum # of attributes to store "densely" */ +#if 0 + htri_t is_dense; /* Are attributes stored densely? */ +#endif + unsigned u, i; /* Local index variable */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing operations with two IDs for Dense Storage\n")); + + /*----------------------------------------------------------------------------------- + * Create an attribute in dense storage and fill it with fill value. + */ + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Create dataspace for dataset */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* need DCPL to query the group creation properties */ + if (dcpl_g == H5P_DEFAULT) { + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + } + else { + dcpl = H5Pcopy(dcpl_g); + CHECK(dcpl, FAIL, "H5Pcopy"); + } + + /* Create a dataset */ + dataset = H5Dcreate2(fid, DSET1_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Retrieve limits for compact/dense attribute storage */ + ret = H5Pget_attr_phase_change(dcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + + /* Close property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Add attributes, until just before converting to dense storage */ + for (u = 0; u < max_compact; u++) { + /* Create attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = H5Acreate2(dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + } /* end for */ +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Add one more attribute, to push into "dense" storage */ + /* Create dataspace for attribute */ + sid2 = H5Screate_simple(ATTR1_RANK, dims, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Create attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = H5Acreate2(dataset, attrname, H5T_NATIVE_INT, sid2, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); +#endif + /* Open the attribute just created and get a second ID */ + attr2 = H5Aopen(dataset, attrname, H5P_DEFAULT); + CHECK(attr2, FAIL, "H5Aopen"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + ret = H5Aclose(attr2); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /*----------------------------------------------------------------------------------- + * Reopen the file and verify the fill value for attribute. Also write + * some real data. + */ + /* Open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Open the dataset */ + dataset = H5Dopen2(fid, DSET1_NAME, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); +#endif + /* Open first attribute for the dataset */ + attr = H5Aopen(dataset, attrname, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); + + /* Read attribute with fill value */ + ret = H5Aread(attr, H5T_NATIVE_INT, read_data1); + CHECK(ret, FAIL, "H5Aread"); + + /* Verify values read in */ + for (i = 0; i < ATTR1_DIM1; i++) + if (0 != read_data1[i]) + TestErrPrintf("%d: attribute data different: read_data1[%d]=%d\n", __LINE__, i, read_data1[i]); + + /* Open attribute for the second time */ + attr2 = H5Aopen(dataset, attrname, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); + + /* Write attribute information */ + ret = H5Awrite(attr2, H5T_NATIVE_INT, attr_data1); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr2); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /*----------------------------------------------------------------------------------- + * Reopen the file and verify the data. Also rewrite the data and verify it. + */ + /* Open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Open the dataset */ + dataset = H5Dopen2(fid, DSET1_NAME, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); +#endif + /* Open first attribute for the dataset */ + attr = H5Aopen(dataset, attrname, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); + + /* Read attribute information */ + ret = H5Aread(attr, H5T_NATIVE_INT, read_data1); + CHECK(ret, FAIL, "H5Aread"); + + /* Verify values read in */ + for (i = 0; i < ATTR1_DIM1; i++) + if (attr_data1[i] != read_data1[i]) + TestErrPrintf("%d: attribute data different: attr_data1[%d]=%d, read_data1[%d]=%d\n", __LINE__, i, + attr_data1[i], i, read_data1[i]); + + /* Open attribute for the second time */ + attr2 = H5Aopen(dataset, attrname, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); + + /* Write attribute information with the second ID */ + ret = H5Awrite(attr2, H5T_NATIVE_INT, rewrite_data); + CHECK(ret, FAIL, "H5Awrite"); + + /* Read attribute information with the first ID */ + ret = H5Aread(attr, H5T_NATIVE_INT, read_data1); + CHECK(ret, FAIL, "H5Aread"); + + /* Verify values read in */ + for (i = 0; i < ATTR1_DIM1; i++) + if (read_data1[i] != rewrite_data[i]) + TestErrPrintf("%d: attribute data different: read_data1[%d]=%d, rewrite_data[%d]=%d\n", __LINE__, + i, read_data1[i], i, rewrite_data[i]); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + ret = H5Aclose(attr2); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /*----------------------------------------------------------------------------------- + * Open the attribute by index. Verify the data is shared when the attribute + * is opened twice. + */ + /* Open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Open the dataset */ + dataset = H5Dopen2(fid, DSET1_NAME, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); +#endif + /* Open first attribute for the dataset */ + attr = H5Aopen_by_idx(dataset, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)4, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); + + /* Open attribute for the second time */ + attr2 = H5Aopen_by_idx(dataset, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)4, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); + + /* Write attribute information with the second ID */ + ret = H5Awrite(attr2, H5T_NATIVE_UINT, &scalar_data); + CHECK(ret, FAIL, "H5Awrite"); + + /* Read attribute information with the first ID */ + ret = H5Aread(attr, H5T_NATIVE_INT, &read_scalar); + CHECK(ret, FAIL, "H5Aread"); + + /* Verify values read in */ + if (read_scalar != scalar_data) + TestErrPrintf("%d: attribute data different: read_scalar=%d, scalar_data=%d\n", __LINE__, read_scalar, + scalar_data); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + ret = H5Aclose(attr2); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /*----------------------------------------------------------------------------------- + * Open one attribute. As it remains open, delete some attributes. The + * attribute storage should switch from dense to compact. Then open the + * same attribute for the second time and verify that the attribute data + * is shared. + */ + /* Open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Open the dataset */ + dataset = H5Dopen2(fid, DSET1_NAME, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); +#endif + /* Open attribute of the dataset for the first time */ + attr = H5Aopen_by_idx(dataset, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)2, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); + + /* Delete a few attributes until the storage switches to compact */ + for (u = max_compact; u >= min_dense - 1; u--) { + ret = H5Adelete_by_idx(dataset, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)u, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Adelete_by_idx"); + } +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Open attribute for the second time */ + attr2 = H5Aopen_by_idx(dataset, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)2, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); + + /* Write attribute information with the second ID */ + ret = H5Awrite(attr2, H5T_NATIVE_UINT, &scalar_data); + CHECK(ret, FAIL, "H5Awrite"); + + /* Read attribute information with the first ID */ + ret = H5Aread(attr, H5T_NATIVE_INT, &read_scalar); + CHECK(ret, FAIL, "H5Aread"); + + /* Verify values read in */ + if (read_scalar != scalar_data) + TestErrPrintf("%d: attribute data different: read_scalar=%d, scalar_data=%d\n", __LINE__, read_scalar, + scalar_data); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + ret = H5Aclose(attr2); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /*----------------------------------------------------------------------------------- + * Open one attribute. As it remains open, create some attributes. The + * attribute storage should switch from compact to dense. Then open the + * same attribute for the second time and verify that the attribute data + * is shared. + */ + /* Open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Open the dataset */ + dataset = H5Dopen2(fid, DSET1_NAME, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Open attribute of the dataset for the first time */ + attr = H5Aopen_by_idx(dataset, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)3, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); + + /* Delete a few attributes until the storage switches to compact */ + for (u = min_dense - 1; u <= max_compact; u++) { + /* Create attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + add_attr = H5Acreate2(dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(add_attr, FAIL, "H5Acreate2"); + + /* Write data into the attribute */ + ret = H5Awrite(add_attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(add_attr); + CHECK(ret, FAIL, "H5Aclose"); + } +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); +#endif + /* Open attribute for the second time */ + attr2 = H5Aopen_by_idx(dataset, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)3, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); + + /* Write attribute information with the second ID */ + ret = H5Awrite(attr2, H5T_NATIVE_UINT, &scalar_data); + CHECK(ret, FAIL, "H5Awrite"); + + /* Read attribute information with the first ID */ + ret = H5Aread(attr, H5T_NATIVE_INT, &read_scalar); + CHECK(ret, FAIL, "H5Aread"); + + /* Verify values read in */ + if (read_scalar != scalar_data) + TestErrPrintf("%d: attribute data different: read_scalar=%d, scalar_data=%d\n", __LINE__, read_scalar, + scalar_data); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + ret = H5Aclose(attr2); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /*----------------------------------------------------------------------------------- + * Verify that the attribute being pointed to by different paths shares + * the same data. + */ + /* Open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Create a group */ + gid1 = H5Gcreate2(fid, GROUP1_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid1, FAIL, "H5Gcreate2"); + + /* Create hard link to the first group */ + ret = H5Lcreate_hard(gid1, GROUP1_NAME, H5L_SAME_LOC, GROUP2_NAME, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lcreate_hard"); + + /* Add attributes, until just before converting to dense storage */ + for (u = 0; u < max_compact; u++) { + /* Create attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = H5Acreate2(gid1, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + } /* end for */ + + /* Try to create another attribute to make dense storage */ + attr = H5Acreate2(gid1, ATTR2_NAME, H5T_NATIVE_INT, sid2, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); +#if 0 + /* Check on group's attribute storage status */ + is_dense = H5O__is_attr_dense_test(gid1); + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); +#endif + /* Open the hard link just created */ + gid2 = H5Gopen2(fid, GROUP2_NAME, H5P_DEFAULT); + CHECK(gid2, FAIL, "H5Gopen2"); + + /* Open the attribute of the group for the second time */ + attr2 = H5Aopen(gid2, ATTR2_NAME, H5P_DEFAULT); + CHECK(attr2, FAIL, "H5Aopen"); + + /* Write attribute information with the first attribute handle */ + ret = H5Awrite(attr, H5T_NATIVE_INT, attr_data1); + CHECK(ret, FAIL, "H5Awrite"); + + /* Read attribute information with the second attribute handle */ + ret = H5Aread(attr2, H5T_NATIVE_INT, read_data1); + CHECK(ret, FAIL, "H5Aread"); + + /* Verify values read in */ + for (i = 0; i < ATTR1_DIM1; i++) + if (attr_data1[i] != read_data1[i]) + TestErrPrintf("%d: attribute data different: attr_data1[%d]=%d, read_data1[%d]=%d\n", __LINE__, i, + attr_data1[i], i, read_data1[i]); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + ret = H5Aclose(attr2); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close group */ + ret = H5Gclose(gid1); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Gclose(gid2); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close Attribute dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_attr_dense_dup_ids() */ + +/**************************************************************** +** +** test_attr_big(): Test basic H5A (attribute) code. +** Tests storing "big" attribute in dense storage immediately, if available +** +****************************************************************/ +static void +test_attr_big(hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* HDF5 File ID */ + hid_t dataset; /* Dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t big_sid; /* "Big" dataspace ID */ + hsize_t dims[ATTR6_RANK] = {ATTR6_DIM1, ATTR6_DIM2, ATTR6_DIM3}; /* Attribute dimensions */ + hid_t attr; /* Attribute ID */ + hid_t dcpl; /* Dataset creation property list ID */ + char attrname[NAME_BUF_SIZE]; /* Name of attribute */ + unsigned max_compact; /* Maximum # of attributes to store compactly */ + unsigned min_dense; /* Minimum # of attributes to store "densely" */ + unsigned nshared_indices; /* # of shared message indices */ + H5F_libver_t low, high; /* File format bounds */ +#if 0 + htri_t is_empty; /* Are there any attributes? */ + htri_t is_dense; /* Are attributes stored densely? */ +#endif + unsigned u; /* Local index variable */ +#if 0 + h5_stat_size_t empty_filesize; /* Size of empty file */ + h5_stat_size_t filesize; /* Size of file after modifications */ +#endif + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Storing 'Big' Attributes in Dense Storage\n")); + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +#if 0 + /* Get size of file */ + empty_filesize = h5_get_file_size(FILENAME, fapl); + if (empty_filesize < 0) + TestErrPrintf("Line %d: file size wrong!\n", __LINE__); +#endif + /* Re-open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Create dataspace for dataset & "small" attributes */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create "big" dataspace for "big" attributes */ + big_sid = H5Screate_simple(ATTR6_RANK, dims, NULL); + CHECK(big_sid, FAIL, "H5Screate_simple"); + + /* need DCPL to query the group creation properties */ + if (dcpl_g == H5P_DEFAULT) { + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + } + else { + dcpl = H5Pcopy(dcpl_g); + CHECK(dcpl, FAIL, "H5Pcopy"); + } + + /* Retrieve limits for compact/dense attribute storage */ + ret = H5Pget_attr_phase_change(dcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + + /* Retrieve # of shared message indices (ie. whether attributes are shared or not) */ + ret = H5Pget_shared_mesg_nindexes(fcpl, &nshared_indices); + CHECK(ret, FAIL, "H5Pget_shared_mesg_nindexes"); + + /* Retrieve the format bounds for creating objects in the file */ + ret = H5Pget_libver_bounds(fapl, &low, &high); + CHECK(ret, FAIL, "H5Pget_libver_bounds"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid, DSET1_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Close property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + +#if 0 + /* Check on dataset's attribute storage status */ + is_empty = H5O__is_attr_empty_test(dataset); + VERIFY(is_empty, TRUE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + + /* Add first "small" attribute, which should be in compact storage */ + + /* Create attribute */ + u = 0; + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = H5Acreate2(dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); +#if 0 + /* Check on dataset's attribute storage status */ + is_empty = H5O__is_attr_empty_test(dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + + /* Add second "small" attribute, which should stay in compact storage */ + + /* Create attribute */ + u = 1; + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = H5Acreate2(dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); +#if 0 + /* Check on dataset's attribute storage status */ + is_empty = H5O__is_attr_empty_test(dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + + /* Add first "big" attribute, which should push storage into dense form */ + + /* Create attribute */ + u = 2; + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = H5Acreate2(dataset, attrname, H5T_NATIVE_UINT, big_sid, H5P_DEFAULT, H5P_DEFAULT); + if (low == H5F_LIBVER_LATEST || attr >= 0) { + CHECK(attr, FAIL, "H5Acreate2"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Check on dataset's attribute storage status */ + /* (when attributes are shared, the "big" attribute goes into the shared + * message heap instead of forcing the attribute storage into the dense + * form - QAK) + */ +#if 0 + is_empty = H5O__is_attr_empty_test(dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, (nshared_indices ? FALSE : TRUE), "H5O__is_attr_dense_test"); +#endif + + /* Add second "big" attribute, which should leave storage in dense form */ + + /* Create attribute */ + u = 3; + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = H5Acreate2(dataset, attrname, H5T_NATIVE_UINT, big_sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Check on dataset's attribute storage status */ + /* (when attributes are shared, the "big" attribute goes into the shared + * message heap instead of forcing the attribute storage into the dense + * form - QAK) + */ +#if 0 + is_empty = H5O__is_attr_empty_test(dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, (nshared_indices ? FALSE : TRUE), "H5O__is_attr_dense_test"); +#endif + + /* Delete second "small" attribute, attributes should still be stored densely */ + + /* Delete attribute */ + u = 1; + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + ret = H5Adelete(dataset, attrname); + CHECK(ret, FAIL, "H5Adelete"); +#if 0 + /* Check on dataset's attribute storage status */ + is_empty = H5O__is_attr_empty_test(dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, (nshared_indices ? FALSE : TRUE), "H5O__is_attr_dense_test"); +#endif + + /* Delete second "big" attribute, attributes should still be stored densely */ + + /* Delete attribute */ + u = 3; + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + ret = H5Adelete(dataset, attrname); + CHECK(ret, FAIL, "H5Adelete"); +#if 0 + /* Check on dataset's attribute storage status */ + is_empty = H5O__is_attr_empty_test(dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, (nshared_indices ? FALSE : TRUE), "H5O__is_attr_dense_test"); +#endif + + /* Delete first "big" attribute, attributes should _not_ be stored densely */ + + /* Delete attribute */ + u = 2; + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + ret = H5Adelete(dataset, attrname); + CHECK(ret, FAIL, "H5Adelete"); +#if 0 + /* Check on dataset's attribute storage status */ + is_empty = H5O__is_attr_empty_test(dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + + /* Delete first "small" attribute, should be no attributes now */ + + /* Delete attribute */ + u = 0; + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + ret = H5Adelete(dataset, attrname); + CHECK(ret, FAIL, "H5Adelete"); +#if 0 + /* Check on dataset's attribute storage status */ + is_empty = H5O__is_attr_empty_test(dataset); + VERIFY(is_empty, TRUE, "H5O__is_attr_empty_test"); +#endif + } /* end if */ +#if 0 + else { + /* Shouldn't be able to create "big" attributes with older version of format */ + VERIFY(attr, FAIL, "H5Acreate2"); + + /* Check on dataset's attribute storage status */ + /* (when attributes are shared, the "big" attribute goes into the shared + * message heap instead of forcing the attribute storage into the dense + * form - QAK) + */ + is_empty = H5O__is_attr_empty_test(dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); + } /* end else */ +#endif + + /* Close dataspaces */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(big_sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Unlink dataset */ + ret = H5Ldelete(fid, DSET1_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +#if 0 + if (h5_using_default_driver(NULL)) { + /* Check size of file */ + filesize = h5_get_file_size(FILENAME, fapl); + VERIFY(filesize, empty_filesize, "h5_get_file_size"); + } +#endif +} /* test_attr_big() */ + +/**************************************************************** +** +** test_attr_null_space(): Test basic H5A (attribute) code. +** Tests storing attribute with "null" dataspace +** +****************************************************************/ +static void +test_attr_null_space(hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* HDF5 File ID */ + hid_t dataset; /* Dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t null_sid; /* "null" dataspace ID */ + hid_t attr_sid; /* Attribute's dataspace ID */ + hid_t attr; /* Attribute ID */ + char attrname[NAME_BUF_SIZE]; /* Name of attribute */ + unsigned value; /* Attribute value */ + htri_t cmp; /* Results of comparison */ +#if 0 + hsize_t storage_size; /* Size of storage for attribute */ +#endif + H5A_info_t ainfo; /* Attribute info */ +#if 0 + h5_stat_size_t empty_filesize; /* Size of empty file */ + h5_stat_size_t filesize; /* Size of file after modifications */ +#endif + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Storing Attributes with 'null' dataspace\n")); + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +#if 0 + /* Get size of file */ + empty_filesize = h5_get_file_size(FILENAME, fapl); + if (empty_filesize < 0) + TestErrPrintf("Line %d: file size wrong!\n", __LINE__); +#endif + /* Re-open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Create dataspace for dataset attributes */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create "null" dataspace for attribute */ + null_sid = H5Screate(H5S_NULL); + CHECK(null_sid, FAIL, "H5Screate"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid, DSET1_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl_g, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Add attribute with 'null' dataspace */ + + /* Create attribute */ + HDstrcpy(attrname, "null attr"); + attr = H5Acreate2(dataset, attrname, H5T_NATIVE_UINT, null_sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Try to read data from the attribute */ + /* (shouldn't fail, but should leave buffer alone) */ + value = 23; + ret = H5Aread(attr, H5T_NATIVE_UINT, &value); + CHECK(ret, FAIL, "H5Aread"); + VERIFY(value, 23, "H5Aread"); + + /* Get the dataspace for the attribute and make certain it's 'null' */ + attr_sid = H5Aget_space(attr); + CHECK(attr_sid, FAIL, "H5Aget_space"); + + /* Compare the dataspaces */ + cmp = H5Sextent_equal(attr_sid, null_sid); + CHECK(cmp, FAIL, "H5Sextent_equal"); + VERIFY(cmp, TRUE, "H5Sextent_equal"); + + /* Close dataspace */ + ret = H5Sclose(attr_sid); + CHECK(ret, FAIL, "H5Sclose"); +#if 0 + /* Check the storage size for the attribute */ + storage_size = H5Aget_storage_size(attr); + VERIFY(storage_size, 0, "H5Aget_storage_size"); +#endif + /* Get the attribute info */ + ret = H5Aget_info(attr, &ainfo); + CHECK(ret, FAIL, "H5Aget_info"); +#if 0 + VERIFY(ainfo.data_size, storage_size, "H5Aget_info"); +#endif + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Add another attribute with 'null' dataspace */ + + /* Create attribute */ + HDstrcpy(attrname, "null attr #2"); + attr = H5Acreate2(dataset, attrname, H5T_NATIVE_UINT, null_sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Try to write data to the attribute */ + /* (shouldn't fail, but should leave buffer alone) */ + value = 23; + ret = H5Awrite(attr, H5T_NATIVE_UINT, &value); + CHECK(ret, FAIL, "H5Awrite"); + VERIFY(value, 23, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open the file and check on the attributes */ + + /* Re-open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Open dataset */ + dataset = H5Dopen2(fid, DSET1_NAME, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Open first attribute */ + HDstrcpy(attrname, "null attr #2"); + attr = H5Aopen(dataset, attrname, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); + + /* Try to read data from the attribute */ + /* (shouldn't fail, but should leave buffer alone) */ + value = 23; + ret = H5Aread(attr, H5T_NATIVE_UINT, &value); + CHECK(ret, FAIL, "H5Aread"); + VERIFY(value, 23, "H5Aread"); + + /* Get the dataspace for the attribute and make certain it's 'null' */ + attr_sid = H5Aget_space(attr); + CHECK(attr_sid, FAIL, "H5Aget_space"); + + /* Compare the dataspaces */ + cmp = H5Sextent_equal(attr_sid, null_sid); + CHECK(cmp, FAIL, "H5Sextent_equal"); + VERIFY(cmp, TRUE, "H5Sextent_equal"); + + /* Close dataspace */ + ret = H5Sclose(attr_sid); + CHECK(ret, FAIL, "H5Sclose"); +#if 0 + /* Check the storage size for the attribute */ + storage_size = H5Aget_storage_size(attr); + VERIFY(storage_size, 0, "H5Aget_storage_size"); +#endif + /* Get the attribute info */ + ret = H5Aget_info(attr, &ainfo); + CHECK(ret, FAIL, "H5Aget_info"); +#if 0 + VERIFY(ainfo.data_size, storage_size, "H5Aget_info"); +#endif + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Open second attribute */ + HDstrcpy(attrname, "null attr"); + attr = H5Aopen(dataset, attrname, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); + + /* Try to write data to the attribute */ + /* (shouldn't fail, but should leave buffer alone) */ + value = 23; + ret = H5Awrite(attr, H5T_NATIVE_UINT, &value); + CHECK(ret, FAIL, "H5Awrite"); + VERIFY(value, 23, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Unlink dataset */ + ret = H5Ldelete(fid, DSET1_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Close dataspaces */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(null_sid); + CHECK(ret, FAIL, "H5Sclose"); + +#if 0 + if (h5_using_default_driver(NULL)) { + /* Check size of file */ + filesize = h5_get_file_size(FILENAME, fapl); + VERIFY(filesize, empty_filesize, "h5_get_file_size"); + } +#endif +} /* test_attr_null_space() */ + +/**************************************************************** +** +** test_attr_deprec(): Test basic H5A (attribute) code. +** Tests deprecated API routines +** +****************************************************************/ +static void +test_attr_deprec(hid_t fcpl, hid_t fapl) +{ +#ifndef H5_NO_DEPRECATED_SYMBOLS + hid_t fid; /* HDF5 File ID */ + hid_t dataset; /* Dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t attr; /* Attribute ID */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Deprecated Attribute Routines\n")); + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset attributes */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid, DSET1_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl_g, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Add attribute to dataset */ + + /* Create attribute */ + attr = H5Acreate1(dataset, "attr", H5T_NATIVE_UINT, sid, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate1"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close dataspaces */ + ret = H5Sclose(sid); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open the file and operate on the attribute */ + + /* Re-open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Open dataset */ + dataset = H5Dopen2(fid, DSET1_NAME, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + +#if 0 + /* Get number of attributes with bad ID */ + H5E_BEGIN_TRY + { + ret = H5Aget_num_attrs((hid_t)-1); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Aget_num_attrs"); + + /* Get number of attributes */ + ret = H5Aget_num_attrs(dataset); + VERIFY(ret, 1, "H5Aget_num_attrs"); +#endif + /* Open the attribute by index */ + attr = H5Aopen_idx(dataset, 0); + CHECK(attr, FAIL, "H5Aopen_idx"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Open the attribute by name */ + attr = H5Aopen_name(dataset, "attr"); + CHECK(attr, FAIL, "H5Aopen_name"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +#else /* H5_NO_DEPRECATED_SYMBOLS */ + /* Shut compiler up */ + (void)fcpl; + (void)fapl; + + /* Output message about test being skipped */ + MESSAGE(5, ("Skipping Test On Deprecated Attribute Routines\n")); + +#endif /* H5_NO_DEPRECATED_SYMBOLS */ +} /* test_attr_deprec() */ + +/**************************************************************** +** +** test_attr_many(): Test basic H5A (attribute) code. +** Tests storing lots of attributes +** +****************************************************************/ +static void +test_attr_many(hbool_t new_format, hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* HDF5 File ID */ + hid_t gid; /* Group ID */ + hid_t sid; /* Dataspace ID */ + hid_t aid; /* Attribute ID */ + char attrname[NAME_BUF_SIZE]; /* Name of attribute */ + unsigned nattr = (new_format ? NATTR_MANY_NEW : NATTR_MANY_OLD); /* Number of attributes */ + htri_t exists; /* Whether the attribute exists or not */ + unsigned u; /* Local index variable */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Storing Many Attributes\n")); + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create dataspace for attribute */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create group for attributes */ + gid = H5Gcreate2(fid, GROUP1_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gcreate2"); + + /* Create many attributes */ + for (u = 0; u < nattr; u++) { + HDsnprintf(attrname, sizeof(attrname), "a-%06u", u); + + exists = H5Aexists(gid, attrname); + VERIFY(exists, FALSE, "H5Aexists"); + + exists = H5Aexists_by_name(fid, GROUP1_NAME, attrname, H5P_DEFAULT); + VERIFY(exists, FALSE, "H5Aexists_by_name"); + + aid = H5Acreate2(gid, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + + exists = H5Aexists(gid, attrname); + VERIFY(exists, TRUE, "H5Aexists"); + + exists = H5Aexists_by_name(fid, GROUP1_NAME, attrname, H5P_DEFAULT); + VERIFY(exists, TRUE, "H5Aexists_by_name"); + + ret = H5Awrite(aid, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + + exists = H5Aexists(gid, attrname); + VERIFY(exists, TRUE, "H5Aexists"); + + exists = H5Aexists_by_name(fid, GROUP1_NAME, attrname, H5P_DEFAULT); + VERIFY(exists, TRUE, "H5Aexists_by_name"); + } /* end for */ + + /* Close group */ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open the file and check on the attributes */ + + /* Re-open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDONLY, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Re-open group */ + gid = H5Gopen2(fid, GROUP1_NAME, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gopen2"); + + /* Verify attributes */ + for (u = 0; u < nattr; u++) { + unsigned value; /* Attribute value */ + + HDsnprintf(attrname, sizeof(attrname), "a-%06u", u); + + exists = H5Aexists(gid, attrname); + VERIFY(exists, TRUE, "H5Aexists"); + + exists = H5Aexists_by_name(fid, GROUP1_NAME, attrname, H5P_DEFAULT); + VERIFY(exists, TRUE, "H5Aexists_by_name"); + + aid = H5Aopen(gid, attrname, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Aopen"); + + exists = H5Aexists(gid, attrname); + VERIFY(exists, TRUE, "H5Aexists"); + + exists = H5Aexists_by_name(fid, GROUP1_NAME, attrname, H5P_DEFAULT); + VERIFY(exists, TRUE, "H5Aexists_by_name"); + + ret = H5Aread(aid, H5T_NATIVE_UINT, &value); + CHECK(ret, FAIL, "H5Aread"); + VERIFY(value, u, "H5Aread"); + + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + } /* end for */ + + /* Close group */ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Close dataspaces */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_attr_many() */ + +/**************************************************************** +** +** test_attr_corder_create_empty(): Test basic H5A (attribute) code. +** Tests basic code to create objects with attribute creation order info +** +****************************************************************/ +static void +test_attr_corder_create_basic(hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* HDF5 File ID */ + hid_t dataset; /* Dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t dcpl; /* Dataset creation property list ID */ + unsigned crt_order_flags; /* Creation order flags */ +#if 0 + htri_t is_empty; /* Are there any attributes? */ + htri_t is_dense; /* Are attributes stored densely? */ +#endif + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Basic Code for Attributes with Creation Order Info\n")); + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create dataset creation property list */ + if (dcpl_g == H5P_DEFAULT) { + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + } + else { + dcpl = H5Pcopy(dcpl_g); + CHECK(dcpl, FAIL, "H5Pcopy"); + } +#if 0 + /* Get creation order indexing on object */ + ret = H5Pget_attr_creation_order(dcpl, &crt_order_flags); + CHECK(ret, FAIL, "H5Pget_attr_creation_order"); + VERIFY(crt_order_flags, 0, "H5Pget_attr_creation_order"); +#endif + /* Setting invalid combination of a attribute order creation order indexing on should fail */ + H5E_BEGIN_TRY + { + ret = H5Pset_attr_creation_order(dcpl, H5P_CRT_ORDER_INDEXED); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Pset_attr_creation_order"); + +#if 0 + ret = H5Pget_attr_creation_order(dcpl, &crt_order_flags); + CHECK(ret, FAIL, "H5Pget_attr_creation_order"); + VERIFY(crt_order_flags, 0, "H5Pget_attr_creation_order"); +#endif + + /* Set attribute creation order tracking & indexing for object */ + ret = H5Pset_attr_creation_order(dcpl, (H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED)); + CHECK(ret, FAIL, "H5Pset_attr_creation_order"); + ret = H5Pget_attr_creation_order(dcpl, &crt_order_flags); + CHECK(ret, FAIL, "H5Pget_attr_creation_order"); + VERIFY(crt_order_flags, (H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED), "H5Pget_attr_creation_order"); + + /* Create dataspace for dataset */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid, DSET1_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); +#if 0 + /* Check on dataset's attribute storage status */ + is_empty = H5O__is_attr_empty_test(dataset); + VERIFY(is_empty, TRUE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Open dataset created */ + dataset = H5Dopen2(fid, DSET1_NAME, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); +#if 0 + /* Check on dataset's attribute storage status */ + is_empty = H5O__is_attr_empty_test(dataset); + VERIFY(is_empty, TRUE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + + /* Retrieve dataset creation property list for group */ + dcpl = H5Dget_create_plist(dataset); + CHECK(dcpl, FAIL, "H5Dget_create_plist"); + + /* Query the attribute creation properties */ + ret = H5Pget_attr_creation_order(dcpl, &crt_order_flags); + CHECK(ret, FAIL, "H5Pget_attr_creation_order"); + VERIFY(crt_order_flags, (H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED), "H5Pget_attr_creation_order"); + + /* Close property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_attr_corder_create_basic() */ + +/**************************************************************** +** +** test_attr_corder_create_compact(): Test basic H5A (attribute) code. +** Tests compact attribute storage on objects with attribute creation order info +** +****************************************************************/ +static void +test_attr_corder_create_compact(hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* HDF5 File ID */ + hid_t dset1, dset2, dset3; /* Dataset IDs */ + hid_t my_dataset; /* Current dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t attr; /* Attribute ID */ + hid_t dcpl; /* Dataset creation property list ID */ + unsigned max_compact; /* Maximum # of links to store in group compactly */ + unsigned min_dense; /* Minimum # of links to store in group "densely" */ +#if 0 + htri_t is_empty; /* Are there any attributes? */ + htri_t is_dense; /* Are attributes stored densely? */ + hsize_t nattrs; /* Number of attributes on object */ +#endif + char attrname[NAME_BUF_SIZE]; /* Name of attribute */ + unsigned curr_dset; /* Current dataset to work on */ + unsigned u; /* Local index variable */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Compact Storage of Attributes with Creation Order Info\n")); + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create dataset creation property list */ + if (dcpl_g == H5P_DEFAULT) { + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + } + else { + dcpl = H5Pcopy(dcpl_g); + CHECK(dcpl, FAIL, "H5Pcopy"); + } + + /* Set attribute creation order tracking & indexing for object */ + ret = H5Pset_attr_creation_order(dcpl, (H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED)); + CHECK(ret, FAIL, "H5Pset_attr_creation_order"); + + /* Query the attribute creation properties */ + ret = H5Pget_attr_phase_change(dcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + + /* Create dataspace for dataset & attributes */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create datasets */ + dset1 = H5Dcreate2(fid, DSET1_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset1, FAIL, "H5Dcreate2"); + dset2 = H5Dcreate2(fid, DSET2_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset2, FAIL, "H5Dcreate2"); + dset3 = H5Dcreate2(fid, DSET3_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset3, FAIL, "H5Dcreate2"); + + /* Work on all the datasets */ + for (curr_dset = 0; curr_dset < NUM_DSETS; curr_dset++) { + switch (curr_dset) { + case 0: + my_dataset = dset1; + break; + + case 1: + my_dataset = dset2; + break; + + case 2: + my_dataset = dset3; + break; + + default: + HDassert(0 && "Too many datasets!"); + } /* end switch */ +#if 0 + /* Check on dataset's attribute storage status */ + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, TRUE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Create several attributes, but keep storage in compact form */ + for (u = 0; u < max_compact; u++) { + /* Create attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = H5Acreate2(my_dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); +#if 0 + /* Verify state of object */ + ret = H5O__num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O__num_attrs_test"); + VERIFY(nattrs, (u + 1), "H5O__num_attrs_test"); + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + } /* end for */ + } /* end for */ + + /* Close Datasets */ + ret = H5Dclose(dset1); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset2); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset3); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Open datasets created */ + dset1 = H5Dopen2(fid, DSET1_NAME, H5P_DEFAULT); + CHECK(dset1, FAIL, "H5Dopen2"); + dset2 = H5Dopen2(fid, DSET2_NAME, H5P_DEFAULT); + CHECK(dset2, FAIL, "H5Dopen2"); + dset3 = H5Dopen2(fid, DSET3_NAME, H5P_DEFAULT); + CHECK(dset3, FAIL, "H5Dopen2"); + + /* Work on all the datasets */ + for (curr_dset = 0; curr_dset < NUM_DSETS; curr_dset++) { + switch (curr_dset) { + case 0: + my_dataset = dset1; + break; + + case 1: + my_dataset = dset2; + break; + + case 2: + my_dataset = dset3; + break; + + default: + HDassert(0 && "Too many datasets!"); + } /* end switch */ +#if 0 + /* Check on dataset's attribute storage status */ + ret = H5O__num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O__num_attrs_test"); + VERIFY(nattrs, max_compact, "H5O__num_attrs_test"); + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Loop through attributes, checking their creation order values */ + /* (the name index is used, but the creation order value is in the same order) */ + for (u = 0; u < max_compact; u++) { + H5A_info_t ainfo; /* Attribute information */ + + /* Retrieve information for attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + ret = H5Aget_info_by_name(my_dataset, ".", attrname, &ainfo, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aget_info_by_name"); + + /* Verify creation order of attribute */ + VERIFY(ainfo.corder_valid, TRUE, "H5Aget_info_by_name"); + VERIFY(ainfo.corder, u, "H5Aget_info_by_name"); + } /* end for */ + } /* end for */ + + /* Close Datasets */ + ret = H5Dclose(dset1); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset2); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset3); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_attr_corder_create_compact() */ + +/**************************************************************** +** +** test_attr_corder_create_dense(): Test basic H5A (attribute) code. +** Tests dense attribute storage on objects with attribute creation order info +** +****************************************************************/ +static void +test_attr_corder_create_dense(hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* HDF5 File ID */ + hid_t dset1, dset2, dset3; /* Dataset IDs */ + hid_t my_dataset; /* Current dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t attr; /* Attribute ID */ + hid_t dcpl; /* Dataset creation property list ID */ + unsigned max_compact; /* Maximum # of links to store in group compactly */ + unsigned min_dense; /* Minimum # of links to store in group "densely" */ +#if 0 + htri_t is_empty; /* Are there any attributes? */ + htri_t is_dense; /* Are attributes stored densely? */ + hsize_t nattrs; /* Number of attributes on object */ + hsize_t name_count; /* # of records in name index */ + hsize_t corder_count; /* # of records in creation order index */ +#endif + char attrname[NAME_BUF_SIZE]; /* Name of attribute */ + unsigned curr_dset; /* Current dataset to work on */ + unsigned u; /* Local index variable */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Dense Storage of Attributes with Creation Order Info\n")); + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create dataset creation property list */ + if (dcpl_g == H5P_DEFAULT) { + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + } + else { + dcpl = H5Pcopy(dcpl_g); + CHECK(dcpl, FAIL, "H5Pcopy"); + } + + /* Set attribute creation order tracking & indexing for object */ + ret = H5Pset_attr_creation_order(dcpl, (H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED)); + CHECK(ret, FAIL, "H5Pset_attr_creation_order"); + + /* Query the attribute creation properties */ + ret = H5Pget_attr_phase_change(dcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + + /* Create dataspace for dataset & attributes */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create datasets */ + dset1 = H5Dcreate2(fid, DSET1_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset1, FAIL, "H5Dcreate2"); + dset2 = H5Dcreate2(fid, DSET2_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset2, FAIL, "H5Dcreate2"); + dset3 = H5Dcreate2(fid, DSET3_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset3, FAIL, "H5Dcreate2"); + + /* Work on all the datasets */ + for (curr_dset = 0; curr_dset < NUM_DSETS; curr_dset++) { + switch (curr_dset) { + case 0: + my_dataset = dset1; + break; + + case 1: + my_dataset = dset2; + break; + + case 2: + my_dataset = dset3; + break; + + default: + HDassert(0 && "Too many datasets!"); + } /* end switch */ +#if 0 + /* Check on dataset's attribute storage status */ + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, TRUE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Create several attributes, but keep storage in compact form */ + for (u = 0; u < max_compact; u++) { + /* Create attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = H5Acreate2(my_dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); +#if 0 + /* Verify state of object */ + ret = H5O__num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O__num_attrs_test"); + VERIFY(nattrs, (u + 1), "H5O__num_attrs_test"); + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + } /* end for */ + + /* Create another attribute, to push into dense storage */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", max_compact); + attr = H5Acreate2(my_dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); +#if 0 + /* Verify state of object */ + ret = H5O__num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O__num_attrs_test"); + VERIFY(nattrs, (max_compact + 1), "H5O__num_attrs_test"); + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); + + /* Retrieve & verify # of records in the name & creation order indices */ + ret = H5O__attr_dense_info_test(my_dataset, &name_count, &corder_count); + CHECK(ret, FAIL, "H5O__attr_dense_info_test"); + VERIFY(name_count, corder_count, "H5O__attr_dense_info_test"); +#endif + } /* end for */ + + /* Close Datasets */ + ret = H5Dclose(dset1); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset2); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset3); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Open datasets created */ + dset1 = H5Dopen2(fid, DSET1_NAME, H5P_DEFAULT); + CHECK(dset1, FAIL, "H5Dopen2"); + dset2 = H5Dopen2(fid, DSET2_NAME, H5P_DEFAULT); + CHECK(dset2, FAIL, "H5Dopen2"); + dset3 = H5Dopen2(fid, DSET3_NAME, H5P_DEFAULT); + CHECK(dset3, FAIL, "H5Dopen2"); + + /* Work on all the datasets */ + for (curr_dset = 0; curr_dset < NUM_DSETS; curr_dset++) { + switch (curr_dset) { + case 0: + my_dataset = dset1; + break; + + case 1: + my_dataset = dset2; + break; + + case 2: + my_dataset = dset3; + break; + + default: + HDassert(0 && "Too many datasets!"); + } /* end switch */ +#if 0 + /* Check on dataset's attribute storage status */ + ret = H5O__num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O__num_attrs_test"); + VERIFY(nattrs, (max_compact + 1), "H5O__num_attrs_test"); + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); +#endif + /* Loop through attributes, checking their creation order values */ + /* (the name index is used, but the creation order value is in the same order) */ + for (u = 0; u < (max_compact + 1); u++) { + H5A_info_t ainfo; /* Attribute information */ + + /* Retrieve information for attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + ret = H5Aget_info_by_name(my_dataset, ".", attrname, &ainfo, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aget_info_by_name"); + + /* Verify creation order of attribute */ + VERIFY(ainfo.corder_valid, TRUE, "H5Aget_info_by_name"); + VERIFY(ainfo.corder, u, "H5Aget_info_by_name"); + } /* end for */ + } /* end for */ + + /* Close Datasets */ + ret = H5Dclose(dset1); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset2); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset3); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_attr_corder_create_dense() */ + +/**************************************************************** +** +** test_attr_corder_create_reopen(): Test basic H5A (attribute) code. +** Test creating attributes w/reopening file from using new format +** to using old format +** +****************************************************************/ +static void +test_attr_corder_create_reopen(hid_t fcpl, hid_t fapl) +{ + hid_t fid = -1; /* File ID */ + hid_t gcpl_id = -1; /* Group creation property list ID */ + hid_t gid = -1; /* Group ID */ + hid_t sid = -1; /* Dataspace ID */ + hid_t aid = -1; /* Attribute ID */ + int buf; /* Attribute data */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Creating Attributes w/New & Old Format\n")); + + /* Create dataspace for attributes */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create group */ + gcpl_id = H5Pcreate(H5P_GROUP_CREATE); + CHECK(gcpl_id, FAIL, "H5Pcreate"); + ret = H5Pset_attr_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED); + CHECK(ret, FAIL, "H5Pset_attr_creation_order"); + gid = H5Gcreate2(fid, GROUP1_NAME, H5P_DEFAULT, gcpl_id, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gcreate2"); + + /* Create a couple of attributes */ + aid = H5Acreate2(gid, "attr-003", H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + buf = 3; + ret = H5Awrite(aid, H5T_NATIVE_INT, &buf); + CHECK(ret, FAIL, "H5Awrite"); + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + + aid = H5Acreate2(gid, "attr-004", H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + buf = 4; + ret = H5Awrite(aid, H5T_NATIVE_INT, &buf); + CHECK(ret, FAIL, "H5Awrite"); + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + + /***** Close group & GCPL *****/ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Pclose(gcpl_id); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open file, without "use the latest format" flag */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* Re-open group */ + gid = H5Gopen2(fid, GROUP1_NAME, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gopen2"); + + /* Delete attribute */ + ret = H5Adelete(gid, "attr-003"); + CHECK(aid, FAIL, "H5Adelete"); + + /* Create some additional attributes */ + aid = H5Acreate2(gid, "attr-008", H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + buf = 8; + ret = H5Awrite(aid, H5T_NATIVE_INT, &buf); + CHECK(ret, FAIL, "H5Awrite"); + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + + aid = H5Acreate2(gid, "attr-006", H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + buf = 6; + ret = H5Awrite(aid, H5T_NATIVE_INT, &buf); + CHECK(ret, FAIL, "H5Awrite"); + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + + /***** Close group *****/ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Close attribute dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_attr_corder_create_reopen() */ + +/**************************************************************** +** +** test_attr_corder_transition(): Test basic H5A (attribute) code. +** Tests attribute storage transitions on objects with attribute creation order info +** +****************************************************************/ +static void +test_attr_corder_transition(hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* HDF5 File ID */ + hid_t dset1, dset2, dset3; /* Dataset IDs */ + hid_t my_dataset; /* Current dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t attr; /* Attribute ID */ + hid_t dcpl; /* Dataset creation property list ID */ + unsigned max_compact; /* Maximum # of links to store in group compactly */ + unsigned min_dense; /* Minimum # of links to store in group "densely" */ +#if 0 + htri_t is_empty; /* Are there any attributes? */ + htri_t is_dense; /* Are attributes stored densely? */ + hsize_t nattrs; /* Number of attributes on object */ + hsize_t name_count; /* # of records in name index */ + hsize_t corder_count; /* # of records in creation order index */ +#endif + char attrname[NAME_BUF_SIZE]; /* Name of attribute */ + unsigned curr_dset; /* Current dataset to work on */ + unsigned u; /* Local index variable */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Storage Transitions of Attributes with Creation Order Info\n")); + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create dataset creation property list */ + if (dcpl_g == H5P_DEFAULT) { + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + } + else { + dcpl = H5Pcopy(dcpl_g); + CHECK(dcpl, FAIL, "H5Pcopy"); + } + + /* Set attribute creation order tracking & indexing for object */ + ret = H5Pset_attr_creation_order(dcpl, (H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED)); + CHECK(ret, FAIL, "H5Pset_attr_creation_order"); + + /* Query the attribute creation properties */ + ret = H5Pget_attr_phase_change(dcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + + /* Create dataspace for dataset & attributes */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* XXX: Try to find a way to resize dataset's object header so that the object + * header can have one chunk, then retrieve "empty" file size and check + * that size after everything is deleted -QAK + */ + /* Create datasets */ + dset1 = H5Dcreate2(fid, DSET1_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset1, FAIL, "H5Dcreate2"); + dset2 = H5Dcreate2(fid, DSET2_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset2, FAIL, "H5Dcreate2"); + dset3 = H5Dcreate2(fid, DSET3_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset3, FAIL, "H5Dcreate2"); + + /* Work on all the datasets */ + for (curr_dset = 0; curr_dset < NUM_DSETS; curr_dset++) { + switch (curr_dset) { + case 0: + my_dataset = dset1; + break; + + case 1: + my_dataset = dset2; + break; + + case 2: + my_dataset = dset3; + break; + + default: + HDassert(0 && "Too many datasets!"); + } /* end switch */ +#if 0 + /* Check on dataset's attribute storage status */ + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, TRUE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + } /* end for */ + + /* Close Datasets */ + ret = H5Dclose(dset1); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset2); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset3); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Open datasets created */ + dset1 = H5Dopen2(fid, DSET1_NAME, H5P_DEFAULT); + CHECK(dset1, FAIL, "H5Dopen2"); + dset2 = H5Dopen2(fid, DSET2_NAME, H5P_DEFAULT); + CHECK(dset2, FAIL, "H5Dopen2"); + dset3 = H5Dopen2(fid, DSET3_NAME, H5P_DEFAULT); + CHECK(dset3, FAIL, "H5Dopen2"); + + /* Work on all the datasets */ + for (curr_dset = 0; curr_dset < NUM_DSETS; curr_dset++) { + switch (curr_dset) { + case 0: + my_dataset = dset1; + break; + + case 1: + my_dataset = dset2; + break; + + case 2: + my_dataset = dset3; + break; + + default: + HDassert(0 && "Too many datasets!"); + } /* end switch */ + + /* Create several attributes, but keep storage in compact form */ + for (u = 0; u < max_compact; u++) { + /* Create attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = H5Acreate2(my_dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); +#if 0 + /* Verify state of object */ + ret = H5O__num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O__num_attrs_test"); + VERIFY(nattrs, (u + 1), "H5O__num_attrs_test"); + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + } /* end for */ + + /* Create another attribute, to push into dense storage */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", max_compact); + attr = H5Acreate2(my_dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); +#if 0 + /* Verify state of object */ + ret = H5O__num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O__num_attrs_test"); + VERIFY(nattrs, (max_compact + 1), "H5O__num_attrs_test"); + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); + + /* Retrieve & verify # of records in the name & creation order indices */ + ret = H5O__attr_dense_info_test(my_dataset, &name_count, &corder_count); + CHECK(ret, FAIL, "H5O__attr_dense_info_test"); + VERIFY(name_count, corder_count, "H5O__attr_dense_info_test"); +#endif + /* Delete several attributes from object, until attribute storage resumes compact form */ + for (u = max_compact; u >= min_dense; u--) { + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + ret = H5Adelete(my_dataset, attrname); + CHECK(ret, FAIL, "H5Adelete"); +#if 0 + /* Verify state of object */ + ret = H5O__num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O__num_attrs_test"); + VERIFY(nattrs, u, "H5O__num_attrs_test"); + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); + + /* Retrieve & verify # of records in the name & creation order indices */ + ret = H5O__attr_dense_info_test(my_dataset, &name_count, &corder_count); + CHECK(ret, FAIL, "H5O__attr_dense_info_test"); + VERIFY(name_count, corder_count, "H5O__attr_dense_info_test"); +#endif + } /* end for */ + + /* Delete another attribute, to push attribute storage into compact form */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", (min_dense - 1)); + ret = H5Adelete(my_dataset, attrname); + CHECK(ret, FAIL, "H5Adelete"); +#if 0 + /* Verify state of object */ + ret = H5O__num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O__num_attrs_test"); + VERIFY(nattrs, (min_dense - 1), "H5O__num_attrs_test"); + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Re-add attributes to get back into dense form */ + for (u = (min_dense - 1); u < (max_compact + 1); u++) { + /* Create attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = H5Acreate2(my_dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + } /* end for */ +#if 0 + /* Verify state of object */ + ret = H5O__num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O__num_attrs_test"); + VERIFY(nattrs, (max_compact + 1), "H5O__num_attrs_test"); + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); + + /* Retrieve & verify # of records in the name & creation order indices */ + ret = H5O__attr_dense_info_test(my_dataset, &name_count, &corder_count); + CHECK(ret, FAIL, "H5O__attr_dense_info_test"); + VERIFY(name_count, corder_count, "H5O__attr_dense_info_test"); +#endif + } /* end for */ + + /* Close Datasets */ + ret = H5Dclose(dset1); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset2); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset3); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Open datasets created */ + dset1 = H5Dopen2(fid, DSET1_NAME, H5P_DEFAULT); + CHECK(dset1, FAIL, "H5Dopen2"); + dset2 = H5Dopen2(fid, DSET2_NAME, H5P_DEFAULT); + CHECK(dset2, FAIL, "H5Dopen2"); + dset3 = H5Dopen2(fid, DSET3_NAME, H5P_DEFAULT); + CHECK(dset3, FAIL, "H5Dopen2"); + + /* Work on all the datasets */ + for (curr_dset = 0; curr_dset < NUM_DSETS; curr_dset++) { + switch (curr_dset) { + case 0: + my_dataset = dset1; + break; + + case 1: + my_dataset = dset2; + break; + + case 2: + my_dataset = dset3; + break; + + default: + HDassert(0 && "Too many datasets!"); + } /* end switch */ +#if 0 + /* Check on dataset's attribute storage status */ + ret = H5O__num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O__num_attrs_test"); + VERIFY(nattrs, (max_compact + 1), "H5O__num_attrs_test"); + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); + + /* Retrieve & verify # of records in the name & creation order indices */ + ret = H5O__attr_dense_info_test(my_dataset, &name_count, &corder_count); + CHECK(ret, FAIL, "H5O__attr_dense_info_test"); + VERIFY(name_count, corder_count, "H5O__attr_dense_info_test"); +#endif + /* Delete several attributes from object, until attribute storage resumes compact form */ + for (u = max_compact; u >= min_dense; u--) { + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + ret = H5Adelete(my_dataset, attrname); + CHECK(ret, FAIL, "H5Adelete"); +#if 0 + /* Verify state of object */ + ret = H5O__num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O__num_attrs_test"); + VERIFY(nattrs, u, "H5O__num_attrs_test"); + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); + + /* Retrieve & verify # of records in the name & creation order indices */ + ret = H5O__attr_dense_info_test(my_dataset, &name_count, &corder_count); + CHECK(ret, FAIL, "H5O__attr_dense_info_test"); + VERIFY(name_count, corder_count, "H5O__attr_dense_info_test"); +#endif + } /* end for */ + + /* Delete another attribute, to push attribute storage into compact form */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", (min_dense - 1)); + ret = H5Adelete(my_dataset, attrname); + CHECK(ret, FAIL, "H5Adelete"); +#if 0 + /* Verify state of object */ + ret = H5O__num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O__num_attrs_test"); + VERIFY(nattrs, (min_dense - 1), "H5O__num_attrs_test"); + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Re-add attributes to get back into dense form */ + for (u = (min_dense - 1); u < (max_compact + 1); u++) { + /* Create attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = H5Acreate2(my_dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + } /* end for */ +#if 0 + /* Verify state of object */ + ret = H5O__num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O__num_attrs_test"); + VERIFY(nattrs, (max_compact + 1), "H5O__num_attrs_test"); + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); + + /* Retrieve & verify # of records in the name & creation order indices */ + ret = H5O__attr_dense_info_test(my_dataset, &name_count, &corder_count); + CHECK(ret, FAIL, "H5O__attr_dense_info_test"); + VERIFY(name_count, corder_count, "H5O__attr_dense_info_test"); +#endif + /* Delete all attributes */ + for (u = max_compact; u > 0; u--) { + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + ret = H5Adelete(my_dataset, attrname); + CHECK(ret, FAIL, "H5Adelete"); + } /* end for */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", 0); + ret = H5Adelete(my_dataset, attrname); + CHECK(ret, FAIL, "H5Adelete"); + } /* end for */ + + /* Close Datasets */ + ret = H5Dclose(dset1); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset2); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset3); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_attr_corder_transition() */ + +/**************************************************************** +** +** test_attr_corder_delete(): Test basic H5A (attribute) code. +** Tests deleting object w/dense attribute storage on objects with attribute creation order info +** +****************************************************************/ +static void +test_attr_corder_delete(hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* HDF5 File ID */ + hid_t dset1, dset2, dset3; /* Dataset IDs */ + hid_t my_dataset; /* Current dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t attr; /* Attribute ID */ + hid_t dcpl; /* Dataset creation property list ID */ + unsigned max_compact; /* Maximum # of links to store in group compactly */ + unsigned min_dense; /* Minimum # of links to store in group "densely" */ +#if 0 + htri_t is_empty; /* Are there any attributes? */ + htri_t is_dense; /* Are attributes stored densely? */ + hsize_t nattrs; /* Number of attributes on object */ + hsize_t name_count; /* # of records in name index */ + hsize_t corder_count; /* # of records in creation order index */ +#endif + unsigned reopen_file; /* Whether to re-open the file before deleting group */ + char attrname[NAME_BUF_SIZE]; /* Name of attribute */ +#ifdef LATER + h5_stat_size_t empty_size; /* Size of empty file */ + h5_stat_size_t file_size; /* Size of file after operating on it */ +#endif /* LATER */ + unsigned curr_dset; /* Current dataset to work on */ + unsigned u; /* Local index variable */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Deleting Object w/Dense Attribute Storage and Creation Order Info\n")); + + /* Create dataspace for dataset & attributes */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create dataset creation property list */ + if (dcpl_g == H5P_DEFAULT) { + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + } + else { + dcpl = H5Pcopy(dcpl_g); + CHECK(dcpl, FAIL, "H5Pcopy"); + } + + /* Set attribute creation order tracking & indexing for object */ + ret = H5Pset_attr_creation_order(dcpl, (H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED)); + CHECK(ret, FAIL, "H5Pset_attr_creation_order"); + + /* Query the attribute creation properties */ + ret = H5Pget_attr_phase_change(dcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + +/* XXX: Try to find a way to resize dataset's object header so that the object + * header can have one chunk, then retrieve "empty" file size and check + * that size after everything is deleted -QAK + */ +#ifdef LATER + /* Create empty file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Get the size of an empty file */ + empty_size = h5_get_file_size(FILENAME); + CHECK(empty_size, FAIL, "h5_get_file_size"); +#endif /* LATER */ + + /* Loop to leave file open when deleting dataset, or to close & re-open file + * before deleting dataset */ + for (reopen_file = FALSE; reopen_file <= TRUE; reopen_file++) { + /* Create test file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Create datasets */ + dset1 = H5Dcreate2(fid, DSET1_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset1, FAIL, "H5Dcreate2"); + dset2 = H5Dcreate2(fid, DSET2_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset2, FAIL, "H5Dcreate2"); + dset3 = H5Dcreate2(fid, DSET3_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset3, FAIL, "H5Dcreate2"); + + /* Work on all the datasets */ + for (curr_dset = 0; curr_dset < NUM_DSETS; curr_dset++) { + switch (curr_dset) { + case 0: + my_dataset = dset1; + break; + + case 1: + my_dataset = dset2; + break; + + case 2: + my_dataset = dset3; + break; + + default: + HDassert(0 && "Too many datasets!"); + } /* end switch */ +#if 0 + /* Check on dataset's attribute storage status */ + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, TRUE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Create attributes, until attribute storage is in dense form */ + for (u = 0; u < max_compact * 2; u++) { + /* Create attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = H5Acreate2(my_dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + } /* end for */ +#if 0 + /* Verify state of object */ + ret = H5O__num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O__num_attrs_test"); + VERIFY(nattrs, (max_compact * 2), "H5O__num_attrs_test"); + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); + + /* Retrieve & verify # of records in the name & creation order indices */ + ret = H5O__attr_dense_info_test(my_dataset, &name_count, &corder_count); + CHECK(ret, FAIL, "H5O__attr_dense_info_test"); + VERIFY(name_count, corder_count, "H5O__attr_dense_info_test"); +#endif + } /* end for */ + + /* Close Datasets */ + ret = H5Dclose(dset1); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset2); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset3); + CHECK(ret, FAIL, "H5Dclose"); + + /* Check for deleting datasets without re-opening file */ + if (!reopen_file) { + ret = H5Ldelete(fid, DSET1_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + ret = H5Ldelete(fid, DSET2_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + ret = H5Ldelete(fid, DSET3_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + } /* end if */ + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Check for deleting dataset after re-opening file */ + if (reopen_file) { + /* Re-open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Delete the datasets */ + ret = H5Ldelete(fid, DSET1_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + ret = H5Ldelete(fid, DSET2_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + ret = H5Ldelete(fid, DSET3_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + } /* end if */ + +#ifdef LATER + /* Get the size of the file now */ + file_size = h5_get_file_size(FILENAME); + CHECK(file_size, FAIL, "h5_get_file_size"); + VERIFY(file_size, empty_size, "h5_get_file_size"); +#endif /* LATER */ + } /* end for */ + + /* Close property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_attr_corder_delete() */ + +/*------------------------------------------------------------------------- + * Function: attr_info_by_idx_check + * + * Purpose: Support routine for attr_info_by_idx, to verify the attribute + * info is correct for a attribute + * + * Note: This routine assumes that the attributes have been added to the + * object in alphabetical order. + * + * Return: Success: 0 + * Failure: -1 + * + * Programmer: Quincey Koziol + * Tuesday, Februrary 13, 2007 + * + *------------------------------------------------------------------------- + */ +static int +attr_info_by_idx_check(hid_t obj_id, const char *attrname, hsize_t n, hbool_t use_index) +{ + char tmpname[NAME_BUF_SIZE]; /* Temporary attribute name */ + H5A_info_t ainfo; /* Attribute info struct */ + int old_nerrs; /* Number of errors when entering this check */ + herr_t ret; /* Generic return value */ + + /* Retrieve the current # of reported errors */ + old_nerrs = nerrors; + + /* Verify the information for first attribute, in increasing creation order */ + HDmemset(&ainfo, 0, sizeof(ainfo)); + ret = H5Aget_info_by_idx(obj_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, (hsize_t)0, &ainfo, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aget_info_by_idx"); + VERIFY(ainfo.corder, 0, "H5Aget_info_by_idx"); + + /* Verify the information for new attribute, in increasing creation order */ + HDmemset(&ainfo, 0, sizeof(ainfo)); + ret = H5Aget_info_by_idx(obj_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, n, &ainfo, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aget_info_by_idx"); + VERIFY(ainfo.corder, n, "H5Aget_info_by_idx"); + + /* Verify the name for new link, in increasing creation order */ + HDmemset(tmpname, 0, (size_t)NAME_BUF_SIZE); + ret = (herr_t)H5Aget_name_by_idx(obj_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, n, tmpname, + (size_t)NAME_BUF_SIZE, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aget_name_by_idx"); + if (HDstrcmp(attrname, tmpname) != 0) + TestErrPrintf("Line %d: attribute name size wrong!\n", __LINE__); + + /* Don't test "native" order if there is no creation order index, since + * there's not a good way to easily predict the attribute's order in the name + * index. + */ + if (use_index) { + /* Verify the information for first attribute, in native creation order */ + HDmemset(&ainfo, 0, sizeof(ainfo)); + ret = H5Aget_info_by_idx(obj_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC /* H5_ITER_NATIVE */, + (hsize_t)0, &ainfo, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aget_info_by_idx"); + VERIFY(ainfo.corder, 0, "H5Aget_info_by_idx"); + + /* Verify the information for new attribute, in native creation order */ + HDmemset(&ainfo, 0, sizeof(ainfo)); + ret = H5Aget_info_by_idx(obj_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC /* H5_ITER_NATIVE */, n, &ainfo, + H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aget_info_by_idx"); + VERIFY(ainfo.corder, n, "H5Aget_info_by_idx"); + + /* Verify the name for new link, in increasing native order */ + HDmemset(tmpname, 0, (size_t)NAME_BUF_SIZE); + ret = (herr_t)H5Aget_name_by_idx(obj_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC /* H5_ITER_NATIVE */, n, + tmpname, (size_t)NAME_BUF_SIZE, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aget_name_by_idx"); + if (HDstrcmp(attrname, tmpname) != 0) + TestErrPrintf("Line %d: attribute name size wrong!\n", __LINE__); + } /* end if */ + + /* Verify the information for first attribute, in decreasing creation order */ + HDmemset(&ainfo, 0, sizeof(ainfo)); + ret = H5Aget_info_by_idx(obj_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, n, &ainfo, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aget_info_by_idx"); + VERIFY(ainfo.corder, 0, "H5Aget_info_by_idx"); + + /* Verify the information for new attribute, in increasing creation order */ + HDmemset(&ainfo, 0, sizeof(ainfo)); + ret = H5Aget_info_by_idx(obj_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, (hsize_t)0, &ainfo, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aget_info_by_idx"); + VERIFY(ainfo.corder, n, "H5Aget_info_by_idx"); + + /* Verify the name for new link, in increasing creation order */ + HDmemset(tmpname, 0, (size_t)NAME_BUF_SIZE); + ret = (herr_t)H5Aget_name_by_idx(obj_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, (hsize_t)0, tmpname, + (size_t)NAME_BUF_SIZE, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aget_name_by_idx"); + if (HDstrcmp(attrname, tmpname) != 0) + TestErrPrintf("Line %d: attribute name size wrong!\n", __LINE__); + + /* Verify the information for first attribute, in increasing name order */ + HDmemset(&ainfo, 0, sizeof(ainfo)); + ret = H5Aget_info_by_idx(obj_id, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)0, &ainfo, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aget_info_by_idx"); + VERIFY(ainfo.corder, 0, "H5Aget_info_by_idx"); + + /* Verify the information for new attribute, in increasing name order */ + HDmemset(&ainfo, 0, sizeof(ainfo)); + ret = H5Aget_info_by_idx(obj_id, ".", H5_INDEX_NAME, H5_ITER_INC, n, &ainfo, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aget_info_by_idx"); + VERIFY(ainfo.corder, n, "H5Aget_info_by_idx"); + + /* Verify the name for new link, in increasing name order */ + HDmemset(tmpname, 0, (size_t)NAME_BUF_SIZE); + ret = (herr_t)H5Aget_name_by_idx(obj_id, ".", H5_INDEX_NAME, H5_ITER_INC, n, tmpname, + (size_t)NAME_BUF_SIZE, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aget_name_by_idx"); + if (HDstrcmp(attrname, tmpname) != 0) + TestErrPrintf("Line %d: attribute name size wrong!\n", __LINE__); + + /* Don't test "native" order queries on link name order, since there's not + * a good way to easily predict the order of the links in the name index. + */ + +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + /* Verify the information for first attribute, in decreasing name order */ + HDmemset(&ainfo, 0, sizeof(ainfo)); + ret = H5Aget_info_by_idx(obj_id, ".", H5_INDEX_NAME, H5_ITER_DEC, n, &ainfo, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aget_info_by_idx"); + VERIFY(ainfo.corder, 0, "H5Aget_info_by_idx"); + + /* Verify the information for new attribute, in increasing name order */ + HDmemset(&ainfo, 0, sizeof(ainfo)); + ret = H5Aget_info_by_idx(obj_id, ".", H5_INDEX_NAME, H5_ITER_DEC, (hsize_t)0, &ainfo, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aget_info_by_idx"); + VERIFY(ainfo.corder, n, "H5Aget_info_by_idx"); + + /* Verify the name for new link, in increasing name order */ + HDmemset(tmpname, 0, (size_t)NAME_BUF_SIZE); + ret = (herr_t)H5Aget_name_by_idx(obj_id, ".", H5_INDEX_NAME, H5_ITER_DEC, (hsize_t)0, tmpname, + (size_t)NAME_BUF_SIZE, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aget_name_by_idx"); + if (HDstrcmp(attrname, tmpname) != 0) + TestErrPrintf("Line %d: attribute name size wrong!\n", __LINE__); +#endif + /* Retrieve current # of errors */ + if (old_nerrs == nerrors) + return (0); + else + return (-1); +} /* end attr_info_by_idx_check() */ + +/**************************************************************** +** +** test_attr_info_by_idx(): Test basic H5A (attribute) code. +** Tests querying attribute info by index +** +****************************************************************/ +static void +test_attr_info_by_idx(hbool_t new_format, hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* HDF5 File ID */ + hid_t dset1, dset2, dset3; /* Dataset IDs */ + hid_t my_dataset; /* Current dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t attr; /* Attribute ID */ + hid_t dcpl; /* Dataset creation property list ID */ + H5A_info_t ainfo; /* Attribute information */ + unsigned max_compact; /* Maximum # of links to store in group compactly */ + unsigned min_dense; /* Minimum # of links to store in group "densely" */ +#if 0 + htri_t is_empty; /* Are there any attributes? */ + htri_t is_dense; /* Are attributes stored densely? */ + hsize_t nattrs; /* Number of attributes on object */ + hsize_t name_count; /* # of records in name index */ + hsize_t corder_count; /* # of records in creation order index */ +#endif + unsigned use_index; /* Use index on creation order values */ + char attrname[NAME_BUF_SIZE]; /* Name of attribute */ + char tmpname[NAME_BUF_SIZE]; /* Temporary attribute name */ + unsigned curr_dset; /* Current dataset to work on */ + unsigned u; /* Local index variable */ + herr_t ret; /* Generic return value */ + + /* Create dataspace for dataset & attributes */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create dataset creation property list */ + if (dcpl_g == H5P_DEFAULT) { + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + } + else { + dcpl = H5Pcopy(dcpl_g); + CHECK(dcpl, FAIL, "H5Pcopy"); + } + + /* Query the attribute creation properties */ + ret = H5Pget_attr_phase_change(dcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + + /* Loop over using index for creation order value */ + for (use_index = FALSE; use_index <= TRUE; use_index++) { + /* Output message about test being performed */ + if (use_index) + MESSAGE(5, ("Testing Querying Attribute Info By Index w/Creation Order Index\n")) + else + MESSAGE(5, ("Testing Querying Attribute Info By Index w/o Creation Order Index\n")) + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Set attribute creation order tracking & indexing for object */ + if (new_format == TRUE) { + ret = H5Pset_attr_creation_order( + dcpl, (H5P_CRT_ORDER_TRACKED | (use_index ? H5P_CRT_ORDER_INDEXED : (unsigned)0))); + CHECK(ret, FAIL, "H5Pset_attr_creation_order"); + } /* end if */ + + /* Create datasets */ + dset1 = H5Dcreate2(fid, DSET1_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset1, FAIL, "H5Dcreate2"); + dset2 = H5Dcreate2(fid, DSET2_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset2, FAIL, "H5Dcreate2"); + dset3 = H5Dcreate2(fid, DSET3_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset3, FAIL, "H5Dcreate2"); + + /* Work on all the datasets */ + for (curr_dset = 0; curr_dset < NUM_DSETS; curr_dset++) { + switch (curr_dset) { + case 0: + my_dataset = dset1; + break; + + case 1: + my_dataset = dset2; + break; + + case 2: + my_dataset = dset3; + break; + + default: + HDassert(0 && "Too many datasets!"); + } /* end switch */ +#if 0 + /* Check on dataset's attribute storage status */ + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, TRUE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Check for query on non-existent attribute */ + H5E_BEGIN_TRY + { + ret = H5Aget_info_by_idx(my_dataset, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, (hsize_t)0, &ainfo, + H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Aget_info_by_idx"); + H5E_BEGIN_TRY + { + ret = (herr_t)H5Aget_name_by_idx(my_dataset, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, (hsize_t)0, + tmpname, (size_t)NAME_BUF_SIZE, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Aget_name_by_idx"); + + /* Create attributes, up to limit of compact form */ + for (u = 0; u < max_compact; u++) { + /* Create attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = H5Acreate2(my_dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Verify information for new attribute */ + ret = attr_info_by_idx_check(my_dataset, attrname, (hsize_t)u, use_index); + CHECK(ret, FAIL, "attr_info_by_idx_check"); + } /* end for */ +#if 0 + /* Verify state of object */ + ret = H5O__num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O__num_attrs_test"); + VERIFY(nattrs, max_compact, "H5O__num_attrs_test"); + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Check for out of bound offset queries */ + H5E_BEGIN_TRY + { + ret = H5Aget_info_by_idx(my_dataset, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, (hsize_t)u, &ainfo, + H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Aget_info_by_idx"); + H5E_BEGIN_TRY + { + ret = H5Aget_info_by_idx(my_dataset, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, (hsize_t)u, &ainfo, + H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Aget_info_by_idx"); + H5E_BEGIN_TRY + { + ret = (herr_t)H5Aget_name_by_idx(my_dataset, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, (hsize_t)u, + tmpname, (size_t)NAME_BUF_SIZE, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Aget_name_by_idx"); + + /* Create more attributes, to push into dense form */ + for (; u < (max_compact * 2); u++) { + /* Create attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = H5Acreate2(my_dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); +#if 0 + /* Verify state of object */ + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, (new_format ? TRUE : FALSE), "H5O__is_attr_dense_test"); +#endif + /* Verify information for new attribute */ + ret = attr_info_by_idx_check(my_dataset, attrname, (hsize_t)u, use_index); + CHECK(ret, FAIL, "attr_info_by_idx_check"); + } /* end for */ +#if 0 + /* Verify state of object */ + ret = H5O__num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O__num_attrs_test"); + VERIFY(nattrs, (max_compact * 2), "H5O__num_attrs_test"); + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, (new_format ? TRUE : FALSE), "H5O__is_attr_dense_test"); + + if (new_format) { + /* Retrieve & verify # of records in the name & creation order indices */ + ret = H5O__attr_dense_info_test(my_dataset, &name_count, &corder_count); + CHECK(ret, FAIL, "H5O__attr_dense_info_test"); + if (use_index) + VERIFY(name_count, corder_count, "H5O__attr_dense_info_test"); + VERIFY(name_count, (max_compact * 2), "H5O__attr_dense_info_test"); + } /* end if */ +#endif + /* Check for out of bound offset queries */ + H5E_BEGIN_TRY + { + ret = H5Aget_info_by_idx(my_dataset, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, (hsize_t)u, &ainfo, + H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Aget_info_by_idx"); + H5E_BEGIN_TRY + { + ret = H5Aget_info_by_idx(my_dataset, ".", H5_INDEX_CRT_ORDER, H5_ITER_DEC, (hsize_t)u, &ainfo, + H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Aget_info_by_idx"); + H5E_BEGIN_TRY + { + ret = (herr_t)H5Aget_name_by_idx(my_dataset, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, (hsize_t)u, + tmpname, (size_t)NAME_BUF_SIZE, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Aget_name_by_idx"); + } /* end for */ + + /* Close Datasets */ + ret = H5Dclose(dset1); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset2); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset3); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + } /* end for */ + + /* Close property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_attr_info_by_idx() */ + +/*************************************************************** +** +** test_attr_info_null_info_pointer(): A test to ensure that +** passing a NULL attribute info pointer to H5Aget_info +** (_by_name/_by_idx) doesn't cause bad behavior. +** +****************************************************************/ +static void +test_attr_info_null_info_pointer(hid_t fcpl, hid_t fapl) +{ + herr_t err_ret = -1; + hid_t fid; + hid_t attr; + hid_t sid; + + /* Create dataspace for attribute */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create attribute */ + attr = H5Acreate2(fid, GET_INFO_NULL_POINTER_ATTR_NAME, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + H5E_BEGIN_TRY + { + err_ret = H5Aget_info(attr, NULL); + } + H5E_END_TRY; + + CHECK(err_ret, SUCCEED, "H5Aget_info"); + + H5E_BEGIN_TRY + { + err_ret = H5Aget_info_by_name(fid, ".", GET_INFO_NULL_POINTER_ATTR_NAME, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + CHECK(err_ret, SUCCEED, "H5Aget_info_by_name"); + + H5E_BEGIN_TRY + { + err_ret = H5Aget_info_by_idx(fid, ".", H5_INDEX_NAME, H5_ITER_INC, 0, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + CHECK(err_ret, SUCCEED, "H5Aget_info_by_idx"); + + /* Close dataspace */ + err_ret = H5Sclose(sid); + CHECK(err_ret, FAIL, "H5Sclose"); + + /* Close attribute */ + err_ret = H5Aclose(attr); + CHECK(err_ret, FAIL, "H5Aclose"); + + /* Close file */ + err_ret = H5Fclose(fid); + CHECK(err_ret, FAIL, "H5Fclose"); +} + +/*************************************************************** +** +** test_attr_rename_invalid_name(): A test to ensure that +** passing a NULL or empty attribute name to +** H5Arename(_by_name) doesn't cause bad behavior. +** +****************************************************************/ +static void +test_attr_rename_invalid_name(hid_t fcpl, hid_t fapl) +{ + herr_t err_ret = -1; + hid_t fid; + hid_t attr; + hid_t sid; + + /* Create dataspace for attribute */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create attribute */ + attr = H5Acreate2(fid, INVALID_RENAME_TEST_ATTR_NAME, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + H5E_BEGIN_TRY + { + err_ret = H5Arename(fid, NULL, INVALID_RENAME_TEST_NEW_ATTR_NAME); + } + H5E_END_TRY; + + CHECK(err_ret, SUCCEED, "H5Arename"); + + H5E_BEGIN_TRY + { + err_ret = H5Arename(fid, "", INVALID_RENAME_TEST_NEW_ATTR_NAME); + } + H5E_END_TRY; + + CHECK(err_ret, SUCCEED, "H5Arename"); + + H5E_BEGIN_TRY + { + err_ret = H5Arename(fid, INVALID_RENAME_TEST_ATTR_NAME, NULL); + } + H5E_END_TRY; + + CHECK(err_ret, SUCCEED, "H5Arename"); + + H5E_BEGIN_TRY + { + err_ret = H5Arename(fid, INVALID_RENAME_TEST_ATTR_NAME, ""); + } + H5E_END_TRY; + + CHECK(err_ret, SUCCEED, "H5Arename"); + + H5E_BEGIN_TRY + { + err_ret = H5Arename_by_name(fid, ".", NULL, INVALID_RENAME_TEST_NEW_ATTR_NAME, H5P_DEFAULT); + } + H5E_END_TRY; + + CHECK(err_ret, SUCCEED, "H5Arename_by_name"); + + H5E_BEGIN_TRY + { + err_ret = H5Arename_by_name(fid, ".", "", INVALID_RENAME_TEST_NEW_ATTR_NAME, H5P_DEFAULT); + } + H5E_END_TRY; + + CHECK(err_ret, SUCCEED, "H5Arename_by_name"); + + H5E_BEGIN_TRY + { + err_ret = H5Arename_by_name(fid, ".", INVALID_RENAME_TEST_ATTR_NAME, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + + CHECK(err_ret, SUCCEED, "H5Arename_by_name"); + + H5E_BEGIN_TRY + { + err_ret = H5Arename_by_name(fid, ".", INVALID_RENAME_TEST_ATTR_NAME, "", H5P_DEFAULT); + } + H5E_END_TRY; + + CHECK(err_ret, SUCCEED, "H5Arename_by_name"); + + /* Close dataspace */ + err_ret = H5Sclose(sid); + CHECK(err_ret, FAIL, "H5Sclose"); + + /* Close attribute */ + err_ret = H5Aclose(attr); + CHECK(err_ret, FAIL, "H5Aclose"); + + /* Close file */ + err_ret = H5Fclose(fid); + CHECK(err_ret, FAIL, "H5Fclose"); +} + +/*************************************************************** +** +** test_attr_get_name_invalid_buf(): A test to ensure that +** passing a NULL buffer to H5Aget_name(_by_idx) when +** the 'size' parameter is non-zero doesn't cause bad +** behavior. +** +****************************************************************/ +static void +test_attr_get_name_invalid_buf(hid_t fcpl, hid_t fapl) +{ + ssize_t err_ret = -1; + hid_t fid; + hid_t attr; + hid_t sid; + + /* Create dataspace for attribute */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create attribute */ + attr = + H5Acreate2(fid, GET_NAME_INVALID_BUF_TEST_ATTR_NAME, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + H5E_BEGIN_TRY + { + err_ret = H5Aget_name(attr, 1, NULL); + } + H5E_END_TRY; + + VERIFY(err_ret, FAIL, "H5Aget_name"); + + H5E_BEGIN_TRY + { + err_ret = H5Aget_name_by_idx(fid, ".", H5_INDEX_NAME, H5_ITER_INC, 0, NULL, 1, H5P_DEFAULT); + } + H5E_END_TRY; + + VERIFY(err_ret, FAIL, "H5Aget_name_by_idx"); + + /* Close dataspace */ + err_ret = H5Sclose(sid); + CHECK(err_ret, FAIL, "H5Sclose"); + + /* Close attribute */ + err_ret = H5Aclose(attr); + CHECK(err_ret, FAIL, "H5Aclose"); + + /* Close file */ + err_ret = H5Fclose(fid); + CHECK(err_ret, FAIL, "H5Fclose"); +} + +/**************************************************************** +** +** test_attr_delete_by_idx(): Test basic H5A (attribute) code. +** Tests deleting attribute by index +** +****************************************************************/ +static void +test_attr_delete_by_idx(hbool_t new_format, hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* HDF5 File ID */ + hid_t dset1, dset2, dset3; /* Dataset IDs */ + hid_t my_dataset; /* Current dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t attr; /* Attribute ID */ + hid_t dcpl; /* Dataset creation property list ID */ + H5A_info_t ainfo; /* Attribute information */ + unsigned max_compact; /* Maximum # of links to store in group compactly */ + unsigned min_dense; /* Minimum # of links to store in group "densely" */ +#if 0 + htri_t is_empty; /* Are there any attributes? */ + htri_t is_dense; /* Are attributes stored densely? */ + hsize_t nattrs; /* Number of attributes on object */ + hsize_t name_count; /* # of records in name index */ + hsize_t corder_count; /* # of records in creation order index */ +#endif + H5_index_t idx_type; /* Type of index to operate on */ + H5_iter_order_t order; /* Order within in the index */ + unsigned use_index; /* Use index on creation order values */ + char attrname[NAME_BUF_SIZE]; /* Name of attribute */ + char tmpname[NAME_BUF_SIZE]; /* Temporary attribute name */ + unsigned curr_dset; /* Current dataset to work on */ + unsigned u; /* Local index variable */ + herr_t ret; /* Generic return value */ + + MESSAGE(5, ("Testing Deleting Attribute By Index\n")) + + /* Create dataspace for dataset & attributes */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create dataset creation property list */ + if (dcpl_g == H5P_DEFAULT) { + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + } + else { + dcpl = H5Pcopy(dcpl_g); + CHECK(dcpl, FAIL, "H5Pcopy"); + } + + /* Query the attribute creation properties */ + ret = H5Pget_attr_phase_change(dcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + + /* Loop over operating on different indices on link fields */ + for (idx_type = H5_INDEX_NAME; idx_type <= H5_INDEX_CRT_ORDER; idx_type++) { + /* Loop over operating in different orders */ + for (order = H5_ITER_INC; order <= H5_ITER_DEC; order++) { + /* Loop over using index for creation order value */ + for (use_index = FALSE; use_index <= TRUE; use_index++) { + /* Print appropriate test message */ + if (idx_type == H5_INDEX_CRT_ORDER) { + if (order == H5_ITER_INC) { + if (use_index) + MESSAGE(5, ("Testing Deleting Attribute By Creation Order Index in Increasing " + "Order w/Creation Order Index\n")) + else + MESSAGE(5, ("Testing Deleting Attribute By Creation Order Index in Increasing " + "Order w/o Creation Order Index\n")) + } /* end if */ + else { + if (use_index) + MESSAGE(5, ("Testing Deleting Attribute By Creation Order Index in Decreasing " + "Order w/Creation Order Index\n")) + else + MESSAGE(5, ("Testing Deleting Attribute By Creation Order Index in Decreasing " + "Order w/o Creation Order Index\n")) + } /* end else */ + } /* end if */ + else { + if (order == H5_ITER_INC) { + if (use_index) + MESSAGE(5, ("Testing Deleting Attribute By Name Index in Increasing Order " + "w/Creation Order Index\n")) + else + MESSAGE(5, ("Testing Deleting Attribute By Name Index in Increasing Order w/o " + "Creation Order Index\n")) + } /* end if */ + else { +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + if (use_index) + MESSAGE(5, ("Testing Deleting Attribute By Name Index in Decreasing Order " + "w/Creation Order Index\n")) + else + MESSAGE(5, ("Testing Deleting Attribute By Name Index in Decreasing Order w/o " + "Creation Order Index\n")) +#else + continue; +#endif + } /* end else */ + } /* end else */ + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Set attribute creation order tracking & indexing for object */ + if (new_format == TRUE) { + ret = H5Pset_attr_creation_order( + dcpl, (H5P_CRT_ORDER_TRACKED | (use_index ? H5P_CRT_ORDER_INDEXED : (unsigned)0))); + CHECK(ret, FAIL, "H5Pset_attr_creation_order"); + } /* end if */ + + /* Create datasets */ + dset1 = H5Dcreate2(fid, DSET1_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset1, FAIL, "H5Dcreate2"); + dset2 = H5Dcreate2(fid, DSET2_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset2, FAIL, "H5Dcreate2"); + dset3 = H5Dcreate2(fid, DSET3_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset3, FAIL, "H5Dcreate2"); + + /* Work on all the datasets */ + for (curr_dset = 0; curr_dset < NUM_DSETS; curr_dset++) { + switch (curr_dset) { + case 0: + my_dataset = dset1; + break; + + case 1: + my_dataset = dset2; + break; + + case 2: + my_dataset = dset3; + break; + + default: + HDassert(0 && "Too many datasets!"); + } /* end switch */ +#if 0 + /* Check on dataset's attribute storage status */ + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, TRUE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Check for deleting non-existent attribute */ + H5E_BEGIN_TRY + { + ret = H5Adelete_by_idx(my_dataset, ".", idx_type, order, (hsize_t)0, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Adelete_by_idx"); + + /* Create attributes, up to limit of compact form */ + for (u = 0; u < max_compact; u++) { + /* Create attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = + H5Acreate2(my_dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Verify information for new attribute */ + ret = attr_info_by_idx_check(my_dataset, attrname, (hsize_t)u, use_index); + CHECK(ret, FAIL, "attr_info_by_idx_check"); + } /* end for */ +#if 0 + /* Verify state of object */ + ret = H5O__num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O__num_attrs_test"); + VERIFY(nattrs, max_compact, "H5O__num_attrs_test"); + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Check for out of bound deletions */ + H5E_BEGIN_TRY + { + ret = H5Adelete_by_idx(my_dataset, ".", idx_type, order, (hsize_t)u, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Adelete_by_idx"); + } /* end for */ + + /* Work on all the datasets */ + for (curr_dset = 0; curr_dset < NUM_DSETS; curr_dset++) { + switch (curr_dset) { + case 0: + my_dataset = dset1; + break; + + case 1: + my_dataset = dset2; + break; + + case 2: + my_dataset = dset3; + break; + + default: + HDassert(0 && "Too many datasets!"); + } /* end switch */ + + /* Delete attributes from compact storage */ + for (u = 0; u < (max_compact - 1); u++) { + /* Delete first attribute in appropriate order */ + ret = H5Adelete_by_idx(my_dataset, ".", idx_type, order, (hsize_t)0, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Adelete_by_idx"); + + /* Verify the attribute information for first attribute in appropriate order */ + HDmemset(&ainfo, 0, sizeof(ainfo)); + ret = H5Aget_info_by_idx(my_dataset, ".", idx_type, order, (hsize_t)0, &ainfo, + H5P_DEFAULT); + if (new_format) { + if (order == H5_ITER_INC) { + VERIFY(ainfo.corder, (u + 1), "H5Aget_info_by_idx"); + } /* end if */ + else { + VERIFY(ainfo.corder, (max_compact - (u + 2)), "H5Aget_info_by_idx"); + } /* end else */ + } /* end if */ + + /* Verify the name for first attribute in appropriate order */ + HDmemset(tmpname, 0, (size_t)NAME_BUF_SIZE); + ret = (herr_t)H5Aget_name_by_idx(my_dataset, ".", idx_type, order, (hsize_t)0, + tmpname, (size_t)NAME_BUF_SIZE, H5P_DEFAULT); + if (order == H5_ITER_INC) + HDsnprintf(attrname, sizeof(attrname), "attr %02u", (u + 1)); + else + HDsnprintf(attrname, sizeof(attrname), "attr %02u", (max_compact - (u + 2))); + ret = HDstrcmp(attrname, tmpname); + VERIFY(ret, 0, "H5Aget_name_by_idx"); + } /* end for */ + + /* Delete last attribute */ + ret = H5Adelete_by_idx(my_dataset, ".", idx_type, order, (hsize_t)0, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Adelete_by_idx"); +#if 0 + /* Verify state of attribute storage (empty) */ + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, TRUE, "H5O__is_attr_empty_test"); +#endif + } /* end for */ + + /* Work on all the datasets */ + for (curr_dset = 0; curr_dset < NUM_DSETS; curr_dset++) { + switch (curr_dset) { + case 0: + my_dataset = dset1; + break; + + case 1: + my_dataset = dset2; + break; + + case 2: + my_dataset = dset3; + break; + + default: + HDassert(0 && "Too many datasets!"); + } /* end switch */ + + /* Create more attributes, to push into dense form */ + for (u = 0; u < (max_compact * 2); u++) { + /* Create attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = + H5Acreate2(my_dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); +#if 0 + /* Verify state of object */ + if (u >= max_compact) { + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, (new_format ? TRUE : FALSE), "H5O__is_attr_dense_test"); + } /* end if */ +#endif + /* Verify information for new attribute */ + ret = attr_info_by_idx_check(my_dataset, attrname, (hsize_t)u, use_index); + CHECK(ret, FAIL, "attr_info_by_idx_check"); + } /* end for */ +#if 0 + /* Verify state of object */ + ret = H5O__num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O__num_attrs_test"); + VERIFY(nattrs, (max_compact * 2), "H5O__num_attrs_test"); + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, (new_format ? TRUE : FALSE), "H5O__is_attr_dense_test"); + + if (new_format) { + /* Retrieve & verify # of records in the name & creation order indices */ + ret = H5O__attr_dense_info_test(my_dataset, &name_count, &corder_count); + CHECK(ret, FAIL, "H5O__attr_dense_info_test"); + if (use_index) + VERIFY(name_count, corder_count, "H5O__attr_dense_info_test"); + VERIFY(name_count, (max_compact * 2), "H5O__attr_dense_info_test"); + } /* end if */ +#endif + /* Check for out of bound deletion */ + H5E_BEGIN_TRY + { + ret = H5Adelete_by_idx(my_dataset, ".", idx_type, order, (hsize_t)u, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Adelete_by_idx"); + } /* end for */ + + /* Work on all the datasets */ + for (curr_dset = 0; curr_dset < NUM_DSETS; curr_dset++) { + switch (curr_dset) { + case 0: + my_dataset = dset1; + break; + + case 1: + my_dataset = dset2; + break; + + case 2: + my_dataset = dset3; + break; + + default: + HDassert(0 && "Too many datasets!"); + } /* end switch */ + + /* Delete attributes from dense storage */ + for (u = 0; u < ((max_compact * 2) - 1); u++) { + /* Delete first attribute in appropriate order */ + ret = H5Adelete_by_idx(my_dataset, ".", idx_type, order, (hsize_t)0, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Adelete_by_idx"); + + /* Verify the attribute information for first attribute in appropriate order */ + HDmemset(&ainfo, 0, sizeof(ainfo)); + ret = H5Aget_info_by_idx(my_dataset, ".", idx_type, order, (hsize_t)0, &ainfo, + H5P_DEFAULT); + if (new_format) { + if (order == H5_ITER_INC) { + VERIFY(ainfo.corder, (u + 1), "H5Aget_info_by_idx"); + } /* end if */ + else { + VERIFY(ainfo.corder, ((max_compact * 2) - (u + 2)), "H5Aget_info_by_idx"); + } /* end else */ + } /* end if */ + + /* Verify the name for first attribute in appropriate order */ + HDmemset(tmpname, 0, (size_t)NAME_BUF_SIZE); + ret = (herr_t)H5Aget_name_by_idx(my_dataset, ".", idx_type, order, (hsize_t)0, + tmpname, (size_t)NAME_BUF_SIZE, H5P_DEFAULT); + if (order == H5_ITER_INC) + HDsnprintf(attrname, sizeof(attrname), "attr %02u", (u + 1)); + else + HDsnprintf(attrname, sizeof(attrname), "attr %02u", + ((max_compact * 2) - (u + 2))); + ret = HDstrcmp(attrname, tmpname); + VERIFY(ret, 0, "H5Aget_name_by_idx"); + } /* end for */ + + /* Delete last attribute */ + ret = H5Adelete_by_idx(my_dataset, ".", idx_type, order, (hsize_t)0, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Adelete_by_idx"); +#if 0 + /* Verify state of attribute storage (empty) */ + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, TRUE, "H5O__is_attr_empty_test"); +#endif + /* Check for deletion on empty attribute storage again */ + H5E_BEGIN_TRY + { + ret = H5Adelete_by_idx(my_dataset, ".", idx_type, order, (hsize_t)0, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Adelete_by_idx"); + } /* end for */ + + /* Delete attributes in middle */ + + /* Work on all the datasets */ + for (curr_dset = 0; curr_dset < NUM_DSETS; curr_dset++) { + switch (curr_dset) { + case 0: + my_dataset = dset1; + break; + + case 1: + my_dataset = dset2; + break; + + case 2: + my_dataset = dset3; + break; + + default: + HDassert(0 && "Too many datasets!"); + } /* end switch */ + + /* Create attributes, to push into dense form */ + for (u = 0; u < (max_compact * 2); u++) { + /* Create attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = + H5Acreate2(my_dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); +#if 0 + /* Verify state of object */ + if (u >= max_compact) { + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, (new_format ? TRUE : FALSE), "H5O__is_attr_dense_test"); + } /* end if */ +#endif + /* Verify information for new attribute */ + ret = attr_info_by_idx_check(my_dataset, attrname, (hsize_t)u, use_index); + CHECK(ret, FAIL, "attr_info_by_idx_check"); + } /* end for */ + } /* end for */ + + /* Work on all the datasets */ + for (curr_dset = 0; curr_dset < NUM_DSETS; curr_dset++) { + switch (curr_dset) { + case 0: + my_dataset = dset1; + break; + + case 1: + my_dataset = dset2; + break; + + case 2: + my_dataset = dset3; + break; + + default: + HDassert(0 && "Too many datasets!"); + } /* end switch */ + + /* Delete every other attribute from dense storage, in appropriate order */ + for (u = 0; u < max_compact; u++) { + /* Delete attribute */ + ret = H5Adelete_by_idx(my_dataset, ".", idx_type, order, (hsize_t)u, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Adelete_by_idx"); + + /* Verify the attribute information for first attribute in appropriate order */ + HDmemset(&ainfo, 0, sizeof(ainfo)); + ret = H5Aget_info_by_idx(my_dataset, ".", idx_type, order, (hsize_t)u, &ainfo, + H5P_DEFAULT); + if (new_format) { + if (order == H5_ITER_INC) { + VERIFY(ainfo.corder, ((u * 2) + 1), "H5Aget_info_by_idx"); + } /* end if */ + else { + VERIFY(ainfo.corder, ((max_compact * 2) - ((u * 2) + 2)), + "H5Aget_info_by_idx"); + } /* end else */ + } /* end if */ + + /* Verify the name for first attribute in appropriate order */ + HDmemset(tmpname, 0, (size_t)NAME_BUF_SIZE); + ret = (herr_t)H5Aget_name_by_idx(my_dataset, ".", idx_type, order, (hsize_t)u, + tmpname, (size_t)NAME_BUF_SIZE, H5P_DEFAULT); + if (order == H5_ITER_INC) + HDsnprintf(attrname, sizeof(attrname), "attr %02u", ((u * 2) + 1)); + else + HDsnprintf(attrname, sizeof(attrname), "attr %02u", + ((max_compact * 2) - ((u * 2) + 2))); + ret = HDstrcmp(attrname, tmpname); + VERIFY(ret, 0, "H5Aget_name_by_idx"); + } /* end for */ + } /* end for */ + + /* Work on all the datasets */ + for (curr_dset = 0; curr_dset < NUM_DSETS; curr_dset++) { + switch (curr_dset) { + case 0: + my_dataset = dset1; + break; + + case 1: + my_dataset = dset2; + break; + + case 2: + my_dataset = dset3; + break; + + default: + HDassert(0 && "Too many datasets!"); + } /* end switch */ + + /* Delete remaining attributes from dense storage, in appropriate order */ + for (u = 0; u < (max_compact - 1); u++) { + /* Delete attribute */ + ret = H5Adelete_by_idx(my_dataset, ".", idx_type, order, (hsize_t)0, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Adelete_by_idx"); + + /* Verify the attribute information for first attribute in appropriate order */ + HDmemset(&ainfo, 0, sizeof(ainfo)); + ret = H5Aget_info_by_idx(my_dataset, ".", idx_type, order, (hsize_t)0, &ainfo, + H5P_DEFAULT); + if (new_format) { + if (order == H5_ITER_INC) { + VERIFY(ainfo.corder, ((u * 2) + 3), "H5Aget_info_by_idx"); + } /* end if */ + else { + VERIFY(ainfo.corder, ((max_compact * 2) - ((u * 2) + 4)), + "H5Aget_info_by_idx"); + } /* end else */ + } /* end if */ + + /* Verify the name for first attribute in appropriate order */ + HDmemset(tmpname, 0, (size_t)NAME_BUF_SIZE); + ret = (herr_t)H5Aget_name_by_idx(my_dataset, ".", idx_type, order, (hsize_t)0, + tmpname, (size_t)NAME_BUF_SIZE, H5P_DEFAULT); + if (order == H5_ITER_INC) + HDsnprintf(attrname, sizeof(attrname), "attr %02u", ((u * 2) + 3)); + else + HDsnprintf(attrname, sizeof(attrname), "attr %02u", + ((max_compact * 2) - ((u * 2) + 4))); + ret = HDstrcmp(attrname, tmpname); + VERIFY(ret, 0, "H5Aget_name_by_idx"); + } /* end for */ + + /* Delete last attribute */ + ret = H5Adelete_by_idx(my_dataset, ".", idx_type, order, (hsize_t)0, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Adelete_by_idx"); +#if 0 + /* Verify state of attribute storage (empty) */ + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, TRUE, "H5O__is_attr_empty_test"); +#endif + /* Check for deletion on empty attribute storage again */ + H5E_BEGIN_TRY + { + ret = H5Adelete_by_idx(my_dataset, ".", idx_type, order, (hsize_t)0, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Adelete_by_idx"); + } /* end for */ + + /* Close Datasets */ + ret = H5Dclose(dset1); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset2); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset3); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + } /* end for */ + } /* end for */ + } /* end for */ + + /* Close property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_attr_delete_by_idx() */ + +/**************************************************************** +** +** attr_iterate2_cb(): Revised attribute operator +** +****************************************************************/ +static herr_t +attr_iterate2_cb(hid_t loc_id, const char *attr_name, const H5A_info_t *info, void *_op_data) +{ + attr_iter_info_t *op_data = (attr_iter_info_t *)_op_data; /* User data */ + char attrname[NAME_BUF_SIZE]; /* Object name */ + H5A_info_t my_info; /* Local attribute info */ + + /* Increment # of times the callback was called */ + op_data->ncalled++; + + /* Get the attribute information directly to compare */ + if (H5Aget_info_by_name(loc_id, ".", attr_name, &my_info, H5P_DEFAULT) < 0) + return (H5_ITER_ERROR); + + /* Check more things for revised attribute iteration (vs. older attribute iteration) */ + if (info) { + /* Check for correct order of iteration */ + /* (if we are operating in increasing or decreasing order) */ + if (op_data->order != H5_ITER_NATIVE) + if (info->corder != op_data->curr) + return (H5_ITER_ERROR); + + /* Compare attribute info structs */ + if (info->corder_valid != my_info.corder_valid) + return (H5_ITER_ERROR); + if (info->corder != my_info.corder) + return (H5_ITER_ERROR); + if (info->cset != my_info.cset) + return (H5_ITER_ERROR); + if (info->data_size != my_info.data_size) + return (H5_ITER_ERROR); + } /* end if */ + + /* Verify name of link */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", (unsigned)my_info.corder); + if (HDstrcmp(attr_name, attrname) != 0) + return (H5_ITER_ERROR); + + /* Check if we've visited this link before */ + if ((size_t)op_data->curr >= op_data->max_visit) + return (H5_ITER_ERROR); + if (op_data->visited[op_data->curr]) + return (H5_ITER_ERROR); + op_data->visited[op_data->curr] = TRUE; + + /* Advance to next value, in correct direction */ + if (op_data->order != H5_ITER_DEC) + op_data->curr++; + else + op_data->curr--; + + /* Check for stopping in the middle of iterating */ + if (op_data->stop > 0) + if (--op_data->stop == 0) + return (CORDER_ITER_STOP); + + return (H5_ITER_CONT); +} /* end attr_iterate2_cb() */ + +#ifndef H5_NO_DEPRECATED_SYMBOLS + +/**************************************************************** +** +** attr_iterate1_cb(): Attribute operator +** +****************************************************************/ +#if 0 +static herr_t +attr_iterate1_cb(hid_t loc_id, const char *attr_name, void *_op_data) +{ + return (attr_iterate2_cb(loc_id, attr_name, NULL, _op_data)); +} /* end attr_iterate1_cb() */ +#endif /* H5_NO_DEPRECATED_SYMBOLS */ +#endif + +#ifndef NO_ITERATION_RESTART +/*------------------------------------------------------------------------- + * Function: attr_iterate2_fail_cb + * + * Purpose: Callback routine for iterating over attributes on object that + * always returns failure + * + * Return: Success: 0 + * Failure: -1 + * + * Programmer: Quincey Koziol + * Tuesday, February 20, 2007 + * + *------------------------------------------------------------------------- + */ +static int +attr_iterate2_fail_cb(hid_t H5_ATTR_UNUSED group_id, const char H5_ATTR_UNUSED *attr_name, + const H5A_info_t H5_ATTR_UNUSED *info, void H5_ATTR_UNUSED *_op_data) +{ + return (H5_ITER_ERROR); +} /* end attr_iterate2_fail_cb() */ + +/*------------------------------------------------------------------------- + * Function: attr_iterate_check + * + * Purpose: Check iteration over attributes on an object + * + * Return: Success: 0 + * Failure: -1 + * + * Programmer: Quincey Koziol + * Tuesday, February 20, 2007 + * + *------------------------------------------------------------------------- + */ +static int +attr_iterate_check(hid_t fid, const char *dsetname, hid_t obj_id, H5_index_t idx_type, H5_iter_order_t order, + unsigned max_attrs, attr_iter_info_t *iter_info) +{ + unsigned v; /* Local index variable */ + hsize_t skip; /* # of attributes to skip on object */ +#if 0 +#ifndef H5_NO_DEPRECATED_SYMBOLS + unsigned oskip; /* # of attributes to skip on object, with H5Aiterate1 */ +#endif /* H5_NO_DEPRECATED_SYMBOLS */ +#endif + int old_nerrs; /* Number of errors when entering this check */ + herr_t ret; /* Generic return value */ + + /* Retrieve the current # of reported errors */ + old_nerrs = nerrors; + + /* Iterate over attributes on object */ + iter_info->nskipped = (unsigned)(skip = 0); + iter_info->order = order; + iter_info->stop = -1; + iter_info->ncalled = 0; + iter_info->curr = order != H5_ITER_DEC ? 0 : (max_attrs - 1); + HDmemset(iter_info->visited, 0, sizeof(hbool_t) * iter_info->max_visit); + ret = H5Aiterate2(obj_id, idx_type, order, &skip, attr_iterate2_cb, iter_info); + CHECK(ret, FAIL, "H5Aiterate2"); + + /* Verify that we visited all the attributes */ + VERIFY(skip, max_attrs, "H5Aiterate2"); + for (v = 0; v < max_attrs; v++) + VERIFY(iter_info->visited[v], TRUE, "H5Aiterate2"); + + /* Iterate over attributes on object */ + iter_info->nskipped = (unsigned)(skip = 0); + iter_info->order = order; + iter_info->stop = -1; + iter_info->ncalled = 0; + iter_info->curr = order != H5_ITER_DEC ? 0 : (max_attrs - 1); + HDmemset(iter_info->visited, 0, sizeof(hbool_t) * iter_info->max_visit); + ret = H5Aiterate_by_name(fid, dsetname, idx_type, order, &skip, attr_iterate2_cb, iter_info, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aiterate_by_name"); + + /* Verify that we visited all the attributes */ + VERIFY(skip, max_attrs, "H5Aiterate_by_name"); + for (v = 0; v < max_attrs; v++) + VERIFY(iter_info->visited[v], TRUE, "H5Aiterate_by_name"); + + /* Iterate over attributes on object */ + iter_info->nskipped = (unsigned)(skip = 0); + iter_info->order = order; + iter_info->stop = -1; + iter_info->ncalled = 0; + iter_info->curr = order != H5_ITER_DEC ? 0 : (max_attrs - 1); + HDmemset(iter_info->visited, 0, sizeof(hbool_t) * iter_info->max_visit); + ret = H5Aiterate_by_name(obj_id, ".", idx_type, order, &skip, attr_iterate2_cb, iter_info, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aiterate_by_name"); + + /* Verify that we visited all the attributes */ + VERIFY(skip, max_attrs, "H5Aiterate_by_name"); + for (v = 0; v < max_attrs; v++) + VERIFY(iter_info->visited[v], TRUE, "H5Aiterate_by_name"); + +#if 0 +#ifndef H5_NO_DEPRECATED_SYMBOLS + /* Iterate over attributes on object, with H5Aiterate1 */ + iter_info->nskipped = oskip = 0; + iter_info->order = order; + iter_info->stop = -1; + iter_info->ncalled = 0; + iter_info->curr = order != H5_ITER_DEC ? 0 : (max_attrs - 1); + HDmemset(iter_info->visited, 0, sizeof(hbool_t) * iter_info->max_visit); + ret = H5Aiterate1(obj_id, &oskip, attr_iterate1_cb, iter_info); + CHECK(ret, FAIL, "H5Aiterate1"); + + /* Verify that we visited all the attributes */ + VERIFY(skip, max_attrs, "H5Aiterate1"); + for (v = 0; v < max_attrs; v++) + VERIFY(iter_info->visited[v], TRUE, "H5Aiterate1"); +#endif /* H5_NO_DEPRECATED_SYMBOLS */ +#endif + + /* Skip over some attributes on object */ + iter_info->nskipped = (unsigned)(skip = max_attrs / 2); + iter_info->order = order; + iter_info->stop = -1; + iter_info->ncalled = 0; + iter_info->curr = order != H5_ITER_DEC ? skip : ((max_attrs - 1) - skip); + HDmemset(iter_info->visited, 0, sizeof(hbool_t) * iter_info->max_visit); + ret = H5Aiterate2(obj_id, idx_type, order, &skip, attr_iterate2_cb, iter_info); + CHECK(ret, FAIL, "H5Aiterate2"); + + /* Verify that we visited all the attributes */ + VERIFY(skip, max_attrs, "H5Aiterate2"); + if (order == H5_ITER_INC) { + for (v = 0; v < (max_attrs / 2); v++) + VERIFY(iter_info->visited[v + (max_attrs / 2)], TRUE, "H5Aiterate2"); + } /* end if */ + else if (order == H5_ITER_DEC) { + for (v = 0; v < (max_attrs / 2); v++) + VERIFY(iter_info->visited[v], TRUE, "H5Aiterate2"); + } /* end if */ + else { + unsigned nvisit = 0; /* # of links visited */ + + HDassert(order == H5_ITER_NATIVE); + for (v = 0; v < max_attrs; v++) + if (iter_info->visited[v] == TRUE) + nvisit++; + + VERIFY(skip, (max_attrs / 2), "H5Aiterate2"); + } /* end else */ + + /* Skip over some attributes on object */ + iter_info->nskipped = (unsigned)(skip = max_attrs / 2); + iter_info->order = order; + iter_info->stop = -1; + iter_info->ncalled = 0; + iter_info->curr = order != H5_ITER_DEC ? skip : ((max_attrs - 1) - skip); + HDmemset(iter_info->visited, 0, sizeof(hbool_t) * iter_info->max_visit); + ret = H5Aiterate_by_name(fid, dsetname, idx_type, order, &skip, attr_iterate2_cb, iter_info, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aiterate_by_name"); + + /* Verify that we visited all the attributes */ + VERIFY(skip, max_attrs, "H5Aiterate_by_name"); + if (order == H5_ITER_INC) { + for (v = 0; v < (max_attrs / 2); v++) + VERIFY(iter_info->visited[v + (max_attrs / 2)], TRUE, "H5Aiterate_by_name"); + } /* end if */ + else if (order == H5_ITER_DEC) { + for (v = 0; v < (max_attrs / 2); v++) + VERIFY(iter_info->visited[v], TRUE, "H5Aiterate_by_name"); + } /* end if */ + else { + unsigned nvisit = 0; /* # of links visited */ + + HDassert(order == H5_ITER_NATIVE); + for (v = 0; v < max_attrs; v++) + if (iter_info->visited[v] == TRUE) + nvisit++; + + VERIFY(skip, (max_attrs / 2), "H5Aiterate_by_name"); + } /* end else */ + + /* Skip over some attributes on object */ + iter_info->nskipped = (unsigned)(skip = max_attrs / 2); + iter_info->order = order; + iter_info->stop = -1; + iter_info->ncalled = 0; + iter_info->curr = order != H5_ITER_DEC ? skip : ((max_attrs - 1) - skip); + HDmemset(iter_info->visited, 0, sizeof(hbool_t) * iter_info->max_visit); + ret = H5Aiterate_by_name(obj_id, ".", idx_type, order, &skip, attr_iterate2_cb, iter_info, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aiterate_by_name"); + + /* Verify that we visited all the attributes */ + VERIFY(skip, max_attrs, "H5Aiterate_by_name"); + if (order == H5_ITER_INC) { + for (v = 0; v < (max_attrs / 2); v++) + VERIFY(iter_info->visited[v + (max_attrs / 2)], TRUE, "H5Aiterate_by_name"); + } /* end if */ + else if (order == H5_ITER_DEC) { + for (v = 0; v < (max_attrs / 2); v++) + VERIFY(iter_info->visited[v], TRUE, "H5Aiterate_by_name"); + } /* end if */ + else { + unsigned nvisit = 0; /* # of links visited */ + + HDassert(order == H5_ITER_NATIVE); + for (v = 0; v < max_attrs; v++) + if (iter_info->visited[v] == TRUE) + nvisit++; + + VERIFY(skip, (max_attrs / 2), "H5Aiterate_by_name"); + } /* end else */ + +#if 0 +#ifndef H5_NO_DEPRECATED_SYMBOLS + /* Skip over some attributes on object, with H5Aiterate1 */ + iter_info->nskipped = oskip = max_attrs / 2; + iter_info->order = order; + iter_info->stop = -1; + iter_info->ncalled = 0; + iter_info->curr = order != H5_ITER_DEC ? (unsigned)oskip : ((max_attrs - 1) - oskip); + HDmemset(iter_info->visited, 0, sizeof(hbool_t) * iter_info->max_visit); + ret = H5Aiterate1(obj_id, &oskip, attr_iterate1_cb, iter_info); + CHECK(ret, FAIL, "H5Aiterate1"); + + /* Verify that we visited all the links */ + VERIFY(oskip, max_attrs, "H5Aiterate1"); + if (order == H5_ITER_INC) { + for (v = 0; v < (max_attrs / 2); v++) + VERIFY(iter_info->visited[v + (max_attrs / 2)], TRUE, "H5Aiterate1"); + } /* end if */ + else if (order == H5_ITER_DEC) { + for (v = 0; v < (max_attrs / 2); v++) + VERIFY(iter_info->visited[v], TRUE, "H5Aiterate1"); + } /* end if */ + else { + unsigned nvisit = 0; /* # of links visited */ + + HDassert(order == H5_ITER_NATIVE); + for (v = 0; v < max_attrs; v++) + if (iter_info->visited[v] == TRUE) + nvisit++; + + VERIFY(skip, (max_attrs / 2), "H5Aiterate1"); + } /* end else */ +#endif /* H5_NO_DEPRECATED_SYMBOLS */ +#endif + + /* Iterate over attributes on object, stopping in the middle */ + iter_info->nskipped = (unsigned)(skip = 0); + iter_info->order = order; + iter_info->stop = 3; + iter_info->ncalled = 0; + iter_info->curr = order != H5_ITER_DEC ? 0 : (max_attrs - 1); + HDmemset(iter_info->visited, 0, sizeof(hbool_t) * iter_info->max_visit); + ret = H5Aiterate2(obj_id, idx_type, order, &skip, attr_iterate2_cb, iter_info); + CHECK(ret, FAIL, "H5Aiterate2"); + VERIFY(ret, CORDER_ITER_STOP, "H5Aiterate2"); + VERIFY(iter_info->ncalled, 3, "H5Aiterate2"); + + /* Iterate over attributes on object, stopping in the middle */ + iter_info->nskipped = (unsigned)(skip = 0); + iter_info->order = order; + iter_info->stop = 3; + iter_info->ncalled = 0; + iter_info->curr = order != H5_ITER_DEC ? 0 : (max_attrs - 1); + HDmemset(iter_info->visited, 0, sizeof(hbool_t) * iter_info->max_visit); + ret = H5Aiterate_by_name(fid, dsetname, idx_type, order, &skip, attr_iterate2_cb, iter_info, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aiterate_by_name"); + VERIFY(ret, CORDER_ITER_STOP, "H5Aiterate_by_name"); + VERIFY(iter_info->ncalled, 3, "H5Aiterate_by_name"); + + /* Iterate over attributes on object, stopping in the middle */ + iter_info->nskipped = (unsigned)(skip = 0); + iter_info->order = order; + iter_info->stop = 3; + iter_info->ncalled = 0; + iter_info->curr = order != H5_ITER_DEC ? 0 : (max_attrs - 1); + HDmemset(iter_info->visited, 0, sizeof(hbool_t) * iter_info->max_visit); + ret = H5Aiterate_by_name(obj_id, ".", idx_type, order, &skip, attr_iterate2_cb, iter_info, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aiterate_by_name"); + VERIFY(ret, CORDER_ITER_STOP, "H5Aiterate_by_name"); + VERIFY(iter_info->ncalled, 3, "H5Aiterate_by_name"); + +#if 0 +#ifndef H5_NO_DEPRECATED_SYMBOLS + /* Iterate over attributes on object, stopping in the middle, with H5Aiterate1() */ + iter_info->nskipped = oskip = 0; + iter_info->order = order; + iter_info->stop = 3; + iter_info->ncalled = 0; + iter_info->curr = order != H5_ITER_DEC ? 0 : (max_attrs - 1); + HDmemset(iter_info->visited, 0, sizeof(hbool_t) * iter_info->max_visit); + ret = H5Aiterate1(obj_id, &oskip, attr_iterate1_cb, iter_info); + CHECK(ret, FAIL, "H5Aiterate1"); + VERIFY(ret, CORDER_ITER_STOP, "H5Aiterate1"); + VERIFY(iter_info->ncalled, 3, "H5Aiterate1"); +#endif /* H5_NO_DEPRECATED_SYMBOLS */ +#endif + + /* Check for iteration routine indicating failure */ + skip = 0; + H5E_BEGIN_TRY + { + ret = H5Aiterate2(obj_id, idx_type, order, &skip, attr_iterate2_fail_cb, NULL); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Aiterate2"); + + skip = 0; + H5E_BEGIN_TRY + { + ret = H5Aiterate_by_name(fid, dsetname, idx_type, order, &skip, attr_iterate2_fail_cb, NULL, + H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Aiterate_by_name"); + + skip = 0; + H5E_BEGIN_TRY + { + ret = + H5Aiterate_by_name(obj_id, ".", idx_type, order, &skip, attr_iterate2_fail_cb, NULL, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Aiterate_by_name"); + + /* Retrieve current # of errors */ + if (old_nerrs == nerrors) + return (0); + else + return (-1); +} /* end attr_iterate_check() */ +#endif + +/**************************************************************** +** +** test_attr_iterate2(): Test basic H5A (attribute) code. +** Tests iterating over attributes by index +** +****************************************************************/ +static void +test_attr_iterate2(hbool_t new_format, hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* HDF5 File ID */ + hid_t dset1, dset2, dset3; /* Dataset IDs */ + hid_t my_dataset; /* Current dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t attr; /* Attribute ID */ + hid_t dcpl; /* Dataset creation property list ID */ + unsigned max_compact; /* Maximum # of links to store in group compactly */ + unsigned min_dense; /* Minimum # of links to store in group "densely" */ +#if 0 + htri_t is_empty; /* Are there any attributes? */ + htri_t is_dense; /* Are attributes stored densely? */ + hsize_t nattrs; /* Number of attributes on object */ + hsize_t name_count; /* # of records in name index */ + hsize_t corder_count; /* # of records in creation order index */ +#endif + H5_index_t idx_type; /* Type of index to operate on */ + H5_iter_order_t order; /* Order within in the index */ + attr_iter_info_t iter_info; /* Iterator info */ + hbool_t *visited = NULL; /* Array of flags for visiting links */ +#ifndef NO_ITERATION_RESTART + hsize_t idx; /* Start index for iteration */ +#endif + unsigned use_index; /* Use index on creation order values */ + const char *dsetname; /* Name of dataset for attributes */ + char attrname[NAME_BUF_SIZE]; /* Name of attribute */ + unsigned curr_dset; /* Current dataset to work on */ + unsigned u; /* Local index variable */ + herr_t ret; /* Generic return value */ + + /* Create dataspace for dataset & attributes */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create dataset creation property list */ + if (dcpl_g == H5P_DEFAULT) { + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + } + else { + dcpl = H5Pcopy(dcpl_g); + CHECK(dcpl, FAIL, "H5Pcopy"); + } + + /* Query the attribute creation properties */ + ret = H5Pget_attr_phase_change(dcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + + /* Allocate the "visited link" array */ + iter_info.max_visit = max_compact * 2; + visited = (hbool_t *)HDmalloc(sizeof(hbool_t) * iter_info.max_visit); + CHECK_PTR(visited, "HDmalloc"); + iter_info.visited = visited; + + /* Loop over operating on different indices on link fields */ + for (idx_type = H5_INDEX_NAME; idx_type <= H5_INDEX_CRT_ORDER; idx_type++) { + /* Loop over operating in different orders */ + for (order = H5_ITER_INC; order <= H5_ITER_DEC; order++) { + /* Loop over using index for creation order value */ + for (use_index = FALSE; use_index <= TRUE; use_index++) { + /* Print appropriate test message */ + if (idx_type == H5_INDEX_CRT_ORDER) { + if (order == H5_ITER_INC) { + if (use_index) + MESSAGE(5, ("Testing Iterating over Attributes By Creation Order Index in " + "Increasing Order w/Creation Order Index\n")) + else + MESSAGE(5, ("Testing Iterating over Attributes By Creation Order Index in " + "Increasing Order w/o Creation Order Index\n")) + } /* end if */ + else { + if (use_index) + MESSAGE(5, ("Testing Iterating over Attributes By Creation Order Index in " + "Decreasing Order w/Creation Order Index\n")) + else + MESSAGE(5, ("Testing Iterating over Attributes By Creation Order Index in " + "Decreasing Order w/o Creation Order Index\n")) + } /* end else */ + } /* end if */ + else { + if (order == H5_ITER_INC) { + if (use_index) + MESSAGE(5, ("Testing Iterating over Attributes By Name Index in Increasing Order " + "w/Creation Order Index\n")) + else + MESSAGE(5, ("Testing Iterating over Attributes By Name Index in Increasing Order " + "w/o Creation Order Index\n")) + } /* end if */ + else { +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + if (use_index) + MESSAGE(5, ("Testing Iterating over Attributes By Name Index in Decreasing Order " + "w/Creation Order Index\n")) + else + MESSAGE(5, ("Testing Iterating over Attributes By Name Index in Decreasing Order " + "w/o Creation Order Index\n")) +#else + continue; +#endif + } /* end else */ + } /* end else */ + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Set attribute creation order tracking & indexing for object */ + if (new_format == TRUE) { + ret = H5Pset_attr_creation_order( + dcpl, (H5P_CRT_ORDER_TRACKED | (use_index ? H5P_CRT_ORDER_INDEXED : (unsigned)0))); + CHECK(ret, FAIL, "H5Pset_attr_creation_order"); + } /* end if */ + + /* Create datasets */ + dset1 = H5Dcreate2(fid, DSET1_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset1, FAIL, "H5Dcreate2"); + dset2 = H5Dcreate2(fid, DSET2_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset2, FAIL, "H5Dcreate2"); + dset3 = H5Dcreate2(fid, DSET3_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset3, FAIL, "H5Dcreate2"); + + /* Work on all the datasets */ + for (curr_dset = 0; curr_dset < NUM_DSETS; curr_dset++) { + switch (curr_dset) { + case 0: + my_dataset = dset1; + dsetname = DSET1_NAME; + break; + + case 1: + my_dataset = dset2; + dsetname = DSET2_NAME; + break; + + case 2: + my_dataset = dset3; + dsetname = DSET3_NAME; + break; + + default: + HDassert(0 && "Too many datasets!"); + } /* end switch */ +#if 0 + /* Check on dataset's attribute storage status */ + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, TRUE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Check for iterating over object with no attributes (should be OK) */ + ret = H5Aiterate2(my_dataset, idx_type, order, NULL, attr_iterate2_cb, NULL); + CHECK(ret, FAIL, "H5Aiterate2"); + + ret = H5Aiterate_by_name(fid, dsetname, idx_type, order, NULL, attr_iterate2_cb, NULL, + H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aiterate_by_name"); + + ret = H5Aiterate_by_name(my_dataset, ".", idx_type, order, NULL, attr_iterate2_cb, NULL, + H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aiterate_by_name"); + + /* Create attributes, up to limit of compact form */ + for (u = 0; u < max_compact; u++) { + /* Create attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = + H5Acreate2(my_dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Verify information for new attribute */ + ret = attr_info_by_idx_check(my_dataset, attrname, (hsize_t)u, use_index); + CHECK(ret, FAIL, "attr_info_by_idx_check"); + } /* end for */ +#if 0 + /* Verify state of object */ + ret = H5O__num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O__num_attrs_test"); + VERIFY(nattrs, max_compact, "H5O__num_attrs_test"); + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif +#ifndef NO_ITERATION_RESTART + /* Check for out of bound iteration */ + idx = u; + H5E_BEGIN_TRY + { + ret = H5Aiterate2(my_dataset, idx_type, order, &idx, attr_iterate2_cb, NULL); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Aiterate2"); + + idx = u; + H5E_BEGIN_TRY + { + ret = H5Aiterate_by_name(fid, dsetname, idx_type, order, &idx, attr_iterate2_cb, NULL, + H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Aiterate_by_name"); + + idx = u; + H5E_BEGIN_TRY + { + ret = H5Aiterate_by_name(my_dataset, ".", idx_type, order, &idx, attr_iterate2_cb, + NULL, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Aiterate_by_name"); + + /* Test iteration over attributes stored compactly */ + ret = attr_iterate_check(fid, dsetname, my_dataset, idx_type, order, u, &iter_info); + CHECK(ret, FAIL, "attr_iterate_check"); +#endif + } /* end for */ + + /* Work on all the datasets */ + for (curr_dset = 0; curr_dset < NUM_DSETS; curr_dset++) { + switch (curr_dset) { + case 0: + my_dataset = dset1; + dsetname = DSET1_NAME; + break; + + case 1: + my_dataset = dset2; + dsetname = DSET2_NAME; + break; + + case 2: + my_dataset = dset3; + dsetname = DSET3_NAME; + break; + + default: + HDassert(0 && "Too many datasets!"); + } /* end switch */ + + /* Create more attributes, to push into dense form */ + for (u = max_compact; u < (max_compact * 2); u++) { + /* Create attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = + H5Acreate2(my_dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); +#if 0 + /* Verify state of object */ + if (u >= max_compact) { + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, (new_format ? TRUE : FALSE), "H5O__is_attr_dense_test"); + } /* end if */ +#endif + /* Verify information for new attribute */ + ret = attr_info_by_idx_check(my_dataset, attrname, (hsize_t)u, use_index); + CHECK(ret, FAIL, "attr_info_by_idx_check"); + } /* end for */ +#if 0 + /* Verify state of object */ + ret = H5O__num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O__num_attrs_test"); + VERIFY(nattrs, (max_compact * 2), "H5O__num_attrs_test"); + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, (new_format ? TRUE : FALSE), "H5O__is_attr_dense_test"); + + if (new_format) { + /* Retrieve & verify # of records in the name & creation order indices */ + ret = H5O__attr_dense_info_test(my_dataset, &name_count, &corder_count); + CHECK(ret, FAIL, "H5O__attr_dense_info_test"); + if (use_index) + VERIFY(name_count, corder_count, "H5O__attr_dense_info_test"); + VERIFY(name_count, (max_compact * 2), "H5O__attr_dense_info_test"); + } /* end if */ +#endif +#ifndef NO_ITERATION_RESTART + /* Check for out of bound iteration */ + idx = u; + H5E_BEGIN_TRY + { + ret = H5Aiterate2(my_dataset, idx_type, order, &idx, attr_iterate2_cb, NULL); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Aiterate2"); + + idx = u; + H5E_BEGIN_TRY + { + ret = H5Aiterate_by_name(fid, dsetname, idx_type, order, &idx, attr_iterate2_cb, NULL, + H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Aiterate_by_name"); + + idx = u; + H5E_BEGIN_TRY + { + ret = H5Aiterate_by_name(my_dataset, ".", idx_type, order, &idx, attr_iterate2_cb, + NULL, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Aiterate_by_name"); + + /* Test iteration over attributes stored densely */ + ret = attr_iterate_check(fid, dsetname, my_dataset, idx_type, order, u, &iter_info); + CHECK(ret, FAIL, "attr_iterate_check"); +#endif + } /* end for */ + + /* Close Datasets */ + ret = H5Dclose(dset1); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset2); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset3); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + } /* end for */ + } /* end for */ + } /* end for */ + + /* Close property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Free the "visited link" array */ + HDfree(visited); +} /* test_attr_iterate2() */ + +/*------------------------------------------------------------------------- + * Function: attr_open_by_idx_check + * + * Purpose: Check opening attribute by index on an object + * + * Return: Success: 0 + * Failure: -1 + * + * Programmer: Quincey Koziol + * Wednesday, February 21, 2007 + * + *------------------------------------------------------------------------- + */ +static int +attr_open_by_idx_check(hid_t obj_id, H5_index_t idx_type, H5_iter_order_t order, unsigned max_attrs) +{ + hid_t attr_id; /* ID of attribute to test */ + H5A_info_t ainfo; /* Attribute info */ + int old_nerrs; /* Number of errors when entering this check */ + unsigned u; /* Local index variable */ + herr_t ret; /* Generic return value */ + + /* Retrieve the current # of reported errors */ + old_nerrs = nerrors; + + /* Open each attribute on object by index and check that it's the correct one */ + for (u = 0; u < max_attrs; u++) { + /* Open the attribute */ + attr_id = H5Aopen_by_idx(obj_id, ".", idx_type, order, (hsize_t)u, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr_id, FAIL, "H5Aopen_by_idx"); + + /* Get the attribute's information */ + ret = H5Aget_info(attr_id, &ainfo); + CHECK(ret, FAIL, "H5Aget_info"); + + /* Check that the object is the correct one */ + if (order == H5_ITER_INC) { + VERIFY(ainfo.corder, u, "H5Aget_info"); + } /* end if */ + else if (order == H5_ITER_DEC) { + VERIFY(ainfo.corder, (max_attrs - (u + 1)), "H5Aget_info"); + } /* end if */ + else { + /* XXX: What to do about native order? */ + } /* end else */ + + /* Close attribute */ + ret = H5Aclose(attr_id); + CHECK(ret, FAIL, "H5Aclose"); + } /* end for */ + + /* Retrieve current # of errors */ + if (old_nerrs == nerrors) + return (0); + else + return (-1); +} /* end attr_open_by_idx_check() */ + +/**************************************************************** +** +** test_attr_open_by_idx(): Test basic H5A (attribute) code. +** Tests opening attributes by index +** +****************************************************************/ +static void +test_attr_open_by_idx(hbool_t new_format, hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* HDF5 File ID */ + hid_t dset1, dset2, dset3; /* Dataset IDs */ + hid_t my_dataset; /* Current dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t attr; /* Attribute ID */ + hid_t dcpl; /* Dataset creation property list ID */ + unsigned max_compact; /* Maximum # of links to store in group compactly */ + unsigned min_dense; /* Minimum # of links to store in group "densely" */ +#if 0 + htri_t is_empty; /* Are there any attributes? */ + htri_t is_dense; /* Are attributes stored densely? */ + hsize_t nattrs; /* Number of attributes on object */ + hsize_t name_count; /* # of records in name index */ + hsize_t corder_count; /* # of records in creation order index */ +#endif + H5_index_t idx_type; /* Type of index to operate on */ + H5_iter_order_t order; /* Order within in the index */ + unsigned use_index; /* Use index on creation order values */ + char attrname[NAME_BUF_SIZE]; /* Name of attribute */ + unsigned curr_dset; /* Current dataset to work on */ + unsigned u; /* Local index variable */ + hid_t ret_id; /* Generic hid_t return value */ + herr_t ret; /* Generic return value */ + + /* Create dataspace for dataset & attributes */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create dataset creation property list */ + if (dcpl_g == H5P_DEFAULT) { + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + } + else { + dcpl = H5Pcopy(dcpl_g); + CHECK(dcpl, FAIL, "H5Pcopy"); + } + + /* Query the attribute creation properties */ + ret = H5Pget_attr_phase_change(dcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + + /* Loop over operating on different indices on link fields */ + for (idx_type = H5_INDEX_NAME; idx_type <= H5_INDEX_CRT_ORDER; idx_type++) { + /* Loop over operating in different orders */ + for (order = H5_ITER_INC; order <= H5_ITER_DEC; order++) { + /* Loop over using index for creation order value */ + for (use_index = FALSE; use_index <= TRUE; use_index++) { + /* Print appropriate test message */ + if (idx_type == H5_INDEX_CRT_ORDER) { + if (order == H5_ITER_INC) { + if (use_index) + MESSAGE(5, ("Testing Opening Attributes By Creation Order Index in Increasing " + "Order w/Creation Order Index\n")) + else + MESSAGE(5, ("Testing Opening Attributes By Creation Order Index in Increasing " + "Order w/o Creation Order Index\n")) + } /* end if */ + else { + if (use_index) + MESSAGE(5, ("Testing Opening Attributes By Creation Order Index in Decreasing " + "Order w/Creation Order Index\n")) + else + MESSAGE(5, ("Testing Opening Attributes By Creation Order Index in Decreasing " + "Order w/o Creation Order Index\n")) + } /* end else */ + } /* end if */ + else { + if (order == H5_ITER_INC) { + if (use_index) + MESSAGE(5, ("Testing Opening Attributes By Name Index in Increasing Order " + "w/Creation Order Index\n")) + else + MESSAGE(5, ("Testing Opening Attributes By Name Index in Increasing Order w/o " + "Creation Order Index\n")) + } /* end if */ + else { +#ifndef NO_DECREASING_ALPHA_ITER_ORDER + if (use_index) + MESSAGE(5, ("Testing Opening Attributes By Name Index in Decreasing Order " + "w/Creation Order Index\n")) + else + MESSAGE(5, ("Testing Opening Attributes By Name Index in Decreasing Order w/o " + "Creation Order Index\n")) +#else + continue; +#endif + } /* end else */ + } /* end else */ + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Set attribute creation order tracking & indexing for object */ + if (new_format == TRUE) { + ret = H5Pset_attr_creation_order( + dcpl, (H5P_CRT_ORDER_TRACKED | (use_index ? H5P_CRT_ORDER_INDEXED : (unsigned)0))); + CHECK(ret, FAIL, "H5Pset_attr_creation_order"); + } /* end if */ + + /* Create datasets */ + dset1 = H5Dcreate2(fid, DSET1_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset1, FAIL, "H5Dcreate2"); + dset2 = H5Dcreate2(fid, DSET2_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset2, FAIL, "H5Dcreate2"); + dset3 = H5Dcreate2(fid, DSET3_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset3, FAIL, "H5Dcreate2"); + + /* Work on all the datasets */ + for (curr_dset = 0; curr_dset < NUM_DSETS; curr_dset++) { + switch (curr_dset) { + case 0: + my_dataset = dset1; + break; + + case 1: + my_dataset = dset2; + break; + + case 2: + my_dataset = dset3; + break; + + default: + HDassert(0 && "Too many datasets!"); + } /* end switch */ +#if 0 + /* Check on dataset's attribute storage status */ + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, TRUE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Check for opening an attribute on an object with no attributes */ + H5E_BEGIN_TRY + { + ret_id = H5Aopen_by_idx(my_dataset, ".", idx_type, order, (hsize_t)0, H5P_DEFAULT, + H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret_id, FAIL, "H5Aopen_by_idx"); + + /* Create attributes, up to limit of compact form */ + for (u = 0; u < max_compact; u++) { + /* Create attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = + H5Acreate2(my_dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Verify information for new attribute */ + ret = attr_info_by_idx_check(my_dataset, attrname, (hsize_t)u, use_index); + CHECK(ret, FAIL, "attr_info_by_idx_check"); + } /* end for */ +#if 0 + /* Verify state of object */ + ret = H5O__num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O__num_attrs_test"); + VERIFY(nattrs, max_compact, "H5O__num_attrs_test"); + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Check for out of bound opening an attribute on an object */ + H5E_BEGIN_TRY + { + ret_id = H5Aopen_by_idx(my_dataset, ".", idx_type, order, (hsize_t)u, H5P_DEFAULT, + H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret_id, FAIL, "H5Aopen_by_idx"); + + /* Test opening attributes by index stored compactly */ + ret = attr_open_by_idx_check(my_dataset, idx_type, order, u); + CHECK(ret, FAIL, "attr_open_by_idx_check"); + } /* end for */ + + /* Work on all the datasets */ + for (curr_dset = 0; curr_dset < NUM_DSETS; curr_dset++) { + switch (curr_dset) { + case 0: + my_dataset = dset1; + break; + + case 1: + my_dataset = dset2; + break; + + case 2: + my_dataset = dset3; + break; + + default: + HDassert(0 && "Too many datasets!"); + } /* end switch */ + + /* Create more attributes, to push into dense form */ + for (u = max_compact; u < (max_compact * 2); u++) { + /* Create attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = + H5Acreate2(my_dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); +#if 0 + /* Verify state of object */ + if (u >= max_compact) { + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, (new_format ? TRUE : FALSE), "H5O__is_attr_dense_test"); + } /* end if */ +#endif + /* Verify information for new attribute */ + ret = attr_info_by_idx_check(my_dataset, attrname, (hsize_t)u, use_index); + CHECK(ret, FAIL, "attr_info_by_idx_check"); + } /* end for */ +#if 0 + /* Verify state of object */ + ret = H5O__num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O__num_attrs_test"); + VERIFY(nattrs, (max_compact * 2), "H5O__num_attrs_test"); + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, (new_format ? TRUE : FALSE), "H5O__is_attr_dense_test"); + + if (new_format) { + /* Retrieve & verify # of records in the name & creation order indices */ + ret = H5O__attr_dense_info_test(my_dataset, &name_count, &corder_count); + CHECK(ret, FAIL, "H5O__attr_dense_info_test"); + if (use_index) + VERIFY(name_count, corder_count, "H5O__attr_dense_info_test"); + VERIFY(name_count, (max_compact * 2), "H5O__attr_dense_info_test"); + } /* end if */ +#endif + /* Check for out of bound opening an attribute on an object */ + H5E_BEGIN_TRY + { + ret_id = H5Aopen_by_idx(my_dataset, ".", idx_type, order, (hsize_t)u, H5P_DEFAULT, + H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret_id, FAIL, "H5Aopen_by_idx"); + + /* Test opening attributes by index stored compactly */ + ret = attr_open_by_idx_check(my_dataset, idx_type, order, u); + CHECK(ret, FAIL, "attr_open_by_idx_check"); + } /* end for */ + + /* Close Datasets */ + ret = H5Dclose(dset1); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset2); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset3); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + } /* end for */ + } /* end for */ + } /* end for */ + + /* Close property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_attr_open_by_idx() */ + +/*------------------------------------------------------------------------- + * Function: attr_open_check + * + * Purpose: Check opening attribute on an object + * + * Return: Success: 0 + * Failure: -1 + * + * Programmer: Quincey Koziol + * Wednesday, February 21, 2007 + * + *------------------------------------------------------------------------- + */ +static int +attr_open_check(hid_t fid, const char *dsetname, hid_t obj_id, unsigned max_attrs) +{ + hid_t attr_id; /* ID of attribute to test */ + H5A_info_t ainfo; /* Attribute info */ + char attrname[NAME_BUF_SIZE]; /* Name of attribute */ + int old_nerrs; /* Number of errors when entering this check */ + unsigned u; /* Local index variable */ + herr_t ret; /* Generic return value */ + + /* Retrieve the current # of reported errors */ + old_nerrs = nerrors; + + /* Open each attribute on object by index and check that it's the correct one */ + for (u = 0; u < max_attrs; u++) { + /* Open the attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr_id = H5Aopen(obj_id, attrname, H5P_DEFAULT); + CHECK(attr_id, FAIL, "H5Aopen"); + + /* Get the attribute's information */ + ret = H5Aget_info(attr_id, &ainfo); + CHECK(ret, FAIL, "H5Aget_info"); + + /* Check that the object is the correct one */ + VERIFY(ainfo.corder, u, "H5Aget_info"); + + /* Close attribute */ + ret = H5Aclose(attr_id); + CHECK(ret, FAIL, "H5Aclose"); + + /* Open the attribute */ + attr_id = H5Aopen_by_name(obj_id, ".", attrname, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr_id, FAIL, "H5Aopen_by_name"); + + /* Get the attribute's information */ + ret = H5Aget_info(attr_id, &ainfo); + CHECK(ret, FAIL, "H5Aget_info"); + + /* Check that the object is the correct one */ + VERIFY(ainfo.corder, u, "H5Aget_info"); + + /* Close attribute */ + ret = H5Aclose(attr_id); + CHECK(ret, FAIL, "H5Aclose"); + + /* Open the attribute */ + attr_id = H5Aopen_by_name(fid, dsetname, attrname, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr_id, FAIL, "H5Aopen_by_name"); + + /* Get the attribute's information */ + ret = H5Aget_info(attr_id, &ainfo); + CHECK(ret, FAIL, "H5Aget_info"); + + /* Check that the object is the correct one */ + VERIFY(ainfo.corder, u, "H5Aget_info"); + + /* Close attribute */ + ret = H5Aclose(attr_id); + CHECK(ret, FAIL, "H5Aclose"); + } /* end for */ + + /* Retrieve current # of errors */ + if (old_nerrs == nerrors) + return (0); + else + return (-1); +} /* end attr_open_check() */ + +/**************************************************************** +** +** test_attr_open_by_name(): Test basic H5A (attribute) code. +** Tests opening attributes by name +** +****************************************************************/ +static void +test_attr_open_by_name(hbool_t new_format, hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* HDF5 File ID */ + hid_t dset1, dset2, dset3; /* Dataset IDs */ + hid_t my_dataset; /* Current dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t attr; /* Attribute ID */ + hid_t dcpl; /* Dataset creation property list ID */ + unsigned max_compact; /* Maximum # of links to store in group compactly */ + unsigned min_dense; /* Minimum # of links to store in group "densely" */ +#if 0 + htri_t is_empty; /* Are there any attributes? */ + htri_t is_dense; /* Are attributes stored densely? */ + hsize_t nattrs; /* Number of attributes on object */ + hsize_t name_count; /* # of records in name index */ + hsize_t corder_count; /* # of records in creation order index */ +#endif + unsigned use_index; /* Use index on creation order values */ + const char *dsetname; /* Name of dataset for attributes */ + char attrname[NAME_BUF_SIZE]; /* Name of attribute */ + unsigned curr_dset; /* Current dataset to work on */ + unsigned u; /* Local index variable */ + hid_t ret_id; /* Generic hid_t return value */ + herr_t ret; /* Generic return value */ + + /* Create dataspace for dataset & attributes */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create dataset creation property list */ + if (dcpl_g == H5P_DEFAULT) { + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + } + else { + dcpl = H5Pcopy(dcpl_g); + CHECK(dcpl, FAIL, "H5Pcopy"); + } + + /* Query the attribute creation properties */ + ret = H5Pget_attr_phase_change(dcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + + /* Loop over using index for creation order value */ + for (use_index = FALSE; use_index <= TRUE; use_index++) { + /* Print appropriate test message */ + if (use_index) + MESSAGE(5, ("Testing Opening Attributes By Name w/Creation Order Index\n")) + else + MESSAGE(5, ("Testing Opening Attributes By Name w/o Creation Order Index\n")) + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Set attribute creation order tracking & indexing for object */ + if (new_format == TRUE) { + ret = H5Pset_attr_creation_order( + dcpl, (H5P_CRT_ORDER_TRACKED | (use_index ? H5P_CRT_ORDER_INDEXED : (unsigned)0))); + CHECK(ret, FAIL, "H5Pset_attr_creation_order"); + } /* end if */ + + /* Create datasets */ + dset1 = H5Dcreate2(fid, DSET1_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset1, FAIL, "H5Dcreate2"); + dset2 = H5Dcreate2(fid, DSET2_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset2, FAIL, "H5Dcreate2"); + dset3 = H5Dcreate2(fid, DSET3_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset3, FAIL, "H5Dcreate2"); + + /* Work on all the datasets */ + for (curr_dset = 0; curr_dset < NUM_DSETS; curr_dset++) { + switch (curr_dset) { + case 0: + my_dataset = dset1; + dsetname = DSET1_NAME; + break; + + case 1: + my_dataset = dset2; + dsetname = DSET2_NAME; + break; + + case 2: + my_dataset = dset3; + dsetname = DSET3_NAME; + break; + + default: + HDassert(0 && "Too many datasets!"); + } /* end switch */ +#if 0 + /* Check on dataset's attribute storage status */ + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, TRUE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Check for opening a non-existent attribute on an object with no attributes */ + H5E_BEGIN_TRY + { + ret_id = H5Aopen(my_dataset, "foo", H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret_id, FAIL, "H5Aopen"); + + H5E_BEGIN_TRY + { + ret_id = H5Aopen_by_name(my_dataset, ".", "foo", H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret_id, FAIL, "H5Aopen_by_name"); + + H5E_BEGIN_TRY + { + ret_id = H5Aopen_by_name(fid, dsetname, "foo", H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret_id, FAIL, "H5Aopen_by_name"); + + /* Create attributes, up to limit of compact form */ + for (u = 0; u < max_compact; u++) { + /* Create attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = H5Acreate2(my_dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Verify information for new attribute */ + ret = attr_info_by_idx_check(my_dataset, attrname, (hsize_t)u, use_index); + CHECK(ret, FAIL, "attr_info_by_idx_check"); + } /* end for */ +#if 0 + /* Verify state of object */ + ret = H5O__num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O__num_attrs_test"); + VERIFY(nattrs, max_compact, "H5O__num_attrs_test"); + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Check for opening a non-existent attribute on an object with compact attribute storage */ + H5E_BEGIN_TRY + { + ret_id = H5Aopen(my_dataset, "foo", H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret_id, FAIL, "H5Aopen"); + + H5E_BEGIN_TRY + { + ret_id = H5Aopen_by_name(my_dataset, ".", "foo", H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret_id, FAIL, "H5Aopen_by_name"); + + H5E_BEGIN_TRY + { + ret_id = H5Aopen_by_name(fid, dsetname, "foo", H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret_id, FAIL, "H5Aopen_by_name"); + + /* Test opening attributes stored compactly */ + ret = attr_open_check(fid, dsetname, my_dataset, u); + CHECK(ret, FAIL, "attr_open_check"); + } /* end for */ + + /* Work on all the datasets */ + for (curr_dset = 0; curr_dset < NUM_DSETS; curr_dset++) { + switch (curr_dset) { + case 0: + my_dataset = dset1; + dsetname = DSET1_NAME; + break; + + case 1: + my_dataset = dset2; + dsetname = DSET2_NAME; + break; + + case 2: + my_dataset = dset3; + dsetname = DSET3_NAME; + break; + + default: + HDassert(0 && "Too many datasets!"); + } /* end switch */ + + /* Create more attributes, to push into dense form */ + for (u = max_compact; u < (max_compact * 2); u++) { + /* Create attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = H5Acreate2(my_dataset, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); +#if 0 + /* Verify state of object */ + if (u >= max_compact) { + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, (new_format ? TRUE : FALSE), "H5O__is_attr_dense_test"); + } /* end if */ +#endif + /* Verify information for new attribute */ + ret = attr_info_by_idx_check(my_dataset, attrname, (hsize_t)u, use_index); + CHECK(ret, FAIL, "attr_info_by_idx_check"); + } /* end for */ +#if 0 + /* Verify state of object */ + ret = H5O__num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O__num_attrs_test"); + VERIFY(nattrs, (max_compact * 2), "H5O__num_attrs_test"); + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, (new_format ? TRUE : FALSE), "H5O__is_attr_dense_test"); + + if (new_format) { + /* Retrieve & verify # of records in the name & creation order indices */ + ret = H5O__attr_dense_info_test(my_dataset, &name_count, &corder_count); + CHECK(ret, FAIL, "H5O__attr_dense_info_test"); + if (use_index) + VERIFY(name_count, corder_count, "H5O__attr_dense_info_test"); + VERIFY(name_count, (max_compact * 2), "H5O__attr_dense_info_test"); + } /* end if */ +#endif + /* Check for opening a non-existent attribute on an object with dense attribute storage */ + H5E_BEGIN_TRY + { + ret_id = H5Aopen(my_dataset, "foo", H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret_id, FAIL, "H5Aopen"); + + H5E_BEGIN_TRY + { + ret_id = H5Aopen_by_name(my_dataset, ".", "foo", H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret_id, FAIL, "H5Aopen_by_name"); + + H5E_BEGIN_TRY + { + ret_id = H5Aopen_by_name(fid, dsetname, "foo", H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret_id, FAIL, "H5Aopen_by_name"); + + /* Test opening attributes stored compactly */ + ret = attr_open_check(fid, dsetname, my_dataset, u); + CHECK(ret, FAIL, "attr_open_check"); + } /* end for */ + + /* Close Datasets */ + ret = H5Dclose(dset1); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset2); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset3); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + } /* end for */ + + /* Close property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_attr_open_by_name() */ + +/**************************************************************** +** +** test_attr_create_by_name(): Test basic H5A (attribute) code. +** Tests creating attributes by name +** +****************************************************************/ +static void +test_attr_create_by_name(hbool_t new_format, hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* HDF5 File ID */ + hid_t dset1, dset2, dset3; /* Dataset IDs */ + hid_t my_dataset; /* Current dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t attr; /* Attribute ID */ + hid_t dcpl; /* Dataset creation property list ID */ + unsigned max_compact; /* Maximum # of links to store in group compactly */ + unsigned min_dense; /* Minimum # of links to store in group "densely" */ +#if 0 + htri_t is_empty; /* Are there any attributes? */ + htri_t is_dense; /* Are attributes stored densely? */ + hsize_t nattrs; /* Number of attributes on object */ + hsize_t name_count; /* # of records in name index */ + hsize_t corder_count; /* # of records in creation order index */ +#endif + unsigned use_index; /* Use index on creation order values */ + const char *dsetname; /* Name of dataset for attributes */ + char attrname[NAME_BUF_SIZE]; /* Name of attribute */ + unsigned curr_dset; /* Current dataset to work on */ + unsigned u; /* Local index variable */ + herr_t ret; /* Generic return value */ + + /* Create dataspace for dataset & attributes */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create dataset creation property list */ + if (dcpl_g == H5P_DEFAULT) { + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + } + else { + dcpl = H5Pcopy(dcpl_g); + CHECK(dcpl, FAIL, "H5Pcopy"); + } + + /* Query the attribute creation properties */ + ret = H5Pget_attr_phase_change(dcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + + /* Loop over using index for creation order value */ + for (use_index = FALSE; use_index <= TRUE; use_index++) { + /* Print appropriate test message */ + if (use_index) + MESSAGE(5, ("Testing Creating Attributes By Name w/Creation Order Index\n")) + else + MESSAGE(5, ("Testing Creating Attributes By Name w/o Creation Order Index\n")) + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Set attribute creation order tracking & indexing for object */ + if (new_format == TRUE) { + ret = H5Pset_attr_creation_order( + dcpl, (H5P_CRT_ORDER_TRACKED | (use_index ? H5P_CRT_ORDER_INDEXED : (unsigned)0))); + CHECK(ret, FAIL, "H5Pset_attr_creation_order"); + } /* end if */ + + /* Create datasets */ + dset1 = H5Dcreate2(fid, DSET1_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset1, FAIL, "H5Dcreate2"); + dset2 = H5Dcreate2(fid, DSET2_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset2, FAIL, "H5Dcreate2"); + dset3 = H5Dcreate2(fid, DSET3_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset3, FAIL, "H5Dcreate2"); + + /* Work on all the datasets */ + for (curr_dset = 0; curr_dset < NUM_DSETS; curr_dset++) { + switch (curr_dset) { + case 0: + my_dataset = dset1; + dsetname = DSET1_NAME; + break; + + case 1: + my_dataset = dset2; + dsetname = DSET2_NAME; + break; + + case 2: + my_dataset = dset3; + dsetname = DSET3_NAME; + break; + + default: + HDassert(0 && "Too many datasets!"); + } /* end switch */ +#if 0 + /* Check on dataset's attribute storage status */ + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, TRUE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Create attributes, up to limit of compact form */ + for (u = 0; u < max_compact; u++) { + /* Create attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = H5Acreate_by_name(fid, dsetname, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate_by_name"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Verify information for new attribute */ + ret = attr_info_by_idx_check(my_dataset, attrname, (hsize_t)u, use_index); + CHECK(ret, FAIL, "attr_info_by_idx_check"); + } /* end for */ +#if 0 + /* Verify state of object */ + ret = H5O__num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O__num_attrs_test"); + VERIFY(nattrs, max_compact, "H5O__num_attrs_test"); + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Test opening attributes stored compactly */ + ret = attr_open_check(fid, dsetname, my_dataset, u); + CHECK(ret, FAIL, "attr_open_check"); + } /* end for */ + + /* Work on all the datasets */ + for (curr_dset = 0; curr_dset < NUM_DSETS; curr_dset++) { + switch (curr_dset) { + case 0: + my_dataset = dset1; + dsetname = DSET1_NAME; + break; + + case 1: + my_dataset = dset2; + dsetname = DSET2_NAME; + break; + + case 2: + my_dataset = dset3; + dsetname = DSET3_NAME; + break; + + default: + HDassert(0 && "Too many datasets!"); + } /* end switch */ + + /* Create more attributes, to push into dense form */ + for (u = max_compact; u < (max_compact * 2); u++) { + /* Create attribute */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + attr = H5Acreate_by_name(fid, dsetname, attrname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate_by_name"); + + /* Write data into the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &u); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); +#if 0 + /* Verify state of object */ + if (u >= max_compact) { + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, (new_format ? TRUE : FALSE), "H5O__is_attr_dense_test"); + } /* end if */ +#endif + /* Verify information for new attribute */ + ret = attr_info_by_idx_check(my_dataset, attrname, (hsize_t)u, use_index); + CHECK(ret, FAIL, "attr_info_by_idx_check"); + } /* end for */ +#if 0 + /* Verify state of object */ + ret = H5O__num_attrs_test(my_dataset, &nattrs); + CHECK(ret, FAIL, "H5O__num_attrs_test"); + VERIFY(nattrs, (max_compact * 2), "H5O__num_attrs_test"); + is_empty = H5O__is_attr_empty_test(my_dataset); + VERIFY(is_empty, FALSE, "H5O__is_attr_empty_test"); + is_dense = H5O__is_attr_dense_test(my_dataset); + VERIFY(is_dense, (new_format ? TRUE : FALSE), "H5O__is_attr_dense_test"); + + if (new_format) { + /* Retrieve & verify # of records in the name & creation order indices */ + ret = H5O__attr_dense_info_test(my_dataset, &name_count, &corder_count); + CHECK(ret, FAIL, "H5O__attr_dense_info_test"); + if (use_index) + VERIFY(name_count, corder_count, "H5O__attr_dense_info_test"); + VERIFY(name_count, (max_compact * 2), "H5O__attr_dense_info_test"); + } /* end if */ +#endif + /* Test opening attributes stored compactly */ + ret = attr_open_check(fid, dsetname, my_dataset, u); + CHECK(ret, FAIL, "attr_open_check"); + } /* end for */ + + /* Close Datasets */ + ret = H5Dclose(dset1); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset2); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset3); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + } /* end for */ + + /* Close property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_attr_create_by_name() */ + +/**************************************************************** +** +** test_attr_shared_write(): Test basic H5A (attribute) code. +** Tests writing mix of shared & un-shared attributes in "compact" & "dense" storage +** +****************************************************************/ +static void +test_attr_shared_write(hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* File ID */ + hid_t my_fcpl; /* File creation property list ID */ + hid_t dataset, dataset2; /* Dataset IDs */ + hid_t attr_tid; /* Attribute's datatype ID */ + hid_t sid, big_sid; /* Dataspace IDs */ + hsize_t big_dims[] = {SPACE1_DIM1, SPACE1_DIM2, SPACE1_DIM3}; /* Dimensions for "big" attribute */ + hid_t attr; /* Attribute ID */ + hid_t dcpl; /* Dataset creation property list ID */ + char attrname[NAME_BUF_SIZE]; /* Name of attribute */ + unsigned max_compact; /* Maximum # of attributes to store compactly */ + unsigned min_dense; /* Minimum # of attributes to store "densely" */ +#if 0 + htri_t is_dense; /* Are attributes stored densely? */ + htri_t is_shared; /* Is attributes shared? */ + hsize_t shared_refcount; /* Reference count of shared attribute */ +#endif + unsigned attr_value; /* Attribute value */ + unsigned *big_value; /* Data for "big" attribute */ +#if 0 + size_t mesg_count; /* # of shared messages */ +#endif + unsigned test_shared; /* Index over shared component type */ + unsigned u; /* Local index variable */ +#if 0 + h5_stat_size_t empty_filesize; /* Size of empty file */ + h5_stat_size_t filesize; /* Size of file after modifications */ +#endif + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Writing Shared & Unshared Attributes in Compact & Dense Storage\n")); + + /* Allocate & initialize "big" attribute data */ + big_value = (unsigned *)HDmalloc((size_t)(SPACE1_DIM1 * SPACE1_DIM2 * SPACE1_DIM3) * sizeof(unsigned)); + CHECK_PTR(big_value, "HDmalloc"); + HDmemset(big_value, 1, sizeof(unsigned) * (size_t)(SPACE1_DIM1 * SPACE1_DIM2 * SPACE1_DIM3)); + + /* Create dataspace for dataset */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create "big" dataspace for "large" attributes */ + big_sid = H5Screate_simple(SPACE1_RANK, big_dims, NULL); + CHECK(big_sid, FAIL, "H5Screate_simple"); + + /* Loop over type of shared components */ + for (test_shared = 0; test_shared < 3; test_shared++) { + /* Make copy of file creation property list */ + my_fcpl = H5Pcopy(fcpl); + CHECK(my_fcpl, FAIL, "H5Pcopy"); + + /* Set up datatype for attributes */ + attr_tid = H5Tcopy(H5T_NATIVE_UINT); + CHECK(attr_tid, FAIL, "H5Tcopy"); + + /* Special setup for each type of shared components */ + if (test_shared == 0) { + /* Make attributes > 500 bytes shared */ + ret = H5Pset_shared_mesg_nindexes(my_fcpl, (unsigned)1); + CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); + ret = H5Pset_shared_mesg_index(my_fcpl, (unsigned)0, H5O_SHMESG_ATTR_FLAG, (unsigned)500); + CHECK_I(ret, "H5Pset_shared_mesg_index"); + } /* end if */ + else { + /* Set up copy of file creation property list */ + + ret = H5Pset_shared_mesg_nindexes(my_fcpl, (unsigned)3); + CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); + + /* Make attributes > 500 bytes shared */ + ret = H5Pset_shared_mesg_index(my_fcpl, (unsigned)0, H5O_SHMESG_ATTR_FLAG, (unsigned)500); + CHECK_I(ret, "H5Pset_shared_mesg_index"); + + /* Make datatypes & dataspaces > 1 byte shared (i.e. all of them :-) */ + ret = H5Pset_shared_mesg_index(my_fcpl, (unsigned)1, H5O_SHMESG_DTYPE_FLAG, (unsigned)1); + CHECK_I(ret, "H5Pset_shared_mesg_index"); + ret = H5Pset_shared_mesg_index(my_fcpl, (unsigned)2, H5O_SHMESG_SDSPACE_FLAG, (unsigned)1); + CHECK_I(ret, "H5Pset_shared_mesg_index"); + } /* end else */ + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, my_fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Close FCPL copy */ + ret = H5Pclose(my_fcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +#if 0 + /* Get size of file */ + empty_filesize = h5_get_file_size(FILENAME, fapl); + if (empty_filesize < 0) + TestErrPrintf("Line %d: file size wrong!\n", __LINE__); +#endif + + /* Re-open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Commit datatype to file */ + if (test_shared == 2) { + ret = H5Tcommit2(fid, TYPE1_NAME, attr_tid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + } /* end if */ + + /* Set up to query the object creation properties */ + if (dcpl_g == H5P_DEFAULT) { + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + } + else { + dcpl = H5Pcopy(dcpl_g); + CHECK(dcpl, FAIL, "H5Pcopy"); + } + + /* Create datasets */ + dataset = H5Dcreate2(fid, DSET1_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + dataset2 = H5Dcreate2(fid, DSET2_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dataset2, FAIL, "H5Dcreate2"); + + /* Check on dataset's message storage status */ + if (test_shared != 0) { +#if 0 + /* Datasets' datatypes can be shared */ + ret = H5F__get_sohm_mesg_count_test(fid, H5O_DTYPE_ID, &mesg_count); + CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); + VERIFY(mesg_count, 1, "H5F__get_sohm_mesg_count_test"); + + /* Datasets' dataspace can be shared */ + ret = H5F__get_sohm_mesg_count_test(fid, H5O_SDSPACE_ID, &mesg_count); + CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); + VERIFY(mesg_count, 1, "H5F__get_sohm_mesg_count_test"); +#endif + } /* end if */ + + /* Retrieve limits for compact/dense attribute storage */ + ret = H5Pget_attr_phase_change(dcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + + /* Close property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); +#if 0 + /* Check on datasets' attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); + is_dense = H5O__is_attr_dense_test(dataset2); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Add attributes to each dataset, until after converting to dense storage */ + for (u = 0; u < max_compact * 2; u++) { + /* Create attribute name */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + + /* Alternate between creating "small" & "big" attributes */ + if (u % 2) { + /* Create "small" attribute on first dataset */ + attr = H5Acreate2(dataset, attrname, attr_tid, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); +#if 0 + /* Check that attribute is not shared */ + is_shared = H5A__is_shared_test(attr); + VERIFY(is_shared, FALSE, "H5A__is_shared_test"); +#endif + /* Write data into the attribute */ + attr_value = u + 1; + ret = H5Awrite(attr, attr_tid, &attr_value); + CHECK(ret, FAIL, "H5Awrite"); + } /* end if */ + else { + /* Create "big" attribute on first dataset */ + attr = H5Acreate2(dataset, attrname, attr_tid, big_sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); +#if 0 + /* Check that attribute is shared */ + is_shared = H5A__is_shared_test(attr); + VERIFY(is_shared, TRUE, "H5A__is_shared_test"); + + /* Check refcount for attribute */ + ret = H5A__get_shared_rc_test(attr, &shared_refcount); + CHECK(ret, FAIL, "H5A__get_shared_rc_test"); + VERIFY(shared_refcount, 1, "H5A__get_shared_rc_test"); +#endif + /* Write data into the attribute */ + big_value[0] = u + 1; + ret = H5Awrite(attr, attr_tid, big_value); + CHECK(ret, FAIL, "H5Awrite"); +#if 0 + /* Check refcount for attribute */ + ret = H5A__get_shared_rc_test(attr, &shared_refcount); + CHECK(ret, FAIL, "H5A__get_shared_rc_test"); + VERIFY(shared_refcount, 1, "H5A__get_shared_rc_test"); +#endif + } /* end else */ + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + if (u < max_compact) + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); + else + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); +#endif + + /* Alternate between creating "small" & "big" attributes */ + if (u % 2) { + /* Create "small" attribute on second dataset */ + attr = H5Acreate2(dataset2, attrname, attr_tid, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); +#if 0 + /* Check that attribute is not shared */ + is_shared = H5A__is_shared_test(attr); + VERIFY(is_shared, FALSE, "H5A__is_shared_test"); +#endif + /* Write data into the attribute */ + attr_value = u + 1; + ret = H5Awrite(attr, attr_tid, &attr_value); + CHECK(ret, FAIL, "H5Awrite"); + } /* end if */ + else { + /* Create "big" attribute on second dataset */ + attr = H5Acreate2(dataset2, attrname, attr_tid, big_sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); +#if 0 + /* Check that attribute is shared */ + is_shared = H5A__is_shared_test(attr); + VERIFY(is_shared, TRUE, "H5A__is_shared_test"); + + /* Check refcount for attribute */ + ret = H5A__get_shared_rc_test(attr, &shared_refcount); + CHECK(ret, FAIL, "H5A__get_shared_rc_test"); + VERIFY(shared_refcount, 1, "H5A__get_shared_rc_test"); +#endif + /* Write data into the attribute */ + big_value[0] = u + 1; + ret = H5Awrite(attr, attr_tid, big_value); + CHECK(ret, FAIL, "H5Awrite"); +#if 0 + /* Check refcount for attribute */ + ret = H5A__get_shared_rc_test(attr, &shared_refcount); + CHECK(ret, FAIL, "H5A__get_shared_rc_test"); + VERIFY(shared_refcount, 2, "H5A__get_shared_rc_test"); +#endif + } /* end else */ + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset2); + if (u < max_compact) + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); + else + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); +#endif + } /* end for */ + + /* Close attribute's datatype */ + ret = H5Tclose(attr_tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close Datasets */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dataset2); + CHECK(ret, FAIL, "H5Dclose"); +#if 0 + /* Check on shared message status now */ + if (test_shared != 0) { + if (test_shared == 1) { + /* Check on datatype storage status */ + ret = H5F__get_sohm_mesg_count_test(fid, H5O_DTYPE_ID, &mesg_count); + CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); + VERIFY(mesg_count, 2, "H5F__get_sohm_mesg_count_test"); + } /* end if */ + + /* Check on dataspace storage status */ + ret = H5F__get_sohm_mesg_count_test(fid, H5O_SDSPACE_ID, &mesg_count); + CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); + VERIFY(mesg_count, 2, "H5F__get_sohm_mesg_count_test"); + } /* end if */ +#endif + /* Unlink datasets with attributes */ + ret = H5Ldelete(fid, DSET1_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + ret = H5Ldelete(fid, DSET2_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + + /* Unlink committed datatype */ + if (test_shared == 2) { + ret = H5Ldelete(fid, TYPE1_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + } /* end if */ +#if 0 + /* Check on attribute storage status */ + ret = H5F__get_sohm_mesg_count_test(fid, H5O_ATTR_ID, &mesg_count); + CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); + VERIFY(mesg_count, 0, "H5F__get_sohm_mesg_count_test"); + + if (test_shared != 0) { + /* Check on datatype storage status */ + ret = H5F__get_sohm_mesg_count_test(fid, H5O_DTYPE_ID, &mesg_count); + CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); + VERIFY(mesg_count, 0, "H5F__get_sohm_mesg_count_test"); + + /* Check on dataspace storage status */ + ret = H5F__get_sohm_mesg_count_test(fid, H5O_SDSPACE_ID, &mesg_count); + CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); + VERIFY(mesg_count, 0, "H5F__get_sohm_mesg_count_test"); + } /* end if */ +#endif + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +#if 0 + if (h5_using_default_driver(NULL)) { + /* Check size of file */ + filesize = h5_get_file_size(FILENAME, fapl); + VERIFY(filesize, empty_filesize, "h5_get_file_size"); + } +#endif + } /* end for */ + + /* Close dataspaces */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(big_sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Release memory */ + HDfree(big_value); +} /* test_attr_shared_write() */ + +/**************************************************************** +** +** test_attr_shared_rename(): Test basic H5A (attribute) code. +** Tests renaming shared attributes in "compact" & "dense" storage +** +****************************************************************/ +static void +test_attr_shared_rename(hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* HDF5 File ID */ + hid_t my_fcpl; /* File creation property list ID */ + hid_t dataset, dataset2; /* Dataset ID2 */ + hid_t attr_tid; /* Attribute's datatype ID */ + hid_t sid, big_sid; /* Dataspace IDs */ + hsize_t big_dims[] = {SPACE1_DIM1, SPACE1_DIM2, SPACE1_DIM3}; /* Dimensions for "big" attribute */ + hid_t attr; /* Attribute ID */ + hid_t dcpl; /* Dataset creation property list ID */ + char attrname[NAME_BUF_SIZE]; /* Name of attribute on first dataset */ + char attrname2[NAME_BUF_SIZE]; /* Name of attribute on second dataset */ + unsigned max_compact; /* Maximum # of attributes to store compactly */ + unsigned min_dense; /* Minimum # of attributes to store "densely" */ +#if 0 + htri_t is_dense; /* Are attributes stored densely? */ + htri_t is_shared; /* Is attributes shared? */ + hsize_t shared_refcount; /* Reference count of shared attribute */ +#endif + unsigned attr_value; /* Attribute value */ + unsigned *big_value; /* Data for "big" attribute */ +#if 0 + size_t mesg_count; /* # of shared messages */ +#endif + unsigned test_shared; /* Index over shared component type */ + unsigned u; /* Local index variable */ +#if 0 + h5_stat_size_t empty_filesize; /* Size of empty file */ + h5_stat_size_t filesize; /* Size of file after modifications */ +#endif + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Renaming Shared & Unshared Attributes in Compact & Dense Storage\n")); + + /* Allocate & initialize "big" attribute data */ + big_value = (unsigned *)HDmalloc((size_t)(SPACE1_DIM1 * SPACE1_DIM2 * SPACE1_DIM3) * sizeof(unsigned)); + CHECK_PTR(big_value, "HDmalloc"); + HDmemset(big_value, 1, sizeof(unsigned) * (size_t)(SPACE1_DIM1 * SPACE1_DIM2 * SPACE1_DIM3)); + + /* Create dataspace for dataset */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create "big" dataspace for "large" attributes */ + big_sid = H5Screate_simple(SPACE1_RANK, big_dims, NULL); + CHECK(big_sid, FAIL, "H5Screate_simple"); + + /* Loop over type of shared components */ + for (test_shared = 0; test_shared < 3; test_shared++) { + /* Make copy of file creation property list */ + my_fcpl = H5Pcopy(fcpl); + CHECK(my_fcpl, FAIL, "H5Pcopy"); + + /* Set up datatype for attributes */ + attr_tid = H5Tcopy(H5T_NATIVE_UINT); + CHECK(attr_tid, FAIL, "H5Tcopy"); + + /* Special setup for each type of shared components */ + if (test_shared == 0) { + /* Make attributes > 500 bytes shared */ + ret = H5Pset_shared_mesg_nindexes(my_fcpl, (unsigned)1); + CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); + ret = H5Pset_shared_mesg_index(my_fcpl, (unsigned)0, H5O_SHMESG_ATTR_FLAG, (unsigned)500); + CHECK_I(ret, "H5Pset_shared_mesg_index"); + } /* end if */ + else { + /* Set up copy of file creation property list */ + + ret = H5Pset_shared_mesg_nindexes(my_fcpl, (unsigned)3); + CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); + + /* Make attributes > 500 bytes shared */ + ret = H5Pset_shared_mesg_index(my_fcpl, (unsigned)0, H5O_SHMESG_ATTR_FLAG, (unsigned)500); + CHECK_I(ret, "H5Pset_shared_mesg_index"); + + /* Make datatypes & dataspaces > 1 byte shared (i.e. all of them :-) */ + ret = H5Pset_shared_mesg_index(my_fcpl, (unsigned)1, H5O_SHMESG_DTYPE_FLAG, (unsigned)1); + CHECK_I(ret, "H5Pset_shared_mesg_index"); + ret = H5Pset_shared_mesg_index(my_fcpl, (unsigned)2, H5O_SHMESG_SDSPACE_FLAG, (unsigned)1); + CHECK_I(ret, "H5Pset_shared_mesg_index"); + } /* end else */ + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, my_fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Close FCPL copy */ + ret = H5Pclose(my_fcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +#if 0 + /* Get size of file */ + empty_filesize = h5_get_file_size(FILENAME, fapl); + if (empty_filesize < 0) + TestErrPrintf("Line %d: file size wrong!\n", __LINE__); +#endif + + /* Re-open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Commit datatype to file */ + if (test_shared == 2) { + ret = H5Tcommit2(fid, TYPE1_NAME, attr_tid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + } /* end if */ + + /* Set up to query the object creation properties */ + if (dcpl_g == H5P_DEFAULT) { + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + } + else { + dcpl = H5Pcopy(dcpl_g); + CHECK(dcpl, FAIL, "H5Pcopy"); + } + + /* Create datasets */ + dataset = H5Dcreate2(fid, DSET1_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + dataset2 = H5Dcreate2(fid, DSET2_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dataset2, FAIL, "H5Dcreate2"); +#if 0 + /* Check on dataset's message storage status */ + if (test_shared != 0) { + /* Datasets' datatypes can be shared */ + ret = H5F__get_sohm_mesg_count_test(fid, H5O_DTYPE_ID, &mesg_count); + CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); + VERIFY(mesg_count, 1, "H5F__get_sohm_mesg_count_test"); + + /* Datasets' dataspace can be shared */ + ret = H5F__get_sohm_mesg_count_test(fid, H5O_SDSPACE_ID, &mesg_count); + CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); + VERIFY(mesg_count, 1, "H5F__get_sohm_mesg_count_test"); + } /* end if */ +#endif + /* Retrieve limits for compact/dense attribute storage */ + ret = H5Pget_attr_phase_change(dcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + + /* Close property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); +#if 0 + /* Check on datasets' attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); + is_dense = H5O__is_attr_dense_test(dataset2); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Add attributes to each dataset, until after converting to dense storage */ + for (u = 0; u < max_compact * 2; u++) { + /* Create attribute name */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + + /* Alternate between creating "small" & "big" attributes */ + if (u % 2) { + /* Create "small" attribute on first dataset */ + attr = H5Acreate2(dataset, attrname, attr_tid, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); +#if 0 + /* Check that attribute is not shared */ + is_shared = H5A__is_shared_test(attr); + VERIFY(is_shared, FALSE, "H5A__is_shared_test"); +#endif + /* Write data into the attribute */ + attr_value = u + 1; + ret = H5Awrite(attr, attr_tid, &attr_value); + CHECK(ret, FAIL, "H5Awrite"); + } /* end if */ + else { + /* Create "big" attribute on first dataset */ + attr = H5Acreate2(dataset, attrname, attr_tid, big_sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); +#if 0 + /* Check that attribute is shared */ + is_shared = H5A__is_shared_test(attr); + VERIFY(is_shared, TRUE, "H5A__is_shared_test"); + + /* Check refcount for attribute */ + ret = H5A__get_shared_rc_test(attr, &shared_refcount); + CHECK(ret, FAIL, "H5A__get_shared_rc_test"); + VERIFY(shared_refcount, 1, "H5A__get_shared_rc_test"); +#endif + /* Write data into the attribute */ + big_value[0] = u + 1; + ret = H5Awrite(attr, attr_tid, big_value); + CHECK(ret, FAIL, "H5Awrite"); +#if 0 + /* Check refcount for attribute */ + ret = H5A__get_shared_rc_test(attr, &shared_refcount); + CHECK(ret, FAIL, "H5A__get_shared_rc_test"); + VERIFY(shared_refcount, 1, "H5A__get_shared_rc_test"); +#endif + } /* end else */ + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + if (u < max_compact) + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); + else + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); +#endif + + /* Alternate between creating "small" & "big" attributes */ + if (u % 2) { + /* Create "small" attribute on second dataset */ + attr = H5Acreate2(dataset2, attrname, attr_tid, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); +#if 0 + /* Check that attribute is not shared */ + is_shared = H5A__is_shared_test(attr); + VERIFY(is_shared, FALSE, "H5A__is_shared_test"); +#endif + /* Write data into the attribute */ + attr_value = u + 1; + ret = H5Awrite(attr, attr_tid, &attr_value); + CHECK(ret, FAIL, "H5Awrite"); + } /* end if */ + else { + /* Create "big" attribute on second dataset */ + attr = H5Acreate2(dataset2, attrname, attr_tid, big_sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); +#if 0 + /* Check that attribute is shared */ + is_shared = H5A__is_shared_test(attr); + VERIFY(is_shared, TRUE, "H5A__is_shared_test"); + + /* Check refcount for attribute */ + ret = H5A__get_shared_rc_test(attr, &shared_refcount); + CHECK(ret, FAIL, "H5A__get_shared_rc_test"); + VERIFY(shared_refcount, 1, "H5A__get_shared_rc_test"); +#endif + /* Write data into the attribute */ + big_value[0] = u + 1; + ret = H5Awrite(attr, attr_tid, big_value); + CHECK(ret, FAIL, "H5Awrite"); +#if 0 + /* Check refcount for attribute */ + ret = H5A__get_shared_rc_test(attr, &shared_refcount); + CHECK(ret, FAIL, "H5A__get_shared_rc_test"); + VERIFY(shared_refcount, 2, "H5A__get_shared_rc_test"); +#endif + } /* end else */ + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset2); + if (u < max_compact) + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); + else + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); +#endif + + /* Create new attribute name */ + HDsnprintf(attrname2, sizeof(attrname2), "new attr %02u", u); + + /* Change second dataset's attribute's name */ + ret = H5Arename_by_name(fid, DSET2_NAME, attrname, attrname2, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Arename_by_name"); + + /* Check refcount on attributes now */ + + /* Check refcount on renamed attribute */ + attr = H5Aopen(dataset2, attrname2, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); +#if 0 + if (u % 2) { + /* Check that attribute is not shared */ + is_shared = H5A__is_shared_test(attr); + VERIFY(is_shared, FALSE, "H5A__is_shared_test"); + } /* end if */ + else { + /* Check that attribute is shared */ + is_shared = H5A__is_shared_test(attr); + VERIFY(is_shared, TRUE, "H5A__is_shared_test"); + + /* Check refcount for attribute */ + ret = H5A__get_shared_rc_test(attr, &shared_refcount); + CHECK(ret, FAIL, "H5A__get_shared_rc_test"); + VERIFY(shared_refcount, 1, "H5A__get_shared_rc_test"); + } /* end else */ +#endif + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Check refcount on original attribute */ + attr = H5Aopen(dataset, attrname, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); +#if 0 + if (u % 2) { + /* Check that attribute is not shared */ + is_shared = H5A__is_shared_test(attr); + VERIFY(is_shared, FALSE, "H5A__is_shared_test"); + } /* end if */ + else { + /* Check that attribute is shared */ + is_shared = H5A__is_shared_test(attr); + VERIFY(is_shared, TRUE, "H5A__is_shared_test"); + + /* Check refcount for attribute */ + ret = H5A__get_shared_rc_test(attr, &shared_refcount); + CHECK(ret, FAIL, "H5A__get_shared_rc_test"); + VERIFY(shared_refcount, 1, "H5A__get_shared_rc_test"); + } /* end else */ +#endif + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Change second dataset's attribute's name back to original */ + ret = H5Arename_by_name(fid, DSET2_NAME, attrname2, attrname, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Arename_by_name"); + + /* Check refcount on attributes now */ + + /* Check refcount on renamed attribute */ + attr = H5Aopen(dataset2, attrname, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); +#if 0 + if (u % 2) { + /* Check that attribute is not shared */ + is_shared = H5A__is_shared_test(attr); + VERIFY(is_shared, FALSE, "H5A__is_shared_test"); + } /* end if */ + else { + /* Check that attribute is shared */ + is_shared = H5A__is_shared_test(attr); + VERIFY(is_shared, TRUE, "H5A__is_shared_test"); + + /* Check refcount for attribute */ + ret = H5A__get_shared_rc_test(attr, &shared_refcount); + CHECK(ret, FAIL, "H5A__get_shared_rc_test"); + VERIFY(shared_refcount, 2, "H5A__get_shared_rc_test"); + } /* end else */ +#endif + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Check refcount on original attribute */ + attr = H5Aopen(dataset, attrname, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); +#if 0 + if (u % 2) { + /* Check that attribute is not shared */ + is_shared = H5A__is_shared_test(attr); + VERIFY(is_shared, FALSE, "H5A__is_shared_test"); + } /* end if */ + else { + /* Check that attribute is shared */ + is_shared = H5A__is_shared_test(attr); + VERIFY(is_shared, TRUE, "H5A__is_shared_test"); + + /* Check refcount for attribute */ + ret = H5A__get_shared_rc_test(attr, &shared_refcount); + CHECK(ret, FAIL, "H5A__get_shared_rc_test"); + VERIFY(shared_refcount, 2, "H5A__get_shared_rc_test"); + } /* end else */ +#endif + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + } /* end for */ + + /* Close attribute's datatype */ + ret = H5Tclose(attr_tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close Datasets */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dataset2); + CHECK(ret, FAIL, "H5Dclose"); +#if 0 + /* Check on shared message status now */ + if (test_shared != 0) { + if (test_shared == 1) { + /* Check on datatype storage status */ + ret = H5F__get_sohm_mesg_count_test(fid, H5O_DTYPE_ID, &mesg_count); + CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); + VERIFY(mesg_count, 2, "H5F__get_sohm_mesg_count_test"); + } /* end if */ + + /* Check on dataspace storage status */ + ret = H5F__get_sohm_mesg_count_test(fid, H5O_SDSPACE_ID, &mesg_count); + CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); + VERIFY(mesg_count, 2, "H5F__get_sohm_mesg_count_test"); + } /* end if */ +#endif + /* Unlink datasets with attributes */ + ret = H5Ldelete(fid, DSET1_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "HLdelete"); + ret = H5Ldelete(fid, DSET2_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + + /* Unlink committed datatype */ + if (test_shared == 2) { + ret = H5Ldelete(fid, TYPE1_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + } /* end if */ +#if 0 + /* Check on attribute storage status */ + ret = H5F__get_sohm_mesg_count_test(fid, H5O_ATTR_ID, &mesg_count); + CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); + VERIFY(mesg_count, 0, "H5F__get_sohm_mesg_count_test"); + + if (test_shared != 0) { + /* Check on datatype storage status */ + ret = H5F__get_sohm_mesg_count_test(fid, H5O_DTYPE_ID, &mesg_count); + CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); + VERIFY(mesg_count, 0, "H5F__get_sohm_mesg_count_test"); + + /* Check on dataspace storage status */ + ret = H5F__get_sohm_mesg_count_test(fid, H5O_SDSPACE_ID, &mesg_count); + CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); + VERIFY(mesg_count, 0, "H5F__get_sohm_mesg_count_test"); + } /* end if */ +#endif + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +#if 0 + if (h5_using_default_driver(NULL)) { + /* Check size of file */ + filesize = h5_get_file_size(FILENAME, fapl); + VERIFY(filesize, empty_filesize, "h5_get_file_size"); + } +#endif + } /* end for */ + + /* Close dataspaces */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(big_sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Release memory */ + HDfree(big_value); +} /* test_attr_shared_rename() */ + +/**************************************************************** +** +** test_attr_shared_delete(): Test basic H5A (attribute) code. +** Tests deleting shared attributes in "compact" & "dense" storage +** +****************************************************************/ +static void +test_attr_shared_delete(hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* File ID */ + hid_t my_fcpl; /* File creation property list ID */ + hid_t dataset, dataset2; /* Dataset IDs */ + hid_t attr_tid; /* Attribute's datatype ID */ + hid_t sid, big_sid; /* Dataspace IDs */ + hsize_t big_dims[] = {SPACE1_DIM1, SPACE1_DIM2, SPACE1_DIM3}; /* Dimensions for "big" attribute */ + hid_t attr; /* Attribute ID */ + hid_t dcpl; /* Dataset creation property list ID */ + char attrname[NAME_BUF_SIZE]; /* Name of attribute on first dataset */ + unsigned max_compact; /* Maximum # of attributes to store compactly */ + unsigned min_dense; /* Minimum # of attributes to store "densely" */ +#if 0 + htri_t is_dense; /* Are attributes stored densely? */ + htri_t is_shared; /* Is attributes shared? */ + hsize_t shared_refcount; /* Reference count of shared attribute */ +#endif + unsigned attr_value; /* Attribute value */ + unsigned *big_value; /* Data for "big" attribute */ +#if 0 + size_t mesg_count; /* # of shared messages */ +#endif + unsigned test_shared; /* Index over shared component type */ + unsigned u; /* Local index variable */ +#if 0 + h5_stat_size_t empty_filesize; /* Size of empty file */ + h5_stat_size_t filesize; /* Size of file after modifications */ +#endif + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Deleting Shared & Unshared Attributes in Compact & Dense Storage\n")); + + /* Allocate & initialize "big" attribute data */ + big_value = (unsigned *)HDmalloc((size_t)(SPACE1_DIM1 * SPACE1_DIM2 * SPACE1_DIM3) * sizeof(unsigned)); + CHECK_PTR(big_value, "HDmalloc"); + HDmemset(big_value, 1, sizeof(unsigned) * (size_t)(SPACE1_DIM1 * SPACE1_DIM2 * SPACE1_DIM3)); + + /* Create dataspace for dataset */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create "big" dataspace for "large" attributes */ + big_sid = H5Screate_simple(SPACE1_RANK, big_dims, NULL); + CHECK(big_sid, FAIL, "H5Screate_simple"); + + /* Loop over type of shared components */ + for (test_shared = 0; test_shared < 3; test_shared++) { + /* Make copy of file creation property list */ + my_fcpl = H5Pcopy(fcpl); + CHECK(my_fcpl, FAIL, "H5Pcopy"); + + /* Set up datatype for attributes */ + attr_tid = H5Tcopy(H5T_NATIVE_UINT); + CHECK(attr_tid, FAIL, "H5Tcopy"); + + /* Special setup for each type of shared components */ + if (test_shared == 0) { + /* Make attributes > 500 bytes shared */ + ret = H5Pset_shared_mesg_nindexes(my_fcpl, (unsigned)1); + CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); + ret = H5Pset_shared_mesg_index(my_fcpl, (unsigned)0, H5O_SHMESG_ATTR_FLAG, (unsigned)500); + CHECK_I(ret, "H5Pset_shared_mesg_index"); + } /* end if */ + else { + /* Set up copy of file creation property list */ + + ret = H5Pset_shared_mesg_nindexes(my_fcpl, (unsigned)3); + CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); + + /* Make attributes > 500 bytes shared */ + ret = H5Pset_shared_mesg_index(my_fcpl, (unsigned)0, H5O_SHMESG_ATTR_FLAG, (unsigned)500); + CHECK_I(ret, "H5Pset_shared_mesg_index"); + + /* Make datatypes & dataspaces > 1 byte shared (i.e. all of them :-) */ + ret = H5Pset_shared_mesg_index(my_fcpl, (unsigned)1, H5O_SHMESG_DTYPE_FLAG, (unsigned)1); + CHECK_I(ret, "H5Pset_shared_mesg_index"); + ret = H5Pset_shared_mesg_index(my_fcpl, (unsigned)2, H5O_SHMESG_SDSPACE_FLAG, (unsigned)1); + CHECK_I(ret, "H5Pset_shared_mesg_index"); + } /* end else */ + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, my_fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Close FCPL copy */ + ret = H5Pclose(my_fcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +#if 0 + /* Get size of file */ + empty_filesize = h5_get_file_size(FILENAME, fapl); + if (empty_filesize < 0) + TestErrPrintf("Line %d: file size wrong!\n", __LINE__); +#endif + + /* Re-open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Commit datatype to file */ + if (test_shared == 2) { + ret = H5Tcommit2(fid, TYPE1_NAME, attr_tid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + } /* end if */ + + /* Set up to query the object creation properties */ + if (dcpl_g == H5P_DEFAULT) { + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + } + else { + dcpl = H5Pcopy(dcpl_g); + CHECK(dcpl, FAIL, "H5Pcopy"); + } + + /* Create datasets */ + dataset = H5Dcreate2(fid, DSET1_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + dataset2 = H5Dcreate2(fid, DSET2_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dataset2, FAIL, "H5Dcreate2"); +#if 0 + /* Check on dataset's message storage status */ + if (test_shared != 0) { + /* Datasets' datatypes can be shared */ + ret = H5F__get_sohm_mesg_count_test(fid, H5O_DTYPE_ID, &mesg_count); + CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); + VERIFY(mesg_count, 1, "H5F__get_sohm_mesg_count_test"); + + /* Datasets' dataspace can be shared */ + ret = H5F__get_sohm_mesg_count_test(fid, H5O_SDSPACE_ID, &mesg_count); + CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); + VERIFY(mesg_count, 1, "H5F__get_sohm_mesg_count_test"); + } /* end if */ +#endif + /* Retrieve limits for compact/dense attribute storage */ + ret = H5Pget_attr_phase_change(dcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + + /* Close property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); +#if 0 + /* Check on datasets' attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); + is_dense = H5O__is_attr_dense_test(dataset2); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Add attributes to each dataset, until after converting to dense storage */ + for (u = 0; u < max_compact * 2; u++) { + /* Create attribute name */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + + /* Alternate between creating "small" & "big" attributes */ + if (u % 2) { + /* Create "small" attribute on first dataset */ + attr = H5Acreate2(dataset, attrname, attr_tid, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); +#if 0 + /* Check that attribute is not shared */ + is_shared = H5A__is_shared_test(attr); + VERIFY(is_shared, FALSE, "H5A__is_shared_test"); +#endif + /* Write data into the attribute */ + attr_value = u + 1; + ret = H5Awrite(attr, attr_tid, &attr_value); + CHECK(ret, FAIL, "H5Awrite"); + } /* end if */ + else { + /* Create "big" attribute on first dataset */ + attr = H5Acreate2(dataset, attrname, attr_tid, big_sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); +#if 0 + /* Check that attribute is shared */ + is_shared = H5A__is_shared_test(attr); + VERIFY(is_shared, TRUE, "H5A__is_shared_test"); + + /* Check refcount for attribute */ + ret = H5A__get_shared_rc_test(attr, &shared_refcount); + CHECK(ret, FAIL, "H5A__get_shared_rc_test"); + VERIFY(shared_refcount, 1, "H5A__get_shared_rc_test"); +#endif + /* Write data into the attribute */ + big_value[0] = u + 1; + ret = H5Awrite(attr, attr_tid, big_value); + CHECK(ret, FAIL, "H5Awrite"); +#if 0 + /* Check refcount for attribute */ + ret = H5A__get_shared_rc_test(attr, &shared_refcount); + CHECK(ret, FAIL, "H5A__get_shared_rc_test"); + VERIFY(shared_refcount, 1, "H5A__get_shared_rc_test"); +#endif + } /* end else */ + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + if (u < max_compact) + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); + else + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); +#endif + + /* Alternate between creating "small" & "big" attributes */ + if (u % 2) { + /* Create "small" attribute on second dataset */ + attr = H5Acreate2(dataset2, attrname, attr_tid, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); +#if 0 + /* Check that attribute is not shared */ + is_shared = H5A__is_shared_test(attr); + VERIFY(is_shared, FALSE, "H5A__is_shared_test"); +#endif + /* Write data into the attribute */ + attr_value = u + 1; + ret = H5Awrite(attr, attr_tid, &attr_value); + CHECK(ret, FAIL, "H5Awrite"); + } /* end if */ + else { + /* Create "big" attribute on second dataset */ + attr = H5Acreate2(dataset2, attrname, attr_tid, big_sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); +#if 0 + /* Check that attribute is shared */ + is_shared = H5A__is_shared_test(attr); + VERIFY(is_shared, TRUE, "H5A__is_shared_test"); + + /* Check refcount for attribute */ + ret = H5A__get_shared_rc_test(attr, &shared_refcount); + CHECK(ret, FAIL, "H5A__get_shared_rc_test"); + VERIFY(shared_refcount, 1, "H5A__get_shared_rc_test"); +#endif + /* Write data into the attribute */ + big_value[0] = u + 1; + ret = H5Awrite(attr, attr_tid, big_value); + CHECK(ret, FAIL, "H5Awrite"); +#if 0 + /* Check refcount for attribute */ + ret = H5A__get_shared_rc_test(attr, &shared_refcount); + CHECK(ret, FAIL, "H5A__get_shared_rc_test"); + VERIFY(shared_refcount, 2, "H5A__get_shared_rc_test"); +#endif + } /* end else */ + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset2); + if (u < max_compact) + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); + else + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); +#endif + } /* end for */ + + /* Delete attributes from second dataset */ + for (u = 0; u < max_compact * 2; u++) { + /* Create attribute name */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + + /* Delete second dataset's attribute */ + ret = H5Adelete_by_name(fid, DSET2_NAME, attrname, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Adelete_by_name"); + + /* Check refcount on attributes now */ + + /* Check refcount on first dataset's attribute */ + attr = H5Aopen(dataset, attrname, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); +#if 0 + if (u % 2) { + /* Check that attribute is not shared */ + is_shared = H5A__is_shared_test(attr); + VERIFY(is_shared, FALSE, "H5A__is_shared_test"); + } /* end if */ + else { + /* Check that attribute is shared */ + is_shared = H5A__is_shared_test(attr); + VERIFY(is_shared, TRUE, "H5A__is_shared_test"); + + /* Check refcount for attribute */ + ret = H5A__get_shared_rc_test(attr, &shared_refcount); + CHECK(ret, FAIL, "H5A__get_shared_rc_test"); + VERIFY(shared_refcount, 1, "H5A__get_shared_rc_test"); + } /* end else */ +#endif + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + } /* end for */ + + /* Close attribute's datatype */ + ret = H5Tclose(attr_tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close Datasets */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dataset2); + CHECK(ret, FAIL, "H5Dclose"); +#if 0 + /* Check on shared message status now */ + if (test_shared != 0) { + if (test_shared == 1) { + /* Check on datatype storage status */ + ret = H5F__get_sohm_mesg_count_test(fid, H5O_DTYPE_ID, &mesg_count); + CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); + VERIFY(mesg_count, 2, "H5F__get_sohm_mesg_count_test"); + } /* end if */ + + /* Check on dataspace storage status */ + ret = H5F__get_sohm_mesg_count_test(fid, H5O_SDSPACE_ID, &mesg_count); + CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); + VERIFY(mesg_count, 2, "H5F__get_sohm_mesg_count_test"); + } /* end if */ +#endif + /* Unlink datasets with attributes */ + ret = H5Ldelete(fid, DSET1_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + ret = H5Ldelete(fid, DSET2_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + + /* Unlink committed datatype */ + if (test_shared == 2) { + ret = H5Ldelete(fid, TYPE1_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + } /* end if */ +#if 0 + /* Check on attribute storage status */ + ret = H5F__get_sohm_mesg_count_test(fid, H5O_ATTR_ID, &mesg_count); + CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); + VERIFY(mesg_count, 0, "H5F__get_sohm_mesg_count_test"); + + if (test_shared != 0) { + /* Check on datatype storage status */ + ret = H5F__get_sohm_mesg_count_test(fid, H5O_DTYPE_ID, &mesg_count); + CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); + VERIFY(mesg_count, 0, "H5F__get_sohm_mesg_count_test"); + + /* Check on dataspace storage status */ + ret = H5F__get_sohm_mesg_count_test(fid, H5O_SDSPACE_ID, &mesg_count); + CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); + VERIFY(mesg_count, 0, "H5F__get_sohm_mesg_count_test"); + } /* end if */ +#endif + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +#if 0 + if (h5_using_default_driver(NULL)) { + /* Check size of file */ + filesize = h5_get_file_size(FILENAME, fapl); + VERIFY(filesize, empty_filesize, "h5_get_file_size"); + } +#endif + } /* end for */ + + /* Close dataspaces */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(big_sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Release memory */ + HDfree(big_value); +} /* test_attr_shared_delete() */ + +/**************************************************************** +** +** test_attr_shared_unlink(): Test basic H5A (attribute) code. +** Tests unlinking object with shared attributes in "compact" & "dense" storage +** +****************************************************************/ +static void +test_attr_shared_unlink(hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* File ID */ + hid_t my_fcpl; /* File creation property list ID */ + hid_t dataset, dataset2; /* Dataset IDs */ + hid_t attr_tid; /* Attribute's datatype ID */ + hid_t sid, big_sid; /* Dataspace IDs */ + hsize_t big_dims[] = {SPACE1_DIM1, SPACE1_DIM2, SPACE1_DIM3}; /* Dimensions for "big" attribute */ + hid_t attr; /* Attribute ID */ + hid_t dcpl; /* Dataset creation property list ID */ + char attrname[NAME_BUF_SIZE]; /* Name of attribute on first dataset */ + unsigned max_compact; /* Maximum # of attributes to store compactly */ + unsigned min_dense; /* Minimum # of attributes to store "densely" */ +#if 0 + htri_t is_dense; /* Are attributes stored densely? */ + htri_t is_shared; /* Is attributes shared? */ + hsize_t shared_refcount; /* Reference count of shared attribute */ +#endif + unsigned attr_value; /* Attribute value */ + unsigned *big_value; /* Data for "big" attribute */ +#if 0 + size_t mesg_count; /* # of shared messages */ +#endif + unsigned test_shared; /* Index over shared component type */ + unsigned u; /* Local index variable */ +#if 0 + h5_stat_size_t empty_filesize; /* Size of empty file */ + h5_stat_size_t filesize; /* Size of file after modifications */ +#endif + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Unlinking Object with Shared Attributes in Compact & Dense Storage\n")); + + /* Allocate & initialize "big" attribute data */ + big_value = (unsigned *)HDmalloc((size_t)(SPACE1_DIM1 * SPACE1_DIM2 * SPACE1_DIM3) * sizeof(unsigned)); + CHECK_PTR(big_value, "HDmalloc"); + HDmemset(big_value, 1, sizeof(unsigned) * (size_t)(SPACE1_DIM1 * SPACE1_DIM2 * SPACE1_DIM3)); + + /* Create dataspace for dataset */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create "big" dataspace for "large" attributes */ + big_sid = H5Screate_simple(SPACE1_RANK, big_dims, NULL); + CHECK(big_sid, FAIL, "H5Screate_simple"); + + /* Loop over type of shared components */ + for (test_shared = 0; test_shared < 3; test_shared++) { + /* Make copy of file creation property list */ + my_fcpl = H5Pcopy(fcpl); + CHECK(my_fcpl, FAIL, "H5Pcopy"); + + /* Set up datatype for attributes */ + attr_tid = H5Tcopy(H5T_NATIVE_UINT); + CHECK(attr_tid, FAIL, "H5Tcopy"); + + /* Special setup for each type of shared components */ + if (test_shared == 0) { + /* Make attributes > 500 bytes shared */ + ret = H5Pset_shared_mesg_nindexes(my_fcpl, (unsigned)1); + CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); + ret = H5Pset_shared_mesg_index(my_fcpl, (unsigned)0, H5O_SHMESG_ATTR_FLAG, (unsigned)500); + CHECK_I(ret, "H5Pset_shared_mesg_index"); + } /* end if */ + else { + /* Set up copy of file creation property list */ + + ret = H5Pset_shared_mesg_nindexes(my_fcpl, (unsigned)3); + CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); + + /* Make attributes > 500 bytes shared */ + ret = H5Pset_shared_mesg_index(my_fcpl, (unsigned)0, H5O_SHMESG_ATTR_FLAG, (unsigned)500); + CHECK_I(ret, "H5Pset_shared_mesg_index"); + + /* Make datatypes & dataspaces > 1 byte shared (i.e. all of them :-) */ + ret = H5Pset_shared_mesg_index(my_fcpl, (unsigned)1, H5O_SHMESG_DTYPE_FLAG, (unsigned)1); + CHECK_I(ret, "H5Pset_shared_mesg_index"); + ret = H5Pset_shared_mesg_index(my_fcpl, (unsigned)2, H5O_SHMESG_SDSPACE_FLAG, (unsigned)1); + CHECK_I(ret, "H5Pset_shared_mesg_index"); + } /* end else */ + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, my_fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Close FCPL copy */ + ret = H5Pclose(my_fcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +#if 0 + /* Get size of file */ + empty_filesize = h5_get_file_size(FILENAME, fapl); + if (empty_filesize < 0) + TestErrPrintf("Line %d: file size wrong!\n", __LINE__); +#endif + + /* Re-open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Commit datatype to file */ + if (test_shared == 2) { + ret = H5Tcommit2(fid, TYPE1_NAME, attr_tid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + } /* end if */ + + /* Set up to query the object creation properties */ + if (dcpl_g == H5P_DEFAULT) { + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + } + else { + dcpl = H5Pcopy(dcpl_g); + CHECK(dcpl, FAIL, "H5Pcopy"); + } + + /* Create datasets */ + dataset = H5Dcreate2(fid, DSET1_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + dataset2 = H5Dcreate2(fid, DSET2_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dataset2, FAIL, "H5Dcreate2"); +#if 0 + /* Check on dataset's message storage status */ + if (test_shared != 0) { + /* Datasets' datatypes can be shared */ + ret = H5F__get_sohm_mesg_count_test(fid, H5O_DTYPE_ID, &mesg_count); + CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); + VERIFY(mesg_count, 1, "H5F__get_sohm_mesg_count_test"); + + /* Datasets' dataspace can be shared */ + ret = H5F__get_sohm_mesg_count_test(fid, H5O_SDSPACE_ID, &mesg_count); + CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); + VERIFY(mesg_count, 1, "H5F__get_sohm_mesg_count_test"); + } /* end if */ +#endif + /* Retrieve limits for compact/dense attribute storage */ + ret = H5Pget_attr_phase_change(dcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + + /* Close property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); +#if 0 + /* Check on datasets' attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); + is_dense = H5O__is_attr_dense_test(dataset2); + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); +#endif + /* Add attributes to each dataset, until after converting to dense storage */ + for (u = 0; u < max_compact * 2; u++) { + /* Create attribute name */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + + /* Alternate between creating "small" & "big" attributes */ + if (u % 2) { + /* Create "small" attribute on first dataset */ + attr = H5Acreate2(dataset, attrname, attr_tid, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); +#if 0 + /* Check that attribute is not shared */ + is_shared = H5A__is_shared_test(attr); + VERIFY(is_shared, FALSE, "H5A__is_shared_test"); +#endif + /* Write data into the attribute */ + attr_value = u + 1; + ret = H5Awrite(attr, attr_tid, &attr_value); + CHECK(ret, FAIL, "H5Awrite"); + } /* end if */ + else { + /* Create "big" attribute on first dataset */ + attr = H5Acreate2(dataset, attrname, attr_tid, big_sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); +#if 0 + /* ChecFk that attribute is shared */ + is_shared = H5A__is_shared_test(attr); + VERIFY(is_shared, TRUE, "H5A__is_shared_test"); + + /* Check refcount for attribute */ + ret = H5A__get_shared_rc_test(attr, &shared_refcount); + CHECK(ret, FAIL, "H5A__get_shared_rc_test"); + VERIFY(shared_refcount, 1, "H5A__get_shared_rc_test"); +#endif + /* Write data into the attribute */ + big_value[0] = u + 1; + ret = H5Awrite(attr, attr_tid, big_value); + CHECK(ret, FAIL, "H5Awrite"); +#if 0 + /* Check refcount for attribute */ + ret = H5A__get_shared_rc_test(attr, &shared_refcount); + CHECK(ret, FAIL, "H5A__get_shared_rc_test"); + VERIFY(shared_refcount, 1, "H5A__get_shared_rc_test"); +#endif + } /* end else */ + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + if (u < max_compact) + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); + else + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); +#endif + + /* Alternate between creating "small" & "big" attributes */ + if (u % 2) { + /* Create "small" attribute on second dataset */ + attr = H5Acreate2(dataset2, attrname, attr_tid, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); +#if 0 + /* Check that attribute is not shared */ + is_shared = H5A__is_shared_test(attr); + VERIFY(is_shared, FALSE, "H5A__is_shared_test"); +#endif + /* Write data into the attribute */ + attr_value = u + 1; + ret = H5Awrite(attr, attr_tid, &attr_value); + CHECK(ret, FAIL, "H5Awrite"); + } /* end if */ + else { + /* Create "big" attribute on second dataset */ + attr = H5Acreate2(dataset2, attrname, attr_tid, big_sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); +#if 0 + /* Check that attribute is shared */ + is_shared = H5A__is_shared_test(attr); + VERIFY(is_shared, TRUE, "H5A__is_shared_test"); + + /* Check refcount for attribute */ + ret = H5A__get_shared_rc_test(attr, &shared_refcount); + CHECK(ret, FAIL, "H5A__get_shared_rc_test"); + VERIFY(shared_refcount, 1, "H5A__get_shared_rc_test"); +#endif + /* Write data into the attribute */ + big_value[0] = u + 1; + ret = H5Awrite(attr, attr_tid, big_value); + CHECK(ret, FAIL, "H5Awrite"); +#if 0 + /* Check refcount for attribute */ + ret = H5A__get_shared_rc_test(attr, &shared_refcount); + CHECK(ret, FAIL, "H5A__get_shared_rc_test"); + VERIFY(shared_refcount, 2, "H5A__get_shared_rc_test"); +#endif + } /* end else */ + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); +#if 0 + /* Check on dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset2); + if (u < max_compact) + VERIFY(is_dense, FALSE, "H5O__is_attr_dense_test"); + else + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); +#endif + } /* end for */ + + /* Close attribute's datatype */ + ret = H5Tclose(attr_tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close second dataset */ + ret = H5Dclose(dataset2); + CHECK(ret, FAIL, "H5Dclose"); + + /* Unlink second dataset */ + ret = H5Ldelete(fid, DSET2_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + +#if 0 + /* Check on first dataset's attribute storage status */ + is_dense = H5O__is_attr_dense_test(dataset); + VERIFY(is_dense, TRUE, "H5O__is_attr_dense_test"); +#endif + /* Check ref count on attributes of first dataset */ + for (u = 0; u < max_compact * 2; u++) { + /* Create attribute name */ + HDsnprintf(attrname, sizeof(attrname), "attr %02u", u); + + /* Open attribute on first dataset */ + attr = H5Aopen(dataset, attrname, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); +#if 0 + if (u % 2) { + /* Check that attribute is not shared */ + is_shared = H5A__is_shared_test(attr); + VERIFY(is_shared, FALSE, "H5A__is_shared_test"); + } /* end if */ + else { + /* Check that attribute is shared */ + is_shared = H5A__is_shared_test(attr); + VERIFY(is_shared, TRUE, "H5A__is_shared_test"); + + /* Check refcount for attribute */ + ret = H5A__get_shared_rc_test(attr, &shared_refcount); + CHECK(ret, FAIL, "H5A__get_shared_rc_test"); + VERIFY(shared_refcount, 1, "H5A__get_shared_rc_test"); + } /* end else */ +#endif + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + } /* end for */ + + /* Close Datasets */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Unlink first dataset */ + ret = H5Ldelete(fid, DSET1_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + + /* Unlink committed datatype */ + if (test_shared == 2) { + ret = H5Ldelete(fid, TYPE1_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + } /* end if */ +#if 0 + /* Check on attribute storage status */ + ret = H5F__get_sohm_mesg_count_test(fid, H5O_ATTR_ID, &mesg_count); + CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); + VERIFY(mesg_count, 0, "H5F__get_sohm_mesg_count_test"); + + if (test_shared != 0) { + /* Check on datatype storage status */ + ret = H5F__get_sohm_mesg_count_test(fid, H5O_DTYPE_ID, &mesg_count); + CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); + VERIFY(mesg_count, 0, "H5F__get_sohm_mesg_count_test"); + + /* Check on dataspace storage status */ + ret = H5F__get_sohm_mesg_count_test(fid, H5O_SDSPACE_ID, &mesg_count); + CHECK(ret, FAIL, "H5F__get_sohm_mesg_count_test"); + VERIFY(mesg_count, 0, "H5F__get_sohm_mesg_count_test"); + } /* end if */ +#endif + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +#if 0 + if (h5_using_default_driver(NULL)) { + /* Check size of file */ + filesize = h5_get_file_size(FILENAME, fapl); + VERIFY(filesize, empty_filesize, "h5_get_file_size"); + } +#endif + } /* end for */ + + /* Close dataspaces */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(big_sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Release memory */ + HDfree(big_value); +} /* test_attr_shared_unlink() */ + +/**************************************************************** +** +** test_attr_bug1(): Test basic H5A (attribute) code. +** Tests odd sequence of allocating and deallocating space in the file. +** The series of actions below constructs a file with an attribute +** in each object header chunk, except the first. Then, the attributes +** are removed and re-created in a way that makes the object header +** allocation code remove an object header chunk "in the middle" of +** the sequence of the chunks. +** +****************************************************************/ +static void +test_attr_bug1(hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* File ID */ + hid_t gid; /* Group ID */ + hid_t aid; /* Attribute ID */ + hid_t sid; /* Dataspace ID */ + herr_t ret; /* Generic return status */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Allocating and De-allocating Attributes in Unusual Way\n")); + + /* Create dataspace ID for attributes */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create main group to operate on */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + gid = H5Gcreate2(fid, GROUP1_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gcreate2"); + + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open file and create another group, then attribute on first group */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Create second group */ + gid = H5Gcreate2(fid, GROUP2_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gcreate2"); + + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + /* Re-open first group */ + gid = H5Gopen2(fid, GROUP1_NAME, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gopen2"); + + /* Create attribute on first group */ + aid = H5Acreate2(gid, ATTR7_NAME, H5T_NATIVE_DOUBLE, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open file and create another group, then another attribute on first group */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Create third group */ + gid = H5Gcreate2(fid, GROUP3_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gcreate2"); + + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + /* Unlink second group */ + ret = H5Ldelete(fid, GROUP2_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + + /* Re-open first group */ + gid = H5Gopen2(fid, GROUP1_NAME, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gopen2"); + + /* Create another attribute on first group */ + aid = H5Acreate2(gid, ATTR8_NAME, H5T_NATIVE_DOUBLE, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open file and re-create attributes on first group */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Re-open first group */ + gid = H5Gopen2(fid, GROUP1_NAME, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gopen2"); + + /* Delete first attribute */ + ret = H5Adelete(gid, ATTR7_NAME); + CHECK(ret, FAIL, "H5Adelete"); + + /* Re-create first attribute */ + aid = H5Acreate2(gid, ATTR7_NAME, H5T_NATIVE_DOUBLE, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + + /* Delete second attribute */ + ret = H5Adelete(gid, ATTR8_NAME); + CHECK(ret, FAIL, "H5Adelete"); + + /* Re-create second attribute */ + aid = H5Acreate2(gid, ATTR8_NAME, H5T_NATIVE_DOUBLE, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Close dataspace ID */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Gclose"); +} /* test_attr_bug1() */ + +/**************************************************************** +** +** test_attr_bug2(): Test basic H5A (attribute) code. +** Tests deleting a large number of attributes with the +** intention of creating a null message with a size that +** is too large. This routine deletes every other +** attribute, but the original bug could also be +** reproduced by deleting every attribute except a few to +** keep the chunk open. +** +****************************************************************/ +static void +test_attr_bug2(hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* File ID */ + hid_t gid; /* Group ID */ + hid_t aid; /* Attribute ID */ + hid_t sid; /* Dataspace ID */ + hid_t tid; /* Datatype ID */ + hid_t gcpl; /* Group creation property list */ + hsize_t dims[2] = {10, 100}; /* Attribute dimensions */ + char aname[16]; /* Attribute name */ + unsigned i; /* index */ + herr_t ret; /* Generic return status */ + htri_t tri_ret; /* htri_t return status */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Allocating and De-allocating Attributes in Unusual Way\n")); + + /* Create group creation property list */ + gcpl = H5Pcreate(H5P_GROUP_CREATE); + CHECK(gcpl, FAIL, "H5Pcreate"); + + /* Prevent the library from switching to dense attribute storage */ + /* Not doing this with the latest format actually triggers a different bug. + * This will be tested here as soon as it is fixed. -NAF + */ + ret = H5Pset_attr_phase_change(gcpl, BUG2_NATTR + 10, BUG2_NATTR + 5); + CHECK(ret, FAIL, "H5Pset_attr_phase_change"); + + /* Create dataspace ID for attributes */ + sid = H5Screate_simple(2, dims, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Create main group to operate on */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + gid = H5Gcreate2(fid, GROUP1_NAME, H5P_DEFAULT, gcpl, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gcreate2"); + + /* Create attributes on group */ + for (i = 0; i < BUG2_NATTR; i++) { + HDsnprintf(aname, sizeof(aname), "%03u", i); + aid = H5Acreate2(gid, aname, H5T_STD_I32LE, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + } + + /* Delete every other attribute */ + for (i = 1; i < BUG2_NATTR; i += 2) { + HDsnprintf(aname, sizeof(aname), "%03u", i); + ret = H5Adelete(gid, aname); + CHECK(ret, FAIL, "H5Adelete"); + } + + /* Close IDs */ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Reopen file and group */ + fid = H5Fopen(FILENAME, H5F_ACC_RDONLY, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + gid = H5Gopen2(fid, GROUP1_NAME, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gopen"); + + /* Open an attribute in the middle */ + i = (BUG2_NATTR / 4) * 2; + HDsnprintf(aname, sizeof(aname), "%03u", i); + aid = H5Aopen(gid, aname, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Aopen"); + + /* Verify that the attribute has the correct datatype */ + tid = H5Aget_type(aid); + CHECK(tid, FAIL, "H5Aget_type"); + + tri_ret = H5Tequal(tid, H5T_STD_I32LE); + VERIFY(tri_ret, TRUE, "H5Tequal"); + + /* Close IDs */ + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Now test a variation on this bug - where either the size of chunk 0 goes + * down a "notch" or two, or chunk 1 becomes completely null at the same + * time that a null message that is too large is formed */ + dims[0] = 25; + dims[1] = 41; /* 1025*4 byte attribute size */ + + /* Create dataspace ID for attributes */ + sid = H5Screate_simple(2, dims, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Create main group to operate on */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + gid = H5Gcreate2(fid, GROUP1_NAME, H5P_DEFAULT, gcpl, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gcreate2"); + + /* Create attributes on group */ + for (i = 0; i < BUG2_NATTR2; i++) { + HDsnprintf(aname, sizeof(aname), "%03u", i); + aid = H5Acreate2(gid, aname, H5T_STD_I32LE, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + } + + /* Delete every other attribute */ + for (i = 0; i < BUG2_NATTR2; i++) { + HDsnprintf(aname, sizeof(aname), "%03u", i); + ret = H5Adelete(gid, aname); + CHECK(ret, FAIL, "H5Adelete"); + } + + /* Close IDs */ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Pclose(gcpl); + CHECK(ret, FAIL, "H5Pclose"); +} /* test_attr_bug2() */ + +/**************************************************************** +** +** test_attr_bug3(): Test basic H5A (attribute) code. +** Tests creating and deleting attributes which use a +** datatype and/or dataspace stored in the same object +** header. +** +****************************************************************/ +static void +test_attr_bug3(hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* File ID */ + hid_t aid1, aid2; /* Attribute IDs */ + hid_t sid1, sid2; /* Dataspace ID */ + hid_t tid1, tid2; /* Datatype IDs */ + hid_t did; /* Dataset ID */ + hsize_t dims1[2] = {2, 2}, dims2[2] = {3, 3}; /* Dimensions */ + int wdata1[2][2]; + unsigned wdata2[3][3]; /* Write buffers */ + unsigned u, v; /* Local index variables */ + herr_t ret; /* Generic return status */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Attributes in the Same Header as their Datatypes\n")); + + /* Create dataspaces */ + sid1 = H5Screate_simple(2, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + sid2 = H5Screate_simple(2, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Create file to operate on */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create datatypes and commit tid1 */ + tid1 = H5Tcopy(H5T_STD_I16BE); + CHECK(tid1, FAIL, "H5Tcopy"); + tid2 = H5Tcopy(H5T_STD_U64LE); + CHECK(tid1, FAIL, "H5Tcopy"); + ret = H5Tcommit2(fid, "dtype", tid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + + /* Create dataset */ + did = H5Dcreate2(fid, "dset", tid2, sid2, H5P_DEFAULT, dcpl_g, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); + + /* Create attribute on datatype, using that datatype as its datatype */ + aid1 = H5Acreate2(tid1, "attr", tid1, sid1, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid1, FAIL, "H5Acreate2"); + + /* Create attribute on dataset, using its datatype and dataspace */ + aid2 = H5Acreate2(did, "attr", tid2, sid2, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid2, FAIL, "H5Acreate2"); + + /* Close attributes */ + ret = H5Aclose(aid1); + CHECK(ret, FAIL, "H5Aclose"); + ret = H5Aclose(aid2); + CHECK(ret, FAIL, "H5Aclose"); + + /* Reopen attributes */ + aid1 = H5Aopen(tid1, "attr", H5P_DEFAULT); + CHECK(aid1, FAIL, "H5Aopen"); + aid2 = H5Aopen(did, "attr", H5P_DEFAULT); + CHECK(aid2, FAIL, "H5Aopen"); + + /* Initialize the write buffers */ + for (u = 0; u < dims1[0]; u++) + for (v = 0; v < dims1[1]; v++) + wdata1[u][v] = (int)((u * dims1[1]) + v); + for (u = 0; u < dims2[0]; u++) + for (v = 0; v < dims2[1]; v++) + wdata2[u][v] = (unsigned)((u * dims2[1]) + v); + + /* Write data to the attributes */ + ret = H5Awrite(aid1, H5T_NATIVE_INT, wdata1); + CHECK(ret, FAIL, "H5Awrite"); + ret = H5Awrite(aid2, H5T_NATIVE_UINT, wdata2); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attributes */ + ret = H5Aclose(aid1); + CHECK(ret, FAIL, "H5Aclose"); + ret = H5Aclose(aid2); + CHECK(ret, FAIL, "H5Aclose"); + + /* Delete attributes */ + ret = H5Adelete(tid1, "attr"); + CHECK(ret, FAIL, "H5Adelete"); + ret = H5Adelete(did, "attr"); + CHECK(ret, FAIL, "H5Adelete"); + + /* Recreate attributes */ + aid1 = H5Acreate2(tid1, "attr", tid1, sid1, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid1, FAIL, "H5Acreate2"); + aid2 = H5Acreate2(did, "attr", tid2, sid2, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid2, FAIL, "H5Acreate2"); + + /* Delete attributes (note they are still open) */ + ret = H5Adelete(tid1, "attr"); + CHECK(ret, FAIL, "H5Adelete"); + ret = H5Adelete(did, "attr"); + CHECK(ret, FAIL, "H5Adelete"); + + /* Close dataspaces and transient datatype */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Tclose(tid2); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close dataset and committed datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* Delete dataset and committed datatype */ + ret = H5Ldelete(fid, "dtype", H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Ldelete(fid, "dset", H5P_DEFAULT); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close attributes */ + ret = H5Aclose(aid1); + CHECK(ret, FAIL, "H5Aclose"); + ret = H5Aclose(aid2); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_attr_bug3() */ + +/**************************************************************** +** +** test_attr_bug4(): Test basic H5A (attribute) code. +** Attempts to trigger a bug which would result in being +** unable to add an attribute to a named datatype. This +** happened when an object header chunk was too small to +** hold a continuation message and could not be extended. +** +****************************************************************/ +static void +test_attr_bug4(hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* File ID */ + hid_t gid; /* Group ID */ + hid_t aid1, aid2, aid3; /* Attribute IDs */ + hid_t sid; /* Dataspace ID */ + hid_t tid; /* Datatype ID */ + hid_t did; /* Dataset ID */ + hsize_t dims[1] = {5}; /* Attribute dimensions */ + herr_t ret; /* Generic return status */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing that attributes can always be added to named datatypes\n")); + + /* Create dataspace */ + sid = H5Screate_simple(1, dims, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Open root group */ + gid = H5Gopen2(fid, "/", H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gcreate2"); + + /* Create committed datatype */ + tid = H5Tcopy(H5T_STD_I32LE); + CHECK(tid, FAIL, "H5Tcopy"); + ret = H5Tcommit2(fid, "dtype", tid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + + /* Create dataset */ + did = H5Dcreate2(fid, "dset", tid, sid, H5P_DEFAULT, dcpl_g, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); + + /* Create attributes on group and dataset */ + aid1 = H5Acreate2(gid, "attr", tid, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid1, FAIL, "H5Acreate2"); + aid2 = H5Acreate2(did, "attr", tid, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid2, FAIL, "H5Acreate2"); + + /* Create attribute on datatype (this is the main test) */ + aid3 = H5Acreate2(tid, "attr", tid, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid3, FAIL, "H5Acreate2"); + + /* Close IDs */ + ret = H5Aclose(aid3); + CHECK(ret, FAIL, "H5Aclose"); + + ret = H5Aclose(aid2); + CHECK(ret, FAIL, "H5Aclose"); + + ret = H5Aclose(aid1); + CHECK(ret, FAIL, "H5Aclose"); + + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_attr_bug4() */ + +/**************************************************************** +** +** test_attr_bug5(): Test basic H5A (attribute) code. +** Tests opening an attribute multiple times through +** objects opened through different file handles. +** +****************************************************************/ +static void +test_attr_bug5(hid_t fcpl, hid_t fapl) +{ + hid_t fid1, fid2; /* File IDs */ + hid_t gid1, gid2; /* Group IDs */ + hid_t did1, did2; /* Dataset IDs */ + hid_t tid1, tid2; /* Datatype IDs */ + hid_t aidg1, aidg2, aidd1, aidd2, aidt1, aidt2; /* Attribute IDs */ + hid_t sid; /* Dataspace ID */ + hsize_t dims[1] = {5}; /* Attribute dimensions */ + herr_t ret; /* Generic return status */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Opening an Attribute Through Multiple Files Concurrently\n")); + + /* Create dataspace ID for attributes and datasets */ + sid = H5Screate_simple(1, dims, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Open root group */ + gid1 = H5Gopen2(fid1, "/", H5P_DEFAULT); + CHECK(gid1, FAIL, "H5Gopen2"); + + /* Create and commit datatype */ + tid1 = H5Tcopy(H5T_STD_I32LE); + CHECK(tid1, FAIL, "H5Tcopy"); + ret = H5Tcommit2(fid1, BUG3_DT_NAME, tid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + + /* Create dataset */ + did1 = H5Dcreate2(fid1, BUG3_DSET_NAME, tid1, sid, H5P_DEFAULT, dcpl_g, H5P_DEFAULT); + CHECK(did1, FAIL, "H5Dcreate2"); + + /* Create attribute on root group */ + aidg1 = H5Acreate2(gid1, BUG3_ATTR_NAME, tid1, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aidg1, FAIL, "H5Acreate2"); + + /* Create attribute on dataset */ + aidd1 = H5Acreate2(did1, BUG3_ATTR_NAME, tid1, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aidd1, FAIL, "H5Acreate2"); + + /* Create attribute on datatype */ + aidt1 = H5Acreate2(tid1, BUG3_ATTR_NAME, tid1, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aidt1, FAIL, "H5Acreate2"); + + /* Close all IDs */ + ret = H5Aclose(aidt1); + CHECK(ret, FAIL, "H5Aclose"); + ret = H5Aclose(aidd1); + CHECK(ret, FAIL, "H5Aclose"); + ret = H5Aclose(aidg1); + CHECK(ret, FAIL, "H5Aclose"); + ret = H5Dclose(did1); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Gclose(gid1); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Open file twice */ + fid1 = H5Fopen(FILENAME, H5F_ACC_RDONLY, fapl); + CHECK(fid1, FAIL, "H5Fopen"); + fid2 = H5Fopen(FILENAME, H5F_ACC_RDONLY, fapl); + CHECK(fid2, FAIL, "H5Fopen"); + + /* Open the root group twice */ + gid1 = H5Gopen2(fid1, "/", H5P_DEFAULT); + CHECK(gid1, FAIL, "H5Gopen2"); + gid2 = H5Gopen2(fid2, "/", H5P_DEFAULT); + CHECK(gid2, FAIL, "H5Gopen2"); + + /* Open the root group attribute twice */ + aidg1 = H5Aopen(gid1, BUG3_ATTR_NAME, H5P_DEFAULT); + CHECK(aidg1, FAIL, "H5Aopen"); + aidg2 = H5Aopen(gid2, BUG3_ATTR_NAME, H5P_DEFAULT); + CHECK(aidg1, FAIL, "H5Aopen"); + + /* Open the dataset twice */ + did1 = H5Dopen2(fid1, BUG3_DSET_NAME, H5P_DEFAULT); + CHECK(did1, FAIL, "H5Dopen2"); + did2 = H5Dopen2(fid2, BUG3_DSET_NAME, H5P_DEFAULT); + CHECK(did2, FAIL, "H5Dopen2"); + + /* Open the dataset attribute twice */ + aidd1 = H5Aopen(did1, BUG3_ATTR_NAME, H5P_DEFAULT); + CHECK(aidd1, FAIL, "H5Aopen"); + aidd2 = H5Aopen(did2, BUG3_ATTR_NAME, H5P_DEFAULT); + CHECK(aidd1, FAIL, "H5Aopen"); + + /* Open the datatype twice */ + tid1 = H5Topen2(fid1, BUG3_DT_NAME, H5P_DEFAULT); + CHECK(tid1, FAIL, "H5Topen2"); + tid2 = H5Topen2(fid2, BUG3_DT_NAME, H5P_DEFAULT); + CHECK(tid2, FAIL, "H5Topen2"); + + /* Open the datatype attribute twice */ + aidt1 = H5Aopen(tid1, BUG3_ATTR_NAME, H5P_DEFAULT); + CHECK(aidt1, FAIL, "H5Aopen"); + aidt2 = H5Aopen(tid2, BUG3_ATTR_NAME, H5P_DEFAULT); + CHECK(aidt2, FAIL, "H5Aopen"); + + /* Close all attributes */ + ret = H5Aclose(aidg1); + CHECK(ret, FAIL, "H5Aclose"); + ret = H5Aclose(aidg2); + CHECK(ret, FAIL, "H5Aclose"); + ret = H5Aclose(aidd1); + CHECK(ret, FAIL, "H5Aclose"); + ret = H5Aclose(aidd2); + CHECK(ret, FAIL, "H5Aclose"); + ret = H5Aclose(aidt1); + CHECK(ret, FAIL, "H5Aclose"); + ret = H5Aclose(aidt2); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close root groups */ + ret = H5Gclose(gid1); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Gclose(gid2); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close datasets */ + ret = H5Dclose(did1); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(did2); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close datatypes */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Tclose(tid2); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close files */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + ret = H5Fclose(fid2); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_attr_bug5() */ + +/**************************************************************** +** +** test_attr_bug6(): Test basic H5A (attribute) code. +** Tests if reading an empty attribute is OK. +** +****************************************************************/ +static void +test_attr_bug6(hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* File ID */ + hid_t gid; /* Group ID */ + hid_t aid1, aid2; /* Attribute IDs */ + hid_t sid; /* Dataspace ID */ + hsize_t dims[ATTR1_RANK] = {ATTR1_DIM1}; /* Attribute dimensions */ + int intar[ATTR1_DIM1]; /* Data reading buffer */ + herr_t ret; /* Generic return status */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing that empty attribute can be read\n")); + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Open root group */ + gid = H5Gopen2(fid, "/", H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gopen2"); + + /* Create dataspace */ + sid = H5Screate_simple(1, dims, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Create attribute on group */ + aid1 = H5Acreate2(gid, ATTR1_NAME, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid1, FAIL, "H5Acreate2"); + + ret = H5Aclose(aid1); + CHECK(ret, FAIL, "H5Aclose"); + + /* Open the attribute again */ + aid2 = H5Aopen(gid, ATTR1_NAME, H5P_DEFAULT); + CHECK(aid2, FAIL, "H5Aopen"); + + ret = H5Aread(aid2, H5T_NATIVE_INT, intar); + CHECK(ret, FAIL, "H5Aread"); + + /* Close IDs */ + ret = H5Aclose(aid2); + CHECK(ret, FAIL, "H5Aclose"); + + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_attr_bug6() */ + +/**************************************************************** +** +** test_attr_bug7(): Test basic H5A (attribute) code. +** (Really tests object header allocation code). +** Tests creating and deleting attributes in such a way as +** to change the size of the "chunk #0 size" field. +** Includes testing "skipping" a possible size of the +** field, i.e. going from 1 to 4 bytes or 4 to 1 byte. +** +****************************************************************/ +#if 0 +static void +test_attr_bug7(hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* File ID */ + hid_t aid; /* Attribute ID */ + hid_t sid; /* Dataspace ID */ + hid_t tid; /* Datatype ID */ + hsize_t dims_s = 140; /* Small attribute dimensions */ + hsize_t dims_l = 65480; /* Large attribute dimensions */ + H5A_info_t ainfo; /* Attribute info */ + herr_t ret; /* Generic return status */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing adding and deleting large attributes\n")); + + /* Create committed datatype to operate on. Use a committed datatype so that + * there is nothing after the object header and the first chunk can expand and + * contract as necessary. */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + tid = H5Tcopy(H5T_STD_I32LE); + CHECK(tid, FAIL, "H5Tcopy"); + ret = H5Tcommit2(fid, TYPE1_NAME, tid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + + /* + * Create small attribute + */ + sid = H5Screate_simple(1, &dims_s, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + aid = H5Acreate2(tid, ATTR1_NAME, H5T_STD_I8LE, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + + /* Close file */ + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Check attribute */ + tid = H5Topen2(fid, TYPE1_NAME, H5P_DEFAULT); + CHECK(tid, FAIL, "H5Topen2"); + ret = H5Aget_info_by_name(tid, ".", ATTR1_NAME, &ainfo, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aget_info_by_name"); + if (ainfo.data_size != dims_s) + TestErrPrintf("attribute data size different: data_size=%llu, should be %llu\n", + (long long unsigned)ainfo.data_size, (long long unsigned)dims_s); + + /* + * Create another small attribute. Should cause chunk size field to expand by + * 1 byte (1->2). + */ + aid = H5Acreate2(tid, ATTR2_NAME, H5T_STD_I8LE, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + + /* Close file */ + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Check attributes */ + tid = H5Topen2(fid, TYPE1_NAME, H5P_DEFAULT); + CHECK(tid, FAIL, "H5Topen2"); + ret = H5Aget_info_by_name(tid, ".", ATTR1_NAME, &ainfo, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aget_info_by_name"); + if (ainfo.data_size != dims_s) + TestErrPrintf("attribute data size different: data_size=%llu, should be %llu\n", + (long long unsigned)ainfo.data_size, (long long unsigned)dims_s); + ret = H5Aget_info_by_name(tid, ".", ATTR2_NAME, &ainfo, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aget_info_by_name"); + if (ainfo.data_size != dims_s) + TestErrPrintf("attribute data size different: data_size=%llu, should be %llu\n", + (long long unsigned)ainfo.data_size, (long long unsigned)dims_s); + + /* + * Create large attribute. Should cause chunk size field to expand by 2 bytes + * (2->4). + */ + ret = H5Sset_extent_simple(sid, 1, &dims_l, NULL); + CHECK(ret, FAIL, "H5Sset_extent_simple"); + aid = H5Acreate2(tid, ATTR3_NAME, H5T_STD_I8LE, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + + /* Close file */ + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Check attributes */ + tid = H5Topen2(fid, TYPE1_NAME, H5P_DEFAULT); + CHECK(tid, FAIL, "H5Topen2"); + ret = H5Aget_info_by_name(tid, ".", ATTR1_NAME, &ainfo, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aget_info_by_name"); + if (ainfo.data_size != dims_s) + TestErrPrintf("attribute data size different: data_size=%llu, should be %llu\n", + (long long unsigned)ainfo.data_size, (long long unsigned)dims_s); + ret = H5Aget_info_by_name(tid, ".", ATTR2_NAME, &ainfo, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aget_info_by_name"); + if (ainfo.data_size != dims_s) + TestErrPrintf("attribute data size different: data_size=%llu, should be %llu\n", + (long long unsigned)ainfo.data_size, (long long unsigned)dims_s); + ret = H5Aget_info_by_name(tid, ".", ATTR3_NAME, &ainfo, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aget_info_by_name"); + if (ainfo.data_size != dims_l) + TestErrPrintf("attribute data size different: data_size=%llu, should be %llu\n", + (long long unsigned)ainfo.data_size, (long long unsigned)dims_l); + + /* + * Delete last two attributes - should merge into a null message that is too + * large, causing the chunk size field to shrink by 3 bytes (4->1). + */ + ret = H5Sset_extent_simple(sid, 1, &dims_l, NULL); + CHECK(ret, FAIL, "H5Sset_extent_simple"); + ret = H5Adelete(tid, ATTR2_NAME); + CHECK(ret, FAIL, "H5Adelete"); + ret = H5Adelete(tid, ATTR3_NAME); + CHECK(ret, FAIL, "H5Adelete"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Check attribute */ + tid = H5Topen2(fid, TYPE1_NAME, H5P_DEFAULT); + CHECK(tid, FAIL, "H5Topen2"); + ret = H5Aget_info_by_name(tid, ".", ATTR1_NAME, &ainfo, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aget_info_by_name"); + if (ainfo.data_size != dims_s) + TestErrPrintf("attribute data size different: data_size=%llu, should be %llu\n", + (long long unsigned)ainfo.data_size, (long long unsigned)dims_s); + + /* + * Create large attribute. Should cause chunk size field to expand by 3 bytes + * (1->4). + */ + aid = H5Acreate2(tid, ATTR2_NAME, H5T_STD_I8LE, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + + /* Close file */ + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Check attributes */ + tid = H5Topen2(fid, TYPE1_NAME, H5P_DEFAULT); + CHECK(tid, FAIL, "H5Topen2"); + ret = H5Aget_info_by_name(tid, ".", ATTR1_NAME, &ainfo, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aget_info_by_name"); + if (ainfo.data_size != dims_s) + TestErrPrintf("attribute data size different: data_size=%llu, should be %llu\n", + (long long unsigned)ainfo.data_size, (long long unsigned)dims_s); + ret = H5Aget_info_by_name(tid, ".", ATTR2_NAME, &ainfo, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aget_info_by_name"); + if (ainfo.data_size != dims_l) + TestErrPrintf("attribute data size different: data_size=%llu, should be %llu\n", + (long long unsigned)ainfo.data_size, (long long unsigned)dims_l); + + /* Close IDs */ + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_attr_bug7() */ +#endif + +/**************************************************************** +** +** test_attr_bug8(): Test basic H5A (attribute) code. +** (Really tests object header code). +** Tests adding a link and attribute to a group in such a +** way as to cause the "chunk #0 size" field to expand +** when some object header messages are not loaded into +** cache. Before the bug was fixed, this would prevent +** these messages from being shifted to the correct +** position as the expansion algorithm marked them dirty, +** invalidating the raw form, when there was no native +** form to encode. +** +****************************************************************/ +static void +test_attr_bug8(hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* File ID */ + hid_t aid; /* Attribute ID */ + hid_t sid; /* Dataspace ID */ + hid_t gid; /* Group ID */ + hid_t oid; /* Object ID */ + hsize_t dims = 256; /* Attribute dimensions */ + H5O_info2_t oinfo; /* Object info */ + H5A_info_t ainfo; /* Attribute info */ + H5O_token_t root_token; /* Root group token */ + int cmp_value; /* Result from H5Otoken_cmp */ + herr_t ret; /* Generic return status */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing attribute expanding object header with undecoded messages\n")); + + /* Create committed datatype to operate on. Use a committed datatype so that + * there is nothing after the object header and the first chunk can expand and + * contract as necessary. */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + gid = H5Gcreate2(fid, GROUP1_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gcreate2"); + + /* Get root group token */ + ret = H5Oget_info3(fid, &oinfo, H5O_INFO_BASIC); + CHECK(ret, FAIL, "H5Oget_info"); + root_token = oinfo.token; + + /* + * Create link to root group + */ + ret = H5Lcreate_hard(fid, "/", gid, LINK1_NAME, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lcreate_hard"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + /* Open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDONLY, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Check link */ + gid = H5Gopen2(fid, GROUP1_NAME, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gopen2"); + oid = H5Oopen(gid, LINK1_NAME, H5P_DEFAULT); + CHECK(oid, FAIL, "H5Oopen"); + ret = H5Oget_info3(oid, &oinfo, H5O_INFO_BASIC); + CHECK(ret, FAIL, "H5Oget_info"); + ret = H5Otoken_cmp(oid, &oinfo.token, &root_token, &cmp_value); + CHECK(ret, FAIL, "H5Otoken_cmp"); + VERIFY(cmp_value, 0, "H5Otoken_cmp"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Oclose(oid); + CHECK(ret, FAIL, "H5Oclose"); + + /* Open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* + * Create attribute. Should cause chunk size field to expand by 1 byte + * (1->2). + */ + gid = H5Gopen2(fid, GROUP1_NAME, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gopen2"); + sid = H5Screate_simple(1, &dims, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + aid = H5Acreate2(gid, ATTR1_NAME, H5T_STD_I8LE, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + + /* Close file */ + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + /* Open file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDONLY, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Check link and attribute */ + gid = H5Gopen2(fid, GROUP1_NAME, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gopen2"); + oid = H5Oopen(gid, LINK1_NAME, H5P_DEFAULT); + CHECK(oid, FAIL, "H5Oopen"); + ret = H5Oget_info3(oid, &oinfo, H5O_INFO_BASIC); + CHECK(ret, FAIL, "H5Oget_info"); + ret = H5Otoken_cmp(oid, &oinfo.token, &root_token, &cmp_value); + CHECK(ret, FAIL, "H5Otoken_cmp"); + VERIFY(cmp_value, 0, "H5Otoken_cmp"); + ret = H5Aget_info_by_name(gid, ".", ATTR1_NAME, &ainfo, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Aget_info_by_name"); + if (ainfo.data_size != dims) + TestErrPrintf("attribute data size different: data_size=%llu, should be %llu\n", + (long long unsigned)ainfo.data_size, (long long unsigned)dims); + + /* Close IDs */ + ret = H5Oclose(oid); + CHECK(ret, FAIL, "H5Oclose"); + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_attr_bug8() */ + +/**************************************************************** +** +** test_attr_bug9(): Test basic H5A (attribute) code. +** (Really tests object header code). +** Tests adding several large attributes to an object until +** they convert to dense storage. The total size of all +** attributes is larger than 64K, causing the internal +** object header code to, after merging the deleted +** messages in to a NULL message, shrink the object header +** chunk. Do this twice: once with only attributes in the +** object header chunk and once with a (small) soft link in +** the chunk as well. In both cases, the shrunk chunk will +** initially be too small and a new NULL message must be +** created. +** +****************************************************************/ +static void +test_attr_bug9(hid_t fcpl, hid_t fapl) +{ + hid_t fid = -1; /* File ID */ + hid_t gid = -1; /* Group ID */ + hid_t aid = -1; /* Attribute ID */ + hid_t sid = -1; /* Dataspace ID */ + hsize_t dims[1] = {32768}; /* Attribute dimensions */ + int create_link; /* Whether to create a soft link */ + unsigned max_compact; /* Setting from fcpl */ + unsigned min_dense; /* Setting from fcpl */ + char aname[11]; /* Attribute name */ + unsigned i; /* Local index variable */ + herr_t ret; /* Generic return status */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing that attributes can always be added to named datatypes\n")); + + /* Create dataspace */ + sid = H5Screate_simple(1, dims, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Obtain attribute phase change settings */ + ret = H5Pget_attr_phase_change(fcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + + /* Run with and without the soft link */ + for (create_link = 0; create_link < 2; create_link++) { + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create second group */ + gid = H5Gcreate2(fid, "group", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gcreate2"); + + /* Close second group */ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + /* Open root group */ + gid = H5Gopen2(fid, "/", H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gopen2"); + + /* Create enough attributes to cause a change to dense storage */ + for (i = 0; i < max_compact + 1; i++) { + /* Create attribute */ + HDsnprintf(aname, sizeof(aname), "%u", i); + aid = H5Acreate2(gid, aname, H5T_NATIVE_CHAR, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + + /* Close attribute */ + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + + /* Create enough soft links that exactly one goes into chunk 1 if + * requested */ + if (i == 0 && create_link) { + ret = H5Lcreate_soft("b", gid, "a", H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lcreate_soft"); + ret = H5Lcreate_soft("d", gid, "c", H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lcreate_soft"); + ret = H5Lcreate_soft("f", gid, "e", H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lcreate_soft"); + } /* end if */ + } /* end for */ + + /* Close IDs */ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + } /* end for */ + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_attr_bug9() */ + +/**************************************************************** +** +** test_attr_bug10(): Test basic H5A (attribute) code. +** Attempts to trigger a bug which would result in a +** segfault. Create a vlen attribute through a file +** handle, then open the same file through a different +** handle, open the same attribute through the second file +** handle, then close the second file and attribute +** handles, then write to the attribute through the first +** handle. +** +****************************************************************/ +static void +test_attr_bug10(hid_t fcpl, hid_t fapl) +{ + hid_t fid1, fid2; /* File IDs */ + hid_t aid1, aid2; /* Attribute IDs */ + hid_t sid; /* Dataspace ID */ + hid_t tid; /* Datatype ID */ + hsize_t dims[1] = {1}; /* Attribute dimensions */ + const char *wbuf[1] = {"foo"}; /* Write buffer */ + herr_t ret; /* Generic return status */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing that vlen attributes can be written to after a second file handle is closed\n")); + + /* Create dataspace */ + sid = H5Screate_simple(1, dims, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Create VL string datatype */ + tid = H5Tcopy(H5T_C_S1); + CHECK(tid, FAIL, "H5Tcreate"); + ret = H5Tset_size(tid, H5T_VARIABLE); + CHECK(ret, FAIL, "H5Tset_size"); + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create attribute on root group */ + aid1 = H5Acreate2(fid1, "attr", tid, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid1, FAIL, "H5Acreate2"); + + /* Open the same file again */ + fid2 = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid2, FAIL, "H5Fcreate"); + + /* Open the same attribute through the second file handle */ + aid2 = H5Aopen(fid2, "attr", H5P_DEFAULT); + CHECK(aid2, FAIL, "H5Aopen"); + + /* Close the second attribute and file handles */ + ret = H5Aclose(aid2); + CHECK(ret, FAIL, "H5Aclose"); + ret = H5Fclose(fid2); + CHECK(ret, FAIL, "H5Fclose"); + + /* Write to the attribute through the first handle */ + ret = H5Awrite(aid1, tid, wbuf); + + /* Close IDs */ + ret = H5Aclose(aid1); + CHECK(ret, FAIL, "H5Aclose"); + + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_attr_bug10() */ + +/**************************************************************** +** +** test_attr_delete_dense(): +** This is to verify the error as described in HDFFV-9277 +** is fixed when deleting the last "large" attribute that +** is stored densely. +** +****************************************************************/ +#if 0 /* Native VOL connector only supports large attributes with latest format */ +static void +test_attr_delete_last_dense(hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* File ID */ + hid_t gid; /* Group ID */ + hid_t aid; /* Attribute ID */ + hid_t sid; /* Dataspace ID */ + hsize_t dim2[2] = {DIM0, DIM1}; /* Dimension sizes */ + int i, j; /* Local index variables */ + double *data = NULL; /* Pointer to the data buffer */ + herr_t ret; /* Generic return status */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Deleting the last large attribute stored densely\n")); + + /* Create the file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create the group */ + gid = H5Gcreate2(fid, GRPNAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gcreate"); + + /* Create the dataspace */ + sid = H5Screate_simple(RANK, dim2, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Attach the attribute to the group */ + aid = H5Acreate2(gid, ATTRNAME, H5T_IEEE_F64LE, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + + /* Allocate the data buffer */ + data = (double *)HDmalloc((size_t)(DIM0 * DIM1) * sizeof(double)); + CHECK_PTR(data, "HDmalloc"); + + /* Initialize the data */ + for (i = 0; i < DIM0; i++) + for (j = 0; j < DIM1; j++) + *(data + i * DIM1 + j) = i + j; + + /* Write to the attribute */ + ret = H5Awrite(aid, H5T_NATIVE_DOUBLE, data); + CHECK(ret, FAIL, "H5Awrite"); + + /* Closing */ + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open the file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Open the group */ + gid = H5Gopen2(fid, GRPNAME, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gopen"); + + /* Delete the attribute */ + ret = H5Adelete(gid, ATTRNAME); + CHECK(ret, FAIL, "H5Adelete"); + + /* Closing */ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free the data buffer */ + if (data) + HDfree(data); + +} /* test_attr_delete_last_dense() */ +#endif + +/**************************************************************** +** +** test_attr(): Main H5A (attribute) testing routine. +** +****************************************************************/ +void +test_attr(void) +{ + hid_t fapl = (-1), fapl2 = (-1); /* File access property lists */ + hid_t fcpl = (-1), fcpl2 = (-1); /* File creation property lists */ + hid_t dcpl = -1; /* Dataset creation property list */ + unsigned new_format; /* Whether to use the new format or not */ + unsigned use_shared; /* Whether to use shared attributes or not */ + unsigned minimize_dset_oh; /* Whether to use minimized dataset object headers */ + herr_t ret; /* Generic return value */ + + MESSAGE(5, ("Testing Attributes\n")); + + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + + /* fapl2 uses "latest version of the format" for creating objects in the file */ + fapl2 = H5Pcopy(fapl); + CHECK(fapl2, FAIL, "H5Pcopy"); + ret = H5Pset_libver_bounds(fapl2, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST); + CHECK(ret, FAIL, "H5Pset_libver_bounds"); + + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, FAIL, "H5Pcreate"); + + /* files with fcpl2 make all attributes ( > 1 byte) shared + * (i.e. all of them :-) */ + fcpl2 = H5Pcopy(fcpl); + CHECK(fcpl2, FAIL, "H5Pcopy"); + ret = H5Pset_shared_mesg_nindexes(fcpl2, (unsigned)1); + CHECK_I(ret, "H5Pset_shared_mesg_nindexes"); + ret = H5Pset_shared_mesg_index(fcpl2, (unsigned)0, H5O_SHMESG_ATTR_FLAG, (unsigned)1); + CHECK_I(ret, "H5Pset_shared_mesg_index"); + + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, H5I_INVALID_HID, "H5Pcreate"); + + ret = H5Pset_attr_creation_order(dcpl, H5P_CRT_ORDER_TRACKED); + CHECK(ret, FAIL, ""); + + dcpl_g = dcpl; + + for (minimize_dset_oh = 0; minimize_dset_oh <= 1; minimize_dset_oh++) { + if (minimize_dset_oh != 0) + continue; + +#if 0 + if (minimize_dset_oh == 0) { + MESSAGE(7, ("testing with default dataset object headers\n")); + dcpl_g = H5P_DEFAULT; + } + else { + MESSAGE(7, ("testing with minimzied dataset object headers\n")); + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + ret = H5Pset_dset_no_attrs_hint(dcpl, TRUE); + CHECK_I(ret, "H5Pset_dset_no_attrs_hint"); + dcpl_g = dcpl; + } +#endif + + for (new_format = FALSE; new_format <= TRUE; new_format++) { + hid_t my_fapl = fapl; + + if (new_format) + continue; + +#if 0 + /* Set the FAPL for the type of format */ + if (new_format) { + MESSAGE(7, ("testing with new file format\n")); + my_fapl = fapl2; + } + else { + MESSAGE(7, ("testing with old file format\n")); + my_fapl = fapl; + } +#endif + + /* These next two tests use the same file information */ + test_attr_basic_write(my_fapl); /* Test basic H5A writing code */ + test_attr_basic_read(my_fapl); /* Test basic H5A reading code */ + + /* These next two tests use their own file information */ + test_attr_flush(my_fapl); /* Test H5A I/O in the presence of H5Fflush calls */ + test_attr_plist(my_fapl); /* Test attribute property lists */ + + /* These next two tests use the same file information */ + test_attr_compound_write(my_fapl); /* Test complex datatype H5A writing code */ + test_attr_compound_read(my_fapl); /* Test complex datatype H5A reading code */ + + /* These next two tests use the same file information */ + test_attr_scalar_write(my_fapl); /* Test scalar dataspace H5A writing code */ + test_attr_scalar_read(my_fapl); /* Test scalar dataspace H5A reading code */ + + /* These next four tests use the same file information */ + test_attr_mult_write(my_fapl); /* Test H5A writing code for multiple attributes */ + test_attr_mult_read(my_fapl); /* Test H5A reading code for multiple attributes */ + test_attr_iterate(my_fapl); /* Test H5A iterator code */ + test_attr_delete(my_fapl); /* Test H5A code for deleting attributes */ + + /* This next test uses its own file information */ + test_attr_dtype_shared(my_fapl); /* Test using shared dataypes in attributes */ + + /* This next test uses its own file information */ + test_attr_duplicate_ids(my_fapl); + + for (use_shared = FALSE; use_shared <= TRUE; use_shared++) { + hid_t my_fcpl; + + if (new_format == TRUE && use_shared) { + MESSAGE(7, ("testing with shared attributes\n")); + my_fcpl = fcpl2; + } + else { + MESSAGE(7, ("testing without shared attributes\n")); + my_fcpl = fcpl; + } + + test_attr_big(my_fcpl, my_fapl); /* Test storing big attribute */ + test_attr_null_space(my_fcpl, my_fapl); /* Test storing attribute with NULL dataspace */ + test_attr_deprec(fcpl, my_fapl); /* Test deprecated API routines */ + test_attr_many(new_format, my_fcpl, my_fapl); /* Test storing lots of attributes */ + test_attr_info_null_info_pointer(my_fcpl, + my_fapl); /* Test passing a NULL attribute info pointer to + H5Aget_info(_by_name/_by_idx) */ + test_attr_rename_invalid_name( + my_fcpl, + my_fapl); /* Test passing a NULL or empty attribute name to H5Arename(_by_name) */ + test_attr_get_name_invalid_buf( + my_fcpl, my_fapl); /* Test passing NULL buffer to H5Aget_name(_by_idx) */ + + /* New attribute API routine tests */ + test_attr_info_by_idx(new_format, my_fcpl, + my_fapl); /* Test querying attribute info by index */ + test_attr_delete_by_idx(new_format, my_fcpl, my_fapl); /* Test deleting attribute by index */ + test_attr_iterate2(new_format, my_fcpl, + my_fapl); /* Test iterating over attributes by index */ + test_attr_open_by_idx(new_format, my_fcpl, my_fapl); /* Test opening attributes by index */ + test_attr_open_by_name(new_format, my_fcpl, my_fapl); /* Test opening attributes by name */ + test_attr_create_by_name(new_format, my_fcpl, my_fapl); /* Test creating attributes by name */ + + /* Tests that address specific bugs */ + test_attr_bug1(my_fcpl, my_fapl); /* Test odd allocation operations */ + test_attr_bug2(my_fcpl, my_fapl); /* Test many deleted attributes */ + test_attr_bug3(my_fcpl, my_fapl); /* Test "self referential" attributes */ + test_attr_bug4(my_fcpl, my_fapl); /* Test attributes on named datatypes */ + test_attr_bug5(my_fcpl, + my_fapl); /* Test opening/closing attributes through different file handles */ + test_attr_bug6(my_fcpl, my_fapl); /* Test reading empty attribute */ + /* test_attr_bug7 is specific to the "new" object header format, + * and in fact fails if used with the old format due to the + * attributes being larger than 64K */ + test_attr_bug8(my_fcpl, + my_fapl); /* Test attribute expanding object header with undecoded messages */ + test_attr_bug9(my_fcpl, my_fapl); /* Test large attributes converting to dense storage */ + test_attr_bug10(my_fcpl, my_fapl); /* Test writing an attribute after opening and closing + through a different file handle */ + + /* tests specific to the "new format" */ + if (new_format == TRUE) { + /* General attribute tests */ + test_attr_dense_create(my_fcpl, my_fapl); /* Test dense attribute storage creation */ + test_attr_dense_open(my_fcpl, my_fapl); /* Test opening attributes in dense storage */ + test_attr_dense_delete(my_fcpl, my_fapl); /* Test deleting attributes in dense storage */ + test_attr_dense_rename(my_fcpl, my_fapl); /* Test renaming attributes in dense storage */ + test_attr_dense_unlink( + my_fcpl, my_fapl); /* Test unlinking object with attributes in dense storage */ + test_attr_dense_limits(my_fcpl, my_fapl); /* Test dense attribute storage limits */ + test_attr_dense_dup_ids(my_fcpl, + my_fapl); /* Test duplicated IDs for dense attribute storage */ + + /* Attribute creation order tests */ + test_attr_corder_create_basic( + my_fcpl, my_fapl); /* Test creating an object w/attribute creation order info */ + test_attr_corder_create_compact(my_fcpl, + my_fapl); /* Test compact attribute storage on an object + w/attribute creation order info */ + test_attr_corder_create_dense(my_fcpl, + my_fapl); /* Test dense attribute storage on an object + w/attribute creation order info */ + test_attr_corder_create_reopen(my_fcpl, + my_fapl); /* Test creating attributes w/reopening file from + using new format to using old format */ + test_attr_corder_transition(my_fcpl, + my_fapl); /* Test attribute storage transitions on an object + w/attribute creation order info */ + test_attr_corder_delete(my_fcpl, my_fapl); /* Test deleting object using dense storage + w/attribute creation order info */ + + /* More complex tests with exclusively both "new format" and "shared" attributes */ + if (use_shared == TRUE) { + test_attr_shared_write( + my_fcpl, + my_fapl); /* Test writing to shared attributes in compact & dense storage */ + test_attr_shared_rename( + my_fcpl, + my_fapl); /* Test renaming shared attributes in compact & dense storage */ + test_attr_shared_delete( + my_fcpl, + my_fapl); /* Test deleting shared attributes in compact & dense storage */ + test_attr_shared_unlink(my_fcpl, my_fapl); /* Test unlinking object with shared + attributes in compact & dense storage */ + } /* if using shared attributes */ + +#if 0 /* Native VOL connector only supports large attributes with latest format */ + test_attr_delete_last_dense(my_fcpl, my_fapl); + + /* test_attr_bug7 is specific to the "new" object header format, + * and in fact fails if used with the old format due to the + * attributes being larger than 64K */ + test_attr_bug7(my_fcpl, + my_fapl); /* Test creating and deleting large attributes in ohdr chunk 0 */ +#endif + + } /* if using "new format" */ + } /* for unshared/shared attributes */ + } /* for old/new format */ + + if (minimize_dset_oh != 0) { + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + dcpl_g = H5P_DEFAULT; + } + + } /* for default/minimized dataset object headers */ + + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close FCPLs */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(fcpl2); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close FAPLs */ + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(fapl2); + CHECK(ret, FAIL, "H5Pclose"); +} /* test_attr() */ + +/*------------------------------------------------------------------------- + * Function: cleanup_attr + * + * Purpose: Cleanup temporary test files + * + * Return: none + * + * Programmer: Albert Cheng + * July 2, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +void +cleanup_attr(void) +{ + H5Fdelete(FILENAME, H5P_DEFAULT); +} diff --git a/test/API/tchecksum.c b/test/API/tchecksum.c new file mode 100644 index 0000000..a77ffcd --- /dev/null +++ b/test/API/tchecksum.c @@ -0,0 +1,251 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*------------------------------------------------------------------------- + * + * Created: tchecksum.c + * Aug 21 2006 + * Quincey Koziol + * + * Purpose: Test internal checksum routine(s) + * + *------------------------------------------------------------------------- + */ + +/***********/ +/* Headers */ +/***********/ +#include "testhdf5.h" + +/**********/ +/* Macros */ +/**********/ +#define BUF_LEN 3093 /* No particular value */ + +/*******************/ +/* Local variables */ +/*******************/ + +/**************************************************************** +** +** test_chksum_size_one(): Checksum 1 byte buffer +** +****************************************************************/ +static void +test_chksum_size_one(void) +{ + uint8_t buf[1] = {23}; /* Buffer to checksum */ + uint32_t chksum; /* Checksum value */ + + /* Buffer w/real data */ + chksum = H5_checksum_fletcher32(buf, sizeof(buf)); + VERIFY(chksum, 0x17001700, "H5_checksum_fletcher32"); + + chksum = H5_checksum_crc(buf, sizeof(buf)); + VERIFY(chksum, 0xfa2568b7, "H5_checksum_crc"); + + chksum = H5_checksum_lookup3(buf, sizeof(buf), 0); + VERIFY(chksum, 0xa209c931, "H5_checksum_lookup3"); + + /* Buffer w/zero(s) for data */ + HDmemset(buf, 0, sizeof(buf)); + chksum = H5_checksum_fletcher32(buf, sizeof(buf)); + VERIFY(chksum, 0, "H5_checksum_fletcher32"); + + chksum = H5_checksum_crc(buf, sizeof(buf)); + VERIFY(chksum, 0xfa60fb57, "H5_checksum_crc"); + + chksum = H5_checksum_lookup3(buf, sizeof(buf), 0); + VERIFY(chksum, 0x8ba9414b, "H5_checksum_lookup3"); +} /* test_chksum_size_one() */ + +/**************************************************************** +** +** test_chksum_size_two(): Checksum 2 byte buffer +** +****************************************************************/ +static void +test_chksum_size_two(void) +{ + uint8_t buf[2] = {23, 187}; /* Buffer to checksum */ + uint32_t chksum; /* Checksum value */ + + /* Buffer w/real data */ + chksum = H5_checksum_fletcher32(buf, sizeof(buf)); + VERIFY(chksum, 0x17bb17bb, "H5_checksum_fletcher32"); + + chksum = H5_checksum_crc(buf, sizeof(buf)); + VERIFY(chksum, 0xfc856608, "H5_checksum_crc"); + + chksum = H5_checksum_lookup3(buf, sizeof(buf), 0); + VERIFY(chksum, 0x8ba7a6c9, "H5_checksum_lookup3"); + + /* Buffer w/zero(s) for data */ + HDmemset(buf, 0, sizeof(buf)); + chksum = H5_checksum_fletcher32(buf, sizeof(buf)); + VERIFY(chksum, 0, "H5_checksum_fletcher32"); + + chksum = H5_checksum_crc(buf, sizeof(buf)); + VERIFY(chksum, 0xfc7e9b20, "H5_checksum_crc"); + + chksum = H5_checksum_lookup3(buf, sizeof(buf), 0); + VERIFY(chksum, 0x62cd61b3, "H5_checksum_lookup3"); +} /* test_chksum_size_two() */ + +/**************************************************************** +** +** test_chksum_size_three(): Checksum 3 byte buffer +** +****************************************************************/ +static void +test_chksum_size_three(void) +{ + uint8_t buf[3] = {23, 187, 98}; /* Buffer to checksum */ + uint32_t chksum; /* Checksum value */ + + /* Buffer w/real data */ + chksum = H5_checksum_fletcher32(buf, sizeof(buf)); + VERIFY(chksum, 0x917679bb, "H5_checksum_fletcher32"); + + chksum = H5_checksum_crc(buf, sizeof(buf)); + VERIFY(chksum, 0xfebc5d70, "H5_checksum_crc"); + + chksum = H5_checksum_lookup3(buf, sizeof(buf), 0); + VERIFY(chksum, 0xcebdf4f0, "H5_checksum_lookup3"); + + /* Buffer w/zero(s) for data */ + HDmemset(buf, 0, sizeof(buf)); + chksum = H5_checksum_fletcher32(buf, sizeof(buf)); + VERIFY(chksum, 0, "H5_checksum_fletcher32"); + + chksum = H5_checksum_crc(buf, sizeof(buf)); + VERIFY(chksum, 0xf9cc4c7a, "H5_checksum_crc"); + + chksum = H5_checksum_lookup3(buf, sizeof(buf), 0); + VERIFY(chksum, 0x6bd0060f, "H5_checksum_lookup3"); +} /* test_chksum_size_three() */ + +/**************************************************************** +** +** test_chksum_size_four(): Checksum 4 byte buffer +** +****************************************************************/ +static void +test_chksum_size_four(void) +{ + uint8_t buf[4] = {23, 187, 98, 217}; /* Buffer to checksum */ + uint32_t chksum; /* Checksum value */ + + /* Buffer w/real data */ + chksum = H5_checksum_fletcher32(buf, sizeof(buf)); + VERIFY(chksum, 0x924f7a94, "H5_checksum_fletcher32"); + + chksum = H5_checksum_crc(buf, sizeof(buf)); + VERIFY(chksum, 0xff398a46, "H5_checksum_crc"); + + chksum = H5_checksum_lookup3(buf, sizeof(buf), 0); + VERIFY(chksum, 0x2c88bb51, "H5_checksum_lookup3"); + + /* Buffer w/zero(s) for data */ + HDmemset(buf, 0, sizeof(buf)); + chksum = H5_checksum_fletcher32(buf, sizeof(buf)); + VERIFY(chksum, 0, "H5_checksum_fletcher32"); + + chksum = H5_checksum_crc(buf, sizeof(buf)); + VERIFY(chksum, 0xff117081, "H5_checksum_crc"); + + chksum = H5_checksum_lookup3(buf, sizeof(buf), 0); + VERIFY(chksum, 0x049396b8, "H5_checksum_lookup3"); +} /* test_chksum_size_four() */ + +/**************************************************************** +** +** test_chksum_large(): Checksum larger buffer +** +****************************************************************/ +static void +test_chksum_large(void) +{ + uint8_t *large_buf; /* Buffer for checksum calculations */ + uint32_t chksum; /* Checksum value */ + size_t u; /* Local index variable */ + + /* Allocate the buffer */ + large_buf = (uint8_t *)HDmalloc((size_t)BUF_LEN); + CHECK_PTR(large_buf, "HDmalloc"); + + /* Initialize buffer w/known data */ + for (u = 0; u < BUF_LEN; u++) + large_buf[u] = (uint8_t)(u * 3); + + /* Buffer w/real data */ + chksum = H5_checksum_fletcher32(large_buf, (size_t)BUF_LEN); + VERIFY(chksum, 0x85b4e2a, "H5_checksum_fletcher32"); + + chksum = H5_checksum_crc(large_buf, (size_t)BUF_LEN); + VERIFY(chksum, 0xfbd0f7c0, "H5_checksum_crc"); + + chksum = H5_checksum_lookup3(large_buf, (size_t)BUF_LEN, 0); + VERIFY(chksum, 0x1bd2ee7b, "H5_checksum_lookup3"); + + /* Buffer w/zero(s) for data */ + HDmemset(large_buf, 0, (size_t)BUF_LEN); + chksum = H5_checksum_fletcher32(large_buf, (size_t)BUF_LEN); + VERIFY(chksum, 0, "H5_checksum_fletcher32"); + + chksum = H5_checksum_crc(large_buf, (size_t)BUF_LEN); + VERIFY(chksum, 0xfac8b4c4, "H5_checksum_crc"); + + chksum = H5_checksum_lookup3(large_buf, (size_t)BUF_LEN, 0); + VERIFY(chksum, 0x930c7afc, "H5_checksum_lookup3"); + + /* Release memory for buffer */ + HDfree(large_buf); +} /* test_chksum_large() */ + +/**************************************************************** +** +** test_checksum(): Main checksum testing routine. +** +****************************************************************/ +void +test_checksum(void) +{ + /* Output message about test being performed */ + MESSAGE(5, ("Testing checksum algorithms\n")); + + /* Various checks for fletcher32 checksum algorithm */ + test_chksum_size_one(); /* Test buffer w/only 1 byte */ + test_chksum_size_two(); /* Test buffer w/only 2 bytes */ + test_chksum_size_three(); /* Test buffer w/only 3 bytes */ + test_chksum_size_four(); /* Test buffer w/only 4 bytes */ + test_chksum_large(); /* Test buffer w/larger # of bytes */ + +} /* test_checksum() */ + +/*------------------------------------------------------------------------- + * Function: cleanup_checksum + * + * Purpose: Cleanup temporary test files + * + * Return: none + * + * Programmer: Quincey Koziol + * August 21, 2006 + * + *------------------------------------------------------------------------- + */ +void +cleanup_checksum(void) +{ + /* no file to clean */ +} diff --git a/test/API/tconfig.c b/test/API/tconfig.c new file mode 100644 index 0000000..fdab5ef --- /dev/null +++ b/test/API/tconfig.c @@ -0,0 +1,199 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*********************************************************** + * + * Test program: tconfig + * + * Test the definitions in the H5config.h as much as possible + * + *************************************************************/ + +#include "testhdf5.h" + +/* macros definitions */ +/* verify C int type: verify the size of signed and unsigned int type + * with the macro size. + */ +#define vrfy_cint_type(ctype, uctype, ctype_macro) \ + /* check signed type size */ \ + vrfy_macrosize(ctype, ctype_macro, #ctype_macro); \ + /* check unsigned type size */ \ + vrfy_macrosize(uctype, ctype_macro, #ctype_macro); + +/* verify C type sizes: verify the sizeof type with the macro size. */ +#define vrfy_ctype(type, macro) vrfy_macrosize(type, macro, #macro); + +/* verify if the sizeof(type) matches size defined in macro. */ +/* Needs this extra step so that we can print the macro name. */ +#define vrfy_macrosize(type, macro, macroname) \ + if (sizeof(type) != (macro)) \ + TestErrPrintf("Error: sizeof(%s) is %zu but %s is %d\n", #type, sizeof(type), macroname, \ + (int)(macro)); + +/* local routine prototypes */ +void test_config_ctypes(void); +void test_exit_definitions(void); + +/*------------------------------------------------------------------------- + * Function: test_configure + * + * Purpose: Main configure definitions testing routine + * + * Return: none (error is fed back via global variable num_errs) + * + * Programmer: Albert Cheng + * September 25, 2001 + * + *------------------------------------------------------------------------- + */ +void +test_configure(void) +{ + /* Output message about test being performed */ + MESSAGE(5, ("Testing configure definitions\n")); + test_config_ctypes(); + test_exit_definitions(); +} + +/*------------------------------------------------------------------------- + * Function: cleanup_configure + * + * Purpose: Cleanup temporary test files + * + * Return: none + * + * Programmer: Albert Cheng + * September 25, 2001 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +void +cleanup_configure(void) +{ + /* no file to clean */ +} + +/*------------------------------------------------------------------------- + * Function: test_config_ctypes + * + * Purpose: test C language data type sizes + * + * Return: none (error is fed back via global variable num_errs) + * + * Programmer: Albert Cheng + * September 25, 2001 + * + * Modifications: + * Albert Cheng, 2004/10/14 + * Verified both signed and unsigned int types. + * + *------------------------------------------------------------------------- + */ +void +test_config_ctypes(void) +{ + /* standard C89 basic types */ + /* char, signed char, unsigned char are three distinct types. */ + vrfy_ctype(char, H5_SIZEOF_CHAR); + vrfy_cint_type(signed char, unsigned char, H5_SIZEOF_CHAR); + vrfy_cint_type(int, unsigned int, H5_SIZEOF_INT); + vrfy_cint_type(short, unsigned short, H5_SIZEOF_SHORT); + vrfy_cint_type(long, unsigned long, H5_SIZEOF_LONG); + vrfy_ctype(float, H5_SIZEOF_FLOAT); + vrfy_ctype(double, H5_SIZEOF_DOUBLE); + vrfy_ctype(long double, H5_SIZEOF_LONG_DOUBLE); + + /* standard C99 basic types */ + vrfy_cint_type(long long, unsigned long long, H5_SIZEOF_LONG_LONG); + vrfy_cint_type(int8_t, uint8_t, H5_SIZEOF_INT8_T); + vrfy_cint_type(int16_t, uint16_t, H5_SIZEOF_INT16_T); + vrfy_cint_type(int32_t, uint32_t, H5_SIZEOF_INT32_T); + vrfy_cint_type(int64_t, uint64_t, H5_SIZEOF_INT64_T); + + /* Some vendors have different sizes for the signed and unsigned */ + /* fast8_t. Need to check them individually. */ +#if H5_SIZEOF_INT_FAST8_T > 0 + vrfy_ctype(int_fast8_t, H5_SIZEOF_INT_FAST8_T); +#endif + +#if H5_SIZEOF_UINT_FAST8_T > 0 + vrfy_ctype(uint_fast8_t, H5_SIZEOF_UINT_FAST8_T); +#endif + +#if H5_SIZEOF_INT_FAST16_T > 0 + vrfy_cint_type(int_fast16_t, uint_fast16_t, H5_SIZEOF_INT_FAST16_T); +#endif + +#if H5_SIZEOF_INT_FAST32_T > 0 + vrfy_cint_type(int_fast32_t, uint_fast32_t, H5_SIZEOF_INT_FAST32_T); +#endif + +#if H5_SIZEOF_INT_FAST64_T > 0 + vrfy_cint_type(int_fast64_t, uint_fast64_t, H5_SIZEOF_INT_FAST64_T); +#endif + +#if H5_SIZEOF_INT_LEAST8_T > 0 + vrfy_cint_type(int_least8_t, uint_least8_t, H5_SIZEOF_INT_LEAST8_T); +#endif + +#if H5_SIZEOF_INT_LEAST16_T > 0 + vrfy_cint_type(int_least16_t, uint_least16_t, H5_SIZEOF_INT_LEAST16_T); +#endif + +#if H5_SIZEOF_INT_LEAST32_T > 0 + vrfy_cint_type(int_least32_t, uint_least32_t, H5_SIZEOF_INT_LEAST32_T); +#endif + +#if H5_SIZEOF_INT_LEAST64_T > 0 + vrfy_cint_type(int_least64_t, uint_least64_t, H5_SIZEOF_INT_LEAST64_T); +#endif + +#if H5_SIZEOF_OFF_T > 0 + vrfy_ctype(off_t, H5_SIZEOF_OFF_T); +#endif + +#if H5_SIZEOF_SIZE_T > 0 + vrfy_ctype(size_t, H5_SIZEOF_SIZE_T); +#endif + +#if H5_SIZEOF_SSIZE_T > 0 + vrfy_ctype(ssize_t, H5_SIZEOF_SSIZE_T); +#endif +} + +/*------------------------------------------------------------------------- + * Function: test_exit_definitions + * + * Purpose: test the exit macros values + * + * Return: none (error is fed back via global variable num_errs) + * + * Programmer: Albert Cheng + * October 12, 2009 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +void +test_exit_definitions(void) +{ + /* Verify the EXIT_SUCCESS and EXIT_FAILURE are 0 and 1 respectively. */ + /* This should be true for POSIX compliant systems. */ + if (EXIT_SUCCESS != 0) + TestErrPrintf("Error: EXIT_SUCCESS is %d, should be %d\n", EXIT_SUCCESS, 0); + if (EXIT_FAILURE != 1) + TestErrPrintf("Error: EXIT_FAILURE is %d, should be %d\n", EXIT_FAILURE, 1); +} diff --git a/test/API/tcoords.c b/test/API/tcoords.c new file mode 100644 index 0000000..9c66b40 --- /dev/null +++ b/test/API/tcoords.c @@ -0,0 +1,724 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*********************************************************** + * + * Test program: tcoords + * + * Test the element coordinates for dataspace selection. For + * chunked dataset, when the hyperslab selection of some + * dimensions is full, the library optimize it by "flattening" + * the fully selected dimensions. This program tests if the + * coordinates of selected elements are correctly calculated. + * + *************************************************************/ + +#include "testhdf5.h" + +#define FILENAME "coord.h5" + +#define SINGLE_END_DSET "single_end_dset" +#define MULTI_ENDS_SEL_HYPER_DSET "multiple_ends_dset" + +#define NAME_LEN 128 + +/* Data written to the dataset for single block test. Global variable + * for convenience. */ +int da_buffer[2][3][6][2]; + +/*********************************************************** +** +** test_singleEnd_selElements(): Test element selection of only +** one block. +** +*************************************************************/ +static void +test_singleEnd_selElements(hid_t file, hbool_t is_chunked) +{ + hid_t sid, plid, did, msid; + char dset_name[NAME_LEN]; /* Dataset name */ + size_t elmts_numb; + herr_t ret; /* Generic error return */ + int i, j, k; + hsize_t da_dims[4] = {2, 3, 6, 2}; + hsize_t da_chunksize[4] = {1, 3, 3, 2}; + + /* For testing the full selection in the fastest-growing end */ + int mem1_buffer[1][1][6][2]; + hsize_t mem1_dims[4] = {1, 1, 6, 2}; + hsize_t da_elmts1[12][4] = {{0, 0, 0, 0}, {0, 0, 0, 1}, {0, 0, 1, 0}, {0, 0, 1, 1}, + {0, 0, 2, 0}, {0, 0, 2, 1}, {0, 0, 3, 0}, {0, 0, 3, 1}, + {0, 0, 4, 0}, {0, 0, 4, 1}, {0, 0, 5, 0}, {0, 0, 5, 1}}; + + /* For testing the full selection in the slowest-growing end */ + int mem2_buffer[2][3][1][1]; + hsize_t mem2_dims[4] = {2, 3, 1, 1}; + hsize_t da_elmts2[6][4] = {{0, 0, 0, 0}, {0, 1, 0, 0}, {0, 2, 0, 0}, + {1, 0, 0, 0}, {1, 1, 0, 0}, {1, 2, 0, 0}}; + + /* For testing the full selection in the middle dimensions */ + int mem3_buffer[1][3][6][1]; + hsize_t mem3_dims[4] = {1, 3, 6, 1}; + hsize_t da_elmts3[18][4] = {{0, 0, 0, 0}, {0, 0, 1, 0}, {0, 0, 2, 0}, {0, 0, 3, 0}, {0, 0, 4, 0}, + {0, 0, 5, 0}, {0, 1, 0, 0}, {0, 1, 1, 0}, {0, 1, 2, 0}, {0, 1, 3, 0}, + {0, 1, 4, 0}, {0, 1, 5, 0}, {0, 2, 0, 0}, {0, 2, 1, 0}, {0, 2, 2, 0}, + {0, 2, 3, 0}, {0, 2, 4, 0}, {0, 2, 5, 0}}; + + /* Create and write the dataset */ + sid = H5Screate_simple(4, da_dims, da_dims); + CHECK(sid, FAIL, "H5Screate_simple"); + + plid = H5Pcreate(H5P_DATASET_CREATE); + CHECK(plid, FAIL, "H5Pcreate"); + + if (is_chunked) { + ret = H5Pset_chunk(plid, 4, da_chunksize); + CHECK(ret, FAIL, "H5Pset_chunk"); + } + + /* Construct dataset's name */ + HDmemset(dset_name, 0, (size_t)NAME_LEN); + HDstrcat(dset_name, SINGLE_END_DSET); + if (is_chunked) + HDstrcat(dset_name, "_chunked"); + + did = H5Dcreate2(file, dset_name, H5T_NATIVE_INT, sid, H5P_DEFAULT, plid, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); + + /* Initialize the data to be written to file */ + for (i = 0; i < 2; i++) { + for (j = 0; j < 3; j++) { + for (k = 0; k < 6; k++) { + da_buffer[i][j][k][0] = i * 100 + j * 10 + k; + da_buffer[i][j][k][1] = i * 100 + j * 10 + k + 1; + } + } + } + + ret = H5Dwrite(did, H5T_NATIVE_INT, sid, sid, H5P_DEFAULT, da_buffer); + CHECK(ret, FAIL, "H5Dwrite"); + + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* ****** Case 1: ****** + * Testing the full selection in the fastest-growing end */ + did = H5Dopen2(file, dset_name, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen2"); + + /* Select the elements in the dataset */ + elmts_numb = 12; + + ret = H5Sselect_elements(sid, H5S_SELECT_SET, elmts_numb, (const hsize_t *)da_elmts1); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Dataspace for memory buffer */ + msid = H5Screate_simple(4, mem1_dims, mem1_dims); + CHECK(msid, FAIL, "H5Screate_simple"); + + ret = H5Sselect_all(msid); + CHECK(ret, FAIL, "H5Sselect_all"); + + ret = H5Dread(did, H5T_NATIVE_INT, msid, sid, H5P_DEFAULT, mem1_buffer); + CHECK(ret, FAIL, "H5Dread"); + + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Sclose(msid); + CHECK(ret, FAIL, "H5Sclose"); + + for (i = 0; i < 6; i++) + for (j = 0; j < 2; j++) + if (da_buffer[0][0][i][j] != mem1_buffer[0][0][i][j]) { + TestErrPrintf("%u: Read different values than written at index 0,0,%d,%d\n", __LINE__, i, j); + } + + /* ****** Case 2: ****** + * Testing the full selection in the slowest-growing end */ + did = H5Dopen2(file, dset_name, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen2"); + + /* Select the elements in the dataset */ + elmts_numb = 6; + + ret = H5Sselect_elements(sid, H5S_SELECT_SET, elmts_numb, (const hsize_t *)da_elmts2); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Dataspace for memory buffer */ + msid = H5Screate_simple(4, mem2_dims, mem2_dims); + CHECK(msid, FAIL, "H5Screate_simple"); + + ret = H5Sselect_all(msid); + CHECK(ret, FAIL, "H5Sselect_all"); + + ret = H5Dread(did, H5T_NATIVE_INT, msid, sid, H5P_DEFAULT, mem2_buffer); + CHECK(ret, FAIL, "H5Dread"); + + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Sclose(msid); + CHECK(ret, FAIL, "H5Sclose"); + + for (i = 0; i < 2; i++) + for (j = 0; j < 3; j++) + if (da_buffer[i][j][0][0] != mem2_buffer[i][j][0][0]) { + TestErrPrintf("%u: Read different values than written at index %d,%d,0,0, da_buffer = %d, " + "mem2_buffer = %d\n", + __LINE__, i, j, da_buffer[i][j][0][0], mem2_buffer[i][j][0][0]); + } + + /* ****** Case 3: ****** + * Testing the full selection in the middle dimensions */ + did = H5Dopen2(file, dset_name, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen2"); + + /* Select the elements in the dataset */ + elmts_numb = 18; + + ret = H5Sselect_elements(sid, H5S_SELECT_SET, elmts_numb, (const hsize_t *)da_elmts3); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Dataspace for memory buffer */ + msid = H5Screate_simple(4, mem3_dims, mem3_dims); + CHECK(msid, FAIL, "H5Screate_simple"); + + ret = H5Sselect_all(msid); + CHECK(ret, FAIL, "H5Sselect_all"); + + ret = H5Dread(did, H5T_NATIVE_INT, msid, sid, H5P_DEFAULT, mem3_buffer); + CHECK(ret, FAIL, "H5Dread"); + + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Sclose(msid); + CHECK(ret, FAIL, "H5Sclose"); + + for (i = 0; i < 3; i++) + for (j = 0; j < 6; j++) + if (da_buffer[0][i][j][0] != mem3_buffer[0][i][j][0]) { + TestErrPrintf("%u: Read different values than written at index 0,%d,%d,0\n", __LINE__, i, j); + } + + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Pclose(plid); + CHECK(ret, FAIL, "H5Pclose"); +} + +/*********************************************************** +** +** test_singleEnd_selHyperslab(): Test full hyperslab selection +** of only one block. +** +*************************************************************/ +static void +test_singleEnd_selHyperslab(hid_t file, hbool_t is_chunked) +{ + hid_t sid, did, msid; + char dset_name[NAME_LEN]; /* Dataset name */ + herr_t ret; /* Generic error return */ + int i, j; + hsize_t da_dims[4] = {2, 3, 6, 2}; + + /* For testing the full selection in the fastest-growing end */ + int mem1_buffer[1][1][6][2]; + hsize_t mem1_dims[4] = {1, 1, 6, 2}; + hsize_t mem1_start[4] = {0, 0, 0, 0}; + hsize_t mem1_count[4] = {1, 1, 1, 1}; + hsize_t mem1_stride[4] = {1, 1, 1, 1}; + hsize_t mem1_block[4] = {1, 1, 6, 2}; + + /* For testing the full selection in the slowest-growing end */ + int mem2_buffer[2][3][1][1]; + hsize_t mem2_dims[4] = {2, 3, 1, 1}; + hsize_t mem2_start[4] = {0, 0, 0, 0}; + hsize_t mem2_count[4] = {1, 1, 1, 1}; + hsize_t mem2_stride[4] = {1, 1, 1, 1}; + hsize_t mem2_block[4] = {2, 3, 1, 1}; + + /* For testing the full selection in the middle dimensions */ + int mem3_buffer[1][3][6][1]; + hsize_t mem3_dims[4] = {1, 3, 6, 1}; + hsize_t mem3_start[4] = {0, 0, 0, 0}; + hsize_t mem3_count[4] = {1, 1, 1, 1}; + hsize_t mem3_stride[4] = {1, 1, 1, 1}; + hsize_t mem3_block[4] = {1, 3, 6, 1}; + + /* Construct dataset's name */ + HDmemset(dset_name, 0, NAME_LEN); + HDstrcat(dset_name, SINGLE_END_DSET); + if (is_chunked) + HDstrcat(dset_name, "_chunked"); + + /* Dataspace for the dataset in file */ + sid = H5Screate_simple(4, da_dims, da_dims); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* ****** Case 1: ****** + * Testing the full selection in the fastest-growing end */ + did = H5Dopen2(file, dset_name, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen2"); + + /* Select the elements in the dataset */ + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, mem1_start, mem1_stride, mem1_count, mem1_block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Dataspace for memory buffer */ + msid = H5Screate_simple(4, mem1_dims, mem1_dims); + CHECK(msid, FAIL, "H5Screate_simple"); + + ret = H5Sselect_all(msid); + CHECK(ret, FAIL, "H5Sselect_all"); + + ret = H5Dread(did, H5T_NATIVE_INT, msid, sid, H5P_DEFAULT, mem1_buffer); + CHECK(ret, FAIL, "H5Dread"); + + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Sclose(msid); + CHECK(ret, FAIL, "H5Sclose"); + + for (i = 0; i < 6; i++) + for (j = 0; j < 2; j++) + if (da_buffer[0][0][i][j] != mem1_buffer[0][0][i][j]) { + TestErrPrintf("%u: Read different values than written at index 0,0,%d,%d\n", __LINE__, i, j); + } + + /* ****** Case 2: ****** + * Testing the full selection in the slowest-growing end */ + did = H5Dopen2(file, dset_name, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen2"); + + /* Select the elements in the dataset */ + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, mem2_start, mem2_stride, mem2_count, mem2_block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Dataspace for memory buffer */ + msid = H5Screate_simple(4, mem2_dims, mem2_dims); + CHECK(msid, FAIL, "H5Screate_simple"); + + ret = H5Sselect_all(msid); + CHECK(ret, FAIL, "H5Sselect_all"); + + ret = H5Dread(did, H5T_NATIVE_INT, msid, sid, H5P_DEFAULT, mem2_buffer); + CHECK(ret, FAIL, "H5Dread"); + + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Sclose(msid); + CHECK(ret, FAIL, "H5Sclose"); + + for (i = 0; i < 2; i++) + for (j = 0; j < 3; j++) + if (da_buffer[i][j][0][0] != mem2_buffer[i][j][0][0]) { + TestErrPrintf("%u: Read different values than written at index %d,%d,0,0\n", __LINE__, i, j); + } + + /* ****** Case 3: ****** + * Testing the full selection in the middle dimensions */ + did = H5Dopen2(file, dset_name, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen2"); + + /* Select the elements in the dataset */ + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, mem3_start, mem3_stride, mem3_count, mem3_block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Dataspace for memory buffer */ + msid = H5Screate_simple(4, mem3_dims, mem3_dims); + CHECK(msid, FAIL, "H5Screate_simple"); + + ret = H5Sselect_all(msid); + CHECK(ret, FAIL, "H5Sselect_all"); + + ret = H5Dread(did, H5T_NATIVE_INT, msid, sid, H5P_DEFAULT, mem3_buffer); + CHECK(ret, FAIL, "H5Dread"); + + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Sclose(msid); + CHECK(ret, FAIL, "H5Sclose"); + + for (i = 0; i < 3; i++) + for (j = 0; j < 6; j++) + if (da_buffer[0][i][j][0] != mem3_buffer[0][i][j][0]) { + TestErrPrintf("%u: Read different values than written at index 0,%d,%d,0\n", __LINE__, i, j); + } + + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); +} + +/*********************************************************** +** +** test_multiple_end(): Test full hyperslab selection of +** multiple blocks. +** +*************************************************************/ +static void +test_multiple_ends(hid_t file, hbool_t is_chunked) +{ + hid_t sid, plid, did, msid; + char dset_name[NAME_LEN]; /* Dataset name */ + herr_t ret; /* Generic error return */ + int i, j, k, l, m, n, p; + hsize_t da_dims[8] = {4, 5, 3, 4, 2, 3, 6, 2}; + hsize_t da_chunksize[8] = {1, 5, 3, 2, 2, 3, 3, 2}; + struct { + int arr[4][5][3][4][2][3][6][2]; + } *data_buf = NULL; + + /* For testing the full selections in the fastest-growing end and in the middle dimensions */ + struct { + int arr[1][1][1][4][2][1][6][2]; + } *mem1_buffer = NULL; + hsize_t mem1_dims[8] = {1, 1, 1, 4, 2, 1, 6, 2}; + hsize_t mem1_start[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + hsize_t mem1_count[8] = {1, 1, 1, 1, 1, 1, 1, 1}; + hsize_t mem1_stride[8] = {1, 1, 1, 1, 1, 1, 1, 1}; + hsize_t mem1_block[8] = {1, 1, 1, 4, 2, 1, 6, 2}; + + /* For testing the full selections in the slowest-growing end and in the middle dimensions */ + struct { + int arr[4][5][1][4][2][1][1][1]; + } *mem2_buffer = NULL; + hsize_t mem2_dims[8] = {4, 5, 1, 4, 2, 1, 1, 1}; + hsize_t mem2_start[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + hsize_t mem2_count[8] = {1, 1, 1, 1, 1, 1, 1, 1}; + hsize_t mem2_stride[8] = {1, 1, 1, 1, 1, 1, 1, 1}; + hsize_t mem2_block[8] = {4, 5, 1, 4, 2, 1, 1, 1}; + + /* For testing two unadjacent full selections in the middle dimensions */ + struct { + int arr[1][5][3][1][1][3][6][1]; + } *mem3_buffer = NULL; + hsize_t mem3_dims[8] = {1, 5, 3, 1, 1, 3, 6, 1}; + hsize_t mem3_start[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + hsize_t mem3_count[8] = {1, 1, 1, 1, 1, 1, 1, 1}; + hsize_t mem3_stride[8] = {1, 1, 1, 1, 1, 1, 1, 1}; + hsize_t mem3_block[8] = {1, 5, 3, 1, 1, 3, 6, 1}; + + /* For testing the full selections in the fastest-growing end and the slowest-growing end */ + struct { + int arr[4][5][1][1][1][1][6][2]; + } *mem4_buffer = NULL; + hsize_t mem4_dims[8] = {4, 5, 1, 1, 1, 1, 6, 2}; + hsize_t mem4_start[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + hsize_t mem4_count[8] = {1, 1, 1, 1, 1, 1, 1, 1}; + hsize_t mem4_stride[8] = {1, 1, 1, 1, 1, 1, 1, 1}; + hsize_t mem4_block[8] = {4, 5, 1, 1, 1, 1, 6, 2}; + + /* For testing the full selections in the fastest-growing end and slowest-growing end, + * also in the middle dimensions */ + struct { + int arr[4][5][1][4][2][1][6][2]; + } *mem5_buffer = NULL; + hsize_t mem5_dims[8] = {4, 5, 1, 4, 2, 1, 6, 2}; + hsize_t mem5_start[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + hsize_t mem5_count[8] = {1, 1, 1, 1, 1, 1, 1, 1}; + hsize_t mem5_stride[8] = {1, 1, 1, 1, 1, 1, 1, 1}; + hsize_t mem5_block[8] = {4, 5, 1, 4, 2, 1, 6, 2}; + + /* Initialize dynamic arrays */ + data_buf = HDcalloc(1, sizeof(*data_buf)); + CHECK_PTR(data_buf, "HDcalloc"); + mem1_buffer = HDcalloc(1, sizeof(*mem1_buffer)); + CHECK_PTR(data_buf, "HDcalloc"); + mem2_buffer = HDcalloc(1, sizeof(*mem2_buffer)); + CHECK_PTR(data_buf, "HDcalloc"); + mem3_buffer = HDcalloc(1, sizeof(*mem3_buffer)); + CHECK_PTR(data_buf, "HDcalloc"); + mem4_buffer = HDcalloc(1, sizeof(*mem4_buffer)); + CHECK_PTR(data_buf, "HDcalloc"); + mem5_buffer = HDcalloc(1, sizeof(*mem5_buffer)); + CHECK_PTR(data_buf, "HDcalloc"); + + /* Create and write the dataset */ + sid = H5Screate_simple(8, da_dims, da_dims); + CHECK(sid, FAIL, "H5Screate_simple"); + + plid = H5Pcreate(H5P_DATASET_CREATE); + CHECK(plid, FAIL, "H5Pcreate"); + + if (is_chunked) { + ret = H5Pset_chunk(plid, 8, da_chunksize); + CHECK(ret, FAIL, "H5Pset_chunk"); + } + + /* Construct dataset's name */ + HDmemset(dset_name, 0, NAME_LEN); + HDstrcat(dset_name, MULTI_ENDS_SEL_HYPER_DSET); + if (is_chunked) + HDstrcat(dset_name, "_chunked"); + + did = H5Dcreate2(file, dset_name, H5T_NATIVE_INT, sid, H5P_DEFAULT, plid, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); + + for (i = 0; i < 4; i++) + for (j = 0; j < 5; j++) + for (k = 0; k < 3; k++) + for (l = 0; l < 4; l++) + for (m = 0; m < 2; m++) + for (n = 0; n < 3; n++) + for (p = 0; p < 6; p++) { + data_buf->arr[i][j][k][l][m][n][p][0] = + i * 1000000 + j * 100000 + k * 10000 + l * 1000 + m * 100 + n * 10 + p; + data_buf->arr[i][j][k][l][m][n][p][1] = i * 1000000 + j * 100000 + k * 10000 + + l * 1000 + m * 100 + n * 10 + p + 1; + } + + ret = H5Dwrite(did, H5T_NATIVE_INT, sid, sid, H5P_DEFAULT, data_buf); + CHECK(ret, FAIL, "H5Dwrite"); + + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* ****** Case 1: ****** + * Testing the full selections in the fastest-growing end and in the middle dimensions*/ + did = H5Dopen2(file, dset_name, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen2"); + + /* Select the elements in the dataset */ + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, mem1_start, mem1_stride, mem1_count, mem1_block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + msid = H5Screate_simple(8, mem1_dims, mem1_dims); + CHECK(msid, FAIL, "H5Screate_simple"); + + ret = H5Sselect_all(msid); + CHECK(ret, FAIL, "H5Sselect_all"); + + ret = H5Dread(did, H5T_NATIVE_INT, msid, sid, H5P_DEFAULT, mem1_buffer); + CHECK(ret, FAIL, "H5Dread"); + + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Sclose(msid); + CHECK(ret, FAIL, "H5Sclose"); + + for (i = 0; i < 4; i++) + for (j = 0; j < 2; j++) + for (k = 0; k < 6; k++) + for (l = 0; l < 2; l++) + if (data_buf->arr[0][0][0][i][j][0][k][l] != mem1_buffer->arr[0][0][0][i][j][0][k][l]) { + TestErrPrintf("%u: Read different values than written at index 0,0,0,%d,%d,0,%d,%d\n", + __LINE__, i, j, k, l); + } + + /* ****** Case 2: ****** + * Testing the full selections in the slowest-growing end and in the middle dimensions*/ + did = H5Dopen2(file, dset_name, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen2"); + + /* Select the elements in the dataset */ + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, mem2_start, mem2_stride, mem2_count, mem2_block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + msid = H5Screate_simple(8, mem2_dims, mem2_dims); + CHECK(msid, FAIL, "H5Screate_simple"); + + ret = H5Sselect_all(msid); + CHECK(ret, FAIL, "H5Sselect_all"); + + ret = H5Dread(did, H5T_NATIVE_INT, msid, sid, H5P_DEFAULT, mem2_buffer); + CHECK(ret, FAIL, "H5Dread"); + + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Sclose(msid); + CHECK(ret, FAIL, "H5Sclose"); + + for (i = 0; i < 4; i++) + for (j = 0; j < 5; j++) + for (k = 0; k < 4; k++) + for (l = 0; l < 2; l++) + if (data_buf->arr[i][j][0][k][l][0][0][0] != mem2_buffer->arr[i][j][0][k][l][0][0][0]) { + TestErrPrintf("%u: Read different values than written at index %d,%d,0,%d,%d,0,0,0\n", + __LINE__, i, j, k, l); + } + + /* ****** Case 3: ****** + * Testing two unadjacent full selections in the middle dimensions */ + did = H5Dopen2(file, dset_name, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen2"); + + /* Select the elements in the dataset */ + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, mem3_start, mem3_stride, mem3_count, mem3_block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + msid = H5Screate_simple(8, mem3_dims, mem3_dims); + CHECK(msid, FAIL, "H5Screate_simple"); + + ret = H5Sselect_all(msid); + CHECK(ret, FAIL, "H5Sselect_all"); + + ret = H5Dread(did, H5T_NATIVE_INT, msid, sid, H5P_DEFAULT, mem3_buffer); + CHECK(ret, FAIL, "H5Dread"); + + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Sclose(msid); + CHECK(ret, FAIL, "H5Sclose"); + + for (i = 0; i < 5; i++) + for (j = 0; j < 3; j++) + for (k = 0; k < 3; k++) + for (l = 0; l < 6; l++) + if (data_buf->arr[0][i][j][0][0][k][l][0] != mem3_buffer->arr[0][i][j][0][0][k][l][0]) { + TestErrPrintf("%u: Read different values than written at index 0,%d,%d,0,0,%d,%d,0\n", + __LINE__, i, j, k, l); + } + + /* ****** Case 4: ****** + * Testing the full selections in the fastest-growing end and the slowest-growing end */ + did = H5Dopen2(file, dset_name, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen2"); + + /* Select the elements in the dataset */ + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, mem4_start, mem4_stride, mem4_count, mem4_block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + msid = H5Screate_simple(8, mem4_dims, mem4_dims); + CHECK(msid, FAIL, "H5Screate_simple"); + + ret = H5Sselect_all(msid); + CHECK(ret, FAIL, "H5Sselect_all"); + + ret = H5Dread(did, H5T_NATIVE_INT, msid, sid, H5P_DEFAULT, mem4_buffer); + CHECK(ret, FAIL, "H5Dread"); + + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Sclose(msid); + CHECK(ret, FAIL, "H5Sclose"); + + for (i = 0; i < 4; i++) + for (j = 0; j < 5; j++) + for (k = 0; k < 6; k++) + for (l = 0; l < 2; l++) + if (data_buf->arr[i][j][0][0][0][0][k][l] != mem4_buffer->arr[i][j][0][0][0][0][k][l]) { + TestErrPrintf("%u: Read different values than written at index %d,%d,0,0,0,0,%d,%d\n", + __LINE__, i, j, k, l); + } + + /* ****** Case 5: ****** + * Testing the full selections in the fastest-growing end and the slowest-growing end, + * and also in the middle dimensions */ + did = H5Dopen2(file, dset_name, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen2"); + + /* Select the elements in the dataset */ + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, mem5_start, mem5_stride, mem5_count, mem5_block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + msid = H5Screate_simple(8, mem5_dims, mem5_dims); + CHECK(msid, FAIL, "H5Screate_simple"); + + ret = H5Sselect_all(msid); + CHECK(ret, FAIL, "H5Sselect_all"); + + ret = H5Dread(did, H5T_NATIVE_INT, msid, sid, H5P_DEFAULT, mem5_buffer); + CHECK(ret, FAIL, "H5Dread"); + + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Sclose(msid); + CHECK(ret, FAIL, "H5Sclose"); + + for (i = 0; i < 4; i++) + for (j = 0; j < 5; j++) + for (k = 0; k < 4; k++) + for (l = 0; l < 2; l++) + for (m = 0; m < 6; m++) + for (n = 0; n < 2; n++) + if (data_buf->arr[i][j][0][k][l][0][m][n] != + mem5_buffer->arr[i][j][0][k][l][0][m][n]) { + TestErrPrintf( + "%u: Read different values than written at index %d,%d,0,%d,%d,0,%d,%d\n", + __LINE__, i, j, k, l, m, n); + } + + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Pclose(plid); + CHECK(ret, FAIL, "H5Pclose"); + + HDfree(data_buf); + HDfree(mem1_buffer); + HDfree(mem2_buffer); + HDfree(mem3_buffer); + HDfree(mem4_buffer); + HDfree(mem5_buffer); +} + +/**************************************************************** +** +** test_coords(): Main testing routine. +** +****************************************************************/ +void +test_coords(void) +{ + hid_t fid; + hbool_t is_chunk[2] = {TRUE, FALSE}; + int i; + herr_t ret; /* Generic error return */ + + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + for (i = 0; i < 2; i++) { + /* Test H5Sselect_elements with selection of one block of data */ + test_singleEnd_selElements(fid, is_chunk[i]); + + /* Test H5Sselect_hyperslab with selection of one block of data */ + test_singleEnd_selHyperslab(fid, is_chunk[i]); + + /* Test H5Sselect_hyperslab with selection of multiple blocks of data */ + test_multiple_ends(fid, is_chunk[i]); + } + + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +} + +/*------------------------------------------------------------------------- + * Function: cleanup_coords + * + * Purpose: Cleanup temporary test files + * + * Return: none + * + * Programmer: Raymond Lu + * 20 Dec. 2007 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +void +cleanup_coords(void) +{ + H5Fdelete(FILENAME, H5P_DEFAULT); +} diff --git a/test/API/testhdf5.c b/test/API/testhdf5.c new file mode 100644 index 0000000..f29b603 --- /dev/null +++ b/test/API/testhdf5.c @@ -0,0 +1,729 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + FILE + testhdf5.c - HDF5 testing framework main file. + + REMARKS + General test wrapper for HDF5 base library test programs + + DESIGN + Each test function should be implemented as function having no + parameters and returning void (i.e. no return value). They should be put + into the list of AddTest() calls in main() below. Functions which depend + on other functionality should be placed below the AddTest() call for the + base functionality testing. + Each test module should include testhdf5.h and define a unique set of + names for test files they create. + + BUGS/LIMITATIONS + + + */ + +/* ANY new test needs to have a prototype in testhdf5.h */ +#include "testhdf5.h" + +int nerrors = 0; + +char *paraprefix = NULL; /* for command line option para-prefix */ + +/* Length of multi-file VFD filename buffers */ +#define H5TEST_MULTI_FILENAME_LEN 1024 + +/* + * This routine is designed to provide equivalent functionality to 'printf' + * and allow easy replacement for environments which don't have stdin/stdout + * available. (i.e. Windows & the Mac) + */ +H5_ATTR_FORMAT(printf, 1, 2) +int +print_func(const char *format, ...) +{ + va_list arglist; + int ret_value; + + HDva_start(arglist, format); + ret_value = HDvprintf(format, arglist); + HDva_end(arglist); + return ret_value; +} + +/* + * This routine is designed to provide equivalent functionality to 'printf' + * and also increment the error count for the testing framework. + */ +int +TestErrPrintf(const char *format, ...) +{ + va_list arglist; + int ret_value; + + /* Increment the error count */ + nerrors++; + + /* Print the requested information */ + HDva_start(arglist, format); + ret_value = HDvprintf(format, arglist); + HDva_end(arglist); + + /* Return the length of the string produced (like printf() does) */ + return ret_value; +} + +#ifdef H5_HAVE_PARALLEL +/*------------------------------------------------------------------------- + * Function: getenv_all + * + * Purpose: Used to get the environment that the root MPI task has. + * name specifies which environment variable to look for + * val is the string to which the value of that environment + * variable will be copied. + * + * NOTE: The pointer returned by this function is only + * valid until the next call to getenv_all and the data + * stored there must be copied somewhere else before any + * further calls to getenv_all take place. + * + * Return: pointer to a string containing the value of the environment variable + * NULL if the variable doesn't exist in task 'root's environment. + * + * Programmer: Leon Arber + * 4/4/05 + * + * Modifications: + * Use original getenv if MPI is not initialized. This happens + * one uses the PHDF5 library to build a serial nature code. + * Albert 2006/04/07 + * + *------------------------------------------------------------------------- + */ +char * +getenv_all(MPI_Comm comm, int root, const char *name) +{ + int mpi_size, mpi_rank, mpi_initialized, mpi_finalized; + int len; + static char *env = NULL; + + HDassert(name); + + MPI_Initialized(&mpi_initialized); + MPI_Finalized(&mpi_finalized); + + if (mpi_initialized && !mpi_finalized) { + MPI_Comm_rank(comm, &mpi_rank); + MPI_Comm_size(comm, &mpi_size); + HDassert(root < mpi_size); + + /* The root task does the getenv call + * and sends the result to the other tasks */ + if (mpi_rank == root) { + env = HDgetenv(name); + if (env) { + len = (int)HDstrlen(env); + MPI_Bcast(&len, 1, MPI_INT, root, comm); + MPI_Bcast(env, len, MPI_CHAR, root, comm); + } + else { + /* len -1 indicates that the variable was not in the environment */ + len = -1; + MPI_Bcast(&len, 1, MPI_INT, root, comm); + } + } + else { + MPI_Bcast(&len, 1, MPI_INT, root, comm); + if (len >= 0) { + if (env == NULL) + env = (char *)HDmalloc((size_t)len + 1); + else if (HDstrlen(env) < (size_t)len) + env = (char *)HDrealloc(env, (size_t)len + 1); + + MPI_Bcast(env, len, MPI_CHAR, root, comm); + env[len] = '\0'; + } + else { + if (env) + HDfree(env); + env = NULL; + } + } +#ifndef NDEBUG + MPI_Barrier(comm); +#endif + } + else { + /* use original getenv */ + if (env) + HDfree(env); + env = HDgetenv(name); + } /* end if */ + + return env; +} + +#endif + +/*------------------------------------------------------------------------- + * Function: h5_fileaccess + * + * Purpose: Returns a file access template which is the default template + * but with a file driver, VOL connector, or libver bound set + * according to a constant or environment variable + * + * Return: Success: A file access property list + * Failure: H5I_INVALID_HID + * + * Programmer: Robb Matzke + * Thursday, November 19, 1998 + * + *------------------------------------------------------------------------- + */ +hid_t +h5_fileaccess(void) +{ + hid_t fapl_id = H5I_INVALID_HID; + + if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) + goto error; + + /* Finally, check for libver bounds */ + if (h5_get_libver_fapl(fapl_id) < 0) + goto error; + + return fapl_id; + +error: + if (fapl_id != H5I_INVALID_HID) + H5Pclose(fapl_id); + return H5I_INVALID_HID; +} /* end h5_fileaccess() */ + +/*------------------------------------------------------------------------- + * Function: h5_get_libver_fapl + * + * Purpose: Sets the library version bounds for a FAPL according to the + * value in the constant or environment variable "HDF5_LIBVER_BOUNDS". + * + * Return: Success: 0 + * Failure: -1 + * + * Programmer: Quincey Koziol + * November 2018 + * + *------------------------------------------------------------------------- + */ +herr_t +h5_get_libver_fapl(hid_t fapl) +{ + const char *env = NULL; /* HDF5_DRIVER environment variable */ + const char *tok = NULL; /* strtok pointer */ + char *lasts = NULL; /* Context pointer for strtok_r() call */ + char buf[1024]; /* buffer for tokenizing HDF5_DRIVER */ + + /* Get the environment variable, if it exists */ + env = HDgetenv("HDF5_LIBVER_BOUNDS"); +#ifdef HDF5_LIBVER_BOUNDS + /* Use the environment variable, then the compile-time constant */ + if (!env) + env = HDF5_LIBVER_BOUNDS; +#endif + + /* If the environment variable was not set, just return + * without modifying the FAPL. + */ + if (!env || !*env) + goto done; + + /* Get the first 'word' of the environment variable. + * If it's nothing (environment variable was whitespace) + * just return the default fapl. + */ + HDstrncpy(buf, env, sizeof(buf)); + buf[sizeof(buf) - 1] = '\0'; + if (NULL == (tok = HDstrtok_r(buf, " \t\n\r", &lasts))) + goto done; + + if (!HDstrcmp(tok, "latest")) { + /* use the latest format */ + if (H5Pset_libver_bounds(fapl, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST) < 0) + goto error; + } /* end if */ + else { + /* Unknown setting */ + goto error; + } /* end else */ + +done: + return 0; + +error: + return -1; +} /* end h5_get_libver_fapl() */ + +#ifndef HDF5_PARAPREFIX +#define HDF5_PARAPREFIX "" +#endif +static char * +h5_fixname_real(const char *base_name, hid_t fapl, const char *_suffix, char *fullname, size_t size, + hbool_t nest_printf, hbool_t subst_for_superblock) +{ + const char *prefix = NULL; + const char *driver_env_var = NULL; /* HDF5_DRIVER environment variable */ + char *ptr, last = '\0'; + const char *suffix = _suffix; + size_t i, j; + hid_t driver = -1; + int isppdriver = 0; /* if the driver is MPI parallel */ + + if (!base_name || !fullname || size < 1) + return NULL; + + HDmemset(fullname, 0, size); + + /* Determine if driver is set by environment variable. If it is, + * only generate a suffix if fixing the filename for the superblock + * file. */ + driver_env_var = HDgetenv(HDF5_DRIVER); + if (driver_env_var && (H5P_DEFAULT == fapl) && subst_for_superblock) + fapl = H5P_FILE_ACCESS_DEFAULT; + + /* figure out the suffix */ + if (H5P_DEFAULT != fapl) { + if ((driver = H5Pget_driver(fapl)) < 0) + return NULL; + + if (suffix) { + if (H5FD_FAMILY == driver) { + if (subst_for_superblock) + suffix = "-000000.h5"; + else + suffix = nest_printf ? "-%%06d.h5" : "-%06d.h5"; + } + else if (H5FD_MULTI == driver) { + + /* Check the HDF5_DRIVER environment variable in case + * we are using the split driver since both of those + * use the multi VFD under the hood. + */ + if (driver_env_var && !HDstrcmp(driver_env_var, "split")) { + /* split VFD */ + if (subst_for_superblock) + suffix = ".h5.meta"; + } + else { + /* multi VFD */ + if (subst_for_superblock) + suffix = "-s.h5"; + else + suffix = NULL; + } + } + } + } + + /* Must first check fapl is not H5P_DEFAULT (-1) because H5FD_XXX + * could be of value -1 if it is not defined. + */ + isppdriver = ((H5P_DEFAULT != fapl) || driver_env_var) && (H5FD_MPIO == driver); +#if 0 + /* Check HDF5_NOCLEANUP environment setting. + * (The #ifdef is needed to prevent compile failure in case MPI is not + * configured.) + */ + if (isppdriver) { +#ifdef H5_HAVE_PARALLEL + if (getenv_all(MPI_COMM_WORLD, 0, HDF5_NOCLEANUP)) + SetTestNoCleanup(); +#endif /* H5_HAVE_PARALLEL */ + } + else { + if (HDgetenv(HDF5_NOCLEANUP)) + SetTestNoCleanup(); + } +#endif + /* Check what prefix to use for test files. Process HDF5_PARAPREFIX and + * HDF5_PREFIX. + * Use different ones depending on parallel or serial driver used. + * (The #ifdef is needed to prevent compile failure in case MPI is not + * configured.) + */ + if (isppdriver) { +#ifdef H5_HAVE_PARALLEL + /* + * For parallel: + * First use command line option, then the environment + * variable, then try the constant + */ + static int explained = 0; + + prefix = (paraprefix ? paraprefix : getenv_all(MPI_COMM_WORLD, 0, "HDF5_PARAPREFIX")); + + if (!prefix && !explained) { + /* print hint by process 0 once. */ + int mpi_rank; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + if (mpi_rank == 0) + HDprintf("*** Hint ***\n" + "You can use environment variable HDF5_PARAPREFIX to " + "run parallel test files in a\n" + "different directory or to add file type prefix. e.g.,\n" + " HDF5_PARAPREFIX=pfs:/PFS/user/me\n" + " export HDF5_PARAPREFIX\n" + "*** End of Hint ***\n"); + + explained = TRUE; +#ifdef HDF5_PARAPREFIX + prefix = HDF5_PARAPREFIX; +#endif /* HDF5_PARAPREFIX */ + } +#endif /* H5_HAVE_PARALLEL */ + } + else { + /* + * For serial: + * First use the environment variable, then try the constant + */ + prefix = HDgetenv("HDF5_PREFIX"); + +#ifdef HDF5_PREFIX + if (!prefix) + prefix = HDF5_PREFIX; +#endif /* HDF5_PREFIX */ + } + + /* Prepend the prefix value to the base name */ + if (prefix && *prefix) { + if (isppdriver) { + /* This is a parallel system */ + char *subdir; + + if (!HDstrcmp(prefix, HDF5_PARAPREFIX)) { + /* + * If the prefix specifies the HDF5_PARAPREFIX directory, then + * default to using the "/tmp/$USER" or "/tmp/$LOGIN" + * directory instead. + */ + char *user, *login; + + user = HDgetenv("USER"); + login = HDgetenv("LOGIN"); + subdir = (user ? user : login); + + if (subdir) { + for (i = 0; i < size && prefix[i]; i++) + fullname[i] = prefix[i]; + + fullname[i++] = '/'; + + for (j = 0; i < size && subdir[j]; ++i, ++j) + fullname[i] = subdir[j]; + } + } + + if (!fullname[0]) { + /* We didn't append the prefix yet */ + HDstrncpy(fullname, prefix, size); + fullname[size - 1] = '\0'; + } + + if (HDstrlen(fullname) + HDstrlen(base_name) + 1 < size) { + /* + * Append the base_name with a slash first. Multiple + * slashes are handled below. + */ + h5_stat_t buf; + + if (HDstat(fullname, &buf) < 0) + /* The directory doesn't exist just yet */ + if (HDmkdir(fullname, (mode_t)0755) < 0 && errno != EEXIST) + /* + * We couldn't make the "/tmp/${USER,LOGIN}" + * subdirectory. Default to PREFIX's original + * prefix value. + */ + HDstrcpy(fullname, prefix); + + HDstrcat(fullname, "/"); + HDstrcat(fullname, base_name); + } + else { + /* Buffer is too small */ + return NULL; + } + } + else { + if (HDsnprintf(fullname, size, "%s/%s", prefix, base_name) == (int)size) + /* Buffer is too small */ + return NULL; + } + } + else if (HDstrlen(base_name) >= size) { + /* Buffer is too small */ + return NULL; + } + else { + HDstrcpy(fullname, base_name); + } + + /* Append a suffix */ + if (suffix) { + if (HDstrlen(fullname) + HDstrlen(suffix) >= size) + return NULL; + + HDstrcat(fullname, suffix); + } + + /* Remove any double slashes in the filename */ + for (ptr = fullname, i = j = 0; ptr && i < size; i++, ptr++) { + if (*ptr != '/' || last != '/') + fullname[j++] = *ptr; + + last = *ptr; + } + + return fullname; +} + +char * +h5_fixname(const char *base_name, hid_t fapl, char *fullname, size_t size) +{ + return (h5_fixname_real(base_name, fapl, ".h5", fullname, size, FALSE, FALSE)); +} + +char * +h5_fixname_superblock(const char *base_name, hid_t fapl_id, char *fullname, size_t size) +{ + return (h5_fixname_real(base_name, fapl_id, ".h5", fullname, size, FALSE, TRUE)); +} + +hbool_t +h5_using_default_driver(const char *drv_name) +{ + hbool_t ret_val = TRUE; + + HDassert(H5_DEFAULT_VFD == H5FD_SEC2); + + if (!drv_name) + drv_name = HDgetenv(HDF5_DRIVER); + + if (drv_name) + return (!HDstrcmp(drv_name, "sec2") || !HDstrcmp(drv_name, "nomatch")); + + return ret_val; +} + +herr_t +h5_driver_is_default_vfd_compatible(hid_t fapl_id, hbool_t *default_vfd_compatible) +{ + unsigned long feat_flags = 0; + hid_t driver_id = H5I_INVALID_HID; + herr_t ret_value = SUCCEED; + + HDassert(fapl_id >= 0); + HDassert(default_vfd_compatible); + + if (fapl_id == H5P_DEFAULT) + fapl_id = H5P_FILE_ACCESS_DEFAULT; + + if ((driver_id = H5Pget_driver(fapl_id)) < 0) + return FAIL; + + if (H5FDdriver_query(driver_id, &feat_flags) < 0) + return FAIL; + + *default_vfd_compatible = (feat_flags & H5FD_FEAT_DEFAULT_VFD_COMPATIBLE); + + return ret_value; +} /* end h5_driver_is_default_vfd_compatible() */ + +int +main(int argc, char *argv[]) +{ +#if defined(H5_PARALLEL_TEST) + MPI_Init(&argc, &argv); +#else + (void)argc; + (void)argv; +#endif + + HDprintf("===================================\n"); + HDprintf("HDF5 TESTS START\n"); + HDprintf("===================================\n"); + + /* Initialize testing framework */ + /* TestInit(argv[0], NULL, NULL); */ + + /* Tests are generally arranged from least to most complexity... */ + /* AddTest("config", test_configure, cleanup_configure, "Configure definitions", NULL); */ + HDprintf("** CONFIGURE DEFINITIONS **\n"); + test_configure(); + HDprintf("\n"); + + /* AddTest("metadata", test_metadata, cleanup_metadata, "Encoding/decoding metadata", NULL); */ + + /* AddTest("checksum", test_checksum, cleanup_checksum, "Checksum algorithm", NULL); */ + HDprintf("** CHECKSUM ALGORITHM **\n"); + test_checksum(); + HDprintf("\n"); + + /* AddTest("tst", test_tst, NULL, "Ternary Search Trees", NULL); */ + + /* AddTest("heap", test_heap, NULL, "Memory Heaps", NULL); */ + + /* AddTest("skiplist", test_skiplist, NULL, "Skip Lists", NULL); */ + + /* AddTest("refstr", test_refstr, NULL, "Reference Counted Strings", NULL); */ + + /* AddTest("file", test_file, cleanup_file, "Low-Level File I/O", NULL); */ + HDprintf("** LOW-LEVEL FILE I/O **\n"); + test_file(); + HDprintf("\n"); + + /* AddTest("objects", test_h5o, cleanup_h5o, "Generic Object Functions", NULL); */ + HDprintf("** GENERIC OBJECT FUNCTIONS **\n"); + test_h5o(); + HDprintf("\n"); + + /* AddTest("h5s", test_h5s, cleanup_h5s, "Dataspaces", NULL); */ + HDprintf("** DATASPACES **\n"); + test_h5s(); + HDprintf("\n"); + + /* AddTest("coords", test_coords, cleanup_coords, "Dataspace coordinates", NULL); */ + HDprintf("** DATASPACE COORDINATES **\n"); + test_coords(); + HDprintf("\n"); + + /* AddTest("sohm", test_sohm, cleanup_sohm, "Shared Object Header Messages", NULL); */ + + /* AddTest("attr", test_attr, cleanup_attr, "Attributes", NULL); */ + HDprintf("** ATTRIBUTES **\n"); + test_attr(); + HDprintf("\n"); + + /* AddTest("select", test_select, cleanup_select, "Selections", NULL); */ + HDprintf("** SELECTIONS **\n"); + test_select(); + HDprintf("\n"); + + /* AddTest("time", test_time, cleanup_time, "Time Datatypes", NULL); */ + HDprintf("** TIME DATATYPES**\n"); + test_time(); + HDprintf("\n"); + + /* AddTest("ref_deprec", test_reference_deprec, cleanup_reference_deprec, "Deprecated References", NULL); + */ + + /* AddTest("ref", test_reference, cleanup_reference, "References", NULL); */ + HDprintf("** REFERENCES **\n"); + test_reference(); + HDprintf("\n"); + + /* AddTest("vltypes", test_vltypes, cleanup_vltypes, "Variable-Length Datatypes", NULL); */ + HDprintf("** VARIABLE-LENGTH DATATYPES **\n"); + test_vltypes(); + HDprintf("\n"); + + /* AddTest("vlstrings", test_vlstrings, cleanup_vlstrings, "Variable-Length Strings", NULL); */ + HDprintf("** VARIABLE-LENGTH STRINGS **\n"); + test_vlstrings(); + HDprintf("\n"); + + /* AddTest("iterate", test_iterate, cleanup_iterate, "Group & Attribute Iteration", NULL); */ + HDprintf("** GROUP & ATTRIBUTE ITERATION **\n"); + test_iterate(); + HDprintf("\n"); + + /* AddTest("array", test_array, cleanup_array, "Array Datatypes", NULL); */ + HDprintf("** ARRAY DATATYPES **\n"); + test_array(); + HDprintf("\n"); + + /* AddTest("genprop", test_genprop, cleanup_genprop, "Generic Properties", NULL); */ + HDprintf("** GENERIC PROPERTIES **\n"); + test_genprop(); + HDprintf("\n"); + + /* AddTest("unicode", test_unicode, cleanup_unicode, "UTF-8 Encoding", NULL); */ + HDprintf("** UTF-8 ENCODING **\n"); + test_unicode(); + HDprintf("\n"); + + /* AddTest("id", test_ids, NULL, "User-Created Identifiers", NULL); */ + HDprintf("** USER-CREATED IDENTIFIERS **\n"); + test_ids(); + HDprintf("\n"); + + /* AddTest("misc", test_misc, cleanup_misc, "Miscellaneous", NULL); */ + HDprintf("** MISCELLANEOUS **\n"); + test_misc(); + HDprintf("\n"); + + /* Display testing information */ + /* TestInfo(argv[0]); */ + + /* Parse command line arguments */ + /* TestParseCmdLine(argc,argv); */ + + /* Perform requested testing */ + /* PerformTests(); */ + + /* Display test summary, if requested */ + /* if (GetTestSummary()) + TestSummary(); */ + + /* Clean up test files, if allowed */ + if (/* GetTestCleanup() && */ !getenv("HDF5_NOCLEANUP")) { + /* TestCleanup(); */ + + HDprintf("TEST CLEANUP\n"); + + H5E_BEGIN_TRY + cleanup_configure(); + cleanup_checksum(); + cleanup_file(); + cleanup_h5o(); + cleanup_h5s(); + cleanup_coords(); + cleanup_attr(); + cleanup_select(); + cleanup_time(); + cleanup_reference(); + cleanup_vltypes(); + cleanup_vlstrings(); + cleanup_iterate(); + cleanup_array(); + cleanup_genprop(); + cleanup_unicode(); + cleanup_misc(); + H5E_END_TRY; + + HDprintf("\n"); + } + + /* Release test infrastructure */ + /* TestShutdown(); */ + + /* Exit failure if errors encountered; else exit success. */ + /* No need to print anything since PerformTests() already does. */ + if (nerrors /* GetTestNumErrs() */ > 0) { + HDprintf("** HDF5 tests failed with %d errors **\n", nerrors); + HDexit(EXIT_FAILURE); + } + else { + HDprintf("** HDF5 tests ran successfully **\n"); + HDexit(EXIT_SUCCESS); + } +} /* end main() */ diff --git a/test/API/testhdf5.h b/test/API/testhdf5.h new file mode 100644 index 0000000..44ccfe0 --- /dev/null +++ b/test/API/testhdf5.h @@ -0,0 +1,349 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * This header file contains information required for testing the HDF5 library. + */ + +#ifndef TESTHDF5_H +#define TESTHDF5_H + +/* Include generic testing header also */ +/* #include "h5test.h" */ +#include "hdf5.h" +#include "H5private.h" +#include "H5_api_tests_disabled.h" + +#define VERBO_NONE 0 /* None */ +#define VERBO_DEF 3 /* Default */ +#define VERBO_LO 5 /* Low */ +#define VERBO_MED 7 /* Medium */ +#define VERBO_HI 9 /* High */ + +/* Turn off verbose reporting by default */ +#define VERBOSE_MED (FALSE) +#define VERBOSE_HI (FALSE) + +/* Use %ld to print the value because long should cover most cases. */ +/* Used to make certain a return value _is_not_ a value */ +#define CHECK(ret, val, where) \ + do { \ + if (VERBOSE_HI) { \ + print_func(" Call to routine: %15s at line %4d " \ + "in %s returned %ld \n", \ + where, (int)__LINE__, __FILE__, (long)(ret)); \ + } \ + if ((ret) == (val)) { \ + TestErrPrintf("*** UNEXPECTED RETURN from %s is %ld at line %4d " \ + "in %s\n", \ + where, (long)(ret), (int)__LINE__, __FILE__); \ + H5Eprint2(H5E_DEFAULT, stdout); \ + } \ + } while (0) + +#define CHECK_I(ret, where) \ + { \ + if (VERBOSE_HI) { \ + print_func(" Call to routine: %15s at line %4d in %s returned %ld\n", (where), (int)__LINE__, \ + __FILE__, (long)(ret)); \ + } \ + if ((ret) < 0) { \ + TestErrPrintf("*** UNEXPECTED RETURN from %s is %ld line %4d in %s\n", (where), (long)(ret), \ + (int)__LINE__, __FILE__); \ + H5Eprint2(H5E_DEFAULT, stdout); \ + } \ + } + +/* Check that a pointer is valid (i.e.: not NULL) */ +#define CHECK_PTR(ret, where) \ + { \ + if (VERBOSE_HI) { \ + print_func(" Call to routine: %15s at line %4d in %s returned %p\n", (where), (int)__LINE__, \ + __FILE__, ((const void *)ret)); \ + } \ + if (!(ret)) { \ + TestErrPrintf("*** UNEXPECTED RETURN from %s is NULL line %4d in %s\n", (where), (int)__LINE__, \ + __FILE__); \ + H5Eprint2(H5E_DEFAULT, stdout); \ + } \ + } + +/* Check that a pointer is NULL */ +#define CHECK_PTR_NULL(ret, where) \ + { \ + if (VERBOSE_HI) { \ + print_func(" Call to routine: %15s at line %4d in %s returned %p\n", (where), (int)__LINE__, \ + __FILE__, ((const void *)ret)); \ + } \ + if (ret) { \ + TestErrPrintf("*** UNEXPECTED RETURN from %s is not NULL line %4d in %s\n", (where), \ + (int)__LINE__, __FILE__); \ + H5Eprint2(H5E_DEFAULT, stdout); \ + } \ + } + +/* Check that two pointers are equal */ +#define CHECK_PTR_EQ(ret, val, where) \ + { \ + if (VERBOSE_HI) { \ + print_func(" Call to routine: %15s at line %4d in %s returned %p\n", (where), (int)__LINE__, \ + __FILE__, (const void *)(ret)); \ + } \ + if (ret != val) { \ + TestErrPrintf( \ + "*** UNEXPECTED RETURN from %s: returned value of %p is not equal to %p line %4d in %s\n", \ + (where), (const void *)(ret), (const void *)(val), (int)__LINE__, __FILE__); \ + H5Eprint2(H5E_DEFAULT, stdout); \ + } \ + } + +/* Used to make certain a return value _is_ a value */ +#define VERIFY(_x, _val, where) \ + do { \ + long __x = (long)_x, __val = (long)_val; \ + if (VERBOSE_HI) { \ + print_func(" Call to routine: %15s at line %4d in %s had value " \ + "%ld \n", \ + (where), (int)__LINE__, __FILE__, __x); \ + } \ + if ((__x) != (__val)) { \ + TestErrPrintf("*** UNEXPECTED VALUE from %s should be %ld, but is %ld at line %4d " \ + "in %s\n", \ + (where), __val, __x, (int)__LINE__, __FILE__); \ + H5Eprint2(H5E_DEFAULT, stdout); \ + } \ + } while (0) + +/* Used to make certain a (non-'long' type's) return value _is_ a value */ +#define VERIFY_TYPE(_x, _val, _type, _format, where) \ + do { \ + _type __x = (_type)_x, __val = (_type)_val; \ + if (VERBOSE_HI) { \ + print_func(" Call to routine: %15s at line %4d in %s had value " _format " \n", (where), \ + (int)__LINE__, __FILE__, __x); \ + } \ + if ((__x) != (__val)) { \ + TestErrPrintf("*** UNEXPECTED VALUE from %s should be " _format ", but is " _format \ + " at line %4d " \ + "in %s\n", \ + (where), __val, __x, (int)__LINE__, __FILE__); \ + H5Eprint2(H5E_DEFAULT, stdout); \ + } \ + } while (0) + +/* Used to make certain a string return value _is_ a value */ +#define VERIFY_STR(x, val, where) \ + do { \ + if (VERBOSE_HI) { \ + print_func(" Call to routine: %15s at line %4d in %s had value " \ + "%s \n", \ + (where), (int)__LINE__, __FILE__, x); \ + } \ + if (HDstrcmp(x, val) != 0) { \ + TestErrPrintf("*** UNEXPECTED VALUE from %s should be %s, but is %s at line %4d " \ + "in %s\n", \ + where, val, x, (int)__LINE__, __FILE__); \ + H5Eprint2(H5E_DEFAULT, stdout); \ + } \ + } while (0) + +/* Used to document process through a test and to check for errors */ +#define RESULT(ret, func) \ + do { \ + if (VERBOSE_MED) { \ + print_func(" Call to routine: %15s at line %4d in %s returned " \ + "%ld\n", \ + func, (int)__LINE__, __FILE__, (long)(ret)); \ + } \ + if (VERBOSE_HI) \ + H5Eprint2(H5E_DEFAULT, stdout); \ + if ((ret) == FAIL) { \ + TestErrPrintf("*** UNEXPECTED RETURN from %s is %ld at line %4d " \ + "in %s\n", \ + func, (long)(ret), (int)__LINE__, __FILE__); \ + H5Eprint2(H5E_DEFAULT, stdout); \ + } \ + } while (0) + +/* Used to document process through a test */ +#if defined(H5_HAVE_PARALLEL) && defined(H5_PARALLEL_TEST) +#define MESSAGE(V, A) \ + { \ + int mpi_rank; \ + \ + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); \ + if (mpi_rank == 0 && VERBO_LO /* HDGetTestVerbosity() */ >= (V)) \ + print_func A; \ + } +#else /* H5_HAVE_PARALLEL */ +#define MESSAGE(V, A) \ + { \ + if (VERBO_LO /* HDGetTestVerbosity() */ >= (V)) \ + print_func A; \ + } +#endif /* H5_HAVE_PARALLEL */ + +/* Used to indicate an error that is complex to check for */ +#define ERROR(where) \ + do { \ + if (VERBOSE_HI) \ + print_func(" Call to routine: %15s at line %4d in %s returned " \ + "invalid result\n", \ + where, (int)__LINE__, __FILE__); \ + TestErrPrintf("*** UNEXPECTED RESULT from %s at line %4d in %s\n", where, (int)__LINE__, __FILE__); \ + } while (0) + +/* definitions for command strings */ +#define VERBOSITY_STR "Verbosity" +#define SKIP_STR "Skip" +#define TEST_STR "Test" +#define CLEAN_STR "Cleanup" + +#define AT() HDprintf(" at %s:%d in %s()...\n", __FILE__, __LINE__, __func__); +#define TESTING(WHAT) \ + { \ + HDprintf("Testing %-62s", WHAT); \ + HDfflush(stdout); \ + } +#define TESTING_2(WHAT) \ + { \ + HDprintf(" Testing %-60s", WHAT); \ + HDfflush(stdout); \ + } +#define PASSED() \ + { \ + HDputs(" PASSED"); \ + HDfflush(stdout); \ + } +#define H5_FAILED() \ + { \ + HDputs("*FAILED*"); \ + HDfflush(stdout); \ + } +#define H5_WARNING() \ + { \ + HDputs("*WARNING*"); \ + HDfflush(stdout); \ + } +#define SKIPPED() \ + { \ + HDputs(" -SKIP-"); \ + HDfflush(stdout); \ + } +#define PUTS_ERROR(s) \ + { \ + HDputs(s); \ + AT(); \ + goto error; \ + } +#define TEST_ERROR \ + { \ + H5_FAILED(); \ + AT(); \ + goto error; \ + } +#define STACK_ERROR \ + { \ + H5Eprint2(H5E_DEFAULT, stdout); \ + goto error; \ + } +#define FAIL_STACK_ERROR \ + { \ + H5_FAILED(); \ + AT(); \ + H5Eprint2(H5E_DEFAULT, stdout); \ + goto error; \ + } +#define FAIL_PUTS_ERROR(s) \ + { \ + H5_FAILED(); \ + AT(); \ + HDputs(s); \ + goto error; \ + } + +#ifdef __cplusplus +extern "C" { +#endif + +extern int nerrors; + +int print_func(const char *format, ...); +int TestErrPrintf(const char *format, ...); +hid_t h5_fileaccess(void); +/* Functions that will replace components of a FAPL */ +herr_t h5_get_vfd_fapl(hid_t fapl_id); +herr_t h5_get_libver_fapl(hid_t fapl_id); +char *h5_fixname(const char *base_name, hid_t fapl, char *fullname, size_t size); +char *h5_fixname_superblock(const char *base_name, hid_t fapl, char *fullname, size_t size); +hbool_t h5_using_default_driver(const char *drv_name); +herr_t h5_driver_is_default_vfd_compatible(hid_t fapl_id, hbool_t *default_vfd_compatible); + +#ifdef H5_HAVE_PARALLEL +char *getenv_all(MPI_Comm comm, int root, const char *name); +#endif + +/* Prototypes for the test routines */ +void test_metadata(void); +void test_checksum(void); +void test_refstr(void); +void test_file(void); +void test_h5o(void); +void test_h5t(void); +void test_h5s(void); +void test_coords(void); +void test_h5d(void); +void test_attr(void); +void test_select(void); +void test_time(void); +void test_reference(void); +void test_reference_deprec(void); +void test_vltypes(void); +void test_vlstrings(void); +void test_iterate(void); +void test_array(void); +void test_genprop(void); +void test_configure(void); +void test_h5_system(void); +void test_misc(void); +void test_ids(void); +void test_skiplist(void); +void test_sohm(void); +void test_unicode(void); + +/* Prototypes for the cleanup routines */ +void cleanup_metadata(void); +void cleanup_checksum(void); +void cleanup_file(void); +void cleanup_h5o(void); +void cleanup_h5s(void); +void cleanup_coords(void); +void cleanup_attr(void); +void cleanup_select(void); +void cleanup_time(void); +void cleanup_reference(void); +void cleanup_reference_deprec(void); +void cleanup_vltypes(void); +void cleanup_vlstrings(void); +void cleanup_iterate(void); +void cleanup_array(void); +void cleanup_genprop(void); +void cleanup_configure(void); +void cleanup_h5_system(void); +void cleanup_sohm(void); +void cleanup_misc(void); +void cleanup_unicode(void); + +#ifdef __cplusplus +} +#endif +#endif /* TESTHDF5_H */ diff --git a/test/API/tfile.c b/test/API/tfile.c new file mode 100644 index 0000000..bc0f18e --- /dev/null +++ b/test/API/tfile.c @@ -0,0 +1,8381 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*********************************************************** + * + * Test program: tfile + * + * Test the low-level file I/O features. + * + *************************************************************/ + +#include "testhdf5.h" +/* #include "H5srcdir.h" */ + +/* #include "H5Iprivate.h" */ +/* #include "H5Pprivate.h" */ +/* #include "H5VLprivate.h" */ /* Virtual Object Layer */ + +#if 0 +/* + * This file needs to access private information from the H5F package. + * This file also needs to access the file testing code. + */ +#define H5F_FRIEND /*suppress error about including H5Fpkg */ +#define H5F_TESTING +#include "H5Fpkg.h" /* File access */ + +#define H5FD_FRIEND /*suppress error about including H5FDpkg.h */ +#define H5FD_TESTING +#include "H5FDpkg.h" + +#define H5D_FRIEND /*suppress error about including H5Dpkg */ +#include "H5Dpkg.h" /* Dataset access */ + +#define H5S_FRIEND /*suppress error about including H5Spkg */ +#include "H5Spkg.h" /* Dataspace */ + +#define H5T_FRIEND /*suppress error about including H5Tpkg */ +#include "H5Tpkg.h" /* Datatype */ + +#define H5A_FRIEND /*suppress error about including H5Apkg */ +#include "H5Apkg.h" /* Attributes */ + +#define H5O_FRIEND /*suppress error about including H5Opkg */ +#include "H5Opkg.h" /* Object headers */ +#endif + +#define BAD_USERBLOCK_SIZE1 (hsize_t)1 +#define BAD_USERBLOCK_SIZE2 (hsize_t)2 +#define BAD_USERBLOCK_SIZE3 (hsize_t)3 +#define BAD_USERBLOCK_SIZE4 (hsize_t)64 +#define BAD_USERBLOCK_SIZE5 (hsize_t)511 +#define BAD_USERBLOCK_SIZE6 (hsize_t)513 +#define BAD_USERBLOCK_SIZE7 (hsize_t)6144 + +#define F1_USERBLOCK_SIZE (hsize_t)0 +#define F1_OFFSET_SIZE sizeof(haddr_t) +#define F1_LENGTH_SIZE sizeof(hsize_t) +#define F1_SYM_LEAF_K 4 +#define F1_SYM_INTERN_K 16 +#define FILE1 "tfile1.h5" +#define SFILE1 "sys_file1" + +#define REOPEN_FILE "tfile_reopen.h5" +#define REOPEN_DSET "dset" + +#define F2_USERBLOCK_SIZE (hsize_t)512 +#define F2_OFFSET_SIZE 8 +#define F2_LENGTH_SIZE 8 +#define F2_SYM_LEAF_K 8 +#define F2_SYM_INTERN_K 32 +#define F2_RANK 2 +#define F2_DIM0 4 +#define F2_DIM1 6 +#define F2_DSET "dset" +#define FILE2 "tfile2.h5" + +#define F3_USERBLOCK_SIZE (hsize_t)0 +#define F3_OFFSET_SIZE F2_OFFSET_SIZE +#define F3_LENGTH_SIZE F2_LENGTH_SIZE +#define F3_SYM_LEAF_K F2_SYM_LEAF_K +#define F3_SYM_INTERN_K F2_SYM_INTERN_K +#define FILE3 "tfile3.h5" + +#define GRP_NAME "/group" +#define DSET_NAME "dataset" +#define ATTR_NAME "attr" +#define TYPE_NAME "type" +#define FILE4 "tfile4.h5" + +#define OBJ_ID_COUNT_0 0 +#define OBJ_ID_COUNT_1 1 +#define OBJ_ID_COUNT_2 2 +#define OBJ_ID_COUNT_3 3 +#define OBJ_ID_COUNT_4 4 +#define OBJ_ID_COUNT_6 6 +#define OBJ_ID_COUNT_8 8 + +#define GROUP1 "Group1" +#define DSET1 "Dataset1" +#define DSET2 "/Group1/Dataset2" + +#define TESTA_GROUPNAME "group" +#define TESTA_DSETNAME "dataset" +#define TESTA_ATTRNAME "attribute" +#define TESTA_DTYPENAME "compound" +#define TESTA_NAME_BUF_SIZE 64 +#define TESTA_RANK 2 +#define TESTA_NX 4 +#define TESTA_NY 5 + +#define USERBLOCK_SIZE ((hsize_t)512) + +/* Declarations for test_filespace_*() */ +#define FILENAME_LEN 1024 /* length of file name */ +#define DSETNAME "dset" /* Name of dataset */ +#define NELMTS(X) (sizeof(X) / sizeof(X[0])) /* # of elements */ +#define READ_OLD_BUFSIZE 1024 /* Buffer for holding file data */ +#define FILE5 "tfile5.h5" /* Test file */ +#define TEST_THRESHOLD10 10 /* Free space section threshold */ +#define FSP_SIZE_DEF 4096 /* File space page size default */ +#define FSP_SIZE512 512 /* File space page size */ +#define FSP_SIZE1G (1024 * 1024 * 1024) /* File space page size */ + +/* Declaration for test_libver_macros2() */ +#define FILE6 "tfile6.h5" /* Test file */ + +/* Declaration for test_get_obj_ids() */ +#define FILE7 "tfile7.h5" /* Test file */ +#define NGROUPS 2 +#define NDSETS 4 + +/* Declaration for test_incr_filesize() */ +#define FILE8 "tfile8.h5" /* Test file */ + +/* Files created under 1.6 branch and 1.8 branch--used in test_filespace_compatible() */ +const char *OLD_FILENAME[] = { + "filespace_1_6.h5", /* 1.6 HDF5 file */ + "filespace_1_8.h5" /* 1.8 HDF5 file */ +}; + +/* Files created in 1.10.0 release --used in test_filespace_1.10.0_compatible() */ +/* These files are copied from release 1.10.0 tools/h5format_convert/testfiles */ +const char *OLD_1_10_0_FILENAME[] = { + "h5fc_ext1_i.h5", /* 0 */ + "h5fc_ext1_f.h5", /* 1 */ + "h5fc_ext2_if.h5", /* 2 */ + "h5fc_ext2_sf.h5", /* 3 */ + "h5fc_ext3_isf.h5", /* 4 */ + "h5fc_ext_none.h5" /* 5 */ +}; + +/* Files used in test_filespace_round_compatible() */ +const char *FSPACE_FILENAMES[] = { + "fsm_aggr_nopersist.h5", /* H5F_FILE_SPACE_AGGR, not persisting free-space */ + "fsm_aggr_persist.h5", /* H5F_FILE_SPACE_AGGR, persisting free-space */ + "paged_nopersist.h5", /* H5F_FILE_SPACE_PAGE, not persisting free-space */ + "paged_persist.h5", /* H5F_FILE_SPACE_PAGE, persisting free-space */ + "aggr.h5", /* H5F_FILE_SPACE_AGGR */ + "none.h5" /* H5F_FILE_SPACE_NONE */ +}; + +const char *FILESPACE_NAME[] = {"tfilespace.h5", NULL}; + +/* Declarations for test_libver_bounds_copy(): */ +/* SRC_FILE: source file created under 1.8 branch with latest format */ +/* DST_FILE: destination file for copying the dataset in SRC_FILE */ +/* DSET_DS1: the dataset created in SRC_FILE to be copied to DST_FILE */ +#define SRC_FILE "fill18.h5" +#define DST_FILE "fill18_copy.h5" +#define DSET_DS1 "DS1" + +#if 0 +/* Local test function declarations for version bounds */ +static void test_libver_bounds_low_high(const char *env_h5_drvr); +static void test_libver_bounds_super(hid_t fapl, const char *env_h5_drvr); +static void test_libver_bounds_super_create(hid_t fapl, hid_t fcpl, htri_t is_swmr, htri_t non_def_fsm); +static void test_libver_bounds_super_open(hid_t fapl, hid_t fcpl, htri_t is_swmr, htri_t non_def_fsm); +static void test_libver_bounds_obj(hid_t fapl); +static void test_libver_bounds_dataset(hid_t fapl); +static void test_libver_bounds_dataspace(hid_t fapl); +static void test_libver_bounds_datatype(hid_t fapl); +static void test_libver_bounds_datatype_check(hid_t fapl, hid_t tid); +static void test_libver_bounds_attributes(hid_t fapl); +#endif + +#define DSET_NULL "DSET_NULL" +#define DSET "DSET" +#define DSETA "DSETA" +#define DSETB "DSETB" +#define DSETC "DSETC" + +#if 0 +static void +create_objects(hid_t, hid_t, hid_t *, hid_t *, hid_t *, hid_t *); +static void +test_obj_count_and_id(hid_t, hid_t, hid_t, hid_t, hid_t, hid_t); +static void +check_file_id(hid_t, hid_t); +#endif + +#if 0 +/* Helper routine used by test_rw_noupdate() */ +static int cal_chksum(const char *file, uint32_t *chksum); + +static void test_rw_noupdate(void); +#endif + +/**************************************************************** +** +** test_file_create(): Low-level file creation I/O test routine. +** +****************************************************************/ +static void +test_file_create(void) +{ + hid_t fid1 = H5I_INVALID_HID; + hid_t fid2 = H5I_INVALID_HID; + hid_t fid3 = H5I_INVALID_HID; /* HDF5 File IDs */ + hid_t tmpl1, tmpl2; /* file creation templates */ + hsize_t ublock; /* sizeof userblock */ + size_t parm; /* file-creation parameters */ + size_t parm2; /* file-creation parameters */ + unsigned iparm; + unsigned iparm2; + herr_t ret; /*generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Low-Level File Creation I/O\n")); + + /* First ensure the file does not exist */ + H5E_BEGIN_TRY + { + H5Fdelete(FILE1, H5P_DEFAULT); + } + H5E_END_TRY; + + /* Try opening a non-existent file */ + H5E_BEGIN_TRY + { + fid1 = H5Fopen(FILE1, H5F_ACC_RDWR, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(fid1, FAIL, "H5Fopen"); + + /* Test create with various sequences of H5F_ACC_EXCL and */ + /* H5F_ACC_TRUNC flags */ + + /* Create with H5F_ACC_EXCL */ + fid1 = H5Fcreate(FILE1, H5F_ACC_EXCL, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); +#ifndef NO_TRUNCATE_OPEN_FILE + /* + * try to create the same file with H5F_ACC_TRUNC. This should fail + * because fid1 is the same file and is currently open. + */ + H5E_BEGIN_TRY + { + fid2 = H5Fcreate(FILE1, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(fid2, FAIL, "H5Fcreate"); +#endif + /* Close all files */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + H5E_BEGIN_TRY + { + ret = H5Fclose(fid2); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Fclose"); /*file should not have been open */ + + /* + * Try again with H5F_ACC_EXCL. This should fail because the file already + * exists from the previous steps. + */ + H5E_BEGIN_TRY + { + fid1 = H5Fcreate(FILE1, H5F_ACC_EXCL, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(fid1, FAIL, "H5Fcreate"); + + /* Test create with H5F_ACC_TRUNC. This will truncate the existing file. */ + fid1 = H5Fcreate(FILE1, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); +#ifndef NO_TRUNCATE_OPEN_FILE + /* + * Try to truncate first file again. This should fail because fid1 is the + * same file and is currently open. + */ + H5E_BEGIN_TRY + { + fid2 = H5Fcreate(FILE1, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(fid2, FAIL, "H5Fcreate"); +#endif + /* + * Try with H5F_ACC_EXCL. This should fail too because the file already + * exists. + */ + H5E_BEGIN_TRY + { + fid2 = H5Fcreate(FILE1, H5F_ACC_EXCL, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(fid2, FAIL, "H5Fcreate"); + + /* Get the file-creation template */ + tmpl1 = H5Fget_create_plist(fid1); + CHECK(tmpl1, FAIL, "H5Fget_create_plist"); + + /* Get the file-creation parameters */ + ret = H5Pget_userblock(tmpl1, &ublock); + CHECK(ret, FAIL, "H5Pget_userblock"); + VERIFY(ublock, F1_USERBLOCK_SIZE, "H5Pget_userblock"); + + ret = H5Pget_sizes(tmpl1, &parm, &parm2); + CHECK(ret, FAIL, "H5Pget_sizes"); + VERIFY(parm, F1_OFFSET_SIZE, "H5Pget_sizes"); + VERIFY(parm2, F1_LENGTH_SIZE, "H5Pget_sizes"); + + ret = H5Pget_sym_k(tmpl1, &iparm, &iparm2); + CHECK(ret, FAIL, "H5Pget_sym_k"); + VERIFY(iparm, F1_SYM_INTERN_K, "H5Pget_sym_k"); + VERIFY(iparm2, F1_SYM_LEAF_K, "H5Pget_sym_k"); + + /* Release file-creation template */ + ret = H5Pclose(tmpl1); + CHECK(ret, FAIL, "H5Pclose"); + +#ifdef LATER + /* Double-check that the atom has been vaporized */ + ret = H5Pclose(tmpl1); + VERIFY(ret, FAIL, "H5Pclose"); +#endif + + if (h5_using_default_driver(NULL)) { + + /* Create a new file with a non-standard file-creation template */ + tmpl1 = H5Pcreate(H5P_FILE_CREATE); + CHECK(tmpl1, FAIL, "H5Pcreate"); + + /* Try setting some bad userblock sizes */ + H5E_BEGIN_TRY + { + ret = H5Pset_userblock(tmpl1, BAD_USERBLOCK_SIZE1); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Pset_userblock"); + H5E_BEGIN_TRY + { + ret = H5Pset_userblock(tmpl1, BAD_USERBLOCK_SIZE2); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Pset_userblock"); + H5E_BEGIN_TRY + { + ret = H5Pset_userblock(tmpl1, BAD_USERBLOCK_SIZE3); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Pset_userblock"); + H5E_BEGIN_TRY + { + ret = H5Pset_userblock(tmpl1, BAD_USERBLOCK_SIZE4); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Pset_userblock"); + H5E_BEGIN_TRY + { + ret = H5Pset_userblock(tmpl1, BAD_USERBLOCK_SIZE5); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Pset_userblock"); + H5E_BEGIN_TRY + { + ret = H5Pset_userblock(tmpl1, BAD_USERBLOCK_SIZE6); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Pset_userblock"); + H5E_BEGIN_TRY + { + ret = H5Pset_userblock(tmpl1, BAD_USERBLOCK_SIZE7); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Pset_userblock"); + + /* Set the new file-creation parameters */ + ret = H5Pset_userblock(tmpl1, F2_USERBLOCK_SIZE); + CHECK(ret, FAIL, "H5Pset_userblock"); + + ret = H5Pset_sizes(tmpl1, (size_t)F2_OFFSET_SIZE, (size_t)F2_LENGTH_SIZE); + CHECK(ret, FAIL, "H5Pset_sizes"); + + ret = H5Pset_sym_k(tmpl1, F2_SYM_INTERN_K, F2_SYM_LEAF_K); + CHECK(ret, FAIL, "H5Pset_sym_k"); + + /* + * Try to create second file, with non-standard file-creation template + * params. + */ + fid2 = H5Fcreate(FILE2, H5F_ACC_TRUNC, tmpl1, H5P_DEFAULT); + CHECK(fid2, FAIL, "H5Fcreate"); + + /* Release file-creation template */ + ret = H5Pclose(tmpl1); + CHECK(ret, FAIL, "H5Pclose"); + + /* Make certain we can create a dataset properly in the file with the userblock */ + { + hid_t dataset_id, dataspace_id; /* identifiers */ + hsize_t dims[F2_RANK]; + unsigned data[F2_DIM0][F2_DIM1]; + unsigned i, j; + + /* Create the data space for the dataset. */ + dims[0] = F2_DIM0; + dims[1] = F2_DIM1; + dataspace_id = H5Screate_simple(F2_RANK, dims, NULL); + CHECK(dataspace_id, FAIL, "H5Screate_simple"); + + /* Create the dataset. */ + dataset_id = H5Dcreate2(fid2, F2_DSET, H5T_NATIVE_UINT, dataspace_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT); + CHECK(dataset_id, FAIL, "H5Dcreate2"); + + for (i = 0; i < F2_DIM0; i++) + for (j = 0; j < F2_DIM1; j++) + data[i][j] = i * 10 + j; + + /* Write data to the new dataset */ + ret = H5Dwrite(dataset_id, H5T_NATIVE_UINT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data); + CHECK(ret, FAIL, "H5Dwrite"); + + /* End access to the dataset and release resources used by it. */ + ret = H5Dclose(dataset_id); + CHECK(ret, FAIL, "H5Dclose"); + + /* Terminate access to the data space. */ + ret = H5Sclose(dataspace_id); + CHECK(ret, FAIL, "H5Sclose"); + } + + /* Get the file-creation template */ + tmpl1 = H5Fget_create_plist(fid2); + CHECK(tmpl1, FAIL, "H5Fget_create_plist"); + + /* Get the file-creation parameters */ + ret = H5Pget_userblock(tmpl1, &ublock); + CHECK(ret, FAIL, "H5Pget_userblock"); + VERIFY(ublock, F2_USERBLOCK_SIZE, "H5Pget_userblock"); + + ret = H5Pget_sizes(tmpl1, &parm, &parm2); + CHECK(ret, FAIL, "H5Pget_sizes"); + VERIFY(parm, F2_OFFSET_SIZE, "H5Pget_sizes"); + VERIFY(parm2, F2_LENGTH_SIZE, "H5Pget_sizes"); + + ret = H5Pget_sym_k(tmpl1, &iparm, &iparm2); + CHECK(ret, FAIL, "H5Pget_sym_k"); + VERIFY(iparm, F2_SYM_INTERN_K, "H5Pget_sym_k"); + VERIFY(iparm2, F2_SYM_LEAF_K, "H5Pget_sym_k"); + + /* Clone the file-creation template */ + tmpl2 = H5Pcopy(tmpl1); + CHECK(tmpl2, FAIL, "H5Pcopy"); + + /* Release file-creation template */ + ret = H5Pclose(tmpl1); + CHECK(ret, FAIL, "H5Pclose"); + + /* Set the new file-creation parameter */ + ret = H5Pset_userblock(tmpl2, F3_USERBLOCK_SIZE); + CHECK(ret, FAIL, "H5Pset_userblock"); + + /* + * Try to create second file, with non-standard file-creation template + * params + */ + fid3 = H5Fcreate(FILE3, H5F_ACC_TRUNC, tmpl2, H5P_DEFAULT); + CHECK(fid3, FAIL, "H5Fcreate"); + + /* Release file-creation template */ + ret = H5Pclose(tmpl2); + CHECK(ret, FAIL, "H5Pclose"); + + /* Get the file-creation template */ + tmpl1 = H5Fget_create_plist(fid3); + CHECK(tmpl1, FAIL, "H5Fget_create_plist"); + + /* Get the file-creation parameters */ + ret = H5Pget_userblock(tmpl1, &ublock); + CHECK(ret, FAIL, "H5Pget_userblock"); + VERIFY(ublock, F3_USERBLOCK_SIZE, "H5Pget_userblock"); + + ret = H5Pget_sizes(tmpl1, &parm, &parm2); + CHECK(ret, FAIL, "H5Pget_sizes"); + VERIFY(parm, F3_OFFSET_SIZE, "H5Pget_sizes"); + VERIFY(parm2, F3_LENGTH_SIZE, "H5Pget_sizes"); + + ret = H5Pget_sym_k(tmpl1, &iparm, &iparm2); + CHECK(ret, FAIL, "H5Pget_sym_k"); + VERIFY(iparm, F3_SYM_INTERN_K, "H5Pget_sym_k"); + VERIFY(iparm2, F3_SYM_LEAF_K, "H5Pget_sym_k"); + + /* Release file-creation template */ + ret = H5Pclose(tmpl1); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close second file */ + ret = H5Fclose(fid2); + CHECK(ret, FAIL, "H5Fclose"); + + /* Close third file */ + ret = H5Fclose(fid3); + CHECK(ret, FAIL, "H5Fclose"); + } + + /* Close first file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_file_create() */ + +/**************************************************************** +** +** test_file_open(): Low-level file open I/O test routine. +** +****************************************************************/ +static void +test_file_open(const char *env_h5_drvr) +{ + hid_t fid1; /*HDF5 File IDs */ +#if 0 + hid_t fid2; + hid_t did; /*dataset ID */ + hid_t fapl_id; /*file access property list ID */ +#endif + hid_t tmpl1; /*file creation templates */ + hsize_t ublock; /*sizeof user block */ + size_t parm; /*file-creation parameters */ + size_t parm2; /*file-creation parameters */ + unsigned iparm; + unsigned iparm2; + unsigned intent; + herr_t ret; /*generic return value */ + + /* + * Test single file open + */ + + /* Only run this test with sec2/default driver */ + if (!h5_using_default_driver(env_h5_drvr)) + return; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Low-Level File Opening I/O\n")); + + /* Open first file */ + fid1 = H5Fopen(FILE2, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Get the intent */ + ret = H5Fget_intent(fid1, &intent); + CHECK(ret, FAIL, "H5Fget_intent"); + VERIFY(intent, H5F_ACC_RDWR, "H5Fget_intent"); + + /* Get the file-creation template */ + tmpl1 = H5Fget_create_plist(fid1); + CHECK(tmpl1, FAIL, "H5Fget_create_plist"); + + /* Get the file-creation parameters */ + ret = H5Pget_userblock(tmpl1, &ublock); + CHECK(ret, FAIL, "H5Pget_userblock"); + VERIFY(ublock, F2_USERBLOCK_SIZE, "H5Pget_userblock"); + + ret = H5Pget_sizes(tmpl1, &parm, &parm2); + CHECK(ret, FAIL, "H5Pget_sizes"); + VERIFY(parm, F2_OFFSET_SIZE, "H5Pget_sizes"); + VERIFY(parm2, F2_LENGTH_SIZE, "H5Pget_sizes"); + + ret = H5Pget_sym_k(tmpl1, &iparm, &iparm2); + CHECK(ret, FAIL, "H5Pget_sym_k"); + VERIFY(iparm, F2_SYM_INTERN_K, "H5Pget_sym_k"); + VERIFY(iparm2, F2_SYM_LEAF_K, "H5Pget_sym_k"); + + /* Release file-creation template */ + ret = H5Pclose(tmpl1); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close first file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* + * Test two file opens: one is opened H5F_ACC_RDONLY and H5F_CLOSE_WEAK. + * It's closed with an object left open. Then another is opened + * H5F_ACC_RDWR, which should fail. + */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing 2 File Openings - SKIPPED for now due to no file close degree support\n")); +#if 0 + /* Create file access property list */ + fapl_id = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl_id, FAIL, "H5Pcreate"); + + /* Set file close mode to H5F_CLOSE_WEAK */ + ret = H5Pset_fclose_degree(fapl_id, H5F_CLOSE_WEAK); + CHECK(ret, FAIL, "H5Pset_fclose_degree"); + + /* Open file for first time */ + fid1 = H5Fopen(FILE2, H5F_ACC_RDONLY, fapl_id); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Check the intent */ + ret = H5Fget_intent(fid1, &intent); + CHECK(ret, FAIL, "H5Fget_intent"); + VERIFY(intent, H5F_ACC_RDONLY, "H5Fget_intent"); + + /* Open dataset */ + did = H5Dopen2(fid1, F2_DSET, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen2"); + + /* Check that the intent works even if NULL is passed in */ + ret = H5Fget_intent(fid1, NULL); + CHECK(ret, FAIL, "H5Fget_intent"); + + /* Close first open */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Open file for second time, which should fail. */ + H5E_BEGIN_TRY + { + fid2 = H5Fopen(FILE2, H5F_ACC_RDWR, fapl_id); + } + H5E_END_TRY; + VERIFY(fid2, FAIL, "H5Fopen"); + + /* Check that the intent fails for an invalid ID */ + H5E_BEGIN_TRY + { + ret = H5Fget_intent(fid1, &intent); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Fget_intent"); + + /* Close dataset from first open */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Pclose(fapl_id); + CHECK(ret, FAIL, "H5Pclose"); +#endif +} /* test_file_open() */ + +/**************************************************************** +** +** test_file_reopen(): File reopen test routine. +** +****************************************************************/ +static void +test_file_reopen(void) +{ + hid_t fid = -1; /* file ID from initial open */ + hid_t rfid = -1; /* file ID from reopen */ + hid_t did = -1; /* dataset ID (both opens) */ + hid_t sid = -1; /* dataspace ID for dataset creation */ + hsize_t dims = 6; /* dataspace size */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing File Re-opening\n")); + + /* Create file via first ID */ + fid = H5Fcreate(REOPEN_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK_I(fid, "H5Fcreate"); + + /* Create a dataset in the file */ + sid = H5Screate_simple(1, &dims, &dims); + CHECK_I(sid, "H5Screate_simple") + did = H5Dcreate2(fid, REOPEN_DSET, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK_I(did, "H5Dcreate2"); + + /* Close dataset and dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* Reopen the file with a different file ID */ + rfid = H5Freopen(fid); + CHECK_I(rfid, "H5Freopen"); + + /* Reopen the dataset through the reopen file ID */ + did = H5Dopen2(rfid, REOPEN_DSET, H5P_DEFAULT); + CHECK_I(did, "H5Dopen2"); + + /* Close and clean up */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + ret = H5Fclose(rfid); + CHECK(ret, FAIL, "H5Fclose"); + H5Fdelete(REOPEN_FILE, H5P_DEFAULT); + +} /* test_file_reopen() */ + +/**************************************************************** +** +** test_file_close(): low-level file close test routine. +** It mainly tests behavior with close degree. +** +*****************************************************************/ +static void +test_file_close(void) +{ +#if 0 + hid_t fid1, fid2; + hid_t fapl_id, access_id; + hid_t dataset_id, group_id1, group_id2, group_id3; + H5F_close_degree_t fc_degree; + herr_t ret; +#endif + + /* Output message about test being performed */ + MESSAGE(5, ("Testing File Closing with file close degrees - SKIPPED for now due to no file close degree " + "support\n")); +#if 0 + /* Test behavior while opening file multiple times with different + * file close degree value + */ + fid1 = H5Fcreate(FILE1, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + fapl_id = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl_id, FAIL, "H5Pcreate"); + + ret = H5Pset_fclose_degree(fapl_id, H5F_CLOSE_STRONG); + CHECK(ret, FAIL, "H5Pset_fclose_degree"); + + ret = H5Pget_fclose_degree(fapl_id, &fc_degree); + VERIFY(fc_degree, H5F_CLOSE_STRONG, "H5Pget_fclose_degree"); + + /* should fail */ + H5E_BEGIN_TRY + { + fid2 = H5Fopen(FILE1, H5F_ACC_RDWR, fapl_id); + } + H5E_END_TRY; + VERIFY(fid2, FAIL, "H5Fopen"); + + ret = H5Pset_fclose_degree(fapl_id, H5F_CLOSE_DEFAULT); + CHECK(ret, FAIL, "H5Pset_fclose_degree"); + + /* should succeed */ + fid2 = H5Fopen(FILE1, H5F_ACC_RDWR, fapl_id); + CHECK(fid2, FAIL, "H5Fopen"); + + /* Close first open */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Close second open */ + ret = H5Fclose(fid2); + CHECK(ret, FAIL, "H5Fclose"); + + /* Test behavior while opening file multiple times with different file + * close degree + */ + fid1 = H5Fcreate(FILE1, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + ret = H5Pset_fclose_degree(fapl_id, H5F_CLOSE_WEAK); + CHECK(ret, FAIL, "H5Pset_fclose_degree"); + + ret = H5Pget_fclose_degree(fapl_id, &fc_degree); + VERIFY(fc_degree, H5F_CLOSE_WEAK, "H5Pget_fclose_degree"); + + /* should succeed */ + fid2 = H5Fopen(FILE1, H5F_ACC_RDWR, fapl_id); + CHECK(fid2, FAIL, "H5Fopen"); + + /* Close first open */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Close second open */ + ret = H5Fclose(fid2); + CHECK(ret, FAIL, "H5Fclose"); + + /* Test behavior while opening file multiple times with file close + * degree STRONG */ + ret = H5Pset_fclose_degree(fapl_id, H5F_CLOSE_STRONG); + CHECK(ret, FAIL, "H5Pset_fclose_degree"); + + fid1 = H5Fcreate(FILE1, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id); + CHECK(fid1, FAIL, "H5Fcreate"); + + ret = H5Pset_fclose_degree(fapl_id, H5F_CLOSE_WEAK); + CHECK(ret, FAIL, "H5Pset_fclose_degree"); + + /* should fail */ + H5E_BEGIN_TRY + { + fid2 = H5Fopen(FILE1, H5F_ACC_RDWR, fapl_id); + } + H5E_END_TRY; + VERIFY(fid2, FAIL, "H5Fopen"); + + ret = H5Pset_fclose_degree(fapl_id, H5F_CLOSE_STRONG); + CHECK(ret, FAIL, "H5Pset_fclose_degree"); + + /* should succeed */ + fid2 = H5Fopen(FILE1, H5F_ACC_RDWR, fapl_id); + CHECK(fid2, FAIL, "H5Fopen"); + + /* Create a dataset and a group in each file open respectively */ + create_objects(fid1, fid2, NULL, NULL, NULL, NULL); + + /* Close first open */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Close second open */ + ret = H5Fclose(fid2); + CHECK(ret, FAIL, "H5Fclose"); + + /* Test behavior while opening file multiple times with file close + * degree SEMI */ + ret = H5Pset_fclose_degree(fapl_id, H5F_CLOSE_SEMI); + CHECK(ret, FAIL, "H5Pset_fclose_degree"); + + fid1 = H5Fcreate(FILE1, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id); + CHECK(fid1, FAIL, "H5Fcreate"); + + ret = H5Pset_fclose_degree(fapl_id, H5F_CLOSE_DEFAULT); + CHECK(ret, FAIL, "H5Pset_fclose_degree"); + + /* should fail */ + H5E_BEGIN_TRY + { + fid2 = H5Fopen(FILE1, H5F_ACC_RDWR, fapl_id); + } + H5E_END_TRY; + VERIFY(fid2, FAIL, "H5Fopen"); + + ret = H5Pset_fclose_degree(fapl_id, H5F_CLOSE_SEMI); + CHECK(ret, FAIL, "H5Pset_fclose_degree"); + + /* should succeed */ + fid2 = H5Fopen(FILE1, H5F_ACC_RDWR, fapl_id); + CHECK(fid2, FAIL, "H5Fopen"); + + /* Create a dataset and a group in each file open respectively */ + create_objects(fid1, fid2, &dataset_id, &group_id1, &group_id2, &group_id3); + + /* Close first open, should fail since it is SEMI and objects are + * still open. */ + H5E_BEGIN_TRY + { + ret = H5Fclose(fid1); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Fclose"); + + /* Close second open, should fail since it is SEMI and objects are + * still open. */ + H5E_BEGIN_TRY + { + ret = H5Fclose(fid2); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Fclose"); + + ret = H5Dclose(dataset_id); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close first open */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + ret = H5Gclose(group_id1); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Gclose(group_id2); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close second open, should fail since it is SEMI and one group ID is + * still open. */ + H5E_BEGIN_TRY + { + ret = H5Fclose(fid2); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Fclose"); + + /* Same check with H5Idec_ref() (should fail also) */ + H5E_BEGIN_TRY + { + ret = H5Idec_ref(fid2); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Idec_ref"); + + ret = H5Gclose(group_id3); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close second open again. Should succeed. */ + ret = H5Fclose(fid2); + CHECK(ret, FAIL, "H5Fclose"); + + /* Test behavior while opening file multiple times with file close + * degree WEAK */ + ret = H5Pset_fclose_degree(fapl_id, H5F_CLOSE_WEAK); + CHECK(ret, FAIL, "H5Pset_fclose_degree"); + + fid1 = H5Fcreate(FILE1, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id); + CHECK(fid1, FAIL, "H5Fcreate"); + + ret = H5Pset_fclose_degree(fapl_id, H5F_CLOSE_SEMI); + CHECK(ret, FAIL, "H5Pset_fclose_degree"); + + /* should fail */ + H5E_BEGIN_TRY + { + fid2 = H5Fopen(FILE1, H5F_ACC_RDWR, fapl_id); + } + H5E_END_TRY; + VERIFY(fid2, FAIL, "H5Fopen"); + + ret = H5Pset_fclose_degree(fapl_id, H5F_CLOSE_DEFAULT); + CHECK(ret, FAIL, "H5Pset_fclose_degree"); + + /* should succeed */ + fid2 = H5Fopen(FILE1, H5F_ACC_RDWR, fapl_id); + CHECK(fid2, FAIL, "H5Fopen"); + + /* Create a dataset and a group in each file open respectively */ + create_objects(fid1, fid2, &dataset_id, &group_id1, &group_id2, &group_id3); + + /* Create more new files and test object count and ID list functions */ + test_obj_count_and_id(fid1, fid2, dataset_id, group_id1, group_id2, group_id3); + + /* Close first open */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Close second open. File will be finally closed after all objects + * are closed. */ + ret = H5Fclose(fid2); + CHECK(ret, FAIL, "H5Fclose"); + + ret = H5Dclose(dataset_id); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Gclose(group_id1); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Gclose(group_id2); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Gclose(group_id3); + CHECK(ret, FAIL, "H5Gclose"); + + /* Test behavior while opening file multiple times with file close + * degree DEFAULT */ + ret = H5Pset_fclose_degree(fapl_id, H5F_CLOSE_DEFAULT); + CHECK(ret, FAIL, "H5Pset_fclose_degree"); + + fid1 = H5Fcreate(FILE1, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id); + CHECK(fid1, FAIL, "H5Fcreate"); + + ret = H5Pset_fclose_degree(fapl_id, H5F_CLOSE_SEMI); + CHECK(ret, FAIL, "H5Pset_fclose_degree"); + + /* should fail */ + H5E_BEGIN_TRY + { + fid2 = H5Fopen(FILE1, H5F_ACC_RDWR, fapl_id); + } + H5E_END_TRY; + VERIFY(fid2, FAIL, "H5Fopen"); + + ret = H5Pset_fclose_degree(fapl_id, H5F_CLOSE_DEFAULT); + CHECK(ret, FAIL, "H5Pset_fclose_degree"); + + /* should succeed */ + fid2 = H5Fopen(FILE1, H5F_ACC_RDWR, fapl_id); + CHECK(fid2, FAIL, "H5Fopen"); + + /* Create a dataset and a group in each file open respectively */ + create_objects(fid1, fid2, &dataset_id, &group_id1, &group_id2, &group_id3); + + access_id = H5Fget_access_plist(fid1); + CHECK(access_id, FAIL, "H5Fget_access_plist"); + + ret = H5Pget_fclose_degree(access_id, &fc_degree); + CHECK(ret, FAIL, "H5Pget_fclose_degree"); + + switch (fc_degree) { + case H5F_CLOSE_STRONG: + /* Close first open */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + /* Close second open */ + ret = H5Fclose(fid2); + CHECK(ret, FAIL, "H5Fclose"); + break; + case H5F_CLOSE_SEMI: + /* Close first open */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + ret = H5Dclose(dataset_id); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Gclose(group_id1); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Gclose(group_id2); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Gclose(group_id3); + CHECK(ret, FAIL, "H5Gclose"); + /* Close second open */ + ret = H5Fclose(fid2); + CHECK(ret, FAIL, "H5Fclose"); + break; + case H5F_CLOSE_WEAK: + /* Close first open */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + /* Close second open */ + ret = H5Fclose(fid2); + CHECK(ret, FAIL, "H5Fclose"); + ret = H5Dclose(dataset_id); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Gclose(group_id1); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Gclose(group_id2); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Gclose(group_id3); + CHECK(ret, FAIL, "H5Gclose"); + break; + case H5F_CLOSE_DEFAULT: + default: + CHECK(fc_degree, H5F_CLOSE_DEFAULT, "H5Pget_fclose_degree"); + break; + } + + /* Close file access property list */ + ret = H5Pclose(fapl_id); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(access_id); + CHECK(ret, FAIL, "H5Pclose"); +#endif +} + +/**************************************************************** +** +** create_objects(): routine called by test_file_close to create +** a dataset and a group in file. +** +****************************************************************/ +#if 0 +static void +create_objects(hid_t fid1, hid_t fid2, hid_t *ret_did, hid_t *ret_gid1, hid_t *ret_gid2, hid_t *ret_gid3) +{ + ssize_t oid_count; + herr_t ret; + + /* Check reference counts of file IDs and opened object IDs. + * The verification is hard-coded. If in any case, this testing + * is changed, remember to check this part and update the macros. + */ + { + oid_count = H5Fget_obj_count(fid1, H5F_OBJ_ALL); + CHECK(oid_count, FAIL, "H5Fget_obj_count"); + VERIFY(oid_count, OBJ_ID_COUNT_2, "H5Fget_obj_count"); + + oid_count = H5Fget_obj_count(fid1, H5F_OBJ_DATASET | H5F_OBJ_GROUP | H5F_OBJ_DATATYPE | H5F_OBJ_ATTR); + CHECK(oid_count, FAIL, "H5Fget_obj_count"); + VERIFY(oid_count, OBJ_ID_COUNT_0, "H5Fget_obj_count"); + + oid_count = H5Fget_obj_count(fid2, H5F_OBJ_ALL); + CHECK(oid_count, FAIL, "H5Fget_obj_count"); + VERIFY(oid_count, OBJ_ID_COUNT_2, "H5Fget_obj_count"); + + oid_count = H5Fget_obj_count(fid2, H5F_OBJ_DATASET | H5F_OBJ_GROUP | H5F_OBJ_DATATYPE | H5F_OBJ_ATTR); + CHECK(oid_count, FAIL, "H5Fget_obj_count"); + VERIFY(oid_count, OBJ_ID_COUNT_0, "H5Fget_obj_count"); + } + + /* create a dataset in the first file open */ + { + hid_t dataset_id, dataspace_id; /* identifiers */ + hsize_t dims[F2_RANK]; + unsigned data[F2_DIM0][F2_DIM1]; + unsigned i, j; + + /* Create the data space for the dataset. */ + dims[0] = F2_DIM0; + dims[1] = F2_DIM1; + dataspace_id = H5Screate_simple(F2_RANK, dims, NULL); + CHECK(dataspace_id, FAIL, "H5Screate_simple"); + + /* Create the dataset. */ + dataset_id = + H5Dcreate2(fid1, "/dset", H5T_NATIVE_UINT, dataspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset_id, FAIL, "H5Dcreate2"); + + for (i = 0; i < F2_DIM0; i++) + for (j = 0; j < F2_DIM1; j++) + data[i][j] = i * 10 + j; + + /* Write data to the new dataset */ + ret = H5Dwrite(dataset_id, H5T_NATIVE_UINT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data); + CHECK(ret, FAIL, "H5Dwrite"); + + if (ret_did != NULL) + *ret_did = dataset_id; + + /* Terminate access to the data space. */ + ret = H5Sclose(dataspace_id); + CHECK(ret, FAIL, "H5Sclose"); + } + + /* Create a group in the second file open */ + { + hid_t gid1, gid2, gid3; + gid1 = H5Gcreate2(fid2, "/group", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid1, FAIL, "H5Gcreate2"); + if (ret_gid1 != NULL) + *ret_gid1 = gid1; + + gid2 = H5Gopen2(fid2, "/group", H5P_DEFAULT); + CHECK(gid2, FAIL, "H5Gopen2"); + if (ret_gid2 != NULL) + *ret_gid2 = gid2; + + gid3 = H5Gopen2(fid2, "/group", H5P_DEFAULT); + CHECK(gid3, FAIL, "H5Gopen2"); + if (ret_gid3 != NULL) + *ret_gid3 = gid3; + } + + /* Check reference counts of file IDs and opened object IDs. + * The verification is hard-coded. If in any case, this testing + * is changed, remember to check this part and update the macros. + */ + { + oid_count = H5Fget_obj_count(fid1, H5F_OBJ_ALL); + CHECK(oid_count, FAIL, "H5Fget_obj_count"); + VERIFY(oid_count, OBJ_ID_COUNT_6, "H5Fget_obj_count"); + + oid_count = H5Fget_obj_count(fid1, H5F_OBJ_DATASET | H5F_OBJ_GROUP | H5F_OBJ_DATATYPE | H5F_OBJ_ATTR); + CHECK(oid_count, FAIL, "H5Fget_obj_count"); + VERIFY(oid_count, OBJ_ID_COUNT_4, "H5Fget_obj_count"); + + oid_count = H5Fget_obj_count(fid2, H5F_OBJ_ALL); + CHECK(oid_count, FAIL, "H5Fget_obj_count"); + VERIFY(oid_count, OBJ_ID_COUNT_6, "H5Fget_obj_count"); + + oid_count = H5Fget_obj_count(fid2, H5F_OBJ_DATASET | H5F_OBJ_GROUP | H5F_OBJ_DATATYPE | H5F_OBJ_ATTR); + CHECK(oid_count, FAIL, "H5Fget_obj_count"); + VERIFY(oid_count, OBJ_ID_COUNT_4, "H5Fget_obj_count"); + } +} +#endif + +/**************************************************************** +** +** test_get_obj_ids(): Test the bug and the fix for Jira 8528. +** H5Fget_obj_ids overfilled the list of +** object IDs by one. This is an enhancement +** for test_obj_count_and_id(). +** +****************************************************************/ +static void +test_get_obj_ids(void) +{ + hid_t fid, gid[NGROUPS], dset[NDSETS]; + hid_t filespace; + hsize_t file_dims[F2_RANK] = {F2_DIM0, F2_DIM1}; + ssize_t oid_count, ret_count; + hid_t *oid_list = NULL; + herr_t ret; + int i, m, n; + ssize_t oid_list_size = NDSETS; + char gname[64], dname[64]; + + MESSAGE(5, ("Testing retrieval of object IDs\n")); + + /* Create a new file */ + fid = H5Fcreate(FILE7, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + filespace = H5Screate_simple(F2_RANK, file_dims, NULL); + CHECK(filespace, FAIL, "H5Screate_simple"); + + /* creates NGROUPS groups under the root group */ + for (m = 0; m < NGROUPS; m++) { + HDsnprintf(gname, sizeof(gname), "group%d", m); + gid[m] = H5Gcreate2(fid, gname, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid[m], FAIL, "H5Gcreate2"); + } + + /* create NDSETS datasets under the root group */ + for (n = 0; n < NDSETS; n++) { + HDsnprintf(dname, sizeof(dname), "dataset%d", n); + dset[n] = H5Dcreate2(fid, dname, H5T_NATIVE_INT, filespace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dset[n], FAIL, "H5Dcreate2"); + } + + /* The number of opened objects should be NGROUPS + NDSETS + 1. One is opened file. */ + oid_count = H5Fget_obj_count(fid, H5F_OBJ_ALL); + CHECK(oid_count, FAIL, "H5Fget_obj_count"); + VERIFY(oid_count, (NGROUPS + NDSETS + 1), "H5Fget_obj_count"); + + oid_list = (hid_t *)HDcalloc((size_t)oid_list_size, sizeof(hid_t)); + CHECK_PTR(oid_list, "HDcalloc"); + + /* Call the public function H5F_get_obj_ids to use H5F__get_objects. User reported having problem here. + * that the returned size (ret_count) from H5Fget_obj_ids is one greater than the size passed in + * (oid_list_size) */ + ret_count = H5Fget_obj_ids(fid, H5F_OBJ_ALL, (size_t)oid_list_size, oid_list); + CHECK(ret_count, FAIL, "H5Fget_obj_ids"); + VERIFY(ret_count, oid_list_size, "H5Fget_obj_count"); + + /* Close all object IDs on the list except the file ID. The first ID is supposed to be file ID according + * to the library design */ + for (i = 0; i < ret_count; i++) { + if (fid != oid_list[i]) { + ret = H5Oclose(oid_list[i]); + CHECK(ret, FAIL, "H5Oclose"); + } + } + + /* The number of opened objects should be NGROUPS + 1 + 1. The first one is opened file. The second one + * is the dataset ID left open from the previous around of H5Fget_obj_ids */ + oid_count = H5Fget_obj_count(fid, H5F_OBJ_ALL); + CHECK(oid_count, FAIL, "H5Fget_obj_count"); + VERIFY(oid_count, NGROUPS + 2, "H5Fget_obj_count"); + + /* Get the IDs of the left opened objects */ + ret_count = H5Fget_obj_ids(fid, H5F_OBJ_ALL, (size_t)oid_list_size, oid_list); + CHECK(ret_count, FAIL, "H5Fget_obj_ids"); + VERIFY(ret_count, oid_list_size, "H5Fget_obj_count"); + + /* Close all object IDs on the list except the file ID. The first ID is still the file ID */ + for (i = 0; i < ret_count; i++) { + if (fid != oid_list[i]) { + ret = H5Oclose(oid_list[i]); + CHECK(ret, FAIL, "H5Oclose"); + } + } + + H5Sclose(filespace); + H5Fclose(fid); + + HDfree(oid_list); + + /* Reopen the file to check whether H5Fget_obj_count and H5Fget_obj_ids still works + * when the file is closed first */ + fid = H5Fopen(FILE7, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* Open NDSETS datasets under the root group */ + for (n = 0; n < NDSETS; n++) { + HDsnprintf(dname, sizeof(dname), "dataset%d", n); + dset[n] = H5Dopen2(fid, dname, H5P_DEFAULT); + CHECK(dset[n], FAIL, "H5Dcreate2"); + } + + /* Close the file first */ + H5Fclose(fid); +#ifndef WRONG_DATATYPE_OBJ_COUNT + /* Get the number of all opened objects */ + oid_count = H5Fget_obj_count((hid_t)H5F_OBJ_ALL, H5F_OBJ_ALL); + CHECK(oid_count, FAIL, "H5Fget_obj_count"); + VERIFY(oid_count, NDSETS, "H5Fget_obj_count"); + + oid_list = (hid_t *)HDcalloc((size_t)oid_count, sizeof(hid_t)); + CHECK_PTR(oid_list, "HDcalloc"); + + /* Get the list of all opened objects */ + ret_count = H5Fget_obj_ids((hid_t)H5F_OBJ_ALL, H5F_OBJ_ALL, (size_t)oid_count, oid_list); + CHECK(ret_count, FAIL, "H5Fget_obj_ids"); + VERIFY(ret_count, NDSETS, "H5Fget_obj_ids"); + + H5E_BEGIN_TRY + { + /* Close all open objects with H5Oclose */ + for (n = 0; n < oid_count; n++) + H5Oclose(oid_list[n]); + } + H5E_END_TRY; + + HDfree(oid_list); +#endif +} + +/**************************************************************** +** +** test_get_file_id(): Test H5Iget_file_id() +** +*****************************************************************/ +static void +test_get_file_id(void) +{ +#if 0 + hid_t fid, fid2, fid3; + hid_t datatype_id, dataset_id, dataspace_id, group_id, attr_id; + hid_t plist; + hsize_t dims[F2_RANK]; + unsigned intent; + herr_t ret; +#endif + + MESSAGE(5, ("Testing H5Iget_file_id - SKIPPED for now due to no H5Iget_file_id support\n")); +#if 0 + /* Create a file */ + fid = H5Fcreate(FILE4, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Check the intent */ + ret = H5Fget_intent(fid, &intent); + CHECK(ret, FAIL, "H5Fget_intent"); + VERIFY(intent, H5F_ACC_RDWR, "H5Fget_intent"); + + /* Test H5Iget_file_id() */ + check_file_id(fid, fid); + + /* Create a group in the file. Make a duplicated file ID from the group. + * And close this duplicated ID + */ + group_id = H5Gcreate2(fid, GRP_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(group_id, FAIL, "H5Gcreate2"); + + /* Test H5Iget_file_id() */ + check_file_id(fid, group_id); + + /* Close the file and get file ID from the group ID */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Test H5Iget_file_id() */ + check_file_id((hid_t)-1, group_id); + + ret = H5Gclose(group_id); + CHECK(ret, FAIL, "H5Gclose"); + + /* Open the file again. Test H5Iget_file_id() */ + fid = H5Fopen(FILE4, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + group_id = H5Gopen2(fid, GRP_NAME, H5P_DEFAULT); + CHECK(group_id, FAIL, "H5Gopen2"); + + /* Test H5Iget_file_id() */ + check_file_id(fid, group_id); + + /* Open the file for second time. Test H5Iget_file_id() */ + fid3 = H5Freopen(fid); + CHECK(fid3, FAIL, "H5Freopen"); + + /* Test H5Iget_file_id() */ + check_file_id(fid3, fid3); + + ret = H5Fclose(fid3); + CHECK(ret, FAIL, "H5Fclose"); + + /* Create a dataset in the group. Make a duplicated file ID from the + * dataset. And close this duplicated ID. + */ + dims[0] = F2_DIM0; + dims[1] = F2_DIM1; + dataspace_id = H5Screate_simple(F2_RANK, dims, NULL); + CHECK(dataspace_id, FAIL, "H5Screate_simple"); + + dataset_id = + H5Dcreate2(group_id, DSET_NAME, H5T_NATIVE_INT, dataspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset_id, FAIL, "H5Dcreate2"); + + /* Test H5Iget_file_id() */ + check_file_id(fid, dataset_id); + + /* Create an attribute for the dataset. Make a duplicated file ID from + * this attribute. And close it. + */ + attr_id = H5Acreate2(dataset_id, ATTR_NAME, H5T_NATIVE_INT, dataspace_id, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Acreate2"); + + /* Test H5Iget_file_id() */ + check_file_id(fid, attr_id); + + /* Create a named datatype. Make a duplicated file ID from + * this attribute. And close it. + */ + datatype_id = H5Tcopy(H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tcopy"); + + ret = H5Tcommit2(fid, TYPE_NAME, datatype_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + + /* Test H5Iget_file_id() */ + check_file_id(fid, datatype_id); + + /* Create a property list and try to get file ID from it. + * Supposed to fail. + */ + plist = H5Pcreate(H5P_FILE_ACCESS); + CHECK(plist, FAIL, "H5Pcreate"); + + H5E_BEGIN_TRY + { + fid2 = H5Iget_file_id(plist); + } + H5E_END_TRY; + VERIFY(fid2, FAIL, "H5Iget_file_id"); + + /* Close objects */ + ret = H5Pclose(plist); + CHECK(ret, FAIL, "H5Pclose"); + + ret = H5Tclose(datatype_id); + CHECK(ret, FAIL, "H5Tclose"); + + ret = H5Aclose(attr_id); + CHECK(ret, FAIL, "H5Aclose"); + + ret = H5Sclose(dataspace_id); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Dclose(dataset_id); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Gclose(group_id); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +#endif +} + +/**************************************************************** +** +** check_file_id(): Internal function of test_get_file_id() +** +*****************************************************************/ +#if 0 +static void +check_file_id(hid_t fid, hid_t object_id) +{ + hid_t new_fid; + herr_t ret; + + /* Return a duplicated file ID even not expecting user to do it. + * And close this duplicated ID + */ + new_fid = H5Iget_file_id(object_id); + + if (fid >= 0) + VERIFY(new_fid, fid, "H5Iget_file_id"); + else + CHECK(new_fid, FAIL, "H5Iget_file_id"); + + ret = H5Fclose(new_fid); + CHECK(ret, FAIL, "H5Fclose"); +} +#endif + +/**************************************************************** +** +** test_obj_count_and_id(): test object count and ID list functions. +** +****************************************************************/ +#if 0 +static void +test_obj_count_and_id(hid_t fid1, hid_t fid2, hid_t did, hid_t gid1, hid_t gid2, hid_t gid3) +{ + hid_t fid3, fid4; + ssize_t oid_count, ret_count; + herr_t ret; + + /* Create two new files */ + fid3 = H5Fcreate(FILE2, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid3, FAIL, "H5Fcreate"); + fid4 = H5Fcreate(FILE3, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid4, FAIL, "H5Fcreate"); + + /* test object count of all files IDs open */ + oid_count = H5Fget_obj_count((hid_t)H5F_OBJ_ALL, H5F_OBJ_FILE); + CHECK(oid_count, FAIL, "H5Fget_obj_count"); + VERIFY(oid_count, OBJ_ID_COUNT_4, "H5Fget_obj_count"); + + /* test object count of all datasets open */ + oid_count = H5Fget_obj_count((hid_t)H5F_OBJ_ALL, H5F_OBJ_DATASET); + CHECK(oid_count, FAIL, "H5Fget_obj_count"); + VERIFY(oid_count, OBJ_ID_COUNT_1, "H5Fget_obj_count"); + + /* test object count of all groups open */ + oid_count = H5Fget_obj_count((hid_t)H5F_OBJ_ALL, H5F_OBJ_GROUP); + CHECK(oid_count, FAIL, "H5Fget_obj_count"); + VERIFY(oid_count, OBJ_ID_COUNT_3, "H5Fget_obj_count"); + + /* test object count of all named datatypes open */ + oid_count = H5Fget_obj_count((hid_t)H5F_OBJ_ALL, H5F_OBJ_DATATYPE); + CHECK(oid_count, FAIL, "H5Fget_obj_count"); + VERIFY(oid_count, OBJ_ID_COUNT_0, "H5Fget_obj_count"); + + /* test object count of all attributes open */ + oid_count = H5Fget_obj_count((hid_t)H5F_OBJ_ALL, H5F_OBJ_ATTR); + CHECK(oid_count, FAIL, "H5Fget_obj_count"); + VERIFY(oid_count, OBJ_ID_COUNT_0, "H5Fget_obj_count"); + + /* test object count of all objects currently open */ + oid_count = H5Fget_obj_count((hid_t)H5F_OBJ_ALL, H5F_OBJ_ALL); + CHECK(oid_count, FAIL, "H5Fget_obj_count"); + VERIFY(oid_count, OBJ_ID_COUNT_8, "H5Fget_obj_count"); + + if (oid_count > 0) { + hid_t *oid_list; + + oid_list = (hid_t *)HDcalloc((size_t)oid_count, sizeof(hid_t)); + if (oid_list != NULL) { + int i; + + ret_count = H5Fget_obj_ids((hid_t)H5F_OBJ_ALL, H5F_OBJ_ALL, (size_t)oid_count, oid_list); + CHECK(ret_count, FAIL, "H5Fget_obj_ids"); + + for (i = 0; i < oid_count; i++) { + H5I_type_t id_type; + + id_type = H5Iget_type(oid_list[i]); + switch (id_type) { + case H5I_FILE: + if (oid_list[i] != fid1 && oid_list[i] != fid2 && oid_list[i] != fid3 && + oid_list[i] != fid4) + ERROR("H5Fget_obj_ids"); + break; + + case H5I_GROUP: + if (oid_list[i] != gid1 && oid_list[i] != gid2 && oid_list[i] != gid3) + ERROR("H5Fget_obj_ids"); + break; + + case H5I_DATASET: + VERIFY(oid_list[i], did, "H5Fget_obj_ids"); + break; + + case H5I_MAP: + /* TODO: Not supported in native VOL connector yet */ + + case H5I_UNINIT: + case H5I_BADID: + case H5I_DATATYPE: + case H5I_DATASPACE: + case H5I_ATTR: + case H5I_VFL: + case H5I_VOL: + case H5I_GENPROP_CLS: + case H5I_GENPROP_LST: + case H5I_ERROR_CLASS: + case H5I_ERROR_MSG: + case H5I_ERROR_STACK: + case H5I_SPACE_SEL_ITER: + case H5I_EVENTSET: + case H5I_NTYPES: + default: + ERROR("H5Fget_obj_ids"); + } /* end switch */ + } /* end for */ + + HDfree(oid_list); + } /* end if */ + } /* end if */ + + /* close the two new files */ + ret = H5Fclose(fid3); + CHECK(ret, FAIL, "H5Fclose"); + ret = H5Fclose(fid4); + CHECK(ret, FAIL, "H5Fclose"); +} +#endif + +/**************************************************************** +** +** test_file_perm(): low-level file test routine. +** This test verifies that a file can be opened for both +** read-only and read-write access and things will be handled +** appropriately. +** +*****************************************************************/ +static void +test_file_perm(void) +{ + hid_t file; /* File opened with read-write permission */ + hid_t filero; /* Same file opened with read-only permission */ + hid_t dspace; /* Dataspace ID */ + hid_t dset; /* Dataset ID */ + herr_t ret; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Low-Level File Permissions\n")); + + dspace = H5Screate(H5S_SCALAR); + CHECK(dspace, FAIL, "H5Screate"); + + /* Create the file (with read-write permission) */ + file = H5Fcreate(FILE2, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file, FAIL, "H5Fcreate"); + + /* Create a dataset with the read-write file handle */ + dset = H5Dcreate2(file, F2_DSET, H5T_NATIVE_INT, dspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dset, FAIL, "H5Dcreate2"); + + ret = H5Dclose(dset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Open the file (with read-only permission) */ + filero = H5Fopen(FILE2, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(filero, FAIL, "H5Fopen"); + + /* Create a dataset with the read-only file handle (should fail) */ + H5E_BEGIN_TRY + { + dset = H5Dcreate2(filero, F2_DSET, H5T_NATIVE_INT, dspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(dset, FAIL, "H5Dcreate2"); + if (dset != FAIL) { + ret = H5Dclose(dset); + CHECK(ret, FAIL, "H5Dclose"); + } /* end if */ + + ret = H5Fclose(filero); + CHECK(ret, FAIL, "H5Fclose"); + + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + + ret = H5Sclose(dspace); + CHECK(ret, FAIL, "H5Sclose"); + +} /* end test_file_perm() */ + +/**************************************************************** +** +** test_file_perm2(): low-level file test routine. +** This test verifies that no object can be created in a +** file that is opened for read-only. +** +*****************************************************************/ +static void +test_file_perm2(void) +{ + hid_t file; /* File opened with read-write permission */ + hid_t filero; /* Same file opened with read-only permission */ + hid_t dspace; /* Dataspace ID */ + hid_t group; /* Group ID */ + hid_t dset; /* Dataset ID */ + hid_t type; /* Datatype ID */ + hid_t attr; /* Attribute ID */ + herr_t ret; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Low-Level File Permissions again\n")); + + dspace = H5Screate(H5S_SCALAR); + CHECK(dspace, FAIL, "H5Screate"); + + /* Create the file (with read-write permission) */ + file = H5Fcreate(FILE2, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file, FAIL, "H5Fcreate"); + + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + + /* Open the file (with read-only permission) */ + filero = H5Fopen(FILE2, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(filero, FAIL, "H5Fopen"); + + /* Create a group with the read-only file handle (should fail) */ + H5E_BEGIN_TRY + { + group = H5Gcreate2(filero, "MY_GROUP", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(group, FAIL, "H5Gcreate2"); + + /* Create a dataset with the read-only file handle (should fail) */ + H5E_BEGIN_TRY + { + dset = H5Dcreate2(filero, F2_DSET, H5T_NATIVE_INT, dspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(dset, FAIL, "H5Dcreate2"); + + /* Create an attribute with the read-only file handle (should fail) */ + H5E_BEGIN_TRY + { + attr = H5Acreate2(filero, "MY_ATTR", H5T_NATIVE_INT, dspace, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(attr, FAIL, "H5Acreate2"); + + type = H5Tcopy(H5T_NATIVE_SHORT); + CHECK(type, FAIL, "H5Tcopy"); + + /* Commit a datatype with the read-only file handle (should fail) */ + H5E_BEGIN_TRY + { + ret = H5Tcommit2(filero, "MY_DTYPE", type, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Tcommit2"); + + ret = H5Tclose(type); + CHECK(ret, FAIL, "H5Tclose"); + + ret = H5Fclose(filero); + CHECK(ret, FAIL, "H5Fclose"); + + ret = H5Sclose(dspace); + CHECK(ret, FAIL, "H5Sclose"); +} /* end test_file_perm2() */ + +/**************************************************************** +** +** test_file_is_accessible(): low-level file test routine. +** Clone of test_file_ishdf5 but uses the newer VOL-enabled +** H5Fis_accessible() API call. +** +*****************************************************************/ +#define FILE_IS_ACCESSIBLE "tfile_is_accessible" +#define FILE_IS_ACCESSIBLE_NON_HDF5 "tfile_is_accessible_non_hdf5" +static void +test_file_is_accessible(const char *env_h5_drvr) +{ + hid_t fid = H5I_INVALID_HID; /* File opened with read-write permission */ + hid_t fcpl_id = H5I_INVALID_HID; /* File creation property list */ + hid_t fapl_id = H5I_INVALID_HID; /* File access property list */ +#if 0 + int fd; /* POSIX file descriptor */ +#endif + char filename[FILENAME_LEN]; /* Filename to use */ + char non_hdf5_filename[FILENAME_LEN]; /* Base name of non-hdf5 file */ + char non_hdf5_sb_filename[FILENAME_LEN]; /* Name of non-hdf5 superblock file */ +#if 0 + ssize_t nbytes; /* Number of bytes written */ + unsigned u; /* Local index variable */ + unsigned char buf[1024]; /* Buffer of data to write */ +#endif + htri_t is_hdf5; /* Whether a file is an HDF5 file */ +#if 0 + int posix_ret; /* Return value from POSIX calls */ +#endif + hbool_t driver_is_default_compatible; + herr_t ret; /* Return value from HDF5 calls */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Detection of HDF5 Files\n")); + + /* Get FAPL */ + fapl_id = h5_fileaccess(); + CHECK(fapl_id, H5I_INVALID_HID, "H5Pcreate"); + + if (h5_driver_is_default_vfd_compatible(fapl_id, &driver_is_default_compatible) < 0) { + TestErrPrintf("Can't check if VFD is compatible with default VFD"); + return; + } + + /* Fix up filenames */ + h5_fixname(FILE_IS_ACCESSIBLE, fapl_id, filename, sizeof(filename)); + h5_fixname(FILE_IS_ACCESSIBLE_NON_HDF5, fapl_id, non_hdf5_filename, sizeof(non_hdf5_filename)); + h5_fixname_superblock(FILE_IS_ACCESSIBLE_NON_HDF5, fapl_id, non_hdf5_sb_filename, + sizeof(non_hdf5_sb_filename)); + + /****************/ + /* Normal usage */ + /****************/ + + /* Create a file */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id); + CHECK(fid, H5I_INVALID_HID, "H5Fcreate"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Verify that the file is an HDF5 file */ + is_hdf5 = H5Fis_accessible(filename, fapl_id); + VERIFY(is_hdf5, TRUE, "H5Fis_accessible"); + + /*****************************************/ + /* Newly created file that is still open */ + /*****************************************/ + + /* On Windows, file locking is mandatory so this check ensures that + * H5Fis_accessible() works on files that have an exclusive lock. + * Previous versions of this API call created an additional file handle + * and attempted to read through it, which will not work when locks + * are enforced by the OS. + */ + + /* Create a file and hold it open */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id); + CHECK(fid, H5I_INVALID_HID, "H5Fcreate"); + + /* Verify that the file is an HDF5 file */ + is_hdf5 = H5Fis_accessible(filename, fapl_id); + VERIFY(is_hdf5, TRUE, "H5Fis_accessible"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /*******************************/ + /* Non-default user block size */ + /*******************************/ + + /* This test is not currently working for the family VFD. + * There are failures when creating files with userblocks. + */ + if (0 != HDstrcmp(env_h5_drvr, "family")) { + /* Create a file creation property list with a non-default user block size */ + fcpl_id = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl_id, H5I_INVALID_HID, "H5Pcreate"); + + ret = H5Pset_userblock(fcpl_id, (hsize_t)2048); + CHECK(ret, FAIL, "H5Pset_userblock"); + + /* Create file with non-default user block */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl_id, fapl_id); + CHECK(fid, H5I_INVALID_HID, "H5Fcreate"); + + /* Release file-creation property list */ + ret = H5Pclose(fcpl_id); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Verify that the file is an HDF5 file */ + is_hdf5 = H5Fis_accessible(filename, fapl_id); + VERIFY(is_hdf5, TRUE, "H5Fis_accessible"); + } /* end if */ +#if 0 + if (driver_is_default_compatible) { + /***********************/ + /* EMPTY non-HDF5 file */ + /***********************/ + + /* Create non-HDF5 file and check it */ + fd = HDopen(non_hdf5_sb_filename, O_RDWR | O_CREAT | O_TRUNC, H5_POSIX_CREATE_MODE_RW); + CHECK(fd, (-1), "HDopen"); + + /* Close the file */ + posix_ret = HDclose(fd); + CHECK(posix_ret, (-1), "HDclose"); + + /* Verify that the file is NOT an HDF5 file using the base filename */ + is_hdf5 = H5Fis_accessible(non_hdf5_filename, fapl_id); + VERIFY(is_hdf5, FALSE, "H5Fis_accessible (empty non-HDF5 file)"); + + /***************************/ + /* Non-empty non-HDF5 file */ + /***************************/ + + /* Create non-HDF5 file and check it */ + fd = HDopen(non_hdf5_sb_filename, O_RDWR | O_CREAT | O_TRUNC, H5_POSIX_CREATE_MODE_RW); + CHECK(fd, (-1), "HDopen"); + + /* Initialize information to write */ + for (u = 0; u < 1024; u++) + buf[u] = (unsigned char)u; + + /* Write some information */ + nbytes = HDwrite(fd, buf, (size_t)1024); + VERIFY(nbytes, 1024, "HDwrite"); + + /* Close the file */ + posix_ret = HDclose(fd); + CHECK(posix_ret, (-1), "HDclose"); + + /* Verify that the file is not an HDF5 file */ + is_hdf5 = H5Fis_accessible(non_hdf5_filename, fapl_id); + VERIFY(is_hdf5, FALSE, "H5Fis_accessible (non-HDF5 file)"); + } + + /* Clean up files */ + h5_delete_test_file(filename, fapl_id); + h5_delete_test_file(non_hdf5_filename, fapl_id); +#endif + H5Fdelete(filename, fapl_id); + + /* Close property list */ + ret = H5Pclose(fapl_id); + CHECK(ret, FAIL, "H5Pclose"); + +} /* end test_file_is_accessible() */ + +/**************************************************************** +** +** test_file_ishdf5(): low-level file test routine. +** This test checks whether the H5Fis_hdf5() routine is working +** correctly in various situations. +** +*****************************************************************/ +#if 0 +#ifndef H5_NO_DEPRECATED_SYMBOLS +static void +test_file_ishdf5(const char *env_h5_drvr) +{ + hid_t fid = H5I_INVALID_HID; /* File opened with read-write permission */ + hid_t fcpl_id = H5I_INVALID_HID; /* File creation property list */ + hid_t fapl_id = H5I_INVALID_HID; /* File access property list */ + int fd; /* POSIX file descriptor */ + char filename[FILENAME_LEN]; /* Filename to use */ + char sb_filename[FILENAME_LEN]; /* Name of file w/ superblock */ + ssize_t nbytes; /* Number of bytes written */ + unsigned u; /* Local index variable */ + unsigned char buf[1024]; /* Buffer of data to write */ + htri_t is_hdf5; /* Whether a file is an HDF5 file */ + int posix_ret; /* Return value from POSIX calls */ + herr_t ret; /* Return value from HDF5 calls */ + + if (!h5_using_default_driver(env_h5_drvr)) + return; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Detection of HDF5 Files (using deprecated H5Fis_hdf5() call)\n")); + + /* Get FAPL */ + fapl_id = h5_fileaccess(); + CHECK(fapl_id, H5I_INVALID_HID, "H5Pcreate"); + + /* Fix up filenames + * For VFDs that create multiple files, we also need the name + * of the file with the superblock. With single-file VFDs, this + * will be equal to the one from h5_fixname(). + */ + h5_fixname(FILE_IS_ACCESSIBLE, fapl_id, filename, sizeof(filename)); + h5_fixname_superblock(FILE_IS_ACCESSIBLE, fapl_id, sb_filename, sizeof(filename)); + + /****************/ + /* Normal usage */ + /****************/ + + /* Create a file */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id); + CHECK(fid, H5I_INVALID_HID, "H5Fcreate"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Verify that the file is an HDF5 file */ + is_hdf5 = H5Fis_hdf5(sb_filename); + VERIFY(is_hdf5, TRUE, "H5Fis_hdf5"); + + /*******************************/ + /* Non-default user block size */ + /*******************************/ + + /* Create a file creation property list with a non-default user block size */ + fcpl_id = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl_id, H5I_INVALID_HID, "H5Pcreate"); + + ret = H5Pset_userblock(fcpl_id, (hsize_t)2048); + CHECK(ret, FAIL, "H5Pset_userblock"); + + /* Create file with non-default user block */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl_id, fapl_id); + CHECK(fid, H5I_INVALID_HID, "H5Fcreate"); + + /* Release file creation property list */ + ret = H5Pclose(fcpl_id); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Verify that the file is an HDF5 file */ + is_hdf5 = H5Fis_hdf5(sb_filename); + VERIFY(is_hdf5, TRUE, "H5Fis_hdf5"); + + /***************************/ + /* Non-empty non-HDF5 file */ + /***************************/ + + /* Create non-HDF5 file. Use the calculated superblock + * filename to avoid the format strings that will make + * open(2) sad. + */ + fd = HDopen(sb_filename, O_RDWR | O_CREAT | O_TRUNC, H5_POSIX_CREATE_MODE_RW); + CHECK(fd, (-1), "HDopen"); + + /* Initialize information to write */ + for (u = 0; u < 1024; u++) + buf[u] = (unsigned char)u; + + /* Write some information */ + nbytes = HDwrite(fd, buf, (size_t)1024); + VERIFY(nbytes, 1024, "HDwrite"); + + /* Close the file */ + posix_ret = HDclose(fd); + CHECK(posix_ret, (-1), "HDclose"); + + /* Verify that the file is not an HDF5 file */ + is_hdf5 = H5Fis_hdf5(sb_filename); + VERIFY(is_hdf5, FALSE, "H5Fis_hdf5"); + + /* Clean up files */ +#if 0 + h5_delete_test_file(filename, fapl_id); +#endif + H5Fdelete(filename, fapl_id); + + /* Close property list */ + ret = H5Pclose(fapl_id); + CHECK(ret, FAIL, "H5Pclose"); + +} /* end test_file_ishdf5() */ +#endif /* H5_NO_DEPRECATED_SYMBOLS */ +#endif + +/**************************************************************** +** +** test_file_delete(): tests H5Fdelete for all VFDs +** +*****************************************************************/ +#define FILE_DELETE "test_file_delete.h5" +#define FILE_DELETE_NOT_HDF5 "test_file_delete_not_hdf5" +static void +test_file_delete(hid_t fapl_id) +{ + hid_t fid = H5I_INVALID_HID; /* File to be deleted */ + char filename[FILENAME_LEN]; /* Filename to use */ + htri_t is_hdf5; /* Whether a file is an HDF5 file */ +#if 0 + int fd; /* POSIX file descriptor */ + int iret; +#endif + herr_t ret; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Deletion of HDF5 Files\n")); + + /*************/ + /* HDF5 FILE */ + /*************/ + + /* Get fapl-dependent filename */ + h5_fixname(FILE_DELETE, fapl_id, filename, sizeof(filename)); + + /* Create a file */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id); + CHECK(fid, H5I_INVALID_HID, "H5Fcreate"); + + /* Close file */ + ret = H5Fclose(fid); + VERIFY(ret, SUCCEED, "H5Fclose"); + + /* Verify that the file is an HDF5 file */ + is_hdf5 = H5Fis_accessible(filename, fapl_id); + VERIFY(is_hdf5, TRUE, "H5Fis_accessible"); + + /* Delete the file */ + ret = H5Fdelete(filename, fapl_id); + VERIFY(ret, SUCCEED, "H5Fdelete"); + + /* Verify that the file is NO LONGER an HDF5 file */ + /* This should fail since there is no file */ + H5E_BEGIN_TRY + { + is_hdf5 = H5Fis_accessible(filename, fapl_id); + } + H5E_END_TRY; + VERIFY(is_hdf5, FAIL, "H5Fis_accessible"); + +#if 0 + /* Just in case deletion fails - silent on errors */ + h5_delete_test_file(FILE_DELETE, fapl_id); + + /*****************/ + /* NON-HDF5 FILE */ + /*****************/ + + /* Get fapl-dependent filename */ + h5_fixname(FILE_DELETE_NOT_HDF5, fapl_id, filename, sizeof(filename)); + + /* Create a non-HDF5 file */ + fd = HDopen(filename, O_RDWR | O_CREAT | O_TRUNC, H5_POSIX_CREATE_MODE_RW); + CHECK_I(fd, "HDopen"); + + /* Close the file */ + ret = HDclose(fd); + VERIFY(ret, 0, "HDclose"); + + /* Verify that the file is not an HDF5 file */ + /* Note that you can get a FAIL result when h5_fixname() + * perturbs the filename as a file with that exact name + * may not have been created since we created it with + * open(2) and not the library. + */ + H5E_BEGIN_TRY + { + is_hdf5 = H5Fis_accessible(filename, fapl_id); + } + H5E_END_TRY; + CHECK(is_hdf5, TRUE, "H5Fis_accessible"); + + /* Try to delete it (should fail) */ + H5E_BEGIN_TRY + { + ret = H5Fdelete(filename, fapl_id); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Fdelete"); + + /* Delete the file */ + iret = H5Fdelete(filename, H5P_DEFAULT); + VERIFY(iret, 0, "H5Fdelete"); +#endif +} /* end test_file_delete() */ + +/**************************************************************** +** +** test_file_open_dot(): low-level file test routine. +** This test checks whether opening objects with "." for a name +** works correctly in various situations. +** +*****************************************************************/ +static void +test_file_open_dot(void) +{ + hid_t fid; /* File ID */ + hid_t gid, gid2; /* Group IDs */ + hid_t did; /* Dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t tid, tid2; /* Datatype IDs */ + herr_t ret; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing opening objects with \".\" for a name\n")); + + /* Create a new HDF5 file to work with */ + fid = H5Fcreate(FILE1, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create a group in the HDF5 file */ + gid = H5Gcreate2(fid, GRP_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gcreate2"); + + /* Create a dataspace for creating datasets */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create a dataset with no name using the file ID */ + H5E_BEGIN_TRY + { + did = H5Dcreate2(fid, ".", H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(did, FAIL, "H5Dcreate2"); + + /* Create a dataset with no name using the group ID */ + H5E_BEGIN_TRY + { + did = H5Dcreate2(gid, ".", H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(did, FAIL, "H5Dcreate2"); + + /* Open a dataset with no name using the file ID */ + H5E_BEGIN_TRY + { + did = H5Dopen2(fid, ".", H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(did, FAIL, "H5Dopen2"); + + /* Open a dataset with no name using the group ID */ + H5E_BEGIN_TRY + { + did = H5Dopen2(gid, ".", H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(did, FAIL, "H5Dopen2"); + + /* Make a copy of a datatype to use for creating a named datatype */ + tid = H5Tcopy(H5T_NATIVE_INT); + CHECK(tid, FAIL, "H5Tcopy"); + + /* Create a named datatype with no name using the file ID */ + H5E_BEGIN_TRY + { + ret = H5Tcommit2(fid, ".", tid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Tcommit2"); + + /* Create a named datatype with no name using the group ID */ + H5E_BEGIN_TRY + { + ret = H5Tcommit2(gid, ".", tid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Tcommit2"); + + /* Open a named datatype with no name using the file ID */ + H5E_BEGIN_TRY + { + tid2 = H5Topen2(fid, ".", H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(tid2, FAIL, "H5Topen2"); + + /* Open a named datatype with no name using the group ID */ + H5E_BEGIN_TRY + { + tid2 = H5Topen2(gid, ".", H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(tid2, FAIL, "H5Topen2"); + + /* Create a group with no name using the file ID */ + H5E_BEGIN_TRY + { + gid2 = H5Gcreate2(fid, ".", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(gid2, FAIL, "H5Gcreate2"); + + /* Create a group with no name using the group ID */ + H5E_BEGIN_TRY + { + gid2 = H5Gcreate2(gid, ".", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(gid2, FAIL, "H5Gcreate2"); + + /* Open a group with no name using the file ID (should open the root group) */ + gid2 = H5Gopen2(fid, ".", H5P_DEFAULT); + CHECK(gid2, FAIL, "H5Gopen2"); + + ret = H5Gclose(gid2); + CHECK(ret, FAIL, "H5Gclose"); + + /* Open a group with no name using the group ID (should open the group again) */ + gid2 = H5Gopen2(gid, ".", H5P_DEFAULT); + CHECK(gid2, FAIL, "H5Gopen2"); + + ret = H5Gclose(gid2); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close everything */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + +} /* end test_file_open_dot() */ + +/**************************************************************** +** +** test_file_open_overlap(): low-level file test routine. +** This test checks whether opening files in an overlapping way +** (as opposed to a nested manner) works correctly. +** +*****************************************************************/ +static void +test_file_open_overlap(void) +{ + hid_t fid1, fid2; + hid_t did1, did2; + hid_t gid; + hid_t sid; + ssize_t nobjs; /* # of open objects */ + unsigned intent; +#if 0 + unsigned long fileno1, fileno2; /* File number */ +#endif + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing opening overlapping file opens\n")); + + /* Create file */ + fid1 = H5Fcreate(FILE1, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Open file also */ + fid2 = H5Fopen(FILE1, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid2, FAIL, "H5Fopen"); + + /* Check the intent */ + ret = H5Fget_intent(fid1, &intent); + CHECK(ret, FAIL, "H5Fget_intent"); + VERIFY(intent, H5F_ACC_RDWR, "H5Fget_intent"); +#if 0 + /* Check the file numbers */ + fileno1 = 0; + ret = H5Fget_fileno(fid1, &fileno1); + CHECK(ret, FAIL, "H5Fget_fileno"); + fileno2 = 0; + ret = H5Fget_fileno(fid2, &fileno2); + CHECK(ret, FAIL, "H5Fget_fileno"); + VERIFY(fileno1, fileno2, "H5Fget_fileno"); + + /* Check that a file number pointer of NULL is ignored */ + ret = H5Fget_fileno(fid1, NULL); + CHECK(ret, FAIL, "H5Fget_fileno"); +#endif + + /* Create a group in file */ + gid = H5Gcreate2(fid1, GROUP1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gcreate2"); + + /* Create dataspace for dataset */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create dataset in group w/first file ID */ + did1 = H5Dcreate2(gid, DSET1, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(did1, FAIL, "H5Dcreate2"); +#ifndef WRONG_DATATYPE_OBJ_COUNT + /* Check number of objects opened in first file */ + nobjs = H5Fget_obj_count(fid1, H5F_OBJ_LOCAL | H5F_OBJ_ALL); + VERIFY(nobjs, 3, "H5Fget_obj_count"); /* 3 == file, dataset & group */ +#endif + /* Close dataset */ + ret = H5Dclose(did1); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close group */ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close first file ID */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Create dataset with second file ID */ + did2 = H5Dcreate2(fid2, DSET2, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(did2, FAIL, "H5Dcreate2"); + + /* Check number of objects opened in first file */ + nobjs = H5Fget_obj_count(fid2, H5F_OBJ_ALL); + VERIFY(nobjs, 2, "H5Fget_obj_count"); /* 3 == file & dataset */ + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close second dataset */ + ret = H5Dclose(did2); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close second file */ + ret = H5Fclose(fid2); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_file_open_overlap() */ + +/**************************************************************** +** +** test_file_getname(): low-level file test routine. +** This test checks whether H5Fget_name works correctly. +** +*****************************************************************/ +static void +test_file_getname(void) +{ + /* Compound datatype */ + typedef struct s1_t { + unsigned int a; + float b; + } s1_t; + + hid_t file_id; + hid_t group_id; + hid_t dataset_id; + hid_t space_id; + hid_t type_id; + hid_t attr_id; + hsize_t dims[TESTA_RANK] = {TESTA_NX, TESTA_NY}; + char name[TESTA_NAME_BUF_SIZE]; + ssize_t name_len; + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing H5Fget_name() functionality\n")); + + /* Create a new file_id using default properties. */ + file_id = H5Fcreate(FILE1, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file_id, FAIL, "H5Fcreate"); + + /* Get and verify file name */ + name_len = H5Fget_name(file_id, name, (size_t)TESTA_NAME_BUF_SIZE); + CHECK(name_len, FAIL, "H5Fget_name"); + VERIFY_STR(name, FILE1, "H5Fget_name"); + + /* Create a group in the root group */ + group_id = H5Gcreate2(file_id, TESTA_GROUPNAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(group_id, FAIL, "H5Gcreate2"); + + /* Get and verify file name */ + name_len = H5Fget_name(group_id, name, (size_t)TESTA_NAME_BUF_SIZE); + CHECK(name_len, FAIL, "H5Fget_name"); + VERIFY_STR(name, FILE1, "H5Fget_name"); + + /* Create the data space */ + space_id = H5Screate_simple(TESTA_RANK, dims, NULL); + CHECK(space_id, FAIL, "H5Screate_simple"); + + /* Try get file name from data space. Supposed to fail because + * it's illegal operation. */ + H5E_BEGIN_TRY + { + name_len = H5Fget_name(space_id, name, (size_t)TESTA_NAME_BUF_SIZE); + } + H5E_END_TRY; + VERIFY(name_len, FAIL, "H5Fget_name"); + + /* Create a new dataset */ + dataset_id = + H5Dcreate2(file_id, TESTA_DSETNAME, H5T_NATIVE_INT, space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset_id, FAIL, "H5Dcreate2"); + + /* Get and verify file name */ + name_len = H5Fget_name(dataset_id, name, (size_t)TESTA_NAME_BUF_SIZE); + CHECK(name_len, FAIL, "H5Fget_name"); + VERIFY_STR(name, FILE1, "H5Fget_name"); + + /* Create an attribute for the dataset */ + attr_id = H5Acreate2(dataset_id, TESTA_ATTRNAME, H5T_NATIVE_INT, space_id, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr_id, FAIL, "H5Acreate2"); + + /* Get and verify file name */ + name_len = H5Fget_name(attr_id, name, (size_t)TESTA_NAME_BUF_SIZE); + CHECK(name_len, FAIL, "H5Fget_name"); + VERIFY_STR(name, FILE1, "H5Fget_name"); + + /* Create a compound datatype */ + type_id = H5Tcreate(H5T_COMPOUND, sizeof(s1_t)); + CHECK(type_id, FAIL, "H5Tcreate"); + + /* Insert fields */ + ret = H5Tinsert(type_id, "a", HOFFSET(s1_t, a), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(type_id, "b", HOFFSET(s1_t, b), H5T_NATIVE_FLOAT); + CHECK(ret, FAIL, "H5Tinsert"); + + /* Save it on file */ + ret = H5Tcommit2(file_id, TESTA_DTYPENAME, type_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + + /* Get and verify file name */ + name_len = H5Fget_name(type_id, name, (size_t)TESTA_NAME_BUF_SIZE); + CHECK(name_len, FAIL, "H5Fget_name"); + VERIFY_STR(name, FILE1, "H5Fget_name"); + + /* Close things down */ + ret = H5Tclose(type_id); + CHECK(ret, FAIL, "H5Tclose"); + + ret = H5Aclose(attr_id); + CHECK(ret, FAIL, "H5Aclose"); + + ret = H5Dclose(dataset_id); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Sclose(space_id); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Gclose(group_id); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Fclose(file_id); + CHECK(ret, FAIL, "H5Fclose"); + +} /* end test_file_getname() */ + +/**************************************************************** +** +** test_file_double_root_open(): low-level file test routine. +** This test checks whether opening the root group from two +** different files works correctly. +** +*****************************************************************/ +static void +test_file_double_root_open(void) +{ + hid_t file1_id, file2_id; + hid_t grp1_id, grp2_id; + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing double root group open\n")); + + file1_id = H5Fcreate(FILE1, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file1_id, FAIL, "H5Fcreate"); + file2_id = H5Fopen(FILE1, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(file2_id, FAIL, "H5Fopen"); + + grp1_id = H5Gopen2(file1_id, "/", H5P_DEFAULT); + CHECK(grp1_id, FAIL, "H5Gopen2"); + grp2_id = H5Gopen2(file2_id, "/", H5P_DEFAULT); + CHECK(grp2_id, FAIL, "H5Gopen2"); + + /* Note "asymmetric" close order */ + ret = H5Gclose(grp1_id); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Gclose(grp2_id); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Fclose(file1_id); + CHECK(ret, FAIL, "H5Fclose"); + ret = H5Fclose(file2_id); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_file_double_root_open() */ + +/**************************************************************** +** +** test_file_double_group_open(): low-level file test routine. +** This test checks whether opening the same group from two +** different files works correctly. +** +*****************************************************************/ +static void +test_file_double_group_open(void) +{ + hid_t file1_id, file2_id; + hid_t grp1_id, grp2_id; + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing double non-root group open\n")); + + file1_id = H5Fcreate(FILE1, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file1_id, FAIL, "H5Fcreate"); + file2_id = H5Fopen(FILE1, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(file2_id, FAIL, "H5Fopen"); + + grp1_id = H5Gcreate2(file1_id, GRP_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(grp1_id, FAIL, "H5Gcreate2"); + grp2_id = H5Gopen2(file2_id, GRP_NAME, H5P_DEFAULT); + CHECK(grp2_id, FAIL, "H5Gopen2"); + + /* Note "asymmetric" close order */ + ret = H5Gclose(grp1_id); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Gclose(grp2_id); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Fclose(file1_id); + CHECK(ret, FAIL, "H5Fclose"); + ret = H5Fclose(file2_id); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_file_double_group_open() */ + +/**************************************************************** +** +** test_file_double_dataset_open(): low-level file test routine. +** This test checks whether opening the same dataset from two +** different files works correctly. +** +*****************************************************************/ +static void +test_file_double_dataset_open(void) +{ + hid_t file1_id, file2_id; + hid_t dset1_id, dset2_id; + hid_t space_id; + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing double dataset open\n")); + + file1_id = H5Fcreate(FILE1, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file1_id, FAIL, "H5Fcreate"); + file2_id = H5Fopen(FILE1, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(file2_id, FAIL, "H5Fopen"); + + /* Create dataspace for dataset */ + space_id = H5Screate(H5S_SCALAR); + CHECK(space_id, FAIL, "H5Screate"); + + dset1_id = + H5Dcreate2(file1_id, DSET_NAME, H5T_NATIVE_INT, space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dset1_id, FAIL, "H5Dcreate2"); + dset2_id = H5Dopen2(file2_id, DSET_NAME, H5P_DEFAULT); + CHECK(dset2_id, FAIL, "H5Dopen2"); + + /* Close "supporting" dataspace */ + ret = H5Sclose(space_id); + CHECK(ret, FAIL, "H5Sclose"); + + /* Note "asymmetric" close order */ + ret = H5Dclose(dset1_id); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset2_id); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Fclose(file1_id); + CHECK(ret, FAIL, "H5Fclose"); + ret = H5Fclose(file2_id); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_file_double_dataset_open() */ + +/**************************************************************** +** +** test_file_double_file_dataset_open(): +** This test checks multi-opens of files & datasets: +** It simulates the multi-thread test program from DLS +** which exposes the file pointer segmentation fault failure. +** NOTE: The order on when the files and datasets are open/close +** is important. +** +*****************************************************************/ +static void +test_file_double_file_dataset_open(hbool_t new_format) +{ + hid_t fapl = -1; /* File access property list */ + hid_t dcpl = -1; /* Dataset creation property list */ + hid_t fid1 = -1, fid2 = -1; /* File IDs */ + hid_t did1 = -1, did2 = -1; /* Dataset IDs */ + hid_t sid1 = -1, sid2 = -1; /* Dataspace IDs */ + hid_t tid1 = -1, tid2 = -1; /* Datatype IDs */ + hsize_t dims[1] = {5}, dims2[2] = {1, 4}; /* Dimension sizes */ + hsize_t e_ext_dims[1] = {7}; /* Expanded dimension sizes */ + hsize_t s_ext_dims[1] = {3}; /* Shrunk dimension sizes */ + hsize_t max_dims0[1] = {8}; /* Maximum dimension sizes */ + hsize_t max_dims1[1] = {H5S_UNLIMITED}; /* Maximum dimesion sizes for extensible array index */ + hsize_t max_dims2[2] = {H5S_UNLIMITED, H5S_UNLIMITED}; /* Maximum dimension sizes for v2 B-tree index */ + hsize_t chunks[1] = {2}, chunks2[2] = {4, 5}; /* Chunk dimension sizes */ +#if 0 + hsize_t size; /* File size */ +#endif + char filename[FILENAME_LEN]; /* Filename to use */ + const char *data[] = {"String 1", "String 2", "String 3", "String 4", "String 5"}; /* Input Data */ + const char *e_data[] = {"String 1", "String 2", "String 3", "String 4", + "String 5", "String 6", "String 7"}; /* Input Data */ + char *buffer[5]; /* Output buffer */ + int wbuf[4] = {1, 2, 3, 4}; /* Input data */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing double file and dataset open/close\n")); + + /* Setting up test file */ + fapl = h5_fileaccess(); + CHECK(fapl, FAIL, "H5Pcreate"); + if (new_format) { + ret = H5Pset_libver_bounds(fapl, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST); + CHECK(ret, FAIL, "H5Pset_libver_bounds"); + } /* end if */ + h5_fixname(FILE1, fapl, filename, sizeof filename); + + /* Create the test file */ + fid1 = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create a chunked dataset with fixed array indexing */ + sid1 = H5Screate_simple(1, dims, max_dims0); + CHECK(sid1, FAIL, "H5Screate_simple"); + tid1 = H5Tcopy(H5T_C_S1); + CHECK(tid1, FAIL, "H5Tcopy"); + ret = H5Tset_size(tid1, H5T_VARIABLE); + CHECK(ret, FAIL, "H5Tset_size"); + + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + ret = H5Pset_chunk(dcpl, 1, chunks); + CHECK(ret, FAIL, "H5Pset_chunk"); + + did1 = H5Dcreate2(fid1, "dset_fa", tid1, sid1, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(did1, FAIL, "H5Dcreate2"); + + /* Closing */ + ret = H5Dclose(did1); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Dclose"); + + /* Create a chunked dataset with extensible array indexing */ + sid1 = H5Screate_simple(1, dims, max_dims1); + CHECK(sid1, FAIL, "H5Screate_simple"); + tid1 = H5Tcopy(H5T_C_S1); + CHECK(tid1, FAIL, "H5Tcopy"); + ret = H5Tset_size(tid1, H5T_VARIABLE); + CHECK(ret, FAIL, "H5Tset_size"); + + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + ret = H5Pset_chunk(dcpl, 1, chunks); + CHECK(ret, FAIL, "H5Pset_chunk"); + + did1 = H5Dcreate2(fid1, "dset_ea", tid1, sid1, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(did1, FAIL, "H5Dcreate2"); + + /* Write to the dataset */ + ret = H5Dwrite(did1, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, data); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Closing */ + /* (Leave sid1 open for later use) */ + ret = H5Dclose(did1); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Dclose"); + + /* Create a chunked dataset with v2 btree indexing */ + sid2 = H5Screate_simple(2, dims2, max_dims2); + CHECK(sid2, FAIL, "H5Screate_simple"); + + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + ret = H5Pset_chunk(dcpl, 2, chunks2); + CHECK(ret, FAIL, "H5Pset_chunk"); + + did2 = H5Dcreate2(fid1, "dset_bt2", H5T_NATIVE_INT, sid2, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(did2, FAIL, "H5Dcreate2"); + + /* Write to the dataset */ + ret = H5Dwrite(did2, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Closing */ + ret = H5Dclose(did2); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* + * Scenario 1 + */ + + /* First file open */ + fid1 = H5Fopen(filename, H5F_ACC_RDWR, fapl); + CHECK(fid1, FAIL, "H5Fopen"); + + /* First file's dataset open */ + did1 = H5Dopen2(fid1, "/dset_fa", H5P_DEFAULT); + CHECK(did1, FAIL, "H5Dopen2"); + + tid1 = H5Tcopy(did1); + CHECK(tid1, FAIL, "H5Tcopy"); + + /* First file's dataset write */ + ret = H5Dwrite(did1, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, data); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Second file open */ + fid2 = H5Fopen(filename, H5F_ACC_RDWR, fapl); + CHECK(fid2, FAIL, "H5Fopen"); + + /* Second file's dataset open */ + did2 = H5Dopen2(fid2, "/dset_fa", H5P_DEFAULT); + CHECK(did2, FAIL, "H5Dopen2"); + + tid2 = H5Tcopy(did2); + CHECK(tid2, FAIL, "H5Tcopy"); + + /* First file's dataset close */ + ret = H5Dclose(did1); + CHECK(ret, FAIL, "H5Dclose"); + + /* First file close */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Second file's dataset write */ + ret = H5Dwrite(did2, tid2, H5S_ALL, H5S_ALL, H5P_DEFAULT, data); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Second file's dataset close */ + ret = H5Dclose(did2); + CHECK(ret, FAIL, "H5Dclose"); + + /* Second file close */ + ret = H5Fclose(fid2); + CHECK(ret, FAIL, "H5Fclose"); + + /* Closing */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Tclose(tid2); + CHECK(ret, FAIL, "H5Tclose"); + + /* + * Scenario 2 + */ + + /* First file open */ + fid1 = H5Fopen(filename, H5F_ACC_RDONLY, fapl); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Second file open */ + fid2 = H5Fopen(filename, H5F_ACC_RDONLY, fapl); + CHECK(fid2, FAIL, "H5Fopen"); + + /* Second file's dataset open */ + did2 = H5Dopen2(fid2, "/dset_ea", H5P_DEFAULT); + CHECK(did2, FAIL, "H5Dopen2"); + + tid2 = H5Tcopy(did2); + CHECK(tid2, FAIL, "H5Tcopy"); + + /* First file's dataset open */ + did1 = H5Dopen2(fid1, "/dset_ea", H5P_DEFAULT); + CHECK(did1, FAIL, "H5Dopen2"); + + tid1 = H5Tcopy(did1); + CHECK(tid1, FAIL, "H5Tcopy"); + + /* Second file's dataset read */ + HDmemset(buffer, 0, sizeof(char *) * 5); + ret = H5Dread(did2, tid2, H5S_ALL, H5S_ALL, H5P_DEFAULT, buffer); + CHECK(ret, FAIL, "H5Dread"); + ret = H5Treclaim(tid2, sid1, H5P_DEFAULT, buffer); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Second file's dataset close */ + ret = H5Dclose(did2); + CHECK(ret, FAIL, "H5Dclose"); + + /* Second file close */ + ret = H5Fclose(fid2); + CHECK(ret, FAIL, "H5Fclose"); + + /* First file's dataset read */ + HDmemset(buffer, 0, sizeof(char *) * 5); + ret = H5Dread(did1, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, buffer); + CHECK(ret, FAIL, "H5Dread"); + ret = H5Treclaim(tid2, sid1, H5P_DEFAULT, buffer); + CHECK(ret, FAIL, "H5Treclaim"); + + /* First file's dataset close */ + ret = H5Dclose(did1); + CHECK(ret, FAIL, "H5Dclose"); + + /* First file close */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Closing */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Tclose(tid2); + CHECK(ret, FAIL, "H5Tclose"); + + /* + * Scenario 3 + */ + + /* First file open */ + fid1 = H5Fopen(filename, H5F_ACC_RDONLY, fapl); + CHECK(fid1, FAIL, "H5Fopen"); + + /* First file's dataset open */ + did1 = H5Dopen2(fid1, "/dset_bt2", H5P_DEFAULT); + CHECK(did1, FAIL, "H5Dopen2"); +#if 0 + /* First file's get storage size */ + size = H5Dget_storage_size(did1); + CHECK(size, 0, "H5Dget_storage_size"); +#endif + /* Second file open */ + fid2 = H5Fopen(filename, H5F_ACC_RDONLY, fapl); + CHECK(fid2, FAIL, "H5Fopen"); + + /* Second file's dataset open */ + did2 = H5Dopen2(fid2, "/dset_bt2", H5P_DEFAULT); + CHECK(did2, FAIL, "H5Dopen2"); + + /* First file's dataset close */ + ret = H5Dclose(did1); + CHECK(ret, FAIL, "H5Dclose"); + + /* First file close */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); +#if 0 + /* Second file's get storage size */ + size = H5Dget_storage_size(did2); + CHECK(size, 0, "H5Dget_storage_size"); +#endif + /* Second file's dataset close */ + ret = H5Dclose(did2); + CHECK(ret, FAIL, "H5Dclose"); + + /* Second file close */ + ret = H5Fclose(fid2); + CHECK(ret, FAIL, "H5Fclose"); + + /* + * Scenario 4 + * --trigger H5AC_protect: Assertion `f->shared' failed + * from second call to + * H5Dset_extent->...H5D__earray_idx_remove->H5EA_get...H5EA__iblock_protect...H5AC_protect + */ + /* First file open */ + fid1 = H5Fopen(filename, H5F_ACC_RDWR, fapl); + CHECK(fid1, FAIL, "H5Fopen"); + + /* First file's dataset open */ + did1 = H5Dopen2(fid1, "/dset_ea", H5P_DEFAULT); + CHECK(did1, FAIL, "H5Dopen2"); + + tid1 = H5Tcopy(did1); + CHECK(tid1, FAIL, "H5Tcopy"); + + /* Extend the dataset */ + ret = H5Dset_extent(did1, e_ext_dims); + CHECK(ret, FAIL, "H5Dset_extent"); + + /* Write to the dataset */ + ret = H5Dwrite(did1, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, e_data); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Second file open */ + fid2 = H5Fopen(filename, H5F_ACC_RDWR, fapl); + CHECK(fid2, FAIL, "H5Fopen"); + + /* Second file's dataset open */ + did2 = H5Dopen2(fid2, "/dset_ea", H5P_DEFAULT); + CHECK(did2, FAIL, "H5Dopen2"); + + /* First file's dataset close */ + ret = H5Dclose(did1); + CHECK(ret, FAIL, "H5Dclose"); + + /* First file close */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Shrink the dataset */ + ret = H5Dset_extent(did2, s_ext_dims); + CHECK(ret, FAIL, "H5Dset_extent"); + + /* Second file's dataset close */ + ret = H5Dclose(did2); + CHECK(ret, FAIL, "H5Dclose"); + + /* Second file close */ + ret = H5Fclose(fid2); + CHECK(ret, FAIL, "H5Fclose"); + + /* Close the data type */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close FAPL */ + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); +} /* end test_file_double_dataset_open() */ + +/**************************************************************** +** +** test_file_double_datatype_open(): low-level file test routine. +** This test checks whether opening the same named datatype from two +** different files works correctly. +** +*****************************************************************/ +static void +test_file_double_datatype_open(void) +{ + hid_t file1_id, file2_id; + hid_t type1_id, type2_id; + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing double datatype open\n")); + + file1_id = H5Fcreate(FILE1, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file1_id, FAIL, "H5Fcreate"); + file2_id = H5Fopen(FILE1, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(file2_id, FAIL, "H5Fopen"); + + type1_id = H5Tcopy(H5T_NATIVE_INT); + CHECK(type1_id, FAIL, "H5Tcopy"); + ret = H5Tcommit2(file1_id, TYPE_NAME, type1_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + type2_id = H5Topen2(file2_id, TYPE_NAME, H5P_DEFAULT); + CHECK(type2_id, FAIL, "H5Topen2"); + + /* Note "asymmetric" close order */ + ret = H5Tclose(type1_id); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Tclose(type2_id); + CHECK(ret, FAIL, "H5Tclose"); + + ret = H5Fclose(file1_id); + CHECK(ret, FAIL, "H5Fclose"); + ret = H5Fclose(file2_id); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_file_double_dataset_open() */ + +/**************************************************************** +** +** test_userblock_file_size(): low-level file test routine. +** This test checks that the presence of a userblock +** affects the file size in the expected manner, and that +** the filesize is not changed by reopening the file. It +** creates two files which are identical except that one +** contains a userblock, and verifies that their file sizes +** differ exactly by the userblock size. +** +*****************************************************************/ +#if 0 +static void +test_userblock_file_size(const char *env_h5_drvr) +{ + hid_t file1_id, file2_id; + hid_t group1_id, group2_id; + hid_t dset1_id, dset2_id; + hid_t space_id; + hid_t fcpl2_id; + hsize_t dims[2] = {3, 4}; +#if 0 + hsize_t filesize1, filesize2, filesize; + unsigned long fileno1, fileno2; /* File number */ +#endif + herr_t ret; /* Generic return value */ + + /* Don't run with multi/split, family or direct drivers */ + if (!HDstrcmp(env_h5_drvr, "multi") || !HDstrcmp(env_h5_drvr, "split") || + !HDstrcmp(env_h5_drvr, "family") || !HDstrcmp(env_h5_drvr, "direct")) + return; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing file size with user block\n")); + + /* Create property list with userblock size set */ + fcpl2_id = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl2_id, FAIL, "H5Pcreate"); + ret = H5Pset_userblock(fcpl2_id, USERBLOCK_SIZE); + CHECK(ret, FAIL, "H5Pset_userblock"); + + /* Create files. Only file2 with have a userblock. */ + file1_id = H5Fcreate(FILE1, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file1_id, FAIL, "H5Fcreate"); + file2_id = H5Fcreate(FILE2, H5F_ACC_TRUNC, fcpl2_id, H5P_DEFAULT); + CHECK(file2_id, FAIL, "H5Fcreate"); +#if 0 + /* Check the file numbers */ + fileno1 = 0; + ret = H5Fget_fileno(file1_id, &fileno1); + CHECK(ret, FAIL, "H5Fget_fileno"); + fileno2 = 0; + ret = H5Fget_fileno(file2_id, &fileno2); + CHECK(ret, FAIL, "H5Fget_fileno"); + CHECK(fileno1, fileno2, "H5Fget_fileno"); +#endif + /* Create groups */ + group1_id = H5Gcreate2(file1_id, GROUP1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(group1_id, FAIL, "H5Gcreate2"); + group2_id = H5Gcreate2(file2_id, GROUP1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(group2_id, FAIL, "H5Gcreate2"); + + /* Create dataspace */ + space_id = H5Screate_simple(2, dims, NULL); + CHECK(space_id, FAIL, "H5Screate_simple"); + + /* Create datasets */ + dset1_id = H5Dcreate2(file1_id, DSET2, H5T_NATIVE_INT, space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dset1_id, FAIL, "H5Dcreate2"); + dset2_id = H5Dcreate2(file2_id, DSET2, H5T_NATIVE_INT, space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dset2_id, FAIL, "H5Dcreate2"); + + /* Close IDs */ + ret = H5Dclose(dset1_id); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(dset2_id); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Sclose(space_id); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Gclose(group1_id); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Gclose(group2_id); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Pclose(fcpl2_id); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close files */ + ret = H5Fclose(file1_id); + CHECK(ret, FAIL, "H5Fclose"); + ret = H5Fclose(file2_id); + CHECK(ret, FAIL, "H5Fclose"); + + /* Reopen files */ + file1_id = H5Fopen(FILE1, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(file1_id, FAIL, "H5Fopen"); + file2_id = H5Fopen(FILE2, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(file2_id, FAIL, "H5Fopen"); +#if 0 + /* Check file sizes */ + ret = H5Fget_filesize(file1_id, &filesize1); + CHECK(ret, FAIL, "H5Fget_filesize"); + ret = H5Fget_filesize(file2_id, &filesize2); + CHECK(ret, FAIL, "H5Fget_filesize"); + + /* Verify that the file sizes differ exactly by the userblock size */ + VERIFY_TYPE((unsigned long long)filesize2, (unsigned long long)(filesize1 + USERBLOCK_SIZE), + unsigned long long, "%llu", "H5Fget_filesize"); +#endif + /* Close files */ + ret = H5Fclose(file1_id); + CHECK(ret, FAIL, "H5Fclose"); + ret = H5Fclose(file2_id); + CHECK(ret, FAIL, "H5Fclose"); + + /* Reopen files */ + file1_id = H5Fopen(FILE1, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(file1_id, FAIL, "H5Fopen"); + file2_id = H5Fopen(FILE2, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(file2_id, FAIL, "H5Fopen"); +#if 0 + /* Verify file sizes did not change */ + ret = H5Fget_filesize(file1_id, &filesize); + CHECK(ret, FAIL, "H5Fget_filesize"); + VERIFY(filesize, filesize1, "H5Fget_filesize"); + ret = H5Fget_filesize(file2_id, &filesize); + CHECK(ret, FAIL, "H5Fget_filesize"); + VERIFY(filesize, filesize2, "H5Fget_filesize"); +#endif + /* Close files */ + ret = H5Fclose(file1_id); + CHECK(ret, FAIL, "H5Fclose"); + ret = H5Fclose(file2_id); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_userblock_file_size() */ +#endif + +/**************************************************************** +** +** test_cached_stab_info(): low-level file test routine. +** This test checks that new files are created with cached +** symbol table information in the superblock (when using +** the old format). This is necessary to ensure backwards +** compatibility with versions from 1.3.0 to 1.6.3. +** +*****************************************************************/ +#if 0 +static void +test_cached_stab_info(void) +{ + hid_t file_id; + hid_t group_id; + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing cached symbol table information\n")); + + /* Create file */ + file_id = H5Fcreate(FILE1, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file_id, FAIL, "H5Fcreate"); + + /* Create group */ + group_id = H5Gcreate2(file_id, GROUP1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(group_id, FAIL, "H5Gcreate2"); + + /* Close file and group */ + ret = H5Gclose(group_id); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Fclose(file_id); + CHECK(ret, FAIL, "H5Fclose"); + + /* Reopen file */ + file_id = H5Fopen(FILE1, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(file_id, FAIL, "H5Fopen"); +#if 0 + /* Verify the cached symbol table information */ + ret = H5F__check_cached_stab_test(file_id); + CHECK(ret, FAIL, "H5F__check_cached_stab_test"); +#endif + /* Close file */ + ret = H5Fclose(file_id); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_cached_stab_info() */ +#endif + +#if 0 +/* + * To calculate the checksum for a file. + * This is a helper routine for test_rw_noupdate(). + */ +static int +cal_chksum(const char *file, uint32_t *chksum) +{ + int curr_num_errs = nerrors; /* Retrieve the current # of errors */ + int fdes = -1; /* File descriptor */ + void *file_data = NULL; /* Copy of file data */ + ssize_t bytes_read; /* # of bytes read */ + h5_stat_t sb; /* Stat buffer for file */ + herr_t ret; /* Generic return value */ + + /* Open the file */ + fdes = HDopen(file, O_RDONLY); + CHECK(fdes, FAIL, "HDopen"); + + /* Retrieve the file's size */ + ret = HDfstat(fdes, &sb); + CHECK(fdes, FAIL, "HDfstat"); + + /* Allocate space for the file data */ + file_data = HDmalloc((size_t)sb.st_size); + CHECK_PTR(file_data, "HDmalloc"); + + if (file_data) { + /* Read file's data into memory */ + bytes_read = HDread(fdes, file_data, (size_t)sb.st_size); + CHECK(bytes_read == sb.st_size, FALSE, "HDmalloc"); + + /* Calculate checksum */ + *chksum = H5_checksum_lookup3(file_data, sizeof(file_data), 0); + + /* Free memory */ + HDfree(file_data); + } + + /* Close the file */ + ret = HDclose(fdes); + CHECK(ret, FAIL, "HDclose"); + + return ((nerrors == curr_num_errs) ? 0 : -1); +} /* cal_chksum() */ +#endif + +/**************************************************************** +** +** test_rw_noupdate(): low-level file test routine. +** This test checks to ensure that opening and closing a file +** with read/write permissions does not write anything to the +** file if the file does not change. +** Due to the implementation of file locking (status_flags in +** the superblock is used), this test is changed to use checksum +** instead of timestamp to verify the file is not changed. +** +** Programmer: Vailin Choi; July 2013 +** +*****************************************************************/ +#if 0 +static void +test_rw_noupdate(void) +{ + herr_t ret; /* Generic return value */ + hid_t fid; /* File ID */ + uint32_t chksum1, chksum2; /* Checksum value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing to verify that nothing is written if nothing is changed.\n")); + + /* Create and Close a HDF5 File */ + fid = H5Fcreate(FILE1, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Calculate checksum for the file */ + ret = cal_chksum(FILE1, &chksum1); + CHECK(ret, FAIL, "cal_chksum"); + + /* Open and close File With Read/Write Permission */ + fid = H5Fopen(FILE1, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Calculate checksum for the file */ + ret = cal_chksum(FILE1, &chksum2); + CHECK(ret, FAIL, "cal_chksum"); + + /* The two checksums are the same, i.e. the file is not changed */ + VERIFY(chksum1, chksum2, "Checksum"); + +} /* end test_rw_noupdate() */ +#endif + +/**************************************************************** +** +** test_userblock_alignment_helper1(): helper routine for +** test_userblock_alignment() test, to handle common testing +** +** Programmer: Quincey Koziol +** Septmber 10, 2009 +** +*****************************************************************/ +#if 0 +static int +test_userblock_alignment_helper1(hid_t fcpl, hid_t fapl) +{ + hid_t fid; /* File ID */ + int curr_num_errs = nerrors(); /* Retrieve the current # of errors */ + herr_t ret; /* Generic return value */ + + /* Create a file with FAPL & FCPL */ + fid = H5Fcreate(FILE1, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Only proceed further if file ID is OK */ + if (fid > 0) { + hid_t gid; /* Group ID */ + hid_t sid; /* Dataspace ID */ + hid_t did; /* Dataset ID */ + int val = 2; /* Dataset value */ + + /* Create a group */ + gid = H5Gcreate2(fid, "group1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gcreate2"); + + /* Create a dataset */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + did = H5Dcreate2(gid, "dataset", H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Write value to dataset */ + ret = H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &val); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close group */ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + } /* end if */ + + return ((nerrors == curr_num_errs) ? 0 : -1); +} /* end test_userblock_alignment_helper1() */ + +/**************************************************************** +** +** test_userblock_alignment_helper2(): helper routine for +** test_userblock_alignment() test, to handle common testing +** +** Programmer: Quincey Koziol +** Septmber 10, 2009 +** +*****************************************************************/ +static int +test_userblock_alignment_helper2(hid_t fapl, hbool_t open_rw) +{ + hid_t fid; /* File ID */ + int curr_num_errs = nerrors(); /* Retrieve the current # of errors */ + herr_t ret; /* Generic return value */ + + /* Re-open file */ + fid = H5Fopen(FILE1, (open_rw ? H5F_ACC_RDWR : H5F_ACC_RDONLY), fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Only proceed further if file ID is OK */ + if (fid > 0) { + hid_t gid; /* Group ID */ + hid_t did; /* Dataset ID */ + int val = -1; /* Dataset value */ + + /* Open group */ + gid = H5Gopen2(fid, "group1", H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gopen2"); + + /* Open dataset */ + did = H5Dopen2(gid, "dataset", H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen2"); + + /* Read value from dataset */ + ret = H5Dread(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &val); + CHECK(ret, FAIL, "H5Dread"); + VERIFY(val, 2, "H5Dread"); + + /* Close dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* Only create new objects if file is open R/W */ + if (open_rw) { + hid_t gid2; /* Group ID */ + + /* Create a new group */ + gid2 = H5Gcreate2(gid, "group2", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gcreate2"); + + /* Close new group */ + ret = H5Gclose(gid2); + CHECK(ret, FAIL, "H5Gclose"); + } /* end if */ + + /* Close group */ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + } /* end if */ + + return ((nerrors == curr_num_errs) ? 0 : -1); +} /* end test_userblock_alignment_helper2() */ + +/**************************************************************** +** +** test_userblock_alignment(): low-level file test routine. +** This test checks to ensure that files with both a userblock and a +** object [allocation] alignment size set interact properly. +** +** Programmer: Quincey Koziol +** Septmber 8, 2009 +** +*****************************************************************/ +static void +test_userblock_alignment(const char *env_h5_drvr) +{ + hid_t fid; /* File ID */ + hid_t fcpl; /* File creation property list ID */ + hid_t fapl; /* File access property list ID */ + herr_t ret; /* Generic return value */ + + /* Only run with sec2 driver */ + if (!h5_using_default_driver(env_h5_drvr)) + return; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing that non-zero userblocks and object alignment interact correctly.\n")); + + /* Case 1: + * Userblock size = 0, alignment != 0 + * Outcome: + * Should succeed + */ + /* Create file creation property list with user block */ + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, FAIL, "H5Pcreate"); + ret = H5Pset_userblock(fcpl, (hsize_t)0); + CHECK(ret, FAIL, "H5Pset_userblock"); + + /* Create file access property list with alignment */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + ret = H5Pset_alignment(fapl, (hsize_t)1, (hsize_t)3); + CHECK(ret, FAIL, "H5Pset_alignment"); + + /* Call helper routines to perform file manipulations */ + ret = test_userblock_alignment_helper1(fcpl, fapl); + CHECK(ret, FAIL, "test_userblock_alignment_helper1"); + ret = test_userblock_alignment_helper2(fapl, TRUE); + CHECK(ret, FAIL, "test_userblock_alignment_helper2"); + + /* Release property lists */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Case 2: + * Userblock size = 512, alignment = 16 + * (userblock is integral mult. of alignment) + * Outcome: + * Should succeed + */ + /* Create file creation property list with user block */ + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, FAIL, "H5Pcreate"); + ret = H5Pset_userblock(fcpl, (hsize_t)512); + CHECK(ret, FAIL, "H5Pset_userblock"); + + /* Create file access property list with alignment */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + ret = H5Pset_alignment(fapl, (hsize_t)1, (hsize_t)16); + CHECK(ret, FAIL, "H5Pset_alignment"); + + /* Call helper routines to perform file manipulations */ + ret = test_userblock_alignment_helper1(fcpl, fapl); + CHECK(ret, FAIL, "test_userblock_alignment_helper1"); + ret = test_userblock_alignment_helper2(fapl, TRUE); + CHECK(ret, FAIL, "test_userblock_alignment_helper2"); + + /* Release property lists */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Case 3: + * Userblock size = 512, alignment = 512 + * (userblock is equal to alignment) + * Outcome: + * Should succeed + */ + /* Create file creation property list with user block */ + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, FAIL, "H5Pcreate"); + ret = H5Pset_userblock(fcpl, (hsize_t)512); + CHECK(ret, FAIL, "H5Pset_userblock"); + + /* Create file access property list with alignment */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + ret = H5Pset_alignment(fapl, (hsize_t)1, (hsize_t)512); + CHECK(ret, FAIL, "H5Pset_alignment"); + + /* Call helper routines to perform file manipulations */ + ret = test_userblock_alignment_helper1(fcpl, fapl); + CHECK(ret, FAIL, "test_userblock_alignment_helper1"); + ret = test_userblock_alignment_helper2(fapl, TRUE); + CHECK(ret, FAIL, "test_userblock_alignment_helper2"); + + /* Release property lists */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Case 4: + * Userblock size = 512, alignment = 3 + * (userblock & alignment each individually valid, but userblock is + * non-integral multiple of alignment) + * Outcome: + * Should fail at file creation + */ + /* Create file creation property list with user block */ + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, FAIL, "H5Pcreate"); + ret = H5Pset_userblock(fcpl, (hsize_t)512); + CHECK(ret, FAIL, "H5Pset_userblock"); + + /* Create file access property list with alignment */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + ret = H5Pset_alignment(fapl, (hsize_t)1, (hsize_t)3); + CHECK(ret, FAIL, "H5Pset_alignment"); + + /* Create a file with FAPL & FCPL */ + H5E_BEGIN_TRY + { + fid = H5Fcreate(FILE1, H5F_ACC_TRUNC, fcpl, fapl); + } + H5E_END_TRY; + VERIFY(fid, FAIL, "H5Fcreate"); + + /* Release property lists */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Case 5: + * Userblock size = 512, alignment = 1024 + * (userblock & alignment each individually valid, but userblock is + * less than alignment) + * Outcome: + * Should fail at file creation + */ + /* Create file creation property list with user block */ + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, FAIL, "H5Pcreate"); + ret = H5Pset_userblock(fcpl, (hsize_t)512); + CHECK(ret, FAIL, "H5Pset_userblock"); + + /* Create file access property list with alignment */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + ret = H5Pset_alignment(fapl, (hsize_t)1, (hsize_t)1024); + CHECK(ret, FAIL, "H5Pset_alignment"); + + /* Create a file with FAPL & FCPL */ + H5E_BEGIN_TRY + { + fid = H5Fcreate(FILE1, H5F_ACC_TRUNC, fcpl, fapl); + } + H5E_END_TRY; + VERIFY(fid, FAIL, "H5Fcreate"); + + /* Release property lists */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Case 6: + * File created with: + * Userblock size = 512, alignment = 512 + * File re-opened for read-only & read-write access with: + * Userblock size = 512, alignment = 1024 + * Outcome: + * Should succeed + */ + /* Create file creation property list with user block */ + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, FAIL, "H5Pcreate"); + ret = H5Pset_userblock(fcpl, (hsize_t)512); + CHECK(ret, FAIL, "H5Pset_userblock"); + + /* Create file access property list with alignment */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + ret = H5Pset_alignment(fapl, (hsize_t)1, (hsize_t)512); + CHECK(ret, FAIL, "H5Pset_alignment"); + + /* Call helper routines to perform file manipulations */ + ret = test_userblock_alignment_helper1(fcpl, fapl); + CHECK(ret, FAIL, "test_userblock_alignment_helper1"); + + /* Change alignment in FAPL */ + ret = H5Pset_alignment(fapl, (hsize_t)1, (hsize_t)1024); + CHECK(ret, FAIL, "H5Pset_alignment"); + + /* Call helper routines to perform file manipulations */ + ret = test_userblock_alignment_helper2(fapl, FALSE); + CHECK(ret, FAIL, "test_userblock_alignment_helper2"); + ret = test_userblock_alignment_helper2(fapl, TRUE); + CHECK(ret, FAIL, "test_userblock_alignment_helper2"); + + /* Release property lists */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); +} /* end test_userblock_alignment() */ + +/**************************************************************** +** +** test_userblock_alignment_paged(): low-level file test routine. +** This test checks to ensure that files with both a userblock and +** alignment interact properly: +** -- alignment via H5Pset_alignment +** -- alignment via paged aggregation +** +** Programmer: Vailin Choi; March 2013 +** +*****************************************************************/ +static void +test_userblock_alignment_paged(const char *env_h5_drvr) +{ + hid_t fid; /* File ID */ + hid_t fcpl; /* File creation property list ID */ + hid_t fapl; /* File access property list ID */ + herr_t ret; /* Generic return value */ + + /* Only run with sec2 driver */ + if (!h5_using_default_driver(env_h5_drvr)) + return; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing interaction between userblock and alignment (via paged aggregation and " + "H5Pset_alignment)\n")); + + /* + * Case 1: + * Userblock size = 0 + * Alignment in use = 4096 + * Strategy = H5F_FILE_SPACE_PAGE; fsp_size = alignment = 4096 + * Outcome: + * Should succeed: + * userblock is 0 and alignment != 0 + */ + /* Create file creation property list with user block */ + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, FAIL, "H5Pcreate"); + ret = H5Pset_userblock(fcpl, (hsize_t)0); + CHECK(ret, FAIL, "H5Pset_userblock"); + + /* Create file access property list */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + + /* Set the "use the latest version of the format" bounds */ + ret = H5Pset_libver_bounds(fapl, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST); + CHECK(ret, FAIL, "H5Pset_libver_bounds"); + + ret = H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_PAGE, FALSE, (hsize_t)1); + CHECK(ret, FAIL, "H5Pset_file_space_strategy"); + + /* Call helper routines to perform file manipulations */ + ret = test_userblock_alignment_helper1(fcpl, fapl); + CHECK(ret, FAIL, "test_userblock_alignment_helper1"); + ret = test_userblock_alignment_helper2(fapl, TRUE); + CHECK(ret, FAIL, "test_userblock_alignment_helper2"); + + /* Release property lists */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + + /* + * Case 2a: + * Userblock size = 1024 + * Alignment in use = 512 + * Strategy = H5F_FILE_SPACE_PAGE; fsp_size = alignment = 512 + * H5Pset_alignment() is 3 + * Outcome: + * Should succeed: + * userblock (1024) is integral mult. of alignment (512) + */ + /* Create file creation property list with user block */ + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, FAIL, "H5Pcreate"); + ret = H5Pset_userblock(fcpl, (hsize_t)1024); + CHECK(ret, FAIL, "H5Pset_userblock"); + ret = H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_PAGE, FALSE, (hsize_t)1); + ret = H5Pset_file_space_page_size(fcpl, (hsize_t)512); + + /* Create file access property list */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + ret = H5Pset_alignment(fapl, (hsize_t)1, (hsize_t)3); + CHECK(ret, FAIL, "H5Pset_alignment"); + + /* Call helper routines to perform file manipulations */ + ret = test_userblock_alignment_helper1(fcpl, fapl); + CHECK(ret, FAIL, "test_userblock_alignment_helper1"); + ret = test_userblock_alignment_helper2(fapl, TRUE); + CHECK(ret, FAIL, "test_userblock_alignment_helper2"); + + /* Release property lists */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + + /* + * Case 2b: + * Userblock size = 1024 + * Alignment in use = 3 + * Strategy = H5F_FILE_SPACE_AGGR; fsp_size = 512 + * (via default file creation property) + * H5Pset_alignment() is 3 + * Outcome: + * Should fail at file creation: + * userblock (1024) is non-integral mult. of alignment (3) + */ + /* Create file creation property list with user block */ + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, FAIL, "H5Pcreate"); + ret = H5Pset_userblock(fcpl, (hsize_t)1024); + CHECK(ret, FAIL, "H5Pset_userblock"); + ret = H5Pset_file_space_page_size(fcpl, (hsize_t)512); + + /* Create file access property list */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + ret = H5Pset_alignment(fapl, (hsize_t)1, (hsize_t)3); + CHECK(ret, FAIL, "H5Pset_alignment"); + + /* Create a file with FAPL & FCPL */ + H5E_BEGIN_TRY + { + fid = H5Fcreate(FILE1, H5F_ACC_TRUNC, fcpl, fapl); + } + H5E_END_TRY; + VERIFY(fid, FAIL, "H5Fcreate"); + + /* Release property lists */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + + /* + * Case 3a: + * Userblock size = 512 + * Alignment in use = 512 + * Strategy is H5F_FILE_SPACE_PAGE; fsp_size = alignment = 512 + * H5Pset_alignment() is 3 + * Outcome: + * Should succeed: + * userblock (512) is equal to alignment (512) + */ + /* Create file creation property list with user block */ + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, FAIL, "H5Pcreate"); + ret = H5Pset_userblock(fcpl, (hsize_t)512); + CHECK(ret, FAIL, "H5Pset_userblock"); + ret = H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_PAGE, TRUE, (hsize_t)1); + CHECK(ret, FAIL, "H5Pset_file_space_strategy"); + ret = H5Pset_file_space_page_size(fcpl, (hsize_t)512); + CHECK(ret, FAIL, "H5Pset_file_space_page_size"); + + /* Create file access property list with alignment */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + ret = H5Pset_alignment(fapl, (hsize_t)1, (hsize_t)3); + CHECK(ret, FAIL, "H5Pset_alignment"); + + /* Call helper routines to perform file manipulations */ + ret = test_userblock_alignment_helper1(fcpl, fapl); + CHECK(ret, FAIL, "test_userblock_alignment_helper1"); + ret = test_userblock_alignment_helper2(fapl, TRUE); + CHECK(ret, FAIL, "test_userblock_alignment_helper2"); + + /* Release property lists */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + + /* + * Case 3b: + * Userblock size = 512 + * Alignment in use = 3 + * Strategy is H5F_FILE_SPACE_NONE; fsp_size = 512 + * H5Pset_alignment() is 3 + * Outcome: + * Should fail at file creation: + * userblock (512) is non-integral mult. of alignment (3) + */ + /* Create file creation property list with user block */ + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, FAIL, "H5Pcreate"); + ret = H5Pset_userblock(fcpl, (hsize_t)512); + CHECK(ret, FAIL, "H5Pset_userblock"); + ret = H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_NONE, FALSE, (hsize_t)1); + CHECK(ret, FAIL, "H5Pset_file_space_strategy"); + ret = H5Pset_file_space_page_size(fcpl, (hsize_t)512); + CHECK(ret, FAIL, "H5Pset_file_space_page_size"); + + /* Create file access property list with alignment */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + ret = H5Pset_alignment(fapl, (hsize_t)1, (hsize_t)3); + CHECK(ret, FAIL, "H5Pset_alignment"); + + /* Create a file with FAPL & FCPL */ + H5E_BEGIN_TRY + { + fid = H5Fcreate(FILE1, H5F_ACC_TRUNC, fcpl, fapl); + } + H5E_END_TRY; + VERIFY(fid, FAIL, "H5Fcreate"); + + /* Release property lists */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + + /* + * Case 4a: + * Userblock size = 1024 + * Alignment in use = 1023 + * Strategy is H5F_FILE_SPACE_PAGE; fsp_size = alignment = 1023 + * H5Pset_alignment() is 16 + * Outcome: + * Should fail at file creation: + * userblock (1024) is non-integral multiple of alignment (1023) + */ + /* Create file creation property list with user block */ + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, FAIL, "H5Pcreate"); + ret = H5Pset_userblock(fcpl, (hsize_t)1024); + CHECK(ret, FAIL, "H5Pset_userblock"); + ret = H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_PAGE, TRUE, (hsize_t)1); + CHECK(ret, FAIL, "H5Pset_file_space_strategy"); + ret = H5Pset_file_space_page_size(fcpl, (hsize_t)1023); + CHECK(ret, FAIL, "H5Pset_file_space_page_size"); + + /* Create file access property list with alignment */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + ret = H5Pset_alignment(fapl, (hsize_t)1, (hsize_t)16); + CHECK(ret, FAIL, "H5Pset_alignment"); + + /* Create a file with FAPL & FCPL */ + H5E_BEGIN_TRY + { + fid = H5Fcreate(FILE1, H5F_ACC_TRUNC, fcpl, fapl); + } + H5E_END_TRY; + VERIFY(fid, FAIL, "H5Fcreate"); + + /* Release property lists */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + + /* + * Case 4b: + * Userblock size = 1024 + * Alignment in use = 16 + * Strategy is H5F_FILE_SPACE_FSM_AGGR; fsp_size = 1023 + * H5Pset_alignment() is 16 + * Outcome: + * Should succeed: + * userblock (512) is integral multiple of alignment (16) + */ + /* Create file creation property list with user block */ + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, FAIL, "H5Pcreate"); + ret = H5Pset_userblock(fcpl, (hsize_t)1024); + CHECK(ret, FAIL, "H5Pset_userblock"); + ret = H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_FSM_AGGR, FALSE, (hsize_t)1); + CHECK(ret, FAIL, "H5Pset_file_space_strategy"); + ret = H5Pset_file_space_page_size(fcpl, (hsize_t)1023); + CHECK(ret, FAIL, "H5Pset_file_space_page_size"); + + /* Create file access property list with alignment */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + ret = H5Pset_alignment(fapl, (hsize_t)1, (hsize_t)16); + CHECK(ret, FAIL, "H5Pset_alignment"); + + /* Call helper routines to perform file manipulations */ + ret = test_userblock_alignment_helper1(fcpl, fapl); + CHECK(ret, FAIL, "test_userblock_alignment_helper1"); + ret = test_userblock_alignment_helper2(fapl, TRUE); + CHECK(ret, FAIL, "test_userblock_alignment_helper2"); + + /* Release property lists */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + + /* + * Case 5a: + * Userblock size = 512 + * Alignment in use = 1024 + * Strategy is H5F_FILE_SPACE_PAGE; fsp_size = alignment = 1024 + * H5Pset_alignment() is 16 + * Outcome: + * Should fail at file creation: + * userblock (512) is less than alignment (1024) + */ + /* Create file creation property list with user block */ + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, FAIL, "H5Pcreate"); + ret = H5Pset_userblock(fcpl, (hsize_t)512); + CHECK(ret, FAIL, "H5Pset_userblock"); + ret = H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_PAGE, FALSE, (hsize_t)1); + CHECK(ret, FAIL, "H5Pset_file_space_strategy"); + ret = H5Pset_file_space_page_size(fcpl, (hsize_t)1024); + CHECK(ret, FAIL, "H5Pset_file_space_page_size"); + + /* Create file access property list with alignment */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + ret = H5Pset_alignment(fapl, (hsize_t)1, (hsize_t)16); + CHECK(ret, FAIL, "H5Pset_alignment"); + + /* Create a file with FAPL & FCPL */ + H5E_BEGIN_TRY + { + fid = H5Fcreate(FILE1, H5F_ACC_TRUNC, fcpl, fapl); + } + H5E_END_TRY; + VERIFY(fid, FAIL, "H5Fcreate"); + + /* Release property lists */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + + /* + * Case 5b: + * Userblock size = 512 + * Alignment in use = 16 + * Strategy is H5F_FILE_SPACE_NONE; fsp_size = 1024 + * H5Pset_alignment() is 16 + * Outcome: + * Should succeed: + * userblock (512) is integral multiple of alignment (16) + */ + /* Create file creation property list with user block */ + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, FAIL, "H5Pcreate"); + ret = H5Pset_userblock(fcpl, (hsize_t)512); + CHECK(ret, FAIL, "H5Pset_userblock"); + ret = H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_NONE, FALSE, (hsize_t)1); + CHECK(ret, FAIL, "H5Pset_file_space_strategy"); + ret = H5Pset_file_space_page_size(fcpl, (hsize_t)1024); + CHECK(ret, FAIL, "H5Pset_file_space_page_size"); + + /* Create file access property list with alignment */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + ret = H5Pset_alignment(fapl, (hsize_t)1, (hsize_t)16); + CHECK(ret, FAIL, "H5Pset_alignment"); + + /* Call helper routines to perform file manipulations */ + ret = test_userblock_alignment_helper1(fcpl, fapl); + CHECK(ret, FAIL, "test_userblock_alignment_helper1"); + ret = test_userblock_alignment_helper2(fapl, TRUE); + CHECK(ret, FAIL, "test_userblock_alignment_helper2"); + + /* Release property lists */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + + /* + * Case 6: + * Userblock size = 512 + * Alignment in use = 512 + * Strategy is H5F_FILE_SPACE_PAGE; fsp_size = alignment = 512 + * H5Pset_alignment() is 3 + * Reopen the file; H5Pset_alignment() is 1024 + * Outcome: + * Should succeed: + * Userblock (512) is the same as alignment (512); + * The H5Pset_alignment() calls have no effect + */ + /* Create file creation property list with user block */ + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, FAIL, "H5Pcreate"); + ret = H5Pset_userblock(fcpl, (hsize_t)512); + CHECK(ret, FAIL, "H5Pset_userblock"); + ret = H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_PAGE, FALSE, (hsize_t)1); + CHECK(ret, FAIL, "H5Pset_file_space_strategy"); + ret = H5Pset_file_space_page_size(fcpl, (hsize_t)512); + CHECK(ret, FAIL, "H5Pset_file_space_page_size"); + + /* Create file access property list with alignment */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + ret = H5Pset_alignment(fapl, (hsize_t)1, (hsize_t)3); + CHECK(ret, FAIL, "H5Pset_alignment"); + + /* Call helper routines to perform file manipulations */ + ret = test_userblock_alignment_helper1(fcpl, fapl); + CHECK(ret, FAIL, "test_userblock_alignment_helper1"); + + /* Change alignment in FAPL */ + ret = H5Pset_alignment(fapl, (hsize_t)1, (hsize_t)1024); + CHECK(ret, FAIL, "H5Pset_alignment"); + + /* Call helper routines to perform file manipulations */ + ret = test_userblock_alignment_helper2(fapl, FALSE); + CHECK(ret, FAIL, "test_userblock_alignment_helper2"); + ret = test_userblock_alignment_helper2(fapl, TRUE); + CHECK(ret, FAIL, "test_userblock_alignment_helper2"); + + /* Release property lists */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + +} /* end test_userblock_alignment_paged() */ +#endif + +/**************************************************************** +** +** test_filespace_info(): +** Verify the following public routines retrieve and set file space +** information correctly: +** (1) H5Pget/set_file_space_strategy(): +** Retrieve and set file space strategy, persisting free-space, +** and free-space section threshold as specified +** (2) H5Pget/set_file_space_page_size(): +** Retrieve and set the page size for paged aggregation +** +****************************************************************/ +#if 0 +static void +test_filespace_info(const char *env_h5_drvr) +{ + hid_t fid; /* File IDs */ + hid_t fapl, new_fapl; /* File access property lists */ + hid_t fcpl, fcpl1, fcpl2; /* File creation property lists */ + H5F_fspace_strategy_t strategy; /* File space strategy */ + hbool_t persist; /* Persist free-space or not */ + hsize_t threshold; /* Free-space section threshold */ + unsigned new_format; /* New or old format */ + H5F_fspace_strategy_t fs_strategy; /* File space strategy--iteration variable */ + unsigned fs_persist; /* Persist free-space or not--iteration variable */ + hsize_t fs_threshold; /* Free-space section threshold--iteration variable */ + hsize_t fsp_size; /* File space page size */ + char filename[FILENAME_LEN]; /* Filename to use */ + hbool_t contig_addr_vfd; /* Whether VFD used has a contiguous address space */ + herr_t ret; /* Return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing file creation public routines: H5Pget/set_file_space_strategy & " + "H5Pget/set_file_space_page_size\n")); + + contig_addr_vfd = (hbool_t)(HDstrcmp(env_h5_drvr, "split") != 0 && HDstrcmp(env_h5_drvr, "multi") != 0); + + fapl = h5_fileaccess(); + h5_fixname(FILESPACE_NAME[0], fapl, filename, sizeof filename); + + /* Get a copy of the file access property list */ + new_fapl = H5Pcopy(fapl); + CHECK(new_fapl, FAIL, "H5Pcopy"); + + /* Set the "use the latest version of the format" bounds */ + ret = H5Pset_libver_bounds(new_fapl, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST); + CHECK(ret, FAIL, "H5Pset_libver_bounds"); + + /* + * Case (1) + * Check file space information from a default file creation property list. + * Values expected: + * strategy--H5F_FILE_SPACE_AGGR + * persist--FALSE + * threshold--1 + * file space page size--4096 + */ + /* Create file creation property list template */ + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, FAIL, "H5Pcreate"); + + /* Retrieve file space information */ + ret = H5Pget_file_space_strategy(fcpl, &strategy, &persist, &threshold); + CHECK(ret, FAIL, "H5Pget_file_space_strategy"); + + /* Verify file space information */ + VERIFY(strategy, H5F_FSPACE_STRATEGY_FSM_AGGR, "H5Pget_file_space_strategy"); + VERIFY(persist, FALSE, "H5Pget_file_space_strategy"); + VERIFY(threshold, 1, "H5Pget_file_space_strategy"); + + /* Retrieve file space page size */ + ret = H5Pget_file_space_page_size(fcpl, &fsp_size); + CHECK(ret, FAIL, "H5Pget_file_space_page_size"); + VERIFY(fsp_size, FSP_SIZE_DEF, "H5Pget_file_space_page_size"); + + /* Close property list */ + H5Pclose(fcpl); + + /* + * Case (2) + * File space page size has a minimum size of 512. + * Setting value less than 512 will return an error; + * --setting file space page size to 0 + * --setting file space page size to 511 + * + * File space page size has a maximum size of 1 gigabyte. + * Setting value greater than 1 gigabyte will return an error. + */ + /* Create file creation property list template */ + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, FAIL, "H5Pcreate"); + + /* Setting to 0: should fail */ + H5E_BEGIN_TRY + { + ret = H5Pset_file_space_page_size(fcpl, 0); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Pset_file_space_page_size"); + + /* Setting to 511: should fail */ + H5E_BEGIN_TRY + { + ret = H5Pset_file_space_page_size(fcpl, 511); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Pset_file_space_page_size"); + + /* Setting to 1GB+1: should fail */ + H5E_BEGIN_TRY + { + ret = H5Pset_file_space_page_size(fcpl, FSP_SIZE1G + 1); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Pset_file_space_page_size"); + + /* Setting to 512: should succeed */ + ret = H5Pset_file_space_page_size(fcpl, FSP_SIZE512); + CHECK(ret, FAIL, "H5Pset_file_space_page_size"); + ret = H5Pget_file_space_page_size(fcpl, &fsp_size); + CHECK(ret, FAIL, "H5Pget_file_space_page_size"); + VERIFY(fsp_size, FSP_SIZE512, "H5Pget_file_space_page_size"); + + /* Setting to 1GB: should succeed */ + ret = H5Pset_file_space_page_size(fcpl, FSP_SIZE1G); + CHECK(ret, FAIL, "H5Pset_file_space_page_size"); + ret = H5Pget_file_space_page_size(fcpl, &fsp_size); + CHECK(ret, FAIL, "H5Pget_file_space_page_size"); + VERIFY(fsp_size, FSP_SIZE1G, "H5Pget_file_space_page_size"); + + /* Close property list */ + H5Pclose(fcpl); + + /* + * Case (3) + * Check file space information when creating a file with default properties. + * Values expected: + * strategy--H5F_FILE_SPACE_AGGR + * persist--FALSE + * threshold--1 + * file space page size--4096 + */ + /* Create a file with default file creation and access property lists */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Get the file's creation property list */ + fcpl1 = H5Fget_create_plist(fid); + CHECK(fcpl1, FAIL, "H5Fget_create_plist"); + + /* Retrieve file space information */ + ret = H5Pget_file_space_strategy(fcpl1, &strategy, &persist, &threshold); + CHECK(ret, FAIL, "H5Pget_file_space_strategy"); + + /* Verify file space information */ + VERIFY(strategy, H5F_FSPACE_STRATEGY_FSM_AGGR, "H5Pget_file_space_strategy"); + VERIFY(persist, FALSE, "H5Pget_file_space_strategy"); + VERIFY(threshold, 1, "H5Pget_file_space_strategy"); + + /* Retrieve file space page size */ + ret = H5Pget_file_space_page_size(fcpl1, &fsp_size); + CHECK(ret, FAIL, "H5Pget_file_space_page_size"); + VERIFY(fsp_size, FSP_SIZE_DEF, "H5Pget_file_space_page_size"); + + /* Close property lists */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + ret = H5Pclose(fcpl1); + CHECK(ret, FAIL, "H5Pclose"); + + /* + * Case (4) + * Check file space information when creating a file with the + * latest library format and default properties. + * Values expected: + * strategy--H5F_FILE_SPACE_AGGR + * persist--FALSE + * threshold--1 + * file space page size--4096 + */ + /* Create a file with the latest library format */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, new_fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Get the file's creation property */ + fcpl1 = H5Fget_create_plist(fid); + CHECK(fcpl1, FAIL, "H5Fget_create_plist"); + + /* Retrieve file space information */ + ret = H5Pget_file_space_strategy(fcpl1, &strategy, &persist, &threshold); + CHECK(ret, FAIL, "H5Pget_file_space_strategy"); + + /* Verify file space information */ + VERIFY(strategy, H5F_FSPACE_STRATEGY_FSM_AGGR, "H5Pget_file_space_strategy"); + VERIFY(persist, FALSE, "H5Pget_file_space_strategy"); + VERIFY(threshold, 1, "H5Pget_file_space_strategy"); + + /* Retrieve file space page size */ + ret = H5Pget_file_space_page_size(fcpl1, &fsp_size); + CHECK(ret, FAIL, "H5Pget_file_space_page_size"); + VERIFY(fsp_size, FSP_SIZE_DEF, "H5Pget_file_space_page_size"); + + /* Close property lists */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + ret = H5Pclose(fcpl1); + CHECK(ret, FAIL, "H5Pclose"); + + /* + * Case (5) + * Check file space information with the following combinations: + * Create file with -- + * New or old format + * Persist or not persist free-space + * Different sizes for free-space section threshold (0 to 10) + * The four file space strategies: + * H5F_FSPACE_STRATEGY_FSM_AGGR, H5F_FSPACE_STRATEGY_PAGE, + * H5F_FSPACE_STRATEGY_AGGR, H5F_FSPACE_STRATEGY_NONE + * File space page size: set to 512 + * + */ + for (new_format = FALSE; new_format <= TRUE; new_format++) { + hid_t my_fapl; + + /* Set the FAPL for the type of format */ + if (new_format) { + MESSAGE(5, ("Testing with new group format\n")); + my_fapl = new_fapl; + } /* end if */ + else { + MESSAGE(5, ("Testing with old group format\n")); + my_fapl = fapl; + } /* end else */ + + /* Test with TRUE or FALSE for persisting free-space */ + for (fs_persist = FALSE; fs_persist <= TRUE; fs_persist++) { + + /* Test with free-space section threshold size: 0 to 10 */ + for (fs_threshold = 0; fs_threshold <= TEST_THRESHOLD10; fs_threshold++) { + + /* Test with 4 file space strategies */ + for (fs_strategy = H5F_FSPACE_STRATEGY_FSM_AGGR; fs_strategy < H5F_FSPACE_STRATEGY_NTYPES; + fs_strategy++) { + + if (!contig_addr_vfd && (fs_strategy == H5F_FSPACE_STRATEGY_PAGE || fs_persist)) + continue; + + /* Create file creation property list template */ + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, FAIL, "H5Pcreate"); + + /* Set file space information */ + ret = H5Pset_file_space_strategy(fcpl, fs_strategy, (hbool_t)fs_persist, fs_threshold); + CHECK(ret, FAIL, "H5Pset_file_space_strategy"); + + ret = H5Pset_file_space_page_size(fcpl, FSP_SIZE512); + CHECK(ret, FAIL, "H5Pset_file_space_strategy"); + + /* Retrieve file space information */ + ret = H5Pget_file_space_strategy(fcpl, &strategy, &persist, &threshold); + CHECK(ret, FAIL, "H5Pget_file_space_strategy"); + + /* Verify file space information */ + VERIFY(strategy, fs_strategy, "H5Pget_file_space_strategy"); + + if (fs_strategy < H5F_FSPACE_STRATEGY_AGGR) { + VERIFY(persist, (hbool_t)fs_persist, "H5Pget_file_space_strategy"); + VERIFY(threshold, fs_threshold, "H5Pget_file_space_strategy"); + } + else { + VERIFY(persist, FALSE, "H5Pget_file_space_strategy"); + VERIFY(threshold, 1, "H5Pget_file_space_strategy"); + } + + /* Retrieve and verify file space page size */ + ret = H5Pget_file_space_page_size(fcpl, &fsp_size); + CHECK(ret, FAIL, "H5Pget_file_space_page_size"); + VERIFY(fsp_size, FSP_SIZE512, "H5Pget_file_space_page_size"); + + /* Create the file with the specified file space info */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl, my_fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Get the file's creation property */ + fcpl1 = H5Fget_create_plist(fid); + CHECK(fcpl1, FAIL, "H5Fget_create_plist"); + + /* Retrieve file space information */ + ret = H5Pget_file_space_strategy(fcpl1, &strategy, &persist, &threshold); + CHECK(ret, FAIL, "H5Pget_file_space_strategy"); + + /* Verify file space information */ + VERIFY(strategy, fs_strategy, "H5Pget_file_space_strategy"); + + if (fs_strategy < H5F_FSPACE_STRATEGY_AGGR) { + VERIFY(persist, fs_persist, "H5Pget_file_space_strategy"); + VERIFY(threshold, fs_threshold, "H5Pget_file_space_strategy"); + } + else { + VERIFY(persist, FALSE, "H5Pget_file_space_strategy"); + VERIFY(threshold, 1, "H5Pget_file_space_strategy"); + } + + /* Retrieve and verify file space page size */ + ret = H5Pget_file_space_page_size(fcpl1, &fsp_size); + CHECK(ret, FAIL, "H5Pget_file_space_page_size"); + VERIFY(fsp_size, FSP_SIZE512, "H5Pget_file_space_page_size"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open the file */ + fid = H5Fopen(filename, H5F_ACC_RDWR, my_fapl); + CHECK(ret, FAIL, "H5Fopen"); + + /* Get the file's creation property */ + fcpl2 = H5Fget_create_plist(fid); + CHECK(fcpl2, FAIL, "H5Fget_create_plist"); + + /* Retrieve file space information */ + ret = H5Pget_file_space_strategy(fcpl2, &strategy, &persist, &threshold); + CHECK(ret, FAIL, "H5Pget_file_space_strategy"); + + /* Verify file space information */ + VERIFY(strategy, fs_strategy, "H5Pget_file_space_strategy"); + if (fs_strategy < H5F_FSPACE_STRATEGY_AGGR) { + VERIFY(persist, fs_persist, "H5Pget_file_space_strategy"); + VERIFY(threshold, fs_threshold, "H5Pget_file_space_strategy"); + } + else { + VERIFY(persist, FALSE, "H5Pget_file_space_strategy"); + VERIFY(threshold, 1, "H5Pget_file_space_strategy"); + } + + /* Retrieve and verify file space page size */ + ret = H5Pget_file_space_page_size(fcpl2, &fsp_size); + CHECK(ret, FAIL, "H5Pget_file_space_page_size"); + VERIFY(fsp_size, FSP_SIZE512, "H5Pget_file_space_page_size"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Release file creation property lists */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(fcpl1); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(fcpl2); + CHECK(ret, FAIL, "H5Pclose"); + } /* end for file space strategy type */ + } /* end for free-space section threshold */ + } /* end for fs_persist */ + + /* close fapl_ and remove the file */ +#if 0 + h5_clean_files(FILESPACE_NAME, my_fapl); +#endif + + H5E_BEGIN_TRY + { + H5Fdelete(FILESPACE_NAME[0], my_fapl); + } + H5E_END_TRY; + } /* end for new_format */ + +} /* test_filespace_info() */ +#endif + +/**************************************************************** +** +** set_multi_split(): +** Internal routine to set up page-aligned address space for multi/split driver +** when testing paged aggregation. +** This is used by test_file_freespace() and test_sects_freespace(). +** +*****************************************************************/ +#if 0 +static int +set_multi_split(hid_t fapl, hsize_t pagesize, hbool_t split) +{ + H5FD_mem_t memb_map[H5FD_MEM_NTYPES]; + hid_t memb_fapl_arr[H5FD_MEM_NTYPES]; + char *memb_name[H5FD_MEM_NTYPES]; + haddr_t memb_addr[H5FD_MEM_NTYPES]; + hbool_t relax; + H5FD_mem_t mt; + + HDassert(split); + + HDmemset(memb_name, 0, sizeof memb_name); + + /* Get current split settings */ + if (H5Pget_fapl_multi(fapl, memb_map, memb_fapl_arr, memb_name, memb_addr, &relax) < 0) + TEST_ERROR; + + if (split) { + /* Set memb_addr aligned */ + memb_addr[H5FD_MEM_SUPER] = ((memb_addr[H5FD_MEM_SUPER] + pagesize - 1) / pagesize) * pagesize; + memb_addr[H5FD_MEM_DRAW] = ((memb_addr[H5FD_MEM_DRAW] + pagesize - 1) / pagesize) * pagesize; + } + else { + /* Set memb_addr aligned */ + for (mt = H5FD_MEM_DEFAULT; mt < H5FD_MEM_NTYPES; mt++) + memb_addr[mt] = ((memb_addr[mt] + pagesize - 1) / pagesize) * pagesize; + } /* end else */ + + /* Set multi driver with new FAPLs */ + if (H5Pset_fapl_multi(fapl, memb_map, memb_fapl_arr, (const char *const *)memb_name, memb_addr, relax) < + 0) + TEST_ERROR; + + /* Free memb_name */ + for (mt = H5FD_MEM_DEFAULT; mt < H5FD_MEM_NTYPES; mt++) + HDfree(memb_name[mt]); + + return 0; + +error: + return (-1); + +} /* set_multi_split() */ +#endif + +/**************************************************************** +** +** test_file_freespace(): +** This routine checks the free space available in a file as +** returned by the public routine H5Fget_freespace(). +** +** +*****************************************************************/ +#if 0 +static void +test_file_freespace(const char *env_h5_drvr) +{ + hid_t file; /* File opened with read-write permission */ +#if 0 + h5_stat_size_t empty_filesize; /* Size of file when empty */ + h5_stat_size_t mod_filesize; /* Size of file after being modified */ + hssize_t free_space; /* Amount of free space in file */ +#endif + hid_t fcpl; /* File creation property list */ + hid_t fapl, new_fapl; /* File access property list IDs */ + hid_t dspace; /* Dataspace ID */ + hid_t dset; /* Dataset ID */ + hid_t dcpl; /* Dataset creation property list */ + int k; /* Local index variable */ + unsigned u; /* Local index variable */ + char filename[FILENAME_LEN]; /* Filename to use */ + char name[32]; /* Dataset name */ + unsigned new_format; /* To use old or new format */ + hbool_t split_vfd, multi_vfd; /* Indicate multi/split driver */ + hsize_t expected_freespace; /* Freespace expected */ + hsize_t expected_fs_del; /* Freespace expected after delete */ + herr_t ret; /* Return value */ + + split_vfd = !HDstrcmp(env_h5_drvr, "split"); + multi_vfd = !HDstrcmp(env_h5_drvr, "multi"); + + if (!split_vfd && !multi_vfd) { + fapl = h5_fileaccess(); + h5_fixname(FILESPACE_NAME[0], fapl, filename, sizeof filename); + + new_fapl = H5Pcopy(fapl); + CHECK(new_fapl, FAIL, "H5Pcopy"); + + /* Set the "use the latest version of the format" bounds */ + ret = H5Pset_libver_bounds(new_fapl, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST); + CHECK(ret, FAIL, "H5Pset_libver_bounds"); + + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, FAIL, "H5Pcreate"); + + /* Test with old & new format */ + for (new_format = FALSE; new_format <= TRUE; new_format++) { + hid_t my_fapl; + + /* Set the FAPL for the type of format */ + if (new_format) { + MESSAGE(5, ("Testing with new group format\n")); + + my_fapl = new_fapl; + + if (multi_vfd || split_vfd) { + ret = set_multi_split(new_fapl, FSP_SIZE_DEF, split_vfd); + CHECK(ret, FAIL, "set_multi_split"); + } + + ret = H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_PAGE, FALSE, (hsize_t)1); + CHECK(ret, FAIL, "H5P_set_file_space_strategy"); + + expected_freespace = 4534; + if (split_vfd) + expected_freespace = 427; + if (multi_vfd) + expected_freespace = 248; + expected_fs_del = 0; + } /* end if */ + else { + MESSAGE(5, ("Testing with old group format\n")); + /* Default: non-paged aggregation, non-persistent free-space */ + my_fapl = fapl; + expected_freespace = 2464; + if (split_vfd) + expected_freespace = 264; + if (multi_vfd) + expected_freespace = 0; + expected_fs_del = 4096; + + } /* end else */ + + /* Create an "empty" file */ + file = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl, my_fapl); + CHECK(file, FAIL, "H5Fcreate"); + + ret = H5Fclose(file); + CHECK_I(ret, "H5Fclose"); +#if 0 + /* Get the "empty" file size */ + empty_filesize = h5_get_file_size(filename, H5P_DEFAULT); +#endif + /* Re-open the file (with read-write permission) */ + file = H5Fopen(filename, H5F_ACC_RDWR, my_fapl); + CHECK_I(file, "H5Fopen"); +#if 0 + /* Check that the free space is 0 */ + free_space = H5Fget_freespace(file); + CHECK(free_space, FAIL, "H5Fget_freespace"); + VERIFY(free_space, 0, "H5Fget_freespace"); +#endif + /* Create dataspace for datasets */ + dspace = H5Screate(H5S_SCALAR); + CHECK(dspace, FAIL, "H5Screate"); + + /* Create a dataset creation property list */ + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + + /* Set the space allocation time to early */ + ret = H5Pset_alloc_time(dcpl, H5D_ALLOC_TIME_EARLY); + CHECK(ret, FAIL, "H5Pset_alloc_time"); + + /* Create datasets in file */ + for (u = 0; u < 10; u++) { + HDsnprintf(name, sizeof(name), "Dataset %u", u); + dset = H5Dcreate2(file, name, H5T_STD_U32LE, dspace, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset, FAIL, "H5Dcreate2"); + + ret = H5Dclose(dset); + CHECK(ret, FAIL, "H5Dclose"); + } /* end for */ + + /* Close dataspace */ + ret = H5Sclose(dspace); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close dataset creation property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); +#if 0 + /* Check that there is the right amount of free space in the file */ + free_space = H5Fget_freespace(file); + CHECK(free_space, FAIL, "H5Fget_freespace"); + VERIFY(free_space, expected_freespace, "H5Fget_freespace"); +#endif + /* Delete datasets in file */ + for (k = 9; k >= 0; k--) { + HDsnprintf(name, sizeof(name), "Dataset %u", (unsigned)k); + ret = H5Ldelete(file, name, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + } /* end for */ +#if 0 + /* Check that there is the right amount of free space in the file */ + free_space = H5Fget_freespace(file); + CHECK(free_space, FAIL, "H5Fget_freespace"); + VERIFY(free_space, expected_fs_del, "H5Fget_freespace"); +#endif + /* Close file */ + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); +#if 0 + /* Get the file size after modifications*/ + mod_filesize = h5_get_file_size(filename, H5P_DEFAULT); + + /* Check that the file reverted to empty size */ + VERIFY(mod_filesize, empty_filesize, "H5Fget_freespace"); + + h5_clean_files(FILESPACE_NAME, my_fapl); +#endif + H5Fdelete(FILESPACE_NAME[0], my_fapl); + } /* end for */ + } + +} /* end test_file_freespace() */ + +/**************************************************************** +** +** test_sects_freespace(): +** This routine checks free-space section information for the +** file as returned by the public routine H5Fget_free_sections(). +** +*****************************************************************/ +static void +test_sects_freespace(const char *env_h5_drvr, hbool_t new_format) +{ + char filename[FILENAME_LEN]; /* Filename to use */ + hid_t file; /* File ID */ + hid_t fcpl; /* File creation property list template */ + hid_t fapl; /* File access property list template */ +#if 0 + hssize_t free_space; /* Amount of free-space in the file */ +#endif + hid_t dspace; /* Dataspace ID */ + hid_t dset; /* Dataset ID */ + hid_t dcpl; /* Dataset creation property list */ + char name[32]; /* Dataset name */ + hssize_t nsects = 0; /* # of free-space sections */ + hssize_t nall; /* # of free-space sections for all types of data */ + hssize_t nmeta = 0, nraw = 0; /* # of free-space sections for meta/raw/generic data */ + H5F_sect_info_t sect_info[15]; /* Array to hold free-space information */ + H5F_sect_info_t all_sect_info[15]; /* Array to hold free-space information for all types of data */ + H5F_sect_info_t meta_sect_info[15]; /* Array to hold free-space information for metadata */ + H5F_sect_info_t raw_sect_info[15]; /* Array to hold free-space information for raw data */ + hsize_t total = 0; /* sum of the free-space section sizes */ + hsize_t tmp_tot = 0; /* Sum of the free-space section sizes */ + hsize_t last_size; /* Size of last free-space section */ + hsize_t dims[1]; /* Dimension sizes */ + unsigned u; /* Local index variable */ + H5FD_mem_t type; + hbool_t split_vfd = FALSE, multi_vfd = FALSE; + herr_t ret; /* Return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing H5Fget_free_sections()--free-space section info in the file\n")); + + split_vfd = !HDstrcmp(env_h5_drvr, "split"); + multi_vfd = !HDstrcmp(env_h5_drvr, "multi"); + + if (!split_vfd && !multi_vfd) { + + fapl = h5_fileaccess(); + h5_fixname(FILESPACE_NAME[0], fapl, filename, sizeof filename); + + /* Create file-creation template */ + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, FAIL, "H5Pcreate"); + + if (new_format) { + ret = H5Pset_libver_bounds(fapl, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST); + CHECK(ret, FAIL, "H5Pset_libver_bounds"); + + /* Set to paged aggregation and persistent free-space */ + ret = H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_PAGE, TRUE, (hsize_t)1); + CHECK(ret, FAIL, "H5Pget_file_space_strategy"); + + /* Set up paged aligned address space for multi/split driver */ + if (multi_vfd || split_vfd) { + ret = set_multi_split(fapl, FSP_SIZE_DEF, split_vfd); + CHECK(ret, FAIL, "set_multi_split"); + } + } + else { + ret = H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_FSM_AGGR, TRUE, (hsize_t)1); + CHECK(ret, FAIL, "H5Pget_file_space_strategy"); + } + + /* Create the file */ + file = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(file, FAIL, "H5Fcreate"); + + /* Create a dataset creation property list */ + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + + /* Set the space allocation time to early */ + ret = H5Pset_alloc_time(dcpl, H5D_ALLOC_TIME_EARLY); + CHECK(ret, FAIL, "H5Pset_alloc_time"); + + /* Create 1 large dataset */ + dims[0] = 1200; + dspace = H5Screate_simple(1, dims, NULL); + dset = H5Dcreate2(file, "Dataset_large", H5T_STD_U32LE, dspace, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset, FAIL, "H5Dcreate2"); + + /* Close dataset */ + ret = H5Dclose(dset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close dataspace */ + ret = H5Sclose(dspace); + CHECK(ret, FAIL, "H5Sclose"); + + /* Create dataspace for datasets */ + dspace = H5Screate(H5S_SCALAR); + CHECK(dspace, FAIL, "H5Screate"); + + /* Create datasets in file */ + for (u = 0; u < 10; u++) { + HDsnprintf(name, sizeof(name), "Dataset %u", u); + dset = H5Dcreate2(file, name, H5T_STD_U32LE, dspace, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset, FAIL, "H5Dcreate2"); + + ret = H5Dclose(dset); + CHECK(ret, FAIL, "H5Dclose"); + } /* end for */ + + /* Close dataspace */ + ret = H5Sclose(dspace); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close dataset creation property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Delete odd-numbered datasets in file */ + for (u = 0; u < 10; u++) { + HDsnprintf(name, sizeof(name), "Dataset %u", u); + if (u % 2) { + ret = H5Ldelete(file, name, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + } /* end if */ + } /* end for */ + + /* Close file */ + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open the file with read-only permission */ + file = H5Fopen(filename, H5F_ACC_RDONLY, fapl); + CHECK_I(file, "H5Fopen"); +#if 0 + /* Get the amount of free space in the file */ + free_space = H5Fget_freespace(file); + CHECK(free_space, FAIL, "H5Fget_freespace"); +#endif + /* Get the total # of free-space sections in the file */ + nall = H5Fget_free_sections(file, H5FD_MEM_DEFAULT, (size_t)0, NULL); + CHECK(nall, FAIL, "H5Fget_free_sections"); + + /* Should return failure when nsects is 0 with a nonnull sect_info */ + nsects = H5Fget_free_sections(file, H5FD_MEM_DEFAULT, (size_t)0, all_sect_info); + VERIFY(nsects, FAIL, "H5Fget_free_sections"); + + /* Retrieve and verify free space info for all the sections */ + HDmemset(all_sect_info, 0, sizeof(all_sect_info)); + nsects = H5Fget_free_sections(file, H5FD_MEM_DEFAULT, (size_t)nall, all_sect_info); + VERIFY(nsects, nall, "H5Fget_free_sections"); + + /* Verify the amount of free-space is correct */ + for (u = 0; u < nall; u++) + total += all_sect_info[u].size; +#if 0 + VERIFY(free_space, total, "H5Fget_free_sections"); +#endif + /* Save the last section's size */ + last_size = all_sect_info[nall - 1].size; + + /* Retrieve and verify free space info for -1 sections */ + HDmemset(sect_info, 0, sizeof(sect_info)); + nsects = H5Fget_free_sections(file, H5FD_MEM_DEFAULT, (size_t)(nall - 1), sect_info); + VERIFY(nsects, nall, "H5Fget_free_sections"); + + /* Verify the amount of free-space is correct */ + total = 0; + for (u = 0; u < (nall - 1); u++) { + VERIFY(sect_info[u].addr, all_sect_info[u].addr, "H5Fget_free_sections"); + VERIFY(sect_info[u].size, all_sect_info[u].size, "H5Fget_free_sections"); + total += sect_info[u].size; + } +#if 0 + VERIFY(((hsize_t)free_space - last_size), total, "H5Fget_free_sections"); +#endif + /* Retrieve and verify free-space info for +1 sections */ + HDmemset(sect_info, 0, sizeof(sect_info)); + nsects = H5Fget_free_sections(file, H5FD_MEM_DEFAULT, (size_t)(nall + 1), sect_info); + VERIFY(nsects, nall, "H5Fget_free_sections"); + + /* Verify amount of free-space is correct */ + total = 0; + for (u = 0; u < nall; u++) { + VERIFY(sect_info[u].addr, all_sect_info[u].addr, "H5Fget_free_sections"); + VERIFY(sect_info[u].size, all_sect_info[u].size, "H5Fget_free_sections"); + total += sect_info[u].size; + } + VERIFY(sect_info[nall].addr, 0, "H5Fget_free_sections"); + VERIFY(sect_info[nall].size, 0, "H5Fget_free_sections"); +#if 0 + VERIFY(free_space, total, "H5Fget_free_sections"); +#endif + + HDmemset(meta_sect_info, 0, sizeof(meta_sect_info)); + if (multi_vfd) { + hssize_t ntmp; + + for (type = H5FD_MEM_SUPER; type < H5FD_MEM_NTYPES; type++) { + if (type == H5FD_MEM_DRAW || type == H5FD_MEM_GHEAP) + continue; + /* Get the # of free-space sections in the file for metadata */ + ntmp = H5Fget_free_sections(file, type, (size_t)0, NULL); + CHECK(ntmp, FAIL, "H5Fget_free_sections"); + + if (ntmp > 0) { + nsects = H5Fget_free_sections(file, type, (size_t)ntmp, &meta_sect_info[nmeta]); + VERIFY(nsects, ntmp, "H5Fget_free_sections"); + nmeta += ntmp; + } + } + } + else { + /* Get the # of free-space sections in the file for metadata */ + nmeta = H5Fget_free_sections(file, H5FD_MEM_SUPER, (size_t)0, NULL); + CHECK(nmeta, FAIL, "H5Fget_free_sections"); + + /* Retrieve and verify free-space sections for metadata */ + nsects = H5Fget_free_sections(file, H5FD_MEM_SUPER, (size_t)nmeta, meta_sect_info); + VERIFY(nsects, nmeta, "H5Fget_free_sections"); + } + + /* Get the # of free-space sections in the file for raw data */ + nraw = H5Fget_free_sections(file, H5FD_MEM_DRAW, (size_t)0, NULL); + CHECK(nraw, FAIL, "H5Fget_free_sections"); + + /* Retrieve and verify free-space sections for raw data */ + HDmemset(raw_sect_info, 0, sizeof(raw_sect_info)); + nsects = H5Fget_free_sections(file, H5FD_MEM_DRAW, (size_t)nraw, raw_sect_info); + VERIFY(nsects, nraw, "H5Fget_free_sections"); + + /* Sum all the free-space sections */ + for (u = 0; u < nmeta; u++) + tmp_tot += meta_sect_info[u].size; + + for (u = 0; u < nraw; u++) + tmp_tot += raw_sect_info[u].size; + + /* Verify free-space info */ + VERIFY(nmeta + nraw, nall, "H5Fget_free_sections"); + VERIFY(tmp_tot, total, "H5Fget_free_sections"); + + /* Closing */ + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + ret = H5Pclose(fcpl); + CHECK(fcpl, FAIL, "H5Pclose"); +#if 0 + h5_clean_files(FILESPACE_NAME, fapl); +#endif + H5Fdelete(FILESPACE_NAME[0], fapl); + } + +} /* end test_sects_freespace() */ +#endif + +/**************************************************************** +** +** test_filespace_compatible(): +** Verify that the trunk with the latest file space management +** can open, read and modify 1.6 HDF5 file and 1.8 HDF5 file. +** Also verify the correct file space handling information +** and the amount of free space. +** +****************************************************************/ +#if 0 +static void +test_filespace_compatible(void) +{ + int fd_old = (-1), fd_new = (-1); /* File descriptors for copying data */ + hid_t fid = -1; /* File id */ + hid_t did = -1; /* Dataset id */ + hid_t fcpl; /* File creation property list template */ + int check[100]; /* Temporary buffer for verifying dataset data */ + int rdbuf[100]; /* Temporary buffer for reading in dataset data */ + uint8_t buf[READ_OLD_BUFSIZE]; /* temporary buffer for reading */ + ssize_t nread; /* Number of bytes read in */ + unsigned i, j; /* Local index variable */ + hssize_t free_space; /* Amount of free-space in the file */ + hbool_t persist; /* Persist free-space or not */ + hsize_t threshold; /* Free-space section threshold */ + H5F_fspace_strategy_t strategy; /* File space handling strategy */ + herr_t ret; /* Return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("File space compatibility testing for 1.6 and 1.8 files\n")); + + for (j = 0; j < NELMTS(OLD_FILENAME); j++) { + const char *filename = H5_get_srcdir_filename(OLD_FILENAME[j]); /* Corrected test file name */ + + /* Open and copy the test file into a temporary file */ + fd_old = HDopen(filename, O_RDONLY); + CHECK(fd_old, FAIL, "HDopen"); + fd_new = HDopen(FILE5, O_RDWR | O_CREAT | O_TRUNC, H5_POSIX_CREATE_MODE_RW); + CHECK(fd_new, FAIL, "HDopen"); + + /* Copy data */ + while ((nread = HDread(fd_old, buf, (size_t)READ_OLD_BUFSIZE)) > 0) { + ssize_t write_err = HDwrite(fd_new, buf, (size_t)nread); + CHECK(write_err, -1, "HDwrite"); + } /* end while */ + + /* Close the files */ + ret = HDclose(fd_old); + CHECK(ret, FAIL, "HDclose"); + ret = HDclose(fd_new); + CHECK(ret, FAIL, "HDclose"); + + /* Open the temporary test file */ + fid = H5Fopen(FILE5, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* There should not be any free space in the file */ + free_space = H5Fget_freespace(fid); + CHECK(free_space, FAIL, "H5Fget_freespace"); + VERIFY(free_space, (hssize_t)0, "H5Fget_freespace"); + + /* Get the file's file creation property list */ + fcpl = H5Fget_create_plist(fid); + CHECK(fcpl, FAIL, "H5Fget_create_plist"); + + /* Retrieve the file space info */ + ret = H5Pget_file_space_strategy(fcpl, &strategy, &persist, &threshold); + CHECK(ret, FAIL, "H5Pget_file_space_strategy"); + + /* File space handling strategy should be H5F_FSPACE_STRATEGY_FSM_AGGR */ + /* Persisting free-space should be FALSE */ + /* Free-space section threshold should be 1 */ + VERIFY(strategy, H5F_FSPACE_STRATEGY_FSM_AGGR, "H5Pget_file_space_strategy"); + VERIFY(persist, FALSE, "H5Pget_file_space_strategy"); + VERIFY(threshold, 1, "H5Pget_file_space_strategy"); + + /* Generate raw data */ + for (i = 0; i < 100; i++) + check[i] = (int)i; + + /* Open and read the dataset */ + did = H5Dopen2(fid, DSETNAME, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen"); + ret = H5Dread(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &rdbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Verify the data read is correct */ + for (i = 0; i < 100; i++) + VERIFY(rdbuf[i], check[i], "test_compatible"); + + /* Close the dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* Remove the dataset */ + ret = H5Ldelete(fid, DSETNAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + + /* Close the plist */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-Open the file */ + fid = H5Fopen(FILE5, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* The dataset should not be there */ + did = H5Dopen2(fid, DSETNAME, H5P_DEFAULT); + VERIFY(did, FAIL, "H5Dopen"); + + /* There should not be any free space in the file */ + free_space = H5Fget_freespace(fid); + CHECK(free_space, FAIL, "H5Fget_freespace"); + VERIFY(free_space, (hssize_t)0, "H5Fget_freespace"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + } /* end for */ +} /* test_filespace_compatible */ +#endif + +/**************************************************************** +** +** test_filespace_1.10.0_compatible(): +** Verify that the latest file space management can open, read and +** modify 1.10.0 HDF5 files : +** h5fc_ext1_i.h5: H5F_FILE_SPACE_ALL, default threshold; has superblock extension but no fsinfo message +** h5fc_ext1_f.h5: H5F_FILE_SPACE_ALL_PERSIST, default threshold; has superblock extension with fsinfo +*message +** h5fc_ext2_if.h5: H5F_FILE_SPACE_ALL, non-default threshold; has superblock extension with fsinfo +*message +** h5fc_ext2_sf.h5: H5F_FILE_SPACE_VFD, default threshold; has superblock extension with fsinfo message +** h5fc_ext3_isf.h5: H5F_FILE_SPACE_AGGR_VFD, default threshold; has superblock extension with fsinfo +*message +** h5fc_ext_none.h5: H5F_FILE_SPACE_ALL, default threshold; without superblock extension +** The above files are copied from release 1.10.0 tools/h5format_convert/testfiles. +** +****************************************************************/ +#if 0 +static void +test_filespace_1_10_0_compatible(void) +{ + hid_t fid = -1; /* File id */ + hid_t did = -1; /* Dataset id */ + hid_t fcpl; /* File creation property list */ + hbool_t persist; /* Persist free-space or not */ + hsize_t threshold; /* Free-space section threshold */ + H5F_fspace_strategy_t strategy; /* File space handling strategy */ + int wbuf[24]; /* Buffer for dataset data */ + int rdbuf[24]; /* Buffer for dataset data */ + int status; /* Status from copying the existing file */ + unsigned i, j; /* Local index variable */ + herr_t ret; /* Return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("File space compatibility testing for 1.10.0 files\n")); + + for (j = 0; j < NELMTS(OLD_1_10_0_FILENAME); j++) { + /* Make a copy of the test file */ + status = h5_make_local_copy(OLD_1_10_0_FILENAME[j], FILE5); + CHECK(status, FAIL, "h5_make_local_copy"); + + /* Open the temporary test file */ + fid = H5Fopen(FILE5, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* Get the file's file creation property list */ + fcpl = H5Fget_create_plist(fid); + CHECK(fcpl, FAIL, "H5Fget_create_plist"); + + /* Retrieve the file space info */ + ret = H5Pget_file_space_strategy(fcpl, &strategy, &persist, &threshold); + CHECK(ret, FAIL, "H5Pget_file_space_strategy"); + + switch (j) { + case 0: +#if 0 + VERIFY(strategy, H5F_FILE_SPACE_STRATEGY_DEF, "H5Pget_file_space_strategy"); + VERIFY(persist, H5F_FREE_SPACE_PERSIST_DEF, "H5Pget_file_space_strategy"); + VERIFY(threshold, H5F_FREE_SPACE_THRESHOLD_DEF, "H5Pget_file_space_strategy"); +#endif + /* Open the dataset */ + did = H5Dopen2(fid, "/DSET_EA", H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen"); + + for (i = 0; i < 24; i++) + wbuf[i] = (int)j + 1; + + /* Write to the dataset */ + ret = H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close the dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + break; + + case 1: + VERIFY(strategy, H5F_FSPACE_STRATEGY_FSM_AGGR, "H5Pget_file_space_strategy"); + VERIFY(persist, TRUE, "H5Pget_file_space_strategy"); +#if 0 + VERIFY(threshold, H5F_FREE_SPACE_THRESHOLD_DEF, "H5Pget_file_space_strategy"); +#endif + + /* Open the dataset */ + did = H5Dopen2(fid, "/DSET_NDATA_BT2", H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen"); + + for (i = 0; i < 24; i++) + wbuf[i] = (int)j + 1; + + /* Write to the dataset */ + ret = H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close the dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + break; + + case 2: + VERIFY(strategy, H5F_FSPACE_STRATEGY_FSM_AGGR, "H5Pget_file_space_strategy"); +#if 0 + VERIFY(persist, H5F_FREE_SPACE_PERSIST_DEF, "H5Pget_file_space_strategy"); +#endif + VERIFY(threshold, 2, "H5Pget_file_space_strategy"); + + /* Open the dataset */ + did = H5Dopen2(fid, "/DSET_NONE", H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen"); + + for (i = 0; i < 24; i++) + wbuf[i] = (int)j + 1; + + /* Write to the dataset */ + ret = H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close the dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + break; + + case 3: + VERIFY(strategy, H5F_FSPACE_STRATEGY_NONE, "H5Pget_file_space_strategy"); +#if 0 + VERIFY(persist, H5F_FREE_SPACE_PERSIST_DEF, "H5Pget_file_space_strategy"); + VERIFY(threshold, H5F_FREE_SPACE_THRESHOLD_DEF, "H5Pget_file_space_strategy"); +#endif + /* Open the dataset */ + did = H5Dopen2(fid, "/GROUP/DSET_NDATA_EA", H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen"); + + for (i = 0; i < 24; i++) + wbuf[i] = (int)j + 1; + + /* Write to the dataset */ + ret = H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close the dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + break; + + case 4: + VERIFY(strategy, H5F_FSPACE_STRATEGY_AGGR, "H5Pget_file_space_strategy"); +#if 0 + VERIFY(persist, H5F_FREE_SPACE_PERSIST_DEF, "H5Pget_file_space_strategy"); + VERIFY(threshold, H5F_FREE_SPACE_THRESHOLD_DEF, "H5Pget_file_space_strategy"); +#endif + /* Open the dataset */ + did = H5Dopen2(fid, "/GROUP/DSET_NDATA_FA", H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen"); + + for (i = 0; i < 24; i++) + wbuf[i] = (int)j + 1; + + /* Write to the dataset */ + ret = H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close the dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + break; + case 5: + VERIFY(strategy, H5F_FSPACE_STRATEGY_FSM_AGGR, "H5Pget_file_space_strategy"); +#if 0 + VERIFY(persist, H5F_FREE_SPACE_PERSIST_DEF, "H5Pget_file_space_strategy"); + VERIFY(threshold, H5F_FREE_SPACE_THRESHOLD_DEF, "H5Pget_file_space_strategy"); +#endif + /* Open the dataset */ + did = H5Dopen2(fid, "/GROUP/DSET_NDATA_NONE", H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen"); + + for (i = 0; i < 24; i++) + wbuf[i] = (int)j + 1; + + /* Write to the dataset */ + ret = H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close the dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + break; + + default: + break; + } + + /* Close the plist */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-Open the file */ + fid = H5Fopen(FILE5, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + switch (j) { + case 0: + /* Open and read the dataset */ + did = H5Dopen2(fid, "/DSET_EA", H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen"); + + ret = H5Dread(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &rdbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Verify the data read is correct */ + for (i = 0; i < 24; i++) + VERIFY(rdbuf[i], j + 1, "test_compatible"); + + /* Close the dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + break; + + case 1: + /* Open and read the dataset */ + did = H5Dopen2(fid, "/DSET_NDATA_BT2", H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen"); + + ret = H5Dread(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &rdbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Verify the data read is correct */ + for (i = 0; i < 24; i++) + VERIFY(rdbuf[i], j + 1, "test_compatible"); + + /* Close the dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + break; + + case 2: + /* Open and read the dataset */ + did = H5Dopen2(fid, "/DSET_NONE", H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen"); + + ret = H5Dread(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &rdbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Verify the data read is correct */ + for (i = 0; i < 24; i++) + VERIFY(rdbuf[i], j + 1, "test_compatible"); + + /* Close the dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + break; + + case 3: + /* Open and read the dataset */ + did = H5Dopen2(fid, "/GROUP/DSET_NDATA_EA", H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen"); + + ret = H5Dread(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &rdbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Verify the data read is correct */ + for (i = 0; i < 24; i++) + VERIFY(rdbuf[i], j + 1, "test_compatible"); + + /* Close the dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + break; + + case 4: + + /* Open and read the dataset */ + did = H5Dopen2(fid, "/GROUP/DSET_NDATA_FA", H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen"); + + ret = H5Dread(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &rdbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Verify the data read is correct */ + for (i = 0; i < 24; i++) + VERIFY(rdbuf[i], j + 1, "test_compatible"); + + /* Close the dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + break; + + case 5: + + /* Open and read the dataset */ + did = H5Dopen2(fid, "/GROUP/DSET_NDATA_NONE", H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen"); + + ret = H5Dread(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &rdbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Verify the data read is correct */ + for (i = 0; i < 24; i++) + VERIFY(rdbuf[i], j + 1, "test_compatible"); + + /* Close the dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + break; + + default: + break; + } + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + } /* end for */ + +} /* test_filespace_1_10_0_compatible */ +#endif + +/**************************************************************** +** +** test_filespace_round_compatible(): +** Verify that the trunk can open, read and modify these files-- +** 1) They are initially created (via gen_filespace.c) in the trunk +** with combinations of file space strategies, default/non-default +** threshold, and file spacing paging enabled/disabled. +** The library creates the file space info message with +** "mark if unknown" in these files. +** 2) They are copied to the 1.8 branch, and are opened/read/modified +** there via test_filespace_compatible() in test/tfile.c. +** The 1.8 library marks the file space info message as "unknown" +** in these files. +** 3) They are then copied back from the 1.8 branch to the trunk for +** compatibility testing via this routine. +** 4) Upon encountering the file space info message which is marked +** as "unknown", the library will use the default file space management +** from then on: non-persistent free-space managers, default threshold, +** and non-paging file space. +** +****************************************************************/ +#if 0 +static void +test_filespace_round_compatible(void) +{ + hid_t fid = -1; /* File id */ + hid_t fcpl = -1; /* File creation property list ID */ + unsigned j; /* Local index variable */ + H5F_fspace_strategy_t strategy; /* File space strategy */ + hbool_t persist; /* Persist free-space or not */ + hsize_t threshold; /* Free-space section threshold */ + hssize_t free_space; /* Amount of free space in the file */ + int status; /* Status from copying the existing file */ + herr_t ret; /* Return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("File space compatibility testing for files from trunk to 1_8 to trunk\n")); + + for (j = 0; j < NELMTS(FSPACE_FILENAMES); j++) { + /* Make a copy of the test file */ + status = h5_make_local_copy(FSPACE_FILENAMES[j], FILE5); + CHECK(status, FAIL, "h5_make_local_copy"); + + /* Open the temporary test file */ + fid = H5Fopen(FILE5, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* Get the file's creation property list */ + fcpl = H5Fget_create_plist(fid); + CHECK(fcpl, FAIL, "H5Fget_create_plist"); + + ret = H5Pget_file_space_strategy(fcpl, &strategy, &persist, &threshold); + CHECK(ret, FAIL, "H5Pget_file_space_strategy"); + VERIFY(strategy, H5F_FSPACE_STRATEGY_FSM_AGGR, "H5Pget_file_space_strategy"); + VERIFY(persist, FALSE, "H5Pget_file_space_strategy"); + VERIFY(threshold, 1, "H5Pget_file_space_strategy"); + + /* There should not be any free space in the file */ + free_space = H5Fget_freespace(fid); + CHECK(free_space, FAIL, "H5Fget_freespace"); + VERIFY(free_space, (hssize_t)0, "H5Fget_freespace"); + + /* Closing */ + ret = H5Fclose(fid); + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Fclose"); + } /* end for */ + +} /* test_filespace_round_compatible */ + +/**************************************************************** +** +** test_libver_bounds_real(): +** Verify that a file created and modified with the +** specified libver bounds has the specified object header +** versions for the right objects. +** +****************************************************************/ +static void +test_libver_bounds_real(H5F_libver_t libver_create, unsigned oh_vers_create, H5F_libver_t libver_mod, + unsigned oh_vers_mod) +{ + hid_t file, group; /* Handles */ + hid_t fapl; /* File access property list */ + H5O_native_info_t ninfo; /* Object info */ + herr_t ret; /* Return value */ + + /* + * Create a new file using the creation properties. + */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + + ret = H5Pset_libver_bounds(fapl, libver_create, H5F_LIBVER_LATEST); + CHECK(ret, FAIL, "H5Pset_libver_bounds"); + + file = H5Fcreate("tfile5.h5", H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(file, FAIL, "H5Fcreate"); + + /* + * Make sure the root group has the correct object header version + */ + ret = H5Oget_native_info_by_name(file, "/", &ninfo, H5O_NATIVE_INFO_HDR, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_native_info_by_name"); + VERIFY(ninfo.hdr.version, oh_vers_create, "H5Oget_native_info_by_name"); + + /* + * Reopen the file and make sure the root group still has the correct version + */ + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + + ret = H5Pset_libver_bounds(fapl, libver_mod, H5F_LIBVER_LATEST); + CHECK(ret, FAIL, "H5Pset_libver_bounds"); + + file = H5Fopen("tfile5.h5", H5F_ACC_RDWR, fapl); + CHECK(file, FAIL, "H5Fopen"); + + ret = H5Oget_native_info_by_name(file, "/", &ninfo, H5O_NATIVE_INFO_HDR, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_native_info_by_name"); + VERIFY(ninfo.hdr.version, oh_vers_create, "H5Oget_native_info_by_name"); + + /* + * Create a group named "G1" in the file, and make sure it has the correct + * object header version + */ + group = H5Gcreate2(file, "/G1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(group, FAIL, "H5Gcreate"); + + //! [H5Oget_native_info_snip] + + ret = H5Oget_native_info(group, &ninfo, H5O_NATIVE_INFO_HDR); + + //! [H5Oget_native_info_snip] + + CHECK(ret, FAIL, "H5Oget_native)info"); + VERIFY(ninfo.hdr.version, oh_vers_mod, "H5Oget_native_info"); + + ret = H5Gclose(group); + CHECK(ret, FAIL, "H5Gclose"); + + /* + * Create a group named "/G1/G3" in the file, and make sure it has the + * correct object header version + */ + group = H5Gcreate2(file, "/G1/G3", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(group, FAIL, "H5Gcreate"); + + ret = H5Oget_native_info(group, &ninfo, H5O_NATIVE_INFO_HDR); + CHECK(ret, FAIL, "H5Oget_native_info"); + VERIFY(ninfo.hdr.version, oh_vers_mod, "H5Oget_native_info"); + + ret = H5Gclose(group); + CHECK(ret, FAIL, "H5Gclose"); + + //! [H5Oget_native_info_by_name_snip] + + /* + * Make sure the root group still has the correct object header version + */ + ret = H5Oget_native_info_by_name(file, "/", &ninfo, H5O_NATIVE_INFO_HDR, H5P_DEFAULT); + + //! [H5Oget_native_info_by_name_snip] + + CHECK(ret, FAIL, "H5Oget_native_info_by_name"); + VERIFY(ninfo.hdr.version, oh_vers_create, "H5Oget_native_info_by_name"); + + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); +} /* end test_libver_bounds_real() */ +#endif + +/*------------------------------------------------------------------------- + * Function: test_libver_bounds_open + * + * Purpose: Tests opening latest file with various low/high bounds. + * + * Return: Success: 0 + * Failure: number of errors + * + *------------------------------------------------------------------------- + */ +#if 0 +#define VERBFNAME "tverbounds_dspace.h5" +#define VERBDSNAME "dataset 1" +#define SPACE1_DIM1 3 +static void +test_libver_bounds_open(void) +{ + hid_t file = -1; /* File ID */ + hid_t space = -1; /* Dataspace ID */ + hid_t dset = -1; /* Dataset ID */ + hid_t fapl = -1; /* File access property list ID */ + hid_t new_fapl = -1; /* File access property list ID for reopened file */ + hid_t dcpl = -1; /* Dataset creation property list ID */ + hsize_t dim[1] = {SPACE1_DIM1}; /* Dataset dimensions */ + H5F_libver_t low, high; /* File format bounds */ + hsize_t chunk_dim[1] = {SPACE1_DIM1}; /* Chunk dimensions */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Opening File in Various Version Bounds\n")); + + /* Create a file access property list */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + + /* Create dataspace */ + space = H5Screate_simple(1, dim, NULL); + CHECK(space, FAIL, "H5Screate_simple"); + + /* Create a dataset creation property list */ + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + + /* Create and set chunk plist */ + ret = H5Pset_chunk(dcpl, 1, chunk_dim); + CHECK(ret, FAIL, "H5Pset_chunk"); + ret = H5Pset_deflate(dcpl, 9); + CHECK(ret, FAIL, "H5Pset_deflate"); + ret = H5Pset_chunk_opts(dcpl, H5D_CHUNK_DONT_FILTER_PARTIAL_CHUNKS); + CHECK(ret, FAIL, "H5Pset_chunk_opts"); + + /* Create a file with (LATEST, LATEST) bounds, create a layout version 4 + dataset, then close the file */ + + /* Set version bounds to (LATEST, LATEST) */ + low = H5F_LIBVER_LATEST; + high = H5F_LIBVER_LATEST; + ret = H5Pset_libver_bounds(fapl, low, high); + CHECK(ret, FAIL, "H5Pset_libver_bounds"); + + /* Create the file */ + file = H5Fcreate(VERBFNAME, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(file, FAIL, "H5Fcreate"); + + /* Create dataset */ + dset = H5Dcreate2(file, VERBDSNAME, H5T_NATIVE_INT, space, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset, FAIL, "H5Dcreate2"); + + /* Close dataset and file */ + ret = H5Dclose(dset); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + + /* Attempt to open latest file with (earliest, v18), should fail */ + ret = H5Pset_libver_bounds(fapl, H5F_LIBVER_EARLIEST, H5F_LIBVER_V18); + H5E_BEGIN_TRY + { + file = H5Fopen(VERBFNAME, H5F_ACC_RDONLY, fapl); + } + H5E_END_TRY; + VERIFY(file, FAIL, "Attempted to open latest file with earliest version"); + + /* Attempt to open latest file with (v18, v18), should fail */ + ret = H5Pset_libver_bounds(fapl, H5F_LIBVER_V18, H5F_LIBVER_V18); + H5E_BEGIN_TRY + { + file = H5Fopen(VERBFNAME, H5F_ACC_RDONLY, fapl); + } + H5E_END_TRY; + VERIFY(file, FAIL, "Attempted to open latest file with v18 bounds"); + + /* Opening VERBFNAME in these combination should succeed. + For each low bound, verify that it is upgraded properly */ + high = H5F_LIBVER_LATEST; + for (low = H5F_LIBVER_EARLIEST; low < H5F_LIBVER_NBOUNDS; low++) { + H5F_libver_t new_low = H5F_LIBVER_EARLIEST; + + /* Set version bounds for opening file */ + ret = H5Pset_libver_bounds(fapl, low, high); + CHECK(ret, FAIL, "H5Pset_libver_bounds"); + + /* Open the file */ + file = H5Fopen(VERBFNAME, H5F_ACC_RDONLY, fapl); + CHECK(file, FAIL, "H5Fopen"); + + /* Get the new file access property */ + new_fapl = H5Fget_access_plist(file); + CHECK(new_fapl, FAIL, "H5Fget_access_plist"); + + /* Get new low bound and verify that it has been upgraded properly */ + ret = H5Pget_libver_bounds(new_fapl, &new_low, NULL); + CHECK(ret, FAIL, "H5Pget_libver_bounds"); + VERIFY(new_low >= H5F_LIBVER_V110, TRUE, "Low bound should be upgraded to at least H5F_LIBVER_V110"); + + ret = H5Pclose(new_fapl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + } /* for low */ + + /* Close dataspace and property lists */ + ret = H5Sclose(space); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); +} /* end test_libver_bounds_open() */ +#endif + +/*------------------------------------------------------------------------- + * Function: test_libver_bounds_copy + * + * Purpose: Test to verify HDFFV-10800 is fixed: + * This test is copied from the user test program: copy10.c. + * (See attached programs in the jira issue.) + * + * The source file used in the test is generated by the user test + * program "fill18.c" with the 1.8 library. The file is created + * with the latest format and the dataset created in the file + * has version 3 fill value message (latest). + * + * The test creates the destination file with (v18, v18) version bounds. + * H5Ocopy() should succeed in copying the dataset in the source file + * to the destination file. + * + * Return: Success: 0 + * Failure: number of errors + * + *------------------------------------------------------------------------- + */ +#if 0 +static void +test_libver_bounds_copy(void) +{ + hid_t src_fid = -1; /* File ID */ + hid_t dst_fid = -1; /* File ID */ + hid_t fapl = -1; /* File access property list ID */ + const char *src_fname; /* Source file name */ + herr_t ret; /* Generic return value */ + hbool_t driver_is_default_compatible; + + /* Output message about the test being performed */ + MESSAGE(5, ("Testing H5Ocopy a dataset in a 1.8 library file to a 1.10 library file\n")); + + ret = h5_driver_is_default_vfd_compatible(H5P_DEFAULT, &driver_is_default_compatible); + CHECK_I(ret, "h5_driver_is_default_vfd_compatible"); + + if (!driver_is_default_compatible) { + HDprintf("-- SKIPPED --\n"); + return; + } + + /* Get the test file name */ + src_fname = H5_get_srcdir_filename(SRC_FILE); + + /* Open the source test file */ + src_fid = H5Fopen(src_fname, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(src_fid, FAIL, "H5Fopen"); + + /* Create file access property list */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + + /* Set library version bounds to (v18, v18) */ + ret = H5Pset_libver_bounds(fapl, H5F_LIBVER_V18, H5F_LIBVER_V18); + CHECK(ret, FAIL, "H5Pset_libver_bounds"); + + /* Create the destination file with the fapl */ + dst_fid = H5Fcreate(DST_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(dst_fid, FAIL, "H5Pcreate"); + + /* Close the fapl */ + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Copy the dataset in the source file to the destination file */ + ret = H5Ocopy(src_fid, DSET_DS1, dst_fid, DSET_DS1, H5P_DEFAULT, H5P_DEFAULT); + VERIFY(ret, SUCCEED, "H5Ocopy"); + + /* Close the source file */ + ret = H5Fclose(src_fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Close the destination file */ + ret = H5Fclose(dst_fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Remove the destination file */ + H5Fdelete(DST_FILE, H5P_DEFAULT); + +} /* end test_libver_bounds_copy() */ +#endif + +/**************************************************************** +** +** test_libver_bounds(): +** Verify that a file created and modified with various +** libver bounds is handled correctly. (Further testing +** welcome) +** +****************************************************************/ +#if 0 +static void +test_libver_bounds(void) +{ + /* Output message about test being performed */ + MESSAGE(5, ("Testing setting library version bounds\n")); + + /* Run the tests */ + test_libver_bounds_real(H5F_LIBVER_EARLIEST, 1, H5F_LIBVER_LATEST, 2); + test_libver_bounds_real(H5F_LIBVER_LATEST, 2, H5F_LIBVER_EARLIEST, 2); + test_libver_bounds_open(); +#if 0 + test_libver_bounds_copy(); +#endif +} /* end test_libver_bounds() */ +#endif + +/************************************************************************************** +** +** test_libver_bounds_low_high(): +** Tests to verify that format versions are correct with the following five +** pairs of low/high version bounds set in fapl via H5Pset_libver_bounds(): +** (1) (earliest, v18) +** (2) (earliest, v110) +** (3) (v18, v18) +** (4) (v18, v110) +** (5) (v110, v110) +** +** For each pair of setting in fapl, verify format versions with the following +** six tests: +** (1) test_libver_bounds_super(fapl): superblock versions +** (2) test_libver_bounds_obj(fapl): object header versions +** (3) test_libver_bounds_dataset(fapl): message versions associated with dataset +** (4) test_libver_bounds_dataspace(fapl): dataspace message versions +** (5) test_libver_bounds_datatype(fapl): datatype message versions +** (6) test_libver_bounds_attributes(fapl): attribute message versions +** +**************************************************************************************/ +#if 0 +static void +test_libver_bounds_low_high(const char *env_h5_drvr) +{ + hid_t fapl = H5I_INVALID_HID; /* File access property list */ + H5F_libver_t low, high; /* Low and high bounds */ + herr_t ret; /* The return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing setting (low, high) format version bounds\n")); + + /* Create a file access property list */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, H5I_INVALID_HID, "H5Pcreate"); + + /* Loop through all the combinations of low/high version bounds */ + for (low = H5F_LIBVER_EARLIEST; low < H5F_LIBVER_NBOUNDS; low++) + for (high = H5F_LIBVER_EARLIEST; high < H5F_LIBVER_NBOUNDS; high++) { + + H5E_BEGIN_TRY + { + /* Set the low/high version bounds */ + ret = H5Pset_libver_bounds(fapl, low, high); + } + H5E_END_TRY; + + /* Should fail: invalid combinations */ + if (high == H5F_LIBVER_EARLIEST) { + VERIFY(ret, FAIL, "H5Pset_libver_bounds"); + continue; + } + + /* Should fail: invalid combinations */ + if (high < low) { + VERIFY(ret, FAIL, "H5Pset_libver_bounds"); + continue; + } + + /* All other combinations are valid and should succeed */ + VERIFY(ret, SUCCEED, "H5Pset_libver_bounds"); + + /* Tests to verify version bounds */ + test_libver_bounds_super(fapl, env_h5_drvr); + test_libver_bounds_obj(fapl); + test_libver_bounds_dataset(fapl); + test_libver_bounds_dataspace(fapl); + test_libver_bounds_datatype(fapl); + test_libver_bounds_attributes(fapl); + } + + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + +} /* end test_libver_bounds_low_high() */ +#endif + +/*********************************************************************** +** +** test_libver_bounds_super(): +** Verify superblock version with the following two tests: +** (1) test_libver_bounds_super_create(): +** --when creating a file with the input fapl and the fcpl +** that has the following feature enabled: +** (A) default fcpl +** (B) fcpl with v1-btee K value enabled +** (C) fcpl with shared messages enabled +** (D) fcpl with persistent free-space manager enabled +** +** (2) test_libver_bounds_super_open(): +** --when opening a file which is created with the input fapl +** and the fcpl setting as #A to #D above. +** +** These two tests are run with or without SWMR file access. +** +*************************************************************************/ +#if 0 +static void +test_libver_bounds_super(hid_t fapl, const char *env_h5_drvr) +{ + hid_t fcpl = H5I_INVALID_HID; /* File creation property list */ + herr_t ret; /* The return value */ + + /* Create a default fcpl: #A */ + /* This will result in superblock version 0 */ + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, H5I_INVALID_HID, "H5Pcreate"); + + /* Verify superblock version when creating a file with input fapl, + fcpl #A and with/without SWMR access */ + if (H5FD__supports_swmr_test(env_h5_drvr)) + test_libver_bounds_super_create(fapl, fcpl, TRUE, FALSE); + test_libver_bounds_super_create(fapl, fcpl, FALSE, FALSE); + + /* Verify superblock version when opening a file which is created + with input fapl, fcpl #A and with/without SWMR access */ + if (H5FD__supports_swmr_test(env_h5_drvr)) + test_libver_bounds_super_open(fapl, fcpl, TRUE, FALSE); + test_libver_bounds_super_open(fapl, fcpl, FALSE, FALSE); + + /* Close the fcpl */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Create a fcpl with v1-btree K value enabled: #B */ + /* This will result in superblock version 1 */ + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, H5I_INVALID_HID, "H5Pcreate"); + ret = H5Pset_istore_k(fcpl, 64); + CHECK(ret, FAIL, "H5Pset_istore_k"); + + /* Verify superblock version when creating a file with input fapl, + fcpl #B and with/without SWMR access */ + if (H5FD__supports_swmr_test(env_h5_drvr)) + test_libver_bounds_super_create(fapl, fcpl, TRUE, FALSE); + test_libver_bounds_super_create(fapl, fcpl, FALSE, FALSE); + + /* Verify superblock version when opening a file which is created + with input fapl, fcpl #B and with/without SWMR access */ + if (H5FD__supports_swmr_test(env_h5_drvr)) + test_libver_bounds_super_open(fapl, fcpl, TRUE, FALSE); + test_libver_bounds_super_open(fapl, fcpl, FALSE, FALSE); + + /* Close the fcpl */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Create a fcpl with shared messages enabled: #C */ + /* This will result in superblock version 2 */ + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, H5I_INVALID_HID, "H5Pcreate"); + ret = H5Pset_shared_mesg_nindexes(fcpl, 1); + CHECK(ret, FAIL, "H5Pset_shared_mesg_nindexes"); + ret = H5Pset_shared_mesg_index(fcpl, 0, H5O_SHMESG_ATTR_FLAG, 2); + CHECK(ret, FAIL, "H5Pset_shared_mesg_index"); + + /* Verify superblock version when creating a file with input fapl, + fcpl #C and with/without SWMR access */ + if (H5FD__supports_swmr_test(env_h5_drvr)) + test_libver_bounds_super_create(fapl, fcpl, TRUE, FALSE); + test_libver_bounds_super_create(fapl, fcpl, FALSE, FALSE); + + /* Verify superblock version when opening a file which is created + with input fapl, fcpl #C and with/without SWMR access */ + if (H5FD__supports_swmr_test(env_h5_drvr)) + test_libver_bounds_super_open(fapl, fcpl, TRUE, FALSE); + test_libver_bounds_super_open(fapl, fcpl, FALSE, FALSE); + + /* Close the fcpl */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + + if (h5_using_default_driver(env_h5_drvr)) { + /* Create a fcpl with persistent free-space manager enabled: #D */ + /* This will result in superblock version 2 */ + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, H5I_INVALID_HID, "H5Pcreate"); + ret = H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_FSM_AGGR, 1, (hsize_t)1); + CHECK(ret, FAIL, "H5Pset_file_space"); + + /* Verify superblock version when creating a file with input fapl, + fcpl #D and with/without SWMR access */ + if (H5FD__supports_swmr_test(env_h5_drvr)) + test_libver_bounds_super_create(fapl, fcpl, TRUE, TRUE); + test_libver_bounds_super_create(fapl, fcpl, FALSE, TRUE); + + /* Verify superblock version when opening a file which is created + with input fapl, fcpl #D and with/without SWMR access */ + if (H5FD__supports_swmr_test(env_h5_drvr)) + test_libver_bounds_super_open(fapl, fcpl, TRUE, TRUE); + test_libver_bounds_super_open(fapl, fcpl, FALSE, TRUE); + + /* Close the fcpl */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + } + +} /* end test_libver_bounds_super() */ + +/************************************************************************************************** +** +** test_libver_bounds_super_create(): +** Verify the following when the file is created with the input fapl, fcpl, +** and with/without SWMR access: +** (a) the superblock version # +** (b) the file's low bound setting +** (c) fail or succeed in creating the file +** +** For file creation, the bounds setting in fapl, the feature enabled in fcpl, +** and with/without SWMR file access will determine the results for #a to #c. +** +** The first row for the following two tables is the 5 pairs of low/high bounds setting +** in the input fapl. The next three rows list the expected results for #a to #c. +** "-->" indicates "upgrade to" +** +** The last table lists the expected results in creating the file when non-default +** free-space info (fsinfo) is enabled in fcpl. +** +** Creating a file with write access +** -------------------------------------------------------------------------------- +** | (earliest, v18) | (earliest, v110) | (v18, v18) | (v18, v110) | (v110, v110) | +** |______________________________________________________________________________| +** Superblock version | vers 0, 1, 2 | vers 0, 1, 2 | vers 2 | vers 2 | vers 3 | +** |------------------------------------------------------------------------------| +** File's low bound | no change | +** |------------------------------------------------------------------------------| +** File creation | succeed | +** |______________________________________________________________________________| +** +** Creating a file with SWMR-write access +** -------------------------------------------------------------------------------- +** | (earliest, v18) | (earliest, v110) | (v18, v18) | (v18, v110) | (v110, v110) | +** |______________________________________________________________________________| +** Superblock version | -- | vers 3 | -- | vers 3 | vers 3 | +** |------------------------------------------------------------------------------| +** File's low bound | -- | ->v110 | -- | ->v110 | no change | +** |------------------------------------------------------------------------------| +** File creation | fail | succeed | fail | succeed | succeed | +** |______________________________________________________________________________| +** +** Creating a file with write/SWMR-write access + non-default fsinfo +** -------------------------------------------------------------------------------- +** | (earliest, v18) | (earliest, v110) | (v18, v18) | (v18, v110) | (v110, v110) | +** |______________________________________________________________________________| +** File creation | fail | succeed | fail | succeed | succeed | +** |______________________________________________________________________________| +** +******************************************************************************************************/ +static void +test_libver_bounds_super_create(hid_t fapl, hid_t fcpl, htri_t is_swmr, htri_t non_def_fsm) +{ + hid_t fid = H5I_INVALID_HID; /* File ID */ +#if 0 + H5F_t *f = NULL; /* Internal file pointer */ +#endif + H5F_libver_t low, high; /* Low and high bounds */ +#if 0 + hbool_t ok; /* The result is ok or not */ +#endif + herr_t ret; /* The return value */ + + /* Try to create the file */ + H5E_BEGIN_TRY + { + fid = H5Fcreate(FILE8, H5F_ACC_TRUNC | (is_swmr ? H5F_ACC_SWMR_WRITE : 0), fcpl, fapl); + } + H5E_END_TRY; + +#if 0 + /* Get the internal file pointer if the create succeeds */ + if (fid >= 0) { + f = (H5F_t *)H5VL_object(fid); + CHECK_PTR(f, "H5VL_object"); + } +#endif + /* Retrieve the low/high bounds */ + ret = H5Pget_libver_bounds(fapl, &low, &high); + CHECK(ret, FAIL, "H5Pget_libver_bounds"); + + if (non_def_fsm && high < H5F_LIBVER_V110) + VERIFY(fid, H5I_INVALID_HID, "H5Fcreate"); + + else if (is_swmr) { /* SWMR is enabled */ + if (high >= H5F_LIBVER_V110) { /* Should succeed */ + VERIFY(fid >= 0, TRUE, "H5Fcreate"); +#if 0 + VERIFY(HDF5_SUPERBLOCK_VERSION_3, f->shared->sblock->super_vers, "HDF5_superblock_ver_bounds"); + VERIFY(f->shared->low_bound >= H5F_LIBVER_V110, TRUE, "HDF5_superblock_ver_bounds"); +#endif + } + else /* Should fail */ + VERIFY(fid >= 0, FALSE, "H5Fcreate"); + } + else { /* Should succeed */ + VERIFY(fid >= 0, TRUE, "H5Fcreate"); +#if 0 + VERIFY(low, f->shared->low_bound, "HDF5_superblock_ver_bounds"); + + switch (low) { + case H5F_LIBVER_EARLIEST: + ok = (f->shared->sblock->super_vers == HDF5_SUPERBLOCK_VERSION_DEF || + f->shared->sblock->super_vers == HDF5_SUPERBLOCK_VERSION_1 || + f->shared->sblock->super_vers == HDF5_SUPERBLOCK_VERSION_2); + VERIFY(ok, TRUE, "HDF5_superblock_ver_bounds"); + break; + + case H5F_LIBVER_V18: + ok = (f->shared->sblock->super_vers == HDF5_SUPERBLOCK_VERSION_2); + VERIFY(ok, TRUE, "HDF5_superblock_ver_bounds"); + break; + + case H5F_LIBVER_V110: + case H5F_LIBVER_V112: + case H5F_LIBVER_V114: + case H5F_LIBVER_V116: + ok = (f->shared->sblock->super_vers == HDF5_SUPERBLOCK_VERSION_3); + VERIFY(ok, TRUE, "HDF5_superblock_ver_bounds"); + break; + + case H5F_LIBVER_ERROR: + case H5F_LIBVER_NBOUNDS: + default: + ERROR("H5Pget_libver_bounds"); + + } /* end switch */ +#endif + } /* end else */ + + if (fid >= 0) { /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + } + +} /* end test_libver_bounds_super_create() */ + +/************************************************************************************************** +** +** test_libver_bounds_super_open(): +** Verify the following when opening a file which is created with the input fapl, fcpl, +** and with/without SWMR access: +** (a) the file's low bound setting +** (b) fail or succeed in opening the file +** +** (1) Create a file with the input fapl, fcpl and with/without SWMR access +** (2) Close the file +** (3) Reopen the file with a new fapl that is set to the 5 pairs of low/high bounds +** in a for loop. For each pair of setting in the new fapl: +** --Verify the expected results for #a and #b above. +** --Close the file. +** +** For file open, the file's superblock version, the low/high bounds setting in fapl, +** and with/without SWMR file access will determine the results for #a and #b. +** +** The first row for the following tables (#A - #B) is the 5 pairs of low/high bounds setting +** in the input fapl. The next two rows list the expected results for #a and #b. +** "-->" indicates "upgrade to" +** +** The last table (#C) lists the expected results in opening the file when non-default +** free-space info (fsinfo) is enabled in fcpl. +** +** (A) Opening a file with write access +** +** Superblock version 0, 1 +** -------------------------------------------------------------------------------- +** | (earliest, v18) | (earliest, v110) | (v18, v18) | (v18, v110) | (v110, v110) | +** |______________________________________________________________________________| +** File's low bound | no change | +** |------------------------------------------------------------------------------| +** File open | succeed | +** |______________________________________________________________________________| +** +** +** Superblock version 2 +** -------------------------------------------------------------------------------- +** | (earliest, v18) | (earliest, v110) | (v18, v18) | (v18, v110) | (v110, v110) | +** |______________________________________________________________________________| +** File's low bound | -->v18 | no change | +** |------------------------------------------------------------------------------| +** File open | succeed | +** |______________________________________________________________________________| +** +** Superblock version 3 +** -------------------------------------------------------------------------------- +** | (earliest, v18) | (earliest, v110) | (v18, v18) | (v18, v110) | (v110, v110) | +** |______________________________________________________________________________| +** File's low bound | -- | -->v110 | -- | -->v110 | no change | +** |------------------------------------------------------------------------------| +** File open | fail | succeed | fail | succeed | succeed | +** |______________________________________________________________________________| +** +** +** +** (B) Opening a file with SWMR-write access +** +** Superblock version 0, 1, 2 +** ------------------------------------------------------------------------------- +** | (earliest, v18) | (earliest, v10) | (v18, v18) | (v18, v110) | (v110, v110) | +** |_____________________________________________________________________________| +** File's low bound | ---- +** |-----------------------------------------------------------------------------| +** File open | fail +** |_____________________________________________________________________________| +** +** +** Superblock version 3 +** ------------------------------------------------------------------------------- +** | (earliest, v18) | (earliest, v10) | (v18, v18) | (v18, v110) | (v110, v110) | +** |_____________________________________________________________________________| +** File's low bound | -- | -->v110 | -- | -->v110 | no change | +** |-----------------------------------------------------------------------------| +** File open | fail | succeed | fail | succeed | succeed | +** |_____________________________________________________________________________| +** +** +** (C) Opening a file with write/SWMR-write access + non-default fsinfo +** ------------------------------------------------------------------------------- +** | (earliest, v18) | (earliest, v10) | (v18, v18) | (v18, v110) | (v110, v110) | +** |_____________________________________________________________________________| +** File open | fail | succeed | fail | succeed | succeed | +** |_____________________________________________________________________________| +** +** +******************************************************************************************************/ +static void +test_libver_bounds_super_open(hid_t fapl, hid_t fcpl, htri_t is_swmr, htri_t non_def_fsm) +{ + hid_t fid = H5I_INVALID_HID; /* File ID */ +#if 0 + H5F_t *f = NULL; /* Internal file pointer */ +#endif + hid_t new_fapl = H5I_INVALID_HID; /* File access property list */ +#if 0 + unsigned super_vers; /* Superblock version */ +#endif + H5F_libver_t low, high; /* Low and high bounds */ + herr_t ret; /* Return value */ + + /* Create the file with the input fcpl and fapl */ + H5E_BEGIN_TRY + { + fid = H5Fcreate(FILE8, H5F_ACC_TRUNC, fcpl, fapl); + } + H5E_END_TRY; + + /* Retrieve the low/high bounds */ + ret = H5Pget_libver_bounds(fapl, &low, &high); + CHECK(ret, FAIL, "H5Pget_libver_bounds"); + + if (non_def_fsm && high < H5F_LIBVER_V110) { + VERIFY(fid, H5I_INVALID_HID, "H5Fcreate"); + } + else { + VERIFY(fid >= 0, TRUE, "H5Fcreate"); +#if 0 + /* Get the internal file pointer */ + f = (H5F_t *)H5VL_object(fid); + CHECK_PTR(f, "H5VL_object"); + + /* The file's superblock version */ + super_vers = f->shared->sblock->super_vers; +#endif + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Create a default file access property list */ + new_fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(new_fapl, FAIL, "H5Pcreate"); + + /* Loop through all the combinations of low/high bounds in new_fapl */ + for (low = H5F_LIBVER_EARLIEST; low < H5F_LIBVER_NBOUNDS; low++) { + for (high = H5F_LIBVER_EARLIEST; high < H5F_LIBVER_NBOUNDS; high++) { + H5E_BEGIN_TRY + { + ret = H5Pset_libver_bounds(new_fapl, low, high); + } + H5E_END_TRY; + + /* Invalid combinations */ + if (ret < 0) + continue; + + /* Open the file with or without SWMR access */ + H5E_BEGIN_TRY + { + fid = H5Fopen(FILE8, H5F_ACC_RDWR | (is_swmr ? H5F_ACC_SWMR_WRITE : 0), new_fapl); + } + H5E_END_TRY; + + if (non_def_fsm && high < H5F_LIBVER_V110) { + VERIFY(fid, H5I_INVALID_HID, "H5Fopen"); + continue; + } +#if 0 + /* Get the internal file pointer if the open succeeds */ + if (fid >= 0) { + f = (H5F_t *)H5VL_object(fid); + CHECK_PTR(f, "H5VL_object"); + } + + /* Verify the file open succeeds or fails */ + switch (super_vers) { + case 3: + if (high >= H5F_LIBVER_V110) { + /* Should succeed */ + VERIFY(fid >= 0, TRUE, "H5Fopen"); + VERIFY(f->shared->low_bound >= H5F_LIBVER_V110, TRUE, + "HDF5_superblock_ver_bounds"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + } + else /* Should fail */ + VERIFY(fid >= 0, FALSE, "H5Fopen"); + break; + + case 2: + if (is_swmr) /* Should fail */ + VERIFY(fid >= 0, FALSE, "H5Fopen"); + else { /* Should succeed */ + VERIFY(fid >= 0, TRUE, "H5Fopen"); + VERIFY(f->shared->low_bound >= H5F_LIBVER_V18, TRUE, + "HDF5_superblock_ver_bounds"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + } + break; + + case 1: + case 0: + if (is_swmr) /* Should fail */ + VERIFY(fid >= 0, FALSE, "H5Fopen"); + else { /* Should succeed */ + VERIFY(fid >= 0, TRUE, "H5Fopen"); + VERIFY(f->shared->low_bound, low, "HDF5_superblock_ver_bounds"); + + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + } + break; + + default: + break; + } /* end switch */ +#endif + } /* end for */ + } /* end for */ + + /* Close the file access property list */ + ret = H5Pclose(new_fapl); + CHECK(ret, FAIL, "H5Pclose"); + } /* end else */ + +} /* end test_libver_bounds_super_open() */ +#endif + +/**************************************************************** +** +** test_libver_bounds_obj(): +** Verify object header versions: +** +** (a) Create a file with: +** --the input fapl +** --a fcpl that has shared message enabled +** Verify the root group's object header version. +** Close the file. +** +** (b) Create another file with: +** --the input fapl +** --a default fcpl +** Verify the root group's object header version. +** Close the file. +** +** (c) Reopen the same file in (b) with a new fapl. +** The new fapl is set to the 5 pairs of low/high +** bounds in a "for" loop. For each setting in fapl: +** --Create a group in the file +** --Verify the group's object header version +** --Close and delete the group +** --Close the file +** +****************************************************************/ +#if 0 +static void +test_libver_bounds_obj(hid_t fapl) +{ + hid_t fid = H5I_INVALID_HID; /* File ID */ + hid_t gid = H5I_INVALID_HID; /* Group ID */ + hid_t fcpl = H5I_INVALID_HID; /* File creation property list */ + hid_t new_fapl = H5I_INVALID_HID; /* File access property list */ + H5F_t *f = NULL; /* Internal file pointer */ + H5F_libver_t low, high; /* Low and high bounds */ + H5O_native_info_t ninfo; /* Object info */ + H5G_info_t ginfo; /* Group info */ + herr_t ret; /* Return value */ + + /* Retrieve the low/high bounds from the input fapl */ + ret = H5Pget_libver_bounds(fapl, &low, &high); + CHECK(ret, FAIL, "H5Pget_libver_bounds"); + + /* Create a default file creation property list */ + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, H5I_INVALID_HID, "H5Pcreate"); + + /* Enable shared message in the fcpl */ + /* This will result in a version 2 object header */ + ret = H5Pset_shared_mesg_nindexes(fcpl, 1); + CHECK(ret, FAIL, "H5Pset_shared_mesg_nindexes"); + ret = H5Pset_shared_mesg_index(fcpl, 0, H5O_SHMESG_ATTR_FLAG, 2); + CHECK(ret, FAIL, "H5Pset_shared_mesg_index"); + + /* Create the file with the fcpl and the input fapl */ + fid = H5Fcreate(FILE8, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, H5I_INVALID_HID, "H5Fcreate"); + + /* Get root group's object info */ + ret = H5Oget_native_info_by_name(fid, "/", &ninfo, H5O_NATIVE_INFO_HDR, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_native_info_by_name"); + + /* Verify object header version is 2 because shared message is enabled */ + VERIFY(ninfo.hdr.version, H5O_VERSION_2, "H5O_obj_ver_bounds"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Close the file creation property list */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Create a file with the default fcpl and input fapl */ + fid = H5Fcreate(FILE8, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(fid, H5I_INVALID_HID, "H5Fcreate"); + + /* Get root group's object info */ + ret = H5Oget_native_info_by_name(fid, "/", &ninfo, H5O_NATIVE_INFO_HDR, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_native_info_by_name"); + + /* Verify object header version is as indicated by low_bound */ + VERIFY(ninfo.hdr.version, H5O_obj_ver_bounds[low], "H5O_obj_ver_bounds"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Create a new default file access property list which + is used to open the file in the "for" loop */ + new_fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(new_fapl, H5I_INVALID_HID, "H5Pcreate"); + + /* Loop through all the combinations of low/high bounds in new_fapl */ + /* Open the file with the fapl; create a group and verify the + object header version, then delete the group and close the file.*/ + for (low = H5F_LIBVER_EARLIEST; low < H5F_LIBVER_NBOUNDS; low++) { + for (high = H5F_LIBVER_EARLIEST; high < H5F_LIBVER_NBOUNDS; high++) { + H5E_BEGIN_TRY + { + ret = H5Pset_libver_bounds(new_fapl, low, high); + } + H5E_END_TRY; + + if (ret < 0) /* Invalid combinations */ + continue; + + /* Open the file */ + H5E_BEGIN_TRY + { + fid = H5Fopen(FILE8, H5F_ACC_RDWR, new_fapl); + } + H5E_END_TRY; + + if (fid >= 0) { /* The file open succeeds */ + + /* Get the internal file pointer */ + f = (H5F_t *)H5VL_object(fid); + CHECK_PTR(f, "H5VL_object"); + + /* Create a group in the file */ + gid = H5Gcreate2(fid, GRP_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gcreate2"); + + /* Get group information */ + ret = H5Gget_info(gid, &ginfo); + CHECK(ret, FAIL, "H5Gget_info"); + + /* Verify group storage type */ + if (f->shared->low_bound >= H5F_LIBVER_V18) + /* Links in group are stored in object header */ + VERIFY(ginfo.storage_type, H5G_STORAGE_TYPE_COMPACT, "H5Gget_info"); + else + /* Links in group are stored with a "symbol table" */ + VERIFY(ginfo.storage_type, H5G_STORAGE_TYPE_SYMBOL_TABLE, "H5Gget_info"); + + /* Get object header information */ + ret = H5Oget_native_info_by_name(gid, GRP_NAME, &ninfo, H5O_NATIVE_INFO_HDR, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_native_info_by_name"); + + /* Verify object header version as indicated by low_bound */ + VERIFY(ninfo.hdr.version, H5O_obj_ver_bounds[f->shared->low_bound], "H5O_obj_ver_bounds"); + + /* Close the group */ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + /* Delete the group */ + ret = H5Ldelete(fid, GRP_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + } /* end if */ + } /* end for */ + } /* end for */ + + /* Close the file access property list */ + ret = H5Pclose(new_fapl); + CHECK(ret, FAIL, "H5Pclose"); + +} /* end test_libver_bounds_obj() */ + +/**************************************************************** +** +** test_libver_bounds_dataset(): +** Verify message versions associated with datasets: +** +** (a) Create a file with default fcpl and the input fapl. +** Create the following two datasets: +** --A contiguous dataset +** --A chunked dataset with "no filter edge chunks" +** For both datasets, verify the versions for the layout, +** fill value and filter pipeline messages. +** Close the file. +** +** (b) Create a new fapl that is set to the 5 pairs of low/high +** bounds in a "for" loop. For each pair of setting in the +** new fapl: +** --Open the same file in (a) with the fapl +** --Create a chunked dataset with 2 unlimited +** dimensions +** --Verify the versions for the layout, fill value +** and filter pipeline messages +** --Close and delete the dataset +** --Close the file +** +****************************************************************/ +static void +test_libver_bounds_dataset(hid_t fapl) +{ + hid_t fid = H5I_INVALID_HID; /* File ID */ + hid_t new_fapl = H5I_INVALID_HID; /* File access property list */ + hid_t did = H5I_INVALID_HID; /* Dataset ID */ + hid_t sid = H5I_INVALID_HID; /* Dataspace ID */ + hid_t dcpl = H5I_INVALID_HID; /* Dataset creation property list */ + H5D_t *dset = NULL; /* Internal dataset pointer */ + H5F_t *f = NULL; /* Internal file pointer */ + H5F_libver_t low, high; /* Low and high bounds */ + herr_t ret; /* Return value */ + hsize_t fix_dims2[2] = {10, 4}; /* Dimension sizes */ + hsize_t fix_chunks2[2] = {4, 3}; /* Chunk dimension sizes */ + hsize_t dims2[2] = {1, 4}; /* Dimension sizes */ + hsize_t max_dims2[2] = {H5S_UNLIMITED, H5S_UNLIMITED}; /* Maximum dimension sizes */ + hsize_t chunks2[2] = {4, 5}; /* Chunk dimension sizes */ + + /* Retrieve the low/high bounds from the input fapl */ + ret = H5Pget_libver_bounds(fapl, &low, &high); + CHECK(ret, FAIL, "H5Pget_libver_bounds"); + + /* Create the file with the input fapl */ + fid = H5Fcreate(FILE8, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(fid, H5I_INVALID_HID, "H5Fcreate"); + + /* Create the dataspace */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, H5I_INVALID_HID, "H5Screate"); + + /* Create a contiguous dataset */ + did = H5Dcreate2(fid, DSETA, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(did, H5I_INVALID_HID, "H5Dcreate"); + + /* Get the internal dataset pointer */ + dset = (H5D_t *)H5VL_object(did); + CHECK_PTR(dset, "H5VL_object"); + + /* Verify version for layout and fill value messages */ + if (low == H5F_LIBVER_EARLIEST) { + /* For layout message: the earliest version the library will set is 3 */ + /* For fill value message: the earliest version the library will set is 2 */ + VERIFY(dset->shared->layout.version, H5O_LAYOUT_VERSION_DEFAULT, "H5O_layout_ver_bounds"); + VERIFY(dset->shared->dcpl_cache.fill.version, H5O_FILL_VERSION_2, "H5O_fill_ver_bounds"); + } + else { + VERIFY(dset->shared->layout.version, H5O_layout_ver_bounds[low], "H5O_layout_ver_bounds"); + VERIFY(dset->shared->dcpl_cache.fill.version, H5O_fill_ver_bounds[low], "H5O_fill_ver_bounds"); + } + + /* Verify filter pipeline message version */ + VERIFY(dset->shared->dcpl_cache.pline.version, H5O_pline_ver_bounds[low], "H5O_pline_ver_bounds"); + + /* Close the dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close the dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Set up dataspace and dcpl for creating a chunked dataset + with "no filter edge chunks" enabled. + This will result in a version 4 layout message */ + sid = H5Screate_simple(2, fix_dims2, NULL); + CHECK(sid, H5I_INVALID_HID, "H5Screate_simple"); + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, H5I_INVALID_HID, "H5Pcreate"); + ret = H5Pset_chunk(dcpl, 2, fix_chunks2); + CHECK(ret, FAIL, "H5Pset_chunk"); + ret = H5Pset_chunk_opts(dcpl, H5D_CHUNK_DONT_FILTER_PARTIAL_CHUNKS); + CHECK(ret, FAIL, "H5Pset_chunk_opts"); + + /* Create the chunked dataset */ + H5E_BEGIN_TRY + { + did = H5Dcreate2(fid, DSETB, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + } + H5E_END_TRY; + + if (did >= 0) { + + /* Get the internal dataset pointer */ + dset = (H5D_t *)H5VL_object(did); + CHECK_PTR(dset, "H5VL_object"); + + /* Verify layout message version and chunk indexing type */ + VERIFY(dset->shared->layout.version, H5O_LAYOUT_VERSION_4, "H5O_layout_ver_bounds"); + VERIFY(dset->shared->layout.u.chunk.idx_type, H5D_CHUNK_IDX_FARRAY, "chunk_index_type"); + + /* Close the dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + } + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Close the dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close the dataset creation property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Create a default file access property list which is used + to open the file in the 'for' loop */ + new_fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(new_fapl, H5I_INVALID_HID, "H5Pcreate"); + + /* Set up dataspace and dcpl for creating a chunked dataset with + 2 unlimited dimensions in the 'for' loop */ + sid = H5Screate_simple(2, dims2, max_dims2); + CHECK(sid, H5I_INVALID_HID, "H5Screate_simple"); + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, H5I_INVALID_HID, "H5Pcreate"); + ret = H5Pset_chunk(dcpl, 2, chunks2); + CHECK(ret, FAIL, "H5Pset_chunk"); + + /* Loop through all the combinations of low/high bounds in new_fapl */ + /* Open the file with the fapl and create the chunked dataset */ + /* Verify the dataset's layout, fill value and filter pipeline message versions */ + for (low = H5F_LIBVER_EARLIEST; low < H5F_LIBVER_NBOUNDS; low++) { + for (high = H5F_LIBVER_EARLIEST; high < H5F_LIBVER_NBOUNDS; high++) { + H5E_BEGIN_TRY + { + ret = H5Pset_libver_bounds(new_fapl, low, high); + } + H5E_END_TRY; + + if (ret < 0) /* Invalid low/high combinations */ + continue; + + /* Open the file */ + H5E_BEGIN_TRY + { + fid = H5Fopen(FILE8, H5F_ACC_RDWR, new_fapl); + } + H5E_END_TRY; + + if (fid >= 0) { /* The file open succeeds */ + + /* Get the internal file pointer */ + f = (H5F_t *)H5VL_object(fid); + CHECK_PTR(f, "H5VL_object"); + + /* Create the chunked dataset */ + did = H5Dcreate2(fid, DSETC, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(did, H5I_INVALID_HID, "H5Dcreate2"); + + /* Get the internal file pointer */ + dset = (H5D_t *)H5VL_object(did); + CHECK_PTR(dset, "H5VL_object"); + + if (dset) { + /* Verify the dataset's layout, fill value and filter pipeline message versions */ + /* Also verify the chunk indexing type */ + if (f->shared->low_bound == H5F_LIBVER_EARLIEST) { + /* For layout message: the earliest version the library will set is 3 */ + /* For fill value message: the earliest version the library will set is 2 */ + VERIFY(dset->shared->layout.version, H5O_LAYOUT_VERSION_DEFAULT, + "H5O_layout_ver_bounds"); + VERIFY(dset->shared->dcpl_cache.fill.version, H5O_FILL_VERSION_2, + "H5O_fill_ver_bounds"); + } + else { + VERIFY(dset->shared->layout.version, H5O_layout_ver_bounds[f->shared->low_bound], + "H5O_layout_ver_bounds"); + VERIFY(dset->shared->dcpl_cache.fill.version, + H5O_fill_ver_bounds[f->shared->low_bound], "H5O_fill_ver_bounds"); + } + + /* Verify the filter pipeline message version */ + VERIFY(dset->shared->dcpl_cache.pline.version, H5O_pline_ver_bounds[f->shared->low_bound], + "H5O_pline_ver_bounds"); + + /* Verify the dataset's chunk indexing type */ + if (dset->shared->layout.version == H5O_LAYOUT_VERSION_LATEST) + VERIFY(dset->shared->layout.u.chunk.idx_type, H5D_CHUNK_IDX_BT2, "chunk_index_type"); + else + VERIFY(dset->shared->layout.u.chunk.idx_type, H5D_CHUNK_IDX_BTREE, + "chunk_index_type"); + } + + /* Close the dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* Delete the dataset */ + ret = H5Ldelete(fid, DSETC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + } /* end if */ + } /* end for */ + } /* end for */ + + /* Close the file access property list */ + ret = H5Pclose(new_fapl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close the dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close the dataset creation property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + +} /* end test_libver_bounds_dataset() */ + +/**************************************************************** +** +** test_libver_bounds_dataspace(): +** Verify dataspace message versions: +** +** (a) Create a file with default fcpl and the input fapl. +** Create the following two datasets: +** --A dataset with scalar dataspace +** --A dataset with null dataspace +** For both datasets, verify the dataspace message versions. +** Close the file. +** +** (b) Create a new fapl that is set to the 5 pairs of low/high +** bounds in a "for" loop. For each pair of setting in the +** new fapl: +** --Open the same file in (a) with the fapl +** --Create a chunked dataset, a compact dataset and +** a contiguous dataset +** --Verify the dataspace message version for these +** three datasets +** --Delete the three datasets and the dataspaces +** --Close the file +** +****************************************************************/ +static void +test_libver_bounds_dataspace(hid_t fapl) +{ + hid_t fid = H5I_INVALID_HID; /* File ID */ + hid_t new_fapl = H5I_INVALID_HID; /* File access property list */ + hid_t did = H5I_INVALID_HID, did_null = H5I_INVALID_HID; /* Dataset IDs */ + hid_t did_compact = H5I_INVALID_HID, did_contig = H5I_INVALID_HID; /* Dataset IDs */ + hid_t sid = H5I_INVALID_HID, sid_null = H5I_INVALID_HID; /* Dataspace IDs */ + hid_t sid_compact = H5I_INVALID_HID, sid_contig = H5I_INVALID_HID; /* Dataspace IDs */ + hid_t dcpl = H5I_INVALID_HID; /* Dataset creation property list */ + hid_t dcpl_compact = H5I_INVALID_HID, dcpl_contig = H5I_INVALID_HID; /* Dataset creation property lists */ + H5S_t *space = NULL, *space_null = NULL; /* Internal dataspace pointers */ + H5F_t *f = NULL; /* Internal file pointer */ + H5F_libver_t low, high; /* Low and high bounds */ + hsize_t dims[1] = {1}; /* Dimension sizes */ + hsize_t dims2[2] = {5, 4}; /* Dimension sizes */ + hsize_t max_dims[1] = {H5S_UNLIMITED}; /* Maximum dimension sizes */ + hsize_t chunks[1] = {4}; /* Chunk dimension sizes */ + herr_t ret; /* Return value */ + + /* Retrieve the low/high bounds from the input fapl */ + ret = H5Pget_libver_bounds(fapl, &low, &high); + CHECK(ret, FAIL, "H5Pget_libver_bounds"); + + /* Create the file with the input fapl */ + fid = H5Fcreate(FILE8, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(fid, H5I_INVALID_HID, "H5Fcreate"); + + /* Create scalar dataspace */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, H5I_INVALID_HID, "H5Screate"); + + /* Create a dataset with the scalar dataspace */ + did = H5Dcreate2(fid, DSET, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(did, H5I_INVALID_HID, "H5Dcreate"); + + /* Get the internal dataspace pointer */ + sid = H5Dget_space(did); + CHECK(sid, H5I_INVALID_HID, "H5Dget_space"); + space = (H5S_t *)H5I_object(sid); + CHECK_PTR(space, "H5I_object"); + + /* Verify the dataspace version */ + VERIFY(space->extent.version, H5O_sdspace_ver_bounds[low], "H5O_sdspace_ver_bounds"); + + /* Create null dataspace */ + sid_null = H5Screate(H5S_NULL); + CHECK(sid_null, H5I_INVALID_HID, "H5Screate"); + + /* Create a dataset with the null dataspace */ + did_null = H5Dcreate2(fid, DSET_NULL, H5T_NATIVE_INT, sid_null, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(did_null, H5I_INVALID_HID, "H5Dcreate"); + + /* Get the internal dataspace pointer */ + sid_null = H5Dget_space(did_null); + CHECK(sid_null, H5I_INVALID_HID, "H5Dget_space"); + space_null = (H5S_t *)H5I_object(sid_null); + CHECK_PTR(space_null, "H5I_object"); + + /* Verify the dataspace version */ + VERIFY(space_null->extent.version, H5O_SDSPACE_VERSION_2, "H5O_sdspace_ver_bounds"); + + /* Close the datasets */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(did_null); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close the dataspaces */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(sid_null); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Create a default file access property list which is used + to open the file in the 'for' loop */ + new_fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(new_fapl, H5I_INVALID_HID, "H5Pcreate"); + + /* Set up dataspace and dcpl for creating a chunked dataset */ + sid = H5Screate_simple(1, dims, max_dims); + CHECK(sid, H5I_INVALID_HID, "H5Screate_simple"); + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, H5I_INVALID_HID, "H5Pcreate"); + ret = H5Pset_chunk(dcpl, 1, chunks); + CHECK(ret, FAIL, "H5Pset_chunk"); + + /* Set up dataspace and dcpl for creating a compact dataset */ + sid_compact = H5Screate_simple(1, dims, NULL); + CHECK(sid_compact, H5I_INVALID_HID, "H5Screate_simple"); + dcpl_compact = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl_compact, H5I_INVALID_HID, "H5Pcreate"); + ret = H5Pset_layout(dcpl_compact, H5D_COMPACT); + CHECK(ret, FAIL, "H5Pset_layout"); + + /* Set up dataspace and dcpl for creating a contiguous dataset */ + sid_contig = H5Screate_simple(2, dims2, NULL); + CHECK(sid_contig, H5I_INVALID_HID, "H5Screate_simple"); + dcpl_contig = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl_contig, H5I_INVALID_HID, "H5Pcreate"); + ret = H5Pset_layout(dcpl_contig, H5D_CONTIGUOUS); + CHECK(ret, FAIL, "H5Pset_layout"); + + /* Loop through all the combinations of low/high bounds in new_fapl */ + /* Open the file and create the chunked/compact/contiguous datasets */ + /* Verify the dataspace message version for the three datasets */ + for (low = H5F_LIBVER_EARLIEST; low < H5F_LIBVER_NBOUNDS; low++) { + for (high = H5F_LIBVER_EARLIEST; high < H5F_LIBVER_NBOUNDS; high++) { + hid_t tmp_sid, tmp_sid_compact, tmp_sid_contig; /* Dataspace IDs */ + H5S_t *tmp_space, *tmp_space_compact, *tmp_space_contig; /* Internal dataspace pointers */ + + H5E_BEGIN_TRY + { + ret = H5Pset_libver_bounds(new_fapl, low, high); + } + H5E_END_TRY; + + if (ret < 0) /* Invalid low/high combinations */ + continue; + + /* Open the file */ + H5E_BEGIN_TRY + { + fid = H5Fopen(FILE8, H5F_ACC_RDWR, new_fapl); + } + H5E_END_TRY; + + if (fid >= 0) { /* The file open succeeds */ + + /* Get the internal file pointer */ + f = (H5F_t *)H5VL_object(fid); + CHECK_PTR(f, "H5VL_object"); + + /* Create the chunked dataset */ + did = H5Dcreate2(fid, DSETA, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(did, H5I_INVALID_HID, "H5Dcreate2"); + + /* Get the internal dataspace pointer for the chunked dataset */ + tmp_sid = H5Dget_space(did); + CHECK(tmp_sid, H5I_INVALID_HID, "H5Dget_space"); + tmp_space = (H5S_t *)H5I_object(tmp_sid); + CHECK_PTR(tmp_space, "H5I_object"); + + /* Create the compact dataset */ + did_compact = H5Dcreate2(fid, DSETB, H5T_NATIVE_INT, sid_compact, H5P_DEFAULT, dcpl_compact, + H5P_DEFAULT); + CHECK(did_compact, H5I_INVALID_HID, "H5Dcreate2"); + + /* Get the internal dataspace pointer for the compact dataset */ + tmp_sid_compact = H5Dget_space(did_compact); + CHECK(tmp_sid_compact, H5I_INVALID_HID, "H5Dget_space"); + tmp_space_compact = (H5S_t *)H5I_object(tmp_sid_compact); + CHECK_PTR(tmp_space_compact, "H5I_object"); + + /* Create the contiguous dataset */ + did_contig = + H5Dcreate2(fid, DSETC, H5T_NATIVE_INT, sid_contig, H5P_DEFAULT, dcpl_contig, H5P_DEFAULT); + CHECK(did_contig, H5I_INVALID_HID, "H5Dcreate2"); + + /* Get the internal dataspace pointer for the contiguous dataset */ + tmp_sid_contig = H5Dget_space(did_contig); + CHECK(tmp_sid_contig, H5I_INVALID_HID, "H5Dget_space"); + tmp_space_contig = (H5S_t *)H5I_object(tmp_sid_contig); + CHECK_PTR(tmp_space_contig, "H5I_object"); + + if (tmp_space) { + /* Verify versions for the three dataspaces */ + VERIFY(tmp_space->extent.version, H5O_sdspace_ver_bounds[f->shared->low_bound], + "H5O_sdspace_ver_bounds"); + } + if (tmp_space_compact) { + VERIFY(tmp_space_compact->extent.version, H5O_sdspace_ver_bounds[f->shared->low_bound], + "H5O_sdspace_ver_bounds"); + } + if (tmp_space_contig) { + VERIFY(tmp_space_contig->extent.version, H5O_sdspace_ver_bounds[f->shared->low_bound], + "H5O_sdspace_ver_bounds"); + } + + /* Close the three datasets */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(did_compact); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Dclose(did_contig); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close the three dataspaces */ + ret = H5Sclose(tmp_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(tmp_sid_compact); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(tmp_sid_contig); + CHECK(ret, FAIL, "H5Sclose"); + + /* Delete the three datasets */ + ret = H5Ldelete(fid, DSETA, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + ret = H5Ldelete(fid, DSETB, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + ret = H5Ldelete(fid, DSETC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + } /* end if */ + } /* end for */ + } /* end for */ + + /* Close the file access property list */ + ret = H5Pclose(new_fapl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close the three dataspaces */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(sid_compact); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(sid_contig); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close the three dataset creation property lists */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(dcpl_compact); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(dcpl_contig); + CHECK(ret, FAIL, "H5Pclose"); + +} /* end test_libver_bounds_dataspace() */ + +/**************************************************************** +** +** test_libver_bounds_datatype(): +** Verify the datatype message version: +** +** (a) Create the following datatypes: +** 1) integer +** 2) enum +** 3) array +** 4) compound +** 5) vlen +** (b) Call test_libver_bounds_datatype_check() for each +** datatype in (a) to verify the datatype message version. +** +****************************************************************/ +static void +test_libver_bounds_datatype(hid_t fapl) +{ + hid_t tid = H5I_INVALID_HID, tid_enum = H5I_INVALID_HID, tid_array = H5I_INVALID_HID; /* Datatype IDs */ + hid_t tid_compound = H5I_INVALID_HID, tid_vlen = H5I_INVALID_HID; /* Datatype IDs */ + int enum_value; /* Value for enum datatype */ + typedef struct s1 { /* Data structure for compound datatype */ + char c; + int i; + } s1; + hsize_t dims[1] = {1}; /* Dimension sizes */ + herr_t ret; /* Return value */ + + /* Create integer datatype */ + tid = H5Tcopy(H5T_NATIVE_INT); + + /* Verify datatype message version */ + test_libver_bounds_datatype_check(fapl, tid); + + /* Create enum datatype */ + tid_enum = H5Tenum_create(tid); + enum_value = 0; + H5Tenum_insert(tid_enum, "val1", &enum_value); + enum_value = 1; + H5Tenum_insert(tid_enum, "val2", &enum_value); + + /* Verify datatype message version */ + test_libver_bounds_datatype_check(fapl, tid_enum); + + /* Create array datatype */ + tid_array = H5Tarray_create2(tid, 1, dims); + + /* Verify datatype message version */ + test_libver_bounds_datatype_check(fapl, tid_array); + + /* Create compound datatype */ + tid_compound = H5Tcreate(H5T_COMPOUND, sizeof(s1)); + H5Tinsert(tid_compound, "c", HOFFSET(s1, c), H5T_STD_U8LE); + H5Tinsert(tid_compound, "i", HOFFSET(s1, i), H5T_NATIVE_INT); + + /* Verify datatype message version */ + test_libver_bounds_datatype_check(fapl, tid_compound); + + /* Create vlen datatype */ + tid_vlen = H5Tvlen_create(tid); + + /* Verify datatype message version */ + test_libver_bounds_datatype_check(fapl, tid_vlen); + + /* Close the datatypes */ + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + + ret = H5Tclose(tid_enum); + CHECK(ret, FAIL, "H5Tclose"); + + ret = H5Tclose(tid_array); + CHECK(ret, FAIL, "H5Tclose"); + + ret = H5Tclose(tid_compound); + CHECK(ret, FAIL, "H5Tclose"); + + ret = H5Tclose(tid_vlen); + CHECK(ret, FAIL, "H5Tclose"); + +} /* end test_libver_bounds_datatype() */ + +/**************************************************************** +** +** test_libver_bounds_datatype_check(): +** Helper routine called by test_libver_bounds_datatype() +** to verify the datatype message version for the input tid: +** +** (a) Create a file with default fcpl and the input fapl. +** Create a contiguous dataset with the input tid. +** Verify the datatype message version. +** Create a committed datatype of string to be +** used later. +** Close the file. +** +** (b) Create a new fapl that is set to the 5 pairs of low/high +** bounds in a "for" loop. For each pair of setting in +** the new fapl: +** --Open the same file in (a) with the fapl +** --Verify the message version for the committed +** datatype created earlier +** --Create a chunked dataset with the input tid +** --Verify the datatype message version +** --Close and delete the dataset +** --Close the file +** +****************************************************************/ +static void +test_libver_bounds_datatype_check(hid_t fapl, hid_t tid) +{ + hid_t fid = H5I_INVALID_HID; /* File ID */ + hid_t new_fapl = H5I_INVALID_HID; /* File access property list */ + hid_t dcpl = H5I_INVALID_HID; /* Dataset creation property list */ + hid_t dtid = H5I_INVALID_HID; /* Datatype ID for the dataset */ + hid_t str_tid = H5I_INVALID_HID; /* String datatype ID */ + hid_t did = H5I_INVALID_HID; /* Dataset ID */ + hid_t sid = H5I_INVALID_HID; /* Dataspace ID */ + hsize_t dims[1] = {1}; /* Dimension sizes */ + hsize_t dims2[2] = {5, 4}; /* Dimension sizes */ + hsize_t max_dims2[2] = {H5S_UNLIMITED, H5S_UNLIMITED}; /* Maximum dimension sizes */ + hsize_t chunks[2] = {2, 3}; /* Chunk dimension sizes */ + H5T_t *dtype = NULL; /* Internal datatype pointer */ + H5T_t *str_dtype = NULL; /* Internal datatype pointer for the string datatype */ + H5F_t *f = NULL; /* Internal file pointer */ + H5F_libver_t low, high; /* Low and high bounds */ + herr_t ret; /* Return value */ + + /* Retrieve the low/high version bounds from the input fapl */ + ret = H5Pget_libver_bounds(fapl, &low, &high); + CHECK(ret, FAIL, "H5Pget_libver_bounds"); + + /* Create the file with the input fapl */ + fid = H5Fcreate(FILE8, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(fid, H5I_INVALID_HID, "H5Fcreate"); + + /* Create a committed datatype of string which will be used + later inside the 'for' loop */ + str_tid = H5Tcopy(H5T_C_S1); + CHECK(str_tid, H5I_INVALID_HID, "H5Tcopy"); + ret = H5Tset_size(str_tid, (size_t)10); + CHECK(ret, FAIL, "H5Tset_size"); + ret = H5Tcommit2(fid, "datatype", str_tid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + ret = H5Tclose(str_tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Create dataspace */ + sid = H5Screate_simple(1, dims, NULL); + CHECK(sid, H5I_INVALID_HID, "H5Screate_simple"); + + /* Create a dataset with the input tid */ + did = H5Dcreate2(fid, DSET1, tid, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(did, H5I_INVALID_HID, "H5Dcreate2"); + + /* Get the dataset's datatype */ + dtid = H5Dget_type(did); + CHECK(dtid, H5I_INVALID_HID, "H5Dget_type"); + + /* Get the internal datatype pointer */ + dtype = (H5T_t *)H5I_object(dtid); + CHECK_PTR(dtype, "H5I_object"); + + /* Verify the datatype message version */ + /* H5T_COMPOUND, H5T_ENUM, H5T_ARRAY: + * --the library will set version according to low_bound + * --H5T_ARRAY: the earliest version the library will set is 2 + * H5T_INTEGER, H5T_FLOAT, H5T_TIME, H5T_STRING, H5T_BITFIELD, H5T_OPAQUE, H5T_REFERENCE: + * --the library will only use basic version + */ + + if (dtype->shared->type == H5T_COMPOUND || dtype->shared->type == H5T_ENUM || + dtype->shared->type == H5T_ARRAY) { + if (dtype->shared->type == H5T_ARRAY && low == H5F_LIBVER_EARLIEST) + VERIFY(dtype->shared->version, H5O_DTYPE_VERSION_2, "H5O_dtype_ver_bounds"); + else + VERIFY(dtype->shared->version, H5O_dtype_ver_bounds[low], "H5O_dtype_ver_bounds"); + } + else + VERIFY(dtype->shared->version, H5O_dtype_ver_bounds[H5F_LIBVER_EARLIEST], "H5O_dtype_ver_bounds"); + + /* Close the dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close the dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close the datatype */ + ret = H5Tclose(dtid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Create a default file access property list */ + new_fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(new_fapl, H5I_INVALID_HID, "H5Pcreate"); + + /* Set up dataspace and dcpl for creating a chunked dataset */ + sid = H5Screate_simple(2, dims2, max_dims2); + CHECK(sid, H5I_INVALID_HID, "H5Screate_simple"); + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, H5I_INVALID_HID, "H5Pcreate"); + ret = H5Pset_chunk(dcpl, 2, chunks); + CHECK(ret, FAIL, "H5Pset_chunk"); + + /* Loop through all the combinations of low/high bounds */ + /* Open the file and create the chunked dataset with the input tid */ + /* Verify the dataset's datatype message version */ + /* Also verify the committed atatype message version */ + for (low = H5F_LIBVER_EARLIEST; low < H5F_LIBVER_NBOUNDS; low++) { + for (high = H5F_LIBVER_EARLIEST; high < H5F_LIBVER_NBOUNDS; high++) { + H5E_BEGIN_TRY + { + ret = H5Pset_libver_bounds(new_fapl, low, high); + } + H5E_END_TRY; + + if (ret < 0) /* Invalid low/high combinations */ + continue; + + /* Open the file */ + H5E_BEGIN_TRY + { + fid = H5Fopen(FILE8, H5F_ACC_RDWR, new_fapl); + } + H5E_END_TRY; + + if (fid >= 0) { /* The file open succeeds */ + + /* Get the internal file pointer */ + f = (H5F_t *)H5VL_object(fid); + CHECK_PTR(f, "H5VL_object"); + + /* Open the committed datatype */ + str_tid = H5Topen2(fid, "datatype", H5P_DEFAULT); + CHECK(str_tid, FAIL, "H5Topen2"); + str_dtype = (H5T_t *)H5VL_object(str_tid); + CHECK_PTR(str_dtype, "H5VL_object"); + + /* Verify the committed datatype message version */ + VERIFY(str_dtype->shared->version, H5O_dtype_ver_bounds[H5F_LIBVER_EARLIEST], + "H5O_dtype_ver_bounds"); + + /* Close the committed datatype */ + ret = H5Tclose(str_tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Create the chunked dataset */ + did = H5Dcreate2(fid, DSETNAME, tid, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(did, H5I_INVALID_HID, "H5Dcreate2"); + + /* Get the dataset's datatype */ + dtid = H5Dget_type(did); + CHECK(dtid, H5I_INVALID_HID, "H5Dget_type"); + + /* Get the internal datatype pointer */ + dtype = (H5T_t *)H5I_object(dtid); + CHECK_PTR(dtype, "H5I_object"); + + if (dtype) { + /* Verify the dataset's datatype message version */ + /* H5T_COMPOUND, H5T_ENUM, H5T_ARRAY: + * --the library will set version according to low_bound + * --H5T_ARRAY: the earliest version the library will set is 2 + * H5T_INTEGER, H5T_FLOAT, H5T_TIME, H5T_STRING, H5T_BITFIELD, H5T_OPAQUE, H5T_REFERENCE: + * --the library will only use basic version + */ + if (dtype->shared->type == H5T_COMPOUND || dtype->shared->type == H5T_ENUM || + dtype->shared->type == H5T_ARRAY) { + if (dtype->shared->type == H5T_ARRAY && f->shared->low_bound == H5F_LIBVER_EARLIEST) + VERIFY(dtype->shared->version, H5O_DTYPE_VERSION_2, "H5O_dtype_ver_bounds"); + else + VERIFY(dtype->shared->version, H5O_dtype_ver_bounds[f->shared->low_bound], + "H5O_dtype_ver_bounds"); + } + else + VERIFY(dtype->shared->version, H5O_dtype_ver_bounds[H5F_LIBVER_EARLIEST], + "H5O_dtype_ver_bounds"); + } + + /* Close the dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close the dataset's datatype */ + ret = H5Tclose(dtid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Delete the dataset */ + ret = H5Ldelete(fid, DSETNAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + } /* end if */ + } /* end for */ + } /* end for */ + + /* Close the file access property list */ + ret = H5Pclose(new_fapl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close the dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close the dataset creation property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + +} /* end test_libver_bounds_datatype_check() */ + +/**************************************************************** +** +** test_libver_bounds_attributes(): +** Verify the attribute message versions: +** +** (a) Create a file with default fcpl and the input fapl. +** Create a group and attach the following three attributes +** to the group: +** (1) Attribute with a committed datatype +** (2) Attribute with integer type +** (3) Attribute with character encoding set +** Verify the three attributes' message versions. +** Close the file. +** +** (b) Create a fcpl that has shared datatype message enabled. +** Create a file with the fcpl and the input fapl. +** Create a group and attach an attribute with shared +** integer type to the group. +** Verify the attribute message version. +** Close the file +** +** (b) Create a new fapl that is set to the 5 pairs of low/high +** bounds in a "for" loop. For each pair of setting in +** the new fapl: +** --Open the same file in (b) with the fapl +** --Open the group and attach an attribute with integer +** type to the group +** --Verify the attribute message version +** --Delete the attribute +** --Close the group and the file +** +****************************************************************/ +static void +test_libver_bounds_attributes(hid_t fapl) +{ + hid_t fid = H5I_INVALID_HID; /* File ID */ + hid_t fcpl = H5I_INVALID_HID; /* File creation property list */ + hid_t new_fapl = H5I_INVALID_HID; /* File access property list */ + hid_t tid = H5I_INVALID_HID; /* Datatype ID */ + hid_t gid = H5I_INVALID_HID; /* Group ID */ + hid_t sid = H5I_INVALID_HID; /* Dataspace ID */ + hid_t aid = H5I_INVALID_HID; /* Attribute ID */ + hid_t attr_cpl = H5I_INVALID_HID; /* Attribute creation property list */ + H5A_t *attr = NULL; /* Internal attribute pointer */ + H5F_t *f = NULL; /* Internal file pointer */ + H5F_libver_t low, high; /* Low and high bounds */ + herr_t ret; /* Return value */ + + /* Retrieve the low/high bounds from the input fapl */ + ret = H5Pget_libver_bounds(fapl, &low, &high); + CHECK(ret, FAIL, "H5Pget_libver_bounds"); + + /* Create the file */ + fid = H5Fcreate(FILE8, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(fid, H5I_INVALID_HID, "H5Fcreate"); + + /* Integer datatype */ + tid = H5Tcopy(H5T_NATIVE_INT); + CHECK(tid, H5I_INVALID_HID, "H5Tcopy"); + + /* Create a committed datatype */ + ret = H5Tcommit2(fid, "datatype", tid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + + /* Create dataspace */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, H5I_INVALID_HID, "H5Screate"); + + /* Create a group */ + gid = H5Gcreate2(fid, GRP_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid, H5I_INVALID_HID, "H5Gcreate2"); + + /* Attach an attribute to the group with the committed datatype */ + aid = H5Acreate2(gid, "attr1", tid, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, H5I_INVALID_HID, "H5Acreate2"); + + /* Get the internal attribute pointer */ + attr = (H5A_t *)H5VL_object(aid); + CHECK_PTR(attr, "H5VL_object"); + + /* Verify the attribute version */ + if (low == H5F_LIBVER_EARLIEST) + /* The earliest version the library can set for an attribute with committed datatype is 2 */ + VERIFY(attr->shared->version, H5O_ATTR_VERSION_2, "H5O_attr_ver_bounds"); + else + VERIFY(attr->shared->version, H5O_attr_ver_bounds[low], "H5O_attr_ver_bounds"); + + /* Close the attribute */ + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + + /* Create an attribute to the group with integer type */ + aid = H5Acreate2(gid, "attr2", H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + + /* Get the internal attribute pointer */ + attr = (H5A_t *)H5VL_object(aid); + CHECK_PTR(attr, "H5VL_object"); + + /* Verify attribute version */ + VERIFY(attr->shared->version, H5O_attr_ver_bounds[low], "H5O_attr_ver_bounds"); + + /* Close the attribute */ + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + + /* Enable character encoding in attribute creation property list */ + attr_cpl = H5Pcreate(H5P_ATTRIBUTE_CREATE); + CHECK(attr_cpl, H5I_INVALID_HID, "H5Pcreate"); + ret = H5Pset_char_encoding(attr_cpl, H5T_CSET_UTF8); + CHECK(ret, FAIL, "H5Pset_char_encoding"); + + /* Attach an attribute to the group with character encoding set */ + aid = H5Acreate2(gid, "attr3", H5T_NATIVE_INT, sid, attr_cpl, H5P_DEFAULT); + CHECK(aid, H5I_INVALID_HID, "H5Acreate2"); + + /* Get internal attribute pointer */ + attr = (H5A_t *)H5VL_object(aid); + CHECK_PTR(attr, "H5VL_object"); + + /* Verify attribute version */ + if (low == H5F_LIBVER_EARLIEST) + /* The earliest version the library can set for an attribute with character encoding is 3 */ + VERIFY(attr->shared->version, H5O_ATTR_VERSION_3, "H5O_attr_ver_bounds"); + else + VERIFY(attr->shared->version, H5O_attr_ver_bounds[low], "H5O_attr_ver_bounds"); + + /* Close the attribute */ + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close the attribute creation property list */ + ret = H5Pclose(attr_cpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close the group */ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close the dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close the datatype */ + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Create a copy of the file creation property list */ + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, H5I_INVALID_HID, "H5Pcreate"); + + /* Enable shared datatype message */ + ret = H5Pset_shared_mesg_nindexes(fcpl, 1); + CHECK(ret, FAIL, "H5Pset_shared_mesg_nindexes"); + ret = H5Pset_shared_mesg_index(fcpl, 0, H5O_SHMESG_DTYPE_FLAG, 2); + CHECK(ret, FAIL, "H5Pset_shared_mesg_index"); + + /* Create the file with shared datatype message enabled */ + fid = H5Fcreate(FILE8, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, H5I_INVALID_HID, "H5Fcreate"); + + /* Create an integer datatype */ + tid = H5Tcopy(H5T_NATIVE_INT); + CHECK(tid, H5I_INVALID_HID, "H5Tcopy"); + + /* Create dataspace */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, H5I_INVALID_HID, "H5Screate"); + + /* Create a group */ + gid = H5Gcreate2(fid, GRP_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid, H5I_INVALID_HID, "H5Gcreate2"); + + /* Attach an attribute to the group with shared integer datatype */ + aid = H5Acreate2(gid, ATTR_NAME, tid, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, H5I_INVALID_HID, "H5Acreate2"); + + /* Get the internal attribute pointer */ + attr = (H5A_t *)H5VL_object(aid); + CHECK_PTR(attr, "H5VL_object"); + + /* Verify the attribute version */ + if (low == H5F_LIBVER_EARLIEST) + /* The earliest version the library can set for an attribute with shared datatype is 2 */ + VERIFY(attr->shared->version, H5O_ATTR_VERSION_2, "H5O_attr_ver_bounds"); + else + VERIFY(attr->shared->version, H5O_attr_ver_bounds[low], "H5O_attr_ver_bounds"); + + /* Close the attribute */ + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close the group */ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close the dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close the datatype */ + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Create a default file access property list */ + new_fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(new_fapl, FAIL, "H5Pcreate"); + + /* Create a scalar dataspace to be used later for the attribute */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, H5I_INVALID_HID, "H5Screate"); + + /* Loop through all the combinations of low/high bounds */ + /* Open the file and group and attach an attribute to the group */ + /* Verify the attribute version */ + for (low = H5F_LIBVER_EARLIEST; low < H5F_LIBVER_NBOUNDS; low++) { + for (high = H5F_LIBVER_EARLIEST; high < H5F_LIBVER_NBOUNDS; high++) { + H5E_BEGIN_TRY + { + ret = H5Pset_libver_bounds(new_fapl, low, high); + } + H5E_END_TRY; + + if (ret < 0) /* Invalid low/high combinations */ + continue; + + /* Open the file */ + H5E_BEGIN_TRY + { + fid = H5Fopen(FILE8, H5F_ACC_RDWR, new_fapl); + } + H5E_END_TRY; + + if (fid >= 0) { /* The file open succeeds */ + + /* Get the internal file pointer */ + f = (H5F_t *)H5VL_object(fid); + CHECK_PTR(f, "H5VL_object"); + + /* Open the group */ + gid = H5Gopen2(fid, GRP_NAME, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gopen2"); + + /* Attach an attribute to the group */ + aid = H5Acreate2(gid, "attr1", H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + + /* Get the internal attribute pointer */ + attr = (H5A_t *)H5VL_object(aid); + CHECK_PTR(attr, "H5VL_object"); + + /* Verify the attribute message version */ + VERIFY(attr->shared->version, H5O_attr_ver_bounds[f->shared->low_bound], + "H5O_attr_ver_bounds"); + + /* Close the attribute */ + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + + /* Delete the attribute */ + ret = H5Adelete(gid, "attr1"); + CHECK(ret, FAIL, "H5Adelete"); + + /* Close the group */ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + } /* end if */ + } /* end for */ + } /* end for */ + + /* Close the file access property list */ + ret = H5Pclose(new_fapl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close the dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + +} /* end test_libver_bounds_attributes() */ + +/**************************************************************** +** +** test_libver_macros(): +** Verify that H5_VERSION_GE and H5_VERSION_LE work correactly. +** +****************************************************************/ +static void +test_libver_macros(void) +{ + int major = H5_VERS_MAJOR; + int minor = H5_VERS_MINOR; + int release = H5_VERS_RELEASE; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing macros for library version comparison\n")); + + VERIFY(H5_VERSION_GE(major, minor, release), TRUE, "H5_VERSION_GE"); + VERIFY(H5_VERSION_GE(major - 1, minor, release), TRUE, "H5_VERSION_GE"); + VERIFY(H5_VERSION_GE(major - 1, minor + 1, release), TRUE, "H5_VERSION_GE"); + VERIFY(H5_VERSION_GE(major - 1, minor, release + 1), TRUE, "H5_VERSION_GE"); + VERIFY(H5_VERSION_GE(major, minor - 1, release), TRUE, "H5_VERSION_GE"); + VERIFY(H5_VERSION_GE(major, minor - 1, release + 1), TRUE, "H5_VERSION_GE"); + if (H5_VERS_RELEASE > 0) + VERIFY(H5_VERSION_GE(major, minor, release - 1), TRUE, "H5_VERSION_GE"); + + VERIFY(H5_VERSION_GE(major + 1, minor, release), FALSE, "H5_VERSION_GE"); + VERIFY(H5_VERSION_GE(major + 1, minor - 1, release), FALSE, "H5_VERSION_GE"); + VERIFY(H5_VERSION_GE(major + 1, minor - 1, release - 1), FALSE, "H5_VERSION_GE"); + VERIFY(H5_VERSION_GE(major, minor + 1, release), FALSE, "H5_VERSION_GE"); + VERIFY(H5_VERSION_GE(major, minor + 1, release - 1), FALSE, "H5_VERSION_GE"); + VERIFY(H5_VERSION_GE(major, minor, release + 1), FALSE, "H5_VERSION_GE"); + + VERIFY(H5_VERSION_LE(major, minor, release), TRUE, "H5_VERSION_LE"); + VERIFY(H5_VERSION_LE(major + 1, minor, release), TRUE, "H5_VERSION_LE"); + VERIFY(H5_VERSION_LE(major + 1, minor - 1, release), TRUE, "H5_VERSION_LE"); + VERIFY(H5_VERSION_LE(major + 1, minor - 1, release - 1), TRUE, "H5_VERSION_LE"); + VERIFY(H5_VERSION_LE(major, minor + 1, release), TRUE, "H5_VERSION_LE"); + VERIFY(H5_VERSION_LE(major, minor + 1, release - 1), TRUE, "H5_VERSION_LE"); + VERIFY(H5_VERSION_LE(major, minor, release + 1), TRUE, "H5_VERSION_LE"); + + VERIFY(H5_VERSION_LE(major - 1, minor, release), FALSE, "H5_VERSION_LE"); + VERIFY(H5_VERSION_LE(major - 1, minor + 1, release), FALSE, "H5_VERSION_LE"); + VERIFY(H5_VERSION_LE(major - 1, minor + 1, release + 1), FALSE, "H5_VERSION_LE"); + VERIFY(H5_VERSION_LE(major, minor - 1, release), FALSE, "H5_VERSION_LE"); + VERIFY(H5_VERSION_LE(major, minor - 1, release + 1), FALSE, "H5_VERSION_LE"); + if (H5_VERS_RELEASE > 0) + VERIFY(H5_VERSION_LE(major, minor, release - 1), FALSE, "H5_VERSION_LE"); +} /* test_libver_macros() */ + +/**************************************************************** +** +** test_libver_macros2(): +** Verify that H5_VERSION_GE works correactly and show how +** to use it. +** +****************************************************************/ +static void +test_libver_macros2(void) +{ + hid_t file; + hid_t grp; + htri_t status; + herr_t ret; /* Return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing macros for library version comparison with a file\n")); + + /* + * Create a file. + */ + file = H5Fcreate(FILE6, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file, FAIL, "H5Fcreate"); + + /* + * Create a group in the file. + */ + grp = H5Gcreate2(file, "Group", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file, FAIL, "H5Gcreate"); + + /* + * Close the group + */ + ret = H5Gclose(grp); + CHECK(ret, FAIL, "H5Gclose"); + + /* + * Delete the group using different function based on the library version. + * And verify the action. + */ +#if H5_VERSION_GE(1, 8, 0) + ret = H5Ldelete(file, "Group", H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lunlink"); + + status = H5Lexists(file, "Group", H5P_DEFAULT); + VERIFY(status, FALSE, "H5Lexists"); +#else + ret = H5Gunlink(file, "Group"); + CHECK(ret, FAIL, "H5Gunlink"); + + H5E_BEGIN_TRY + { + grp = H5Gopen(file, "Group"); + } + H5E_END_TRY; + VERIFY(grp, FAIL, "H5Gopen"); +#endif + + /* + * Close the file. + */ + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + +} /* test_libver_macros2() */ +#endif + +#if 0 +/**************************************************************** +** +** test_filesize(): +** Verify H5Fincrement_filesize() and H5Fget_eoa() works as +** indicated in the "RFC: Enhancement to the tool h5clear". +** +****************************************************************/ +static void +test_incr_filesize(void) +{ + hid_t fid; /* File opened with read-write permission */ + h5_stat_size_t filesize; /* Size of file when empty */ + hid_t fcpl; /* File creation property list */ + hid_t fapl; /* File access property list */ + hid_t dspace; /* Dataspace ID */ + hid_t dset; /* Dataset ID */ + hid_t dcpl; /* Dataset creation property list */ + unsigned u; /* Local index variable */ + char filename[FILENAME_LEN]; /* Filename to use */ + char name[32]; /* Dataset name */ + haddr_t stored_eoa; /* The stored EOA value */ + hid_t driver_id = -1; /* ID for this VFD */ + unsigned long driver_flags = 0; /* VFD feature flags */ + herr_t ret; /* Return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing H5Fincrement_filesize() and H5Fget_eoa())\n")); + + fapl = h5_fileaccess(); + h5_fixname(FILE8, fapl, filename, sizeof filename); + + /* Get the VFD feature flags */ + driver_id = H5Pget_driver(fapl); + CHECK(driver_id, FAIL, "H5Pget_driver"); + + ret = H5FDdriver_query(driver_id, &driver_flags); + CHECK(ret, FAIL, "H5PDdriver_query"); + + /* Check whether the VFD feature flag supports these two public routines */ + if (driver_flags & H5FD_FEAT_SUPPORTS_SWMR_IO) { + + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, FAIL, "H5Pcreate"); + + /* Set file space strategy */ + ret = H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_FSM_AGGR, FALSE, (hsize_t)1); + CHECK(ret, FAIL, "H5P_set_file_space_strategy"); + + /* Create the test file */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create dataspace for datasets */ + dspace = H5Screate(H5S_SCALAR); + CHECK(dspace, FAIL, "H5Screate"); + + /* Create a dataset creation property list */ + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + + /* Set the space allocation time to early */ + ret = H5Pset_alloc_time(dcpl, H5D_ALLOC_TIME_EARLY); + CHECK(ret, FAIL, "H5Pset_alloc_time"); + + /* Create datasets in file */ + for (u = 0; u < 10; u++) { + HDsnprintf(name, sizeof(name), "Dataset %u", u); + dset = H5Dcreate2(fid, name, H5T_STD_U32LE, dspace, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dset, FAIL, "H5Dcreate2"); + + ret = H5Dclose(dset); + CHECK(ret, FAIL, "H5Dclose"); + } /* end for */ + + /* Close dataspace */ + ret = H5Sclose(dspace); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close dataset creation property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Get the file size */ + filesize = h5_get_file_size(filename, fapl); + + /* Open the file */ + fid = H5Fopen(filename, H5F_ACC_RDWR, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Get the stored EOA */ + ret = H5Fget_eoa(fid, &stored_eoa); + CHECK(ret, FAIL, "H5Fget_eoa"); + + /* Verify the stored EOA is the same as filesize */ + VERIFY(filesize, stored_eoa, "file size"); + + /* Set the EOA to the MAX(EOA, EOF) + 512 */ + ret = H5Fincrement_filesize(fid, 512); + CHECK(ret, FAIL, "H5Fincrement_filesize"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Get the file size */ + filesize = h5_get_file_size(filename, fapl); + + /* Verify the filesize is the previous stored_eoa + 512 */ + VERIFY(filesize, stored_eoa + 512, "file size"); + + /* Close the file access property list */ + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close the file creation property list */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + } +} /* end test_incr_filesize() */ +#endif + +/**************************************************************** +** +** test_min_dset_ohdr(): +** Test API calls to toggle dataset object header minimization. +** +** TODO (as separate function?): +** + setting persists between close and (re)open? +** + dataset header sizes created while changing value of toggle +** +****************************************************************/ +#if 0 +static void +test_min_dset_ohdr(void) +{ + const char basename[] = "min_dset_ohdr_testfile"; + char filename[FILENAME_LEN] = ""; + hid_t file_id = -1; + hid_t file2_id = -1; + hbool_t minimize; + herr_t ret; + + MESSAGE(5, ("Testing dataset object header minimization\n")); + + /*********/ + /* SETUP */ + /*********/ + + h5_fixname(basename, H5P_DEFAULT, filename, sizeof(filename)); + + file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK_I(file_id, "H5Fcreate"); + + /*********/ + /* TESTS */ + /*********/ + + /*---------------------------------------- + * TEST default value + */ + ret = H5Fget_dset_no_attrs_hint(file_id, &minimize); + CHECK(ret, FAIL, "H5Fget_dset_no_attrs_hint"); + VERIFY(minimize, FALSE, "minimize flag"); + + /*---------------------------------------- + * TEST set to TRUE + */ + ret = H5Fset_dset_no_attrs_hint(file_id, TRUE); + CHECK(ret, FAIL, "H5Fset_dset_no_attrs_hint"); + + ret = H5Fget_dset_no_attrs_hint(file_id, &minimize); + CHECK(ret, FAIL, "H5Fget_dset_no_attrs_hint"); + VERIFY(minimize, TRUE, "minimize flag"); + + /*---------------------------------------- + * TEST second file open on same filename + */ + file2_id = H5Fopen(filename, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK_I(file2_id, "H5Fopen"); + + /* verify TRUE setting on second open + */ + ret = H5Fget_dset_no_attrs_hint(file_id, &minimize); + CHECK(ret, FAIL, "H5Fget_dset_no_attrs_hint"); + VERIFY(minimize, TRUE, "minimize flag"); + + /* re-set to FALSE on first open + */ + ret = H5Fset_dset_no_attrs_hint(file_id, FALSE); + CHECK(ret, FAIL, "H5Fset_dset_no_attrs_hint"); + + /* verify FALSE set on both opens + */ + ret = H5Fget_dset_no_attrs_hint(file_id, &minimize); + CHECK(ret, FAIL, "H5Fget_dset_no_attrs_hint"); + VERIFY(minimize, FALSE, "minimize flag"); + + ret = H5Fget_dset_no_attrs_hint(file2_id, &minimize); + CHECK(ret, FAIL, "H5Fget_dset_no_attrs_hint"); + VERIFY(minimize, FALSE, "minimize flag"); + + /* re-set to TRUE on second open + */ + ret = H5Fset_dset_no_attrs_hint(file2_id, TRUE); + CHECK(ret, FAIL, "H5Fset_dset_no_attrs_hint"); + + /* verify TRUE set on both opens + */ + ret = H5Fget_dset_no_attrs_hint(file_id, &minimize); + CHECK(ret, FAIL, "H5Fget_dset_no_attrs_hint"); + VERIFY(minimize, TRUE, "minimize flag"); + + ret = H5Fget_dset_no_attrs_hint(file2_id, &minimize); + CHECK(ret, FAIL, "H5Fget_dset_no_attrs_hint"); + VERIFY(minimize, TRUE, "minimize flag"); + + /*---------------------------------------- + * TEST error cases + */ + + /* trying to set with invalid file ID */ + H5E_BEGIN_TRY + { + ret = H5Fset_dset_no_attrs_hint(-1, TRUE); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Fset_dset_no_attrs_hint"); + + /* trying to get with invalid file ID */ + H5E_BEGIN_TRY + { + ret = H5Fget_dset_no_attrs_hint(-1, &minimize); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Fget_dset_no_attrs_hint"); + + /* trying to get with invalid pointer */ + H5E_BEGIN_TRY + { + ret = H5Fget_dset_no_attrs_hint(file_id, NULL); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Fget_dset_no_attrs_hint"); + + /************/ + /* TEARDOWN */ + /************/ + + ret = H5Fclose(file_id); + CHECK(ret, FAIL, "H5Fclose"); + ret = H5Fclose(file2_id); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_min_dset_ohdr() */ +#endif + +/**************************************************************** +** +** test_deprec(): +** Test deprecated functionality. +** +****************************************************************/ +#if 0 +#ifndef H5_NO_DEPRECATED_SYMBOLS +static void +test_deprec(const char *env_h5_drvr) +{ + hid_t file; /* File IDs for old & new files */ + hid_t fcpl; /* File creation property list */ + hid_t fapl; /* File creation property list */ + hid_t new_fapl; + hsize_t align; + unsigned super; /* Superblock version # */ + unsigned freelist; /* Free list version # */ + unsigned stab; /* Symbol table entry version # */ + unsigned shhdr; /* Shared object header version # */ + H5F_info1_t finfo; /* global information about file */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing deprecated routines\n")); + + /* Creating a file with the default file creation property list should + * create a version 0 superblock + */ + + /* Create file with default file creation property list */ + file = H5Fcreate(FILE1, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file, FAIL, "H5Fcreate"); + + /* Get the file's version information */ + ret = H5Fget_info1(file, &finfo); + CHECK(ret, FAIL, "H5Fget_info1"); + VERIFY(finfo.super_ext_size, 0, "H5Fget_info1"); + VERIFY(finfo.sohm.hdr_size, 0, "H5Fget_info1"); + VERIFY(finfo.sohm.msgs_info.index_size, 0, "H5Fget_info1"); + VERIFY(finfo.sohm.msgs_info.heap_size, 0, "H5Fget_info1"); + + /* Get the file's dataset creation property list */ + fcpl = H5Fget_create_plist(file); + CHECK(fcpl, FAIL, "H5Fget_create_plist"); + + /* Get the file's version information */ + ret = H5Pget_version(fcpl, &super, &freelist, &stab, &shhdr); + CHECK(ret, FAIL, "H5Pget_version"); + VERIFY(super, 0, "H5Pget_version"); + VERIFY(freelist, 0, "H5Pget_version"); + VERIFY(stab, 0, "H5Pget_version"); + VERIFY(shhdr, 0, "H5Pget_version"); + + /* Close FCPL */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + + /* Only run this part of the test with the sec2/default driver */ + if (h5_using_default_driver(env_h5_drvr)) { + /* Create a file creation property list */ + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, FAIL, "H5Pcreate"); + + /* Set a property in the FCPL that will push the superblock version up */ + ret = H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_PAGE, 1, (hsize_t)0); + ret = H5Pset_file_space_page_size(fcpl, (hsize_t)512); + CHECK(ret, FAIL, "H5Pset_file_space_strategy"); + + fapl = H5Pcreate(H5P_FILE_ACCESS); + ret = H5Pset_alignment(fapl, (hsize_t)1, (hsize_t)1024); + CHECK(ret, FAIL, "H5Pset_alignment"); + + /* Creating a file with the non-default file creation property list should + * create a version 2 superblock + */ + + /* Create file with custom file creation property list */ + file = H5Fcreate(FILE1, H5F_ACC_TRUNC, fcpl, fapl); + CHECK(file, FAIL, "H5Fcreate"); + + new_fapl = H5Fget_access_plist(file); + H5Pget_alignment(new_fapl, NULL, &align); + + /* Close FCPL */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Get the file's version information */ + ret = H5Fget_info1(file, &finfo); + CHECK(ret, FAIL, "H5Fget_info1"); + VERIFY(finfo.super_ext_size, 152, "H5Fget_info1"); + VERIFY(finfo.sohm.hdr_size, 0, "H5Fget_info1"); + VERIFY(finfo.sohm.msgs_info.index_size, 0, "H5Fget_info1"); + VERIFY(finfo.sohm.msgs_info.heap_size, 0, "H5Fget_info1"); + + /* Get the file's dataset creation property list */ + fcpl = H5Fget_create_plist(file); + CHECK(fcpl, FAIL, "H5Fget_create_plist"); + + /* Get the file's version information */ + ret = H5Pget_version(fcpl, &super, &freelist, &stab, &shhdr); + CHECK(ret, FAIL, "H5Pget_version"); + VERIFY(super, 2, "H5Pget_version"); + VERIFY(freelist, 0, "H5Pget_version"); + VERIFY(stab, 0, "H5Pget_version"); + VERIFY(shhdr, 0, "H5Pget_version"); + + /* Close FCPL */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open the file */ + file = H5Fopen(FILE1, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(file, FAIL, "H5Fcreate"); + + /* Get the file's version information */ + ret = H5Fget_info1(file, &finfo); + CHECK(ret, FAIL, "H5Fget_info1"); + VERIFY(finfo.super_ext_size, 152, "H5Fget_info1"); + VERIFY(finfo.sohm.hdr_size, 0, "H5Fget_info1"); + VERIFY(finfo.sohm.msgs_info.index_size, 0, "H5Fget_info1"); + VERIFY(finfo.sohm.msgs_info.heap_size, 0, "H5Fget_info1"); + + /* Get the file's creation property list */ + fcpl = H5Fget_create_plist(file); + CHECK(fcpl, FAIL, "H5Fget_create_plist"); + + /* Get the file's version information */ + ret = H5Pget_version(fcpl, &super, &freelist, &stab, &shhdr); + CHECK(ret, FAIL, "H5Pget_version"); + VERIFY(super, 2, "H5Pget_version"); + VERIFY(freelist, 0, "H5Pget_version"); + VERIFY(stab, 0, "H5Pget_version"); + VERIFY(shhdr, 0, "H5Pget_version"); + + /* Close FCPL */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + + { /* Test deprecated H5Pget/set_file_space() */ + + H5F_file_space_type_t old_strategy; + hsize_t old_threshold; + hid_t fid; + hid_t ffcpl; + + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, FAIL, "H5Pcreate"); + + ret = H5Pget_file_space(fcpl, &old_strategy, &old_threshold); + CHECK(ret, FAIL, "H5Pget_file_space"); + VERIFY(old_strategy, H5F_FILE_SPACE_ALL, "H5Pget_file_space"); + VERIFY(old_threshold, H5F_FREE_SPACE_THRESHOLD_DEF, "H5Pget_file_space"); + + /* Set file space strategy and free space section threshold */ + ret = H5Pset_file_space(fcpl, H5F_FILE_SPACE_ALL_PERSIST, (hsize_t)0); + CHECK(ret, FAIL, "H5Pget_file_space"); + + /* Get the file space info from the creation property */ + ret = H5Pget_file_space(fcpl, &old_strategy, &old_threshold); + CHECK(ret, FAIL, "H5Pget_file_space"); + VERIFY(old_strategy, H5F_FILE_SPACE_ALL_PERSIST, "H5Pget_file_space"); + VERIFY(old_threshold, H5F_FREE_SPACE_THRESHOLD_DEF, "H5Pget_file_space"); + + ret = H5Pset_file_space(fcpl, H5F_FILE_SPACE_DEFAULT, (hsize_t)3); + CHECK(ret, FAIL, "H5Pget_file_space"); + + ret = H5Pget_file_space(fcpl, &old_strategy, &old_threshold); + CHECK(ret, FAIL, "H5Pget_file_space"); + VERIFY(old_strategy, H5F_FILE_SPACE_ALL_PERSIST, "H5Pget_file_space"); + VERIFY(old_threshold, 3, "H5Pget_file_space"); + + /* Create a file */ + fid = H5Fcreate(FILE1, H5F_ACC_TRUNC, fcpl, H5P_DEFAULT); + CHECK(file, FAIL, "H5Fcreate"); + + old_strategy = H5F_FILE_SPACE_DEFAULT; + old_threshold = 0; + ffcpl = H5Fget_create_plist(fid); + ret = H5Pget_file_space(ffcpl, &old_strategy, &old_threshold); + CHECK(ret, FAIL, "H5Pget_file_space"); + VERIFY(old_strategy, H5F_FILE_SPACE_ALL_PERSIST, "H5Pget_file_space"); + VERIFY(old_threshold, 3, "H5Pget_file_space"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + ret = H5Pclose(ffcpl); + CHECK(ret, FAIL, "H5Pclose"); + + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Reopen the file */ + fid = H5Fopen(FILE1, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + old_strategy = H5F_FILE_SPACE_DEFAULT; + old_threshold = 0; + ffcpl = H5Fget_create_plist(fid); + ret = H5Pget_file_space(ffcpl, &old_strategy, &old_threshold); + CHECK(ret, FAIL, "H5Pget_file_space"); + VERIFY(old_strategy, H5F_FILE_SPACE_ALL_PERSIST, "H5Pget_file_space"); + VERIFY(old_threshold, 3, "H5Pget_file_space"); + + ret = H5Pclose(ffcpl); + CHECK(ret, FAIL, "H5Pclose"); + + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + } + } + +} /* test_deprec */ +#endif /* H5_NO_DEPRECATED_SYMBOLS */ +#endif + +/**************************************************************** +** +** test_file(): Main low-level file I/O test routine. +** +****************************************************************/ +void +test_file(void) +{ + const char *env_h5_drvr; /* File Driver value from environment */ + hid_t fapl_id = H5I_INVALID_HID; /* VFD-dependent fapl ID */ + hbool_t driver_is_default_compatible; + herr_t ret; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Low-Level File I/O\n")); + + /* Get the VFD to use */ + env_h5_drvr = HDgetenv(HDF5_DRIVER); + if (env_h5_drvr == NULL) + env_h5_drvr = "nomatch"; + + /* Improved version of VFD-dependent checks */ + fapl_id = h5_fileaccess(); + CHECK(fapl_id, H5I_INVALID_HID, "h5_fileaccess"); + + ret = h5_driver_is_default_vfd_compatible(fapl_id, &driver_is_default_compatible); + CHECK(ret, FAIL, "h5_driver_is_default_vfd_compatible"); + + test_file_create(); /* Test file creation(also creation templates)*/ + test_file_open(env_h5_drvr); /* Test file opening */ + test_file_reopen(); /* Test file reopening */ + test_file_close(); /* Test file close behavior */ + test_get_file_id(); /* Test H5Iget_file_id */ + test_get_obj_ids(); /* Test H5Fget_obj_ids for Jira Issue 8528 */ + test_file_perm(); /* Test file access permissions */ + test_file_perm2(); /* Test file access permission again */ + test_file_is_accessible(env_h5_drvr); /* Test detecting HDF5 files correctly */ + test_file_delete(fapl_id); /* Test H5Fdelete */ + test_file_open_dot(); /* Test opening objects with "." for a name */ + test_file_open_overlap(); /* Test opening files in an overlapping manner */ + test_file_getname(); /* Test basic H5Fget_name() functionality */ + test_file_double_root_open(); /* Test opening root group from two files works properly */ + test_file_double_group_open(); /* Test opening same group from two files works properly */ + test_file_double_dataset_open(); /* Test opening same dataset from two files works properly */ + test_file_double_datatype_open(); /* Test opening same named datatype from two files works properly */ + test_file_double_file_dataset_open(TRUE); + test_file_double_file_dataset_open(FALSE); +#if 0 + test_userblock_file_size( + env_h5_drvr); /* Tests that files created with a userblock have the correct size */ + test_cached_stab_info(); /* Tests that files are created with cached stab info in the superblock */ + + if (driver_is_default_compatible) { + test_rw_noupdate(); /* Test to ensure that RW permissions don't write the file unless dirtied */ + } + + test_userblock_alignment( + env_h5_drvr); /* Tests that files created with a userblock and alignment interact properly */ + test_userblock_alignment_paged(env_h5_drvr); /* Tests files created with a userblock and alignment (via + paged aggregation) interact properly */ + test_filespace_info(env_h5_drvr); /* Test file creation public routines: */ + /* H5Pget/set_file_space_strategy() & H5Pget/set_file_space_page_size() */ + /* Skipped testing for multi/split drivers */ + test_file_freespace(env_h5_drvr); /* Test file public routine H5Fget_freespace() */ + /* Skipped testing for multi/split drivers */ + /* Setup for multi/split drivers are there already */ + test_sects_freespace(env_h5_drvr, + TRUE); /* Test file public routine H5Fget_free_sections() for new format */ + /* Skipped testing for multi/split drivers */ + /* Setup for multi/split drivers are there already */ + test_sects_freespace(env_h5_drvr, FALSE); /* Test file public routine H5Fget_free_sections() */ + /* Skipped testing for multi/split drivers */ + + if (driver_is_default_compatible) { + test_filespace_compatible(); /* Test compatibility for file space management */ + + test_filespace_round_compatible(); /* Testing file space compatibility for files from trunk to 1_8 to + trunk */ + test_filespace_1_10_0_compatible(); /* Testing file space compatibility for files from release 1.10.0 + */ + } + + test_libver_bounds(); /* Test compatibility for file space management */ + test_libver_bounds_low_high(env_h5_drvr); + test_libver_macros(); /* Test the macros for library version comparison */ + test_libver_macros2(); /* Test the macros for library version comparison */ + test_incr_filesize(); /* Test H5Fincrement_filesize() and H5Fget_eoa() */ + test_min_dset_ohdr(); /* Test dataset object header minimization */ +#ifndef H5_NO_DEPRECATED_SYMBOLS + test_file_ishdf5(env_h5_drvr); /* Test detecting HDF5 files correctly */ + test_deprec(env_h5_drvr); /* Test deprecated routines */ +#endif /* H5_NO_DEPRECATED_SYMBOLS */ +#endif + + ret = H5Pclose(fapl_id); + CHECK(ret, FAIL, "H5Pclose"); + +} /* test_file() */ + +/*------------------------------------------------------------------------- + * Function: cleanup_file + * + * Purpose: Cleanup temporary test files + * + * Return: none + * + * Programmer: Albert Cheng + * July 2, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +void +cleanup_file(void) +{ + H5E_BEGIN_TRY + { + H5Fdelete(SFILE1, H5P_DEFAULT); + H5Fdelete(FILE1, H5P_DEFAULT); + H5Fdelete(FILE2, H5P_DEFAULT); + H5Fdelete(FILE3, H5P_DEFAULT); + H5Fdelete(FILE4, H5P_DEFAULT); + H5Fdelete(FILE5, H5P_DEFAULT); + H5Fdelete(FILE6, H5P_DEFAULT); + H5Fdelete(FILE7, H5P_DEFAULT); + H5Fdelete(DST_FILE, H5P_DEFAULT); + } + H5E_END_TRY; +} diff --git a/test/API/tgenprop.c b/test/API/tgenprop.c new file mode 100644 index 0000000..c1ee8af --- /dev/null +++ b/test/API/tgenprop.c @@ -0,0 +1,2201 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*********************************************************** + * + * Test program: tgenprop + * + * Test the Generic Property functionality + * + *************************************************************/ + +#define H5P_FRIEND /*suppress error about including H5Ppkg */ + +/* Define this macro to indicate that the testing APIs should be available */ +#define H5P_TESTING + +#include "testhdf5.h" + +/* #include "H5Dprivate.h" */ /* For Dataset creation property list names */ +/* #include "H5Ppkg.h" */ /* Generic Properties */ + +#define FILENAME "tgenprop.h5" + +/* Property definitions */ +#define CLASS1_NAME "Class 1" +#define CLASS1_PATH "root/Class 1" + +#define CLASS2_NAME "Class 2" +#define CLASS2_PATH "root/Class 1/Class 2" + +/* Property definitions */ +#define PROP1_NAME "Property 1" +int prop1_def = 10; /* Property 1 default value */ +#define PROP1_SIZE sizeof(prop1_def) +#define PROP1_DEF_VALUE (&prop1_def) + +#define PROP2_NAME "Property 2" +float prop2_def = 3.14F; /* Property 2 default value */ +#define PROP2_SIZE sizeof(prop2_def) +#define PROP2_DEF_VALUE (&prop2_def) + +#define PROP3_NAME "Property 3" +char prop3_def[10] = "Ten chars"; /* Property 3 default value */ +#define PROP3_SIZE sizeof(prop3_def) +#define PROP3_DEF_VALUE (&prop3_def) + +#define PROP4_NAME "Property 4" +double prop4_def = 1.41; /* Property 4 default value */ +#define PROP4_SIZE sizeof(prop4_def) +#define PROP4_DEF_VALUE (&prop4_def) + +/* Structs used during iteration */ +typedef struct iter_data_t { + int iter_count; + char **names; +} iter_data_t; + +typedef struct count_data_t { + int count; + hid_t id; +} count_data_t; + +/**************************************************************** +** +** test_genprop_basic_class(): Test basic generic property list code. +** Tests creating new generic classes. +** +****************************************************************/ +static void +test_genprop_basic_class(void) +{ + hid_t cid1; /* Generic Property class ID */ + hid_t cid2; /* Generic Property class ID */ + hid_t cid3; /* Generic Property class ID */ + char *name; /* Name of class */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Basic Generic Property List Class Creation Functionality\n")); + + /* Create a new generic class, derived from the root of the class hierarchy */ + cid1 = H5Pcreate_class(H5P_ROOT, CLASS1_NAME, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(cid1, "H5Pcreate_class"); + + /* Check class name */ + name = H5Pget_class_name(cid1); + CHECK_PTR(name, "H5Pget_class_name"); + if (HDstrcmp(name, CLASS1_NAME) != 0) + TestErrPrintf("Class names don't match!, name=%s, CLASS1_NAME=%s\n", name, CLASS1_NAME); + H5free_memory(name); + + /* Check class parent */ + cid2 = H5Pget_class_parent(cid1); + CHECK_I(cid2, "H5Pget_class_parent"); + + /* Verify class parent correct */ + ret = H5Pequal(cid2, H5P_ROOT); + VERIFY(ret, 1, "H5Pequal"); + + /* Make certain false positives aren't being returned */ + ret = H5Pequal(cid2, H5P_FILE_CREATE); + VERIFY(ret, 0, "H5Pequal"); + + /* Close parent class */ + ret = H5Pclose_class(cid2); + CHECK_I(ret, "H5Pclose_class"); + + /* Close class */ + ret = H5Pclose_class(cid1); + CHECK_I(ret, "H5Pclose_class"); + + /* Create another new generic class, derived from file creation class */ + cid1 = H5Pcreate_class(H5P_FILE_CREATE, CLASS2_NAME, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(cid1, "H5Pcreate_class"); + + /* Check class name */ + name = H5Pget_class_name(cid1); + CHECK_PTR(name, "H5Pget_class_name"); + if (HDstrcmp(name, CLASS2_NAME) != 0) + TestErrPrintf("Class names don't match!, name=%s, CLASS2_NAME=%s\n", name, CLASS2_NAME); + H5free_memory(name); + + /* Check class parent */ + cid2 = H5Pget_class_parent(cid1); + CHECK_I(cid2, "H5Pget_class_parent"); + + /* Verify class parent correct */ + ret = H5Pequal(cid2, H5P_FILE_CREATE); + VERIFY(ret, 1, "H5Pequal"); + + /* Check class parent's parent */ + cid3 = H5Pget_class_parent(cid2); + CHECK_I(cid3, "H5Pget_class_parent"); + + /* Verify class parent's parent correct */ + ret = H5Pequal(cid3, H5P_GROUP_CREATE); + VERIFY(ret, 1, "H5Pequal"); + + /* Close parent class's parent */ + ret = H5Pclose_class(cid3); + CHECK_I(ret, "H5Pclose_class"); + + /* Close parent class */ + ret = H5Pclose_class(cid2); + CHECK_I(ret, "H5Pclose_class"); + + /* Close class */ + ret = H5Pclose_class(cid1); + CHECK_I(ret, "H5Pclose_class"); +} /* end test_genprop_basic_class() */ + +/**************************************************************** +** +** test_genprop_basic_class_prop(): Test basic generic property list code. +** Tests adding properties to generic classes. +** +****************************************************************/ +static void +test_genprop_basic_class_prop(void) +{ + hid_t cid1; /* Generic Property class ID */ + size_t size; /* Size of property */ + size_t nprops; /* Number of properties in class */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Basic Generic Property List Class Properties Functionality\n")); + + /* Create a new generic class, derived from the root of the class hierarchy */ + cid1 = H5Pcreate_class(H5P_ROOT, CLASS1_NAME, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(cid1, "H5Pcreate_class"); + + /* Check the number of properties in class */ + ret = H5Pget_nprops(cid1, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 0, "H5Pget_nprops"); + + /* Check the existence of the first property (should fail) */ + ret = H5Pexist(cid1, PROP1_NAME); + VERIFY(ret, 0, "H5Pexist"); + + /* Insert first property into class (with no callbacks) */ + ret = + H5Pregister2(cid1, PROP1_NAME, PROP1_SIZE, PROP1_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pregister2"); + + /* Try to insert the first property again (should fail) */ + H5E_BEGIN_TRY + { + ret = H5Pregister2(cid1, PROP1_NAME, PROP1_SIZE, PROP1_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL, + NULL); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Pregister2"); + + /* Check the existence of the first property */ + ret = H5Pexist(cid1, PROP1_NAME); + VERIFY(ret, 1, "H5Pexist"); + + /* Check the size of the first property */ + ret = H5Pget_size(cid1, PROP1_NAME, &size); + CHECK_I(ret, "H5Pget_size"); + VERIFY(size, PROP1_SIZE, "H5Pget_size"); + + /* Check the number of properties in class */ + ret = H5Pget_nprops(cid1, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 1, "H5Pget_nprops"); + + /* Insert second property into class (with no callbacks) */ + ret = + H5Pregister2(cid1, PROP2_NAME, PROP2_SIZE, PROP2_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pregister2"); + + /* Try to insert the second property again (should fail) */ + H5E_BEGIN_TRY + { + ret = H5Pregister2(cid1, PROP2_NAME, PROP2_SIZE, PROP2_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL, + NULL); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Pregister2"); + + /* Check the existence of the second property */ + ret = H5Pexist(cid1, PROP2_NAME); + VERIFY(ret, 1, "H5Pexist"); + + /* Check the size of the second property */ + ret = H5Pget_size(cid1, PROP2_NAME, &size); + CHECK_I(ret, "H5Pget_size"); + VERIFY(size, PROP2_SIZE, "H5Pget_size"); + + /* Check the number of properties in class */ + ret = H5Pget_nprops(cid1, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 2, "H5Pget_nprops"); + + /* Insert third property into class (with no callbacks) */ + ret = + H5Pregister2(cid1, PROP3_NAME, PROP3_SIZE, PROP3_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pregister2"); + + /* Check the existence of the third property */ + ret = H5Pexist(cid1, PROP3_NAME); + VERIFY(ret, 1, "H5Pexist"); + + /* Check the size of the third property */ + ret = H5Pget_size(cid1, PROP3_NAME, &size); + CHECK_I(ret, "H5Pget_size"); + VERIFY(size, PROP3_SIZE, "H5Pget_size"); + + /* Check the number of properties in class */ + ret = H5Pget_nprops(cid1, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 3, "H5Pget_nprops"); + + /* Unregister first property */ + ret = H5Punregister(cid1, PROP1_NAME); + CHECK_I(ret, "H5Punregister"); + + /* Try to check the size of the first property (should fail) */ + H5E_BEGIN_TRY + { + ret = H5Pget_size(cid1, PROP1_NAME, &size); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Pget_size"); + + /* Check the number of properties in class */ + ret = H5Pget_nprops(cid1, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 2, "H5Pget_nprops"); + + /* Unregister second property */ + ret = H5Punregister(cid1, PROP2_NAME); + CHECK_I(ret, "H5Punregister"); + + /* Check the number of properties in class */ + ret = H5Pget_nprops(cid1, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 1, "H5Pget_nprops"); + + /* Unregister third property */ + ret = H5Punregister(cid1, PROP3_NAME); + CHECK_I(ret, "H5Punregister"); + + /* Check the number of properties in class */ + ret = H5Pget_nprops(cid1, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 0, "H5Pget_nprops"); + + /* Close class */ + ret = H5Pclose_class(cid1); + CHECK_I(ret, "H5Pclose_class"); +} /* end test_genprop_basic_class_prop() */ + +/**************************************************************** +** +** test_genprop_iter1(): Property iterator for test_genprop_class_iter +** +****************************************************************/ +static int +test_genprop_iter1(hid_t H5_ATTR_UNUSED id, const char *name, void *iter_data) +{ + iter_data_t *idata = (iter_data_t *)iter_data; + + return HDstrcmp(name, idata->names[idata->iter_count++]); +} + +/**************************************************************** +** +** test_genprop_class_iter(): Test basic generic property list code. +** Tests iterating over properties in a generic class. +** +****************************************************************/ +static void +test_genprop_class_iter(void) +{ + hid_t cid1; /* Generic Property class ID */ + size_t nprops; /* Number of properties in class */ + int idx; /* Index to start iteration at */ + struct { /* Struct for iterations */ + int iter_count; + const char **names; + } iter_struct; + const char *pnames[4] = {/* Names of properties for iterator */ + PROP1_NAME, PROP2_NAME, PROP3_NAME, PROP4_NAME}; + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Basic Generic Property List Class Property Iteration Functionality\n")); + + /* Create a new generic class, derived from the root of the class hierarchy */ + cid1 = H5Pcreate_class(H5P_ROOT, CLASS1_NAME, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(cid1, "H5Pcreate_class"); + + /* Insert first property into class (with no callbacks) */ + ret = + H5Pregister2(cid1, PROP1_NAME, PROP1_SIZE, PROP1_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pregister2"); + + /* Insert second property into class (with no callbacks) */ + ret = + H5Pregister2(cid1, PROP2_NAME, PROP2_SIZE, PROP2_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pregister2"); + + /* Insert third property into class (with no callbacks) */ + ret = + H5Pregister2(cid1, PROP3_NAME, PROP3_SIZE, PROP3_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pregister2"); + + /* Insert third property into class (with no callbacks) */ + ret = + H5Pregister2(cid1, PROP4_NAME, PROP4_SIZE, PROP4_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pregister2"); + + /* Check the number of properties in class */ + ret = H5Pget_nprops(cid1, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 4, "H5Pget_nprops"); + + /* Iterate over all properties in class */ + iter_struct.iter_count = 0; + iter_struct.names = pnames; + ret = H5Piterate(cid1, NULL, test_genprop_iter1, &iter_struct); + VERIFY(ret, 0, "H5Piterate"); + + /* Iterate over last three properties in class */ + idx = iter_struct.iter_count = 1; + ret = H5Piterate(cid1, &idx, test_genprop_iter1, &iter_struct); + VERIFY(ret, 0, "H5Piterate"); + VERIFY(idx, (int)nprops, "H5Piterate"); + + /* Close class */ + ret = H5Pclose_class(cid1); + CHECK_I(ret, "H5Pclose_class"); +} /* end test_genprop_class_iter() */ + +/**************************************************************** +** +** test_genprop_cls_*_cb1(): Property List callbacks for test_genprop_class_callback +** +****************************************************************/ +static herr_t +test_genprop_cls_crt_cb1(hid_t list_id, void *create_data) +{ + count_data_t *cdata = (count_data_t *)create_data; + + cdata->count++; + cdata->id = list_id; + + return SUCCEED; +} + +static herr_t +test_genprop_cls_cpy_cb1(hid_t new_list_id, hid_t H5_ATTR_UNUSED old_list_id, void *copy_data) +{ + count_data_t *cdata = (count_data_t *)copy_data; + + cdata->count++; + cdata->id = new_list_id; + + return SUCCEED; +} + +static herr_t +test_genprop_cls_cls_cb1(hid_t list_id, void *create_data) +{ + count_data_t *cdata = (count_data_t *)create_data; + + cdata->count++; + cdata->id = list_id; + + return SUCCEED; +} + +/**************************************************************** +** +** test_genprop_class_callback(): Test basic generic property list code. +** Tests callbacks for property lists in a generic class. +** +****************************************************************/ +static void +test_genprop_class_callback(void) +{ + hid_t cid1; /* Generic Property class ID */ + hid_t cid2; /* Generic Property class ID */ + hid_t lid1; /* Generic Property list ID */ + hid_t lid2; /* Generic Property list ID */ + hid_t lid3; /* Generic Property list ID */ + size_t nprops; /* Number of properties in class */ + struct { /* Struct for callbacks */ + int count; + hid_t id; + } crt_cb_struct, cpy_cb_struct, cls_cb_struct; + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Basic Generic Property List Class Callback Functionality\n")); + + /* Create a new generic class, derived from the root of the class hierarchy */ + cid1 = + H5Pcreate_class(H5P_ROOT, CLASS1_NAME, test_genprop_cls_crt_cb1, &crt_cb_struct, + test_genprop_cls_cpy_cb1, &cpy_cb_struct, test_genprop_cls_cls_cb1, &cls_cb_struct); + CHECK_I(cid1, "H5Pcreate_class"); + + /* Insert first property into class (with no callbacks) */ + ret = + H5Pregister2(cid1, PROP1_NAME, PROP1_SIZE, PROP1_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pregister2"); + + /* Insert second property into class (with no callbacks) */ + ret = + H5Pregister2(cid1, PROP2_NAME, PROP2_SIZE, PROP2_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pregister2"); + + /* Insert third property into class (with no callbacks) */ + ret = + H5Pregister2(cid1, PROP3_NAME, PROP3_SIZE, PROP3_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pregister2"); + + /* Check the number of properties in class */ + ret = H5Pget_nprops(cid1, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 3, "H5Pget_nprops"); + + /* Initialize class callback structs */ + crt_cb_struct.count = 0; + crt_cb_struct.id = (-1); + cpy_cb_struct.count = 0; + cpy_cb_struct.id = (-1); + cls_cb_struct.count = 0; + cls_cb_struct.id = (-1); + + /* Create a property list from the class */ + lid1 = H5Pcreate(cid1); + CHECK_I(lid1, "H5Pcreate"); + + /* Verify that the creation callback occurred */ + VERIFY(crt_cb_struct.count, 1, "H5Pcreate"); + VERIFY(crt_cb_struct.id, lid1, "H5Pcreate"); + + /* Check the number of properties in list */ + ret = H5Pget_nprops(lid1, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 3, "H5Pget_nprops"); + + /* Create another property list from the class */ + lid2 = H5Pcreate(cid1); + CHECK_I(lid2, "H5Pcreate"); + + /* Verify that the creation callback occurred */ + VERIFY(crt_cb_struct.count, 2, "H5Pcreate"); + VERIFY(crt_cb_struct.id, lid2, "H5Pcreate"); + + /* Check the number of properties in list */ + ret = H5Pget_nprops(lid2, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 3, "H5Pget_nprops"); + + /* Create another property list by copying an existing list */ + lid3 = H5Pcopy(lid1); + CHECK_I(lid3, "H5Pcopy"); + + /* Verify that the copy callback occurred */ + VERIFY(cpy_cb_struct.count, 1, "H5Pcopy"); + VERIFY(cpy_cb_struct.id, lid3, "H5Pcopy"); + + /* Check the number of properties in list */ + ret = H5Pget_nprops(lid3, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 3, "H5Pget_nprops"); + + /* Close first list */ + ret = H5Pclose(lid1); + CHECK_I(ret, "H5Pclose"); + + /* Verify that the close callback occurred */ + VERIFY(cls_cb_struct.count, 1, "H5Pclose"); + VERIFY(cls_cb_struct.id, lid1, "H5Pclose"); + + /* Close second list */ + ret = H5Pclose(lid2); + CHECK_I(ret, "H5Pclose"); + + /* Verify that the close callback occurred */ + VERIFY(cls_cb_struct.count, 2, "H5Pclose"); + VERIFY(cls_cb_struct.id, lid2, "H5Pclose"); + + /* Close third list */ + ret = H5Pclose(lid3); + CHECK_I(ret, "H5Pclose"); + + /* Verify that the close callback occurred */ + VERIFY(cls_cb_struct.count, 3, "H5Pclose"); + VERIFY(cls_cb_struct.id, lid3, "H5Pclose"); + + /* Create another new generic class, derived from first class */ + cid2 = + H5Pcreate_class(cid1, CLASS2_NAME, test_genprop_cls_crt_cb1, &crt_cb_struct, test_genprop_cls_cpy_cb1, + &cpy_cb_struct, test_genprop_cls_cls_cb1, &cls_cb_struct); + CHECK_I(cid2, "H5Pcreate_class"); + + /* Insert fourth property into class (with no callbacks) */ + ret = + H5Pregister2(cid2, PROP4_NAME, PROP4_SIZE, PROP4_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pregister2"); + + /* Check the number of properties in class */ + /* (only reports the number of properties in 2nd class) */ + ret = H5Pget_nprops(cid2, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 1, "H5Pget_nprops"); + + /* Create a property list from the 2nd class */ + lid1 = H5Pcreate(cid2); + CHECK_I(lid1, "H5Pcreate"); + + /* Verify that both of the creation callbacks occurred */ + VERIFY(crt_cb_struct.count, 4, "H5Pcreate"); + VERIFY(crt_cb_struct.id, lid1, "H5Pcreate"); + + /* Check the number of properties in list */ + ret = H5Pget_nprops(lid1, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 4, "H5Pget_nprops"); + + /* Create another property list by copying existing list */ + lid2 = H5Pcopy(lid1); + CHECK_I(lid2, "H5Pcopy"); + + /* Verify that both of the copy callbacks occurred */ + VERIFY(cpy_cb_struct.count, 3, "H5Pcopy"); + VERIFY(cpy_cb_struct.id, lid2, "H5Pcopy"); + + /* Check the number of properties in list */ + ret = H5Pget_nprops(lid2, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 4, "H5Pget_nprops"); + + /* Close first list */ + ret = H5Pclose(lid1); + CHECK_I(ret, "H5Pclose"); + + /* Verify that both of the close callbacks occurred */ + VERIFY(cls_cb_struct.count, 5, "H5Pclose"); + VERIFY(cls_cb_struct.id, lid1, "H5Pclose"); + + /* Close second list */ + ret = H5Pclose(lid2); + CHECK_I(ret, "H5Pclose"); + + /* Verify that both of the close callbacks occurred */ + VERIFY(cls_cb_struct.count, 7, "H5Pclose"); + VERIFY(cls_cb_struct.id, lid2, "H5Pclose"); + + /* Close classes */ + ret = H5Pclose_class(cid1); + CHECK_I(ret, "H5Pclose_class"); + ret = H5Pclose_class(cid2); + CHECK_I(ret, "H5Pclose_class"); +} /* end test_genprop_class_callback() */ + +/**************************************************************** +** +** test_genprop_basic_list(): Test basic generic property list code. +** Tests creating new generic property lists. +** +****************************************************************/ +static void +test_genprop_basic_list(void) +{ + hid_t cid1; /* Generic Property class ID */ + hid_t cid2; /* Generic Property class ID */ + hid_t lid1; /* Generic Property list ID */ + size_t nprops; /* Number of properties */ + size_t size; /* Size of property */ + int prop1_value; /* Value for property #1 */ + float prop2_value; /* Value for property #2 */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Basic Generic Property List Creation Functionality\n")); + + /* Create a new generic class, derived from the root of the class hierarchy */ + cid1 = H5Pcreate_class(H5P_ROOT, CLASS1_NAME, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(cid1, "H5Pcreate_class"); + + /* Add several properties (w/default values) */ + + /* Insert first property into class (with no callbacks) */ + ret = + H5Pregister2(cid1, PROP1_NAME, PROP1_SIZE, PROP1_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pregister2"); + + /* Insert second property into class (with no callbacks) */ + ret = + H5Pregister2(cid1, PROP2_NAME, PROP2_SIZE, PROP2_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pregister2"); + + /* Check the number of properties in class */ + ret = H5Pget_nprops(cid1, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 2, "H5Pget_nprops"); + + /* Create a property list from the class */ + lid1 = H5Pcreate(cid1); + CHECK_I(lid1, "H5Pcreate"); + + /* Get the list's class */ + cid2 = H5Pget_class(lid1); + CHECK_I(cid2, "H5Pget_class"); + + /* Check that the list's class is correct */ + ret = H5Pequal(cid1, cid2); + VERIFY(ret, 1, "H5Pequal"); + + /* Check correct "is a" class/list relationship */ + ret = H5Pisa_class(lid1, cid1); + VERIFY(ret, 1, "H5Pisa_class"); + + /* Check "is a" class/list relationship another way */ + ret = H5Pisa_class(lid1, cid2); + VERIFY(ret, 1, "H5Pisa_class"); + + /* Close class */ + ret = H5Pclose_class(cid2); + CHECK_I(ret, "H5Pclose_class"); + + /* Check the number of properties in list */ + ret = H5Pget_nprops(lid1, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 2, "H5Pget_nprops"); + + /* Check existence of properties */ + ret = H5Pexist(lid1, PROP1_NAME); + VERIFY(ret, 1, "H5Pexist"); + ret = H5Pexist(lid1, PROP2_NAME); + VERIFY(ret, 1, "H5Pexist"); + + /* Check the sizes of the properties */ + ret = H5Pget_size(lid1, PROP1_NAME, &size); + CHECK_I(ret, "H5Pget_size"); + VERIFY(size, PROP1_SIZE, "H5Pget_size"); + ret = H5Pget_size(lid1, PROP2_NAME, &size); + CHECK_I(ret, "H5Pget_size"); + VERIFY(size, PROP2_SIZE, "H5Pget_size"); + + /* Check values of properties (set with default values) */ + ret = H5Pget(lid1, PROP1_NAME, &prop1_value); + CHECK_I(ret, "H5Pget"); + VERIFY(prop1_value, *PROP1_DEF_VALUE, "H5Pget"); + ret = H5Pget(lid1, PROP2_NAME, &prop2_value); + CHECK_I(ret, "H5Pget"); + /* Verify the floating-poing value in this way to avoid compiler warning. */ + if (!H5_FLT_ABS_EQUAL(prop2_value, *PROP2_DEF_VALUE)) + HDprintf("*** UNEXPECTED VALUE from %s should be %f, but is %f at line %4d in %s\n", "H5Pget", + (double)*PROP2_DEF_VALUE, (double)prop2_value, (int)__LINE__, __FILE__); + + /* Close list */ + ret = H5Pclose(lid1); + CHECK_I(ret, "H5Pclose"); + + /* Close class */ + ret = H5Pclose_class(cid1); + CHECK_I(ret, "H5Pclose_class"); + +} /* end test_genprop_basic_list() */ + +/**************************************************************** +** +** test_genprop_basic_list_prop(): Test basic generic property list code. +** Tests creating new generic property lists and adding and +** removing properties from them. +** +****************************************************************/ +static void +test_genprop_basic_list_prop(void) +{ + hid_t cid1; /* Generic Property class ID */ + hid_t lid1; /* Generic Property list ID */ + size_t nprops; /* Number of properties */ + int prop1_value; /* Value for property #1 */ + float prop2_value; /* Value for property #2 */ + char prop3_value[10]; /* Property #3 value */ + double prop4_value; /* Property #4 value */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Basic Generic Property List Property Functionality\n")); + + /* Create a new generic class, derived from the root of the class hierarchy */ + cid1 = H5Pcreate_class(H5P_ROOT, CLASS1_NAME, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(cid1, "H5Pcreate_class"); + + /* Add several properties (several w/default values) */ + + /* Insert first property into class (with no callbacks) */ + ret = + H5Pregister2(cid1, PROP1_NAME, PROP1_SIZE, PROP1_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pregister2"); + + /* Insert second property into class (with no callbacks) */ + ret = + H5Pregister2(cid1, PROP2_NAME, PROP2_SIZE, PROP2_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pregister2"); + + /* Create a property list from the class */ + lid1 = H5Pcreate(cid1); + CHECK_I(lid1, "H5Pcreate"); + + /* Check the number of properties in list */ + ret = H5Pget_nprops(lid1, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 2, "H5Pget_nprops"); + + /* Add temporary properties */ + + /* Insert first temporary property into list (with no callbacks) */ + ret = H5Pinsert2(lid1, PROP3_NAME, PROP3_SIZE, PROP3_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pinsert2"); + + /* Insert second temporary property into list (with no callbacks) */ + ret = H5Pinsert2(lid1, PROP4_NAME, PROP4_SIZE, PROP4_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pinsert2"); + + /* Check the number of properties in list */ + ret = H5Pget_nprops(lid1, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 4, "H5Pget_nprops"); + + /* Check existence of all properties */ + ret = H5Pexist(lid1, PROP1_NAME); + VERIFY(ret, 1, "H5Pexist"); + ret = H5Pexist(lid1, PROP2_NAME); + VERIFY(ret, 1, "H5Pexist"); + ret = H5Pexist(lid1, PROP3_NAME); + VERIFY(ret, 1, "H5Pexist"); + ret = H5Pexist(lid1, PROP4_NAME); + VERIFY(ret, 1, "H5Pexist"); + + /* Check values of permanent properties (set with default values) */ + ret = H5Pget(lid1, PROP1_NAME, &prop1_value); + CHECK_I(ret, "H5Pget"); + VERIFY(prop1_value, *PROP1_DEF_VALUE, "H5Pget"); + ret = H5Pget(lid1, PROP2_NAME, &prop2_value); + CHECK_I(ret, "H5Pget"); + /* Verify the floating-poing value in this way to avoid compiler warning. */ + if (!H5_FLT_ABS_EQUAL(prop2_value, *PROP2_DEF_VALUE)) + HDprintf("*** UNEXPECTED VALUE from %s should be %f, but is %f at line %4d in %s\n", "H5Pget", + (double)*PROP2_DEF_VALUE, (double)prop2_value, (int)__LINE__, __FILE__); + + /* Check values of temporary properties (set with regular values) */ + ret = H5Pget(lid1, PROP3_NAME, &prop3_value); + CHECK_I(ret, "H5Pget"); + if (HDmemcmp(&prop3_value, PROP3_DEF_VALUE, PROP3_SIZE) != 0) + TestErrPrintf("Property #3 doesn't match!, line=%d\n", __LINE__); + ret = H5Pget(lid1, PROP4_NAME, &prop4_value); + CHECK_I(ret, "H5Pget"); + /* Verify the floating-poing value in this way to avoid compiler warning. */ + if (!H5_DBL_ABS_EQUAL(prop4_value, *PROP4_DEF_VALUE)) + HDprintf("*** UNEXPECTED VALUE from %s should be %f, but is %f at line %4d in %s\n", "H5Pget", + *PROP4_DEF_VALUE, prop4_value, (int)__LINE__, __FILE__); + + /* Delete permanent property */ + ret = H5Premove(lid1, PROP2_NAME); + CHECK_I(ret, "H5Premove"); + + /* Check number of properties */ + ret = H5Pget_nprops(lid1, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 3, "H5Pget_nprops"); + + /* Delete temporary property */ + ret = H5Premove(lid1, PROP3_NAME); + CHECK_I(ret, "H5Premove"); + + /* Check number of properties */ + ret = H5Pget_nprops(lid1, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 2, "H5Pget_nprops"); + + /* Check existence of remaining properties */ + ret = H5Pexist(lid1, PROP1_NAME); + VERIFY(ret, 1, "H5Pexist"); + ret = H5Pexist(lid1, PROP4_NAME); + VERIFY(ret, 1, "H5Pexist"); + + /* Check values of permanent properties (set with default values) */ + ret = H5Pget(lid1, PROP1_NAME, &prop1_value); + CHECK_I(ret, "H5Pget"); + VERIFY(prop1_value, *PROP1_DEF_VALUE, "H5Pget"); + + /* Check values of temporary properties (set with regular values) */ + ret = H5Pget(lid1, PROP4_NAME, &prop4_value); + CHECK_I(ret, "H5Pget"); + /* Verify the floating-poing value in this way to avoid compiler warning. */ + if (!H5_DBL_ABS_EQUAL(prop4_value, *PROP4_DEF_VALUE)) + HDprintf("*** UNEXPECTED VALUE from %s should be %f, but is %f at line %4d in %s\n", "H5Pget", + *PROP4_DEF_VALUE, prop4_value, (int)__LINE__, __FILE__); + + /* Close list */ + ret = H5Pclose(lid1); + CHECK_I(ret, "H5Pclose"); + + /* Close class */ + ret = H5Pclose_class(cid1); + CHECK_I(ret, "H5Pclose_class"); + +} /* end test_genprop_basic_list_prop() */ + +/**************************************************************** +** +** test_genprop_iter2(): Property iterator for test_genprop_list_iter +** +****************************************************************/ +static int +test_genprop_iter2(hid_t H5_ATTR_UNUSED id, const char *name, void *iter_data) +{ + iter_data_t *idata = (iter_data_t *)iter_data; + + return HDstrcmp(name, idata->names[idata->iter_count++]); +} + +/**************************************************************** +** +** test_genprop_list_iter(): Test basic generic property list code. +** Tests iterating over generic property list properties. +** +****************************************************************/ +static void +test_genprop_list_iter(void) +{ + hid_t cid1; /* Generic Property class ID */ + hid_t lid1; /* Generic Property list ID */ + size_t nprops; /* Number of properties */ + int idx; /* Index to start iteration at */ + struct { /* Struct for iterations */ + int iter_count; + const char **names; + } iter_struct; + const char *pnames[4] = {/* Names of properties for iterator */ + PROP3_NAME, PROP4_NAME, PROP1_NAME, PROP2_NAME}; + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Generic Property List Iteration Functionality\n")); + + /* Create a new generic class, derived from the root of the class hierarchy */ + cid1 = H5Pcreate_class(H5P_ROOT, CLASS1_NAME, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(cid1, "H5Pcreate_class"); + + /* Add several properties (several w/default values) */ + + /* Insert first property into class (with no callbacks) */ + ret = + H5Pregister2(cid1, PROP1_NAME, PROP1_SIZE, PROP1_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pregister2"); + + /* Insert second property into class (with no callbacks) */ + ret = + H5Pregister2(cid1, PROP2_NAME, PROP2_SIZE, PROP2_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pregister2"); + + /* Create a property list from the class */ + lid1 = H5Pcreate(cid1); + CHECK_I(lid1, "H5Pcreate"); + + /* Check the number of properties in list */ + ret = H5Pget_nprops(lid1, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 2, "H5Pget_nprops"); + + /* Add temporary properties */ + + /* Insert first temporary property into class (with no callbacks) */ + ret = H5Pinsert2(lid1, PROP3_NAME, PROP3_SIZE, PROP3_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pinsert2"); + + /* Insert second temporary property into class (with no callbacks) */ + ret = H5Pinsert2(lid1, PROP4_NAME, PROP4_SIZE, PROP4_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pinsert2"); + + /* Check the number of properties in list */ + ret = H5Pget_nprops(lid1, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 4, "H5Pget_nprops"); + + /* Iterate over all properties in list */ + iter_struct.iter_count = 0; + iter_struct.names = pnames; + ret = H5Piterate(lid1, NULL, test_genprop_iter2, &iter_struct); + VERIFY(ret, 0, "H5Piterate"); + + /* Iterate over last three properties in list */ + idx = iter_struct.iter_count = 1; + ret = H5Piterate(lid1, &idx, test_genprop_iter2, &iter_struct); + VERIFY(ret, 0, "H5Piterate"); + VERIFY(idx, (int)nprops, "H5Piterate"); + + /* Close list */ + ret = H5Pclose(lid1); + CHECK_I(ret, "H5Pclose"); + + /* Close class */ + ret = H5Pclose_class(cid1); + CHECK_I(ret, "H5Pclose_class"); + +} /* end test_genprop_list_iter() */ + +typedef struct { + /* Creation information */ + int crt_count; + char *crt_name; + void *crt_value; + + /* Set information */ + int set_count; + hid_t set_plist_id; + char *set_name; + void *set_value; + + /* Get information */ + int get_count; + hid_t get_plist_id; + char *get_name; + void *get_value; + + /* Delete information */ + int del_count; + hid_t del_plist_id; + char *del_name; + void *del_value; + + /* Copy information */ + int cop_count; + char *cop_name; + void *cop_value; + + /* Compare information */ + int cmp_count; + + /* Close information */ + int cls_count; + char *cls_name; + void *cls_value; +} prop_cb_info; + +/* Global variables for Callback information */ +prop_cb_info prop1_cb_info; /* Callback statistics for property #1 */ +prop_cb_info prop2_cb_info; /* Callback statistics for property #2 */ +prop_cb_info prop3_cb_info; /* Callback statistics for property #3 */ + +/**************************************************************** +** +** test_genprop_cls_cpy_cb2(): Property Class callback for test_genprop_list_callback +** +****************************************************************/ +static herr_t +test_genprop_cls_cpy_cb2(hid_t new_list_id, hid_t H5_ATTR_UNUSED old_list_id, void *create_data) +{ + count_data_t *cdata = (count_data_t *)create_data; + + cdata->count++; + cdata->id = new_list_id; + + return SUCCEED; +} + +/**************************************************************** +** +** test_genprop_prop_crt_cb1(): Property creation callback for test_genprop_list_callback +** +****************************************************************/ +static herr_t +test_genprop_prop_crt_cb1(const char *name, size_t size, void *def_value) +{ + /* Set the information from the creation call */ + prop1_cb_info.crt_count++; + prop1_cb_info.crt_name = HDstrdup(name); + prop1_cb_info.crt_value = HDmalloc(size); + HDmemcpy(prop1_cb_info.crt_value, def_value, size); + + return (SUCCEED); +} + +/**************************************************************** +** +** test_genprop_prop_set_cb1(): Property set callback for test_genprop_list_callback +** +****************************************************************/ +static herr_t +test_genprop_prop_set_cb1(hid_t plist_id, const char *name, size_t size, void *value) +{ + /* Set the information from the set call */ + prop1_cb_info.set_count++; + prop1_cb_info.set_plist_id = plist_id; + if (prop1_cb_info.set_name == NULL) + prop1_cb_info.set_name = HDstrdup(name); + if (prop1_cb_info.set_value == NULL) + prop1_cb_info.set_value = HDmalloc(size); + HDmemcpy(prop1_cb_info.set_value, value, size); + + return (SUCCEED); +} + +/**************************************************************** +** +** test_genprop_prop_get_cb1(): Property get callback for test_genprop_list_callback +** +****************************************************************/ +static herr_t +test_genprop_prop_get_cb1(hid_t plist_id, const char *name, size_t size, void *value) +{ + /* Set the information from the get call */ + prop1_cb_info.get_count++; + prop1_cb_info.get_plist_id = plist_id; + if (prop1_cb_info.get_name == NULL) + prop1_cb_info.get_name = HDstrdup(name); + if (prop1_cb_info.get_value == NULL) + prop1_cb_info.get_value = HDmalloc(size); + HDmemcpy(prop1_cb_info.get_value, value, size); + + return (SUCCEED); +} + +/**************************************************************** +** +** test_genprop_prop_cop_cb1(): Property copy callback for test_genprop_list_callback +** +****************************************************************/ +static herr_t +test_genprop_prop_cop_cb1(const char *name, size_t size, void *value) +{ + /* Set the information from the get call */ + prop1_cb_info.cop_count++; + if (prop1_cb_info.cop_name == NULL) + prop1_cb_info.cop_name = HDstrdup(name); + if (prop1_cb_info.cop_value == NULL) + prop1_cb_info.cop_value = HDmalloc(size); + HDmemcpy(prop1_cb_info.cop_value, value, size); + + return (SUCCEED); +} + +/**************************************************************** +** +** test_genprop_prop_cmp_cb1(): Property comparison callback for test_genprop_list_callback +** +****************************************************************/ +static int +test_genprop_prop_cmp_cb1(const void *value1, const void *value2, size_t size) +{ + /* Set the information from the comparison call */ + prop1_cb_info.cmp_count++; + + return (HDmemcmp(value1, value2, size)); +} + +/**************************************************************** +** +** test_genprop_prop_cmp_cb3(): Property comparison callback for test_genprop_list_callback +** +****************************************************************/ +static int +test_genprop_prop_cmp_cb3(const void *value1, const void *value2, size_t size) +{ + /* Set the information from the comparison call */ + prop3_cb_info.cmp_count++; + + return (HDmemcmp(value1, value2, size)); +} + +/**************************************************************** +** +** test_genprop_prop_cls_cb1(): Property close callback for test_genprop_list_callback +** +****************************************************************/ +static herr_t +test_genprop_prop_cls_cb1(const char *name, size_t size, void *value) +{ + /* Set the information from the close call */ + prop1_cb_info.cls_count++; + if (prop1_cb_info.cls_name == NULL) + prop1_cb_info.cls_name = HDstrdup(name); + if (prop1_cb_info.cls_value == NULL) + prop1_cb_info.cls_value = HDmalloc(size); + HDmemcpy(prop1_cb_info.cls_value, value, size); + + return (SUCCEED); +} + +/**************************************************************** +** +** test_genprop_prop_del_cb2(): Property delete callback for test_genprop_list_callback +** +****************************************************************/ +static herr_t +test_genprop_prop_del_cb2(hid_t plist_id, const char *name, size_t size, void *value) +{ + /* Set the information from the delete call */ + prop2_cb_info.del_count++; + prop2_cb_info.del_plist_id = plist_id; + prop2_cb_info.del_name = HDstrdup(name); + prop2_cb_info.del_value = HDmalloc(size); + HDmemcpy(prop2_cb_info.del_value, value, size); + + return (SUCCEED); +} + +/**************************************************************** +** +** test_genprop_list_callback(): Test basic generic property list code. +** Tests callbacks for properties in a generic property list. +** +****************************************************************/ +static void +test_genprop_list_callback(void) +{ + hid_t cid1; /* Generic Property class ID */ + hid_t lid1; /* Generic Property list ID */ + hid_t lid2; /* 2nd Generic Property list ID */ + size_t nprops; /* Number of properties in class */ + int prop1_value; /* Value for property #1 */ + int prop1_new_value = 20; /* Property #1 new value */ + float prop2_value; /* Value for property #2 */ + char prop3_value[10]; /* Property #3 value */ + char prop3_new_value[10] = "10 chairs"; /* Property #3 new value */ + double prop4_value; /* Property #4 value */ + struct { /* Struct for callbacks */ + int count; + hid_t id; + } cop_cb_struct; + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Basic Generic Property List Property Callback Functionality\n")); + + /* Create a new generic class, derived from the root of the class hierarchy */ + cid1 = H5Pcreate_class(H5P_ROOT, CLASS1_NAME, NULL, NULL, test_genprop_cls_cpy_cb2, &cop_cb_struct, NULL, + NULL); + CHECK_I(cid1, "H5Pcreate_class"); + + /* Insert first property into class (with callbacks) */ + ret = H5Pregister2(cid1, PROP1_NAME, PROP1_SIZE, PROP1_DEF_VALUE, test_genprop_prop_crt_cb1, + test_genprop_prop_set_cb1, test_genprop_prop_get_cb1, NULL, test_genprop_prop_cop_cb1, + test_genprop_prop_cmp_cb1, test_genprop_prop_cls_cb1); + CHECK_I(ret, "H5Pregister2"); + + /* Insert second property into class (with only delete callback) */ + ret = H5Pregister2(cid1, PROP2_NAME, PROP2_SIZE, PROP2_DEF_VALUE, NULL, NULL, NULL, + test_genprop_prop_del_cb2, NULL, NULL, NULL); + CHECK_I(ret, "H5Pregister2"); + + /* Insert third property into class (with only compare callback) */ + ret = H5Pregister2(cid1, PROP3_NAME, PROP3_SIZE, PROP3_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, + test_genprop_prop_cmp_cb3, NULL); + CHECK_I(ret, "H5Pregister2"); + + /* Insert fourth property into class (with no callbacks) */ + ret = + H5Pregister2(cid1, PROP4_NAME, PROP4_SIZE, PROP4_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pregister2"); + + /* Check the number of properties in class */ + ret = H5Pget_nprops(cid1, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 4, "H5Pget_nprops"); + + /* Initialize class callback structs */ + cop_cb_struct.count = 0; + cop_cb_struct.id = (-1); + + /* Initialize callback information for properties tracked */ + HDmemset(&prop1_cb_info, 0, sizeof(prop_cb_info)); + HDmemset(&prop2_cb_info, 0, sizeof(prop_cb_info)); + HDmemset(&prop3_cb_info, 0, sizeof(prop_cb_info)); + + /* Create a property list from the class */ + lid1 = H5Pcreate(cid1); + CHECK_I(lid1, "H5Pcreate"); + + /* The compare callback should not have been called once on property 1, as + * the property is always copied */ + VERIFY(prop1_cb_info.cmp_count, 0, "H5Pcreate"); + /* The compare callback should not have been called on property 3, as there + * is no create callback */ + VERIFY(prop3_cb_info.cmp_count, 0, "H5Pcreate"); + + /* Verify creation callback information for properties tracked */ + VERIFY(prop1_cb_info.crt_count, 1, "H5Pcreate"); + if (HDstrcmp(prop1_cb_info.crt_name, PROP1_NAME) != 0) + TestErrPrintf("Property #1 name doesn't match!, line=%d\n", __LINE__); + if (HDmemcmp(prop1_cb_info.crt_value, PROP1_DEF_VALUE, PROP1_SIZE) != 0) + TestErrPrintf("Property #1 value doesn't match!, line=%d\n", __LINE__); + + /* Check values of permanent properties (set with default values) */ + ret = H5Pget(lid1, PROP1_NAME, &prop1_value); + CHECK_I(ret, "H5Pget"); + VERIFY(prop1_value, *PROP1_DEF_VALUE, "H5Pget"); + /* The compare callback should not have been called */ + VERIFY(prop1_cb_info.cmp_count, 0, "H5Pget"); + ret = H5Pget(lid1, PROP2_NAME, &prop2_value); + CHECK_I(ret, "H5Pget"); + /* Verify the floating-poing value in this way to avoid compiler warning. */ + if (!H5_FLT_ABS_EQUAL(prop2_value, *PROP2_DEF_VALUE)) + HDprintf("*** UNEXPECTED VALUE from %s should be %f, but is %f at line %4d in %s\n", "H5Pget", + (double)*PROP2_DEF_VALUE, (double)prop2_value, (int)__LINE__, __FILE__); + + /* Check values of temporary properties (set with regular values) */ + ret = H5Pget(lid1, PROP3_NAME, &prop3_value); + CHECK_I(ret, "H5Pget"); + if (HDmemcmp(&prop3_value, PROP3_DEF_VALUE, PROP3_SIZE) != 0) + TestErrPrintf("Property #3 doesn't match!, line=%d\n", __LINE__); + /* The compare callback should not have been called, as there is no get + * callback for this property */ + VERIFY(prop3_cb_info.cmp_count, 0, "H5Pget"); + ret = H5Pget(lid1, PROP4_NAME, &prop4_value); + CHECK_I(ret, "H5Pget"); + /* Verify the floating-poing value in this way to avoid compiler warning. */ + if (!H5_DBL_ABS_EQUAL(prop4_value, *PROP4_DEF_VALUE)) + HDprintf("*** UNEXPECTED VALUE from %s should be %f, but is %f at line %4d in %s\n", "H5Pget", + *PROP4_DEF_VALUE, prop4_value, (int)__LINE__, __FILE__); + + /* Verify get callback information for properties tracked */ + VERIFY(prop1_cb_info.get_count, 1, "H5Pget"); + VERIFY(prop1_cb_info.get_plist_id, lid1, "H5Pget"); + if (HDstrcmp(prop1_cb_info.get_name, PROP1_NAME) != 0) + TestErrPrintf("Property #1 name doesn't match!, line=%d\n", __LINE__); + if (HDmemcmp(prop1_cb_info.get_value, PROP1_DEF_VALUE, PROP1_SIZE) != 0) + TestErrPrintf("Property #1 value doesn't match!, line=%d\n", __LINE__); + + /* Set value of property #1 to different value */ + ret = H5Pset(lid1, PROP1_NAME, &prop1_new_value); + CHECK_I(ret, "H5Pset"); + + /* Verify set callback information for properties tracked */ + VERIFY(prop1_cb_info.set_count, 1, "H5Pset"); + VERIFY(prop1_cb_info.set_plist_id, lid1, "H5Pset"); + if (HDstrcmp(prop1_cb_info.set_name, PROP1_NAME) != 0) + TestErrPrintf("Property #1 name doesn't match!, line=%d\n", __LINE__); + if (HDmemcmp(prop1_cb_info.set_value, &prop1_new_value, PROP1_SIZE) != 0) + TestErrPrintf("Property #1 value doesn't match!, line=%d\n", __LINE__); + + /* The compare callback should not have been called */ + VERIFY(prop1_cb_info.cmp_count, 0, "H5Pset"); + + /* Set value of property #3 to different value */ + ret = H5Pset(lid1, PROP3_NAME, prop3_new_value); + CHECK_I(ret, "H5Pset"); + + /* The compare callback should not have been called */ + VERIFY(prop3_cb_info.cmp_count, 0, "H5Pset"); + + /* Check new value of tracked properties */ + ret = H5Pget(lid1, PROP1_NAME, &prop1_value); + CHECK_I(ret, "H5Pget"); + VERIFY(prop1_value, prop1_new_value, "H5Pget"); + + /* Verify get callback information again for properties tracked */ + VERIFY(prop1_cb_info.get_count, 2, "H5Pget"); + VERIFY(prop1_cb_info.get_plist_id, lid1, "H5Pget"); + if (HDstrcmp(prop1_cb_info.get_name, PROP1_NAME) != 0) + TestErrPrintf("Property #1 name doesn't match!, line=%d\n", __LINE__); + if (HDmemcmp(prop1_cb_info.get_value, &prop1_new_value, PROP1_SIZE) != 0) + TestErrPrintf("Property #1 value doesn't match!, line=%d\n", __LINE__); + + /* Delete property #2 */ + ret = H5Premove(lid1, PROP2_NAME); + CHECK_I(ret, "H5Premove"); + + /* Verify delete callback information for properties tracked */ + VERIFY(prop2_cb_info.del_count, 1, "H5Premove"); + VERIFY(prop2_cb_info.del_plist_id, lid1, "H5Premove"); + if (HDstrcmp(prop2_cb_info.del_name, PROP2_NAME) != 0) + TestErrPrintf("Property #2 name doesn't match!, line=%d\n", __LINE__); + if (HDmemcmp(prop2_cb_info.del_value, PROP2_DEF_VALUE, PROP2_SIZE) != 0) + TestErrPrintf("Property #2 value doesn't match!, line=%d\n", __LINE__); + + /* Copy first list */ + lid2 = H5Pcopy(lid1); + CHECK_I(lid2, "H5Pcopy"); + + /* Verify copy callback information for properties tracked */ + VERIFY(prop1_cb_info.cop_count, 1, "H5Pcopy"); + if (HDstrcmp(prop1_cb_info.cop_name, PROP1_NAME) != 0) + TestErrPrintf("Property #1 name doesn't match!, line=%d\n", __LINE__); + if (HDmemcmp(prop1_cb_info.cop_value, &prop1_new_value, PROP1_SIZE) != 0) + TestErrPrintf("Property #1 value doesn't match!, line=%d\n", __LINE__); + + /* Verify that the class creation callback occurred */ + VERIFY(cop_cb_struct.count, 1, "H5Pcopy"); + VERIFY(cop_cb_struct.id, lid2, "H5Pcopy"); + + /* Compare the two lists */ + ret = H5Pequal(lid1, lid2); + VERIFY(ret, 1, "H5Pequal"); + + /* Verify compare callback information for properties tracked */ + VERIFY(prop1_cb_info.cmp_count, 1, "H5Pequal"); + VERIFY(prop3_cb_info.cmp_count, 1, "H5Pequal"); + + /* Close first list */ + ret = H5Pclose(lid1); + CHECK_I(ret, "H5Pclose"); + + /* Verify close callback information for properties tracked */ + VERIFY(prop1_cb_info.cls_count, 1, "H5Pclose"); + if (HDstrcmp(prop1_cb_info.cls_name, PROP1_NAME) != 0) + TestErrPrintf("Property #1 name doesn't match!, line=%d\n", __LINE__); + if (HDmemcmp(prop1_cb_info.cls_value, &prop1_new_value, PROP1_SIZE) != 0) + TestErrPrintf("Property #1 value doesn't match!, line=%d\n", __LINE__); + + /* Close second list */ + ret = H5Pclose(lid2); + CHECK_I(ret, "H5Pclose"); + + /* Verify close callback information for properties tracked */ + VERIFY(prop1_cb_info.cls_count, 2, "H5Pclose"); + + /* Free memory allocated for tracking properties */ + HDfree(prop1_cb_info.crt_name); + HDfree(prop1_cb_info.crt_value); + HDfree(prop1_cb_info.get_name); + HDfree(prop1_cb_info.get_value); + HDfree(prop1_cb_info.set_name); + HDfree(prop1_cb_info.set_value); + HDfree(prop1_cb_info.cop_name); + HDfree(prop1_cb_info.cop_value); + HDfree(prop1_cb_info.cls_name); + HDfree(prop1_cb_info.cls_value); + HDfree(prop2_cb_info.del_name); + HDfree(prop2_cb_info.del_value); + + /* Close class */ + ret = H5Pclose_class(cid1); + CHECK_I(ret, "H5Pclose_class"); +} /* end test_genprop_list_callback() */ + +/**************************************************************** +** +** test_genprop_list_addprop(): Test adding properties to a +** standard HDF5 property list and verify that the library +** ignores the extra properties. +** +****************************************************************/ +static void +test_genprop_list_addprop(void) +{ + hid_t fid; /* File ID */ + hid_t did; /* Dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t pid; /* Property List ID */ + int prop1_value; /* Value for property #1 */ + herr_t ret; /* Generic return value */ + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create scalar dataspace for dataset */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create a dataset creation property list */ + pid = H5Pcreate(H5P_DATASET_CREATE); + CHECK(pid, FAIL, "H5Pcreate"); + + /* Insert temporary property into class (with no callbacks) */ + ret = H5Pinsert2(pid, PROP1_NAME, PROP1_SIZE, PROP1_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pinsert2"); + + /* Check existence of added property */ + ret = H5Pexist(pid, PROP1_NAME); + VERIFY(ret, 1, "H5Pexist"); + + /* Check values of property (set with default value) */ + ret = H5Pget(pid, PROP1_NAME, &prop1_value); + CHECK_I(ret, "H5Pget"); + VERIFY(prop1_value, *PROP1_DEF_VALUE, "H5Pget"); + + /* Create a dataset */ + did = H5Dcreate2(fid, "Dataset1", H5T_NATIVE_INT, sid, H5P_DEFAULT, pid, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); + + /* Check existence of added property (after using property list) */ + ret = H5Pexist(pid, PROP1_NAME); + VERIFY(ret, 1, "H5Pexist"); + + /* Check values of property (set with default value) (after using property list) */ + ret = H5Pget(pid, PROP1_NAME, &prop1_value); + CHECK_I(ret, "H5Pget"); + VERIFY(prop1_value, *PROP1_DEF_VALUE, "H5Pget"); + + /* Close property list */ + ret = H5Pclose(pid); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + +} /* end test_genprop_list_addprop() */ + +/**************************************************************** +** +** test_genprop_class_addprop(): Test adding properties to a +** standard HDF5 property class and verify that the library +** ignores the extra properties and continues to recognize the +** derived class as a valid version of the derived-from class. +** +****************************************************************/ +static void +test_genprop_class_addprop(void) +{ + hid_t fid; /* File ID */ + hid_t did; /* Dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t cid; /* Property Class ID */ + hid_t pid; /* Property List ID */ + int prop1_value; /* Value for property #1 */ + herr_t ret; /* Generic return value */ + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create scalar dataspace for dataset */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create a new class, derived from the dataset creation property list class */ + cid = H5Pcreate_class(H5P_DATASET_CREATE, CLASS1_NAME, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(cid, "H5Pcreate_class"); +#if 0 + /* Check existence of an original property */ + ret = H5Pexist(cid, H5O_CRT_PIPELINE_NAME); + VERIFY(ret, 1, "H5Pexist"); +#endif + /* Insert first property into class (with no callbacks) */ + ret = + H5Pregister2(cid, PROP1_NAME, PROP1_SIZE, PROP1_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pregister2"); +#if 0 + /* Check existence of an original property */ + ret = H5Pexist(cid, H5O_CRT_PIPELINE_NAME); + VERIFY(ret, 1, "H5Pexist"); +#endif + /* Check existence of added property */ + ret = H5Pexist(cid, PROP1_NAME); + VERIFY(ret, 1, "H5Pexist"); + + /* Create a derived dataset creation property list */ + pid = H5Pcreate(cid); + CHECK(pid, FAIL, "H5Pcreate"); +#if 0 + /* Check existence of an original property */ + ret = H5Pexist(pid, H5O_CRT_PIPELINE_NAME); + VERIFY(ret, 1, "H5Pexist"); +#endif + /* Check existence of added property */ + ret = H5Pexist(pid, PROP1_NAME); + VERIFY(ret, 1, "H5Pexist"); + + /* Check values of property (set with default value) */ + ret = H5Pget(pid, PROP1_NAME, &prop1_value); + CHECK_I(ret, "H5Pget"); + VERIFY(prop1_value, *PROP1_DEF_VALUE, "H5Pget"); + + /* Insert second property into class (with no callbacks) */ + ret = + H5Pregister2(cid, PROP2_NAME, PROP2_SIZE, PROP2_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pregister2"); +#if 0 + /* Check existence of an original property (in class) */ + ret = H5Pexist(cid, H5O_CRT_PIPELINE_NAME); + VERIFY(ret, 1, "H5Pexist"); +#endif + /* Check existence of first added property (in class) */ + ret = H5Pexist(cid, PROP1_NAME); + VERIFY(ret, 1, "H5Pexist"); + + /* Check existence of second added property (in class) */ + ret = H5Pexist(cid, PROP2_NAME); + VERIFY(ret, 1, "H5Pexist"); +#if 0 + /* Check existence of an original property (in property list) */ + ret = H5Pexist(pid, H5O_CRT_PIPELINE_NAME); + VERIFY(ret, 1, "H5Pexist"); +#endif + /* Check existence of first added property (in property list) */ + ret = H5Pexist(pid, PROP1_NAME); + VERIFY(ret, 1, "H5Pexist"); + + /* Check existence of second added property (in property list) (should not exist) */ + ret = H5Pexist(pid, PROP2_NAME); + VERIFY(ret, 0, "H5Pexist"); + + /* Create a dataset */ + did = H5Dcreate2(fid, "Dataset1", H5T_NATIVE_INT, sid, H5P_DEFAULT, pid, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); + + /* Check existence of added property (after using property list) */ + ret = H5Pexist(pid, PROP1_NAME); + VERIFY(ret, 1, "H5Pexist"); + + /* Check values of property (set with default value) (after using property list) */ + ret = H5Pget(pid, PROP1_NAME, &prop1_value); + CHECK_I(ret, "H5Pget"); + VERIFY(prop1_value, *PROP1_DEF_VALUE, "H5Pget"); + + /* Close property class */ + ret = H5Pclose_class(cid); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close property list */ + ret = H5Pclose(pid); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + +} /* end test_genprop_class_addprop() */ + +/**************************************************************** +** +** test_genprop_list_add_remove_prop(): Test adding then removing the +** same properties to a standard HDF5 property list. This is testing +** also for a memory leak that could be caused by not freeing the +** removed property resources from the property list. +** +****************************************************************/ +static void +test_genprop_list_add_remove_prop(void) +{ + hid_t pid; /* Property List ID */ + herr_t ret; /* Generic return value */ + + /* Create a dataset creation property list */ + pid = H5Pcreate(H5P_DATASET_CREATE); + CHECK(pid, FAIL, "H5Pcreate"); + + /* Insert temporary property into class (with no callbacks) */ + ret = H5Pinsert2(pid, PROP1_NAME, PROP1_SIZE, PROP1_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pinsert2"); + + /* Delete added property */ + ret = H5Premove(pid, PROP1_NAME); + CHECK_I(ret, "H5Premove"); + + /* Insert temporary property into class (with no callbacks) */ + ret = H5Pinsert2(pid, PROP1_NAME, PROP1_SIZE, PROP1_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pinsert2"); + + /* Delete added property */ + ret = H5Premove(pid, PROP1_NAME); + CHECK_I(ret, "H5Premove"); + + /* Close property list */ + ret = H5Pclose(pid); + CHECK(ret, FAIL, "H5Pclose"); + +} /* end test_genprop_list_add_remove_prop() */ + +/**************************************************************** +** +** test_genprop_equal(): Test basic generic property list code. +** More tests for H5Pequal() +** +****************************************************************/ +static void +test_genprop_equal(void) +{ + hid_t cid1; /* Generic Property class ID */ + hid_t lid1; /* Generic Property list ID */ + hid_t lid2; /* Generic Property list ID */ + int prop1_new_value = 20; /* Property #1 new value */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Basic Generic Property List Equal Functionality\n")); + + /* Create a new generic class, derived from the root of the class hierarchy */ + cid1 = H5Pcreate_class(H5P_ROOT, CLASS1_NAME, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(cid1, "H5Pcreate_class"); + + /* Insert first property into class (with no callbacks) */ + ret = + H5Pregister2(cid1, PROP1_NAME, PROP1_SIZE, PROP1_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pregister2"); + + /* Insert second property into class (with no callbacks) */ + ret = + H5Pregister2(cid1, PROP2_NAME, PROP2_SIZE, PROP2_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pregister2"); + + /* Create a property list from the class */ + lid1 = H5Pcreate(cid1); + CHECK_I(lid1, "H5Pcreate"); + + /* Copy the property list */ + lid2 = H5Pcopy(lid1); + CHECK_I(lid2, "H5Pcopy"); + + /* Check that the lists are equal */ + ret = H5Pequal(lid1, lid2); + VERIFY(ret, 1, "H5Pequal"); + + /* Set property in first list to another value */ + ret = H5Pset(lid1, PROP1_NAME, &prop1_new_value); + CHECK_I(ret, "H5Pset"); + + /* Check that the lists are not equal */ + ret = H5Pequal(lid1, lid2); + VERIFY(ret, 0, "H5Pequal"); + + /* Set property in first list back to default */ + ret = H5Pset(lid1, PROP1_NAME, PROP1_DEF_VALUE); + CHECK_I(ret, "H5Pset"); + + /* Check that the lists are still equal */ + ret = H5Pequal(lid1, lid2); + VERIFY(ret, 1, "H5Pequal"); + + /* Insert first temporary property into first list (with no callbacks) */ + ret = H5Pinsert2(lid1, PROP3_NAME, PROP3_SIZE, PROP3_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pinsert2"); + + /* Check that the lists are not equal */ + ret = H5Pequal(lid1, lid2); + VERIFY(ret, 0, "H5Pequal"); + + /* Insert first temporary property into second list (with no callbacks) */ + ret = H5Pinsert2(lid2, PROP3_NAME, PROP3_SIZE, PROP3_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pinsert2"); + + /* Check that the lists are equal */ + ret = H5Pequal(lid1, lid2); + VERIFY(ret, 1, "H5Pequal"); + + /* Insert second temporary property into second list (with no callbacks) */ + ret = H5Pinsert2(lid2, PROP4_NAME, PROP4_SIZE, PROP4_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pinsert2"); + + /* Check that the lists are not equal */ + ret = H5Pequal(lid1, lid2); + VERIFY(ret, 0, "H5Pequal"); + + /* Insert second temporary property into first list (with no callbacks) */ + ret = H5Pinsert2(lid1, PROP4_NAME, PROP4_SIZE, PROP4_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pinsert2"); + + /* Check that the lists are equal */ + ret = H5Pequal(lid1, lid2); + VERIFY(ret, 1, "H5Pequal"); + + /* Remove first temporary property from first list */ + ret = H5Premove(lid1, PROP3_NAME); + CHECK_I(ret, "H5Premove"); + + /* Check that the lists are not equal */ + ret = H5Pequal(lid1, lid2); + VERIFY(ret, 0, "H5Pequal"); + + /* Remove second temporary property from second list */ + ret = H5Premove(lid2, PROP4_NAME); + CHECK_I(ret, "H5Premove"); + + /* Check that the lists are not equal */ + ret = H5Pequal(lid1, lid2); + VERIFY(ret, 0, "H5Pequal"); + + /* Remove first temporary property from second list */ + ret = H5Premove(lid2, PROP3_NAME); + CHECK_I(ret, "H5Premove"); + + /* Check that the lists are not equal */ + ret = H5Pequal(lid1, lid2); + VERIFY(ret, 0, "H5Pequal"); + + /* Remove first permanent property from first list */ + ret = H5Premove(lid1, PROP1_NAME); + CHECK_I(ret, "H5Premove"); + + /* Check that the lists are not equal */ + ret = H5Pequal(lid1, lid2); + VERIFY(ret, 0, "H5Pequal"); + + /* Remove second temporary property from first list */ + ret = H5Premove(lid1, PROP4_NAME); + CHECK_I(ret, "H5Premove"); + + /* Check that the lists are not equal */ + ret = H5Pequal(lid1, lid2); + VERIFY(ret, 0, "H5Pequal"); + + /* Remove first permanent property from second list */ + ret = H5Premove(lid2, PROP1_NAME); + CHECK_I(ret, "H5Premove"); + + /* Check that the lists are equal */ + ret = H5Pequal(lid1, lid2); + VERIFY(ret, 1, "H5Pequal"); + + /* Close property lists */ + ret = H5Pclose(lid1); + CHECK_I(ret, "H5Pclose"); + ret = H5Pclose(lid2); + CHECK_I(ret, "H5Pclose"); + + /* Close class */ + ret = H5Pclose_class(cid1); + CHECK_I(ret, "H5Pclose_class"); +} /* ent test_genprop_equal() */ + +/**************************************************************** +** +** test_genprop_path(): Test basic generic property list code. +** Tests for class paths +** +****************************************************************/ +static void +test_genprop_path(void) +{ + hid_t cid1; /* Generic Property class ID */ + hid_t cid2; /* Generic Property class ID */ +#if 0 + hid_t cid3; /* Generic Property class ID */ + char *path; /* Class path */ +#endif + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Generic Property List Class Path Functionality\n")); + + /* Create a new generic class, derived from the root of the class hierarchy */ + cid1 = H5Pcreate_class(H5P_ROOT, CLASS1_NAME, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(cid1, "H5Pcreate_class"); + + /* Insert first property into class (with no callbacks) */ + ret = + H5Pregister2(cid1, PROP1_NAME, PROP1_SIZE, PROP1_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pregister2"); +#if 0 + /* Get full path for first class */ + path = H5P__get_class_path_test(cid1); + CHECK_PTR(path, "H5P__get_class_path_test"); + if (HDstrcmp(path, CLASS1_PATH) != 0) + TestErrPrintf("Class names don't match!, path=%s, CLASS1_PATH=%s\n", path, CLASS1_PATH); + H5free_memory(path); +#endif + /* Create another new generic class, derived from first class */ + cid2 = H5Pcreate_class(cid1, CLASS2_NAME, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(cid2, "H5Pcreate_class"); + + /* Insert second property into class (with no callbacks) */ + ret = + H5Pregister2(cid2, PROP2_NAME, PROP2_SIZE, PROP2_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pregister2"); +#if 0 + /* Get full path for second class */ + path = H5P__get_class_path_test(cid2); + CHECK_PTR(path, "H5P__get_class_path_test"); + if (HDstrcmp(path, CLASS2_PATH) != 0) + TestErrPrintf("Class names don't match!, path=%s, CLASS2_PATH=%s\n", path, CLASS2_PATH); + + /* Open a copy of the class with the path name */ + cid3 = H5P__open_class_path_test(path); + CHECK_I(cid3, "H5P__open_class_path_test"); + + /* Check that the classes are equal */ + ret = H5Pequal(cid2, cid3); + VERIFY(ret, 1, "H5Pequal"); + + /* Release the path string */ + H5free_memory(path); + + /* Close class */ + ret = H5Pclose_class(cid3); + CHECK_I(ret, "H5Pclose_class"); +#endif + /* Close class */ + ret = H5Pclose_class(cid1); + CHECK_I(ret, "H5Pclose_class"); + + /* Close class */ + ret = H5Pclose_class(cid2); + CHECK_I(ret, "H5Pclose_class"); + +} /* ent test_genprop_path() */ + +/**************************************************************** +** +** test_genprop_refcount(): Test basic generic property list code. +** Tests for correct reference counting +** +****************************************************************/ +static void +test_genprop_refcount(void) +{ + hid_t cid1; /* Generic Property class ID */ + hid_t lid1; /* Generic Property class ID */ + char *name; /* Name of class */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Generic Property List Reference Count Functionality\n")); + + /* Create a new generic class, derived from the root of the class hierarchy */ + cid1 = H5Pcreate_class(H5P_ROOT, CLASS1_NAME, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(cid1, "H5Pcreate_class"); + + /* Insert first property into class (with no callbacks) */ + ret = + H5Pregister2(cid1, PROP1_NAME, PROP1_SIZE, PROP1_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pregister2"); + + /* Create a new generic list, derived from the root of the class hierarchy */ + lid1 = H5Pcreate(cid1); + CHECK_I(lid1, "H5Pcreate"); + + /* Check class name */ + name = H5Pget_class_name(cid1); + CHECK_PTR(name, "H5Pget_class_name"); + if (HDstrcmp(name, CLASS1_NAME) != 0) + TestErrPrintf("Class names don't match!, name=%s, CLASS1_NAME=%s\n", name, CLASS1_NAME); + H5free_memory(name); + + /* Close class */ + ret = H5Pclose_class(cid1); + CHECK_I(ret, "H5Pclose_class"); + + /* Get the list's class */ + cid1 = H5Pget_class(lid1); + CHECK_I(cid1, "H5Pget_class"); + + /* Check correct "is a" class/list relationship */ + ret = H5Pisa_class(lid1, cid1); + VERIFY(ret, 1, "H5Pisa_class"); + + /* Check class name */ + name = H5Pget_class_name(cid1); + CHECK_PTR(name, "H5Pget_class_name"); + if (HDstrcmp(name, CLASS1_NAME) != 0) + TestErrPrintf("Class names don't match!, name=%s, CLASS1_NAME=%s\n", name, CLASS1_NAME); + H5free_memory(name); + + /* Close list */ + ret = H5Pclose(lid1); + CHECK_I(ret, "H5Pclose"); + + /* Check class name */ + name = H5Pget_class_name(cid1); + CHECK_PTR(name, "H5Pget_class_name"); + if (HDstrcmp(name, CLASS1_NAME) != 0) + TestErrPrintf("Class names don't match!, name=%s, CLASS1_NAME=%s\n", name, CLASS1_NAME); + H5free_memory(name); + + /* Close class */ + ret = H5Pclose_class(cid1); + CHECK_I(ret, "H5Pclose_class"); + +} /* ent test_genprop_refcount() */ + +#ifndef H5_NO_DEPRECATED_SYMBOLS +/**************************************************************** +** +** test_genprop_deprec_class(): Test basic generic property list code. +** Tests deprecated property class API routines. +** +****************************************************************/ +static void +test_genprop_deprec_class(void) +{ + hid_t cid1; /* Generic Property class ID */ + size_t size; /* Size of property */ + size_t nprops; /* Number of properties in class */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Deprecated Generic Property List Functions\n")); + + /* Create a new generic class, derived from the root of the class hierarchy */ + cid1 = H5Pcreate_class(H5P_ROOT, CLASS1_NAME, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(cid1, "H5Pcreate_class"); + + /* Check the number of properties in class */ + ret = H5Pget_nprops(cid1, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 0, "H5Pget_nprops"); + + /* Check the existence of the first property (should fail) */ + ret = H5Pexist(cid1, PROP1_NAME); + VERIFY(ret, 0, "H5Pexist"); + + /* Insert first property into class (with no callbacks) */ + ret = H5Pregister1(cid1, PROP1_NAME, PROP1_SIZE, PROP1_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pregister1"); + + /* Try to insert the first property again (should fail) */ + H5E_BEGIN_TRY + { + ret = H5Pregister1(cid1, PROP1_NAME, PROP1_SIZE, PROP1_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Pregister1"); + + /* Check the existence of the first property */ + ret = H5Pexist(cid1, PROP1_NAME); + VERIFY(ret, 1, "H5Pexist"); + + /* Check the size of the first property */ + ret = H5Pget_size(cid1, PROP1_NAME, &size); + CHECK_I(ret, "H5Pget_size"); + VERIFY(size, PROP1_SIZE, "H5Pget_size"); + + /* Check the number of properties in class */ + ret = H5Pget_nprops(cid1, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 1, "H5Pget_nprops"); + + /* Insert second property into class (with no callbacks) */ + ret = H5Pregister1(cid1, PROP2_NAME, PROP2_SIZE, PROP2_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pregister1"); + + /* Try to insert the second property again (should fail) */ + H5E_BEGIN_TRY + { + ret = H5Pregister1(cid1, PROP2_NAME, PROP2_SIZE, PROP2_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Pregister1"); + + /* Check the existence of the second property */ + ret = H5Pexist(cid1, PROP2_NAME); + VERIFY(ret, 1, "H5Pexist"); + + /* Check the size of the second property */ + ret = H5Pget_size(cid1, PROP2_NAME, &size); + CHECK_I(ret, "H5Pget_size"); + VERIFY(size, PROP2_SIZE, "H5Pget_size"); + + /* Check the number of properties in class */ + ret = H5Pget_nprops(cid1, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 2, "H5Pget_nprops"); + + /* Insert third property into class (with no callbacks) */ + ret = H5Pregister1(cid1, PROP3_NAME, PROP3_SIZE, PROP3_DEF_VALUE, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pregister1"); + + /* Check the existence of the third property */ + ret = H5Pexist(cid1, PROP3_NAME); + VERIFY(ret, 1, "H5Pexist"); + + /* Check the size of the third property */ + ret = H5Pget_size(cid1, PROP3_NAME, &size); + CHECK_I(ret, "H5Pget_size"); + VERIFY(size, PROP3_SIZE, "H5Pget_size"); + + /* Check the number of properties in class */ + ret = H5Pget_nprops(cid1, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 3, "H5Pget_nprops"); + + /* Unregister first property */ + ret = H5Punregister(cid1, PROP1_NAME); + CHECK_I(ret, "H5Punregister"); + + /* Try to check the size of the first property (should fail) */ + H5E_BEGIN_TRY + { + ret = H5Pget_size(cid1, PROP1_NAME, &size); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Pget_size"); + + /* Check the number of properties in class */ + ret = H5Pget_nprops(cid1, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 2, "H5Pget_nprops"); + + /* Unregister second property */ + ret = H5Punregister(cid1, PROP2_NAME); + CHECK_I(ret, "H5Punregister"); + + /* Check the number of properties in class */ + ret = H5Pget_nprops(cid1, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 1, "H5Pget_nprops"); + + /* Unregister third property */ + ret = H5Punregister(cid1, PROP3_NAME); + CHECK_I(ret, "H5Punregister"); + + /* Check the number of properties in class */ + ret = H5Pget_nprops(cid1, &nprops); + CHECK_I(ret, "H5Pget_nprops"); + VERIFY(nprops, 0, "H5Pget_nprops"); + + /* Close class */ + ret = H5Pclose_class(cid1); + CHECK_I(ret, "H5Pclose_class"); +} /* end test_genprop_deprec_class() */ + +/**************************************************************** +** +** test_genprop_deprec2(): Test basic generic property list code. +** Tests deprecated property list API routines. +** +****************************************************************/ +static void +test_genprop_deprec_list(void) +{ + hid_t fid; /* File ID */ + hid_t did; /* Dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t pid; /* Property List ID */ + int prop1_value; /* Value for property #1 */ + herr_t ret; /* Generic return value */ + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create scalar dataspace for dataset */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create a dataset creation property list */ + pid = H5Pcreate(H5P_DATASET_CREATE); + CHECK(pid, FAIL, "H5Pcreate"); + + /* Insert temporary property into class (with no callbacks) */ + ret = H5Pinsert1(pid, PROP1_NAME, PROP1_SIZE, PROP1_DEF_VALUE, NULL, NULL, NULL, NULL, NULL); + CHECK_I(ret, "H5Pinsert1"); + + /* Check existence of added property */ + ret = H5Pexist(pid, PROP1_NAME); + VERIFY(ret, 1, "H5Pexist"); + + /* Check values of property (set with default value) */ + ret = H5Pget(pid, PROP1_NAME, &prop1_value); + CHECK_I(ret, "H5Pget"); + VERIFY(prop1_value, *PROP1_DEF_VALUE, "H5Pget"); + + /* Create a dataset */ + did = H5Dcreate2(fid, "Dataset1", H5T_NATIVE_INT, sid, H5P_DEFAULT, pid, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); + + /* Check existence of added property (after using property list) */ + ret = H5Pexist(pid, PROP1_NAME); + VERIFY(ret, 1, "H5Pexist"); + + /* Check values of property (set with default value) (after using property list) */ + ret = H5Pget(pid, PROP1_NAME, &prop1_value); + CHECK_I(ret, "H5Pget"); + VERIFY(prop1_value, *PROP1_DEF_VALUE, "H5Pget"); + + /* Close property list */ + ret = H5Pclose(pid); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_genprop_deprec_list() */ +#endif /* H5_NO_DEPRECATED_SYMBOLS */ + +/**************************************************************** +** +** test_genprop(): Main generic property testing routine. +** +****************************************************************/ +void +test_genprop(void) +{ + /* Output message about test being performed */ + MESSAGE(5, ("Testing Generic Properties\n")); + + /* These tests use the same file... */ + test_genprop_basic_class(); /* Test basic code for creating a generic class */ + test_genprop_basic_class_prop(); /* Test basic code for adding properties to a generic class */ + test_genprop_class_iter(); /* Test code for iterating over properties in a generic class */ + test_genprop_class_callback(); /* Test code for property class callbacks */ + + test_genprop_basic_list(); /* Test basic code for creating a generic property list */ + test_genprop_basic_list_prop(); /* Test basic code for adding properties to a generic property list */ + test_genprop_list_iter(); /* Test basic code for iterating over properties in a generic property list */ + test_genprop_list_callback(); /* Test code for property list callbacks */ + + test_genprop_list_addprop(); /* Test adding properties to HDF5 property list */ + test_genprop_class_addprop(); /* Test adding properties to HDF5 property class */ + + test_genprop_list_add_remove_prop(); /* Test adding and removing the same property several times to HDF5 + property list */ + + test_genprop_equal(); /* Tests for more H5Pequal verification */ + test_genprop_path(); /* Tests for class path verification */ + test_genprop_refcount(); /* Tests for class reference counting */ + +#ifndef H5_NO_DEPRECATED_SYMBOLS + test_genprop_deprec_class(); /* Tests for deprecated routines */ + test_genprop_deprec_list(); /* Tests for deprecated routines */ +#endif /* H5_NO_DEPRECATED_SYMBOLS */ + +} /* test_genprop() */ + +/*------------------------------------------------------------------------- + * Function: cleanup_genprop + * + * Purpose: Cleanup temporary test files + * + * Return: none + * + * Programmer: Quincey Koziol + * June 8, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +void +cleanup_genprop(void) +{ + H5Fdelete(FILENAME, H5P_DEFAULT); +} diff --git a/test/API/th5o.c b/test/API/th5o.c new file mode 100644 index 0000000..916f005 --- /dev/null +++ b/test/API/th5o.c @@ -0,0 +1,1889 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*********************************************************** + * + * Test program: th5o + * + * Test public H5O functions for accessing + * + *************************************************************/ + +#include "testhdf5.h" + +#if 0 +#include "H5Fprivate.h" +#include "H5VLprivate.h" +#include "H5VLnative_private.h" +#endif + +#define TEST_FILENAME "th5o_file.h5" + +#define RANK 2 +#define DIM0 5 +#define DIM1 10 + +#define TEST6_DIM1 100 +#define TEST6_DIM2 100 + +/**************************************************************** +** +** test_h5o_open(): Test H5Oopen function. +** +****************************************************************/ +static void +test_h5o_open(void) +{ + hid_t fid; /* HDF5 File ID */ + hid_t grp, dset, dtype, dspace; /* Object identifiers */ + char filename[1024]; + hsize_t dims[RANK]; + H5I_type_t id_type; /* Type of IDs returned from H5Oopen */ + H5G_info_t ginfo; /* Group info struct */ + H5T_class_t type_class; /* Class of the datatype */ + herr_t ret; /* Value returned from API calls */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing H5Oopen\n")); + + h5_fixname(TEST_FILENAME, H5P_DEFAULT, filename, sizeof filename); + + /* Create a new HDF5 file */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create a group, dataset, and committed datatype within the file */ + /* Create the group */ + grp = H5Gcreate2(fid, "group", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(grp, FAIL, "H5Gcreate2"); + ret = H5Gclose(grp); + CHECK(ret, FAIL, "H5Gclose"); + + /* Commit the type inside the group */ + dtype = H5Tcopy(H5T_NATIVE_INT); + CHECK(dtype, FAIL, "H5Tcopy"); + ret = H5Tcommit2(fid, "group/datatype", dtype, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + ret = H5Tclose(dtype); + CHECK(ret, FAIL, "H5Tclose"); + + /* Create the data space for the dataset. */ + dims[0] = DIM0; + dims[1] = DIM1; + dspace = H5Screate_simple(RANK, dims, NULL); + CHECK(dspace, FAIL, "H5Screate_simple"); + + /* Create the dataset. */ + dset = H5Dcreate2(fid, "dataset", H5T_NATIVE_INT, dspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dset, FAIL, "H5Dcreate2"); + ret = H5Dclose(dset); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Sclose(dspace); + CHECK(ret, FAIL, "H5Sclose"); + + /* Now make sure that H5Oopen can open all three types of objects */ + grp = H5Oopen(fid, "group", H5P_DEFAULT); + CHECK(grp, FAIL, "H5Oopen"); + dtype = H5Oopen(fid, "group/datatype", H5P_DEFAULT); + CHECK(dtype, FAIL, "H5Oopen"); + /* Check that we can use the group as a valid location */ + dset = H5Oopen(grp, "/dataset", H5P_DEFAULT); + CHECK(dset, FAIL, "H5Oopen"); + + /* Make sure that each is the right kind of ID */ + id_type = H5Iget_type(grp); + VERIFY(id_type, H5I_GROUP, "H5Iget_type for group ID"); + id_type = H5Iget_type(dtype); + VERIFY(id_type, H5I_DATATYPE, "H5Iget_type for datatype ID"); + id_type = H5Iget_type(dset); + VERIFY(id_type, H5I_DATASET, "H5Iget_type for dataset ID"); + + /* Do something more complex with each of the IDs to make sure they "work" */ + ret = H5Gget_info(grp, &ginfo); + CHECK(ret, FAIL, "H5Gget_info"); + VERIFY(ginfo.nlinks, 1, "H5Gget_info"); /* There should be one object, the datatype */ + + type_class = H5Tget_class(dtype); + VERIFY(type_class, H5T_INTEGER, "H5Tget_class"); + + dspace = H5Dget_space(dset); + CHECK(dspace, FAIL, "H5Dget_space"); + + /* Close the IDs */ + ret = H5Sclose(dspace); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Gclose(grp); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Tclose(dtype); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Dclose(dset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Trying to open objects with bogus names should fail gracefully */ + H5E_BEGIN_TRY + { + grp = H5Oopen(fid, "bogus_group", H5P_DEFAULT); + VERIFY(grp, FAIL, "H5Oopen"); + dtype = H5Oopen(fid, "group/bogus_datatype", H5P_DEFAULT); + VERIFY(dtype, FAIL, "H5Oopen"); + dset = H5Oopen(fid, "/bogus_dataset", H5P_DEFAULT); + VERIFY(dset, FAIL, "H5Oopen"); + } + H5E_END_TRY + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Trying to open an object with a bogus file ID should fail */ + H5E_BEGIN_TRY + { + dset = H5Oopen(fid, "dataset", H5P_DEFAULT); + VERIFY(dset, FAIL, "H5Oopen"); + } + H5E_END_TRY +} /* test_h5o_open() */ + +/**************************************************************** +** +** test_h5o_close(): Test H5Oclose function. +** +****************************************************************/ +static void +test_h5o_close(void) +{ + hid_t fid; /* HDF5 File ID */ + hid_t grp, dset, dtype, dspace; /* Object identifiers */ + char filename[1024]; + hsize_t dims[RANK]; + herr_t ret; /* Value returned from API calls */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing H5Oclose\n")); + + h5_fixname(TEST_FILENAME, H5P_DEFAULT, filename, sizeof filename); + + /* Create a new HDF5 file */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create a group, dataset, and committed datatype within the file */ + /* Create the group and close it with H5Oclose */ + grp = H5Gcreate2(fid, "group", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(grp, FAIL, "H5Gcreate2"); + VERIFY_TYPE(H5Iget_type(grp), H5I_GROUP, H5I_type_t, "%d", "H5Iget_type"); + ret = H5Oclose(grp); + CHECK(ret, FAIL, "H5Oclose"); + + /* Commit the type inside the group */ + dtype = H5Tcopy(H5T_NATIVE_INT); + CHECK(dtype, FAIL, "H5Tcopy"); + ret = H5Tcommit2(fid, "group/datatype", dtype, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + ret = H5Oclose(dtype); + CHECK(ret, FAIL, "H5Oclose"); + + /* Create the data space for the dataset. */ + dims[0] = DIM0; + dims[1] = DIM1; + dspace = H5Screate_simple(RANK, dims, NULL); + CHECK(dspace, FAIL, "H5Screate_simple"); + + /* Create the dataset. */ + dset = H5Dcreate2(fid, "dataset", H5T_NATIVE_INT, dspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dset, FAIL, "H5Dcreate2"); + ret = H5Oclose(dset); + CHECK(ret, FAIL, "H5Oclose"); + + /* Attempting to close the data space with H5Oclose should fail */ + H5E_BEGIN_TRY + { + ret = H5Oclose(dspace); + VERIFY(ret, FAIL, "H5Oclose"); + } + H5E_END_TRY + /* Close the dataspace for real */ + ret = H5Sclose(dspace); + CHECK(ret, FAIL, "H5Sclose"); + + /* Make sure that H5Oclose can close objects opened with H5Oopen */ + grp = H5Oopen(fid, "group", H5P_DEFAULT); + CHECK(grp, FAIL, "H5Oopen"); + dtype = H5Oopen(fid, "group/datatype", H5P_DEFAULT); + CHECK(dtype, FAIL, "H5Oopen"); + dset = H5Oopen(fid, "dataset", H5P_DEFAULT); + CHECK(dset, FAIL, "H5Oopen"); + + ret = H5Oclose(grp); + CHECK(ret, FAIL, "H5Oclose"); + ret = H5Oclose(dtype); + CHECK(ret, FAIL, "H5Oclose"); + ret = H5Oclose(dset); + CHECK(ret, FAIL, "H5Oclose"); + + /* Make sure H5Oclose can close objects opened with H5*open */ + grp = H5Gopen2(fid, "group", H5P_DEFAULT); + CHECK(grp, FAIL, "H5Gopen2"); + dtype = H5Topen2(fid, "group/datatype", H5P_DEFAULT); + CHECK(dtype, FAIL, "H5Topen2"); + dset = H5Dopen2(fid, "dataset", H5P_DEFAULT); + CHECK(dset, FAIL, "H5Dopen2"); + + ret = H5Oclose(grp); + CHECK(ret, FAIL, "H5Oclose"); + ret = H5Oclose(dtype); + CHECK(ret, FAIL, "H5Oclose"); + ret = H5Oclose(dset); + CHECK(ret, FAIL, "H5Oclose"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +} + +#if 0 +#ifndef H5_NO_DEPRECATED_SYMBOLS +/**************************************************************** +** +** test_h5o_open_by_addr(): Test H5Oopen_by_addr function. +** +****************************************************************/ +static void +test_h5o_open_by_addr(void) +{ + hid_t fid; /* HDF5 File ID */ + hid_t grp, dset, dtype, dspace; /* Object identifiers */ + char filename[1024]; + H5L_info2_t li; /* Buffer for H5Lget_info2 */ + haddr_t grp_addr; /* Addresses for objects */ + haddr_t dset_addr; + haddr_t dtype_addr; + hsize_t dims[RANK]; + H5I_type_t id_type; /* Type of IDs returned from H5Oopen */ + H5G_info_t ginfo; /* Group info struct */ + H5T_class_t type_class; /* Class of the datatype */ + herr_t ret; /* Value returned from API calls */ + + h5_fixname(TEST_FILENAME, H5P_DEFAULT, filename, sizeof filename); + + /* Create a new HDF5 file */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create a group, dataset, and committed datatype within the file */ + /* Create the group */ + grp = H5Gcreate2(fid, "group", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(grp, FAIL, "H5Gcreate2"); + ret = H5Gclose(grp); + CHECK(ret, FAIL, "H5Gclose"); + + /* Commit the type inside the group */ + dtype = H5Tcopy(H5T_NATIVE_INT); + CHECK(dtype, FAIL, "H5Tcopy"); + ret = H5Tcommit2(fid, "group/datatype", dtype, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + ret = H5Tclose(dtype); + CHECK(ret, FAIL, "H5Tclose"); + + /* Create the data space for the dataset. */ + dims[0] = DIM0; + dims[1] = DIM1; + dspace = H5Screate_simple(RANK, dims, NULL); + CHECK(dspace, FAIL, "H5Screate_simple"); + + /* Create the dataset. */ + dset = H5Dcreate2(fid, "dataset", H5T_NATIVE_INT, dspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dset, FAIL, "H5Dcreate2"); + ret = H5Dclose(dset); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Sclose(dspace); + CHECK(ret, FAIL, "H5Sclose"); + + /* Get address for each object */ + ret = H5Lget_info2(fid, "group", &li, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lget_info2"); + ret = H5VLnative_token_to_addr(fid, li.u.token, &grp_addr); + CHECK(ret, FAIL, "H5VLnative_token_to_addr"); + + ret = H5Lget_info2(fid, "group/datatype", &li, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lget_info2"); + ret = H5VLnative_token_to_addr(fid, li.u.token, &dtype_addr); + CHECK(ret, FAIL, "H5VLnative_token_to_addr"); + + ret = H5Lget_info2(fid, "dataset", &li, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lget_info2"); + ret = H5VLnative_token_to_addr(fid, li.u.token, &dset_addr); + CHECK(ret, FAIL, "H5VLnative_token_to_addr"); + + /* Now make sure that H5Oopen_by_addr can open all three types of objects */ + grp = H5Oopen_by_addr(fid, grp_addr); + CHECK(grp, FAIL, "H5Oopen_by_addr"); + dtype = H5Oopen_by_addr(fid, dtype_addr); + CHECK(dtype, FAIL, "H5Oopen_by_addr"); + /* Check that we can use the group ID as a valid location */ + dset = H5Oopen_by_addr(grp, dset_addr); + CHECK(dset, FAIL, "H5Oopen_by_addr"); + + /* Make sure that each is the right kind of ID */ + id_type = H5Iget_type(grp); + VERIFY(id_type, H5I_GROUP, "H5Iget_type for group ID"); + id_type = H5Iget_type(dtype); + VERIFY(id_type, H5I_DATATYPE, "H5Iget_type for datatype ID"); + id_type = H5Iget_type(dset); + VERIFY(id_type, H5I_DATASET, "H5Iget_type for dataset ID"); + + /* Do something more complex with each of the IDs to make sure they "work" */ + ret = H5Gget_info(grp, &ginfo); + CHECK(ret, FAIL, "H5Gget_info"); + VERIFY(ginfo.nlinks, 1, "H5Gget_info"); /* There should be one object, the datatype */ + + type_class = H5Tget_class(dtype); + VERIFY(type_class, H5T_INTEGER, "H5Tget_class"); + + dspace = H5Dget_space(dset); + CHECK(dspace, FAIL, "H5Dget_space"); + + /* Close the IDs */ + ret = H5Sclose(dspace); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Gclose(grp); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Tclose(dtype); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Dclose(dset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Try giving some bogus values to H5O_open_by_addr. */ + /* Try to open an object with a bad address */ + grp_addr += 20; + H5E_BEGIN_TRY + { + grp = H5Oopen_by_addr(fid, grp_addr); + } + H5E_END_TRY + VERIFY(grp, FAIL, "H5Oopen_by_addr"); + + /* For instance, an objectno smaller than the end of the file's superblock should + * trigger an error */ + grp_addr = 10; + H5E_BEGIN_TRY + { + grp = H5Oopen_by_addr(fid, grp_addr); + } + H5E_END_TRY + VERIFY(grp, FAIL, "H5Oopen_by_addr"); + + /* Likewise, an objectno larger than the size of the file should fail */ + grp_addr = 0; + grp_addr = 1000000000; + H5E_BEGIN_TRY + { + grp = H5Oopen_by_addr(fid, grp_addr); + } + H5E_END_TRY + VERIFY(grp, FAIL, "H5Oopen_by_addr"); + + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Also, trying to open an object without a valid location should fail */ + H5E_BEGIN_TRY + { + dtype = H5Oopen_by_addr(fid, dtype_addr); + } + H5E_END_TRY + VERIFY(dtype, FAIL, "H5Oopen_by_addr"); +} /* test_h5o_open_by_addr() */ +#endif /* H5_NO_DEPRECATED_SYMBOLS */ +#endif + +/**************************************************************** +** +** test_h5o_open_by_token(): Test H5Oopen_by_token function. +** +****************************************************************/ +static void +test_h5o_open_by_token(void) +{ + hid_t fid; /* HDF5 File ID */ + hid_t grp, dset, dtype, dspace; /* Object identifiers */ + char filename[1024]; + H5L_info2_t li; /* Buffer for H5Lget_info */ + hsize_t dims[RANK]; + H5I_type_t id_type; /* Type of IDs returned from H5Oopen */ + H5G_info_t ginfo; /* Group info struct */ + H5T_class_t type_class; /* Class of the datatype */ + herr_t ret; /* Value returned from API calls */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing H5Oopen_by_token\n")); + + h5_fixname(TEST_FILENAME, H5P_DEFAULT, filename, sizeof filename); + + /* Create a new HDF5 file */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create a group, dataset, and committed datatype within the file */ + /* Create the group */ + grp = H5Gcreate2(fid, "group", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(grp, FAIL, "H5Gcreate2"); + ret = H5Gclose(grp); + CHECK(ret, FAIL, "H5Gclose"); + + /* Commit the type inside the group */ + dtype = H5Tcopy(H5T_NATIVE_INT); + CHECK(dtype, FAIL, "H5Tcopy"); + ret = H5Tcommit2(fid, "group/datatype", dtype, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + ret = H5Tclose(dtype); + CHECK(ret, FAIL, "H5Tclose"); + + /* Create the data space for the dataset. */ + dims[0] = DIM0; + dims[1] = DIM1; + dspace = H5Screate_simple(RANK, dims, NULL); + CHECK(dspace, FAIL, "H5Screate_simple"); + + /* Create the dataset. */ + dset = H5Dcreate2(fid, "dataset", H5T_NATIVE_INT, dspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dset, FAIL, "H5Dcreate2"); + ret = H5Dclose(dset); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Sclose(dspace); + CHECK(ret, FAIL, "H5Sclose"); + + /* Make sure that H5Oopen_by_token can open all three types of objects */ + ret = H5Lget_info2(fid, "group", &li, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lget_info"); + grp = H5Oopen_by_token(fid, li.u.token); + CHECK(grp, FAIL, "H5Oopen_by_token"); + + ret = H5Lget_info2(fid, "group/datatype", &li, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lget_info"); + dtype = H5Oopen_by_token(fid, li.u.token); + CHECK(dtype, FAIL, "H5Oopen_by_token"); + + ret = H5Lget_info2(fid, "dataset", &li, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lget_info"); + /* Check that we can use the group ID as a valid location */ + dset = H5Oopen_by_token(grp, li.u.token); + CHECK(dset, FAIL, "H5Oopen_by_token"); + + /* Make sure that each is the right kind of ID */ + id_type = H5Iget_type(grp); + VERIFY(id_type, H5I_GROUP, "H5Iget_type for group ID"); + id_type = H5Iget_type(dtype); + VERIFY(id_type, H5I_DATATYPE, "H5Iget_type for datatype ID"); + id_type = H5Iget_type(dset); + VERIFY(id_type, H5I_DATASET, "H5Iget_type for dataset ID"); + + /* Do something more complex with each of the IDs to make sure they "work" */ + ret = H5Gget_info(grp, &ginfo); + CHECK(ret, FAIL, "H5Gget_info"); + VERIFY(ginfo.nlinks, 1, "H5Gget_info"); /* There should be one object, the datatype */ + + type_class = H5Tget_class(dtype); + VERIFY(type_class, H5T_INTEGER, "H5Tget_class"); + + dspace = H5Dget_space(dset); + CHECK(dspace, FAIL, "H5Dget_space"); + + /* Close the IDs */ + ret = H5Sclose(dspace); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Gclose(grp); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Tclose(dtype); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Dclose(dset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Try giving some bogus values to H5O_open_by_token */ + /* Try opening an object using H5O_TOKEN_UNDEF (should fail) */ + H5E_BEGIN_TRY + { + dtype = H5Oopen_by_token(fid, H5O_TOKEN_UNDEF); + } + H5E_END_TRY + VERIFY(dtype, FAIL, "H5Oopen_by_token"); + + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Also, trying to open an object without a valid location (should fail) */ + H5E_BEGIN_TRY + { + dtype = H5Oopen_by_token(fid, li.u.token); + } + H5E_END_TRY + VERIFY(dtype, FAIL, "H5Oopen_by_token"); + +} /* test_h5o_open_by_token() */ + +/**************************************************************** +** +** test_h5o_refcount(): Test H5O refcounting functions. +** +****************************************************************/ +static void +test_h5o_refcount(void) +{ + hid_t fid; /* HDF5 File ID */ + hid_t grp, dset, dtype, dspace; /* Object identifiers */ + char filename[1024]; + H5O_info2_t oinfo; /* Object info struct */ + hsize_t dims[RANK]; + herr_t ret; /* Value returned from API calls */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing retrieval of object reference count with H5Oget_info\n")); + + h5_fixname(TEST_FILENAME, H5P_DEFAULT, filename, sizeof filename); + + /* Create a new HDF5 file */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create a group, dataset, and committed datatype within the file */ + /* Create the group */ + grp = H5Gcreate2(fid, "group", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(grp, FAIL, "H5Gcreate2"); + + /* Commit the type inside the group */ + dtype = H5Tcopy(H5T_NATIVE_INT); + CHECK(dtype, FAIL, "H5Tcopy"); + ret = H5Tcommit2(fid, "datatype", dtype, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + + /* Create the data space for the dataset. */ + dims[0] = DIM0; + dims[1] = DIM1; + dspace = H5Screate_simple(RANK, dims, NULL); + CHECK(dspace, FAIL, "H5Screate_simple"); + + /* Create the dataset. */ + dset = H5Dcreate2(fid, "dataset", H5T_NATIVE_INT, dspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dset, FAIL, "H5Dcreate2"); + ret = H5Sclose(dspace); + CHECK(ret, FAIL, "H5Sclose"); + + /* Get ref counts for each object. They should all be 1, since each object has a hard link. */ + ret = H5Oget_info_by_name3(fid, "group", &oinfo, H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name3"); + VERIFY(oinfo.rc, 1, "reference count in H5Oget_info_by_name3"); + ret = H5Oget_info_by_name3(fid, "datatype", &oinfo, H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name3"); + VERIFY(oinfo.rc, 1, "reference count in H5Oget_info_by_name3"); + ret = H5Oget_info_by_name3(fid, "dataset", &oinfo, H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name3"); + VERIFY(oinfo.rc, 1, "reference count in H5Oget_info_by_name3"); + + /* Increment each object's reference count. */ + ret = H5Oincr_refcount(grp); + CHECK(ret, FAIL, "H5Oincr_refcount"); + ret = H5Oincr_refcount(dtype); + CHECK(ret, FAIL, "H5Oincr_refcount"); + ret = H5Oincr_refcount(dset); + CHECK(ret, FAIL, "H5Oincr_refcount"); + + /* Get ref counts for each object. They should all be 2 now. */ + ret = H5Oget_info_by_name3(fid, "group", &oinfo, H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name3"); + VERIFY(oinfo.rc, 2, "reference count in H5Oget_info_by_name3"); + ret = H5Oget_info_by_name3(fid, "datatype", &oinfo, H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name3"); + VERIFY(oinfo.rc, 2, "reference count in H5Oget_info_by_name3"); + ret = H5Oget_info_by_name3(fid, "dataset", &oinfo, H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name3"); + VERIFY(oinfo.rc, 2, "reference count in H5Oget_info_by_name3"); + + /* Decrement the reference counts and check that they decrease back to 1. */ + ret = H5Odecr_refcount(grp); + CHECK(ret, FAIL, "H5Odecr_refcount"); + ret = H5Odecr_refcount(dtype); + CHECK(ret, FAIL, "H5Odecr_refcount"); + ret = H5Odecr_refcount(dset); + CHECK(ret, FAIL, "H5Odecr_refcount"); + + ret = H5Oget_info_by_name3(fid, "group", &oinfo, H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name3"); + VERIFY(oinfo.rc, 1, "reference count in H5Oget_info_by_name3"); + ret = H5Oget_info_by_name3(fid, "datatype", &oinfo, H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name3"); + VERIFY(oinfo.rc, 1, "reference count in H5Oget_info_by_name3"); + ret = H5Oget_info_by_name3(fid, "dataset", &oinfo, H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name3"); + VERIFY(oinfo.rc, 1, "reference count in H5Oget_info_by_name3"); + + /* Increment the reference counts and then close the file to make sure the increment is permanent */ + ret = H5Oincr_refcount(grp); + CHECK(ret, FAIL, "H5Oincr_refcount"); + ret = H5Oincr_refcount(dtype); + CHECK(ret, FAIL, "H5Oincr_refcount"); + ret = H5Oincr_refcount(dset); + CHECK(ret, FAIL, "H5Oincr_refcount"); + + ret = H5Gclose(grp); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Tclose(dtype); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Dclose(dset); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open the file and check that the reference counts were really incremented */ + fid = H5Fopen(filename, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + grp = H5Gopen2(fid, "group", H5P_DEFAULT); + CHECK(grp, FAIL, "H5Gopen2"); + dtype = H5Topen2(fid, "datatype", H5P_DEFAULT); + CHECK(dtype, FAIL, "H5Topen2"); + dset = H5Dopen2(fid, "dataset", H5P_DEFAULT); + CHECK(dset, FAIL, "H5Dopen2"); + + ret = H5Oget_info_by_name3(fid, "group", &oinfo, H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name3"); + VERIFY(oinfo.rc, 2, "reference count in H5Oget_info_by_name3"); + ret = H5Oget_info_by_name3(fid, "datatype", &oinfo, H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name3"); + VERIFY(oinfo.rc, 2, "reference count in H5Oget_info_by_name3"); + ret = H5Oget_info_by_name3(fid, "dataset", &oinfo, H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name3"); + VERIFY(oinfo.rc, 2, "reference count in H5Oget_info_by_name3"); + + /* Decrement the reference counts and close the file */ + ret = H5Odecr_refcount(grp); + CHECK(ret, FAIL, "H5Odecr_refcount"); + ret = H5Odecr_refcount(dtype); + CHECK(ret, FAIL, "H5Odecr_refcount"); + ret = H5Odecr_refcount(dset); + CHECK(ret, FAIL, "H5Odecr_refcount"); + + ret = H5Gclose(grp); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Tclose(dtype); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Dclose(dset); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open the file and check that the reference counts were really decremented */ + fid = H5Fopen(filename, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + grp = H5Gopen2(fid, "group", H5P_DEFAULT); + CHECK(grp, FAIL, "H5Gopen2"); + dtype = H5Topen2(fid, "datatype", H5P_DEFAULT); + CHECK(dtype, FAIL, "H5Topen2"); + dset = H5Dopen2(fid, "dataset", H5P_DEFAULT); + CHECK(dset, FAIL, "H5Dopen2"); + + ret = H5Oget_info_by_name3(fid, "group", &oinfo, H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name3"); + VERIFY(oinfo.rc, 1, "reference count in H5Oget_info_by_name3"); + ret = H5Oget_info_by_name3(fid, "datatype", &oinfo, H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name3"); + VERIFY(oinfo.rc, 1, "reference count in H5Oget_info_by_name3"); + ret = H5Oget_info_by_name3(fid, "dataset", &oinfo, H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name3"); + VERIFY(oinfo.rc, 1, "reference count in H5Oget_info_by_name3"); + + /* Close the IDs */ + ret = H5Gclose(grp); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Tclose(dtype); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Dclose(dset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Make sure that bogus IDs return errors properly */ + H5E_BEGIN_TRY + { + ret = H5Oincr_refcount(grp); + VERIFY(ret, FAIL, "H5Oincr_refcount"); + ret = H5Oincr_refcount(dtype); + VERIFY(ret, FAIL, "H5Oincr_refcount"); + ret = H5Oincr_refcount(dset); + VERIFY(ret, FAIL, "H5Oincr_refcount"); + ret = H5Odecr_refcount(grp); + VERIFY(ret, FAIL, "H5Odecr_refcount"); + ret = H5Odecr_refcount(dtype); + VERIFY(ret, FAIL, "H5Odecr_refcount"); + ret = H5Odecr_refcount(dset); + VERIFY(ret, FAIL, "H5Odecr_refcount"); + } + H5E_END_TRY + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_h5o_refcount() */ + +/**************************************************************** +** +** test_h5o_plist(): Test object creation properties +** +****************************************************************/ +static void +test_h5o_plist(void) +{ + hid_t fid; /* HDF5 File ID */ + hid_t grp, dset, dtype, dspace; /* Object identifiers */ + hid_t fapl; /* File access property list */ + hid_t gcpl, dcpl, tcpl; /* Object creation properties */ + char filename[1024]; + unsigned def_max_compact, def_min_dense; /* Default phase change parameters */ + unsigned max_compact, min_dense; /* Actual phase change parameters */ + herr_t ret; /* Value returned from API calls */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Object creation properties\n")); + + /* Make a FAPL that uses the "use the latest version of the format" flag */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + + /* Set the "use the latest version of the format" bounds for creating objects in the file */ + ret = H5Pset_libver_bounds(fapl, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST); + CHECK(ret, FAIL, "H5Pset_libver_bounds"); + + h5_fixname(TEST_FILENAME, fapl, filename, sizeof filename); + + /* Create a new HDF5 file */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create group, dataset & named datatype creation property lists */ + gcpl = H5Pcreate(H5P_GROUP_CREATE); + CHECK(gcpl, FAIL, "H5Pcreate"); + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + tcpl = H5Pcreate(H5P_DATATYPE_CREATE); + CHECK(tcpl, FAIL, "H5Pcreate"); + + /* Retrieve default attribute phase change values */ + ret = H5Pget_attr_phase_change(gcpl, &def_max_compact, &def_min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + + /* Set non-default attribute phase change values on each creation property list */ + ret = H5Pset_attr_phase_change(gcpl, def_max_compact + 1, def_min_dense - 1); + CHECK(ret, FAIL, "H5Pset_attr_phase_change"); + ret = H5Pset_attr_phase_change(dcpl, def_max_compact + 1, def_min_dense - 1); + CHECK(ret, FAIL, "H5Pset_attr_phase_change"); + ret = H5Pset_attr_phase_change(tcpl, def_max_compact + 1, def_min_dense - 1); + CHECK(ret, FAIL, "H5Pset_attr_phase_change"); + + /* Retrieve attribute phase change values on each creation property list and verify */ + ret = H5Pget_attr_phase_change(gcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + VERIFY(max_compact, (def_max_compact + 1), "H5Pget_attr_phase_change"); + VERIFY(min_dense, (def_min_dense - 1), "H5Pget_attr_phase_change"); + ret = H5Pget_attr_phase_change(dcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + VERIFY(max_compact, (def_max_compact + 1), "H5Pget_attr_phase_change"); + VERIFY(min_dense, (def_min_dense - 1), "H5Pget_attr_phase_change"); + ret = H5Pget_attr_phase_change(tcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + VERIFY(max_compact, (def_max_compact + 1), "H5Pget_attr_phase_change"); + VERIFY(min_dense, (def_min_dense - 1), "H5Pget_attr_phase_change"); + + /* Create a group, dataset, and committed datatype within the file, + * using the respective type of creation property lists. + */ + + /* Create the group anonymously and link it in */ + grp = H5Gcreate_anon(fid, gcpl, H5P_DEFAULT); + CHECK(grp, FAIL, "H5Gcreate_anon"); + ret = H5Olink(grp, fid, "group", H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Olink"); + + /* Commit the type inside the group anonymously and link it in */ + dtype = H5Tcopy(H5T_NATIVE_INT); + CHECK(dtype, FAIL, "H5Tcopy"); + ret = H5Tcommit_anon(fid, dtype, tcpl, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit_anon"); + ret = H5Olink(dtype, fid, "datatype", H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Olink"); + + /* Create the dataspace for the dataset. */ + dspace = H5Screate(H5S_SCALAR); + CHECK(dspace, FAIL, "H5Screate"); + + /* Create the dataset anonymously and link it in */ + dset = H5Dcreate_anon(fid, H5T_NATIVE_INT, dspace, dcpl, H5P_DEFAULT); + CHECK(dset, FAIL, "H5Dcreate_anon"); + ret = H5Olink(dset, fid, "dataset", H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Olink"); + ret = H5Sclose(dspace); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close current creation property lists */ + ret = H5Pclose(gcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(tcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Retrieve each object's creation property list */ + gcpl = H5Gget_create_plist(grp); + CHECK(gcpl, FAIL, "H5Gget_create_plist"); + tcpl = H5Tget_create_plist(dtype); + CHECK(tcpl, FAIL, "H5Tget_create_plist"); + dcpl = H5Dget_create_plist(dset); + CHECK(dcpl, FAIL, "H5Dget_create_plist"); + + /* Retrieve attribute phase change values on each creation property list and verify */ + ret = H5Pget_attr_phase_change(gcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + VERIFY(max_compact, (def_max_compact + 1), "H5Pget_attr_phase_change"); + VERIFY(min_dense, (def_min_dense - 1), "H5Pget_attr_phase_change"); + ret = H5Pget_attr_phase_change(dcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + VERIFY(max_compact, (def_max_compact + 1), "H5Pget_attr_phase_change"); + VERIFY(min_dense, (def_min_dense - 1), "H5Pget_attr_phase_change"); + ret = H5Pget_attr_phase_change(tcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + VERIFY(max_compact, (def_max_compact + 1), "H5Pget_attr_phase_change"); + VERIFY(min_dense, (def_min_dense - 1), "H5Pget_attr_phase_change"); + + /* Close current objects */ + ret = H5Pclose(gcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(tcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Gclose(grp); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Tclose(dtype); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Dclose(dset); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open the file and check that the object creation properties persist */ + fid = H5Fopen(filename, H5F_ACC_RDONLY, fapl); + CHECK(fid, FAIL, "H5Fopen"); + + /* Re-open objects */ + grp = H5Gopen2(fid, "group", H5P_DEFAULT); + CHECK(grp, FAIL, "H5Gopen2"); + dtype = H5Topen2(fid, "datatype", H5P_DEFAULT); + CHECK(dtype, FAIL, "H5Topen2"); + dset = H5Dopen2(fid, "dataset", H5P_DEFAULT); + CHECK(dset, FAIL, "H5Dopen2"); + + /* Retrieve each object's creation property list */ + gcpl = H5Gget_create_plist(grp); + CHECK(gcpl, FAIL, "H5Gget_create_plist"); + tcpl = H5Tget_create_plist(dtype); + CHECK(tcpl, FAIL, "H5Tget_create_plist"); + dcpl = H5Dget_create_plist(dset); + CHECK(dcpl, FAIL, "H5Dget_create_plist"); + + /* Retrieve attribute phase change values on each creation property list and verify */ + ret = H5Pget_attr_phase_change(gcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + VERIFY(max_compact, (def_max_compact + 1), "H5Pget_attr_phase_change"); + VERIFY(min_dense, (def_min_dense - 1), "H5Pget_attr_phase_change"); + ret = H5Pget_attr_phase_change(dcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + VERIFY(max_compact, (def_max_compact + 1), "H5Pget_attr_phase_change"); + VERIFY(min_dense, (def_min_dense - 1), "H5Pget_attr_phase_change"); + ret = H5Pget_attr_phase_change(tcpl, &max_compact, &min_dense); + CHECK(ret, FAIL, "H5Pget_attr_phase_change"); + VERIFY(max_compact, (def_max_compact + 1), "H5Pget_attr_phase_change"); + VERIFY(min_dense, (def_min_dense - 1), "H5Pget_attr_phase_change"); + + /* Close current objects */ + ret = H5Pclose(gcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(tcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Gclose(grp); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Tclose(dtype); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Dclose(dset); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Close the FAPL */ + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); +} /* test_h5o_plist() */ + +/**************************************************************** +** +** test_h5o_link(): Test creating link to object +** +****************************************************************/ +static void +test_h5o_link(void) +{ + hid_t file_id = -1; + hid_t group_id = -1; + hid_t space_id = -1; + hid_t dset_id = -1; + hid_t type_id = -1; + hid_t fapl_id = -1; + hid_t lcpl_id = -1; + char filename[1024]; + hsize_t dims[2] = {TEST6_DIM1, TEST6_DIM2}; + htri_t committed; /* Whether the named datatype is committed */ + H5F_libver_t low, high; /* File format bounds */ + int *wdata; + int *rdata; + int i, n; + herr_t ret; /* Value returned from API calls */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing H5Olink\n")); + + h5_fixname(TEST_FILENAME, H5P_DEFAULT, filename, sizeof filename); + + /* Allocate memory buffers */ + /* (These are treated as 2-D buffers) */ + wdata = (int *)HDmalloc((size_t)(TEST6_DIM1 * TEST6_DIM2) * sizeof(int)); + CHECK_PTR(wdata, "HDmalloc"); + rdata = (int *)HDmalloc((size_t)(TEST6_DIM1 * TEST6_DIM2) * sizeof(int)); + CHECK_PTR(rdata, "HDmalloc"); + + /* Initialize the raw data */ + for (i = n = 0; i < (TEST6_DIM1 * TEST6_DIM2); i++) + wdata[i] = n++; + + /* Create the dataspace */ + space_id = H5Screate_simple(2, dims, NULL); + CHECK(space_id, FAIL, "H5Screate_simple"); + + /* Create LCPL with intermediate group creation flag set */ + lcpl_id = H5Pcreate(H5P_LINK_CREATE); + CHECK(lcpl_id, FAIL, "H5Pcreate"); + ret = H5Pset_create_intermediate_group(lcpl_id, TRUE); + CHECK(ret, FAIL, "H5Pset_create_intermediate_group"); + + /* Create a file access property list */ + fapl_id = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl_id, FAIL, "H5Pcreate"); + + /* Loop through all the combinations of low/high library format bounds */ + for (low = H5F_LIBVER_EARLIEST; low < H5F_LIBVER_NBOUNDS; low++) { + for (high = H5F_LIBVER_EARLIEST; high < H5F_LIBVER_NBOUNDS; high++) { + + /* Set version bounds */ + H5E_BEGIN_TRY + { + ret = H5Pset_libver_bounds(fapl_id, low, high); + } + H5E_END_TRY; + + if (ret < 0) /* Invalid low/high combinations */ + continue; + + /* Create a new HDF5 file */ + file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id); + CHECK(file_id, FAIL, "H5Fcreate"); + + /* Close the FAPL */ + ret = H5Pclose(fapl_id); + CHECK(ret, FAIL, "H5Pclose"); + + /* Create and commit a datatype with no name */ + type_id = H5Tcopy(H5T_NATIVE_INT); + CHECK(type_id, FAIL, "H5Fcreate"); + ret = H5Tcommit_anon(file_id, type_id, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit_anon"); + committed = H5Tcommitted(type_id); + VERIFY(committed, TRUE, "H5Tcommitted"); + + /* Create a dataset with no name using the committed datatype*/ + dset_id = H5Dcreate_anon(file_id, type_id, space_id, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dset_id, FAIL, "H5Dcreate_anon"); + + /* Verify that we can write to and read from the dataset */ + + /* Write the data to the dataset */ + ret = H5Dwrite(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Read the data back */ + ret = H5Dread(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Verify the data */ + for (i = 0; i < (TEST6_DIM1 * TEST6_DIM2); i++) + VERIFY(wdata[i], rdata[i], "H5Dread"); + + /* Create a group with no name*/ + group_id = H5Gcreate_anon(file_id, H5P_DEFAULT, H5P_DEFAULT); + CHECK(group_id, FAIL, "H5Gcreate_anon"); + + /* Link nameless datatype into nameless group */ + ret = H5Olink(type_id, group_id, "datatype", H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Olink"); + + /* Link nameless dataset into nameless group with intermediate group */ + ret = H5Olink(dset_id, group_id, "inter_group/dataset", lcpl_id, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Olink"); + + /* Close IDs for dataset and datatype */ + ret = H5Dclose(dset_id); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Tclose(type_id); + CHECK(ret, FAIL, "H5Tclose"); + + /* Re-open datatype using new link */ + type_id = H5Topen2(group_id, "datatype", H5P_DEFAULT); + CHECK(type_id, FAIL, "H5Topen2"); + + /* Link nameless group to root group and close the group ID*/ + ret = H5Olink(group_id, file_id, "/group", H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Olink"); + ret = H5Gclose(group_id); + CHECK(ret, FAIL, "H5Gclose"); + + /* Open dataset through root group and verify its data */ + dset_id = H5Dopen2(file_id, "/group/inter_group/dataset", H5P_DEFAULT); + CHECK(dset_id, FAIL, "H5Dopen2"); + + /* Read data from dataset */ + ret = H5Dread(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + for (i = 0; i < (TEST6_DIM1 * TEST6_DIM2); i++) + VERIFY(wdata[i], rdata[i], "H5Dread"); + + /* Close open IDs */ + ret = H5Dclose(dset_id); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Tclose(type_id); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Fclose(file_id); + CHECK(ret, FAIL, "H5Fclose"); + } /* for high */ + } /* for low */ + + /* Close remaining IDs */ + ret = H5Sclose(space_id); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Pclose(lcpl_id); + CHECK(ret, FAIL, "H5Pclose"); + + /* Release buffers */ + HDfree(wdata); + HDfree(rdata); +} /* end test_h5o_link() */ + +#if 0 +/**************************************************************** +** +** test_h5o_comment(): Test H5Oset(get)_comment functions. +** +****************************************************************/ +static void +test_h5o_comment(void) +{ + hid_t fid; /* HDF5 File ID */ + hid_t grp, dset, dtype, dspace; /* Object identifiers */ + hid_t attr_space, attr_id; + char filename[1024]; + hsize_t dims[RANK]; + hsize_t attr_dims = 1; + int attr_value = 5; + const char *file_comment = "file comment"; + const char *grp_comment = "group comment"; + const char *dset_comment = "dataset comment"; + const char *dtype_comment = "datatype comment"; + char check_comment[64]; + ssize_t comment_len = 0; + ssize_t len; + herr_t ret; /* Value returned from API calls */ + int ret_value; + + h5_fixname(TEST_FILENAME, H5P_DEFAULT, filename, sizeof filename); + + /* Create a new HDF5 file */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create an attribute for the file */ + attr_space = H5Screate_simple(1, &attr_dims, NULL); + CHECK(attr_space, FAIL, "H5Screate_simple"); + attr_id = H5Acreate2(fid, "file attribute", H5T_NATIVE_INT, attr_space, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr_id, FAIL, "H5Acreate2"); + ret = H5Awrite(attr_id, H5T_NATIVE_INT, &attr_value); + CHECK(ret, FAIL, "H5Awrite"); + + /* Putting a comment on the file through its attribute */ + ret = H5Oset_comment(attr_id, file_comment); + CHECK(ret, FAIL, "H5Oset_comment"); + + ret = H5Sclose(attr_space); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Aclose(attr_id); + CHECK(ret, FAIL, "H5Aclose"); + + /* Create a group, dataset, and committed datatype within the file */ + /* Create the group */ + grp = H5Gcreate2(fid, "group", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(grp, FAIL, "H5Gcreate2"); + + /* Putting a comment on the group */ + ret = H5Oset_comment(grp, grp_comment); + CHECK(ret, FAIL, "H5Oset_comment"); + + ret = H5Gclose(grp); + CHECK(ret, FAIL, "H5Gclose"); + + /* Commit the type inside the group */ + dtype = H5Tcopy(H5T_NATIVE_INT); + CHECK(dtype, FAIL, "H5Tcopy"); + ret = H5Tcommit2(fid, "group/datatype", dtype, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + + /* Putting a comment on the committed data type */ + ret = H5Oset_comment(dtype, dtype_comment); + CHECK(ret, FAIL, "H5Oset_comment"); + + ret = H5Tclose(dtype); + CHECK(ret, FAIL, "H5Tclose"); + + /* Create the data space for the dataset. */ + dims[0] = DIM0; + dims[1] = DIM1; + dspace = H5Screate_simple(RANK, dims, NULL); + CHECK(dspace, FAIL, "H5Screate_simple"); + + /* Create the dataset. */ + dset = H5Dcreate2(fid, "dataset", H5T_NATIVE_INT, dspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dset, FAIL, "H5Dcreate2"); + + /* Putting a comment on the dataset */ + ret = H5Oset_comment(dset, dset_comment); + CHECK(ret, FAIL, "H5Oset_comment"); + + /* Putting a comment on the dataspace. It's supposed to fail. */ + H5E_BEGIN_TRY + { + ret = H5Oset_comment(dspace, "dataspace comment"); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Oset_comment"); + + /* Close the file */ + ret = H5Dclose(dset); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Sclose(dspace); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Now make sure that the comments are correct all 4 types of objects */ + /* Open file */ + fid = H5Fopen(filename, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* Getting the comment on the file and verify it */ + comment_len = H5Oget_comment(fid, NULL, (size_t)0); + CHECK(comment_len, FAIL, "H5Oget_comment"); + + len = H5Oget_comment(fid, check_comment, (size_t)comment_len + 1); + CHECK(len, FAIL, "H5Oget_comment"); + + ret_value = HDstrcmp(file_comment, check_comment); + VERIFY(ret_value, 0, "H5Oget_comment"); + + /* Open the group */ + grp = H5Gopen2(fid, "group", H5P_DEFAULT); + CHECK(grp, FAIL, "H5Gopen2"); + + /* Getting the comment on the group and verify it */ + comment_len = H5Oget_comment(grp, NULL, (size_t)0); + CHECK(comment_len, FAIL, "H5Oget_comment"); + + len = H5Oget_comment(grp, check_comment, (size_t)comment_len + 1); + CHECK(len, FAIL, "H5Oget_comment"); + + ret_value = HDstrcmp(grp_comment, check_comment); + VERIFY(ret_value, 0, "H5Oget_comment"); + + /* Open the datatype */ + dtype = H5Topen2(fid, "group/datatype", H5P_DEFAULT); + CHECK(dtype, FAIL, "H5Topen2"); + + /* Getting the comment on the datatype and verify it */ + comment_len = H5Oget_comment(dtype, NULL, (size_t)0); + CHECK(comment_len, FAIL, "H5Oget_comment"); + + len = H5Oget_comment(dtype, check_comment, (size_t)comment_len + 1); + CHECK(len, FAIL, "H5Oget_comment"); + + ret_value = HDstrcmp(dtype_comment, check_comment); + VERIFY(ret_value, 0, "H5Oget_comment"); + + /* Open the dataset */ + dset = H5Dopen2(fid, "dataset", H5P_DEFAULT); + CHECK(dset, FAIL, "H5Dopen2"); + + /* Getting the comment on the dataset and verify it */ + comment_len = H5Oget_comment(dset, NULL, (size_t)0); + CHECK(comment_len, FAIL, "H5Oget_comment"); + + len = H5Oget_comment(dset, check_comment, (size_t)comment_len + 1); + CHECK(ret, len, "H5Oget_comment"); + + ret_value = HDstrcmp(dset_comment, check_comment); + VERIFY(ret_value, 0, "H5Oget_comment"); + + /* Close the IDs */ + ret = H5Gclose(grp); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Tclose(dtype); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Dclose(dset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + +} /* test_h5o_comment() */ + +/**************************************************************** +** +** test_h5o_comment_by_name(): Test H5Oset(get)_comment_by_name functions. +** +****************************************************************/ +static void +test_h5o_comment_by_name(void) +{ + hid_t fid; /* HDF5 File ID */ + hid_t grp, dset, dtype, dspace; /* Object identifiers */ + hid_t attr_space, attr_id; + char filename[1024]; + hsize_t dims[RANK]; + hsize_t attr_dims = 1; + int attr_value = 5; + const char *file_comment = "file comment by name"; + const char *grp_comment = "group comment by name"; + const char *dset_comment = "dataset comment by name"; + const char *dtype_comment = "datatype comment by name"; + char check_comment[64]; + ssize_t comment_len = 0; + ssize_t len; + herr_t ret; /* Value returned from API calls */ + int ret_value; + + h5_fixname(TEST_FILENAME, H5P_DEFAULT, filename, sizeof filename); + + /* Create a new HDF5 file */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create an attribute for the file */ + attr_space = H5Screate_simple(1, &attr_dims, NULL); + CHECK(attr_space, FAIL, "H5Screate_simple"); + attr_id = H5Acreate2(fid, "file attribute", H5T_NATIVE_INT, attr_space, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr_id, FAIL, "H5Acreate2"); + ret = H5Awrite(attr_id, H5T_NATIVE_INT, &attr_value); + CHECK(ret, FAIL, "H5Awrite"); + + /* Putting a comment on the file through its attribute */ + ret = H5Oset_comment_by_name(attr_id, ".", file_comment, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oset_comment_by_name"); + + ret = H5Sclose(attr_space); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Aclose(attr_id); + CHECK(ret, FAIL, "H5Aclose"); + + /* Create a group, dataset, and committed datatype within the file */ + /* Create the group */ + grp = H5Gcreate2(fid, "group", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(grp, FAIL, "H5Gcreate2"); + + /* Putting a comment on the group */ + ret = H5Oset_comment_by_name(fid, "group", grp_comment, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oset_comment_by_name"); + + /* Commit the type inside the group */ + dtype = H5Tcopy(H5T_NATIVE_INT); + CHECK(dtype, FAIL, "H5Tcopy"); + ret = H5Tcommit2(fid, "group/datatype", dtype, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + + /* Putting a comment on the committed data type */ + ret = H5Oset_comment_by_name(grp, "datatype", dtype_comment, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oset_comment_by_name"); + + ret = H5Tclose(dtype); + CHECK(ret, FAIL, "H5Tclose"); + + ret = H5Gclose(grp); + CHECK(ret, FAIL, "H5Gclose"); + + /* Create the data space for the dataset. */ + dims[0] = DIM0; + dims[1] = DIM1; + dspace = H5Screate_simple(RANK, dims, NULL); + CHECK(dspace, FAIL, "H5Screate_simple"); + + /* Create the dataset. */ + dset = H5Dcreate2(fid, "dataset", H5T_NATIVE_INT, dspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dset, FAIL, "H5Dcreate2"); + + /* Putting a comment on the dataset */ + ret = H5Oset_comment_by_name(fid, "dataset", dset_comment, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oset_comment_by_name"); + + /* Putting a comment on the dataspace. It's supposed to fail. */ + H5E_BEGIN_TRY + { + ret = H5Oset_comment_by_name(dspace, ".", "dataspace comment", H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Oset_comment"); + + /* Close the file */ + ret = H5Dclose(dset); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Sclose(dspace); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Now make sure that the comments are correct all 4 types of objects */ + /* Open file */ + fid = H5Fopen(filename, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* Getting the comment on the file and verify it */ + comment_len = H5Oget_comment_by_name(fid, ".", NULL, (size_t)0, H5P_DEFAULT); + CHECK(comment_len, FAIL, "H5Oget_comment_by_name"); + + len = H5Oget_comment_by_name(fid, ".", check_comment, (size_t)comment_len + 1, H5P_DEFAULT); + CHECK(len, FAIL, "H5Oget_comment_by_name"); + + ret_value = HDstrcmp(file_comment, check_comment); + VERIFY(ret_value, 0, "H5Oget_comment_by_name"); + + /* Open the group */ + grp = H5Gopen2(fid, "group", H5P_DEFAULT); + CHECK(grp, FAIL, "H5Gopen2"); + + /* Getting the comment on the group and verify it */ + comment_len = H5Oget_comment_by_name(fid, "group", NULL, (size_t)0, H5P_DEFAULT); + CHECK(comment_len, FAIL, "H5Oget_comment_by_name"); + + len = H5Oget_comment_by_name(fid, "group", check_comment, (size_t)comment_len + 1, H5P_DEFAULT); + CHECK(len, FAIL, "H5Oget_comment_by_name"); + + ret_value = HDstrcmp(grp_comment, check_comment); + VERIFY(ret_value, 0, "H5Oget_comment_by_name"); + + /* Getting the comment on the datatype and verify it */ + comment_len = H5Oget_comment_by_name(grp, "datatype", NULL, (size_t)0, H5P_DEFAULT); + CHECK(comment_len, FAIL, "H5Oget_comment_by_name"); + + len = H5Oget_comment_by_name(grp, "datatype", check_comment, (size_t)comment_len + 1, H5P_DEFAULT); + CHECK(len, FAIL, "H5Oget_comment"); + + ret_value = HDstrcmp(dtype_comment, check_comment); + VERIFY(ret_value, 0, "H5Oget_comment_by_name"); + + /* Getting the comment on the dataset and verify it */ + comment_len = H5Oget_comment_by_name(fid, "dataset", NULL, (size_t)0, H5P_DEFAULT); + CHECK(comment_len, FAIL, "H5Oget_comment_by_name"); + + len = H5Oget_comment_by_name(fid, "dataset", check_comment, (size_t)comment_len + 1, H5P_DEFAULT); + CHECK(len, FAIL, "H5Oget_comment_by_name"); + + ret_value = HDstrcmp(dset_comment, check_comment); + VERIFY(ret_value, 0, "H5Oget_comment_by_name"); + + /* Close the IDs */ + ret = H5Gclose(grp); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + +} /* test_h5o_comment_by_name() */ +#endif + +/**************************************************************** +** +** test_h5o_getinfo_same_file(): Test that querying the object info for +** objects in the same file will return the same file "number" +** +****************************************************************/ +static void +test_h5o_getinfo_same_file(void) +{ + hid_t fid1, fid2; /* HDF5 File ID */ + hid_t gid1, gid2; /* Group IDs */ + char filename[1024]; + H5O_info2_t oinfo1, oinfo2; /* Object info structs */ + herr_t ret; /* Value returned from API calls */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing H5Oget_info on objects in same file\n")); + + h5_fixname(TEST_FILENAME, H5P_DEFAULT, filename, sizeof filename); + + /* Create a new HDF5 file */ + fid1 = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create two groups in the file */ + gid1 = H5Gcreate2(fid1, "group1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid1, FAIL, "H5Gcreate2"); + gid2 = H5Gcreate2(fid1, "group2", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid2, FAIL, "H5Gcreate2"); + + /* Reset object info */ + HDmemset(&oinfo1, 0, sizeof(oinfo1)); + HDmemset(&oinfo2, 0, sizeof(oinfo2)); + + /* Query the object info for each object, through group IDs */ + ret = H5Oget_info3(gid1, &oinfo1, H5O_INFO_BASIC); + CHECK(ret, FAIL, "H5Oget_info3"); + ret = H5Oget_info3(gid2, &oinfo2, H5O_INFO_BASIC); + CHECK(ret, FAIL, "H5Oget_info3"); + + VERIFY(oinfo1.fileno, oinfo2.fileno, "file number from H5Oget_info3"); + + /* Reset object info */ + HDmemset(&oinfo1, 0, sizeof(oinfo1)); + HDmemset(&oinfo2, 0, sizeof(oinfo2)); + + /* Query the object info for each object, by name */ + ret = H5Oget_info_by_name3(fid1, "group1", &oinfo1, H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name3"); + ret = H5Oget_info_by_name3(fid1, "group2", &oinfo2, H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name3"); + + VERIFY(oinfo1.fileno, oinfo2.fileno, "file number from H5Oget_info3"); + + /* Close everything */ + ret = H5Gclose(gid1); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Gclose(gid2); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Open file twice */ + fid1 = H5Fopen(filename, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fopen"); + fid2 = H5Fopen(filename, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid2, FAIL, "H5Fopen"); + + /* Open the two groups in the file */ + gid1 = H5Gopen2(fid1, "group1", H5P_DEFAULT); + CHECK(gid1, FAIL, "H5Gopen2"); + gid2 = H5Gopen2(fid2, "group2", H5P_DEFAULT); + CHECK(gid2, FAIL, "H5Gopen2"); + + /* Reset object info */ + HDmemset(&oinfo1, 0, sizeof(oinfo1)); + HDmemset(&oinfo2, 0, sizeof(oinfo2)); + + /* Query the object info for each object, through group IDs */ + ret = H5Oget_info3(gid1, &oinfo1, H5O_INFO_BASIC); + CHECK(ret, FAIL, "H5Oget_info3"); + ret = H5Oget_info3(gid2, &oinfo2, H5O_INFO_BASIC); + CHECK(ret, FAIL, "H5Oget_info3"); + + VERIFY(oinfo1.fileno, oinfo2.fileno, "file number from H5Oget_info3"); + + /* Reset object info */ + HDmemset(&oinfo1, 0, sizeof(oinfo1)); + HDmemset(&oinfo2, 0, sizeof(oinfo2)); + + /* Query the object info for each object, by name */ + ret = H5Oget_info_by_name3(fid1, "group1", &oinfo1, H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name3"); + ret = H5Oget_info_by_name3(fid1, "group2", &oinfo2, H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name3"); + + VERIFY(oinfo1.fileno, oinfo2.fileno, "file number from H5Oget_info3"); + + /* Close everything */ + ret = H5Gclose(gid1); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Gclose(gid2); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + ret = H5Fclose(fid2); + CHECK(ret, FAIL, "H5Fclose"); + +} /* test_h5o_getinfo_same_file() */ + +#ifndef H5_NO_DEPRECATED_SYMBOLS +#if 0 +/**************************************************************** +** +** test_h5o_open_by_addr_deprec(): Test H5Oopen_by_addr function. +** +****************************************************************/ +static void +test_h5o_open_by_addr_deprec(void) +{ + hid_t fid; /* HDF5 File ID */ + hid_t grp, dset, dtype, dspace; /* Object identifiers */ + char filename[1024]; + H5L_info1_t li; /* Buffer for H5Lget_info1 */ + haddr_t grp_addr; /* Addresses for objects */ + haddr_t dset_addr; + haddr_t dtype_addr; + hsize_t dims[RANK]; + H5I_type_t id_type; /* Type of IDs returned from H5Oopen */ + H5G_info_t ginfo; /* Group info struct */ + H5T_class_t type_class; /* Class of the datatype */ + herr_t ret; /* Value returned from API calls */ + + h5_fixname(TEST_FILENAME, H5P_DEFAULT, filename, sizeof filename); + + /* Create a new HDF5 file */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create a group, dataset, and committed datatype within the file */ + /* Create the group */ + grp = H5Gcreate2(fid, "group", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(grp, FAIL, "H5Gcreate2"); + ret = H5Gclose(grp); + CHECK(ret, FAIL, "H5Gclose"); + + /* Commit the type inside the group */ + dtype = H5Tcopy(H5T_NATIVE_INT); + CHECK(dtype, FAIL, "H5Tcopy"); + ret = H5Tcommit2(fid, "group/datatype", dtype, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + ret = H5Tclose(dtype); + CHECK(ret, FAIL, "H5Tclose"); + + /* Create the data space for the dataset. */ + dims[0] = DIM0; + dims[1] = DIM1; + dspace = H5Screate_simple(RANK, dims, NULL); + CHECK(dspace, FAIL, "H5Screate_simple"); + + /* Create the dataset. */ + dset = H5Dcreate2(fid, "dataset", H5T_NATIVE_INT, dspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dset, FAIL, "H5Dcreate2"); + ret = H5Dclose(dset); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Sclose(dspace); + CHECK(ret, FAIL, "H5Sclose"); + + /* Get address for each object */ + ret = H5Lget_info1(fid, "group", &li, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lget_info"); + grp_addr = li.u.address; + ret = H5Lget_info1(fid, "group/datatype", &li, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lget_info"); + dtype_addr = li.u.address; + ret = H5Lget_info1(fid, "dataset", &li, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lget_info"); + dset_addr = li.u.address; + + /* Now make sure that H5Oopen_by_addr can open all three types of objects */ + grp = H5Oopen_by_addr(fid, grp_addr); + CHECK(grp, FAIL, "H5Oopen_by_addr"); + dtype = H5Oopen_by_addr(fid, dtype_addr); + CHECK(dtype, FAIL, "H5Oopen_by_addr"); + /* Check that we can use the group ID as a valid location */ + dset = H5Oopen_by_addr(grp, dset_addr); + CHECK(dset, FAIL, "H5Oopen_by_addr"); + + /* Make sure that each is the right kind of ID */ + id_type = H5Iget_type(grp); + VERIFY(id_type, H5I_GROUP, "H5Iget_type for group ID"); + id_type = H5Iget_type(dtype); + VERIFY(id_type, H5I_DATATYPE, "H5Iget_type for datatype ID"); + id_type = H5Iget_type(dset); + VERIFY(id_type, H5I_DATASET, "H5Iget_type for dataset ID"); + + /* Do something more complex with each of the IDs to make sure they "work" */ + ret = H5Gget_info(grp, &ginfo); + CHECK(ret, FAIL, "H5Gget_info"); + VERIFY(ginfo.nlinks, 1, "H5Gget_info"); /* There should be one object, the datatype */ + + type_class = H5Tget_class(dtype); + VERIFY(type_class, H5T_INTEGER, "H5Tget_class"); + + dspace = H5Dget_space(dset); + CHECK(dspace, FAIL, "H5Dget_space"); + + /* Close the IDs */ + ret = H5Sclose(dspace); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Gclose(grp); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Tclose(dtype); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Dclose(dset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Try giving some bogus values to H5O_open_by_addr. */ + /* Try to open an object with a bad address */ + grp_addr += 20; + H5E_BEGIN_TRY + { + grp = H5Oopen_by_addr(fid, grp_addr); + } + H5E_END_TRY + VERIFY(grp, FAIL, "H5Oopen_by_addr"); + + /* For instance, an objectno smaller than the end of the file's superblock should + * trigger an error */ + grp_addr = 10; + H5E_BEGIN_TRY + { + grp = H5Oopen_by_addr(fid, grp_addr); + } + H5E_END_TRY + VERIFY(grp, FAIL, "H5Oopen_by_addr"); + + /* Likewise, an objectno larger than the size of the file should fail */ + grp_addr = 0; + grp_addr = 1000000000; + H5E_BEGIN_TRY + { + grp = H5Oopen_by_addr(fid, grp_addr); + } + H5E_END_TRY + VERIFY(grp, FAIL, "H5Oopen_by_addr"); + + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Also, trying to open an object without a valid location should fail */ + H5E_BEGIN_TRY + { + dtype = H5Oopen_by_addr(fid, dtype_addr); + } + H5E_END_TRY + VERIFY(dtype, FAIL, "H5Oopen_by_addr"); +} /* test_h5o_open_by_addr_deprec() */ + +/**************************************************************** +** +** visit_obj_cb(): +** This is the callback function invoked by H5Ovisit1() in +** test_h5o_getinfo_visit(): +** --Verify that the object info returned to the callback +** function is the same as H5Oget_info2(). +** +****************************************************************/ +static int +visit_obj_cb(hid_t group_id, const char *name, const H5O_info1_t *oinfo1, void H5_ATTR_UNUSED *_op_data) +{ + H5O_info1_t oinfo2; /* Object info structs */ + + /* Verify the object info for "group1", "group2" and the root group */ + if (!(HDstrcmp(name, "group1"))) { + H5Oget_info_by_name2(group_id, name, &oinfo2, H5O_INFO_NUM_ATTRS, H5P_DEFAULT); + VERIFY(oinfo1->num_attrs, oinfo2.num_attrs, "obj info from H5Ovisit1"); + } + else if (!(HDstrcmp(name, "group2"))) { + H5Oget_info_by_name2(group_id, name, &oinfo2, H5O_INFO_HDR, H5P_DEFAULT); + VERIFY(oinfo1->hdr.nmesgs, oinfo2.hdr.nmesgs, "obj info from H5Ovisit1/H5Oget_info2"); + VERIFY(oinfo1->hdr.nchunks, oinfo2.hdr.nchunks, "obj info from H5Ovisit1/H5Oget_info2"); + } + else if (!(HDstrcmp(name, "."))) { + H5Oget_info_by_name2(group_id, name, &oinfo2, H5O_INFO_META_SIZE, H5P_DEFAULT); + VERIFY(oinfo1->meta_size.obj.index_size, oinfo2.meta_size.obj.index_size, + "obj info from H5Ovisit1/H5Oget_info2"); + VERIFY(oinfo1->meta_size.obj.heap_size, oinfo2.meta_size.obj.heap_size, + "obj info from H5Ovisit1/H5Oget_info2"); + } + + return (H5_ITER_CONT); +} /* end visit_obj_cb() */ + +/**************************************************************** +** +** test_h5o_getinfo_visit(): +** Verify that the object info returned via H5Oget_info1() +** and H5Oget_info2() are the same. +** Verify that the object info retrieved via H5Ovisit1() is +** the same as H5Oget_info2(). +** +****************************************************************/ +static void +test_h5o_getinfo_visit(void) +{ + hid_t fid = -1; /* HDF5 File ID */ + hid_t gid1 = -1, gid2 = -1; /* Group IDs */ + hid_t sid = -1; /* Dataspace ID */ + hid_t aid = -1; /* Attribute ID */ + char filename[1024]; + H5O_info1_t oinfo1, oinfo2; /* Object info structs */ + char attrname[25]; /* Attribute name */ + int j; /* Local index variable */ + herr_t ret; /* Value returned from API calls */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing info returned by H5Oget_info vs H5Ovisit\n")); + + h5_fixname(TEST_FILENAME, H5P_DEFAULT, filename, sizeof filename); + + /* Create an HDF5 file */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create "group1" in the file */ + gid1 = H5Gcreate2(fid, "group1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid1, FAIL, "H5Gcreate2"); + + /* Create dataspace */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Attach 10 attributes to "group1" */ + for (j = 0; j < 10; j++) { + /* Create the attribute name */ + HDsnprintf(attrname, sizeof(attrname), "attr%u", j); + /* Create the attribute */ + aid = H5Acreate2(gid1, attrname, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + /* Close the attribute */ + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + } + + /* Create "group2" in the file */ + gid2 = H5Gcreate2(fid, "group2", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid2, FAIL, "H5Gcreate2"); + + /* Reset object info */ + HDmemset(&oinfo1, 0, sizeof(oinfo1)); + HDmemset(&oinfo2, 0, sizeof(oinfo2)); + + /* Query the object info for "group1" via H5Oget_info1 and H5Oget_info2 */ + ret = H5Oget_info1(gid1, &oinfo1); + CHECK(ret, FAIL, "H5Oget_info1"); + ret = H5Oget_info2(gid1, &oinfo2, H5O_INFO_BASIC | H5O_INFO_NUM_ATTRS); + CHECK(ret, FAIL, "H5Oget_info2"); + + /* Verify the object info for "group1" is correct */ + VERIFY(oinfo1.fileno, oinfo2.fileno, "obj info from H5Oget_info1/2"); + VERIFY(oinfo1.num_attrs, oinfo2.num_attrs, "obj info from H5Oget_info1/2"); + + /* Reset object info */ + HDmemset(&oinfo1, 0, sizeof(oinfo1)); + HDmemset(&oinfo2, 0, sizeof(oinfo2)); + + /* Query the object info for "group2" via H5Oget_info1 and H5Oget_info2 */ + ret = H5Oget_info_by_name1(fid, "group2", &oinfo1, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_native_info_by_name"); + ret = H5Oget_info_by_name2(fid, "group2", &oinfo2, H5O_INFO_HDR | H5O_INFO_META_SIZE, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_native_info_by_name"); + + /* Verify the object info for "group2" is correct */ + VERIFY(oinfo1.hdr.nmesgs, oinfo2.hdr.nmesgs, "obj info from H5Oget_info1/2"); + VERIFY(oinfo1.hdr.nchunks, oinfo2.hdr.nchunks, "obj info from H5Oget_info1/2"); + VERIFY(oinfo1.meta_size.obj.index_size, oinfo2.meta_size.obj.index_size, "obj info from H5Oget_info1/2"); + VERIFY(oinfo1.meta_size.obj.heap_size, oinfo2.meta_size.obj.heap_size, "obj info from H5Oget_info1/2"); + + /* Close everything */ + ret = H5Gclose(gid1); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Gclose(gid2); + CHECK(ret, FAIL, "H5Gclose"); + + /* Verify the object info returned to the callback function is correct */ + ret = H5Ovisit1(fid, H5_INDEX_NAME, H5_ITER_INC, visit_obj_cb, NULL); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + +} /* test_h5o_getinfo_visit() */ +#endif +#endif /* H5_NO_DEPRECATED_SYMBOLS */ + +/**************************************************************** +** +** test_h5o(): Main H5O (generic object) testing routine. +** +****************************************************************/ +void +test_h5o(void) +{ + /* Output message about test being performed */ + MESSAGE(5, ("Testing Objects\n")); + + test_h5o_open(); /* Test generic open function */ +#if 0 +#ifndef H5_NO_DEPRECATED_SYMBOLS + test_h5o_open_by_addr(); /* Test opening objects by address */ +#endif /* H5_NO_DEPRECATED_SYMBOLS */ +#endif + test_h5o_open_by_token(); /* Test opening objects by token */ + test_h5o_close(); /* Test generic close function */ + test_h5o_refcount(); /* Test incrementing and decrementing reference count */ + test_h5o_plist(); /* Test object creation properties */ + test_h5o_link(); /* Test object link routine */ +#if 0 + test_h5o_comment(); /* Test routines for comment */ + test_h5o_comment_by_name(); /* Test routines for comment by name */ +#endif + test_h5o_getinfo_same_file(); /* Test info for objects in the same file */ +#ifndef H5_NO_DEPRECATED_SYMBOLS +#if 0 + test_h5o_open_by_addr_deprec(); /* Test opening objects by address with H5Lget_info1 */ + test_h5o_getinfo_visit(); /* Test object info for H5Oget_info1/2 and H5Ovisit1 */ +#endif /* H5_NO_DEPRECATED_SYMBOLS */ +#endif +} /* test_h5o() */ + +/*------------------------------------------------------------------------- + * Function: cleanup_h5o + * + * Purpose: Cleanup temporary test files + * + * Return: none + * + * Programmer: James Laird + * June 3, 2006 + * + *------------------------------------------------------------------------- + */ +void +cleanup_h5o(void) +{ + char filename[1024]; + + H5E_BEGIN_TRY + { + h5_fixname(TEST_FILENAME, H5P_DEFAULT, filename, sizeof filename); + H5Fdelete(filename, H5P_DEFAULT); + } + H5E_END_TRY; +} diff --git a/test/API/th5s.c b/test/API/th5s.c new file mode 100644 index 0000000..cb1c899 --- /dev/null +++ b/test/API/th5s.c @@ -0,0 +1,3538 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*********************************************************** + * + * Test program: th5s + * + * Test the dataspace functionality + * + *************************************************************/ + +#include "testhdf5.h" +/* #include "H5srcdir.h" */ + +/* #include "H5Iprivate.h" */ +/* #include "H5Pprivate.h" */ + +#if 0 +/* + * This file needs to access private information from the H5S package. + * This file also needs to access the dataspace testing code. + */ +#define H5S_FRIEND /*suppress error about including H5Spkg */ +#define H5S_TESTING /*suppress warning about H5S testing funcs*/ +#include "H5Spkg.h" /* Dataspaces */ + +/* + * This file needs to access private information from the H5O package. + * This file also needs to access the dataspace testing code. + */ +#define H5O_FRIEND /*suppress error about including H5Opkg */ +#define H5O_TESTING +#include "H5Opkg.h" /* Object header */ +#endif + +#define TESTFILE "th5s.h5" +#define DATAFILE "th5s1.h5" +#define NULLFILE "th5s2.h5" +#define BASICFILE "th5s3.h5" +#define ZEROFILE "th5s4.h5" +#define BASICDATASET "basic_dataset" +#define BASICDATASET1 "basic_dataset1" +#define BASICDATASET2 "basic_dataset2" +#define BASICDATASET3 "basic_dataset3" +#define BASICDATASET4 "basic_dataset4" +#define BASICATTR "basic_attribute" +#define NULLDATASET "null_dataset" +#define NULLATTR "null_attribute" +#define EXTFILE_NAME "ext_file" + +/* 3-D dataset with fixed dimensions */ +#define SPACE1_RANK 3 +#define SPACE1_DIM1 3 +#define SPACE1_DIM2 15 +#define SPACE1_DIM3 13 + +/* 4-D dataset with one unlimited dimension */ +#define SPACE2_RANK 4 +#define SPACE2_DIM1 0 +#define SPACE2_DIM2 15 +#define SPACE2_DIM3 13 +#define SPACE2_DIM4 23 +#define SPACE2_MAX1 H5S_UNLIMITED +#define SPACE2_MAX2 15 +#define SPACE2_MAX3 13 +#define SPACE2_MAX4 23 + +/* Scalar dataset with simple datatype */ +#define SPACE3_RANK 0 +unsigned space3_data = 65; + +/* Scalar dataset with compound datatype */ +#define SPACE4_FIELDNAME1 "c1" +#define SPACE4_FIELDNAME2 "u" +#define SPACE4_FIELDNAME3 "f" +#define SPACE4_FIELDNAME4 "c2" +size_t space4_field1_off = 0; +size_t space4_field2_off = 0; +size_t space4_field3_off = 0; +size_t space4_field4_off = 0; +struct space4_struct { + char c1; + unsigned u; + float f; + char c2; +} space4_data = {'v', 987123, -3.14F, 'g'}; /* Test data for 4th dataspace */ + +/* + * Testing configuration defines used by: + * test_h5s_encode_regular_hyper() + * test_h5s_encode_irregular_hyper() + * test_h5s_encode_points() + */ +#define CONFIG_8 1 +#define CONFIG_16 2 +#define CONFIG_32 3 +#define POWER8 256 /* 2^8 */ +#define POWER16 65536 /* 2^16 */ +#define POWER32 4294967296 /* 2^32 */ + +/**************************************************************** +** +** test_h5s_basic(): Test basic H5S (dataspace) code. +** +****************************************************************/ +static void +test_h5s_basic(void) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t sid1, sid2; /* Dataspace ID */ + hid_t dset1; /* Dataset ID */ +#ifndef NO_VALIDATE_DATASPACE + hid_t aid1; /* Attribute ID */ +#endif + int rank; /* Logical rank of dataspace */ + hsize_t dims1[] = {SPACE1_DIM1, SPACE1_DIM2, SPACE1_DIM3}; + hsize_t dims2[] = {SPACE2_DIM1, SPACE2_DIM2, SPACE2_DIM3, SPACE2_DIM4}; + hsize_t dims3[H5S_MAX_RANK + 1]; + hsize_t max2[] = {SPACE2_MAX1, SPACE2_MAX2, SPACE2_MAX3, SPACE2_MAX4}; + hsize_t tdims[4]; /* Dimension array to test with */ + hsize_t tmax[4]; + hssize_t n; /* Number of dataspace elements */ +#if 0 + hbool_t driver_is_default_compatible; +#endif + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Dataspace Manipulation\n")); + + sid1 = H5Screate_simple(SPACE1_RANK, dims1, max2); + CHECK(sid1, FAIL, "H5Screate_simple"); + + n = H5Sget_simple_extent_npoints(sid1); + CHECK(n, FAIL, "H5Sget_simple_extent_npoints"); + VERIFY(n, SPACE1_DIM1 * SPACE1_DIM2 * SPACE1_DIM3, "H5Sget_simple_extent_npoints"); + + rank = H5Sget_simple_extent_ndims(sid1); + CHECK(rank, FAIL, "H5Sget_simple_extent_ndims"); + VERIFY(rank, SPACE1_RANK, "H5Sget_simple_extent_ndims"); + + rank = H5Sget_simple_extent_dims(sid1, tdims, NULL); + CHECK(rank, FAIL, "H5Sget_simple_extent_dims"); + VERIFY(HDmemcmp(tdims, dims1, SPACE1_RANK * sizeof(hsize_t)), 0, "H5Sget_simple_extent_dims"); + + sid2 = H5Screate_simple(SPACE2_RANK, dims2, max2); + CHECK(sid2, FAIL, "H5Screate_simple"); + + n = H5Sget_simple_extent_npoints(sid2); + CHECK(n, FAIL, "H5Sget_simple_extent_npoints"); + VERIFY(n, SPACE2_DIM1 * SPACE2_DIM2 * SPACE2_DIM3 * SPACE2_DIM4, "H5Sget_simple_extent_npoints"); + + rank = H5Sget_simple_extent_ndims(sid2); + CHECK(rank, FAIL, "H5Sget_simple_extent_ndims"); + VERIFY(rank, SPACE2_RANK, "H5Sget_simple_extent_ndims"); + + rank = H5Sget_simple_extent_dims(sid2, tdims, tmax); + CHECK(rank, FAIL, "H5Sget_simple_extent_dims"); + VERIFY(HDmemcmp(tdims, dims2, SPACE2_RANK * sizeof(hsize_t)), 0, "H5Sget_simple_extent_dims"); + VERIFY(HDmemcmp(tmax, max2, SPACE2_RANK * sizeof(hsize_t)), 0, "H5Sget_simple_extent_dims"); + + /* Change max dims to be equal to the dimensions */ + ret = H5Sset_extent_simple(sid1, SPACE1_RANK, dims1, NULL); + CHECK(ret, FAIL, "H5Sset_extent_simple"); + rank = H5Sget_simple_extent_dims(sid1, tdims, tmax); + CHECK(rank, FAIL, "H5Sget_simple_extent_dims"); + VERIFY(HDmemcmp(tdims, dims1, SPACE1_RANK * sizeof(hsize_t)), 0, "H5Sget_simple_extent_dims"); + VERIFY(HDmemcmp(tmax, dims1, SPACE1_RANK * sizeof(hsize_t)), 0, "H5Sget_simple_extent_dims"); + + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* + * Check to be sure we can't create a simple dataspace that has too many + * dimensions. + */ + H5E_BEGIN_TRY + { + sid1 = H5Screate_simple(H5S_MAX_RANK + 1, dims3, NULL); + } + H5E_END_TRY; + VERIFY(sid1, FAIL, "H5Screate_simple"); +#if 0 + /* + * Try reading a file that has been prepared that has a dataset with a + * higher dimensionality than what the library can handle. + * + * If this test fails and the H5S_MAX_RANK variable has changed, follow + * the instructions in space_overflow.c for regenerating the th5s.h5 file. + */ + ret = h5_driver_is_default_vfd_compatible(H5P_DEFAULT, &driver_is_default_compatible); + CHECK_I(ret, "h5_driver_is_default_vfd_compatible"); + + if (driver_is_default_compatible) { + const char *testfile = H5_get_srcdir_filename(TESTFILE); /* Corrected test file name */ + + fid1 = H5Fopen(testfile, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK_I(fid1, "H5Fopen"); + if (fid1 >= 0) { + dset1 = H5Dopen2(fid1, "dset", H5P_DEFAULT); + VERIFY(dset1, FAIL, "H5Dopen2"); + ret = H5Fclose(fid1); + CHECK_I(ret, "H5Fclose"); + } + else + HDprintf("***cannot open the pre-created H5S_MAX_RANK test file (%s)\n", testfile); + } +#endif + /* Verify that incorrect dimensions don't work */ + dims1[0] = H5S_UNLIMITED; + H5E_BEGIN_TRY + { + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + } + H5E_END_TRY; + VERIFY(sid1, FAIL, "H5Screate_simple"); + + dims1[0] = H5S_UNLIMITED; + sid1 = H5Screate(H5S_SIMPLE); + CHECK(sid1, FAIL, "H5Screate"); + + H5E_BEGIN_TRY + { + ret = H5Sset_extent_simple(sid1, SPACE1_RANK, dims1, NULL); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Sset_extent_simple"); + + ret = H5Sclose(sid1); + CHECK_I(ret, "H5Sclose"); + + /* + * Try writing simple dataspaces without setting their extents + */ + /* Create the file */ + fid1 = H5Fcreate(BASICFILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + dims1[0] = SPACE1_DIM1; + + sid1 = H5Screate(H5S_SIMPLE); + CHECK(sid1, FAIL, "H5Screate"); + sid2 = H5Screate_simple(1, dims1, dims1); + CHECK(sid2, FAIL, "H5Screate"); +#ifndef NO_VALIDATE_DATASPACE + /* This dataset's space has no extent; it should not be created */ + H5E_BEGIN_TRY + { + dset1 = H5Dcreate2(fid1, BASICDATASET, H5T_NATIVE_INT, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY + VERIFY(dset1, FAIL, "H5Dcreate2"); +#endif + dset1 = H5Dcreate2(fid1, BASICDATASET2, H5T_NATIVE_INT, sid2, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dset1, FAIL, "H5Dcreate2"); + + /* Try some writes with the bad dataspace (sid1) */ + H5E_BEGIN_TRY + { + ret = H5Dwrite(dset1, H5T_NATIVE_INT, sid1, H5S_ALL, H5P_DEFAULT, &n); + } + H5E_END_TRY + VERIFY(ret, FAIL, "H5Dwrite"); +#ifndef NO_VALIDATE_DATASPACE + H5E_BEGIN_TRY + { + ret = H5Dwrite(dset1, H5T_NATIVE_INT, H5S_ALL, sid1, H5P_DEFAULT, &n); + } + H5E_END_TRY + VERIFY(ret, FAIL, "H5Dwrite"); + + H5E_BEGIN_TRY + { + ret = H5Dwrite(dset1, H5T_NATIVE_INT, sid1, sid1, H5P_DEFAULT, &n); + } + H5E_END_TRY + VERIFY(ret, FAIL, "H5Dwrite"); +#endif + /* Try to iterate using the bad dataspace */ + H5E_BEGIN_TRY + { + ret = H5Diterate(&n, H5T_NATIVE_INT, sid1, NULL, NULL); + } + H5E_END_TRY + VERIFY(ret, FAIL, "H5Diterate"); + + /* Try to fill using the bad dataspace */ + H5E_BEGIN_TRY + { + ret = H5Dfill(NULL, H5T_NATIVE_INT, &n, H5T_NATIVE_INT, sid1); + } + H5E_END_TRY + VERIFY(ret, FAIL, "H5Dfill"); +#ifndef NO_VALIDATE_DATASPACE + /* Now use the bad dataspace as the space for an attribute */ + H5E_BEGIN_TRY + { + aid1 = H5Acreate2(dset1, BASICATTR, H5T_NATIVE_INT, sid1, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY + VERIFY(aid1, FAIL, "H5Acreate2"); +#endif + /* Make sure that dataspace reads using the bad dataspace fail */ + H5E_BEGIN_TRY + { + ret = H5Dread(dset1, H5T_NATIVE_INT, sid1, H5S_ALL, H5P_DEFAULT, &n); + } + H5E_END_TRY + VERIFY(ret, FAIL, "H5Dread"); +#ifndef NO_VALIDATE_DATASPACE + H5E_BEGIN_TRY + { + ret = H5Dread(dset1, H5T_NATIVE_INT, H5S_ALL, sid1, H5P_DEFAULT, &n); + } + H5E_END_TRY + VERIFY(ret, FAIL, "H5Dread"); + + H5E_BEGIN_TRY + { + ret = H5Dread(dset1, H5T_NATIVE_INT, sid1, sid1, H5P_DEFAULT, &n); + } + H5E_END_TRY + VERIFY(ret, FAIL, "H5Dread"); +#endif + /* Clean up */ + ret = H5Dclose(dset1); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_h5s_basic() */ + +/**************************************************************** +** +** test_h5s_null(): Test NULL dataspace +** +****************************************************************/ +static void +test_h5s_null(void) +{ + hid_t fid; /* File ID */ + hid_t sid; /* Dataspace IDs */ + hid_t dset_sid, dset_sid2; /* Dataspace IDs */ + hid_t attr_sid; /* Dataspace IDs */ + hid_t did; /* Dataset ID */ + hid_t attr; /*Attribute ID */ + H5S_class_t stype; /* dataspace type */ + hssize_t nelem; /* Number of elements */ + unsigned uval = 2; /* Buffer for writing to dataset */ + int val = 1; /* Buffer for writing to attribute */ + H5S_sel_type sel_type; /* Type of selection currently */ + hsize_t dims[1] = {10}; /* Dimensions for converting null dataspace to simple */ + H5S_class_t space_type; /* Type of dataspace */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Null Dataspace\n")); + + /* Create the file */ + fid = H5Fcreate(NULLFILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + sid = H5Screate(H5S_NULL); + CHECK(sid, FAIL, "H5Screate"); + + /* Check that the null dataspace actually has 0 elements */ + nelem = H5Sget_simple_extent_npoints(sid); + VERIFY(nelem, 0, "H5Sget_simple_extent_npoints"); + + /* Check that the dataspace was created with an "all" selection */ + sel_type = H5Sget_select_type(sid); + VERIFY(sel_type, H5S_SEL_ALL, "H5Sget_select_type"); + + /* Check that the null dataspace has 0 elements selected */ + nelem = H5Sget_select_npoints(sid); + VERIFY(nelem, 0, "H5Sget_select_npoints"); + + /* Change to "none" selection */ + ret = H5Sselect_none(sid); + CHECK(ret, FAIL, "H5Sselect_none"); + + /* Check that the null dataspace has 0 elements selected */ + nelem = H5Sget_select_npoints(sid); + VERIFY(nelem, 0, "H5Sget_select_npoints"); + + /* Check to be sure we can't set a hyperslab selection on a null dataspace */ + H5E_BEGIN_TRY + { + hsize_t start[1] = {0}; + hsize_t count[1] = {0}; + + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, NULL, count, NULL); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Sselect_hyperslab"); + + /* Check to be sure we can't set a point selection on a null dataspace */ + H5E_BEGIN_TRY + { + hsize_t coord[1][1]; /* Coordinates for point selection */ + + coord[0][0] = 0; + ret = H5Sselect_elements(sid, H5S_SELECT_SET, (size_t)1, (const hsize_t *)coord); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Sselect_elements"); + + /* Create first dataset */ + did = H5Dcreate2(fid, NULLDATASET, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); + + /* Write "nothing" to the dataset */ + ret = H5Dwrite(did, H5T_NATIVE_UINT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &uval); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Write "nothing" to the dataset (with type conversion :-) */ + ret = H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &val); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Try reading from the dataset (make certain our buffer is unmodified) */ + ret = H5Dread(did, H5T_NATIVE_UINT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &uval); + CHECK(ret, FAIL, "H5Dread"); + VERIFY(uval, 2, "H5Dread"); + + /* Try reading from the dataset (with type conversion :-) (make certain our buffer is unmodified) */ + ret = H5Dread(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &val); + CHECK(ret, FAIL, "H5Dread"); + VERIFY(val, 1, "H5Dread"); + + /* Create an attribute for the group */ + attr = H5Acreate2(did, NULLATTR, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Write "nothing" to the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_INT, &val); + CHECK(ret, FAIL, "H5Awrite"); + + /* Write "nothing" to the attribute (with type conversion :-) */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, &uval); + CHECK(ret, FAIL, "H5Awrite"); + + /* Try reading from the attribute (make certain our buffer is unmodified) */ + ret = H5Aread(attr, H5T_NATIVE_INT, &val); + CHECK(ret, FAIL, "H5Aread"); + VERIFY(val, 1, "H5Aread"); + + /* Try reading from the attribute (with type conversion :-) (make certain our buffer is unmodified) */ + ret = H5Aread(attr, H5T_NATIVE_UINT, &uval); + CHECK(ret, FAIL, "H5Aread"); + VERIFY(uval, 2, "H5Aread"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close the dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* Verify that we've got the right kind of dataspace */ + space_type = H5Sget_simple_extent_type(sid); + VERIFY(space_type, H5S_NULL, "H5Sget_simple_extent_type"); + + /* Convert the null dataspace to a simple dataspace */ + ret = H5Sset_extent_simple(sid, 1, dims, NULL); + CHECK(ret, FAIL, "H5Sset_extent_simple"); + + /* Verify that we've got the right kind of dataspace now */ + space_type = H5Sget_simple_extent_type(sid); + VERIFY(space_type, H5S_SIMPLE, "H5Sget_simple_extent_type"); + + /* Close the dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /*============================================ + * Reopen the file to check the dataspace + *============================================ + */ + fid = H5Fopen(NULLFILE, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* Reopen the dataset */ + did = H5Dopen2(fid, NULLDATASET, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen2"); + + /* Get the space of the dataset */ + dset_sid = H5Dget_space(did); + CHECK(dset_sid, FAIL, "H5Dget_space"); + + /* Query the NULL dataspace */ + dset_sid2 = H5Scopy(dset_sid); + CHECK(dset_sid2, FAIL, "H5Scopy"); + + /* Verify the class type of dataspace */ + stype = H5Sget_simple_extent_type(dset_sid2); + VERIFY(stype, H5S_NULL, "H5Sget_simple_extent_type"); + + /* Verify there is zero element in the dataspace */ + ret = (herr_t)H5Sget_simple_extent_npoints(dset_sid2); + VERIFY(ret, 0, "H5Sget_simple_extent_npoints"); + + /* Try reading from the dataset (make certain our buffer is unmodified) */ + ret = H5Dread(did, H5T_NATIVE_UINT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &uval); + CHECK(ret, FAIL, "H5Dread"); + VERIFY(uval, 2, "H5Dread"); + + /* Close the dataspace */ + ret = H5Sclose(dset_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(dset_sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Open the attribute for the dataset */ + attr = H5Aopen(did, NULLATTR, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); + + /* Get the space of the dataset */ + attr_sid = H5Aget_space(attr); + CHECK(attr_sid, FAIL, "H5Aget_space"); + + /* Verify the class type of dataspace */ + stype = H5Sget_simple_extent_type(attr_sid); + VERIFY(stype, H5S_NULL, "H5Sget_simple_extent_type"); + + /* Verify there is zero element in the dataspace */ + ret = (herr_t)H5Sget_simple_extent_npoints(attr_sid); + VERIFY(ret, 0, "H5Sget_simple_extent_npoints"); + + /* Close the dataspace */ + ret = H5Sclose(attr_sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Try reading from the attribute (make certain our buffer is unmodified) */ + ret = H5Aread(attr, H5T_NATIVE_INT, &val); + CHECK(ret, FAIL, "H5Aread"); + VERIFY(val, 1, "H5Aread"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close the dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_h5s_null() */ + +/**************************************************************** +** +** test_h5s_zero_dim(): Test the code for dataspace with zero dimension size +** +****************************************************************/ +static void +test_h5s_zero_dim(void) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t sid1, attr_sid; /* Dataspace ID */ + hid_t sid_chunk; /* Dataspace ID for chunked dataset */ + hid_t dset1; /* Dataset ID */ + hid_t plist_id; /* Dataset creation property list */ + hid_t attr; /* Attribute ID */ + int rank; /* Logical rank of dataspace */ + hsize_t dims1[] = {0, SPACE1_DIM2, SPACE1_DIM3}; + hsize_t max_dims[] = {SPACE1_DIM1 + 1, SPACE1_DIM2, SPACE1_DIM3}; + hsize_t extend_dims[] = {SPACE1_DIM1, SPACE1_DIM2, SPACE1_DIM3}; + hsize_t chunk_dims[] = {SPACE1_DIM1, SPACE1_DIM2 / 3, SPACE1_DIM3}; + hsize_t tdims[SPACE1_RANK]; /* Dimension array to test with */ + int wdata[SPACE1_DIM2][SPACE1_DIM3]; + int rdata[SPACE1_DIM2][SPACE1_DIM3]; + short wdata_short[SPACE1_DIM2][SPACE1_DIM3]; + short rdata_short[SPACE1_DIM2][SPACE1_DIM3]; + int wdata_real[SPACE1_DIM1][SPACE1_DIM2][SPACE1_DIM3]; + int rdata_real[SPACE1_DIM1][SPACE1_DIM2][SPACE1_DIM3]; +#ifndef NO_CHECK_SELECTION_BOUNDS + int val = 3; + hsize_t start[] = {0, 0, 0}; + hsize_t count[] = {3, 15, 13}; + hsize_t coord[1][3]; /* Coordinates for point selection */ +#endif + hssize_t nelem; /* Number of elements */ + H5S_sel_type sel_type; /* Type of selection currently */ + H5S_class_t stype; /* dataspace type */ + H5D_alloc_time_t alloc_time; /* Space allocation time */ + herr_t ret; /* Generic return value */ + unsigned int i, j, k; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Dataspace with zero dimension size\n")); + + /* Initialize the data */ + for (i = 0; i < SPACE1_DIM2; i++) + for (j = 0; j < SPACE1_DIM3; j++) { + wdata[i][j] = (int)(i + j); + rdata[i][j] = 7; + wdata_short[i][j] = (short)(i + j); + rdata_short[i][j] = 7; + } + + for (i = 0; i < SPACE1_DIM1; i++) + for (j = 0; j < SPACE1_DIM2; j++) + for (k = 0; k < SPACE1_DIM3; k++) + wdata_real[i][j][k] = (int)(i + j + k); + + /* Test with different space allocation times */ + for (alloc_time = H5D_ALLOC_TIME_EARLY; alloc_time <= H5D_ALLOC_TIME_INCR; alloc_time++) { + + /* Make sure we can create the space with the dimension size 0 (starting from v1.8.7). + * The dimension doesn't need to be unlimited. */ + dims1[0] = 0; + dims1[1] = SPACE1_DIM2; + dims1[2] = SPACE1_DIM3; + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + sid1 = H5Screate(H5S_SIMPLE); + CHECK(sid1, FAIL, "H5Screate"); + + /* SID1 has the 1st dimension size as zero. The maximal dimension will be + * the same as the dimension because of the NULL passed in. */ + ret = H5Sset_extent_simple(sid1, SPACE1_RANK, dims1, NULL); + CHECK(ret, FAIL, "H5Sset_extent_simple"); + + /* Check that the dataspace actually has 0 elements */ + nelem = H5Sget_simple_extent_npoints(sid1); + VERIFY(nelem, 0, "H5Sget_simple_extent_npoints"); + + /* Check that the dataspace was created with an "all" selection */ + sel_type = H5Sget_select_type(sid1); + VERIFY(sel_type, H5S_SEL_ALL, "H5Sget_select_type"); + + /* Check that the dataspace has 0 elements selected */ + nelem = H5Sget_select_npoints(sid1); + VERIFY(nelem, 0, "H5Sget_select_npoints"); + + /* Change to "none" selection */ + ret = H5Sselect_none(sid1); + CHECK(ret, FAIL, "H5Sselect_none"); + + /* Check that the dataspace has 0 elements selected */ + nelem = H5Sget_select_npoints(sid1); + VERIFY(nelem, 0, "H5Sget_select_npoints"); + + /* Try to select all dataspace */ + ret = H5Sselect_all(sid1); + CHECK(ret, FAIL, "H5Sselect_all"); + + /* Check that the dataspace has 0 elements selected */ + nelem = H5Sget_select_npoints(sid1); + VERIFY(nelem, 0, "H5Sget_select_npoints"); + + /* Create the dataspace for chunked dataset with the first dimension size as zero. + * The maximal dimensions are bigger than the dimensions for later expansion. */ + sid_chunk = H5Screate_simple(SPACE1_RANK, dims1, max_dims); + CHECK(sid_chunk, FAIL, "H5Screate_simple"); + + /*============================================ + * Make sure we can use 0-dimension to create + * contiguous, chunked, compact, and external + * datasets, and also attribute. + *============================================ + */ + fid1 = H5Fcreate(ZEROFILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /*===================== Contiguous dataset =======================*/ + plist_id = H5Pcreate(H5P_DATASET_CREATE); + CHECK(plist_id, FAIL, "H5Pcreate"); + + ret = H5Pset_alloc_time(plist_id, alloc_time); + CHECK(ret, FAIL, "H5Pset_alloc_time"); + + dset1 = H5Dcreate2(fid1, BASICDATASET, H5T_NATIVE_INT, sid1, H5P_DEFAULT, plist_id, H5P_DEFAULT); + CHECK(dset1, FAIL, "H5Dcreate2"); + + ret = H5Pclose(plist_id); + CHECK(ret, FAIL, "H5Pclose"); + + /* Write "nothing" to the dataset */ + ret = H5Dwrite(dset1, H5T_NATIVE_INT, sid1, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + ret = H5Fflush(fid1, H5F_SCOPE_GLOBAL); + CHECK(ret, FAIL, "H5Fflush"); + + /* Try reading from the dataset (make certain our buffer is unmodified) */ + ret = H5Dread(dset1, H5T_NATIVE_INT, sid1, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Check results */ + for (i = 0; i < SPACE1_DIM2; i++) { + for (j = 0; j < SPACE1_DIM3; j++) { + if (rdata[i][j] != 7) { + H5_FAILED(); + HDprintf("element [%d][%d] is %d but should have been 7\n", i, j, rdata[i][j]); + } + } + } + + /* Write "nothing" to the dataset (with type conversion :-) */ + ret = H5Dwrite(dset1, H5T_NATIVE_SHORT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata_short); + CHECK(ret, FAIL, "H5Dwrite"); + + ret = H5Fflush(fid1, H5F_SCOPE_GLOBAL); + CHECK(ret, FAIL, "H5Fflush"); + + /* Try reading from the dataset (make certain our buffer is unmodified) */ + ret = H5Dread(dset1, H5T_NATIVE_INT, sid1, H5S_ALL, H5P_DEFAULT, rdata_short); + CHECK(ret, FAIL, "H5Dread"); + + /* Check results */ + for (i = 0; i < SPACE1_DIM2; i++) { + for (j = 0; j < SPACE1_DIM3; j++) { + if (rdata_short[i][j] != 7) { + H5_FAILED(); + HDprintf("element [%d][%d] is %d but should have been 7\n", i, j, rdata_short[i][j]); + } + } + } +#ifndef NO_CHECK_SELECTION_BOUNDS + /* Select a hyperslab beyond its current dimension sizes, then try to write + * the data. It should fail. */ + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + H5E_BEGIN_TRY + { + ret = H5Dwrite(dset1, H5T_NATIVE_INT, H5S_ALL, sid1, H5P_DEFAULT, wdata); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Dwrite"); +#endif + /* Change to "none" selection */ + ret = H5Sselect_none(sid1); + CHECK(ret, FAIL, "H5Sselect_none"); +#ifndef NO_CHECK_SELECTION_BOUNDS + /* Select a point beyond the dimension size, then try to write the data. + * It should fail. */ + coord[0][0] = 2; + coord[0][1] = 5; + coord[0][2] = 3; + ret = H5Sselect_elements(sid1, H5S_SELECT_SET, (size_t)1, (const hsize_t *)coord); + CHECK(ret, FAIL, "H5Sselect_elements"); + + H5E_BEGIN_TRY + { + ret = H5Dwrite(dset1, H5T_NATIVE_INT, H5S_ALL, sid1, H5P_DEFAULT, &val); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Dwrite"); +#endif + /* Restore the selection to all */ + ret = H5Sselect_all(sid1); + CHECK(ret, FAIL, "H5Sselect_all"); + + ret = H5Dclose(dset1); + CHECK(ret, FAIL, "H5Dclose"); + + /*=================== Chunked dataset ====================*/ + plist_id = H5Pcreate(H5P_DATASET_CREATE); + CHECK(plist_id, FAIL, "H5Pcreate"); + + ret = H5Pset_chunk(plist_id, SPACE1_RANK, chunk_dims); + CHECK(ret, FAIL, "H5Pset_chunk"); + + /* ret = H5Pset_alloc_time(plist_id, alloc_time); */ + /* CHECK(ret, FAIL, "H5Pset_alloc_time"); */ + + dset1 = + H5Dcreate2(fid1, BASICDATASET1, H5T_NATIVE_INT, sid_chunk, H5P_DEFAULT, plist_id, H5P_DEFAULT); + CHECK(dset1, FAIL, "H5Dcreate2"); + + /* Write "nothing" to the dataset */ + ret = H5Dwrite(dset1, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + ret = H5Fflush(fid1, H5F_SCOPE_GLOBAL); + CHECK(ret, FAIL, "H5Fflush"); + + /* Try reading from the dataset (make certain our buffer is unmodified) */ + ret = H5Dread(dset1, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Check results */ + for (i = 0; i < SPACE1_DIM2; i++) + for (j = 0; j < SPACE1_DIM3; j++) { + if (rdata[i][j] != 7) { + H5_FAILED(); + HDprintf("element [%d][%d] is %d but should have been 7\n", i, j, rdata[i][j]); + } + } + + /* Now extend the dataset to SPACE1_DIM1*SPACE1_DIM2*SPACE1_DIM3 and make sure + * we can write data to it */ + extend_dims[0] = SPACE1_DIM1; + ret = H5Dset_extent(dset1, extend_dims); + CHECK(ret, FAIL, "H5Dset_extent"); + + ret = H5Dwrite(dset1, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata_real); + CHECK(ret, FAIL, "H5Dwrite"); + + ret = H5Fflush(fid1, H5F_SCOPE_GLOBAL); + CHECK(ret, FAIL, "H5Fflush"); + + ret = H5Dread(dset1, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata_real); + CHECK(ret, FAIL, "H5Dread"); + + /* Check results */ + for (i = 0; i < SPACE1_DIM1; i++) { + for (j = 0; j < SPACE1_DIM2; j++) { + for (k = 0; k < SPACE1_DIM3; k++) { + if (rdata_real[i][j][k] != wdata_real[i][j][k]) { + H5_FAILED(); + HDprintf("element [%d][%d][%d] is %d but should have been %d\n", i, j, k, + rdata_real[i][j][k], wdata_real[i][j][k]); + } + } + } + } + + /* Now shrink the first dimension size of the dataset to 0 and make sure no data is in it */ + extend_dims[0] = 0; + ret = H5Dset_extent(dset1, extend_dims); + CHECK(ret, FAIL, "H5Dset_extent"); + + ret = H5Fflush(fid1, H5F_SCOPE_GLOBAL); + CHECK(ret, FAIL, "H5Fflush"); + + /* Try reading from the dataset (make certain our buffer is unmodified) */ + ret = H5Dread(dset1, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Check results */ + for (i = 0; i < SPACE1_DIM2; i++) + for (j = 0; j < SPACE1_DIM3; j++) { + if (rdata[i][j] != 7) { + H5_FAILED(); + HDprintf("element [%d][%d] is %d but should have been 7\n", i, j, rdata[i][j]); + } + } +#ifndef NO_CHECK_SELECTION_BOUNDS + /* Now extend the first dimension size of the dataset to SPACE1_DIM1*3 past the maximal size. + * It is supposed to fail. */ + extend_dims[0] = SPACE1_DIM1 * 3; + H5E_BEGIN_TRY + { + ret = H5Dset_extent(dset1, extend_dims); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Dset_extent"); +#endif + ret = H5Pclose(plist_id); + CHECK(ret, FAIL, "H5Pclose"); + + ret = H5Dclose(dset1); + CHECK(ret, FAIL, "H5Dclose"); + + /*=================== Compact dataset =====================*/ + plist_id = H5Pcreate(H5P_DATASET_CREATE); + CHECK(plist_id, FAIL, "H5Pcreate"); + + ret = H5Pset_layout(plist_id, H5D_COMPACT); + CHECK(ret, FAIL, "H5Pset_layout"); + + /* Don't set the allocation time for compact storage datasets (must be early) */ + + dset1 = H5Dcreate2(fid1, BASICDATASET2, H5T_NATIVE_INT, sid1, H5P_DEFAULT, plist_id, H5P_DEFAULT); + CHECK(dset1, FAIL, "H5Dcreate2"); + + /* Write "nothing" to the dataset */ + ret = H5Dwrite(dset1, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + ret = H5Fflush(fid1, H5F_SCOPE_GLOBAL); + CHECK(ret, FAIL, "H5Fflush"); + + /* Try reading from the dataset (make certain our buffer is unmodified) */ + ret = H5Dread(dset1, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Check results */ + for (i = 0; i < SPACE1_DIM2; i++) + for (j = 0; j < SPACE1_DIM3; j++) { + if (rdata[i][j] != 7) { + H5_FAILED(); + HDprintf("element [%d][%d] is %d but should have been 7\n", i, j, rdata[i][j]); + } + } + + ret = H5Pclose(plist_id); + CHECK(ret, FAIL, "H5Pclose"); + + ret = H5Dclose(dset1); + CHECK(ret, FAIL, "H5Dclose"); + + /*=========== Contiguous dataset with external storage ============*/ + plist_id = H5Pcreate(H5P_DATASET_CREATE); + CHECK(plist_id, FAIL, "H5Pcreate"); + + /* Change the DCPL for contiguous layout with external storage. The size of the reserved + * space in the external file is the size of the dataset (zero because one dimension size is zero). + * There's no need to clean up the external file since the library doesn't create it + * until the data is written to it. */ + ret = H5Pset_external(plist_id, EXTFILE_NAME, (off_t)0, (hsize_t)0); + CHECK(ret, FAIL, "H5Pset_external"); + + ret = H5Pset_alloc_time(plist_id, alloc_time); + CHECK(ret, FAIL, "H5Pset_alloc_time"); + + dset1 = H5Dcreate2(fid1, BASICDATASET3, H5T_NATIVE_INT, sid1, H5P_DEFAULT, plist_id, H5P_DEFAULT); + CHECK(dset1, FAIL, "H5Dcreate2"); + + /* Write "nothing" to the dataset */ + ret = H5Dwrite(dset1, H5T_NATIVE_INT, sid1, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + ret = H5Fflush(fid1, H5F_SCOPE_GLOBAL); + CHECK(ret, FAIL, "H5Fflush"); + + /* Try reading from the dataset (make certain our buffer is unmodified) */ + ret = H5Dread(dset1, H5T_NATIVE_INT, sid1, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Check results */ + for (i = 0; i < SPACE1_DIM2; i++) { + for (j = 0; j < SPACE1_DIM3; j++) { + if (rdata[i][j] != 7) { + H5_FAILED(); + HDprintf("element [%d][%d] is %d but should have been 7\n", i, j, rdata[i][j]); + } + } + } + + ret = H5Pclose(plist_id); + CHECK(ret, FAIL, "H5Pclose"); + + ret = H5Dclose(dset1); + CHECK(ret, FAIL, "H5Dclose"); + + /*=============== Create an attribute for the file ================*/ + attr = H5Acreate2(fid1, NULLATTR, H5T_NATIVE_INT, sid1, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Acreate2"); + + /* Write "nothing" to the attribute */ + ret = H5Awrite(attr, H5T_NATIVE_INT, wdata); + CHECK(ret, FAIL, "H5Awrite"); + + ret = H5Fflush(fid1, H5F_SCOPE_GLOBAL); + CHECK(ret, FAIL, "H5Fflush"); + + /* Try reading from the attribute (make certain our buffer is unmodified) */ + ret = H5Aread(attr, H5T_NATIVE_INT, rdata); + CHECK(ret, FAIL, "H5Aread"); + + /* Check results */ + for (i = 0; i < SPACE1_DIM2; i++) { + for (j = 0; j < SPACE1_DIM3; j++) { + if (rdata[i][j] != 7) { + H5_FAILED(); + HDprintf("element [%d][%d] is %d but should have been 7\n", i, j, rdata[i][j]); + } + } + } + + /* Write "nothing" to the attribute (with type conversion :-) */ + ret = H5Awrite(attr, H5T_NATIVE_SHORT, wdata_short); + CHECK(ret, FAIL, "H5Awrite"); + + ret = H5Fflush(fid1, H5F_SCOPE_GLOBAL); + CHECK(ret, FAIL, "H5Fflush"); + + /* Try reading from the attribute (with type conversion :-) (make certain our buffer is unmodified) */ + ret = H5Aread(attr, H5T_NATIVE_SHORT, rdata_short); + CHECK(ret, FAIL, "H5Aread"); + + /* Check results */ + for (i = 0; i < SPACE1_DIM2; i++) { + for (j = 0; j < SPACE1_DIM3; j++) { + if (rdata_short[i][j] != 7) { + H5_FAILED(); + HDprintf("element [%d][%d] is %d but should have been 7\n", i, j, rdata_short[i][j]); + } + } + } + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /*=============================================================== + * Extend the dimension to make it a normal dataspace (3x15x13). + * Verify that data can be written to and read from the chunked + * dataset now. + *=============================================================== + */ + dims1[0] = SPACE1_DIM1; + ret = H5Sset_extent_simple(sid_chunk, SPACE1_RANK, dims1, max_dims); + CHECK(ret, FAIL, "H5Sset_extent_simple"); + + nelem = H5Sget_simple_extent_npoints(sid_chunk); + CHECK(nelem, FAIL, "H5Sget_simple_extent_npoints"); + VERIFY(nelem, SPACE1_DIM1 * SPACE1_DIM2 * SPACE1_DIM3, "H5Sget_simple_extent_npoints"); + + rank = H5Sget_simple_extent_ndims(sid_chunk); + CHECK(rank, FAIL, "H5Sget_simple_extent_ndims"); + VERIFY(rank, SPACE1_RANK, "H5Sget_simple_extent_ndims"); + + rank = H5Sget_simple_extent_dims(sid_chunk, tdims, NULL); + CHECK(rank, FAIL, "H5Sget_simple_extent_dims"); + VERIFY(HDmemcmp(tdims, dims1, SPACE1_RANK * sizeof(hsize_t)), 0, "H5Sget_simple_extent_dims"); + + /* Set it to chunked dataset */ + plist_id = H5Pcreate(H5P_DATASET_CREATE); + CHECK(plist_id, FAIL, "H5Pcreate"); + + ret = H5Pset_chunk(plist_id, SPACE1_RANK, chunk_dims); + CHECK(ret, FAIL, "H5Pset_chunk"); + + ret = H5Pset_alloc_time(plist_id, alloc_time); + CHECK(ret, FAIL, "H5Pset_alloc_time"); + + dset1 = + H5Dcreate2(fid1, BASICDATASET4, H5T_NATIVE_INT, sid_chunk, H5P_DEFAULT, plist_id, H5P_DEFAULT); + CHECK(dset1, FAIL, "H5Dcreate2"); + + ret = H5Dwrite(dset1, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata_real); + CHECK(ret, FAIL, "H5Dwrite"); + + ret = H5Fflush(fid1, H5F_SCOPE_GLOBAL); + CHECK(ret, FAIL, "H5Fflush"); + + ret = H5Dread(dset1, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata_real); + CHECK(ret, FAIL, "H5Dread"); + + /* Check results */ + for (i = 0; i < SPACE1_DIM1; i++) { + for (j = 0; j < SPACE1_DIM2; j++) { + for (k = 0; k < SPACE1_DIM3; k++) { + if (rdata_real[i][j][k] != wdata_real[i][j][k]) { + H5_FAILED(); + HDprintf("element [%d][%d][%d] is %d but should have been %d\n", i, j, k, + rdata_real[i][j][k], wdata_real[i][j][k]); + } + } + } + } + + ret = H5Pclose(plist_id); + CHECK(ret, FAIL, "H5Pclose"); + + ret = H5Dclose(dset1); + CHECK(ret, FAIL, "H5Dclose"); + + /* Change the dimensions to make them zero size again (0x0x0). Verify that + * no element is in the dataspace. */ + dims1[0] = dims1[1] = dims1[2] = 0; + ret = H5Sset_extent_simple(sid_chunk, SPACE1_RANK, dims1, NULL); + CHECK(ret, FAIL, "H5Sset_extent_simple"); + + /* Check that the dataspace actually has 0 elements */ + nelem = H5Sget_simple_extent_npoints(sid_chunk); + VERIFY(nelem, 0, "H5Sget_simple_extent_npoints"); + + /* Check that the dataspace was created with an "all" selection */ + sel_type = H5Sget_select_type(sid_chunk); + VERIFY(sel_type, H5S_SEL_ALL, "H5Sget_select_type"); + + /* Check that the dataspace has 0 elements selected */ + nelem = H5Sget_select_npoints(sid_chunk); + VERIFY(nelem, 0, "H5Sget_select_npoints"); + + /* Change to "none" selection */ + ret = H5Sselect_none(sid_chunk); + CHECK(ret, FAIL, "H5Sselect_none"); + + /* Check that the dataspace has 0 elements selected */ + nelem = H5Sget_select_npoints(sid_chunk); + VERIFY(nelem, 0, "H5Sget_select_npoints"); + + ret = H5Sclose(sid_chunk); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /*============================================ + * Reopen the file to check the dataspace + *============================================ + */ + fid1 = H5Fopen(ZEROFILE, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Reopen the chunked dataset */ + dset1 = H5Dopen2(fid1, BASICDATASET1, H5P_DEFAULT); + CHECK(dset1, FAIL, "H5Dopen2"); + + /* Get the space of the dataset and query it */ + sid1 = H5Dget_space(dset1); + CHECK(sid1, FAIL, "H5Dget_space"); + + /* Verify the class type of dataspace */ + stype = H5Sget_simple_extent_type(sid1); + VERIFY(stype, H5S_SIMPLE, "H5Sget_simple_extent_type"); + + /* Verify there is zero element in the dataspace */ + nelem = H5Sget_simple_extent_npoints(sid1); + VERIFY(nelem, 0, "H5Sget_simple_extent_npoints"); + + /* Verify the dimension sizes are correct */ + rank = H5Sget_simple_extent_dims(sid1, tdims, NULL); + CHECK(rank, FAIL, "H5Sget_simple_extent_dims"); + VERIFY(tdims[0], 0, "H5Sget_simple_extent_dims"); + VERIFY(tdims[1], SPACE1_DIM2, "H5Sget_simple_extent_dims"); + VERIFY(tdims[2], SPACE1_DIM3, "H5Sget_simple_extent_dims"); + + /* Try reading from the dataset (make certain our buffer is unmodified) */ + ret = H5Dread(dset1, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Check results */ + for (i = 0; i < SPACE1_DIM2; i++) { + for (j = 0; j < SPACE1_DIM3; j++) { + if (rdata[i][j] != 7) { + H5_FAILED(); + HDprintf("element [%d][%d] is %d but should have been 7\n", i, j, rdata[i][j]); + } + } + } + + /* Close the dataset and its dataspace */ + ret = H5Dclose(dset1); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Open the attribute for the file */ + attr = H5Aopen(fid1, NULLATTR, H5P_DEFAULT); + CHECK(attr, FAIL, "H5Aopen"); + + /* Get the space of the dataset */ + attr_sid = H5Aget_space(attr); + CHECK(attr_sid, FAIL, "H5Aget_space"); + + /* Verify the class type of dataspace */ + stype = H5Sget_simple_extent_type(attr_sid); + VERIFY(stype, H5S_SIMPLE, "H5Sget_simple_extent_type"); + + /* Verify there is zero element in the dataspace */ + nelem = H5Sget_simple_extent_npoints(attr_sid); + VERIFY(nelem, 0, "H5Sget_simple_extent_npoints"); + + /* Try reading from the attribute (make certain our buffer is unmodified) */ + ret = H5Aread(attr, H5T_NATIVE_SHORT, rdata_short); + CHECK(ret, FAIL, "H5Aread"); + + /* Check results */ + for (i = 0; i < SPACE1_DIM2; i++) { + for (j = 0; j < SPACE1_DIM3; j++) { + if (rdata_short[i][j] != 7) { + H5_FAILED(); + HDprintf("element [%d][%d] is %d but should have been 7\n", i, j, rdata_short[i][j]); + } + } + } + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close the dataspace */ + ret = H5Sclose(attr_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + } /* end for */ +} /* test_h5s_zero_dim() */ + +/**************************************************************** +** +** test_h5s_encode(): Test H5S (dataspace) encoding and decoding. +** +** Note: See "RFC: H5Sencode/H5Sdecode Format Change". +** +****************************************************************/ +static void +test_h5s_encode(H5F_libver_t low, H5F_libver_t high) +{ + hid_t sid1, sid2, sid3; /* Dataspace ID */ + hid_t decoded_sid1, decoded_sid2, decoded_sid3; + int rank; /* Logical rank of dataspace */ + hid_t fapl = -1; /* File access property list ID */ + hsize_t dims1[] = {SPACE1_DIM1, SPACE1_DIM2, SPACE1_DIM3}; + size_t sbuf_size = 0, null_size = 0, scalar_size = 0; + unsigned char *sbuf = NULL, *null_sbuf = NULL, *scalar_buf = NULL; + hsize_t tdims[4]; /* Dimension array to test with */ + hssize_t n; /* Number of dataspace elements */ + hsize_t start[] = {0, 0, 0}; + hsize_t stride[] = {2, 5, 3}; + hsize_t count[] = {2, 2, 2}; + hsize_t block[] = {1, 3, 1}; + H5S_sel_type sel_type; + H5S_class_t space_type; + hssize_t nblocks; + hid_t ret_id; /* Generic hid_t return value */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Dataspace Encoding and Decoding\n")); + + /*------------------------------------------------------------------------- + * Test encoding and decoding of simple dataspace and hyperslab selection. + *------------------------------------------------------------------------- + */ + + /* Create the file access property list */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + + /* Set low/high bounds in the fapl */ + ret = H5Pset_libver_bounds(fapl, low, high); + CHECK(ret, FAIL, "H5Pset_libver_bounds"); + + /* Create the dataspace */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Set the hyperslab selection */ + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Encode simple dataspace in a buffer with the fapl setting */ + ret = H5Sencode2(sid1, NULL, &sbuf_size, fapl); + CHECK(ret, FAIL, "H5Sencode2"); + + if (sbuf_size > 0) { + sbuf = (unsigned char *)HDcalloc((size_t)1, sbuf_size); + CHECK_PTR(sbuf, "HDcalloc"); + } + + /* Try decoding bogus buffer */ + H5E_BEGIN_TRY + { + ret_id = H5Sdecode(sbuf); + } + H5E_END_TRY; + VERIFY(ret_id, FAIL, "H5Sdecode"); + + /* Encode the simple dataspace in a buffer with the fapl setting */ + ret = H5Sencode2(sid1, sbuf, &sbuf_size, fapl); + CHECK(ret, FAIL, "H5Sencode"); + + /* Decode from the dataspace buffer and return an object handle */ + decoded_sid1 = H5Sdecode(sbuf); + CHECK(decoded_sid1, FAIL, "H5Sdecode"); + + /* Verify the decoded dataspace */ + n = H5Sget_simple_extent_npoints(decoded_sid1); + CHECK(n, FAIL, "H5Sget_simple_extent_npoints"); + VERIFY(n, SPACE1_DIM1 * SPACE1_DIM2 * SPACE1_DIM3, "H5Sget_simple_extent_npoints"); + + /* Retrieve and verify the dataspace rank */ + rank = H5Sget_simple_extent_ndims(decoded_sid1); + CHECK(rank, FAIL, "H5Sget_simple_extent_ndims"); + VERIFY(rank, SPACE1_RANK, "H5Sget_simple_extent_ndims"); + + /* Retrieve and verify the dataspace dimensions */ + rank = H5Sget_simple_extent_dims(decoded_sid1, tdims, NULL); + CHECK(rank, FAIL, "H5Sget_simple_extent_dims"); + VERIFY(HDmemcmp(tdims, dims1, SPACE1_RANK * sizeof(hsize_t)), 0, "H5Sget_simple_extent_dims"); + + /* Verify the type of dataspace selection */ + sel_type = H5Sget_select_type(decoded_sid1); + VERIFY(sel_type, H5S_SEL_HYPERSLABS, "H5Sget_select_type"); + + /* Verify the number of hyperslab blocks */ + nblocks = H5Sget_select_hyper_nblocks(decoded_sid1); + VERIFY(nblocks, 2 * 2 * 2, "H5Sget_select_hyper_nblocks"); + + /* Close the dataspaces */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(decoded_sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /*------------------------------------------------------------------------- + * Test encoding and decoding of null dataspace. + *------------------------------------------------------------------------- + */ + sid2 = H5Screate(H5S_NULL); + CHECK(sid2, FAIL, "H5Screate"); + + /* Encode null dataspace in a buffer */ + ret = H5Sencode2(sid2, NULL, &null_size, fapl); + CHECK(ret, FAIL, "H5Sencode"); + + if (null_size > 0) { + null_sbuf = (unsigned char *)HDcalloc((size_t)1, null_size); + CHECK_PTR(null_sbuf, "HDcalloc"); + } + + /* Encode the null dataspace in the buffer */ + ret = H5Sencode2(sid2, null_sbuf, &null_size, fapl); + CHECK(ret, FAIL, "H5Sencode2"); + + /* Decode from the dataspace buffer and return an object handle */ + decoded_sid2 = H5Sdecode(null_sbuf); + CHECK(decoded_sid2, FAIL, "H5Sdecode"); + + /* Verify the decoded dataspace type */ + space_type = H5Sget_simple_extent_type(decoded_sid2); + VERIFY(space_type, H5S_NULL, "H5Sget_simple_extent_type"); + + /* Close the dataspaces */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(decoded_sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /*------------------------------------------------------------------------- + * Test encoding and decoding of scalar dataspace. + *------------------------------------------------------------------------- + */ + /* Create scalar dataspace */ + sid3 = H5Screate(H5S_SCALAR); + CHECK(sid3, FAIL, "H5Screate_simple"); + + /* Encode scalar dataspace in a buffer */ + ret = H5Sencode2(sid3, NULL, &scalar_size, fapl); + CHECK(ret, FAIL, "H5Sencode"); + + if (scalar_size > 0) { + scalar_buf = (unsigned char *)HDcalloc((size_t)1, scalar_size); + CHECK_PTR(scalar_buf, "HDcalloc"); + } + + /* Encode the scalar dataspace in the buffer */ + ret = H5Sencode2(sid3, scalar_buf, &scalar_size, fapl); + CHECK(ret, FAIL, "H5Sencode2"); + + /* Decode from the dataspace buffer and return an object handle */ + decoded_sid3 = H5Sdecode(scalar_buf); + CHECK(decoded_sid3, FAIL, "H5Sdecode"); + + /* Verify extent type */ + space_type = H5Sget_simple_extent_type(decoded_sid3); + VERIFY(space_type, H5S_SCALAR, "H5Sget_simple_extent_type"); + + /* Verify decoded dataspace */ + n = H5Sget_simple_extent_npoints(decoded_sid3); + CHECK(n, FAIL, "H5Sget_simple_extent_npoints"); + VERIFY(n, 1, "H5Sget_simple_extent_npoints"); + + /* Retrieve and verify the dataspace rank */ + rank = H5Sget_simple_extent_ndims(decoded_sid3); + CHECK(rank, FAIL, "H5Sget_simple_extent_ndims"); + VERIFY(rank, 0, "H5Sget_simple_extent_ndims"); + + /* Close the dataspaces */ + ret = H5Sclose(sid3); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(decoded_sid3); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close the file access property list */ + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Release resources */ + if (sbuf) + HDfree(sbuf); + if (null_sbuf) + HDfree(null_sbuf); + if (scalar_buf) + HDfree(scalar_buf); +} /* test_h5s_encode() */ + +#ifndef H5_NO_DEPRECATED_SYMBOLS + +/**************************************************************** +** +** test_h5s_encode(): Test H5S (dataspace) encoding and decoding. +** +****************************************************************/ +static void +test_h5s_encode1(void) +{ + hid_t sid1, sid2, sid3; /* Dataspace ID */ + hid_t decoded_sid1, decoded_sid2, decoded_sid3; + int rank; /* Logical rank of dataspace */ + hsize_t dims1[] = {SPACE1_DIM1, SPACE1_DIM2, SPACE1_DIM3}; + size_t sbuf_size = 0, null_size = 0, scalar_size = 0; + unsigned char *sbuf = NULL, *null_sbuf = NULL, *scalar_buf = NULL; + hsize_t tdims[4]; /* Dimension array to test with */ + hssize_t n; /* Number of dataspace elements */ + hsize_t start[] = {0, 0, 0}; + hsize_t stride[] = {2, 5, 3}; + hsize_t count[] = {2, 2, 2}; + hsize_t block[] = {1, 3, 1}; + H5S_sel_type sel_type; + H5S_class_t space_type; + hssize_t nblocks; + hid_t ret_id; /* Generic hid_t return value */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Dataspace Encoding (H5Sencode1) and Decoding\n")); + + /*------------------------------------------------------------------------- + * Test encoding and decoding of simple dataspace and hyperslab selection. + *------------------------------------------------------------------------- + */ + /* Create the dataspace */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Set the hyperslab selection */ + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Encode simple dataspace in a buffer with the fapl setting */ + ret = H5Sencode1(sid1, NULL, &sbuf_size); + CHECK(ret, FAIL, "H5Sencode2"); + + if (sbuf_size > 0) { + sbuf = (unsigned char *)HDcalloc((size_t)1, sbuf_size); + CHECK_PTR(sbuf, "HDcalloc"); + } + + /* Try decoding bogus buffer */ + H5E_BEGIN_TRY + { + ret_id = H5Sdecode(sbuf); + } + H5E_END_TRY; + VERIFY(ret_id, FAIL, "H5Sdecode"); + + /* Encode the simple dataspace in a buffer */ + ret = H5Sencode1(sid1, sbuf, &sbuf_size); + CHECK(ret, FAIL, "H5Sencode"); + + /* Decode from the dataspace buffer and return an object handle */ + decoded_sid1 = H5Sdecode(sbuf); + CHECK(decoded_sid1, FAIL, "H5Sdecode"); + + /* Verify the decoded dataspace */ + n = H5Sget_simple_extent_npoints(decoded_sid1); + CHECK(n, FAIL, "H5Sget_simple_extent_npoints"); + VERIFY(n, SPACE1_DIM1 * SPACE1_DIM2 * SPACE1_DIM3, "H5Sget_simple_extent_npoints"); + + /* Retrieve and verify the dataspace rank */ + rank = H5Sget_simple_extent_ndims(decoded_sid1); + CHECK(rank, FAIL, "H5Sget_simple_extent_ndims"); + VERIFY(rank, SPACE1_RANK, "H5Sget_simple_extent_ndims"); + + /* Retrieve and verify the dataspace dimensions */ + rank = H5Sget_simple_extent_dims(decoded_sid1, tdims, NULL); + CHECK(rank, FAIL, "H5Sget_simple_extent_dims"); + VERIFY(HDmemcmp(tdims, dims1, SPACE1_RANK * sizeof(hsize_t)), 0, "H5Sget_simple_extent_dims"); + + /* Verify the type of dataspace selection */ + sel_type = H5Sget_select_type(decoded_sid1); + VERIFY(sel_type, H5S_SEL_HYPERSLABS, "H5Sget_select_type"); + + /* Verify the number of hyperslab blocks */ + nblocks = H5Sget_select_hyper_nblocks(decoded_sid1); + VERIFY(nblocks, 2 * 2 * 2, "H5Sget_select_hyper_nblocks"); + + /* Close the dataspaces */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(decoded_sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /*------------------------------------------------------------------------- + * Test encoding and decoding of null dataspace. + *------------------------------------------------------------------------- + */ + sid2 = H5Screate(H5S_NULL); + CHECK(sid2, FAIL, "H5Screate"); + + /* Encode null dataspace in a buffer */ + ret = H5Sencode1(sid2, NULL, &null_size); + CHECK(ret, FAIL, "H5Sencode"); + + if (null_size > 0) { + null_sbuf = (unsigned char *)HDcalloc((size_t)1, null_size); + CHECK_PTR(null_sbuf, "HDcalloc"); + } + + /* Encode the null dataspace in the buffer */ + ret = H5Sencode1(sid2, null_sbuf, &null_size); + CHECK(ret, FAIL, "H5Sencode2"); + + /* Decode from the dataspace buffer and return an object handle */ + decoded_sid2 = H5Sdecode(null_sbuf); + CHECK(decoded_sid2, FAIL, "H5Sdecode"); + + /* Verify the decoded dataspace type */ + space_type = H5Sget_simple_extent_type(decoded_sid2); + VERIFY(space_type, H5S_NULL, "H5Sget_simple_extent_type"); + + /* Close the dataspaces */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(decoded_sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /*------------------------------------------------------------------------- + * Test encoding and decoding of scalar dataspace. + *------------------------------------------------------------------------- + */ + /* Create scalar dataspace */ + sid3 = H5Screate(H5S_SCALAR); + CHECK(sid3, FAIL, "H5Screate"); + + /* Encode scalar dataspace in a buffer */ + ret = H5Sencode1(sid3, NULL, &scalar_size); + CHECK(ret, FAIL, "H5Sencode"); + + if (scalar_size > 0) { + scalar_buf = (unsigned char *)HDcalloc((size_t)1, scalar_size); + CHECK_PTR(scalar_buf, "HDcalloc"); + } + + /* Encode the scalar dataspace in the buffer */ + ret = H5Sencode1(sid3, scalar_buf, &scalar_size); + CHECK(ret, FAIL, "H5Sencode2"); + + /* Decode from the dataspace buffer and return an object handle */ + decoded_sid3 = H5Sdecode(scalar_buf); + CHECK(decoded_sid3, FAIL, "H5Sdecode"); + + /* Verify extent type */ + space_type = H5Sget_simple_extent_type(decoded_sid3); + VERIFY(space_type, H5S_SCALAR, "H5Sget_simple_extent_type"); + + /* Verify decoded dataspace */ + n = H5Sget_simple_extent_npoints(decoded_sid3); + CHECK(n, FAIL, "H5Sget_simple_extent_npoints"); + VERIFY(n, 1, "H5Sget_simple_extent_npoints"); + + /* Retrieve and verify the dataspace rank */ + rank = H5Sget_simple_extent_ndims(decoded_sid3); + CHECK(rank, FAIL, "H5Sget_simple_extent_ndims"); + VERIFY(rank, 0, "H5Sget_simple_extent_ndims"); + + /* Close the dataspaces */ + ret = H5Sclose(sid3); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(decoded_sid3); + CHECK(ret, FAIL, "H5Sclose"); + + /* Release resources */ + if (sbuf) + HDfree(sbuf); + if (null_sbuf) + HDfree(null_sbuf); + if (scalar_buf) + HDfree(scalar_buf); +} /* test_h5s_encode1() */ + +#endif /* H5_NO_DEPRECATED_SYMBOLS */ + +/**************************************************************** +** +** test_h5s_check_encoding(): +** This is the helper routine to verify that H5Sencode2() +** works as specified in the RFC for the library format setting +** in the file access property list. +** See "RFC: H5Sencode/H5Sdeocde Format Change". +** +** This routine is used by: +** test_h5s_encode_regular_hyper() +** test_h5s_encode_irregular_hyper() +** test_h5s_encode_points() +** +****************************************************************/ +static herr_t +test_h5s_check_encoding(hid_t in_fapl, hid_t in_sid, uint32_t expected_version, uint8_t expected_enc_size, + hbool_t expected_to_fail) +{ + char *buf = NULL; /* Pointer to the encoded buffer */ + size_t buf_size; /* Size of the encoded buffer */ + hid_t d_sid = -1; /* The decoded dataspace ID */ + htri_t check; + hsize_t in_low_bounds[1]; /* The low bounds for the selection for in_sid */ + hsize_t in_high_bounds[1]; /* The high bounds for the selection for in_sid */ + hsize_t d_low_bounds[1]; /* The low bounds for the selection for d_sid */ + hsize_t d_high_bounds[1]; /* The high bounds for the selection for d_sid */ + herr_t ret; /* Return value */ + + /* Get buffer size for encoding with the format setting in in_fapl */ + H5E_BEGIN_TRY + { + ret = H5Sencode2(in_sid, NULL, &buf_size, in_fapl); + } + H5E_END_TRY + + if (expected_to_fail) { + VERIFY(ret, FAIL, "H5Screate_simple"); + } + else { + + CHECK(ret, FAIL, "H5Sencode2"); + + /* Allocate the buffer for encoding */ + buf = (char *)HDmalloc(buf_size); + CHECK_PTR(buf, "HDmalloc"); + + /* Encode according to the setting in in_fapl */ + ret = H5Sencode2(in_sid, buf, &buf_size, in_fapl); + CHECK(ret, FAIL, "H5Sencode2"); + + /* Decode the buffer */ + d_sid = H5Sdecode(buf); + CHECK(d_sid, FAIL, "H5Sdecode"); + + /* Verify the number of selected points for in_sid and d_sid */ + VERIFY(H5Sget_select_npoints(in_sid), H5Sget_select_npoints(d_sid), "Compare npoints"); + + /* Verify if the two dataspace selections (in_sid, d_sid) are the same shape */ + check = H5Sselect_shape_same(in_sid, d_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* Compare the starting/ending coordinates of the bounding box for in_sid and d_sid */ + ret = H5Sget_select_bounds(in_sid, in_low_bounds, in_high_bounds); + CHECK(ret, FAIL, "H5Sget_select_bounds"); + ret = H5Sget_select_bounds(d_sid, d_low_bounds, d_high_bounds); + CHECK(ret, FAIL, "H5Sget_select_bounds"); + VERIFY(in_low_bounds[0], d_low_bounds[0], "Compare selection low bounds"); + VERIFY(in_high_bounds[0], d_high_bounds[0], "Compare selection high bounds"); + + /* + * See "RFC: H5Sencode/H5Sdeocde Format Change" for the verification of: + * H5S_SEL_POINTS: + * --the expected version for point selection info + * --the expected encoded size (version 2 points selection info) + * H5S_SEL_HYPERSLABS: + * --the expected version for hyperslab selection info + * --the expected encoded size (version 3 hyperslab selection info) + */ + + if (H5Sget_select_type(in_sid) == H5S_SEL_POINTS) { + + /* Verify the version */ + VERIFY((uint32_t)buf[35], expected_version, "Version for point selection"); + + /* Verify the encoded size for version 2 */ + if (expected_version == 2) + VERIFY((uint8_t)buf[39], expected_enc_size, "Encoded size of point selection info"); + } + + if (H5Sget_select_type(in_sid) == H5S_SEL_HYPERSLABS) { + + /* Verify the version */ + VERIFY((uint32_t)buf[35], expected_version, "Version for hyperslab selection info"); + + /* Verify the encoded size for version 3 */ + if (expected_version == 3) + VERIFY((uint8_t)buf[40], expected_enc_size, "Encoded size of selection info"); + + } /* hyperslab selection */ + + ret = H5Sclose(d_sid); + CHECK(ret, FAIL, "H5Sclose"); + if (buf) + HDfree(buf); + } + + return (0); + +} /* test_h5s_check_encoding */ + +/**************************************************************** +** +** test_h5s_encode_regular_hyper(): +** This test verifies that H5Sencode2() works as specified in +** the RFC for regular hyperslabs. +** See "RFC: H5Sencode/H5Sdeocde Format Change". +** +****************************************************************/ +static void +test_h5s_encode_regular_hyper(H5F_libver_t low, H5F_libver_t high) +{ + hid_t fapl = -1; /* File access property list ID */ + hid_t sid = -1; /* Dataspace ID */ + hsize_t numparticles = 8388608; /* Used to calculate dimension size */ + unsigned num_dsets = 513; /* Used to calculate dimension size */ + hsize_t total_particles = numparticles * num_dsets; + hsize_t vdsdims[1] = {total_particles}; /* Dimension size */ + hsize_t start, stride, count, block; /* Selection info */ + unsigned config; /* Testing configuration */ + unsigned unlim; /* H5S_UNLIMITED setting or not */ + herr_t ret; /* Generic return value */ + uint32_t expected_version = 0; /* Expected version for selection info */ + uint8_t expected_enc_size = 0; /* Expected encoded size for selection info */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Dataspace encoding of regular hyperslabs\n")); + + /* Create the file access property list */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + + /* Set the low/high bounds in the fapl */ + ret = H5Pset_libver_bounds(fapl, low, high); + CHECK(ret, FAIL, "H5Pset_libver_bounds"); + + /* Create the dataspace */ + sid = H5Screate_simple(1, vdsdims, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Testing with each configuration */ + for (config = CONFIG_16; config <= CONFIG_32; config++) { + hbool_t expected_to_fail = FALSE; + + /* Testing with unlimited or not */ + for (unlim = 0; unlim <= 1; unlim++) { + start = 0; + count = unlim ? H5S_UNLIMITED : 2; + + if ((high <= H5F_LIBVER_V18) && (unlim || config == CONFIG_32)) + expected_to_fail = TRUE; + + if (low >= H5F_LIBVER_V112) + expected_version = 3; + else if (config == CONFIG_16 && !unlim) + expected_version = 1; + else + expected_version = 2; + + /* test 1 */ + switch (config) { + case CONFIG_16: + stride = POWER16 - 1; + block = 4; + expected_enc_size = (uint8_t)(expected_version == 3 ? 2 : 4); + break; + case CONFIG_32: + stride = POWER32 - 1; + block = 4; + expected_enc_size = (uint8_t)(expected_version == 3 ? 4 : 8); + + break; + default: + HDassert(0); + break; + } /* end switch */ + + /* Set the hyperslab selection */ + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, &start, &stride, &count, &block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Verify the version and encoded size expected for this configuration */ + ret = test_h5s_check_encoding(fapl, sid, expected_version, expected_enc_size, expected_to_fail); + CHECK(ret, FAIL, "test_h5s_check_encoding"); + + /* test 2 */ + switch (config) { + case CONFIG_16: + stride = POWER16 - 1; + block = POWER16 - 2; + expected_enc_size = (uint8_t)(expected_version == 3 ? 2 : 4); + break; + case CONFIG_32: + stride = POWER32 - 1; + block = POWER32 - 2; + expected_enc_size = (uint8_t)(expected_version == 3 ? 4 : 8); + break; + default: + HDassert(0); + break; + } /* end switch */ + + /* Set the hyperslab selection */ + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, &start, &stride, &count, &block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Verify the version and encoded size for this configuration */ + ret = test_h5s_check_encoding(fapl, sid, expected_version, expected_enc_size, expected_to_fail); + CHECK(ret, FAIL, "test_h5s_check_encoding"); + + /* test 3 */ + switch (config) { + case CONFIG_16: + stride = POWER16 - 1; + block = POWER16 - 1; + expected_enc_size = 4; + break; + case CONFIG_32: + stride = POWER32 - 1; + block = POWER32 - 1; + expected_enc_size = 8; + break; + default: + HDassert(0); + break; + } + + /* Set the hyperslab selection */ + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, &start, &stride, &count, &block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Verify the version and encoded size expected for this configuration */ + ret = test_h5s_check_encoding(fapl, sid, expected_version, expected_enc_size, expected_to_fail); + CHECK(ret, FAIL, "test_h5s_check_encoding"); + + /* test 4 */ + switch (config) { + case CONFIG_16: + stride = POWER16; + block = POWER16 - 2; + expected_enc_size = 4; + break; + case CONFIG_32: + stride = POWER32; + block = POWER32 - 2; + expected_enc_size = 8; + break; + default: + HDassert(0); + break; + } /* end switch */ + + /* Set the hyperslab selection */ + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, &start, &stride, &count, &block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Verify the version and encoded size expected for this configuration */ + ret = test_h5s_check_encoding(fapl, sid, expected_version, expected_enc_size, expected_to_fail); + CHECK(ret, FAIL, "test_h5s_check_encoding"); + + /* test 5 */ + switch (config) { + case CONFIG_16: + stride = POWER16; + block = 1; + expected_enc_size = 4; + break; + case CONFIG_32: + stride = POWER32; + block = 1; + expected_enc_size = 8; + break; + default: + HDassert(0); + break; + } + + /* Set the hyperslab selection */ + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, &start, &stride, &count, &block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Verify the version and encoded size expected for this configuration */ + ret = test_h5s_check_encoding(fapl, sid, expected_version, expected_enc_size, expected_to_fail); + CHECK(ret, FAIL, "test_h5s_check_encoding"); + + } /* for unlim */ + } /* for config */ + + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + +} /* test_h5s_encode_regular_hyper() */ + +/**************************************************************** +** +** test_h5s_encode_irregular_hyper(): +** This test verifies that H5Sencode2() works as specified in +** the RFC for irregular hyperslabs. +** See "RFC: H5Sencode/H5Sdeocde Format Change". +** +****************************************************************/ +static void +test_h5s_encode_irregular_hyper(H5F_libver_t low, H5F_libver_t high) +{ + hid_t fapl = -1; /* File access property list ID */ + hid_t sid; /* Dataspace ID */ + hsize_t numparticles = 8388608; /* Used to calculate dimension size */ + unsigned num_dsets = 513; /* Used to calculate dimension size */ + hsize_t total_particles = numparticles * num_dsets; + hsize_t vdsdims[1] = {total_particles}; /* Dimension size */ + hsize_t start, stride, count, block; /* Selection info */ + htri_t is_regular; /* Is this a regular hyperslab */ + unsigned config; /* Testing configuration */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Dataspace encoding of irregular hyperslabs\n")); + + /* Create the file access property list */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + + /* Set the low/high bounds in the fapl */ + ret = H5Pset_libver_bounds(fapl, low, high); + CHECK(ret, FAIL, "H5Pset_libver_bounds"); + + /* Create the dataspace */ + sid = H5Screate_simple(1, vdsdims, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Testing with each configuration */ + for (config = CONFIG_8; config <= CONFIG_32; config++) { + hbool_t expected_to_fail = FALSE; /* Whether H5Sencode2 is expected to fail */ + uint32_t expected_version = 0; /* Expected version for selection info */ + uint32_t expected_enc_size = 0; /* Expected encoded size for selection info */ + + start = 0; + count = 2; + block = 4; + + /* H5Sencode2 is expected to fail for library v110 and below + when the selection exceeds the 32 bits integer limit */ + if (high <= H5F_LIBVER_V110 && config == CONFIG_32) + expected_to_fail = TRUE; + + if (low >= H5F_LIBVER_V112 || config == CONFIG_32) + expected_version = 3; + else + expected_version = 1; + + switch (config) { + case CONFIG_8: + stride = POWER8 - 2; + break; + + case CONFIG_16: + stride = POWER16 - 2; + break; + + case CONFIG_32: + stride = POWER32 - 2; + break; + + default: + HDassert(0); + break; + } + + /* Set the hyperslab selection */ + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, &start, &stride, &count, &block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start = 8; + count = 5; + block = 2; + + switch (config) { + case CONFIG_8: + stride = POWER8; + expected_enc_size = expected_version == 3 ? 2 : 4; + break; + + case CONFIG_16: + stride = POWER16; + expected_enc_size = 4; + break; + + case CONFIG_32: + stride = POWER32; + expected_enc_size = 8; + break; + + default: + HDassert(0); + break; + } + + /* Set the hyperslab selection */ + ret = H5Sselect_hyperslab(sid, H5S_SELECT_OR, &start, &stride, &count, &block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Should be irregular hyperslab */ + is_regular = H5Sis_regular_hyperslab(sid); + VERIFY(is_regular, FALSE, "H5Sis_regular_hyperslab"); + + /* Verify the version and encoded size expected for the configuration */ + HDassert(expected_enc_size <= 255); + ret = test_h5s_check_encoding(fapl, sid, expected_version, (uint8_t)expected_enc_size, + expected_to_fail); + CHECK(ret, FAIL, "test_h5s_check_encoding"); + + } /* for config */ + + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + +} /* test_h5s_encode_irregular_hyper() */ + +/**************************************************************** +** +** test_h5s_encode_points(): +** This test verifies that H5Sencode2() works as specified in +** the RFC for point selection. +** See "RFC: H5Sencode/H5Sdeocde Format Change". +** +****************************************************************/ +static void +test_h5s_encode_points(H5F_libver_t low, H5F_libver_t high) +{ + hid_t fapl = -1; /* File access property list ID */ + hid_t sid; /* Dataspace ID */ + hsize_t numparticles = 8388608; /* Used to calculate dimension size */ + unsigned num_dsets = 513; /* used to calculate dimension size */ + hsize_t total_particles = numparticles * num_dsets; + hsize_t vdsdims[1] = {total_particles}; /* Dimension size */ + hsize_t coord[4]; /* The point coordinates */ + herr_t ret; /* Generic return value */ + hbool_t expected_to_fail = FALSE; /* Expected to fail or not */ + uint32_t expected_version = 0; /* Expected version for selection info */ + uint8_t expected_enc_size = 0; /* Expected encoded size of selection info */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Dataspace encoding of points selection\n")); + + /* Create the file access property list */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + + /* Set the low/high bounds in the fapl */ + ret = H5Pset_libver_bounds(fapl, low, high); + CHECK(ret, FAIL, "H5Pset_libver_bounds"); + + /* Create the dataspace */ + sid = H5Screate_simple(1, vdsdims, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* test 1 */ + coord[0] = 5; + coord[1] = 15; + coord[2] = POWER16; + coord[3] = 19; + ret = H5Sselect_elements(sid, H5S_SELECT_SET, (size_t)4, coord); + CHECK(ret, FAIL, "H5Sselect_elements"); + + expected_to_fail = FALSE; + expected_enc_size = 4; + expected_version = 1; + + if (low >= H5F_LIBVER_V112) + expected_version = 2; + + /* Verify the version and encoded size expected for the configuration */ + ret = test_h5s_check_encoding(fapl, sid, expected_version, expected_enc_size, expected_to_fail); + CHECK(ret, FAIL, "test_h5s_check_encoding"); + + /* test 2 */ + coord[0] = 5; + coord[1] = 15; + coord[2] = POWER32 - 1; + coord[3] = 19; + ret = H5Sselect_elements(sid, H5S_SELECT_SET, (size_t)4, coord); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Expected result same as test 1 */ + ret = test_h5s_check_encoding(fapl, sid, expected_version, expected_enc_size, expected_to_fail); + CHECK(ret, FAIL, "test_h5s_check_encoding"); + + /* test 3 */ + if (high <= H5F_LIBVER_V110) + expected_to_fail = TRUE; + + if (high >= H5F_LIBVER_V112) { + expected_version = 2; + expected_enc_size = 8; + } + + coord[0] = 5; + coord[1] = 15; + coord[2] = POWER32 + 1; + coord[3] = 19; + ret = H5Sselect_elements(sid, H5S_SELECT_SET, (size_t)4, coord); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Verify the version and encoded size expected for the configuration */ + ret = test_h5s_check_encoding(fapl, sid, expected_version, expected_enc_size, expected_to_fail); + CHECK(ret, FAIL, "test_h5s_check_encoding"); + + /* Close the dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + +} /* test_h5s_encode_points() */ + +/**************************************************************** +** +** test_h5s_encode_length(): +** Test to verify HDFFV-10271 is fixed. +** Verify that version 2 hyperslab encoding length is correct. +** +** See "RFC: H5Sencode/H5Sdecode Format Change" for the +** description of the encoding format. +** +****************************************************************/ +static void +test_h5s_encode_length(void) +{ + hid_t sid; /* Dataspace ID */ + hid_t decoded_sid; /* Dataspace ID from H5Sdecode2 */ + size_t sbuf_size = 0; /* Buffer size for H5Sencode2/1 */ + unsigned char *sbuf = NULL; /* Buffer for H5Sencode2/1 */ + hsize_t dims[1] = {500}; /* Dimension size */ + hsize_t start, count, block, stride; /* Hyperslab selection specifications */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Version 2 Hyperslab Encoding Length is correct\n")); + + /* Create dataspace */ + sid = H5Screate_simple(1, dims, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Setting H5S_UNLIMITED in count will use version 2 for hyperslab encoding */ + start = 0; + stride = 10; + block = 4; + count = H5S_UNLIMITED; + + /* Set hyperslab selection */ + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, &start, &stride, &count, &block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Encode simple dataspace in a buffer */ + ret = H5Sencode2(sid, NULL, &sbuf_size, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Sencode"); + + /* Allocate the buffer */ + if (sbuf_size > 0) { + sbuf = (unsigned char *)HDcalloc((size_t)1, sbuf_size); + CHECK_PTR(sbuf, "H5Sencode2"); + } + + /* Encode the dataspace */ + ret = H5Sencode2(sid, sbuf, &sbuf_size, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Sencode"); + + /* Verify that length stored at this location in the buffer is correct */ + VERIFY((uint32_t)sbuf[40], 36, "Length for encoding version 2"); + VERIFY((uint32_t)sbuf[35], 2, "Hyperslab encoding version is 2"); + + /* Decode from the dataspace buffer and return an object handle */ + decoded_sid = H5Sdecode(sbuf); + CHECK(decoded_sid, FAIL, "H5Sdecode"); + + /* Verify that the original and the decoded dataspace are equal */ + VERIFY(H5Sget_select_npoints(sid), H5Sget_select_npoints(decoded_sid), "Compare npoints"); + + /* Close the decoded dataspace */ + ret = H5Sclose(decoded_sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Free the buffer */ + if (sbuf) + HDfree(sbuf); + + /* Close the original dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + +} /* test_h5s_encode_length() */ + +/**************************************************************** +** +** test_h5s_scalar_write(): Test scalar H5S (dataspace) writing code. +** +****************************************************************/ +static void +test_h5s_scalar_write(void) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1; /* Dataspace ID */ + int rank; /* Logical rank of dataspace */ + hsize_t tdims[4]; /* Dimension array to test with */ + hssize_t n; /* Number of dataspace elements */ + H5S_class_t ext_type; /* Extent type */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Scalar Dataspace Manipulation during Writing\n")); + + /* Create file */ + fid1 = H5Fcreate(DATAFILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Verify a non-zero rank fails with a NULL dimension. */ + H5E_BEGIN_TRY + { + sid1 = H5Screate_simple(SPACE1_RANK, NULL, NULL); + } + H5E_END_TRY + VERIFY(sid1, FAIL, "H5Screate_simple"); + + /* Create scalar dataspace */ + sid1 = H5Screate_simple(SPACE3_RANK, NULL, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Retrieve the number of elements in the dataspace selection */ + n = H5Sget_simple_extent_npoints(sid1); + CHECK(n, FAIL, "H5Sget_simple_extent_npoints"); + VERIFY(n, 1, "H5Sget_simple_extent_npoints"); + + /* Get the dataspace rank */ + rank = H5Sget_simple_extent_ndims(sid1); + CHECK(rank, FAIL, "H5Sget_simple_extent_ndims"); + VERIFY(rank, SPACE3_RANK, "H5Sget_simple_extent_ndims"); + + /* Get the dataspace dimension sizes */ + rank = H5Sget_simple_extent_dims(sid1, tdims, NULL); + VERIFY(rank, 0, "H5Sget_simple_extent_dims"); + + /* Verify extent type */ + ext_type = H5Sget_simple_extent_type(sid1); + VERIFY(ext_type, H5S_SCALAR, "H5Sget_simple_extent_type"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, "Dataset1", H5T_NATIVE_UINT, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write to the dataset */ + ret = H5Dwrite(dataset, H5T_NATIVE_UINT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &space3_data); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close scalar dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_h5s_scalar_write() */ + +/**************************************************************** +** +** test_h5s_scalar_read(): Test scalar H5S (dataspace) reading code. +** +****************************************************************/ +static void +test_h5s_scalar_read(void) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1; /* Dataspace ID */ + int rank; /* Logical rank of dataspace */ + hsize_t tdims[4]; /* Dimension array to test with */ + hssize_t n; /* Number of dataspace elements */ + unsigned rdata; /* Scalar data read in */ + herr_t ret; /* Generic return value */ + H5S_class_t ext_type; /* Extent type */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Scalar Dataspace Manipulation during Reading\n")); + + /* Create file */ + fid1 = H5Fopen(DATAFILE, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Create a dataset */ + dataset = H5Dopen2(fid1, "Dataset1", H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + sid1 = H5Dget_space(dataset); + CHECK(sid1, FAIL, "H5Dget_space"); + + n = H5Sget_simple_extent_npoints(sid1); + CHECK(n, FAIL, "H5Sget_simple_extent_npoints"); + VERIFY(n, 1, "H5Sget_simple_extent_npoints"); + + rank = H5Sget_simple_extent_ndims(sid1); + CHECK(rank, FAIL, "H5Sget_simple_extent_ndims"); + VERIFY(rank, SPACE3_RANK, "H5Sget_simple_extent_ndims"); + + rank = H5Sget_simple_extent_dims(sid1, tdims, NULL); + VERIFY(rank, 0, "H5Sget_simple_extent_dims"); + + /* Verify extent type */ + ext_type = H5Sget_simple_extent_type(sid1); + VERIFY(ext_type, H5S_SCALAR, "H5Sget_simple_extent_type"); + + ret = H5Dread(dataset, H5T_NATIVE_UINT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &rdata); + CHECK(ret, FAIL, "H5Dread"); + VERIFY(rdata, space3_data, "H5Dread"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close scalar dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_h5s_scalar_read() */ + +/**************************************************************** +** +** test_h5s_compound_scalar_write(): Test scalar H5S (dataspace) writing for +** compound datatypes. +** +****************************************************************/ +static void +test_h5s_compound_scalar_write(void) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t tid1; /* Attribute datatype ID */ + hid_t sid1; /* Dataspace ID */ + int rank; /* Logical rank of dataspace */ + hsize_t tdims[4]; /* Dimension array to test with */ + hssize_t n; /* Number of dataspace elements */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Scalar Dataspace Manipulation for Writing Compound Datatypes\n")); + + /* Create file */ + fid1 = H5Fcreate(DATAFILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create the compound datatype. */ + tid1 = H5Tcreate(H5T_COMPOUND, sizeof(struct space4_struct)); + CHECK(tid1, FAIL, "H5Tcreate"); + space4_field1_off = HOFFSET(struct space4_struct, c1); + ret = H5Tinsert(tid1, SPACE4_FIELDNAME1, space4_field1_off, H5T_NATIVE_SCHAR); + CHECK(ret, FAIL, "H5Tinsert"); + space4_field2_off = HOFFSET(struct space4_struct, u); + ret = H5Tinsert(tid1, SPACE4_FIELDNAME2, space4_field2_off, H5T_NATIVE_UINT); + CHECK(ret, FAIL, "H5Tinsert"); + space4_field3_off = HOFFSET(struct space4_struct, f); + ret = H5Tinsert(tid1, SPACE4_FIELDNAME3, space4_field3_off, H5T_NATIVE_FLOAT); + CHECK(ret, FAIL, "H5Tinsert"); + space4_field4_off = HOFFSET(struct space4_struct, c2); + ret = H5Tinsert(tid1, SPACE4_FIELDNAME4, space4_field4_off, H5T_NATIVE_SCHAR); + CHECK(ret, FAIL, "H5Tinsert"); + + /* Create scalar dataspace */ + sid1 = H5Screate_simple(SPACE3_RANK, NULL, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + n = H5Sget_simple_extent_npoints(sid1); + CHECK(n, FAIL, "H5Sget_simple_extent_npoints"); + VERIFY(n, 1, "H5Sget_simple_extent_npoints"); + + rank = H5Sget_simple_extent_ndims(sid1); + CHECK(rank, FAIL, "H5Sget_simple_extent_ndims"); + VERIFY(rank, SPACE3_RANK, "H5Sget_simple_extent_ndims"); + + rank = H5Sget_simple_extent_dims(sid1, tdims, NULL); + VERIFY(rank, 0, "H5Sget_simple_extent_dims"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, "Dataset1", tid1, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + ret = H5Dwrite(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, &space4_data); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close compound datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close scalar dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_h5s_compound_scalar_write() */ + +/**************************************************************** +** +** test_h5s_compound_scalar_read(): Test scalar H5S (dataspace) reading for +** compound datatypes. +** +****************************************************************/ +static void +test_h5s_compound_scalar_read(void) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1; /* Dataspace ID */ + hid_t type; /* Datatype */ + int rank; /* Logical rank of dataspace */ + hsize_t tdims[4]; /* Dimension array to test with */ + hssize_t n; /* Number of dataspace elements */ + struct space4_struct rdata; /* Scalar data read in */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Scalar Dataspace Manipulation for Reading Compound Datatypes\n")); + + /* Create file */ + fid1 = H5Fopen(DATAFILE, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Create a dataset */ + dataset = H5Dopen2(fid1, "Dataset1", H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + sid1 = H5Dget_space(dataset); + CHECK(sid1, FAIL, "H5Dget_space"); + + n = H5Sget_simple_extent_npoints(sid1); + CHECK(n, FAIL, "H5Sget_simple_extent_npoints"); + VERIFY(n, 1, "H5Sget_simple_extent_npoints"); + + rank = H5Sget_simple_extent_ndims(sid1); + CHECK(rank, FAIL, "H5Sget_simple_extent_ndims"); + VERIFY(rank, SPACE3_RANK, "H5Sget_simple_extent_ndims"); + + rank = H5Sget_simple_extent_dims(sid1, tdims, NULL); + VERIFY(rank, 0, "H5Sget_simple_extent_dims"); + + type = H5Dget_type(dataset); + CHECK(type, FAIL, "H5Dget_type"); + + ret = H5Dread(dataset, type, H5S_ALL, H5S_ALL, H5P_DEFAULT, &rdata); + CHECK(ret, FAIL, "H5Dread"); + if (HDmemcmp(&space4_data, &rdata, sizeof(struct space4_struct)) != 0) { + HDprintf("scalar data different: space4_data.c1=%c, read_data4.c1=%c\n", space4_data.c1, rdata.c1); + HDprintf("scalar data different: space4_data.u=%u, read_data4.u=%u\n", space4_data.u, rdata.u); + HDprintf("scalar data different: space4_data.f=%f, read_data4.f=%f\n", (double)space4_data.f, + (double)rdata.f); + TestErrPrintf("scalar data different: space4_data.c1=%c, read_data4.c1=%c\n", space4_data.c1, + rdata.c2); + } /* end if */ + + /* Close datatype */ + ret = H5Tclose(type); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close scalar dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_h5s_compound_scalar_read() */ + +/* Data array sizes for chunk test */ +#define CHUNK_DATA_NX 50000 +#define CHUNK_DATA_NY 3 + +/**************************************************************** +** +** test_h5s_chunk(): Exercise chunked I/O, testing when data conversion +** is necessary and the entire chunk read in doesn't fit into the +** conversion buffer +** +****************************************************************/ +static void +test_h5s_chunk(void) +{ + herr_t status; + hid_t fileID, dsetID; + hid_t plist_id; + hid_t space_id; + hsize_t dims[2]; + hsize_t csize[2]; + double **chunk_data_dbl = NULL; + double *chunk_data_dbl_data = NULL; + float **chunk_data_flt = NULL; + float *chunk_data_flt_data = NULL; + int i, j; + + /* Allocate memory */ + chunk_data_dbl_data = (double *)HDcalloc(CHUNK_DATA_NX * CHUNK_DATA_NY, sizeof(double)); + CHECK_PTR(chunk_data_dbl_data, "HDcalloc"); + chunk_data_dbl = (double **)HDcalloc(CHUNK_DATA_NX, sizeof(chunk_data_dbl_data)); + CHECK_PTR(chunk_data_dbl, "HDcalloc"); + for (i = 0; i < CHUNK_DATA_NX; i++) + chunk_data_dbl[i] = chunk_data_dbl_data + (i * CHUNK_DATA_NY); + + chunk_data_flt_data = (float *)HDcalloc(CHUNK_DATA_NX * CHUNK_DATA_NY, sizeof(float)); + CHECK_PTR(chunk_data_flt_data, "HDcalloc"); + chunk_data_flt = (float **)HDcalloc(CHUNK_DATA_NX, sizeof(chunk_data_flt_data)); + CHECK_PTR(chunk_data_flt, "HDcalloc"); + for (i = 0; i < CHUNK_DATA_NX; i++) + chunk_data_flt[i] = chunk_data_flt_data + (i * CHUNK_DATA_NY); + + fileID = H5Fcreate(DATAFILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fileID, FAIL, "H5Fcreate"); + + plist_id = H5Pcreate(H5P_DATASET_CREATE); + CHECK(plist_id, FAIL, "H5Pcreate"); + + csize[0] = CHUNK_DATA_NX; + csize[1] = CHUNK_DATA_NY; + status = H5Pset_chunk(plist_id, 2, csize); + CHECK(status, FAIL, "H5Pset_chunk"); + + /* Create the dataspace */ + dims[0] = CHUNK_DATA_NX; + dims[1] = CHUNK_DATA_NY; + space_id = H5Screate_simple(2, dims, NULL); + CHECK(space_id, FAIL, "H5Screate_simple"); + + dsetID = H5Dcreate2(fileID, "coords", H5T_NATIVE_FLOAT, space_id, H5P_DEFAULT, plist_id, H5P_DEFAULT); + CHECK(dsetID, FAIL, "H5Dcreate2"); + + /* Initialize float array */ + for (i = 0; i < CHUNK_DATA_NX; i++) + for (j = 0; j < CHUNK_DATA_NY; j++) + chunk_data_flt[i][j] = (float)(i + 1) * 2.5F - (float)j * 100.3F; + + status = H5Dwrite(dsetID, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, chunk_data_flt_data); + CHECK(status, FAIL, "H5Dwrite"); + + status = H5Pclose(plist_id); + CHECK(status, FAIL, "H5Pclose"); + status = H5Sclose(space_id); + CHECK(status, FAIL, "H5Sclose"); + status = H5Dclose(dsetID); + CHECK(status, FAIL, "H5Dclose"); + status = H5Fclose(fileID); + CHECK(status, FAIL, "H5Fclose"); + + /* Reset/initialize the data arrays to read in */ + HDmemset(chunk_data_dbl_data, 0, sizeof(double) * CHUNK_DATA_NX * CHUNK_DATA_NY); + HDmemset(chunk_data_flt_data, 0, sizeof(float) * CHUNK_DATA_NX * CHUNK_DATA_NY); + + fileID = H5Fopen(DATAFILE, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fileID, FAIL, "H5Fopen"); + dsetID = H5Dopen2(fileID, "coords", H5P_DEFAULT); + CHECK(dsetID, FAIL, "H5Dopen2"); + + status = H5Dread(dsetID, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, chunk_data_dbl_data); + CHECK(status, FAIL, "H5Dread"); + status = H5Dread(dsetID, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, chunk_data_flt_data); + CHECK(status, FAIL, "H5Dread"); + + status = H5Dclose(dsetID); + CHECK(status, FAIL, "H5Dclose"); + status = H5Fclose(fileID); + CHECK(status, FAIL, "H5Fclose"); + + for (i = 0; i < CHUNK_DATA_NX; i++) { + for (j = 0; j < CHUNK_DATA_NY; j++) { + /* Check if the two values are within 0.001% range. */ + if (!H5_DBL_REL_EQUAL(chunk_data_dbl[i][j], (double)chunk_data_flt[i][j], 0.00001)) + TestErrPrintf("%u: chunk_data_dbl[%d][%d]=%e, chunk_data_flt[%d][%d]=%e\n", + (unsigned)__LINE__, i, j, chunk_data_dbl[i][j], i, j, + (double)chunk_data_flt[i][j]); + } /* end for */ + } /* end for */ + + HDfree(chunk_data_dbl); + HDfree(chunk_data_dbl_data); + HDfree(chunk_data_flt); + HDfree(chunk_data_flt_data); +} /* test_h5s_chunk() */ + +/**************************************************************** +** +** test_h5s_extent_equal(): Exercise extent comparison code +** +****************************************************************/ +static void +test_h5s_extent_equal(void) +{ + hid_t null_space; /* Null dataspace */ + hid_t scalar_space; /* Scalar dataspace */ + hid_t d1_space1, d1_space2, d1_space3, d1_space4; /* 1-D dataspaces */ + hid_t d2_space1, d2_space2, d2_space3, d2_space4; /* 2-D dataspaces */ + hid_t d3_space1, d3_space2, d3_space3, d3_space4; /* 3-D dataspaces */ + hsize_t d1_dims1[1] = {10}, /* 1-D dimensions */ + d1_dims2[1] = {20}, d1_dims3[1] = {H5S_UNLIMITED}; + hsize_t d2_dims1[2] = {10, 10}, /* 2-D dimensions */ + d2_dims2[2] = {20, 20}, d2_dims3[2] = {H5S_UNLIMITED, H5S_UNLIMITED}; + hsize_t d3_dims1[3] = {10, 10, 10}, /* 3-D dimensions */ + d3_dims2[3] = {20, 20, 20}, d3_dims3[3] = {H5S_UNLIMITED, H5S_UNLIMITED, H5S_UNLIMITED}; + htri_t ext_equal; /* Whether two dataspace extents are equal */ + herr_t ret; /* Generic error return */ + + /* Create dataspaces */ + null_space = H5Screate(H5S_NULL); + CHECK(null_space, FAIL, "H5Screate"); + + scalar_space = H5Screate(H5S_SCALAR); + CHECK(scalar_space, FAIL, "H5Screate"); + + d1_space1 = H5Screate_simple(1, d1_dims1, NULL); + CHECK(d1_space1, FAIL, "H5Screate"); + d1_space2 = H5Screate_simple(1, d1_dims2, NULL); + CHECK(d1_space2, FAIL, "H5Screate"); + d1_space3 = H5Screate_simple(1, d1_dims1, d1_dims2); + CHECK(d1_space3, FAIL, "H5Screate"); + d1_space4 = H5Screate_simple(1, d1_dims1, d1_dims3); + CHECK(d1_space4, FAIL, "H5Screate"); + + d2_space1 = H5Screate_simple(2, d2_dims1, NULL); + CHECK(d2_space1, FAIL, "H5Screate"); + d2_space2 = H5Screate_simple(2, d2_dims2, NULL); + CHECK(d2_space2, FAIL, "H5Screate"); + d2_space3 = H5Screate_simple(2, d2_dims1, d2_dims2); + CHECK(d2_space3, FAIL, "H5Screate"); + d2_space4 = H5Screate_simple(2, d2_dims1, d2_dims3); + CHECK(d2_space4, FAIL, "H5Screate"); + + d3_space1 = H5Screate_simple(3, d3_dims1, NULL); + CHECK(d3_space1, FAIL, "H5Screate"); + d3_space2 = H5Screate_simple(3, d3_dims2, NULL); + CHECK(d3_space2, FAIL, "H5Screate"); + d3_space3 = H5Screate_simple(3, d3_dims1, d3_dims2); + CHECK(d3_space3, FAIL, "H5Screate"); + d3_space4 = H5Screate_simple(3, d3_dims1, d3_dims3); + CHECK(d3_space4, FAIL, "H5Screate"); + + /* Compare all dataspace combinations */ + + /* Compare null dataspace against all others, including itself */ + ext_equal = H5Sextent_equal(null_space, null_space); + VERIFY(ext_equal, TRUE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(null_space, scalar_space); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(null_space, d1_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(null_space, d1_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(null_space, d1_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(null_space, d1_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(null_space, d2_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(null_space, d2_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(null_space, d2_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(null_space, d2_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(null_space, d3_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(null_space, d3_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(null_space, d3_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(null_space, d3_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + + /* Compare scalar dataspace against all others, including itself */ + ext_equal = H5Sextent_equal(scalar_space, null_space); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(scalar_space, scalar_space); + VERIFY(ext_equal, TRUE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(scalar_space, d1_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(scalar_space, d1_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(scalar_space, d1_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(scalar_space, d1_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(scalar_space, d2_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(scalar_space, d2_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(scalar_space, d2_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(scalar_space, d2_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(scalar_space, d3_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(scalar_space, d3_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(scalar_space, d3_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(scalar_space, d3_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + + /* Compare small 1-D dataspace w/no max. dims against all others, including itself */ + ext_equal = H5Sextent_equal(d1_space1, null_space); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space1, scalar_space); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space1, d1_space1); + VERIFY(ext_equal, TRUE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space1, d1_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space1, d1_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space1, d1_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space1, d2_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space1, d2_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space1, d2_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space1, d2_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space1, d3_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space1, d3_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space1, d3_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space1, d3_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + + /* Compare larger 1-D dataspace w/no max. dims against all others, including itself */ + ext_equal = H5Sextent_equal(d1_space2, null_space); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space2, scalar_space); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space2, d1_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space2, d1_space2); + VERIFY(ext_equal, TRUE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space2, d1_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space2, d1_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space2, d2_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space2, d2_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space2, d2_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space2, d2_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space2, d3_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space2, d3_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space2, d3_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space2, d3_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + + /* Compare small 1-D dataspace w/fixed max. dims against all others, including itself */ + ext_equal = H5Sextent_equal(d1_space3, null_space); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space3, scalar_space); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space3, d1_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space3, d1_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space3, d1_space3); + VERIFY(ext_equal, TRUE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space3, d1_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space3, d2_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space3, d2_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space3, d2_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space3, d2_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space3, d3_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space3, d3_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space3, d3_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space3, d3_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + + /* Compare small 1-D dataspace w/unlimited max. dims against all others, including itself */ + ext_equal = H5Sextent_equal(d1_space4, null_space); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space4, scalar_space); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space4, d1_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space4, d1_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space4, d1_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space4, d1_space4); + VERIFY(ext_equal, TRUE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space4, d2_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space4, d2_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space4, d2_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space4, d2_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space4, d3_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space4, d3_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space4, d3_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d1_space4, d3_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + + /* Compare small 2-D dataspace w/no max. dims against all others, including itself */ + ext_equal = H5Sextent_equal(d2_space1, null_space); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space1, scalar_space); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space1, d1_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space1, d1_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space1, d1_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space1, d1_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space1, d2_space1); + VERIFY(ext_equal, TRUE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space1, d2_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space1, d2_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space1, d2_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space1, d3_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space1, d3_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space1, d3_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space1, d3_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + + /* Compare larger 2-D dataspace w/no max. dims against all others, including itself */ + ext_equal = H5Sextent_equal(d2_space2, null_space); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space2, scalar_space); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space2, d1_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space2, d1_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space2, d1_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space2, d1_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space2, d2_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space2, d2_space2); + VERIFY(ext_equal, TRUE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space2, d2_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space2, d2_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space2, d3_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space2, d3_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space2, d3_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space2, d3_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + + /* Compare small 2-D dataspace w/fixed max. dims against all others, including itself */ + ext_equal = H5Sextent_equal(d2_space3, null_space); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space3, scalar_space); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space3, d1_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space3, d1_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space3, d1_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space3, d1_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space3, d2_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space3, d2_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space3, d2_space3); + VERIFY(ext_equal, TRUE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space3, d2_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space3, d3_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space3, d3_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space3, d3_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space3, d3_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + + /* Compare small 2-D dataspace w/unlimited max. dims against all others, including itself */ + ext_equal = H5Sextent_equal(d2_space4, null_space); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space4, scalar_space); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space4, d1_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space4, d1_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space4, d1_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space4, d1_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space4, d2_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space4, d2_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space4, d2_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space4, d2_space4); + VERIFY(ext_equal, TRUE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space4, d3_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space4, d3_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space4, d3_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d2_space4, d3_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + + /* Compare small 3-D dataspace w/no max. dims against all others, including itself */ + ext_equal = H5Sextent_equal(d3_space1, null_space); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space1, scalar_space); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space1, d1_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space1, d1_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space1, d1_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space1, d1_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space1, d2_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space1, d2_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space1, d2_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space1, d2_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space1, d3_space1); + VERIFY(ext_equal, TRUE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space1, d3_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space1, d3_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space1, d3_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + + /* Compare larger 2-D dataspace w/no max. dims against all others, including itself */ + ext_equal = H5Sextent_equal(d3_space2, null_space); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space2, scalar_space); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space2, d1_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space2, d1_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space2, d1_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space2, d1_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space2, d2_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space2, d2_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space2, d2_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space2, d2_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space2, d3_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space2, d3_space2); + VERIFY(ext_equal, TRUE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space2, d3_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space2, d3_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + + /* Compare small 2-D dataspace w/fixed max. dims against all others, including itself */ + ext_equal = H5Sextent_equal(d3_space3, null_space); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space3, scalar_space); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space3, d1_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space3, d1_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space3, d1_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space3, d1_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space3, d2_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space3, d2_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space3, d2_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space3, d2_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space3, d3_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space3, d3_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space3, d3_space3); + VERIFY(ext_equal, TRUE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space3, d3_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + + /* Compare small 2-D dataspace w/unlimited max. dims against all others, including itself */ + ext_equal = H5Sextent_equal(d3_space4, null_space); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space4, scalar_space); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space4, d1_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space4, d1_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space4, d1_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space4, d1_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space4, d2_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space4, d2_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space4, d2_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space4, d2_space4); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space4, d3_space1); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space4, d3_space2); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space4, d3_space3); + VERIFY(ext_equal, FALSE, "H5Sextent_equal"); + ext_equal = H5Sextent_equal(d3_space4, d3_space4); + VERIFY(ext_equal, TRUE, "H5Sextent_equal"); + + /* Close dataspaces */ + ret = H5Sclose(null_space); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(scalar_space); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(d1_space1); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(d1_space2); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(d1_space3); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(d1_space4); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(d2_space1); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(d2_space2); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(d2_space3); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(d2_space4); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(d3_space1); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(d3_space2); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(d3_space3); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(d3_space4); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_h5s_extent_equal() */ + +/**************************************************************** +** +** test_h5s_extent_copy(): Exercise extent copy code +** +****************************************************************/ +static void +test_h5s_extent_copy(void) +{ + hid_t spaces[14] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; /* Array of all dataspaces */ + hid_t tmp_space = -1; + hsize_t d1_dims1[1] = {10}, /* 1-D dimensions */ + d1_dims2[1] = {20}, d1_dims3[1] = {H5S_UNLIMITED}; + hsize_t d2_dims1[2] = {10, 10}, /* 2-D dimensions */ + d2_dims2[2] = {20, 20}, d2_dims3[2] = {H5S_UNLIMITED, H5S_UNLIMITED}; + hsize_t d3_dims1[3] = {10, 10, 10}, /* 3-D dimensions */ + d3_dims2[3] = {20, 20, 20}, d3_dims3[3] = {H5S_UNLIMITED, H5S_UNLIMITED, H5S_UNLIMITED}; + hsize_t npoints[14]; /* Expected number of points in selection for each element in spaces */ + hssize_t npoints_ret; /* Number of points returned by H5Sget_select_npoints() */ + htri_t ext_equal; /* Whether two dataspace extents are equal */ + const unsigned num_spaces = sizeof(spaces) / sizeof(spaces[0]); + unsigned i, j; + herr_t ret; /* Generic error return */ + + /* Create dataspaces */ + spaces[0] = H5Screate(H5S_NULL); + CHECK(spaces[0], FAIL, "H5Screate"); + npoints[0] = (hsize_t)0; + + spaces[1] = H5Screate(H5S_SCALAR); + CHECK(spaces[1], FAIL, "H5Screate"); + npoints[1] = (hsize_t)1; + + spaces[2] = H5Screate_simple(1, d1_dims1, NULL); + CHECK(spaces[2], FAIL, "H5Screate"); + npoints[2] = d1_dims1[0]; + spaces[3] = H5Screate_simple(1, d1_dims2, NULL); + CHECK(spaces[3], FAIL, "H5Screate"); + npoints[3] = d1_dims2[0]; + spaces[4] = H5Screate_simple(1, d1_dims1, d1_dims2); + CHECK(spaces[4], FAIL, "H5Screate"); + npoints[4] = d1_dims1[0]; + spaces[5] = H5Screate_simple(1, d1_dims1, d1_dims3); + CHECK(spaces[5], FAIL, "H5Screate"); + npoints[5] = d1_dims1[0]; + + spaces[6] = H5Screate_simple(2, d2_dims1, NULL); + CHECK(spaces[6], FAIL, "H5Screate"); + npoints[6] = d2_dims1[0] * d2_dims1[1]; + spaces[7] = H5Screate_simple(2, d2_dims2, NULL); + CHECK(spaces[7], FAIL, "H5Screate"); + npoints[7] = d2_dims2[0] * d2_dims2[1]; + spaces[8] = H5Screate_simple(2, d2_dims1, d2_dims2); + CHECK(spaces[8], FAIL, "H5Screate"); + npoints[8] = d2_dims1[0] * d2_dims1[1]; + spaces[9] = H5Screate_simple(2, d2_dims1, d2_dims3); + CHECK(spaces[9], FAIL, "H5Screate"); + npoints[9] = d2_dims1[0] * d2_dims1[1]; + + spaces[10] = H5Screate_simple(3, d3_dims1, NULL); + CHECK(spaces[10], FAIL, "H5Screate"); + npoints[10] = d3_dims1[0] * d3_dims1[1] * d3_dims1[2]; + spaces[11] = H5Screate_simple(3, d3_dims2, NULL); + CHECK(spaces[11], FAIL, "H5Screate"); + npoints[11] = d3_dims2[0] * d3_dims2[1] * d3_dims2[2]; + spaces[12] = H5Screate_simple(3, d3_dims1, d3_dims2); + CHECK(spaces[12], FAIL, "H5Screate"); + npoints[12] = d3_dims1[0] * d3_dims1[1] * d3_dims1[2]; + spaces[13] = H5Screate_simple(3, d3_dims1, d3_dims3); + CHECK(spaces[13], FAIL, "H5Screate"); + npoints[13] = d3_dims1[0] * d3_dims1[1] * d3_dims1[2]; + + tmp_space = H5Screate(H5S_NULL); + CHECK(tmp_space, FAIL, "H5Screate"); + + /* Copy between all dataspace combinations. Note there are a few + * duplicates. */ + for (i = 0; i < num_spaces; i++) + for (j = i; j < num_spaces; j++) { + /* Copy from i to j, unless the inner loop just restarted, in which + * case i and j are the same, so the second call to H5Sextent_copy() + * will test copying from i/j to i/j */ + ret = H5Sextent_copy(tmp_space, spaces[j]); + CHECK(ret, FAIL, "H5Sextent_copy"); + + /* Verify that the extents are equal */ + ext_equal = H5Sextent_equal(tmp_space, spaces[j]); + VERIFY(ext_equal, TRUE, "H5Sextent_equal"); + + /* Verify that the correct number of elements is selected */ + npoints_ret = H5Sget_select_npoints(tmp_space); + VERIFY((hsize_t)npoints_ret, npoints[j], "H5Sget_select_npoints"); + + /* Copy from j to i */ + ret = H5Sextent_copy(tmp_space, spaces[i]); + CHECK(ret, FAIL, "H5Sextent_copy"); + + /* Verify that the extents are equal */ + ext_equal = H5Sextent_equal(tmp_space, spaces[i]); + VERIFY(ext_equal, TRUE, "H5Sextent_equal"); + + /* Verify that the correct number of elements is selected */ + npoints_ret = H5Sget_select_npoints(tmp_space); + VERIFY((hsize_t)npoints_ret, npoints[i], "H5Sget_select_npoints"); + } /* end for */ + + /* Close dataspaces */ + for (i = 0; i < num_spaces; i++) { + ret = H5Sclose(spaces[i]); + CHECK(ret, FAIL, "H5Sclose"); + spaces[i] = -1; + } /* end for */ + + ret = H5Sclose(tmp_space); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_h5s_extent_copy() */ + +/**************************************************************** +** +** test_h5s_bug1(): Test Creating dataspace with H5Screate then +* setting extent with H5Sextent_copy. +** +****************************************************************/ +static void +test_h5s_bug1(void) +{ + hid_t space1; /* Dataspace to copy extent to */ + hid_t space2; /* Scalar dataspace */ + hsize_t dims[2] = {10, 10}; /* Dimensions */ + hsize_t start[2] = {0, 0}; /* Hyperslab start */ + htri_t select_valid; /* Whether the dataspace selection is valid */ + herr_t ret; /* Generic error return */ + + /* Create dataspaces */ + space1 = H5Screate(H5S_SIMPLE); + CHECK(space1, FAIL, "H5Screate"); + space2 = H5Screate_simple(2, dims, NULL); + CHECK(space2, FAIL, "H5Screate"); + + /* Copy extent to space1 */ + ret = H5Sextent_copy(space1, space2); + CHECK(ret, FAIL, "H5Sextent_copy"); + + /* Select hyperslab in space1 containing entire extent */ + ret = H5Sselect_hyperslab(space1, H5S_SELECT_SET, start, NULL, dims, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Check that space1's selection is valid */ + select_valid = H5Sselect_valid(space1); + CHECK(select_valid, FAIL, "H5Sselect_valid"); + VERIFY(select_valid, TRUE, "H5Sselect_valid result"); + + /* Close dataspaces */ + ret = H5Sclose(space1); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(space2); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_h5s_bug1() */ + +/**************************************************************** +** +** test_h5s_bug2(): Test combining hyperslabs in a way that used +** to trip up H5S__hyper_update_diminfo() +** +****************************************************************/ +static void +test_h5s_bug2(void) +{ + hid_t space; /* Dataspace to copy extent to */ + hsize_t dims[2] = {1, 5}; /* Dimensions */ + hsize_t start[2] = {0, 0}; /* Hyperslab start */ + hsize_t count[2] = {1, 1}; /* Hyperslab start */ + htri_t select_valid; /* Whether the dataspace selection is valid */ + hssize_t elements_selected; /* Number of elements selected */ + herr_t ret; /* Generic error return */ + + /* Create dataspace */ + space = H5Screate_simple(2, dims, NULL); + CHECK(space, FAIL, "H5Screate"); + + /* Select hyperslab in space containing first element */ + ret = H5Sselect_hyperslab(space, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Add hyperslab in space containing last element */ + start[1] = 4; + ret = H5Sselect_hyperslab(space, H5S_SELECT_OR, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Add hyperslab in space containing the first 3 elements */ + start[1] = 0; + count[1] = 3; + ret = H5Sselect_hyperslab(space, H5S_SELECT_OR, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Check that space's selection is valid */ + select_valid = H5Sselect_valid(space); + CHECK(select_valid, FAIL, "H5Sselect_valid"); + VERIFY(select_valid, TRUE, "H5Sselect_valid result"); + + /* Check that 4 elements are selected */ + elements_selected = H5Sget_select_npoints(space); + CHECK(elements_selected, FAIL, "H5Sselect_valid"); + VERIFY(elements_selected, 4, "H5Sselect_valid result"); + + /* Close dataspaces */ + ret = H5Sclose(space); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_h5s_bug2() */ + +/*------------------------------------------------------------------------- + * Function: test_versionbounds + * + * Purpose: Tests version bounds with dataspace. + * + * Description: + * This function creates a file with lower bounds then later + * reopens it with higher bounds to show that the dataspace + * version is upgraded appropriately. + * + * Return: Success: 0 + * Failure: number of errors + * + *------------------------------------------------------------------------- + */ +#define VERBFNAME "tverbounds_dspace.h5" +#define BASIC_DSET "Basic Dataset" +#define LATEST_DSET "Latest Dataset" +static void +test_versionbounds(void) +{ + hid_t file = -1; /* File ID */ + hid_t space = -1; /* Dataspace ID */ + hid_t dset = -1; /* Dataset ID */ + hid_t fapl = -1; /* File access property list ID */ + hid_t dset_space = -1; /* Retrieved dataset's dataspace ID */ + hsize_t dim[1]; /* Dataset dimensions */ + H5F_libver_t low, high; /* File format bounds */ +#if 0 + H5S_t *spacep = NULL; /* Pointer to internal dataspace */ +#endif + herr_t ret = 0; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Version Bounds\n")); + + /* Create a file access property list */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + + /* Create dataspace */ + dim[0] = 10; + space = H5Screate_simple(1, dim, NULL); + CHECK(space, FAIL, "H5Screate"); +#if 0 + /* Its version should be H5O_SDSPACE_VERSION_1 */ + spacep = (H5S_t *)H5I_object(space); + CHECK_PTR(spacep, "H5I_object"); + VERIFY(spacep->extent.version, H5O_SDSPACE_VERSION_1, "basic dataspace version bound"); +#endif + + /* Set high bound to V18 */ + low = H5F_LIBVER_EARLIEST; + high = H5F_LIBVER_V18; + ret = H5Pset_libver_bounds(fapl, low, high); + CHECK(ret, FAIL, "H5Pset_libver_bounds"); + + /* Create the file */ + file = H5Fcreate(VERBFNAME, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(file, FAIL, "H5Fcreate"); + + /* Create a basic dataset */ + dset = H5Dcreate2(file, BASIC_DSET, H5T_NATIVE_INT, space, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (dset > 0) /* dataset created successfully */ + { + /* Get the internal dataspace pointer */ + dset_space = H5Dget_space(dset); + CHECK(dset_space, FAIL, "H5Dget_space"); +#if 0 + spacep = (H5S_t *)H5I_object(dset_space); + CHECK_PTR(spacep, "H5I_object"); + + /* Dataspace version should remain as H5O_SDSPACE_VERSION_1 */ + VERIFY(spacep->extent.version, H5O_SDSPACE_VERSION_1, "basic dataspace version bound"); +#endif + /* Close dataspace */ + ret = H5Sclose(dset_space); + CHECK(ret, FAIL, "H5Sclose"); + } + + /* Close basic dataset and the file */ + ret = H5Dclose(dset); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + + /* Set low and high bounds to latest to trigger the increment of the + dataspace version */ + low = H5F_LIBVER_LATEST; + high = H5F_LIBVER_LATEST; + ret = H5Pset_libver_bounds(fapl, low, high); + CHECK(ret, FAIL, "H5Pset_libver_bounds"); + + /* Reopen the file with new version bounds, LATEST/LATEST */ + file = H5Fopen(VERBFNAME, H5F_ACC_RDWR, fapl); + + /* Create another dataset using the same dspace as the previous dataset */ + dset = H5Dcreate2(file, LATEST_DSET, H5T_NATIVE_INT, space, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dset, FAIL, "H5Dcreate2"); + + /* Dataset created successfully. Verify that dataspace version has been + upgraded per the low bound */ + + /* Get the internal dataspace pointer */ + dset_space = H5Dget_space(dset); + CHECK(dset_space, FAIL, "H5Dget_space"); +#if 0 + spacep = (H5S_t *)H5I_object(dset_space); + CHECK_PTR(spacep, "H5I_object"); + + /* Verify the dataspace version */ + VERIFY(spacep->extent.version, H5O_sdspace_ver_bounds[low], "upgraded dataspace version"); +#endif + /* Close everything */ + ret = H5Sclose(dset_space); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Dclose(dset); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Sclose(space); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_versionbounds() */ + +/**************************************************************** +** +** test_h5s(): Main H5S (dataspace) testing routine. +** +****************************************************************/ +void +test_h5s(void) +{ + H5F_libver_t low, high; /* Low and high bounds */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Dataspaces\n")); + + test_h5s_basic(); /* Test basic H5S code */ + test_h5s_null(); /* Test Null dataspace H5S code */ + test_h5s_zero_dim(); /* Test dataspace with zero dimension size */ +#if 0 + /* Loop through all the combinations of low/high version bounds */ + for (low = H5F_LIBVER_EARLIEST; low < H5F_LIBVER_NBOUNDS; low++) { + for (high = H5F_LIBVER_EARLIEST; high < H5F_LIBVER_NBOUNDS; high++) { + + /* Invalid combinations, just continue */ + if (high == H5F_LIBVER_EARLIEST || high < low) + continue; +#else + low = H5F_LIBVER_LATEST; + high = H5F_LIBVER_LATEST; +#endif + test_h5s_encode(low, high); /* Test encoding and decoding */ + test_h5s_encode_regular_hyper(low, high); /* Test encoding regular hyperslabs */ + test_h5s_encode_irregular_hyper(low, high); /* Test encoding irregular hyperslabs */ + test_h5s_encode_points(low, high); /* Test encoding points */ +#if 0 + } /* end high bound */ + } /* end low bound */ +#endif + test_h5s_encode_length(); /* Test version 2 hyperslab encoding length is correct */ +#ifndef H5_NO_DEPRECATED_SYMBOLS + test_h5s_encode1(); /* Test operations with old API routine (H5Sencode1) */ +#endif /* H5_NO_DEPRECATED_SYMBOLS */ + + test_h5s_scalar_write(); /* Test scalar H5S writing code */ + test_h5s_scalar_read(); /* Test scalar H5S reading code */ + + test_h5s_compound_scalar_write(); /* Test compound datatype scalar H5S writing code */ + test_h5s_compound_scalar_read(); /* Test compound datatype scalar H5S reading code */ + + /* This test was added later to exercise a bug in chunked I/O */ + test_h5s_chunk(); /* Exercise bug fix for chunked I/O */ + + test_h5s_extent_equal(); /* Test extent comparison code */ + test_h5s_extent_copy(); /* Test extent copy code */ + test_h5s_bug1(); /* Test bug in offset initialization */ + test_h5s_bug2(); /* Test bug found in H5S__hyper_update_diminfo() */ + test_versionbounds(); /* Test version bounds with dataspace */ +} /* test_h5s() */ + +/*------------------------------------------------------------------------- + * Function: cleanup_h5s + * + * Purpose: Cleanup temporary test files + * + * Return: none + * + * Programmer: Albert Cheng + * July 2, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +void +cleanup_h5s(void) +{ + H5Fdelete(DATAFILE, H5P_DEFAULT); + H5Fdelete(NULLFILE, H5P_DEFAULT); + H5Fdelete(BASICFILE, H5P_DEFAULT); + H5Fdelete(ZEROFILE, H5P_DEFAULT); + H5Fdelete(VERBFNAME, H5P_DEFAULT); +} diff --git a/test/API/tid.c b/test/API/tid.c new file mode 100644 index 0000000..2dd8851 --- /dev/null +++ b/test/API/tid.c @@ -0,0 +1,1413 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* Test user-created identifiers (hid_t's) and identifier types. */ + +#include "testhdf5.h" + +#if 0 +/* Include H5Ipkg.h to calculate max number of groups */ +#define H5I_FRIEND /*suppress error about including H5Ipkg */ +#include "H5Ipkg.h" +#endif + +/* + * Number of bits to use for ID Type in each ID. Increase if more types + * are needed (though this will decrease the number of available IDs per + * type). This is the only number that must be changed since all other bit + * field sizes and masks are calculated from TYPE_BITS. + */ +#define TYPE_BITS 7 +#define TYPE_MASK (((hid_t)1 << TYPE_BITS) - 1) + +#define H5I_MAX_NUM_TYPES TYPE_MASK + +static herr_t +free_wrapper(void *p, void H5_ATTR_UNUSED **_ctx) +{ + HDfree(p); + return SUCCEED; +} + +/* Test basic functionality of registering and deleting types and IDs */ +static int +basic_id_test(void) +{ + H5I_type_t myType = H5I_BADID; + hid_t arrayID = H5I_INVALID_HID; + void *testObj = NULL; + void *testPtr = NULL; + char nameString[10]; + hid_t testID; + ssize_t testSize = -1; + herr_t err; + int num_ref; + hsize_t num_members; + + /* Try to register an ID with fictitious types */ + H5E_BEGIN_TRY + arrayID = H5Iregister((H5I_type_t)420, testObj); + H5E_END_TRY + + VERIFY(arrayID, H5I_INVALID_HID, "H5Iregister"); + if (arrayID != H5I_INVALID_HID) + goto out; + + H5E_BEGIN_TRY + arrayID = H5Iregister((H5I_type_t)-1, testObj); + H5E_END_TRY + + VERIFY(arrayID, H5I_INVALID_HID, "H5Iregister"); + if (arrayID != H5I_INVALID_HID) + goto out; + + /* Try to access IDs with fictitious types */ + H5E_BEGIN_TRY + testPtr = H5Iobject_verify((hid_t)100, (H5I_type_t)0); + H5E_END_TRY + + CHECK_PTR_NULL(testPtr, "H5Iobject_verify"); + if (testPtr != NULL) + goto out; + + H5E_BEGIN_TRY + testPtr = H5Iobject_verify((hid_t)700, (H5I_type_t)700); + H5E_END_TRY + + CHECK_PTR_NULL(testPtr, "H5Iobject_verify"); + if (testPtr != NULL) + goto out; + + /* Register a type */ + myType = H5Iregister_type((size_t)64, 0, free_wrapper); + + CHECK(myType, H5I_BADID, "H5Iregister_type"); + if (myType == H5I_BADID) + goto out; + + /* Register an ID and retrieve the object it points to. + * Once the ID has been registered, testObj will be freed when + * its ID type is destroyed. + */ + testObj = HDmalloc(7 * sizeof(int)); + arrayID = H5Iregister(myType, testObj); + + CHECK(arrayID, H5I_INVALID_HID, "H5Iregister"); + if (arrayID == H5I_INVALID_HID) { + HDfree(testObj); + goto out; + } + + testPtr = (int *)H5Iobject_verify(arrayID, myType); + + CHECK_PTR_EQ(testPtr, testObj, "H5Iobject_verify"); + if (testPtr != testObj) + goto out; + + /* Ensure that H5Iget_file_id and H5Iget_name() fail, since this + * is an hid_t for the wrong kind of object + */ + H5E_BEGIN_TRY + testID = H5Iget_file_id(arrayID); + H5E_END_TRY + + VERIFY(testID, H5I_INVALID_HID, "H5Iget_file_id"); + if (testID != H5I_INVALID_HID) + goto out; + + H5E_BEGIN_TRY + testSize = H5Iget_name(arrayID, nameString, (size_t)9); + H5E_END_TRY + + VERIFY(testSize, -1, "H5Iget_name"); + if (testSize != -1) + goto out; + + /* Make sure H5Iremove_verify catches objects of the wrong type */ + H5E_BEGIN_TRY + testPtr = (int *)H5Iremove_verify(arrayID, (H5I_type_t)0); + H5E_END_TRY + + CHECK_PTR_NULL(testPtr, "H5Iremove_verify"); + if (testPtr != NULL) + goto out; + + H5E_BEGIN_TRY + testPtr = (int *)H5Iremove_verify(arrayID, (H5I_type_t)((int)myType - 1)); + H5E_END_TRY + + CHECK_PTR_NULL(testPtr, "H5Iremove_verify"); + if (testPtr != NULL) + goto out; + + /* Remove an ID and make sure we can't access it */ + testPtr = (int *)H5Iremove_verify(arrayID, myType); + + CHECK_PTR(testPtr, "H5Iremove_verify"); + if (testPtr == NULL) + goto out; + + H5E_BEGIN_TRY + testPtr = (int *)H5Iobject_verify(arrayID, myType); + H5E_END_TRY + + CHECK_PTR_NULL(testPtr, "H5Iobject_verify"); + if (testPtr != NULL) + goto out; + + /* Delete the type and make sure we can't access objects within it */ + arrayID = H5Iregister(myType, testObj); + + err = H5Idestroy_type(myType); + VERIFY(err, 0, "H5Idestroy_type"); + if (err != 0) + goto out; + VERIFY(H5Itype_exists(myType), 0, "H5Itype_exists"); + if (H5Itype_exists(myType) != 0) + goto out; + + H5E_BEGIN_TRY + VERIFY(H5Inmembers(myType, NULL), -1, "H5Inmembers"); + if (H5Inmembers(myType, NULL) != -1) + goto out; + H5E_END_TRY + + /* Register another type and another object in that type */ + myType = H5Iregister_type((size_t)64, 0, free_wrapper); + + CHECK(myType, H5I_BADID, "H5Iregister_type"); + if (myType == H5I_BADID) + goto out; + + /* The memory that testObj pointed to should already have been + * freed when the previous type was destroyed. Allocate new + * memory for it. + */ + testObj = HDmalloc(7 * sizeof(int)); + arrayID = H5Iregister(myType, testObj); + + CHECK(arrayID, H5I_INVALID_HID, "H5Iregister"); + if (arrayID == H5I_INVALID_HID) { + HDfree(testObj); + goto out; + } + + err = H5Inmembers(myType, &num_members); + CHECK(err, -1, "H5Inmembers"); + if (err < 0) + goto out; + VERIFY(num_members, 1, "H5Inmembers"); + if (num_members != 1) + goto out; + + /* Increment references to type and ensure that dec_type_ref + * doesn't destroy the type + */ + num_ref = H5Iinc_type_ref(myType); + VERIFY(num_ref, 2, "H5Iinc_type_ref"); + if (num_ref != 2) + goto out; + num_ref = H5Idec_type_ref(myType); + VERIFY(num_ref, 1, "H5Idec_type_ref"); + if (num_ref != 1) + goto out; + err = H5Inmembers(myType, &num_members); + CHECK(err, -1, "H5Inmembers"); + if (err < 0) + goto out; + VERIFY(num_members, 1, "H5Inmembers"); + if (num_members != 1) + goto out; + + /* This call to dec_type_ref should destroy the type */ + num_ref = H5Idec_type_ref(myType); + VERIFY(num_ref, 0, "H5Idec_type_ref"); + if (num_ref != 0) + goto out; + VERIFY(H5Itype_exists(myType), 0, "H5Itype_exists"); + if (H5Itype_exists(myType) != 0) + goto out; + + H5E_BEGIN_TRY + err = H5Inmembers(myType, &num_members); + if (err >= 0) + goto out; + H5E_END_TRY + + return 0; + +out: + /* Clean up type if it has been allocated and free memory used + * by testObj + */ + if (myType >= 0) + H5Idestroy_type(myType); + + return -1; +} + +/* A dummy search function for the next test */ +static int +test_search_func(void H5_ATTR_UNUSED *ptr1, hid_t H5_ATTR_UNUSED id, void H5_ATTR_UNUSED *ptr2) +{ + return 0; +} + +/* Ensure that public functions cannot access "predefined" ID types */ +static int +id_predefined_test(void) +{ + void *testObj; + hid_t testID; + hid_t typeID = H5I_INVALID_HID; + void *testPtr; + herr_t testErr; + + testObj = HDmalloc(sizeof(int)); + + /* + * Attempt to perform public functions on various library types + */ + + H5E_BEGIN_TRY + testID = H5Iregister(H5I_FILE, testObj); + H5E_END_TRY + + VERIFY(testID, H5I_INVALID_HID, "H5Iregister"); + if (testID != H5I_INVALID_HID) + goto out; + + H5E_BEGIN_TRY + testPtr = H5Isearch(H5I_GENPROP_LST, test_search_func, testObj); + H5E_END_TRY + + CHECK_PTR_NULL(testPtr, "H5Isearch"); + if (testPtr != NULL) + goto out; + + H5E_BEGIN_TRY + testErr = H5Inmembers(H5I_ERROR_STACK, NULL); + H5E_END_TRY + + VERIFY(testErr, -1, "H5Inmembers"); + if (testErr != -1) + goto out; + + H5E_BEGIN_TRY + testErr = H5Iclear_type(H5I_FILE, 0); + H5E_END_TRY + + VERIFY((testErr >= 0), 0, "H5Iclear_type"); + if (testErr >= 0) + goto out; + + H5E_BEGIN_TRY + testErr = H5Idestroy_type(H5I_DATASET); + H5E_END_TRY + + VERIFY((testErr >= 0), 0, "H5Idestroy_type"); + if (testErr >= 0) + goto out; + + H5E_BEGIN_TRY + testErr = H5Itype_exists(H5I_GROUP); + H5E_END_TRY + + VERIFY(testErr, -1, "H5Itype_exists"); + if (testErr != -1) + goto out; + + H5E_BEGIN_TRY + testErr = H5Itype_exists(H5I_ATTR); + H5E_END_TRY + + VERIFY(testErr, -1, "H5Itype_exists"); + if (testErr != -1) + goto out; + + /* + * Create a datatype ID and try to perform illegal functions on it + */ + + typeID = H5Tcreate(H5T_OPAQUE, (size_t)42); + CHECK(typeID, H5I_INVALID_HID, "H5Tcreate"); + if (typeID == H5I_INVALID_HID) + goto out; + + H5E_BEGIN_TRY + testPtr = H5Iremove_verify(typeID, H5I_DATATYPE); + H5E_END_TRY + + CHECK_PTR_NULL(testPtr, "H5Iremove_verify"); + if (testPtr != NULL) + goto out; + + H5E_BEGIN_TRY + testPtr = H5Iobject_verify(typeID, H5I_DATATYPE); + H5E_END_TRY + + CHECK_PTR_NULL(testPtr, "H5Iobject_verify"); + if (testPtr != NULL) + goto out; + + H5Tclose(typeID); + + /* testObj was never registered as an atom, so it will not be + * automatically freed. */ + HDfree(testObj); + return 0; + +out: + if (typeID != H5I_INVALID_HID) + H5Tclose(typeID); + if (testObj != NULL) + HDfree(testObj); + + return -1; +} + +/* Test the H5Iis_valid function */ +static int +test_is_valid(void) +{ + hid_t dtype; /* datatype id */ +#if 0 + int64_t nmembs1; /* number of type memnbers */ + int64_t nmembs2; +#endif + htri_t tri_ret; /* htri_t return value */ +#if 0 + herr_t ret; /* return value */ +#endif + + /* Create a datatype id */ + dtype = H5Tcopy(H5T_NATIVE_INT); + CHECK(dtype, FAIL, "H5Tcopy"); + if (dtype < 0) + goto out; + + /* Check that the ID is valid */ + tri_ret = H5Iis_valid(dtype); + VERIFY(tri_ret, TRUE, "H5Iis_valid"); + if (tri_ret != TRUE) + goto out; +#if 0 /* Cannot call internal APIs and cannot call public H5Inmembers on library types */ + /* Artificially manipulate the reference counts so app_count is 0, and dtype + * appears to be an internal id. This takes advantage of the fact that + * H5Ipkg is included. + */ + ret = H5I_inc_ref(dtype, FALSE); + CHECK(ret, FAIL, "H5I_inc_ref"); + if (ret < 0) + goto out; + ret = H5I_dec_app_ref(dtype); + CHECK(ret, FAIL, "H5I_dec_ref"); + if (ret < 0) + goto out; + + /* Check that dtype is invalid */ + tri_ret = H5Iis_valid(dtype); + VERIFY(tri_ret, FALSE, "H5Iis_valid"); + if (tri_ret != FALSE) + goto out; + + /* Close dtype and verify that it has been closed */ + nmembs1 = H5I_nmembers(H5I_DATATYPE); + CHECK(nmembs1, FAIL, "H5I_nmembers"); + if (nmembs1 < 0) + goto out; + ret = H5I_dec_ref(dtype); + CHECK(ret, FAIL, "H5I_dec_ref"); + if (ret < 0) + goto out; + nmembs2 = H5I_nmembers(H5I_DATATYPE); + VERIFY(nmembs2, nmembs1 - 1, "H5I_nmembers"); + if (nmembs2 != nmembs1 - 1) + goto out; + + /* Check that dtype is invalid */ + tri_ret = H5Iis_valid(dtype); + VERIFY(tri_ret, FALSE, "H5Iis_valid"); + if (tri_ret != FALSE) + goto out; +#endif + /* Check that an id of -1 is invalid */ + tri_ret = H5Iis_valid((hid_t)-1); + VERIFY(tri_ret, FALSE, "H4Iis_valid"); + if (tri_ret != FALSE) + goto out; + + return 0; + +out: + /* Don't attempt to close dtype as we don't know the exact state of the + * reference counts. Every state in this function will be automatically + * closed at library exit anyways, as internal count is never > 1. + */ + return -1; +} + +/* Test the H5Iget_type function */ +static int +test_get_type(void) +{ + hid_t dtype; /* datatype id */ + H5I_type_t type_ret; /* return value */ + + /* Create a datatype id */ + dtype = H5Tcopy(H5T_NATIVE_INT); + CHECK(dtype, FAIL, "H5Tcopy"); + if (dtype < 0) + goto out; + + /* Check that the ID is correct */ + type_ret = H5Iget_type(dtype); + VERIFY(type_ret, H5I_DATATYPE, "H5Iget_type"); + if (type_ret == H5I_BADID) + goto out; + + /* Check that the ID is correct */ + type_ret = H5Iget_type((hid_t)H5T_STRING); + VERIFY(type_ret, H5I_BADID, "H5Iget_type"); + if (type_ret != H5I_BADID) + goto out; + + /* Check that the ID is correct */ + type_ret = H5Iget_type((hid_t)-1); + VERIFY(type_ret, H5I_BADID, "H5Iget_type"); + if (type_ret != H5I_BADID) + goto out; + + H5Tclose(dtype); + + return 0; + +out: + if (dtype != H5I_INVALID_HID) + H5Tclose(dtype); + + return -1; +} + +/* Test boundary cases with lots of types */ + +/* Type IDs range from H5I_NTYPES to H5I_MAX_NUM_TYPES. The system will assign */ +/* IDs in sequential order until H5I_MAX_NUM_TYPES IDs have been given out, at which */ +/* point it will search for type IDs that were allocated but have since been */ +/* deleted. */ +/* This test will allocate IDs up to H5I_MAX_NUM_TYPES, ensure that IDs wrap around */ +/* to low values successfully, ensure that an error is thrown when all possible */ +/* type IDs are taken, then ensure that deleting types frees up their IDs. */ +/* Note that this test depends on the implementation of IDs, so may break */ +/* if the implementation changes. */ +/* Also note that if someone else registered a user-defined type and forgot to */ +/* destroy it, this test will mysteriously fail (because it will expect there to */ +/* be one more "free" type ID than there is). */ +/* H5I_NTYPES is defined in h5public.h, H5I_MAX_NUM_TYPES is defined in h5pkg.h */ +static int +test_id_type_list(void) +{ + H5I_type_t startType; /* The first type ID we were assigned in this test */ + H5I_type_t currentType; + H5I_type_t testType; + int i; /* Just a counter variable */ + + startType = H5Iregister_type((size_t)8, 0, free_wrapper); + CHECK(startType, H5I_BADID, "H5Iregister_type"); + if (startType == H5I_BADID) + goto out; + + /* Sanity check */ + if ((int)startType >= H5I_MAX_NUM_TYPES || startType < H5I_NTYPES) { + /* Error condition, throw an error */ + ERROR("H5Iregister_type"); + goto out; + } + /* Create types up to H5I_MAX_NUM_TYPES */ + for (i = startType + 1; i < H5I_MAX_NUM_TYPES; i++) { + currentType = H5Iregister_type((size_t)8, 0, free_wrapper); + CHECK(currentType, H5I_BADID, "H5Iregister_type"); + if (currentType == H5I_BADID) + goto out; + } + + /* Wrap around to low type ID numbers */ + for (i = H5I_NTYPES; i < startType; i++) { + currentType = H5Iregister_type((size_t)8, 0, free_wrapper); + CHECK(currentType, H5I_BADID, "H5Iregister_type"); + if (currentType == H5I_BADID) + goto out; + } + + /* There should be no room at the inn for a new ID type*/ + H5E_BEGIN_TRY + testType = H5Iregister_type((size_t)8, 0, free_wrapper); + H5E_END_TRY + + VERIFY(testType, H5I_BADID, "H5Iregister_type"); + if (testType != H5I_BADID) + goto out; + + /* Now delete a type and try to insert again */ + H5Idestroy_type(H5I_NTYPES); + testType = H5Iregister_type((size_t)8, 0, free_wrapper); + + VERIFY(testType, H5I_NTYPES, "H5Iregister_type"); + if (testType != H5I_NTYPES) + goto out; + + /* Cleanup. Destroy all types. */ + for (i = H5I_NTYPES; i < H5I_MAX_NUM_TYPES; i++) + H5Idestroy_type((H5I_type_t)i); + + return 0; + +out: + /* Cleanup. For simplicity, just destroy all types and ignore errors. */ + H5E_BEGIN_TRY + for (i = H5I_NTYPES; i < H5I_MAX_NUM_TYPES; i++) + H5Idestroy_type((H5I_type_t)i); + H5E_END_TRY + return -1; +} + +/* Test removing ids in callback for H5Iclear_type */ + +/* There was a rare bug where, if an id free callback being called by + * H5I_clear_type() removed another id in that type, a segfault could occur. + * This test tests for that error (and freeing ids "out of order" within + * H5Iclear_type() in general). + * + * NB: RCT = "remove clear type" + */ + +/* Macro definitions */ +#define RCT_MAX_NOBJS 25 /* Maximum number of objects in the list */ +#define RCT_MIN_NOBJS 5 +#define RCT_NITER 50 /* Number of times we cycle through object creation and deletion */ + +/* Structure to hold the master list of objects */ +typedef struct rct_obj_list_t { + + /* Pointer to the objects */ + struct rct_obj_t *objects; + + /* The number of objects in the list */ + long count; + + /* The number of objects in the list that have not been freed */ + long remaining; +} rct_obj_list_t; + +/* Structure for an object */ +typedef struct rct_obj_t { + /* The ID for this object */ + hid_t id; + + /* The number of times this object has been freed */ + int nfrees; + + /* Whether we are currently freeing this object directly + * through H5Idec_ref(). + */ + hbool_t freeing; + + /* Pointer to the master list of all objects */ + rct_obj_list_t *list; +} rct_obj_t; + +/* Free callback passed to H5Iclear_type() + * + * When invoked on a closing object, frees a random unfreed ID in the + * master list of objects. + */ +static herr_t +rct_free_cb(void *_obj, void H5_ATTR_UNUSED **_ctx) +{ + rct_obj_t *obj = (rct_obj_t *)_obj; + long remove_nth; + long i; + herr_t ret; + + /* Mark this object as freed */ + obj->nfrees++; + + /* Decrement the number of objects in the list that have not been freed */ + obj->list->remaining--; + + /* If this object isn't already being freed by a callback free call and + * the master object list still contains objects to free, pick another + * object and free it. + */ + if (!obj->freeing && (obj->list->remaining > 0)) { + + /* Pick a random object from the list. This is done by picking a + * random number between 0 and the # of remaining unfreed objects + * and then scanning through the list to find that nth unfreed + * object. + */ + remove_nth = HDrandom() % obj->list->remaining; + for (i = 0; i < obj->list->count; i++) + if (obj->list->objects[i].nfrees == 0) { + if (remove_nth == 0) + break; + else + remove_nth--; + } + + /* Badness if we scanned through the list and didn't manage to + * select one to delete (the list stats were probably updated + * incorrectly). + */ + if (i == obj->list->count) { + ERROR("invalid obj_list"); + goto error; + } + + /* Mark the object we're about to free so its own callback does + * not free another object. We don't want to recursively free the + * entire list when we free the first ID. + */ + obj->list->objects[i].freeing = TRUE; + + /* Decrement the reference count on the object */ + ret = H5Idec_ref(obj->list->objects[i].id); + CHECK(ret, FAIL, "H5Idec_ref"); + if (ret == FAIL) + goto error; + + /* Unset the "freeing" flag */ + obj->list->objects[i].freeing = FALSE; + } + + /* Verify the number of objects remaining in the master list is non-negative */ + if (obj->list->remaining < 0) { + ERROR("invalid number of objects remaining"); + goto error; + } + + return 0; + +error: + return -1; +} /* end rct_free_cb() */ + +/* Test function */ +static int +test_remove_clear_type(void) +{ + H5I_type_t obj_type; + rct_obj_list_t obj_list; + rct_obj_t *objects = NULL; /* Convenience pointer to objects stored in master list */ + size_t list_size; + long i, j; + herr_t ret; /* return value */ + + /* Register a user-defined type with our custom ID-deleting callback */ + obj_type = H5Iregister_type((size_t)8, 0, rct_free_cb); + CHECK(obj_type, H5I_BADID, "H5Iregister_type"); + if (obj_type == H5I_BADID) + goto error; + + /* Create an array to hold the objects in the master list */ + list_size = RCT_MAX_NOBJS * sizeof(rct_obj_t); + obj_list.objects = HDmalloc(list_size); + CHECK_PTR(obj_list.objects, "HDcalloc"); + if (NULL == obj_list.objects) + goto error; + + /* Set a convenience pointer to the object array */ + objects = obj_list.objects; + + for (i = 0; i < RCT_NITER; i++) { + + /* The number of members in the type, according to the HDF5 library */ + hsize_t nmembers = 1234567; /* (init to fake number) */ + + /* The number of objects found while scanning through the object list */ + int found; + + /********************* + * Build object list * + *********************/ + + HDmemset(obj_list.objects, 0, list_size); + + /* The number of objects used is a random number between the min and max */ + obj_list.count = obj_list.remaining = + RCT_MIN_NOBJS + (HDrandom() % (long)(RCT_MAX_NOBJS - RCT_MIN_NOBJS + 1)); + + /* Create the actual objects */ + for (j = 0; j < obj_list.count; j++) { + + /* Object setup */ + objects[j].nfrees = 0; + objects[j].freeing = FALSE; + objects[j].list = &obj_list; + + /* Register an ID for it */ + objects[j].id = H5Iregister(obj_type, &objects[j]); + CHECK(objects[j].id, FAIL, "H5Iregister"); + if (objects[j].id == FAIL) + goto error; + + /* Bump the reference count by 1 (to 2) 50% of the time */ + if (HDrandom() % 2) { + ret = H5Iinc_ref(objects[j].id); + CHECK(ret, FAIL, "H5Iinc_ref"); + if (ret == FAIL) + goto error; + } + } + + /****************************************** + * Clear the type with force set to FALSE * + ******************************************/ + + /* Clear the type. Since force is FALSE, only + * IDs with a reference count of 1 will be cleared. + */ + ret = H5Iclear_type(obj_type, FALSE); + CHECK(ret, FAIL, "H5Iclear_type"); + if (ret == FAIL) + goto error; + + /* Verify that the object struct fields are sane and count the + * number of unfreed objects + */ + found = 0; + for (j = 0; j < obj_list.count; j++) { + + if (objects[j].nfrees == 0) { + /* Count unfreed objects */ + found++; + } + else { + /* Every freed object should have been freed exactly once */ + VERIFY(objects[j].nfrees, 1, "object freed more than once"); + if (objects[j].nfrees != 1) + goto error; + } + + /* No object should still be marked as "freeing" */ + VERIFY(objects[j].freeing, FALSE, "object marked as freeing"); + if (objects[j].freeing != FALSE) + goto error; + } + + /* Verify the number of unfreed objects we found during our scan + * matches the number stored in the list + */ + VERIFY(obj_list.remaining, found, "incorrect number of objects remaining"); + if (obj_list.remaining != found) + goto error; + + /* Make sure the HDF5 library confirms our count */ + ret = H5Inmembers(obj_type, &nmembers); + CHECK(ret, FAIL, "H5Inmembers"); + if (ret == FAIL) + goto error; + VERIFY(nmembers, found, "The number of members remaining in the type did not match our count"); + if (nmembers != (hsize_t)found) + goto error; + + /***************************************** + * Clear the type with force set to TRUE * + *****************************************/ + + /* Clear the type. Since force is TRUE, all IDs will be cleared. */ + ret = H5Iclear_type(obj_type, TRUE); + CHECK(ret, FAIL, "H5Iclear_type"); + if (ret == FAIL) + goto error; + + /* Verify that the object struct fields are sane */ + for (j = 0; j < obj_list.count; j++) { + + /* Every object should have been freed exactly once */ + VERIFY(objects[j].nfrees, 1, "object freed more than once"); + if (objects[j].nfrees != 1) + goto error; + + /* No object should still be marked as "freeing" */ + VERIFY(objects[j].freeing, FALSE, "object marked as freeing"); + if (objects[j].freeing != FALSE) + goto error; + } + + /* Verify the number of objects is 0 */ + VERIFY(obj_list.remaining, 0, "objects remaining was not zero"); + if (obj_list.remaining != 0) + goto error; + + /* Make sure the HDF5 library confirms zero members in the type */ + ret = H5Inmembers(obj_type, &nmembers); + CHECK(ret, FAIL, "H5Inmembers"); + if (ret == FAIL) + goto error; + VERIFY(nmembers, 0, "The number of members remaining in the type was not zero"); + if (nmembers != 0) + goto error; + } + + /* Destroy the type */ + ret = H5Idestroy_type(obj_type); + CHECK(ret, FAIL, "H5Idestroy_type"); + if (ret == FAIL) + goto error; + + /* Free the object array */ + HDfree(obj_list.objects); + + return 0; + +error: + /* Cleanup. For simplicity, just destroy the types and ignore errors. */ + H5E_BEGIN_TRY + { + H5Idestroy_type(obj_type); + } + H5E_END_TRY + + HDfree(obj_list.objects); + + return -1; +} /* end test_remove_clear_type() */ + +#if defined(H5VL_VERSION) && H5VL_VERSION >= 2 +/* Typedef for future objects */ +typedef struct { + H5I_type_t obj_type; /* ID type for actual object */ +} future_obj_t; + +/* Global (static) future ID object type */ +H5I_type_t future_obj_type_g = H5I_BADID; + +/* Callback to free the actual object for future object test */ +static herr_t +free_actual_object(void *_p, void H5_ATTR_UNUSED **_ctx) +{ + int *p = (int *)_p; + + if (7 != *p) + return FAIL; + + HDfree(p); + + return SUCCEED; +} + +/* Callback to realize a future object */ +static herr_t +realize_future_cb(void *_future_obj, hid_t *actual_id) +{ + future_obj_t *future_obj = (future_obj_t *)_future_obj; /* Future object */ + int *actual_obj; /* Pointer to the actual object */ + + /* Check for bad future object */ + if (NULL == future_obj) + return FAIL; + + /* Determine type of object to realize */ + if (H5I_DATASPACE == future_obj->obj_type) { + hsize_t dims = 13; + + if ((*actual_id = H5Screate_simple(1, &dims, NULL)) < 0) + return FAIL; + } + else if (H5I_DATATYPE == future_obj->obj_type) { + if ((*actual_id = H5Tcopy(H5T_NATIVE_INT)) < 0) + return FAIL; + } + else if (H5I_GENPROP_LST == future_obj->obj_type) { + if ((*actual_id = H5Pcreate(H5P_DATASET_XFER)) < 0) + return FAIL; + } + else { + /* Create a new object (the 'actual object') of the correct type */ + if (NULL == (actual_obj = HDmalloc(sizeof(int)))) + return FAIL; + *actual_obj = 7; + + /* Register actual object of the user-defined type */ + *actual_id = H5Iregister(future_obj->obj_type, actual_obj); + CHECK(*actual_id, FAIL, "H5Iregister"); + if (*actual_id == FAIL) + return FAIL; + } + + return SUCCEED; +} + +/* Callback to discard a future object */ +static herr_t +discard_future_cb(void *future_obj) +{ + if (NULL == future_obj) + return FAIL; + + HDfree(future_obj); + + return SUCCEED; +} + +/* Callback to realize a future object when future objects are NULL*/ +static herr_t +realize_future_generate_cb(void *_future_obj, hid_t *actual_id) +{ + future_obj_t *future_obj = (future_obj_t *)_future_obj; /* Future object */ + int *actual_obj; /* Pointer to the actual object */ + + if (NULL != future_obj) + return FAIL; + /* Create a new object (the 'actual object') of the correct type */ + if (NULL == (actual_obj = HDmalloc(sizeof(int)))) + return FAIL; + *actual_obj = 7; + + /* Register actual object without using future object info */ + *actual_id = H5Iregister(future_obj_type_g, actual_obj); + CHECK(*actual_id, FAIL, "H5Iregister"); + if (*actual_id == FAIL) + return FAIL; + + return SUCCEED; +} + +/* Callback to discard a future object when future objects are NULL */ +static herr_t +discard_future_generate_cb(void *future_obj) +{ + if (NULL != future_obj) + return FAIL; + + return SUCCEED; +} + +/* Test function */ +static int +test_future_ids(void) +{ + H5I_type_t obj_type; /* New user-defined ID type */ + hid_t future_id; /* ID for future object */ + int fake_future_obj; /* "Fake" future object for tests */ + future_obj_t *future_obj; /* Future object */ + int *actual_obj; /* Actual object */ + int *actual_obj2; /* Another actual object */ + H5I_type_t id_type; /* Type of ID */ + H5T_class_t type_class; /* Datatype class */ + herr_t ret; /* Return value */ + + /* Register a user-defined type with our custom ID-deleting callback */ + obj_type = H5Iregister_type((size_t)15, 0, free_actual_object); + CHECK(obj_type, H5I_BADID, "H5Iregister_type"); + if (H5I_BADID == obj_type) + goto error; + + /* Test basic error conditions */ + fake_future_obj = 0; + H5E_BEGIN_TRY + { + future_id = H5Iregister_future(obj_type, &fake_future_obj, NULL, NULL); + } + H5E_END_TRY + VERIFY(future_id, H5I_INVALID_HID, "H5Iregister_future"); + if (H5I_INVALID_HID != future_id) + goto error; + + H5E_BEGIN_TRY + { + future_id = H5Iregister_future(obj_type, &fake_future_obj, realize_future_cb, NULL); + } + H5E_END_TRY + VERIFY(future_id, H5I_INVALID_HID, "H5Iregister_future"); + if (H5I_INVALID_HID != future_id) + goto error; + + H5E_BEGIN_TRY + { + future_id = H5Iregister_future(obj_type, &fake_future_obj, NULL, discard_future_cb); + } + H5E_END_TRY + VERIFY(future_id, H5I_INVALID_HID, "H5Iregister_future"); + if (H5I_INVALID_HID != future_id) + goto error; + + H5E_BEGIN_TRY + { + future_id = H5Iregister_future(H5I_BADID, &fake_future_obj, realize_future_cb, discard_future_cb); + } + H5E_END_TRY + VERIFY(future_id, H5I_INVALID_HID, "H5Iregister_future"); + if (H5I_INVALID_HID != future_id) + goto error; + + /* Test base use-case: create a future object and destroy type without + * realizing the future object. + */ + future_obj = HDmalloc(sizeof(future_obj_t)); + future_obj->obj_type = obj_type; + future_id = H5Iregister_future(obj_type, future_obj, realize_future_cb, discard_future_cb); + CHECK(future_id, H5I_INVALID_HID, "H5Iregister_future"); + if (H5I_INVALID_HID == future_id) + goto error; + + /* Destroy the type */ + ret = H5Idestroy_type(obj_type); + CHECK(ret, FAIL, "H5Idestroy_type"); + if (FAIL == ret) + goto error; + + /* Re-register a user-defined type with our custom ID-deleting callback */ + obj_type = H5Iregister_type((size_t)15, 0, free_actual_object); + CHECK(obj_type, H5I_BADID, "H5Iregister_type"); + if (H5I_BADID == obj_type) + goto error; + + /* Test base use-case: create a future object and realize the actual object. */ + future_obj = HDmalloc(sizeof(future_obj_t)); + future_obj->obj_type = obj_type; + future_id = H5Iregister_future(obj_type, future_obj, realize_future_cb, discard_future_cb); + CHECK(future_id, H5I_INVALID_HID, "H5Iregister_future"); + if (H5I_INVALID_HID == future_id) + goto error; + + actual_obj = H5Iobject_verify(future_id, obj_type); + CHECK_PTR(actual_obj, "H5Iobject_verify"); + if (NULL == actual_obj) + goto error; + VERIFY(*actual_obj, 7, "H5Iobject_verify"); + if (7 != *actual_obj) + goto error; + + /* Retrieve the object again and verify that it's the same actual object */ + actual_obj2 = H5Iobject_verify(future_id, obj_type); + CHECK_PTR(actual_obj2, "H5Iobject_verify"); + if (NULL == actual_obj2) + goto error; + VERIFY(*actual_obj2, 7, "H5Iobject_verify"); + if (7 != *actual_obj2) + goto error; + CHECK_PTR_EQ(actual_obj, actual_obj2, "H5Iobject_verify"); + if (actual_obj != actual_obj2) + goto error; + + /* Destroy the type */ + ret = H5Idestroy_type(obj_type); + CHECK(ret, FAIL, "H5Idestroy_type"); + if (FAIL == ret) + goto error; + + /* Re-register a user-defined type with our custom ID-deleting callback */ + obj_type = H5Iregister_type((size_t)15, 0, free_actual_object); + CHECK(obj_type, H5I_BADID, "H5Iregister_type"); + if (H5I_BADID == obj_type) + goto error; + + /* Set the global future object type */ + future_obj_type_g = obj_type; + + /* Test "actual object generator" use-case: create a future object with + * NULL object pointer, to create new object of predefined type when + * future object is realized. + */ + future_id = H5Iregister_future(obj_type, NULL, realize_future_generate_cb, discard_future_generate_cb); + CHECK(future_id, H5I_INVALID_HID, "H5Iregister_future"); + if (H5I_INVALID_HID == future_id) + goto error; + + /* Realize the actual object, with will be dynamically allocated within + * the 'realize' callback. + */ + actual_obj = H5Iobject_verify(future_id, obj_type); + CHECK_PTR(actual_obj, "H5Iobject_verify"); + if (NULL == actual_obj) + goto error; + VERIFY(*actual_obj, 7, "H5Iobject_verify"); + if (7 != *actual_obj) + goto error; + + /* Reset the global future object type */ + future_obj_type_g = H5I_BADID; + + /* Retrieve the object again and verify that it's the same actual object */ + /* (Will fail if global future object type used) */ + actual_obj2 = H5Iobject_verify(future_id, obj_type); + CHECK_PTR(actual_obj2, "H5Iobject_verify"); + if (NULL == actual_obj2) + goto error; + VERIFY(*actual_obj2, 7, "H5Iobject_verify"); + if (7 != *actual_obj2) + goto error; + CHECK_PTR_EQ(actual_obj, actual_obj2, "H5Iobject_verify"); + if (actual_obj != actual_obj2) + goto error; + + /* Destroy the type */ + ret = H5Idestroy_type(obj_type); + CHECK(ret, FAIL, "H5Idestroy_type"); + if (FAIL == ret) + goto error; + + /* Test base use-case: create a future object for a pre-defined type */ + /* (DATASPACE) */ + future_obj = HDmalloc(sizeof(future_obj_t)); + future_obj->obj_type = H5I_DATASPACE; + future_id = H5Iregister_future(H5I_DATASPACE, future_obj, realize_future_cb, discard_future_cb); + CHECK(future_id, H5I_INVALID_HID, "H5Iregister_future"); + if (H5I_INVALID_HID == future_id) + goto error; + + /* (Can't verify the type of the future ID, because the library's current + * implementation realizes the object during sanity checks on the ID) + */ + + /* Close future object for pre-defined type without realizing it */ + ret = H5Idec_ref(future_id); + CHECK(ret, FAIL, "H5Idec_ref"); + if (FAIL == ret) + goto error; + + /* Test base use-case: create a future object for a pre-defined type */ + future_obj = HDmalloc(sizeof(future_obj_t)); + future_obj->obj_type = H5I_DATASPACE; + future_id = H5Iregister_future(H5I_DATASPACE, future_obj, realize_future_cb, discard_future_cb); + CHECK(future_id, H5I_INVALID_HID, "H5Iregister_future"); + if (H5I_INVALID_HID == future_id) + goto error; + + /* Verify that the application believes the future ID is a dataspace */ + /* (Currently realizes the object "implicitly" during a sanity check) */ + id_type = H5Iget_type(future_id); + CHECK(id_type, H5I_BADID, "H5Iget_type"); + if (H5I_BADID == id_type) + goto error; + if (H5I_DATASPACE != id_type) + goto error; + + /* Close future object for pre-defined type without realizing it */ + ret = H5Idec_ref(future_id); + CHECK(ret, FAIL, "H5Idec_ref"); + if (FAIL == ret) + goto error; + + /* Test base use-case: create a future object for a pre-defined type */ + future_obj = HDmalloc(sizeof(future_obj_t)); + future_obj->obj_type = H5I_DATASPACE; + future_id = H5Iregister_future(H5I_DATASPACE, future_obj, realize_future_cb, discard_future_cb); + CHECK(future_id, H5I_INVALID_HID, "H5Iregister_future"); + if (H5I_INVALID_HID == future_id) + goto error; + + /* Realize future dataspace by requesting its rank */ + ret = H5Sget_simple_extent_ndims(future_id); + CHECK(ret, FAIL, "H5Sget_simple_extent_ndims"); + if (FAIL == ret) + goto error; + if (1 != ret) + goto error; + + /* Verify that the application believes the ID is still a dataspace */ + id_type = H5Iget_type(future_id); + CHECK(id_type, H5I_BADID, "H5Iget_type"); + if (H5I_BADID == id_type) + goto error; + if (H5I_DATASPACE != id_type) + goto error; + + /* Close future object for pre-defined type after realizing it */ + ret = H5Idec_ref(future_id); + CHECK(ret, FAIL, "H5Idec_ref"); + if (FAIL == ret) + goto error; + + /* Test base use-case: create a future object for a pre-defined type */ + /* (DATATYPE) */ + future_obj = HDmalloc(sizeof(future_obj_t)); + future_obj->obj_type = H5I_DATATYPE; + future_id = H5Iregister_future(H5I_DATATYPE, future_obj, realize_future_cb, discard_future_cb); + CHECK(future_id, H5I_INVALID_HID, "H5Iregister_future"); + if (H5I_INVALID_HID == future_id) + goto error; + + /* (Can't verify the type of the future ID, because the library's current + * implementation realizes the object during sanity checks on the ID) + */ + + /* Close future object for pre-defined type without realizing it */ + ret = H5Idec_ref(future_id); + CHECK(ret, FAIL, "H5Idec_ref"); + if (FAIL == ret) + goto error; + + /* Test base use-case: create a future object for a pre-defined type */ + future_obj = HDmalloc(sizeof(future_obj_t)); + future_obj->obj_type = H5I_DATATYPE; + future_id = H5Iregister_future(H5I_DATATYPE, future_obj, realize_future_cb, discard_future_cb); + CHECK(future_id, H5I_INVALID_HID, "H5Iregister_future"); + if (H5I_INVALID_HID == future_id) + goto error; + + /* Verify that the application believes the future ID is a datatype */ + /* (Currently realizes the object "implicitly" during a sanity check) */ + id_type = H5Iget_type(future_id); + CHECK(id_type, H5I_BADID, "H5Iget_type"); + if (H5I_BADID == id_type) + goto error; + if (H5I_DATATYPE != id_type) + goto error; + + /* Close future object for pre-defined type without realizing it */ + ret = H5Idec_ref(future_id); + CHECK(ret, FAIL, "H5Idec_ref"); + if (FAIL == ret) + goto error; + + /* Test base use-case: create a future object for a pre-defined type */ + future_obj = HDmalloc(sizeof(future_obj_t)); + future_obj->obj_type = H5I_DATATYPE; + future_id = H5Iregister_future(H5I_DATATYPE, future_obj, realize_future_cb, discard_future_cb); + CHECK(future_id, H5I_INVALID_HID, "H5Iregister_future"); + if (H5I_INVALID_HID == future_id) + goto error; + + /* Realize future datatype by requesting its class */ + type_class = H5Tget_class(future_id); + CHECK(ret, FAIL, "H5Tget_class"); + if (FAIL == ret) + goto error; + if (H5T_INTEGER != type_class) + goto error; + + /* Verify that the application believes the ID is still a datatype */ + id_type = H5Iget_type(future_id); + CHECK(id_type, H5I_BADID, "H5Iget_type"); + if (H5I_BADID == id_type) + goto error; + if (H5I_DATATYPE != id_type) + goto error; + + /* Close future object for pre-defined type after realizing it */ + ret = H5Idec_ref(future_id); + CHECK(ret, FAIL, "H5Idec_ref"); + if (FAIL == ret) + goto error; + + /* Test base use-case: create a future object for a pre-defined type */ + /* (PROPERTY LIST) */ + future_obj = HDmalloc(sizeof(future_obj_t)); + future_obj->obj_type = H5I_GENPROP_LST; + future_id = H5Iregister_future(H5I_GENPROP_LST, future_obj, realize_future_cb, discard_future_cb); + CHECK(future_id, H5I_INVALID_HID, "H5Iregister_future"); + if (H5I_INVALID_HID == future_id) + goto error; + + /* (Can't verify the type of the future ID, because the library's current + * implementation realizes the object during sanity checks on the ID) + */ + + /* Close future object for pre-defined type without realizing it */ + ret = H5Idec_ref(future_id); + CHECK(ret, FAIL, "H5Idec_ref"); + if (FAIL == ret) + goto error; + + /* Test base use-case: create a future object for a pre-defined type */ + future_obj = HDmalloc(sizeof(future_obj_t)); + future_obj->obj_type = H5I_GENPROP_LST; + future_id = H5Iregister_future(H5I_GENPROP_LST, future_obj, realize_future_cb, discard_future_cb); + CHECK(future_id, H5I_INVALID_HID, "H5Iregister_future"); + if (H5I_INVALID_HID == future_id) + goto error; + + /* Verify that the application believes the future ID is a property list */ + /* (Currently realizes the object "implicitly" during a sanity check) */ + id_type = H5Iget_type(future_id); + CHECK(id_type, H5I_BADID, "H5Iget_type"); + if (H5I_BADID == id_type) + goto error; + if (H5I_GENPROP_LST != id_type) + goto error; + + /* Close future object for pre-defined type without realizing it */ + ret = H5Idec_ref(future_id); + CHECK(ret, FAIL, "H5Idec_ref"); + if (FAIL == ret) + goto error; + + /* Test base use-case: create a future object for a pre-defined type */ + future_obj = HDmalloc(sizeof(future_obj_t)); + future_obj->obj_type = H5I_GENPROP_LST; + future_id = H5Iregister_future(H5I_GENPROP_LST, future_obj, realize_future_cb, discard_future_cb); + CHECK(future_id, H5I_INVALID_HID, "H5Iregister_future"); + if (H5I_INVALID_HID == future_id) + goto error; + + /* Realize future property list by verifying its class */ + ret = H5Pisa_class(future_id, H5P_DATASET_XFER); + CHECK(ret, FAIL, "H5Pisa_class"); + if (FAIL == ret) + goto error; + if (TRUE != ret) + goto error; + + /* Verify that the application believes the ID is still a property list */ + id_type = H5Iget_type(future_id); + CHECK(id_type, H5I_BADID, "H5Iget_type"); + if (H5I_BADID == id_type) + goto error; + if (H5I_GENPROP_LST != id_type) + goto error; + + /* Close future object for pre-defined type after realizing it */ + ret = H5Idec_ref(future_id); + CHECK(ret, FAIL, "H5Idec_ref"); + if (FAIL == ret) + goto error; + + return 0; + +error: + /* Cleanup. For simplicity, just destroy the types and ignore errors. */ + H5E_BEGIN_TRY + { + H5Idestroy_type(obj_type); + } + H5E_END_TRY + + return -1; +} /* end test_future_ids() */ +#endif + +void +test_ids(void) +{ + /* Set the random # seed */ + HDsrandom((unsigned)HDtime(NULL)); + + if (basic_id_test() < 0) + TestErrPrintf("Basic ID test failed\n"); + if (id_predefined_test() < 0) + TestErrPrintf("Predefined ID type test failed\n"); + if (test_is_valid() < 0) + TestErrPrintf("H5Iis_valid test failed\n"); + if (test_get_type() < 0) + TestErrPrintf("H5Iget_type test failed\n"); + if (test_id_type_list() < 0) + TestErrPrintf("ID type list test failed\n"); + if (test_remove_clear_type() < 0) + TestErrPrintf("ID remove during H5Iclear_type test failed\n"); +#if defined(H5VL_VERSION) && H5VL_VERSION >= 2 + if (test_future_ids() < 0) + TestErrPrintf("Future ID test failed\n"); +#endif +} diff --git a/test/API/titerate.c b/test/API/titerate.c new file mode 100644 index 0000000..6cbebbd --- /dev/null +++ b/test/API/titerate.c @@ -0,0 +1,1263 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*********************************************************** + * + * Test program: titerate + * + * Test the Group & Attribute functionality + * + *************************************************************/ + +#include "testhdf5.h" +/* #include "H5srcdir.h" */ + +#define DATAFILE "titerate.h5" + +/* Number of datasets for group iteration test */ +#define NDATASETS 50 + +/* Number of attributes for attribute iteration test */ +#define NATTR 50 + +/* Number of groups for second group iteration test */ +#define ITER_NGROUPS 150 + +/* General maximum length of names used */ +#define NAMELEN 80 + +/* 1-D dataset with fixed dimensions */ +#define SPACE1_RANK 1 +#define SPACE1_DIM1 4 + +typedef enum { RET_ZERO, RET_TWO, RET_CHANGE, RET_CHANGE2 } iter_enum; + +/* Custom group iteration callback data */ +typedef struct { + char name[NAMELEN]; /* The name of the object */ + H5O_type_t type; /* The type of the object */ + iter_enum command; /* The type of return value */ +} iter_info; + +/* Definition for test_corrupted_attnamelen */ +#define CORRUPTED_ATNAMELEN_FILE "memleak_H5O_dtype_decode_helper_H5Odtype.h5" +#define DSET_NAME "image" +typedef struct searched_err_t { + char message[256]; + hbool_t found; +} searched_err_t; +#if 0 +/* Call back function for test_corrupted_attnamelen */ +static int find_err_msg_cb(unsigned n, const H5E_error2_t *err_desc, void *_client_data); +#endif +/* Local functions */ +int iter_strcmp(const void *s1, const void *s2); +int iter_strcmp2(const void *s1, const void *s2); +#ifndef NO_ITERATION_RESTART +static herr_t liter_cb(hid_t group, const char *name, const H5L_info2_t *info, void *op_data); +static herr_t liter_cb2(hid_t group, const char *name, const H5L_info2_t *info, void *op_data); +#endif +herr_t aiter_cb(hid_t group, const char *name, const H5A_info_t *ainfo, void *op_data); + +/**************************************************************** +** +** iter_strcmp(): String comparison routine for qsort +** +****************************************************************/ +H5_ATTR_PURE int +iter_strcmp(const void *s1, const void *s2) +{ + return (HDstrcmp(*(const char *const *)s1, *(const char *const *)s2)); +} + +/**************************************************************** +** +** liter_cb(): Custom link iteration callback routine. +** +****************************************************************/ +#ifndef NO_ITERATION_RESTART +static herr_t +liter_cb(hid_t H5_ATTR_UNUSED group, const char *name, const H5L_info2_t H5_ATTR_UNUSED *link_info, + void *op_data) +{ + iter_info *info = (iter_info *)op_data; + static int count = 0; + static int count2 = 0; + + HDstrcpy(info->name, name); + + switch (info->command) { + case RET_ZERO: + return (0); + + case RET_TWO: + return (2); + + case RET_CHANGE: + count++; + return (count > 10 ? 1 : 0); + + case RET_CHANGE2: + count2++; + return (count2 > 10 ? 1 : 0); + + default: + HDprintf("invalid iteration command"); + return (-1); + } /* end switch */ +} /* end liter_cb() */ +#endif + +/**************************************************************** +** +** test_iter_group(): Test group iteration functionality +** +****************************************************************/ +static void +test_iter_group(hid_t fapl, hbool_t new_format) +{ +#ifndef NO_ITERATION_RESTART + hid_t file; /* File ID */ + hid_t dataset; /* Dataset ID */ + hid_t datatype; /* Common datatype ID */ + hid_t filespace; /* Common dataspace ID */ + hid_t root_group, grp; /* Root group ID */ + int i; /* counting variable */ + hsize_t idx; /* Index in the group */ + char name[NAMELEN]; /* temporary name buffer */ + char *lnames[NDATASETS + 2]; /* Names of the links created */ + char dataset_name[NAMELEN]; /* dataset name */ + iter_info info; /* Custom iteration information */ + H5G_info_t ginfo; /* Buffer for querying object's info */ + herr_t ret; /* Generic return value */ +#else + (void)fapl; + (void)new_format; +#endif + + /* Output message about test being performed */ + MESSAGE( + 5, ("Testing Group Iteration Functionality - SKIPPED for now due to no iteration restart support\n")); +#ifndef NO_ITERATION_RESTART + /* Create the test file with the datasets */ + file = H5Fcreate(DATAFILE, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(file, FAIL, "H5Fcreate"); + + /* Test iterating over empty group */ + info.command = RET_ZERO; + idx = 0; + ret = H5Literate2(file, H5_INDEX_NAME, H5_ITER_INC, &idx, liter_cb, &info); + VERIFY(ret, SUCCEED, "H5Literate2"); + + datatype = H5Tcopy(H5T_NATIVE_INT); + CHECK(datatype, FAIL, "H5Tcopy"); + + filespace = H5Screate(H5S_SCALAR); + CHECK(filespace, FAIL, "H5Screate"); + + for (i = 0; i < NDATASETS; i++) { + HDsnprintf(name, sizeof(name), "Dataset %d", i); + dataset = H5Dcreate2(file, name, datatype, filespace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Keep a copy of the dataset names around for later */ + lnames[i] = HDstrdup(name); + CHECK_PTR(lnames[i], "strdup"); + + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + } /* end for */ + + /* Create a group and named datatype under root group for testing */ + grp = H5Gcreate2(file, "grp", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Gcreate2"); + + lnames[NDATASETS] = HDstrdup("grp"); + CHECK_PTR(lnames[NDATASETS], "strdup"); + + ret = H5Tcommit2(file, "dtype", datatype, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + + lnames[NDATASETS + 1] = HDstrdup("dtype"); + CHECK_PTR(lnames[NDATASETS], "strdup"); + + /* Close everything up */ + ret = H5Tclose(datatype); + CHECK(ret, FAIL, "H5Tclose"); + + ret = H5Gclose(grp); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Sclose(filespace); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + + /* Sort the dataset names */ + HDqsort(lnames, (size_t)(NDATASETS + 2), sizeof(char *), iter_strcmp); + + /* Iterate through the datasets in the root group in various ways */ + file = H5Fopen(DATAFILE, H5F_ACC_RDONLY, fapl); + CHECK(file, FAIL, "H5Fopen"); + + /* These two functions, H5Oget_info_by_idx and H5Lget_name_by_idx, actually + * iterate through B-tree for group members in internal library design. + */ + root_group = H5Gopen2(file, "/", H5P_DEFAULT); + CHECK(root_group, FAIL, "H5Gopen2"); + + ret = H5Gget_info(root_group, &ginfo); + CHECK(ret, FAIL, "H5Gget_info"); + VERIFY(ginfo.nlinks, (NDATASETS + 2), "H5Gget_info"); + + for (i = 0; i < (int)ginfo.nlinks; i++) { + H5O_info2_t oinfo; /* Object info */ + + ret = (herr_t)H5Lget_name_by_idx(root_group, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)i, + dataset_name, (size_t)NAMELEN, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lget_name_by_idx"); + + //! [H5Oget_info_by_idx3_snip] + + ret = H5Oget_info_by_idx3(root_group, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)i, &oinfo, + H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_idx"); + + //! [H5Oget_info_by_idx3_snip] + + } /* end for */ + + H5E_BEGIN_TRY + { + ret = + (herr_t)H5Lget_name_by_idx(root_group, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)(NDATASETS + 3), + dataset_name, (size_t)NAMELEN, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Lget_name_by_idx"); + + ret = H5Gclose(root_group); + CHECK(ret, FAIL, "H5Gclose"); + + /* These two functions, H5Oget_info_by_idx and H5Lget_name_by_idx, actually + * iterate through B-tree for group members in internal library design. + * (Same as test above, but with the file ID instead of opening the root group) + */ + ret = H5Gget_info(file, &ginfo); + CHECK(ret, FAIL, "H5Gget_info"); + VERIFY(ginfo.nlinks, NDATASETS + 2, "H5Gget_info"); + + for (i = 0; i < (int)ginfo.nlinks; i++) { + H5O_info2_t oinfo; /* Object info */ + + ret = (herr_t)H5Lget_name_by_idx(file, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)i, dataset_name, + (size_t)NAMELEN, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lget_name_by_idx"); + + ret = H5Oget_info_by_idx3(file, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)i, &oinfo, H5O_INFO_BASIC, + H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_idx3"); + } /* end for */ + + H5E_BEGIN_TRY + { + ret = (herr_t)H5Lget_name_by_idx(file, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)(NDATASETS + 3), + dataset_name, (size_t)NAMELEN, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Lget_name_by_idx"); + + /* Test invalid indices for starting iteration */ + info.command = RET_ZERO; + idx = (hsize_t)-1; + H5E_BEGIN_TRY + { + ret = H5Literate2(file, H5_INDEX_NAME, H5_ITER_INC, &idx, liter_cb, &info); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Literate2"); + + /* Test skipping exactly as many entries as in the group */ + idx = NDATASETS + 2; + H5E_BEGIN_TRY + { + ret = H5Literate2(file, H5_INDEX_NAME, H5_ITER_INC, &idx, liter_cb, &info); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Literate2"); + + /* Test skipping more entries than are in the group */ + idx = NDATASETS + 3; + H5E_BEGIN_TRY + { + ret = H5Literate2(file, H5_INDEX_NAME, H5_ITER_INC, &idx, liter_cb, &info); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Literate2"); + + /* Test all objects in group, when callback always returns 0 */ + info.command = RET_ZERO; + idx = 0; + if ((ret = H5Literate2(file, H5_INDEX_NAME, H5_ITER_INC, &idx, liter_cb, &info)) > 0) + TestErrPrintf("Group iteration function didn't return zero correctly!\n"); + + /* Test all objects in group, when callback always returns 1 */ + /* This also tests the "restarting" ability, because the index changes */ + info.command = RET_TWO; + i = 0; + idx = 0; + memset(info.name, 0, NAMELEN); + while ((ret = H5Literate2(file, H5_INDEX_NAME, H5_ITER_INC, &idx, liter_cb, &info)) > 0) { + /* Verify return value from iterator gets propagated correctly */ + VERIFY(ret, 2, "H5Literate2"); + + /* Increment the number of times "2" is returned */ + i++; + + /* Verify that the index is the correct value */ + VERIFY(idx, (hsize_t)i, "H5Literate2"); + if (idx != (hsize_t)i) + break; + if (idx > (NDATASETS + 2)) + TestErrPrintf("Group iteration function walked too far!\n"); + + /* Verify that the correct name is retrieved */ + if (HDstrncmp(info.name, lnames[(size_t)(idx - 1)], NAMELEN) != 0) + TestErrPrintf( + "Group iteration function didn't return name correctly for link - lnames[%u] = '%s'!\n", + (unsigned)(idx - 1), lnames[(size_t)(idx - 1)]); + } /* end while */ + VERIFY(ret, -1, "H5Literate2"); + + if (i != (NDATASETS + 2)) + TestErrPrintf("%u: Group iteration function didn't perform multiple iterations correctly!\n", + __LINE__); + + /* Test all objects in group, when callback changes return value */ + /* This also tests the "restarting" ability, because the index changes */ + info.command = new_format ? RET_CHANGE2 : RET_CHANGE; + i = 0; + idx = 0; + memset(info.name, 0, NAMELEN); + while ((ret = H5Literate2(file, H5_INDEX_NAME, H5_ITER_INC, &idx, liter_cb, &info)) >= 0) { + /* Verify return value from iterator gets propagated correctly */ + VERIFY(ret, 1, "H5Literate2"); + + /* Increment the number of times "1" is returned */ + i++; + + /* Verify that the index is the correct value */ + VERIFY(idx, (hsize_t)(i + 10), "H5Literate2"); + if (idx != (hsize_t)(i + 10)) + break; + if (idx > (NDATASETS + 2)) + TestErrPrintf("Group iteration function walked too far!\n"); + + /* Verify that the correct name is retrieved */ + if (HDstrncmp(info.name, lnames[(size_t)(idx - 1)], NAMELEN) != 0) + TestErrPrintf( + "Group iteration function didn't return name correctly for link - lnames[%u] = '%s'!\n", + (unsigned)(idx - 1), lnames[(size_t)(idx - 1)]); + } /* end while */ + VERIFY(ret, -1, "H5Literate2"); + + if (i != 42 || idx != 52) + TestErrPrintf("%u: Group iteration function didn't perform multiple iterations correctly!\n", + __LINE__); + + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free the dataset names */ + for (i = 0; i < (NDATASETS + 2); i++) + HDfree(lnames[i]); +#endif +} /* test_iter_group() */ + +/**************************************************************** +** +** aiter_cb(): Custom group iteration callback routine. +** +****************************************************************/ +herr_t +aiter_cb(hid_t H5_ATTR_UNUSED group, const char *name, const H5A_info_t H5_ATTR_UNUSED *ainfo, void *op_data) +{ + iter_info *info = (iter_info *)op_data; + static int count = 0; + static int count2 = 0; + + HDstrcpy(info->name, name); + + switch (info->command) { + case RET_ZERO: + return (0); + + case RET_TWO: + return (2); + + case RET_CHANGE: + count++; + return (count > 10 ? 1 : 0); + + case RET_CHANGE2: + count2++; + return (count2 > 10 ? 1 : 0); + + default: + HDprintf("invalid iteration command"); + return (-1); + } /* end switch */ +} /* end aiter_cb() */ + +/**************************************************************** +** +** test_iter_attr(): Test attribute iteration functionality +** +****************************************************************/ +static void +test_iter_attr(hid_t fapl, hbool_t new_format) +{ +#ifndef NO_ITERATION_RESTART + hid_t file; /* File ID */ + hid_t dataset; /* Common Dataset ID */ + hid_t filespace; /* Common dataspace ID */ + hid_t attribute; /* Attribute ID */ + int i; /* counting variable */ + hsize_t idx; /* Index in the attribute list */ + char name[NAMELEN]; /* temporary name buffer */ + char *anames[NATTR]; /* Names of the attributes created */ + iter_info info; /* Custom iteration information */ + herr_t ret; /* Generic return value */ +#else + (void)fapl; + (void)new_format; +#endif + + /* Output message about test being performed */ + MESSAGE( + 5, + ("Testing Attribute Iteration Functionality - SKIPPED for no due to no iteration restart support\n")); +#ifndef NO_ITERATION_RESTART + HDmemset(&info, 0, sizeof(iter_info)); + + /* Create the test file with the datasets */ + file = H5Fcreate(DATAFILE, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(file, FAIL, "H5Fcreate"); + + filespace = H5Screate(H5S_SCALAR); + CHECK(filespace, FAIL, "H5Screate"); + + dataset = H5Dcreate2(file, "Dataset", H5T_NATIVE_INT, filespace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + for (i = 0; i < NATTR; i++) { + HDsnprintf(name, sizeof(name), "Attribute %02d", i); + attribute = H5Acreate2(dataset, name, H5T_NATIVE_INT, filespace, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attribute, FAIL, "H5Acreate2"); + + /* Keep a copy of the attribute names around for later */ + anames[i] = HDstrdup(name); + CHECK_PTR(anames[i], "strdup"); + + ret = H5Aclose(attribute); + CHECK(ret, FAIL, "H5Aclose"); + } /* end for */ + + /* Close everything up */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Sclose(filespace); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + + /* Iterate through the attributes on the dataset in various ways */ + file = H5Fopen(DATAFILE, H5F_ACC_RDONLY, fapl); + CHECK(file, FAIL, "H5Fopen"); + + dataset = H5Dopen2(file, "Dataset", H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Test invalid indices for starting iteration */ + info.command = RET_ZERO; + + /* Test skipping exactly as many attributes as there are */ + idx = NATTR; + H5E_BEGIN_TRY + { + ret = H5Aiterate2(dataset, H5_INDEX_NAME, H5_ITER_INC, &idx, aiter_cb, &info); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Aiterate2"); + + /* Test skipping more attributes than there are */ + idx = NATTR + 1; + H5E_BEGIN_TRY + { + ret = H5Aiterate2(dataset, H5_INDEX_NAME, H5_ITER_INC, &idx, aiter_cb, &info); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Aiterate2"); + + /* Test all attributes on dataset, when callback always returns 0 */ + info.command = RET_ZERO; + idx = 0; + if ((ret = H5Aiterate2(dataset, H5_INDEX_NAME, H5_ITER_INC, &idx, aiter_cb, &info)) > 0) + TestErrPrintf("Attribute iteration function didn't return zero correctly!\n"); + + /* Test all attributes on dataset, when callback always returns 2 */ + /* This also tests the "restarting" ability, because the index changes */ + info.command = RET_TWO; + i = 0; + idx = 0; + while ((ret = H5Aiterate2(dataset, H5_INDEX_NAME, H5_ITER_INC, &idx, aiter_cb, &info)) > 0) { + /* Verify return value from iterator gets propagated correctly */ + VERIFY(ret, 2, "H5Aiterate2"); + + /* Increment the number of times "2" is returned */ + i++; + + /* Verify that the index is the correct value */ + VERIFY(idx, (unsigned)i, "H5Aiterate2"); + + /* Don't check name when new format is used */ + if (!new_format) { + /* Verify that the correct name is retrieved */ + if (idx > 0) { + if (HDstrcmp(info.name, anames[(size_t)idx - 1]) != 0) + TestErrPrintf("%u: Attribute iteration function didn't set names correctly, info.name = " + "'%s', anames[%u] = '%s'!\n", + __LINE__, info.name, (unsigned)(idx - 1), anames[(size_t)idx - 1]); + } /* end if */ + else + TestErrPrintf("%u: 'idx' was not set correctly!\n", __LINE__); + } /* end if */ + } /* end while */ + VERIFY(ret, -1, "H5Aiterate2"); + if (i != 50 || idx != 50) + TestErrPrintf("%u: Attribute iteration function didn't perform multiple iterations correctly!\n", + __LINE__); + + /* Test all attributes on dataset, when callback changes return value */ + /* This also tests the "restarting" ability, because the index changes */ + info.command = new_format ? RET_CHANGE2 : RET_CHANGE; + i = 0; + idx = 0; + while ((ret = H5Aiterate2(dataset, H5_INDEX_NAME, H5_ITER_INC, &idx, aiter_cb, &info)) > 0) { + /* Verify return value from iterator gets propagated correctly */ + VERIFY(ret, 1, "H5Aiterate2"); + + /* Increment the number of times "1" is returned */ + i++; + + /* Verify that the index is the correct value */ + VERIFY(idx, (unsigned)i + 10, "H5Aiterate2"); + + /* Don't check name when new format is used */ + if (!new_format) { + /* Verify that the correct name is retrieved */ + if (idx > 0) { + if (HDstrcmp(info.name, anames[(size_t)idx - 1]) != 0) + TestErrPrintf("%u: Attribute iteration function didn't set names correctly, info.name = " + "'%s', anames[%u] = '%s'!\n", + __LINE__, info.name, (unsigned)(idx - 1), anames[(size_t)idx - 1]); + } + else + TestErrPrintf("%u: 'idx' was not set correctly!\n", __LINE__); + } /* end if */ + } /* end while */ + VERIFY(ret, -1, "H5Aiterate2"); + if (i != 40 || idx != 50) + TestErrPrintf("%u: Attribute iteration function didn't perform multiple iterations correctly!\n", + __LINE__); + + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Free the attribute names */ + for (i = 0; i < NATTR; i++) + HDfree(anames[i]); +#endif +} /* test_iter_attr() */ + +/**************************************************************** +** +** iter_strcmp2(): String comparison routine for qsort +** +****************************************************************/ +H5_ATTR_PURE int +iter_strcmp2(const void *s1, const void *s2) +{ + return (HDstrcmp((const char *)s1, (const char *)s2)); +} /* end iter_strcmp2() */ + +/**************************************************************** +** +** liter_cb2(): Custom link iteration callback routine. +** +****************************************************************/ +#ifndef NO_ITERATION_RESTART +static herr_t +liter_cb2(hid_t loc_id, const char *name, const H5L_info2_t H5_ATTR_UNUSED *link_info, void *opdata) +{ + const iter_info *test_info = (const iter_info *)opdata; + H5O_info2_t oinfo; + herr_t ret; /* Generic return value */ + + if (HDstrcmp(name, test_info->name) != 0) { + TestErrPrintf("name = '%s', test_info = '%s'\n", name, test_info->name); + return (H5_ITER_ERROR); + } /* end if */ + + /* + * Get type of the object and check it. + */ + ret = H5Oget_info_by_name3(loc_id, name, &oinfo, H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name3"); + + if (test_info->type != oinfo.type) { + TestErrPrintf("test_info->type = %d, oinfo.type = %d\n", test_info->type, (int)oinfo.type); + return (H5_ITER_ERROR); + } /* end if */ + + return (H5_ITER_STOP); +} /* liter_cb2() */ +#endif + +/**************************************************************** +** +** test_iter_group_large(): Test group iteration functionality +** for groups with large #'s of objects +** +****************************************************************/ +static void +test_iter_group_large(hid_t fapl) +{ +#ifndef NO_ITERATION_RESTART + hid_t file; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t group; /* Group ID */ + hid_t sid; /* Dataspace ID */ + hid_t tid; /* Datatype ID */ + hsize_t dims[] = {SPACE1_DIM1}; + herr_t ret; /* Generic return value */ + char gname[20]; /* Temporary group name */ + iter_info *names; /* Names of objects in the root group */ + iter_info *curr_name; /* Pointer to the current name in the root group */ + int i; + + /* Compound datatype */ + typedef struct s1_t { + unsigned int a; + unsigned int b; + float c; + } s1_t; + + /* Allocate & initialize array */ + names = (iter_info *)HDcalloc(sizeof(iter_info), (ITER_NGROUPS + 2)); + CHECK_PTR(names, "HDcalloc"); +#else + (void)fapl; +#endif + /* Output message about test being performed */ + MESSAGE(5, ("Testing Large Group Iteration Functionality - SKIPPED for now due to no iteration restart " + "support\n")); +#ifndef NO_ITERATION_RESTART + /* Create file */ + file = H5Fcreate(DATAFILE, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(file, FAIL, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid = H5Screate_simple(SPACE1_RANK, dims, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Create a bunch of groups */ + for (i = 0; i < ITER_NGROUPS; i++) { + HDsnprintf(gname, sizeof(gname), "Group_%d", i); + + /* Add the name to the list of objects in the root group */ + HDstrcpy(names[i].name, gname); + names[i].type = H5O_TYPE_GROUP; + + /* Create a group */ + group = H5Gcreate2(file, gname, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(group, FAIL, "H5Gcreate2"); + + /* Close a group */ + ret = H5Gclose(group); + CHECK(ret, FAIL, "H5Gclose"); + } /* end for */ + + /* Create a dataset */ + dataset = H5Dcreate2(file, "Dataset1", H5T_STD_U32LE, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Add the name to the list of objects in the root group */ + HDstrcpy(names[ITER_NGROUPS].name, "Dataset1"); + names[ITER_NGROUPS].type = H5O_TYPE_DATASET; + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close Dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Create a datatype */ + tid = H5Tcreate(H5T_COMPOUND, sizeof(s1_t)); + CHECK(tid, FAIL, "H5Tcreate"); + + /* Insert fields */ + ret = H5Tinsert(tid, "a", HOFFSET(s1_t, a), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(tid, "b", HOFFSET(s1_t, b), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(tid, "c", HOFFSET(s1_t, c), H5T_NATIVE_FLOAT); + CHECK(ret, FAIL, "H5Tinsert"); + + /* Save datatype for later */ + ret = H5Tcommit2(file, "Datatype1", tid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + + /* Add the name to the list of objects in the root group */ + HDstrcpy(names[ITER_NGROUPS + 1].name, "Datatype1"); + names[ITER_NGROUPS + 1].type = H5O_TYPE_NAMED_DATATYPE; + + /* Close datatype */ + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Need to sort the names in the root group, cause that's what the library does */ + HDqsort(names, (size_t)(ITER_NGROUPS + 2), sizeof(iter_info), iter_strcmp2); + + /* Iterate through the file to see members of the root group */ + curr_name = &names[0]; + ret = H5Literate2(file, H5_INDEX_NAME, H5_ITER_INC, NULL, liter_cb2, curr_name); + CHECK(ret, FAIL, "H5Literate2"); + for (i = 1; i < 100; i++) { + hsize_t idx = (hsize_t)i; + + curr_name = &names[i]; + ret = H5Literate2(file, H5_INDEX_NAME, H5_ITER_INC, &idx, liter_cb2, curr_name); + CHECK(ret, FAIL, "H5Literate2"); + } /* end for */ + + /* Close file */ + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + + /* Release memory */ + HDfree(names); +#endif +} /* test_iterate_group_large() */ + +/**************************************************************** +** +** test_grp_memb_funcs(): Test group member information +** functionality +** +****************************************************************/ +static void +test_grp_memb_funcs(hid_t fapl) +{ + hid_t file; /* File ID */ + hid_t dataset; /* Dataset ID */ + hid_t datatype; /* Common datatype ID */ + hid_t filespace; /* Common dataspace ID */ + hid_t root_group, grp; /* Root group ID */ + int i; /* counting variable */ + char name[NAMELEN]; /* temporary name buffer */ + char *dnames[NDATASETS + 2]; /* Names of the datasets created */ + char *obj_names[NDATASETS + 2]; /* Names of the objects in group */ + char dataset_name[NAMELEN]; /* dataset name */ + ssize_t name_len; /* Length of object's name */ + H5G_info_t ginfo; /* Buffer for querying object's info */ + herr_t ret = SUCCEED; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Group Member Information Functionality\n")); + + /* Create the test file with the datasets */ + file = H5Fcreate(DATAFILE, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(file, FAIL, "H5Fcreate"); + + datatype = H5Tcopy(H5T_NATIVE_INT); + CHECK(datatype, FAIL, "H5Tcopy"); + + filespace = H5Screate(H5S_SCALAR); + CHECK(filespace, FAIL, "H5Screate"); + + for (i = 0; i < NDATASETS; i++) { + HDsnprintf(name, sizeof(name), "Dataset %d", i); + dataset = H5Dcreate2(file, name, datatype, filespace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Keep a copy of the dataset names around for later */ + dnames[i] = HDstrdup(name); + CHECK_PTR(dnames[i], "strdup"); + + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + } /* end for */ + + /* Create a group and named datatype under root group for testing */ + grp = H5Gcreate2(file, "grp", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Gcreate2"); + + dnames[NDATASETS] = HDstrdup("grp"); + CHECK_PTR(dnames[NDATASETS], "strdup"); + + ret = H5Tcommit2(file, "dtype", datatype, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + + dnames[NDATASETS + 1] = HDstrdup("dtype"); + CHECK_PTR(dnames[NDATASETS], "strdup"); + + /* Close everything up */ + ret = H5Tclose(datatype); + CHECK(ret, FAIL, "H5Tclose"); + + ret = H5Gclose(grp); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Sclose(filespace); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + + /* Sort the dataset names */ + HDqsort(dnames, (size_t)(NDATASETS + 2), sizeof(char *), iter_strcmp); + + /* Iterate through the datasets in the root group in various ways */ + file = H5Fopen(DATAFILE, H5F_ACC_RDONLY, fapl); + CHECK(file, FAIL, "H5Fopen"); + + /* These two functions, H5Oget_info_by_idx and H5Lget_name_by_idx, actually + * iterate through B-tree for group members in internal library design. + */ + root_group = H5Gopen2(file, "/", H5P_DEFAULT); + CHECK(root_group, FAIL, "H5Gopen2"); + + ret = H5Gget_info(root_group, &ginfo); + CHECK(ret, FAIL, "H5Gget_info"); + VERIFY(ginfo.nlinks, (NDATASETS + 2), "H5Gget_info"); + + for (i = 0; i < (int)ginfo.nlinks; i++) { + H5O_info2_t oinfo; /* Object info */ + + /* Test with NULL for name, to query length */ + name_len = H5Lget_name_by_idx(root_group, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)i, NULL, + (size_t)NAMELEN, H5P_DEFAULT); + CHECK(name_len, FAIL, "H5Lget_name_by_idx"); + + ret = (herr_t)H5Lget_name_by_idx(root_group, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)i, + dataset_name, (size_t)(name_len + 1), H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lget_name_by_idx"); + + /* Double-check that the length is the same */ + VERIFY(ret, name_len, "H5Lget_name_by_idx"); + + /* Keep a copy of the dataset names around for later */ + obj_names[i] = HDstrdup(dataset_name); + CHECK_PTR(obj_names[i], "strdup"); + + ret = H5Oget_info_by_idx3(root_group, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)i, &oinfo, + H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_idx3"); + + if (!HDstrcmp(dataset_name, "grp")) + VERIFY(oinfo.type, H5O_TYPE_GROUP, "H5Lget_name_by_idx"); + if (!HDstrcmp(dataset_name, "dtype")) + VERIFY(oinfo.type, H5O_TYPE_NAMED_DATATYPE, "H5Lget_name_by_idx"); + if (!HDstrncmp(dataset_name, "Dataset", (size_t)7)) + VERIFY(oinfo.type, H5O_TYPE_DATASET, "H5Lget_name_by_idx"); + } /* end for */ + + H5E_BEGIN_TRY + { + ret = + (herr_t)H5Lget_name_by_idx(root_group, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)(NDATASETS + 3), + dataset_name, (size_t)NAMELEN, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Lget_name_by_idx"); + + /* Sort the dataset names */ + HDqsort(obj_names, (size_t)(NDATASETS + 2), sizeof(char *), iter_strcmp); + + /* Compare object names */ + for (i = 0; i < (int)ginfo.nlinks; i++) { + ret = HDstrcmp(dnames[i], obj_names[i]); + VERIFY(ret, 0, "HDstrcmp"); + } /* end for */ + + ret = H5Gclose(root_group); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free the dataset names */ + for (i = 0; i < (NDATASETS + 2); i++) { + HDfree(dnames[i]); + HDfree(obj_names[i]); + } /* end for */ +} /* test_grp_memb_funcs() */ + +/**************************************************************** +** +** test_links(): Test soft and hard link iteration +** +****************************************************************/ +static void +test_links(hid_t fapl) +{ + hid_t file; /* File ID */ + char obj_name[NAMELEN]; /* Names of the object in group */ + ssize_t name_len; /* Length of object's name */ + hid_t gid, gid1; + H5G_info_t ginfo; /* Buffer for querying object's info */ + hsize_t i; + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Soft and Hard Link Iteration Functionality\n")); + + /* Create the test file with the datasets */ + file = H5Fcreate(DATAFILE, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(file, FAIL, "H5Fcreate"); + + /* create groups */ + gid = H5Gcreate2(file, "/g1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gcreate2"); + + gid1 = H5Gcreate2(file, "/g1/g1.1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid1, FAIL, "H5Gcreate2"); + + /* create soft and hard links to the group "/g1". */ + ret = H5Lcreate_soft("something", gid, "softlink", H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lcreate_soft"); + + ret = H5Lcreate_hard(gid, "/g1", H5L_SAME_LOC, "hardlink", H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lcreate_hard"); + + ret = H5Gget_info(gid, &ginfo); + CHECK(ret, FAIL, "H5Gget_info"); + VERIFY(ginfo.nlinks, 3, "H5Gget_info"); + + /* Test these two functions, H5Oget_info_by_idx and H5Lget_name_by_idx */ + for (i = 0; i < ginfo.nlinks; i++) { + H5O_info2_t oinfo; /* Object info */ + H5L_info2_t linfo; /* Link info */ + + /* Get link name */ + name_len = H5Lget_name_by_idx(gid, ".", H5_INDEX_NAME, H5_ITER_INC, i, obj_name, (size_t)NAMELEN, + H5P_DEFAULT); + CHECK(name_len, FAIL, "H5Lget_name_by_idx"); + + /* Get link type */ + ret = H5Lget_info_by_idx2(gid, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)i, &linfo, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lget_info_by_idx2"); + + /* Get object type */ + if (linfo.type == H5L_TYPE_HARD) { + ret = H5Oget_info_by_idx3(gid, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)i, &oinfo, + H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_idx3"); + } /* end if */ + + if (!HDstrcmp(obj_name, "g1.1")) + VERIFY(oinfo.type, H5O_TYPE_GROUP, "H5Lget_name_by_idx"); + else if (!HDstrcmp(obj_name, "hardlink")) + VERIFY(oinfo.type, H5O_TYPE_GROUP, "H5Lget_name_by_idx"); + else if (!HDstrcmp(obj_name, "softlink")) + VERIFY(linfo.type, H5L_TYPE_SOFT, "H5Lget_name_by_idx"); + else + ERROR("unknown object name"); + } /* end for */ + + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Gclose(gid1); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_links() */ + +/*------------------------------------------------------------------------- + * Function: find_err_msg_cb + * + * Purpose: Callback function to find the given error message. + * Helper function for test_corrupted_attnamelen(). + * + * Return: H5_ITER_STOP when the message is found + * H5_ITER_CONT, otherwise + * + *------------------------------------------------------------------------- + */ +#if 0 +static int +find_err_msg_cb(unsigned H5_ATTR_UNUSED n, const H5E_error2_t *err_desc, void *_client_data) +{ + int status = H5_ITER_CONT; + searched_err_t *searched_err = (searched_err_t *)_client_data; + + if (searched_err == NULL) + return H5_ITER_ERROR; + + /* If the searched error message is found, stop the iteration */ + if (err_desc->desc != NULL && HDstrcmp(err_desc->desc, searched_err->message) == 0) { + searched_err->found = TRUE; + status = H5_ITER_STOP; + } + + return status; +} /* end find_err_msg_cb() */ +#endif + +/************************************************************************** +** +** test_corrupted_attnamelen(): Test the fix for the JIRA issue HDFFV-10588, +** where corrupted attribute's name length can be +** detected and invalid read can be avoided. +** +**************************************************************************/ +#if 0 +static void +test_corrupted_attnamelen(void) +{ + hid_t fid = -1; /* File ID */ + hid_t did = -1; /* Dataset ID */ + searched_err_t err_caught; /* Data to be passed to callback func */ + int err_status; /* Status returned by H5Aiterate2 */ + herr_t ret; /* Return value */ + hbool_t driver_is_default_compatible; + const char *testfile = H5_get_srcdir_filename(CORRUPTED_ATNAMELEN_FILE); /* Corrected test file name */ + + const char *err_message = "attribute name has different length than stored length"; + /* the error message produced when the failure occurs */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing the Handling of Corrupted Attribute's Name Length\n")); + + ret = h5_driver_is_default_vfd_compatible(H5P_DEFAULT, &driver_is_default_compatible); + CHECK(ret, FAIL, "h5_driver_is_default_vfd_compatible"); + + if (!driver_is_default_compatible) { + HDprintf("-- SKIPPED --\n"); + return; + } + + fid = H5Fopen(testfile, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* Open the dataset */ + did = H5Dopen2(fid, DSET_NAME, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen2"); + + /* Call H5Aiterate2 to trigger the failure in HDFFV-10588. Failure should + occur in the decoding stage, so some arguments are not needed. */ + err_status = H5Aiterate2(did, H5_INDEX_NAME, H5_ITER_INC, NULL, NULL, NULL); + VERIFY(err_status, FAIL, "H5Aiterate2"); + + /* Make sure the intended error was caught */ + if (err_status == -1) { + /* Initialize client data */ + HDstrcpy(err_caught.message, err_message); + err_caught.found = FALSE; + + /* Look for the correct error message */ + ret = H5Ewalk2(H5E_DEFAULT, H5E_WALK_UPWARD, find_err_msg_cb, &err_caught); + CHECK(ret, FAIL, "H5Ewalk2"); + + /* Fail if the indicated message is not found */ + CHECK(err_caught.found, FALSE, "test_corrupted_attnamelen: Expected error not found"); + } + + /* Close the dataset and file */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + +} /* test_corrupted_attnamelen() */ +#endif + +#if 0 +#ifndef H5_NO_DEPRECATED_SYMBOLS +/**************************************************************** +** +** test_links_deprec(): Test soft and hard link iteration +** +****************************************************************/ +static void +test_links_deprec(hid_t fapl) +{ + hid_t file; /* File ID */ + char obj_name[NAMELEN]; /* Names of the object in group */ + ssize_t name_len; /* Length of object's name */ + hid_t gid, gid1; + H5G_info_t ginfo; /* Buffer for querying object's info */ + hsize_t i; + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Soft and Hard Link Iteration Functionality Using Deprecated Routines\n")); + + /* Create the test file with the datasets */ + file = H5Fcreate(DATAFILE, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(file, FAIL, "H5Fcreate"); + + /* create groups */ + gid = H5Gcreate2(file, "/g1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gcreate2"); + + gid1 = H5Gcreate2(file, "/g1/g1.1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid1, FAIL, "H5Gcreate2"); + + /* create soft and hard links to the group "/g1". */ + ret = H5Lcreate_soft("something", gid, "softlink", H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lcreate_soft"); + + ret = H5Lcreate_hard(gid, "/g1", H5L_SAME_LOC, "hardlink", H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lcreate_hard"); + + ret = H5Gget_info(gid, &ginfo); + CHECK(ret, FAIL, "H5Gget_info"); + VERIFY(ginfo.nlinks, 3, "H5Gget_info"); + + /* Test these two functions, H5Oget_info_by_idx and H5Lget_name_by_idx */ + for (i = 0; i < ginfo.nlinks; i++) { + H5O_info2_t oinfo; /* Object info */ + H5L_info2_t linfo; /* Link info */ + + /* Get link name */ + name_len = H5Lget_name_by_idx(gid, ".", H5_INDEX_NAME, H5_ITER_INC, i, obj_name, (size_t)NAMELEN, + H5P_DEFAULT); + CHECK(name_len, FAIL, "H5Lget_name_by_idx"); + + /* Get link type */ + ret = H5Lget_info_by_idx2(gid, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)i, &linfo, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lget_info_by_idx1"); + + /* Get object type */ + if (linfo.type == H5L_TYPE_HARD) { + ret = H5Oget_info_by_idx3(gid, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)i, &oinfo, + H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_idx"); + } /* end if */ + + if (!HDstrcmp(obj_name, "g1.1")) + VERIFY(oinfo.type, H5O_TYPE_GROUP, "H5Lget_name_by_idx"); + else if (!HDstrcmp(obj_name, "hardlink")) + VERIFY(oinfo.type, H5O_TYPE_GROUP, "H5Lget_name_by_idx"); + else if (!HDstrcmp(obj_name, "softlink")) + VERIFY(linfo.type, H5L_TYPE_SOFT, "H5Lget_name_by_idx"); + else + ERROR("unknown object name"); + } /* end for */ + + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Gclose(gid1); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_links_deprec() */ +#endif +#endif + +/**************************************************************** +** +** test_iterate(): Main iteration testing routine. +** +****************************************************************/ +void +test_iterate(void) +{ + hid_t fapl, fapl2; /* File access property lists */ + unsigned new_format; /* Whether to use the new format or not */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Iteration Operations\n")); + + /* Get the default FAPL */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + + /* Copy the file access property list */ + fapl2 = H5Pcopy(fapl); + CHECK(fapl2, FAIL, "H5Pcopy"); + + /* Set the "use the latest version of the format" bounds for creating objects in the file */ + ret = H5Pset_libver_bounds(fapl2, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST); + CHECK(ret, FAIL, "H5Pset_libver_bounds"); + + /* These next tests use the same file */ + for (new_format = FALSE; new_format <= TRUE; new_format++) { + test_iter_group(new_format ? fapl2 : fapl, new_format); /* Test group iteration */ + test_iter_group_large(new_format ? fapl2 : fapl); /* Test group iteration for large # of objects */ + test_iter_attr(new_format ? fapl2 : fapl, new_format); /* Test attribute iteration */ + test_grp_memb_funcs(new_format ? fapl2 : fapl); /* Test group member information functions */ + test_links(new_format ? fapl2 : fapl); /* Test soft and hard link iteration */ +#if 0 +#ifndef H5_NO_DEPRECATED_SYMBOLS + test_links_deprec(new_format ? fapl2 : fapl); /* Test soft and hard link iteration */ +#endif +#endif + } /* end for */ +#if 0 + /* Test the fix for issue HDFFV-10588 */ + test_corrupted_attnamelen(); +#endif + /* Close FAPLs */ + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(fapl2); + CHECK(ret, FAIL, "H5Pclose"); +} /* test_iterate() */ + +/*------------------------------------------------------------------------- + * Function: cleanup_iterate + * + * Purpose: Cleanup temporary test files + * + * Return: none + * + * Programmer: Quincey Koziol + * April 5, 2000 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +void +cleanup_iterate(void) +{ + H5Fdelete(DATAFILE, H5P_DEFAULT); +} diff --git a/test/API/tmisc.c b/test/API/tmisc.c new file mode 100644 index 0000000..d35a00b --- /dev/null +++ b/test/API/tmisc.c @@ -0,0 +1,6349 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*********************************************************** + * + * Test program: tmisc + * + * Test miscellaneous features not tested elsewhere. Generally + * regression tests for bugs that are reported and don't + * have an existing test to add them to. + * + *************************************************************/ + +#define H5D_FRIEND /*suppress error about including H5Dpkg */ + +/* Define this macro to indicate that the testing APIs should be available */ +#define H5D_TESTING + +#include "testhdf5.h" +/* #include "H5srcdir.h" */ +/* #include "H5Dpkg.h" */ /* Datasets */ +/* #include "H5MMprivate.h" */ /* Memory */ + +/* Definitions for misc. test #1 */ +#define MISC1_FILE "tmisc1.h5" +#define MISC1_VAL (13417386) /* 0xccbbaa */ +#define MISC1_VAL2 (15654348) /* 0xeeddcc */ +#define MISC1_DSET_NAME "/scalar_set" + +/* Definitions for misc. test #2 */ +#define MISC2_FILE_1 "tmisc2a.h5" +#define MISC2_FILE_2 "tmisc2b.h5" +#define MISC2_ATT_NAME_1 "scalar_att_1" +#define MISC2_ATT_NAME_2 "scalar_att_2" + +typedef struct { + char *string; +} misc2_struct; + +/* Definitions for misc. test #3 */ +#define MISC3_FILE "tmisc3.h5" +#define MISC3_RANK 2 +#define MISC3_DIM1 6 +#define MISC3_DIM2 6 +#define MISC3_CHUNK_DIM1 2 +#define MISC3_CHUNK_DIM2 2 +#define MISC3_FILL_VALUE 2 +#define MISC3_DSET_NAME "/chunked" + +/* Definitions for misc. test #4 */ +#define MISC4_FILE_1 "tmisc4a.h5" +#define MISC4_FILE_2 "tmisc4b.h5" +#define MISC4_GROUP_1 "/Group1" +#define MISC4_GROUP_2 "/Group2" + +/* Definitions for misc. test #5 */ +#define MISC5_FILE "tmisc5.h5" +#define MISC5_DSETNAME "dset1" +#define MISC5_DSETRANK 1 +#define MISC5_NELMTOPLVL 1 +#define MISC5_DBGNELM1 2 +#define MISC5_DBGNELM2 1 +#define MISC5_DBGNELM3 1 +#define MISC5_DBGELVAL1 999999999 +#define MISC5_DBGELVAL2 888888888 +#define MISC5_DBGELVAL3 777777777 + +typedef struct { + int st1_el1; + hvl_t st1_el2; +} misc5_struct1; + +typedef struct { + int st2_el1; + hvl_t st2_el2; +} misc5_struct2; + +typedef struct { + int st3_el1; +} misc5_struct3; + +typedef struct { + hid_t st3h_base; + hid_t st3h_id; +} misc5_struct3_hndl; + +typedef struct { + hid_t st2h_base; + hid_t st2h_id; + misc5_struct3_hndl *st2h_st3hndl; +} misc5_struct2_hndl; + +typedef struct { + hid_t st1h_base; + hid_t st1h_id; + misc5_struct2_hndl *st1h_st2hndl; +} misc5_struct1_hndl; + +/* Definitions for misc. test #6 */ +#define MISC6_FILE "tmisc6.h5" +#define MISC6_DSETNAME1 "dset1" +#define MISC6_DSETNAME2 "dset2" +#define MISC6_NUMATTR 16 + +/* Definitions for misc. test #7 */ +#define MISC7_FILE "tmisc7.h5" +#define MISC7_DSETNAME1 "Dataset1" +#define MISC7_DSETNAME2 "Dataset2" +#define MISC7_TYPENAME1 "Datatype1" +#define MISC7_TYPENAME2 "Datatype2" + +/* Definitions for misc. test #8 */ +#define MISC8_FILE "tmisc8.h5" +#define MISC8_DSETNAME1 "Dataset1" +#define MISC8_DSETNAME4 "Dataset4" +#define MISC8_DSETNAME5 "Dataset5" +#define MISC8_DSETNAME8 "Dataset8" + +#ifndef H5_HAVE_PARALLEL +#define MISC8_DSETNAME2 "Dataset2" +#define MISC8_DSETNAME3 "Dataset3" +#define MISC8_DSETNAME6 "Dataset6" +#define MISC8_DSETNAME7 "Dataset7" +#define MISC8_DSETNAME9 "Dataset9" +#define MISC8_DSETNAME10 "Dataset10" +#endif + +#define MISC8_RANK 2 +#define MISC8_DIM0 50 +#define MISC8_DIM1 50 +#define MISC8_CHUNK_DIM0 10 +#define MISC8_CHUNK_DIM1 10 + +/* Definitions for misc. test #9 */ +#define MISC9_FILE "tmisc9.h5" + +/* Definitions for misc. test #10 */ +#define MISC10_FILE_OLD "tmtimeo.h5" +#define MISC10_FILE_NEW "tmisc10.h5" +#define MISC10_DSETNAME "Dataset1" + +/* Definitions for misc. test #11 */ +#define MISC11_FILE "tmisc11.h5" +#define MISC11_USERBLOCK 1024 +#define MISC11_SIZEOF_OFF 4 +#define MISC11_SIZEOF_LEN 4 +#define MISC11_SYM_LK 8 +#define MISC11_SYM_IK 32 +#define MISC11_ISTORE_IK 64 +#define MISC11_NINDEXES 1 + +/* Definitions for misc. test #12 */ +#define MISC12_FILE "tmisc12.h5" +#define MISC12_DSET_NAME "Dataset" +#define MISC12_SPACE1_RANK 1 +#define MISC12_SPACE1_DIM1 4 +#define MISC12_CHUNK_SIZE 2 +#define MISC12_APPEND_SIZE 5 + +/* Definitions for misc. test #13 */ +#define MISC13_FILE_1 "tmisc13a.h5" +#define MISC13_FILE_2 "tmisc13b.h5" +#define MISC13_DSET1_NAME "Dataset1" +#define MISC13_DSET2_NAME "Dataset2" +#define MISC13_DSET3_NAME "Dataset3" +#define MISC13_GROUP1_NAME "Group1" +#define MISC13_GROUP2_NAME "Group2" +#define MISC13_DTYPE_NAME "Datatype" +#define MISC13_RANK 1 +#define MISC13_DIM1 600 +#define MISC13_CHUNK_DIM1 10 +#define MISC13_USERBLOCK_SIZE 512 +#define MISC13_COPY_BUF_SIZE 4096 + +/* Definitions for misc. test #14 */ +#define MISC14_FILE "tmisc14.h5" +#define MISC14_DSET1_NAME "Dataset1" +#define MISC14_DSET2_NAME "Dataset2" +#define MISC14_DSET3_NAME "Dataset3" +#define MISC14_METADATA_SIZE 4096 + +/* Definitions for misc. test #15 */ +#define MISC15_FILE "tmisc15.h5" +#define MISC15_BUF_SIZE 1024 + +/* Definitions for misc. test #16 */ +#define MISC16_FILE "tmisc16.h5" +#define MISC16_SPACE_DIM 4 +#define MISC16_SPACE_RANK 1 +#define MISC16_STR_SIZE 8 +#define MISC16_DSET_NAME "Dataset" + +/* Definitions for misc. test #17 */ +#define MISC17_FILE "tmisc17.h5" +#define MISC17_SPACE_RANK 2 +#define MISC17_SPACE_DIM1 4 +#define MISC17_SPACE_DIM2 8 +#define MISC17_DSET_NAME "Dataset" + +/* Definitions for misc. test #18 */ +#define MISC18_FILE "tmisc18.h5" +#define MISC18_DSET1_NAME "Dataset1" +#define MISC18_DSET2_NAME "Dataset2" + +/* Definitions for misc. test #19 */ +#define MISC19_FILE "tmisc19.h5" +#define MISC19_DSET_NAME "Dataset" +#define MISC19_ATTR_NAME "Attribute" +#define MISC19_GROUP_NAME "Group" + +/* Definitions for misc. test #20 */ +#define MISC20_FILE "tmisc20.h5" +#define MISC20_FILE_OLD "tlayouto.h5" +#define MISC20_DSET_NAME "Dataset" +#define MISC20_DSET2_NAME "Dataset2" +#define MISC20_SPACE_RANK 2 +/* Make sure the product of the following 2 does not get too close to */ +/* 64 bits, risking an overflow. */ +#define MISC20_SPACE_DIM0 (8 * 1024 * 1024 * (uint64_t)1024) +#define MISC20_SPACE_DIM1 ((256 * 1024 * (uint64_t)1024) + 1) +#define MISC20_SPACE2_DIM0 8 +#define MISC20_SPACE2_DIM1 4 + +#if defined(H5_HAVE_FILTER_SZIP) && !defined(H5_API_TEST_NO_FILTERS) +/* Definitions for misc. test #21 */ +#define MISC21_FILE "tmisc21.h5" +#define MISC21_DSET_NAME "Dataset" +#define MISC21_SPACE_RANK 2 +#define MISC21_SPACE_DIM0 7639 +#define MISC21_SPACE_DIM1 6308 +#define MISC21_CHUNK_DIM0 2048 +#define MISC21_CHUNK_DIM1 2048 + +/* Definitions for misc. test #22 */ +#define MISC22_FILE "tmisc22.h5" +#define MISC22_DSET_NAME "Dataset" +#define MISC22_SPACE_RANK 2 +#define MISC22_CHUNK_DIM0 512 +#define MISC22_CHUNK_DIM1 512 +#define MISC22_SPACE_DIM0 639 +#define MISC22_SPACE_DIM1 1308 +#endif /* H5_HAVE_FILTER_SZIP */ + +/* Definitions for misc. test #23 */ +#define MISC23_FILE "tmisc23.h5" +#define MISC23_NAME_BUF_SIZE 40 + +/* Definitions for misc. test #24 */ +#define MISC24_FILE "tmisc24.h5" +#define MISC24_GROUP_NAME "group" +#define MISC24_GROUP_LINK "group_link" +#define MISC24_DATASET_NAME "dataset" +#define MISC24_DATASET_LINK "dataset_link" +#define MISC24_DATATYPE_NAME "datatype" +#define MISC24_DATATYPE_LINK "datatype_link" + +/* Definitions for misc. test #25 'a', 'b' & 'c' */ +#define MISC25A_FILE "foo.h5" +#define MISC25A_GROUP0_NAME "grp0" +#define MISC25A_GROUP1_NAME "/grp0/grp1" +#define MISC25A_GROUP2_NAME "/grp0/grp2" +#define MISC25A_GROUP3_NAME "/grp0/grp3" +#define MISC25A_ATTR1_NAME "_long attribute_" +#define MISC25A_ATTR1_LEN 11 +#define MISC25A_ATTR2_NAME "_short attr__" +#define MISC25A_ATTR2_LEN 11 +#define MISC25A_ATTR3_NAME "_short attr__" +#define MISC25A_ATTR3_LEN 1 +#define MISC25B_FILE "mergemsg.h5" +#define MISC25B_GROUP "grp1" +#define MISC25C_FILE "nc4_rename.h5" +#define MISC25C_DSETNAME "da" +#define MISC25C_DSETNAME2 "dz" +#define MISC25C_DSETGRPNAME "ga" +#define MISC25C_GRPNAME "gb" +#define MISC25C_GRPNAME2 "gc" +#define MISC25C_ATTRNAME "aa" +#define MISC25C_ATTRNAME2 "ab" + +/* Definitions for misc. test #26 */ +#define MISC26_FILE "dcpl_file" + +/* Definitions for misc. test #27 */ +/* (Note that this test file is generated by the "gen_bad_ohdr.c" code) */ +#define MISC27_FILE "tbad_msg_count.h5" +#define MISC27_GROUP "Group" + +/* Definitions for misc. test #28 */ +#define MISC28_FILE "tmisc28.h5" +#define MISC28_SIZE 10 +#define MISC28_NSLOTS 10000 + +/* Definitions for misc. test #29 */ +#define MISC29_ORIG_FILE "specmetaread.h5" +#define MISC29_COPY_FILE "tmisc29.h5" +#define MISC29_DSETNAME "dset2" + +/* Definitions for misc. test #30 */ +#define MISC30_FILE "tmisc30.h5" + +#ifndef H5_NO_DEPRECATED_SYMBOLS +/* Definitions for misc. test #31 */ +#define MISC31_FILE "tmisc31.h5" +#define MISC31_DSETNAME "dset" +#define MISC31_ATTRNAME1 "attr1" +#define MISC31_ATTRNAME2 "attr2" +#define MISC31_GROUPNAME "group" +#define MISC31_PROPNAME "misc31_prop" +#define MISC31_DTYPENAME "dtype" +#endif /* H5_NO_DEPRECATED_SYMBOLS */ + +/* Definitions for misc. test #33 */ +/* Note that this test file is generated by "gen_bad_offset.c" */ +/* and bad offset values are written to that file for testing */ +#define MISC33_FILE "bad_offset.h5" + +/* Definitions for misc. test #35 */ +#define MISC35_SPACE_RANK 3 +#define MISC35_SPACE_DIM1 3 +#define MISC35_SPACE_DIM2 15 +#define MISC35_SPACE_DIM3 13 +#define MISC35_NPOINTS 10 + +/* Definitions for misc. test #37 */ +/* The test file is formerly named h5_nrefs_POC. + See https://nvd.nist.gov/vuln/detail/CVE-2020-10812 */ +#define CVE_2020_10812_FILENAME "cve_2020_10812.h5" + +#if defined(H5_HAVE_FILTER_SZIP) && !defined(H5_API_TEST_NO_FILTERS) +/*------------------------------------------------------------------------- + * Function: h5_szip_can_encode + * + * Purpose: Retrieve the filter config flags for szip, tell if + * encoder is available. + * + * Return: 1: decode+encode is enabled + * 0: only decode is enabled + * -1: other + * + * Programmer: + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +int +h5_szip_can_encode(void) +{ + unsigned int filter_config_flags; + + H5Zget_filter_info(H5Z_FILTER_SZIP, &filter_config_flags); + if ((filter_config_flags & (H5Z_FILTER_CONFIG_ENCODE_ENABLED | H5Z_FILTER_CONFIG_DECODE_ENABLED)) == 0) { + /* filter present but neither encode nor decode is supported (???) */ + return -1; + } + else if ((filter_config_flags & (H5Z_FILTER_CONFIG_ENCODE_ENABLED | H5Z_FILTER_CONFIG_DECODE_ENABLED)) == + H5Z_FILTER_CONFIG_DECODE_ENABLED) { + /* decoder only: read but not write */ + return 0; + } + else if ((filter_config_flags & (H5Z_FILTER_CONFIG_ENCODE_ENABLED | H5Z_FILTER_CONFIG_DECODE_ENABLED)) == + H5Z_FILTER_CONFIG_ENCODE_ENABLED) { + /* encoder only: write but not read (???) */ + return -1; + } + else if ((filter_config_flags & (H5Z_FILTER_CONFIG_ENCODE_ENABLED | H5Z_FILTER_CONFIG_DECODE_ENABLED)) == + (H5Z_FILTER_CONFIG_ENCODE_ENABLED | H5Z_FILTER_CONFIG_DECODE_ENABLED)) { + return 1; + } + return (-1); +} +#endif /* H5_HAVE_FILTER_SZIP */ + +/**************************************************************** +** +** test_misc1(): test unlinking a dataset from a group and immediately +** re-using the dataset name +** +****************************************************************/ +static void +test_misc1(void) +{ + int i; + int i_check; + hid_t file, dataspace, dataset; + herr_t ret; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Unlinking Dataset and Re-creating It\n")); + + file = H5Fcreate(MISC1_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file, FAIL, "H5Fcreate"); + + dataspace = H5Screate(H5S_SCALAR); + CHECK(dataspace, FAIL, "H5Screate"); + + /* Write the dataset the first time. */ + dataset = + H5Dcreate2(file, MISC1_DSET_NAME, H5T_NATIVE_INT, dataspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + i = MISC1_VAL; + ret = H5Dwrite(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &i); + CHECK(ret, FAIL, "H5Dwrite"); + + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Remove the dataset. */ + ret = H5Ldelete(file, MISC1_DSET_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + + /* Write the dataset for the second time with a different value. */ + dataset = + H5Dcreate2(file, MISC1_DSET_NAME, H5T_NATIVE_INT, dataspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + i = MISC1_VAL2; + ret = H5Dwrite(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &i); + CHECK(ret, FAIL, "H5Dwrite"); + + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Sclose(dataspace); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + + /* Now, check the value written to the dataset, after it was re-created */ + file = H5Fopen(MISC1_FILE, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(file, FAIL, "H5Fopen"); + + dataspace = H5Screate(H5S_SCALAR); + CHECK(dataspace, FAIL, "H5Screate"); + + dataset = H5Dopen2(file, MISC1_DSET_NAME, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + ret = H5Dread(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &i_check); + CHECK(ret, FAIL, "H5Dread"); + VERIFY(i_check, MISC1_VAL2, "H5Dread"); + + ret = H5Sclose(dataspace); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + +} /* end test_misc1() */ + +static hid_t +misc2_create_type(void) +{ + hid_t type, type_tmp; + herr_t ret; + + type_tmp = H5Tcopy(H5T_C_S1); + CHECK(type_tmp, FAIL, "H5Tcopy"); + + ret = H5Tset_size(type_tmp, H5T_VARIABLE); + CHECK(ret, FAIL, "H5Tset_size"); + + type = H5Tcreate(H5T_COMPOUND, sizeof(misc2_struct)); + CHECK(type, FAIL, "H5Tcreate"); + + ret = H5Tinsert(type, "string", offsetof(misc2_struct, string), type_tmp); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tclose(type_tmp); + CHECK(ret, FAIL, "H5Tclose"); + + return type; +} + +static void +test_misc2_write_attribute(void) +{ + hid_t file1, file2, root1, root2, dataspace, att1, att2; + hid_t type; + herr_t ret; + misc2_struct data, data_check; + char *string_att1 = HDstrdup("string attribute in file one"); + char *string_att2 = HDstrdup("string attribute in file two"); + + HDmemset(&data, 0, sizeof(data)); + HDmemset(&data_check, 0, sizeof(data_check)); + + type = misc2_create_type(); + + dataspace = H5Screate(H5S_SCALAR); + CHECK(dataspace, FAIL, "H5Screate"); + + file2 = H5Fcreate(MISC2_FILE_2, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file2, FAIL, "H5Fcreate"); + + file1 = H5Fcreate(MISC2_FILE_1, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file1, FAIL, "H5Fcreate"); + + root1 = H5Gopen2(file1, "/", H5P_DEFAULT); + CHECK(root1, FAIL, "H5Gopen2"); + + att1 = H5Acreate2(root1, MISC2_ATT_NAME_1, type, dataspace, H5P_DEFAULT, H5P_DEFAULT); + CHECK(att1, FAIL, "H5Acreate2"); + + data.string = string_att1; + + ret = H5Awrite(att1, type, &data); + CHECK(ret, FAIL, "H5Awrite"); + + ret = H5Aread(att1, type, &data_check); + CHECK(ret, FAIL, "H5Aread"); + + ret = H5Treclaim(type, dataspace, H5P_DEFAULT, &data_check); + CHECK(ret, FAIL, "H5Treclaim"); + + ret = H5Aclose(att1); + CHECK(ret, FAIL, "H5Aclose"); + + ret = H5Gclose(root1); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Fclose(file1); + CHECK(ret, FAIL, "H5Fclose"); + + root2 = H5Gopen2(file2, "/", H5P_DEFAULT); + CHECK(root2, FAIL, "H5Gopen2"); + + att2 = H5Acreate2(root2, MISC2_ATT_NAME_2, type, dataspace, H5P_DEFAULT, H5P_DEFAULT); + CHECK(att2, FAIL, "H5Acreate2"); + + data.string = string_att2; + + ret = H5Awrite(att2, type, &data); + CHECK(ret, FAIL, "H5Awrite"); + + ret = H5Aread(att2, type, &data_check); + CHECK(ret, FAIL, "H5Aread"); + + ret = H5Treclaim(type, dataspace, H5P_DEFAULT, &data_check); + CHECK(ret, FAIL, "H5Treclaim"); + + ret = H5Aclose(att2); + CHECK(ret, FAIL, "H5Aclose"); + + ret = H5Gclose(root2); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Tclose(type); + CHECK(ret, FAIL, "H5Tclose"); + + ret = H5Sclose(dataspace); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Fclose(file2); + CHECK(ret, FAIL, "H5Fclose"); + + HDfree(string_att1); + HDfree(string_att2); +} + +static void +test_misc2_read_attribute(const char *filename, const char *att_name) +{ + hid_t file, root, att; + hid_t type; + hid_t space; + herr_t ret; + misc2_struct data_check; + + type = misc2_create_type(); + + file = H5Fopen(filename, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(file, FAIL, "H5Fopen"); + + root = H5Gopen2(file, "/", H5P_DEFAULT); + CHECK(root, FAIL, "H5Gopen2"); + + att = H5Aopen(root, att_name, H5P_DEFAULT); + CHECK(att, FAIL, "H5Aopen"); + + space = H5Aget_space(att); + CHECK(space, FAIL, "H5Aget_space"); + + ret = H5Aread(att, type, &data_check); + CHECK(ret, FAIL, "H5Aread"); + + ret = H5Treclaim(type, space, H5P_DEFAULT, &data_check); + CHECK(ret, FAIL, "H5Treclaim"); + + ret = H5Sclose(space); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Aclose(att); + CHECK(ret, FAIL, "H5Aclose"); + + ret = H5Tclose(type); + CHECK(ret, FAIL, "H5Tclose"); + + ret = H5Gclose(root); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); +} +/**************************************************************** +** +** test_misc2(): test using the same VL-derived datatype in two +** different files, which was causing problems with the +** datatype conversion functions +** +****************************************************************/ +static void +test_misc2(void) +{ + /* Output message about test being performed */ + MESSAGE(5, ("Testing VL datatype in two different files\n")); + + test_misc2_write_attribute(); + test_misc2_read_attribute(MISC2_FILE_1, MISC2_ATT_NAME_1); + test_misc2_read_attribute(MISC2_FILE_2, MISC2_ATT_NAME_2); +} /* end test_misc2() */ + +/**************************************************************** +** +** test_misc3(): Test reading from chunked dataset with non-zero +** fill value +** +****************************************************************/ +static void +test_misc3(void) +{ + hid_t file, dataspace, dataset, dcpl; + int rank = MISC3_RANK; + hsize_t dims[MISC3_RANK] = {MISC3_DIM1, MISC3_DIM2}; + hsize_t chunk_dims[MISC3_RANK] = {MISC3_CHUNK_DIM1, MISC3_CHUNK_DIM2}; + int fill = MISC3_FILL_VALUE; + int read_buf[MISC3_DIM1][MISC3_DIM2]; + int i, j; + herr_t ret; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing reading from chunked dataset with non-zero fill-value\n")); + + file = H5Fcreate(MISC3_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file, FAIL, "H5Fcreate"); + + /* Create a simple dataspace */ + dataspace = H5Screate_simple(rank, dims, NULL); + CHECK(dataspace, FAIL, "H5Screate_simple"); + + /* Create a dataset creation property list */ + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + + /* Set the chunk information */ + ret = H5Pset_chunk(dcpl, rank, chunk_dims); + CHECK(dcpl, FAIL, "H5Pset_chunk"); + + /* Set the fill-value information */ + ret = H5Pset_fill_value(dcpl, H5T_NATIVE_INT, &fill); + CHECK(dcpl, FAIL, "H5Pset_fill_value"); + + /* Create the dataset */ + dataset = H5Dcreate2(file, MISC3_DSET_NAME, H5T_NATIVE_INT, dataspace, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Read from the dataset (should be fill-values) */ + ret = H5Dread(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &read_buf); + CHECK(ret, FAIL, "H5Dread"); + + for (i = 0; i < MISC3_DIM1; i++) + for (j = 0; j < MISC3_DIM2; j++) + VERIFY(read_buf[i][j], fill, "H5Dread"); + + /* Release resources */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + + ret = H5Sclose(dataspace); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_misc3() */ + +/**************************************************************** +** +** test_misc4(): Test the that 'fileno' field in H5O_info_t is +** valid. +** +****************************************************************/ +static void +test_misc4(void) +{ + hid_t file1, file2, group1, group2, group3; + H5O_info2_t oinfo1, oinfo2, oinfo3; + herr_t ret; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing fileno working in H5O_info2_t\n")); + + file1 = H5Fcreate(MISC4_FILE_1, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file1, FAIL, "H5Fcreate"); + + /* Create the first group */ + group1 = H5Gcreate2(file1, MISC4_GROUP_1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(group1, FAIL, "H5Gcreate2"); + + /* Create the second group */ + group2 = H5Gcreate2(file1, MISC4_GROUP_2, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(group2, FAIL, "H5Gcreate2"); + + file2 = H5Fcreate(MISC4_FILE_2, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file2, FAIL, "H5Fcreate"); + + /* Create the first group */ + group3 = H5Gcreate2(file2, MISC4_GROUP_1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(group3, FAIL, "H5Gcreate2"); + + /* Get the stat information for each group */ + ret = H5Oget_info_by_name3(file1, MISC4_GROUP_1, &oinfo1, H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name3"); + ret = H5Oget_info_by_name3(file1, MISC4_GROUP_2, &oinfo2, H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name3"); + ret = H5Oget_info_by_name3(file2, MISC4_GROUP_1, &oinfo3, H5O_INFO_BASIC, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name3"); + + /* Verify that the fileno values are the same for groups from file1 */ + VERIFY(oinfo1.fileno, oinfo2.fileno, "H5Oget_info_by_name"); + + /* Verify that the fileno values are not the same between file1 & file2 */ + if (oinfo1.fileno == oinfo3.fileno) + TestErrPrintf("Error on line %d: oinfo1.fileno != oinfo3.fileno\n", __LINE__); + if (oinfo2.fileno == oinfo3.fileno) + TestErrPrintf("Error on line %d: oinfo2.fileno != oinfo3.fileno\n", __LINE__); + + /* Close the objects */ + ret = H5Gclose(group1); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Gclose(group2); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Gclose(group3); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Fclose(file1); + CHECK(ret, FAIL, "H5Fclose"); + + ret = H5Fclose(file2); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_misc4() */ + +/**************************************************************** +** +** test_misc5(): Test several level deep nested compound & VL datatypes +** +****************************************************************/ + +/*********************** struct3 ***********************/ + +static misc5_struct3_hndl * +create_struct3(void) +{ + misc5_struct3_hndl *str3hndl; /* New 'struct3' created */ + herr_t ret; /* For error checking */ + + str3hndl = (misc5_struct3_hndl *)HDmalloc(sizeof(misc5_struct3_hndl)); + CHECK_PTR(str3hndl, "malloc"); + + str3hndl->st3h_base = H5Tcreate(H5T_COMPOUND, sizeof(misc5_struct3)); + CHECK(str3hndl->st3h_base, FAIL, "H5Tcreate"); + + ret = H5Tinsert(str3hndl->st3h_base, "st3_el1", HOFFSET(misc5_struct3, st3_el1), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + str3hndl->st3h_id = H5Tvlen_create(str3hndl->st3h_base); + CHECK(str3hndl->st3h_id, FAIL, "H5Tvlen_create"); + + return str3hndl; +} + +static void +delete_struct3(misc5_struct3_hndl *str3hndl) +{ + herr_t ret; /* For error checking */ + + ret = H5Tclose(str3hndl->st3h_id); + CHECK(ret, FAIL, "H5Tclose"); + + ret = H5Tclose(str3hndl->st3h_base); + CHECK(ret, FAIL, "H5Tclose"); + + HDfree(str3hndl); +} + +static void +set_struct3(misc5_struct3 *buf) +{ + buf->st3_el1 = MISC5_DBGELVAL3; +} + +/*********************** struct2 ***********************/ + +static misc5_struct2_hndl * +create_struct2(void) +{ + misc5_struct2_hndl *str2hndl; /* New 'struct2' created */ + herr_t ret; /* For error checking */ + + str2hndl = (misc5_struct2_hndl *)HDmalloc(sizeof(misc5_struct2_hndl)); + CHECK_PTR(str2hndl, "HDmalloc"); + + str2hndl->st2h_base = H5Tcreate(H5T_COMPOUND, sizeof(misc5_struct2)); + CHECK(str2hndl->st2h_base, FAIL, "H5Tcreate"); + + ret = H5Tinsert(str2hndl->st2h_base, "st2_el1", HOFFSET(misc5_struct2, st2_el1), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + str2hndl->st2h_st3hndl = create_struct3(); + CHECK_PTR(str2hndl->st2h_st3hndl, "create_struct3"); + + ret = H5Tinsert(str2hndl->st2h_base, "st2_el2", HOFFSET(misc5_struct2, st2_el2), + str2hndl->st2h_st3hndl->st3h_id); + CHECK(ret, FAIL, "H5Tinsert"); + + str2hndl->st2h_id = H5Tvlen_create(str2hndl->st2h_base); + CHECK(str2hndl->st2h_id, FAIL, "H5Tvlen_create"); + + return str2hndl; +} + +static void +delete_struct2(misc5_struct2_hndl *str2hndl) +{ + herr_t ret; /* For error checking */ + + ret = H5Tclose(str2hndl->st2h_id); + CHECK(ret, FAIL, "H5Tclose"); + + delete_struct3(str2hndl->st2h_st3hndl); + + H5Tclose(str2hndl->st2h_base); + CHECK(ret, FAIL, "H5Tclose"); + + HDfree(str2hndl); +} + +static void +set_struct2(misc5_struct2 *buf) +{ + unsigned i; /* Local index variable */ + + buf->st2_el1 = MISC5_DBGELVAL2; + buf->st2_el2.len = MISC5_DBGNELM3; + + buf->st2_el2.p = HDmalloc((buf->st2_el2.len) * sizeof(misc5_struct3)); + CHECK_PTR(buf->st2_el2.p, "HDmalloc"); + + for (i = 0; i < (buf->st2_el2.len); i++) + set_struct3(&(((misc5_struct3 *)(buf->st2_el2.p))[i])); +} + +static void +clear_struct2(misc5_struct2 *buf) +{ + HDfree(buf->st2_el2.p); +} + +/*********************** struct1 ***********************/ + +static misc5_struct1_hndl * +create_struct1(void) +{ + misc5_struct1_hndl *str1hndl; /* New 'struct1' created */ + herr_t ret; /* For error checking */ + + str1hndl = (misc5_struct1_hndl *)HDmalloc(sizeof(misc5_struct1_hndl)); + CHECK_PTR(str1hndl, "HDmalloc"); + + str1hndl->st1h_base = H5Tcreate(H5T_COMPOUND, sizeof(misc5_struct1)); + CHECK(str1hndl->st1h_base, FAIL, "H5Tcreate"); + + ret = H5Tinsert(str1hndl->st1h_base, "st1_el1", HOFFSET(misc5_struct1, st1_el1), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + str1hndl->st1h_st2hndl = create_struct2(); + CHECK_PTR(str1hndl->st1h_st2hndl, "create_struct2"); + + ret = H5Tinsert(str1hndl->st1h_base, "st1_el2", HOFFSET(misc5_struct1, st1_el2), + str1hndl->st1h_st2hndl->st2h_id); + CHECK(ret, FAIL, "H5Tinsert"); + + str1hndl->st1h_id = H5Tvlen_create(str1hndl->st1h_base); + CHECK(str1hndl->st1h_id, FAIL, "H5Tvlen_create"); + + return str1hndl; +} + +static void +delete_struct1(misc5_struct1_hndl *str1hndl) +{ + herr_t ret; /* For error checking */ + + ret = H5Tclose(str1hndl->st1h_id); + CHECK(ret, FAIL, "H5Tclose"); + + delete_struct2(str1hndl->st1h_st2hndl); + + ret = H5Tclose(str1hndl->st1h_base); + CHECK(ret, FAIL, "H5Tclose"); + + HDfree(str1hndl); +} + +static void +set_struct1(misc5_struct1 *buf) +{ + unsigned i; /* Local index variable */ + + buf->st1_el1 = MISC5_DBGELVAL1; + buf->st1_el2.len = MISC5_DBGNELM2; + + buf->st1_el2.p = HDmalloc((buf->st1_el2.len) * sizeof(misc5_struct2)); + CHECK_PTR(buf->st1_el2.p, "HDmalloc"); + + for (i = 0; i < (buf->st1_el2.len); i++) + set_struct2(&(((misc5_struct2 *)(buf->st1_el2.p))[i])); +} + +static void +clear_struct1(misc5_struct1 *buf) +{ + unsigned i; + + for (i = 0; i < buf->st1_el2.len; i++) + clear_struct2(&(((misc5_struct2 *)(buf->st1_el2.p))[i])); + HDfree(buf->st1_el2.p); +} + +static void +test_misc5(void) +{ + hid_t loc_id, space_id, dataset_id; + hid_t mem_type_id; + misc5_struct1_hndl *str1hndl; + hsize_t dims[MISC5_DSETRANK]; + hvl_t buf; + unsigned i, j, k; + herr_t ret; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing several level deep nested compound & VL datatypes \n")); + + /* Write the dataset out */ + loc_id = H5Fcreate(MISC5_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(loc_id, FAIL, "H5Fcreate"); + + /* Create the memory structure to write */ + str1hndl = create_struct1(); + CHECK_PTR(str1hndl, "create_struct1"); + + /* Create the dataspace */ + dims[0] = MISC5_NELMTOPLVL; + space_id = H5Screate_simple(MISC5_DSETRANK, dims, NULL); + CHECK(space_id, FAIL, "H5Screate_simple"); + + /* Create the dataset */ + dataset_id = H5Dcreate2(loc_id, MISC5_DSETNAME, str1hndl->st1h_id, space_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT); + CHECK(dataset_id, FAIL, "H5Dcreate2"); + + /* Create the variable-length buffer */ + buf.len = MISC5_DBGNELM1; + buf.p = HDmalloc((buf.len) * sizeof(misc5_struct1)); + CHECK_PTR(buf.p, "HDmalloc"); + + /* Create the top-level VL information */ + for (i = 0; i < MISC5_DBGNELM1; i++) + set_struct1(&(((misc5_struct1 *)(buf.p))[i])); + + /* Write the data out */ + ret = H5Dwrite(dataset_id, str1hndl->st1h_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, &buf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Release the top-level VL information */ + for (j = 0; j < MISC5_DBGNELM1; j++) + clear_struct1(&(((misc5_struct1 *)(buf.p))[j])); + + /* Free the variable-length buffer */ + HDfree(buf.p); + + /* Close dataset */ + ret = H5Dclose(dataset_id); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close dataspace */ + ret = H5Sclose(space_id); + CHECK(ret, FAIL, "H5Sclose"); + + /* Delete memory structures */ + delete_struct1(str1hndl); + + /* Close file */ + ret = H5Fclose(loc_id); + CHECK(ret, FAIL, "H5Fclose"); + + /* Read the dataset back in & verify it */ + loc_id = H5Fopen(MISC5_FILE, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(loc_id, FAIL, "H5Fopen"); + + /* Open dataset again */ + dataset_id = H5Dopen2(loc_id, MISC5_DSETNAME, H5P_DEFAULT); + CHECK(dataset_id, FAIL, "H5Dopen2"); + + /* Get the dataset's datatype */ + mem_type_id = H5Dget_type(dataset_id); + CHECK(mem_type_id, FAIL, "H5Dget_type"); + + /* Get the dataset's dataspace */ + space_id = H5Dget_space(dataset_id); + CHECK(space_id, FAIL, "H5Dget_space"); + + /* Read the data back in */ + ret = H5Dread(dataset_id, mem_type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, &buf); + CHECK(ret, FAIL, "H5Dread"); + + /* Verify the correct information was read in */ + for (i = 0; i < (buf.len); i++) { + /* HDprintf("[%d]=%d\n",i, ((misc5_struct1 *)(buf.p))[i].st1_el1); */ + VERIFY(((misc5_struct1 *)(buf.p))[i].st1_el1, MISC5_DBGELVAL1, "H5Dread"); + for (j = 0; j < (((misc5_struct1 *)(buf.p))[i].st1_el2.len); j++) { + /* HDprintf(" [%d]=%d\n",j, ((misc5_struct2 *)(((misc5_struct1 *) + * (buf.p))[i].st1_el2.p))[j].st2_el1); */ + VERIFY(((misc5_struct2 *)(((misc5_struct1 *)(buf.p))[i].st1_el2.p))[j].st2_el1, MISC5_DBGELVAL2, + "H5Dread"); + for (k = 0; k < (((misc5_struct2 *)(((misc5_struct1 *)(buf.p))[i].st1_el2.p))[j].st2_el2.len); + k++) { + /* HDprintf(" [%d]=%d\n",k, ((misc5_struct3 *)(((misc5_struct2 *) (((misc5_struct1 + * *)(buf.p))[i]. st1_el2.p))[j].st2_el2.p))[k].st3_el1); */ + VERIFY(((misc5_struct3 *)(((misc5_struct2 *)(((misc5_struct1 *)(buf.p))[i].st1_el2.p))[j] + .st2_el2.p))[k] + .st3_el1, + MISC5_DBGELVAL3, "H5Dread"); + } /* end for */ + } + } + + /* Reclaim the memory for the VL information */ + ret = H5Treclaim(mem_type_id, space_id, H5P_DEFAULT, &buf); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Close dataspace */ + ret = H5Sclose(space_id); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close dataset */ + ret = H5Tclose(mem_type_id); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close dataset */ + ret = H5Dclose(dataset_id); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(loc_id); + CHECK(ret, FAIL, "H5Fclose"); + +} /* end test_misc5() */ + +/**************************************************************** +** +** test_misc6(): Test that object header continuation messages are +** created correctly. +** +****************************************************************/ +static void +test_misc6(void) +{ + hid_t loc_id, space_id, dataset_id; + hid_t attr_id; + char attr_name[16]; + unsigned u; + herr_t ret; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing object header continuation code \n")); + + /* Create the file */ + loc_id = H5Fcreate(MISC6_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(loc_id, FAIL, "H5Fcreate"); + + /* Create the dataspace */ + space_id = H5Screate(H5S_SCALAR); + CHECK(space_id, FAIL, "H5Screate"); + + /* Create the first dataset */ + dataset_id = + H5Dcreate2(loc_id, MISC6_DSETNAME1, H5T_NATIVE_INT, space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset_id, FAIL, "H5Dcreate2"); + + /* Close dataset */ + ret = H5Dclose(dataset_id); + CHECK(ret, FAIL, "H5Dclose"); + + /* Create the second dataset */ + dataset_id = + H5Dcreate2(loc_id, MISC6_DSETNAME2, H5T_NATIVE_INT, space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset_id, FAIL, "H5Dcreate2"); + + /* Close dataset */ + ret = H5Dclose(dataset_id); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(loc_id); + CHECK(ret, FAIL, "H5Fclose"); + + /* Loop through adding attributes to each dataset */ + for (u = 0; u < MISC6_NUMATTR; u++) { + /* Create name for attribute */ + HDsnprintf(attr_name, sizeof(attr_name), "Attr#%u", u); + + /* Open the file */ + loc_id = H5Fopen(MISC6_FILE, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(loc_id, FAIL, "H5Fopen"); + + /* Open first dataset */ + dataset_id = H5Dopen2(loc_id, MISC6_DSETNAME1, H5P_DEFAULT); + CHECK(dataset_id, FAIL, "H5Dopen2"); + + /* Add attribute to dataset */ + attr_id = H5Acreate2(dataset_id, attr_name, H5T_NATIVE_INT, space_id, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr_id, FAIL, "H5Acreate2"); + + /* Close attribute */ + ret = H5Aclose(attr_id); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close dataset */ + ret = H5Dclose(dataset_id); + CHECK(ret, FAIL, "H5Dclose"); + + /* Open second dataset */ + dataset_id = H5Dopen2(loc_id, MISC6_DSETNAME2, H5P_DEFAULT); + CHECK(dataset_id, FAIL, "H5Dopen2"); + + /* Add attribute to dataset */ + attr_id = H5Acreate2(dataset_id, attr_name, H5T_NATIVE_INT, space_id, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr_id, FAIL, "H5Acreate2"); + + /* Close attribute */ + ret = H5Aclose(attr_id); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close dataset */ + ret = H5Dclose(dataset_id); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(loc_id); + CHECK(ret, FAIL, "H5Fclose"); + } /* end for */ + + /* Close dataspace */ + ret = H5Sclose(space_id); + CHECK(ret, FAIL, "H5Sclose"); + +} /* end test_misc6() */ + +/**************************************************************** +** +** test_misc7(): Test that datatypes are sensible to store on +** disk. (i.e. not partially initialized) +** +****************************************************************/ +#if 0 +static void +test_misc7(void) +{ + hid_t fid, did, tid, sid; + int enum_value = 1; + herr_t ret; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing sensible datatype on disk code \n")); + + /* Attempt to commit a non-sensible datatype */ + + /* Create the file */ + fid = H5Fcreate(MISC7_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create the dataspace */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create the compound datatype to commit*/ + tid = H5Tcreate(H5T_COMPOUND, (size_t)32); + CHECK(tid, FAIL, "H5Tcreate"); + + /* Attempt to commit an empty compound datatype */ + ret = H5Tcommit2(fid, MISC7_TYPENAME1, tid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VERIFY(ret, FAIL, "H5Tcommit2"); + + /* Attempt to use empty compound datatype to create dataset */ + did = H5Dcreate2(fid, MISC7_DSETNAME1, tid, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VERIFY(ret, FAIL, "H5Dcreate2"); + + /* Add a field to the compound datatype */ + ret = H5Tinsert(tid, "a", (size_t)0, H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + /* Attempt to commit the compound datatype now - should work */ + ret = H5Tcommit2(fid, MISC7_TYPENAME1, tid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + + /* Attempt to use compound datatype to create dataset now - should work */ + did = H5Dcreate2(fid, MISC7_DSETNAME1, tid, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); + + /* Close dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close compound datatype */ + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Create the enum datatype to commit*/ + tid = H5Tenum_create(H5T_NATIVE_INT); + CHECK(tid, FAIL, "H5Tenum_create"); + + /* Attempt to commit an empty enum datatype */ + ret = H5Tcommit2(fid, MISC7_TYPENAME2, tid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VERIFY(ret, FAIL, "H5Tcommit2"); + + /* Attempt to use empty enum datatype to create dataset */ + did = H5Dcreate2(fid, MISC7_DSETNAME2, tid, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VERIFY(did, FAIL, "H5Dcreate2"); + + /* Add a member to the enum datatype */ + ret = H5Tenum_insert(tid, "a", &enum_value); + CHECK(ret, FAIL, "H5Tenum_insert"); + + /* Attempt to commit the enum datatype now - should work */ + ret = H5Tcommit2(fid, MISC7_TYPENAME2, tid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + + /* Attempt to use enum datatype to create dataset now - should work */ + did = H5Dcreate2(fid, MISC7_DSETNAME2, tid, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); + + /* Close dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close enum datatype */ + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + +} /* end test_misc7() */ +#endif + +/**************************************************************** +** +** test_misc8(): Test storage size of various types of dataset +** storage methods. +** +****************************************************************/ +#if 0 +static void +test_misc8(void) +{ + hid_t fid, did, sid; + hid_t fapl; /* File access property list */ + hid_t dcpl; /* Dataset creation property list */ + int rank = MISC8_RANK; + hsize_t dims[MISC8_RANK] = {MISC8_DIM0, MISC8_DIM1}; + hsize_t chunk_dims[MISC8_RANK] = {MISC8_CHUNK_DIM0, MISC8_CHUNK_DIM1}; + hsize_t storage_size; /* Number of bytes of raw data storage used */ + int *wdata; /* Data to write */ + int *tdata; /* Temporary pointer to data write */ +#ifdef VERIFY_DATA + int *rdata; /* Data to read */ + int *tdata2; /* Temporary pointer to data to read */ +#endif /* VERIFY_DATA */ + unsigned u, v; /* Local index variables */ + int mdc_nelmts; /* Metadata number of elements */ + size_t rdcc_nelmts; /* Raw data number of elements */ + size_t rdcc_nbytes; /* Raw data number of bytes */ + double rdcc_w0; /* Raw data write percentage */ + hsize_t start[MISC8_RANK]; /* Hyperslab start */ + hsize_t count[MISC8_RANK]; /* Hyperslab block count */ + herr_t ret; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing dataset storage sizes\n")); + + /* Allocate space for the data to write & read */ + wdata = (int *)HDmalloc(sizeof(int) * MISC8_DIM0 * MISC8_DIM1); + CHECK_PTR(wdata, "HDmalloc"); +#ifdef VERIFY_DATA + rdata = (int *)HDmalloc(sizeof(int) * MISC8_DIM0 * MISC8_DIM1); + CHECK_PTR(rdata, "HDmalloc"); +#endif /* VERIFY_DATA */ + + /* Initialize values */ + tdata = wdata; + for (u = 0; u < MISC8_DIM0; u++) + for (v = 0; v < MISC8_DIM1; v++) + *tdata++ = (int)(((u * MISC8_DIM1) + v) % 13); + + /* Create a file access property list */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + + /* Get the default file access properties for caching */ + ret = H5Pget_cache(fapl, &mdc_nelmts, &rdcc_nelmts, &rdcc_nbytes, &rdcc_w0); + CHECK(ret, FAIL, "H5Pget_cache"); + + /* Decrease the size of the raw data cache */ + rdcc_nbytes = 0; + + /* Set the file access properties for caching */ + ret = H5Pset_cache(fapl, mdc_nelmts, rdcc_nelmts, rdcc_nbytes, rdcc_w0); + CHECK(ret, FAIL, "H5Pset_cache"); + + /* Create the file */ + fid = H5Fcreate(MISC8_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Close file access property list */ + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Create a simple dataspace */ + sid = H5Screate_simple(rank, dims, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Select a hyperslab which coincides with chunk boundaries */ + /* (For later use) */ + start[0] = 1; + start[1] = 1; + count[0] = (MISC8_CHUNK_DIM0 * 2) - 1; + count[1] = (MISC8_CHUNK_DIM1 * 2) - 1; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create a dataset creation property list */ + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + + /* I. contiguous dataset tests */ + + ret = H5Pset_layout(dcpl, H5D_CONTIGUOUS); + CHECK(ret, FAIL, "H5Pset_layout"); + + /* Set the space allocation time to early */ + ret = H5Pset_alloc_time(dcpl, H5D_ALLOC_TIME_EARLY); + CHECK(ret, FAIL, "H5Pset_alloc_time"); + + /* Create a contiguous dataset, with space allocation early */ + did = H5Dcreate2(fid, MISC8_DSETNAME1, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); + + /* Check the storage size */ + storage_size = H5Dget_storage_size(did); + CHECK(storage_size, 0, "H5Dget_storage_size"); + VERIFY(storage_size, (hsize_t)(MISC8_DIM0 * MISC8_DIM1 * H5Tget_size(H5T_NATIVE_INT)), + "H5Dget_storage_size"); + + /* Close dataset ID */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + +#ifndef H5_HAVE_PARALLEL + /* Set the space allocation time to late */ + ret = H5Pset_alloc_time(dcpl, H5D_ALLOC_TIME_LATE); + CHECK(ret, FAIL, "H5Pset_alloc_time"); + + /* Create a contiguous dataset, with space allocation late */ + did = H5Dcreate2(fid, MISC8_DSETNAME2, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); + + /* Check the storage size before data is written */ + storage_size = H5Dget_storage_size(did); + VERIFY(storage_size, 0, "H5Dget_storage_size"); + + /* Write data */ + ret = H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Check the storage size after data is written */ + storage_size = H5Dget_storage_size(did); + CHECK(storage_size, 0, "H5Dget_storage_size"); + VERIFY(storage_size, (hsize_t)(MISC8_DIM0 * MISC8_DIM1 * H5Tget_size(H5T_NATIVE_INT)), + "H5Dget_storage_size"); + + /* Close dataset ID */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* Set the space allocation time to incremental */ + ret = H5Pset_alloc_time(dcpl, H5D_ALLOC_TIME_INCR); + CHECK(ret, FAIL, "H5Pset_alloc_time"); + + /* Create a contiguous dataset, with space allocation late */ + did = H5Dcreate2(fid, MISC8_DSETNAME3, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); + + /* Check the storage size before data is written */ + storage_size = H5Dget_storage_size(did); + VERIFY(storage_size, 0, "H5Dget_storage_size"); + + /* Write data */ + ret = H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Check the storage size after data is written */ + storage_size = H5Dget_storage_size(did); + CHECK(storage_size, 0, "H5Dget_storage_size"); + VERIFY(storage_size, (hsize_t)(MISC8_DIM0 * MISC8_DIM1 * H5Tget_size(H5T_NATIVE_INT)), + "H5Dget_storage_size"); + + /* Close dataset ID */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); +#endif /* H5_HAVE_PARALLEL */ + + /* II. compact dataset tests */ + ret = H5Pset_layout(dcpl, H5D_COMPACT); + CHECK(ret, FAIL, "H5Pset_layout"); + + /* Set the space allocation time to late */ + ret = H5Pset_alloc_time(dcpl, H5D_ALLOC_TIME_LATE); + CHECK(ret, FAIL, "H5Pset_alloc_time"); + + /* Create a contiguous dataset, with space allocation late */ + /* Should fail */ + H5E_BEGIN_TRY + { + did = H5Dcreate2(fid, MISC8_DSETNAME4, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(did, FAIL, "H5Dcreate2"); + + /* Set the space allocation time to incremental */ + ret = H5Pset_alloc_time(dcpl, H5D_ALLOC_TIME_INCR); + CHECK(ret, FAIL, "H5Pset_alloc_time"); + + /* Create a contiguous dataset, with space allocation incremental */ + /* Should fail */ + H5E_BEGIN_TRY + { + did = H5Dcreate2(fid, MISC8_DSETNAME4, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(did, FAIL, "H5Dcreate2"); + + /* Set the space allocation time to early */ + ret = H5Pset_alloc_time(dcpl, H5D_ALLOC_TIME_EARLY); + CHECK(ret, FAIL, "H5Pset_alloc_time"); + + /* Set the fill time to allocation */ + ret = H5Pset_fill_time(dcpl, H5D_FILL_TIME_ALLOC); + CHECK(ret, FAIL, "H5Pset_alloc_time"); + + /* Create a contiguous dataset, with space allocation early */ + did = H5Dcreate2(fid, MISC8_DSETNAME4, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); + + /* Check the storage size */ + storage_size = H5Dget_storage_size(did); + CHECK(storage_size, 0, "H5Dget_storage_size"); + VERIFY(storage_size, (hsize_t)(MISC8_DIM0 * MISC8_DIM1 * H5Tget_size(H5T_NATIVE_INT)), + "H5Dget_storage_size"); + + /* Close dataset ID */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* III. chunked dataset tests */ + + ret = H5Pset_layout(dcpl, H5D_CHUNKED); + CHECK(ret, FAIL, "H5Pset_layout"); + + /* Set the space allocation time to early */ + ret = H5Pset_alloc_time(dcpl, H5D_ALLOC_TIME_EARLY); + CHECK(ret, FAIL, "H5Pset_alloc_time"); + + /* Use chunked storage for this dataset */ + ret = H5Pset_chunk(dcpl, rank, chunk_dims); + CHECK(ret, FAIL, "H5Pset_chunk"); + + /* Create a chunked dataset, with space allocation early */ + did = H5Dcreate2(fid, MISC8_DSETNAME5, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); + + /* Check the storage size after data is written */ + storage_size = H5Dget_storage_size(did); + CHECK(storage_size, 0, "H5Dget_storage_size"); + VERIFY(storage_size, (hsize_t)(MISC8_DIM0 * MISC8_DIM1 * H5Tget_size(H5T_NATIVE_INT)), + "H5Dget_storage_size"); + + /* Close dataset ID */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + +#ifndef H5_HAVE_PARALLEL + /* Set the space allocation time to late */ + ret = H5Pset_alloc_time(dcpl, H5D_ALLOC_TIME_LATE); + CHECK(ret, FAIL, "H5Pset_alloc_time"); + + /* Use chunked storage for this dataset */ + ret = H5Pset_chunk(dcpl, rank, chunk_dims); + CHECK(ret, FAIL, "H5Pset_chunk"); + + /* Create a chunked dataset, with space allocation late */ + did = H5Dcreate2(fid, MISC8_DSETNAME6, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); + + /* Check the storage size after dataset is created */ + storage_size = H5Dget_storage_size(did); + VERIFY(storage_size, 0, "H5Dget_storage_size"); + + /* Write part of the dataset */ + ret = H5Dwrite(did, H5T_NATIVE_INT, sid, sid, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Check the storage size after data is written */ + storage_size = H5Dget_storage_size(did); + CHECK(storage_size, 0, "H5Dget_storage_size"); + VERIFY(storage_size, (hsize_t)(MISC8_DIM0 * MISC8_DIM1 * H5Tget_size(H5T_NATIVE_INT)), + "H5Dget_storage_size"); + + /* Close dataset ID */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* Set the space allocation time to incremental */ + ret = H5Pset_alloc_time(dcpl, H5D_ALLOC_TIME_INCR); + CHECK(ret, FAIL, "H5Pset_alloc_time"); + + /* Create a chunked dataset, with space allocation incremental */ + did = H5Dcreate2(fid, MISC8_DSETNAME7, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); + + /* Check the storage size before data is written */ + storage_size = H5Dget_storage_size(did); + VERIFY(storage_size, 0, "H5Dget_storage_size"); + + /* Write part of the dataset */ + ret = H5Dwrite(did, H5T_NATIVE_INT, sid, sid, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Check the storage size after only four chunks are written */ + storage_size = H5Dget_storage_size(did); + VERIFY(storage_size, (hsize_t)(4 * MISC8_CHUNK_DIM0 * MISC8_CHUNK_DIM1 * H5Tget_size(H5T_NATIVE_INT)), + "H5Dget_storage_size"); + + /* Write entire dataset */ + ret = H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + +#ifdef VERIFY_DATA + /* Read data */ + ret = H5Dread(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Check values written */ + tdata = wdata; + tdata2 = rdata; + for (u = 0; u < MISC8_DIM0; u++) + for (v = 0; v < MISC8_DIM1; v++, tdata++, tdata2++) + if (*tdata != *tdata2) + TestErrPrintf("Error on line %d: u=%u, v=%d, *tdata=%d, *tdata2=%d\n", __LINE__, (unsigned)u, + (unsigned)v, (int)*tdata, (int)*tdata2); +#endif /* VERIFY_DATA */ + + /* Check the storage size after data is written */ + storage_size = H5Dget_storage_size(did); + CHECK(storage_size, 0, "H5Dget_storage_size"); + VERIFY(storage_size, (hsize_t)(MISC8_DIM0 * MISC8_DIM1 * H5Tget_size(H5T_NATIVE_INT)), + "H5Dget_storage_size"); + + /* Close dataset ID */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); +#endif /* H5_HAVE_PARALLEL */ + + /* Set the space allocation time to early */ + ret = H5Pset_alloc_time(dcpl, H5D_ALLOC_TIME_EARLY); + CHECK(ret, FAIL, "H5Pset_alloc_time"); + + /* Use compression as well as chunking for these datasets */ +#ifdef H5_HAVE_FILTER_DEFLATE + ret = H5Pset_deflate(dcpl, 9); + CHECK(ret, FAIL, "H5Pset_deflate"); +#endif /* end H5_HAVE_FILTER_DEFLATE */ + + /* Create a chunked dataset, with space allocation early */ + did = H5Dcreate2(fid, MISC8_DSETNAME8, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); + + /* Write part of the dataset */ + ret = H5Dwrite(did, H5T_NATIVE_INT, sid, sid, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Check the storage size after data is written */ + storage_size = H5Dget_storage_size(did); + CHECK(storage_size, 0, "H5Dget_storage_size"); +#ifdef H5_HAVE_FILTER_DEFLATE + if (storage_size >= (MISC8_DIM0 * MISC8_DIM1 * H5Tget_size(H5T_NATIVE_INT))) + TestErrPrintf("Error on line %d: data wasn't compressed! storage_size=%u\n", __LINE__, + (unsigned)storage_size); +#else /* Compression is not configured */ + if (storage_size != (MISC8_DIM0 * MISC8_DIM1 * H5Tget_size(H5T_NATIVE_INT))) + TestErrPrintf("Error on line %d: wrong storage size! storage_size=%u\n", __LINE__, + (unsigned)storage_size); +#endif /* H5_HAVE_FILTER_DEFLATE */ + + /* Close dataset ID */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + +#ifndef H5_HAVE_PARALLEL + /* Set the space allocation time to late */ + ret = H5Pset_alloc_time(dcpl, H5D_ALLOC_TIME_LATE); + CHECK(ret, FAIL, "H5Pset_alloc_time"); + + /* Create a chunked dataset, with space allocation late */ + did = H5Dcreate2(fid, MISC8_DSETNAME9, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); + + /* Check the storage size before data is written */ + storage_size = H5Dget_storage_size(did); + VERIFY(storage_size, 0, "H5Dget_storage_size"); + + /* Write part of the dataset */ + ret = H5Dwrite(did, H5T_NATIVE_INT, sid, sid, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Check the storage size after only four chunks are written */ + storage_size = H5Dget_storage_size(did); + CHECK(storage_size, 0, "H5Dget_storage_size"); +#ifdef H5_HAVE_FILTER_DEFLATE + if (storage_size >= (MISC8_DIM0 * MISC8_DIM1 * H5Tget_size(H5T_NATIVE_INT))) + TestErrPrintf("Error on line %d: data wasn't compressed! storage_size=%u\n", __LINE__, + (unsigned)storage_size); +#else /* Compression is not configured */ + if (storage_size != (MISC8_DIM0 * MISC8_DIM1 * H5Tget_size(H5T_NATIVE_INT))) + TestErrPrintf("Error on line %d: wrong storage size! storage_size=%u\n", __LINE__, + (unsigned)storage_size); +#endif /* H5_HAVE_FILTER_DEFLATE */ + + /* Write entire dataset */ + ret = H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + +#ifdef VERIFY_DATA + /* Read data */ + ret = H5Dread(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Check values written */ + tdata = wdata; + tdata2 = rdata; + for (u = 0; u < MISC8_DIM0; u++) + for (v = 0; v < MISC8_DIM1; v++, tdata++, tdata2++) + if (*tdata != *tdata2) + TestErrPrintf("Error on line %d: u=%u, v=%d, *tdata=%d, *tdata2=%d\n", __LINE__, (unsigned)u, + (unsigned)v, (int)*tdata, (int)*tdata2); +#endif /* VERIFY_DATA */ + + /* Check the storage size after data is written */ + storage_size = H5Dget_storage_size(did); + CHECK(storage_size, 0, "H5Dget_storage_size"); +#ifdef H5_HAVE_FILTER_DEFLATE + if (storage_size >= (MISC8_DIM0 * MISC8_DIM1 * H5Tget_size(H5T_NATIVE_INT))) + TestErrPrintf("Error on line %d: data wasn't compressed! storage_size=%u\n", __LINE__, + (unsigned)storage_size); +#else + if (storage_size != (MISC8_DIM0 * MISC8_DIM1 * H5Tget_size(H5T_NATIVE_INT))) + TestErrPrintf("Error on line %d: wrong storage size! storage_size=%u\n", __LINE__, + (unsigned)storage_size); +#endif /*H5_HAVE_FILTER_DEFLATE*/ + + /* Close dataset ID */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* Set the space allocation time to incremental */ + ret = H5Pset_alloc_time(dcpl, H5D_ALLOC_TIME_INCR); + CHECK(ret, FAIL, "H5Pset_alloc_time"); + + /* Create a chunked dataset, with space allocation incremental */ + did = H5Dcreate2(fid, MISC8_DSETNAME10, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); + + /* Check the storage size before data is written */ + storage_size = H5Dget_storage_size(did); + VERIFY(storage_size, 0, "H5Dget_storage_size"); + + /* Write part of the dataset */ + ret = H5Dwrite(did, H5T_NATIVE_INT, sid, sid, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Check the storage size after only four chunks are written */ + storage_size = H5Dget_storage_size(did); + CHECK(storage_size, 0, "H5Dget_storage_size"); +#ifdef H5_HAVE_FILTER_DEFLATE + if (storage_size >= (4 * MISC8_CHUNK_DIM0 * MISC8_CHUNK_DIM1 * H5Tget_size(H5T_NATIVE_INT))) + TestErrPrintf("Error on line %d: data wasn't compressed! storage_size=%u\n", __LINE__, + (unsigned)storage_size); +#else /* Compression is not configured */ + if (storage_size != (4 * MISC8_CHUNK_DIM0 * MISC8_CHUNK_DIM1 * H5Tget_size(H5T_NATIVE_INT))) + TestErrPrintf("Error on line %d: wrong storage size! storage_size=%u\n", __LINE__, + (unsigned)storage_size); +#endif /* H5_HAVE_FILTER_DEFLATE */ + + /* Write entire dataset */ + ret = H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + +#ifdef VERIFY_DATA + /* Read data */ + ret = H5Dread(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Check values written */ + tdata = wdata; + tdata2 = rdata; + for (u = 0; u < MISC8_DIM0; u++) + for (v = 0; v < MISC8_DIM1; v++, tdata++, tdata2++) + if (*tdata != *tdata2) + TestErrPrintf("Error on line %d: u=%u, v=%d, *tdata=%d, *tdata2=%d\n", __LINE__, (unsigned)u, + (unsigned)v, (int)*tdata, (int)*tdata2); +#endif /* VERIFY_DATA */ + + /* Check the storage size after data is written */ + storage_size = H5Dget_storage_size(did); + CHECK(storage_size, 0, "H5Dget_storage_size"); +#ifdef H5_HAVE_FILTER_DEFLATE + if (storage_size >= (MISC8_DIM0 * MISC8_DIM1 * H5Tget_size(H5T_NATIVE_INT))) + TestErrPrintf("Error on line %d: data wasn't compressed! storage_size=%u\n", __LINE__, + (unsigned)storage_size); +#else + if (storage_size != (MISC8_DIM0 * MISC8_DIM1 * H5Tget_size(H5T_NATIVE_INT))) + TestErrPrintf("Error on line %d: wrong storage size! storage_size=%u\n", __LINE__, + (unsigned)storage_size); +#endif /*H5_HAVE_FILTER_DEFLATE*/ + + /* Close dataset ID */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); +#endif /* H5_HAVE_PARALLEL */ + + /* Close dataset creation property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free the read & write buffers */ + HDfree(wdata); +#ifdef VERIFY_DATA + HDfree(rdata); +#endif /* VERIFY_DATA */ +} /* end test_misc8() */ +#endif + +/**************************************************************** +** +** test_misc9(): Test that H5Fopen() does not succeed for core +** files, H5Fcreate() must be used to open them. +** +****************************************************************/ +static void +test_misc9(void) +{ + hid_t fapl, fid; + herr_t ret; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing core file opening\n")); + + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + + ret = H5Pset_fapl_core(fapl, (size_t)1024, 0); + CHECK(ret, FAIL, "H5Pset_fapl_core"); + + H5E_BEGIN_TRY + { + fid = H5Fopen(MISC9_FILE, H5F_ACC_RDWR, fapl); + } + H5E_END_TRY; + VERIFY(fid, FAIL, "H5Fopen"); + + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pset_fapl_core"); +} /* end test_misc9() */ + +/**************************************************************** +** +** test_misc10(): Test opening a dataset created with an older +** version of the library (shares the tmtimeo.h5 file with the mtime.c +** test - see notes in gen_old_mtime.c for notes on generating this +** data file) and using the dataset creation property list from +** that dataset to create a dataset with the current version of +** the library. Also tests using file creation property in same way. +** +****************************************************************/ +#if 0 +static void +test_misc10(void) +{ + hid_t file, file_new; /* File IDs for old & new files */ + hid_t fcpl; /* File creation property list */ + hid_t dataset, dataset_new; /* Dataset IDs for old & new datasets */ + hid_t dcpl; /* Dataset creation property list */ + hid_t space, type; /* Old dataset's dataspace & datatype */ + const char *testfile = H5_get_srcdir_filename(MISC10_FILE_OLD); /* Corrected test file name */ + hbool_t driver_is_default_compatible; + herr_t ret; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing using old dataset creation property list\n")); + + ret = h5_driver_is_default_vfd_compatible(H5P_DEFAULT, &driver_is_default_compatible); + CHECK(ret, FAIL, "h5_driver_is_default_vfd_compatible"); + + if (!driver_is_default_compatible) { + HDprintf("-- SKIPPED --\n"); + return; + } + + /* + * Open the old file and the dataset and get old settings. + */ + file = H5Fopen(testfile, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(file, FAIL, "H5Fopen"); + fcpl = H5Fget_create_plist(file); + CHECK(fcpl, FAIL, "H5Fget_create_plist"); + + dataset = H5Dopen2(file, MISC10_DSETNAME, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + dcpl = H5Dget_create_plist(dataset); + CHECK(dcpl, FAIL, "H5Dget_create_plist"); + space = H5Dget_space(dataset); + CHECK(space, FAIL, "H5Dget_space"); + type = H5Dget_type(dataset); + CHECK(type, FAIL, "H5Dget_type"); + + /* Create new file & dataset */ + file_new = H5Fcreate(MISC10_FILE_NEW, H5F_ACC_TRUNC, fcpl, H5P_DEFAULT); + CHECK(file_new, FAIL, "H5Fcreate"); + + dataset_new = H5Dcreate2(file_new, MISC10_DSETNAME, type, space, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dataset_new, FAIL, "H5Dcreate2"); + + /* Close new dataset & file */ + ret = H5Dclose(dataset_new); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Fclose(file_new); + CHECK(ret, FAIL, "H5Fclose"); + + /* Close old dataset information */ + ret = H5Tclose(type); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Sclose(space); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close old file information */ + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); +} /* end test_misc10() */ +#endif + +/**************************************************************** +** +** test_misc11(): Test that all properties in a file creation property +** list are stored correctly in the file and can be retrieved +** when the file is re-opened. +** +****************************************************************/ +static void +test_misc11(void) +{ + hid_t file; /* File IDs for old & new files */ + hid_t fcpl; /* File creation property list */ + hsize_t userblock; /* Userblock size retrieved from FCPL */ + size_t off_size; /* Size of offsets in the file */ + size_t len_size; /* Size of lengths in the file */ + unsigned sym_ik; /* Symbol table B-tree initial 'K' value */ + unsigned istore_ik; /* Indexed storage B-tree initial 'K' value */ + unsigned sym_lk; /* Symbol table B-tree leaf 'K' value */ + unsigned nindexes; /* Shared message number of indexes */ +#if 0 + H5F_info2_t finfo; /* global information about file */ +#endif + H5F_fspace_strategy_t strategy; /* File space strategy */ + hsize_t threshold; /* Free-space section threshold */ + hbool_t persist; /* To persist free-space or not */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing file creation properties retrieved correctly\n")); + + /* Creating a file with the default file creation property list should + * create a version 0 superblock + */ + + /* Create file with default file creation property list */ + file = H5Fcreate(MISC11_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file, FAIL, "H5Fcreate"); +#if 0 + /* Get the file's version information */ + ret = H5Fget_info2(file, &finfo); + CHECK(ret, FAIL, "H5Fget_info2"); + VERIFY(finfo.super.version, 0, "H5Fget_info2"); + VERIFY(finfo.free.version, 0, "H5Fget_info2"); + VERIFY(finfo.sohm.version, 0, "H5Fget_info2"); +#endif + /* Close file */ + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + + /* Create a file creation property list */ + fcpl = H5Pcreate(H5P_FILE_CREATE); + CHECK(fcpl, FAIL, "H5Pcreate"); + + /* Set all the properties in the FCPL */ + ret = H5Pset_userblock(fcpl, (hsize_t)MISC11_USERBLOCK); + CHECK(ret, FAIL, "H5Pset_userblock"); + + ret = H5Pset_sizes(fcpl, (size_t)MISC11_SIZEOF_OFF, (size_t)MISC11_SIZEOF_LEN); + CHECK(ret, FAIL, "H5Pset_sizes"); + + /* This should fail as (32770*2) will exceed ^16 - 2 bytes for storing btree entries */ + H5E_BEGIN_TRY + { + ret = H5Pset_sym_k(fcpl, 32770, 0); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Pset_sym_k"); + + ret = H5Pset_sym_k(fcpl, MISC11_SYM_IK, MISC11_SYM_LK); + CHECK(ret, FAIL, "H5Pset_sym_k"); + + /* This should fail as (32770*2) will exceed ^16 - 2 bytes for storing btree entries */ + H5E_BEGIN_TRY + { + ret = H5Pset_istore_k(fcpl, 32770); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Pset_istore_k"); + + ret = H5Pset_istore_k(fcpl, MISC11_ISTORE_IK); + CHECK(ret, FAIL, "H5Pset_istore_k"); + + ret = H5Pset_shared_mesg_nindexes(fcpl, MISC11_NINDEXES); + CHECK(ret, FAIL, "H5Pset_shared_mesg"); + + ret = H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_NONE, FALSE, (hsize_t)1); + CHECK(ret, FAIL, "H5Pset_file_space"); + + /* Creating a file with the non-default file creation property list should + * create a version 2 superblock + */ + + /* Create file with custom file creation property list */ + file = H5Fcreate(MISC11_FILE, H5F_ACC_TRUNC, fcpl, H5P_DEFAULT); + CHECK(file, FAIL, "H5Fcreate"); + + /* Close FCPL */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); +#if 0 + /* Get the file's version information */ + ret = H5Fget_info2(file, &finfo); + CHECK(ret, FAIL, "H5Fget_info2"); + VERIFY(finfo.super.version, 2, "H5Fget_info2"); + VERIFY(finfo.free.version, 0, "H5Fget_info2"); + VERIFY(finfo.sohm.version, 0, "H5Fget_info2"); +#endif + /* Close file */ + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open the file */ + file = H5Fopen(MISC11_FILE, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(file, FAIL, "H5Fcreate"); + + /* Get the file's creation property list */ + fcpl = H5Fget_create_plist(file); + CHECK(fcpl, FAIL, "H5Fget_create_plist"); +#if 0 + /* Get the file's version information */ + ret = H5Fget_info2(file, &finfo); + CHECK(ret, FAIL, "H5Fget_info2"); + VERIFY(finfo.super.version, 2, "H5Fget_info2"); + VERIFY(finfo.free.version, 0, "H5Fget_info2"); + VERIFY(finfo.sohm.version, 0, "H5Fget_info2"); +#endif + /* Retrieve all the property values & check them */ + ret = H5Pget_userblock(fcpl, &userblock); + CHECK(ret, FAIL, "H5Pget_userblock"); + VERIFY(userblock, MISC11_USERBLOCK, "H5Pget_userblock"); + + ret = H5Pget_sizes(fcpl, &off_size, &len_size); + CHECK(ret, FAIL, "H5Pget_sizes"); + VERIFY(off_size, MISC11_SIZEOF_OFF, "H5Pget_sizes"); + VERIFY(len_size, MISC11_SIZEOF_LEN, "H5Pget_sizes"); + + ret = H5Pget_sym_k(fcpl, &sym_ik, &sym_lk); + CHECK(ret, FAIL, "H5Pget_sym_k"); + VERIFY(sym_ik, MISC11_SYM_IK, "H5Pget_sym_k"); + VERIFY(sym_lk, MISC11_SYM_LK, "H5Pget_sym_k"); + + ret = H5Pget_istore_k(fcpl, &istore_ik); + CHECK(ret, FAIL, "H5Pget_istore_k"); + VERIFY(istore_ik, MISC11_ISTORE_IK, "H5Pget_istore_k"); + + ret = H5Pget_shared_mesg_nindexes(fcpl, &nindexes); + CHECK(ret, FAIL, "H5Pget_shared_mesg_nindexes"); + VERIFY(nindexes, MISC11_NINDEXES, "H5Pget_shared_mesg_nindexes"); + + ret = H5Pget_file_space_strategy(fcpl, &strategy, &persist, &threshold); + CHECK(ret, FAIL, "H5Pget_file_space_strategy"); + VERIFY(strategy, 3, "H5Pget_file_space_strategy"); + VERIFY(persist, FALSE, "H5Pget_file_space_strategy"); + VERIFY(threshold, 1, "H5Pget_file_space_strategy"); + + /* Close file */ + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + + /* Close FCPL */ + ret = H5Pclose(fcpl); + CHECK(ret, FAIL, "H5Pclose"); +} /* end test_misc11() */ + +/**************************************************************** +** +** test_misc12(): Test that VL-types operate correctly in chunked +** datasets that are extended. +** +****************************************************************/ +static void +test_misc12(void) +{ + const char *wdata[MISC12_SPACE1_DIM1] = { + "Four score and seven years ago our forefathers brought forth on this continent a new nation,", + "conceived in liberty and dedicated to the proposition that all men are created equal.", + "Now we are engaged in a great civil war,", + "testing whether that nation or any nation so conceived and so dedicated can long endure."}; + const char *wdata1[MISC12_APPEND_SIZE] = { + "O Gloria inmarcesible! O Jubilo inmortal! En surcos de dolores, el", + "bien germina ya! Ceso la horrible noche, La libertad sublime", + "derrama las auroras de su invencible luz.", "La humanidad entera, que entre cadenas gime, comprende", + "las palabras del que murio en la cruz."}; + char *rdata[MISC12_SPACE1_DIM1 + MISC12_APPEND_SIZE]; /* Information read in */ + hid_t fid1; + hid_t dataset; + hid_t sid1, space, memspace; + hid_t tid1, cparms; + hsize_t dims1[] = {MISC12_SPACE1_DIM1}; + hsize_t dimsn[] = {MISC12_APPEND_SIZE}; + hsize_t maxdims1[1] = {H5S_UNLIMITED}; + hsize_t chkdims1[1] = {MISC12_CHUNK_SIZE}; + hsize_t newsize[1] = {MISC12_SPACE1_DIM1 + MISC12_APPEND_SIZE}; + hsize_t offset[1] = {MISC12_SPACE1_DIM1}; + hsize_t count[1] = {MISC12_APPEND_SIZE}; + int i; /* counting variable */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing VL-type in chunked dataset\n")); + + /* This test requirese a relatively "fresh" library environment */ + ret = H5garbage_collect(); + CHECK(ret, FAIL, "H5garbage_collect"); + + /* Create file */ + fid1 = H5Fcreate(MISC12_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid1 = H5Screate_simple(MISC12_SPACE1_RANK, dims1, maxdims1); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create a datatype to refer to */ + tid1 = H5Tcopy(H5T_C_S1); + CHECK(tid1, FAIL, "H5Tcopy"); + + ret = H5Tset_size(tid1, H5T_VARIABLE); + CHECK(ret, FAIL, "H5Tset_size"); + + cparms = H5Pcreate(H5P_DATASET_CREATE); + CHECK(cparms, FAIL, "H5Pcreate"); + + ret = H5Pset_chunk(cparms, 1, chkdims1); + CHECK(ret, FAIL, "H5Pset_chunk"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, MISC12_DSET_NAME, tid1, sid1, H5P_DEFAULT, cparms, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write dataset to disk */ + ret = H5Dwrite(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Extend dataset */ + ret = H5Dset_extent(dataset, newsize); + CHECK(ret, FAIL, "H5Dset_extent"); + + memspace = H5Screate_simple(MISC12_SPACE1_RANK, dimsn, NULL); + CHECK(memspace, FAIL, "H5Screate_simple"); + + space = H5Dget_space(dataset); + CHECK(space, FAIL, "H5Dget_space"); + + ret = H5Sselect_hyperslab(space, H5S_SELECT_SET, offset, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Write data to new portion of dataset */ + ret = H5Dwrite(dataset, tid1, memspace, space, H5P_DEFAULT, wdata1); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Read all data back */ + ret = H5Dread(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + for (i = 0; i < MISC12_SPACE1_DIM1; i++) + if (HDstrcmp(wdata[i], rdata[i]) != 0) + TestErrPrintf("Error on line %d: wdata[%d]=%s, rdata[%d]=%s\n", __LINE__, i, wdata[i], i, + rdata[i]); + for (; i < (MISC12_SPACE1_DIM1 + MISC12_APPEND_SIZE); i++) + if (HDstrcmp(wdata1[i - MISC12_SPACE1_DIM1], rdata[i]) != 0) + TestErrPrintf("Error on line %d: wdata1[%d]=%s, rdata[%d]=%s\n", __LINE__, i - MISC12_SPACE1_DIM1, + wdata1[i - MISC12_SPACE1_DIM1], i, rdata[i]); + + ret = H5Sselect_all(space); + CHECK(ret, FAIL, "H5Sselect_all"); + + /* Reclaim VL data memory */ + ret = H5Treclaim(tid1, space, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Close Everything */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Sclose(space); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(memspace); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Pclose(cparms); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_misc12() */ +#if 0 +/* Various routines for misc. 13 test */ +static void +misc13_init_data(unsigned *original_data) +{ + unsigned u; + + for (u = 0; u < MISC13_DIM1; u++) + original_data[u] = u; +} + +static hbool_t +misc13_verify_data_match(const unsigned *original_data, const unsigned *read_data) +{ + unsigned u; + + for (u = 0; u < MISC13_DIM1; u++) + if (original_data[u] != read_data[u]) + return FALSE; + + return TRUE; +} + +static void +misc13_create_dataset(hid_t loc_id, const char *name, hid_t dcpl, const unsigned *data) +{ + hid_t dsid = -1; /* Dataset ID */ + hid_t sid = -1; /* Dataspace ID */ + hsize_t dims[MISC13_RANK]; /* Dataset dimensions */ + herr_t ret; /* Generic return value */ + + /* Create dataspace for use with dataset */ + dims[0] = MISC13_DIM1; + sid = H5Screate_simple(MISC13_RANK, dims, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Create contiguous dataset in root group */ + dsid = H5Dcreate2(loc_id, name, H5T_NATIVE_UINT, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dsid, FAIL, "H5Dcreate2"); + + /* Write some data to dataset */ + ret = H5Dwrite(dsid, H5T_NATIVE_UINT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close the contiguous dataset */ + ret = H5Dclose(dsid); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close the dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + +} /* end misc13_create_dataset() */ + +static void +misc13_verify_dataset(hid_t loc_id, const char *name, const unsigned *data) +{ + unsigned *read_data = NULL; /* Data to write to dataset */ + hid_t dsid = -1; /* Dataset ID */ + herr_t ret; /* Generic return value */ + + /* Create a data buffer for the dataset read */ + read_data = (unsigned *)HDcalloc(MISC13_DIM1, sizeof(unsigned)); + CHECK_PTR(read_data, "HDcalloc"); + + /* Open the contiguous dataset in the root group */ + dsid = H5Dopen2(loc_id, name, H5P_DEFAULT); + CHECK(dsid, FAIL, "H5Dopen2"); + + /* Read the data */ + ret = H5Dread(dsid, H5T_NATIVE_UINT, H5S_ALL, H5S_ALL, H5P_DEFAULT, read_data); + CHECK(ret, FAIL, "H5Dread"); + + /* Verify that the data are correct */ + ret = misc13_verify_data_match(data, read_data); + CHECK(ret, FAIL, "misc13_verify_data_match"); + + /* Close the contiguous dataset */ + ret = H5Dclose(dsid); + CHECK(ret, FAIL, "H5Dclose"); + + /* Free the dataset read buffer */ + HDfree(read_data); + +} /* end misc13_verify_dataset() */ + +static void +misc13_create_hdf_file(const char *name, const unsigned *data) +{ + hid_t fid = -1; /* File ID */ + hid_t gid1 = -1; /* Group ID (level 1) */ + hid_t gid2 = -1; /* Group ID (level 2) */ + hid_t tid = -1; /* Datatype ID */ + hid_t dcplid = -1; /* Dataset creation property list ID */ + hsize_t chunk_dims[MISC13_RANK]; /* Chunk dimensions */ + herr_t ret; /* Generic return value */ + + /* Create file */ + fid = H5Fcreate(name, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create DCPL for use with datasets */ + dcplid = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcplid, FAIL, "H5Pcreate"); + + /* Set the DCPL to be chunked */ + ret = H5Pset_layout(dcplid, H5D_CHUNKED); + CHECK(ret, FAIL, "H5Pset_layout"); + + /* Use chunked storage for this DCPL */ + chunk_dims[0] = MISC13_CHUNK_DIM1; + ret = H5Pset_chunk(dcplid, MISC13_RANK, chunk_dims); + CHECK(ret, FAIL, "H5Pset_chunk"); + + /* Create contiguous dataset in root group */ + misc13_create_dataset(fid, MISC13_DSET1_NAME, H5P_DEFAULT, data); + + /* Create chunked dataset in root group */ + misc13_create_dataset(fid, MISC13_DSET2_NAME, dcplid, data); + + /* Create a datatype to commit to the file */ + tid = H5Tcopy(H5T_NATIVE_INT); + CHECK(tid, FAIL, "H5Tcopy"); + + /* Create a named datatype in the root group */ + ret = H5Tcommit2(fid, MISC13_DTYPE_NAME, tid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + + /* Close named datatype */ + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Create a group in the root group */ + gid1 = H5Gcreate2(fid, MISC13_GROUP1_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid1, FAIL, "H5Gcreate2"); + + /* Create another group in the new group */ + gid2 = H5Gcreate2(gid1, MISC13_GROUP2_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid2, FAIL, "H5Gcreate2"); + + /* Close the second group */ + ret = H5Gclose(gid2); + CHECK(ret, FAIL, "H5Gclose"); + + /* Create contiguous dataset in new group */ + misc13_create_dataset(gid1, MISC13_DSET1_NAME, H5P_DEFAULT, data); + + /* Create chunked dataset in new group */ + misc13_create_dataset(gid1, MISC13_DSET2_NAME, dcplid, data); + + /* Create a datatype to commit to the new group */ + tid = H5Tcopy(H5T_NATIVE_INT); + CHECK(tid, FAIL, "H5Tcopy"); + + /* Create a named datatype in the new group */ + ret = H5Tcommit2(gid1, MISC13_DTYPE_NAME, tid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + + /* Close named datatype */ + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close the first group */ + ret = H5Gclose(gid1); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close the DCPL */ + ret = H5Pclose(dcplid); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + +} /* end misc13_create_hdf_file() */ + +static void +misc13_insert_user_block(const char *old_name, const char *new_name, const char *str, size_t size) +{ + FILE *new_fp = NULL; /* Pointers to new & old files */ + FILE *old_fp = NULL; + void *user_block = NULL; /* Pointer to user block to write to file */ + void *copy_buf = NULL; /* Pointer to buffer for copying data */ + size_t written; /* Amount of data written to new file */ + size_t read_in; /* Amount of data read in from old file */ + int ret; /* Generic status value */ + + /* Allocate space for the user block */ + user_block = HDcalloc(size, (size_t)1); + CHECK_PTR(user_block, "HDcalloc"); + + /* Copy in the user block data */ + HDmemcpy(user_block, str, HDstrlen(str)); + + /* Open the new file */ + new_fp = HDfopen(new_name, "wb"); + CHECK_PTR(new_fp, "HDfopen"); + + /* Write the user block to the new file */ + written = HDfwrite(user_block, (size_t)1, size, new_fp); + VERIFY(written, size, "HDfwrite"); + + /* Open the old file */ + old_fp = HDfopen(old_name, "rb"); + CHECK_PTR(old_fp, "HDfopen"); + + /* Allocate space for the copy buffer */ + copy_buf = HDmalloc((size_t)MISC13_COPY_BUF_SIZE); + CHECK_PTR(copy_buf, "HDmalloc"); + + /* Copy data from the old file to the new file */ + while ((read_in = HDfread(copy_buf, (size_t)1, (size_t)MISC13_COPY_BUF_SIZE, old_fp)) > 0) { + /* Write the data to the new file */ + written = HDfwrite(copy_buf, (size_t)1, read_in, new_fp); + VERIFY(written, read_in, "HDfwrite"); + } + + /* Close the old file */ + ret = HDfclose(old_fp); + VERIFY(ret, 0, "HDfclose"); + + /* Close the new file */ + ret = HDfclose(new_fp); + VERIFY(ret, 0, "HDfclose"); + + /* Free the copy buffer */ + HDfree(copy_buf); + + /* Free the user block */ + HDfree(user_block); + +} /* end misc13_insert_user_block() */ + +static void +misc13_verify_file(const char *name, const unsigned *data, hsize_t userblock_size, + hbool_t check_for_new_dataset) +{ + hid_t fid = -1; /* File ID */ + hid_t gid1 = -1; /* Group IDs */ + hid_t gid2 = -1; /* Group IDs */ + hid_t tid = -1; /* Datatype ID */ + hid_t fcplid = -1; /* File creation property list ID */ + hsize_t ub_size_out; /* Userblock size retrieved from FCPL */ + herr_t ret; /* Generic return value */ + + /* Open the file */ + fid = H5Fopen(name, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* Get the file's FCPL */ + fcplid = H5Fget_create_plist(fid); + CHECK(fcplid, FAIL, "H5Fget_create_plist"); + + /* Get the user block size for the file */ + ret = H5Pget_userblock(fcplid, &ub_size_out); + CHECK(ret, FAIL, "H5Pget_userblock"); + + /* Check the userblock size */ + VERIFY(userblock_size, ub_size_out, "H5Pget_userblock"); + + /* Close the FCPL */ + ret = H5Pclose(fcplid); + CHECK(ret, FAIL, "H5Pclose"); + + /* Verify the contiguous dataset in the root group */ + misc13_verify_dataset(fid, MISC13_DSET1_NAME, data); + + /* Verify the chunked dataset in the root group */ + misc13_verify_dataset(fid, MISC13_DSET2_NAME, data); + + /* Verify the "new" contiguous dataset in the root group, if asked */ + if (check_for_new_dataset) + misc13_verify_dataset(fid, MISC13_DSET3_NAME, data); + + /* Open the named datatype in the root group */ + tid = H5Topen2(fid, MISC13_DTYPE_NAME, H5P_DEFAULT); + CHECK(tid, FAIL, "H5Topen2"); + + /* Verify the type is correct */ + VERIFY(H5Tequal(tid, H5T_NATIVE_INT), TRUE, "H5Tequal"); + + /* Close named datatype */ + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Open the first group */ + gid1 = H5Gopen2(fid, MISC13_GROUP1_NAME, H5P_DEFAULT); + CHECK(gid1, FAIL, "H5Gopen2"); + + /* Verify the contiguous dataset in the first group */ + misc13_verify_dataset(gid1, MISC13_DSET1_NAME, data); + + /* Verify the chunked dataset in the first group */ + misc13_verify_dataset(gid1, MISC13_DSET2_NAME, data); + + /* Open the named datatype in the first group */ + tid = H5Topen2(gid1, MISC13_DTYPE_NAME, H5P_DEFAULT); + CHECK(tid, FAIL, "H5Topen2"); + + /* Verify the type is correct */ + VERIFY(H5Tequal(tid, H5T_NATIVE_INT), TRUE, "H5Tequal"); + + /* Close named datatype */ + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Open the second group */ + gid2 = H5Gopen2(gid1, MISC13_GROUP2_NAME, H5P_DEFAULT); + CHECK(gid2, FAIL, "H5Gopen2"); + + /* Close the second group */ + ret = H5Gclose(gid2); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close the first group */ + ret = H5Gclose(gid1); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + +} /* end misc13_verify_file() */ + +static void +misc13_add_to_new_file(const char *name, const unsigned *data) +{ + hid_t fid = -1; /* File ID */ + herr_t ret; /* Generic return value */ + + /* Open the file */ + fid = H5Fopen(name, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* Create new contiguous dataset in root group */ + misc13_create_dataset(fid, MISC13_DSET3_NAME, H5P_DEFAULT, data); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + +} /* end misc13_add_to_new_file() */ + +/**************************************************************** +** +** test_misc13(): Test that file contents can be "slid down" by +** inserting a user block in front of an existing file. +** +****************************************************************/ +static void +test_misc13(void) +{ + unsigned *data = NULL; /* Data to write to dataset */ + hsize_t userblock_size; /* Correct size of userblock */ + hbool_t check_for_new_dataset; /* Whether to check for the post-userblock-creation dataset */ + + /* Create a data buffer for the datasets */ + data = (unsigned *)HDcalloc(MISC13_DIM1, sizeof(unsigned)); + CHECK_PTR(data, "HDcalloc"); + + /* Initialize data to write */ + misc13_init_data(data); + + /* Create first file, with no user block */ + misc13_create_hdf_file(MISC13_FILE_1, data); + + /* Verify file contents are correct */ + userblock_size = 0; + check_for_new_dataset = FALSE; + misc13_verify_file(MISC13_FILE_1, data, userblock_size, check_for_new_dataset); + + /* Create a new file by inserting a user block in front of the first file */ + misc13_insert_user_block(MISC13_FILE_1, MISC13_FILE_2, "Test String", (size_t)MISC13_USERBLOCK_SIZE); + + /* Verify file contents are still correct */ + userblock_size = MISC13_USERBLOCK_SIZE; + check_for_new_dataset = FALSE; + misc13_verify_file(MISC13_FILE_2, data, userblock_size, check_for_new_dataset); + + /* Make certain we can modify the new file */ + misc13_add_to_new_file(MISC13_FILE_2, data); + + /* Verify file contents are still correct */ + userblock_size = MISC13_USERBLOCK_SIZE; + check_for_new_dataset = TRUE; + misc13_verify_file(MISC13_FILE_2, data, userblock_size, check_for_new_dataset); + + /* Free the dataset buffer */ + HDfree(data); + +} /* end test_misc13() */ +#endif + +/**************************************************************** +** +** test_misc14(): Test that file contents can be "slid down" by +** inserting a user block in front of an existing file. +** +****************************************************************/ +static void +test_misc14(void) +{ + hid_t file_id; /* File ID */ + hid_t fapl; /* File access property list ID */ + hid_t DataSpace; /* Dataspace ID */ + hid_t Dataset1; /* Dataset ID #1 */ + hid_t Dataset2; /* Dataset ID #2 */ + hid_t Dataset3; /* Dataset ID #3 */ + double data1 = 5.0; /* Data to write for dataset #1 */ + double data2 = 10.0; /* Data to write for dataset #2 */ + double data3 = 15.0; /* Data to write for dataset #3 */ + double rdata; /* Data read in */ + herr_t ret; /* Generic return value */ + + /* Test creating two datasets and deleting the second */ + + /* Increase the metadata block size */ + /* (This makes certain that all the data blocks are allocated together) */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + + ret = H5Pset_meta_block_size(fapl, (hsize_t)MISC14_METADATA_SIZE); + CHECK(ret, FAIL, "H5Pset_meta_block_size"); + + /* Create dataspace to use */ + DataSpace = H5Screate(H5S_SCALAR); + CHECK(DataSpace, FAIL, "H5Screate"); + + /* Open the file */ + file_id = H5Fcreate(MISC14_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(file_id, FAIL, "H5Fcreate"); + + /* Create first dataset & write data */ + Dataset1 = H5Dcreate2(file_id, MISC14_DSET1_NAME, H5T_NATIVE_DOUBLE, DataSpace, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT); + CHECK(Dataset1, FAIL, "H5Dcreate2"); + + ret = H5Dwrite(Dataset1, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, &data1); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Create second dataset (to be unlinked). */ + Dataset2 = H5Dcreate2(file_id, MISC14_DSET2_NAME, H5T_NATIVE_DOUBLE, DataSpace, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT); + CHECK(Dataset2, FAIL, "H5Dcreate2"); + + ret = H5Dwrite(Dataset2, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, &data2); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Check data from first dataset */ + ret = H5Dread(Dataset1, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, &rdata); + CHECK(ret, FAIL, "H5Dread"); + if (!H5_DBL_ABS_EQUAL(rdata, data1)) + TestErrPrintf("Error on line %d: data1!=rdata\n", __LINE__); + + /* Unlink second dataset */ + ret = H5Ldelete(file_id, MISC14_DSET2_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + + /* Close second dataset */ + ret = H5Dclose(Dataset2); + CHECK(ret, FAIL, "H5Dclose"); + + /* Verify the data from dataset #1 */ + ret = H5Dread(Dataset1, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, &rdata); + CHECK(ret, FAIL, "H5Dread"); + if (!H5_DBL_ABS_EQUAL(rdata, data1)) + TestErrPrintf("Error on line %d: data1!=rdata\n", __LINE__); + + /* Close first dataset */ + ret = H5Dclose(Dataset1); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close the file */ + ret = H5Fclose(file_id); + CHECK(ret, FAIL, "H5Fclose"); + + /* Test creating two datasets and deleting the first */ + + /* Open the file */ + file_id = H5Fcreate(MISC14_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(file_id, FAIL, "H5Fcreate"); + + /* Create first dataset & write data */ + Dataset1 = H5Dcreate2(file_id, MISC14_DSET1_NAME, H5T_NATIVE_DOUBLE, DataSpace, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT); + CHECK(Dataset1, FAIL, "H5Dcreate2"); + + ret = H5Dwrite(Dataset1, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, &data1); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Create second dataset */ + Dataset2 = H5Dcreate2(file_id, MISC14_DSET2_NAME, H5T_NATIVE_DOUBLE, DataSpace, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT); + CHECK(Dataset2, FAIL, "H5Dcreate2"); + + ret = H5Dwrite(Dataset2, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, &data2); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Check data from second dataset */ + ret = H5Dread(Dataset2, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, &rdata); + CHECK(ret, FAIL, "H5Dread"); + if (!H5_DBL_ABS_EQUAL(rdata, data2)) + TestErrPrintf("Error on line %d: data2!=rdata\n", __LINE__); + + /* Unlink first dataset */ + ret = H5Ldelete(file_id, MISC14_DSET1_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + + /* Close first dataset */ + ret = H5Dclose(Dataset1); + CHECK(ret, FAIL, "H5Dclose"); + + /* Verify the data from dataset #2 */ + ret = H5Dread(Dataset2, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, &rdata); + CHECK(ret, FAIL, "H5Dread"); + if (!H5_DBL_ABS_EQUAL(rdata, data2)) + TestErrPrintf("Error on line %d: data2!=rdata\n", __LINE__); + + /* Close second dataset */ + ret = H5Dclose(Dataset2); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close the file */ + ret = H5Fclose(file_id); + CHECK(ret, FAIL, "H5Fclose"); + + /* Test creating three datasets and deleting the second */ + + /* Open the file */ + file_id = H5Fcreate(MISC14_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(file_id, FAIL, "H5Fcreate"); + + /* Create first dataset & write data */ + Dataset1 = H5Dcreate2(file_id, MISC14_DSET1_NAME, H5T_NATIVE_DOUBLE, DataSpace, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT); + CHECK(Dataset1, FAIL, "H5Dcreate2"); + + ret = H5Dwrite(Dataset1, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, &data1); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Create second dataset */ + Dataset2 = H5Dcreate2(file_id, MISC14_DSET2_NAME, H5T_NATIVE_DOUBLE, DataSpace, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT); + CHECK(Dataset2, FAIL, "H5Dcreate2"); + + ret = H5Dwrite(Dataset2, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, &data2); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Create third dataset */ + Dataset3 = H5Dcreate2(file_id, MISC14_DSET3_NAME, H5T_NATIVE_DOUBLE, DataSpace, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT); + CHECK(Dataset2, FAIL, "H5Dcreate2"); + + ret = H5Dwrite(Dataset3, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, &data3); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Check data from first dataset */ + ret = H5Dread(Dataset1, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, &rdata); + CHECK(ret, FAIL, "H5Dread"); + if (!H5_DBL_ABS_EQUAL(rdata, data1)) + TestErrPrintf("Error on line %d: data1!=rdata\n", __LINE__); + + /* Check data from third dataset */ + ret = H5Dread(Dataset3, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, &rdata); + CHECK(ret, FAIL, "H5Dread"); + if (!H5_DBL_ABS_EQUAL(rdata, data3)) + TestErrPrintf("Error on line %d: data3!=rdata\n", __LINE__); + + /* Unlink second dataset */ + ret = H5Ldelete(file_id, MISC14_DSET2_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + + /* Close second dataset */ + ret = H5Dclose(Dataset2); + CHECK(ret, FAIL, "H5Dclose"); + + /* Verify the data from dataset #1 */ + ret = H5Dread(Dataset1, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, &rdata); + CHECK(ret, FAIL, "H5Dread"); + if (!H5_DBL_ABS_EQUAL(rdata, data1)) + TestErrPrintf("Error on line %d: data1!=rdata\n", __LINE__); + + /* Verify the data from dataset #3 */ + ret = H5Dread(Dataset3, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, &rdata); + CHECK(ret, FAIL, "H5Dread"); + if (!H5_DBL_ABS_EQUAL(rdata, data3)) + TestErrPrintf("Error on line %d: data3!=rdata\n", __LINE__); + + /* Close first dataset */ + ret = H5Dclose(Dataset1); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close third dataset */ + ret = H5Dclose(Dataset3); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close the file */ + ret = H5Fclose(file_id); + CHECK(ret, FAIL, "H5Fclose"); + + /* Close shared objects (dataspace & fapl) */ + ret = H5Sclose(DataSpace); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + +} /* end test_misc14() */ + +/**************************************************************** +** +** test_misc15(): Test that checking a file's access property list +** more than once correctly increments internal reference counts. +** +****************************************************************/ +static void +test_misc15(void) +{ + char filename[MISC15_BUF_SIZE]; + hid_t file; /* File ID */ + hid_t fapl; /* File access property list */ + herr_t ret; /* Generic return value */ + + fapl = h5_fileaccess(); + h5_fixname(MISC15_FILE, fapl, filename, MISC15_BUF_SIZE); + + /* Create the file & get it's FAPL */ + file = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(file, FAIL, "H5Fcreate"); + + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + + fapl = H5Fget_access_plist(file); + CHECK(fapl, FAIL, "H5Fget_access_plist"); + + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + + /* Open the file & get it's FAPL again */ + file = H5Fopen(filename, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(file, FAIL, "H5Fopen"); + + fapl = H5Fget_access_plist(file); + CHECK(fapl, FAIL, "H5Fget_access_plist"); + + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + + /* Verify that the file is still OK */ + ret = H5Fis_accessible(filename, fapl); + CHECK(ret, FAIL, "H5Fis_accessible"); + + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + + file = H5Fopen(filename, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(file, FAIL, "H5Fopen"); + + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_misc15() */ + +/**************************************************************** +** +** test_misc16(): Test array of NULL-terminated +** fixed-length string. It creates a dataset of fixed-length +** strings. Each string is MISC16_STR_SIZE long. There are +** totally MISC16_SPACE_DIM by MISC16_SPACE_RANK strings. +** +****************************************************************/ +static void +test_misc16(void) +{ + hid_t file; /* File ID */ + herr_t ret; /* Generic return value */ + char wdata[MISC16_SPACE_DIM][MISC16_STR_SIZE]; + char rdata[MISC16_SPACE_DIM][MISC16_STR_SIZE]; /* Information read in */ + hid_t dataset; /* Dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t tid; /* Datatype ID */ + hsize_t dims[] = {MISC16_SPACE_DIM}; + int i; + + HDmemset(wdata, 0, sizeof(wdata)); + HDmemset(rdata, 0, sizeof(rdata)); + + /* Initialize the data */ + /* (Note that these are supposed to stress the code, so are a little weird) */ + HDmemcpy(wdata[0], "1234567", MISC16_STR_SIZE); + HDmemcpy(wdata[1], "1234567\0", MISC16_STR_SIZE); + HDmemcpy(wdata[2], "12345678", MISC16_STR_SIZE); + HDmemcpy(wdata[3], "\0\0\0\0\0\0\0\0", MISC16_STR_SIZE); + + /* Create the file */ + file = H5Fcreate(MISC16_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file, FAIL, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid = H5Screate_simple(MISC16_SPACE_RANK, dims, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Create a datatype to refer to */ + tid = H5Tcopy(H5T_C_S1); + CHECK(tid, FAIL, "H5Tcopy"); + + ret = H5Tset_size(tid, (size_t)MISC16_STR_SIZE); + CHECK(ret, FAIL, "H5Tset_size"); + + /*ret = H5Tset_strpad(tid,H5T_STR_NULLPAD); + CHECK(ret, FAIL, "H5Tset_strpad");*/ + + /* Create a dataset */ + dataset = H5Dcreate2(file, MISC16_DSET_NAME, tid, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write dataset to disk */ + ret = H5Dwrite(dataset, tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Read dataset from disk */ + ret = H5Dread(dataset, tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < MISC16_SPACE_DIM; i++) { + if (HDstrlen(wdata[i]) != HDstrlen(rdata[i])) { + TestErrPrintf( + "Line %u: VL data length don't match!, strlen(wdata[%d])=%d, strlen(rdata[%d])=%d\n", + (unsigned)__LINE__, (int)i, (int)HDstrlen(wdata[i]), (int)i, (int)HDstrlen(rdata[i])); + continue; + } /* end if */ + if (HDstrcmp(wdata[i], rdata[i]) != 0) { + TestErrPrintf("Line %u: VL data values don't match!, wdata[%d]=%s, rdata[%d]=%s\n", + (unsigned)__LINE__, (int)i, wdata[i], (int)i, rdata[i]); + continue; + } /* end if */ + } /* end for */ + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close datatype */ + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_misc16() */ + +/**************************************************************** +** +** test_misc17(): Test array of characters. It creates a dataset +** of ASCII characters, with dimensionality of MISC17_SPACE_DIM1 +** by MISC17_SPACE_DIM2. +** +****************************************************************/ +static void +test_misc17(void) +{ + hid_t file; /* File ID */ + herr_t ret; /* Generic return value */ + char wdata[MISC17_SPACE_DIM1][MISC17_SPACE_DIM2]; + char rdata[MISC17_SPACE_DIM1][MISC17_SPACE_DIM2]; /* Information read in */ + hid_t dataset; /* Dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t tid; /* Datatype ID */ + hsize_t dims[] = {MISC17_SPACE_DIM1, MISC17_SPACE_DIM2}; + int i; + + HDmemset(wdata, 0, sizeof(wdata)); + HDmemset(rdata, 0, sizeof(rdata)); + + /* Initialize the data */ + /* (Note that these are supposed to stress the code, so are a little weird) */ + HDmemcpy(wdata[0], "1234567", MISC17_SPACE_DIM2); + HDmemcpy(wdata[1], "1234567\0", MISC17_SPACE_DIM2); + HDmemcpy(wdata[2], "12345678", MISC17_SPACE_DIM2); + HDmemcpy(wdata[3], "\0\0\0\0\0\0\0\0", MISC17_SPACE_DIM2); + + /* Create the file */ + file = H5Fcreate(MISC17_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file, FAIL, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid = H5Screate_simple(MISC17_SPACE_RANK, dims, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Create a datatype to refer to */ + tid = H5Tcopy(H5T_C_S1); + CHECK(tid, FAIL, "H5Tcopy"); + + ret = H5Tset_strpad(tid, H5T_STR_NULLPAD); + CHECK(ret, FAIL, "H5Tset_strpad"); + + /* Create a dataset */ + dataset = H5Dcreate2(file, MISC17_DSET_NAME, tid, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write dataset to disk */ + ret = H5Dwrite(dataset, tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Read dataset from disk */ + ret = H5Dread(dataset, tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data in the way of strings. */ + for (i = 0; i < MISC17_SPACE_DIM1; i++) { + if (HDstrlen(wdata[i]) != HDstrlen(rdata[i])) { + TestErrPrintf( + "Line %u: VL data length don't match!, strlen(wdata[%d])=%d, strlen(rdata[%d])=%d\n", + (unsigned)__LINE__, (int)i, (int)HDstrlen(wdata[i]), (int)i, (int)HDstrlen(rdata[i])); + continue; + } /* end if */ + if (HDstrcmp(wdata[i], rdata[i]) != 0) { + TestErrPrintf("Line %u: VL data values don't match!, wdata[%d]=%s, rdata[%d]=%s\n", + (unsigned)__LINE__, (int)i, wdata[i], (int)i, rdata[i]); + continue; + } /* end if */ + } /* end for */ + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close datatype */ + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_misc17() */ + +/**************************************************************** +** +** test_misc18(): Test new object header information in H5O_info_t +** struct. +** +****************************************************************/ +static void +test_misc18(void) +{ + hid_t fid; /* File ID */ + hid_t sid; /* 'Space ID */ + hid_t did1, did2; /* Dataset IDs */ + hid_t aid; /* Attribute ID */ +#if 0 +#ifndef H5_NO_DEPRECATED_SYMBOLS + H5O_info1_t old_oinfo; /* (deprecated) information about object */ +#endif /* H5_NO_DEPRECATED_SYMBOLS */ +#endif + H5O_info2_t oinfo; /* Data model information about object */ +#if 0 + H5O_native_info_t ninfo; /* Native file format information about object */ +#endif + char attr_name[32]; /* Attribute name buffer */ + unsigned u; /* Local index variable */ + herr_t ret; /* Generic return value */ + + /* Create the file */ + fid = H5Fcreate(MISC18_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create dataspace for attributes */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create first dataset */ + did1 = H5Dcreate2(fid, MISC18_DSET1_NAME, H5T_STD_U32LE, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(did1, FAIL, "H5Dcreate2"); + + /* Get object information */ + ret = H5Oget_info_by_name3(fid, MISC18_DSET1_NAME, &oinfo, H5O_INFO_NUM_ATTRS, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name"); + VERIFY(oinfo.num_attrs, 0, "H5Oget_info_by_name"); +#if 0 +#ifndef H5_NO_DEPRECATED_SYMBOLS + ret = H5Oget_info_by_name2(fid, MISC18_DSET1_NAME, &old_oinfo, H5O_INFO_HDR | H5O_INFO_NUM_ATTRS, + H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name"); + VERIFY(old_oinfo.hdr.nmesgs, 6, "H5Oget_info_by_name"); + VERIFY(old_oinfo.hdr.nchunks, 1, "H5Oget_info_by_name"); + VERIFY(old_oinfo.hdr.space.total, 272, "H5Oget_info_by_name"); + VERIFY(old_oinfo.hdr.space.free, 152, "H5Oget_info_by_name"); + VERIFY(old_oinfo.num_attrs, 0, "H5Oget_info_by_name"); +#endif /* H5_NO_DEPRECATED_SYMBOLS */ + ret = H5Oget_native_info_by_name(fid, MISC18_DSET1_NAME, &ninfo, H5O_NATIVE_INFO_HDR, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_native_info_by_name"); + VERIFY(ninfo.hdr.nmesgs, 6, "H5Oget_native_info_by_name"); + VERIFY(ninfo.hdr.nchunks, 1, "H5Oget_native_info_by_name"); + VERIFY(ninfo.hdr.space.total, 272, "H5Oget_native_info_by_name"); + VERIFY(ninfo.hdr.space.free, 152, "H5Oget_native_info_by_name"); +#endif + + /* Create second dataset */ + did2 = H5Dcreate2(fid, MISC18_DSET2_NAME, H5T_STD_U32LE, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(did2, FAIL, "H5Dcreate2"); + + /* Get object information */ + ret = H5Oget_info_by_name3(fid, MISC18_DSET2_NAME, &oinfo, H5O_INFO_NUM_ATTRS, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name"); + VERIFY(oinfo.num_attrs, 0, "H5Oget_info_by_name"); +#if 0 +#ifndef H5_NO_DEPRECATED_SYMBOLS + ret = H5Oget_info_by_name2(fid, MISC18_DSET2_NAME, &old_oinfo, H5O_INFO_HDR | H5O_INFO_NUM_ATTRS, + H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name"); + VERIFY(old_oinfo.hdr.nmesgs, 6, "H5Oget_info_by_name"); + VERIFY(old_oinfo.hdr.nchunks, 1, "H5Oget_info_by_name"); + VERIFY(old_oinfo.hdr.space.total, 272, "H5Oget_info_by_name"); + VERIFY(old_oinfo.hdr.space.free, 152, "H5Oget_info_by_name"); + VERIFY(old_oinfo.num_attrs, 0, "H5Oget_info_by_name"); +#endif /* H5_NO_DEPRECATED_SYMBOLS */ + ret = H5Oget_native_info_by_name(fid, MISC18_DSET2_NAME, &ninfo, H5O_NATIVE_INFO_HDR, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_native_info_by_name"); + VERIFY(ninfo.hdr.nmesgs, 6, "H5Oget_native_info_by_name"); + VERIFY(ninfo.hdr.nchunks, 1, "H5Oget_native_info_by_name"); + VERIFY(ninfo.hdr.space.total, 272, "H5Oget_native_info_by_name"); + VERIFY(ninfo.hdr.space.free, 152, "H5Oget_native_info_by_name"); +#endif + + /* Loop creating attributes on each dataset, flushing them to the file each time */ + for (u = 0; u < 10; u++) { + /* Set up attribute name */ + HDsnprintf(attr_name, sizeof(attr_name), "Attr %u", u); + + /* Create & close attribute on first dataset */ + aid = H5Acreate2(did1, attr_name, H5T_STD_U32LE, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + + /* Create & close attribute on second dataset */ + aid = H5Acreate2(did2, attr_name, H5T_STD_U32LE, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + + /* Flush file, to 'fix' size of dataset object headers */ + ret = H5Fflush(fid, H5F_SCOPE_GLOBAL); + CHECK(ret, FAIL, "H5Fflush"); + } /* end for */ + + /* Get object information for dataset #1 now */ + ret = H5Oget_info_by_name3(fid, MISC18_DSET1_NAME, &oinfo, H5O_INFO_NUM_ATTRS, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name"); + VERIFY(oinfo.num_attrs, 10, "H5Oget_info_by_name"); +#if 0 +#ifndef H5_NO_DEPRECATED_SYMBOLS + ret = H5Oget_info_by_name2(fid, MISC18_DSET1_NAME, &old_oinfo, H5O_INFO_HDR | H5O_INFO_NUM_ATTRS, + H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name"); + VERIFY(old_oinfo.hdr.nmesgs, 24, "H5Oget_info_by_name"); + VERIFY(old_oinfo.hdr.nchunks, 9, "H5Oget_info_by_name"); + VERIFY(old_oinfo.hdr.space.total, 888, "H5Oget_info_by_name"); + VERIFY(old_oinfo.hdr.space.free, 16, "H5Oget_info_by_name"); + VERIFY(old_oinfo.num_attrs, 10, "H5Oget_info_by_name"); +#endif /* H5_NO_DEPRECATED_SYMBOLS */ + ret = H5Oget_native_info_by_name(fid, MISC18_DSET1_NAME, &ninfo, H5O_NATIVE_INFO_HDR, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_native_info_by_name"); + VERIFY(ninfo.hdr.nmesgs, 24, "H5Oget_native_info_by_name"); + VERIFY(ninfo.hdr.nchunks, 9, "H5Oget_native_info_by_name"); + VERIFY(ninfo.hdr.space.total, 888, "H5Oget_native_info_by_name"); + VERIFY(ninfo.hdr.space.free, 16, "H5Oget_native_info_by_name"); +#endif + + /* Get object information for dataset #2 now */ + ret = H5Oget_info_by_name3(fid, MISC18_DSET2_NAME, &oinfo, H5O_INFO_NUM_ATTRS, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name"); + VERIFY(oinfo.num_attrs, 10, "H5Oget_info_by_name"); +#if 0 +#ifndef H5_NO_DEPRECATED_SYMBOLS + ret = H5Oget_info_by_name2(fid, MISC18_DSET2_NAME, &old_oinfo, H5O_INFO_HDR | H5O_INFO_NUM_ATTRS, + H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_name"); + VERIFY(old_oinfo.hdr.nmesgs, 24, "H5Oget_info_by_name"); + VERIFY(old_oinfo.hdr.nchunks, 9, "H5Oget_info_by_name"); + VERIFY(old_oinfo.hdr.space.total, 888, "H5Oget_info_by_name"); + VERIFY(old_oinfo.hdr.space.free, 16, "H5Oget_info_by_name"); + VERIFY(old_oinfo.num_attrs, 10, "H5Oget_info_by_name"); +#endif /* H5_NO_DEPRECATED_SYMBOLS */ + ret = H5Oget_native_info_by_name(fid, MISC18_DSET2_NAME, &ninfo, H5O_NATIVE_INFO_HDR, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_mative_info_by_name"); + VERIFY(ninfo.hdr.nmesgs, 24, "H5Oget_native_info_by_name"); + VERIFY(ninfo.hdr.nchunks, 9, "H5Oget_native_info_by_name"); + VERIFY(ninfo.hdr.space.total, 888, "H5Oget_native_info_by_name"); + VERIFY(ninfo.hdr.space.free, 16, "H5Oget_native_info_by_name"); +#endif + + /* Close second dataset */ + ret = H5Dclose(did2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close first dataset */ + ret = H5Dclose(did1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_misc18() */ + +/**************************************************************** +** +** test_misc19(): Test incrementing & decrementing ref count on IDs +** +****************************************************************/ +static void +test_misc19(void) +{ + hid_t fid = -1; /* File ID */ + hid_t sid = -1; /* Dataspace ID */ + hid_t did = -1; /* Dataset ID */ + hid_t tid = -1; /* Datatype ID */ + hid_t aid = -1; /* Attribute ID */ + hid_t plid = -1; /* Property List ID */ + hid_t pcid = -1; /* Property Class ID */ + hid_t gid = -1; /* Group ID */ + hid_t ecid = -1; /* Error Class ID */ + hid_t emid = -1; /* Error Message ID */ + hid_t esid = -1; /* Error Stack ID */ +#if 0 + hid_t vfdid = -1; /* Virtual File Driver ID */ + hid_t volid = -1; /* Virtual Object Layer ID */ + H5FD_class_t *vfd_cls = NULL; /* VFD class */ + H5VL_class_t *vol_cls = NULL; /* VOL class */ +#endif + int rc; /* Reference count */ + herr_t ret; /* Generic return value */ + + /* Check H5I operations on files */ + + /* Create the file */ + fid = H5Fcreate(MISC19_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Check the reference count */ + rc = H5Iget_ref(fid); + VERIFY(rc, 1, "H5Iget_ref"); + + /* Inc the reference count */ + rc = H5Iinc_ref(fid); + VERIFY(rc, 2, "H5Iinc_ref"); + + /* Close the file normally */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Check the reference count */ + rc = H5Iget_ref(fid); + VERIFY(rc, 1, "H5Iget_ref"); + + /* Close the file by decrementing the reference count */ + rc = H5Idec_ref(fid); + VERIFY(rc, 0, "H5Idec_ref"); + + /* Try closing the file again (should fail) */ + H5E_BEGIN_TRY + { + ret = H5Fclose(fid); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Fclose"); + + /* Check H5I operations on property lists */ + + /* Create the property list */ + plid = H5Pcreate(H5P_DATASET_CREATE); + CHECK(plid, FAIL, "H5Pcreate"); + + /* Check the reference count */ + rc = H5Iget_ref(plid); + VERIFY(rc, 1, "H5Iget_ref"); + + /* Inc the reference count */ + rc = H5Iinc_ref(plid); + VERIFY(rc, 2, "H5Iinc_ref"); + + /* Close the property list normally */ + ret = H5Pclose(plid); + CHECK(ret, FAIL, "H5Pclose"); + + /* Check the reference count */ + rc = H5Iget_ref(plid); + VERIFY(rc, 1, "H5Iget_ref"); + + /* Close the property list by decrementing the reference count */ + rc = H5Idec_ref(plid); + VERIFY(rc, 0, "H5Idec_ref"); + + /* Try closing the property list again (should fail) */ + H5E_BEGIN_TRY + { + ret = H5Pclose(plid); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Pclose"); + + /* Check H5I operations on property classes */ + + /* Create a property class */ + pcid = H5Pcreate_class(H5P_DATASET_CREATE, "foo", NULL, NULL, NULL, NULL, NULL, NULL); + CHECK(pcid, FAIL, "H5Pcreate_class"); + + /* Check the reference count */ + rc = H5Iget_ref(pcid); + VERIFY(rc, 1, "H5Iget_ref"); + + /* Inc the reference count */ + rc = H5Iinc_ref(pcid); + VERIFY(rc, 2, "H5Iinc_ref"); + + /* Close the property class normally */ + ret = H5Pclose_class(pcid); + CHECK(ret, FAIL, "H5Pclose_class"); + + /* Check the reference count */ + rc = H5Iget_ref(pcid); + VERIFY(rc, 1, "H5Iget_ref"); + + /* Close the property class by decrementing the reference count */ + rc = H5Idec_ref(pcid); + VERIFY(rc, 0, "H5Idec_ref"); + + /* Try closing the property class again (should fail) */ + H5E_BEGIN_TRY + { + ret = H5Pclose_class(pcid); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Pclose_class"); + + /* Check H5I operations on datatypes */ + + /* Create a datatype */ + tid = H5Tcreate(H5T_OPAQUE, (size_t)16); + CHECK(tid, FAIL, "H5Tcreate"); + + /* Check the reference count */ + rc = H5Iget_ref(tid); + VERIFY(rc, 1, "H5Iget_ref"); + + /* Inc the reference count */ + rc = H5Iinc_ref(tid); + VERIFY(rc, 2, "H5Iinc_ref"); + + /* Close the datatype normally */ + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Check the reference count */ + rc = H5Iget_ref(tid); + VERIFY(rc, 1, "H5Iget_ref"); + + /* Close the datatype by decrementing the reference count */ + rc = H5Idec_ref(tid); + VERIFY(rc, 0, "H5Idec_ref"); + + /* Try closing the datatype again (should fail) */ + H5E_BEGIN_TRY + { + ret = H5Tclose(tid); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Tclose"); + + /* Check H5I operations on dataspaces */ + + /* Create a dataspace */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Check the reference count */ + rc = H5Iget_ref(sid); + VERIFY(rc, 1, "H5Iget_ref"); + + /* Inc the reference count */ + rc = H5Iinc_ref(sid); + VERIFY(rc, 2, "H5Iinc_ref"); + + /* Close the dataspace normally */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Check the reference count */ + rc = H5Iget_ref(sid); + VERIFY(rc, 1, "H5Iget_ref"); + + /* Close the dataspace by decrementing the reference count */ + rc = H5Idec_ref(sid); + VERIFY(rc, 0, "H5Idec_ref"); + + /* Try closing the dataspace again (should fail) */ + H5E_BEGIN_TRY + { + ret = H5Sclose(sid); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Sclose"); + + /* Check H5I operations on datasets */ + + /* Create a file */ + fid = H5Fcreate(MISC19_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create a dataspace */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create a dataset */ + did = H5Dcreate2(fid, MISC19_DSET_NAME, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); + + /* Check the reference count */ + rc = H5Iget_ref(did); + VERIFY(rc, 1, "H5Iget_ref"); + + /* Inc the reference count */ + rc = H5Iinc_ref(did); + VERIFY(rc, 2, "H5Iinc_ref"); + + /* Close the dataset normally */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* Check the reference count */ + rc = H5Iget_ref(did); + VERIFY(rc, 1, "H5Iget_ref"); + + /* Close the dataset by decrementing the reference count */ + rc = H5Idec_ref(did); + VERIFY(rc, 0, "H5Idec_ref"); + + /* Try closing the dataset again (should fail) */ + H5E_BEGIN_TRY + { + ret = H5Dclose(did); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Dclose"); + + /* Close the dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Check H5I operations on attributes */ + + /* Create a file */ + fid = H5Fcreate(MISC19_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Open the root group */ + gid = H5Gopen2(fid, "/", H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gopen2"); + + /* Create a dataspace */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create an attribute */ + aid = H5Acreate2(gid, MISC19_ATTR_NAME, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + + /* Check the reference count */ + rc = H5Iget_ref(aid); + VERIFY(rc, 1, "H5Iget_ref"); + + /* Inc the reference count */ + rc = H5Iinc_ref(aid); + VERIFY(rc, 2, "H5Iinc_ref"); + + /* Close the dataset normally */ + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + + /* Check the reference count */ + rc = H5Iget_ref(aid); + VERIFY(rc, 1, "H5Iget_ref"); + + /* Close the attribute by decrementing the reference count */ + rc = H5Idec_ref(aid); + VERIFY(rc, 0, "H5Idec_ref"); + + /* Try closing the attribute again (should fail) */ + H5E_BEGIN_TRY + { + ret = H5Aclose(aid); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Aclose"); + + /* Close the root group */ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close the dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Check H5I operations on groups */ + + /* Create a file */ + fid = H5Fcreate(MISC19_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create a group */ + gid = H5Gcreate2(fid, MISC19_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gcreate2"); + + /* Check the reference count */ + rc = H5Iget_ref(gid); + VERIFY(rc, 1, "H5Iget_ref"); + + /* Inc the reference count */ + rc = H5Iinc_ref(gid); + VERIFY(rc, 2, "H5Iinc_ref"); + + /* Close the group normally */ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + /* Check the reference count */ + rc = H5Iget_ref(gid); + VERIFY(rc, 1, "H5Iget_ref"); + + /* Close the group by decrementing the reference count */ + rc = H5Idec_ref(gid); + VERIFY(rc, 0, "H5Idec_ref"); + + /* Try closing the group again (should fail) */ + H5E_BEGIN_TRY + { + ret = H5Gclose(gid); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Gclose"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Check H5I operations on error classes */ + + /* Create an error class */ + ecid = H5Eregister_class("foo", "bar", "baz"); + CHECK(ecid, FAIL, "H5Eregister_class"); + + /* Check the reference count */ + rc = H5Iget_ref(ecid); + VERIFY(rc, 1, "H5Iget_ref"); + + /* Inc the reference count */ + rc = H5Iinc_ref(ecid); + VERIFY(rc, 2, "H5Iinc_ref"); + + /* Close the error class normally */ + ret = H5Eunregister_class(ecid); + CHECK(ret, FAIL, "H5Eunregister_class"); + + /* Check the reference count */ + rc = H5Iget_ref(ecid); + VERIFY(rc, 1, "H5Iget_ref"); + + /* Close the error class by decrementing the reference count */ + rc = H5Idec_ref(ecid); + VERIFY(rc, 0, "H5Idec_ref"); + + /* Try closing the error class again (should fail) */ + H5E_BEGIN_TRY + { + ret = H5Eunregister_class(ecid); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Eunregister_class"); + + /* Check H5I operations on error messages */ + + /* Create an error class */ + ecid = H5Eregister_class("foo", "bar", "baz"); + CHECK(ecid, FAIL, "H5Eregister_class"); + + /* Create an error message */ + emid = H5Ecreate_msg(ecid, H5E_MAJOR, "mumble"); + CHECK(emid, FAIL, "H5Ecreate_msg"); + + /* Check the reference count */ + rc = H5Iget_ref(emid); + VERIFY(rc, 1, "H5Iget_ref"); + + /* Inc the reference count */ + rc = H5Iinc_ref(emid); + VERIFY(rc, 2, "H5Iinc_ref"); + + /* Close the error message normally */ + ret = H5Eclose_msg(emid); + CHECK(ret, FAIL, "H5Eclose_msg"); + + /* Check the reference count */ + rc = H5Iget_ref(emid); + VERIFY(rc, 1, "H5Iget_ref"); + + /* Close the error message by decrementing the reference count */ + rc = H5Idec_ref(emid); + VERIFY(rc, 0, "H5Idec_ref"); + + /* Try closing the error message again (should fail) */ + H5E_BEGIN_TRY + { + ret = H5Eclose_msg(emid); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Eclose_msg"); + + /* Close the error class */ + ret = H5Eunregister_class(ecid); + CHECK(ret, FAIL, "H5Eunregister_class"); + + /* Check H5I operations on error stacks */ + + /* Create an error stack */ + esid = H5Eget_current_stack(); + CHECK(esid, FAIL, "H5Eget_current_stack"); + + /* Check the reference count */ + rc = H5Iget_ref(esid); + VERIFY(rc, 1, "H5Iget_ref"); + + /* Inc the reference count */ + rc = H5Iinc_ref(esid); + VERIFY(rc, 2, "H5Iinc_ref"); + + /* Close the error stack normally */ + ret = H5Eclose_stack(esid); + CHECK(ret, FAIL, "H5Eclose_stack"); + + /* Check the reference count */ + rc = H5Iget_ref(esid); + VERIFY(rc, 1, "H5Iget_ref"); + + /* Close the error stack by decrementing the reference count */ + rc = H5Idec_ref(esid); + VERIFY(rc, 0, "H5Idec_ref"); + + /* Try closing the error stack again (should fail) */ + H5E_BEGIN_TRY + { + ret = H5Eclose_stack(esid); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Eclose_stack"); + +#if 0 + /* Check H5I operations on virtual file drivers */ + + /* Get a VFD class to register */ + vfd_cls = h5_get_dummy_vfd_class(); + CHECK_PTR(vfd_cls, "h5_get_dummy_vfd_class"); + + /* Register a virtual file driver */ + vfdid = H5FDregister(vfd_cls); + CHECK(vfdid, FAIL, "H5FDregister"); + + /* Check the reference count */ + rc = H5Iget_ref(vfdid); + VERIFY(rc, 1, "H5Iget_ref"); + + /* Increment the reference count */ + rc = H5Iinc_ref(vfdid); + VERIFY(rc, 2, "H5Iinc_ref"); + + /* Unregister the VFD normally */ + ret = H5FDunregister(vfdid); + CHECK(ret, FAIL, "H5FDunregister"); + + /* Check the reference count */ + rc = H5Iget_ref(vfdid); + VERIFY(rc, 1, "H5Iget_ref"); + + /* Unregister the VFD by decrementing the reference count */ + rc = H5Idec_ref(vfdid); + VERIFY(rc, 0, "H5Idec_ref"); + + /* Try unregistering the VFD again (should fail) */ + H5E_BEGIN_TRY + { + ret = H5FDunregister(vfdid); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5FDunregister"); + + HDfree(vfd_cls); + + /* Check H5I operations on virtual object connectors */ + + /* Get a VOL class to register */ + vol_cls = h5_get_dummy_vol_class(); + CHECK_PTR(vol_cls, "h5_get_dummy_vol_class"); + + /* Register a VOL connector */ + volid = H5VLregister_connector(vol_cls, H5P_DEFAULT); + CHECK(volid, FAIL, "H5VLregister_connector"); + + /* Check the reference count */ + rc = H5Iget_ref(volid); + VERIFY(rc, 1, "H5Iget_ref"); + + /* Increment the reference count */ + rc = H5Iinc_ref(volid); + VERIFY(rc, 2, "H5Iinc_ref"); + + /* Unregister the VOL connector normally */ + ret = H5VLunregister_connector(volid); + CHECK(ret, FAIL, "H5VLunregister_connector"); + + /* Check the reference count */ + rc = H5Iget_ref(volid); + VERIFY(rc, 1, "H5Iget_ref"); + + /* Unregister the VOL connector by decrementing the reference count */ + rc = H5Idec_ref(volid); + VERIFY(rc, 0, "H5Idec_ref"); + + /* Try unregistering the VOL connector again (should fail) */ + H5E_BEGIN_TRY + { + ret = H5VLunregister_connector(volid); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5VLunregister_connector"); + + HDfree(vol_cls); +#endif +} /* end test_misc19() */ + +/**************************************************************** +** +** test_misc20(): Test problems with version 2 of storage layout +** message truncating dimensions +** +****************************************************************/ +#if 0 +static void +test_misc20(void) +{ + hid_t fid; /* File ID */ + hid_t sid; /* 'Space ID */ + hid_t did; /* Dataset ID */ + hid_t dcpl; /* Dataset creation property list ID */ + int rank = MISC20_SPACE_RANK; /* Rank of dataspace */ + hsize_t big_dims[MISC20_SPACE_RANK] = {MISC20_SPACE_DIM0, MISC20_SPACE_DIM1}; /* Large dimensions */ + hsize_t small_dims[MISC20_SPACE_RANK] = {MISC20_SPACE2_DIM0, MISC20_SPACE2_DIM1}; /* Small dimensions */ + unsigned version; /* Version of storage layout info */ + hsize_t contig_size; /* Size of contiguous storage size from layout into */ + const char *testfile = H5_get_srcdir_filename(MISC20_FILE_OLD); /* Corrected test file name */ + hbool_t driver_is_default_compatible; + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing large dimension truncation fix\n")); + + ret = h5_driver_is_default_vfd_compatible(H5P_DEFAULT, &driver_is_default_compatible); + CHECK(ret, FAIL, "h5_driver_is_default_vfd_compatible"); + + if (!driver_is_default_compatible) { + HDprintf("-- SKIPPED --\n"); + return; + } + + /* Verify that chunks with dimensions that are too large get rejected */ + + /* Create a dataset creation property list */ + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + + /* Try to use chunked storage for this dataset */ + ret = H5Pset_chunk(dcpl, rank, big_dims); + VERIFY(ret, FAIL, "H5Pset_chunk"); + + /* Verify that the storage for the dataset is the correct size and hasn't + * been truncated. + */ + + /* Create the file */ + fid = H5Fcreate(MISC20_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create dataspace with _really_ big dimensions */ + sid = H5Screate_simple(rank, big_dims, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Make certain that the dataset's storage doesn't get allocated :-) */ + ret = H5Pset_alloc_time(dcpl, H5D_ALLOC_TIME_LATE); + CHECK(ret, FAIL, "H5Pset_alloc_time"); + + /* Create dataset with big dataspace */ + did = H5Dcreate2(fid, MISC20_DSET_NAME, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); + + /* Close datasset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Create dataspace with small dimensions */ + sid = H5Screate_simple(rank, small_dims, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Create dataset with big dataspace */ + did = H5Dcreate2(fid, MISC20_DSET2_NAME, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); + + /* Close datasset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close dataset creation property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open the file */ + fid = H5Fopen(MISC20_FILE, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* Open dataset with big dimensions */ + did = H5Dopen2(fid, MISC20_DSET_NAME, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen2"); + + /* Get the layout version */ + ret = H5D__layout_version_test(did, &version); + CHECK(ret, FAIL, "H5D__layout_version_test"); + VERIFY(version, 3, "H5D__layout_version_test"); + + /* Get the layout contiguous storage size */ + ret = H5D__layout_contig_size_test(did, &contig_size); + CHECK(ret, FAIL, "H5D__layout_contig_size_test"); + VERIFY(contig_size, (MISC20_SPACE_DIM0 * MISC20_SPACE_DIM1 * H5Tget_size(H5T_NATIVE_INT)), + "H5D__layout_contig_size_test"); + + /* Close datasset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* Open dataset with small dimensions */ + did = H5Dopen2(fid, MISC20_DSET2_NAME, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen2"); + + /* Get the layout version */ + ret = H5D__layout_version_test(did, &version); + CHECK(ret, FAIL, "H5D__layout_version_test"); + VERIFY(version, 3, "H5D__layout_version_test"); + + /* Get the layout contiguous storage size */ + ret = H5D__layout_contig_size_test(did, &contig_size); + CHECK(ret, FAIL, "H5D__layout_contig_size_test"); + VERIFY(contig_size, (MISC20_SPACE2_DIM0 * MISC20_SPACE2_DIM1 * H5Tget_size(H5T_NATIVE_INT)), + "H5D__layout_contig_size_test"); + + /* Close datasset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Verify that the storage size is computed correctly for older versions of layout info */ + + /* + * Open the old file and the dataset and get old settings. + */ + fid = H5Fopen(testfile, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* Open dataset with small dimensions */ + did = H5Dopen2(fid, MISC20_DSET_NAME, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen2"); + + /* Get the layout version */ + ret = H5D__layout_version_test(did, &version); + CHECK(ret, FAIL, "H5D__layout_version_test"); + VERIFY(version, 2, "H5D__layout_version_test"); + + /* Get the layout contiguous storage size */ + ret = H5D__layout_contig_size_test(did, &contig_size); + CHECK(ret, FAIL, "H5D__layout_contig_size_test"); + VERIFY(contig_size, (MISC20_SPACE_DIM0 * MISC20_SPACE_DIM1 * H5Tget_size(H5T_STD_I32LE)), + "H5D__layout_contig_size_test"); + + /* Close datasset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + +} /* end test_misc20() */ +#endif + +/* + test_misc21 and test_misc22 should be executed when SZIP is present + and encoder is available. + EIP 2004/8/04 +*/ +#if defined(H5_HAVE_FILTER_SZIP) && !defined(H5_API_TEST_NO_FILTERS) + +/**************************************************************** +** +** test_misc21(): Test that late allocation time is treated the same +** as incremental allocation time, for chunked datasets +** when overwriting entire dataset where the chunks +** don't exactly match the dataspace. +** +****************************************************************/ +static void +test_misc21(void) +{ + hid_t fid, sid, dcpl, dsid; + char *buf; + hsize_t dims[2] = {MISC21_SPACE_DIM0, MISC21_SPACE_DIM1}, + chunk_size[2] = {MISC21_CHUNK_DIM0, MISC21_CHUNK_DIM1}; + herr_t ret; /* Generic return value */ + + if (h5_szip_can_encode() != 1) + return; + /* Output message about test being performed */ + MESSAGE(5, ("Testing late allocation time w/chunks & filters\n")); + + /* Allocate space for the buffer */ + buf = (char *)HDcalloc(MISC21_SPACE_DIM0 * MISC21_SPACE_DIM1, 1); + CHECK(buf, NULL, "HDcalloc"); + + /* Create the file */ + fid = H5Fcreate(MISC21_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create the DCPL */ + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + + /* Set custom DCPL properties */ + ret = H5Pset_chunk(dcpl, MISC21_SPACE_RANK, chunk_size); + CHECK(ret, FAIL, "H5Pset_chunk"); + ret = H5Pset_szip(dcpl, H5_SZIP_NN_OPTION_MASK, 8); + CHECK(ret, FAIL, "H5Pset_deflate"); + ret = H5Pset_alloc_time(dcpl, H5D_ALLOC_TIME_LATE); + CHECK(ret, FAIL, "H5Pset_alloc_time"); + + /* Create the dataspace for the dataset */ + sid = H5Screate_simple(MISC21_SPACE_RANK, dims, NULL); + CHECK(ret, FAIL, "H5Screate_simple"); + + /* Create the dataset */ + dsid = H5Dcreate2(fid, MISC21_DSET_NAME, H5T_NATIVE_UINT8, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dsid, FAIL, "H5Dcreate2"); + + /* Write out the whole dataset */ + ret = H5Dwrite(dsid, H5T_NATIVE_UINT8, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close everything */ + ret = H5Dclose(dsid); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + HDfree(buf); +} /* end test_misc21() */ + +/**************************************************************** +** +** test_misc22(): Test SZIP bits-per-pixel parameter. +** This should be set according to the datatype. +** Tests for precision and offset combo's. +** +****************************************************************/ +static void +test_misc22(void) +{ + hid_t fid, sid, dcpl, dsid, dcpl2; + char *buf; + hsize_t dims[2] = {MISC22_SPACE_DIM0, MISC22_SPACE_DIM1}, + chunk_size[2] = {MISC22_CHUNK_DIM0, MISC22_CHUNK_DIM1}; + herr_t ret; /* Generic return value */ + hid_t dtype; + /* should extend test to signed ints */ + hid_t idts[4]; + /* do the same for floats + hid_t fdts[2]={H5T_NATIVE_FLOAT32, + H5T_NATIVE_FLOAT64} + */ + size_t prec[4] = {3, 11, 19, 27}; + size_t offsets[5] = {0, 3, 11, 19, 27}; + int i, j, k; + unsigned int flags; + size_t cd_nelmts = 32; + unsigned int cd_values[32]; + size_t correct; + + if (h5_szip_can_encode() != 1) + return; + idts[0] = H5Tcopy(H5T_NATIVE_UINT8); + idts[1] = H5Tcopy(H5T_NATIVE_UINT16); + idts[2] = H5Tcopy(H5T_NATIVE_UINT32); + idts[3] = H5Tcopy(H5T_NATIVE_UINT64); + + /* Output message about test being performed */ + MESSAGE(5, ("Testing datatypes with SZIP filter\n")); + + /* Allocate space for the buffer */ + buf = (char *)HDcalloc(MISC22_SPACE_DIM0 * MISC22_SPACE_DIM1, 8); + CHECK(buf, NULL, "HDcalloc"); + + /* Create the file */ + fid = H5Fcreate(MISC22_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create the dataspace for the dataset */ + sid = H5Screate_simple(MISC22_SPACE_RANK, dims, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + + for (i = 0; i < 4; i++) { + for (j = 0; j < 4; j++) { + if (prec[j] > (H5Tget_size(idts[i]) * 8)) + continue; /* skip irrelevant combination */ + for (k = 0; k < 5; k++) { + if (offsets[k] > (H5Tget_size(idts[i]) * 8)) + continue; /* skip irrelevant combinations */ + if ((prec[j] + offsets[k]) > (H5Tget_size(idts[i]) * 8)) + continue; + + MESSAGE(5, (" Testing datatypes size=%zu precision=%u offset=%d\n", H5Tget_size(idts[i]), + (unsigned)prec[j], (unsigned)offsets[k])); + + /* Create the DCPL */ + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + + /* Set DCPL properties */ + ret = H5Pset_chunk(dcpl, MISC22_SPACE_RANK, chunk_size); + CHECK(ret, FAIL, "H5Pset_chunk"); + /* Set custom DCPL properties */ + ret = H5Pset_szip(dcpl, H5_SZIP_NN_OPTION_MASK, 32); /* vary the PPB */ + CHECK(ret, FAIL, "H5Pset_szip"); + + /* set up the datatype according to the loop */ + dtype = H5Tcopy(idts[i]); + CHECK(dtype, FAIL, "H5Tcopy"); + ret = H5Tset_precision(dtype, prec[j]); + CHECK(ret, FAIL, "H5Tset_precision"); + ret = H5Tset_offset(dtype, offsets[k]); + CHECK(ret, FAIL, "H5Tset_precision"); + + /* compute the correct PPB that should be set by SZIP */ + if (offsets[k] == 0) + correct = prec[j]; + else + correct = H5Tget_size(idts[i]) * 8; + if (correct > 24) { + if (correct <= 32) + correct = 32; + else if (correct <= 64) + correct = 64; + } /* end if */ + + /* Create the dataset */ + dsid = H5Dcreate2(fid, MISC22_DSET_NAME, dtype, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dsid, FAIL, "H5Dcreate2"); + + /* Write out the whole dataset */ + ret = H5Dwrite(dsid, dtype, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close everything */ + ret = H5Dclose(dsid); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Tclose(dtype); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + + dsid = H5Dopen2(fid, MISC22_DSET_NAME, H5P_DEFAULT); + CHECK(dsid, FAIL, "H5Dopen2"); + + dcpl2 = H5Dget_create_plist(dsid); + CHECK(dcpl2, FAIL, "H5Dget_create_plist"); + + ret = H5Pget_filter_by_id2(dcpl2, H5Z_FILTER_SZIP, &flags, &cd_nelmts, cd_values, 0, NULL, + NULL); + CHECK(ret, FAIL, "H5Pget_filter_by_id2"); + + VERIFY(cd_values[2], (unsigned)correct, "SZIP filter returned value for precision"); + + ret = H5Dclose(dsid); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Ldelete(fid, MISC22_DSET_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + + ret = H5Pclose(dcpl2); + CHECK(ret, FAIL, "H5Pclose"); + } + } + } + ret = H5Tclose(idts[0]); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Tclose(idts[1]); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Tclose(idts[2]); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Tclose(idts[3]); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + HDfree(buf); +} /* end test_misc22() */ +#endif /* H5_HAVE_FILTER_SZIP */ + +/**************************************************************** +** +** test_misc23(): Test intermediate group creation. +** +****************************************************************/ +static void +test_misc23(void) +{ + hsize_t dims[] = {10}; + hid_t file_id = 0, group_id = 0, type_id = 0, space_id = 0, tmp_id = 0, create_id = H5P_DEFAULT, + access_id = H5P_DEFAULT; +#ifndef NO_OBJECT_GET_NAME + char objname[MISC23_NAME_BUF_SIZE]; /* Name of object */ +#endif + H5O_info2_t oinfo; + htri_t tri_status; +#ifndef NO_OBJECT_GET_NAME + ssize_t namelen; +#endif + herr_t status; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing intermediate group creation\n")); + + /* Create a new file using default properties. */ + file_id = H5Fcreate(MISC23_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file_id, FAIL, "H5Fcreate"); + + /* Build some infrastructure */ + group_id = H5Gcreate2(file_id, "/A", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(group_id, FAIL, "H5Gcreate2"); + + space_id = H5Screate_simple(1, dims, NULL); + CHECK(space_id, FAIL, "H5Screate_simple"); + + type_id = H5Tcopy(H5T_STD_I32BE); + CHECK(type_id, FAIL, "H5Tcopy"); + +#ifndef H5_NO_DEPRECATED_SYMBOLS + /********************************************************************** + * test the old APIs + **********************************************************************/ + + H5E_BEGIN_TRY + { + tmp_id = H5Gcreate1(file_id, "/A/B00a/grp", (size_t)0); + } + H5E_END_TRY; + VERIFY(tmp_id, FAIL, "H5Gcreate1"); + + /* Make sure that size_hint values that can't fit into a 32-bit + * unsigned integer are rejected. Only necessary on systems where + * size_t is a 64-bit type. + */ + if (SIZE_MAX > UINT32_MAX) { + H5E_BEGIN_TRY + { + tmp_id = H5Gcreate1(file_id, "/size_hint_too_large", SIZE_MAX); + } + H5E_END_TRY; + VERIFY(tmp_id, FAIL, "H5Gcreate1"); + } + + /* Make sure the largest size_hint value works */ + H5E_BEGIN_TRY + { + tmp_id = H5Gcreate1(file_id, "/largest_size_hint", UINT32_MAX); + } + H5E_END_TRY; + CHECK(tmp_id, FAIL, "H5Gcreate1"); + status = H5Gclose(tmp_id); + CHECK(status, FAIL, "H5Gclose"); + + tmp_id = H5Gcreate1(file_id, "/A/grp", (size_t)0); + CHECK(tmp_id, FAIL, "H5Gcreate1"); + status = H5Gclose(tmp_id); + CHECK(status, FAIL, "H5Gclose"); + + H5E_BEGIN_TRY + { + tmp_id = H5Dcreate1(file_id, "/A/B00c/dset", type_id, space_id, create_id); + } + H5E_END_TRY; + VERIFY(tmp_id, FAIL, "H5Dcreate1"); + + tmp_id = H5Dcreate1(file_id, "/A/dset", type_id, space_id, create_id); + CHECK(tmp_id, FAIL, "H5Dcreate1"); + status = H5Dclose(tmp_id); + CHECK(status, FAIL, "H5Dclose"); +#endif /* H5_NO_DEPRECATED_SYMBOLS */ + + /********************************************************************** + * test H5Gcreate2() + **********************************************************************/ + + /* Create link creation property list */ + create_id = H5Pcreate(H5P_LINK_CREATE); + CHECK(create_id, FAIL, "H5Pcreate"); + + /* Set flag for intermediate group creation */ + status = H5Pset_create_intermediate_group(create_id, TRUE); + CHECK(status, FAIL, "H5Pset_create_intermediate_group"); + + tmp_id = H5Gcreate2(file_id, "/A/B01/grp", create_id, H5P_DEFAULT, access_id); + CHECK(tmp_id, FAIL, "H5Gcreate2"); +#ifndef NO_OBJECT_GET_NAME + /* Query that the name of the new group is correct */ + namelen = H5Iget_name(tmp_id, objname, (size_t)MISC23_NAME_BUF_SIZE); + CHECK(namelen, FAIL, "H5Iget_name"); + VERIFY_STR(objname, "/A/B01/grp", "H5Iget_name"); +#endif + status = H5Gclose(tmp_id); + CHECK(status, FAIL, "H5Gclose"); + + /* Check that intermediate group is set up correctly */ + tmp_id = H5Gopen2(file_id, "/A/B01", H5P_DEFAULT); + CHECK(tmp_id, FAIL, "H5Gopen2"); + + status = H5Oget_info3(tmp_id, &oinfo, H5O_INFO_BASIC); + CHECK(status, FAIL, "H5Oget_info3"); + VERIFY(oinfo.rc, 1, "H5Oget_info3"); + + status = H5Gclose(tmp_id); + CHECK(status, FAIL, "H5Gclose"); + + tmp_id = H5Gcreate2(file_id, "/A/B02/C02/grp", create_id, H5P_DEFAULT, access_id); + CHECK(tmp_id, FAIL, "H5Gcreate2"); + + status = H5Gclose(tmp_id); + CHECK(status, FAIL, "H5Gclose"); + + tmp_id = H5Gcreate2(group_id, "B03/grp/", create_id, H5P_DEFAULT, access_id); + CHECK(tmp_id, FAIL, "H5Gcreate2"); + + status = H5Gclose(tmp_id); + CHECK(status, FAIL, "H5Gclose"); + + tmp_id = H5Gcreate2(group_id, "/A/B04/grp/", create_id, H5P_DEFAULT, access_id); + CHECK(tmp_id, FAIL, "H5Gcreate2"); + + status = H5Gclose(tmp_id); + CHECK(status, FAIL, "H5Gclose"); + + tmp_id = H5Gcreate2(file_id, "/A/B05/C05/A", create_id, H5P_DEFAULT, access_id); + CHECK(tmp_id, FAIL, "H5Gcreate2"); + + status = H5Gclose(tmp_id); + CHECK(status, FAIL, "H5Gclose"); + + status = H5Pclose(create_id); + CHECK(status, FAIL, "H5Pclose"); + + /********************************************************************** + * test H5Dcreate2() + **********************************************************************/ + + /* Create link creation property list */ + create_id = H5Pcreate(H5P_LINK_CREATE); + CHECK(create_id, FAIL, "H5Pcreate"); + + /* Set flag for intermediate group creation */ + status = H5Pset_create_intermediate_group(create_id, TRUE); + CHECK(status, FAIL, "H5Pset_create_intermediate_group"); + + tmp_id = H5Dcreate2(file_id, "/A/B06/dset", type_id, space_id, create_id, H5P_DEFAULT, H5P_DEFAULT); + CHECK(tmp_id, FAIL, "H5Dcreate2"); + + status = H5Dclose(tmp_id); + CHECK(status, FAIL, "H5Dclose"); + + tmp_id = H5Dcreate2(file_id, "/A/B07/B07/dset", type_id, space_id, create_id, H5P_DEFAULT, H5P_DEFAULT); + CHECK(tmp_id, FAIL, "H5Dcreate2"); + + status = H5Dclose(tmp_id); + CHECK(status, FAIL, "H5Dclose"); + + tmp_id = H5Dcreate2(group_id, "B08/dset", type_id, space_id, create_id, H5P_DEFAULT, H5P_DEFAULT); + CHECK(tmp_id, FAIL, "H5Dcreate2"); + + status = H5Dclose(tmp_id); + CHECK(status, FAIL, "H5Dclose"); + + tmp_id = H5Dcreate2(group_id, "/A/B09/dset", type_id, space_id, create_id, H5P_DEFAULT, H5P_DEFAULT); + CHECK(tmp_id, FAIL, "H5Dcreate2"); + + status = H5Dclose(tmp_id); + CHECK(status, FAIL, "H5Dclose"); + + tmp_id = H5Dcreate2(file_id, "/A/B10/C10/A/dset", type_id, space_id, create_id, H5P_DEFAULT, H5P_DEFAULT); + CHECK(tmp_id, FAIL, "H5Dcreate2"); + + status = H5Dclose(tmp_id); + CHECK(status, FAIL, "H5Dclose"); + + status = H5Tclose(type_id); + CHECK(status, FAIL, "H5Tclose"); + + status = H5Sclose(space_id); + CHECK(status, FAIL, "H5Sclose"); + + status = H5Pclose(create_id); + CHECK(status, FAIL, "H5Pclose"); + + /********************************************************************** + * test H5Tcommit2() + **********************************************************************/ + + /* Create link creation property list */ + create_id = H5Pcreate(H5P_LINK_CREATE); + CHECK(create_id, FAIL, "H5Pcreate"); + + /* Set flag for intermediate group creation */ + status = H5Pset_create_intermediate_group(create_id, TRUE); + CHECK(status, FAIL, "H5Pset_create_intermediate_group"); + + tmp_id = H5Tcopy(H5T_NATIVE_INT16); + CHECK(tmp_id, FAIL, "H5Tcopy"); + + status = H5Tcommit2(file_id, "/A/B11/dtype", tmp_id, create_id, H5P_DEFAULT, access_id); + CHECK(status, FAIL, "H5Tcommit2"); + + status = H5Tclose(tmp_id); + CHECK(status, FAIL, "H5Tclose"); + + tmp_id = H5Tcopy(H5T_NATIVE_INT32); + CHECK(tmp_id, FAIL, "H5Tcopy"); + + status = H5Tcommit2(file_id, "/A/B12/C12/dtype", tmp_id, create_id, H5P_DEFAULT, access_id); + CHECK(status, FAIL, "H5Tcommit2"); + + status = H5Tclose(tmp_id); + CHECK(status, FAIL, "H5Tclose"); + + tmp_id = H5Tcopy(H5T_NATIVE_INT64); + CHECK(tmp_id, FAIL, "H5Tcopy"); + + status = H5Tcommit2(group_id, "B13/C12/dtype", tmp_id, create_id, H5P_DEFAULT, access_id); + CHECK(status, FAIL, "H5Tcommit2"); + + status = H5Tclose(tmp_id); + CHECK(status, FAIL, "H5Tclose"); + + tmp_id = H5Tcopy(H5T_NATIVE_FLOAT); + CHECK(tmp_id, FAIL, "H5Tcopy"); + + status = H5Tcommit2(group_id, "/A/B14/dtype", tmp_id, create_id, H5P_DEFAULT, access_id); + CHECK(status, FAIL, "H5Tcommit2"); + + status = H5Tclose(tmp_id); + CHECK(status, FAIL, "H5Tclose"); + + tmp_id = H5Tcopy(H5T_NATIVE_DOUBLE); + CHECK(tmp_id, FAIL, "H5Tcopy"); + + status = H5Tcommit2(file_id, "/A/B15/C15/A/dtype", tmp_id, create_id, H5P_DEFAULT, access_id); + CHECK(status, FAIL, "H5Tcommit2"); + + status = H5Tclose(tmp_id); + CHECK(status, FAIL, "H5Tclose"); + + status = H5Pclose(create_id); + CHECK(status, FAIL, "H5Pclose"); + + /********************************************************************** + * test H5Lcopy() + **********************************************************************/ + + /* Create link creation property list */ + create_id = H5Pcreate(H5P_LINK_CREATE); + CHECK(create_id, FAIL, "H5Pcreate"); + + /* Set flag for intermediate group creation */ + status = H5Pset_create_intermediate_group(create_id, TRUE); + CHECK(status, FAIL, "H5Pset_create_intermediate_group"); + + status = H5Lcopy(file_id, "/A/B01/grp", file_id, "/A/B16/grp", create_id, access_id); + CHECK(status, FAIL, "H5Lcopy"); + + tri_status = H5Lexists(file_id, "/A/B16/grp", access_id); + VERIFY(tri_status, TRUE, "H5Lexists"); + + tri_status = H5Lexists(file_id, "/A/B01/grp", access_id); + VERIFY(tri_status, TRUE, "H5Lexists"); + + /********************************************************************** + * test H5Lmove() + **********************************************************************/ + + status = H5Lmove(file_id, "/A/B16/grp", file_id, "/A/B17/grp", create_id, access_id); + CHECK(status, FAIL, "H5Lmove"); + + tri_status = H5Lexists(file_id, "/A/B17/grp", access_id); + VERIFY(tri_status, TRUE, "H5Lexists"); + + tri_status = H5Lexists(file_id, "/A/B16/grp", access_id); + VERIFY(tri_status, FALSE, "H5Lexists"); + + /********************************************************************** + * test H5Lcreate_hard() + **********************************************************************/ + + status = H5Lcreate_hard(file_id, "/A/B01/grp", file_id, "/A/B18/grp", create_id, access_id); + CHECK(status, FAIL, "H5Lcreate_hard"); + + tri_status = H5Lexists(file_id, "/A/B18/grp", access_id); + VERIFY(tri_status, TRUE, "H5Lexists"); + + /********************************************************************** + * test H5Lcreate_soft() + **********************************************************************/ + + status = H5Lcreate_soft("/A/B01/grp", file_id, "/A/B19/grp", create_id, access_id); + CHECK(status, FAIL, "H5Lcreate_soft"); + + tri_status = H5Lexists(file_id, "/A/B19/grp", access_id); + VERIFY(tri_status, TRUE, "H5Lexists"); + + /********************************************************************** + * test H5Lcreate_external() + **********************************************************************/ +#ifndef NO_EXTERNAL_LINKS + status = H5Lcreate_external("fake_filename", "fake_path", file_id, "/A/B20/grp", create_id, access_id); + CHECK(status, FAIL, "H5Lcreate_external"); + + tri_status = H5Lexists(file_id, "/A/B20/grp", access_id); + VERIFY(tri_status, TRUE, "H5Lexists"); +#endif + /********************************************************************** + * test H5Lcreate_ud() + **********************************************************************/ +#ifndef NO_USER_DEFINED_LINKS + status = + H5Lcreate_ud(file_id, "/A/B21/grp", H5L_TYPE_EXTERNAL, "file\0obj", (size_t)9, create_id, access_id); + CHECK(status, FAIL, "H5Lcreate_ud"); + + tri_status = H5Lexists(file_id, "/A/B21/grp", access_id); + VERIFY(tri_status, TRUE, "H5Lexists"); +#endif + /********************************************************************** + * close + **********************************************************************/ + + status = H5Pclose(create_id); + CHECK(status, FAIL, "H5Pclose"); + + status = H5Gclose(group_id); + CHECK(status, FAIL, "H5Gclose"); + + status = H5Fclose(file_id); + CHECK(status, FAIL, "H5Fclose"); + +} /* end test_misc23() */ + +/**************************************************************** +** +** test_misc24(): Test opening objects with inappropriate APIs +** +****************************************************************/ +static void +test_misc24(void) +{ +#if 0 + hid_t file_id = 0, group_id = 0, type_id = 0, space_id = 0, dset_id = 0, tmp_id = 0; + herr_t ret; /* Generic return value */ +#endif + + /* Output message about test being performed */ + MESSAGE(5, + ("Testing opening objects with inappropriate APIs - SKIPPED due to causing problems in HDF5\n")); +#if 0 + /* Create a new file using default properties. */ + file_id = H5Fcreate(MISC24_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file_id, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset */ + space_id = H5Screate(H5S_SCALAR); + CHECK(space_id, FAIL, "H5Screate"); + + /* Create group, dataset & named datatype objects */ + group_id = H5Gcreate2(file_id, MISC24_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(group_id, FAIL, "H5Gcreate2"); + + dset_id = H5Dcreate2(file_id, MISC24_DATASET_NAME, H5T_NATIVE_INT, space_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT); + CHECK(dset_id, FAIL, "H5Dcreate2"); + + type_id = H5Tcopy(H5T_NATIVE_INT); + CHECK(type_id, FAIL, "H5Tcopy"); + + ret = H5Tcommit2(file_id, MISC24_DATATYPE_NAME, type_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + + /* Create soft links to the objects created */ + ret = H5Lcreate_soft(MISC24_GROUP_NAME, file_id, MISC24_GROUP_LINK, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lcreate_soft"); + + ret = H5Lcreate_soft(MISC24_DATASET_NAME, file_id, MISC24_DATASET_LINK, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lcreate_soft"); + + ret = H5Lcreate_soft(MISC24_DATATYPE_NAME, file_id, MISC24_DATATYPE_LINK, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lcreate_soft"); + + /* Close IDs for objects */ + ret = H5Dclose(dset_id); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Sclose(space_id); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Gclose(group_id); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Tclose(type_id); + CHECK(ret, FAIL, "H5Tclose"); + + /* Attempt to open each kind of object with wrong API, including using soft links */ + H5E_BEGIN_TRY + { + tmp_id = H5Dopen2(file_id, MISC24_GROUP_NAME, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(tmp_id, FAIL, "H5Dopen2"); + + H5E_BEGIN_TRY + { + tmp_id = H5Dopen2(file_id, MISC24_GROUP_LINK, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(tmp_id, FAIL, "H5Dopen2"); + + H5E_BEGIN_TRY + { + tmp_id = H5Topen2(file_id, MISC24_GROUP_NAME, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(tmp_id, FAIL, "H5Topen2"); + + H5E_BEGIN_TRY + { + tmp_id = H5Topen2(file_id, MISC24_GROUP_LINK, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(tmp_id, FAIL, "H5Topen2"); + + H5E_BEGIN_TRY + { + tmp_id = H5Gopen2(file_id, MISC24_DATASET_NAME, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(tmp_id, FAIL, "H5Gopen2"); + + H5E_BEGIN_TRY + { + tmp_id = H5Gopen2(file_id, MISC24_DATASET_LINK, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(tmp_id, FAIL, "H5Gopen2"); + + H5E_BEGIN_TRY + { + tmp_id = H5Topen2(file_id, MISC24_DATASET_NAME, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(tmp_id, FAIL, "H5Topen2"); + + H5E_BEGIN_TRY + { + tmp_id = H5Topen2(file_id, MISC24_DATASET_LINK, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(tmp_id, FAIL, "H5Topen2"); + + H5E_BEGIN_TRY + { + tmp_id = H5Gopen2(file_id, MISC24_DATATYPE_NAME, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(tmp_id, FAIL, "H5Gopen2"); + + H5E_BEGIN_TRY + { + tmp_id = H5Gopen2(file_id, MISC24_DATATYPE_LINK, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(tmp_id, FAIL, "H5Gopen2"); + + H5E_BEGIN_TRY + { + tmp_id = H5Dopen2(file_id, MISC24_DATATYPE_NAME, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(tmp_id, FAIL, "H5Dopen2"); + + H5E_BEGIN_TRY + { + tmp_id = H5Dopen2(file_id, MISC24_DATATYPE_LINK, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(tmp_id, FAIL, "H5Dopen2"); + + /* Try again, with the object already open through valid call */ + /* Open group */ + group_id = H5Gopen2(file_id, MISC24_GROUP_NAME, H5P_DEFAULT); + CHECK(group_id, FAIL, "H5Gopen2"); + + H5E_BEGIN_TRY + { + tmp_id = H5Dopen2(file_id, MISC24_GROUP_NAME, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(tmp_id, FAIL, "H5Dopen2"); + + H5E_BEGIN_TRY + { + tmp_id = H5Dopen2(file_id, MISC24_GROUP_LINK, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(tmp_id, FAIL, "H5Dopen2"); + + H5E_BEGIN_TRY + { + tmp_id = H5Topen2(file_id, MISC24_GROUP_NAME, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(tmp_id, FAIL, "H5Topen2"); + + H5E_BEGIN_TRY + { + tmp_id = H5Topen2(file_id, MISC24_GROUP_LINK, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(tmp_id, FAIL, "H5Topen2"); + + ret = H5Gclose(group_id); + CHECK(ret, FAIL, "H5Gclose"); + + /* Open dataset */ + dset_id = H5Dopen2(file_id, MISC24_DATASET_NAME, H5P_DEFAULT); + CHECK(dset_id, FAIL, "H5Dopen2"); + + H5E_BEGIN_TRY + { + tmp_id = H5Gopen2(file_id, MISC24_DATASET_NAME, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(tmp_id, FAIL, "H5Gopen2"); + + H5E_BEGIN_TRY + { + tmp_id = H5Gopen2(file_id, MISC24_DATASET_LINK, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(tmp_id, FAIL, "H5Gopen2"); + + H5E_BEGIN_TRY + { + tmp_id = H5Topen2(file_id, MISC24_DATASET_NAME, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(tmp_id, FAIL, "H5Topen2"); + + H5E_BEGIN_TRY + { + tmp_id = H5Topen2(file_id, MISC24_DATASET_LINK, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(tmp_id, FAIL, "H5Topen2"); + + ret = H5Dclose(dset_id); + CHECK(ret, FAIL, "H5Dclose"); + + /* Open named datatype */ + type_id = H5Topen2(file_id, MISC24_DATATYPE_NAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Topen2"); + + H5E_BEGIN_TRY + { + tmp_id = H5Gopen2(file_id, MISC24_DATATYPE_NAME, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(tmp_id, FAIL, "H5Gopen2"); + + H5E_BEGIN_TRY + { + tmp_id = H5Gopen2(file_id, MISC24_DATATYPE_LINK, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(tmp_id, FAIL, "H5Gopen2"); + + H5E_BEGIN_TRY + { + tmp_id = H5Dopen2(file_id, MISC24_DATATYPE_NAME, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(tmp_id, FAIL, "H5Dopen2"); + + H5E_BEGIN_TRY + { + tmp_id = H5Dopen2(file_id, MISC24_DATATYPE_LINK, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(tmp_id, FAIL, "H5Dopen2"); + + ret = H5Tclose(type_id); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close file */ + ret = H5Fclose(file_id); + CHECK(ret, FAIL, "H5Fclose"); +#endif +} /* end test_misc24() */ + +/**************************************************************** +** +** test_misc25a(): Exercise null object header message merge bug +** with new file +** +****************************************************************/ +static void +test_misc25a(void) +{ + hid_t fid; /* File ID */ + hid_t gid, gid2, gid3; /* Group IDs */ + hid_t aid; /* Attribute ID */ + hid_t sid; /* Dataspace ID */ + hid_t tid; /* Datatype ID */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Exercise null object header message bug\n")); + + /* Create file */ + fid = H5Fcreate(MISC25A_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create top group */ + gid = H5Gcreate2(fid, MISC25A_GROUP0_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gcreate2"); + + /* Close top group */ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + /* Create first group */ + gid = H5Gcreate2(fid, MISC25A_GROUP1_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gcreate2"); + + /* Close first group */ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + /* Create second group */ + gid2 = H5Gcreate2(fid, MISC25A_GROUP2_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid2, FAIL, "H5Gcreate2"); + + /* Close second group */ + ret = H5Gclose(gid2); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open file */ + fid = H5Fopen(MISC25A_FILE, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* Re-open first group */ + gid = H5Gopen2(fid, MISC25A_GROUP1_NAME, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gopen2"); + + /* Create dataspace for attribute */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create dataype for attribute */ + tid = H5Tcopy(H5T_C_S1); + CHECK(tid, FAIL, "H5Tcopy"); + ret = H5Tset_size(tid, (size_t)MISC25A_ATTR1_LEN); + CHECK(ret, FAIL, "H5Tset_size"); + + /* Add 1st attribute on first group */ + aid = H5Acreate2(gid, MISC25A_ATTR1_NAME, tid, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close datatype */ + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close attribute */ + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + + /* Create dataspace for 2nd attribute */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create dataype for attribute */ + tid = H5Tcopy(H5T_C_S1); + CHECK(tid, FAIL, "H5Tcopy"); + ret = H5Tset_size(tid, (size_t)MISC25A_ATTR2_LEN); + CHECK(ret, FAIL, "H5Tset_size"); + + /* Add 2nd attribute on first group */ + aid = H5Acreate2(gid, MISC25A_ATTR2_NAME, tid, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close datatype */ + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close 2nd attribute */ + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close first group */ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open file */ + fid = H5Fopen(MISC25A_FILE, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* Create third group */ + gid3 = H5Gcreate2(fid, MISC25A_GROUP3_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid3, FAIL, "H5Gcreate2"); + + /* Close third group */ + ret = H5Gclose(gid3); + CHECK(ret, FAIL, "H5Gclose"); + + /* Re-open first group */ + gid = H5Gopen2(fid, MISC25A_GROUP1_NAME, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gopen2"); + + /* Delete 2nd attribute */ + ret = H5Adelete(gid, MISC25A_ATTR2_NAME); + CHECK(ret, FAIL, "H5Adelete"); + + /* Close first group */ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open file */ + fid = H5Fopen(MISC25A_FILE, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* Re-open first group */ + gid = H5Gopen2(fid, MISC25A_GROUP1_NAME, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gopen2"); + + /* Create dataspace for 3rd attribute */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create dataype for attribute */ + tid = H5Tcopy(H5T_C_S1); + CHECK(tid, FAIL, "H5Tcopy"); + ret = H5Tset_size(tid, (size_t)MISC25A_ATTR3_LEN); + CHECK(ret, FAIL, "H5Tset_size"); + + /* Add 3rd attribute on first group (smaller than 2nd attribute) */ + aid = H5Acreate2(gid, MISC25A_ATTR3_NAME, tid, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close datatype */ + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close 3rd attribute */ + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close first group */ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open file */ + fid = H5Fopen(MISC25A_FILE, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* Re-open first group */ + gid = H5Gopen2(fid, MISC25A_GROUP1_NAME, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gopen2"); + + /* Delete 3rd attribute */ + ret = H5Adelete(gid, MISC25A_ATTR3_NAME); + CHECK(ret, FAIL, "H5Adelete"); + + /* Create dataspace for 3rd attribute */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create dataype for attribute */ + tid = H5Tcopy(H5T_C_S1); + CHECK(tid, FAIL, "H5Tcopy"); + ret = H5Tset_size(tid, (size_t)MISC25A_ATTR2_LEN); + CHECK(ret, FAIL, "H5Tset_size"); + + /* Re-create 2nd attribute on first group */ + aid = H5Acreate2(gid, MISC25A_ATTR2_NAME, tid, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close datatype */ + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close 2nd attribute */ + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close first group */ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open file */ + fid = H5Fopen(MISC25A_FILE, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* Re-open first group */ + gid = H5Gopen2(fid, MISC25A_GROUP1_NAME, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gopen2"); + + /* Delete 2nd attribute */ + ret = H5Adelete(gid, MISC25A_ATTR2_NAME); + CHECK(ret, FAIL, "H5Adelete"); + + /* Close first group */ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open file */ + fid = H5Fopen(MISC25A_FILE, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* Re-open first group */ + gid = H5Gopen2(fid, MISC25A_GROUP1_NAME, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gopen2"); + + /* Create dataspace for 3rd attribute */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create dataype for attribute */ + tid = H5Tcopy(H5T_C_S1); + CHECK(tid, FAIL, "H5Tcopy"); + ret = H5Tset_size(tid, (size_t)MISC25A_ATTR2_LEN); + CHECK(ret, FAIL, "H5Tset_size"); + + /* Re-create 2nd attribute on first group */ + aid = H5Acreate2(gid, MISC25A_ATTR2_NAME, tid, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close datatype */ + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close 2nd attribute */ + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close first group */ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_misc25a() */ + +/**************************************************************** +** +** test_misc25b(): Exercise null object header message merge bug +** with existing file (This test relies on +** the file produced by test/gen_mergemsg.c) +** +****************************************************************/ +#if 0 +static void +test_misc25b(void) +{ + hid_t fid; /* File ID */ + hid_t gid; /* Group ID */ + const char *testfile = H5_get_srcdir_filename(MISC25B_FILE); /* Corrected test file name */ + hbool_t driver_is_default_compatible; + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Exercise null object header message bug\n")); + + ret = h5_driver_is_default_vfd_compatible(H5P_DEFAULT, &driver_is_default_compatible); + CHECK(ret, FAIL, "h5_driver_is_default_vfd_compatible"); + + if (!driver_is_default_compatible) { + HDprintf("-- SKIPPED --\n"); + return; + } + + /* Open file */ + fid = H5Fopen(testfile, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* Re-open group with object header messages that will merge */ + gid = H5Gopen2(fid, MISC25B_GROUP, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gopen2"); + + /* Close first group */ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_misc25b() */ +#endif + +/**************************************************************** +** +** test_misc25c(): Exercise another null object header message merge bug. +** +****************************************************************/ +static void +test_misc25c(void) +{ + hid_t fid; /* File ID */ + hid_t fapl; /* File access property list ID */ + hid_t gcpl; /* Group creation property list ID */ + hid_t sid; /* Dataspace ID */ + hid_t did; /* Dataset ID */ + hid_t gid; /* Group ID */ + hid_t gid2; /* Group ID */ + hid_t aid; /* Attribute ID */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Exercise another null object header message bug\n")); + + /* Compose file access property list */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + ret = H5Pset_libver_bounds(fapl, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST); + CHECK(ret, FAIL, "H5Pset_libver_bounds"); + + /* Create the file */ + fid = H5Fcreate(MISC25C_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Compose group creation property list */ + gcpl = H5Pcreate(H5P_GROUP_CREATE); + CHECK(gcpl, FAIL, "H5Pcreate"); + ret = H5Pset_link_creation_order(gcpl, (H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED)); + CHECK(ret, FAIL, "H5Pset_link_creation_order"); + ret = H5Pset_attr_creation_order(gcpl, (H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED)); + CHECK(ret, FAIL, "H5Pset_attr_creation_order"); + ret = H5Pset_est_link_info(gcpl, 1, 18); + CHECK(ret, FAIL, "H5Pset_est_link_info"); + + /* Create a group for the dataset */ + gid = H5Gcreate2(fid, MISC25C_DSETGRPNAME, H5P_DEFAULT, gcpl, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gcreate2"); + + /* Create the dataspace */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create the dataset */ + did = H5Dcreate2(gid, MISC25C_DSETNAME, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); + + /* Create an extra group */ + gid2 = H5Gcreate2(fid, MISC25C_GRPNAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid2, FAIL, "H5Gcreate2"); + + /* Close the extra group */ + ret = H5Gclose(gid2); + CHECK(ret, FAIL, "H5Gclose"); + + /* Add an attribute to the dataset group */ + aid = H5Acreate2(gid, MISC25C_ATTRNAME, H5T_NATIVE_CHAR, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + + /* Close the attribute */ + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + + /* Create a second extra group */ + gid2 = H5Gcreate2(fid, MISC25C_GRPNAME2, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid2, FAIL, "H5Gcreate2"); + + /* Close the second extra group */ + ret = H5Gclose(gid2); + CHECK(ret, FAIL, "H5Gclose"); + + /* Add second attribute to the dataset group */ + aid = H5Acreate2(gid, MISC25C_ATTRNAME2, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(aid, FAIL, "H5Acreate2"); + + /* Close the attribute */ + ret = H5Aclose(aid); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close the dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close the dataset group */ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close the dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Close the property lists */ + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Pclose(gcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Re-open the file */ + fid = H5Fopen(MISC25C_FILE, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* Re-open the dataset group */ + gid = H5Gopen2(fid, MISC25C_DSETGRPNAME, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gopen2"); + + /* Rename the dataset */ + ret = H5Lmove(gid, MISC25C_DSETNAME, H5L_SAME_LOC, MISC25C_DSETNAME2, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lmove"); + + /* Delete the first attribute */ + ret = H5Adelete(gid, MISC25C_ATTRNAME); + CHECK(ret, FAIL, "H5Adelete"); + + /* Close the dataset group */ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_misc25c() */ + +/**************************************************************** +** +** test_misc26(): Regression test: ensure that copying filter +** pipelines works properly. +** +****************************************************************/ +static void +test_misc26(void) +{ + hid_t fid; /* File ID */ + hid_t sid; /* Dataspace ID */ + hid_t did; /* Dataset ID */ + hid_t dcpl1, dcpl2, dcpl3; /* Property List IDs */ + hsize_t dims[] = {1}; + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Copying filter pipelines\n")); + + /* Create the property list. It needs chunking so we can add filters */ + dcpl1 = H5Pcreate(H5P_DATASET_CREATE); + CHECK_I(dcpl1, "H5Pcreate"); + ret = H5Pset_chunk(dcpl1, 1, dims); + CHECK_I(ret, "H5Pset_chunk"); + + /* Add a filter with a data value to the property list */ + ret = H5Pset_deflate(dcpl1, 1); + CHECK_I(ret, "H5Pset_deflate"); + + /* Copy the property list */ + dcpl2 = H5Pcopy(dcpl1); + CHECK_I(dcpl2, "H5Pcopy"); + + /* Add a filter with no data values to the copy */ + ret = H5Pset_shuffle(dcpl2); + CHECK_I(ret, "H5Pset_shuffle"); + + /* Copy the copy */ + dcpl3 = H5Pcopy(dcpl2); + CHECK_I(dcpl3, "H5Pcopy"); + + /* Add another filter */ + ret = H5Pset_deflate(dcpl3, 2); + CHECK_I(ret, "H5Pset_deflate"); + + /* Create a new file and datasets within that file that use these + * property lists + */ + fid = H5Fcreate(MISC26_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + sid = H5Screate_simple(1, dims, dims); + CHECK(sid, FAIL, "H5Screate_simple"); + + did = H5Dcreate2(fid, "dataset1", H5T_NATIVE_FLOAT, sid, H5P_DEFAULT, dcpl1, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); + ret = H5Dclose(did); + CHECK_I(ret, "H5Dclose"); + + did = H5Dcreate2(fid, "dataset2", H5T_NATIVE_FLOAT, sid, H5P_DEFAULT, dcpl2, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); + ret = H5Dclose(did); + CHECK_I(ret, "H5Dclose"); + + did = H5Dcreate2(fid, "dataset3", H5T_NATIVE_FLOAT, sid, H5P_DEFAULT, dcpl3, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); + ret = H5Dclose(did); + CHECK_I(ret, "H5Dclose"); + + /* Close the dataspace and file */ + ret = H5Sclose(sid); + CHECK_I(ret, "H5Sclose"); + ret = H5Fclose(fid); + CHECK_I(ret, "H5Fclose"); + + /* Close the property lists. */ + ret = H5Pclose(dcpl1); + CHECK_I(ret, "H5Pclose"); + ret = H5Pclose(dcpl2); + CHECK_I(ret, "H5Pclose"); + ret = H5Pclose(dcpl3); + CHECK_I(ret, "H5Pclose"); +} + +/**************************************************************** +** +** test_misc27(): Ensure that objects with incorrect # of object +** header messages are handled appropriately. +** +** (Note that this test file is generated by the "gen_bad_ohdr.c" code) +** +****************************************************************/ +#if 0 +static void +test_misc27(void) +{ + hid_t fid; /* File ID */ + hid_t gid; /* Group ID */ + const char *testfile = H5_get_srcdir_filename(MISC27_FILE); /* Corrected test file name */ + hbool_t driver_is_default_compatible; + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Corrupt object header handling\n")); + + ret = h5_driver_is_default_vfd_compatible(H5P_DEFAULT, &driver_is_default_compatible); + CHECK(ret, FAIL, "h5_driver_is_default_vfd_compatible"); + + if (!driver_is_default_compatible) { + HDprintf("-- SKIPPED --\n"); + return; + } + + /* Open the file */ + fid = H5Fopen(testfile, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + +#ifdef H5_STRICT_FORMAT_CHECKS + /* Open group with incorrect # of object header messages (should fail) */ + H5E_BEGIN_TRY + { + gid = H5Gopen2(fid, MISC27_GROUP, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(gid, FAIL, "H5Gopen2"); +#else /* H5_STRICT_FORMAT_CHECKS */ + /* Open group with incorrect # of object header messages */ + gid = H5Gopen2(fid, MISC27_GROUP, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gopen2"); + + /* Close group */ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); +#endif /* H5_STRICT_FORMAT_CHECKS */ + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_misc27() */ +#endif + +/**************************************************************** +** +** test_misc28(): Ensure that the dataset chunk cache will hold +** the correct number of chunks in cache without +** evicting them. +** +****************************************************************/ +static void +test_misc28(void) +{ + hid_t fid; /* File ID */ + hid_t sidf; /* File Dataspace ID */ + hid_t sidm; /* Memory Dataspace ID */ + hid_t did; /* Dataset ID */ + hid_t dcpl, fapl; /* Property List IDs */ + hsize_t dims[] = {MISC28_SIZE, MISC28_SIZE}; + hsize_t mdims[] = {MISC28_SIZE}; + hsize_t cdims[] = {1, 1}; + hsize_t start[] = {0, 0}; + hsize_t count[] = {MISC28_SIZE, 1}; +#if 0 + size_t nbytes_used; + int nused; +#endif + char buf[MISC28_SIZE]; + int i; + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Dataset chunk cache\n")); + + /* Create the fapl and set the cache size. Set nelmts to larger than the + * file size so we can be guaranteed that no chunks will be evicted due to + * a hash collision. Set nbytes to fit exactly 1 column of chunks (10 + * bytes). */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + ret = H5Pset_cache(fapl, MISC28_NSLOTS, MISC28_NSLOTS, MISC28_SIZE, 0.75); + CHECK(ret, FAIL, "H5Pset_cache"); + + /* Create the dcpl and set the chunk size */ + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + ret = H5Pset_chunk(dcpl, 2, cdims); + CHECK(ret, FAIL, "H5Pset_chunk"); + + /* Create a new file and datasets within that file that use these + * property lists + */ + fid = H5Fcreate(MISC28_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + sidf = H5Screate_simple(2, dims, NULL); + CHECK(sidf, FAIL, "H5Screate_simple"); + + did = H5Dcreate2(fid, "dataset", H5T_NATIVE_CHAR, sidf, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); +#if 0 + /* Verify that the chunk cache is empty */ + ret = H5D__current_cache_size_test(did, &nbytes_used, &nused); + CHECK(ret, FAIL, "H5D__current_cache_size_test"); + VERIFY(nbytes_used, (size_t)0, "H5D__current_cache_size_test"); + VERIFY(nused, 0, "H5D__current_cache_size_test"); +#endif + /* Initialize write buffer */ + for (i = 0; i < MISC28_SIZE; i++) + buf[i] = (char)i; + + /* Create memory dataspace and selection in file dataspace */ + sidm = H5Screate_simple(1, mdims, NULL); + CHECK(sidm, FAIL, "H5Screate_simple"); + + ret = H5Sselect_hyperslab(sidf, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Write hypserslab */ + ret = H5Dwrite(did, H5T_NATIVE_CHAR, sidm, sidf, H5P_DEFAULT, buf); + CHECK(ret, FAIL, "H5Dwrite"); +#if 0 + /* Verify that all 10 chunks written have been cached */ + ret = H5D__current_cache_size_test(did, &nbytes_used, &nused); + CHECK(ret, FAIL, "H5D__current_cache_size_test"); + VERIFY(nbytes_used, (size_t)MISC28_SIZE, "H5D__current_cache_size_test"); + VERIFY(nused, MISC28_SIZE, "H5D__current_cache_size_test"); +#endif + /* Initialize write buffer */ + for (i = 0; i < MISC28_SIZE; i++) + buf[i] = (char)(MISC28_SIZE - 1 - i); + + /* Select new hyperslab */ + start[1] = 1; + ret = H5Sselect_hyperslab(sidf, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Write hyperslab */ + ret = H5Dwrite(did, H5T_NATIVE_CHAR, sidm, sidf, H5P_DEFAULT, buf); + CHECK(ret, FAIL, "H5Dwrite"); +#if 0 + /* Verify that the size of the cache remains at 10 */ + ret = H5D__current_cache_size_test(did, &nbytes_used, &nused); + CHECK(ret, FAIL, "H5D__current_cache_size_test"); + VERIFY(nbytes_used, (size_t)MISC28_SIZE, "H5D__current_cache_size_test"); + VERIFY(nused, MISC28_SIZE, "H5D__current_cache_size_test"); +#endif + /* Close dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* Re open dataset */ + did = H5Dopen2(fid, "dataset", H5P_DEFAULT); + CHECK(did, FAIL, "H5Dopen2"); +#if 0 + /* Verify that the chunk cache is empty */ + ret = H5D__current_cache_size_test(did, &nbytes_used, &nused); + CHECK(ret, FAIL, "H5D__current_cache_size_test"); + VERIFY(nbytes_used, (size_t)0, "H5D__current_cache_size_test"); + VERIFY(nused, 0, "H5D__current_cache_size_test"); +#endif + /* Select hyperslabe for reading */ + start[1] = 0; + ret = H5Sselect_hyperslab(sidf, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Read hypserslab */ + ret = H5Dread(did, H5T_NATIVE_CHAR, sidm, sidf, H5P_DEFAULT, buf); + CHECK(ret, FAIL, "H5Dread"); + + /* Verify the data read */ + for (i = 0; i < MISC28_SIZE; i++) + VERIFY(buf[i], i, "H5Dread"); +#if 0 + /* Verify that all 10 chunks read have been cached */ + ret = H5D__current_cache_size_test(did, &nbytes_used, &nused); + CHECK(ret, FAIL, "H5D__current_cache_size_test"); + VERIFY(nbytes_used, (size_t)MISC28_SIZE, "H5D__current_cache_size_test"); + VERIFY(nused, MISC28_SIZE, "H5D__current_cache_size_test"); +#endif + /* Select new hyperslab */ + start[1] = 1; + ret = H5Sselect_hyperslab(sidf, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Read hyperslab */ + ret = H5Dread(did, H5T_NATIVE_CHAR, sidm, sidf, H5P_DEFAULT, buf); + CHECK(ret, FAIL, "H5Dread"); + + /* Verify the data read */ + for (i = 0; i < MISC28_SIZE; i++) + VERIFY(buf[i], MISC28_SIZE - 1 - i, "H5Dread"); +#if 0 + /* Verify that the size of the cache remains at 10 */ + ret = H5D__current_cache_size_test(did, &nbytes_used, &nused); + CHECK(ret, FAIL, "H5D__current_cache_size_test"); + VERIFY(nbytes_used, (size_t)MISC28_SIZE, "H5D__current_cache_size_test"); + VERIFY(nused, MISC28_SIZE, "H5D__current_cache_size_test"); +#endif + /* Close dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close the dataspaces and file */ + ret = H5Sclose(sidf); + CHECK_I(ret, "H5Sclose"); + ret = H5Sclose(sidm); + CHECK_I(ret, "H5Sclose"); + ret = H5Fclose(fid); + CHECK_I(ret, "H5Fclose"); + + /* Close the property lists. */ + ret = H5Pclose(dcpl); + CHECK_I(ret, "H5Pclose"); + ret = H5Pclose(fapl); + CHECK_I(ret, "H5Pclose"); +} /* end test_misc28() */ + +/**************************************************************** +** +** test_misc29(): Ensure that speculative metadata reads don't +** get raw data into the metadata accumulator. +** +****************************************************************/ +#if 0 +static void +test_misc29(void) +{ + hbool_t driver_is_default_compatible; + hid_t fid; /* File ID */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Speculative metadata reads\n")); + + ret = h5_driver_is_default_vfd_compatible(H5P_DEFAULT, &driver_is_default_compatible); + CHECK(ret, FAIL, "h5_driver_is_default_vfd_compatible"); + + if (!driver_is_default_compatible) { + HDprintf("-- SKIPPED --\n"); + return; + } + + /* Make a copy of the data file from svn. */ + ret = h5_make_local_copy(MISC29_ORIG_FILE, MISC29_COPY_FILE); + CHECK(ret, -1, "h5_make_local_copy"); + + /* Open the copied file */ + fid = H5Fopen(MISC29_COPY_FILE, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* Delete the last dataset */ + ret = H5Ldelete(fid, MISC29_DSETNAME, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_misc29() */ +#endif + +#if 0 +static int +test_misc30_get_info_cb(hid_t loc_id, const char *name, const H5L_info2_t H5_ATTR_UNUSED *info, + void H5_ATTR_UNUSED *op_data) +{ + H5O_info2_t object_info; + + return H5Oget_info_by_name3(loc_id, name, &object_info, H5O_INFO_BASIC, H5P_DEFAULT); +} + +static int +test_misc30_get_info(hid_t loc_id) +{ + return H5Literate2(loc_id, H5_INDEX_NAME, H5_ITER_INC, NULL, test_misc30_get_info_cb, NULL); +} +#endif + +/**************************************************************** +** +** test_misc30(): Exercise local heap code that loads prefix +** separately from data block, causing the free +** block information to get lost. +** +****************************************************************/ +#if 0 +static void +test_misc30(void) +{ + hsize_t file_size[] = {0, 0}; /* Sizes of file created */ + unsigned get_info; /* Whether to perform the get info call */ + + /* Output message about test being performed */ + MESSAGE(5, ("Local heap dropping free block info\n")); + + for (get_info = FALSE; get_info <= TRUE; get_info++) { + hid_t fid; /* File ID */ + hid_t gid; /* Group ID */ + int i; /* Local index counter */ + herr_t ret; /* Generic return value */ + + fid = H5Fcreate(MISC30_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + gid = H5Gcreate2(fid, "/g0", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gcreate2"); + + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + for (i = 0; i < 20; i++) { + char gname[32]; + + fid = H5Fopen(MISC30_FILE, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + if (get_info) { + ret = test_misc30_get_info(fid); + CHECK(ret, FAIL, "test_misc30_get_info"); + } + + HDsnprintf(gname, sizeof(gname), "/g0/group%d", i); + gid = H5Gcreate2(fid, gname, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid, FAIL, "H5Gcreate2"); + + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + } + + fid = H5Fopen(MISC30_FILE, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + ret = H5Fget_filesize(fid, &file_size[get_info]); + CHECK(fid, FAIL, "H5Fget_filesize"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + } + + VERIFY(file_size[0], file_size[1], "test_misc30"); +} /* end test_misc30() */ +#endif + +/**************************************************************** +** +** test_misc31(): Test reentering library through deprecated +* routines that register an id after calling +* H5close(). +** +****************************************************************/ +#if 0 +static void +test_misc31(void) +{ +#ifndef H5_NO_DEPRECATED_SYMBOLS + hid_t file_id; /* File id */ + hid_t space_id; /* Dataspace id */ + hid_t dset_id; /* Dataset id */ + hid_t attr_id; /* Attribute id */ + hid_t group_id; /* Group id */ + hid_t dtype_id; /* Datatype id */ + herr_t ret; /* Generic return value */ +#endif /* H5_NO_DEPRECATED_SYMBOLS */ + + /* Output message about test being performed */ + MESSAGE(5, ("Deprecated routines initialize after H5close()\n")); + +#ifndef H5_NO_DEPRECATED_SYMBOLS + file_id = H5Fcreate(MISC31_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file_id, FAIL, "H5Fcreate"); + + /* Test dataset package */ + space_id = H5Screate(H5S_SCALAR); + CHECK(space_id, FAIL, "H5Screate"); + dset_id = H5Dcreate1(file_id, MISC31_DSETNAME, H5T_NATIVE_INT, space_id, H5P_DEFAULT); + CHECK(dset_id, FAIL, "H5Dcreate1"); + ret = H5close(); + CHECK(ret, FAIL, "H5close"); + file_id = H5Fopen(MISC31_FILE, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(file_id, FAIL, "H5Fopen"); + dset_id = H5Dopen1(file_id, MISC31_DSETNAME); + CHECK(dset_id, FAIL, "H5Dopen1"); + + /* Test attribute package */ + space_id = H5Screate(H5S_SCALAR); + CHECK(space_id, FAIL, "H5Screate"); + attr_id = H5Acreate1(dset_id, MISC31_ATTRNAME1, H5T_NATIVE_INT, space_id, H5P_DEFAULT); + CHECK(attr_id, FAIL, "H5Acreate1"); + ret = H5close(); + CHECK(ret, FAIL, "H5close"); + file_id = H5Fopen(MISC31_FILE, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(file_id, FAIL, "H5Fopen"); + dset_id = H5Dopen1(file_id, MISC31_DSETNAME); + CHECK(dset_id, FAIL, "H5Dopen1"); + space_id = H5Screate(H5S_SCALAR); + CHECK(space_id, FAIL, "H5Screate"); + attr_id = H5Acreate1(dset_id, MISC31_ATTRNAME2, H5T_NATIVE_INT, space_id, H5P_DEFAULT); + CHECK(attr_id, FAIL, "H5Acreate1"); + + /* Test group package */ + group_id = H5Gcreate1(file_id, MISC31_GROUPNAME, 0); + CHECK(group_id, FAIL, "H5Gcreate1"); + ret = H5close(); + CHECK(ret, FAIL, "H5close"); + file_id = H5Fopen(MISC31_FILE, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(file_id, FAIL, "H5Fopen"); + group_id = H5Gopen1(file_id, MISC31_GROUPNAME); + CHECK(group_id, FAIL, "H5Gopen1"); + + /* Test property list package */ + ret = H5Pregister1(H5P_OBJECT_CREATE, MISC31_PROPNAME, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK(ret, FAIL, "H5Pregister1"); + ret = H5close(); + CHECK(ret, FAIL, "H5close"); + ret = H5Pregister1(H5P_OBJECT_CREATE, MISC31_PROPNAME, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + CHECK(ret, FAIL, "H5Pregister1"); + ret = H5close(); + CHECK(ret, FAIL, "H5close"); + + /* Test datatype package */ + file_id = H5Fopen(MISC31_FILE, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(file_id, FAIL, "H5Fopen"); + dtype_id = H5Tcopy(H5T_NATIVE_INT); + CHECK(dtype_id, FAIL, "H5Tcopy"); + ret = H5Tcommit1(file_id, MISC31_DTYPENAME, dtype_id); + CHECK(ret, FAIL, "H5Tcommit1"); + ret = H5close(); + CHECK(ret, FAIL, "H5close"); + file_id = H5Fopen(MISC31_FILE, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(file_id, FAIL, "H5Fopen"); + dtype_id = H5Topen1(file_id, MISC31_DTYPENAME); + CHECK(ret, FAIL, "H5Topen1"); + ret = H5Fclose(file_id); + CHECK(ret, FAIL, "H5Fclose"); + ret = H5Tclose(dtype_id); + CHECK(ret, FAIL, "H5Tclose"); + +#else /* H5_NO_DEPRECATED_SYMBOLS */ + /* Output message about test being skipped */ + MESSAGE(5, (" ...Skipped")); +#endif /* H5_NO_DEPRECATED_SYMBOLS */ +} /* end test_misc31() */ +#endif + +/**************************************************************** + * + * test_misc32(): Simple test of filter memory allocation + * functions. + * + ***************************************************************/ +static void +test_misc32(void) +{ + void *buffer; + void *resized; + size_t size; + + /* Output message about test being performed */ + MESSAGE(5, ("Edge case test of filter memory allocation functions\n")); + + /* Test that the filter memory allocation functions behave correctly + * at edge cases. + */ + + /* FREE */ + + /* Test freeing a NULL pointer. + * No real confirmation check here, but Valgrind will confirm no + * shenanigans. + */ + buffer = NULL; + H5free_memory(buffer); + + /* ALLOCATE */ + + /* Size zero returns NULL. + * Also checks that a size of zero and setting the buffer clear flag + * to TRUE can be used together. + * + * Note that we have asserts in the code, so only check when NDEBUG + * is defined. + */ +#ifdef NDEBUG + buffer = H5allocate_memory(0, FALSE); + CHECK_PTR_NULL(buffer, "H5allocate_memory"); /*BAD*/ + buffer = H5allocate_memory(0, TRUE); + CHECK_PTR_NULL(buffer, "H5allocate_memory"); /*BAD*/ +#endif /* NDEBUG */ + + /* RESIZE */ + + /* Size zero returns NULL. Valgrind will confirm buffer is freed. */ + size = 1024; + buffer = H5allocate_memory(size, TRUE); + resized = H5resize_memory(buffer, 0); + CHECK_PTR_NULL(resized, "H5resize_memory"); + + /* NULL input pointer returns new buffer */ + resized = H5resize_memory(NULL, 1024); + CHECK_PTR(resized, "H5resize_memory"); + H5free_memory(resized); + + /* NULL input pointer and size zero returns NULL */ +#ifdef NDEBUG + resized = H5resize_memory(NULL, 0); + CHECK_PTR_NULL(resized, "H5resize_memory"); /*BAD*/ +#endif /* NDEBUG */ + +} /* end test_misc32() */ + +/**************************************************************** +** +** test_misc33(): Test for H5FFV-10216 +** --verify that H5HL_offset_into() returns error if the +** input parameter "offset" exceeds heap data block size. +** --case (1), (2), (3) are scenarios that will traverse to the +** the 3 locations in the file having bad offset values to +** the heap. (See description in gen_bad_offset.c) +** +****************************************************************/ +#if 0 +static void +test_misc33(void) +{ + hid_t fid = -1; /* File ID */ + const char *testfile = H5_get_srcdir_filename(MISC33_FILE); /* Corrected test file name */ + H5O_info2_t oinfo; /* Structure for object metadata information */ + hbool_t driver_is_default_compatible; + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing that bad offset into the heap returns error")); + + ret = h5_driver_is_default_vfd_compatible(H5P_DEFAULT, &driver_is_default_compatible); + CHECK(ret, FAIL, "h5_driver_is_default_vfd_compatible"); + + if (!driver_is_default_compatible) { + HDprintf("-- SKIPPED --\n"); + return; + } + + /* Open the test file */ + fid = H5Fopen(testfile, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* Case (1) */ + H5E_BEGIN_TRY + { + ret = H5Oget_info_by_name3(fid, "/soft_two", &oinfo, H5O_INFO_BASIC, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Oget_info_by_name3"); + + /* Case (2) */ + H5E_BEGIN_TRY + { + ret = H5Oget_info_by_name3(fid, "/dsetA", &oinfo, H5O_INFO_BASIC, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Oget_info_by_name3"); + + /* Case (3) */ + H5E_BEGIN_TRY + { + ret = H5Oget_info_by_name3(fid, "/soft_one", &oinfo, H5O_INFO_BASIC, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Oget_info_by_name3"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(fid, FAIL, "H5Fclose"); + +} /* end test_misc33() */ +#endif + +/**************************************************************** +** +** test_misc34(): Ensure zero-size memory allocations work +** +****************************************************************/ +#if 0 +static void +test_misc34(void) +{ + void *mem = NULL; /* allocated buffer */ + char *dup = NULL; /* 'duplicated' string */ + size_t sz = 0; /* buffer size */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing O and NULL behavior in H5MM API calls")); + + /* H5MM_xfree(): Ensure that passing NULL is allowed and returns NULL */ + mem = H5MM_xfree(mem); + CHECK_PTR_NULL(mem, "H5MM_xfree"); + + /* H5MM_realloc(): Check behavior: + * + * H5MM_realloc(NULL, size) <==> H5MM_malloc(size) + * H5MM_realloc(ptr, 0) <==> H5MM_xfree(ptr) + * H5MM_realloc(NULL, 0) <==> NULL + */ + mem = H5MM_xfree(mem); + + sz = 1024; + mem = H5MM_realloc(mem, sz); + CHECK_PTR(mem, "H5MM_realloc (case 1)"); + /* Don't free mem here! */ + + sz = 0; + mem = H5MM_realloc(mem, sz); + CHECK_PTR_NULL(mem, "H5MM_realloc (case 2)"); + mem = H5MM_xfree(mem); + + mem = H5MM_realloc(mem, sz); + CHECK_PTR_NULL(mem, "H5MM_realloc (case 3)"); + mem = H5MM_xfree(mem); + + /* H5MM_xstrdup(): Ensure NULL returns NULL */ + dup = H5MM_xstrdup((const char *)mem); + CHECK_PTR_NULL(dup, "H5MM_xstrdup"); + dup = (char *)H5MM_xfree((void *)dup); + +} /* end test_misc34() */ + +/**************************************************************** +** +** test_misc35(): Check operation of free-list routines +** +****************************************************************/ +static void +test_misc35(void) +{ + hid_t sid = H5I_INVALID_HID; /* Dataspace ID */ + hsize_t dims[] = {MISC35_SPACE_DIM1, MISC35_SPACE_DIM2, MISC35_SPACE_DIM3}; /* Dataspace dims */ + hsize_t coord[MISC35_NPOINTS][MISC35_SPACE_RANK] = /* Coordinates for point selection */ + {{0, 10, 5}, {1, 2, 7}, {2, 4, 9}, {0, 6, 11}, {1, 8, 13}, + {2, 12, 0}, {0, 14, 2}, {1, 0, 4}, {2, 1, 6}, {0, 3, 8}}; + size_t reg_size_start; /* Initial amount of regular memory allocated */ + size_t arr_size_start; /* Initial amount of array memory allocated */ + size_t blk_size_start; /* Initial amount of block memory allocated */ + size_t fac_size_start; /* Initial amount of factory memory allocated */ + size_t reg_size_final; /* Final amount of regular memory allocated */ + size_t arr_size_final; /* Final amount of array memory allocated */ + size_t blk_size_final; /* Final amount of block memory allocated */ + size_t fac_size_final; /* Final amount of factory memory allocated */ + herr_t ret; /* Return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Free-list API calls")); + + /* Create dataspace */ + /* (Allocates array free-list nodes) */ + sid = H5Screate_simple(MISC35_SPACE_RANK, dims, NULL); + CHECK(sid, H5I_INVALID_HID, "H5Screate_simple"); + + /* Select sequence of ten points */ + ret = H5Sselect_elements(sid, H5S_SELECT_SET, (size_t)MISC35_NPOINTS, (const hsize_t *)coord); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Retrieve initial free list values */ + ret = H5get_free_list_sizes(®_size_start, &arr_size_start, &blk_size_start, &fac_size_start); + CHECK(ret, FAIL, "H5get_free_list_sizes"); + +#if !defined H5_NO_FREE_LISTS && !defined H5_USING_MEMCHECKER + /* All the free list values should be >0 */ + CHECK(reg_size_start, 0, "H5get_free_list_sizes"); + CHECK(arr_size_start, 0, "H5get_free_list_sizes"); + CHECK(blk_size_start, 0, "H5get_free_list_sizes"); + CHECK(fac_size_start, 0, "H5get_free_list_sizes"); +#else + /* All the values should be == 0 */ + VERIFY(reg_size_start, 0, "H5get_free_list_sizes"); + VERIFY(arr_size_start, 0, "H5get_free_list_sizes"); + VERIFY(blk_size_start, 0, "H5get_free_list_sizes"); + VERIFY(fac_size_start, 0, "H5get_free_list_sizes"); +#endif + + /* Garbage collect the free lists */ + ret = H5garbage_collect(); + CHECK(ret, FAIL, "H5garbage_collect"); + + /* Retrieve free list values again */ + ret = H5get_free_list_sizes(®_size_final, &arr_size_final, &blk_size_final, &fac_size_final); + CHECK(ret, FAIL, "H5get_free_list_sizes"); + + /* All the free list values should be <= previous values */ + if (reg_size_final > reg_size_start) + ERROR("reg_size_final > reg_size_start"); + if (arr_size_final > arr_size_start) + ERROR("arr_size_final > arr_size_start"); + if (blk_size_final > blk_size_start) + ERROR("blk_size_final > blk_size_start"); + if (fac_size_final > fac_size_start) + ERROR("fac_size_final > fac_size_start"); + +} /* end test_misc35() */ +#endif + +/* Context to pass to 'atclose' callbacks */ +static int test_misc36_context; + +/* 'atclose' callbacks for test_misc36 */ +static void +test_misc36_cb1(void *_ctx) +{ + int *ctx = (int *)_ctx; /* Set up context pointer */ + hbool_t is_terminating; /* Flag indicating the library is terminating */ + herr_t ret; /* Return value */ + + /* Check whether the library thinks it's terminating */ + is_terminating = FALSE; + ret = H5is_library_terminating(&is_terminating); + CHECK(ret, FAIL, "H5is_library_terminating"); + VERIFY(is_terminating, TRUE, "H5is_library_terminating"); + + /* Verify correct ordering for 'atclose' callbacks */ + if (0 != *ctx) + HDabort(); + + /* Update context value */ + *ctx = 1; +} + +static void +test_misc36_cb2(void *_ctx) +{ + int *ctx = (int *)_ctx; /* Set up context pointer */ + hbool_t is_terminating; /* Flag indicating the library is terminating */ + herr_t ret; /* Return value */ + + /* Check whether the library thinks it's terminating */ + is_terminating = FALSE; + ret = H5is_library_terminating(&is_terminating); + CHECK(ret, FAIL, "H5is_library_terminating"); + VERIFY(is_terminating, TRUE, "H5is_library_terminating"); + + /* Verify correct ordering for 'atclose' callbacks */ + if (1 != *ctx) + HDabort(); + + /* Update context value */ + *ctx = 2; +} + +/**************************************************************** +** +** test_misc36(): Exercise H5atclose and H5is_library_terminating +** +****************************************************************/ +static void +test_misc36(void) +{ + hbool_t is_terminating; /* Flag indicating the library is terminating */ + herr_t ret; /* Return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("H5atclose and H5is_library_terminating API calls")); + + /* Check whether the library thinks it's terminating */ + is_terminating = TRUE; + ret = H5is_library_terminating(&is_terminating); + CHECK(ret, FAIL, "H5is_library_terminating"); + VERIFY(is_terminating, FALSE, "H5is_library_terminating"); + + /* Shut the library down */ + test_misc36_context = 0; + H5close(); + + /* Check whether the library thinks it's terminating */ + is_terminating = TRUE; + ret = H5is_library_terminating(&is_terminating); + CHECK(ret, FAIL, "H5is_library_terminating"); + VERIFY(is_terminating, FALSE, "H5is_library_terminating"); + + /* Check the close context was not changed */ + VERIFY(test_misc36_context, 0, "H5atclose"); + + /* Restart the library */ + H5open(); + + /* Check whether the library thinks it's terminating */ + is_terminating = TRUE; + ret = H5is_library_terminating(&is_terminating); + CHECK(ret, FAIL, "H5is_library_terminating"); + VERIFY(is_terminating, FALSE, "H5is_library_terminating"); + + /* Register the 'atclose' callbacks */ + /* (Note that these will be called in reverse order, which is checked) */ + ret = H5atclose(&test_misc36_cb2, &test_misc36_context); + CHECK(ret, FAIL, "H5atclose"); + ret = H5atclose(&test_misc36_cb1, &test_misc36_context); + CHECK(ret, FAIL, "H5atclose"); + + /* Shut the library down */ + test_misc36_context = 0; + H5close(); + + /* Check the close context was changed correctly */ + VERIFY(test_misc36_context, 2, "H5atclose"); + + /* Restart the library */ + H5open(); + + /* Close the library again */ + test_misc36_context = 0; + H5close(); + + /* Check the close context was not changed */ + VERIFY(test_misc36_context, 0, "H5atclose"); +} /* end test_misc36() */ + +#if 0 +/**************************************************************** +** +** test_misc37(): +** Test for seg fault issue when closing the provided test file +** which has an illegal file size in its cache image. +** See HDFFV-11052/CVE-2020-10812 for details. +** +****************************************************************/ +static void +test_misc37(void) +{ + const char *testfile = H5_get_srcdir_filename(CVE_2020_10812_FILENAME); + hbool_t driver_is_default_compatible; + hid_t fid; + herr_t ret; + + /* Output message about test being performed */ + MESSAGE(5, ("Fix for HDFFV-11052/CVE-2020-10812")); + + ret = h5_driver_is_default_vfd_compatible(H5P_DEFAULT, &driver_is_default_compatible); + CHECK(ret, FAIL, "h5_driver_is_default_vfd_compatible"); + + if (!driver_is_default_compatible) { + HDprintf("-- SKIPPED --\n"); + return; + } + + fid = H5Fopen(testfile, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* This should fail due to the illegal file size. + It should fail gracefully and not seg fault */ + H5E_BEGIN_TRY + { + ret = H5Fclose(fid); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Fclose"); + +} /* end test_misc37() */ +#endif + +/**************************************************************** +** +** test_misc(): Main misc. test routine. +** +****************************************************************/ +void +test_misc(void) +{ + hbool_t default_driver = h5_using_default_driver(NULL); + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Miscellaneous Routines\n")); + + test_misc1(); /* Test unlinking a dataset & immediately re-using name */ + test_misc2(); /* Test storing a VL-derived datatype in two different files */ + test_misc3(); /* Test reading from chunked dataset with non-zero fill value */ + test_misc4(); /* Test retrieving the fileno for various objects with H5Oget_info() */ + test_misc5(); /* Test several level deep nested compound & VL datatypes */ + test_misc6(); /* Test object header continuation code */ +#if 0 + test_misc7(); /* Test for sensible datatypes stored on disk */ + test_misc8(); /* Test storage sizes of various types of dataset storage */ +#endif + test_misc9(); /* Test for opening (not creating) core files */ +#if 0 + test_misc10(); /* Test for using dataset creation property lists from old files */ +#endif + + if (default_driver) { + test_misc11(); /* Test for all properties of a file creation property list being stored */ + } + + test_misc12(); /* Test VL-strings in chunked datasets operating correctly */ +#if 0 + if (default_driver) { + test_misc13(); /* Test that a user block can be insert in front of file contents */ + } +#endif + test_misc14(); /* Test that deleted dataset's data is removed from sieve buffer correctly */ + test_misc15(); /* Test that checking a file's access property list more than once works */ + test_misc16(); /* Test array of fixed-length string */ + test_misc17(); /* Test array of ASCII character */ + test_misc18(); /* Test new object header information in H5O_info2_t struct */ + test_misc19(); /* Test incrementing & decrementing ref count on IDs */ +#if 0 + test_misc20(); /* Test problems with truncated dimensions in version 2 of storage layout message */ +#endif +#if defined(H5_HAVE_FILTER_SZIP) && !defined(H5_API_TEST_NO_FILTERS) + test_misc21(); /* Test that "late" allocation time is treated the same as "incremental", for chunked + datasets w/a filters */ + test_misc22(); /* check szip bits per pixel */ +#endif /* H5_HAVE_FILTER_SZIP */ + test_misc23(); /* Test intermediate group creation */ + test_misc24(); /* Test inappropriate API opens of objects */ + test_misc25a(); /* Exercise null object header message merge bug */ +#if 0 + test_misc25b(); /* Exercise null object header message merge bug on existing file */ +#endif + test_misc25c(); /* Exercise another null object header message merge bug */ + test_misc26(); /* Test closing property lists with long filter pipelines */ +#if 0 + test_misc27(); /* Test opening file with object that has bad # of object header messages */ +#endif + test_misc28(); /* Test that chunks are cached appropriately */ +#if 0 + test_misc29(); /* Test that speculative metadata reads are handled correctly */ + test_misc30(); /* Exercise local heap loading bug where free lists were getting dropped */ + + if (default_driver) { + test_misc31(); /* Test Reentering library through deprecated routines after H5close() */ + } +#endif + test_misc32(); /* Test filter memory allocation functions */ +#if 0 + test_misc33(); /* Test to verify that H5HL_offset_into() returns error if offset exceeds heap block */ + test_misc34(); /* Test behavior of 0 and NULL in H5MM API calls */ + test_misc35(); /* Test behavior of free-list & allocation statistics API calls */ +#endif + test_misc36(); /* Exercise H5atclose and H5is_library_terminating */ +#if 0 + test_misc37(); /* Test for seg fault failure at file close */ +#endif +} /* test_misc() */ + +/*------------------------------------------------------------------------- + * Function: cleanup_misc + * + * Purpose: Cleanup temporary test files + * + * Return: none + * + * Programmer: Albert Cheng + * July 2, 1998 + *------------------------------------------------------------------------- + */ +void +cleanup_misc(void) +{ + H5Fdelete(MISC1_FILE, H5P_DEFAULT); + H5Fdelete(MISC2_FILE_1, H5P_DEFAULT); + H5Fdelete(MISC2_FILE_2, H5P_DEFAULT); + H5Fdelete(MISC3_FILE, H5P_DEFAULT); + H5Fdelete(MISC4_FILE_1, H5P_DEFAULT); + H5Fdelete(MISC4_FILE_2, H5P_DEFAULT); + H5Fdelete(MISC5_FILE, H5P_DEFAULT); + H5Fdelete(MISC6_FILE, H5P_DEFAULT); + H5Fdelete(MISC7_FILE, H5P_DEFAULT); + H5Fdelete(MISC8_FILE, H5P_DEFAULT); + H5Fdelete(MISC9_FILE, H5P_DEFAULT); + H5Fdelete(MISC10_FILE_NEW, H5P_DEFAULT); + H5Fdelete(MISC11_FILE, H5P_DEFAULT); + H5Fdelete(MISC12_FILE, H5P_DEFAULT); + H5Fdelete(MISC13_FILE_1, H5P_DEFAULT); + H5Fdelete(MISC13_FILE_2, H5P_DEFAULT); + H5Fdelete(MISC14_FILE, H5P_DEFAULT); + H5Fdelete(MISC15_FILE, H5P_DEFAULT); + H5Fdelete(MISC16_FILE, H5P_DEFAULT); + H5Fdelete(MISC17_FILE, H5P_DEFAULT); + H5Fdelete(MISC18_FILE, H5P_DEFAULT); + H5Fdelete(MISC19_FILE, H5P_DEFAULT); + H5Fdelete(MISC20_FILE, H5P_DEFAULT); +#if defined(H5_HAVE_FILTER_SZIP) && !defined(H5_API_TEST_NO_FILTERS) + H5Fdelete(MISC21_FILE, H5P_DEFAULT); + H5Fdelete(MISC22_FILE, H5P_DEFAULT); +#endif /* H5_HAVE_FILTER_SZIP */ + H5Fdelete(MISC23_FILE, H5P_DEFAULT); + H5Fdelete(MISC24_FILE, H5P_DEFAULT); + H5Fdelete(MISC25A_FILE, H5P_DEFAULT); + H5Fdelete(MISC25C_FILE, H5P_DEFAULT); + H5Fdelete(MISC26_FILE, H5P_DEFAULT); + H5Fdelete(MISC28_FILE, H5P_DEFAULT); + H5Fdelete(MISC29_COPY_FILE, H5P_DEFAULT); + H5Fdelete(MISC30_FILE, H5P_DEFAULT); +#ifndef H5_NO_DEPRECATED_SYMBOLS + H5Fdelete(MISC31_FILE, H5P_DEFAULT); +#endif /* H5_NO_DEPRECATED_SYMBOLS */ +} /* end cleanup_misc() */ diff --git a/test/API/trefer.c b/test/API/trefer.c new file mode 100644 index 0000000..af0b11b --- /dev/null +++ b/test/API/trefer.c @@ -0,0 +1,3641 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*********************************************************** + * + * Test program: trefer + * + * Test the Reference functionality + * + *************************************************************/ + +#include "testhdf5.h" + +#define FILE_REF_PARAM "trefer_param.h5" +#define FILE_REF_OBJ "trefer_obj.h5" +#define FILE_REF_VL_OBJ "trefer_vl_obj.h5" +#define FILE_REF_CMPND_OBJ "trefer_cmpnd_obj.h5" +#define FILE_REF_REG "trefer_reg.h5" +#define FILE_REF_REG_1D "trefer_reg_1d.h5" +#define FILE_REF_OBJ_DEL "trefer_obj_del.h5" +#define FILE_REF_GRP "trefer_grp.h5" +#define FILE_REF_ATTR "trefer_attr.h5" +#define FILE_REF_EXT1 "trefer_ext1.h5" +#define FILE_REF_EXT2 "trefer_ext2.h5" +#define FILE_REF_COMPAT "trefer_compat.h5" + +/* 1-D dataset with fixed dimensions */ +#define SPACE1_RANK 1 +#define SPACE1_DIM1 4 + +/* 2-D dataset with fixed dimensions */ +#define SPACE2_RANK 2 +#define SPACE2_DIM1 10 +#define SPACE2_DIM2 10 + +/* Larger 1-D dataset with fixed dimensions */ +#define SPACE3_RANK 1 +#define SPACE3_DIM1 100 + +/* Element selection information */ +#define POINT1_NPOINTS 10 + +/* Compound datatype */ +typedef struct s1_t { + unsigned int a; + unsigned int b; + float c; +} s1_t; + +/* Compound datatype with reference */ +typedef struct s2_t { + H5R_ref_t ref0; /* reference */ + H5R_ref_t ref1; /* reference */ + H5R_ref_t ref2; /* reference */ + H5R_ref_t ref3; /* reference */ + unsigned int dim_idx; /* dimension index of the dataset */ +} s2_t; + +#define GROUPNAME "/group" +#define GROUPNAME2 "group2" +#define GROUPNAME3 "group3" +#define DSETNAME "/dset" +#define DSETNAME2 "dset2" +#define NAME_SIZE 16 + +#define MAX_ITER_CREATE 1000 +#define MAX_ITER_WRITE MAX_ITER_CREATE +#define MAX_ITER_READ MAX_ITER_CREATE + +/**************************************************************** +** +** test_reference_params(): Test basic H5R (reference) parameters +** for correct processing +** +****************************************************************/ +static void +test_reference_params(void) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset, /* Dataset ID */ + dset2; /* Dereferenced dataset ID */ + hid_t group; /* Group ID */ + hid_t attr; /* Attribute ID */ + hid_t sid1; /* Dataspace ID */ + hid_t tid1; /* Datatype ID */ + hid_t aapl_id; /* Attribute access property list */ + hid_t dapl_id; /* Dataset access property list */ + hsize_t dims1[] = {SPACE1_DIM1}; + H5R_ref_t *wbuf, /* buffer to write to disk */ + *rbuf, /* buffer read from disk */ + *tbuf; /* temp. buffer read from disk */ + unsigned *obuf; + H5R_type_t type; /* Reference type */ + unsigned int i; /* Counters */ +#if 0 + const char *write_comment = "Foo!"; /* Comments for group */ +#endif + hid_t ret_id; /* Generic hid_t return value */ + ssize_t name_size; /* Size of reference name */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Reference Parameters\n")); + + /* Allocate write & read buffers */ + wbuf = (H5R_ref_t *)HDcalloc(sizeof(H5R_ref_t), SPACE1_DIM1); + rbuf = (H5R_ref_t *)HDcalloc(sizeof(H5R_ref_t), SPACE1_DIM1); + tbuf = (H5R_ref_t *)HDcalloc(sizeof(H5R_ref_t), SPACE1_DIM1); + obuf = HDcalloc(sizeof(unsigned), SPACE1_DIM1); + + for (i = 0; i < SPACE1_DIM1; i++) + obuf[i] = i * 3; + + /* Create file */ + fid1 = H5Fcreate(FILE_REF_PARAM, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, H5I_INVALID_HID, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, H5I_INVALID_HID, "H5Screate_simple"); + + /* Create attribute access property list */ + aapl_id = H5Pcreate(H5P_ATTRIBUTE_ACCESS); + CHECK(aapl_id, H5I_INVALID_HID, "H5Pcreate"); + + /* Create dataset access property list */ + dapl_id = H5Pcreate(H5P_DATASET_ACCESS); + CHECK(dapl_id, H5I_INVALID_HID, "H5Pcreate"); + + /* Create a group */ + group = H5Gcreate2(fid1, "Group1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(group, H5I_INVALID_HID, "H5Gcreate2"); +#if 0 + /* Set group's comment */ + ret = H5Oset_comment(group, write_comment); + CHECK(ret, FAIL, "H5Oset_comment"); +#endif + /* Create a dataset (inside Group1) */ + dataset = H5Dcreate2(group, "Dataset1", H5T_NATIVE_UINT, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_UINT, H5S_ALL, H5S_ALL, H5P_DEFAULT, obuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Create another dataset (inside Group1) */ + dataset = H5Dcreate2(group, "Dataset2", H5T_NATIVE_UCHAR, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dcreate2"); + + /* Create an attribute for the dataset */ + attr = H5Acreate2(dataset, "Attr", H5T_NATIVE_UINT, sid1, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, H5I_INVALID_HID, "H5Acreate2"); + + /* Write attribute to disk */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, obuf); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Create a datatype to refer to */ + tid1 = H5Tcreate(H5T_COMPOUND, sizeof(s1_t)); + CHECK(tid1, H5I_INVALID_HID, "H5Tcreate"); + + /* Insert fields */ + ret = H5Tinsert(tid1, "a", HOFFSET(s1_t, a), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(tid1, "b", HOFFSET(s1_t, b), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(tid1, "c", HOFFSET(s1_t, c), H5T_NATIVE_FLOAT); + CHECK(ret, FAIL, "H5Tinsert"); + + /* Save datatype for later */ + ret = H5Tcommit2(group, "Datatype1", tid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close group */ + ret = H5Gclose(group); + CHECK(ret, FAIL, "H5Gclose"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, "Dataset3", H5T_STD_REF, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, H5I_INVALID_HID, "H5Dcreate2"); + + /* Test parameters to H5Rcreate_object */ + H5E_BEGIN_TRY + { + ret = H5Rcreate_object(fid1, "/Group1/Dataset1", H5P_DEFAULT, NULL); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Rcreate_object ref"); + H5E_BEGIN_TRY + { + ret = H5Rcreate_object(H5I_INVALID_HID, "/Group1/Dataset1", H5P_DEFAULT, &wbuf[0]); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Rcreate_object loc_id"); + H5E_BEGIN_TRY + { + ret = H5Rcreate_object(fid1, NULL, H5P_DEFAULT, &wbuf[0]); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Rcreate_object name"); + H5E_BEGIN_TRY + { + ret = H5Rcreate_object(fid1, "", H5P_DEFAULT, &wbuf[0]); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Rcreate_object null name"); + + /* Test parameters to H5Rcreate_region */ + H5E_BEGIN_TRY + { + ret = H5Rcreate_region(fid1, "/Group1/Dataset1", sid1, H5P_DEFAULT, NULL); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Rcreate_region ref"); + H5E_BEGIN_TRY + { + ret = H5Rcreate_region(H5I_INVALID_HID, "/Group1/Dataset1", sid1, H5P_DEFAULT, &wbuf[0]); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Rcreate_region loc_id"); + H5E_BEGIN_TRY + { + ret = H5Rcreate_region(fid1, NULL, sid1, H5P_DEFAULT, &wbuf[0]); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Rcreate_region name"); + H5E_BEGIN_TRY + { + ret = H5Rcreate_region(fid1, "/Group1/Dataset1", H5I_INVALID_HID, H5P_DEFAULT, &wbuf[0]); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Rcreate_region dataspace"); + + /* Test parameters to H5Rcreate_attr */ + H5E_BEGIN_TRY + { + ret = H5Rcreate_attr(fid1, "/Group1/Dataset2", "Attr", H5P_DEFAULT, NULL); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Rcreate_attr ref"); + H5E_BEGIN_TRY + { + ret = H5Rcreate_attr(H5I_INVALID_HID, "/Group1/Dataset2", "Attr", H5P_DEFAULT, &wbuf[0]); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Rcreate_attr loc_id"); + H5E_BEGIN_TRY + { + ret = H5Rcreate_attr(fid1, NULL, "Attr", H5P_DEFAULT, &wbuf[0]); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Rcreate_attr name"); + H5E_BEGIN_TRY + { + ret = H5Rcreate_attr(fid1, "/Group1/Dataset2", NULL, H5P_DEFAULT, &wbuf[0]); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Rcreate_attr attr_name"); + + /* Test parameters to H5Rdestroy */ + H5E_BEGIN_TRY + { + ret = H5Rdestroy(NULL); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Rdestroy"); + + /* Test parameters to H5Rget_type */ + H5E_BEGIN_TRY + { + type = H5Rget_type(NULL); + } + H5E_END_TRY; + VERIFY(type, H5R_BADTYPE, "H5Rget_type ref"); + + /* Test parameters to H5Requal */ + H5E_BEGIN_TRY + { + ret = H5Requal(NULL, &rbuf[0]); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Requal ref1"); + H5E_BEGIN_TRY + { + ret = H5Requal(&rbuf[0], NULL); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Requal ref2"); + + /* Test parameters to H5Rcopy */ + H5E_BEGIN_TRY + { + ret = H5Rcopy(NULL, &wbuf[0]); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Rcopy src_ref"); + H5E_BEGIN_TRY + { + ret = H5Rcopy(&rbuf[0], NULL); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Rcopy dest_ref"); + + /* Test parameters to H5Ropen_object */ + H5E_BEGIN_TRY + { + dset2 = H5Ropen_object(&rbuf[0], H5I_INVALID_HID, H5I_INVALID_HID); + } + H5E_END_TRY; + VERIFY(dset2, H5I_INVALID_HID, "H5Ropen_object oapl_id"); + H5E_BEGIN_TRY + { + dset2 = H5Ropen_object(NULL, H5P_DEFAULT, dapl_id); + } + H5E_END_TRY; + VERIFY(dset2, H5I_INVALID_HID, "H5Ropen_object ref"); + + /* Test parameters to H5Ropen_region */ + H5E_BEGIN_TRY + { + ret_id = H5Ropen_region(NULL, H5I_INVALID_HID, H5I_INVALID_HID); + } + H5E_END_TRY; + VERIFY(ret_id, H5I_INVALID_HID, "H5Ropen_region ref"); + + /* Test parameters to H5Ropen_attr */ + H5E_BEGIN_TRY + { + ret_id = H5Ropen_attr(NULL, H5P_DEFAULT, aapl_id); + } + H5E_END_TRY; + VERIFY(ret_id, H5I_INVALID_HID, "H5Ropen_attr ref"); + + /* Test parameters to H5Rget_obj_type3 */ + H5E_BEGIN_TRY + { + ret = H5Rget_obj_type3(NULL, H5P_DEFAULT, NULL); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Rget_obj_type3 ref"); + + /* Test parameters to H5Rget_file_name */ + H5E_BEGIN_TRY + { + name_size = H5Rget_file_name(NULL, NULL, 0); + } + H5E_END_TRY; + VERIFY(name_size, (-1), "H5Rget_file_name ref"); + + /* Test parameters to H5Rget_obj_name */ + H5E_BEGIN_TRY + { + name_size = H5Rget_obj_name(NULL, H5P_DEFAULT, NULL, 0); + } + H5E_END_TRY; + VERIFY(name_size, (-1), "H5Rget_obj_name ref"); + + /* Test parameters to H5Rget_attr_name */ + H5E_BEGIN_TRY + { + name_size = H5Rget_attr_name(NULL, NULL, 0); + } + H5E_END_TRY; + VERIFY(name_size, (-1), "H5Rget_attr_name ref"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close dataset access property list */ + ret = H5Pclose(dapl_id); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close attribute access property list */ + ret = H5Pclose(aapl_id); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free memory buffers */ + HDfree(wbuf); + HDfree(rbuf); + HDfree(tbuf); + HDfree(obuf); +} /* test_reference_params() */ + +/**************************************************************** +** +** test_reference_obj(): Test basic H5R (reference) object reference code. +** Tests references to various kinds of objects +** +****************************************************************/ +static void +test_reference_obj(void) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset, /* Dataset ID */ + dset2; /* Dereferenced dataset ID */ + hid_t group; /* Group ID */ + hid_t sid1; /* Dataspace ID */ + hid_t tid1; /* Datatype ID */ + hsize_t dims1[] = {SPACE1_DIM1}; + hid_t dapl_id; /* Dataset access property list */ + H5R_ref_t *wbuf, /* buffer to write to disk */ + *rbuf; /* buffer read from disk */ + unsigned *ibuf, *obuf; + unsigned i, j; /* Counters */ + H5O_type_t obj_type; /* Object type */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Object Reference Functions\n")); + + /* Allocate write & read buffers */ + wbuf = HDcalloc(sizeof(H5R_ref_t), SPACE1_DIM1); + rbuf = HDcalloc(sizeof(H5R_ref_t), SPACE1_DIM1); + ibuf = HDcalloc(sizeof(unsigned), SPACE1_DIM1); + obuf = HDcalloc(sizeof(unsigned), SPACE1_DIM1); + + for (i = 0; i < SPACE1_DIM1; i++) + obuf[i] = i * 3; + + /* Create file */ + fid1 = H5Fcreate(FILE_REF_OBJ, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, H5I_INVALID_HID, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, H5I_INVALID_HID, "H5Screate_simple"); + + /* Create dataset access property list */ + dapl_id = H5Pcreate(H5P_DATASET_ACCESS); + CHECK(dapl_id, H5I_INVALID_HID, "H5Pcreate"); + + /* Create a group */ + group = H5Gcreate2(fid1, "Group1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(group, H5I_INVALID_HID, "H5Gcreate2"); + + /* Create a dataset (inside Group1) */ + dataset = H5Dcreate2(group, "Dataset1", H5T_NATIVE_UINT, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_UINT, H5S_ALL, H5S_ALL, H5P_DEFAULT, obuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Create another dataset (inside Group1) */ + dataset = H5Dcreate2(group, "Dataset2", H5T_NATIVE_UCHAR, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Create a datatype to refer to */ + tid1 = H5Tcreate(H5T_COMPOUND, sizeof(s1_t)); + CHECK(tid1, H5I_INVALID_HID, "H5Tcreate"); + + /* Insert fields */ + ret = H5Tinsert(tid1, "a", HOFFSET(s1_t, a), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(tid1, "b", HOFFSET(s1_t, b), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(tid1, "c", HOFFSET(s1_t, c), H5T_NATIVE_FLOAT); + CHECK(ret, FAIL, "H5Tinsert"); + + /* Save datatype for later */ + ret = H5Tcommit2(group, "Datatype1", tid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close group */ + ret = H5Gclose(group); + CHECK(ret, FAIL, "H5Gclose"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, "Dataset3", H5T_STD_REF, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dcreate2"); + + /* Create reference to dataset */ + ret = H5Rcreate_object(fid1, "/Group1/Dataset1", H5P_DEFAULT, &wbuf[0]); + CHECK(ret, FAIL, "H5Rcreate_object"); + ret = H5Rget_obj_type3(&wbuf[0], H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_DATASET, "H5Rget_obj_type3"); + + /* Create reference to dataset */ + ret = H5Rcreate_object(fid1, "/Group1/Dataset2", H5P_DEFAULT, &wbuf[1]); + CHECK(ret, FAIL, "H5Rcreate_object"); + ret = H5Rget_obj_type3(&wbuf[1], H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_DATASET, "H5Rget_obj_type3"); + + /* Create reference to group */ + ret = H5Rcreate_object(fid1, "/Group1", H5P_DEFAULT, &wbuf[2]); + CHECK(ret, FAIL, "H5Rcreate_object"); + ret = H5Rget_obj_type3(&wbuf[2], H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_GROUP, "H5Rget_obj_type3"); + + /* Create reference to named datatype */ + ret = H5Rcreate_object(fid1, "/Group1/Datatype1", H5P_DEFAULT, &wbuf[3]); + CHECK(ret, FAIL, "H5Rcreate_object"); + ret = H5Rget_obj_type3(&wbuf[3], H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_NAMED_DATATYPE, "H5Rget_obj_type3"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open the file */ + fid1 = H5Fopen(FILE_REF_OBJ, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid1, H5I_INVALID_HID, "H5Fopen"); + + /* Open the dataset */ + dataset = H5Dopen2(fid1, "/Dataset3", H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dopen2"); + + /* Read selection from disk */ + ret = H5Dread(dataset, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Open dataset object */ + dset2 = H5Ropen_object(&rbuf[0], H5P_DEFAULT, dapl_id); + CHECK(dset2, H5I_INVALID_HID, "H5Ropen_object"); + + /* Check information in referenced dataset */ + sid1 = H5Dget_space(dset2); + CHECK(sid1, H5I_INVALID_HID, "H5Dget_space"); + + ret = (int)H5Sget_simple_extent_npoints(sid1); + VERIFY(ret, SPACE1_DIM1, "H5Sget_simple_extent_npoints"); + + /* Read from disk */ + ret = H5Dread(dset2, H5T_NATIVE_UINT, H5S_ALL, H5S_ALL, H5P_DEFAULT, ibuf); + CHECK(ret, FAIL, "H5Dread"); + + for (i = 0; i < SPACE1_DIM1; i++) + VERIFY(ibuf[i], i * 3, "Data"); + + /* Close dereferenced Dataset */ + ret = H5Dclose(dset2); + CHECK(ret, FAIL, "H5Dclose"); + + /* Open group object. GAPL isn't supported yet. But it's harmless to pass in */ + group = H5Ropen_object(&rbuf[2], H5P_DEFAULT, H5P_DEFAULT); + CHECK(group, H5I_INVALID_HID, "H5Ropen_object"); + + /* Close group */ + ret = H5Gclose(group); + CHECK(ret, FAIL, "H5Gclose"); + + /* Open datatype object. TAPL isn't supported yet. But it's harmless to pass in */ + tid1 = H5Ropen_object(&rbuf[3], H5P_DEFAULT, H5P_DEFAULT); + CHECK(tid1, H5I_INVALID_HID, "H5Ropen_object"); + + /* Verify correct datatype */ + { + H5T_class_t tclass; + + tclass = H5Tget_class(tid1); + VERIFY(tclass, H5T_COMPOUND, "H5Tget_class"); + + ret = H5Tget_nmembers(tid1); + VERIFY(ret, 3, "H5Tget_nmembers"); + } + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close dataset access property list */ + ret = H5Pclose(dapl_id); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Destroy references */ + for (j = 0; j < SPACE1_DIM1; j++) { + ret = H5Rdestroy(&wbuf[j]); + CHECK(ret, FAIL, "H5Rdestroy"); + ret = H5Rdestroy(&rbuf[j]); + CHECK(ret, FAIL, "H5Rdestroy"); + } + + /* Free memory buffers */ + HDfree(wbuf); + HDfree(rbuf); + HDfree(ibuf); + HDfree(obuf); +} /* test_reference_obj() */ + +/**************************************************************** +** +** test_reference_vlen_obj(): Test basic H5R (reference) object reference +** within a vlen type. +** Tests references to various kinds of objects +** +****************************************************************/ +static void +test_reference_vlen_obj(void) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset, /* Dataset ID */ + dset2; /* Dereferenced dataset ID */ + hid_t group; /* Group ID */ + hid_t sid1; /* Dataspace ID */ + hid_t tid1; /* Datatype ID */ + hsize_t dims1[] = {SPACE1_DIM1}; + hsize_t vl_dims[] = {1}; + hid_t dapl_id; /* Dataset access property list */ + H5R_ref_t *wbuf, /* buffer to write to disk */ + *rbuf = NULL; /* buffer read from disk */ + unsigned *ibuf, *obuf; + unsigned i, j; /* Counters */ + H5O_type_t obj_type; /* Object type */ + herr_t ret; /* Generic return value */ + hvl_t vl_wbuf = {0, NULL}, vl_rbuf = {0, NULL}; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Object Reference Functions within VLEN type\n")); + + /* Allocate write & read buffers */ + wbuf = HDcalloc(sizeof(H5R_ref_t), SPACE1_DIM1); + ibuf = HDcalloc(sizeof(unsigned), SPACE1_DIM1); + obuf = HDcalloc(sizeof(unsigned), SPACE1_DIM1); + + for (i = 0; i < SPACE1_DIM1; i++) + obuf[i] = i * 3; + + /* Create file */ + fid1 = H5Fcreate(FILE_REF_VL_OBJ, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, H5I_INVALID_HID, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, H5I_INVALID_HID, "H5Screate_simple"); + + /* Create dataset access property list */ + dapl_id = H5Pcreate(H5P_DATASET_ACCESS); + CHECK(dapl_id, H5I_INVALID_HID, "H5Pcreate"); + + /* Create a group */ + group = H5Gcreate2(fid1, "Group1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(group, H5I_INVALID_HID, "H5Gcreate2"); + + /* Create a dataset (inside Group1) */ + dataset = H5Dcreate2(group, "Dataset1", H5T_NATIVE_UINT, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_UINT, H5S_ALL, H5S_ALL, H5P_DEFAULT, obuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Create another dataset (inside Group1) */ + dataset = H5Dcreate2(group, "Dataset2", H5T_NATIVE_UCHAR, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Create a datatype to refer to */ + tid1 = H5Tcreate(H5T_COMPOUND, sizeof(s1_t)); + CHECK(tid1, H5I_INVALID_HID, "H5Tcreate"); + + /* Insert fields */ + ret = H5Tinsert(tid1, "a", HOFFSET(s1_t, a), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(tid1, "b", HOFFSET(s1_t, b), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(tid1, "c", HOFFSET(s1_t, c), H5T_NATIVE_FLOAT); + CHECK(ret, FAIL, "H5Tinsert"); + + /* Save datatype for later */ + ret = H5Tcommit2(group, "Datatype1", tid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close group */ + ret = H5Gclose(group); + CHECK(ret, FAIL, "H5Gclose"); + + /* Create vlen type */ + tid1 = H5Tvlen_create(H5T_STD_REF); + CHECK(tid1, H5I_INVALID_HID, "H5Tvlen_create"); + + /* Create dataspace for datasets */ + sid1 = H5Screate_simple(SPACE1_RANK, vl_dims, NULL); + CHECK(sid1, H5I_INVALID_HID, "H5Screate_simple"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, "Dataset3", tid1, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dcreate2"); + + /* Create reference to dataset */ + ret = H5Rcreate_object(fid1, "/Group1/Dataset1", H5P_DEFAULT, &wbuf[0]); + CHECK(ret, FAIL, "H5Rcreate_object"); + ret = H5Rget_obj_type3(&wbuf[0], H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_DATASET, "H5Rget_obj_type3"); + + /* Create reference to dataset */ + ret = H5Rcreate_object(fid1, "/Group1/Dataset2", H5P_DEFAULT, &wbuf[1]); + CHECK(ret, FAIL, "H5Rcreate_object"); + ret = H5Rget_obj_type3(&wbuf[1], H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_DATASET, "H5Rget_obj_type3"); + + /* Create reference to group */ + ret = H5Rcreate_object(fid1, "/Group1", H5P_DEFAULT, &wbuf[2]); + CHECK(ret, FAIL, "H5Rcreate_object"); + ret = H5Rget_obj_type3(&wbuf[2], H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_GROUP, "H5Rget_obj_type3"); + + /* Create reference to named datatype */ + ret = H5Rcreate_object(fid1, "/Group1/Datatype1", H5P_DEFAULT, &wbuf[3]); + CHECK(ret, FAIL, "H5Rcreate_object"); + ret = H5Rget_obj_type3(&wbuf[3], H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_NAMED_DATATYPE, "H5Rget_obj_type3"); + + /* Store references into vlen */ + vl_wbuf.len = SPACE1_DIM1; + vl_wbuf.p = wbuf; + + /* Write selection to disk */ + ret = H5Dwrite(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, &vl_wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open the file */ + fid1 = H5Fopen(FILE_REF_VL_OBJ, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid1, H5I_INVALID_HID, "H5Fopen"); + + /* Open the dataset */ + dataset = H5Dopen2(fid1, "/Dataset3", H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dopen2"); + + tid1 = H5Dget_type(dataset); + CHECK(tid1, H5I_INVALID_HID, "H5Dget_type"); + + /* Read selection from disk */ + ret = H5Dread(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, &vl_rbuf); + CHECK(ret, FAIL, "H5Dread"); + + VERIFY(vl_rbuf.len, SPACE1_DIM1, "H5Dread"); + rbuf = vl_rbuf.p; + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Open dataset object */ + dset2 = H5Ropen_object(&rbuf[0], H5P_DEFAULT, dapl_id); + CHECK(dset2, H5I_INVALID_HID, "H5Ropen_object"); + + /* Check information in referenced dataset */ + sid1 = H5Dget_space(dset2); + CHECK(sid1, H5I_INVALID_HID, "H5Dget_space"); + + ret = (int)H5Sget_simple_extent_npoints(sid1); + VERIFY(ret, SPACE1_DIM1, "H5Sget_simple_extent_npoints"); + + /* Read from disk */ + ret = H5Dread(dset2, H5T_NATIVE_UINT, H5S_ALL, H5S_ALL, H5P_DEFAULT, ibuf); + CHECK(ret, FAIL, "H5Dread"); + + for (i = 0; i < SPACE1_DIM1; i++) + VERIFY(ibuf[i], i * 3, "Data"); + + /* Close dereferenced Dataset */ + ret = H5Dclose(dset2); + CHECK(ret, FAIL, "H5Dclose"); + + /* Open group object. GAPL isn't supported yet. But it's harmless to pass in */ + group = H5Ropen_object(&rbuf[2], H5P_DEFAULT, H5P_DEFAULT); + CHECK(group, H5I_INVALID_HID, "H5Ropen_object"); + + /* Close group */ + ret = H5Gclose(group); + CHECK(ret, FAIL, "H5Gclose"); + + /* Open datatype object. TAPL isn't supported yet. But it's harmless to pass in */ + tid1 = H5Ropen_object(&rbuf[3], H5P_DEFAULT, H5P_DEFAULT); + CHECK(tid1, H5I_INVALID_HID, "H5Ropen_object"); + + /* Verify correct datatype */ + { + H5T_class_t tclass; + + tclass = H5Tget_class(tid1); + VERIFY(tclass, H5T_COMPOUND, "H5Tget_class"); + + ret = H5Tget_nmembers(tid1); + VERIFY(ret, 3, "H5Tget_nmembers"); + } + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close dataset access property list */ + ret = H5Pclose(dapl_id); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Destroy references */ + for (j = 0; j < SPACE1_DIM1; j++) { + ret = H5Rdestroy(&wbuf[j]); + CHECK(ret, FAIL, "H5Rdestroy"); + ret = H5Rdestroy(&rbuf[j]); + CHECK(ret, FAIL, "H5Rdestroy"); + } + + /* Free memory buffers */ + HDfree(wbuf); + HDfree(rbuf); + HDfree(ibuf); + HDfree(obuf); +} /* test_reference_vlen_obj() */ + +/**************************************************************** +** +** test_reference_cmpnd_obj(): Test basic H5R (reference) object reference +** within a compound type. +** Tests references to various kinds of objects +** +****************************************************************/ +static void +test_reference_cmpnd_obj(void) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset, /* Dataset ID */ + dset2; /* Dereferenced dataset ID */ + hid_t group; /* Group ID */ + hid_t sid1; /* Dataspace ID */ + hid_t tid1; /* Datatype ID */ + hsize_t dims1[] = {SPACE1_DIM1}; + hsize_t cmpnd_dims[] = {1}; + hid_t dapl_id; /* Dataset access property list */ + unsigned *ibuf, *obuf; + unsigned i; /* Counter */ + H5O_type_t obj_type; /* Object type */ + herr_t ret; /* Generic return value */ + s2_t cmpnd_wbuf, cmpnd_rbuf; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Object Reference Functions within compound type\n")); + + /* Allocate write & read buffers */ + ibuf = HDcalloc(sizeof(unsigned), SPACE1_DIM1); + obuf = HDcalloc(sizeof(unsigned), SPACE1_DIM1); + + for (i = 0; i < SPACE1_DIM1; i++) + obuf[i] = i * 3; + + /* Create file */ + fid1 = H5Fcreate(FILE_REF_CMPND_OBJ, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, H5I_INVALID_HID, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, H5I_INVALID_HID, "H5Screate_simple"); + + /* Create dataset access property list */ + dapl_id = H5Pcreate(H5P_DATASET_ACCESS); + CHECK(dapl_id, H5I_INVALID_HID, "H5Pcreate"); + + /* Create a group */ + group = H5Gcreate2(fid1, "Group1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(group, H5I_INVALID_HID, "H5Gcreate2"); + + /* Create a dataset (inside Group1) */ + dataset = H5Dcreate2(group, "Dataset1", H5T_NATIVE_UINT, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_UINT, H5S_ALL, H5S_ALL, H5P_DEFAULT, obuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Create another dataset (inside Group1) */ + dataset = H5Dcreate2(group, "Dataset2", H5T_NATIVE_UCHAR, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Create a datatype to refer to */ + tid1 = H5Tcreate(H5T_COMPOUND, sizeof(s1_t)); + CHECK(tid1, H5I_INVALID_HID, "H5Tcreate"); + + /* Insert fields */ + ret = H5Tinsert(tid1, "a", HOFFSET(s1_t, a), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(tid1, "b", HOFFSET(s1_t, b), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(tid1, "c", HOFFSET(s1_t, c), H5T_NATIVE_FLOAT); + CHECK(ret, FAIL, "H5Tinsert"); + + /* Save datatype for later */ + ret = H5Tcommit2(group, "Datatype1", tid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close group */ + ret = H5Gclose(group); + CHECK(ret, FAIL, "H5Gclose"); + + /* Create compound type */ + tid1 = H5Tcreate(H5T_COMPOUND, sizeof(s2_t)); + CHECK(tid1, H5I_INVALID_HID, "H5Tcreate"); + + /* Insert fields */ + ret = H5Tinsert(tid1, "ref0", HOFFSET(s2_t, ref0), H5T_STD_REF); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(tid1, "ref1", HOFFSET(s2_t, ref1), H5T_STD_REF); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(tid1, "ref2", HOFFSET(s2_t, ref2), H5T_STD_REF); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(tid1, "ref3", HOFFSET(s2_t, ref3), H5T_STD_REF); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(tid1, "dim_idx", HOFFSET(s2_t, dim_idx), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + /* Create dataspace for datasets */ + sid1 = H5Screate_simple(SPACE1_RANK, cmpnd_dims, NULL); + CHECK(sid1, H5I_INVALID_HID, "H5Screate_simple"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, "Dataset3", tid1, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dcreate2"); + + /* Reset buffer for writing */ + HDmemset(&cmpnd_wbuf, 0, sizeof(cmpnd_wbuf)); + + /* Create reference to dataset */ + ret = H5Rcreate_object(fid1, "/Group1/Dataset1", H5P_DEFAULT, &cmpnd_wbuf.ref0); + CHECK(ret, FAIL, "H5Rcreate_object"); + ret = H5Rget_obj_type3(&cmpnd_wbuf.ref0, H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_DATASET, "H5Rget_obj_type3"); + + /* Create reference to dataset */ + ret = H5Rcreate_object(fid1, "/Group1/Dataset2", H5P_DEFAULT, &cmpnd_wbuf.ref1); + CHECK(ret, FAIL, "H5Rcreate_object"); + ret = H5Rget_obj_type3(&cmpnd_wbuf.ref1, H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_DATASET, "H5Rget_obj_type3"); + + /* Create reference to group */ + ret = H5Rcreate_object(fid1, "/Group1", H5P_DEFAULT, &cmpnd_wbuf.ref2); + CHECK(ret, FAIL, "H5Rcreate_object"); + ret = H5Rget_obj_type3(&cmpnd_wbuf.ref2, H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_GROUP, "H5Rget_obj_type3"); + + /* Create reference to named datatype */ + ret = H5Rcreate_object(fid1, "/Group1/Datatype1", H5P_DEFAULT, &cmpnd_wbuf.ref3); + CHECK(ret, FAIL, "H5Rcreate_object"); + ret = H5Rget_obj_type3(&cmpnd_wbuf.ref3, H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_NAMED_DATATYPE, "H5Rget_obj_type3"); + + /* Store dimensions */ + cmpnd_wbuf.dim_idx = SPACE1_DIM1; + + /* Write selection to disk */ + ret = H5Dwrite(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, &cmpnd_wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open the file */ + fid1 = H5Fopen(FILE_REF_CMPND_OBJ, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid1, H5I_INVALID_HID, "H5Fopen"); + + /* Open the dataset */ + dataset = H5Dopen2(fid1, "/Dataset3", H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dopen2"); + + tid1 = H5Dget_type(dataset); + CHECK(tid1, H5I_INVALID_HID, "H5Dget_type"); + + /* Read selection from disk */ + ret = H5Dread(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, &cmpnd_rbuf); + CHECK(ret, FAIL, "H5Dread"); + + VERIFY(cmpnd_rbuf.dim_idx, SPACE1_DIM1, "H5Dread"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Open dataset object */ + dset2 = H5Ropen_object(&cmpnd_rbuf.ref0, H5P_DEFAULT, dapl_id); + CHECK(dset2, H5I_INVALID_HID, "H5Ropen_object"); + + /* Check information in referenced dataset */ + sid1 = H5Dget_space(dset2); + CHECK(sid1, H5I_INVALID_HID, "H5Dget_space"); + + ret = (int)H5Sget_simple_extent_npoints(sid1); + VERIFY(ret, SPACE1_DIM1, "H5Sget_simple_extent_npoints"); + + /* Read from disk */ + ret = H5Dread(dset2, H5T_NATIVE_UINT, H5S_ALL, H5S_ALL, H5P_DEFAULT, ibuf); + CHECK(ret, FAIL, "H5Dread"); + + for (i = 0; i < SPACE1_DIM1; i++) + VERIFY(ibuf[i], i * 3, "Data"); + + /* Close dereferenced Dataset */ + ret = H5Dclose(dset2); + CHECK(ret, FAIL, "H5Dclose"); + + /* Open group object. GAPL isn't supported yet. But it's harmless to pass in */ + group = H5Ropen_object(&cmpnd_rbuf.ref2, H5P_DEFAULT, H5P_DEFAULT); + CHECK(group, H5I_INVALID_HID, "H5Ropen_object"); + + /* Close group */ + ret = H5Gclose(group); + CHECK(ret, FAIL, "H5Gclose"); + + /* Open datatype object. TAPL isn't supported yet. But it's harmless to pass in */ + tid1 = H5Ropen_object(&cmpnd_rbuf.ref3, H5P_DEFAULT, H5P_DEFAULT); + CHECK(tid1, H5I_INVALID_HID, "H5Ropen_object"); + + /* Verify correct datatype */ + { + H5T_class_t tclass; + + tclass = H5Tget_class(tid1); + VERIFY(tclass, H5T_COMPOUND, "H5Tget_class"); + + ret = H5Tget_nmembers(tid1); + VERIFY(ret, 3, "H5Tget_nmembers"); + } + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close dataset access property list */ + ret = H5Pclose(dapl_id); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Destroy references */ + ret = H5Rdestroy(&cmpnd_wbuf.ref0); + CHECK(ret, FAIL, "H5Rdestroy"); + ret = H5Rdestroy(&cmpnd_wbuf.ref1); + CHECK(ret, FAIL, "H5Rdestroy"); + ret = H5Rdestroy(&cmpnd_wbuf.ref2); + CHECK(ret, FAIL, "H5Rdestroy"); + ret = H5Rdestroy(&cmpnd_wbuf.ref3); + CHECK(ret, FAIL, "H5Rdestroy"); + + ret = H5Rdestroy(&cmpnd_rbuf.ref0); + CHECK(ret, FAIL, "H5Rdestroy"); + ret = H5Rdestroy(&cmpnd_rbuf.ref1); + CHECK(ret, FAIL, "H5Rdestroy"); + ret = H5Rdestroy(&cmpnd_rbuf.ref2); + CHECK(ret, FAIL, "H5Rdestroy"); + ret = H5Rdestroy(&cmpnd_rbuf.ref3); + CHECK(ret, FAIL, "H5Rdestroy"); + + /* Free memory buffers */ + HDfree(ibuf); + HDfree(obuf); +} /* test_reference_cmpnd_obj() */ + +/**************************************************************** +** +** test_reference_region(): Test basic H5R (reference) object reference code. +** Tests references to various kinds of objects +** +** Note: The libver_low/libver_high parameters are added to create the file +** with the low and high bounds setting in fapl. +** Please see the RFC for "H5Sencode/H5Sdecode Format Change". +** +****************************************************************/ +static void +test_reference_region(H5F_libver_t libver_low, H5F_libver_t libver_high) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t fapl; /* File access property list */ + hid_t dset1, /* Dataset ID */ + dset2; /* Dereferenced dataset ID */ + hid_t sid1, /* Dataspace ID #1 */ + sid2; /* Dataspace ID #2 */ + hid_t dapl_id; /* Dataset access property list */ + hsize_t dims1[] = {SPACE1_DIM1}, dims2[] = {SPACE2_DIM1, SPACE2_DIM2}; + hsize_t start[SPACE2_RANK]; /* Starting location of hyperslab */ + hsize_t stride[SPACE2_RANK]; /* Stride of hyperslab */ + hsize_t count[SPACE2_RANK]; /* Element count of hyperslab */ + hsize_t block[SPACE2_RANK]; /* Block size of hyperslab */ + hsize_t coord1[POINT1_NPOINTS][SPACE2_RANK]; /* Coordinates for point selection */ + hsize_t *coords; /* Coordinate buffer */ + hsize_t low[SPACE2_RANK]; /* Selection bounds */ + hsize_t high[SPACE2_RANK]; /* Selection bounds */ + H5R_ref_t *wbuf = NULL, /* buffer to write to disk */ + *rbuf = NULL; /* buffer read from disk */ + H5R_ref_t nvrbuf[3] = {{{{0}}}, {{{101}}}, {{{255}}}}; /* buffer with non-valid refs */ + uint8_t *dwbuf = NULL, /* Buffer for writing numeric data to disk */ + *drbuf = NULL; /* Buffer for reading numeric data from disk */ + uint8_t *tu8; /* Temporary pointer to uint8 data */ + H5O_type_t obj_type; /* Type of object */ + int i, j; /* Counters */ + hssize_t hssize_ret; /* hssize_t return value */ + htri_t tri_ret; /* htri_t return value */ + herr_t ret; /* Generic return value */ + hid_t dset_NA; /* Dataset id for undefined reference */ + hid_t space_NA; /* Dataspace id for undefined reference */ + hsize_t dims_NA[1] = {1}; /* Dims array for undefined reference */ + H5R_ref_t rdata_NA[1]; /* Read buffer */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Dataset Region Reference Functions\n")); + + /* Allocate write & read buffers */ + wbuf = HDcalloc(sizeof(H5R_ref_t), SPACE1_DIM1); + rbuf = HDcalloc(sizeof(H5R_ref_t), SPACE1_DIM1); + dwbuf = (uint8_t *)HDcalloc(sizeof(uint8_t), (size_t)(SPACE2_DIM1 * SPACE2_DIM2)); + drbuf = (uint8_t *)HDcalloc(sizeof(uint8_t), (size_t)(SPACE2_DIM1 * SPACE2_DIM2)); + + for (tu8 = dwbuf, i = 0; i < (SPACE2_DIM1 * SPACE2_DIM2); i++) + *tu8++ = (uint8_t)(i * 3); + + /* Create file access property list */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, H5I_INVALID_HID, "H5Pcreate"); + + /* Set the low/high version bounds in fapl */ + ret = H5Pset_libver_bounds(fapl, libver_low, libver_high); + CHECK(ret, FAIL, "H5Pset_libver_bounds"); + + /* Create file with the fapl */ + fid1 = H5Fcreate(FILE_REF_REG, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(fid1, H5I_INVALID_HID, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid2 = H5Screate_simple(SPACE2_RANK, dims2, NULL); + CHECK(sid2, H5I_INVALID_HID, "H5Screate_simple"); + + /* Create dataset access property list */ + dapl_id = H5Pcreate(H5P_DATASET_ACCESS); + CHECK(dapl_id, H5I_INVALID_HID, "H5Pcreate"); + + /* Create a dataset */ + dset2 = H5Dcreate2(fid1, "Dataset2", H5T_STD_U8LE, sid2, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dset2, H5I_INVALID_HID, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(dset2, H5T_STD_U8LE, H5S_ALL, H5S_ALL, H5P_DEFAULT, dwbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close Dataset */ + ret = H5Dclose(dset2); + CHECK(ret, FAIL, "H5Dclose"); + + /* Create dataspace for the reference dataset */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, H5I_INVALID_HID, "H5Screate_simple"); + + /* Create a dataset */ + H5E_BEGIN_TRY + { + dset1 = H5Dcreate2(fid1, "Dataset1", H5T_STD_REF, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (dset1 < 0) { + VERIFY(libver_high <= H5F_LIBVER_V110, TRUE, "H5Dcreate2"); + + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + } + else { + + CHECK(dset1, H5I_INVALID_HID, "H5Dcreate2"); + + /* Create references */ + + /* Select 6x6 hyperslab for first reference */ + start[0] = 2; + start[1] = 2; + stride[0] = 1; + stride[1] = 1; + count[0] = 1; + count[1] = 1; + block[0] = 6; + block[1] = 6; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + ret = (int)H5Sget_select_npoints(sid2); + VERIFY(ret, 36, "H5Sget_select_npoints"); + + /* Store first dataset region */ + ret = H5Rcreate_region(fid1, "/Dataset2", sid2, H5P_DEFAULT, &wbuf[0]); + CHECK(ret, FAIL, "H5Rcreate_region"); + ret = H5Rget_obj_type3(&wbuf[0], H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_DATASET, "H5Rget_obj_type3"); + + /* Select sequence of ten points for second reference */ + coord1[0][0] = 6; + coord1[0][1] = 9; + coord1[1][0] = 2; + coord1[1][1] = 2; + coord1[2][0] = 8; + coord1[2][1] = 4; + coord1[3][0] = 1; + coord1[3][1] = 6; + coord1[4][0] = 2; + coord1[4][1] = 8; + coord1[5][0] = 3; + coord1[5][1] = 2; + coord1[6][0] = 0; + coord1[6][1] = 4; + coord1[7][0] = 9; + coord1[7][1] = 0; + coord1[8][0] = 7; + coord1[8][1] = 1; + coord1[9][0] = 3; + coord1[9][1] = 3; + ret = H5Sselect_elements(sid2, H5S_SELECT_SET, (size_t)POINT1_NPOINTS, (const hsize_t *)coord1); + CHECK(ret, FAIL, "H5Sselect_elements"); + + ret = (int)H5Sget_select_npoints(sid2); + VERIFY(ret, SPACE2_DIM2, "H5Sget_select_npoints"); + + /* Store second dataset region */ + ret = H5Rcreate_region(fid1, "/Dataset2", sid2, H5P_DEFAULT, &wbuf[1]); + CHECK(ret, FAIL, "H5Rcreate_region"); + + /* Select unlimited hyperslab for third reference */ + start[0] = 1; + start[1] = 8; + stride[0] = 4; + stride[1] = 1; + count[0] = H5S_UNLIMITED; + count[1] = 1; + block[0] = 2; + block[1] = 2; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + hssize_ret = H5Sget_select_npoints(sid2); + VERIFY(hssize_ret, (hssize_t)H5S_UNLIMITED, "H5Sget_select_npoints"); + + /* Store third dataset region */ + ret = H5Rcreate_region(fid1, "/Dataset2", sid2, H5P_DEFAULT, &wbuf[2]); + CHECK(ret, FAIL, "H5Rcreate_region"); + + ret = H5Rget_obj_type3(&wbuf[2], H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_DATASET, "H5Rget_obj_type3"); + + /* Store fourth dataset region */ + ret = H5Rcreate_region(fid1, "/Dataset2", sid2, H5P_DEFAULT, &wbuf[3]); + CHECK(ret, FAIL, "H5Rcreate_region"); + + /* Write selection to disk */ + ret = H5Dwrite(dset1, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf); + + /* + * Store a dataset region reference which will not get written to disk + */ + + /* Create the dataspace of the region references */ + space_NA = H5Screate_simple(1, dims_NA, NULL); + CHECK(space_NA, H5I_INVALID_HID, "H5Screate_simple"); + + /* Create the dataset and write the region references to it */ + dset_NA = H5Dcreate2(fid1, "DS_NA", H5T_STD_REF, space_NA, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dset_NA, H5I_INVALID_HID, "H5Dcreate"); + + /* Close and release resources for undefined region reference tests */ + ret = H5Dclose(dset_NA); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Sclose(space_NA); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dset1); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close uint8 dataset dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open the file */ + fid1 = H5Fopen(FILE_REF_REG, H5F_ACC_RDWR, fapl); + CHECK(fid1, H5I_INVALID_HID, "H5Fopen"); + + /* + * Start the test of an undefined reference + */ + + /* Open the dataset of the undefined references */ + dset_NA = H5Dopen2(fid1, "DS_NA", H5P_DEFAULT); + CHECK(dset_NA, H5I_INVALID_HID, "H5Dopen2"); + + /* Read the data */ + ret = H5Dread(dset_NA, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata_NA); + CHECK(ret, FAIL, "H5Dread"); + + /* + * Dereference an undefined reference (should fail) + */ + H5E_BEGIN_TRY + { + dset2 = H5Ropen_object(&rdata_NA[0], H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(dset2, H5I_INVALID_HID, "H5Ropen_object"); + + /* Close and release resources. */ + ret = H5Dclose(dset_NA); + CHECK(ret, FAIL, "H5Dclose"); + + /* This close should fail since H5Ropen_object never created + * the id of the referenced object. */ + H5E_BEGIN_TRY + { + ret = H5Dclose(dset2); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Dclose"); + + /* + * End the test of an undefined reference + */ + + /* Open the dataset */ + dset1 = H5Dopen2(fid1, "/Dataset1", H5P_DEFAULT); + CHECK(dset1, H5I_INVALID_HID, "H5Dopen2"); + + /* Read selection from disk */ + ret = H5Dread(dset1, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Try to open objects */ + dset2 = H5Ropen_object(&rbuf[0], H5P_DEFAULT, dapl_id); + CHECK(dset2, H5I_INVALID_HID, "H5Ropen_object"); + + /* Check what H5Rget_obj_type3 function returns */ + ret = H5Rget_obj_type3(&rbuf[0], H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_DATASET, "H5Rget_obj_type3"); + + /* Check information in referenced dataset */ + sid1 = H5Dget_space(dset2); + CHECK(sid1, H5I_INVALID_HID, "H5Dget_space"); + + ret = (int)H5Sget_simple_extent_npoints(sid1); + VERIFY(ret, (SPACE2_DIM1 * SPACE2_DIM2), "H5Sget_simple_extent_npoints"); + + /* Read from disk */ + ret = H5Dread(dset2, H5T_STD_U8LE, H5S_ALL, H5S_ALL, H5P_DEFAULT, drbuf); + CHECK(ret, FAIL, "H5Dread"); + + for (tu8 = (uint8_t *)drbuf, i = 0; i < (SPACE2_DIM1 * SPACE2_DIM2); i++, tu8++) + VERIFY(*tu8, (uint8_t)(i * 3), "Data"); + + /* Get the hyperslab selection */ + sid2 = H5Ropen_region(&rbuf[0], H5P_DEFAULT, H5P_DEFAULT); + CHECK(sid2, H5I_INVALID_HID, "H5Ropen_region"); + + /* Verify correct hyperslab selected */ + ret = (int)H5Sget_select_npoints(sid2); + VERIFY(ret, 36, "H5Sget_select_npoints"); + ret = (int)H5Sget_select_hyper_nblocks(sid2); + VERIFY(ret, 1, "H5Sget_select_hyper_nblocks"); + + /* allocate space for the hyperslab blocks */ + coords = (hsize_t *)HDmalloc((size_t)ret * SPACE2_RANK * sizeof(hsize_t) * 2); + + ret = H5Sget_select_hyper_blocklist(sid2, (hsize_t)0, (hsize_t)ret, coords); + CHECK(ret, FAIL, "H5Sget_select_hyper_blocklist"); + VERIFY(coords[0], 2, "Hyperslab Coordinates"); + VERIFY(coords[1], 2, "Hyperslab Coordinates"); + VERIFY(coords[2], 7, "Hyperslab Coordinates"); + VERIFY(coords[3], 7, "Hyperslab Coordinates"); + HDfree(coords); + ret = H5Sget_select_bounds(sid2, low, high); + CHECK(ret, FAIL, "H5Sget_select_bounds"); + VERIFY(low[0], 2, "Selection Bounds"); + VERIFY(low[1], 2, "Selection Bounds"); + VERIFY(high[0], 7, "Selection Bounds"); + VERIFY(high[1], 7, "Selection Bounds"); + + /* Close region space */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Get the element selection */ + sid2 = H5Ropen_region(&rbuf[1], H5P_DEFAULT, H5P_DEFAULT); + CHECK(sid2, H5I_INVALID_HID, "H5Ropen_region"); + + /* Verify correct elements selected */ + ret = (int)H5Sget_select_npoints(sid2); + VERIFY(ret, SPACE2_DIM2, "H5Sget_select_npoints"); + ret = (int)H5Sget_select_elem_npoints(sid2); + VERIFY(ret, SPACE2_DIM2, "H5Sget_select_elem_npoints"); + + /* allocate space for the element points */ + coords = (hsize_t *)HDmalloc((size_t)ret * SPACE2_RANK * sizeof(hsize_t)); + + ret = H5Sget_select_elem_pointlist(sid2, (hsize_t)0, (hsize_t)ret, coords); + CHECK(ret, FAIL, "H5Sget_select_elem_pointlist"); + VERIFY(coords[0], coord1[0][0], "Element Coordinates"); + VERIFY(coords[1], coord1[0][1], "Element Coordinates"); + VERIFY(coords[2], coord1[1][0], "Element Coordinates"); + VERIFY(coords[3], coord1[1][1], "Element Coordinates"); + VERIFY(coords[4], coord1[2][0], "Element Coordinates"); + VERIFY(coords[5], coord1[2][1], "Element Coordinates"); + VERIFY(coords[6], coord1[3][0], "Element Coordinates"); + VERIFY(coords[7], coord1[3][1], "Element Coordinates"); + VERIFY(coords[8], coord1[4][0], "Element Coordinates"); + VERIFY(coords[9], coord1[4][1], "Element Coordinates"); + VERIFY(coords[10], coord1[5][0], "Element Coordinates"); + VERIFY(coords[11], coord1[5][1], "Element Coordinates"); + VERIFY(coords[12], coord1[6][0], "Element Coordinates"); + VERIFY(coords[13], coord1[6][1], "Element Coordinates"); + VERIFY(coords[14], coord1[7][0], "Element Coordinates"); + VERIFY(coords[15], coord1[7][1], "Element Coordinates"); + VERIFY(coords[16], coord1[8][0], "Element Coordinates"); + VERIFY(coords[17], coord1[8][1], "Element Coordinates"); + VERIFY(coords[18], coord1[9][0], "Element Coordinates"); + VERIFY(coords[19], coord1[9][1], "Element Coordinates"); + HDfree(coords); + ret = H5Sget_select_bounds(sid2, low, high); + CHECK(ret, FAIL, "H5Sget_select_bounds"); + VERIFY(low[0], 0, "Selection Bounds"); + VERIFY(low[1], 0, "Selection Bounds"); + VERIFY(high[0], 9, "Selection Bounds"); + VERIFY(high[1], 9, "Selection Bounds"); + + /* Close region space */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Get the unlimited selection */ + sid2 = H5Ropen_region(&rbuf[2], H5P_DEFAULT, H5P_DEFAULT); + CHECK(sid2, H5I_INVALID_HID, "H5Ropen_region"); + + /* Verify correct hyperslab selected */ + hssize_ret = H5Sget_select_npoints(sid2); + VERIFY(hssize_ret, (hssize_t)H5S_UNLIMITED, "H5Sget_select_npoints"); + tri_ret = H5Sis_regular_hyperslab(sid2); + CHECK(tri_ret, FAIL, "H5Sis_regular_hyperslab"); + VERIFY(tri_ret, TRUE, "H5Sis_regular_hyperslab Result"); + ret = H5Sget_regular_hyperslab(sid2, start, stride, count, block); + CHECK(ret, FAIL, "H5Sget_regular_hyperslab"); + VERIFY(start[0], (hsize_t)1, "Hyperslab Coordinates"); + VERIFY(start[1], (hsize_t)8, "Hyperslab Coordinates"); + VERIFY(stride[0], (hsize_t)4, "Hyperslab Coordinates"); + VERIFY(stride[1], (hsize_t)1, "Hyperslab Coordinates"); + VERIFY(count[0], H5S_UNLIMITED, "Hyperslab Coordinates"); + VERIFY(count[1], (hsize_t)1, "Hyperslab Coordinates"); + VERIFY(block[0], (hsize_t)2, "Hyperslab Coordinates"); + VERIFY(block[1], (hsize_t)2, "Hyperslab Coordinates"); + + /* Close region space */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close first space */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close dereferenced Dataset */ + ret = H5Dclose(dset2); + CHECK(ret, FAIL, "H5Dclose"); + + /* Attempting to retrieve type of object using non-valid refs */ + for (j = 0; j < 3; j++) { + H5E_BEGIN_TRY + { + ret = H5Rget_obj_type3(&nvrbuf[j], H5P_DEFAULT, &obj_type); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Rget_obj_type3"); + } /* end for */ + + /* Close Dataset */ + ret = H5Dclose(dset1); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close dataset access property list */ + ret = H5Pclose(dapl_id); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Destroy references */ + for (j = 0; j < SPACE1_DIM1; j++) { + ret = H5Rdestroy(&wbuf[j]); + CHECK(ret, FAIL, "H5Rdestroy"); + ret = H5Rdestroy(&rbuf[j]); + CHECK(ret, FAIL, "H5Rdestroy"); + } + } + + /* Free memory buffers */ + HDfree(wbuf); + HDfree(rbuf); + HDfree(dwbuf); + HDfree(drbuf); + +} /* test_reference_region() */ + +/**************************************************************** +** +** test_reference_region_1D(): Test H5R (reference) object reference code. +** Tests 1-D references to various kinds of objects +** +** Note: The libver_low/libver_high parameters are added to create the file +** with the low and high bounds setting in fapl. +** Please see the RFC for "H5Sencode/H5Sdecode Format Change". +** +****************************************************************/ +static void +test_reference_region_1D(H5F_libver_t libver_low, H5F_libver_t libver_high) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t fapl; /* File access property list */ + hid_t dset1, /* Dataset ID */ + dset3; /* Dereferenced dataset ID */ + hid_t sid1, /* Dataspace ID #1 */ + sid3; /* Dataspace ID #3 */ + hid_t dapl_id; /* Dataset access property list */ + hsize_t dims1[] = {2}, /* Must be 2 */ + dims3[] = {SPACE3_DIM1}; + hsize_t start[SPACE3_RANK]; /* Starting location of hyperslab */ + hsize_t stride[SPACE3_RANK]; /* Stride of hyperslab */ + hsize_t count[SPACE3_RANK]; /* Element count of hyperslab */ + hsize_t block[SPACE3_RANK]; /* Block size of hyperslab */ + hsize_t coord1[POINT1_NPOINTS][SPACE3_RANK]; /* Coordinates for point selection */ + hsize_t *coords; /* Coordinate buffer */ + hsize_t low[SPACE3_RANK]; /* Selection bounds */ + hsize_t high[SPACE3_RANK]; /* Selection bounds */ + H5R_ref_t *wbuf = NULL, /* buffer to write to disk */ + *rbuf = NULL; /* buffer read from disk */ + uint8_t *dwbuf = NULL, /* Buffer for writing numeric data to disk */ + *drbuf = NULL; /* Buffer for reading numeric data from disk */ + uint8_t *tu8; /* Temporary pointer to uint8 data */ + H5O_type_t obj_type; /* Object type */ + int i; /* Counter */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing 1-D Dataset Region Reference Functions\n")); + + /* Allocate write & read buffers */ + wbuf = HDcalloc(sizeof(H5R_ref_t), (size_t)SPACE1_DIM1); + rbuf = HDcalloc(sizeof(H5R_ref_t), (size_t)SPACE1_DIM1); + dwbuf = (uint8_t *)HDcalloc(sizeof(uint8_t), (size_t)SPACE3_DIM1); + drbuf = (uint8_t *)HDcalloc(sizeof(uint8_t), (size_t)SPACE3_DIM1); + + for (tu8 = dwbuf, i = 0; i < SPACE3_DIM1; i++) + *tu8++ = (uint8_t)(i * 3); + + /* Create the file access property list */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, H5I_INVALID_HID, "H5Pcreate"); + + /* Set the low/high version bounds in fapl */ + ret = H5Pset_libver_bounds(fapl, libver_low, libver_high); + CHECK(ret, FAIL, "H5Pset_libver_bounds"); + + /* Create file with the fapl */ + fid1 = H5Fcreate(FILE_REF_REG_1D, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(fid1, H5I_INVALID_HID, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid3 = H5Screate_simple(SPACE3_RANK, dims3, NULL); + CHECK(sid3, H5I_INVALID_HID, "H5Screate_simple"); + + /* Create dataset access property list */ + dapl_id = H5Pcreate(H5P_DATASET_ACCESS); + CHECK(dapl_id, H5I_INVALID_HID, "H5Pcreate"); + + /* Create a dataset */ + dset3 = H5Dcreate2(fid1, "Dataset2", H5T_STD_U8LE, sid3, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dset3, H5I_INVALID_HID, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(dset3, H5T_STD_U8LE, H5S_ALL, H5S_ALL, H5P_DEFAULT, dwbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close Dataset */ + ret = H5Dclose(dset3); + CHECK(ret, FAIL, "H5Dclose"); + + /* Create dataspace for the reference dataset */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, H5I_INVALID_HID, "H5Screate_simple"); + + /* Create a dataset */ + H5E_BEGIN_TRY + { + dset1 = H5Dcreate2(fid1, "Dataset1", H5T_STD_REF, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + H5E_END_TRY; + + if (dset1 < 0) { + + VERIFY(libver_high <= H5F_LIBVER_V110, TRUE, "H5Dcreate2"); + + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(sid3); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + } + else { + + CHECK(ret, FAIL, "H5Dcreate2"); + + /* Create references */ + + /* Select 15 2x1 hyperslabs for first reference */ + start[0] = 2; + stride[0] = 5; + count[0] = 15; + block[0] = 2; + ret = H5Sselect_hyperslab(sid3, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + ret = (int)H5Sget_select_npoints(sid3); + VERIFY(ret, (block[0] * count[0]), "H5Sget_select_npoints"); + + /* Store first dataset region */ + ret = H5Rcreate_region(fid1, "/Dataset2", sid3, H5P_DEFAULT, &wbuf[0]); + CHECK(ret, FAIL, "H5Rcreate_region"); + ret = H5Rget_obj_type3(&wbuf[0], H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_DATASET, "H5Rget_obj_type3"); + + /* Select sequence of ten points for second reference */ + coord1[0][0] = 16; + coord1[1][0] = 22; + coord1[2][0] = 38; + coord1[3][0] = 41; + coord1[4][0] = 52; + coord1[5][0] = 63; + coord1[6][0] = 70; + coord1[7][0] = 89; + coord1[8][0] = 97; + coord1[9][0] = 03; + ret = H5Sselect_elements(sid3, H5S_SELECT_SET, (size_t)POINT1_NPOINTS, (const hsize_t *)coord1); + CHECK(ret, FAIL, "H5Sselect_elements"); + + ret = (int)H5Sget_select_npoints(sid3); + VERIFY(ret, POINT1_NPOINTS, "H5Sget_select_npoints"); + + /* Store second dataset region */ + ret = H5Rcreate_region(fid1, "/Dataset2", sid3, H5P_DEFAULT, &wbuf[1]); + CHECK(ret, FAIL, "H5Rcreate_region"); + + /* Write selection to disk */ + ret = H5Dwrite(dset1, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dset1); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close uint8 dataset dataspace */ + ret = H5Sclose(sid3); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open the file */ + fid1 = H5Fopen(FILE_REF_REG_1D, H5F_ACC_RDWR, fapl); + CHECK(fid1, H5I_INVALID_HID, "H5Fopen"); + + /* Open the dataset */ + dset1 = H5Dopen2(fid1, "/Dataset1", H5P_DEFAULT); + CHECK(dset1, H5I_INVALID_HID, "H5Dopen2"); + + /* Read selection from disk */ + ret = H5Dread(dset1, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Try to open objects */ + dset3 = H5Ropen_object(&rbuf[0], H5P_DEFAULT, dapl_id); + CHECK(dset3, H5I_INVALID_HID, "H5Ropen_object"); + + /* Check what H5Rget_obj_type3 function returns */ + ret = H5Rget_obj_type3(&rbuf[0], H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_DATASET, "H5Rget_obj_type3"); + + /* Check information in referenced dataset */ + sid1 = H5Dget_space(dset3); + CHECK(sid1, H5I_INVALID_HID, "H5Dget_space"); + + ret = (int)H5Sget_simple_extent_npoints(sid1); + VERIFY(ret, SPACE3_DIM1, "H5Sget_simple_extent_npoints"); + + /* Read from disk */ + ret = H5Dread(dset3, H5T_STD_U8LE, H5S_ALL, H5S_ALL, H5P_DEFAULT, drbuf); + CHECK(ret, FAIL, "H5Dread"); + + for (tu8 = (uint8_t *)drbuf, i = 0; i < SPACE3_DIM1; i++, tu8++) + VERIFY(*tu8, (uint8_t)(i * 3), "Data"); + + /* Get the hyperslab selection */ + sid3 = H5Ropen_region(&rbuf[0], H5P_DEFAULT, H5P_DEFAULT); + CHECK(sid3, H5I_INVALID_HID, "H5Ropen_region"); + + /* Verify correct hyperslab selected */ + ret = (int)H5Sget_select_npoints(sid3); + VERIFY(ret, 30, "H5Sget_select_npoints"); + ret = (int)H5Sget_select_hyper_nblocks(sid3); + VERIFY(ret, 15, "H5Sget_select_hyper_nblocks"); + + /* allocate space for the hyperslab blocks */ + coords = (hsize_t *)HDmalloc((size_t)ret * SPACE3_RANK * sizeof(hsize_t) * 2); + + ret = H5Sget_select_hyper_blocklist(sid3, (hsize_t)0, (hsize_t)ret, coords); + CHECK(ret, FAIL, "H5Sget_select_hyper_blocklist"); + VERIFY(coords[0], 2, "Hyperslab Coordinates"); + VERIFY(coords[1], 3, "Hyperslab Coordinates"); + VERIFY(coords[2], 7, "Hyperslab Coordinates"); + VERIFY(coords[3], 8, "Hyperslab Coordinates"); + VERIFY(coords[4], 12, "Hyperslab Coordinates"); + VERIFY(coords[5], 13, "Hyperslab Coordinates"); + VERIFY(coords[6], 17, "Hyperslab Coordinates"); + VERIFY(coords[7], 18, "Hyperslab Coordinates"); + VERIFY(coords[8], 22, "Hyperslab Coordinates"); + VERIFY(coords[9], 23, "Hyperslab Coordinates"); + VERIFY(coords[10], 27, "Hyperslab Coordinates"); + VERIFY(coords[11], 28, "Hyperslab Coordinates"); + VERIFY(coords[12], 32, "Hyperslab Coordinates"); + VERIFY(coords[13], 33, "Hyperslab Coordinates"); + VERIFY(coords[14], 37, "Hyperslab Coordinates"); + VERIFY(coords[15], 38, "Hyperslab Coordinates"); + VERIFY(coords[16], 42, "Hyperslab Coordinates"); + VERIFY(coords[17], 43, "Hyperslab Coordinates"); + VERIFY(coords[18], 47, "Hyperslab Coordinates"); + VERIFY(coords[19], 48, "Hyperslab Coordinates"); + VERIFY(coords[20], 52, "Hyperslab Coordinates"); + VERIFY(coords[21], 53, "Hyperslab Coordinates"); + VERIFY(coords[22], 57, "Hyperslab Coordinates"); + VERIFY(coords[23], 58, "Hyperslab Coordinates"); + VERIFY(coords[24], 62, "Hyperslab Coordinates"); + VERIFY(coords[25], 63, "Hyperslab Coordinates"); + VERIFY(coords[26], 67, "Hyperslab Coordinates"); + VERIFY(coords[27], 68, "Hyperslab Coordinates"); + VERIFY(coords[28], 72, "Hyperslab Coordinates"); + VERIFY(coords[29], 73, "Hyperslab Coordinates"); + HDfree(coords); + ret = H5Sget_select_bounds(sid3, low, high); + CHECK(ret, FAIL, "H5Sget_select_bounds"); + VERIFY(low[0], 2, "Selection Bounds"); + VERIFY(high[0], 73, "Selection Bounds"); + + /* Close region space */ + ret = H5Sclose(sid3); + CHECK(ret, FAIL, "H5Sclose"); + + /* Get the element selection */ + sid3 = H5Ropen_region(&rbuf[1], H5P_DEFAULT, H5P_DEFAULT); + CHECK(sid3, H5I_INVALID_HID, "H5Ropen_region"); + + /* Verify correct elements selected */ + ret = (int)H5Sget_select_npoints(sid3); + VERIFY(ret, 10, "H5Sget_select_npoints"); + ret = (int)H5Sget_select_elem_npoints(sid3); + VERIFY(ret, 10, "H5Sget_select_elem_npoints"); + + /* allocate space for the element points */ + coords = (hsize_t *)HDmalloc((size_t)ret * SPACE3_RANK * sizeof(hsize_t)); + + ret = H5Sget_select_elem_pointlist(sid3, (hsize_t)0, (hsize_t)ret, coords); + CHECK(ret, FAIL, "H5Sget_select_elem_pointlist"); + VERIFY(coords[0], coord1[0][0], "Element Coordinates"); + VERIFY(coords[1], coord1[1][0], "Element Coordinates"); + VERIFY(coords[2], coord1[2][0], "Element Coordinates"); + VERIFY(coords[3], coord1[3][0], "Element Coordinates"); + VERIFY(coords[4], coord1[4][0], "Element Coordinates"); + VERIFY(coords[5], coord1[5][0], "Element Coordinates"); + VERIFY(coords[6], coord1[6][0], "Element Coordinates"); + VERIFY(coords[7], coord1[7][0], "Element Coordinates"); + VERIFY(coords[8], coord1[8][0], "Element Coordinates"); + VERIFY(coords[9], coord1[9][0], "Element Coordinates"); + HDfree(coords); + ret = H5Sget_select_bounds(sid3, low, high); + CHECK(ret, FAIL, "H5Sget_select_bounds"); + VERIFY(low[0], 3, "Selection Bounds"); + VERIFY(high[0], 97, "Selection Bounds"); + + /* Close region space */ + ret = H5Sclose(sid3); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close first space */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close dereferenced Dataset */ + ret = H5Dclose(dset3); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close Dataset */ + ret = H5Dclose(dset1); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close dataset access property list */ + ret = H5Pclose(dapl_id); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file access property list */ + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Destroy references */ + for (i = 0; i < 2; i++) { + ret = H5Rdestroy(&wbuf[i]); + CHECK(ret, FAIL, "H5Rdestroy"); + ret = H5Rdestroy(&rbuf[i]); + CHECK(ret, FAIL, "H5Rdestroy"); + } + } + + /* Free memory buffers */ + HDfree(wbuf); + HDfree(rbuf); + HDfree(dwbuf); + HDfree(drbuf); + +} /* test_reference_region_1D() */ + +/**************************************************************** +** +** test_reference_obj_deleted(): Test H5R (reference) object reference code. +** Tests for correct failures for deleted and non-existent objects +** +****************************************************************/ +static void +test_reference_obj_deleted(void) +{ +#ifndef NO_REFERENCE_TO_DELETED + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset, /* Dataset ID */ + dset2; /* Dereferenced dataset ID */ + hid_t sid1; /* Dataspace ID */ + H5R_ref_t oref; /* Object Reference to test */ + H5O_type_t obj_type; /* Object type */ + herr_t ret; /* Generic return value */ +#endif + MESSAGE(5, ("Testing References to Deleted Objects - SKIPPED for now due to no support\n")); +#ifndef NO_REFERENCE_TO_DELETED + /* Create file */ + fid1 = H5Fcreate(FILE_REF_OBJ_DEL, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, H5I_INVALID_HID, "H5Fcreate"); + + /* Create scalar dataspace for datasets */ + sid1 = H5Screate_simple(0, NULL, NULL); + CHECK(sid1, H5I_INVALID_HID, "H5Screate_simple"); + + /* Create a dataset to reference (deleted later) */ + dataset = H5Dcreate2(fid1, "Dataset1", H5T_NATIVE_INT, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dcreate2"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, "Dataset2", H5T_STD_REF, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dcreate2"); + + /* Create reference to dataset */ + ret = H5Rcreate_object(fid1, "/Dataset1", H5P_DEFAULT, &oref); + CHECK(ret, FAIL, "H5Rcreate_object"); + ret = H5Rget_obj_type3(&oref, H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_DATASET, "H5Rget_obj_type3"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, &oref); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Delete referenced dataset */ + ret = H5Ldelete(fid1, "/Dataset1", H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Destroy reference */ + ret = H5Rdestroy(&oref); + CHECK(ret, FAIL, "H5Rdestroy"); + + /* Re-open the file */ + fid1 = H5Fopen(FILE_REF_OBJ_DEL, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid1, H5I_INVALID_HID, "H5Fopen"); + + /* Open the dataset */ + dataset = H5Dopen2(fid1, "/Dataset2", H5P_DEFAULT); + CHECK(ret, H5I_INVALID_HID, "H5Dopen2"); + + /* Read selection from disk */ + ret = H5Dread(dataset, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, &oref); + CHECK(ret, FAIL, "H5Dread"); + + /* Open deleted dataset object */ + dset2 = H5Ropen_object(&oref, H5P_DEFAULT, H5P_DEFAULT); + VERIFY(dset2, H5I_INVALID_HID, "H5Ropen_object"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Destroy reference */ + ret = H5Rdestroy(&oref); + CHECK(ret, FAIL, "H5Rdestroy"); +#endif +} /* test_reference_obj_deleted() */ + +/**************************************************************** +** +** test_deref_iter_op(): Iterator callback for test_reference_group_iterate() +** test. +** +****************************************************************/ +static herr_t +test_deref_iter_op(hid_t H5_ATTR_UNUSED group, const char *name, const H5L_info2_t H5_ATTR_UNUSED *info, + void *op_data) +{ + int *count = (int *)op_data; /* Pointer to name counter */ + herr_t ret_value; + + /* Simple check for correct names */ + if (*count == 0) { + if (HDstrcmp(name, DSETNAME2) == 0) + ret_value = 0; + else + ret_value = -1; + } /* end if */ + else if (*count == 1) { + if (HDstrcmp(name, GROUPNAME2) == 0) + ret_value = 0; + else + ret_value = -1; + } /* end if */ + else if (*count == 2) { + if (HDstrcmp(name, GROUPNAME3) == 0) + ret_value = 0; + else + ret_value = -1; + } /* end if */ + else + ret_value = -1; + + (*count)++; + + return (ret_value); +} /* end test_deref_iter_op() */ + +/**************************************************************** +** +** test_reference_group(): Test H5R (reference) object reference code. +** Tests for correct behavior of various routines on dereferenced group +** +****************************************************************/ +static void +test_reference_group(void) +{ + hid_t fid = -1; /* File ID */ + hid_t gid = -1, gid2 = -1; /* Group IDs */ + hid_t did; /* Dataset ID */ + hid_t sid; /* Dataspace ID */ + H5R_ref_t wref; /* Reference to write */ + H5R_ref_t rref; /* Reference to read */ + H5G_info_t ginfo; /* Group info struct */ + char objname[NAME_SIZE]; /* Buffer to store name */ + H5O_info2_t oinfo; /* Object info struct */ + int count = 0; /* Count within iterated group */ + ssize_t size; /* Name length */ + herr_t ret; + + /* Create file with a group and a dataset containing an object reference to the group */ + fid = H5Fcreate(FILE_REF_GRP, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, H5I_INVALID_HID, "H5Fcreate"); + + /* Create dataspace to use for dataset */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, H5I_INVALID_HID, "H5Screate"); + + /* Create group to refer to */ + gid = H5Gcreate2(fid, GROUPNAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid, H5I_INVALID_HID, "H5Gcreate2"); + + /* Create nested groups */ + gid2 = H5Gcreate2(gid, GROUPNAME2, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid2, H5I_INVALID_HID, "H5Gcreate2"); + ret = H5Gclose(gid2); + CHECK(ret, FAIL, "H5Gclose"); + + gid2 = H5Gcreate2(gid, GROUPNAME3, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid2, H5I_INVALID_HID, "H5Gcreate2"); + ret = H5Gclose(gid2); + CHECK(ret, FAIL, "H5Gclose"); + + /* Create bottom dataset */ + did = H5Dcreate2(gid, DSETNAME2, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(did, H5I_INVALID_HID, "H5Dcreate2"); + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + + /* Create dataset */ + did = H5Dcreate2(fid, DSETNAME, H5T_STD_REF, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(did, H5I_INVALID_HID, "H5Dcreate2"); + + /* Create reference to group */ + ret = H5Rcreate_object(fid, GROUPNAME, H5P_DEFAULT, &wref); + CHECK(ret, FAIL, "H5Rcreate_object"); + + /* Write reference to disk */ + ret = H5Dwrite(did, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, &wref); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close objects */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Destroy reference */ + ret = H5Rdestroy(&wref); + CHECK(ret, FAIL, "H5Rdestroy"); + + /* Re-open file */ + fid = H5Fopen(FILE_REF_GRP, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid, H5I_INVALID_HID, "H5Fopen"); + + /* Re-open dataset */ + did = H5Dopen2(fid, DSETNAME, H5P_DEFAULT); + CHECK(did, H5I_INVALID_HID, "H5Dopen2"); + + /* Read in the reference */ + ret = H5Dread(did, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, &rref); + CHECK(ret, FAIL, "H5Dread"); + + /* Dereference to get the group */ + gid = H5Ropen_object(&rref, H5P_DEFAULT, H5P_DEFAULT); + CHECK(gid, H5I_INVALID_HID, "H5Ropen_object"); + + /* Iterate through objects in dereferenced group */ + ret = H5Literate2(gid, H5_INDEX_NAME, H5_ITER_INC, NULL, test_deref_iter_op, &count); + CHECK(ret, FAIL, "H5Literate"); + + /* Various queries on the group opened */ + ret = H5Gget_info(gid, &ginfo); + CHECK(ret, FAIL, "H5Gget_info"); + VERIFY(ginfo.nlinks, 3, "H5Gget_info"); + + size = H5Lget_name_by_idx(gid, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)0, objname, (size_t)NAME_SIZE, + H5P_DEFAULT); + CHECK(size, (-1), "H5Lget_name_by_idx"); + VERIFY_STR(objname, DSETNAME2, "H5Lget_name_by_idx"); + + ret = H5Oget_info_by_idx3(gid, ".", H5_INDEX_NAME, H5_ITER_INC, (hsize_t)0, &oinfo, H5O_INFO_BASIC, + H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oget_info_by_idx3"); + VERIFY(oinfo.type, H5O_TYPE_DATASET, "H5Oget_info_by_idx3"); + + /* Unlink one of the objects in the dereferenced group */ + ret = H5Ldelete(gid, GROUPNAME2, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + + /* Delete dataset object in dereferenced group (with other dataset still open) */ + ret = H5Ldelete(gid, DSETNAME2, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + + /* Close objects */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Destroy reference */ + ret = H5Rdestroy(&rref); + CHECK(ret, FAIL, "H5Rdestroy"); +} /* test_reference_group() */ + +/**************************************************************** +** +** test_reference_attr(): Test basic H5R (reference) attribute reference code. +** Tests references to attributes on various kinds of objects +** +****************************************************************/ +static void +test_reference_attr(void) +{ + hid_t fid; /* HDF5 File ID */ + hid_t dataset; /* Dataset ID */ + hid_t group; /* Group ID */ + hid_t attr; /* Attribute ID */ + hid_t sid; /* Dataspace ID */ + hid_t tid; /* Datatype ID */ + hsize_t dims[] = {SPACE1_DIM1}; + hid_t dapl_id; /* Dataset access property list */ + H5R_ref_t ref_wbuf[SPACE1_DIM1], /* Buffer to write to disk */ + ref_rbuf[SPACE1_DIM1]; /* Buffer read from disk */ + unsigned wbuf[SPACE1_DIM1], rbuf[SPACE1_DIM1]; + unsigned i; /* Local index variables */ + H5O_type_t obj_type; /* Object type */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Attribute Reference Functions\n")); + + /* Create file */ + fid = H5Fcreate(FILE_REF_ATTR, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, H5I_INVALID_HID, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid = H5Screate_simple(SPACE1_RANK, dims, NULL); + CHECK(sid, H5I_INVALID_HID, "H5Screate_simple"); + + /* Create dataset access property list */ + dapl_id = H5Pcreate(H5P_DATASET_ACCESS); + CHECK(dapl_id, H5I_INVALID_HID, "H5Pcreate"); + + /* Create a group */ + group = H5Gcreate2(fid, "Group1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(group, H5I_INVALID_HID, "H5Gcreate2"); + + /* Create an attribute for the dataset */ + attr = H5Acreate2(group, "Attr2", H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, H5I_INVALID_HID, "H5Acreate2"); + + for (i = 0; i < SPACE1_DIM1; i++) + wbuf[i] = (i * 3) + 1; + + /* Write attribute to disk */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, wbuf); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Create a dataset (inside Group1) */ + dataset = H5Dcreate2(group, "Dataset1", H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dcreate2"); + + /* Create an attribute for the dataset */ + attr = H5Acreate2(dataset, "Attr1", H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, H5I_INVALID_HID, "H5Acreate2"); + + for (i = 0; i < SPACE1_DIM1; i++) + wbuf[i] = i * 3; + + /* Write attribute to disk */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, wbuf); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Create another dataset (inside Group1) */ + dataset = H5Dcreate2(group, "Dataset2", H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dcreate2"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Create a datatype to refer to */ + tid = H5Tcreate(H5T_COMPOUND, sizeof(s1_t)); + CHECK(tid, H5I_INVALID_HID, "H5Tcreate"); + + /* Insert fields */ + ret = H5Tinsert(tid, "a", HOFFSET(s1_t, a), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(tid, "b", HOFFSET(s1_t, b), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(tid, "c", HOFFSET(s1_t, c), H5T_NATIVE_FLOAT); + CHECK(ret, FAIL, "H5Tinsert"); + + /* Save datatype for later */ + ret = H5Tcommit2(group, "Datatype1", tid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + + /* Create an attribute for the datatype */ + attr = H5Acreate2(tid, "Attr3", H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, H5I_INVALID_HID, "H5Acreate2"); + + for (i = 0; i < SPACE1_DIM1; i++) + wbuf[i] = (i * 3) + 2; + + /* Write attribute to disk */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, wbuf); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close datatype */ + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close group */ + ret = H5Gclose(group); + CHECK(ret, FAIL, "H5Gclose"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid, "Dataset3", H5T_STD_REF, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dcreate2"); + + /* Create reference to dataset1 attribute */ + ret = H5Rcreate_attr(fid, "/Group1/Dataset1", "Attr1", H5P_DEFAULT, &ref_wbuf[0]); + CHECK(ret, FAIL, "H5Rcreate_attr"); + ret = H5Rget_obj_type3(&ref_wbuf[0], H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_DATASET, "H5Rget_obj_type3"); + + /* Create reference to dataset2 attribute */ + ret = H5Rcreate_attr(fid, "/Group1/Dataset2", "Attr1", H5P_DEFAULT, &ref_wbuf[1]); + CHECK(ret, FAIL, "H5Rcreate_attr"); + ret = H5Rget_obj_type3(&ref_wbuf[1], H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_DATASET, "H5Rget_obj_type3"); + + /* Create reference to group attribute */ + ret = H5Rcreate_attr(fid, "/Group1", "Attr2", H5P_DEFAULT, &ref_wbuf[2]); + CHECK(ret, FAIL, "H5Rcreate_attr"); + ret = H5Rget_obj_type3(&ref_wbuf[2], H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_GROUP, "H5Rget_obj_type3"); + + /* Create reference to named datatype attribute */ + ret = H5Rcreate_attr(fid, "/Group1/Datatype1", "Attr3", H5P_DEFAULT, &ref_wbuf[3]); + CHECK(ret, FAIL, "H5Rcreate_attr"); + ret = H5Rget_obj_type3(&ref_wbuf[3], H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_NAMED_DATATYPE, "H5Rget_obj_type3"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, ref_wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close disk dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open the file */ + fid = H5Fopen(FILE_REF_ATTR, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* Open the dataset */ + dataset = H5Dopen2(fid, "/Dataset3", H5P_DEFAULT); + CHECK(ret, H5I_INVALID_HID, "H5Dopen2"); + + /* Read selection from disk */ + ret = H5Dread(dataset, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, ref_rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Open attribute on dataset object */ + attr = H5Ropen_attr(&ref_rbuf[0], H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, H5I_INVALID_HID, "H5Ropen_attr"); + + /* Check information in referenced dataset */ + sid = H5Aget_space(attr); + CHECK(sid, H5I_INVALID_HID, "H5Aget_space"); + + ret = (int)H5Sget_simple_extent_npoints(sid); + VERIFY(ret, SPACE1_DIM1, "H5Sget_simple_extent_npoints"); + + /* Read from disk */ + ret = H5Aread(attr, H5T_NATIVE_UINT, rbuf); + CHECK(ret, FAIL, "H5Aread"); + + for (i = 0; i < SPACE1_DIM1; i++) + VERIFY(rbuf[i], i * 3, "Data"); + + /* Close dereferenced Dataset */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Open attribute on group object */ + attr = H5Ropen_attr(&ref_rbuf[2], H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, H5I_INVALID_HID, "H5Ropen_attr"); + + /* Read from disk */ + ret = H5Aread(attr, H5T_NATIVE_UINT, rbuf); + CHECK(ret, FAIL, "H5Aread"); + + for (i = 0; i < SPACE1_DIM1; i++) + VERIFY(rbuf[i], (i * 3) + 1, "Data"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Open attribute on named datatype object */ + attr = H5Ropen_attr(&ref_rbuf[3], H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, H5I_INVALID_HID, "H5Ropen_attr"); + + /* Read from disk */ + ret = H5Aread(attr, H5T_NATIVE_UINT, rbuf); + CHECK(ret, FAIL, "H5Aread"); + + for (i = 0; i < SPACE1_DIM1; i++) + VERIFY(rbuf[i], (i * 3) + 2, "Data"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close dataset access property list */ + ret = H5Pclose(dapl_id); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free memory buffers */ + for (i = 0; i < SPACE1_DIM1; i++) { + ret = H5Rdestroy(&ref_wbuf[i]); + CHECK(ret, FAIL, "H5Rdestroy"); + ret = H5Rdestroy(&ref_rbuf[i]); + CHECK(ret, FAIL, "H5Rdestroy"); + } +} /* test_reference_attr() */ + +/**************************************************************** +** +** test_reference_external(): +** Tests external references on various kinds of objects +** +****************************************************************/ +static void +test_reference_external(void) +{ + hid_t fid1, fid2; /* HDF5 File ID */ + hid_t dataset; /* Dataset ID */ + hid_t group; /* Group ID */ + hid_t attr; /* Attribute ID */ + hid_t sid; /* Dataspace ID */ + hid_t tid; /* Datatype ID */ + hsize_t dims[] = {SPACE1_DIM1}; + hid_t dapl_id; /* Dataset access property list */ + H5R_ref_t ref_wbuf[SPACE1_DIM1], /* Buffer to write to disk */ + ref_rbuf[SPACE1_DIM1]; /* Buffer read from disk */ + unsigned wbuf[SPACE1_DIM1], rbuf[SPACE1_DIM1]; + unsigned i; /* Local index variables */ + H5O_type_t obj_type; /* Object type */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing External References Functions\n")); + + /* Create file */ + fid1 = H5Fcreate(FILE_REF_EXT1, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, H5I_INVALID_HID, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid = H5Screate_simple(SPACE1_RANK, dims, NULL); + CHECK(sid, H5I_INVALID_HID, "H5Screate_simple"); + + /* Create dataset access property list */ + dapl_id = H5Pcreate(H5P_DATASET_ACCESS); + CHECK(dapl_id, H5I_INVALID_HID, "H5Pcreate"); + + /* Create a group */ + group = H5Gcreate2(fid1, "Group1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(group, H5I_INVALID_HID, "H5Gcreate2"); + + /* Create an attribute for the dataset */ + attr = H5Acreate2(group, "Attr2", H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, H5I_INVALID_HID, "H5Acreate2"); + + for (i = 0; i < SPACE1_DIM1; i++) + wbuf[i] = (i * 3) + 1; + + /* Write attribute to disk */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, wbuf); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Create a dataset (inside Group1) */ + dataset = H5Dcreate2(group, "Dataset1", H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dcreate2"); + + /* Create an attribute for the dataset */ + attr = H5Acreate2(dataset, "Attr1", H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, H5I_INVALID_HID, "H5Acreate2"); + + for (i = 0; i < SPACE1_DIM1; i++) + wbuf[i] = i * 3; + + /* Write attribute to disk */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, wbuf); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Create another dataset (inside Group1) */ + dataset = H5Dcreate2(group, "Dataset2", H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dcreate2"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Create a datatype to refer to */ + tid = H5Tcreate(H5T_COMPOUND, sizeof(s1_t)); + CHECK(tid, H5I_INVALID_HID, "H5Tcreate"); + + /* Insert fields */ + ret = H5Tinsert(tid, "a", HOFFSET(s1_t, a), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(tid, "b", HOFFSET(s1_t, b), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(tid, "c", HOFFSET(s1_t, c), H5T_NATIVE_FLOAT); + CHECK(ret, FAIL, "H5Tinsert"); + + /* Save datatype for later */ + ret = H5Tcommit2(group, "Datatype1", tid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + + /* Create an attribute for the datatype */ + attr = H5Acreate2(tid, "Attr3", H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, H5I_INVALID_HID, "H5Acreate2"); + + for (i = 0; i < SPACE1_DIM1; i++) + wbuf[i] = (i * 3) + 2; + + /* Write attribute to disk */ + ret = H5Awrite(attr, H5T_NATIVE_UINT, wbuf); + CHECK(ret, FAIL, "H5Awrite"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close datatype */ + ret = H5Tclose(tid); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close group */ + ret = H5Gclose(group); + CHECK(ret, FAIL, "H5Gclose"); + + /* Create reference to dataset1 attribute */ + ret = H5Rcreate_attr(fid1, "/Group1/Dataset1", "Attr1", H5P_DEFAULT, &ref_wbuf[0]); + CHECK(ret, FAIL, "H5Rcreate_attr"); + ret = H5Rget_obj_type3(&ref_wbuf[0], H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_DATASET, "H5Rget_obj_type3"); + + /* Create reference to dataset2 attribute */ + ret = H5Rcreate_attr(fid1, "/Group1/Dataset2", "Attr1", H5P_DEFAULT, &ref_wbuf[1]); + CHECK(ret, FAIL, "H5Rcreate_attr"); + ret = H5Rget_obj_type3(&ref_wbuf[1], H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_DATASET, "H5Rget_obj_type3"); + + /* Create reference to group attribute */ + ret = H5Rcreate_attr(fid1, "/Group1", "Attr2", H5P_DEFAULT, &ref_wbuf[2]); + CHECK(ret, FAIL, "H5Rcreate_attr"); + ret = H5Rget_obj_type3(&ref_wbuf[2], H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_GROUP, "H5Rget_obj_type3"); + + /* Create reference to named datatype attribute */ + ret = H5Rcreate_attr(fid1, "/Group1/Datatype1", "Attr3", H5P_DEFAULT, &ref_wbuf[3]); + CHECK(ret, FAIL, "H5Rcreate_attr"); + ret = H5Rget_obj_type3(&ref_wbuf[3], H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_NAMED_DATATYPE, "H5Rget_obj_type3"); + + /* Close disk dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Create file */ + fid2 = H5Fcreate(FILE_REF_EXT2, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid2, H5I_INVALID_HID, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid = H5Screate_simple(SPACE1_RANK, dims, NULL); + CHECK(sid, H5I_INVALID_HID, "H5Screate_simple"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid2, "Dataset3", H5T_STD_REF, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, ref_wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close disk dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid2); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open the file */ + fid2 = H5Fopen(FILE_REF_EXT2, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid2, FAIL, "H5Fopen"); + + /* Open the dataset */ + dataset = H5Dopen2(fid2, "/Dataset3", H5P_DEFAULT); + CHECK(ret, H5I_INVALID_HID, "H5Dopen2"); + + /* Read selection from disk */ + ret = H5Dread(dataset, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, ref_rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Open attribute on dataset object */ + attr = H5Ropen_attr(&ref_rbuf[0], H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, H5I_INVALID_HID, "H5Ropen_attr"); + + /* Check information in referenced dataset */ + sid = H5Aget_space(attr); + CHECK(sid, H5I_INVALID_HID, "H5Aget_space"); + + ret = (int)H5Sget_simple_extent_npoints(sid); + VERIFY(ret, SPACE1_DIM1, "H5Sget_simple_extent_npoints"); + + /* Read from disk */ + ret = H5Aread(attr, H5T_NATIVE_UINT, rbuf); + CHECK(ret, FAIL, "H5Aread"); + + for (i = 0; i < SPACE1_DIM1; i++) + VERIFY(rbuf[i], i * 3, "Data"); + + /* Close dereferenced Dataset */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Open attribute on group object */ + attr = H5Ropen_attr(&ref_rbuf[2], H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, H5I_INVALID_HID, "H5Ropen_attr"); + + /* Read from disk */ + ret = H5Aread(attr, H5T_NATIVE_UINT, rbuf); + CHECK(ret, FAIL, "H5Aread"); + + for (i = 0; i < SPACE1_DIM1; i++) + VERIFY(rbuf[i], (i * 3) + 1, "Data"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Open attribute on named datatype object */ + attr = H5Ropen_attr(&ref_rbuf[3], H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr, H5I_INVALID_HID, "H5Ropen_attr"); + + /* Read from disk */ + ret = H5Aread(attr, H5T_NATIVE_UINT, rbuf); + CHECK(ret, FAIL, "H5Aread"); + + for (i = 0; i < SPACE1_DIM1; i++) + VERIFY(rbuf[i], (i * 3) + 2, "Data"); + + /* Close attribute */ + ret = H5Aclose(attr); + CHECK(ret, FAIL, "H5Aclose"); + + /* Close dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close dataset access property list */ + ret = H5Pclose(dapl_id); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid2); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free memory buffers */ + for (i = 0; i < SPACE1_DIM1; i++) { + ret = H5Rdestroy(&ref_wbuf[i]); + CHECK(ret, FAIL, "H5Rdestroy"); + ret = H5Rdestroy(&ref_rbuf[i]); + CHECK(ret, FAIL, "H5Rdestroy"); + } +} /* test_reference_external() */ + +/**************************************************************** +** +** test_reference_compat_conv(): Test basic H5R (reference) object reference code. +** Tests deprecated API routines and type conversion. +** +****************************************************************/ +#if 0 +static void +test_reference_compat_conv(void) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset, dset2; /* Dataset ID */ + hid_t group, group2; /* Group ID */ + hid_t sid1, sid2, sid3; /* Dataspace IDs */ + hid_t tid1, tid2; /* Datatype ID */ + hsize_t dims1[] = {SPACE1_DIM1}, dims2[] = {SPACE2_DIM1, SPACE2_DIM2}, + dims3[] = {SPACE1_DIM1}; /* Purposely set dimension larger to test NULL references */ + hsize_t start[SPACE2_RANK]; /* Starting location of hyperslab */ + hsize_t stride[SPACE2_RANK]; /* Stride of hyperslab */ + hsize_t count[SPACE2_RANK]; /* Element count of hyperslab */ + hsize_t block[SPACE2_RANK]; /* Block size of hyperslab */ + hsize_t coord1[POINT1_NPOINTS][SPACE2_RANK]; /* Coordinates for point selection */ + hobj_ref_t *wbuf_obj = NULL; /* Buffer to write to disk */ + H5R_ref_t *rbuf_obj = NULL; /* Buffer read from disk */ + hdset_reg_ref_t *wbuf_reg = NULL; /* Buffer to write to disk */ + H5R_ref_t *rbuf_reg = NULL; /* Buffer read from disk */ + H5O_type_t obj_type; /* Object type */ + herr_t ret; /* Generic return value */ + unsigned int i; /* Counter */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Deprecated Object Reference Functions\n")); + + /* Allocate write & read buffers */ + wbuf_obj = (hobj_ref_t *)HDcalloc(sizeof(hobj_ref_t), SPACE1_DIM1); + rbuf_obj = HDcalloc(sizeof(H5R_ref_t), SPACE1_DIM1); + wbuf_reg = HDcalloc(sizeof(hdset_reg_ref_t), SPACE1_DIM1); + rbuf_reg = HDcalloc(sizeof(H5R_ref_t), SPACE1_DIM1); + + /* Create file */ + fid1 = H5Fcreate(FILE_REF_COMPAT, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, H5I_INVALID_HID, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, H5I_INVALID_HID, "H5Screate_simple"); + + /* Create another dataspace for datasets */ + sid2 = H5Screate_simple(SPACE2_RANK, dims2, NULL); + CHECK(sid2, H5I_INVALID_HID, "H5Screate_simple"); + + /* Create another dataspace for datasets */ + sid3 = H5Screate_simple(SPACE1_RANK, dims3, NULL); + CHECK(sid3, H5I_INVALID_HID, "H5Screate_simple"); + + /* Create a group */ + group = H5Gcreate2(fid1, "Group1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(group, H5I_INVALID_HID, "H5Gcreate2"); + + /* Create a dataset (inside Group1) */ + dataset = H5Dcreate2(group, "Dataset1", H5T_NATIVE_UINT, sid2, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dcreate2"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Create another dataset (inside Group1) */ + dataset = H5Dcreate2(group, "Dataset2", H5T_NATIVE_UCHAR, sid2, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dcreate2"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Create a datatype to refer to */ + tid1 = H5Tcreate(H5T_COMPOUND, sizeof(s1_t)); + CHECK(tid1, H5I_INVALID_HID, "H5Tcreate"); + + /* Insert fields */ + ret = H5Tinsert(tid1, "a", HOFFSET(s1_t, a), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(tid1, "b", HOFFSET(s1_t, b), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(tid1, "c", HOFFSET(s1_t, c), H5T_NATIVE_FLOAT); + CHECK(ret, FAIL, "H5Tinsert"); + + /* Save datatype for later */ + ret = H5Tcommit2(group, "Datatype1", tid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close group */ + ret = H5Gclose(group); + CHECK(ret, FAIL, "H5Gclose"); + + /* Create a dataset with object reference datatype */ + dataset = H5Dcreate2(fid1, "Dataset3", H5T_STD_REF_OBJ, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dcreate2"); + + /* Create reference to dataset */ + ret = H5Rcreate(&wbuf_obj[0], fid1, "/Group1/Dataset1", H5R_OBJECT, H5I_INVALID_HID); + CHECK(ret, FAIL, "H5Rcreate"); + + /* Create reference to dataset */ + ret = H5Rcreate(&wbuf_obj[1], fid1, "/Group1/Dataset2", H5R_OBJECT, H5I_INVALID_HID); + CHECK(ret, FAIL, "H5Rcreate"); + + /* Create reference to group */ + ret = H5Rcreate(&wbuf_obj[2], fid1, "/Group1", H5R_OBJECT, H5I_INVALID_HID); + CHECK(ret, FAIL, "H5Rcreate"); + + /* Create reference to named datatype */ + ret = H5Rcreate(&wbuf_obj[3], fid1, "/Group1/Datatype1", H5R_OBJECT, H5I_INVALID_HID); + CHECK(ret, FAIL, "H5Rcreate"); + + /* Write references to disk */ + ret = H5Dwrite(dataset, H5T_STD_REF_OBJ, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf_obj); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Create a dataset with region reference datatype */ + dataset = H5Dcreate2(fid1, "Dataset4", H5T_STD_REF_DSETREG, sid3, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dcreate2"); + + /* Select 6x6 hyperslab for first reference */ + start[0] = 2; + start[1] = 2; + stride[0] = 1; + stride[1] = 1; + count[0] = 1; + count[1] = 1; + block[0] = 6; + block[1] = 6; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create first dataset region */ + ret = H5Rcreate(&wbuf_reg[0], fid1, "/Group1/Dataset1", H5R_DATASET_REGION, sid2); + CHECK(ret, FAIL, "H5Rcreate"); + + /* Select sequence of ten points for second reference */ + coord1[0][0] = 6; + coord1[0][1] = 9; + coord1[1][0] = 2; + coord1[1][1] = 2; + coord1[2][0] = 8; + coord1[2][1] = 4; + coord1[3][0] = 1; + coord1[3][1] = 6; + coord1[4][0] = 2; + coord1[4][1] = 8; + coord1[5][0] = 3; + coord1[5][1] = 2; + coord1[6][0] = 0; + coord1[6][1] = 4; + coord1[7][0] = 9; + coord1[7][1] = 0; + coord1[8][0] = 7; + coord1[8][1] = 1; + coord1[9][0] = 3; + coord1[9][1] = 3; + ret = H5Sselect_elements(sid2, H5S_SELECT_SET, (size_t)POINT1_NPOINTS, (const hsize_t *)coord1); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Create second dataset region */ + ret = H5Rcreate(&wbuf_reg[1], fid1, "/Group1/Dataset2", H5R_DATASET_REGION, sid2); + CHECK(ret, FAIL, "H5Rcreate"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_STD_REF_DSETREG, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf_reg); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close disk dataspaces */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(sid3); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open the file */ + fid1 = H5Fopen(FILE_REF_COMPAT, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid1, H5I_INVALID_HID, "H5Fopen"); + + /* Open the object reference dataset */ + dataset = H5Dopen2(fid1, "/Dataset3", H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dopen2"); + + /* Read selection from disk */ + ret = H5Dread(dataset, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf_obj); + CHECK(ret, FAIL, "H5Dread"); + + /* Verify type of objects pointed at */ + ret = H5Rget_obj_type3(&rbuf_obj[0], H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_DATASET, "H5Rget_obj_type3"); + + ret = H5Rget_obj_type3(&rbuf_obj[1], H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_DATASET, "H5Rget_obj_type3"); + + ret = H5Rget_obj_type3(&rbuf_obj[2], H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_GROUP, "H5Rget_obj_type3"); + + ret = H5Rget_obj_type3(&rbuf_obj[3], H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_NAMED_DATATYPE, "H5Rget_obj_type3"); + + /* Make sure the referenced objects can be opened */ + dset2 = H5Ropen_object(&rbuf_obj[0], H5P_DEFAULT, H5P_DEFAULT); + CHECK(dset2, H5I_INVALID_HID, "H5Ropen_object"); + + ret = H5Dclose(dset2); + CHECK(ret, FAIL, "H5Dclose"); + + dset2 = H5Ropen_object(&rbuf_obj[1], H5P_DEFAULT, H5P_DEFAULT); + CHECK(dset2, H5I_INVALID_HID, "H5Ropen_object"); + + ret = H5Dclose(dset2); + CHECK(ret, FAIL, "H5Dclose"); + + group2 = H5Ropen_object(&rbuf_obj[2], H5P_DEFAULT, H5P_DEFAULT); + CHECK(group2, H5I_INVALID_HID, "H5Ropen_object"); + + ret = H5Gclose(group2); + CHECK(ret, FAIL, "H5Gclose"); + + tid2 = H5Ropen_object(&rbuf_obj[3], H5P_DEFAULT, H5P_DEFAULT); + CHECK(tid2, H5I_INVALID_HID, "H5Ropen_object"); + + ret = H5Tclose(tid2); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Open the dataset region reference dataset */ + dataset = H5Dopen2(fid1, "/Dataset4", H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dopen2"); + + /* Read selection from disk */ + ret = H5Dread(dataset, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf_reg); + CHECK(ret, FAIL, "H5Dread"); + + /* Verify type of objects pointed at */ + ret = H5Rget_obj_type3(&rbuf_reg[0], H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_DATASET, "H5Rget_obj_type3"); + + ret = H5Rget_obj_type3(&rbuf_reg[1], H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_DATASET, "H5Rget_obj_type3"); + + /* Make sure the referenced objects can be opened */ + dset2 = H5Ropen_object(&rbuf_reg[0], H5P_DEFAULT, H5P_DEFAULT); + CHECK(dset2, H5I_INVALID_HID, "H5Ropen_object"); + + ret = H5Dclose(dset2); + CHECK(ret, FAIL, "H5Dclose"); + + dset2 = H5Ropen_object(&rbuf_reg[1], H5P_DEFAULT, H5P_DEFAULT); + CHECK(dset2, H5I_INVALID_HID, "H5Ropen_object"); + + ret = H5Dclose(dset2); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Destroy references */ + for (i = 0; i < dims1[0]; i++) { + ret = H5Rdestroy(&rbuf_obj[i]); + CHECK(ret, FAIL, "H5Rdestroy"); + } + for (i = 0; i < dims3[0]; i++) { + ret = H5Rdestroy(&rbuf_reg[i]); + CHECK(ret, FAIL, "H5Rdestroy"); + } + + /* Free memory buffers */ + HDfree(wbuf_obj); + HDfree(rbuf_obj); + HDfree(wbuf_reg); + HDfree(rbuf_reg); +} /* test_reference_compat() */ +#endif + +/**************************************************************** +** +** test_reference_perf(): Test basic H5R (reference) object reference +** performance. +** +****************************************************************/ +static void +test_reference_perf(void) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset, /* Dataset ID */ + dset2; /* Dereferenced dataset ID */ + hid_t group; /* Group ID */ + hid_t sid1; /* Dataspace ID */ + hid_t tid1; /* Datatype ID */ + hsize_t dims1[] = {1}; + hid_t dapl_id; /* Dataset access property list */ + H5R_ref_t *wbuf, /* buffer to write to disk */ + *rbuf, /* buffer read from disk */ + *tbuf; /* temp. buffer read from disk */ + H5R_ref_t *wbuf_reg, /* buffer to write to disk */ + *rbuf_reg; /* buffer read from disk */ + hobj_ref_t *wbuf_deprec, /* deprecated references */ + *rbuf_deprec; /* deprecated references */ + hdset_reg_ref_t *wbuf_reg_deprec, /* deprecated references*/ + *rbuf_reg_deprec; /* deprecated references*/ + unsigned *ibuf, *obuf; + unsigned i, j; /* Counters */ + H5O_type_t obj_type; /* Object type */ + herr_t ret; /* Generic return value */ + double t1, t2, t; /* Timers */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Object Reference Performance\n")); + + /* Allocate write & read buffers */ + wbuf = HDcalloc(sizeof(H5R_ref_t), SPACE1_DIM1); + obuf = HDcalloc(sizeof(unsigned), SPACE1_DIM1); + ibuf = HDcalloc(sizeof(unsigned), SPACE1_DIM1); + wbuf_deprec = (hobj_ref_t *)HDcalloc(sizeof(hobj_ref_t), SPACE1_DIM1); + rbuf = (H5R_ref_t *)HDcalloc(sizeof(H5R_ref_t), SPACE1_DIM1); + rbuf_deprec = (hobj_ref_t *)HDcalloc(sizeof(hobj_ref_t), SPACE1_DIM1); + tbuf = (H5R_ref_t *)HDcalloc(sizeof(H5R_ref_t), SPACE1_DIM1); + wbuf_reg = (H5R_ref_t *)HDcalloc(sizeof(H5R_ref_t), SPACE1_DIM1); + rbuf_reg = (H5R_ref_t *)HDcalloc(sizeof(H5R_ref_t), SPACE1_DIM1); + wbuf_reg_deprec = (hdset_reg_ref_t *)HDcalloc(sizeof(hdset_reg_ref_t), SPACE1_DIM1); + rbuf_reg_deprec = (hdset_reg_ref_t *)HDcalloc(sizeof(hdset_reg_ref_t), SPACE1_DIM1); + + for (i = 0; i < SPACE1_DIM1; i++) + obuf[i] = i * 3; + + /* Create file */ + fid1 = H5Fcreate(FILE_REF_OBJ, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, H5I_INVALID_HID, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, H5I_INVALID_HID, "H5Screate_simple"); + + /* Create dataset access property list */ + dapl_id = H5Pcreate(H5P_DATASET_ACCESS); + CHECK(dapl_id, H5I_INVALID_HID, "H5Pcreate"); + + /* Create a group */ + group = H5Gcreate2(fid1, "Group1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(group, H5I_INVALID_HID, "H5Gcreate2"); + + /* Create a dataset (inside Group1) */ + dataset = H5Dcreate2(group, "Dataset1", H5T_NATIVE_UINT, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_UINT, H5S_ALL, H5S_ALL, H5P_DEFAULT, obuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Create another dataset (inside Group1) */ + dataset = H5Dcreate2(group, "Dataset2", H5T_NATIVE_UCHAR, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Create a datatype to refer to */ + tid1 = H5Tcreate(H5T_COMPOUND, sizeof(s1_t)); + CHECK(tid1, H5I_INVALID_HID, "H5Tcreate"); + + /* Insert fields */ + ret = H5Tinsert(tid1, "a", HOFFSET(s1_t, a), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(tid1, "b", HOFFSET(s1_t, b), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(tid1, "c", HOFFSET(s1_t, c), H5T_NATIVE_FLOAT); + CHECK(ret, FAIL, "H5Tinsert"); + + /* Save datatype for later */ + ret = H5Tcommit2(group, "Datatype1", tid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close group */ + ret = H5Gclose(group); + CHECK(ret, FAIL, "H5Gclose"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, "Dataset3", H5T_STD_REF, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dcreate2"); + + t = 0; + for (i = 0; i < MAX_ITER_CREATE; i++) { + t1 = H5_get_time(); + ret = H5Rcreate_object(fid1, "/Group1/Dataset1", H5P_DEFAULT, &wbuf[0]); + CHECK(ret, FAIL, "H5Rcreate_object"); + t2 = H5_get_time(); + t += t2 - t1; + ret = H5Rdestroy(&wbuf[0]); + CHECK(ret, FAIL, "H5Rdestroy"); + } + if (VERBOSE_MED) + HDprintf("--- Object reference create time: %lfs\n", t / MAX_ITER_CREATE); + + /* Create reference to dataset */ + ret = H5Rcreate_object(fid1, "/Group1/Dataset1", H5P_DEFAULT, &wbuf[0]); + CHECK(ret, FAIL, "H5Rcreate_object"); + ret = H5Rget_obj_type3(&wbuf[0], H5P_DEFAULT, &obj_type); + CHECK(ret, FAIL, "H5Rget_obj_type3"); + VERIFY(obj_type, H5O_TYPE_DATASET, "H5Rget_obj_type3"); + + t = 0; + for (i = 0; i < MAX_ITER_WRITE; i++) { + t1 = H5_get_time(); + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + t2 = H5_get_time(); + t += t2 - t1; + } + if (VERBOSE_MED) + HDprintf("--- Object reference write time: %lfs\n", t / MAX_ITER_WRITE); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); +#if 0 + /* Create a dataset */ + dataset = H5Dcreate2(fid1, "Dataset4", H5T_STD_REF_OBJ, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dcreate2"); + + t = 0; + for (i = 0; i < MAX_ITER_CREATE; i++) { + t1 = H5_get_time(); + ret = H5Rcreate(&wbuf_deprec[0], fid1, "/Group1/Dataset1", H5R_OBJECT1, H5I_INVALID_HID); + CHECK(ret, FAIL, "H5Rcreate"); + t2 = H5_get_time(); + t += t2 - t1; + } + if (VERBOSE_MED) + HDprintf("--- Deprecated object reference create time: %lfs\n", t / MAX_ITER_CREATE); + + /* Create reference to dataset */ + ret = H5Rcreate(&wbuf_deprec[0], fid1, "/Group1/Dataset1", H5R_OBJECT1, H5I_INVALID_HID); + CHECK(ret, FAIL, "H5Rcreate"); + + t = 0; + for (i = 0; i < MAX_ITER_WRITE; i++) { + t1 = H5_get_time(); + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_STD_REF_OBJ, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf_deprec); + CHECK(ret, FAIL, "H5Dwrite"); + t2 = H5_get_time(); + t += t2 - t1; + } + if (VERBOSE_MED) + HDprintf("--- Deprecated object reference write time: %lfs\n", t / MAX_ITER_WRITE); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); +#endif + /* Create a dataset */ + dataset = H5Dcreate2(fid1, "Dataset5", H5T_STD_REF, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dcreate2"); + + t = 0; + for (i = 0; i < MAX_ITER_CREATE; i++) { + t1 = H5_get_time(); + /* Store first dataset region */ + ret = H5Rcreate_region(fid1, "/Group1/Dataset1", sid1, H5P_DEFAULT, &wbuf_reg[0]); + CHECK(ret, FAIL, "H5Rcreate_region"); + t2 = H5_get_time(); + t += t2 - t1; + ret = H5Rdestroy(&wbuf_reg[0]); + CHECK(ret, FAIL, "H5Rdestroy"); + } + if (VERBOSE_MED) + HDprintf("--- Region reference create time: %lfs\n", t / MAX_ITER_CREATE); + + /* Store first dataset region */ + ret = H5Rcreate_region(fid1, "/Group1/Dataset1", sid1, H5P_DEFAULT, &wbuf_reg[0]); + CHECK(ret, FAIL, "H5Rcreate_region"); + + t = 0; + for (i = 0; i < MAX_ITER_WRITE; i++) { + t1 = H5_get_time(); + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf_reg); + CHECK(ret, FAIL, "H5Dwrite"); + t2 = H5_get_time(); + t += t2 - t1; + } + if (VERBOSE_MED) + HDprintf("--- Region reference write time: %lfs\n", t / MAX_ITER_WRITE); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); +#if 0 + /* Create a dataset */ + dataset = H5Dcreate2(fid1, "Dataset6", H5T_STD_REF_DSETREG, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dcreate2"); + + t = 0; + for (i = 0; i < MAX_ITER_CREATE; i++) { + t1 = H5_get_time(); + /* Store first dataset region */ + ret = H5Rcreate(&wbuf_reg_deprec[0], fid1, "/Group1/Dataset1", H5R_DATASET_REGION1, sid1); + CHECK(ret, FAIL, "H5Rcreate"); + t2 = H5_get_time(); + t += t2 - t1; + } + if (VERBOSE_MED) + HDprintf("--- Deprecated region reference create time: %lfs\n", t / MAX_ITER_CREATE); + + t = 0; + for (i = 0; i < MAX_ITER_WRITE; i++) { + t1 = H5_get_time(); + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_STD_REF_DSETREG, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf_reg_deprec); + CHECK(ret, FAIL, "H5Dwrite"); + t2 = H5_get_time(); + t += t2 - t1; + } + if (VERBOSE_MED) + HDprintf("--- Deprecated region reference write time: %lfs\n", t / MAX_ITER_WRITE); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); +#endif + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open the file */ + fid1 = H5Fopen(FILE_REF_OBJ, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid1, H5I_INVALID_HID, "H5Fopen"); + + /* Open the dataset */ + dataset = H5Dopen2(fid1, "/Dataset3", H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dopen2"); + + t = 0; + for (i = 0; i < MAX_ITER_READ; i++) { + t1 = H5_get_time(); + /* Read selection from disk */ + ret = H5Dread(dataset, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf); + CHECK(ret, FAIL, "H5Dread"); + t2 = H5_get_time(); + t += t2 - t1; + ret = H5Rdestroy(&rbuf[0]); + CHECK(ret, FAIL, "H5Rdestroy"); + } + if (VERBOSE_MED) + HDprintf("--- Object reference read time: %lfs\n", t / MAX_ITER_READ); + + /* Read selection from disk */ + ret = H5Dread(dataset, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Open dataset object */ + dset2 = H5Ropen_object(&rbuf[0], H5P_DEFAULT, dapl_id); + CHECK(dset2, H5I_INVALID_HID, "H5Ropen_object"); + + /* Check information in referenced dataset */ + sid1 = H5Dget_space(dset2); + CHECK(sid1, H5I_INVALID_HID, "H5Dget_space"); + + ret = (int)H5Sget_simple_extent_npoints(sid1); + VERIFY(ret, dims1[0], "H5Sget_simple_extent_npoints"); + + /* Read from disk */ + ret = H5Dread(dset2, H5T_NATIVE_UINT, H5S_ALL, H5S_ALL, H5P_DEFAULT, ibuf); + CHECK(ret, FAIL, "H5Dread"); + + for (i = 0; i < dims1[0]; i++) + VERIFY(ibuf[i], i * 3, "Data"); + + /* Close dereferenced Dataset */ + ret = H5Dclose(dset2); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); +#if 0 + /* Open the dataset */ + dataset = H5Dopen2(fid1, "/Dataset4", H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dopen2"); + + t = 0; + for (i = 0; i < MAX_ITER_READ; i++) { + t1 = H5_get_time(); + /* Read selection from disk */ + ret = H5Dread(dataset, H5T_STD_REF_OBJ, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf_deprec); + CHECK(ret, FAIL, "H5Dread"); + t2 = H5_get_time(); + t += t2 - t1; + } + if (VERBOSE_MED) + HDprintf("--- Deprecated object reference read time: %lfs\n", t / MAX_ITER_READ); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); +#endif + /* Open the dataset */ + dataset = H5Dopen2(fid1, "/Dataset5", H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dopen2"); + + t = 0; + for (i = 0; i < MAX_ITER_READ; i++) { + t1 = H5_get_time(); + /* Read selection from disk */ + ret = H5Dread(dataset, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf_reg); + CHECK(ret, FAIL, "H5Dread"); + t2 = H5_get_time(); + t += t2 - t1; + ret = H5Rdestroy(&rbuf_reg[0]); + CHECK(ret, FAIL, "H5Rdestroy"); + } + if (VERBOSE_MED) + HDprintf("--- Region reference read time: %lfs\n", t / MAX_ITER_READ); + + /* Read selection from disk */ + ret = H5Dread(dataset, H5T_STD_REF, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf_reg); + CHECK(ret, FAIL, "H5Dread"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); +#if 0 + /* Open the dataset */ + dataset = H5Dopen2(fid1, "/Dataset6", H5P_DEFAULT); + CHECK(dataset, H5I_INVALID_HID, "H5Dopen2"); + + t = 0; + for (i = 0; i < MAX_ITER_READ; i++) { + t1 = H5_get_time(); + /* Read selection from disk */ + ret = H5Dread(dataset, H5T_STD_REF_DSETREG, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf_reg_deprec); + CHECK(ret, FAIL, "H5Dread"); + t2 = H5_get_time(); + t += t2 - t1; + } + if (VERBOSE_MED) + HDprintf("--- Deprecated region reference read time: %lfs\n", t / MAX_ITER_READ); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); +#endif + /* Close dataset access property list */ + ret = H5Pclose(dapl_id); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Destroy references */ + for (j = 0; j < dims1[0]; j++) { + ret = H5Rdestroy(&wbuf[j]); + CHECK(ret, FAIL, "H5Rdestroy"); + ret = H5Rdestroy(&wbuf_reg[j]); + CHECK(ret, FAIL, "H5Rdestroy"); + ret = H5Rdestroy(&rbuf[j]); + CHECK(ret, FAIL, "H5Rdestroy"); + ret = H5Rdestroy(&rbuf_reg[j]); + CHECK(ret, FAIL, "H5Rdestroy"); + } + + /* Free memory buffers */ + HDfree(wbuf); + HDfree(rbuf); + HDfree(wbuf_reg); + HDfree(rbuf_reg); + HDfree(wbuf_deprec); + HDfree(rbuf_deprec); + HDfree(wbuf_reg_deprec); + HDfree(rbuf_reg_deprec); + HDfree(tbuf); + HDfree(ibuf); + HDfree(obuf); +} /* test_reference_perf() */ + +/**************************************************************** +** +** test_reference(): Main H5R reference testing routine. +** +****************************************************************/ +void +test_reference(void) +{ + H5F_libver_t low, high; /* Low and high bounds */ + const char *env_h5_drvr; /* File Driver value from environment */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing References\n")); + + /* Get the VFD to use */ + env_h5_drvr = HDgetenv(HDF5_DRIVER); + if (env_h5_drvr == NULL) + env_h5_drvr = "nomatch"; + + test_reference_params(); /* Test for correct parameter checking */ + test_reference_obj(); /* Test basic H5R object reference code */ + test_reference_vlen_obj(); /* Test reference within vlen */ + test_reference_cmpnd_obj(); /* Test reference within compound type */ + + /* Loop through all the combinations of low/high version bounds */ + for (low = H5F_LIBVER_EARLIEST; low < H5F_LIBVER_NBOUNDS; low++) { + for (high = H5F_LIBVER_EARLIEST; high < H5F_LIBVER_NBOUNDS; high++) { + + /* Invalid combinations, just continue */ + if (high == H5F_LIBVER_EARLIEST || high < low) + continue; + + test_reference_region(low, high); /* Test basic H5R dataset region reference code */ + test_reference_region_1D(low, high); /* Test H5R dataset region reference code for 1-D datasets */ + + } /* end high bound */ + } /* end low bound */ + + /* The following test is currently broken with the Direct VFD */ + if (HDstrcmp(env_h5_drvr, "direct") != 0) { + test_reference_obj_deleted(); /* Test H5R object reference code for deleted objects */ + } + + test_reference_group(); /* Test operations on dereferenced groups */ + test_reference_attr(); /* Test attribute references */ + test_reference_external(); /* Test external references */ +#if 0 + test_reference_compat_conv(); /* Test operations with old types */ +#endif + + test_reference_perf(); + +} /* test_reference() */ + +/*------------------------------------------------------------------------- + * Function: cleanup_reference + * + * Purpose: Cleanup temporary test files + * + * Return: none + * + * Programmer: Quincey Koziol + * September 8, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +void +cleanup_reference(void) +{ + H5Fdelete(FILE_REF_PARAM, H5P_DEFAULT); + H5Fdelete(FILE_REF_OBJ, H5P_DEFAULT); + H5Fdelete(FILE_REF_VL_OBJ, H5P_DEFAULT); + H5Fdelete(FILE_REF_CMPND_OBJ, H5P_DEFAULT); + H5Fdelete(FILE_REF_REG, H5P_DEFAULT); + H5Fdelete(FILE_REF_REG_1D, H5P_DEFAULT); + H5Fdelete(FILE_REF_OBJ_DEL, H5P_DEFAULT); + H5Fdelete(FILE_REF_GRP, H5P_DEFAULT); + H5Fdelete(FILE_REF_ATTR, H5P_DEFAULT); + H5Fdelete(FILE_REF_EXT1, H5P_DEFAULT); + H5Fdelete(FILE_REF_EXT2, H5P_DEFAULT); + H5Fdelete(FILE_REF_COMPAT, H5P_DEFAULT); +} diff --git a/test/API/tselect.c b/test/API/tselect.c new file mode 100644 index 0000000..a2f377d --- /dev/null +++ b/test/API/tselect.c @@ -0,0 +1,16314 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*********************************************************** + * + * Test program: tselect + * + * Test the Dataspace selection functionality + * + *************************************************************/ + +#define H5S_FRIEND /*suppress error about including H5Spkg */ + +/* Define this macro to indicate that the testing APIs should be available */ +#define H5S_TESTING + +#include "testhdf5.h" +#include "hdf5.h" +/* #include "H5Spkg.h" */ /* Dataspaces */ + +#define FILENAME "tselect.h5" + +/* 3-D dataset with fixed dimensions */ +#define SPACE1_NAME "Space1" +#define SPACE1_RANK 3 +#define SPACE1_DIM1 3 +#define SPACE1_DIM2 15 +#define SPACE1_DIM3 13 + +/* 2-D dataset with fixed dimensions */ +#define SPACE2_NAME "Space2" +#define SPACE2_RANK 2 +#define SPACE2_DIM1 30 +#define SPACE2_DIM2 26 +#define SPACE2A_RANK 1 +#define SPACE2A_DIM1 (SPACE2_DIM1 * SPACE2_DIM2) + +/* 2-D dataset with fixed dimensions */ +#define SPACE3_NAME "Space3" +#define SPACE3_RANK 2 +#define SPACE3_DIM1 15 +#define SPACE3_DIM2 26 + +/* 3-D dataset with fixed dimensions */ +#define SPACE4_NAME "Space4" +#define SPACE4_RANK 3 +#define SPACE4_DIM1 11 +#define SPACE4_DIM2 13 +#define SPACE4_DIM3 17 + +/* Number of random hyperslabs to test */ +#define NHYPERSLABS 10 + +/* Number of random hyperslab tests performed */ +#define NRAND_HYPER 100 + +/* 5-D dataset with fixed dimensions */ +#define SPACE5_NAME "Space5" +#define SPACE5_RANK 5 +#define SPACE5_DIM1 10 +#define SPACE5_DIM2 10 +#define SPACE5_DIM3 10 +#define SPACE5_DIM4 10 +#define SPACE5_DIM5 10 + +/* 1-D dataset with same size as 5-D dataset */ +#define SPACE6_RANK 1 +#define SPACE6_DIM1 (SPACE5_DIM1 * SPACE5_DIM2 * SPACE5_DIM3 * SPACE5_DIM4 * SPACE5_DIM5) + +/* 2-D dataset with easy dimension sizes */ +#define SPACE7_NAME "Space7" +#define SPACE7_RANK 2 +#define SPACE7_DIM1 10 +#define SPACE7_DIM2 10 +#define SPACE7_FILL 254 +#define SPACE7_CHUNK_DIM1 5 +#define SPACE7_CHUNK_DIM2 5 +#define SPACE7_NPOINTS 8 + +/* 4-D dataset with fixed dimensions */ +#define SPACE8_NAME "Space8" +#define SPACE8_RANK 4 +#define SPACE8_DIM1 11 +#define SPACE8_DIM2 13 +#define SPACE8_DIM3 17 +#define SPACE8_DIM4 19 + +/* Another 2-D dataset with easy dimension sizes */ +#define SPACE9_RANK 2 +#define SPACE9_DIM1 12 +#define SPACE9_DIM2 12 + +/* Element selection information */ +#define POINT1_NPOINTS 10 + +/* Chunked dataset information */ +#define DATASETNAME "ChunkArray" +#define NX_SUB 87 /* hyperslab dimensions */ +#define NY_SUB 61 +#define NZ_SUB 181 +#define NX 87 /* output buffer dimensions */ +#define NY 61 +#define NZ 181 +#define RANK_F 3 /* File dataspace rank */ +#define RANK_M 3 /* Memory dataspace rank */ +#define X 87 /* dataset dimensions */ +#define Y 61 +#define Z 181 +#define CHUNK_X 87 /* chunk dimensions */ +#define CHUNK_Y 61 +#define CHUNK_Z 181 + +/* Basic chunk size */ +#define SPACE10_DIM1 180 +#define SPACE10_CHUNK_SIZE 12 + +/* Information for bounds checking test */ +#define SPACE11_RANK 2 +#define SPACE11_DIM1 100 +#define SPACE11_DIM2 100 +#define SPACE11_NPOINTS 4 + +/* Information for offsets w/chunks test #2 */ +#define SPACE12_RANK 1 +#define SPACE12_DIM0 25 +#define SPACE12_CHUNK_DIM0 5 + +/* Information for Space rebuild test */ +#define SPACERE1_RANK 1 +#define SPACERE1_DIM0 20 +#define SPACERE2_RANK 2 +#define SPACERE2_DIM0 8 +#define SPACERE2_DIM1 12 +#define SPACERE3_RANK 3 +#define SPACERE3_DIM0 8 +#define SPACERE3_DIM1 12 +#define SPACERE3_DIM2 8 +#define SPACERE4_RANK 4 +#define SPACERE4_DIM0 8 +#define SPACERE4_DIM1 12 +#define SPACERE4_DIM2 8 +#define SPACERE4_DIM3 12 +#define SPACERE5_RANK 5 +#define SPACERE5_DIM0 8 +#define SPACERE5_DIM1 12 +#define SPACERE5_DIM2 8 +#define SPACERE5_DIM3 12 +#define SPACERE5_DIM4 8 + +/* Information for Space update diminfo test */ +#define SPACEUD1_DIM0 20 +#define SPACEUD3_DIM0 9 +#define SPACEUD3_DIM1 12 +#define SPACEUD3_DIM2 13 + +/* #defines for shape same / different rank tests */ +#define SS_DR_MAX_RANK 5 + +/* Information for regular hyperslab query test */ +#define SPACE13_RANK 3 +#define SPACE13_DIM1 50 +#define SPACE13_DIM2 50 +#define SPACE13_DIM3 50 +#define SPACE13_NPOINTS 4 + +/* Information for testing selection iterators */ +#define SEL_ITER_MAX_SEQ 256 + +/* Defines for test_hyper_io_1d() */ +#define DNAME "DSET_1D" +#define RANK 1 +#define NUMCHUNKS 3 +#define CHUNKSZ 20 +#define NUM_ELEMENTS NUMCHUNKS *CHUNKSZ + +/* Location comparison function */ +static int compare_size_t(const void *s1, const void *s2); + +static herr_t test_select_hyper_iter1(void *elem, hid_t type_id, unsigned ndim, const hsize_t *point, + void *operator_data); +static herr_t test_select_point_iter1(void *elem, hid_t type_id, unsigned ndim, const hsize_t *point, + void *operator_data); +static herr_t test_select_all_iter1(void *elem, hid_t type_id, unsigned ndim, const hsize_t *point, + void *operator_data); +static herr_t test_select_none_iter1(void *elem, hid_t type_id, unsigned ndim, const hsize_t *point, + void *operator_data); +static herr_t test_select_hyper_iter2(void *_elem, hid_t type_id, unsigned ndim, const hsize_t *point, + void *_operator_data); +static herr_t test_select_hyper_iter3(void *elem, hid_t type_id, unsigned ndim, const hsize_t *point, + void *operator_data); + +/**************************************************************** +** +** test_select_hyper_iter1(): Iterator for checking hyperslab iteration +** +****************************************************************/ +static herr_t +test_select_hyper_iter1(void *_elem, hid_t H5_ATTR_UNUSED type_id, unsigned H5_ATTR_UNUSED ndim, + const hsize_t H5_ATTR_UNUSED *point, void *_operator_data) +{ + uint8_t *tbuf = (uint8_t *)_elem, /* temporary buffer pointer */ + **tbuf2 = (uint8_t **)_operator_data; /* temporary buffer handle */ + + if (*tbuf != **tbuf2) + return (-1); + else { + (*tbuf2)++; + return (0); + } +} /* end test_select_hyper_iter1() */ + +/**************************************************************** +** +** test_select_hyper(): Test basic H5S (dataspace) selection code. +** Tests hyperslabs of various sizes and dimensionalities. +** +****************************************************************/ +static void +test_select_hyper(hid_t xfer_plist) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1, sid2; /* Dataspace ID */ + hsize_t dims1[] = {SPACE1_DIM1, SPACE1_DIM2, SPACE1_DIM3}; + hsize_t dims2[] = {SPACE2_DIM1, SPACE2_DIM2}; + hsize_t dims3[] = {SPACE3_DIM1, SPACE3_DIM2}; + hsize_t start[SPACE1_RANK]; /* Starting location of hyperslab */ + hsize_t stride[SPACE1_RANK]; /* Stride of hyperslab */ + hsize_t count[SPACE1_RANK]; /* Element count of hyperslab */ + hsize_t block[SPACE1_RANK]; /* Block size of hyperslab */ + uint8_t *wbuf, /* buffer to write to disk */ + *rbuf, /* buffer read from disk */ + *tbuf; /* temporary buffer pointer */ + int i, j; /* Counters */ + herr_t ret; /* Generic return value */ + H5S_class_t ext_type; /* Extent type */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Hyperslab Selection Functions\n")); + + /* Allocate write & read buffers */ + wbuf = (uint8_t *)HDmalloc(sizeof(uint8_t) * SPACE2_DIM1 * SPACE2_DIM2); + CHECK_PTR(wbuf, "HDmalloc"); + rbuf = (uint8_t *)HDcalloc(sizeof(uint8_t), (size_t)(SPACE3_DIM1 * SPACE3_DIM2)); + CHECK_PTR(rbuf, "HDcalloc"); + + /* Initialize write buffer */ + for (i = 0, tbuf = wbuf; i < SPACE2_DIM1; i++) + for (j = 0; j < SPACE2_DIM2; j++) + *tbuf++ = (uint8_t)((i * SPACE2_DIM2) + j); + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create dataspace for writing buffer */ + sid2 = H5Screate_simple(SPACE2_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Verify extent type */ + ext_type = H5Sget_simple_extent_type(sid1); + VERIFY(ext_type, H5S_SIMPLE, "H5Sget_simple_extent_type"); + + /* Test selecting stride==0 to verify failure */ + start[0] = 1; + start[1] = 0; + start[2] = 0; + stride[0] = 0; + stride[1] = 0; + stride[2] = 0; + count[0] = 2; + count[1] = 15; + count[2] = 13; + block[0] = 1; + block[1] = 1; + block[2] = 1; + H5E_BEGIN_TRY + { + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_SET, start, stride, count, block); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Sselect_hyperslab"); + + /* Test selecting stridebuf + (pnt_info->coord[pnt_info->offset][0] * SPACE2_DIM2) + + pnt_info->coord[pnt_info->offset][1]; + if (*elem != *tmp) + return (-1); + else { + pnt_info->offset++; + return (0); + } +} /* end test_select_point_iter1() */ + +/**************************************************************** +** +** test_select_point(): Test basic H5S (dataspace) selection code. +** Tests element selections between dataspaces of various sizes +** and dimensionalities. +** +****************************************************************/ +static void +test_select_point(hid_t xfer_plist) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1, sid2; /* Dataspace ID */ + hsize_t dims1[] = {SPACE1_DIM1, SPACE1_DIM2, SPACE1_DIM3}; + hsize_t dims2[] = {SPACE2_DIM1, SPACE2_DIM2}; + hsize_t dims3[] = {SPACE3_DIM1, SPACE3_DIM2}; + hsize_t coord1[POINT1_NPOINTS][SPACE1_RANK]; /* Coordinates for point selection */ + hsize_t temp_coord1[POINT1_NPOINTS][SPACE1_RANK]; /* Coordinates for point selection */ + hsize_t coord2[POINT1_NPOINTS][SPACE2_RANK]; /* Coordinates for point selection */ + hsize_t temp_coord2[POINT1_NPOINTS][SPACE2_RANK]; /* Coordinates for point selection */ + hsize_t coord3[POINT1_NPOINTS][SPACE3_RANK]; /* Coordinates for point selection */ + hsize_t temp_coord3[POINT1_NPOINTS][SPACE3_RANK]; /* Coordinates for point selection */ + uint8_t *wbuf, /* buffer to write to disk */ + *rbuf, /* buffer read from disk */ + *tbuf; /* temporary buffer pointer */ + int i, j; /* Counters */ + struct pnt_iter pi; /* Custom Pointer iterator struct */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Element Selection Functions\n")); + + /* Allocate write & read buffers */ + wbuf = (uint8_t *)HDmalloc(sizeof(uint8_t) * SPACE2_DIM1 * SPACE2_DIM2); + CHECK_PTR(wbuf, "HDmalloc"); + rbuf = (uint8_t *)HDcalloc(sizeof(uint8_t), (size_t)(SPACE3_DIM1 * SPACE3_DIM2)); + CHECK_PTR(rbuf, "HDcalloc"); + + /* Initialize write buffer */ + for (i = 0, tbuf = wbuf; i < SPACE2_DIM1; i++) + for (j = 0; j < SPACE2_DIM2; j++) + *tbuf++ = (uint8_t)((i * SPACE2_DIM2) + j); + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create dataspace for write buffer */ + sid2 = H5Screate_simple(SPACE2_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select sequence of ten points for disk dataset */ + coord1[0][0] = 0; + coord1[0][1] = 10; + coord1[0][2] = 5; + coord1[1][0] = 1; + coord1[1][1] = 2; + coord1[1][2] = 7; + coord1[2][0] = 2; + coord1[2][1] = 4; + coord1[2][2] = 9; + coord1[3][0] = 0; + coord1[3][1] = 6; + coord1[3][2] = 11; + coord1[4][0] = 1; + coord1[4][1] = 8; + coord1[4][2] = 13; + coord1[5][0] = 2; + coord1[5][1] = 12; + coord1[5][2] = 0; + coord1[6][0] = 0; + coord1[6][1] = 14; + coord1[6][2] = 2; + coord1[7][0] = 1; + coord1[7][1] = 0; + coord1[7][2] = 4; + coord1[8][0] = 2; + coord1[8][1] = 1; + coord1[8][2] = 6; + coord1[9][0] = 0; + coord1[9][1] = 3; + coord1[9][2] = 8; + ret = H5Sselect_elements(sid1, H5S_SELECT_SET, (size_t)POINT1_NPOINTS, (const hsize_t *)coord1); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Verify correct elements selected */ + H5Sget_select_elem_pointlist(sid1, (hsize_t)0, (hsize_t)POINT1_NPOINTS, (hsize_t *)temp_coord1); + for (i = 0; i < POINT1_NPOINTS; i++) { + VERIFY(temp_coord1[i][0], coord1[i][0], "H5Sget_select_elem_pointlist"); + VERIFY(temp_coord1[i][1], coord1[i][1], "H5Sget_select_elem_pointlist"); + VERIFY(temp_coord1[i][2], coord1[i][2], "H5Sget_select_elem_pointlist"); + } /* end for */ + + ret = (int)H5Sget_select_npoints(sid1); + VERIFY(ret, 10, "H5Sget_select_npoints"); + + /* Append another sequence of ten points to disk dataset */ + coord1[0][0] = 0; + coord1[0][1] = 2; + coord1[0][2] = 0; + coord1[1][0] = 1; + coord1[1][1] = 10; + coord1[1][2] = 8; + coord1[2][0] = 2; + coord1[2][1] = 8; + coord1[2][2] = 10; + coord1[3][0] = 0; + coord1[3][1] = 7; + coord1[3][2] = 12; + coord1[4][0] = 1; + coord1[4][1] = 3; + coord1[4][2] = 11; + coord1[5][0] = 2; + coord1[5][1] = 1; + coord1[5][2] = 1; + coord1[6][0] = 0; + coord1[6][1] = 13; + coord1[6][2] = 7; + coord1[7][0] = 1; + coord1[7][1] = 14; + coord1[7][2] = 6; + coord1[8][0] = 2; + coord1[8][1] = 2; + coord1[8][2] = 5; + coord1[9][0] = 0; + coord1[9][1] = 6; + coord1[9][2] = 13; + ret = H5Sselect_elements(sid1, H5S_SELECT_APPEND, (size_t)POINT1_NPOINTS, (const hsize_t *)coord1); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Verify correct elements selected */ + H5Sget_select_elem_pointlist(sid1, (hsize_t)POINT1_NPOINTS, (hsize_t)POINT1_NPOINTS, + (hsize_t *)temp_coord1); + for (i = 0; i < POINT1_NPOINTS; i++) { + VERIFY(temp_coord1[i][0], coord1[i][0], "H5Sget_select_elem_pointlist"); + VERIFY(temp_coord1[i][1], coord1[i][1], "H5Sget_select_elem_pointlist"); + VERIFY(temp_coord1[i][2], coord1[i][2], "H5Sget_select_elem_pointlist"); + } /* end for */ + + ret = (int)H5Sget_select_npoints(sid1); + VERIFY(ret, 20, "H5Sget_select_npoints"); + + /* Select sequence of ten points for memory dataset */ + coord2[0][0] = 12; + coord2[0][1] = 3; + coord2[1][0] = 15; + coord2[1][1] = 13; + coord2[2][0] = 7; + coord2[2][1] = 25; + coord2[3][0] = 0; + coord2[3][1] = 6; + coord2[4][0] = 13; + coord2[4][1] = 0; + coord2[5][0] = 24; + coord2[5][1] = 11; + coord2[6][0] = 12; + coord2[6][1] = 21; + coord2[7][0] = 29; + coord2[7][1] = 4; + coord2[8][0] = 8; + coord2[8][1] = 8; + coord2[9][0] = 19; + coord2[9][1] = 17; + ret = H5Sselect_elements(sid2, H5S_SELECT_SET, (size_t)POINT1_NPOINTS, (const hsize_t *)coord2); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Verify correct elements selected */ + H5Sget_select_elem_pointlist(sid2, (hsize_t)0, (hsize_t)POINT1_NPOINTS, (hsize_t *)temp_coord2); + for (i = 0; i < POINT1_NPOINTS; i++) { + VERIFY(temp_coord2[i][0], coord2[i][0], "H5Sget_select_elem_pointlist"); + VERIFY(temp_coord2[i][1], coord2[i][1], "H5Sget_select_elem_pointlist"); + } /* end for */ + + /* Save points for later iteration */ + /* (these are in the second half of the buffer, because we are prepending */ + /* the next list of points to the beginning of the point selection list) */ + HDmemcpy(((char *)pi.coord) + sizeof(coord2), coord2, sizeof(coord2)); + + ret = (int)H5Sget_select_npoints(sid2); + VERIFY(ret, 10, "H5Sget_select_npoints"); + + /* Append another sequence of ten points to memory dataset */ + coord2[0][0] = 24; + coord2[0][1] = 0; + coord2[1][0] = 2; + coord2[1][1] = 25; + coord2[2][0] = 13; + coord2[2][1] = 17; + coord2[3][0] = 8; + coord2[3][1] = 3; + coord2[4][0] = 29; + coord2[4][1] = 4; + coord2[5][0] = 11; + coord2[5][1] = 14; + coord2[6][0] = 5; + coord2[6][1] = 22; + coord2[7][0] = 12; + coord2[7][1] = 2; + coord2[8][0] = 21; + coord2[8][1] = 12; + coord2[9][0] = 9; + coord2[9][1] = 18; + ret = H5Sselect_elements(sid2, H5S_SELECT_PREPEND, (size_t)POINT1_NPOINTS, (const hsize_t *)coord2); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Verify correct elements selected */ + H5Sget_select_elem_pointlist(sid2, (hsize_t)0, (hsize_t)POINT1_NPOINTS, (hsize_t *)temp_coord2); + for (i = 0; i < POINT1_NPOINTS; i++) { + VERIFY(temp_coord2[i][0], coord2[i][0], "H5Sget_select_elem_pointlist"); + VERIFY(temp_coord2[i][1], coord2[i][1], "H5Sget_select_elem_pointlist"); + } /* end for */ + + ret = (int)H5Sget_select_npoints(sid2); + VERIFY(ret, 20, "H5Sget_select_npoints"); + + /* Save points for later iteration */ + HDmemcpy(pi.coord, coord2, sizeof(coord2)); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, SPACE1_NAME, H5T_NATIVE_UCHAR, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_UCHAR, sid2, sid1, xfer_plist, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Create dataspace for reading buffer */ + sid2 = H5Screate_simple(SPACE3_RANK, dims3, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select sequence of points for read dataset */ + coord3[0][0] = 0; + coord3[0][1] = 2; + coord3[1][0] = 4; + coord3[1][1] = 8; + coord3[2][0] = 13; + coord3[2][1] = 13; + coord3[3][0] = 14; + coord3[3][1] = 20; + coord3[4][0] = 7; + coord3[4][1] = 9; + coord3[5][0] = 2; + coord3[5][1] = 0; + coord3[6][0] = 9; + coord3[6][1] = 19; + coord3[7][0] = 1; + coord3[7][1] = 22; + coord3[8][0] = 12; + coord3[8][1] = 21; + coord3[9][0] = 11; + coord3[9][1] = 6; + ret = H5Sselect_elements(sid2, H5S_SELECT_SET, (size_t)POINT1_NPOINTS, (const hsize_t *)coord3); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Verify correct elements selected */ + H5Sget_select_elem_pointlist(sid2, (hsize_t)0, (hsize_t)POINT1_NPOINTS, (hsize_t *)temp_coord3); + for (i = 0; i < POINT1_NPOINTS; i++) { + VERIFY(temp_coord3[i][0], coord3[i][0], "H5Sget_select_elem_pointlist"); + VERIFY(temp_coord3[i][1], coord3[i][1], "H5Sget_select_elem_pointlist"); + } /* end for */ + + ret = (int)H5Sget_select_npoints(sid2); + VERIFY(ret, 10, "H5Sget_select_npoints"); + + /* Append another sequence of ten points to disk dataset */ + coord3[0][0] = 14; + coord3[0][1] = 25; + coord3[1][0] = 0; + coord3[1][1] = 0; + coord3[2][0] = 11; + coord3[2][1] = 11; + coord3[3][0] = 5; + coord3[3][1] = 14; + coord3[4][0] = 3; + coord3[4][1] = 5; + coord3[5][0] = 2; + coord3[5][1] = 2; + coord3[6][0] = 7; + coord3[6][1] = 13; + coord3[7][0] = 9; + coord3[7][1] = 16; + coord3[8][0] = 12; + coord3[8][1] = 22; + coord3[9][0] = 13; + coord3[9][1] = 9; + ret = H5Sselect_elements(sid2, H5S_SELECT_APPEND, (size_t)POINT1_NPOINTS, (const hsize_t *)coord3); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Verify correct elements selected */ + H5Sget_select_elem_pointlist(sid2, (hsize_t)POINT1_NPOINTS, (hsize_t)POINT1_NPOINTS, + (hsize_t *)temp_coord3); + for (i = 0; i < POINT1_NPOINTS; i++) { + VERIFY(temp_coord3[i][0], coord3[i][0], "H5Sget_select_elem_pointlist"); + VERIFY(temp_coord3[i][1], coord3[i][1], "H5Sget_select_elem_pointlist"); + } /* end for */ + ret = (int)H5Sget_select_npoints(sid2); + VERIFY(ret, 20, "H5Sget_select_npoints"); + + /* Read selection from disk */ + ret = H5Dread(dataset, H5T_NATIVE_UCHAR, sid2, sid1, xfer_plist, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Check that the values match with a dataset iterator */ + pi.buf = wbuf; + pi.offset = 0; + ret = H5Diterate(rbuf, H5T_NATIVE_UCHAR, sid2, test_select_point_iter1, &pi); + CHECK(ret, FAIL, "H5Diterate"); + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free memory buffers */ + HDfree(wbuf); + HDfree(rbuf); +} /* test_select_point() */ + +/**************************************************************** +** +** test_select_all_iter1(): Iterator for checking all iteration +** +** +****************************************************************/ +static herr_t +test_select_all_iter1(void *_elem, hid_t H5_ATTR_UNUSED type_id, unsigned H5_ATTR_UNUSED ndim, + const hsize_t H5_ATTR_UNUSED *point, void *_operator_data) +{ + uint8_t *tbuf = (uint8_t *)_elem, /* temporary buffer pointer */ + **tbuf2 = (uint8_t **)_operator_data; /* temporary buffer handle */ + + if (*tbuf != **tbuf2) + return (-1); + else { + (*tbuf2)++; + return (0); + } +} /* end test_select_all_iter1() */ + +/**************************************************************** +** +** test_select_none_iter1(): Iterator for checking none iteration +** (This is never supposed to be called, so it always returns -1) +** +****************************************************************/ +static herr_t +test_select_none_iter1(void H5_ATTR_UNUSED *_elem, hid_t H5_ATTR_UNUSED type_id, unsigned H5_ATTR_UNUSED ndim, + const hsize_t H5_ATTR_UNUSED *point, void H5_ATTR_UNUSED *_operator_data) +{ + return (-1); +} /* end test_select_none_iter1() */ + +/**************************************************************** +** +** test_select_all(): Test basic H5S (dataspace) selection code. +** Tests "all" selections. +** +****************************************************************/ +static void +test_select_all(hid_t xfer_plist) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1; /* Dataspace ID */ + hsize_t dims1[] = {SPACE4_DIM1, SPACE4_DIM2, SPACE4_DIM3}; + uint8_t *wbuf, /* buffer to write to disk */ + *rbuf, /* buffer read from disk */ + *tbuf; /* temporary buffer pointer */ + int i, j, k; /* Counters */ + herr_t ret; /* Generic return value */ + H5S_class_t ext_type; /* Extent type */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing 'All' Selection Functions\n")); + + /* Allocate write & read buffers */ + wbuf = (uint8_t *)HDmalloc(sizeof(uint8_t) * SPACE4_DIM1 * SPACE4_DIM2 * SPACE4_DIM3); + CHECK_PTR(wbuf, "HDmalloc"); + rbuf = (uint8_t *)HDcalloc(sizeof(uint8_t), (size_t)(SPACE4_DIM1 * SPACE4_DIM2 * SPACE4_DIM3)); + CHECK_PTR(rbuf, "HDcalloc"); + + /* Initialize write buffer */ + for (i = 0, tbuf = wbuf; i < SPACE4_DIM1; i++) + for (j = 0; j < SPACE4_DIM2; j++) + for (k = 0; k < SPACE4_DIM3; k++) + *tbuf++ = (uint8_t)((((i * SPACE4_DIM2) + j) * SPACE4_DIM3) + k); + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset */ + sid1 = H5Screate_simple(SPACE4_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Verify extent type */ + ext_type = H5Sget_simple_extent_type(sid1); + VERIFY(ext_type, H5S_SIMPLE, "H5Sget_simple_extent_type"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, SPACE4_NAME, H5T_NATIVE_INT, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_UCHAR, H5S_ALL, H5S_ALL, xfer_plist, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Read selection from disk */ + ret = H5Dread(dataset, H5T_NATIVE_UCHAR, H5S_ALL, H5S_ALL, xfer_plist, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Check that the values match with a dataset iterator */ + tbuf = wbuf; + ret = H5Diterate(rbuf, H5T_NATIVE_UCHAR, sid1, test_select_all_iter1, &tbuf); + CHECK(ret, FAIL, "H5Diterate"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free memory buffers */ + HDfree(wbuf); + HDfree(rbuf); +} /* test_select_all() */ + +/**************************************************************** +** +** test_select_all_hyper(): Test basic H5S (dataspace) selection code. +** Tests "all" and hyperslab selections. +** +****************************************************************/ +static void +test_select_all_hyper(hid_t xfer_plist) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1, sid2; /* Dataspace ID */ + hsize_t dims1[] = {SPACE3_DIM1, SPACE3_DIM2}; + hsize_t dims2[] = {SPACE2_DIM1, SPACE2_DIM2}; + hsize_t dims3[] = {SPACE3_DIM1, SPACE3_DIM2}; + hsize_t start[SPACE1_RANK]; /* Starting location of hyperslab */ + hsize_t stride[SPACE1_RANK]; /* Stride of hyperslab */ + hsize_t count[SPACE1_RANK]; /* Element count of hyperslab */ + hsize_t block[SPACE1_RANK]; /* Block size of hyperslab */ + uint8_t *wbuf, /* buffer to write to disk */ + *rbuf, /* buffer read from disk */ + *tbuf; /* temporary buffer pointer */ + int i, j; /* Counters */ + herr_t ret; /* Generic return value */ + H5S_class_t ext_type; /* Extent type */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing 'All' Selection Functions\n")); + + /* Allocate write & read buffers */ + wbuf = (uint8_t *)HDmalloc(sizeof(uint8_t) * SPACE2_DIM1 * SPACE2_DIM2); + CHECK_PTR(wbuf, "HDmalloc"); + rbuf = (uint8_t *)HDcalloc(sizeof(uint8_t), (size_t)(SPACE3_DIM1 * SPACE3_DIM2)); + CHECK_PTR(rbuf, "HDcalloc"); + + /* Initialize write buffer */ + for (i = 0, tbuf = wbuf; i < SPACE2_DIM1; i++) + for (j = 0; j < SPACE2_DIM2; j++) + *tbuf++ = (uint8_t)((i * SPACE2_DIM2) + j); + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset */ + sid1 = H5Screate_simple(SPACE3_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create dataspace for writing buffer */ + sid2 = H5Screate_simple(SPACE2_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Verify extent type */ + ext_type = H5Sget_simple_extent_type(sid1); + VERIFY(ext_type, H5S_SIMPLE, "H5Sget_simple_extent_type"); + + /* Select entire 15x26 extent for disk dataset */ + ret = H5Sselect_all(sid1); + CHECK(ret, FAIL, "H5Sselect_all"); + + /* Select 15x26 hyperslab for memory dataset */ + start[0] = 15; + start[1] = 0; + stride[0] = 1; + stride[1] = 1; + count[0] = 15; + count[1] = 26; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, SPACE3_NAME, H5T_NATIVE_UCHAR, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_UCHAR, sid2, sid1, xfer_plist, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Create dataspace for reading buffer */ + sid2 = H5Screate_simple(SPACE3_RANK, dims3, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select 15x26 hyperslab for reading memory dataset */ + start[0] = 0; + start[1] = 0; + stride[0] = 1; + stride[1] = 1; + count[0] = 15; + count[1] = 26; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Select no extent for disk dataset */ + ret = H5Sselect_none(sid1); + CHECK(ret, FAIL, "H5Sselect_none"); + + /* Read selection from disk (should fail with no selection defined) */ + H5E_BEGIN_TRY + { + ret = H5Dread(dataset, H5T_NATIVE_UCHAR, sid2, sid1, xfer_plist, rbuf); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Dread"); + + /* Select entire 15x26 extent for disk dataset */ + ret = H5Sselect_all(sid1); + CHECK(ret, FAIL, "H5Sselect_all"); + + /* Read selection from disk (should work now) */ + ret = H5Dread(dataset, H5T_NATIVE_UCHAR, sid2, sid1, xfer_plist, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Check that the values match with a dataset iterator */ + tbuf = wbuf + (15 * SPACE2_DIM2); + ret = H5Diterate(rbuf, H5T_NATIVE_UCHAR, sid2, test_select_all_iter1, &tbuf); + CHECK(ret, FAIL, "H5Diterate"); + + /* A quick check to make certain that iterating through a "none" selection works */ + ret = H5Sselect_none(sid2); + CHECK(ret, FAIL, "H5Sselect_none"); + ret = H5Diterate(rbuf, H5T_NATIVE_UCHAR, sid2, test_select_none_iter1, &tbuf); + CHECK(ret, FAIL, "H5Diterate"); + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free memory buffers */ + HDfree(wbuf); + HDfree(rbuf); +} /* test_select_all_hyper() */ + +/**************************************************************** +** +** test_select_combo(): Test basic H5S (dataspace) selection code. +** Tests combinations of element and hyperslab selections between +** dataspaces of various sizes and dimensionalities. +** +****************************************************************/ +static void +test_select_combo(void) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1, sid2; /* Dataspace ID */ + hsize_t dims1[] = {SPACE1_DIM1, SPACE1_DIM2, SPACE1_DIM3}; + hsize_t dims2[] = {SPACE2_DIM1, SPACE2_DIM2}; + hsize_t dims3[] = {SPACE3_DIM1, SPACE3_DIM2}; + hsize_t coord1[POINT1_NPOINTS][SPACE1_RANK]; /* Coordinates for point selection */ + hsize_t start[SPACE1_RANK]; /* Starting location of hyperslab */ + hsize_t stride[SPACE1_RANK]; /* Stride of hyperslab */ + hsize_t count[SPACE1_RANK]; /* Element count of hyperslab */ + hsize_t block[SPACE1_RANK]; /* Block size of hyperslab */ + uint8_t *wbuf, /* buffer to write to disk */ + *rbuf, /* buffer read from disk */ + *tbuf, /* temporary buffer pointer */ + *tbuf2; /* temporary buffer pointer */ + int i, j; /* Counters */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Combination of Hyperslab & Element Selection Functions\n")); + + /* Allocate write & read buffers */ + wbuf = (uint8_t *)HDmalloc(sizeof(uint8_t) * SPACE2_DIM1 * SPACE2_DIM2); + CHECK_PTR(wbuf, "HDmalloc"); + rbuf = (uint8_t *)HDcalloc(sizeof(uint8_t), (size_t)(SPACE3_DIM1 * SPACE3_DIM2)); + CHECK_PTR(rbuf, "HDcalloc"); + + /* Initialize write buffer */ + for (i = 0, tbuf = wbuf; i < SPACE2_DIM1; i++) + for (j = 0; j < SPACE2_DIM2; j++) + *tbuf++ = (uint8_t)((i * SPACE2_DIM2) + j); + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create dataspace for write buffer */ + sid2 = H5Screate_simple(SPACE2_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select sequence of ten points for disk dataset */ + coord1[0][0] = 0; + coord1[0][1] = 10; + coord1[0][2] = 5; + coord1[1][0] = 1; + coord1[1][1] = 2; + coord1[1][2] = 7; + coord1[2][0] = 2; + coord1[2][1] = 4; + coord1[2][2] = 9; + coord1[3][0] = 0; + coord1[3][1] = 6; + coord1[3][2] = 11; + coord1[4][0] = 1; + coord1[4][1] = 8; + coord1[4][2] = 13; + coord1[5][0] = 2; + coord1[5][1] = 12; + coord1[5][2] = 0; + coord1[6][0] = 0; + coord1[6][1] = 14; + coord1[6][2] = 2; + coord1[7][0] = 1; + coord1[7][1] = 0; + coord1[7][2] = 4; + coord1[8][0] = 2; + coord1[8][1] = 1; + coord1[8][2] = 6; + coord1[9][0] = 0; + coord1[9][1] = 3; + coord1[9][2] = 8; + ret = H5Sselect_elements(sid1, H5S_SELECT_SET, (size_t)POINT1_NPOINTS, (const hsize_t *)coord1); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Select 1x10 hyperslab for writing memory dataset */ + start[0] = 0; + start[1] = 0; + stride[0] = 1; + stride[1] = 1; + count[0] = 1; + count[1] = 10; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, SPACE1_NAME, H5T_NATIVE_UCHAR, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Create dataspace for reading buffer */ + sid2 = H5Screate_simple(SPACE3_RANK, dims3, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select 10x1 hyperslab for reading memory dataset */ + start[0] = 0; + start[1] = 0; + stride[0] = 1; + stride[1] = 1; + count[0] = 10; + count[1] = 1; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Read selection from disk */ + ret = H5Dread(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read with data written out */ + for (i = 0; i < POINT1_NPOINTS; i++) { + tbuf = wbuf + i; + tbuf2 = rbuf + (i * SPACE3_DIM2); + if (*tbuf != *tbuf2) + TestErrPrintf("element values don't match!, i=%d\n", i); + } /* end for */ + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free memory buffers */ + HDfree(wbuf); + HDfree(rbuf); +} /* test_select_combo() */ + +static int +compare_size_t(const void *s1, const void *s2) +{ + if (*(const size_t *)s1 < *(const size_t *)s2) + return (-1); + else if (*(const size_t *)s1 > *(const size_t *)s2) + return (1); + else + return (0); +} + +/**************************************************************** +** +** test_select_hyper_stride(): Test H5S (dataspace) selection code. +** Tests strided hyperslabs of various sizes and dimensionalities. +** +****************************************************************/ +static void +test_select_hyper_stride(hid_t xfer_plist) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1, sid2; /* Dataspace ID */ + hsize_t dims1[] = {SPACE1_DIM1, SPACE1_DIM2, SPACE1_DIM3}; + hsize_t dims2[] = {SPACE2_DIM1, SPACE2_DIM2}; + hsize_t dims3[] = {SPACE3_DIM1, SPACE3_DIM2}; + hsize_t start[SPACE1_RANK]; /* Starting location of hyperslab */ + hsize_t stride[SPACE1_RANK]; /* Stride of hyperslab */ + hsize_t count[SPACE1_RANK]; /* Element count of hyperslab */ + hsize_t block[SPACE1_RANK]; /* Block size of hyperslab */ + uint16_t *wbuf, /* buffer to write to disk */ + *rbuf, /* buffer read from disk */ + *tbuf, /* temporary buffer pointer */ + *tbuf2; /* temporary buffer pointer */ + size_t loc1[72] = { + /* Gruesomely ugly way to make certain hyperslab locations are checked correctly */ + 27, 28, 29, 53, 54, 55, 79, 80, 81, /* Block #1 */ + 32, 33, 34, 58, 59, 60, 84, 85, 86, /* Block #2 */ + 157, 158, 159, 183, 184, 185, 209, 210, 211, /* Block #3 */ + 162, 163, 164, 188, 189, 190, 214, 215, 216, /* Block #4 */ + 287, 288, 289, 313, 314, 315, 339, 340, 341, /* Block #5 */ + 292, 293, 294, 318, 319, 320, 344, 345, 346, /* Block #6 */ + 417, 418, 419, 443, 444, 445, 469, 470, 471, /* Block #7 */ + 422, 423, 424, 448, 449, 450, 474, 475, 476, /* Block #8 */ + }; + size_t loc2[72] = { + 0, 1, 2, 26, 27, 28, /* Block #1 */ + 4, 5, 6, 30, 31, 32, /* Block #2 */ + 8, 9, 10, 34, 35, 36, /* Block #3 */ + 12, 13, 14, 38, 39, 40, /* Block #4 */ + 104, 105, 106, 130, 131, 132, /* Block #5 */ + 108, 109, 110, 134, 135, 136, /* Block #6 */ + 112, 113, 114, 138, 139, 140, /* Block #7 */ + 116, 117, 118, 142, 143, 144, /* Block #8 */ + 208, 209, 210, 234, 235, 236, /* Block #9 */ + 212, 213, 214, 238, 239, 240, /* Block #10 */ + 216, 217, 218, 242, 243, 244, /* Block #11 */ + 220, 221, 222, 246, 247, 248, /* Block #12 */ + }; + int i, j; /* Counters */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Hyperslabs with Strides Functionality\n")); + + /* Allocate write & read buffers */ + wbuf = (uint16_t *)HDmalloc(sizeof(uint16_t) * SPACE2_DIM1 * SPACE2_DIM2); + CHECK_PTR(wbuf, "HDmalloc"); + rbuf = (uint16_t *)HDcalloc(sizeof(uint16_t), (size_t)(SPACE3_DIM1 * SPACE3_DIM2)); + CHECK_PTR(rbuf, "HDcalloc"); + + /* Initialize write buffer */ + for (i = 0, tbuf = wbuf; i < SPACE2_DIM1; i++) + for (j = 0; j < SPACE2_DIM2; j++) + *tbuf++ = (uint16_t)((i * SPACE2_DIM2) + j); + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create dataspace for writing buffer */ + sid2 = H5Screate_simple(SPACE2_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select 2x3x3 count with a stride of 2x4x3 & 1x2x2 block hyperslab for disk dataset */ + start[0] = 0; + start[1] = 0; + start[2] = 0; + stride[0] = 2; + stride[1] = 4; + stride[2] = 3; + count[0] = 2; + count[1] = 3; + count[2] = 3; + block[0] = 1; + block[1] = 2; + block[2] = 2; + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Select 4x2 count with a stride of 5x5 & 3x3 block hyperslab for memory dataset */ + start[0] = 1; + start[1] = 1; + stride[0] = 5; + stride[1] = 5; + count[0] = 4; + count[1] = 2; + block[0] = 3; + block[1] = 3; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, SPACE2_NAME, H5T_STD_U16LE, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_USHORT, sid2, sid1, xfer_plist, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Create dataspace for reading buffer */ + sid2 = H5Screate_simple(SPACE3_RANK, dims3, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select 3x4 count with a stride of 4x4 & 2x3 block hyperslab for memory dataset */ + start[0] = 0; + start[1] = 0; + stride[0] = 4; + stride[1] = 4; + count[0] = 3; + count[1] = 4; + block[0] = 2; + block[1] = 3; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Read selection from disk */ + ret = H5Dread(dataset, H5T_NATIVE_USHORT, sid2, sid1, xfer_plist, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Sort the locations into the proper order */ + HDqsort(loc1, (size_t)72, sizeof(size_t), compare_size_t); + HDqsort(loc2, (size_t)72, sizeof(size_t), compare_size_t); + /* Compare data read with data written out */ + for (i = 0; i < 72; i++) { + tbuf = wbuf + loc1[i]; + tbuf2 = rbuf + loc2[i]; + if (*tbuf != *tbuf2) { + HDprintf("%d: hyperslab values don't match!, loc1[%d]=%d, loc2[%d]=%d\n", __LINE__, i, + (int)loc1[i], i, (int)loc2[i]); + HDprintf("wbuf=%p, tbuf=%p, rbuf=%p, tbuf2=%p\n", (void *)wbuf, (void *)tbuf, (void *)rbuf, + (void *)tbuf2); + TestErrPrintf("*tbuf=%u, *tbuf2=%u\n", (unsigned)*tbuf, (unsigned)*tbuf2); + } /* end if */ + } /* end for */ + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free memory buffers */ + HDfree(wbuf); + HDfree(rbuf); +} /* test_select_hyper_stride() */ + +/**************************************************************** +** +** test_select_hyper_contig(): Test H5S (dataspace) selection code. +** Tests contiguous hyperslabs of various sizes and dimensionalities. +** +****************************************************************/ +static void +test_select_hyper_contig(hid_t dset_type, hid_t xfer_plist) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1, sid2; /* Dataspace ID */ + hsize_t dims2[] = {SPACE2_DIM2, SPACE2_DIM1}; + hsize_t start[SPACE1_RANK]; /* Starting location of hyperslab */ + hsize_t stride[SPACE1_RANK]; /* Stride of hyperslab */ + hsize_t count[SPACE1_RANK]; /* Element count of hyperslab */ + hsize_t block[SPACE1_RANK]; /* Block size of hyperslab */ + uint16_t *wbuf, /* buffer to write to disk */ + *rbuf, /* buffer read from disk */ + *tbuf; /* temporary buffer pointer */ + int i, j; /* Counters */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Contiguous Hyperslabs Functionality\n")); + + /* Allocate write & read buffers */ + wbuf = (uint16_t *)HDmalloc(sizeof(uint16_t) * SPACE2_DIM1 * SPACE2_DIM2); + CHECK_PTR(wbuf, "HDmalloc"); + rbuf = (uint16_t *)HDcalloc(sizeof(uint16_t), (size_t)(SPACE2_DIM1 * SPACE2_DIM2)); + CHECK_PTR(rbuf, "HDcalloc"); + + /* Initialize write buffer */ + for (i = 0, tbuf = wbuf; i < SPACE2_DIM1; i++) + for (j = 0; j < SPACE2_DIM2; j++) + *tbuf++ = (uint16_t)((i * SPACE2_DIM2) + j); + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset */ + sid1 = H5Screate_simple(SPACE2_RANK, dims2, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create dataspace for writing buffer */ + sid2 = H5Screate_simple(SPACE2_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select 12x10 count with a stride of 1x3 & 3x3 block hyperslab for disk dataset */ + start[0] = 0; + start[1] = 0; + stride[0] = 1; + stride[1] = 3; + count[0] = 12; + count[1] = 10; + block[0] = 1; + block[1] = 3; + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Select 4x5 count with a stride of 3x6 & 3x6 block hyperslab for memory dataset */ + start[0] = 0; + start[1] = 0; + stride[0] = 3; + stride[1] = 6; + count[0] = 4; + count[1] = 5; + block[0] = 3; + block[1] = 6; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, SPACE2_NAME, dset_type, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_USHORT, sid2, sid1, xfer_plist, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Create dataspace for reading buffer */ + sid2 = H5Screate_simple(SPACE2_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select 6x5 count with a stride of 2x6 & 2x6 block hyperslab for disk dataset */ + start[0] = 0; + start[1] = 0; + stride[0] = 2; + stride[1] = 6; + count[0] = 6; + count[1] = 5; + block[0] = 2; + block[1] = 6; + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Select 3x15 count with a stride of 4x2 & 4x2 block hyperslab for memory dataset */ + start[0] = 0; + start[1] = 0; + stride[0] = 4; + stride[1] = 2; + count[0] = 3; + count[1] = 15; + block[0] = 4; + block[1] = 2; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Read selection from disk */ + ret = H5Dread(dataset, H5T_NATIVE_USHORT, sid2, sid1, xfer_plist, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read with data written out */ + if (HDmemcmp(rbuf, wbuf, sizeof(uint16_t) * 30 * 12) != 0) + TestErrPrintf("hyperslab values don't match! Line=%d\n", __LINE__); + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free memory buffers */ + HDfree(wbuf); + HDfree(rbuf); +} /* test_select_hyper_contig() */ + +/**************************************************************** +** +** test_select_hyper_contig2(): Test H5S (dataspace) selection code. +** Tests more contiguous hyperslabs of various sizes and dimensionalities. +** +****************************************************************/ +static void +test_select_hyper_contig2(hid_t dset_type, hid_t xfer_plist) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1, sid2; /* Dataspace ID */ + hsize_t dims2[] = {SPACE8_DIM4, SPACE8_DIM3, SPACE8_DIM2, SPACE8_DIM1}; + hsize_t start[SPACE8_RANK]; /* Starting location of hyperslab */ + hsize_t count[SPACE8_RANK]; /* Element count of hyperslab */ + uint16_t *wbuf, /* buffer to write to disk */ + *rbuf, /* buffer read from disk */ + *tbuf; /* temporary buffer pointer */ + int i, j, k, l; /* Counters */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing More Contiguous Hyperslabs Functionality\n")); + + /* Allocate write & read buffers */ + wbuf = (uint16_t *)HDmalloc(sizeof(uint16_t) * SPACE8_DIM1 * SPACE8_DIM2 * SPACE8_DIM3 * SPACE8_DIM4); + CHECK_PTR(wbuf, "HDmalloc"); + rbuf = (uint16_t *)HDcalloc(sizeof(uint16_t), + (size_t)(SPACE8_DIM1 * SPACE8_DIM2 * SPACE8_DIM3 * SPACE8_DIM4)); + CHECK_PTR(rbuf, "HDcalloc"); + + /* Initialize write buffer */ + for (i = 0, tbuf = wbuf; i < SPACE8_DIM1; i++) + for (j = 0; j < SPACE8_DIM2; j++) + for (k = 0; k < SPACE8_DIM3; k++) + for (l = 0; l < SPACE8_DIM4; l++) + *tbuf++ = (uint16_t)((i * SPACE8_DIM2) + j); + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset */ + sid1 = H5Screate_simple(SPACE8_RANK, dims2, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create dataspace for writing buffer */ + sid2 = H5Screate_simple(SPACE8_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select contiguous hyperslab for disk dataset */ + start[0] = 0; + start[1] = 0; + start[2] = 0; + start[3] = 0; + count[0] = 2; + count[1] = SPACE8_DIM3; + count[2] = SPACE8_DIM2; + count[3] = SPACE8_DIM1; + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Select contiguous hyperslab in memory */ + start[0] = 0; + start[1] = 0; + start[2] = 0; + start[3] = 0; + count[0] = 2; + count[1] = SPACE8_DIM3; + count[2] = SPACE8_DIM2; + count[3] = SPACE8_DIM1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, SPACE8_NAME, dset_type, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_USHORT, sid2, sid1, xfer_plist, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Create dataspace for reading buffer */ + sid2 = H5Screate_simple(SPACE8_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select contiguous hyperslab in memory */ + start[0] = 0; + start[1] = 0; + start[2] = 0; + start[3] = 0; + count[0] = 2; + count[1] = SPACE8_DIM3; + count[2] = SPACE8_DIM2; + count[3] = SPACE8_DIM1; + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Select contiguous hyperslab in memory */ + start[0] = 0; + start[1] = 0; + start[2] = 0; + start[3] = 0; + count[0] = 2; + count[1] = SPACE8_DIM3; + count[2] = SPACE8_DIM2; + count[3] = SPACE8_DIM1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Read selection from disk */ + ret = H5Dread(dataset, H5T_NATIVE_USHORT, sid2, sid1, xfer_plist, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read with data written out */ + if (HDmemcmp(rbuf, wbuf, sizeof(uint16_t) * 2 * SPACE8_DIM3 * SPACE8_DIM2 * SPACE8_DIM1) != 0) + TestErrPrintf("Error: hyperslab values don't match!\n"); + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free memory buffers */ + HDfree(wbuf); + HDfree(rbuf); +} /* test_select_hyper_contig2() */ + +/**************************************************************** +** +** test_select_hyper_contig3(): Test H5S (dataspace) selection code. +** Tests contiguous hyperslabs of various sizes and dimensionalities. +** This test uses a hyperslab that is contiguous in the lowest dimension, +** not contiguous in a dimension, then has a selection across the entire next +** dimension (which should be "flattened" out also). +** +****************************************************************/ +static void +test_select_hyper_contig3(hid_t dset_type, hid_t xfer_plist) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1, sid2; /* Dataspace ID */ + hsize_t dims2[] = {SPACE8_DIM4, SPACE8_DIM3, SPACE8_DIM2, SPACE8_DIM1}; + hsize_t start[SPACE8_RANK]; /* Starting location of hyperslab */ + hsize_t count[SPACE8_RANK]; /* Element count of hyperslab */ + uint16_t *wbuf, /* Buffer to write to disk */ + *rbuf, /* Buffer read from disk */ + *tbuf, *tbuf2; /* Temporary buffer pointers */ + unsigned i, j, k, l; /* Counters */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Yet More Contiguous Hyperslabs Functionality\n")); + + /* Allocate write & read buffers */ + wbuf = (uint16_t *)HDmalloc(sizeof(uint16_t) * SPACE8_DIM1 * SPACE8_DIM2 * SPACE8_DIM3 * SPACE8_DIM4); + CHECK_PTR(wbuf, "HDmalloc"); + rbuf = (uint16_t *)HDcalloc(sizeof(uint16_t), + (size_t)(SPACE8_DIM1 * SPACE8_DIM2 * SPACE8_DIM3 * SPACE8_DIM4)); + CHECK_PTR(rbuf, "HDcalloc"); + + /* Initialize write buffer */ + for (i = 0, tbuf = wbuf; i < SPACE8_DIM4; i++) + for (j = 0; j < SPACE8_DIM3; j++) + for (k = 0; k < SPACE8_DIM2; k++) + for (l = 0; l < SPACE8_DIM1; l++) + *tbuf++ = (uint16_t)((k * SPACE8_DIM2) + l); + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset */ + sid1 = H5Screate_simple(SPACE8_RANK, dims2, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create dataspace for writing buffer */ + sid2 = H5Screate_simple(SPACE8_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select semi-contiguous hyperslab for disk dataset */ + start[0] = 0; + start[1] = 0; + start[2] = SPACE8_DIM2 / 2; + start[3] = 0; + count[0] = 2; + count[1] = SPACE8_DIM3; + count[2] = SPACE8_DIM2 / 2; + count[3] = SPACE8_DIM1; + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Select semi-contiguous hyperslab in memory */ + start[0] = 0; + start[1] = 0; + start[2] = SPACE8_DIM2 / 2; + start[3] = 0; + count[0] = 2; + count[1] = SPACE8_DIM3; + count[2] = SPACE8_DIM2 / 2; + count[3] = SPACE8_DIM1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, SPACE8_NAME, dset_type, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_USHORT, sid2, sid1, xfer_plist, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Create dataspace for reading buffer */ + sid2 = H5Screate_simple(SPACE8_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select semi-contiguous hyperslab in memory */ + start[0] = 0; + start[1] = 0; + start[2] = SPACE8_DIM2 / 2; + start[3] = 0; + count[0] = 2; + count[1] = SPACE8_DIM3; + count[2] = SPACE8_DIM2 / 2; + count[3] = SPACE8_DIM1; + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Select semi-contiguous hyperslab in memory */ + start[0] = 0; + start[1] = 0; + start[2] = SPACE8_DIM2 / 2; + start[3] = 0; + count[0] = 2; + count[1] = SPACE8_DIM3; + count[2] = SPACE8_DIM2 / 2; + count[3] = SPACE8_DIM1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Read selection from disk */ + ret = H5Dread(dataset, H5T_NATIVE_USHORT, sid2, sid1, xfer_plist, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read with data written out */ + for (i = 0, tbuf = wbuf, tbuf2 = rbuf; i < SPACE8_DIM4; i++) + for (j = 0; j < SPACE8_DIM3; j++) + for (k = 0; k < SPACE8_DIM2; k++) + for (l = 0; l < SPACE8_DIM1; l++, tbuf++, tbuf2++) + if ((i >= start[0] && i < (start[0] + count[0])) && + (j >= start[1] && j < (start[1] + count[1])) && + (k >= start[2] && k < (start[2] + count[2])) && + (l >= start[3] && l < (start[3] + count[3]))) { + if (*tbuf != *tbuf2) { + HDprintf("Error: hyperslab values don't match!\n"); + TestErrPrintf("Line: %d, i=%u, j=%u, k=%u, l=%u, *tbuf=%u,*tbuf2=%u\n", __LINE__, + i, j, k, l, (unsigned)*tbuf, (unsigned)*tbuf2); + } /* end if */ + } /* end if */ + else { + if (*tbuf2 != 0) { + HDprintf("Error: invalid data in read buffer!\n"); + TestErrPrintf("Line: %d, i=%u, j=%u, k=%u, l=%u, *tbuf=%u,*tbuf2=%u\n", __LINE__, + i, j, k, l, (unsigned)*tbuf, (unsigned)*tbuf2); + } /* end if */ + } /* end else */ + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free memory buffers */ + HDfree(wbuf); + HDfree(rbuf); +} /* test_select_hyper_contig3() */ + +#if 0 +/**************************************************************** +** +** verify_select_hyper_contig_dr__run_test(): Verify data from +** test_select_hyper_contig_dr__run_test() +** +****************************************************************/ +static void +verify_select_hyper_contig_dr__run_test(const uint16_t *cube_buf, size_t cube_size, + unsigned edge_size, unsigned cube_rank) +{ + const uint16_t *cube_ptr; /* Pointer into the cube buffer */ + uint16_t expected_value; /* Expected value in dataset */ + unsigned i, j, k, l, m; /* Local index variables */ + size_t s; /* Local index variable */ + hbool_t mis_match; /* Flag to indicate mismatch in expected value */ + + HDassert(cube_buf); + HDassert(cube_size > 0); + + expected_value = 0; + mis_match = FALSE; + cube_ptr = cube_buf; + s = 0; + i = 0; + do { + j = 0; + do { + k = 0; + do { + l = 0; + do { + m = 0; + do { + /* Sanity check */ + HDassert(s < cube_size); + + /* Check for correct value */ + if (*cube_ptr != expected_value) + mis_match = TRUE; + + /* Advance to next element */ + cube_ptr++; + expected_value++; + s++; + m++; + } while ((cube_rank > 0) && (m < edge_size)); + l++; + } while ((cube_rank > 1) && (l < edge_size)); + k++; + } while ((cube_rank > 2) && (k < edge_size)); + j++; + } while ((cube_rank > 3) && (j < edge_size)); + i++; + } while ((cube_rank > 4) && (i < edge_size)); + if (mis_match) + TestErrPrintf("Initial cube data don't match! Line = %d\n", __LINE__); +} /* verify_select_hyper_contig_dr__run_test() */ +#endif +#if 0 + +/**************************************************************** +** +** test_select_hyper_contig_dr__run_test(): Test H5S (dataspace) +** selection code with contiguous source and target having +** different ranks but the same shape. We have already +** tested H5Sselect_shape_same in isolation, so now we try to do +** I/O. +** +****************************************************************/ +static void +test_select_hyper_contig_dr__run_test(int test_num, const uint16_t *cube_buf, const uint16_t *zero_buf, + unsigned edge_size, unsigned chunk_edge_size, unsigned small_rank, + unsigned large_rank, hid_t dset_type, hid_t xfer_plist) +{ + hbool_t mis_match; /* Flag indicating a value read in wasn't what was expected */ + hid_t fapl; /* File access property list */ + hid_t fid1; /* File ID */ + hid_t small_cube_sid; /* Dataspace ID for small cube in memory & file */ + hid_t mem_large_cube_sid; /* Dataspace ID for large cube in memory */ + hid_t file_large_cube_sid; /* Dataspace ID for large cube in file */ + hid_t small_cube_dcpl_id = H5P_DEFAULT; /* DCPL for small cube dataset */ + hid_t large_cube_dcpl_id = H5P_DEFAULT; /* DCPL for large cube dataset */ + hid_t small_cube_dataset; /* Dataset ID */ + hid_t large_cube_dataset; /* Dataset ID */ + size_t start_index; /* Offset within buffer to begin inspecting */ + size_t stop_index; /* Offset within buffer to end inspecting */ + uint16_t expected_value; /* Expected value in dataset */ + uint16_t *small_cube_buf_1; /* Buffer for small cube data */ + uint16_t *large_cube_buf_1; /* Buffer for large cube data */ + uint16_t *ptr_1; /* Temporary pointer into cube data */ + hsize_t dims[SS_DR_MAX_RANK]; /* Dataspace dimensions */ + hsize_t start[SS_DR_MAX_RANK]; /* Shared hyperslab start offset */ + hsize_t stride[SS_DR_MAX_RANK]; /* Shared hyperslab stride */ + hsize_t count[SS_DR_MAX_RANK]; /* Shared hyperslab count */ + hsize_t block[SS_DR_MAX_RANK]; /* Shared hyperslab block size */ + hsize_t *start_ptr; /* Actual hyperslab start offset */ + hsize_t *stride_ptr; /* Actual hyperslab stride */ + hsize_t *count_ptr; /* Actual hyperslab count */ + hsize_t *block_ptr; /* Actual hyperslab block size */ + size_t small_cube_size; /* Number of elements in small cube */ + size_t large_cube_size; /* Number of elements in large cube */ + unsigned u, v, w, x; /* Local index variables */ + size_t s; /* Local index variable */ + htri_t check; /* Shape comparison return value */ + herr_t ret; /* Generic return value */ + + MESSAGE(7, ("\tn-cube slice through m-cube I/O test %d.\n", test_num)); + MESSAGE(7, ("\tranks = %u/%u, edge_size = %u, chunk_edge_size = %u.\n", small_rank, large_rank, edge_size, + chunk_edge_size)); + + HDassert(edge_size >= 6); + HDassert(edge_size >= chunk_edge_size); + HDassert((chunk_edge_size == 0) || (chunk_edge_size >= 3)); + HDassert(small_rank > 0); + HDassert(small_rank < large_rank); + HDassert(large_rank <= SS_DR_MAX_RANK); + + /* Compute cube sizes */ + small_cube_size = large_cube_size = (size_t)1; + for (u = 0; u < large_rank; u++) { + if (u < small_rank) + small_cube_size *= (size_t)edge_size; + + large_cube_size *= (size_t)edge_size; + } /* end for */ + + HDassert(large_cube_size < (size_t)UINT_MAX); + + /* set up the start, stride, count, and block pointers */ + start_ptr = &(start[SS_DR_MAX_RANK - large_rank]); + stride_ptr = &(stride[SS_DR_MAX_RANK - large_rank]); + count_ptr = &(count[SS_DR_MAX_RANK - large_rank]); + block_ptr = &(block[SS_DR_MAX_RANK - large_rank]); + + /* Allocate buffers */ + small_cube_buf_1 = (uint16_t *)HDcalloc(sizeof(uint16_t), small_cube_size); + CHECK_PTR(small_cube_buf_1, "HDcalloc"); + large_cube_buf_1 = (uint16_t *)HDcalloc(sizeof(uint16_t), large_cube_size); + CHECK_PTR(large_cube_buf_1, "HDcalloc"); + + /* Create a dataset transfer property list */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + + /* Use the 'core' VFD for this test */ + ret = H5Pset_fapl_core(fapl, (size_t)(1024 * 1024), FALSE); + CHECK(ret, FAIL, "H5Pset_fapl_core"); + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Close file access property list */ + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + + /* setup dims: */ + dims[0] = dims[1] = dims[2] = dims[3] = dims[4] = (hsize_t)edge_size; + + /* Create small cube dataspaces */ + small_cube_sid = H5Screate_simple((int)small_rank, dims, NULL); + CHECK(small_cube_sid, FAIL, "H5Screate_simple"); + + /* Create large cube dataspace */ + mem_large_cube_sid = H5Screate_simple((int)large_rank, dims, NULL); + CHECK(mem_large_cube_sid, FAIL, "H5Screate_simple"); + file_large_cube_sid = H5Screate_simple((int)large_rank, dims, NULL); + CHECK(file_large_cube_sid, FAIL, "H5Screate_simple"); + + /* if chunk edge size is greater than zero, set up the small and + * large data set creation property lists to specify chunked + * datasets. + */ + if (chunk_edge_size > 0) { + hsize_t chunk_dims[SS_DR_MAX_RANK]; /* Chunk dimensions */ + + chunk_dims[0] = chunk_dims[1] = chunk_dims[2] = chunk_dims[3] = chunk_dims[4] = + (hsize_t)chunk_edge_size; + + small_cube_dcpl_id = H5Pcreate(H5P_DATASET_CREATE); + CHECK(small_cube_dcpl_id, FAIL, "H5Pcreate"); + + ret = H5Pset_layout(small_cube_dcpl_id, H5D_CHUNKED); + CHECK(ret, FAIL, "H5Pset_layout"); + + ret = H5Pset_chunk(small_cube_dcpl_id, (int)small_rank, chunk_dims); + CHECK(ret, FAIL, "H5Pset_chunk"); + + large_cube_dcpl_id = H5Pcreate(H5P_DATASET_CREATE); + CHECK(large_cube_dcpl_id, FAIL, "H5Pcreate"); + + ret = H5Pset_layout(large_cube_dcpl_id, H5D_CHUNKED); + CHECK(ret, FAIL, "H5Pset_layout"); + + ret = H5Pset_chunk(large_cube_dcpl_id, (int)large_rank, chunk_dims); + CHECK(ret, FAIL, "H5Pset_chunk"); + } /* end if */ + + /* create the small cube dataset */ + small_cube_dataset = H5Dcreate2(fid1, "small_cube_dataset", dset_type, small_cube_sid, H5P_DEFAULT, + small_cube_dcpl_id, H5P_DEFAULT); + CHECK(small_cube_dataset, FAIL, "H5Dcreate2"); + + /* Close non-default small dataset DCPL */ + if (small_cube_dcpl_id != H5P_DEFAULT) { + ret = H5Pclose(small_cube_dcpl_id); + CHECK(ret, FAIL, "H5Pclose"); + } /* end if */ + + /* create the large cube dataset */ + large_cube_dataset = H5Dcreate2(fid1, "large_cube_dataset", dset_type, file_large_cube_sid, H5P_DEFAULT, + large_cube_dcpl_id, H5P_DEFAULT); + CHECK(large_cube_dataset, FAIL, "H5Dcreate2"); + + /* Close non-default large dataset DCPL */ + if (large_cube_dcpl_id != H5P_DEFAULT) { + ret = H5Pclose(large_cube_dcpl_id); + CHECK(ret, FAIL, "H5Pclose"); + } /* end if */ + + /* write initial data to the on disk datasets */ + ret = + H5Dwrite(small_cube_dataset, H5T_NATIVE_UINT16, small_cube_sid, small_cube_sid, xfer_plist, cube_buf); + CHECK(ret, FAIL, "H5Dwrite"); + + ret = H5Dwrite(large_cube_dataset, H5T_NATIVE_UINT16, mem_large_cube_sid, file_large_cube_sid, xfer_plist, + cube_buf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* read initial data from disk and verify that it is as expected. */ + ret = H5Dread(small_cube_dataset, H5T_NATIVE_UINT16, small_cube_sid, small_cube_sid, xfer_plist, + small_cube_buf_1); + CHECK(ret, FAIL, "H5Dread"); + + /* Check that the data is valid */ + verify_select_hyper_contig_dr__run_test(small_cube_buf_1, small_cube_size, edge_size, small_rank); + + ret = H5Dread(large_cube_dataset, H5T_NATIVE_UINT16, mem_large_cube_sid, file_large_cube_sid, xfer_plist, + large_cube_buf_1); + CHECK(ret, FAIL, "H5Dread"); + + /* Check that the data is valid */ + verify_select_hyper_contig_dr__run_test(large_cube_buf_1, large_cube_size, edge_size, large_rank); + + /* first, verify that we can read from disk correctly using selections + * of different rank that H5Sselect_shape_same() views as being of the + * same shape. + * + * Start by reading small_rank-D slice from the on disk large cube, and + * verifying that the data read is correct. Verify that H5Sselect_shape_same() + * returns true on the memory and file selections. + */ + + /* set up start, stride, count, and block -- note that we will + * change start[] so as to read slices of the large cube. + */ + for (u = 0; u < SS_DR_MAX_RANK; u++) { + start[u] = 0; + stride[u] = 1; + count[u] = 1; + if ((SS_DR_MAX_RANK - u) > small_rank) + block[u] = 1; + else + block[u] = (hsize_t)edge_size; + } /* end for */ + + u = 0; + do { + v = 0; + do { + w = 0; + do { + x = 0; + do { + /* we know that small_rank >= 1 and that large_rank > small_rank + * by the assertions at the head of this function. Thus no + * need for another inner loop. + */ + start[0] = (hsize_t)u; + start[1] = (hsize_t)v; + start[2] = (hsize_t)w; + start[3] = (hsize_t)x; + start[4] = (hsize_t)0; + + ret = H5Sselect_hyperslab(file_large_cube_sid, H5S_SELECT_SET, start_ptr, stride_ptr, + count_ptr, block_ptr); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* verify that H5Sselect_shape_same() reports the two + * selections as having the same shape. + */ + check = H5Sselect_shape_same(small_cube_sid, file_large_cube_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* Read selection from disk */ + ret = H5Dread(large_cube_dataset, H5T_NATIVE_UINT16, small_cube_sid, file_large_cube_sid, + xfer_plist, small_cube_buf_1); + CHECK(ret, FAIL, "H5Dread"); + + /* verify that expected data is retrieved */ + mis_match = FALSE; + ptr_1 = small_cube_buf_1; + expected_value = (uint16_t)((u * edge_size * edge_size * edge_size * edge_size) + + (v * edge_size * edge_size * edge_size) + + (w * edge_size * edge_size) + (x * edge_size)); + for (s = 0; s < small_cube_size; s++) { + if (*ptr_1 != expected_value) + mis_match = TRUE; + ptr_1++; + expected_value++; + } /* end for */ + if (mis_match) + TestErrPrintf("small cube read from largecube has bad data! Line=%d\n", __LINE__); + + x++; + } while ((large_rank >= 2) && (small_rank <= 1) && (x < edge_size)); + w++; + } while ((large_rank >= 3) && (small_rank <= 2) && (w < edge_size)); + v++; + } while ((large_rank >= 4) && (small_rank <= 3) && (v < edge_size)); + u++; + } while ((large_rank >= 5) && (small_rank <= 4) && (u < edge_size)); + + /* similarly, read the on disk small cube into slices through the in memory + * large cube, and verify that the correct data (and only the correct data) + * is read. + */ + + /* zero out the in-memory large cube */ + HDmemset(large_cube_buf_1, 0, large_cube_size * sizeof(uint16_t)); + + u = 0; + do { + v = 0; + do { + w = 0; + do { + x = 0; + do { + /* we know that small_rank >= 1 and that large_rank > small_rank + * by the assertions at the head of this function. Thus no + * need for another inner loop. + */ + start[0] = (hsize_t)u; + start[1] = (hsize_t)v; + start[2] = (hsize_t)w; + start[3] = (hsize_t)x; + start[4] = (hsize_t)0; + + ret = H5Sselect_hyperslab(mem_large_cube_sid, H5S_SELECT_SET, start_ptr, stride_ptr, + count_ptr, block_ptr); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* verify that H5Sselect_shape_same() reports the two + * selections as having the same shape. + */ + check = H5Sselect_shape_same(small_cube_sid, mem_large_cube_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* Read selection from disk */ + ret = H5Dread(small_cube_dataset, H5T_NATIVE_UINT16, mem_large_cube_sid, small_cube_sid, + xfer_plist, large_cube_buf_1); + CHECK(ret, FAIL, "H5Dread"); + + /* verify that the expected data and only the + * expected data was read. + */ + start_index = (u * edge_size * edge_size * edge_size * edge_size) + + (v * edge_size * edge_size * edge_size) + (w * edge_size * edge_size) + + (x * edge_size); + stop_index = start_index + small_cube_size - 1; + + HDassert(start_index < stop_index); + HDassert(stop_index <= large_cube_size); + + mis_match = FALSE; + ptr_1 = large_cube_buf_1; + expected_value = 0; + for (s = 0; s < start_index; s++) { + if (*ptr_1 != 0) + mis_match = TRUE; + ptr_1++; + } /* end for */ + for (; s <= stop_index; s++) { + if (*ptr_1 != expected_value) + mis_match = TRUE; + expected_value++; + ptr_1++; + } /* end for */ + for (; s < large_cube_size; s++) { + if (*ptr_1 != 0) + mis_match = TRUE; + ptr_1++; + } /* end for */ + if (mis_match) + TestErrPrintf("large cube read from small cube has bad data! Line=%u\n", __LINE__); + + /* Zero out the buffer for the next pass */ + HDmemset(large_cube_buf_1 + start_index, 0, small_cube_size * sizeof(uint16_t)); + + x++; + } while ((large_rank >= 2) && (small_rank <= 1) && (x < edge_size)); + w++; + } while ((large_rank >= 3) && (small_rank <= 2) && (w < edge_size)); + v++; + } while ((large_rank >= 4) && (small_rank <= 3) && (v < edge_size)); + u++; + } while ((large_rank >= 5) && (small_rank <= 4) && (u < edge_size)); + + /* now we go in the opposite direction, verifying that we can write + * from memory to file using selections of different rank that + * H5Sselect_shape_same() views as being of the same shape. + * + * Start by writing small_rank D slices from the in memory large cube, to + * the the on disk small cube dataset. After each write, read the small + * cube dataset back from disk, and verify that it contains the expected + * data. Verify that H5Sselect_shape_same() returns true on the + * memory and file selections. + */ + + u = 0; + do { + v = 0; + do { + w = 0; + do { + x = 0; + do { + /* we know that small_rank >= 1 and that large_rank > small_rank + * by the assertions at the head of this function. Thus no + * need for another inner loop. + */ + + /* zero out the on disk small cube */ + ret = H5Dwrite(small_cube_dataset, H5T_NATIVE_UINT16, small_cube_sid, small_cube_sid, + xfer_plist, zero_buf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* select the portion of the in memory large cube from which we + * are going to write data. + */ + start[0] = (hsize_t)u; + start[1] = (hsize_t)v; + start[2] = (hsize_t)w; + start[3] = (hsize_t)x; + start[4] = (hsize_t)0; + + ret = H5Sselect_hyperslab(mem_large_cube_sid, H5S_SELECT_SET, start_ptr, stride_ptr, + count_ptr, block_ptr); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* verify that H5Sselect_shape_same() reports the in + * memory slice through the cube selection and the + * on disk full small cube selections as having the same shape. + */ + check = H5Sselect_shape_same(small_cube_sid, mem_large_cube_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* write the slice from the in memory large cube to the on disk small cube */ + ret = H5Dwrite(small_cube_dataset, H5T_NATIVE_UINT16, mem_large_cube_sid, small_cube_sid, + xfer_plist, cube_buf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* read the on disk small cube into memory */ + ret = H5Dread(small_cube_dataset, H5T_NATIVE_UINT16, small_cube_sid, small_cube_sid, + xfer_plist, small_cube_buf_1); + CHECK(ret, FAIL, "H5Dread"); + + /* verify that expected data is retrieved */ + mis_match = FALSE; + ptr_1 = small_cube_buf_1; + expected_value = (uint16_t)((u * edge_size * edge_size * edge_size * edge_size) + + (v * edge_size * edge_size * edge_size) + + (w * edge_size * edge_size) + (x * edge_size)); + for (s = 0; s < small_cube_size; s++) { + if (*ptr_1 != expected_value) + mis_match = TRUE; + expected_value++; + ptr_1++; + } /* end for */ + if (mis_match) + TestErrPrintf("small cube data don't match! Line=%d\n", __LINE__); + + x++; + } while ((large_rank >= 2) && (small_rank <= 1) && (x < edge_size)); + w++; + } while ((large_rank >= 3) && (small_rank <= 2) && (w < edge_size)); + v++; + } while ((large_rank >= 4) && (small_rank <= 3) && (v < edge_size)); + u++; + } while ((large_rank >= 5) && (small_rank <= 4) && (u < edge_size)); + + /* Now write the contents of the in memory small cube to slices of + * the on disk cube. After each write, read the on disk cube + * into memory, and verify that it contains the expected + * data. Verify that H5Sselect_shape_same() returns true on + * the memory and file selections. + */ + + /* select the entire memory and file cube dataspaces */ + ret = H5Sselect_all(mem_large_cube_sid); + CHECK(ret, FAIL, "H5Sselect_all"); + + ret = H5Sselect_all(file_large_cube_sid); + CHECK(ret, FAIL, "H5Sselect_all"); + + u = 0; + do { + v = 0; + do { + w = 0; + do { + x = 0; + do { + /* we know that small_rank >= 1 and that large_rank > small_rank + * by the assertions at the head of this function. Thus no + * need for another inner loop. + */ + + /* zero out the on disk cube */ + ret = H5Dwrite(large_cube_dataset, H5T_NATIVE_USHORT, mem_large_cube_sid, + file_large_cube_sid, xfer_plist, zero_buf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* select the portion of the in memory large cube to which we + * are going to write data. + */ + start[0] = (hsize_t)u; + start[1] = (hsize_t)v; + start[2] = (hsize_t)w; + start[3] = (hsize_t)x; + start[4] = (hsize_t)0; + + ret = H5Sselect_hyperslab(file_large_cube_sid, H5S_SELECT_SET, start_ptr, stride_ptr, + count_ptr, block_ptr); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* verify that H5Sselect_shape_same() reports the in + * memory full selection of the small cube and the + * on disk slice through the large cube selection + * as having the same shape. + */ + check = H5Sselect_shape_same(small_cube_sid, file_large_cube_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* write the cube from memory to the target slice of the disk cube */ + ret = H5Dwrite(large_cube_dataset, H5T_NATIVE_UINT16, small_cube_sid, file_large_cube_sid, + xfer_plist, cube_buf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* read the on disk cube into memory */ + ret = H5Sselect_all(file_large_cube_sid); + CHECK(ret, FAIL, "H5Sselect_all"); + + ret = H5Dread(large_cube_dataset, H5T_NATIVE_UINT16, mem_large_cube_sid, + file_large_cube_sid, xfer_plist, large_cube_buf_1); + CHECK(ret, FAIL, "H5Dread"); + + /* verify that the expected data and only the + * expected data was read. + */ + start_index = (u * edge_size * edge_size * edge_size * edge_size) + + (v * edge_size * edge_size * edge_size) + (w * edge_size * edge_size) + + (x * edge_size); + stop_index = start_index + small_cube_size - 1; + + HDassert(start_index < stop_index); + HDassert(stop_index <= large_cube_size); + + mis_match = FALSE; + ptr_1 = large_cube_buf_1; + expected_value = 0; + for (s = 0; s < start_index; s++) { + if (*ptr_1 != 0) + mis_match = TRUE; + ptr_1++; + } /* end for */ + for (; s <= stop_index; s++) { + if (*ptr_1 != expected_value) + mis_match = TRUE; + expected_value++; + ptr_1++; + } /* end for */ + for (; s < large_cube_size; s++) { + if (*ptr_1 != 0) + mis_match = TRUE; + ptr_1++; + } /* end for */ + if (mis_match) + TestErrPrintf("large cube written from small cube has bad data! Line=%d\n", __LINE__); + + x++; + } while ((large_rank >= 2) && (small_rank <= 1) && (x < edge_size)); + w++; + } while ((large_rank >= 3) && (small_rank <= 2) && (w < edge_size)); + v++; + } while ((large_rank >= 4) && (small_rank <= 3) && (v < edge_size)); + u++; + } while ((large_rank >= 5) && (small_rank <= 4) && (u < edge_size)); + + /* Close memory dataspaces */ + ret = H5Sclose(small_cube_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(mem_large_cube_sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(file_large_cube_sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Datasets */ + ret = H5Dclose(small_cube_dataset); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Dclose(large_cube_dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free memory buffers */ + HDfree(small_cube_buf_1); + HDfree(large_cube_buf_1); + +} /* test_select_hyper_contig_dr__run_test() */ +#endif +#if 0 +/**************************************************************** +** +** test_select_hyper_contig_dr(): Test H5S (dataspace) +** selection code with contiguous source and target having +** different ranks but the same shape. We have already +** tested H5Sselect_shape_same in isolation, so now we try to do +** I/O. +** +****************************************************************/ +static void +test_select_hyper_contig_dr(hid_t dset_type, hid_t xfer_plist) +{ + int test_num = 0; + unsigned chunk_edge_size; /* Size of chunk's dataspace dimensions */ + unsigned edge_size = 6; /* Size of dataset's dataspace dimensions */ + unsigned small_rank; /* Current rank of small dataset */ + unsigned large_rank; /* Current rank of large dataset */ + uint16_t *cube_buf; /* Buffer for writing cube data */ + uint16_t *zero_buf; /* Buffer for writing zeroed cube data */ + uint16_t *cube_ptr; /* Temporary pointer into cube data */ + unsigned max_rank = 5; /* Max. rank to use */ + size_t max_cube_size; /* Max. number of elements in largest cube */ + size_t s; /* Local index variable */ + unsigned u; /* Local index variable */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Contiguous Hyperslabs With Different Rank I/O Functionality\n")); + + /* Compute max. cube size */ + max_cube_size = (size_t)1; + for (u = 0; u < max_rank; u++) + max_cube_size *= (size_t)edge_size; + + /* Allocate cube buffer for writing values */ + cube_buf = (uint16_t *)HDmalloc(sizeof(uint16_t) * max_cube_size); + CHECK_PTR(cube_buf, "HDmalloc"); + + /* Initialize the cube buffer */ + cube_ptr = cube_buf; + for (s = 0; s < max_cube_size; s++) + *cube_ptr++ = (uint16_t)s; + + /* Allocate cube buffer for zeroing values on disk */ + zero_buf = (uint16_t *)HDcalloc(sizeof(uint16_t), max_cube_size); + CHECK_PTR(zero_buf, "HDcalloc"); + + for (large_rank = 1; large_rank <= max_rank; large_rank++) { + for (small_rank = 1; small_rank < large_rank; small_rank++) { + chunk_edge_size = 0; + test_select_hyper_contig_dr__run_test(test_num, cube_buf, zero_buf, edge_size, chunk_edge_size, + small_rank, large_rank, dset_type, xfer_plist); + test_num++; + + chunk_edge_size = 3; + test_select_hyper_contig_dr__run_test(test_num, cube_buf, zero_buf, edge_size, chunk_edge_size, + small_rank, large_rank, dset_type, xfer_plist); + test_num++; + } /* for loop on small rank */ + } /* for loop on large rank */ + + HDfree(cube_buf); + HDfree(zero_buf); + +} /* test_select_hyper_contig_dr() */ +#endif +/**************************************************************** +** +** test_select_hyper_checker_board_dr__select_checker_board(): +** Given an n-cube dataspace with each edge of length +** edge_size, and a checker_edge_size either select a checker +** board selection of the entire cube(if sel_rank == n), +** or select a checker board selection of a +** sel_rank dimensional slice through n-cube parallel to the +** sel_rank fastest changing indices, with origin (in the +** higher indices) as indicated by the start array. +** +** Note that this function, like all its relatives, is +** hard coded to presume a maximum n-cube rank of 5. +** While this maximum is declared as a constant, increasing +** it will require extensive coding in addition to changing +** the value of the constant. +** +** JRM -- 9/9/09 +** +****************************************************************/ +#if 0 +static void +test_select_hyper_checker_board_dr__select_checker_board(hid_t tgt_n_cube_sid, unsigned tgt_n_cube_rank, + unsigned edge_size, unsigned checker_edge_size, + unsigned sel_rank, const hsize_t sel_start[]) +{ + hbool_t first_selection = TRUE; + unsigned n_cube_offset; + unsigned sel_offset; + hsize_t base_count; + hsize_t offset_count; + hsize_t start[SS_DR_MAX_RANK]; /* Offset of hyperslab selection */ + hsize_t stride[SS_DR_MAX_RANK]; /* Stride of hyperslab selection */ + hsize_t count[SS_DR_MAX_RANK]; /* Count of hyperslab selection */ + hsize_t block[SS_DR_MAX_RANK]; /* Block size of hyperslab selection */ + unsigned i, j, k, l, m; /* Local index variable */ + unsigned u; /* Local index variables */ + herr_t ret; /* Generic return value */ + + HDassert(edge_size >= 6); + HDassert(0 < checker_edge_size); + HDassert(checker_edge_size <= edge_size); + HDassert(0 < sel_rank); + HDassert(sel_rank <= tgt_n_cube_rank); + HDassert(tgt_n_cube_rank <= SS_DR_MAX_RANK); + + sel_offset = SS_DR_MAX_RANK - sel_rank; + n_cube_offset = SS_DR_MAX_RANK - tgt_n_cube_rank; + HDassert(n_cube_offset <= sel_offset); + + /* First, compute the base count (which assumes start == 0 + * for the associated offset) and offset_count (which + * assumes start == checker_edge_size for the associated + * offset). + */ + base_count = edge_size / (checker_edge_size * 2); + if ((edge_size % (checker_edge_size * 2)) > 0) + base_count++; + + offset_count = (edge_size - checker_edge_size) / (checker_edge_size * 2); + if (((edge_size - checker_edge_size) % (checker_edge_size * 2)) > 0) + offset_count++; + + /* Now set up the stride and block arrays, and portions of the start + * and count arrays that will not be altered during the selection of + * the checker board. + */ + u = 0; + while (u < n_cube_offset) { + /* these values should never be used */ + start[u] = 0; + stride[u] = 0; + count[u] = 0; + block[u] = 0; + + u++; + } /* end while */ + + while (u < sel_offset) { + start[u] = sel_start[u]; + stride[u] = 2 * edge_size; + count[u] = 1; + block[u] = 1; + + u++; + } /* end while */ + + while (u < SS_DR_MAX_RANK) { + stride[u] = 2 * checker_edge_size; + block[u] = checker_edge_size; + + u++; + } /* end while */ + + i = 0; + do { + if (0 >= sel_offset) { + if (i == 0) { + start[0] = 0; + count[0] = base_count; + } /* end if */ + else { + start[0] = checker_edge_size; + count[0] = offset_count; + } /* end else */ + } /* end if */ + + j = 0; + do { + if (1 >= sel_offset) { + if (j == 0) { + start[1] = 0; + count[1] = base_count; + } /* end if */ + else { + start[1] = checker_edge_size; + count[1] = offset_count; + } /* end else */ + } /* end if */ + + k = 0; + do { + if (2 >= sel_offset) { + if (k == 0) { + start[2] = 0; + count[2] = base_count; + } /* end if */ + else { + start[2] = checker_edge_size; + count[2] = offset_count; + } /* end else */ + } /* end if */ + + l = 0; + do { + if (3 >= sel_offset) { + if (l == 0) { + start[3] = 0; + count[3] = base_count; + } /* end if */ + else { + start[3] = checker_edge_size; + count[3] = offset_count; + } /* end else */ + } /* end if */ + + m = 0; + do { + if (4 >= sel_offset) { + if (m == 0) { + start[4] = 0; + count[4] = base_count; + } /* end if */ + else { + start[4] = checker_edge_size; + count[4] = offset_count; + } /* end else */ + } /* end if */ + + if (((i + j + k + l + m) % 2) == 0) { + if (first_selection) { + first_selection = FALSE; + + ret = H5Sselect_hyperslab(tgt_n_cube_sid, H5S_SELECT_SET, + &(start[n_cube_offset]), &(stride[n_cube_offset]), + &(count[n_cube_offset]), &(block[n_cube_offset])); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + } /* end if */ + else { + ret = H5Sselect_hyperslab(tgt_n_cube_sid, H5S_SELECT_OR, + &(start[n_cube_offset]), &(stride[n_cube_offset]), + &(count[n_cube_offset]), &(block[n_cube_offset])); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + } /* end else */ + } /* end if */ + + m++; + } while ((m <= 1) && (4 >= sel_offset)); + l++; + } while ((l <= 1) && (3 >= sel_offset)); + k++; + } while ((k <= 1) && (2 >= sel_offset)); + j++; + } while ((j <= 1) && (1 >= sel_offset)); + i++; + } while ((i <= 1) && (0 >= sel_offset)); + + /* Weirdness alert: + * + * Some how, it seems that selections can extend beyond the + * boundaries of the target dataspace -- hence the following + * code to manually clip the selection back to the dataspace + * proper. + */ + for (u = 0; u < SS_DR_MAX_RANK; u++) { + start[u] = 0; + stride[u] = edge_size; + count[u] = 1; + block[u] = edge_size; + } /* end for */ + + ret = H5Sselect_hyperslab(tgt_n_cube_sid, H5S_SELECT_AND, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +} /* test_select_hyper_checker_board_dr__select_checker_board() */ +#endif + +/**************************************************************** +** +** test_select_hyper_checker_board_dr__verify_data(): +** +** Examine the supplied buffer to see if it contains the +** expected data. Return TRUE if it does, and FALSE +** otherwise. +** +** The supplied buffer is presumed to contain the results +** of read or writing a checkerboard selection of an +** n-cube, or a checkerboard selection of an m (1 <= m < n) +** dimensional slice through an n-cube parallel to the +** fastest changing indices. +** +** It is further presumed that the buffer was zeroed before +** the read, and that the n-cube was initialize with the +** natural numbers listed in order from the origin along +** the fastest changing axis. +** +** Thus for a 10x10x10 3-cube, the value stored in location +** (x, y, z) (assuming that z is the fastest changing index +** and x the slowest) is assumed to be: +** +** (10 * 10 * x) + (10 * y) + z +** +** Thus, if the buffer contains the result of reading a +** checker board selection of a 10x10x10 3-cube, location +** (x, y, z) will contain zero if it is not in a checker, +** and 100x + 10y + z if (x, y, z) is in a checker. +** +** If the buffer contains the result of reading a 3 +** dimensional slice (parallel to the three fastest changing +** indices) through an n cube (n > 3), then the expected +** values in the buffer will be the same, save that we will +** add a constant determined by the origin of the 3-cube +** in the n-cube. +** +** Finally, the function presumes that the first element +** of the buffer resides either at the origin of either +** a selected or an unselected checker. +** +****************************************************************/ +#if 0 +H5_ATTR_PURE static hbool_t +test_select_hyper_checker_board_dr__verify_data(uint16_t *buf_ptr, unsigned rank, unsigned edge_size, + unsigned checker_edge_size, uint16_t first_expected_val, + hbool_t buf_starts_in_checker) +{ + hbool_t good_data = TRUE; + hbool_t in_checker; + hbool_t start_in_checker[5]; + uint16_t expected_value; + uint16_t *val_ptr; + unsigned i, j, k, l, m; /* to track position in n-cube */ + unsigned v, w, x, y, z; /* to track position in checker */ + const unsigned test_max_rank = 5; /* code changes needed if this is increased */ + + HDassert(buf_ptr != NULL); + HDassert(0 < rank); + HDassert(rank <= test_max_rank); + HDassert(edge_size >= 6); + HDassert(0 < checker_edge_size); + HDassert(checker_edge_size <= edge_size); + HDassert(test_max_rank <= SS_DR_MAX_RANK); + + val_ptr = buf_ptr; + expected_value = first_expected_val; + + i = 0; + v = 0; + start_in_checker[0] = buf_starts_in_checker; + do { + if (v >= checker_edge_size) { + start_in_checker[0] = !start_in_checker[0]; + v = 0; + } /* end if */ + + j = 0; + w = 0; + start_in_checker[1] = start_in_checker[0]; + do { + if (w >= checker_edge_size) { + start_in_checker[1] = !start_in_checker[1]; + w = 0; + } /* end if */ + + k = 0; + x = 0; + start_in_checker[2] = start_in_checker[1]; + do { + if (x >= checker_edge_size) { + start_in_checker[2] = !start_in_checker[2]; + x = 0; + } /* end if */ + + l = 0; + y = 0; + start_in_checker[3] = start_in_checker[2]; + do { + if (y >= checker_edge_size) { + start_in_checker[3] = !start_in_checker[3]; + y = 0; + } /* end if */ + + m = 0; + z = 0; + in_checker = start_in_checker[3]; + do { + if (z >= checker_edge_size) { + in_checker = !in_checker; + z = 0; + } /* end if */ + + if (in_checker) { + if (*val_ptr != expected_value) + good_data = FALSE; + } /* end if */ + else { + if (*val_ptr != 0) + good_data = FALSE; + } /* end else */ + + val_ptr++; + expected_value++; + + m++; + z++; + } while ((rank >= (test_max_rank - 4)) && (m < edge_size)); + l++; + y++; + } while ((rank >= (test_max_rank - 3)) && (l < edge_size)); + k++; + x++; + } while ((rank >= (test_max_rank - 2)) && (k < edge_size)); + j++; + w++; + } while ((rank >= (test_max_rank - 1)) && (j < edge_size)); + i++; + v++; + } while ((rank >= test_max_rank) && (i < edge_size)); + + return (good_data); +} /* test_select_hyper_checker_board_dr__verify_data() */ +#endif + +/**************************************************************** +** +** test_select_hyper_checker_board_dr__run_test(): Test H5S +** (dataspace) selection code with checker board source and +** target selections having different ranks but the same +** shape. We have already tested H5Sselect_shape_same in +** isolation, so now we try to do I/O. +** +****************************************************************/ +#if 0 +static void +test_select_hyper_checker_board_dr__run_test(int test_num, const uint16_t *cube_buf, const uint16_t *zero_buf, + unsigned edge_size, unsigned checker_edge_size, + unsigned chunk_edge_size, unsigned small_rank, + unsigned large_rank, hid_t dset_type, hid_t xfer_plist) +{ + hbool_t data_ok; + hid_t fapl; /* File access property list */ + hid_t fid; /* HDF5 File IDs */ + hid_t full_small_cube_sid; /* Dataspace for small cube w/all selection */ + hid_t mem_small_cube_sid; + hid_t file_small_cube_sid; + hid_t full_large_cube_sid; /* Dataspace for large cube w/all selection */ + hid_t mem_large_cube_sid; + hid_t file_large_cube_sid; + hid_t small_cube_dcpl_id = H5P_DEFAULT; /* DCPL for small cube dataset */ + hid_t large_cube_dcpl_id = H5P_DEFAULT; /* DCPL for large cube dataset */ + hid_t small_cube_dataset; /* Dataset ID */ + hid_t large_cube_dataset; /* Dataset ID */ + unsigned small_rank_offset; /* Rank offset of slice */ + const unsigned test_max_rank = 5; /* must update code if this changes */ + size_t start_index; /* Offset within buffer to begin inspecting */ + size_t stop_index; /* Offset within buffer to end inspecting */ + uint16_t expected_value; + uint16_t *small_cube_buf_1; + uint16_t *large_cube_buf_1; + uint16_t *ptr_1; + size_t small_cube_size; /* Number of elements in small cube */ + size_t large_cube_size; /* Number of elements in large cube */ + hsize_t dims[SS_DR_MAX_RANK]; + hsize_t chunk_dims[SS_DR_MAX_RANK]; + hsize_t sel_start[SS_DR_MAX_RANK]; + unsigned u, v, w, x; /* Local index variables */ + size_t s; /* Local index variable */ + htri_t check; /* Shape comparison return value */ + herr_t ret; /* Generic return value */ + + MESSAGE(7, ("\tn-cube slice through m-cube I/O test %d.\n", test_num)); + MESSAGE(7, ("\tranks = %d/%d, edge_size = %d, checker_edge_size = %d, chunk_edge_size = %d.\n", + small_rank, large_rank, edge_size, checker_edge_size, chunk_edge_size)); + + HDassert(edge_size >= 6); + HDassert(checker_edge_size > 0); + HDassert(checker_edge_size <= edge_size); + HDassert(edge_size >= chunk_edge_size); + HDassert((chunk_edge_size == 0) || (chunk_edge_size >= 3)); + HDassert(small_rank > 0); + HDassert(small_rank < large_rank); + HDassert(large_rank <= test_max_rank); + HDassert(test_max_rank <= SS_DR_MAX_RANK); + + /* Compute cube sizes */ + small_cube_size = large_cube_size = (size_t)1; + for (u = 0; u < large_rank; u++) { + if (u < small_rank) + small_cube_size *= (size_t)edge_size; + + large_cube_size *= (size_t)edge_size; + } /* end for */ + HDassert(large_cube_size < (size_t)(UINT_MAX)); + + small_rank_offset = test_max_rank - small_rank; + HDassert(small_rank_offset >= 1); + + /* also, at present, we use 16 bit values in this test -- + * hence the following assertion. Delete it if we convert + * to 32 bit values. + */ + HDassert(large_cube_size < (size_t)(64 * 1024)); + + /* Allocate & initialize buffers */ + small_cube_buf_1 = (uint16_t *)HDcalloc(sizeof(uint16_t), small_cube_size); + CHECK_PTR(small_cube_buf_1, "HDcalloc"); + large_cube_buf_1 = (uint16_t *)HDcalloc(sizeof(uint16_t), large_cube_size); + CHECK_PTR(large_cube_buf_1, "HDcalloc"); + + /* Create a dataset transfer property list */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + + /* Use the 'core' VFD for this test */ + ret = H5Pset_fapl_core(fapl, (size_t)(1024 * 1024), FALSE); + CHECK(ret, FAIL, "H5Pset_fapl_core"); + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Close file access property list */ + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + + /* setup dims: */ + dims[0] = dims[1] = dims[2] = dims[3] = dims[4] = edge_size; + + /* Create small cube dataspaces */ + full_small_cube_sid = H5Screate_simple((int)small_rank, dims, NULL); + CHECK(full_small_cube_sid, FAIL, "H5Screate_simple"); + + mem_small_cube_sid = H5Screate_simple((int)small_rank, dims, NULL); + CHECK(mem_small_cube_sid, FAIL, "H5Screate_simple"); + + file_small_cube_sid = H5Screate_simple((int)small_rank, dims, NULL); + CHECK(file_small_cube_sid, FAIL, "H5Screate_simple"); + + /* Create large cube dataspace */ + full_large_cube_sid = H5Screate_simple((int)large_rank, dims, NULL); + CHECK(full_large_cube_sid, FAIL, "H5Screate_simple"); + + mem_large_cube_sid = H5Screate_simple((int)large_rank, dims, NULL); + CHECK(mem_large_cube_sid, FAIL, "H5Screate_simple"); + + file_large_cube_sid = H5Screate_simple((int)large_rank, dims, NULL); + CHECK(file_large_cube_sid, FAIL, "H5Screate_simple"); + + /* if chunk edge size is greater than zero, set up the small and + * large data set creation property lists to specify chunked + * datasets. + */ + if (chunk_edge_size > 0) { + chunk_dims[0] = chunk_dims[1] = chunk_dims[2] = chunk_dims[3] = chunk_dims[4] = chunk_edge_size; + + small_cube_dcpl_id = H5Pcreate(H5P_DATASET_CREATE); + CHECK(small_cube_dcpl_id, FAIL, "H5Pcreate"); + + ret = H5Pset_layout(small_cube_dcpl_id, H5D_CHUNKED); + CHECK(ret, FAIL, "H5Pset_layout"); + + ret = H5Pset_chunk(small_cube_dcpl_id, (int)small_rank, chunk_dims); + CHECK(ret, FAIL, "H5Pset_chunk"); + + large_cube_dcpl_id = H5Pcreate(H5P_DATASET_CREATE); + CHECK(large_cube_dcpl_id, FAIL, "H5Pcreate"); + + ret = H5Pset_layout(large_cube_dcpl_id, H5D_CHUNKED); + CHECK(ret, FAIL, "H5Pset_layout"); + + ret = H5Pset_chunk(large_cube_dcpl_id, (int)large_rank, chunk_dims); + CHECK(ret, FAIL, "H5Pset_chunk"); + } /* end if */ + + /* create the small cube dataset */ + small_cube_dataset = H5Dcreate2(fid, "small_cube_dataset", dset_type, file_small_cube_sid, H5P_DEFAULT, + small_cube_dcpl_id, H5P_DEFAULT); + CHECK(small_cube_dataset, FAIL, "H5Dcreate2"); + + /* Close non-default small dataset DCPL */ + if (small_cube_dcpl_id != H5P_DEFAULT) { + ret = H5Pclose(small_cube_dcpl_id); + CHECK(ret, FAIL, "H5Pclose"); + } /* end if */ + + /* create the large cube dataset */ + large_cube_dataset = H5Dcreate2(fid, "large_cube_dataset", dset_type, file_large_cube_sid, H5P_DEFAULT, + large_cube_dcpl_id, H5P_DEFAULT); + CHECK(large_cube_dataset, FAIL, "H5Dcreate2"); + + /* Close non-default large dataset DCPL */ + if (large_cube_dcpl_id != H5P_DEFAULT) { + ret = H5Pclose(large_cube_dcpl_id); + CHECK(ret, FAIL, "H5Pclose"); + } /* end if */ + + /* write initial data to the on disk datasets */ + ret = H5Dwrite(small_cube_dataset, H5T_NATIVE_UINT16, full_small_cube_sid, full_small_cube_sid, + xfer_plist, cube_buf); + CHECK(ret, FAIL, "H5Dwrite"); + + ret = H5Dwrite(large_cube_dataset, H5T_NATIVE_UINT16, full_large_cube_sid, full_large_cube_sid, + xfer_plist, cube_buf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* read initial small cube data from disk and verify that it is as expected. */ + ret = H5Dread(small_cube_dataset, H5T_NATIVE_UINT16, full_small_cube_sid, full_small_cube_sid, xfer_plist, + small_cube_buf_1); + CHECK(ret, FAIL, "H5Dread"); + + /* Check that the data is valid */ + verify_select_hyper_contig_dr__run_test(small_cube_buf_1, small_cube_size, edge_size, small_rank); + + /* read initial large cube data from disk and verify that it is as expected. */ + ret = H5Dread(large_cube_dataset, H5T_NATIVE_UINT16, full_large_cube_sid, full_large_cube_sid, xfer_plist, + large_cube_buf_1); + CHECK(ret, FAIL, "H5Dread"); + + /* Check that the data is valid */ + verify_select_hyper_contig_dr__run_test(large_cube_buf_1, large_cube_size, edge_size, large_rank); + + /* first, verify that we can read from disk correctly using selections + * of different rank that H5Sselect_shape_same() views as being of the + * same shape. + * + * Start by reading small_rank-D slice from the on disk large cube, and + * verifying that the data read is correct. Verify that H5Sselect_shape_same() + * returns true on the memory and file selections. + * + * The first step is to set up the needed checker board selection in the + * in memory small small cube + */ + + sel_start[0] = sel_start[1] = sel_start[2] = sel_start[3] = sel_start[4] = 0; + + test_select_hyper_checker_board_dr__select_checker_board(mem_small_cube_sid, small_rank, edge_size, + checker_edge_size, small_rank, sel_start); + + /* now read slices from the large, on-disk cube into the small cube. + * Note how we adjust sel_start only in the dimensions peculiar to the + * large cube. + */ + + u = 0; + do { + if (small_rank_offset > 0) + sel_start[0] = u; + + v = 0; + do { + if (small_rank_offset > 1) + sel_start[1] = v; + + w = 0; + do { + if (small_rank_offset > 2) + sel_start[2] = w; + + x = 0; + do { + if (small_rank_offset > 3) + sel_start[3] = x; + + /* we know that small_rank >= 1 and that large_rank > small_rank + * by the assertions at the head of this function. Thus no + * need for another inner loop. + */ + + HDassert((sel_start[0] == 0) || (0 < small_rank_offset)); + HDassert((sel_start[1] == 0) || (1 < small_rank_offset)); + HDassert((sel_start[2] == 0) || (2 < small_rank_offset)); + HDassert((sel_start[3] == 0) || (3 < small_rank_offset)); + HDassert((sel_start[4] == 0) || (4 < small_rank_offset)); + + test_select_hyper_checker_board_dr__select_checker_board( + file_large_cube_sid, large_rank, edge_size, checker_edge_size, small_rank, sel_start); + + /* verify that H5Sselect_shape_same() reports the two + * selections as having the same shape. + */ + check = H5Sselect_shape_same(mem_small_cube_sid, file_large_cube_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* zero the buffer that we will be using for reading */ + HDmemset(small_cube_buf_1, 0, sizeof(*small_cube_buf_1) * small_cube_size); + + /* Read selection from disk */ + ret = H5Dread(large_cube_dataset, H5T_NATIVE_UINT16, mem_small_cube_sid, + file_large_cube_sid, xfer_plist, small_cube_buf_1); + CHECK(ret, FAIL, "H5Dread"); + + expected_value = (uint16_t)((u * edge_size * edge_size * edge_size * edge_size) + + (v * edge_size * edge_size * edge_size) + + (w * edge_size * edge_size) + (x * edge_size)); + + data_ok = test_select_hyper_checker_board_dr__verify_data(small_cube_buf_1, small_rank, + edge_size, checker_edge_size, + expected_value, (hbool_t)TRUE); + if (!data_ok) + TestErrPrintf("small cube read from largecube has bad data! Line=%d\n", __LINE__); + + x++; + } while ((large_rank >= (test_max_rank - 3)) && (small_rank <= (test_max_rank - 4)) && + (x < edge_size)); + w++; + } while ((large_rank >= (test_max_rank - 2)) && (small_rank <= (test_max_rank - 3)) && + (w < edge_size)); + v++; + } while ((large_rank >= (test_max_rank - 1)) && (small_rank <= (test_max_rank - 2)) && + (v < edge_size)); + u++; + } while ((large_rank >= test_max_rank) && (small_rank <= (test_max_rank - 1)) && (u < edge_size)); + + /* similarly, read the on disk small cube into slices through the in memory + * large cube, and verify that the correct data (and only the correct data) + * is read. + */ + + /* select a checker board in the file small cube dataspace */ + sel_start[0] = sel_start[1] = sel_start[2] = sel_start[3] = sel_start[4] = 0; + test_select_hyper_checker_board_dr__select_checker_board(file_small_cube_sid, small_rank, edge_size, + checker_edge_size, small_rank, sel_start); + + u = 0; + do { + if (0 < small_rank_offset) + sel_start[0] = u; + + v = 0; + do { + if (1 < small_rank_offset) + sel_start[1] = v; + + w = 0; + do { + if (2 < small_rank_offset) + sel_start[2] = w; + + x = 0; + do { + if (3 < small_rank_offset) + sel_start[3] = x; + + /* we know that small_rank >= 1 and that large_rank > small_rank + * by the assertions at the head of this function. Thus no + * need for another inner loop. + */ + + HDassert((sel_start[0] == 0) || (0 < small_rank_offset)); + HDassert((sel_start[1] == 0) || (1 < small_rank_offset)); + HDassert((sel_start[2] == 0) || (2 < small_rank_offset)); + HDassert((sel_start[3] == 0) || (3 < small_rank_offset)); + HDassert((sel_start[4] == 0) || (4 < small_rank_offset)); + + test_select_hyper_checker_board_dr__select_checker_board( + mem_large_cube_sid, large_rank, edge_size, checker_edge_size, small_rank, sel_start); + + /* verify that H5Sselect_shape_same() reports the two + * selections as having the same shape. + */ + check = H5Sselect_shape_same(file_small_cube_sid, mem_large_cube_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* zero out the in memory large cube */ + HDmemset(large_cube_buf_1, 0, sizeof(*large_cube_buf_1) * large_cube_size); + + /* Read selection from disk */ + ret = H5Dread(small_cube_dataset, H5T_NATIVE_UINT16, mem_large_cube_sid, + file_small_cube_sid, xfer_plist, large_cube_buf_1); + CHECK(ret, FAIL, "H5Dread"); + + /* verify that the expected data and only the + * expected data was read. + */ + data_ok = TRUE; + ptr_1 = large_cube_buf_1; + expected_value = 0; + start_index = (u * edge_size * edge_size * edge_size * edge_size) + + (v * edge_size * edge_size * edge_size) + (w * edge_size * edge_size) + + (x * edge_size); + stop_index = start_index + small_cube_size - 1; + + HDassert(start_index < stop_index); + HDassert(stop_index <= large_cube_size); + + /* verify that the large cube contains only zeros before the slice */ + for (s = 0; s < start_index; s++) { + if (*ptr_1 != 0) + data_ok = FALSE; + ptr_1++; + } /* end for */ + HDassert(s == start_index); + + data_ok &= test_select_hyper_checker_board_dr__verify_data( + ptr_1, small_rank, edge_size, checker_edge_size, (uint16_t)0, (hbool_t)TRUE); + + ptr_1 += small_cube_size; + s += small_cube_size; + + HDassert(s == stop_index + 1); + + /* verify that the large cube contains only zeros after the slice */ + for (s = stop_index + 1; s < large_cube_size; s++) { + if (*ptr_1 != 0) + data_ok = FALSE; + ptr_1++; + } /* end for */ + if (!data_ok) + TestErrPrintf("large cube read from small cube has bad data! Line=%d\n", __LINE__); + + x++; + } while ((large_rank >= (test_max_rank - 3)) && (small_rank <= (test_max_rank - 4)) && + (x < edge_size)); + w++; + } while ((large_rank >= (test_max_rank - 2)) && (small_rank <= (test_max_rank - 3)) && + (w < edge_size)); + v++; + } while ((large_rank >= (test_max_rank - 1)) && (small_rank <= (test_max_rank - 2)) && + (v < edge_size)); + u++; + } while ((large_rank >= test_max_rank) && (small_rank <= (test_max_rank - 1)) && (u < edge_size)); + + /* now we go in the opposite direction, verifying that we can write + * from memory to file using selections of different rank that + * H5Sselect_shape_same() views as being of the same shape. + * + * Start by writing small_rank D slices from the in memory large cube, to + * the the on disk small cube dataset. After each write, read the small + * cube dataset back from disk, and verify that it contains the expected + * data. Verify that H5Sselect_shape_same() returns true on the + * memory and file selections. + */ + + /* select a checker board in the file small cube dataspace */ + sel_start[0] = sel_start[1] = sel_start[2] = sel_start[3] = sel_start[4] = 0; + test_select_hyper_checker_board_dr__select_checker_board(file_small_cube_sid, small_rank, edge_size, + checker_edge_size, small_rank, sel_start); + + u = 0; + do { + if (small_rank_offset > 0) + sel_start[0] = u; + + v = 0; + do { + if (small_rank_offset > 1) + sel_start[1] = v; + + w = 0; + do { + if (small_rank_offset > 2) + sel_start[2] = w; + + x = 0; + do { + if (small_rank_offset > 3) + sel_start[3] = x; + + /* zero out the on disk small cube */ + ret = H5Dwrite(small_cube_dataset, H5T_NATIVE_UINT16, full_small_cube_sid, + full_small_cube_sid, xfer_plist, zero_buf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* we know that small_rank >= 1 and that large_rank > small_rank + * by the assertions at the head of this function. Thus no + * need for another inner loop. + */ + + HDassert((sel_start[0] == 0) || (0 < small_rank_offset)); + HDassert((sel_start[1] == 0) || (1 < small_rank_offset)); + HDassert((sel_start[2] == 0) || (2 < small_rank_offset)); + HDassert((sel_start[3] == 0) || (3 < small_rank_offset)); + HDassert((sel_start[4] == 0) || (4 < small_rank_offset)); + + test_select_hyper_checker_board_dr__select_checker_board( + mem_large_cube_sid, large_rank, edge_size, checker_edge_size, small_rank, sel_start); + + /* verify that H5Sselect_shape_same() reports the two + * selections as having the same shape. + */ + check = H5Sselect_shape_same(file_small_cube_sid, mem_large_cube_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* write the slice from the in memory large cube to the + * on disk small cube + */ + ret = H5Dwrite(small_cube_dataset, H5T_NATIVE_UINT16, mem_large_cube_sid, + file_small_cube_sid, xfer_plist, cube_buf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* zero the buffer that we will be using for reading */ + HDmemset(small_cube_buf_1, 0, sizeof(*small_cube_buf_1) * small_cube_size); + + /* read the on disk small cube into memory */ + ret = H5Dread(small_cube_dataset, H5T_NATIVE_UINT16, full_small_cube_sid, + full_small_cube_sid, xfer_plist, small_cube_buf_1); + CHECK(ret, FAIL, "H5Dread"); + + expected_value = (uint16_t)((u * edge_size * edge_size * edge_size * edge_size) + + (v * edge_size * edge_size * edge_size) + + (w * edge_size * edge_size) + (x * edge_size)); + + data_ok = test_select_hyper_checker_board_dr__verify_data(small_cube_buf_1, small_rank, + edge_size, checker_edge_size, + expected_value, (hbool_t)TRUE); + if (!data_ok) + TestErrPrintf("small cube read from largecube has bad data! Line=%d\n", __LINE__); + + x++; + } while ((large_rank >= (test_max_rank - 3)) && (small_rank <= (test_max_rank - 4)) && + (x < edge_size)); + w++; + } while ((large_rank >= (test_max_rank - 2)) && (small_rank <= (test_max_rank - 3)) && + (w < edge_size)); + v++; + } while ((large_rank >= (test_max_rank - 1)) && (small_rank <= (test_max_rank - 2)) && + (v < edge_size)); + u++; + } while ((large_rank >= test_max_rank) && (small_rank <= (test_max_rank - 1)) && (u < edge_size)); + + /* Now write checker board selections of the entries in memory + * small cube to slices of the on disk cube. After each write, + * read the on disk large cube * into memory, and verify that + * it contains the expected * data. Verify that + * H5Sselect_shape_same() returns true on the memory and file + * selections. + */ + + /* select a checker board in the in memory small cube dataspace */ + sel_start[0] = sel_start[1] = sel_start[2] = sel_start[3] = sel_start[4] = 0; + test_select_hyper_checker_board_dr__select_checker_board(mem_small_cube_sid, small_rank, edge_size, + checker_edge_size, small_rank, sel_start); + + u = 0; + do { + if (small_rank_offset > 0) + sel_start[0] = u; + + v = 0; + do { + if (small_rank_offset > 1) + sel_start[1] = v; + + w = 0; + do { + if (small_rank_offset > 2) + sel_start[2] = w; + + x = 0; + do { + if (small_rank_offset > 3) + sel_start[3] = x; + + /* zero out the on disk cube */ + ret = H5Dwrite(large_cube_dataset, H5T_NATIVE_USHORT, full_large_cube_sid, + full_large_cube_sid, xfer_plist, zero_buf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* we know that small_rank >= 1 and that large_rank > small_rank + * by the assertions at the head of this function. Thus no + * need for another inner loop. + */ + + HDassert((sel_start[0] == 0) || (0 < small_rank_offset)); + HDassert((sel_start[1] == 0) || (1 < small_rank_offset)); + HDassert((sel_start[2] == 0) || (2 < small_rank_offset)); + HDassert((sel_start[3] == 0) || (3 < small_rank_offset)); + HDassert((sel_start[4] == 0) || (4 < small_rank_offset)); + + test_select_hyper_checker_board_dr__select_checker_board( + file_large_cube_sid, large_rank, edge_size, checker_edge_size, small_rank, sel_start); + + /* verify that H5Sselect_shape_same() reports the two + * selections as having the same shape. + */ + check = H5Sselect_shape_same(file_large_cube_sid, mem_small_cube_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* write the checker board selection of the in memory + * small cube to a slice through the on disk large + * cube. + */ + ret = H5Dwrite(large_cube_dataset, H5T_NATIVE_UINT16, mem_small_cube_sid, + file_large_cube_sid, xfer_plist, cube_buf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* zero out the in memory large cube */ + HDmemset(large_cube_buf_1, 0, sizeof(*large_cube_buf_1) * large_cube_size); + + /* read the on disk large cube into memory */ + ret = H5Dread(large_cube_dataset, H5T_NATIVE_UINT16, full_large_cube_sid, + full_large_cube_sid, xfer_plist, large_cube_buf_1); + CHECK(ret, FAIL, "H5Dread"); + + /* verify that the expected data and only the + * expected data was written to the on disk large + * cube. + */ + data_ok = TRUE; + ptr_1 = large_cube_buf_1; + expected_value = 0; + start_index = (u * edge_size * edge_size * edge_size * edge_size) + + (v * edge_size * edge_size * edge_size) + (w * edge_size * edge_size) + + (x * edge_size); + stop_index = start_index + small_cube_size - 1; + + HDassert(start_index < stop_index); + HDassert(stop_index <= large_cube_size); + + /* verify that the large cube contains only zeros before the slice */ + for (s = 0; s < start_index; s++) { + if (*ptr_1 != 0) + data_ok = FALSE; + ptr_1++; + } /* end for */ + HDassert(s == start_index); + + /* verify that the slice contains the expected data */ + data_ok &= test_select_hyper_checker_board_dr__verify_data( + ptr_1, small_rank, edge_size, checker_edge_size, (uint16_t)0, (hbool_t)TRUE); + + ptr_1 += small_cube_size; + s += small_cube_size; + + HDassert(s == stop_index + 1); + + /* verify that the large cube contains only zeros after the slice */ + for (s = stop_index + 1; s < large_cube_size; s++) { + if (*ptr_1 != 0) + data_ok = FALSE; + ptr_1++; + } /* end for */ + if (!data_ok) + TestErrPrintf("large cube written from small cube has bad data! Line=%d\n", __LINE__); + + x++; + } while ((large_rank >= (test_max_rank - 3)) && (small_rank <= (test_max_rank - 4)) && + (x < edge_size)); + w++; + } while ((large_rank >= (test_max_rank - 2)) && (small_rank <= (test_max_rank - 3)) && + (w < edge_size)); + v++; + } while ((large_rank >= (test_max_rank - 1)) && (small_rank <= (test_max_rank - 2)) && + (v < edge_size)); + u++; + } while ((large_rank >= test_max_rank) && (small_rank <= (test_max_rank - 1)) && (u < edge_size)); + + /* Close memory dataspaces */ + ret = H5Sclose(full_small_cube_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(full_large_cube_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(mem_small_cube_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(mem_large_cube_sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(file_small_cube_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(file_large_cube_sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Datasets */ + ret = H5Dclose(small_cube_dataset); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Dclose(large_cube_dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free memory buffers */ + HDfree(small_cube_buf_1); + HDfree(large_cube_buf_1); + +} /* test_select_hyper_checker_board_dr__run_test() */ +#endif +/**************************************************************** +** +** test_select_hyper_checker_board_dr(): Test H5S (dataspace) +** selection code with checkerboard source and target having +** different ranks but the same shape. We have already +** tested H5Sselect_shape_same in isolation, so now we try to do +** I/O. +** +** This is just an initial smoke check, so we will work +** with a slice through a cube only. +** +****************************************************************/ +#if 0 +static void +test_select_hyper_checker_board_dr(hid_t dset_type, hid_t xfer_plist) +{ + uint16_t *cube_buf; /* Buffer for writing cube data */ + uint16_t *cube_ptr; /* Temporary pointer into cube data */ + uint16_t *zero_buf; /* Buffer for writing zeroed cube data */ + int test_num = 0; + unsigned checker_edge_size = 2; /* Size of checkerboard dimension */ + unsigned chunk_edge_size; /* Size of chunk's dataspace dimensions */ + unsigned edge_size = 6; /* Size of dataset's dataspace dimensions */ + unsigned small_rank; /* Current rank of small dataset */ + unsigned large_rank; /* Current rank of large dataset */ + unsigned max_rank = 5; /* Max. rank to use */ + size_t max_cube_size; /* Max. number of elements in largest cube */ + size_t s; /* Local index variable */ + unsigned u; /* Local index variable */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Checker Board Hyperslabs With Different Rank I/O Functionality\n")); + + /* Compute max. cube size */ + max_cube_size = (size_t)1; + for (u = 0; u < max_rank; u++) + max_cube_size *= (size_t)(edge_size + 1); + + /* Allocate cube buffer for writing values */ + cube_buf = (uint16_t *)HDmalloc(sizeof(uint16_t) * max_cube_size); + CHECK_PTR(cube_buf, "HDmalloc"); + + /* Initialize the cube buffer */ + cube_ptr = cube_buf; + for (s = 0; s < max_cube_size; s++) + *cube_ptr++ = (uint16_t)s; + + /* Allocate cube buffer for zeroing values on disk */ + zero_buf = (uint16_t *)HDcalloc(sizeof(uint16_t), max_cube_size); + CHECK_PTR(zero_buf, "HDcalloc"); + + for (large_rank = 1; large_rank <= max_rank; large_rank++) { + for (small_rank = 1; small_rank < large_rank; small_rank++) { + chunk_edge_size = 0; + test_select_hyper_checker_board_dr__run_test(test_num, cube_buf, zero_buf, edge_size, + checker_edge_size, chunk_edge_size, small_rank, + large_rank, dset_type, xfer_plist); + test_num++; + + test_select_hyper_checker_board_dr__run_test(test_num, cube_buf, zero_buf, edge_size + 1, + checker_edge_size, chunk_edge_size, small_rank, + large_rank, dset_type, xfer_plist); + test_num++; + + chunk_edge_size = 3; + test_select_hyper_checker_board_dr__run_test(test_num, cube_buf, zero_buf, edge_size, + checker_edge_size, chunk_edge_size, small_rank, + large_rank, dset_type, xfer_plist); + test_num++; + + test_select_hyper_checker_board_dr__run_test(test_num, cube_buf, zero_buf, edge_size + 1, + checker_edge_size, chunk_edge_size, small_rank, + large_rank, dset_type, xfer_plist); + test_num++; + } /* for loop on small rank */ + } /* for loop on large rank */ + + HDfree(cube_buf); + HDfree(zero_buf); + +} /* test_select_hyper_checker_board_dr() */ +#endif +/**************************************************************** +** +** test_select_hyper_copy(): Test H5S (dataspace) selection code. +** Tests copying hyperslab selections +** +****************************************************************/ +static void +test_select_hyper_copy(void) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t data1, data2; /* Dataset IDs */ + hid_t sid1, sid2, sid3; /* Dataspace IDs */ + hsize_t dims1[] = {SPACE1_DIM1, SPACE1_DIM2, SPACE1_DIM3}; + hsize_t dims2[] = {SPACE2_DIM1, SPACE2_DIM2}; + hsize_t dims3[] = {SPACE3_DIM1, SPACE3_DIM2}; + hsize_t start[SPACE1_RANK]; /* Starting location of hyperslab */ + hsize_t stride[SPACE1_RANK]; /* Stride of hyperslab */ + hsize_t count[SPACE1_RANK]; /* Element count of hyperslab */ + hsize_t block[SPACE1_RANK]; /* Block size of hyperslab */ + uint16_t *wbuf, /* buffer to write to disk */ + *rbuf, /* 1st buffer read from disk */ + *rbuf2, /* 2nd buffer read from disk */ + *tbuf; /* temporary buffer pointer */ + int i, j; /* Counters */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Hyperslabs with Strides Functionality\n")); + + /* Allocate write & read buffers */ + wbuf = (uint16_t *)HDmalloc(sizeof(uint16_t) * SPACE2_DIM1 * SPACE2_DIM2); + CHECK_PTR(wbuf, "HDmalloc"); + rbuf = (uint16_t *)HDcalloc(sizeof(uint16_t), (size_t)(SPACE3_DIM1 * SPACE3_DIM2)); + CHECK_PTR(rbuf, "HDcalloc"); + rbuf2 = (uint16_t *)HDcalloc(sizeof(uint16_t), (size_t)(SPACE3_DIM1 * SPACE3_DIM2)); + CHECK_PTR(rbuf2, "HDcalloc"); + + /* Initialize write buffer */ + for (i = 0, tbuf = wbuf; i < SPACE2_DIM1; i++) + for (j = 0; j < SPACE2_DIM2; j++) + *tbuf++ = (uint16_t)((i * SPACE2_DIM2) + j); + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create dataspace for writing buffer */ + sid2 = H5Screate_simple(SPACE2_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select 2x3x3 count with a stride of 2x4x3 & 1x2x2 block hyperslab for disk dataset */ + start[0] = 0; + start[1] = 0; + start[2] = 0; + stride[0] = 2; + stride[1] = 4; + stride[2] = 3; + count[0] = 2; + count[1] = 3; + count[2] = 3; + block[0] = 1; + block[1] = 2; + block[2] = 2; + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Select 4x2 count with a stride of 5x5 & 3x3 block hyperslab for memory dataset */ + start[0] = 1; + start[1] = 1; + stride[0] = 5; + stride[1] = 5; + count[0] = 4; + count[1] = 2; + block[0] = 3; + block[1] = 3; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Make a copy of the dataspace to write */ + sid3 = H5Scopy(sid2); + CHECK(sid3, FAIL, "H5Scopy"); + + /* Create a dataset */ + data1 = H5Dcreate2(fid1, SPACE1_NAME, H5T_STD_U16LE, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(data1, FAIL, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(data1, H5T_STD_U16LE, sid2, sid1, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Create another dataset */ + data2 = H5Dcreate2(fid1, SPACE2_NAME, H5T_STD_U16LE, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(data2, FAIL, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(data2, H5T_STD_U16LE, sid3, sid1, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close memory dataspace */ + ret = H5Sclose(sid3); + CHECK(ret, FAIL, "H5Sclose"); + + /* Create dataspace for reading buffer */ + sid2 = H5Screate_simple(SPACE3_RANK, dims3, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select 3x4 count with a stride of 4x4 & 2x3 block hyperslab for memory dataset */ + start[0] = 0; + start[1] = 0; + stride[0] = 4; + stride[1] = 4; + count[0] = 3; + count[1] = 4; + block[0] = 2; + block[1] = 3; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Make a copy of the dataspace to read */ + sid3 = H5Scopy(sid2); + CHECK(sid3, FAIL, "H5Scopy"); + + /* Read selection from disk */ + ret = H5Dread(data1, H5T_STD_U16LE, sid2, sid1, H5P_DEFAULT, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Read selection from disk */ + ret = H5Dread(data2, H5T_STD_U16LE, sid3, sid1, H5P_DEFAULT, rbuf2); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read with data written out */ + if (HDmemcmp(rbuf, rbuf2, sizeof(uint16_t) * SPACE3_DIM1 * SPACE3_DIM2) != 0) + TestErrPrintf("hyperslab values don't match! Line=%d\n", __LINE__); + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close 2nd memory dataspace */ + ret = H5Sclose(sid3); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(data1); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close Dataset */ + ret = H5Dclose(data2); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free memory buffers */ + HDfree(wbuf); + HDfree(rbuf); + HDfree(rbuf2); +} /* test_select_hyper_copy() */ + +/**************************************************************** +** +** test_select_point_copy(): Test H5S (dataspace) selection code. +** Tests copying point selections +** +****************************************************************/ +static void +test_select_point_copy(void) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t data1, data2; /* Dataset IDs */ + hid_t sid1, sid2, sid3; /* Dataspace IDs */ + hsize_t dims1[] = {SPACE1_DIM1, SPACE1_DIM2, SPACE1_DIM3}; + hsize_t dims2[] = {SPACE2_DIM1, SPACE2_DIM2}; + hsize_t dims3[] = {SPACE3_DIM1, SPACE3_DIM2}; + hsize_t coord1[POINT1_NPOINTS][SPACE1_RANK]; /* Coordinates for point selection */ + hsize_t coord2[POINT1_NPOINTS][SPACE2_RANK]; /* Coordinates for point selection */ + hsize_t coord3[POINT1_NPOINTS][SPACE3_RANK]; /* Coordinates for point selection */ + uint16_t *wbuf, /* buffer to write to disk */ + *rbuf, /* 1st buffer read from disk */ + *rbuf2, /* 2nd buffer read from disk */ + *tbuf; /* temporary buffer pointer */ + int i, j; /* Counters */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Hyperslabs with Strides Functionality\n")); + + /* Allocate write & read buffers */ + wbuf = (uint16_t *)HDmalloc(sizeof(uint16_t) * SPACE2_DIM1 * SPACE2_DIM2); + CHECK_PTR(wbuf, "HDmalloc"); + rbuf = (uint16_t *)HDcalloc(sizeof(uint16_t), (size_t)(SPACE3_DIM1 * SPACE3_DIM2)); + CHECK_PTR(rbuf, "HDcalloc"); + rbuf2 = (uint16_t *)HDcalloc(sizeof(uint16_t), (size_t)(SPACE3_DIM1 * SPACE3_DIM2)); + CHECK_PTR(rbuf2, "HDcalloc"); + + /* Initialize write buffer */ + for (i = 0, tbuf = wbuf; i < SPACE2_DIM1; i++) + for (j = 0; j < SPACE2_DIM2; j++) + *tbuf++ = (uint16_t)((i * SPACE2_DIM2) + j); + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create dataspace for writing buffer */ + sid2 = H5Screate_simple(SPACE2_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select sequence of ten points for disk dataset */ + coord1[0][0] = 0; + coord1[0][1] = 10; + coord1[0][2] = 5; + coord1[1][0] = 1; + coord1[1][1] = 2; + coord1[1][2] = 7; + coord1[2][0] = 2; + coord1[2][1] = 4; + coord1[2][2] = 9; + coord1[3][0] = 0; + coord1[3][1] = 6; + coord1[3][2] = 11; + coord1[4][0] = 1; + coord1[4][1] = 8; + coord1[4][2] = 13; + coord1[5][0] = 2; + coord1[5][1] = 12; + coord1[5][2] = 0; + coord1[6][0] = 0; + coord1[6][1] = 14; + coord1[6][2] = 2; + coord1[7][0] = 1; + coord1[7][1] = 0; + coord1[7][2] = 4; + coord1[8][0] = 2; + coord1[8][1] = 1; + coord1[8][2] = 6; + coord1[9][0] = 0; + coord1[9][1] = 3; + coord1[9][2] = 8; + ret = H5Sselect_elements(sid1, H5S_SELECT_SET, (size_t)POINT1_NPOINTS, (const hsize_t *)coord1); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Select sequence of ten points for write dataset */ + coord2[0][0] = 12; + coord2[0][1] = 3; + coord2[1][0] = 15; + coord2[1][1] = 13; + coord2[2][0] = 7; + coord2[2][1] = 25; + coord2[3][0] = 0; + coord2[3][1] = 6; + coord2[4][0] = 13; + coord2[4][1] = 0; + coord2[5][0] = 24; + coord2[5][1] = 11; + coord2[6][0] = 12; + coord2[6][1] = 21; + coord2[7][0] = 29; + coord2[7][1] = 4; + coord2[8][0] = 8; + coord2[8][1] = 8; + coord2[9][0] = 19; + coord2[9][1] = 17; + ret = H5Sselect_elements(sid2, H5S_SELECT_SET, (size_t)POINT1_NPOINTS, (const hsize_t *)coord2); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Make a copy of the dataspace to write */ + sid3 = H5Scopy(sid2); + CHECK(sid3, FAIL, "H5Scopy"); + + /* Create a dataset */ + data1 = H5Dcreate2(fid1, SPACE1_NAME, H5T_STD_U16LE, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(data1, FAIL, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(data1, H5T_STD_U16LE, sid2, sid1, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Create another dataset */ + data2 = H5Dcreate2(fid1, SPACE2_NAME, H5T_STD_U16LE, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(data2, FAIL, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(data2, H5T_STD_U16LE, sid3, sid1, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close memory dataspace */ + ret = H5Sclose(sid3); + CHECK(ret, FAIL, "H5Sclose"); + + /* Create dataspace for reading buffer */ + sid2 = H5Screate_simple(SPACE3_RANK, dims3, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select sequence of points for read dataset */ + coord3[0][0] = 0; + coord3[0][1] = 2; + coord3[1][0] = 4; + coord3[1][1] = 8; + coord3[2][0] = 13; + coord3[2][1] = 13; + coord3[3][0] = 14; + coord3[3][1] = 25; + coord3[4][0] = 7; + coord3[4][1] = 9; + coord3[5][0] = 2; + coord3[5][1] = 0; + coord3[6][0] = 9; + coord3[6][1] = 19; + coord3[7][0] = 1; + coord3[7][1] = 22; + coord3[8][0] = 12; + coord3[8][1] = 21; + coord3[9][0] = 11; + coord3[9][1] = 6; + ret = H5Sselect_elements(sid2, H5S_SELECT_SET, (size_t)POINT1_NPOINTS, (const hsize_t *)coord3); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Make a copy of the dataspace to read */ + sid3 = H5Scopy(sid2); + CHECK(sid3, FAIL, "H5Scopy"); + + /* Read selection from disk */ + ret = H5Dread(data1, H5T_STD_U16LE, sid2, sid1, H5P_DEFAULT, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Read selection from disk */ + ret = H5Dread(data2, H5T_STD_U16LE, sid3, sid1, H5P_DEFAULT, rbuf2); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read with data written out */ + if (HDmemcmp(rbuf, rbuf2, sizeof(uint16_t) * SPACE3_DIM1 * SPACE3_DIM2) != 0) + TestErrPrintf("point values don't match!\n"); + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close 2nd memory dataspace */ + ret = H5Sclose(sid3); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(data1); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close Dataset */ + ret = H5Dclose(data2); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free memory buffers */ + HDfree(wbuf); + HDfree(rbuf); + HDfree(rbuf2); +} /* test_select_point_copy() */ + +/**************************************************************** +** +** test_select_hyper_offset(): Test basic H5S (dataspace) selection code. +** Tests hyperslabs of various sizes and dimensionalities with selection +** offsets. +** +****************************************************************/ +static void +test_select_hyper_offset(void) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1, sid2; /* Dataspace ID */ + hsize_t dims1[] = {SPACE1_DIM1, SPACE1_DIM2, SPACE1_DIM3}; + hsize_t dims2[] = {SPACE2_DIM1, SPACE2_DIM2}; + hsize_t dims3[] = {SPACE3_DIM1, SPACE3_DIM2}; + hsize_t start[SPACE1_RANK]; /* Starting location of hyperslab */ + hsize_t stride[SPACE1_RANK]; /* Stride of hyperslab */ + hsize_t count[SPACE1_RANK]; /* Element count of hyperslab */ + hsize_t block[SPACE1_RANK]; /* Block size of hyperslab */ + hssize_t offset[SPACE1_RANK]; /* Offset of selection */ + uint8_t *wbuf, /* buffer to write to disk */ + *rbuf, /* buffer read from disk */ + *tbuf, /* temporary buffer pointer */ + *tbuf2; /* temporary buffer pointer */ + int i, j; /* Counters */ + herr_t ret; /* Generic return value */ + htri_t valid; /* Generic boolean return value */ + H5S_class_t ext_type; /* Extent type */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Hyperslab Selection Functions with Offsets\n")); + + /* Allocate write & read buffers */ + wbuf = (uint8_t *)HDmalloc(sizeof(uint8_t) * SPACE2_DIM1 * SPACE2_DIM2); + CHECK_PTR(wbuf, "HDmalloc"); + rbuf = (uint8_t *)HDcalloc(sizeof(uint8_t), (size_t)(SPACE3_DIM1 * SPACE3_DIM2)); + CHECK_PTR(rbuf, "HDcalloc"); + + /* Initialize write buffer */ + for (i = 0, tbuf = wbuf; i < SPACE2_DIM1; i++) + for (j = 0; j < SPACE2_DIM2; j++) + *tbuf++ = (uint8_t)((i * SPACE2_DIM2) + j); + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create dataspace for writing buffer */ + sid2 = H5Screate_simple(SPACE2_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Verify extent type */ + ext_type = H5Sget_simple_extent_type(sid1); + VERIFY(ext_type, H5S_SIMPLE, "H5Sget_simple_extent_type"); + + /* Select 2x15x13 hyperslab for disk dataset */ + start[0] = 1; + start[1] = 0; + start[2] = 0; + stride[0] = 1; + stride[1] = 1; + stride[2] = 1; + count[0] = 2; + count[1] = 15; + count[2] = 13; + block[0] = 1; + block[1] = 1; + block[2] = 1; + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Check a valid offset */ + offset[0] = -1; + offset[1] = 0; + offset[2] = 0; + ret = H5Soffset_simple(sid1, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + valid = H5Sselect_valid(sid1); + VERIFY(valid, TRUE, "H5Sselect_valid"); + + /* Check an invalid offset */ + offset[0] = 10; + offset[1] = 0; + offset[2] = 0; + ret = H5Soffset_simple(sid1, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + valid = H5Sselect_valid(sid1); + VERIFY(valid, FALSE, "H5Sselect_valid"); + + /* Reset offset */ + offset[0] = 0; + offset[1] = 0; + offset[2] = 0; + ret = H5Soffset_simple(sid1, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + valid = H5Sselect_valid(sid1); + VERIFY(valid, TRUE, "H5Sselect_valid"); + + /* Select 15x26 hyperslab for memory dataset */ + start[0] = 15; + start[1] = 0; + stride[0] = 1; + stride[1] = 1; + count[0] = 15; + count[1] = 26; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Choose a valid offset for the memory dataspace */ + offset[0] = -10; + offset[1] = 0; + ret = H5Soffset_simple(sid2, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + valid = H5Sselect_valid(sid2); + VERIFY(valid, TRUE, "H5Sselect_valid"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, SPACE1_NAME, H5T_NATIVE_UCHAR, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Create dataspace for reading buffer */ + sid2 = H5Screate_simple(SPACE3_RANK, dims3, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select 15x26 hyperslab for reading memory dataset */ + start[0] = 0; + start[1] = 0; + stride[0] = 1; + stride[1] = 1; + count[0] = 15; + count[1] = 26; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Read selection from disk */ + ret = H5Dread(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read with data written out */ + for (i = 0; i < SPACE3_DIM1; i++) { + tbuf = wbuf + ((i + 5) * SPACE2_DIM2); + tbuf2 = rbuf + (i * SPACE3_DIM2); + for (j = 0; j < SPACE3_DIM2; j++, tbuf++, tbuf2++) { + if (*tbuf != *tbuf2) + TestErrPrintf("%d: hyperslab values don't match!, i=%d, j=%d, *tbuf=%u, *tbuf2=%u\n", + __LINE__, i, j, (unsigned)*tbuf, (unsigned)*tbuf2); + } /* end for */ + } /* end for */ + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free memory buffers */ + HDfree(wbuf); + HDfree(rbuf); +} /* test_select_hyper_offset() */ + +/**************************************************************** +** +** test_select_hyper_offset2(): Test basic H5S (dataspace) selection code. +** Tests optimized hyperslab I/O with selection offsets. +** +****************************************************************/ +static void +test_select_hyper_offset2(void) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1, sid2; /* Dataspace ID */ + hsize_t dims1[] = {SPACE7_DIM1, SPACE7_DIM2}; + hsize_t dims2[] = {SPACE7_DIM1, SPACE7_DIM2}; + hsize_t start[SPACE7_RANK]; /* Starting location of hyperslab */ + hsize_t count[SPACE7_RANK]; /* Element count of hyperslab */ + hssize_t offset[SPACE7_RANK]; /* Offset of selection */ + uint8_t *wbuf, /* buffer to write to disk */ + *rbuf, /* buffer read from disk */ + *tbuf, /* temporary buffer pointer */ + *tbuf2; /* temporary buffer pointer */ + int i, j; /* Counters */ + herr_t ret; /* Generic return value */ + htri_t valid; /* Generic boolean return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing More Hyperslab Selection Functions with Offsets\n")); + + /* Allocate write & read buffers */ + wbuf = (uint8_t *)HDmalloc(sizeof(uint8_t) * SPACE7_DIM1 * SPACE7_DIM2); + CHECK_PTR(wbuf, "HDmalloc"); + rbuf = (uint8_t *)HDcalloc(sizeof(uint8_t), (size_t)(SPACE7_DIM1 * SPACE7_DIM2)); + CHECK_PTR(rbuf, "HDcalloc"); + + /* Initialize write buffer */ + for (i = 0, tbuf = wbuf; i < SPACE7_DIM1; i++) + for (j = 0; j < SPACE7_DIM2; j++) + *tbuf++ = (uint8_t)((i * SPACE7_DIM2) + j); + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset */ + sid1 = H5Screate_simple(SPACE7_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create dataspace for writing buffer */ + sid2 = H5Screate_simple(SPACE7_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select 4x10 hyperslab for disk dataset */ + start[0] = 1; + start[1] = 0; + count[0] = 4; + count[1] = 10; + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Set offset */ + offset[0] = 1; + offset[1] = 0; + ret = H5Soffset_simple(sid1, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + valid = H5Sselect_valid(sid1); + VERIFY(valid, TRUE, "H5Sselect_valid"); + + /* Select 4x10 hyperslab for memory dataset */ + start[0] = 1; + start[1] = 0; + count[0] = 4; + count[1] = 10; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Choose a valid offset for the memory dataspace */ + offset[0] = 2; + offset[1] = 0; + ret = H5Soffset_simple(sid2, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + valid = H5Sselect_valid(sid2); + VERIFY(valid, TRUE, "H5Sselect_valid"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, SPACE7_NAME, H5T_NATIVE_UCHAR, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Read selection from disk */ + ret = H5Dread(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read with data written out */ + for (i = 0; i < 4; i++) { + tbuf = wbuf + ((i + 3) * SPACE7_DIM2); + tbuf2 = rbuf + ((i + 3) * SPACE7_DIM2); + for (j = 0; j < SPACE7_DIM2; j++, tbuf++, tbuf2++) { + if (*tbuf != *tbuf2) + TestErrPrintf("%d: hyperslab values don't match!, i=%d, j=%d, *tbuf=%u, *tbuf2=%u\n", + __LINE__, i, j, (unsigned)*tbuf, (unsigned)*tbuf2); + } /* end for */ + } /* end for */ + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free memory buffers */ + HDfree(wbuf); + HDfree(rbuf); +} /* test_select_hyper_offset2() */ + +/**************************************************************** +** +** test_select_point_offset(): Test basic H5S (dataspace) selection code. +** Tests element selections between dataspaces of various sizes +** and dimensionalities with selection offsets. +** +****************************************************************/ +static void +test_select_point_offset(void) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1, sid2; /* Dataspace ID */ + hsize_t dims1[] = {SPACE1_DIM1, SPACE1_DIM2, SPACE1_DIM3}; + hsize_t dims2[] = {SPACE2_DIM1, SPACE2_DIM2}; + hsize_t dims3[] = {SPACE3_DIM1, SPACE3_DIM2}; + hsize_t coord1[POINT1_NPOINTS][SPACE1_RANK]; /* Coordinates for point selection */ + hsize_t coord2[POINT1_NPOINTS][SPACE2_RANK]; /* Coordinates for point selection */ + hsize_t coord3[POINT1_NPOINTS][SPACE3_RANK]; /* Coordinates for point selection */ + hssize_t offset[SPACE1_RANK]; /* Offset of selection */ + uint8_t *wbuf, /* buffer to write to disk */ + *rbuf, /* buffer read from disk */ + *tbuf, /* temporary buffer pointer */ + *tbuf2; /* temporary buffer pointer */ + int i, j; /* Counters */ + herr_t ret; /* Generic return value */ + htri_t valid; /* Generic boolean return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Element Selection Functions\n")); + + /* Allocate write & read buffers */ + wbuf = (uint8_t *)HDmalloc(sizeof(uint8_t) * SPACE2_DIM1 * SPACE2_DIM2); + CHECK_PTR(wbuf, "HDmalloc"); + rbuf = (uint8_t *)HDcalloc(sizeof(uint8_t), (size_t)(SPACE3_DIM1 * SPACE3_DIM2)); + CHECK_PTR(rbuf, "HDcalloc"); + + /* Initialize write buffer */ + for (i = 0, tbuf = wbuf; i < SPACE2_DIM1; i++) + for (j = 0; j < SPACE2_DIM2; j++) + *tbuf++ = (uint8_t)((i * SPACE2_DIM2) + j); + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create dataspace for write buffer */ + sid2 = H5Screate_simple(SPACE2_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select sequence of ten points for disk dataset */ + coord1[0][0] = 0; + coord1[0][1] = 10; + coord1[0][2] = 5; + coord1[1][0] = 1; + coord1[1][1] = 2; + coord1[1][2] = 7; + coord1[2][0] = 2; + coord1[2][1] = 4; + coord1[2][2] = 9; + coord1[3][0] = 0; + coord1[3][1] = 6; + coord1[3][2] = 11; + coord1[4][0] = 1; + coord1[4][1] = 8; + coord1[4][2] = 12; + coord1[5][0] = 2; + coord1[5][1] = 12; + coord1[5][2] = 0; + coord1[6][0] = 0; + coord1[6][1] = 14; + coord1[6][2] = 2; + coord1[7][0] = 1; + coord1[7][1] = 0; + coord1[7][2] = 4; + coord1[8][0] = 2; + coord1[8][1] = 1; + coord1[8][2] = 6; + coord1[9][0] = 0; + coord1[9][1] = 3; + coord1[9][2] = 8; + ret = H5Sselect_elements(sid1, H5S_SELECT_SET, (size_t)POINT1_NPOINTS, (const hsize_t *)coord1); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Check a valid offset */ + offset[0] = 0; + offset[1] = 0; + offset[2] = 1; + ret = H5Soffset_simple(sid1, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + valid = H5Sselect_valid(sid1); + VERIFY(valid, TRUE, "H5Sselect_valid"); + + /* Check an invalid offset */ + offset[0] = 10; + offset[1] = 0; + offset[2] = 0; + ret = H5Soffset_simple(sid1, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + valid = H5Sselect_valid(sid1); + VERIFY(valid, FALSE, "H5Sselect_valid"); + + /* Reset offset */ + offset[0] = 0; + offset[1] = 0; + offset[2] = 0; + ret = H5Soffset_simple(sid1, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + valid = H5Sselect_valid(sid1); + VERIFY(valid, TRUE, "H5Sselect_valid"); + + /* Select sequence of ten points for write dataset */ + coord2[0][0] = 12; + coord2[0][1] = 3; + coord2[1][0] = 15; + coord2[1][1] = 13; + coord2[2][0] = 7; + coord2[2][1] = 24; + coord2[3][0] = 0; + coord2[3][1] = 6; + coord2[4][0] = 13; + coord2[4][1] = 0; + coord2[5][0] = 24; + coord2[5][1] = 11; + coord2[6][0] = 12; + coord2[6][1] = 21; + coord2[7][0] = 23; + coord2[7][1] = 4; + coord2[8][0] = 8; + coord2[8][1] = 8; + coord2[9][0] = 19; + coord2[9][1] = 17; + ret = H5Sselect_elements(sid2, H5S_SELECT_SET, (size_t)POINT1_NPOINTS, (const hsize_t *)coord2); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Choose a valid offset for the memory dataspace */ + offset[0] = 5; + offset[1] = 1; + ret = H5Soffset_simple(sid2, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + valid = H5Sselect_valid(sid2); + VERIFY(valid, TRUE, "H5Sselect_valid"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, SPACE1_NAME, H5T_NATIVE_UCHAR, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Create dataspace for reading buffer */ + sid2 = H5Screate_simple(SPACE3_RANK, dims3, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select sequence of points for read dataset */ + coord3[0][0] = 0; + coord3[0][1] = 2; + coord3[1][0] = 4; + coord3[1][1] = 8; + coord3[2][0] = 13; + coord3[2][1] = 13; + coord3[3][0] = 14; + coord3[3][1] = 25; + coord3[4][0] = 7; + coord3[4][1] = 9; + coord3[5][0] = 2; + coord3[5][1] = 0; + coord3[6][0] = 9; + coord3[6][1] = 19; + coord3[7][0] = 1; + coord3[7][1] = 22; + coord3[8][0] = 12; + coord3[8][1] = 21; + coord3[9][0] = 11; + coord3[9][1] = 6; + ret = H5Sselect_elements(sid2, H5S_SELECT_SET, (size_t)POINT1_NPOINTS, (const hsize_t *)coord3); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Read selection from disk */ + ret = H5Dread(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read with data written out */ + for (i = 0; i < POINT1_NPOINTS; i++) { + tbuf = wbuf + ((coord2[i][0] + (hsize_t)offset[0]) * SPACE2_DIM2) + coord2[i][1] + (hsize_t)offset[1]; + tbuf2 = rbuf + (coord3[i][0] * SPACE3_DIM2) + coord3[i][1]; + if (*tbuf != *tbuf2) + TestErrPrintf("element values don't match!, i=%d\n", i); + } /* end for */ + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free memory buffers */ + HDfree(wbuf); + HDfree(rbuf); +} /* test_select_point_offset() */ + +/**************************************************************** +** +** test_select_hyper_union(): Test basic H5S (dataspace) selection code. +** Tests unions of hyperslabs of various sizes and dimensionalities. +** +****************************************************************/ +static void +test_select_hyper_union(void) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1, sid2; /* Dataspace ID */ + hid_t xfer; /* Dataset Transfer Property List ID */ + hsize_t dims1[] = {SPACE1_DIM1, SPACE1_DIM2, SPACE1_DIM3}; + hsize_t dims2[] = {SPACE2_DIM1, SPACE2_DIM2}; + hsize_t dims3[] = {SPACE3_DIM1, SPACE3_DIM2}; + hsize_t start[SPACE1_RANK]; /* Starting location of hyperslab */ + hsize_t stride[SPACE1_RANK]; /* Stride of hyperslab */ + hsize_t count[SPACE1_RANK]; /* Element count of hyperslab */ + hsize_t block[SPACE1_RANK]; /* Block size of hyperslab */ + size_t begin[SPACE2_DIM1] = /* Offset within irregular block */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* First ten rows start at offset 0 */ + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}; /* Next eighteen rows start at offset 5 */ + size_t len[SPACE2_DIM1] = /* Len of each row within irregular block */ + {10, 10, 10, 10, 10, 10, 10, 10, /* First eight rows are 10 long */ + 20, 20, /* Next two rows are 20 long */ + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15}; /* Next eighteen rows are 15 long */ + uint8_t *wbuf, /* buffer to write to disk */ + *rbuf, /* buffer read from disk */ + *tbuf, /* temporary buffer pointer */ + *tbuf2; /* temporary buffer pointer */ + int i, j; /* Counters */ + herr_t ret; /* Generic return value */ + hssize_t npoints; /* Number of elements in selection */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Hyperslab Selection Functions with unions of hyperslabs\n")); + + /* Allocate write & read buffers */ + wbuf = (uint8_t *)HDmalloc(sizeof(uint8_t) * SPACE2_DIM1 * SPACE2_DIM2); + CHECK_PTR(wbuf, "HDmalloc"); + rbuf = (uint8_t *)HDcalloc(sizeof(uint8_t), (size_t)(SPACE3_DIM1 * SPACE3_DIM2)); + CHECK_PTR(rbuf, "HDcalloc"); + + /* Initialize write buffer */ + for (i = 0, tbuf = wbuf; i < SPACE2_DIM1; i++) + for (j = 0; j < SPACE2_DIM2; j++) + *tbuf++ = (uint8_t)((i * SPACE2_DIM2) + j); + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Test simple case of one block overlapping another */ + /* Create dataspace for dataset */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create dataspace for writing buffer */ + sid2 = H5Screate_simple(SPACE2_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select 2x15x13 hyperslab for disk dataset */ + start[0] = 1; + start[1] = 0; + start[2] = 0; + stride[0] = 1; + stride[1] = 1; + stride[2] = 1; + count[0] = 2; + count[1] = 15; + count[2] = 13; + block[0] = 1; + block[1] = 1; + block[2] = 1; + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + npoints = H5Sget_select_npoints(sid1); + VERIFY(npoints, 2 * 15 * 13, "H5Sget_select_npoints"); + + /* Select 8x26 hyperslab for memory dataset */ + start[0] = 15; + start[1] = 0; + stride[0] = 1; + stride[1] = 1; + count[0] = 8; + count[1] = 26; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Union overlapping 8x26 hyperslab for memory dataset (to form a 15x26 selection) */ + start[0] = 22; + start[1] = 0; + stride[0] = 1; + stride[1] = 1; + count[0] = 8; + count[1] = 26; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + npoints = H5Sget_select_npoints(sid2); + VERIFY(npoints, 15 * 26, "H5Sget_select_npoints"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, SPACE1_NAME, H5T_NATIVE_UCHAR, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Create dataspace for reading buffer */ + sid2 = H5Screate_simple(SPACE3_RANK, dims3, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select 15x26 hyperslab for reading memory dataset */ + start[0] = 0; + start[1] = 0; + stride[0] = 1; + stride[1] = 1; + count[0] = 15; + count[1] = 26; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Read selection from disk */ + ret = H5Dread(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read with data written out */ + for (i = 0; i < SPACE3_DIM1; i++) { + tbuf = wbuf + ((i + 15) * SPACE2_DIM2); + tbuf2 = rbuf + (i * SPACE3_DIM2); + for (j = 0; j < SPACE3_DIM2; j++, tbuf++, tbuf2++) { + if (*tbuf != *tbuf2) + TestErrPrintf("%d: hyperslab values don't match!, i=%d, j=%d, *tbuf=%d, *tbuf2=%d\n", + __LINE__, i, j, (int)*tbuf, (int)*tbuf2); + } /* end for */ + } /* end for */ + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Test simple case of several block overlapping another */ + /* Create dataspace for dataset */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create dataspace for writing buffer */ + sid2 = H5Screate_simple(SPACE2_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select 2x15x13 hyperslab for disk dataset */ + start[0] = 1; + start[1] = 0; + start[2] = 0; + stride[0] = 1; + stride[1] = 1; + stride[2] = 1; + count[0] = 2; + count[1] = 15; + count[2] = 13; + block[0] = 1; + block[1] = 1; + block[2] = 1; + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Select 8x15 hyperslab for memory dataset */ + start[0] = 15; + start[1] = 0; + stride[0] = 1; + stride[1] = 1; + count[0] = 8; + count[1] = 15; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Union overlapping 8x15 hyperslab for memory dataset (to form a 15x15 selection) */ + start[0] = 22; + start[1] = 0; + stride[0] = 1; + stride[1] = 1; + count[0] = 8; + count[1] = 15; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Union overlapping 15x15 hyperslab for memory dataset (to form a 15x26 selection) */ + start[0] = 15; + start[1] = 11; + stride[0] = 1; + stride[1] = 1; + count[0] = 15; + count[1] = 15; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + npoints = H5Sget_select_npoints(sid2); + VERIFY(npoints, 15 * 26, "H5Sget_select_npoints"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, SPACE2_NAME, H5T_NATIVE_UCHAR, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Create dataspace for reading buffer */ + sid2 = H5Screate_simple(SPACE3_RANK, dims3, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select 15x26 hyperslab for reading memory dataset */ + start[0] = 0; + start[1] = 0; + stride[0] = 1; + stride[1] = 1; + count[0] = 15; + count[1] = 26; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Read selection from disk */ + ret = H5Dread(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read with data written out */ + for (i = 0; i < SPACE3_DIM1; i++) { + tbuf = wbuf + ((i + 15) * SPACE2_DIM2); + tbuf2 = rbuf + (i * SPACE3_DIM2); + for (j = 0; j < SPACE3_DIM2; j++, tbuf++, tbuf2++) { + if (*tbuf != *tbuf2) + TestErrPrintf("%d: hyperslab values don't match!, i=%d, j=%d, *tbuf=%d, *tbuf2=%d\n", + __LINE__, i, j, (int)*tbuf, (int)*tbuf2); + } /* end for */ + } /* end for */ + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Test disjoint case of two non-overlapping blocks */ + /* Create dataspace for dataset */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create dataspace for writing buffer */ + sid2 = H5Screate_simple(SPACE2_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select 2x15x13 hyperslab for disk dataset */ + start[0] = 1; + start[1] = 0; + start[2] = 0; + stride[0] = 1; + stride[1] = 1; + stride[2] = 1; + count[0] = 2; + count[1] = 15; + count[2] = 13; + block[0] = 1; + block[1] = 1; + block[2] = 1; + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Select 7x26 hyperslab for memory dataset */ + start[0] = 1; + start[1] = 0; + stride[0] = 1; + stride[1] = 1; + count[0] = 7; + count[1] = 26; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Union non-overlapping 8x26 hyperslab for memory dataset (to form a 15x26 disjoint selection) */ + start[0] = 22; + start[1] = 0; + stride[0] = 1; + stride[1] = 1; + count[0] = 8; + count[1] = 26; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + npoints = H5Sget_select_npoints(sid2); + VERIFY(npoints, 15 * 26, "H5Sget_select_npoints"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, SPACE3_NAME, H5T_NATIVE_UCHAR, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Create dataspace for reading buffer */ + sid2 = H5Screate_simple(SPACE3_RANK, dims3, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select 15x26 hyperslab for reading memory dataset */ + start[0] = 0; + start[1] = 0; + stride[0] = 1; + stride[1] = 1; + count[0] = 15; + count[1] = 26; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Read selection from disk */ + ret = H5Dread(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read with data written out */ + for (i = 0; i < SPACE3_DIM1; i++) { + /* Jump over gap in middle */ + if (i < 7) + tbuf = wbuf + ((i + 1) * SPACE2_DIM2); + else + tbuf = wbuf + ((i + 15) * SPACE2_DIM2); + tbuf2 = rbuf + (i * SPACE3_DIM2); + for (j = 0; j < SPACE3_DIM2; j++, tbuf++, tbuf2++) { + if (*tbuf != *tbuf2) + TestErrPrintf("%d: hyperslab values don't match!, i=%d, j=%d, *tbuf=%d, *tbuf2=%d\n", + __LINE__, i, j, (int)*tbuf, (int)*tbuf2); + } /* end for */ + } /* end for */ + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Test disjoint case of two non-overlapping blocks with hyperslab caching turned off */ + /* Create dataspace for dataset */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create dataspace for writing buffer */ + sid2 = H5Screate_simple(SPACE2_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select 2x15x13 hyperslab for disk dataset */ + start[0] = 1; + start[1] = 0; + start[2] = 0; + stride[0] = 1; + stride[1] = 1; + stride[2] = 1; + count[0] = 2; + count[1] = 15; + count[2] = 13; + block[0] = 1; + block[1] = 1; + block[2] = 1; + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Select 7x26 hyperslab for memory dataset */ + start[0] = 1; + start[1] = 0; + stride[0] = 1; + stride[1] = 1; + count[0] = 7; + count[1] = 26; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Union non-overlapping 8x26 hyperslab for memory dataset (to form a 15x26 disjoint selection) */ + start[0] = 22; + start[1] = 0; + stride[0] = 1; + stride[1] = 1; + count[0] = 8; + count[1] = 26; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + npoints = H5Sget_select_npoints(sid2); + VERIFY(npoints, 15 * 26, "H5Sget_select_npoints"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, SPACE4_NAME, H5T_NATIVE_UCHAR, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + xfer = H5Pcreate(H5P_DATASET_XFER); + CHECK(xfer, FAIL, "H5Pcreate"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_UCHAR, sid2, sid1, xfer, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Create dataspace for reading buffer */ + sid2 = H5Screate_simple(SPACE3_RANK, dims3, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select 15x26 hyperslab for reading memory dataset */ + start[0] = 0; + start[1] = 0; + stride[0] = 1; + stride[1] = 1; + count[0] = 15; + count[1] = 26; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Read selection from disk */ + ret = H5Dread(dataset, H5T_NATIVE_UCHAR, sid2, sid1, xfer, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Close transfer property list */ + ret = H5Pclose(xfer); + CHECK(ret, FAIL, "H5Pclose"); + + /* Compare data read with data written out */ + for (i = 0; i < SPACE3_DIM1; i++) { + /* Jump over gap in middle */ + if (i < 7) + tbuf = wbuf + ((i + 1) * SPACE2_DIM2); + else + tbuf = wbuf + ((i + 15) * SPACE2_DIM2); + tbuf2 = rbuf + (i * SPACE3_DIM2); + for (j = 0; j < SPACE3_DIM2; j++, tbuf++, tbuf2++) { + if (*tbuf != *tbuf2) + TestErrPrintf("%d: hyperslab values don't match!, i=%d, j=%d, *tbuf=%d, *tbuf2=%d\n", + __LINE__, i, j, (int)*tbuf, (int)*tbuf2); + } /* end for */ + } /* end for */ + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Test case of two blocks which overlap corners and must be split */ + /* Create dataspace for dataset */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create dataspace for writing buffer */ + sid2 = H5Screate_simple(SPACE2_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select 2x15x13 hyperslab for disk dataset */ + start[0] = 1; + start[1] = 0; + start[2] = 0; + stride[0] = 1; + stride[1] = 1; + stride[2] = 1; + count[0] = 2; + count[1] = 15; + count[2] = 13; + block[0] = 1; + block[1] = 1; + block[2] = 1; + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Select 10x10 hyperslab for memory dataset */ + start[0] = 0; + start[1] = 0; + stride[0] = 1; + stride[1] = 1; + count[0] = 10; + count[1] = 10; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Union overlapping 15x20 hyperslab for memory dataset (forming a irregularly shaped region) */ + start[0] = 8; + start[1] = 5; + stride[0] = 1; + stride[1] = 1; + count[0] = 20; + count[1] = 15; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + npoints = H5Sget_select_npoints(sid2); + VERIFY(npoints, 15 * 26, "H5Sget_select_npoints"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, SPACE5_NAME, H5T_NATIVE_UCHAR, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Create dataspace for reading buffer */ + sid2 = H5Screate_simple(SPACE3_RANK, dims3, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select 15x26 hyperslab for reading memory dataset */ + start[0] = 0; + start[1] = 0; + stride[0] = 1; + stride[1] = 1; + count[0] = 15; + count[1] = 26; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Read selection from disk */ + ret = H5Dread(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read with data written out */ + for (i = 0, tbuf2 = rbuf; i < SPACE2_DIM1; i++) { + tbuf = wbuf + (i * SPACE2_DIM2) + begin[i]; + for (j = 0; j < (int)len[i]; j++, tbuf++, tbuf2++) { + if (*tbuf != *tbuf2) + TestErrPrintf("%d: hyperslab values don't match!, i=%d, j=%d, *tbuf=%d, *tbuf2=%d\n", + __LINE__, i, j, (int)*tbuf, (int)*tbuf2); + } /* end for */ + } /* end for */ + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free memory buffers */ + HDfree(wbuf); + HDfree(rbuf); +} /* test_select_hyper_union() */ + +/**************************************************************** +** +** test_select_hyper_union_stagger(): Test basic H5S (dataspace) selection code. +** Tests unions of staggered hyperslabs. (Uses H5Scombine_hyperslab +** and H5Smodify_select instead of H5Sselect_hyperslab) +** +****************************************************************/ +static void +test_select_hyper_union_stagger(void) +{ + hid_t file_id; /* File ID */ + hid_t dset_id; /* Dataset ID */ + hid_t dataspace; /* File dataspace ID */ + hid_t memspace; /* Memory dataspace ID */ + hid_t tmp_space; /* Temporary dataspace ID */ + hid_t tmp2_space; /* Another emporary dataspace ID */ + hsize_t dimsm[2] = {7, 7}; /* Memory array dimensions */ + hsize_t dimsf[2] = {6, 5}; /* File array dimensions */ + hsize_t count[2] = {3, 1}; /* 1st Hyperslab size */ + hsize_t count2[2] = {3, 1}; /* 2nd Hyperslab size */ + hsize_t count3[2] = {2, 1}; /* 3rd Hyperslab size */ + hsize_t start[2] = {0, 0}; /* 1st Hyperslab offset */ + hsize_t start2[2] = {2, 1}; /* 2nd Hyperslab offset */ + hsize_t start3[2] = {4, 2}; /* 3rd Hyperslab offset */ + hsize_t count_out[2] = {4, 2}; /* Hyperslab size in memory */ + hsize_t start_out[2] = {0, 3}; /* Hyperslab offset in memory */ + int data[6][5]; /* Data to write */ + int data_out[7][7]; /* Data read in */ + int input_loc[8][2] = {{0, 0}, {1, 0}, {2, 0}, {2, 1}, {3, 1}, {4, 1}, {4, 2}, {5, 2}}; + int output_loc[8][2] = {{0, 3}, {0, 4}, {1, 3}, {1, 4}, {2, 3}, {2, 4}, {3, 3}, {3, 4}}; + int dsetrank = 2; /* File Dataset rank */ + int memrank = 2; /* Memory Dataset rank */ + int i, j; /* Local counting variables */ + herr_t error; + hsize_t stride[2] = {1, 1}; + hsize_t block[2] = {1, 1}; + + /* Initialize data to write */ + for (i = 0; i < 6; i++) + for (j = 0; j < 5; j++) + data[i][j] = j * 10 + i; + + /* Create file */ + file_id = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file_id, FAIL, "H5Fcreate"); + + /* Create File Dataspace */ + dataspace = H5Screate_simple(dsetrank, dimsf, NULL); + CHECK(dataspace, FAIL, "H5Screate_simple"); + + /* Create File Dataset */ + dset_id = + H5Dcreate2(file_id, "IntArray", H5T_NATIVE_INT, dataspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dset_id, FAIL, "H5Dcreate2"); + + /* Write File Dataset */ + error = H5Dwrite(dset_id, H5T_NATIVE_INT, dataspace, dataspace, H5P_DEFAULT, data); + CHECK(error, FAIL, "H5Dwrite"); + + /* Close things */ + error = H5Sclose(dataspace); + CHECK(error, FAIL, "H5Sclose"); + error = H5Dclose(dset_id); + CHECK(error, FAIL, "H5Dclose"); + error = H5Fclose(file_id); + CHECK(error, FAIL, "H5Fclose"); + + /* Initialize input buffer */ + HDmemset(data_out, 0, 7 * 7 * sizeof(int)); + + /* Open file */ + file_id = H5Fopen(FILENAME, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(file_id, FAIL, "H5Fopen"); + + /* Open dataset */ + dset_id = H5Dopen2(file_id, "IntArray", H5P_DEFAULT); + CHECK(dset_id, FAIL, "H5Dopen2"); + + /* Get the dataspace */ + dataspace = H5Dget_space(dset_id); + CHECK(dataspace, FAIL, "H5Dget_space"); + + /* Select the hyperslabs */ + error = H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, start, stride, count, block); + CHECK(error, FAIL, "H5Sselect_hyperslab"); + tmp_space = H5Scombine_hyperslab(dataspace, H5S_SELECT_OR, start2, stride, count2, block); + CHECK(tmp_space, FAIL, "H5Scombine_hyperslab"); + + /* Copy the file dataspace and select hyperslab */ + tmp2_space = H5Scopy(dataspace); + CHECK(tmp2_space, FAIL, "H5Scopy"); + error = H5Sselect_hyperslab(tmp2_space, H5S_SELECT_SET, start3, stride, count3, block); + CHECK(error, FAIL, "H5Sselect_hyperslab"); + + /* Combine the copied dataspace with the temporary dataspace */ + error = H5Smodify_select(tmp_space, H5S_SELECT_OR, tmp2_space); + CHECK(error, FAIL, "H5Smodify_select"); + + /* Create Memory Dataspace */ + memspace = H5Screate_simple(memrank, dimsm, NULL); + CHECK(memspace, FAIL, "H5Screate_simple"); + + /* Select hyperslab in memory */ + error = H5Sselect_hyperslab(memspace, H5S_SELECT_SET, start_out, stride, count_out, block); + CHECK(error, FAIL, "H5Sselect_hyperslab"); + + /* Read File Dataset */ + error = H5Dread(dset_id, H5T_NATIVE_INT, memspace, tmp_space, H5P_DEFAULT, data_out); + CHECK(error, FAIL, "H5Dread"); + + /* Verify input data */ + for (i = 0; i < 8; i++) { + if (data[input_loc[i][0]][input_loc[i][1]] != data_out[output_loc[i][0]][output_loc[i][1]]) { + HDprintf("input data #%d is wrong!\n", i); + HDprintf("input_loc=[%d][%d]\n", input_loc[i][0], input_loc[i][1]); + HDprintf("output_loc=[%d][%d]\n", output_loc[i][0], output_loc[i][1]); + HDprintf("data=%d\n", data[input_loc[i][0]][input_loc[i][1]]); + TestErrPrintf("data_out=%d\n", data_out[output_loc[i][0]][output_loc[i][1]]); + } /* end if */ + } /* end for */ + + /* Close things */ + error = H5Sclose(tmp2_space); + CHECK(error, FAIL, "H5Sclose"); + error = H5Sclose(tmp_space); + CHECK(error, FAIL, "H5Sclose"); + error = H5Sclose(dataspace); + CHECK(error, FAIL, "H5Sclose"); + error = H5Sclose(memspace); + CHECK(error, FAIL, "H5Sclose"); + error = H5Dclose(dset_id); + CHECK(error, FAIL, "H5Dclose"); + error = H5Fclose(file_id); + CHECK(error, FAIL, "H5Fclose"); +} + +/**************************************************************** +** +** test_select_hyper_union_3d(): Test basic H5S (dataspace) selection code. +** Tests unions of hyperslabs in 3-D (Uses H5Scombine_hyperslab +** and H5Scombine_select instead of H5Sselect_hyperslab) +** +****************************************************************/ +static void +test_select_hyper_union_3d(void) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1, sid2; /* Dataspace ID */ + hid_t tmp_space; /* Temporary Dataspace ID */ + hid_t tmp2_space; /* Another temporary Dataspace ID */ + hsize_t dims1[] = {SPACE1_DIM1, SPACE1_DIM2, SPACE1_DIM3}; + hsize_t dims2[] = {SPACE4_DIM1, SPACE4_DIM2, SPACE4_DIM3}; + hsize_t dims3[] = {SPACE3_DIM1, SPACE3_DIM2}; + hsize_t start[SPACE1_RANK]; /* Starting location of hyperslab */ + hsize_t stride[SPACE1_RANK]; /* Stride of hyperslab */ + hsize_t count[SPACE1_RANK]; /* Element count of hyperslab */ + hsize_t block[SPACE1_RANK]; /* Block size of hyperslab */ + struct row_list { + size_t z; + size_t y; + size_t x; + size_t l; + } rows[] = { + /* Array of x,y,z coordinates & length for each row written from memory */ + {0, 0, 0, 6}, /* 1st face of 3-D object */ + {0, 1, 0, 6}, {0, 2, 0, 6}, {0, 3, 0, 6}, {0, 4, 0, 6}, {1, 0, 0, 6}, /* 2nd face of 3-D object */ + {1, 1, 0, 6}, {1, 2, 0, 6}, {1, 3, 0, 6}, {1, 4, 0, 6}, {2, 0, 0, 6}, /* 3rd face of 3-D object */ + {2, 1, 0, 10}, {2, 2, 0, 10}, {2, 3, 0, 10}, {2, 4, 0, 10}, {2, 5, 2, 8}, + {2, 6, 2, 8}, {3, 0, 0, 6}, /* 4th face of 3-D object */ + {3, 1, 0, 10}, {3, 2, 0, 10}, {3, 3, 0, 10}, {3, 4, 0, 10}, {3, 5, 2, 8}, + {3, 6, 2, 8}, {4, 0, 0, 6}, /* 5th face of 3-D object */ + {4, 1, 0, 10}, {4, 2, 0, 10}, {4, 3, 0, 10}, {4, 4, 0, 10}, {4, 5, 2, 8}, + {4, 6, 2, 8}, {5, 1, 2, 8}, /* 6th face of 3-D object */ + {5, 2, 2, 8}, {5, 3, 2, 8}, {5, 4, 2, 8}, {5, 5, 2, 8}, {5, 6, 2, 8}, + {6, 1, 2, 8}, /* 7th face of 3-D object */ + {6, 2, 2, 8}, {6, 3, 2, 8}, {6, 4, 2, 8}, {6, 5, 2, 8}, {6, 6, 2, 8}, + {7, 1, 2, 8}, /* 8th face of 3-D object */ + {7, 2, 2, 8}, {7, 3, 2, 8}, {7, 4, 2, 8}, {7, 5, 2, 8}, {7, 6, 2, 8}}; + uint8_t *wbuf, /* buffer to write to disk */ + *rbuf, /* buffer read from disk */ + *tbuf, /* temporary buffer pointer */ + *tbuf2; /* temporary buffer pointer */ + int i, j, k; /* Counters */ + herr_t ret; /* Generic return value */ + hsize_t npoints; /* Number of elements in selection */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Hyperslab Selection Functions with unions of 3-D hyperslabs\n")); + + /* Allocate write & read buffers */ + wbuf = (uint8_t *)HDmalloc(sizeof(uint8_t) * SPACE4_DIM1 * SPACE4_DIM2 * SPACE4_DIM3); + CHECK_PTR(wbuf, "HDmalloc"); + rbuf = (uint8_t *)HDcalloc(sizeof(uint8_t), SPACE3_DIM1 * SPACE3_DIM2); + CHECK_PTR(rbuf, "HDcalloc"); + + /* Initialize write buffer */ + for (i = 0, tbuf = wbuf; i < SPACE4_DIM1; i++) + for (j = 0; j < SPACE4_DIM2; j++) + for (k = 0; k < SPACE4_DIM3; k++) + *tbuf++ = (uint8_t)((((i * SPACE4_DIM2) + j) * SPACE4_DIM3) + k); + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Test case of two blocks which overlap corners and must be split */ + /* Create dataspace for dataset on disk */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create dataspace for writing buffer */ + sid2 = H5Screate_simple(SPACE4_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select 2x15x13 hyperslab for disk dataset */ + start[0] = 1; + start[1] = 0; + start[2] = 0; + stride[0] = 1; + stride[1] = 1; + stride[2] = 1; + count[0] = 2; + count[1] = 15; + count[2] = 13; + block[0] = 1; + block[1] = 1; + block[2] = 1; + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Select 5x5x6 hyperslab for memory dataset */ + start[0] = 0; + start[1] = 0; + start[2] = 0; + stride[0] = 1; + stride[1] = 1; + stride[2] = 1; + count[0] = 5; + count[1] = 5; + count[2] = 6; + block[0] = 1; + block[1] = 1; + block[2] = 1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Union overlapping 15x20 hyperslab for memory dataset (forming a irregularly shaped region) */ + start[0] = 2; + start[1] = 1; + start[2] = 2; + stride[0] = 1; + stride[1] = 1; + stride[2] = 1; + count[0] = 6; + count[1] = 6; + count[2] = 8; + block[0] = 1; + block[1] = 1; + block[2] = 1; + tmp_space = H5Scombine_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(tmp_space, FAIL, "H5Sselect_hyperslab"); + + /* Combine dataspaces and create new dataspace */ + tmp2_space = H5Scombine_select(sid2, H5S_SELECT_OR, tmp_space); + CHECK(tmp2_space, FAIL, "H5Scombin_select"); + + npoints = (hsize_t)H5Sget_select_npoints(tmp2_space); + VERIFY(npoints, 15 * 26, "H5Sget_select_npoints"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, SPACE1_NAME, H5T_NATIVE_UCHAR, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_UCHAR, tmp2_space, sid1, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close temporary dataspaces */ + ret = H5Sclose(tmp_space); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(tmp2_space); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Create dataspace for reading buffer */ + sid2 = H5Screate_simple(SPACE3_RANK, dims3, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select 15x26 hyperslab for reading memory dataset */ + start[0] = 0; + start[1] = 0; + stride[0] = 1; + stride[1] = 1; + count[0] = 15; + count[1] = 26; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Read selection from disk */ + ret = H5Dread(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read with data written out */ + for (i = 0, tbuf2 = rbuf; i < (int)(sizeof(rows) / sizeof(struct row_list)); i++) { + tbuf = wbuf + (rows[i].z * SPACE4_DIM3 * SPACE4_DIM2) + (rows[i].y * SPACE4_DIM3) + rows[i].x; + for (j = 0; j < (int)rows[i].l; j++, tbuf++, tbuf2++) { + if (*tbuf != *tbuf2) + TestErrPrintf("%d: hyperslab values don't match!, i=%d, j=%d, *tbuf=%d, *tbuf2=%d\n", + __LINE__, i, j, (int)*tbuf, (int)*tbuf2); + } /* end for */ + } /* end for */ + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free memory buffers */ + HDfree(wbuf); + HDfree(rbuf); +} /* test_select_hyper_union_3d() */ + +/**************************************************************** +** +** test_select_hyper_valid_combination(): Tests invalid and valid +** combinations of selections on dataspace for H5Scombine_select +** and H5Smodify_select. +** +****************************************************************/ +static void +test_select_hyper_valid_combination(void) +{ + hid_t single_pt_sid; /* Dataspace ID with single point selection */ + hid_t single_hyper_sid; /* Dataspace ID with single block hyperslab selection */ + hid_t regular_hyper_sid; /* Dataspace ID with regular hyperslab selection */ + hid_t non_existent_sid = -1; /* A non-existent space id */ + hid_t tmp_sid; /* Temporary dataspace ID */ + hsize_t dims2D[] = {SPACE9_DIM1, SPACE9_DIM2}; + hsize_t dims3D[] = {SPACE4_DIM1, SPACE4_DIM2, SPACE4_DIM3}; + + hsize_t coord1[1][SPACE2_RANK]; /* Coordinates for single point selection */ + hsize_t start[SPACE4_RANK]; /* Hyperslab start */ + hsize_t stride[SPACE4_RANK]; /* Hyperslab stride */ + hsize_t count[SPACE4_RANK]; /* Hyperslab block count */ + hsize_t block[SPACE4_RANK]; /* Hyperslab block size */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(6, ("Testing Selection Combination Validity\n")); + HDassert(SPACE9_DIM2 >= POINT1_NPOINTS); + + /* Create dataspace for single point selection */ + single_pt_sid = H5Screate_simple(SPACE9_RANK, dims2D, NULL); + CHECK(single_pt_sid, FAIL, "H5Screate_simple"); + + /* Select sequence of ten points for multiple point selection */ + coord1[0][0] = 2; + coord1[0][1] = 2; + ret = H5Sselect_elements(single_pt_sid, H5S_SELECT_SET, (size_t)1, (const hsize_t *)coord1); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Create dataspace for single hyperslab selection */ + single_hyper_sid = H5Screate_simple(SPACE9_RANK, dims2D, NULL); + CHECK(single_hyper_sid, FAIL, "H5Screate_simple"); + + /* Select 10x10 hyperslab for single hyperslab selection */ + start[0] = 1; + start[1] = 1; + stride[0] = 1; + stride[1] = 1; + count[0] = 1; + count[1] = 1; + block[0] = (SPACE9_DIM1 - 2); + block[1] = (SPACE9_DIM2 - 2); + ret = H5Sselect_hyperslab(single_hyper_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create dataspace for regular hyperslab selection */ + regular_hyper_sid = H5Screate_simple(SPACE4_RANK, dims3D, NULL); + CHECK(regular_hyper_sid, FAIL, "H5Screate_simple"); + + /* Select regular, strided hyperslab selection */ + start[0] = 2; + start[1] = 2; + start[2] = 2; + stride[0] = 2; + stride[1] = 2; + stride[2] = 2; + count[0] = 5; + count[1] = 2; + count[2] = 5; + block[0] = 1; + block[1] = 1; + block[2] = 1; + ret = H5Sselect_hyperslab(regular_hyper_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Test all the selections created */ + + /* Test the invalid combinations between point and hyperslab */ + H5E_BEGIN_TRY + { + tmp_sid = H5Scombine_select(single_pt_sid, H5S_SELECT_AND, single_hyper_sid); + } + H5E_END_TRY; + VERIFY(tmp_sid, FAIL, "H5Scombine_select"); + + H5E_BEGIN_TRY + { + tmp_sid = H5Smodify_select(single_pt_sid, H5S_SELECT_AND, single_hyper_sid); + } + H5E_END_TRY; + VERIFY(tmp_sid, FAIL, "H5Smodify_select"); + + /* Test the invalid combination between two hyperslab but of different dimension size */ + H5E_BEGIN_TRY + { + tmp_sid = H5Scombine_select(single_hyper_sid, H5S_SELECT_AND, regular_hyper_sid); + } + H5E_END_TRY; + VERIFY(tmp_sid, FAIL, "H5Scombine_select"); + + H5E_BEGIN_TRY + { + tmp_sid = H5Smodify_select(single_hyper_sid, H5S_SELECT_AND, regular_hyper_sid); + } + H5E_END_TRY; + VERIFY(tmp_sid, FAIL, "H5Smodify_select"); + + /* Test invalid operation inputs to the two functions */ + H5E_BEGIN_TRY + { + tmp_sid = H5Scombine_select(single_hyper_sid, H5S_SELECT_SET, single_hyper_sid); + } + H5E_END_TRY; + VERIFY(tmp_sid, FAIL, "H5Scombine_select"); + + H5E_BEGIN_TRY + { + tmp_sid = H5Smodify_select(single_hyper_sid, H5S_SELECT_SET, single_hyper_sid); + } + H5E_END_TRY; + VERIFY(tmp_sid, FAIL, "H5Smodify_select"); + + /* Test inputs in case of non-existent space ids */ + H5E_BEGIN_TRY + { + tmp_sid = H5Scombine_select(single_hyper_sid, H5S_SELECT_AND, non_existent_sid); + } + H5E_END_TRY; + VERIFY(tmp_sid, FAIL, "H5Scombine_select"); + + H5E_BEGIN_TRY + { + tmp_sid = H5Smodify_select(single_hyper_sid, H5S_SELECT_AND, non_existent_sid); + } + H5E_END_TRY; + VERIFY(tmp_sid, FAIL, "H5Smodify_select"); + + /* Close dataspaces */ + ret = H5Sclose(single_pt_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(single_hyper_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(regular_hyper_sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_select_hyper_valid_combination() */ + +/**************************************************************** +** +** test_select_hyper_and_2d(): Test basic H5S (dataspace) selection code. +** Tests 'and' of hyperslabs in 2-D +** +****************************************************************/ +static void +test_select_hyper_and_2d(void) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1, sid2; /* Dataspace ID */ + hsize_t dims1[] = {SPACE2_DIM1, SPACE2_DIM2}; + hsize_t dims2[] = {SPACE2A_DIM1}; + hsize_t start[SPACE2_RANK]; /* Starting location of hyperslab */ + hsize_t stride[SPACE2_RANK]; /* Stride of hyperslab */ + hsize_t count[SPACE2_RANK]; /* Element count of hyperslab */ + hsize_t block[SPACE2_RANK]; /* Block size of hyperslab */ + uint8_t *wbuf, /* buffer to write to disk */ + *rbuf, /* buffer read from disk */ + *tbuf, /* temporary buffer pointer */ + *tbuf2; /* temporary buffer pointer */ + int i, j; /* Counters */ + herr_t ret; /* Generic return value */ + hssize_t npoints; /* Number of elements in selection */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Hyperslab Selection Functions with intersection of 2-D hyperslabs\n")); + + /* Allocate write & read buffers */ + wbuf = (uint8_t *)HDmalloc(sizeof(uint8_t) * SPACE2_DIM1 * SPACE2_DIM2); + CHECK_PTR(wbuf, "HDmalloc"); + rbuf = (uint8_t *)HDcalloc(sizeof(uint8_t), (size_t)(SPACE2_DIM1 * SPACE2_DIM2)); + CHECK_PTR(rbuf, "HDcalloc"); + + /* Initialize write buffer */ + for (i = 0, tbuf = wbuf; i < SPACE2_DIM1; i++) + for (j = 0; j < SPACE2_DIM2; j++) + *tbuf++ = (uint8_t)((i * SPACE2_DIM2) + j); + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset on disk */ + sid1 = H5Screate_simple(SPACE2_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create dataspace for writing buffer */ + sid2 = H5Screate_simple(SPACE2A_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select 10x10 hyperslab for disk dataset */ + start[0] = 0; + start[1] = 0; + stride[0] = 1; + stride[1] = 1; + count[0] = 10; + count[1] = 10; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Intersect overlapping 10x10 hyperslab */ + start[0] = 5; + start[1] = 5; + stride[0] = 1; + stride[1] = 1; + count[0] = 10; + count[1] = 10; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_AND, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + npoints = H5Sget_select_npoints(sid1); + VERIFY(npoints, 5 * 5, "H5Sget_select_npoints"); + + /* Select 25 hyperslab for memory dataset */ + start[0] = 0; + stride[0] = 1; + count[0] = 25; + block[0] = 1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + npoints = H5Sget_select_npoints(sid2); + VERIFY(npoints, 5 * 5, "H5Sget_select_npoints"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, SPACE2_NAME, H5T_NATIVE_UCHAR, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Read entire dataset from disk */ + ret = H5Dread(dataset, H5T_NATIVE_UCHAR, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Initialize write buffer */ + for (i = 0, tbuf = rbuf, tbuf2 = wbuf; i < SPACE2_DIM1; i++) + for (j = 0; j < SPACE2_DIM2; j++, tbuf++) { + if ((i >= 5 && i <= 9) && (j >= 5 && j <= 9)) { + if (*tbuf != *tbuf2) + HDprintf("%d: hyperslab values don't match!, i=%d, j=%d, *tbuf=%d, *tbuf2=%d\n", __LINE__, + i, j, (int)*tbuf, (int)*tbuf2); + tbuf2++; + } /* end if */ + else { + if (*tbuf != 0) + HDprintf("%d: hyperslab element has wrong value!, i=%d, j=%d, *tbuf=%d\n", __LINE__, i, j, + (int)*tbuf); + } /* end else */ + } /* end for */ + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free memory buffers */ + HDfree(wbuf); + HDfree(rbuf); +} /* test_select_hyper_and_2d() */ + +/**************************************************************** +** +** test_select_hyper_xor_2d(): Test basic H5S (dataspace) selection code. +** Tests 'xor' of hyperslabs in 2-D +** +****************************************************************/ +static void +test_select_hyper_xor_2d(void) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1, sid2; /* Dataspace ID */ + hsize_t dims1[] = {SPACE2_DIM1, SPACE2_DIM2}; + hsize_t dims2[] = {SPACE2A_DIM1}; + hsize_t start[SPACE2_RANK]; /* Starting location of hyperslab */ + hsize_t stride[SPACE2_RANK]; /* Stride of hyperslab */ + hsize_t count[SPACE2_RANK]; /* Element count of hyperslab */ + hsize_t block[SPACE2_RANK]; /* Block size of hyperslab */ + uint8_t *wbuf, /* buffer to write to disk */ + *rbuf, /* buffer read from disk */ + *tbuf, /* temporary buffer pointer */ + *tbuf2; /* temporary buffer pointer */ + int i, j; /* Counters */ + herr_t ret; /* Generic return value */ + hssize_t npoints; /* Number of elements in selection */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Hyperslab Selection Functions with XOR of 2-D hyperslabs\n")); + + /* Allocate write & read buffers */ + wbuf = (uint8_t *)HDmalloc(sizeof(uint8_t) * SPACE2_DIM1 * SPACE2_DIM2); + CHECK_PTR(wbuf, "HDmalloc"); + rbuf = (uint8_t *)HDcalloc(sizeof(uint8_t), (size_t)(SPACE2_DIM1 * SPACE2_DIM2)); + CHECK_PTR(rbuf, "HDcalloc"); + + /* Initialize write buffer */ + for (i = 0, tbuf = wbuf; i < SPACE2_DIM1; i++) + for (j = 0; j < SPACE2_DIM2; j++) + *tbuf++ = (uint8_t)((i * SPACE2_DIM2) + j); + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset on disk */ + sid1 = H5Screate_simple(SPACE2_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create dataspace for writing buffer */ + sid2 = H5Screate_simple(SPACE2A_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select 10x10 hyperslab for disk dataset */ + start[0] = 0; + start[1] = 0; + stride[0] = 1; + stride[1] = 1; + count[0] = 10; + count[1] = 10; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Intersect overlapping 10x10 hyperslab */ + start[0] = 5; + start[1] = 5; + stride[0] = 1; + stride[1] = 1; + count[0] = 10; + count[1] = 10; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_XOR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + npoints = H5Sget_select_npoints(sid1); + VERIFY(npoints, 150, "H5Sget_select_npoints"); + + /* Select 25 hyperslab for memory dataset */ + start[0] = 0; + stride[0] = 1; + count[0] = 150; + block[0] = 1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + npoints = H5Sget_select_npoints(sid2); + VERIFY(npoints, 150, "H5Sget_select_npoints"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, SPACE2_NAME, H5T_NATIVE_UCHAR, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Read entire dataset from disk */ + ret = H5Dread(dataset, H5T_NATIVE_UCHAR, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Initialize write buffer */ + for (i = 0, tbuf = rbuf, tbuf2 = wbuf; i < SPACE2_DIM1; i++) + for (j = 0; j < SPACE2_DIM2; j++, tbuf++) { + if (((i >= 0 && i <= 4) && (j >= 0 && j <= 9)) || + ((i >= 5 && i <= 9) && ((j >= 0 && j <= 4) || (j >= 10 && j <= 14))) || + ((i >= 10 && i <= 14) && (j >= 5 && j <= 14))) { + if (*tbuf != *tbuf2) + HDprintf("%d: hyperslab values don't match!, i=%d, j=%d, *tbuf=%d, *tbuf2=%d\n", __LINE__, + i, j, (int)*tbuf, (int)*tbuf2); + tbuf2++; + } /* end if */ + else { + if (*tbuf != 0) + HDprintf("%d: hyperslab element has wrong value!, i=%d, j=%d, *tbuf=%d\n", __LINE__, i, j, + (int)*tbuf); + } /* end else */ + } /* end for */ + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free memory buffers */ + HDfree(wbuf); + HDfree(rbuf); +} /* test_select_hyper_xor_2d() */ + +/**************************************************************** +** +** test_select_hyper_notb_2d(): Test basic H5S (dataspace) selection code. +** Tests 'notb' of hyperslabs in 2-D +** +****************************************************************/ +static void +test_select_hyper_notb_2d(void) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1, sid2; /* Dataspace ID */ + hsize_t dims1[] = {SPACE2_DIM1, SPACE2_DIM2}; + hsize_t dims2[] = {SPACE2A_DIM1}; + hsize_t start[SPACE2_RANK]; /* Starting location of hyperslab */ + hsize_t stride[SPACE2_RANK]; /* Stride of hyperslab */ + hsize_t count[SPACE2_RANK]; /* Element count of hyperslab */ + hsize_t block[SPACE2_RANK]; /* Block size of hyperslab */ + uint8_t *wbuf, /* buffer to write to disk */ + *rbuf, /* buffer read from disk */ + *tbuf, /* temporary buffer pointer */ + *tbuf2; /* temporary buffer pointer */ + int i, j; /* Counters */ + herr_t ret; /* Generic return value */ + hssize_t npoints; /* Number of elements in selection */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Hyperslab Selection Functions with NOTB of 2-D hyperslabs\n")); + + /* Allocate write & read buffers */ + wbuf = (uint8_t *)HDmalloc(sizeof(uint8_t) * SPACE2_DIM1 * SPACE2_DIM2); + CHECK_PTR(wbuf, "HDmalloc"); + rbuf = (uint8_t *)HDcalloc(sizeof(uint8_t), (size_t)(SPACE2_DIM1 * SPACE2_DIM2)); + CHECK_PTR(rbuf, "HDcalloc"); + + /* Initialize write buffer */ + for (i = 0, tbuf = wbuf; i < SPACE2_DIM1; i++) + for (j = 0; j < SPACE2_DIM2; j++) + *tbuf++ = (uint8_t)((i * SPACE2_DIM2) + j); + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset on disk */ + sid1 = H5Screate_simple(SPACE2_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create dataspace for writing buffer */ + sid2 = H5Screate_simple(SPACE2A_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select 10x10 hyperslab for disk dataset */ + start[0] = 0; + start[1] = 0; + stride[0] = 1; + stride[1] = 1; + count[0] = 10; + count[1] = 10; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Intersect overlapping 10x10 hyperslab */ + start[0] = 5; + start[1] = 5; + stride[0] = 1; + stride[1] = 1; + count[0] = 10; + count[1] = 10; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_NOTB, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + npoints = H5Sget_select_npoints(sid1); + VERIFY(npoints, 75, "H5Sget_select_npoints"); + + /* Select 75 hyperslab for memory dataset */ + start[0] = 0; + stride[0] = 1; + count[0] = 75; + block[0] = 1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + npoints = H5Sget_select_npoints(sid2); + VERIFY(npoints, 75, "H5Sget_select_npoints"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, SPACE2_NAME, H5T_NATIVE_UCHAR, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Read entire dataset from disk */ + ret = H5Dread(dataset, H5T_NATIVE_UCHAR, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Initialize write buffer */ + for (i = 0, tbuf = rbuf, tbuf2 = wbuf; i < SPACE2_DIM1; i++) + for (j = 0; j < SPACE2_DIM2; j++, tbuf++) { + if (((i >= 0 && i <= 4) && (j >= 0 && j <= 9)) || ((i >= 5 && i <= 9) && (j >= 0 && j <= 4))) { + if (*tbuf != *tbuf2) + HDprintf("%d: hyperslab values don't match!, i=%d, j=%d, *tbuf=%d, *tbuf2=%d\n", __LINE__, + i, j, (int)*tbuf, (int)*tbuf2); + tbuf2++; + } /* end if */ + else { + if (*tbuf != 0) + HDprintf("%d: hyperslab element has wrong value!, i=%d, j=%d, *tbuf=%d\n", __LINE__, i, j, + (int)*tbuf); + } /* end else */ + } /* end for */ + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free memory buffers */ + HDfree(wbuf); + HDfree(rbuf); +} /* test_select_hyper_notb_2d() */ + +/**************************************************************** +** +** test_select_hyper_nota_2d(): Test basic H5S (dataspace) selection code. +** Tests 'nota' of hyperslabs in 2-D +** +****************************************************************/ +static void +test_select_hyper_nota_2d(void) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1, sid2; /* Dataspace ID */ + hsize_t dims1[] = {SPACE2_DIM1, SPACE2_DIM2}; + hsize_t dims2[] = {SPACE2A_DIM1}; + hsize_t start[SPACE2_RANK]; /* Starting location of hyperslab */ + hsize_t stride[SPACE2_RANK]; /* Stride of hyperslab */ + hsize_t count[SPACE2_RANK]; /* Element count of hyperslab */ + hsize_t block[SPACE2_RANK]; /* Block size of hyperslab */ + uint8_t *wbuf, /* buffer to write to disk */ + *rbuf, /* buffer read from disk */ + *tbuf, /* temporary buffer pointer */ + *tbuf2; /* temporary buffer pointer */ + int i, j; /* Counters */ + herr_t ret; /* Generic return value */ + hssize_t npoints; /* Number of elements in selection */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Hyperslab Selection Functions with NOTA of 2-D hyperslabs\n")); + + /* Allocate write & read buffers */ + wbuf = (uint8_t *)HDmalloc(sizeof(uint8_t) * SPACE2_DIM1 * SPACE2_DIM2); + CHECK_PTR(wbuf, "HDmalloc"); + rbuf = (uint8_t *)HDcalloc(sizeof(uint8_t), (size_t)(SPACE2_DIM1 * SPACE2_DIM2)); + CHECK_PTR(rbuf, "HDcalloc"); + + /* Initialize write buffer */ + for (i = 0, tbuf = wbuf; i < SPACE2_DIM1; i++) + for (j = 0; j < SPACE2_DIM2; j++) + *tbuf++ = (uint8_t)((i * SPACE2_DIM2) + j); + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset on disk */ + sid1 = H5Screate_simple(SPACE2_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create dataspace for writing buffer */ + sid2 = H5Screate_simple(SPACE2A_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Select 10x10 hyperslab for disk dataset */ + start[0] = 0; + start[1] = 0; + stride[0] = 1; + stride[1] = 1; + count[0] = 10; + count[1] = 10; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Intersect overlapping 10x10 hyperslab */ + start[0] = 5; + start[1] = 5; + stride[0] = 1; + stride[1] = 1; + count[0] = 10; + count[1] = 10; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_NOTA, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + npoints = H5Sget_select_npoints(sid1); + VERIFY(npoints, 75, "H5Sget_select_npoints"); + + /* Select 75 hyperslab for memory dataset */ + start[0] = 0; + stride[0] = 1; + count[0] = 75; + block[0] = 1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + npoints = H5Sget_select_npoints(sid2); + VERIFY(npoints, 75, "H5Sget_select_npoints"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, SPACE2_NAME, H5T_NATIVE_UCHAR, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write selection to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Read entire dataset from disk */ + ret = H5Dread(dataset, H5T_NATIVE_UCHAR, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Initialize write buffer */ + for (i = 0, tbuf = rbuf, tbuf2 = wbuf; i < SPACE2_DIM1; i++) + for (j = 0; j < SPACE2_DIM2; j++, tbuf++) { + if (((i >= 10 && i <= 14) && (j >= 5 && j <= 14)) || + ((i >= 5 && i <= 9) && (j >= 10 && j <= 14))) { + if (*tbuf != *tbuf2) + TestErrPrintf("%d: hyperslab values don't match!, i=%d, j=%d, *tbuf=%d, *tbuf2=%d\n", + __LINE__, i, j, (int)*tbuf, (int)*tbuf2); + tbuf2++; + } /* end if */ + else { + if (*tbuf != 0) + TestErrPrintf("%d: hyperslab element has wrong value!, i=%d, j=%d, *tbuf=%d\n", __LINE__, + i, j, (int)*tbuf); + } /* end else */ + } /* end for */ + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free memory buffers */ + HDfree(wbuf); + HDfree(rbuf); +} /* test_select_hyper_nota_2d() */ + +/**************************************************************** +** +** test_select_hyper_iter2(): Iterator for checking hyperslab iteration +** +****************************************************************/ +static herr_t +test_select_hyper_iter2(void *_elem, hid_t H5_ATTR_UNUSED type_id, unsigned ndim, const hsize_t *point, + void *_operator_data) +{ + int *tbuf = (int *)_elem, /* temporary buffer pointer */ + **tbuf2 = (int **)_operator_data; /* temporary buffer handle */ + unsigned u; /* Local counting variable */ + + if (*tbuf != **tbuf2) { + TestErrPrintf("Error in hyperslab iteration!\n"); + HDprintf("location: { "); + for (u = 0; u < ndim; u++) { + HDprintf("%2d", (int)point[u]); + if (u < (ndim - 1)) + HDprintf(", "); + } /* end for */ + HDprintf("}\n"); + HDprintf("*tbuf=%d, **tbuf2=%d\n", *tbuf, **tbuf2); + return (-1); + } /* end if */ + else { + (*tbuf2)++; + return (0); + } +} /* end test_select_hyper_iter2() */ + +/**************************************************************** +** +** test_select_hyper_union_random_5d(): Test basic H5S (dataspace) selection code. +** Tests random unions of 5-D hyperslabs +** +****************************************************************/ +static void +test_select_hyper_union_random_5d(hid_t read_plist) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1, sid2; /* Dataspace ID */ + hsize_t dims1[] = {SPACE5_DIM1, SPACE5_DIM2, SPACE5_DIM3, SPACE5_DIM4, SPACE5_DIM5}; + hsize_t dims2[] = {SPACE6_DIM1}; + hsize_t start[SPACE5_RANK]; /* Starting location of hyperslab */ + hsize_t count[SPACE5_RANK]; /* Element count of hyperslab */ + int *wbuf, /* buffer to write to disk */ + *rbuf, /* buffer read from disk */ + *tbuf; /* temporary buffer pointer */ + int i, j, k, l, m; /* Counters */ + herr_t ret; /* Generic return value */ + hssize_t npoints, /* Number of elements in file selection */ + npoints2; /* Number of elements in memory selection */ + unsigned seed; /* Random number seed for each test */ + unsigned test_num; /* Count of tests being executed */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Hyperslab Selection Functions with random unions of 5-D hyperslabs\n")); + + /* Allocate write & read buffers */ + wbuf = (int *)HDmalloc(sizeof(int) * SPACE5_DIM1 * SPACE5_DIM2 * SPACE5_DIM3 * SPACE5_DIM4 * SPACE5_DIM5); + CHECK_PTR(wbuf, "HDmalloc"); + rbuf = (int *)HDcalloc(sizeof(int), + (size_t)(SPACE5_DIM1 * SPACE5_DIM2 * SPACE5_DIM3 * SPACE5_DIM4 * SPACE5_DIM5)); + CHECK_PTR(rbuf, "HDcalloc"); + + /* Initialize write buffer */ + for (i = 0, tbuf = wbuf; i < SPACE5_DIM1; i++) + for (j = 0; j < SPACE5_DIM2; j++) + for (k = 0; k < SPACE5_DIM3; k++) + for (l = 0; l < SPACE5_DIM4; l++) + for (m = 0; m < SPACE5_DIM5; m++) + *tbuf++ = (int)(((((((i * SPACE5_DIM2) + j) * SPACE5_DIM3) + k) * SPACE5_DIM4) + l) * + SPACE5_DIM5) + + m; + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset on disk */ + sid1 = H5Screate_simple(SPACE5_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, SPACE5_NAME, H5T_NATIVE_INT, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write entire dataset to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Create dataspace for reading buffer */ + sid2 = H5Screate_simple(SPACE6_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Get initial random # seed */ + seed = (unsigned)HDtime(NULL) + (unsigned)HDclock(); + + /* Crunch through a bunch of random hyperslab reads from the file dataset */ + for (test_num = 0; test_num < NRAND_HYPER; test_num++) { + /* Save random # seed for later use */ + /* (Used in case of errors, to regenerate the hyperslab sequence) */ + seed += (unsigned)HDclock(); + HDsrandom(seed); + + for (i = 0; i < NHYPERSLABS; i++) { + /* Select random hyperslab location & size for selection */ + for (j = 0; j < SPACE5_RANK; j++) { + start[j] = ((hsize_t)HDrandom() % dims1[j]); + count[j] = (((hsize_t)HDrandom() % (dims1[j] - start[j])) + 1); + } /* end for */ + + /* Select hyperslab */ + ret = H5Sselect_hyperslab(sid1, (i == 0 ? H5S_SELECT_SET : H5S_SELECT_OR), start, NULL, count, + NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + if (ret < 0) { + TestErrPrintf("Random hyperslabs for seed %u failed!\n", seed); + break; + } /* end if */ + } /* end for */ + + /* Get the number of elements selected */ + npoints = H5Sget_select_npoints(sid1); + CHECK(npoints, 0, "H5Sget_select_npoints"); + + /* Select linear 1-D hyperslab for memory dataset */ + start[0] = 0; + count[0] = (hsize_t)npoints; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + npoints2 = H5Sget_select_npoints(sid2); + VERIFY(npoints, npoints2, "H5Sget_select_npoints"); + + /* Read selection from disk */ + ret = H5Dread(dataset, H5T_NATIVE_INT, sid2, sid1, read_plist, rbuf); + CHECK(ret, FAIL, "H5Dread"); + if (ret < 0) { + TestErrPrintf("Random hyperslabs for seed %u failed!\n", seed); + break; + } /* end if */ + + /* Compare data read with data written out */ + tbuf = rbuf; + ret = H5Diterate(wbuf, H5T_NATIVE_INT, sid1, test_select_hyper_iter2, &tbuf); + if (ret < 0) { + TestErrPrintf("Random hyperslabs for seed %u failed!\n", seed); + break; + } /* end if */ + + /* Set the read buffer back to all zeroes */ + HDmemset(rbuf, 0, (size_t)SPACE6_DIM1); + } /* end for */ + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free memory buffers */ + HDfree(wbuf); + HDfree(rbuf); +} /* test_select_hyper_union_random_5d() */ + +/**************************************************************** +** +** test_select_hyper_chunk(): Test basic H5S (dataspace) selection code. +** Tests large hyperslab selection in chunked dataset +** +****************************************************************/ +static void +test_select_hyper_chunk(hid_t fapl_plist, hid_t xfer_plist) +{ + hsize_t dimsf[3]; /* dataset dimensions */ + hsize_t chunk_dimsf[3] = {CHUNK_X, CHUNK_Y, CHUNK_Z}; /* chunk sizes */ + short *data; /* data to write */ + short *tmpdata; /* data to write */ + + /* + * Data and output buffer initialization. + */ + hid_t file, dataset; /* handles */ + hid_t dataspace; + hid_t memspace; + hid_t plist; + hsize_t dimsm[3]; /* memory space dimensions */ + hsize_t dims_out[3]; /* dataset dimensions */ + herr_t status; + + short *data_out; /* output buffer */ + short *tmpdata_out; /* output buffer */ + + hsize_t count[3]; /* size of the hyperslab in the file */ + hsize_t offset[3]; /* hyperslab offset in the file */ + hsize_t count_out[3]; /* size of the hyperslab in memory */ + hsize_t offset_out[3]; /* hyperslab offset in memory */ + int i, j, k, status_n, rank; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Hyperslab I/O on Large Chunks\n")); + + /* Allocate the transfer buffers */ + data = (short *)HDmalloc(sizeof(short) * X * Y * Z); + CHECK_PTR(data, "HDmalloc"); + data_out = (short *)HDcalloc((size_t)(NX * NY * NZ), sizeof(short)); + CHECK_PTR(data_out, "HDcalloc"); + + /* + * Data buffer initialization. + */ + tmpdata = data; + for (j = 0; j < X; j++) + for (i = 0; i < Y; i++) + for (k = 0; k < Z; k++) + *tmpdata++ = (short)((k + 1) % 256); + + /* + * Create a new file using H5F_ACC_TRUNC access, + * the default file creation properties, and the default file + * access properties. + */ + file = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_plist); + CHECK(file, FAIL, "H5Fcreate"); + + /* + * Describe the size of the array and create the dataspace for fixed + * size dataset. + */ + dimsf[0] = X; + dimsf[1] = Y; + dimsf[2] = Z; + dataspace = H5Screate_simple(RANK_F, dimsf, NULL); + CHECK(dataspace, FAIL, "H5Screate_simple"); + + /* + * Create a new dataset within the file using defined dataspace and + * chunking properties. + */ + plist = H5Pcreate(H5P_DATASET_CREATE); + CHECK(plist, FAIL, "H5Pcreate"); + status = H5Pset_chunk(plist, RANK_F, chunk_dimsf); + CHECK(status, FAIL, "H5Pset_chunk"); + dataset = H5Dcreate2(file, DATASETNAME, H5T_NATIVE_UCHAR, dataspace, H5P_DEFAULT, plist, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* + * Define hyperslab in the dataset. + */ + offset[0] = 0; + offset[1] = 0; + offset[2] = 0; + count[0] = NX_SUB; + count[1] = NY_SUB; + count[2] = NZ_SUB; + status = H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, offset, NULL, count, NULL); + CHECK(status, FAIL, "H5Sselect_hyperslab"); + + /* + * Define the memory dataspace. + */ + dimsm[0] = NX; + dimsm[1] = NY; + dimsm[2] = NZ; + memspace = H5Screate_simple(RANK_M, dimsm, NULL); + CHECK(memspace, FAIL, "H5Screate_simple"); + + /* + * Define memory hyperslab. + */ + offset_out[0] = 0; + offset_out[1] = 0; + offset_out[2] = 0; + count_out[0] = NX_SUB; + count_out[1] = NY_SUB; + count_out[2] = NZ_SUB; + status = H5Sselect_hyperslab(memspace, H5S_SELECT_SET, offset_out, NULL, count_out, NULL); + CHECK(status, FAIL, "H5Sselect_hyperslab"); + + /* + * Write the data to the dataset using hyperslabs + */ + status = H5Dwrite(dataset, H5T_NATIVE_SHORT, memspace, dataspace, xfer_plist, data); + CHECK(status, FAIL, "H5Dwrite"); + + /* + * Close/release resources. + */ + status = H5Pclose(plist); + CHECK(status, FAIL, "H5Pclose"); + status = H5Sclose(dataspace); + CHECK(status, FAIL, "H5Sclose"); + status = H5Sclose(memspace); + CHECK(status, FAIL, "H5Sclose"); + status = H5Dclose(dataset); + CHECK(status, FAIL, "H5Dclose"); + status = H5Fclose(file); + CHECK(status, FAIL, "H5Fclose"); + + /************************************************************* + + This reads the hyperslab from the test.h5 file just + created, into a 3-dimensional plane of the 3-dimensional + array. + + ************************************************************/ + + /* + * Open the file and the dataset. + */ + file = H5Fopen(FILENAME, H5F_ACC_RDONLY, fapl_plist); + CHECK(file, FAIL, "H5Fopen"); + dataset = H5Dopen2(file, DATASETNAME, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + dataspace = H5Dget_space(dataset); /* dataspace handle */ + CHECK(dataspace, FAIL, "H5Dget_space"); + rank = H5Sget_simple_extent_ndims(dataspace); + VERIFY(rank, 3, "H5Sget_simple_extent_ndims"); + status_n = H5Sget_simple_extent_dims(dataspace, dims_out, NULL); + CHECK(status_n, FAIL, "H5Sget_simple_extent_dims"); + VERIFY(dims_out[0], dimsf[0], "Dataset dimensions"); + VERIFY(dims_out[1], dimsf[1], "Dataset dimensions"); + VERIFY(dims_out[2], dimsf[2], "Dataset dimensions"); + + /* + * Define hyperslab in the dataset. + */ + offset[0] = 0; + offset[1] = 0; + offset[2] = 0; + count[0] = NX_SUB; + count[1] = NY_SUB; + count[2] = NZ_SUB; + status = H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, offset, NULL, count, NULL); + CHECK(status, FAIL, "H5Sselect_hyperslab"); + + /* + * Define the memory dataspace. + */ + dimsm[0] = NX; + dimsm[1] = NY; + dimsm[2] = NZ; + memspace = H5Screate_simple(RANK_M, dimsm, NULL); + CHECK(memspace, FAIL, "H5Screate_simple"); + + /* + * Define memory hyperslab. + */ + offset_out[0] = 0; + offset_out[1] = 0; + offset_out[2] = 0; + count_out[0] = NX_SUB; + count_out[1] = NY_SUB; + count_out[2] = NZ_SUB; + status = H5Sselect_hyperslab(memspace, H5S_SELECT_SET, offset_out, NULL, count_out, NULL); + CHECK(status, FAIL, "H5Sselect_hyperslab"); + + /* + * Read data from hyperslab in the file into the hyperslab in + * memory and display. + */ + status = H5Dread(dataset, H5T_NATIVE_SHORT, memspace, dataspace, xfer_plist, data_out); + CHECK(status, FAIL, "H5Dread"); + + /* Compare data written with data read in */ + tmpdata = data; + tmpdata_out = data_out; + for (j = 0; j < X; j++) + for (i = 0; i < Y; i++) + for (k = 0; k < Z; k++, tmpdata++, tmpdata_out++) { + if (*tmpdata != *tmpdata_out) + TestErrPrintf("Line %d: Error! j=%d, i=%d, k=%d, *tmpdata=%x, *tmpdata_out=%x\n", + __LINE__, j, i, k, (unsigned)*tmpdata, (unsigned)*tmpdata_out); + } /* end for */ + + /* + * Close and release resources. + */ + status = H5Dclose(dataset); + CHECK(status, FAIL, "H5Dclose"); + status = H5Sclose(dataspace); + CHECK(status, FAIL, "H5Sclose"); + status = H5Sclose(memspace); + CHECK(status, FAIL, "H5Sclose"); + status = H5Fclose(file); + CHECK(status, FAIL, "H5Fclose"); + HDfree(data); + HDfree(data_out); +} /* test_select_hyper_chunk() */ + +/**************************************************************** +** +** test_select_point_chunk(): Test basic H5S (dataspace) selection code. +** Tests combinations of hyperslab and point selections on +** chunked datasets. +** +****************************************************************/ +static void +test_select_point_chunk(void) +{ + hsize_t dimsf[SPACE7_RANK]; /* dataset dimensions */ + hsize_t chunk_dimsf[SPACE7_RANK] = {SPACE7_CHUNK_DIM1, SPACE7_CHUNK_DIM2}; /* chunk sizes */ + unsigned *data; /* data to write */ + unsigned *tmpdata; /* data to write */ + + /* + * Data and output buffer initialization. + */ + hid_t file, dataset; /* handles */ + hid_t dataspace; + hid_t pnt1_space; /* Dataspace to hold 1st point selection */ + hid_t pnt2_space; /* Dataspace to hold 2nd point selection */ + hid_t hyp1_space; /* Dataspace to hold 1st hyperslab selection */ + hid_t hyp2_space; /* Dataspace to hold 2nd hyperslab selection */ + hid_t dcpl; + herr_t ret; /* Generic return value */ + + unsigned *data_out; /* output buffer */ + + hsize_t start[SPACE7_RANK]; /* hyperslab offset */ + hsize_t count[SPACE7_RANK]; /* size of the hyperslab */ + hsize_t points[SPACE7_NPOINTS][SPACE7_RANK]; /* points for selection */ + unsigned i, j; /* Local index variables */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Point Selections on Chunked Datasets\n")); + + /* Allocate the transfer buffers */ + data = (unsigned *)HDmalloc(sizeof(unsigned) * SPACE7_DIM1 * SPACE7_DIM2); + CHECK_PTR(data, "HDmalloc"); + data_out = (unsigned *)HDcalloc((size_t)(SPACE7_DIM1 * SPACE7_DIM2), sizeof(unsigned)); + CHECK_PTR(data_out, "HDcalloc"); + + /* + * Data buffer initialization. + */ + tmpdata = data; + for (i = 0; i < SPACE7_DIM1; i++) + for (j = 0; j < SPACE7_DIM1; j++) + *tmpdata++ = ((i * SPACE7_DIM2) + j) % 256; + + /* + * Create a new file using H5F_ACC_TRUNC access, + * the default file creation properties and file + * access properties. + */ + file = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file, FAIL, "H5Fcreate"); + + /* Create file dataspace */ + dimsf[0] = SPACE7_DIM1; + dimsf[1] = SPACE7_DIM2; + dataspace = H5Screate_simple(SPACE7_RANK, dimsf, NULL); + CHECK(dataspace, FAIL, "H5Screate_simple"); + + /* + * Create a new dataset within the file using defined dataspace and + * chunking properties. + */ + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + ret = H5Pset_chunk(dcpl, SPACE7_RANK, chunk_dimsf); + CHECK(ret, FAIL, "H5Pset_chunk"); + dataset = H5Dcreate2(file, DATASETNAME, H5T_NATIVE_UCHAR, dataspace, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Create 1st point selection */ + pnt1_space = H5Scopy(dataspace); + CHECK(pnt1_space, FAIL, "H5Scopy"); + + points[0][0] = 3; + points[0][1] = 3; + points[1][0] = 3; + points[1][1] = 8; + points[2][0] = 8; + points[2][1] = 3; + points[3][0] = 8; + points[3][1] = 8; + points[4][0] = 1; /* In same chunk as point #0, but "earlier" in chunk */ + points[4][1] = 1; + points[5][0] = 1; /* In same chunk as point #1, but "earlier" in chunk */ + points[5][1] = 6; + points[6][0] = 6; /* In same chunk as point #2, but "earlier" in chunk */ + points[6][1] = 1; + points[7][0] = 6; /* In same chunk as point #3, but "earlier" in chunk */ + points[7][1] = 6; + ret = H5Sselect_elements(pnt1_space, H5S_SELECT_SET, (size_t)SPACE7_NPOINTS, (const hsize_t *)points); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Create 1st hyperslab selection */ + hyp1_space = H5Scopy(dataspace); + CHECK(hyp1_space, FAIL, "H5Scopy"); + + start[0] = 2; + start[1] = 2; + count[0] = 4; + count[1] = 2; + ret = H5Sselect_hyperslab(hyp1_space, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Write out data using 1st point selection for file & hyperslab for memory */ + ret = H5Dwrite(dataset, H5T_NATIVE_UINT, hyp1_space, pnt1_space, H5P_DEFAULT, data); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Create 2nd point selection */ + pnt2_space = H5Scopy(dataspace); + CHECK(pnt2_space, FAIL, "H5Scopy"); + + points[0][0] = 4; + points[0][1] = 4; + points[1][0] = 4; + points[1][1] = 9; + points[2][0] = 9; + points[2][1] = 4; + points[3][0] = 9; + points[3][1] = 9; + points[4][0] = 2; /* In same chunk as point #0, but "earlier" in chunk */ + points[4][1] = 2; + points[5][0] = 2; /* In same chunk as point #1, but "earlier" in chunk */ + points[5][1] = 7; + points[6][0] = 7; /* In same chunk as point #2, but "earlier" in chunk */ + points[6][1] = 2; + points[7][0] = 7; /* In same chunk as point #3, but "earlier" in chunk */ + points[7][1] = 7; + ret = H5Sselect_elements(pnt2_space, H5S_SELECT_SET, (size_t)SPACE7_NPOINTS, (const hsize_t *)points); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Create 2nd hyperslab selection */ + hyp2_space = H5Scopy(dataspace); + CHECK(hyp2_space, FAIL, "H5Scopy"); + + start[0] = 2; + start[1] = 4; + count[0] = 4; + count[1] = 2; + ret = H5Sselect_hyperslab(hyp2_space, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Write out data using 2nd hyperslab selection for file & point for memory */ + ret = H5Dwrite(dataset, H5T_NATIVE_UINT, pnt2_space, hyp2_space, H5P_DEFAULT, data); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close everything (except selections) */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Sclose(dataspace); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + + /* Re-open file & dataset */ + file = H5Fopen(FILENAME, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(file, FAIL, "H5Fopen"); + dataset = H5Dopen2(file, DATASETNAME, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Read data using 1st point selection for file and hyperslab for memory */ + ret = H5Dread(dataset, H5T_NATIVE_UINT, hyp1_space, pnt1_space, H5P_DEFAULT, data_out); + CHECK(ret, FAIL, "H5Dread"); + + /* Verify data (later) */ + + /* Read data using 2nd hyperslab selection for file and point for memory */ + ret = H5Dread(dataset, H5T_NATIVE_UINT, pnt2_space, hyp2_space, H5P_DEFAULT, data_out); + CHECK(ret, FAIL, "H5Dread"); + + /* Verify data (later) */ + + /* Close everything (including selections) */ + ret = H5Sclose(pnt1_space); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(pnt2_space); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(hyp1_space); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(hyp2_space); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + + HDfree(data); + HDfree(data_out); +} /* test_select_point_chunk() */ + +/**************************************************************** +** +** test_select_sclar_chunk(): Test basic H5S (dataspace) selection code. +** Tests using a scalar dataspace (in memory) to access chunked datasets. +** +****************************************************************/ +static void +test_select_scalar_chunk(void) +{ + hid_t file_id; /* File ID */ + hid_t dcpl; /* Dataset creation property list */ + hid_t dsid; /* Dataset ID */ + hid_t sid; /* Dataspace ID */ + hid_t m_sid; /* Memory dataspace */ + hsize_t dims[] = {2}; /* Dataset dimensions */ + hsize_t maxdims[] = {H5S_UNLIMITED}; /* Dataset maximum dimensions */ + hsize_t offset[] = {0}; /* Hyperslab start */ + hsize_t count[] = {1}; /* Hyperslab count */ + unsigned data = 2; /* Data to write */ + herr_t ret; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Scalar Dataspaces and Chunked Datasets\n")); + + file_id = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file_id, FAIL, "H5Fcreate"); + + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + + dims[0] = 1024U; + ret = H5Pset_chunk(dcpl, 1, dims); + CHECK(ret, FAIL, "H5Pset_chunk"); + + /* Create 1-D dataspace */ + sid = H5Screate_simple(1, dims, maxdims); + CHECK(sid, FAIL, "H5Screate_simple"); + + dsid = H5Dcreate2(file_id, "dset", H5T_NATIVE_UINT, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dsid, FAIL, "H5Dcreate2"); + + /* Select scalar area (offset 0, count 1) */ + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, offset, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create scalar memory dataspace */ + m_sid = H5Screate(H5S_SCALAR); + CHECK(m_sid, FAIL, "H5Screate"); + + /* Write out data using scalar dataspace for memory dataspace */ + ret = H5Dwrite(dsid, H5T_NATIVE_UINT, m_sid, sid, H5P_DEFAULT, &data); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close resources */ + ret = H5Sclose(m_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Dclose(dsid); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Fclose(file_id); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_select_scalar_chunk() */ + +/**************************************************************** +** +** test_select_valid(): Test basic H5S (dataspace) selection code. +** Tests selection validity +** +****************************************************************/ +static void +test_select_valid(void) +{ + herr_t error; + htri_t valid; + hid_t main_space, sub_space; + hsize_t safe_start[2] = {1, 1}; + hsize_t safe_count[2] = {1, 1}; + hsize_t start[2]; + hsize_t dims[2], maxdims[2], size[2], count[2]; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Selection Validity\n")); + + MESSAGE(8, ("Case 1 : sub_space is not a valid dataspace\n")); + dims[0] = dims[1] = H5S_UNLIMITED; + + H5E_BEGIN_TRY + { + sub_space = H5Screate_simple(2, dims, NULL); + } + H5E_END_TRY; + VERIFY(sub_space, FAIL, "H5Screate_simple"); + + H5E_BEGIN_TRY + { + valid = H5Sselect_valid(sub_space); + } + H5E_END_TRY; + VERIFY(valid, FAIL, "H5Sselect_valid"); + + /* Set arrays and dataspace for the rest of the cases */ + count[0] = count[1] = 1; + dims[0] = dims[1] = maxdims[0] = maxdims[1] = 10; + + main_space = H5Screate_simple(2, dims, maxdims); + CHECK(main_space, FAIL, "H5Screate_simple"); + + MESSAGE(8, ("Case 2 : sub_space is a valid but closed dataspace\n")); + sub_space = H5Scopy(main_space); + CHECK(sub_space, FAIL, "H5Scopy"); + + error = H5Sclose(sub_space); + CHECK(error, FAIL, "H5Sclose"); + + H5E_BEGIN_TRY + { + valid = H5Sselect_valid(sub_space); + } + H5E_END_TRY; + VERIFY(valid, FAIL, "H5Sselect_valid"); + + MESSAGE(8, ("Case 3 : in the dimensions\nTry offset (4,4) and size(6,6), the original space is of size " + "(10,10)\n")); + start[0] = start[1] = 4; + size[0] = size[1] = 6; + + sub_space = H5Scopy(main_space); + CHECK(sub_space, FAIL, "H5Scopy"); + + error = H5Sselect_hyperslab(sub_space, H5S_SELECT_SET, start, size, count, size); + CHECK(error, FAIL, "H5Sselect_hyperslab"); + + valid = H5Sselect_valid(sub_space); + VERIFY(valid, TRUE, "H5Sselect_valid"); + + error = H5Sselect_hyperslab(sub_space, H5S_SELECT_OR, safe_start, NULL, safe_count, NULL); + CHECK(error, FAIL, "H5Sselect_hyperslab"); + + valid = H5Sselect_valid(sub_space); + VERIFY(valid, TRUE, "H5Sselect_valid"); + + error = H5Sclose(sub_space); + CHECK(error, FAIL, "H5Sclose"); + + MESSAGE(8, ("Case 4 : exceed dimensions by 1\nTry offset (5,5) and size(6,6), the original space is of " + "size (10,10)\n")); + start[0] = start[1] = 5; + size[0] = size[1] = 6; + + sub_space = H5Scopy(main_space); + CHECK(sub_space, FAIL, "H5Scopy"); + + error = H5Sselect_hyperslab(sub_space, H5S_SELECT_SET, start, size, count, size); + CHECK(error, FAIL, "H5Sselect_hyperslab"); + + valid = H5Sselect_valid(sub_space); + VERIFY(valid, FALSE, "H5Sselect_valid"); + + error = H5Sselect_hyperslab(sub_space, H5S_SELECT_OR, safe_start, NULL, safe_count, NULL); + CHECK(error, FAIL, "H5Sselect_hyperslab"); + + valid = H5Sselect_valid(sub_space); + VERIFY(valid, FALSE, "H5Sselect_valid"); + + error = H5Sclose(sub_space); + CHECK(error, FAIL, "H5Sclose"); + + MESSAGE(8, ("Case 5 : exceed dimensions by 2\nTry offset (6,6) and size(6,6), the original space is of " + "size (10,10)\n")); + start[0] = start[1] = 6; + size[0] = size[1] = 6; + + sub_space = H5Scopy(main_space); + CHECK(sub_space, FAIL, "H5Scopy"); + + error = H5Sselect_hyperslab(sub_space, H5S_SELECT_SET, start, size, count, size); + CHECK(error, FAIL, "H5Sselect_hyperslab"); + + valid = H5Sselect_valid(sub_space); + VERIFY(valid, FALSE, "H5Sselect_valid"); + + error = H5Sselect_hyperslab(sub_space, H5S_SELECT_OR, safe_start, NULL, safe_count, NULL); + CHECK(error, FAIL, "H5Sselect_hyperslab"); + + valid = H5Sselect_valid(sub_space); + VERIFY(valid, FALSE, "H5Sselect_valid"); + + error = H5Sclose(sub_space); + CHECK(error, FAIL, "H5Sclose"); + error = H5Sclose(main_space); + CHECK(error, FAIL, "H5Sclose"); +} /* test_select_valid() */ + +/**************************************************************** +** +** test_select_combine(): Test basic H5S (dataspace) selection code. +** Tests combining "all" and "none" selections with hyperslab +** operations. +** +****************************************************************/ +static void +test_select_combine(void) +{ + hid_t base_id; /* Base dataspace for test */ + hid_t all_id; /* Dataspace for "all" selection */ + hid_t none_id; /* Dataspace for "none" selection */ + hid_t space1; /* Temporary dataspace #1 */ + hsize_t start[SPACE7_RANK]; /* Hyperslab start */ + hsize_t stride[SPACE7_RANK]; /* Hyperslab stride */ + hsize_t count[SPACE7_RANK]; /* Hyperslab count */ + hsize_t block[SPACE7_RANK]; /* Hyperslab block */ + hsize_t dims[SPACE7_RANK] = {SPACE7_DIM1, SPACE7_DIM2}; /* Dimensions of dataspace */ + H5S_sel_type sel_type; /* Selection type */ + hssize_t nblocks; /* Number of hyperslab blocks */ + hsize_t blocks[16][2][SPACE7_RANK]; /* List of blocks */ + herr_t error; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Selection Combinations\n")); + + /* Create dataspace for dataset on disk */ + base_id = H5Screate_simple(SPACE7_RANK, dims, NULL); + CHECK(base_id, FAIL, "H5Screate_simple"); + + /* Copy base dataspace and set selection to "all" */ + all_id = H5Scopy(base_id); + CHECK(all_id, FAIL, "H5Scopy"); + error = H5Sselect_all(all_id); + CHECK(error, FAIL, "H5Sselect_all"); + sel_type = H5Sget_select_type(all_id); + VERIFY(sel_type, H5S_SEL_ALL, "H5Sget_select_type"); + + /* Copy base dataspace and set selection to "none" */ + none_id = H5Scopy(base_id); + CHECK(none_id, FAIL, "H5Scopy"); + error = H5Sselect_none(none_id); + CHECK(error, FAIL, "H5Sselect_none"); + sel_type = H5Sget_select_type(none_id); + VERIFY(sel_type, H5S_SEL_NONE, "H5Sget_select_type"); + + /* Copy "all" selection & space */ + space1 = H5Scopy(all_id); + CHECK(space1, FAIL, "H5Scopy"); + + /* 'OR' "all" selection with another hyperslab */ + start[0] = start[1] = 0; + stride[0] = stride[1] = 1; + count[0] = count[1] = 1; + block[0] = block[1] = 5; + error = H5Sselect_hyperslab(space1, H5S_SELECT_OR, start, stride, count, block); + CHECK(error, FAIL, "H5Sselect_hyperslab"); + + /* Verify that it's still "all" selection */ + sel_type = H5Sget_select_type(space1); + VERIFY(sel_type, H5S_SEL_ALL, "H5Sget_select_type"); + + /* Close temporary dataspace */ + error = H5Sclose(space1); + CHECK(error, FAIL, "H5Sclose"); + + /* Copy "all" selection & space */ + space1 = H5Scopy(all_id); + CHECK(space1, FAIL, "H5Scopy"); + + /* 'AND' "all" selection with another hyperslab */ + start[0] = start[1] = 0; + stride[0] = stride[1] = 1; + count[0] = count[1] = 1; + block[0] = block[1] = 5; + error = H5Sselect_hyperslab(space1, H5S_SELECT_AND, start, stride, count, block); + CHECK(error, FAIL, "H5Sselect_hyperslab"); + + /* Verify that the new selection is the same at the original block */ + sel_type = H5Sget_select_type(space1); + VERIFY(sel_type, H5S_SEL_HYPERSLABS, "H5Sget_select_type"); + + /* Verify that there is only one block */ + nblocks = H5Sget_select_hyper_nblocks(space1); + VERIFY(nblocks, 1, "H5Sget_select_hyper_nblocks"); + + /* Retrieve the block defined */ + HDmemset(blocks, -1, sizeof(blocks)); /* Reset block list */ + error = H5Sget_select_hyper_blocklist(space1, (hsize_t)0, (hsize_t)nblocks, (hsize_t *)blocks); + CHECK(error, FAIL, "H5Sget_select_hyper_blocklist"); + + /* Verify that the correct block is defined */ + VERIFY(blocks[0][0][0], (hsize_t)start[0], "H5Sget_select_hyper_blocklist"); + VERIFY(blocks[0][0][1], (hsize_t)start[1], "H5Sget_select_hyper_blocklist"); + VERIFY(blocks[0][1][0], (block[0] - 1), "H5Sget_select_hyper_blocklist"); + VERIFY(blocks[0][1][1], (block[1] - 1), "H5Sget_select_hyper_blocklist"); + + /* Close temporary dataspace */ + error = H5Sclose(space1); + CHECK(error, FAIL, "H5Sclose"); + + /* Copy "all" selection & space */ + space1 = H5Scopy(all_id); + CHECK(space1, FAIL, "H5Scopy"); + + /* 'XOR' "all" selection with another hyperslab */ + start[0] = start[1] = 0; + stride[0] = stride[1] = 1; + count[0] = count[1] = 1; + block[0] = block[1] = 5; + error = H5Sselect_hyperslab(space1, H5S_SELECT_XOR, start, stride, count, block); + CHECK(error, FAIL, "H5Sselect_hyperslab"); + + /* Verify that the new selection is an inversion of the original block */ + sel_type = H5Sget_select_type(space1); + VERIFY(sel_type, H5S_SEL_HYPERSLABS, "H5Sget_select_type"); + + /* Verify that there are two blocks */ + nblocks = H5Sget_select_hyper_nblocks(space1); + VERIFY(nblocks, 2, "H5Sget_select_hyper_nblocks"); + + /* Retrieve the block defined */ + HDmemset(blocks, -1, sizeof(blocks)); /* Reset block list */ + error = H5Sget_select_hyper_blocklist(space1, (hsize_t)0, (hsize_t)nblocks, (hsize_t *)blocks); + CHECK(error, FAIL, "H5Sget_select_hyper_blocklist"); + + /* Verify that the correct block is defined */ + VERIFY(blocks[0][0][0], 0, "H5Sget_select_hyper_blocklist"); + VERIFY(blocks[0][0][1], 5, "H5Sget_select_hyper_blocklist"); + VERIFY(blocks[0][1][0], 4, "H5Sget_select_hyper_blocklist"); + VERIFY(blocks[0][1][1], 9, "H5Sget_select_hyper_blocklist"); + VERIFY(blocks[1][0][0], 5, "H5Sget_select_hyper_blocklist"); + VERIFY(blocks[1][0][1], 0, "H5Sget_select_hyper_blocklist"); + VERIFY(blocks[1][1][0], 9, "H5Sget_select_hyper_blocklist"); + VERIFY(blocks[1][1][1], 9, "H5Sget_select_hyper_blocklist"); + + /* Close temporary dataspace */ + error = H5Sclose(space1); + CHECK(error, FAIL, "H5Sclose"); + + /* Copy "all" selection & space */ + space1 = H5Scopy(all_id); + CHECK(space1, FAIL, "H5Scopy"); + + /* 'NOTB' "all" selection with another hyperslab */ + start[0] = start[1] = 0; + stride[0] = stride[1] = 1; + count[0] = count[1] = 1; + block[0] = block[1] = 5; + error = H5Sselect_hyperslab(space1, H5S_SELECT_NOTB, start, stride, count, block); + CHECK(error, FAIL, "H5Sselect_hyperslab"); + + /* Verify that the new selection is an inversion of the original block */ + sel_type = H5Sget_select_type(space1); + VERIFY(sel_type, H5S_SEL_HYPERSLABS, "H5Sget_select_type"); + + /* Verify that there are two blocks */ + nblocks = H5Sget_select_hyper_nblocks(space1); + VERIFY(nblocks, 2, "H5Sget_select_hyper_nblocks"); + + /* Retrieve the block defined */ + HDmemset(blocks, -1, sizeof(blocks)); /* Reset block list */ + error = H5Sget_select_hyper_blocklist(space1, (hsize_t)0, (hsize_t)nblocks, (hsize_t *)blocks); + CHECK(error, FAIL, "H5Sget_select_hyper_blocklist"); + + /* Verify that the correct block is defined */ + VERIFY(blocks[0][0][0], 0, "H5Sget_select_hyper_blocklist"); + VERIFY(blocks[0][0][1], 5, "H5Sget_select_hyper_blocklist"); + VERIFY(blocks[0][1][0], 4, "H5Sget_select_hyper_blocklist"); + VERIFY(blocks[0][1][1], 9, "H5Sget_select_hyper_blocklist"); + VERIFY(blocks[1][0][0], 5, "H5Sget_select_hyper_blocklist"); + VERIFY(blocks[1][0][1], 0, "H5Sget_select_hyper_blocklist"); + VERIFY(blocks[1][1][0], 9, "H5Sget_select_hyper_blocklist"); + VERIFY(blocks[1][1][1], 9, "H5Sget_select_hyper_blocklist"); + + /* Close temporary dataspace */ + error = H5Sclose(space1); + CHECK(error, FAIL, "H5Sclose"); + + /* Copy "all" selection & space */ + space1 = H5Scopy(all_id); + CHECK(space1, FAIL, "H5Scopy"); + + /* 'NOTA' "all" selection with another hyperslab */ + start[0] = start[1] = 0; + stride[0] = stride[1] = 1; + count[0] = count[1] = 1; + block[0] = block[1] = 5; + error = H5Sselect_hyperslab(space1, H5S_SELECT_NOTA, start, stride, count, block); + CHECK(error, FAIL, "H5Sselect_hyperslab"); + + /* Verify that the new selection is the "none" selection */ + sel_type = H5Sget_select_type(space1); + VERIFY(sel_type, H5S_SEL_NONE, "H5Sget_select_type"); + + /* Close temporary dataspace */ + error = H5Sclose(space1); + CHECK(error, FAIL, "H5Sclose"); + + /* Copy "none" selection & space */ + space1 = H5Scopy(none_id); + CHECK(space1, FAIL, "H5Scopy"); + + /* 'OR' "none" selection with another hyperslab */ + start[0] = start[1] = 0; + stride[0] = stride[1] = 1; + count[0] = count[1] = 1; + block[0] = block[1] = 5; + error = H5Sselect_hyperslab(space1, H5S_SELECT_OR, start, stride, count, block); + CHECK(error, FAIL, "H5Sselect_hyperslab"); + + /* Verify that the new selection is the same as the original hyperslab */ + sel_type = H5Sget_select_type(space1); + VERIFY(sel_type, H5S_SEL_HYPERSLABS, "H5Sget_select_type"); + + /* Verify that there is only one block */ + nblocks = H5Sget_select_hyper_nblocks(space1); + VERIFY(nblocks, 1, "H5Sget_select_hyper_nblocks"); + + /* Retrieve the block defined */ + HDmemset(blocks, -1, sizeof(blocks)); /* Reset block list */ + error = H5Sget_select_hyper_blocklist(space1, (hsize_t)0, (hsize_t)nblocks, (hsize_t *)blocks); + CHECK(error, FAIL, "H5Sget_select_hyper_blocklist"); + + /* Verify that the correct block is defined */ + VERIFY(blocks[0][0][0], (hsize_t)start[0], "H5Sget_select_hyper_blocklist"); + VERIFY(blocks[0][0][1], (hsize_t)start[1], "H5Sget_select_hyper_blocklist"); + VERIFY(blocks[0][1][0], (block[0] - 1), "H5Sget_select_hyper_blocklist"); + VERIFY(blocks[0][1][1], (block[1] - 1), "H5Sget_select_hyper_blocklist"); + + /* Close temporary dataspace */ + error = H5Sclose(space1); + CHECK(error, FAIL, "H5Sclose"); + + /* Copy "none" selection & space */ + space1 = H5Scopy(none_id); + CHECK(space1, FAIL, "H5Scopy"); + + /* 'AND' "none" selection with another hyperslab */ + start[0] = start[1] = 0; + stride[0] = stride[1] = 1; + count[0] = count[1] = 1; + block[0] = block[1] = 5; + error = H5Sselect_hyperslab(space1, H5S_SELECT_AND, start, stride, count, block); + CHECK(error, FAIL, "H5Sselect_hyperslab"); + + /* Verify that the new selection is the "none" selection */ + sel_type = H5Sget_select_type(space1); + VERIFY(sel_type, H5S_SEL_NONE, "H5Sget_select_type"); + + /* Close temporary dataspace */ + error = H5Sclose(space1); + CHECK(error, FAIL, "H5Sclose"); + + /* Copy "none" selection & space */ + space1 = H5Scopy(none_id); + CHECK(space1, FAIL, "H5Scopy"); + + /* 'XOR' "none" selection with another hyperslab */ + start[0] = start[1] = 0; + stride[0] = stride[1] = 1; + count[0] = count[1] = 1; + block[0] = block[1] = 5; + error = H5Sselect_hyperslab(space1, H5S_SELECT_XOR, start, stride, count, block); + CHECK(error, FAIL, "H5Sselect_hyperslab"); + + /* Verify that the new selection is the same as the original hyperslab */ + sel_type = H5Sget_select_type(space1); + VERIFY(sel_type, H5S_SEL_HYPERSLABS, "H5Sget_select_type"); + + /* Verify that there is only one block */ + nblocks = H5Sget_select_hyper_nblocks(space1); + VERIFY(nblocks, 1, "H5Sget_select_hyper_nblocks"); + + /* Retrieve the block defined */ + HDmemset(blocks, -1, sizeof(blocks)); /* Reset block list */ + error = H5Sget_select_hyper_blocklist(space1, (hsize_t)0, (hsize_t)nblocks, (hsize_t *)blocks); + CHECK(error, FAIL, "H5Sget_select_hyper_blocklist"); + + /* Verify that the correct block is defined */ + VERIFY(blocks[0][0][0], (hsize_t)start[0], "H5Sget_select_hyper_blocklist"); + VERIFY(blocks[0][0][1], (hsize_t)start[1], "H5Sget_select_hyper_blocklist"); + VERIFY(blocks[0][1][0], (block[0] - 1), "H5Sget_select_hyper_blocklist"); + VERIFY(blocks[0][1][1], (block[1] - 1), "H5Sget_select_hyper_blocklist"); + + /* Close temporary dataspace */ + error = H5Sclose(space1); + CHECK(error, FAIL, "H5Sclose"); + + /* Copy "none" selection & space */ + space1 = H5Scopy(none_id); + CHECK(space1, FAIL, "H5Scopy"); + + /* 'NOTB' "none" selection with another hyperslab */ + start[0] = start[1] = 0; + stride[0] = stride[1] = 1; + count[0] = count[1] = 1; + block[0] = block[1] = 5; + error = H5Sselect_hyperslab(space1, H5S_SELECT_NOTB, start, stride, count, block); + CHECK(error, FAIL, "H5Sselect_hyperslab"); + + /* Verify that the new selection is the "none" selection */ + sel_type = H5Sget_select_type(space1); + VERIFY(sel_type, H5S_SEL_NONE, "H5Sget_select_type"); + + /* Close temporary dataspace */ + error = H5Sclose(space1); + CHECK(error, FAIL, "H5Sclose"); + + /* Copy "none" selection & space */ + space1 = H5Scopy(none_id); + CHECK(space1, FAIL, "H5Scopy"); + + /* 'NOTA' "none" selection with another hyperslab */ + start[0] = start[1] = 0; + stride[0] = stride[1] = 1; + count[0] = count[1] = 1; + block[0] = block[1] = 5; + error = H5Sselect_hyperslab(space1, H5S_SELECT_NOTA, start, stride, count, block); + CHECK(error, FAIL, "H5Sselect_hyperslab"); + + /* Verify that the new selection is the same as the original hyperslab */ + sel_type = H5Sget_select_type(space1); + VERIFY(sel_type, H5S_SEL_HYPERSLABS, "H5Sget_select_type"); + + /* Verify that there is only one block */ + nblocks = H5Sget_select_hyper_nblocks(space1); + VERIFY(nblocks, 1, "H5Sget_select_hyper_nblocks"); + + /* Retrieve the block defined */ + HDmemset(blocks, -1, sizeof(blocks)); /* Reset block list */ + error = H5Sget_select_hyper_blocklist(space1, (hsize_t)0, (hsize_t)nblocks, (hsize_t *)blocks); + CHECK(error, FAIL, "H5Sget_select_hyper_blocklist"); + + /* Verify that the correct block is defined */ + VERIFY(blocks[0][0][0], (hsize_t)start[0], "H5Sget_select_hyper_blocklist"); + VERIFY(blocks[0][0][1], (hsize_t)start[1], "H5Sget_select_hyper_blocklist"); + VERIFY(blocks[0][1][0], (block[0] - 1), "H5Sget_select_hyper_blocklist"); + VERIFY(blocks[0][1][1], (block[1] - 1), "H5Sget_select_hyper_blocklist"); + + /* Close temporary dataspace */ + error = H5Sclose(space1); + CHECK(error, FAIL, "H5Sclose"); + + /* Close dataspaces */ + error = H5Sclose(base_id); + CHECK(error, FAIL, "H5Sclose"); + + error = H5Sclose(all_id); + CHECK(error, FAIL, "H5Sclose"); + + error = H5Sclose(none_id); + CHECK(error, FAIL, "H5Sclose"); +} /* test_select_combine() */ + +/* + * Typedef for iteration structure used in the fill value tests + */ +typedef struct { + unsigned short fill_value; /* The fill value to check */ + size_t curr_coord; /* Current coordinate to examine */ + hsize_t *coords; /* Pointer to selection's coordinates */ +} fill_iter_info; + +/**************************************************************** +** +** test_select_hyper_iter3(): Iterator for checking hyperslab iteration +** +****************************************************************/ +static herr_t +test_select_hyper_iter3(void *_elem, hid_t H5_ATTR_UNUSED type_id, unsigned ndim, const hsize_t *point, + void *_operator_data) +{ + unsigned *tbuf = (unsigned *)_elem; /* temporary buffer pointer */ + fill_iter_info *iter_info = + (fill_iter_info *)_operator_data; /* Get the pointer to the iterator information */ + hsize_t *coord_ptr; /* Pointer to the coordinate information for a point*/ + + /* Check value in current buffer location */ + if (*tbuf != iter_info->fill_value) + return (-1); + else { + /* Check number of dimensions */ + if (ndim != SPACE7_RANK) + return (-1); + else { + /* Check Coordinates */ + coord_ptr = iter_info->coords + (2 * iter_info->curr_coord); + iter_info->curr_coord++; + if (coord_ptr[0] != point[0]) + return (-1); + else if (coord_ptr[1] != point[1]) + return (-1); + else + return (0); + } /* end else */ + } /* end else */ +} /* end test_select_hyper_iter3() */ + +/**************************************************************** +** +** test_select_fill_all(): Test basic H5S (dataspace) selection code. +** Tests filling "all" selections +** +****************************************************************/ +static void +test_select_fill_all(void) +{ + hid_t sid1; /* Dataspace ID */ + hsize_t dims1[] = {SPACE7_DIM1, SPACE7_DIM2}; + unsigned fill_value; /* Fill value */ + fill_iter_info iter_info; /* Iterator information structure */ + hsize_t points[SPACE7_DIM1 * SPACE7_DIM2][SPACE7_RANK]; /* Coordinates of selection */ + unsigned *wbuf, /* buffer to write to disk */ + *tbuf; /* temporary buffer pointer */ + unsigned u, v; /* Counters */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Filling 'all' Selections\n")); + + /* Allocate memory buffer */ + wbuf = (unsigned *)HDmalloc(sizeof(unsigned) * SPACE7_DIM1 * SPACE7_DIM2); + CHECK_PTR(wbuf, "HDmalloc"); + + /* Initialize memory buffer */ + for (u = 0, tbuf = wbuf; u < SPACE7_DIM1; u++) + for (v = 0; v < SPACE7_DIM2; v++) + *tbuf++ = (u * SPACE7_DIM2) + v; + + /* Create dataspace for dataset on disk */ + sid1 = H5Screate_simple(SPACE7_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Space defaults to "all" selection */ + + /* Set fill value */ + fill_value = SPACE7_FILL; + + /* Fill selection in memory */ + ret = H5Dfill(&fill_value, H5T_NATIVE_UINT, wbuf, H5T_NATIVE_UINT, sid1); + CHECK(ret, FAIL, "H5Dfill"); + + /* Verify memory buffer the hard way... */ + for (u = 0, tbuf = wbuf; u < SPACE7_DIM1; u++) + for (v = 0; v < SPACE7_DIM2; v++) + if (*tbuf != fill_value) + TestErrPrintf("Error! v=%d, u=%u, *tbuf=%u, fill_value=%u\n", v, u, *tbuf, fill_value); + + /* Set the coordinates of the selection */ + for (u = 0; u < SPACE7_DIM1; u++) + for (v = 0; v < SPACE7_DIM2; v++) { + points[(u * SPACE7_DIM2) + v][0] = u; + points[(u * SPACE7_DIM2) + v][1] = v; + } /* end for */ + + /* Initialize the iterator structure */ + iter_info.fill_value = SPACE7_FILL; + iter_info.curr_coord = 0; + iter_info.coords = (hsize_t *)points; + + /* Iterate through selection, verifying correct data */ + ret = H5Diterate(wbuf, H5T_NATIVE_UINT, sid1, test_select_hyper_iter3, &iter_info); + CHECK(ret, FAIL, "H5Diterate"); + + /* Close dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Free memory buffers */ + HDfree(wbuf); +} /* test_select_fill_all() */ + +/**************************************************************** +** +** test_select_fill_point(): Test basic H5S (dataspace) selection code. +** Tests filling "point" selections +** +****************************************************************/ +static void +test_select_fill_point(hssize_t *offset) +{ + hid_t sid1; /* Dataspace ID */ + hsize_t dims1[] = {SPACE7_DIM1, SPACE7_DIM2}; + hssize_t real_offset[SPACE7_RANK]; /* Actual offset to use */ + hsize_t points[5][SPACE7_RANK] = {{2, 4}, {3, 8}, {8, 4}, {7, 5}, {7, 7}}; + size_t num_points = 5; /* Number of points selected */ + int fill_value; /* Fill value */ + fill_iter_info iter_info; /* Iterator information structure */ + unsigned *wbuf, /* buffer to write to disk */ + *tbuf; /* temporary buffer pointer */ + unsigned u, v, w; /* Counters */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Filling 'point' Selections\n")); + + /* Allocate memory buffer */ + wbuf = (unsigned *)HDmalloc(sizeof(unsigned) * SPACE7_DIM1 * SPACE7_DIM2); + CHECK_PTR(wbuf, "HDmalloc"); + + /* Initialize memory buffer */ + for (u = 0, tbuf = wbuf; u < SPACE7_DIM1; u++) + for (v = 0; v < SPACE7_DIM2; v++) + *tbuf++ = (unsigned short)(u * SPACE7_DIM2) + v; + + /* Create dataspace for dataset on disk */ + sid1 = H5Screate_simple(SPACE7_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Select "point" selection */ + ret = H5Sselect_elements(sid1, H5S_SELECT_SET, num_points, (const hsize_t *)points); + CHECK(ret, FAIL, "H5Sselect_elements"); + + if (offset != NULL) { + HDmemcpy(real_offset, offset, SPACE7_RANK * sizeof(hssize_t)); + + /* Set offset, if provided */ + ret = H5Soffset_simple(sid1, real_offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + } /* end if */ + else + HDmemset(real_offset, 0, SPACE7_RANK * sizeof(hssize_t)); + + /* Set fill value */ + fill_value = SPACE7_FILL; + + /* Fill selection in memory */ + ret = H5Dfill(&fill_value, H5T_NATIVE_INT, wbuf, H5T_NATIVE_UINT, sid1); + CHECK(ret, FAIL, "H5Dfill"); + + /* Verify memory buffer the hard way... */ + for (u = 0, tbuf = wbuf; u < SPACE7_DIM1; u++) + for (v = 0; v < SPACE7_DIM2; v++, tbuf++) { + for (w = 0; w < (unsigned)num_points; w++) { + if (u == (unsigned)(points[w][0] + (hsize_t)real_offset[0]) && + v == (unsigned)(points[w][1] + (hsize_t)real_offset[1])) { + if (*tbuf != (unsigned)fill_value) + TestErrPrintf("Error! v=%u, u=%u, *tbuf=%u, fill_value=%u\n", v, u, *tbuf, + (unsigned)fill_value); + break; + } /* end if */ + } /* end for */ + if (w == (unsigned)num_points && *tbuf != ((u * SPACE7_DIM2) + v)) + TestErrPrintf("Error! v=%d, u=%d, *tbuf=%u, should be: %u\n", v, u, *tbuf, + ((u * SPACE7_DIM2) + v)); + } /* end for */ + + /* Initialize the iterator structure */ + iter_info.fill_value = SPACE7_FILL; + iter_info.curr_coord = 0; + iter_info.coords = (hsize_t *)points; + + /* Add in the offset */ + for (u = 0; u < (unsigned)num_points; u++) { + points[u][0] = (hsize_t)((hssize_t)points[u][0] + real_offset[0]); + points[u][1] = (hsize_t)((hssize_t)points[u][1] + real_offset[1]); + } /* end for */ + + /* Iterate through selection, verifying correct data */ + ret = H5Diterate(wbuf, H5T_NATIVE_UINT, sid1, test_select_hyper_iter3, &iter_info); + CHECK(ret, FAIL, "H5Diterate"); + + /* Close dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Free memory buffers */ + HDfree(wbuf); +} /* test_select_fill_point() */ + +/**************************************************************** +** +** test_select_fill_hyper_simple(): Test basic H5S (dataspace) selection code. +** Tests filling "simple" (i.e. one block) hyperslab selections +** +****************************************************************/ +static void +test_select_fill_hyper_simple(hssize_t *offset) +{ + hid_t sid1; /* Dataspace ID */ + hsize_t dims1[] = {SPACE7_DIM1, SPACE7_DIM2}; + hssize_t real_offset[SPACE7_RANK]; /* Actual offset to use */ + hsize_t start[SPACE7_RANK]; /* Hyperslab start */ + hsize_t count[SPACE7_RANK]; /* Hyperslab block size */ + size_t num_points; /* Number of points in selection */ + hsize_t points[16][SPACE7_RANK]; /* Coordinates selected */ + int fill_value; /* Fill value */ + fill_iter_info iter_info; /* Iterator information structure */ + unsigned *wbuf, /* buffer to write to disk */ + *tbuf; /* temporary buffer pointer */ + unsigned u, v; /* Counters */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Filling Simple 'hyperslab' Selections\n")); + + /* Allocate memory buffer */ + wbuf = (unsigned *)HDmalloc(sizeof(unsigned) * SPACE7_DIM1 * SPACE7_DIM2); + CHECK_PTR(wbuf, "HDmalloc"); + + /* Initialize memory buffer */ + for (u = 0, tbuf = wbuf; u < SPACE7_DIM1; u++) + for (v = 0; v < SPACE7_DIM2; v++) + *tbuf++ = (unsigned short)(u * SPACE7_DIM2) + v; + + /* Create dataspace for dataset on disk */ + sid1 = H5Screate_simple(SPACE7_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Select "hyperslab" selection */ + start[0] = 3; + start[1] = 3; + count[0] = 4; + count[1] = 4; + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + if (offset != NULL) { + HDmemcpy(real_offset, offset, SPACE7_RANK * sizeof(hssize_t)); + + /* Set offset, if provided */ + ret = H5Soffset_simple(sid1, real_offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + } /* end if */ + else + HDmemset(real_offset, 0, SPACE7_RANK * sizeof(hssize_t)); + + /* Set fill value */ + fill_value = SPACE7_FILL; + + /* Fill selection in memory */ + ret = H5Dfill(&fill_value, H5T_NATIVE_INT, wbuf, H5T_NATIVE_UINT, sid1); + CHECK(ret, FAIL, "H5Dfill"); + + /* Verify memory buffer the hard way... */ + for (u = 0, tbuf = wbuf; u < SPACE7_DIM1; u++) + for (v = 0; v < SPACE7_DIM2; v++, tbuf++) { + if ((u >= (unsigned)((hssize_t)start[0] + real_offset[0]) && + u < (unsigned)((hssize_t)(start[0] + count[0]) + real_offset[0])) && + (v >= (unsigned)((hssize_t)start[1] + real_offset[1]) && + v < (unsigned)((hssize_t)(start[1] + count[1]) + real_offset[1]))) { + if (*tbuf != (unsigned)fill_value) + TestErrPrintf("Error! v=%u, u=%u, *tbuf=%u, fill_value=%u\n", v, u, *tbuf, + (unsigned)fill_value); + } /* end if */ + else { + if (*tbuf != ((unsigned)(u * SPACE7_DIM2) + v)) + TestErrPrintf("Error! v=%u, u=%u, *tbuf=%u, should be: %u\n", v, u, *tbuf, + ((u * SPACE7_DIM2) + v)); + } /* end else */ + } /* end for */ + + /* Initialize the iterator structure */ + iter_info.fill_value = SPACE7_FILL; + iter_info.curr_coord = 0; + iter_info.coords = (hsize_t *)points; + + /* Set the coordinates of the selection (with the offset) */ + for (u = 0, num_points = 0; u < (unsigned)count[0]; u++) + for (v = 0; v < (unsigned)count[1]; v++, num_points++) { + points[num_points][0] = (hsize_t)((hssize_t)(u + start[0]) + real_offset[0]); + points[num_points][1] = (hsize_t)((hssize_t)(v + start[1]) + real_offset[1]); + } /* end for */ + + /* Iterate through selection, verifying correct data */ + ret = H5Diterate(wbuf, H5T_NATIVE_UINT, sid1, test_select_hyper_iter3, &iter_info); + CHECK(ret, FAIL, "H5Diterate"); + + /* Close dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Free memory buffers */ + HDfree(wbuf); +} /* test_select_fill_hyper_simple() */ + +/**************************************************************** +** +** test_select_fill_hyper_regular(): Test basic H5S (dataspace) selection code. +** Tests filling "regular" (i.e. strided block) hyperslab selections +** +****************************************************************/ +static void +test_select_fill_hyper_regular(hssize_t *offset) +{ + hid_t sid1; /* Dataspace ID */ + hsize_t dims1[] = {SPACE7_DIM1, SPACE7_DIM2}; + hssize_t real_offset[SPACE7_RANK]; /* Actual offset to use */ + hsize_t start[SPACE7_RANK]; /* Hyperslab start */ + hsize_t stride[SPACE7_RANK]; /* Hyperslab stride size */ + hsize_t count[SPACE7_RANK]; /* Hyperslab block count */ + hsize_t block[SPACE7_RANK]; /* Hyperslab block size */ + hsize_t points[16][SPACE7_RANK] = { + {2, 2}, {2, 3}, {2, 6}, {2, 7}, {3, 2}, {3, 3}, {3, 6}, {3, 7}, + {6, 2}, {6, 3}, {6, 6}, {6, 7}, {7, 2}, {7, 3}, {7, 6}, {7, 7}, + }; + size_t num_points = 16; /* Number of points selected */ + int fill_value; /* Fill value */ + fill_iter_info iter_info; /* Iterator information structure */ + unsigned *wbuf, /* buffer to write to disk */ + *tbuf; /* temporary buffer pointer */ + unsigned u, v, w; /* Counters */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Filling Regular 'hyperslab' Selections\n")); + + /* Allocate memory buffer */ + wbuf = (unsigned *)HDmalloc(sizeof(unsigned) * SPACE7_DIM1 * SPACE7_DIM2); + CHECK_PTR(wbuf, "HDmalloc"); + + /* Initialize memory buffer */ + for (u = 0, tbuf = wbuf; u < SPACE7_DIM1; u++) + for (v = 0; v < SPACE7_DIM2; v++) + *tbuf++ = (u * SPACE7_DIM2) + v; + + /* Create dataspace for dataset on disk */ + sid1 = H5Screate_simple(SPACE7_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Select "hyperslab" selection */ + start[0] = 2; + start[1] = 2; + stride[0] = 4; + stride[1] = 4; + count[0] = 2; + count[1] = 2; + block[0] = 2; + block[1] = 2; + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + if (offset != NULL) { + HDmemcpy(real_offset, offset, SPACE7_RANK * sizeof(hssize_t)); + + /* Set offset, if provided */ + ret = H5Soffset_simple(sid1, real_offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + } /* end if */ + else + HDmemset(real_offset, 0, SPACE7_RANK * sizeof(hssize_t)); + + /* Set fill value */ + fill_value = SPACE7_FILL; + + /* Fill selection in memory */ + ret = H5Dfill(&fill_value, H5T_NATIVE_INT, wbuf, H5T_NATIVE_UINT, sid1); + CHECK(ret, FAIL, "H5Dfill"); + + /* Verify memory buffer the hard way... */ + for (u = 0, tbuf = wbuf; u < SPACE7_DIM1; u++) + for (v = 0; v < SPACE7_DIM2; v++, tbuf++) { + for (w = 0; w < (unsigned)num_points; w++) { + if (u == (unsigned)((hssize_t)points[w][0] + real_offset[0]) && + v == (unsigned)((hssize_t)points[w][1] + real_offset[1])) { + if (*tbuf != (unsigned)fill_value) + TestErrPrintf("Error! v=%u, u=%u, *tbuf=%u, fill_value=%u\n", v, u, *tbuf, + (unsigned)fill_value); + break; + } /* end if */ + } /* end for */ + if (w == (unsigned)num_points && *tbuf != ((u * SPACE7_DIM2) + v)) + TestErrPrintf("Error! v=%d, u=%d, *tbuf=%u, should be: %u\n", v, u, *tbuf, + ((u * SPACE7_DIM2) + v)); + } /* end for */ + + /* Initialize the iterator structure */ + iter_info.fill_value = SPACE7_FILL; + iter_info.curr_coord = 0; + iter_info.coords = (hsize_t *)points; + + /* Add in the offset */ + for (u = 0; u < (unsigned)num_points; u++) { + points[u][0] = (hsize_t)((hssize_t)points[u][0] + real_offset[0]); + points[u][1] = (hsize_t)((hssize_t)points[u][1] + real_offset[1]); + } /* end for */ + + /* Iterate through selection, verifying correct data */ + ret = H5Diterate(wbuf, H5T_NATIVE_UINT, sid1, test_select_hyper_iter3, &iter_info); + CHECK(ret, FAIL, "H5Diterate"); + + /* Close dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Free memory buffers */ + HDfree(wbuf); +} /* test_select_fill_hyper_regular() */ + +/**************************************************************** +** +** test_select_fill_hyper_irregular(): Test basic H5S (dataspace) selection code. +** Tests filling "irregular" (i.e. combined blocks) hyperslab selections +** +****************************************************************/ +static void +test_select_fill_hyper_irregular(hssize_t *offset) +{ + hid_t sid1; /* Dataspace ID */ + hsize_t dims1[] = {SPACE7_DIM1, SPACE7_DIM2}; + hssize_t real_offset[SPACE7_RANK]; /* Actual offset to use */ + hsize_t start[SPACE7_RANK]; /* Hyperslab start */ + hsize_t count[SPACE7_RANK]; /* Hyperslab block count */ + hsize_t points[32][SPACE7_RANK] = { + /* Yes, some of the are duplicated.. */ + {2, 2}, {2, 3}, {2, 4}, {2, 5}, {3, 2}, {3, 3}, {3, 4}, {3, 5}, {4, 2}, {4, 3}, {4, 4}, + {4, 5}, {5, 2}, {5, 3}, {5, 4}, {5, 5}, {4, 4}, {4, 5}, {4, 6}, {4, 7}, {5, 4}, {5, 5}, + {5, 6}, {5, 7}, {6, 4}, {6, 5}, {6, 6}, {6, 7}, {7, 4}, {7, 5}, {7, 6}, {7, 7}, + }; + hsize_t iter_points[28][SPACE7_RANK] = { + /* Coordinates, as iterated through */ + {2, 2}, {2, 3}, {2, 4}, {2, 5}, {3, 2}, {3, 3}, {3, 4}, {3, 5}, {4, 2}, {4, 3}, + {4, 4}, {4, 5}, {4, 6}, {4, 7}, {5, 2}, {5, 3}, {5, 4}, {5, 5}, {5, 6}, {5, 7}, + {6, 4}, {6, 5}, {6, 6}, {6, 7}, {7, 4}, {7, 5}, {7, 6}, {7, 7}, + }; + size_t num_points = 32; /* Number of points selected */ + size_t num_iter_points = 28; /* Number of resulting points */ + int fill_value; /* Fill value */ + fill_iter_info iter_info; /* Iterator information structure */ + unsigned *wbuf, /* buffer to write to disk */ + *tbuf; /* temporary buffer pointer */ + unsigned u, v, w; /* Counters */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Filling Irregular 'hyperslab' Selections\n")); + + /* Allocate memory buffer */ + wbuf = (unsigned *)HDmalloc(sizeof(unsigned) * SPACE7_DIM1 * SPACE7_DIM2); + CHECK_PTR(wbuf, "HDmalloc"); + + /* Initialize memory buffer */ + for (u = 0, tbuf = wbuf; u < SPACE7_DIM1; u++) + for (v = 0; v < SPACE7_DIM2; v++) + *tbuf++ = (u * SPACE7_DIM2) + v; + + /* Create dataspace for dataset on disk */ + sid1 = H5Screate_simple(SPACE7_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Select first "hyperslab" selection */ + start[0] = 2; + start[1] = 2; + count[0] = 4; + count[1] = 4; + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Combine with second "hyperslab" selection */ + start[0] = 4; + start[1] = 4; + count[0] = 4; + count[1] = 4; + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_OR, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + if (offset != NULL) { + HDmemcpy(real_offset, offset, SPACE7_RANK * sizeof(hssize_t)); + + /* Set offset, if provided */ + ret = H5Soffset_simple(sid1, real_offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + } /* end if */ + else + HDmemset(real_offset, 0, SPACE7_RANK * sizeof(hssize_t)); + + /* Set fill value */ + fill_value = SPACE7_FILL; + + /* Fill selection in memory */ + ret = H5Dfill(&fill_value, H5T_NATIVE_INT, wbuf, H5T_NATIVE_UINT, sid1); + CHECK(ret, FAIL, "H5Dfill"); + + /* Verify memory buffer the hard way... */ + for (u = 0, tbuf = wbuf; u < SPACE7_DIM1; u++) + for (v = 0; v < SPACE7_DIM2; v++, tbuf++) { + for (w = 0; w < (unsigned)num_points; w++) { + if (u == (unsigned)((hssize_t)points[w][0] + real_offset[0]) && + v == (unsigned)((hssize_t)points[w][1] + real_offset[1])) { + if (*tbuf != (unsigned)fill_value) + TestErrPrintf("Error! v=%u, u=%u, *tbuf=%u, fill_value=%u\n", v, u, *tbuf, + (unsigned)fill_value); + break; + } /* end if */ + } /* end for */ + if (w == (unsigned)num_points && *tbuf != ((u * SPACE7_DIM2) + v)) + TestErrPrintf("Error! v=%u, u=%u, *tbuf=%u, should be: %u\n", v, u, *tbuf, + ((u * SPACE7_DIM2) + v)); + } /* end for */ + + /* Initialize the iterator structure */ + iter_info.fill_value = SPACE7_FILL; + iter_info.curr_coord = 0; + iter_info.coords = (hsize_t *)iter_points; + + /* Add in the offset */ + for (u = 0; u < (unsigned)num_iter_points; u++) { + iter_points[u][0] = (hsize_t)((hssize_t)iter_points[u][0] + real_offset[0]); + iter_points[u][1] = (hsize_t)((hssize_t)iter_points[u][1] + real_offset[1]); + } /* end for */ + + /* Iterate through selection, verifying correct data */ + ret = H5Diterate(wbuf, H5T_NATIVE_UINT, sid1, test_select_hyper_iter3, &iter_info); + CHECK(ret, FAIL, "H5Diterate"); + + /* Close dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Free memory buffers */ + HDfree(wbuf); +} /* test_select_fill_hyper_irregular() */ + +/**************************************************************** +** +** test_select_none(): Test basic H5S (dataspace) selection code. +** Tests I/O on 0-sized point selections +** +****************************************************************/ +static void +test_select_none(void) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1, sid2; /* Dataspace ID */ + hsize_t dims1[] = {SPACE7_DIM1, SPACE7_DIM2}; + hsize_t dims2[] = {SPACE7_DIM1, SPACE7_DIM2}; + uint8_t *wbuf, /* buffer to write to disk */ + *rbuf, /* buffer to read from disk */ + *tbuf; /* temporary buffer pointer */ + int i, j; /* Counters */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing I/O on 0-sized Selections\n")); + + /* Allocate write & read buffers */ + wbuf = (uint8_t *)HDmalloc(sizeof(uint8_t) * SPACE7_DIM1 * SPACE7_DIM2); + CHECK_PTR(wbuf, "HDmalloc"); + rbuf = (uint8_t *)HDcalloc(sizeof(uint8_t), SPACE7_DIM1 * SPACE7_DIM2); + CHECK_PTR(rbuf, "HDcalloc"); + + /* Initialize write buffer */ + for (i = 0, tbuf = wbuf; i < SPACE7_DIM1; i++) + for (j = 0; j < SPACE7_DIM2; j++) + *tbuf++ = (uint8_t)((i * SPACE7_DIM2) + j); + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset */ + sid1 = H5Screate_simple(SPACE7_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create dataspace for writing buffer */ + sid2 = H5Screate_simple(SPACE7_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, "Dataset1", H5T_NATIVE_UCHAR, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Make "none" selection in both disk and memory datasets */ + ret = H5Sselect_none(sid1); + CHECK(ret, FAIL, "H5Sselect_none"); + + ret = H5Sselect_none(sid2); + CHECK(ret, FAIL, "H5Sselect_none"); + + /* Attempt to read "nothing" from disk (before space is allocated) */ + ret = H5Dread(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Write "nothing" to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Write "nothing" to disk (with a datatype conversion :-) */ + ret = H5Dwrite(dataset, H5T_NATIVE_INT, sid2, sid1, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Write "nothing" to disk (with NULL buffer argument) */ + ret = H5Dwrite(dataset, H5T_NATIVE_INT, sid2, sid1, H5P_DEFAULT, NULL); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Read "nothing" from disk (with NULL buffer argument) */ + ret = H5Dread(dataset, H5T_NATIVE_INT, sid2, sid1, H5P_DEFAULT, NULL); + CHECK(ret, FAIL, "H5Dread"); + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free memory buffers */ + HDfree(wbuf); + HDfree(rbuf); +} /* test_select_none() */ + +/**************************************************************** +** +** test_scalar_select(): Test basic H5S (dataspace) selection code. +** Tests selections on scalar dataspaces +** +****************************************************************/ +static void +test_scalar_select(void) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1, sid2; /* Dataspace ID */ + hsize_t dims2[] = {SPACE7_DIM1, SPACE7_DIM2}; + hsize_t coord1[SPACE7_RANK]; /* Coordinates for point selection */ + hsize_t start[SPACE7_RANK]; /* Hyperslab start */ + hsize_t count[SPACE7_RANK]; /* Hyperslab block count */ + uint8_t *wbuf_uint8, /* buffer to write to disk */ + rval_uint8, /* value read back in */ + *tbuf_uint8; /* temporary buffer pointer */ + unsigned short *wbuf_ushort, /* another buffer to write to disk */ + rval_ushort, /* value read back in */ + *tbuf_ushort; /* temporary buffer pointer */ + int i, j; /* Counters */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing I/O on Selections in Scalar Dataspaces\n")); + + /* Allocate write & read buffers */ + wbuf_uint8 = (uint8_t *)HDmalloc(sizeof(uint8_t) * SPACE7_DIM1 * SPACE7_DIM2); + CHECK_PTR(wbuf_uint8, "HDmalloc"); + wbuf_ushort = (unsigned short *)HDmalloc(sizeof(unsigned short) * SPACE7_DIM1 * SPACE7_DIM2); + CHECK_PTR(wbuf_ushort, "HDmalloc"); + + /* Initialize write buffers */ + for (i = 0, tbuf_uint8 = wbuf_uint8, tbuf_ushort = wbuf_ushort; i < SPACE7_DIM1; i++) + for (j = 0; j < SPACE7_DIM2; j++) { + *tbuf_uint8++ = (uint8_t)((i * SPACE7_DIM2) + j); + *tbuf_ushort++ = (unsigned short)((j * SPACE7_DIM2) + i); + } /* end for */ + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset */ + sid1 = H5Screate(H5S_SCALAR); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create dataspace for writing buffer */ + sid2 = H5Screate_simple(SPACE7_RANK, dims2, NULL); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, "Dataset1", H5T_NATIVE_UCHAR, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Select one element in memory with a point selection */ + coord1[0] = 0; + coord1[1] = 2; + ret = H5Sselect_elements(sid2, H5S_SELECT_SET, (size_t)1, (const hsize_t *)&coord1); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Write single point to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, wbuf_uint8); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Read scalar element from disk */ + ret = H5Dread(dataset, H5T_NATIVE_UCHAR, sid1, sid1, H5P_DEFAULT, &rval_uint8); + CHECK(ret, FAIL, "H5Dread"); + + /* Check value read back in */ + if (rval_uint8 != *(wbuf_uint8 + 2)) + TestErrPrintf("Error! rval=%u, should be: *(wbuf+2)=%u\n", (unsigned)rval_uint8, + (unsigned)*(wbuf_uint8 + 2)); + + /* Write single point to disk (with a datatype conversion) */ + ret = H5Dwrite(dataset, H5T_NATIVE_USHORT, sid2, sid1, H5P_DEFAULT, wbuf_ushort); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Read scalar element from disk */ + ret = H5Dread(dataset, H5T_NATIVE_USHORT, sid1, sid1, H5P_DEFAULT, &rval_ushort); + CHECK(ret, FAIL, "H5Dread"); + + /* Check value read back in */ + if (rval_ushort != *(wbuf_ushort + 2)) + TestErrPrintf("Error! rval=%u, should be: *(wbuf+2)=%u\n", (unsigned)rval_ushort, + (unsigned)*(wbuf_ushort + 2)); + + /* Select one element in memory with a hyperslab selection */ + start[0] = 4; + start[1] = 3; + count[0] = 1; + count[1] = 1; + ret = H5Sselect_hyperslab(sid2, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Write single hyperslab element to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, wbuf_uint8); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Read scalar element from disk */ + ret = H5Dread(dataset, H5T_NATIVE_UCHAR, sid1, sid1, H5P_DEFAULT, &rval_uint8); + CHECK(ret, FAIL, "H5Dread"); + + /* Check value read back in */ + if (rval_uint8 != *(wbuf_uint8 + (SPACE7_DIM2 * 4) + 3)) + TestErrPrintf("Error! rval=%u, should be: *(wbuf+(SPACE7_DIM2*4)+3)=%u\n", (unsigned)rval_uint8, + (unsigned)*(wbuf_uint8 + (SPACE7_DIM2 * 4) + 3)); + + /* Write single hyperslab element to disk (with a datatype conversion) */ + ret = H5Dwrite(dataset, H5T_NATIVE_USHORT, sid2, sid1, H5P_DEFAULT, wbuf_ushort); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Read scalar element from disk */ + ret = H5Dread(dataset, H5T_NATIVE_USHORT, sid1, sid1, H5P_DEFAULT, &rval_ushort); + CHECK(ret, FAIL, "H5Dread"); + + /* Check value read back in */ + if (rval_ushort != *(wbuf_ushort + (SPACE7_DIM2 * 4) + 3)) + TestErrPrintf("Error! rval=%u, should be: *(wbuf+(SPACE7_DIM2*4)+3)=%u\n", (unsigned)rval_ushort, + (unsigned)*(wbuf_ushort + (SPACE7_DIM2 * 4) + 3)); + + /* Select no elements in memory & file with "none" selections */ + ret = H5Sselect_none(sid1); + CHECK(ret, FAIL, "H5Sselect_none"); + + ret = H5Sselect_none(sid2); + CHECK(ret, FAIL, "H5Sselect_none"); + + /* Write no data to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, wbuf_uint8); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Write no data to disk (with a datatype conversion) */ + ret = H5Dwrite(dataset, H5T_NATIVE_USHORT, sid2, sid1, H5P_DEFAULT, wbuf_ushort); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free memory buffers */ + HDfree(wbuf_uint8); + HDfree(wbuf_ushort); +} /* test_scalar_select() */ + +/**************************************************************** +** +** test_scalar_select2(): Tests selections on scalar dataspace, +** verify H5Sselect_hyperslab and H5Sselect_elements fails for +** scalar dataspace. +** +****************************************************************/ +static void +test_scalar_select2(void) +{ + hid_t sid; /* Dataspace ID */ + hsize_t coord1[1]; /* Coordinates for point selection */ + hsize_t start[1]; /* Hyperslab start */ + hsize_t count[1]; /* Hyperslab block count */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(6, ("Testing Selections in Scalar Dataspaces\n")); + + /* Create dataspace for dataset */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Select one element in memory with a point selection */ + coord1[0] = 0; + H5E_BEGIN_TRY + { + ret = H5Sselect_elements(sid, H5S_SELECT_SET, (size_t)1, (const hsize_t *)&coord1); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Sselect_elements"); + + /* Select one element in memory with a hyperslab selection */ + start[0] = 0; + count[0] = 0; + H5E_BEGIN_TRY + { + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, NULL, count, NULL); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Sselect_hyperslab"); + + /* Select no elements in memory & file with "none" selection */ + ret = H5Sselect_none(sid); + CHECK(ret, FAIL, "H5Sselect_none"); + + /* Select all elements in memory & file with "all" selection */ + ret = H5Sselect_all(sid); + CHECK(ret, FAIL, "H5Sselect_all"); + + /* Close disk dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_scalar_select2() */ + +/**************************************************************** +** +** test_scalar_select3(): Test basic H5S (dataspace) selection code. +** Tests selections on scalar dataspaces in memory +** +****************************************************************/ +static void +test_scalar_select3(void) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1, sid2; /* Dataspace ID */ + hsize_t dims2[] = {SPACE7_DIM1, SPACE7_DIM2}; + hsize_t coord1[SPACE7_RANK]; /* Coordinates for point selection */ + hsize_t start[SPACE7_RANK]; /* Hyperslab start */ + hsize_t count[SPACE7_RANK]; /* Hyperslab block count */ + uint8_t wval_uint8, /* Value written out */ + rval_uint8; /* Value read in */ + unsigned short wval_ushort, /* Another value written out */ + rval_ushort; /* Another value read in */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing I/O on Selections in Scalar Dataspaces in Memory\n")); + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset */ + sid1 = H5Screate_simple(SPACE7_RANK, dims2, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create dataspace for writing buffer */ + sid2 = H5Screate(H5S_SCALAR); + CHECK(sid2, FAIL, "H5Screate_simple"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, "Dataset1", H5T_NATIVE_UCHAR, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Select one element in file with a point selection */ + coord1[0] = 0; + coord1[1] = 2; + ret = H5Sselect_elements(sid1, H5S_SELECT_SET, (size_t)1, (const hsize_t *)&coord1); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Write single point to disk */ + wval_uint8 = 12; + ret = H5Dwrite(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, &wval_uint8); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Read scalar element from disk */ + rval_uint8 = 0; + ret = H5Dread(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, &rval_uint8); + CHECK(ret, FAIL, "H5Dread"); + + /* Check value read back in */ + if (rval_uint8 != wval_uint8) + TestErrPrintf("%u: Error! rval=%u, should be: wval=%u\n", (unsigned)__LINE__, (unsigned)rval_uint8, + (unsigned)wval_uint8); + + /* Write single point to disk (with a datatype conversion) */ + wval_ushort = 23; + ret = H5Dwrite(dataset, H5T_NATIVE_USHORT, sid2, sid1, H5P_DEFAULT, &wval_ushort); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Read scalar element from disk */ + rval_ushort = 0; + ret = H5Dread(dataset, H5T_NATIVE_USHORT, sid2, sid1, H5P_DEFAULT, &rval_ushort); + CHECK(ret, FAIL, "H5Dread"); + + /* Check value read back in */ + if (rval_ushort != wval_ushort) + TestErrPrintf("%u: Error! rval=%u, should be: wval=%u\n", (unsigned)__LINE__, (unsigned)rval_ushort, + (unsigned)wval_ushort); + + /* Select one element in file with a hyperslab selection */ + start[0] = 4; + start[1] = 3; + count[0] = 1; + count[1] = 1; + ret = H5Sselect_hyperslab(sid1, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Write single hyperslab element to disk */ + wval_uint8 = 92; + ret = H5Dwrite(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, &wval_uint8); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Read scalar element from disk */ + rval_uint8 = 0; + ret = H5Dread(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, &rval_uint8); + CHECK(ret, FAIL, "H5Dread"); + + /* Check value read back in */ + if (rval_uint8 != wval_uint8) + TestErrPrintf("%u: Error! rval=%u, should be: wval=%u\n", (unsigned)__LINE__, (unsigned)rval_uint8, + (unsigned)wval_uint8); + + /* Write single hyperslab element to disk (with a datatype conversion) */ + wval_ushort = 107; + ret = H5Dwrite(dataset, H5T_NATIVE_USHORT, sid2, sid1, H5P_DEFAULT, &wval_ushort); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Read scalar element from disk */ + rval_ushort = 0; + ret = H5Dread(dataset, H5T_NATIVE_USHORT, sid2, sid1, H5P_DEFAULT, &rval_ushort); + CHECK(ret, FAIL, "H5Dread"); + + /* Check value read back in */ + if (rval_ushort != wval_ushort) + TestErrPrintf("%u: Error! rval=%u, should be: wval=%u\n", (unsigned)__LINE__, (unsigned)rval_ushort, + (unsigned)wval_ushort); + + /* Select no elements in memory & file with "none" selections */ + ret = H5Sselect_none(sid1); + CHECK(ret, FAIL, "H5Sselect_none"); + + ret = H5Sselect_none(sid2); + CHECK(ret, FAIL, "H5Sselect_none"); + + /* Write no data to disk */ + ret = H5Dwrite(dataset, H5T_NATIVE_UCHAR, sid2, sid1, H5P_DEFAULT, &wval_uint8); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Write no data to disk (with a datatype conversion) */ + ret = H5Dwrite(dataset, H5T_NATIVE_USHORT, sid2, sid1, H5P_DEFAULT, &wval_ushort); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close memory dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_scalar_select3() */ + +/**************************************************************** +** +** test_shape_same(): Tests selections on dataspace, verify that +** "shape same" routine is working correctly. +** +****************************************************************/ +static void +test_shape_same(void) +{ + hid_t all_sid; /* Dataspace ID with "all" selection */ + hid_t none_sid; /* Dataspace ID with "none" selection */ + hid_t single_pt_sid; /* Dataspace ID with single point selection */ + hid_t mult_pt_sid; /* Dataspace ID with multiple point selection */ + hid_t single_hyper_sid; /* Dataspace ID with single block hyperslab selection */ + hid_t single_hyper_all_sid; /* Dataspace ID with single block hyperslab + * selection that is the entire dataspace + */ + hid_t single_hyper_pt_sid; /* Dataspace ID with single block hyperslab + * selection that is the same as the single + * point selection + */ + hid_t regular_hyper_sid; /* Dataspace ID with regular hyperslab selection */ + hid_t irreg_hyper_sid; /* Dataspace ID with irregular hyperslab selection */ + hid_t none_hyper_sid; /* Dataspace ID with "no hyperslabs" selection */ + hid_t scalar_all_sid; /* ID for scalar dataspace with "all" selection */ + hid_t scalar_none_sid; /* ID for scalar dataspace with "none" selection */ + hid_t tmp_sid; /* Temporary dataspace ID */ + hsize_t dims[] = {SPACE9_DIM1, SPACE9_DIM2}; + hsize_t coord1[1][SPACE2_RANK]; /* Coordinates for single point selection */ + hsize_t coord2[SPACE9_DIM2][SPACE9_RANK]; /* Coordinates for multiple point selection */ + hsize_t start[SPACE9_RANK]; /* Hyperslab start */ + hsize_t stride[SPACE9_RANK]; /* Hyperslab stride */ + hsize_t count[SPACE9_RANK]; /* Hyperslab block count */ + hsize_t block[SPACE9_RANK]; /* Hyperslab block size */ + unsigned u, v; /* Local index variables */ + htri_t check; /* Shape comparison return value */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(6, ("Testing Same Shape Comparisons\n")); + HDassert(SPACE9_DIM2 >= POINT1_NPOINTS); + + /* Create dataspace for "all" selection */ + all_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(all_sid, FAIL, "H5Screate_simple"); + + /* Select entire extent for dataspace */ + ret = H5Sselect_all(all_sid); + CHECK(ret, FAIL, "H5Sselect_all"); + + /* Create dataspace for "none" selection */ + none_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(none_sid, FAIL, "H5Screate_simple"); + + /* Un-Select entire extent for dataspace */ + ret = H5Sselect_none(none_sid); + CHECK(ret, FAIL, "H5Sselect_none"); + + /* Create dataspace for single point selection */ + single_pt_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(single_pt_sid, FAIL, "H5Screate_simple"); + + /* Select sequence of ten points for multiple point selection */ + coord1[0][0] = 2; + coord1[0][1] = 2; + ret = H5Sselect_elements(single_pt_sid, H5S_SELECT_SET, (size_t)1, (const hsize_t *)coord1); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Create dataspace for multiple point selection */ + mult_pt_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(mult_pt_sid, FAIL, "H5Screate_simple"); + + /* Select sequence of ten points for multiple point selection */ + coord2[0][0] = 2; + coord2[0][1] = 2; + coord2[1][0] = 7; + coord2[1][1] = 2; + coord2[2][0] = 1; + coord2[2][1] = 4; + coord2[3][0] = 2; + coord2[3][1] = 6; + coord2[4][0] = 0; + coord2[4][1] = 8; + coord2[5][0] = 3; + coord2[5][1] = 2; + coord2[6][0] = 4; + coord2[6][1] = 4; + coord2[7][0] = 1; + coord2[7][1] = 0; + coord2[8][0] = 5; + coord2[8][1] = 1; + coord2[9][0] = 9; + coord2[9][1] = 3; + ret = H5Sselect_elements(mult_pt_sid, H5S_SELECT_SET, (size_t)POINT1_NPOINTS, (const hsize_t *)coord2); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Create dataspace for single hyperslab selection */ + single_hyper_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(single_hyper_sid, FAIL, "H5Screate_simple"); + + /* Select 10x10 hyperslab for single hyperslab selection */ + start[0] = 1; + start[1] = 1; + stride[0] = 1; + stride[1] = 1; + count[0] = 1; + count[1] = 1; + block[0] = (SPACE9_DIM1 - 2); + block[1] = (SPACE9_DIM2 - 2); + ret = H5Sselect_hyperslab(single_hyper_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create dataspace for single hyperslab selection with entire extent selected */ + single_hyper_all_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(single_hyper_all_sid, FAIL, "H5Screate_simple"); + + /* Select entire extent for hyperslab selection */ + start[0] = 0; + start[1] = 0; + stride[0] = 1; + stride[1] = 1; + count[0] = 1; + count[1] = 1; + block[0] = SPACE9_DIM1; + block[1] = SPACE9_DIM2; + ret = H5Sselect_hyperslab(single_hyper_all_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create dataspace for single hyperslab selection with single point selected */ + single_hyper_pt_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(single_hyper_pt_sid, FAIL, "H5Screate_simple"); + + /* Select entire extent for hyperslab selection */ + start[0] = 2; + start[1] = 2; + stride[0] = 1; + stride[1] = 1; + count[0] = 1; + count[1] = 1; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(single_hyper_pt_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create dataspace for regular hyperslab selection */ + regular_hyper_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(regular_hyper_sid, FAIL, "H5Screate_simple"); + + /* Select regular, strided hyperslab selection */ + start[0] = 2; + start[1] = 2; + stride[0] = 2; + stride[1] = 2; + count[0] = 5; + count[1] = 2; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(regular_hyper_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create dataspace for irregular hyperslab selection */ + irreg_hyper_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(irreg_hyper_sid, FAIL, "H5Screate_simple"); + + /* Create irregular hyperslab selection by OR'ing two blocks together */ + start[0] = 2; + start[1] = 2; + stride[0] = 1; + stride[1] = 1; + count[0] = 1; + count[1] = 1; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(irreg_hyper_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[0] = 4; + start[1] = 4; + stride[0] = 1; + stride[1] = 1; + count[0] = 1; + count[1] = 1; + block[0] = 3; + block[1] = 3; + ret = H5Sselect_hyperslab(irreg_hyper_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create dataspace for "no" hyperslab selection */ + none_hyper_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(none_hyper_sid, FAIL, "H5Screate_simple"); + + /* Create "no" hyperslab selection by XOR'ing same blocks together */ + start[0] = 2; + start[1] = 2; + stride[0] = 1; + stride[1] = 1; + count[0] = 1; + count[1] = 1; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(none_hyper_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + ret = H5Sselect_hyperslab(none_hyper_sid, H5S_SELECT_XOR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create scalar dataspace for "all" selection */ + scalar_all_sid = H5Screate(H5S_SCALAR); + CHECK(scalar_all_sid, FAIL, "H5Screate"); + + /* Create scalar dataspace for "none" selection */ + scalar_none_sid = H5Screate(H5S_SCALAR); + CHECK(scalar_none_sid, FAIL, "H5Screate"); + + /* Un-Select entire extent for dataspace */ + ret = H5Sselect_none(scalar_none_sid); + CHECK(ret, FAIL, "H5Sselect_none"); + + /* Compare "all" selection to all the selections created */ + /* Compare against itself */ + check = H5Sselect_shape_same(all_sid, all_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* Compare against copy of itself */ + tmp_sid = H5Scopy(all_sid); + CHECK(tmp_sid, FAIL, "H5Scopy"); + + check = H5Sselect_shape_same(all_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + ret = H5Sclose(tmp_sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Compare against "none" selection */ + check = H5Sselect_shape_same(all_sid, none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against single point selection */ + check = H5Sselect_shape_same(all_sid, single_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against multiple point selection */ + check = H5Sselect_shape_same(all_sid, mult_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "plain" single hyperslab selection */ + check = H5Sselect_shape_same(all_sid, single_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "all" single hyperslab selection */ + check = H5Sselect_shape_same(all_sid, single_hyper_all_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* Compare against "single point" single hyperslab selection */ + check = H5Sselect_shape_same(all_sid, single_hyper_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against regular, strided hyperslab selection */ + check = H5Sselect_shape_same(all_sid, regular_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against irregular hyperslab selection */ + check = H5Sselect_shape_same(all_sid, irreg_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "no" hyperslab selection */ + check = H5Sselect_shape_same(all_sid, none_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against scalar "all" hyperslab selection */ + check = H5Sselect_shape_same(all_sid, scalar_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against scalar "none" hyperslab selection */ + check = H5Sselect_shape_same(all_sid, scalar_none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare "none" selection to all the selections created */ + /* Compare against itself */ + check = H5Sselect_shape_same(none_sid, none_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* Compare against copy of itself */ + tmp_sid = H5Scopy(none_sid); + CHECK(tmp_sid, FAIL, "H5Scopy"); + + check = H5Sselect_shape_same(none_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + ret = H5Sclose(tmp_sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Compare against "all" selection */ + check = H5Sselect_shape_same(none_sid, all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against single point selection */ + check = H5Sselect_shape_same(none_sid, single_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against multiple point selection */ + check = H5Sselect_shape_same(none_sid, mult_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "plain" single hyperslab selection */ + check = H5Sselect_shape_same(none_sid, single_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "all" single hyperslab selection */ + check = H5Sselect_shape_same(none_sid, single_hyper_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "single point" single hyperslab selection */ + check = H5Sselect_shape_same(none_sid, single_hyper_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against regular, strided hyperslab selection */ + check = H5Sselect_shape_same(none_sid, regular_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against irregular hyperslab selection */ + check = H5Sselect_shape_same(none_sid, irreg_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "no" hyperslab selection */ + check = H5Sselect_shape_same(none_sid, none_hyper_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* Compare against scalar "all" hyperslab selection */ + check = H5Sselect_shape_same(none_sid, scalar_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against scalar "none" hyperslab selection */ + check = H5Sselect_shape_same(none_sid, scalar_none_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* Compare single point selection to all the selections created */ + /* Compare against itself */ + check = H5Sselect_shape_same(single_pt_sid, single_pt_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* Compare against copy of itself */ + tmp_sid = H5Scopy(single_pt_sid); + CHECK(tmp_sid, FAIL, "H5Scopy"); + + check = H5Sselect_shape_same(single_pt_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + ret = H5Sclose(tmp_sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Compare against "all" selection */ + check = H5Sselect_shape_same(single_pt_sid, all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "none" selection */ + check = H5Sselect_shape_same(single_pt_sid, none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against multiple point selection */ + check = H5Sselect_shape_same(single_pt_sid, mult_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "plain" single hyperslab selection */ + check = H5Sselect_shape_same(single_pt_sid, single_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "all" single hyperslab selection */ + check = H5Sselect_shape_same(single_pt_sid, single_hyper_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "single point" single hyperslab selection */ + check = H5Sselect_shape_same(single_pt_sid, single_hyper_pt_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* Compare against regular, strided hyperslab selection */ + check = H5Sselect_shape_same(single_pt_sid, regular_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against irregular hyperslab selection */ + check = H5Sselect_shape_same(single_pt_sid, irreg_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "no" hyperslab selection */ + check = H5Sselect_shape_same(single_pt_sid, none_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against scalar "all" hyperslab selection */ + check = H5Sselect_shape_same(single_pt_sid, scalar_all_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* Compare against scalar "none" hyperslab selection */ + check = H5Sselect_shape_same(single_pt_sid, scalar_none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare multiple point selection to all the selections created */ + /* Compare against itself */ + check = H5Sselect_shape_same(mult_pt_sid, mult_pt_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* Compare against copy of itself */ + tmp_sid = H5Scopy(mult_pt_sid); + CHECK(tmp_sid, FAIL, "H5Scopy"); + + check = H5Sselect_shape_same(mult_pt_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + ret = H5Sclose(tmp_sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Compare against "all" selection */ + check = H5Sselect_shape_same(mult_pt_sid, all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "none" selection */ + check = H5Sselect_shape_same(mult_pt_sid, none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against single point selection */ + check = H5Sselect_shape_same(mult_pt_sid, single_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "plain" single hyperslab selection */ + check = H5Sselect_shape_same(mult_pt_sid, single_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "all" single hyperslab selection */ + check = H5Sselect_shape_same(mult_pt_sid, single_hyper_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "single point" single hyperslab selection */ + check = H5Sselect_shape_same(mult_pt_sid, single_hyper_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against regular, strided hyperslab selection */ + check = H5Sselect_shape_same(mult_pt_sid, regular_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against irregular hyperslab selection */ + check = H5Sselect_shape_same(mult_pt_sid, irreg_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "no" hyperslab selection */ + check = H5Sselect_shape_same(mult_pt_sid, none_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against scalar "all" hyperslab selection */ + check = H5Sselect_shape_same(mult_pt_sid, scalar_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against scalar "none" hyperslab selection */ + check = H5Sselect_shape_same(mult_pt_sid, scalar_none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare single "normal" hyperslab selection to all the selections created */ + /* Compare against itself */ + check = H5Sselect_shape_same(single_hyper_sid, single_hyper_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* Compare against copy of itself */ + tmp_sid = H5Scopy(single_hyper_sid); + CHECK(tmp_sid, FAIL, "H5Scopy"); + + check = H5Sselect_shape_same(single_hyper_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + ret = H5Sclose(tmp_sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Compare against "all" selection */ + check = H5Sselect_shape_same(single_hyper_sid, all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "none" selection */ + check = H5Sselect_shape_same(single_hyper_sid, none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against single point selection */ + check = H5Sselect_shape_same(single_hyper_sid, single_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against multiple point selection */ + check = H5Sselect_shape_same(single_hyper_sid, mult_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "all" single hyperslab selection */ + check = H5Sselect_shape_same(single_hyper_sid, single_hyper_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "single point" single hyperslab selection */ + check = H5Sselect_shape_same(single_hyper_sid, single_hyper_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against regular, strided hyperslab selection */ + check = H5Sselect_shape_same(single_hyper_sid, regular_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against irregular hyperslab selection */ + check = H5Sselect_shape_same(single_hyper_sid, irreg_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "no" hyperslab selection */ + check = H5Sselect_shape_same(single_hyper_sid, none_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + +#ifdef NOT_YET + /* In theory, these two selections are the same shape, but the + * H5Sselect_shape_same() routine is just not this sophisticated yet and it + * would take too much effort to make this work. The worst case is that the + * non-optimized chunk mapping routines will be invoked instead of the more + * optimized routines, so this only hurts performance, not correctness + */ + /* Construct point selection which matches "plain" hyperslab selection */ + /* Create dataspace for point selection */ + tmp_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(tmp_sid, FAIL, "H5Screate_simple"); + + /* Select sequence of points for point selection */ + for (u = 1; u < (SPACE9_DIM1 - 1); u++) { + for (v = 1; v < (SPACE9_DIM2 - 1); v++) { + coord2[v - 1][0] = u; + coord2[v - 1][1] = v; + } /* end for */ + + ret = H5Sselect_elements(tmp_sid, H5S_SELECT_APPEND, (SPACE9_DIM2 - 2), coord2); + CHECK(ret, FAIL, "H5Sselect_elements"); + } /* end for */ + + /* Compare against hyperslab selection */ + check = H5Sselect_shape_same(single_hyper_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + ret = H5Sclose(tmp_sid); + CHECK(ret, FAIL, "H5Sclose"); +#endif /* NOT_YET */ + + /* Construct hyperslab selection which matches "plain" hyperslab selection */ + /* Create dataspace for hyperslab selection */ + tmp_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(tmp_sid, FAIL, "H5Screate_simple"); + + /* Un-select entire extent */ + ret = H5Sselect_none(tmp_sid); + CHECK(ret, FAIL, "H5Sselect_none"); + + /* Select sequence of rows for hyperslab selection */ + for (u = 1; u < (SPACE9_DIM1 - 1); u++) { + start[0] = u; + start[1] = 1; + stride[0] = 1; + stride[1] = 1; + count[0] = 1; + count[1] = 1; + block[0] = 1; + block[1] = (SPACE9_DIM2 - 2); + ret = H5Sselect_hyperslab(tmp_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + } /* end for */ + + /* Compare against hyperslab selection */ + check = H5Sselect_shape_same(single_hyper_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + ret = H5Sclose(tmp_sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Compare against scalar "all" hyperslab selection */ + check = H5Sselect_shape_same(single_hyper_sid, scalar_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against scalar "none" hyperslab selection */ + check = H5Sselect_shape_same(single_hyper_sid, scalar_none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare single "all" hyperslab selection to all the selections created */ + /* Compare against itself */ + check = H5Sselect_shape_same(single_hyper_all_sid, single_hyper_all_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* Compare against copy of itself */ + tmp_sid = H5Scopy(single_hyper_all_sid); + CHECK(tmp_sid, FAIL, "H5Scopy"); + + check = H5Sselect_shape_same(single_hyper_all_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + ret = H5Sclose(tmp_sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Compare against "all" selection */ + check = H5Sselect_shape_same(single_hyper_all_sid, all_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* Compare against "none" selection */ + check = H5Sselect_shape_same(single_hyper_all_sid, none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against single point selection */ + check = H5Sselect_shape_same(single_hyper_all_sid, single_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against multiple point selection */ + check = H5Sselect_shape_same(single_hyper_all_sid, mult_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "plain" single hyperslab selection */ + check = H5Sselect_shape_same(single_hyper_all_sid, single_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "single point" single hyperslab selection */ + check = H5Sselect_shape_same(single_hyper_all_sid, single_hyper_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against regular, strided hyperslab selection */ + check = H5Sselect_shape_same(single_hyper_all_sid, regular_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against irregular hyperslab selection */ + check = H5Sselect_shape_same(single_hyper_all_sid, irreg_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "no" hyperslab selection */ + check = H5Sselect_shape_same(single_hyper_all_sid, none_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + +#ifdef NOT_YET + /* In theory, these two selections are the same shape, but the + * H5S_select_shape_same() routine is just not this sophisticated yet and it + * would take too much effort to make this work. The worst case is that the + * non-optimized chunk mapping routines will be invoked instead of the more + * optimized routines, so this only hurts performance, not correctness + */ + /* Construct point selection which matches "all" hyperslab selection */ + /* Create dataspace for point selection */ + tmp_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(tmp_sid, FAIL, "H5Screate_simple"); + + /* Select sequence of points for point selection */ + for (u = 0; u < SPACE9_DIM1; u++) { + for (v = 0; v < SPACE9_DIM2; v++) { + coord2[v][0] = u; + coord2[v][1] = v; + } /* end for */ + ret = H5Sselect_elements(tmp_sid, H5S_SELECT_APPEND, SPACE9_DIM2, coord2); + CHECK(ret, FAIL, "H5Sselect_elements"); + } /* end for */ + + /* Compare against hyperslab selection */ + check = H5Sselect_shape_same(single_hyper_all_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + ret = H5Sclose(tmp_sid); + CHECK(ret, FAIL, "H5Sclose"); +#endif /* NOT_YET */ + + /* Construct hyperslab selection which matches "all" hyperslab selection */ + /* Create dataspace for hyperslab selection */ + tmp_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(tmp_sid, FAIL, "H5Screate_simple"); + + /* Un-select entire extent */ + ret = H5Sselect_none(tmp_sid); + CHECK(ret, FAIL, "H5Sselect_none"); + + /* Select sequence of rows for hyperslab selection */ + for (u = 0; u < SPACE9_DIM2; u++) { + start[0] = u; + start[1] = 0; + stride[0] = 1; + stride[1] = 1; + count[0] = 1; + count[1] = 1; + block[0] = 1; + block[1] = SPACE9_DIM2; + ret = H5Sselect_hyperslab(tmp_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + } /* end for */ + + /* Compare against hyperslab selection */ + check = H5Sselect_shape_same(single_hyper_all_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + ret = H5Sclose(tmp_sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Compare against scalar "all" hyperslab selection */ + check = H5Sselect_shape_same(single_hyper_all_sid, scalar_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against scalar "none" hyperslab selection */ + check = H5Sselect_shape_same(single_hyper_all_sid, scalar_none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare single "point" hyperslab selection to all the selections created */ + /* Compare against itself */ + check = H5Sselect_shape_same(single_hyper_pt_sid, single_hyper_pt_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* Compare against copy of itself */ + tmp_sid = H5Scopy(single_hyper_pt_sid); + CHECK(tmp_sid, FAIL, "H5Scopy"); + + check = H5Sselect_shape_same(single_hyper_pt_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + ret = H5Sclose(tmp_sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Compare against "all" selection */ + check = H5Sselect_shape_same(single_hyper_pt_sid, all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "none" selection */ + check = H5Sselect_shape_same(single_hyper_pt_sid, none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against single point selection */ + check = H5Sselect_shape_same(single_hyper_pt_sid, single_pt_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* Compare against multiple point selection */ + check = H5Sselect_shape_same(single_hyper_pt_sid, mult_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "plain" single hyperslab selection */ + check = H5Sselect_shape_same(single_hyper_pt_sid, single_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "all" single hyperslab selection */ + check = H5Sselect_shape_same(single_hyper_pt_sid, single_hyper_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against regular, strided hyperslab selection */ + check = H5Sselect_shape_same(single_hyper_pt_sid, regular_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against irregular hyperslab selection */ + check = H5Sselect_shape_same(single_hyper_pt_sid, irreg_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "no" hyperslab selection */ + check = H5Sselect_shape_same(single_hyper_pt_sid, none_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against scalar "all" hyperslab selection */ + check = H5Sselect_shape_same(single_hyper_pt_sid, scalar_all_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* Compare against scalar "none" hyperslab selection */ + check = H5Sselect_shape_same(single_hyper_pt_sid, scalar_none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare regular, strided hyperslab selection to all the selections created */ + /* Compare against itself */ + check = H5Sselect_shape_same(regular_hyper_sid, regular_hyper_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* Compare against copy of itself */ + tmp_sid = H5Scopy(regular_hyper_sid); + CHECK(tmp_sid, FAIL, "H5Scopy"); + + check = H5Sselect_shape_same(regular_hyper_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + ret = H5Sclose(tmp_sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Compare against "all" selection */ + check = H5Sselect_shape_same(regular_hyper_sid, all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "none" selection */ + check = H5Sselect_shape_same(regular_hyper_sid, none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against single point selection */ + check = H5Sselect_shape_same(regular_hyper_sid, single_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against multiple point selection */ + check = H5Sselect_shape_same(regular_hyper_sid, mult_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "plain" single hyperslab selection */ + check = H5Sselect_shape_same(regular_hyper_sid, single_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "all" single hyperslab selection */ + check = H5Sselect_shape_same(regular_hyper_sid, single_hyper_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "single point" single hyperslab selection */ + check = H5Sselect_shape_same(regular_hyper_sid, single_hyper_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against irregular hyperslab selection */ + check = H5Sselect_shape_same(regular_hyper_sid, irreg_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "no" hyperslab selection */ + check = H5Sselect_shape_same(regular_hyper_sid, none_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Construct point selection which matches regular, strided hyperslab selection */ + /* Create dataspace for point selection */ + tmp_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(tmp_sid, FAIL, "H5Screate_simple"); + + /* Select sequence of points for point selection */ + for (u = 2; u < 11; u += 2) { + for (v = 0; v < 2; v++) { + coord2[v][0] = u; + coord2[v][1] = (v * 2) + 2; + } /* end for */ + ret = H5Sselect_elements(tmp_sid, H5S_SELECT_APPEND, (size_t)2, (const hsize_t *)coord2); + CHECK(ret, FAIL, "H5Sselect_elements"); + } /* end for */ + + /* Compare against hyperslab selection */ + check = H5Sselect_shape_same(regular_hyper_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + ret = H5Sclose(tmp_sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Construct hyperslab selection which matches regular, strided hyperslab selection */ + /* Create dataspace for hyperslab selection */ + tmp_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(tmp_sid, FAIL, "H5Screate_simple"); + + /* Un-select entire extent */ + ret = H5Sselect_none(tmp_sid); + CHECK(ret, FAIL, "H5Sselect_none"); + + /* Select sequence of rows for hyperslab selection */ + for (u = 2; u < 11; u += 2) { + start[0] = u; + start[1] = 3; + stride[0] = 1; + stride[1] = 2; + count[0] = 1; + count[1] = 2; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(tmp_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + } /* end for */ + + /* Compare against hyperslab selection */ + check = H5Sselect_shape_same(regular_hyper_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + ret = H5Sclose(tmp_sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Construct regular hyperslab selection with an offset which matches regular, strided hyperslab selection + */ + /* Create dataspace for hyperslab selection */ + tmp_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(tmp_sid, FAIL, "H5Screate_simple"); + + /* Select regular, strided hyperslab selection at an offset */ + start[0] = 1; + start[1] = 1; + stride[0] = 2; + stride[1] = 2; + count[0] = 5; + count[1] = 2; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(tmp_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Compare against hyperslab selection */ + check = H5Sselect_shape_same(regular_hyper_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + ret = H5Sclose(tmp_sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Compare against scalar "all" hyperslab selection */ + check = H5Sselect_shape_same(regular_hyper_sid, scalar_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against scalar "none" hyperslab selection */ + check = H5Sselect_shape_same(regular_hyper_sid, scalar_none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare irregular hyperslab selection to all the selections created */ + /* Compare against itself */ + check = H5Sselect_shape_same(irreg_hyper_sid, irreg_hyper_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* Compare against copy of itself */ + tmp_sid = H5Scopy(irreg_hyper_sid); + CHECK(tmp_sid, FAIL, "H5Scopy"); + + check = H5Sselect_shape_same(irreg_hyper_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + ret = H5Sclose(tmp_sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Compare against "all" selection */ + check = H5Sselect_shape_same(irreg_hyper_sid, all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "none" selection */ + check = H5Sselect_shape_same(irreg_hyper_sid, none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against single point selection */ + check = H5Sselect_shape_same(irreg_hyper_sid, single_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against multiple point selection */ + check = H5Sselect_shape_same(irreg_hyper_sid, mult_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "plain" single hyperslab selection */ + check = H5Sselect_shape_same(irreg_hyper_sid, single_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "all" single hyperslab selection */ + check = H5Sselect_shape_same(irreg_hyper_sid, single_hyper_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "single point" single hyperslab selection */ + check = H5Sselect_shape_same(irreg_hyper_sid, single_hyper_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against regular, strided hyperslab selection */ + check = H5Sselect_shape_same(irreg_hyper_sid, regular_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "no" hyperslab selection */ + check = H5Sselect_shape_same(irreg_hyper_sid, none_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Construct hyperslab selection which matches irregular hyperslab selection */ + /* Create dataspace for hyperslab selection */ + tmp_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(tmp_sid, FAIL, "H5Screate_simple"); + + start[0] = 2; + start[1] = 2; + stride[0] = 1; + stride[1] = 1; + count[0] = 1; + count[1] = 1; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(tmp_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Select sequence of columns for hyperslab selection */ + for (u = 0; u < 3; u++) { + start[0] = 4; + start[1] = u + 4; + stride[0] = 1; + stride[1] = 1; + count[0] = 1; + count[1] = 1; + block[0] = 3; + block[1] = 1; + ret = H5Sselect_hyperslab(tmp_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + } /* end for */ + + /* Compare against hyperslab selection */ + check = H5Sselect_shape_same(irreg_hyper_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + ret = H5Sclose(tmp_sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Compare against scalar "all" hyperslab selection */ + check = H5Sselect_shape_same(irreg_hyper_sid, scalar_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against scalar "none" hyperslab selection */ + check = H5Sselect_shape_same(irreg_hyper_sid, scalar_none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare scalar "all" dataspace with all selections created */ + + /* Compare against itself */ + check = H5Sselect_shape_same(scalar_all_sid, scalar_all_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* Compare against copy of itself */ + tmp_sid = H5Scopy(scalar_all_sid); + CHECK(tmp_sid, FAIL, "H5Scopy"); + + check = H5Sselect_shape_same(scalar_all_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + ret = H5Sclose(tmp_sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Compare against "all" selection */ + check = H5Sselect_shape_same(scalar_all_sid, all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "none" selection */ + check = H5Sselect_shape_same(scalar_all_sid, none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against single point selection */ + check = H5Sselect_shape_same(scalar_all_sid, single_pt_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* Compare against multiple point selection */ + check = H5Sselect_shape_same(scalar_all_sid, mult_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "plain" single hyperslab selection */ + check = H5Sselect_shape_same(scalar_all_sid, single_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "all" single hyperslab selection */ + check = H5Sselect_shape_same(scalar_all_sid, single_hyper_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "single point" single hyperslab selection */ + check = H5Sselect_shape_same(scalar_all_sid, single_hyper_pt_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* Compare against regular, strided hyperslab selection */ + check = H5Sselect_shape_same(scalar_all_sid, regular_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against irregular hyperslab selection */ + check = H5Sselect_shape_same(scalar_all_sid, irreg_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "no" hyperslab selection */ + check = H5Sselect_shape_same(scalar_all_sid, none_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against scalar "none" hyperslab selection */ + check = H5Sselect_shape_same(scalar_all_sid, scalar_none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare scalar "none" dataspace with all selections created */ + + /* Compare against itself */ + check = H5Sselect_shape_same(scalar_none_sid, scalar_none_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* Compare against copy of itself */ + tmp_sid = H5Scopy(scalar_none_sid); + CHECK(tmp_sid, FAIL, "H5Scopy"); + + check = H5Sselect_shape_same(scalar_none_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + ret = H5Sclose(tmp_sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Compare against "all" selection */ + check = H5Sselect_shape_same(scalar_none_sid, all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "none" selection */ + check = H5Sselect_shape_same(scalar_none_sid, none_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* Compare against single point selection */ + check = H5Sselect_shape_same(scalar_none_sid, single_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against multiple point selection */ + check = H5Sselect_shape_same(scalar_none_sid, mult_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "plain" single hyperslab selection */ + check = H5Sselect_shape_same(scalar_none_sid, single_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "all" single hyperslab selection */ + check = H5Sselect_shape_same(scalar_none_sid, single_hyper_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "single point" single hyperslab selection */ + check = H5Sselect_shape_same(scalar_none_sid, single_hyper_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against regular, strided hyperslab selection */ + check = H5Sselect_shape_same(scalar_none_sid, regular_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against irregular hyperslab selection */ + check = H5Sselect_shape_same(scalar_none_sid, irreg_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "no" hyperslab selection */ + check = H5Sselect_shape_same(scalar_none_sid, none_hyper_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* Compare against scalar "all" hyperslab selection */ + check = H5Sselect_shape_same(scalar_none_sid, scalar_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Close dataspaces */ + ret = H5Sclose(all_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(none_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(single_pt_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(mult_pt_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(single_hyper_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(single_hyper_all_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(single_hyper_pt_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(regular_hyper_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(irreg_hyper_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(none_hyper_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(scalar_all_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(scalar_none_sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_shape_same() */ + +/**************************************************************** +** +** test_shape_same_dr__smoke_check_1(): +** +** Create a square, 2-D dataspace (10 X 10), and select +** all of it. +** +** Similarly, create nine, 3-D dataspaces (10 X 10 X 10), +** and select (10 X 10 X 1) hyperslabs in each, three with +** the slab parallel to the xy plane, three parallel to the +** xz plane, and three parallel to the yz plane. +** +** Assuming that z is the fastest changing dimension, +** H5Sselect_shape_same() should return TRUE when comparing +** the full 2-D space against any hyperslab parallel to the +** yz plane in the 3-D space, and FALSE when comparing the +** full 2-D space against the other two hyperslabs. +** +** Also create two additional 3-D dataspaces (10 X 10 X 10), +** and select a (10 X 10 X 2) hyperslab parallel to the yz +** axis in one of them, and two parallel (10 X 10 X 1) hyper +** slabs parallel to the yz axis in the other. +** H5Sselect_shape_same() should return FALSE when comparing +** each to the 2-D selection. +** +****************************************************************/ +static void +test_shape_same_dr__smoke_check_1(void) +{ + hid_t small_square_sid; + hid_t small_cube_xy_slice_0_sid; + hid_t small_cube_xy_slice_1_sid; + hid_t small_cube_xy_slice_2_sid; + hid_t small_cube_xz_slice_0_sid; + hid_t small_cube_xz_slice_1_sid; + hid_t small_cube_xz_slice_2_sid; + hid_t small_cube_yz_slice_0_sid; + hid_t small_cube_yz_slice_1_sid; + hid_t small_cube_yz_slice_2_sid; + hid_t small_cube_yz_slice_3_sid; + hid_t small_cube_yz_slice_4_sid; + hsize_t small_cube_dims[] = {10, 10, 10}; + hsize_t start[3]; + hsize_t stride[3]; + hsize_t count[3]; + hsize_t block[3]; + htri_t check; /* Shape comparison return value */ + herr_t ret; /* Generic return value */ + + MESSAGE(7, (" Smoke check 1: Slices through a cube.\n")); + + /* Create the 10 x 10 dataspace */ + small_square_sid = H5Screate_simple(2, small_cube_dims, NULL); + CHECK(small_square_sid, FAIL, "H5Screate_simple"); + + /* Create the 10 X 10 X 10 dataspaces for the hyperslab parallel to the xy axis */ + small_cube_xy_slice_0_sid = H5Screate_simple(3, small_cube_dims, NULL); + CHECK(small_cube_xy_slice_0_sid, FAIL, "H5Screate_simple"); + + small_cube_xy_slice_1_sid = H5Screate_simple(3, small_cube_dims, NULL); + CHECK(small_cube_xy_slice_1_sid, FAIL, "H5Screate_simple"); + + small_cube_xy_slice_2_sid = H5Screate_simple(3, small_cube_dims, NULL); + CHECK(small_cube_xy_slice_2_sid, FAIL, "H5Screate_simple"); + + start[0] = 0; /* x */ + start[1] = 0; /* y */ + start[2] = 0; /* z */ + + /* stride is a bit silly here, since we are only selecting a single */ + /* contiguous plane, but include it anyway, with values large enough */ + /* to ensure that we will only get the single block selected. */ + stride[0] = 20; /* x */ + stride[1] = 20; /* y */ + stride[2] = 20; /* z */ + + count[0] = 1; /* x */ + count[1] = 1; /* y */ + count[2] = 1; /* z */ + + block[0] = 10; /* x */ + block[1] = 10; /* y */ + block[2] = 1; /* z */ + ret = H5Sselect_hyperslab(small_cube_xy_slice_0_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[2] = 5; + ret = H5Sselect_hyperslab(small_cube_xy_slice_1_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[2] = 9; + ret = H5Sselect_hyperslab(small_cube_xy_slice_2_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create the 10 X 10 X 10 dataspaces for the hyperslab parallel to the xz axis */ + small_cube_xz_slice_0_sid = H5Screate_simple(3, small_cube_dims, NULL); + CHECK(small_cube_xz_slice_0_sid, FAIL, "H5Screate_simple"); + + small_cube_xz_slice_1_sid = H5Screate_simple(3, small_cube_dims, NULL); + CHECK(small_cube_xz_slice_1_sid, FAIL, "H5Screate_simple"); + + small_cube_xz_slice_2_sid = H5Screate_simple(3, small_cube_dims, NULL); + CHECK(small_cube_xz_slice_2_sid, FAIL, "H5Screate_simple"); + + start[0] = 0; /* x */ + start[1] = 0; /* y */ + start[2] = 0; /* z */ + + /* stride is a bit silly here, since we are only selecting a single */ + /* contiguous chunk, but include it anyway, with values large enough */ + /* to ensure that we will only get the single chunk. */ + stride[0] = 20; /* x */ + stride[1] = 20; /* y */ + stride[2] = 20; /* z */ + + count[0] = 1; /* x */ + count[1] = 1; /* y */ + count[2] = 1; /* z */ + + block[0] = 10; /* x */ + block[1] = 1; /* y */ + block[2] = 10; /* z */ + ret = H5Sselect_hyperslab(small_cube_xz_slice_0_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[1] = 4; + ret = H5Sselect_hyperslab(small_cube_xz_slice_1_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[1] = 9; + ret = H5Sselect_hyperslab(small_cube_xz_slice_2_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create the 10 X 10 X 10 dataspaces for the hyperslabs parallel to the yz axis */ + small_cube_yz_slice_0_sid = H5Screate_simple(3, small_cube_dims, NULL); + CHECK(small_cube_yz_slice_0_sid, FAIL, "H5Screate_simple"); + + small_cube_yz_slice_1_sid = H5Screate_simple(3, small_cube_dims, NULL); + CHECK(small_cube_yz_slice_1_sid, FAIL, "H5Screate_simple"); + + small_cube_yz_slice_2_sid = H5Screate_simple(3, small_cube_dims, NULL); + CHECK(small_cube_yz_slice_2_sid, FAIL, "H5Screate_simple"); + + small_cube_yz_slice_3_sid = H5Screate_simple(3, small_cube_dims, NULL); + CHECK(small_cube_yz_slice_3_sid, FAIL, "H5Screate_simple"); + + small_cube_yz_slice_4_sid = H5Screate_simple(3, small_cube_dims, NULL); + CHECK(small_cube_yz_slice_4_sid, FAIL, "H5Screate_simple"); + + start[0] = 0; /* x */ + start[1] = 0; /* y */ + start[2] = 0; /* z */ + + /* stride is a bit silly here, since we are only selecting a single */ + /* contiguous chunk, but include it anyway, with values large enough */ + /* to ensure that we will only get the single chunk. */ + stride[0] = 20; /* x */ + stride[1] = 20; /* y */ + stride[2] = 20; /* z */ + + count[0] = 1; /* x */ + count[1] = 1; /* y */ + count[2] = 1; /* z */ + + block[0] = 1; /* x */ + block[1] = 10; /* y */ + block[2] = 10; /* z */ + + ret = H5Sselect_hyperslab(small_cube_yz_slice_0_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[0] = 4; + ret = H5Sselect_hyperslab(small_cube_yz_slice_1_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[0] = 9; + ret = H5Sselect_hyperslab(small_cube_yz_slice_2_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[0] = 4; + block[0] = 2; + ret = H5Sselect_hyperslab(small_cube_yz_slice_3_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[0] = 3; + block[0] = 1; + ret = H5Sselect_hyperslab(small_cube_yz_slice_4_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[0] = 6; + ret = H5Sselect_hyperslab(small_cube_yz_slice_4_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* setup is done -- run the tests: */ + + /* Compare against "xy" selection */ + check = H5Sselect_shape_same(small_cube_xy_slice_0_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(small_cube_xy_slice_1_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(small_cube_xy_slice_2_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "xz" selection */ + check = H5Sselect_shape_same(small_cube_xz_slice_0_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(small_cube_xz_slice_1_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(small_cube_xz_slice_2_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "yz" selection */ + check = H5Sselect_shape_same(small_cube_yz_slice_0_sid, small_square_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(small_cube_yz_slice_1_sid, small_square_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(small_cube_yz_slice_2_sid, small_square_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(small_cube_yz_slice_3_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(small_cube_yz_slice_4_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Close dataspaces */ + ret = H5Sclose(small_square_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_cube_xy_slice_0_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_cube_xy_slice_1_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_cube_xy_slice_2_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_cube_xz_slice_0_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_cube_xz_slice_1_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_cube_xz_slice_2_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_cube_yz_slice_0_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_cube_yz_slice_1_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_cube_yz_slice_2_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_cube_yz_slice_3_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_cube_yz_slice_4_sid); + CHECK(ret, FAIL, "H5Sclose"); + +} /* test_shape_same_dr__smoke_check_1() */ + +/**************************************************************** +** +** test_shape_same_dr__smoke_check_2(): +** +** Create a square, 2-D dataspace (10 X 10), and select +** a "checker board" hyperslab as follows: +** +** * * - - * * - - * * +** * * - - * * - - * * +** - - * * - - * * - - +** - - * * - - * * - - +** * * - - * * - - * * +** * * - - * * - - * * +** - - * * - - * * - - +** - - * * - - * * - - +** * * - - * * - - * * +** * * - - * * - - * * +** +** where asterisks indicate selected elements, and dashes +** indicate unselected elements. +** +** Similarly, create nine, 3-D dataspaces (10 X 10 X 10), +** and select similar (10 X 10 X 1) checker board hyper +** slabs in each, three with the slab parallel to the xy +** plane, three parallel to the xz plane, and three parallel +** to the yz plane. +** +** Assuming that z is the fastest changing dimension, +** H5Sselect_shape_same() should return TRUE when comparing +** the 2-D space checker board selection against a checker +** board hyperslab parallel to the yz plane in the 3-D +** space, and FALSE when comparing the 2-D checkerboard +** selection against two hyperslabs parallel to the xy +** or xz planes. +** +** Also create an additional 3-D dataspaces (10 X 10 X 10), +** and select a checker board parallel with the yz axis, +** save with some squares being on different planes. +** H5Sselect_shape_same() should return FALSE when +** comparing this selection to the 2-D selection. +** +****************************************************************/ +static void +test_shape_same_dr__smoke_check_2(void) +{ + hid_t small_square_sid; + hid_t small_cube_xy_slice_0_sid; + hid_t small_cube_xy_slice_1_sid; + hid_t small_cube_xy_slice_2_sid; + hid_t small_cube_xz_slice_0_sid; + hid_t small_cube_xz_slice_1_sid; + hid_t small_cube_xz_slice_2_sid; + hid_t small_cube_yz_slice_0_sid; + hid_t small_cube_yz_slice_1_sid; + hid_t small_cube_yz_slice_2_sid; + hid_t small_cube_yz_slice_3_sid; + hsize_t small_cube_dims[] = {10, 10, 10}; + hsize_t start[3]; + hsize_t stride[3]; + hsize_t count[3]; + hsize_t block[3]; + htri_t check; /* Shape comparison return value */ + herr_t ret; /* Generic return value */ + + MESSAGE(7, (" Smoke check 2: Checker board slices through a cube.\n")); + + /* Create the 10 x 10 dataspace */ + small_square_sid = H5Screate_simple(2, small_cube_dims, NULL); + CHECK(small_square_sid, FAIL, "H5Screate_simple"); + + start[0] = 0; /* x */ + start[1] = 0; /* y */ + + stride[0] = 4; /* x */ + stride[1] = 4; /* y */ + + count[0] = 3; /* x */ + count[1] = 3; /* y */ + + block[0] = 2; /* x */ + block[1] = 2; /* y */ + ret = H5Sselect_hyperslab(small_square_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[0] = 2; /* x */ + start[1] = 2; /* y */ + + stride[0] = 4; /* x */ + stride[1] = 4; /* y */ + + count[0] = 2; /* x */ + count[1] = 2; /* y */ + + block[0] = 2; /* x */ + block[1] = 2; /* y */ + ret = H5Sselect_hyperslab(small_square_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create the 10 X 10 X 10 dataspaces for the hyperslab parallel to the xy axis */ + small_cube_xy_slice_0_sid = H5Screate_simple(3, small_cube_dims, NULL); + CHECK(small_cube_xy_slice_0_sid, FAIL, "H5Screate_simple"); + + small_cube_xy_slice_1_sid = H5Screate_simple(3, small_cube_dims, NULL); + CHECK(small_cube_xy_slice_1_sid, FAIL, "H5Screate_simple"); + + small_cube_xy_slice_2_sid = H5Screate_simple(3, small_cube_dims, NULL); + CHECK(small_cube_xy_slice_2_sid, FAIL, "H5Screate_simple"); + + start[0] = 0; /* x */ + start[1] = 0; /* y */ + start[2] = 0; /* z */ + + stride[0] = 4; /* x */ + stride[1] = 4; /* y */ + stride[2] = 20; /* z -- large enough that there will only be one slice */ + + count[0] = 3; /* x */ + count[1] = 3; /* y */ + count[2] = 1; /* z */ + + block[0] = 2; /* x */ + block[1] = 2; /* y */ + block[2] = 1; /* z */ + ret = H5Sselect_hyperslab(small_cube_xy_slice_0_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[2] = 3; + ret = H5Sselect_hyperslab(small_cube_xy_slice_1_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[2] = 9; + ret = H5Sselect_hyperslab(small_cube_xy_slice_2_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[0] = 2; /* x */ + start[1] = 2; /* y */ + start[2] = 0; /* z */ + + stride[0] = 4; /* x */ + stride[1] = 4; /* y */ + stride[2] = 20; /* z -- large enough that there will only be one slice */ + + count[0] = 2; /* x */ + count[1] = 2; /* y */ + count[2] = 1; /* z */ + + block[0] = 2; /* x */ + block[1] = 2; /* y */ + block[2] = 1; /* z */ + ret = H5Sselect_hyperslab(small_cube_xy_slice_0_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[2] = 3; + ret = H5Sselect_hyperslab(small_cube_xy_slice_1_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[2] = 9; + ret = H5Sselect_hyperslab(small_cube_xy_slice_2_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create the 10 X 10 X 10 dataspaces for the hyperslab parallel to the xz axis */ + small_cube_xz_slice_0_sid = H5Screate_simple(3, small_cube_dims, NULL); + CHECK(small_cube_xz_slice_0_sid, FAIL, "H5Screate_simple"); + + small_cube_xz_slice_1_sid = H5Screate_simple(3, small_cube_dims, NULL); + CHECK(small_cube_xz_slice_1_sid, FAIL, "H5Screate_simple"); + + small_cube_xz_slice_2_sid = H5Screate_simple(3, small_cube_dims, NULL); + CHECK(small_cube_xz_slice_2_sid, FAIL, "H5Screate_simple"); + + start[0] = 0; /* x */ + start[1] = 0; /* y */ + start[2] = 0; /* z */ + + stride[0] = 4; /* x */ + stride[1] = 20; /* y -- large enough that there will only be one slice */ + stride[2] = 4; /* z */ + + count[0] = 3; /* x */ + count[1] = 1; /* y */ + count[2] = 3; /* z */ + + block[0] = 2; /* x */ + block[1] = 1; /* y */ + block[2] = 2; /* z */ + ret = H5Sselect_hyperslab(small_cube_xz_slice_0_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[1] = 5; + ret = H5Sselect_hyperslab(small_cube_xz_slice_1_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[1] = 9; + ret = H5Sselect_hyperslab(small_cube_xz_slice_2_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[0] = 2; /* x */ + start[1] = 0; /* y */ + start[2] = 2; /* z */ + + stride[0] = 4; /* x */ + stride[1] = 20; /* y -- large enough that there will only be one slice */ + stride[2] = 4; /* z */ + + count[0] = 2; /* x */ + count[1] = 1; /* y */ + count[2] = 2; /* z */ + + block[0] = 2; /* x */ + block[1] = 1; /* y */ + block[2] = 2; /* z */ + ret = H5Sselect_hyperslab(small_cube_xz_slice_0_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[1] = 5; + ret = H5Sselect_hyperslab(small_cube_xz_slice_1_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[1] = 9; + ret = H5Sselect_hyperslab(small_cube_xz_slice_2_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create the 10 X 10 X 10 dataspaces for the hyperslabs parallel to the yz axis */ + small_cube_yz_slice_0_sid = H5Screate_simple(3, small_cube_dims, NULL); + CHECK(small_cube_yz_slice_0_sid, FAIL, "H5Screate_simple"); + + small_cube_yz_slice_1_sid = H5Screate_simple(3, small_cube_dims, NULL); + CHECK(small_cube_yz_slice_1_sid, FAIL, "H5Screate_simple"); + + small_cube_yz_slice_2_sid = H5Screate_simple(3, small_cube_dims, NULL); + CHECK(small_cube_yz_slice_2_sid, FAIL, "H5Screate_simple"); + + small_cube_yz_slice_3_sid = H5Screate_simple(3, small_cube_dims, NULL); + CHECK(small_cube_yz_slice_3_sid, FAIL, "H5Screate_simple"); + + start[0] = 0; /* x */ + start[1] = 0; /* y */ + start[2] = 0; /* z */ + + stride[0] = 20; /* x -- large enough that there will only be one slice */ + stride[1] = 4; /* y */ + stride[2] = 4; /* z */ + + count[0] = 1; /* x */ + count[1] = 3; /* y */ + count[2] = 3; /* z */ + + block[0] = 1; /* x */ + block[1] = 2; /* y */ + block[2] = 2; /* z */ + ret = H5Sselect_hyperslab(small_cube_yz_slice_0_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[0] = 8; + ret = H5Sselect_hyperslab(small_cube_yz_slice_1_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[0] = 9; + ret = H5Sselect_hyperslab(small_cube_yz_slice_2_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[0] = 3; + ret = H5Sselect_hyperslab(small_cube_yz_slice_3_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[0] = 0; /* x */ + start[1] = 2; /* y */ + start[2] = 2; /* z */ + + stride[0] = 20; /* x -- large enough that there will only be one slice */ + stride[1] = 4; /* y */ + stride[2] = 4; /* z */ + + count[0] = 1; /* x */ + count[1] = 2; /* y */ + count[2] = 2; /* z */ + + block[0] = 1; /* x */ + block[1] = 2; /* y */ + block[2] = 2; /* z */ + ret = H5Sselect_hyperslab(small_cube_yz_slice_0_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[0] = 8; + ret = H5Sselect_hyperslab(small_cube_yz_slice_1_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[0] = 9; + ret = H5Sselect_hyperslab(small_cube_yz_slice_2_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[0] = 4; + /* This test gets the right answer, but it fails the shape same + * test in an unexpected point. Bring this up with Quincey, as + * the oddness looks like it is not related to my code. + * -- JRM + */ + ret = H5Sselect_hyperslab(small_cube_yz_slice_3_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* setup is done -- run the tests: */ + + /* Compare against "xy" selection */ + check = H5Sselect_shape_same(small_cube_xy_slice_0_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(small_cube_xy_slice_1_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(small_cube_xy_slice_2_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "xz" selection */ + check = H5Sselect_shape_same(small_cube_xz_slice_0_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(small_cube_xz_slice_1_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(small_cube_xz_slice_2_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "yz" selection */ + check = H5Sselect_shape_same(small_cube_yz_slice_0_sid, small_square_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(small_cube_yz_slice_1_sid, small_square_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(small_cube_yz_slice_2_sid, small_square_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(small_cube_yz_slice_3_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Close dataspaces */ + ret = H5Sclose(small_square_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_cube_xy_slice_0_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_cube_xy_slice_1_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_cube_xy_slice_2_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_cube_xz_slice_0_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_cube_xz_slice_1_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_cube_xz_slice_2_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_cube_yz_slice_0_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_cube_yz_slice_1_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_cube_yz_slice_2_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_cube_yz_slice_3_sid); + CHECK(ret, FAIL, "H5Sclose"); + +} /* test_shape_same_dr__smoke_check_2() */ + +/**************************************************************** +** +** test_shape_same_dr__smoke_check_3(): +** +** Create a square, 2-D dataspace (10 X 10), and select an +** irregular hyperslab as follows: +** +** y +** 9 - - - - - - - - - - +** 8 - - - - - - - - - - +** 7 - - - * * * * - - - +** 6 - - * * * * * - - - +** 5 - - * * - - - - - - +** 4 - - * * - * * - - - +** 3 - - * * - * * - - - +** 2 - - - - - - - - - - +** 1 - - - - - - - - - - +** 0 - - - - - - - - - - +** 0 1 2 3 4 5 6 7 8 9 x +** +** where asterisks indicate selected elements, and dashes +** indicate unselected elements. +** +** Similarly, create nine, 3-D dataspaces (10 X 10 X 10), +** and select similar irregular hyperslabs in each, three +** with the slab parallel to the xy plane, three parallel +** to the xz plane, and three parallel to the yz plane. +** Further, translate the irregular slab in 2/3rds of the +** cases. +** +** Assuming that z is the fastest changing dimension, +** H5Sselect_shape_same() should return TRUE when +** comparing the 2-D irregular hyperslab selection +** against the irregular hyperslab selections parallel +** to the yz plane in the 3-D space, and FALSE when +** comparing it against the irregular hyperslabs +** selections parallel to the xy or xz planes. +** +****************************************************************/ +static void +test_shape_same_dr__smoke_check_3(void) +{ + hid_t small_square_sid; + hid_t small_cube_xy_slice_0_sid; + hid_t small_cube_xy_slice_1_sid; + hid_t small_cube_xy_slice_2_sid; + hid_t small_cube_xz_slice_0_sid; + hid_t small_cube_xz_slice_1_sid; + hid_t small_cube_xz_slice_2_sid; + hid_t small_cube_yz_slice_0_sid; + hid_t small_cube_yz_slice_1_sid; + hid_t small_cube_yz_slice_2_sid; + hsize_t small_cube_dims[] = {10, 10, 10}; + hsize_t start[3]; + hsize_t stride[3]; + hsize_t count[3]; + hsize_t block[3]; + htri_t check; /* Shape comparison return value */ + herr_t ret; /* Generic return value */ + + MESSAGE(7, (" Smoke check 3: Offset subsets of slices through a cube.\n")); + + /* Create the 10 x 10 dataspace */ + small_square_sid = H5Screate_simple(2, small_cube_dims, NULL); + CHECK(small_square_sid, FAIL, "H5Screate_simple"); + + start[0] = 2; /* x */ + start[1] = 3; /* y */ + + stride[0] = 20; /* x */ + stride[1] = 20; /* y */ + + count[0] = 1; /* x */ + count[1] = 1; /* y */ + + block[0] = 2; /* x */ + block[1] = 4; /* y */ + ret = H5Sselect_hyperslab(small_square_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[0] = 3; /* x */ + start[1] = 6; /* y */ + + stride[0] = 20; /* x */ + stride[1] = 20; /* y */ + + count[0] = 1; /* x */ + count[1] = 1; /* y */ + + block[0] = 4; /* x */ + block[1] = 2; /* y */ + ret = H5Sselect_hyperslab(small_square_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[0] = 5; /* x */ + start[1] = 3; /* y */ + + stride[0] = 20; /* x */ + stride[1] = 20; /* y */ + + count[0] = 1; /* x */ + count[1] = 1; /* y */ + + block[0] = 2; /* x */ + block[1] = 2; /* y */ + ret = H5Sselect_hyperslab(small_square_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create the 10 X 10 X 10 dataspaces for the hyperslab parallel to the xy axis */ + small_cube_xy_slice_0_sid = H5Screate_simple(3, small_cube_dims, NULL); + CHECK(small_cube_xy_slice_0_sid, FAIL, "H5Screate_simple"); + + small_cube_xy_slice_1_sid = H5Screate_simple(3, small_cube_dims, NULL); + CHECK(small_cube_xy_slice_1_sid, FAIL, "H5Screate_simple"); + + small_cube_xy_slice_2_sid = H5Screate_simple(3, small_cube_dims, NULL); + CHECK(small_cube_xy_slice_2_sid, FAIL, "H5Screate_simple"); + + start[0] = 2; /* x */ + start[1] = 3; /* y */ + start[2] = 5; /* z */ + + stride[0] = 20; /* x */ + stride[1] = 20; /* y */ + stride[2] = 20; /* z */ + + count[0] = 1; /* x */ + count[1] = 1; /* y */ + count[2] = 1; /* z */ + + block[0] = 2; /* x */ + block[1] = 4; /* y */ + block[2] = 1; /* z */ + ret = H5Sselect_hyperslab(small_cube_xy_slice_0_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* move the starting point to the origin */ + start[0] -= 1; /* x */ + start[1] -= 2; /* y */ + ret = H5Sselect_hyperslab(small_cube_xy_slice_1_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* move the irregular selection to the upper right hand corner */ + start[0] += 5; /* x */ + start[1] += 5; /* y */ + ret = H5Sselect_hyperslab(small_cube_xy_slice_2_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[0] = 3; /* x */ + start[1] = 6; /* y */ + start[2] = 5; /* z */ + + stride[0] = 20; /* x */ + stride[1] = 20; /* y */ + stride[2] = 20; /* z */ + + count[0] = 1; /* x */ + count[1] = 1; /* y */ + count[2] = 1; /* z */ + + block[0] = 4; /* x */ + block[1] = 2; /* y */ + block[2] = 1; /* z */ + ret = H5Sselect_hyperslab(small_cube_xy_slice_0_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* move the starting point to the origin */ + start[0] -= 1; /* x */ + start[1] -= 2; /* y */ + ret = H5Sselect_hyperslab(small_cube_xy_slice_1_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* move the irregular selection to the upper right hand corner */ + start[0] += 5; /* x */ + start[1] += 5; /* y */ + ret = H5Sselect_hyperslab(small_cube_xy_slice_2_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[0] = 5; /* x */ + start[1] = 3; /* y */ + start[2] = 5; /* z */ + + stride[0] = 20; /* x */ + stride[1] = 20; /* y */ + stride[2] = 20; /* z */ + + count[0] = 1; /* x */ + count[1] = 1; /* y */ + count[2] = 1; /* z */ + + block[0] = 2; /* x */ + block[1] = 2; /* y */ + block[2] = 1; /* z */ + ret = H5Sselect_hyperslab(small_cube_xy_slice_0_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* move the starting point to the origin */ + start[0] -= 1; /* x */ + start[1] -= 2; /* y */ + ret = H5Sselect_hyperslab(small_cube_xy_slice_1_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* move the irregular selection to the upper right hand corner */ + start[0] += 5; /* x */ + start[1] += 5; /* y */ + ret = H5Sselect_hyperslab(small_cube_xy_slice_2_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create the 10 X 10 X 10 dataspaces for the hyperslab parallel to the xz axis */ + small_cube_xz_slice_0_sid = H5Screate_simple(3, small_cube_dims, NULL); + CHECK(small_cube_xz_slice_0_sid, FAIL, "H5Screate_simple"); + + small_cube_xz_slice_1_sid = H5Screate_simple(3, small_cube_dims, NULL); + CHECK(small_cube_xz_slice_1_sid, FAIL, "H5Screate_simple"); + + small_cube_xz_slice_2_sid = H5Screate_simple(3, small_cube_dims, NULL); + CHECK(small_cube_xz_slice_2_sid, FAIL, "H5Screate_simple"); + + start[0] = 2; /* x */ + start[1] = 5; /* y */ + start[2] = 3; /* z */ + + stride[0] = 20; /* x */ + stride[1] = 20; /* y */ + stride[2] = 20; /* z */ + + count[0] = 1; /* x */ + count[1] = 1; /* y */ + count[2] = 1; /* z */ + + block[0] = 2; /* x */ + block[1] = 1; /* y */ + block[2] = 4; /* z */ + ret = H5Sselect_hyperslab(small_cube_xz_slice_0_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* move the starting point to the origin */ + start[0] -= 1; /* x */ + start[2] -= 2; /* y */ + ret = H5Sselect_hyperslab(small_cube_xz_slice_1_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* move the irregular selection to the upper right hand corner */ + start[0] += 5; /* x */ + start[2] += 5; /* y */ + ret = H5Sselect_hyperslab(small_cube_xz_slice_2_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[0] = 3; /* x */ + start[1] = 5; /* y */ + start[2] = 6; /* z */ + + stride[0] = 20; /* x */ + stride[1] = 20; /* y */ + stride[2] = 20; /* z */ + + count[0] = 1; /* x */ + count[1] = 1; /* y */ + count[2] = 1; /* z */ + + block[0] = 4; /* x */ + block[1] = 1; /* y */ + block[2] = 2; /* z */ + ret = H5Sselect_hyperslab(small_cube_xz_slice_0_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* move the starting point to the origin */ + start[0] -= 1; /* x */ + start[2] -= 2; /* y */ + ret = H5Sselect_hyperslab(small_cube_xz_slice_1_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* move the irregular selection to the upper right hand corner */ + start[0] += 5; /* x */ + start[2] += 5; /* y */ + ret = H5Sselect_hyperslab(small_cube_xz_slice_2_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[0] = 5; /* x */ + start[1] = 5; /* y */ + start[2] = 3; /* z */ + + stride[0] = 20; /* x */ + stride[1] = 20; /* y */ + stride[2] = 20; /* z */ + + count[0] = 1; /* x */ + count[1] = 1; /* y */ + count[2] = 1; /* z */ + + block[0] = 2; /* x */ + block[1] = 1; /* y */ + block[2] = 2; /* z */ + ret = H5Sselect_hyperslab(small_cube_xz_slice_0_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* move the starting point to the origin */ + start[0] -= 1; /* x */ + start[2] -= 2; /* y */ + ret = H5Sselect_hyperslab(small_cube_xz_slice_1_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* move the irregular selection to the upper right hand corner */ + start[0] += 5; /* x */ + start[2] += 5; /* y */ + ret = H5Sselect_hyperslab(small_cube_xz_slice_2_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* QAK: Start here. + */ + /* Create the 10 X 10 X 10 dataspaces for the hyperslabs parallel to the yz axis */ + small_cube_yz_slice_0_sid = H5Screate_simple(3, small_cube_dims, NULL); + CHECK(small_cube_yz_slice_0_sid, FAIL, "H5Screate_simple"); + + small_cube_yz_slice_1_sid = H5Screate_simple(3, small_cube_dims, NULL); + CHECK(small_cube_yz_slice_1_sid, FAIL, "H5Screate_simple"); + + small_cube_yz_slice_2_sid = H5Screate_simple(3, small_cube_dims, NULL); + CHECK(small_cube_yz_slice_2_sid, FAIL, "H5Screate_simple"); + + start[0] = 8; /* x */ + start[1] = 2; /* y */ + start[2] = 3; /* z */ + + stride[0] = 20; /* x -- large enough that there will only be one slice */ + stride[1] = 20; /* y */ + stride[2] = 20; /* z */ + + count[0] = 1; /* x */ + count[1] = 1; /* y */ + count[2] = 1; /* z */ + + block[0] = 1; /* x */ + block[1] = 2; /* y */ + block[2] = 4; /* z */ + ret = H5Sselect_hyperslab(small_cube_yz_slice_0_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* move the starting point to the origin */ + start[1] -= 1; /* x */ + start[2] -= 2; /* y */ + ret = H5Sselect_hyperslab(small_cube_yz_slice_1_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* move the irregular selection to the upper right hand corner */ + start[0] += 5; /* x */ + start[2] += 5; /* y */ + ret = H5Sselect_hyperslab(small_cube_yz_slice_2_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[0] = 8; /* x */ + start[1] = 3; /* y */ + start[2] = 6; /* z */ + + stride[0] = 20; /* x */ + stride[1] = 20; /* y */ + stride[2] = 20; /* z */ + + count[0] = 1; /* x */ + count[1] = 1; /* y */ + count[2] = 1; /* z */ + + block[0] = 1; /* x */ + block[1] = 4; /* y */ + block[2] = 2; /* z */ + ret = H5Sselect_hyperslab(small_cube_yz_slice_0_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* move the starting point to the origin */ + start[1] -= 1; /* x */ + start[2] -= 2; /* y */ + ret = H5Sselect_hyperslab(small_cube_yz_slice_1_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* move the irregular selection to the upper right hand corner */ + start[0] += 5; /* x */ + start[2] += 5; /* y */ + ret = H5Sselect_hyperslab(small_cube_yz_slice_2_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[0] = 8; /* x */ + start[1] = 5; /* y */ + start[2] = 3; /* z */ + + stride[0] = 20; /* x */ + stride[1] = 20; /* y */ + stride[2] = 20; /* z */ + + count[0] = 1; /* x */ + count[1] = 1; /* y */ + count[2] = 1; /* z */ + + block[0] = 1; /* x */ + block[1] = 2; /* y */ + block[2] = 2; /* z */ + ret = H5Sselect_hyperslab(small_cube_yz_slice_0_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* move the starting point to the origin */ + start[1] -= 1; /* x */ + start[2] -= 2; /* y */ + ret = H5Sselect_hyperslab(small_cube_yz_slice_1_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* move the irregular selection to the upper right hand corner */ + start[0] += 5; /* x */ + start[2] += 5; /* y */ + ret = H5Sselect_hyperslab(small_cube_yz_slice_2_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* setup is done -- run the tests: */ + + /* Compare against "xy" selection */ + check = H5Sselect_shape_same(small_cube_xy_slice_0_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(small_cube_xy_slice_1_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(small_cube_xy_slice_2_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "xz" selection */ + check = H5Sselect_shape_same(small_cube_xz_slice_0_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(small_cube_xz_slice_1_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(small_cube_xz_slice_2_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Compare against "yz" selection */ + check = H5Sselect_shape_same(small_cube_yz_slice_0_sid, small_square_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(small_cube_yz_slice_1_sid, small_square_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(small_cube_yz_slice_2_sid, small_square_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + /* Close dataspaces */ + ret = H5Sclose(small_square_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_cube_xy_slice_0_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_cube_xy_slice_1_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_cube_xy_slice_2_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_cube_xz_slice_0_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_cube_xz_slice_1_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_cube_xz_slice_2_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_cube_yz_slice_0_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_cube_yz_slice_1_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_cube_yz_slice_2_sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_shape_same_dr__smoke_check_3() */ + +/**************************************************************** +** +** test_shape_same_dr__smoke_check_4(): +** +** Create a square, 2-D dataspace (10 X 10), and select +** the entire space. +** +** Similarly, create 3-D and 4-D dataspaces: +** +** (1 X 10 X 10) +** (10 X 1 X 10) +** (10 X 10 X 1) +** (10 X 10 X 10) +** +** (1 X 1 X 10 X 10) +** (1 X 10 X 1 X 10) +** (1 X 10 X 10 X 1) +** (10 X 1 X 1 X 10) +** (10 X 1 X 10 X 1) +** (10 X 10 X 1 X 1) +** (10 X 1 X 10 X 10) +** +** And select these entire spaces as well. +** +** Compare the 2-D space against all the other spaces +** with H5Sselect_shape_same(). The (1 X 10 X 10) & +** (1 X 1 X 10 X 10) should return TRUE. All others +** should return FALSE. +** +****************************************************************/ +static void +test_shape_same_dr__smoke_check_4(void) +{ + hid_t square_sid; + hid_t three_d_space_0_sid; + hid_t three_d_space_1_sid; + hid_t three_d_space_2_sid; + hid_t three_d_space_3_sid; + hid_t four_d_space_0_sid; + hid_t four_d_space_1_sid; + hid_t four_d_space_2_sid; + hid_t four_d_space_3_sid; + hid_t four_d_space_4_sid; + hid_t four_d_space_5_sid; + hid_t four_d_space_6_sid; + hsize_t dims[] = {10, 10, 10, 10}; + htri_t check; /* Shape comparison return value */ + herr_t ret; /* Generic return value */ + + MESSAGE(7, (" Smoke check 4: Spaces of different dimension but same size.\n")); + + /* Create the 10 x 10 dataspace */ + square_sid = H5Screate_simple(2, dims, NULL); + CHECK(square_sid, FAIL, "H5Screate_simple"); + + /* create (1 X 10 X 10) dataspace */ + dims[0] = 1; + dims[1] = 10; + dims[2] = 10; + three_d_space_0_sid = H5Screate_simple(3, dims, NULL); + CHECK(three_d_space_0_sid, FAIL, "H5Screate_simple"); + + /* create (10 X 1 X 10) dataspace */ + dims[0] = 10; + dims[1] = 1; + dims[2] = 10; + three_d_space_1_sid = H5Screate_simple(3, dims, NULL); + CHECK(three_d_space_1_sid, FAIL, "H5Screate_simple"); + + /* create (10 X 10 X 1) dataspace */ + dims[0] = 10; + dims[1] = 10; + dims[2] = 1; + three_d_space_2_sid = H5Screate_simple(3, dims, NULL); + CHECK(three_d_space_2_sid, FAIL, "H5Screate_simple"); + + /* create (10 X 10 X 10) dataspace */ + dims[0] = 10; + dims[1] = 10; + dims[2] = 10; + three_d_space_3_sid = H5Screate_simple(3, dims, NULL); + CHECK(three_d_space_3_sid, FAIL, "H5Screate_simple"); + + /* create (1 X 1 X 10 X 10) dataspace */ + dims[0] = 1; + dims[1] = 1; + dims[2] = 10; + dims[3] = 10; + four_d_space_0_sid = H5Screate_simple(4, dims, NULL); + CHECK(four_d_space_0_sid, FAIL, "H5Screate_simple"); + + /* create (1 X 10 X 1 X 10) dataspace */ + dims[0] = 1; + dims[1] = 10; + dims[2] = 1; + dims[3] = 10; + four_d_space_1_sid = H5Screate_simple(4, dims, NULL); + CHECK(four_d_space_1_sid, FAIL, "H5Screate_simple"); + + /* create (1 X 10 X 10 X 1) dataspace */ + dims[0] = 1; + dims[1] = 10; + dims[2] = 10; + dims[3] = 1; + four_d_space_2_sid = H5Screate_simple(4, dims, NULL); + CHECK(four_d_space_2_sid, FAIL, "H5Screate_simple"); + + /* create (10 X 1 X 1 X 10) dataspace */ + dims[0] = 10; + dims[1] = 1; + dims[2] = 1; + dims[3] = 10; + four_d_space_3_sid = H5Screate_simple(4, dims, NULL); + CHECK(four_d_space_3_sid, FAIL, "H5Screate_simple"); + + /* create (10 X 1 X 10 X 1) dataspace */ + dims[0] = 10; + dims[1] = 1; + dims[2] = 10; + dims[3] = 1; + four_d_space_4_sid = H5Screate_simple(4, dims, NULL); + CHECK(four_d_space_4_sid, FAIL, "H5Screate_simple"); + + /* create (10 X 10 X 1 X 1) dataspace */ + dims[0] = 10; + dims[1] = 10; + dims[2] = 1; + dims[3] = 1; + four_d_space_5_sid = H5Screate_simple(4, dims, NULL); + CHECK(four_d_space_5_sid, FAIL, "H5Screate_simple"); + + /* create (10 X 1 X 10 X 10) dataspace */ + dims[0] = 10; + dims[1] = 1; + dims[2] = 10; + dims[3] = 10; + four_d_space_6_sid = H5Screate_simple(4, dims, NULL); + CHECK(four_d_space_6_sid, FAIL, "H5Screate_simple"); + + /* setup is done -- run the tests: */ + + check = H5Sselect_shape_same(three_d_space_0_sid, square_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(three_d_space_1_sid, square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(three_d_space_2_sid, square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(three_d_space_3_sid, square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(four_d_space_0_sid, square_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(four_d_space_1_sid, square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(four_d_space_2_sid, square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(four_d_space_3_sid, square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(four_d_space_4_sid, square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(four_d_space_5_sid, square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + check = H5Sselect_shape_same(four_d_space_6_sid, square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); + + /* Close dataspaces */ + ret = H5Sclose(square_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(three_d_space_0_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(three_d_space_1_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(three_d_space_2_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(three_d_space_3_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(four_d_space_0_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(four_d_space_1_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(four_d_space_2_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(four_d_space_3_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(four_d_space_4_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(four_d_space_5_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(four_d_space_6_sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_shape_same_dr__smoke_check_4() */ + +/**************************************************************** +** +** test_shape_same_dr__full_space_vs_slice(): Tests selection +** of a full n-cube dataspace vs an n-dimensional slice of +** of an m-cube (m > n) in a call to H5Sselect_shape_same(). +** Note that this test does not require the n-cube and the +** n-dimensional slice to have the same rank (although +** H5Sselect_shape_same() should always return FALSE if +** they don't). +** +** Per Quincey's suggestion, only test up to 5 dimensional +** spaces. +** +****************************************************************/ +static void +test_shape_same_dr__full_space_vs_slice(int test_num, int small_rank, int large_rank, int offset, + hsize_t edge_size, hbool_t dim_selected[], hbool_t expected_result) +{ + char test_desc_0[128]; + char test_desc_1[256]; + int i; + hid_t n_cube_0_sid; /* the fully selected hyper cube */ + hid_t n_cube_1_sid; /* the hyper cube in which a slice is selected */ + hsize_t dims[SS_DR_MAX_RANK]; + hsize_t start[SS_DR_MAX_RANK]; + hsize_t *start_ptr; + hsize_t stride[SS_DR_MAX_RANK]; + hsize_t *stride_ptr; + hsize_t count[SS_DR_MAX_RANK]; + hsize_t *count_ptr; + hsize_t block[SS_DR_MAX_RANK]; + hsize_t *block_ptr; + htri_t check; /* Shape comparison return value */ + herr_t ret; /* Generic return value */ + + HDassert(0 < small_rank); + HDassert(small_rank <= large_rank); + HDassert(large_rank <= SS_DR_MAX_RANK); + HDassert(0 <= offset); + HDassert(offset < large_rank); + HDassert(edge_size > 0); + HDassert(edge_size <= 1000); + + HDsnprintf(test_desc_0, sizeof(test_desc_0), "\tn-cube slice through m-cube (n <= m) test %d.\n", + test_num); + MESSAGE(7, ("%s", test_desc_0)); + + /* This statement must be updated if SS_DR_MAX_RANK is changed */ + HDsnprintf(test_desc_1, sizeof(test_desc_1), + "\t\tranks: %d/%d offset: %d dim_selected: %d/%d/%d/%d/%d.\n", small_rank, large_rank, offset, + (int)dim_selected[0], (int)dim_selected[1], (int)dim_selected[2], (int)dim_selected[3], + (int)dim_selected[4]); + MESSAGE(7, ("%s", test_desc_1)); + + /* copy the edge size into the dims array */ + for (i = 0; i < SS_DR_MAX_RANK; i++) + dims[i] = edge_size; + + /* Create the small n-cube */ + n_cube_0_sid = H5Screate_simple(small_rank, dims, NULL); + CHECK(n_cube_0_sid, FAIL, "H5Screate_simple"); + + /* Create the large n-cube */ + n_cube_1_sid = H5Screate_simple(large_rank, dims, NULL); + CHECK(n_cube_1_sid, FAIL, "H5Screate_simple"); + + /* set up start, stride, count, and block for the hyperslab selection */ + for (i = 0; i < SS_DR_MAX_RANK; i++) { + stride[i] = 2 * edge_size; /* a bit silly in this case */ + count[i] = 1; + if (dim_selected[i]) { + start[i] = 0; + block[i] = edge_size; + } + else { + start[i] = (hsize_t)offset; + block[i] = 1; + } + } + + /* since large rank may be less than SS_DR_MAX_RANK, we may not + * use the entire start, stride, count, and block arrays. This + * is a problem, since it is inconvenient to set up the dim_selected + * array to reflect the large rank, and thus if large_rank < + * SS_DR_MAX_RANK, we need to hide the lower index entries + * from H5Sselect_hyperslab(). + * + * Do this by setting up pointers to the first valid entry in start, + * stride, count, and block below, and pass these pointers in + * to H5Sselect_hyperslab() instead of the array base addresses. + */ + + i = SS_DR_MAX_RANK - large_rank; + HDassert(i >= 0); + + start_ptr = &(start[i]); + stride_ptr = &(stride[i]); + count_ptr = &(count[i]); + block_ptr = &(block[i]); + + /* select the hyperslab */ + ret = H5Sselect_hyperslab(n_cube_1_sid, H5S_SELECT_SET, start_ptr, stride_ptr, count_ptr, block_ptr); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* setup is done -- run the test: */ + check = H5Sselect_shape_same(n_cube_0_sid, n_cube_1_sid); + VERIFY(check, expected_result, "H5Sselect_shape_same"); + + /* Close dataspaces */ + ret = H5Sclose(n_cube_0_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(n_cube_1_sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_shape_same_dr__full_space_vs_slice() */ + +/**************************************************************** +** +** test_shape_same_dr__run_full_space_vs_slice_tests(): +** +** Run the test_shape_same_dr__full_space_vs_slice() test +** over a variety of ranks and offsets. +** +** At present, we test H5Sselect_shape_same() with +** fully selected 1, 2, 3, and 4 cubes as one parameter, and +** 1, 2, 3, and 4 dimensional slices through a n-cube of rank +** no more than 5 (and at least the rank of the slice). +** We stop at rank 5, as Quincey suggested that it would be +** sufficient. +** +** All the n-cubes will have lengths of the same size, so +** H5Sselect_shape_same() should return true iff: +** +** 1) the rank for the fully selected n cube equals the +** number of dimensions selected in the slice through the +** m-cube (m >= n). +** +** 2) The dimensions selected in the slice through the m-cube +** are the dimensions with the most quickly changing +** indices. +** +****************************************************************/ +static void +test_shape_same_dr__run_full_space_vs_slice_tests(void) +{ + hbool_t dim_selected[5]; + hbool_t expected_result; + int i, j; + int v, w, x, y, z; + int test_num = 0; + int small_rank; + int large_rank; + hsize_t edge_size = 10; + + for (large_rank = 1; large_rank <= 5; large_rank++) { + for (small_rank = 1; small_rank <= large_rank; small_rank++) { + v = 0; + do { + if (v == 0) + dim_selected[0] = FALSE; + else + dim_selected[0] = TRUE; + + w = 0; + do { + if (w == 0) + dim_selected[1] = FALSE; + else + dim_selected[1] = TRUE; + + x = 0; + do { + if (x == 0) + dim_selected[2] = FALSE; + else + dim_selected[2] = TRUE; + + y = 0; + do { + if (y == 0) + dim_selected[3] = FALSE; + else + dim_selected[3] = TRUE; + + z = 0; + do { + if (z == 0) + dim_selected[4] = FALSE; + else + dim_selected[4] = TRUE; + + /* compute the expected result: */ + i = 0; + j = 4; + expected_result = TRUE; + while ((i < small_rank) && expected_result) { + if (!dim_selected[j]) + expected_result = FALSE; + i++; + j--; + } + + while ((i < large_rank) && expected_result) { + if (dim_selected[j]) + expected_result = FALSE; + i++; + j--; + } + + /* everything is set up -- run the tests */ + + test_shape_same_dr__full_space_vs_slice(test_num++, small_rank, large_rank, 0, + edge_size, dim_selected, + expected_result); + + test_shape_same_dr__full_space_vs_slice(test_num++, small_rank, large_rank, + large_rank / 2, edge_size, + dim_selected, expected_result); + + test_shape_same_dr__full_space_vs_slice(test_num++, small_rank, large_rank, + large_rank - 1, edge_size, + dim_selected, expected_result); + + z++; + } while ((z < 2) && (large_rank >= 1)); + + y++; + } while ((y < 2) && (large_rank >= 2)); + + x++; + } while ((x < 2) && (large_rank >= 3)); + + w++; + } while ((w < 2) && (large_rank >= 4)); + + v++; + } while ((v < 2) && (large_rank >= 5)); + } /* end for */ + } /* end for */ +} /* test_shape_same_dr__run_full_space_vs_slice_tests() */ + +/**************************************************************** +** +** test_shape_same_dr__checkerboard(): Tests selection of a +** "checker board" subset of a full n-cube dataspace vs +** a "checker board" n-dimensional slice of an m-cube (m > n). +** in a call to H5Sselect_shape_same(). +** +** Note that this test does not require the n-cube and the +** n-dimensional slice to have the same rank (although +** H5Sselect_shape_same() should always return FALSE if +** they don't). +** +** Per Quincey's suggestion, only test up to 5 dimensional +** spaces. +** +****************************************************************/ +static void +test_shape_same_dr__checkerboard(int test_num, int small_rank, int large_rank, int offset, hsize_t edge_size, + hsize_t checker_size, hbool_t dim_selected[], hbool_t expected_result) +{ + char test_desc_0[128]; + char test_desc_1[256]; + int i; + int dims_selected = 0; + hid_t n_cube_0_sid; /* the checker board selected + * hyper cube + */ + hid_t n_cube_1_sid; /* the hyper cube in which a + * checkerboard slice is selected + */ + hsize_t dims[SS_DR_MAX_RANK]; + hsize_t base_start[2]; + hsize_t start[SS_DR_MAX_RANK]; + hsize_t *start_ptr; + hsize_t base_stride[2]; + hsize_t stride[SS_DR_MAX_RANK]; + hsize_t *stride_ptr; + hsize_t base_count[2]; + hsize_t count[SS_DR_MAX_RANK]; + hsize_t *count_ptr; + hsize_t base_block[2]; + hsize_t block[SS_DR_MAX_RANK]; + hsize_t *block_ptr; + htri_t check; /* Shape comparison return value */ + herr_t ret; /* Generic return value */ + + HDassert(0 < small_rank); + HDassert(small_rank <= large_rank); + HDassert(large_rank <= SS_DR_MAX_RANK); + HDassert(0 < checker_size); + HDassert(checker_size <= edge_size); + HDassert(edge_size <= 1000); + HDassert(0 <= offset); + HDassert(offset < (int)edge_size); + + for (i = SS_DR_MAX_RANK - large_rank; i < SS_DR_MAX_RANK; i++) + if (dim_selected[i] == TRUE) + dims_selected++; + + HDassert(dims_selected >= 0); + HDassert(dims_selected <= large_rank); + + HDsnprintf(test_desc_0, sizeof(test_desc_0), + "\tcheckerboard n-cube slice through m-cube (n <= m) test %d.\n", test_num); + MESSAGE(7, ("%s", test_desc_0)); + + /* This statement must be updated if SS_DR_MAX_RANK is changed */ + HDsnprintf(test_desc_1, sizeof(test_desc_1), + "\tranks: %d/%d edge/chkr size: %d/%d offset: %d dim_selected: %d/%d/%d/%d/%d:%d.\n", + small_rank, large_rank, (int)edge_size, (int)checker_size, offset, (int)dim_selected[0], + (int)dim_selected[1], (int)dim_selected[2], (int)dim_selected[3], (int)dim_selected[4], + dims_selected); + MESSAGE(7, ("%s", test_desc_1)); + + /* copy the edge size into the dims array */ + for (i = 0; i < SS_DR_MAX_RANK; i++) + dims[i] = edge_size; + + /* Create the small n-cube */ + n_cube_0_sid = H5Screate_simple(small_rank, dims, NULL); + CHECK(n_cube_0_sid, FAIL, "H5Screate_simple"); + + /* Select a "checkerboard" pattern in the small n-cube. + * + * In the 1-D case, the "checkerboard" would look like this: + * + * * * - - * * - - * * + * + * and in the 2-D case, it would look like this: + * + * * * - - * * - - * * + * * * - - * * - - * * + * - - * * - - * * - - + * - - * * - - * * - - + * * * - - * * - - * * + * * * - - * * - - * * + * - - * * - - * * - - + * - - * * - - * * - - + * * * - - * * - - * * + * * * - - * * - - * * + * + * In both cases, asterisks indicate selected elements, + * and dashes indicate unselected elements. + * + * 3-D and 4-D ascii art is somewhat painful, so I'll + * leave those selections to your imagination. :-) + * + * Note, that since the edge_size and checker_size are + * parameters that are passed in, the selection need + * not look exactly like the selection shown above. + * At present, the function allows checker sizes that + * are not even divisors of the edge size -- thus + * something like the following is also possible: + * + * * * * - - - * * * - + * * * * - - - * * * - + * * * * - - - * * * - + * - - - * * * - - - * + * - - - * * * - - - * + * - - - * * * - - - * + * * * * - - - * * * - + * * * * - - - * * * - + * * * * - - - * * * - + * - - - * * * - - - * + * + * As the above pattern can't be selected in one + * call to H5Sselect_hyperslab(), and since the + * values in the start, stride, count, and block + * arrays will be repeated over all entries in + * the selected space case, and over all selected + * dimensions in the selected hyperslab case, we + * compute these values first and store them in + * in the base_start, base_stride, base_count, + * and base_block arrays. + */ + + base_start[0] = 0; + base_start[1] = checker_size; + + base_stride[0] = 2 * checker_size; + base_stride[1] = 2 * checker_size; + + /* Note that the following computation depends on the C99 + * requirement that integer division discard any fraction + * (truncation towards zero) to function correctly. As we + * now require C99, this shouldn't be a problem, but noting + * it may save us some pain if we are ever obliged to support + * pre-C99 compilers again. + */ + + base_count[0] = edge_size / (checker_size * 2); + if ((edge_size % (checker_size * 2)) > 0) + base_count[0]++; + + base_count[1] = (edge_size - checker_size) / (checker_size * 2); + if (((edge_size - checker_size) % (checker_size * 2)) > 0) + base_count[1]++; + + base_block[0] = checker_size; + base_block[1] = checker_size; + + /* now setup start, stride, count, and block arrays for + * the first call to H5Sselect_hyperslab(). + */ + for (i = 0; i < SS_DR_MAX_RANK; i++) { + start[i] = base_start[0]; + stride[i] = base_stride[0]; + count[i] = base_count[0]; + block[i] = base_block[0]; + } /* end for */ + + ret = H5Sselect_hyperslab(n_cube_0_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* if small_rank == 1, or if edge_size == checker_size, we + * are done, as either there is no added dimension in which + * to place offset selected "checkers". + * + * Otherwise, set up start, stride, count and block, and + * make the additional selection. + */ + + if ((small_rank > 1) && (checker_size < edge_size)) { + for (i = 0; i < SS_DR_MAX_RANK; i++) { + start[i] = base_start[1]; + stride[i] = base_stride[1]; + count[i] = base_count[1]; + block[i] = base_block[1]; + } /* end for */ + + ret = H5Sselect_hyperslab(n_cube_0_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + } /* end if */ + + /* Weirdness alert: + * + * Some how, it seems that selections can extend beyond the + * boundaries of the target dataspace -- hence the following + * code to manually clip the selection back to the dataspace + * proper. + */ + for (i = 0; i < SS_DR_MAX_RANK; i++) { + start[i] = 0; + stride[i] = edge_size; + count[i] = 1; + block[i] = edge_size; + } /* end for */ + + ret = H5Sselect_hyperslab(n_cube_0_sid, H5S_SELECT_AND, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create the large n-cube */ + n_cube_1_sid = H5Screate_simple(large_rank, dims, NULL); + CHECK(n_cube_1_sid, FAIL, "H5Screate_simple"); + + /* Now select the checkerboard selection in the (possibly larger) n-cube. + * + * Since we have already calculated the base start, stride, count, + * and block, re-use the values in setting up start, stride, count, + * and block. + */ + for (i = 0; i < SS_DR_MAX_RANK; i++) { + if (dim_selected[i]) { + start[i] = base_start[0]; + stride[i] = base_stride[0]; + count[i] = base_count[0]; + block[i] = base_block[0]; + } /* end if */ + else { + start[i] = (hsize_t)offset; + stride[i] = (hsize_t)(2 * edge_size); + count[i] = 1; + block[i] = 1; + } /* end else */ + } /* end for */ + + /* Since large rank may be less than SS_DR_MAX_RANK, we may not + * use the entire start, stride, count, and block arrays. This + * is a problem, since it is inconvenient to set up the dim_selected + * array to reflect the large rank, and thus if large_rank < + * SS_DR_MAX_RANK, we need to hide the lower index entries + * from H5Sselect_hyperslab(). + * + * Do this by setting up pointers to the first valid entry in start, + * stride, count, and block below, and pass these pointers in + * to H5Sselect_hyperslab() instead of the array base addresses. + */ + + i = SS_DR_MAX_RANK - large_rank; + HDassert(i >= 0); + + start_ptr = &(start[i]); + stride_ptr = &(stride[i]); + count_ptr = &(count[i]); + block_ptr = &(block[i]); + + /* select the hyperslab */ + ret = H5Sselect_hyperslab(n_cube_1_sid, H5S_SELECT_SET, start_ptr, stride_ptr, count_ptr, block_ptr); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* As before, if the number of dimensions selected is less than or + * equal to 1, or if edge_size == checker_size, we are done, as + * either there is no added dimension in which to place offset selected + * "checkers", or the hyperslab is completely occupied by one + * "checker". + * + * Otherwise, set up start, stride, count and block, and + * make the additional selection. + */ + if ((dims_selected > 1) && (checker_size < edge_size)) { + for (i = 0; i < SS_DR_MAX_RANK; i++) { + if (dim_selected[i]) { + start[i] = base_start[1]; + stride[i] = base_stride[1]; + count[i] = base_count[1]; + block[i] = base_block[1]; + } /* end if */ + else { + start[i] = (hsize_t)offset; + stride[i] = (hsize_t)(2 * edge_size); + count[i] = 1; + block[i] = 1; + } /* end else */ + } /* end for */ + + ret = H5Sselect_hyperslab(n_cube_1_sid, H5S_SELECT_OR, start_ptr, stride_ptr, count_ptr, block_ptr); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + } /* end if */ + + /* Weirdness alert: + * + * Again, it seems that selections can extend beyond the + * boundaries of the target dataspace -- hence the following + * code to manually clip the selection back to the dataspace + * proper. + */ + for (i = 0; i < SS_DR_MAX_RANK; i++) { + start[i] = 0; + stride[i] = edge_size; + count[i] = 1; + block[i] = edge_size; + } /* end for */ + + ret = H5Sselect_hyperslab(n_cube_1_sid, H5S_SELECT_AND, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* setup is done -- run the test: */ + check = H5Sselect_shape_same(n_cube_0_sid, n_cube_1_sid); + VERIFY(check, expected_result, "H5Sselect_shape_same"); + + /* Close dataspaces */ + ret = H5Sclose(n_cube_0_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(n_cube_1_sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_shape_same_dr__checkerboard() */ + +/**************************************************************** +** +** test_shape_same_dr__run_checkerboard_tests(): +** +** In this set of tests, we test H5Sselect_shape_same() +** with a "checkerboard" selection of 1, 2, 3, and 4 cubes as +** one parameter, and 1, 2, 3, and 4 dimensional checkerboard +** slices through a n-cube of rank no more than 5 (and at +** least the rank of the slice). +** +** All the n-cubes will have lengths of the same size, so +** H5Sselect_shape_same() should return true iff: +** +** 1) the rank of the n cube equals the number of dimensions +** selected in the checker board slice through the m-cube +** (m >= n). +** +** 2) The dimensions selected in the checkerboard slice +** through the m-cube are the dimensions with the most +** quickly changing indices. +** +****************************************************************/ +static void +test_shape_same_dr__run_checkerboard_tests(void) +{ + hbool_t dim_selected[5]; + hbool_t expected_result; + int i, j; + int v, w, x, y, z; + int test_num = 0; + int small_rank; + int large_rank; + + for (large_rank = 1; large_rank <= 5; large_rank++) { + for (small_rank = 1; small_rank <= large_rank; small_rank++) { + v = 0; + do { + if (v == 0) + dim_selected[0] = FALSE; + else + dim_selected[0] = TRUE; + + w = 0; + do { + if (w == 0) + dim_selected[1] = FALSE; + else + dim_selected[1] = TRUE; + + x = 0; + do { + if (x == 0) + dim_selected[2] = FALSE; + else + dim_selected[2] = TRUE; + + y = 0; + do { + if (y == 0) + dim_selected[3] = FALSE; + else + dim_selected[3] = TRUE; + + z = 0; + do { + if (z == 0) + dim_selected[4] = FALSE; + else + dim_selected[4] = TRUE; + + /* compute the expected result: */ + i = 0; + j = 4; + expected_result = TRUE; + while ((i < small_rank) && expected_result) { + if (!dim_selected[j]) + expected_result = FALSE; + i++; + j--; + } /* end while */ + + while ((i < large_rank) && expected_result) { + if (dim_selected[j]) + expected_result = FALSE; + i++; + j--; + } /* end while */ + + /* everything is set up -- run the tests */ + + /* run test with edge size 16, checker + * size 1, and a variety of offsets + */ + test_shape_same_dr__checkerboard(test_num++, small_rank, large_rank, + /* offset */ 0, + /* edge_size */ 16, + /* checker_size */ 1, dim_selected, + expected_result); + + test_shape_same_dr__checkerboard(test_num++, small_rank, large_rank, + /* offset */ 5, + /* edge_size */ 16, + /* checker_size */ 1, dim_selected, + expected_result); + + test_shape_same_dr__checkerboard(test_num++, small_rank, large_rank, + /* offset */ 15, + /* edge_size */ 16, + /* checker_size */ 1, dim_selected, + expected_result); + + /* run test with edge size 10, checker + * size 2, and a variety of offsets + */ + test_shape_same_dr__checkerboard(test_num++, small_rank, large_rank, + /* offset */ 0, + /* edge_size */ 10, + /* checker_size */ 2, dim_selected, + expected_result); + + test_shape_same_dr__checkerboard(test_num++, small_rank, large_rank, + /* offset */ 5, + /* edge_size */ 10, + /* checker_size */ 2, dim_selected, + expected_result); + + test_shape_same_dr__checkerboard(test_num++, small_rank, large_rank, + /* offset */ 9, + /* edge_size */ 10, + /* checker_size */ 2, dim_selected, + expected_result); + + /* run test with edge size 10, checker + * size 3, and a variety of offsets + */ + test_shape_same_dr__checkerboard(test_num++, small_rank, large_rank, + /* offset */ 0, + /* edge_size */ 10, + /* checker_size */ 3, dim_selected, + expected_result); + + test_shape_same_dr__checkerboard(test_num++, small_rank, large_rank, + /* offset */ 5, + /* edge_size */ 10, + /* checker_size */ 3, dim_selected, + expected_result); + + test_shape_same_dr__checkerboard(test_num++, small_rank, large_rank, + /* offset */ 9, + /* edge_size */ 10, + /* checker_size */ 3, dim_selected, + expected_result); + + /* run test with edge size 8, checker + * size 8, and a variety of offsets + */ + test_shape_same_dr__checkerboard(test_num++, small_rank, large_rank, + /* offset */ 0, + /* edge_size */ 8, + /* checker_size */ 8, dim_selected, + expected_result); + + test_shape_same_dr__checkerboard(test_num++, small_rank, large_rank, + /* offset */ 4, + /* edge_size */ 8, + /* checker_size */ 8, dim_selected, + expected_result); + + test_shape_same_dr__checkerboard(test_num++, small_rank, large_rank, + /* offset */ 7, + /* edge_size */ 8, + /* checker_size */ 8, dim_selected, + expected_result); + + z++; + } while ((z < 2) && (large_rank >= 1)); + + y++; + } while ((y < 2) && (large_rank >= 2)); + + x++; + } while ((x < 2) && (large_rank >= 3)); + + w++; + } while ((w < 2) && (large_rank >= 4)); + + v++; + } while ((v < 2) && (large_rank >= 5)); + } /* end for */ + } /* end for */ +} /* test_shape_same_dr__run_checkerboard_tests() */ + +/**************************************************************** +** +** test_shape_same_dr__irregular(): +** +** Tests selection of an "irregular" subset of a full +** n-cube dataspace vs an identical "irregular" subset +** of an n-dimensional slice of an m-cube (m > n). +** in a call to H5Sselect_shape_same(). +** +** Note that this test does not require the n-cube and the +** n-dimensional slice to have the same rank (although +** H5Sselect_shape_same() should always return FALSE if +** they don't). +** +****************************************************************/ +static void +test_shape_same_dr__irregular(int test_num, int small_rank, int large_rank, int pattern_offset, + int slice_offset, hbool_t dim_selected[], hbool_t expected_result) +{ + char test_desc_0[128]; + char test_desc_1[256]; + int edge_size = 10; + int i; + int j; + int k; + int dims_selected = 0; + hid_t n_cube_0_sid; /* the hyper cube containing + * an irregular selection + */ + hid_t n_cube_1_sid; /* the hyper cube in which a + * slice contains an irregular + * selection. + */ + hsize_t dims[SS_DR_MAX_RANK]; + hsize_t start_0[SS_DR_MAX_RANK] = {2, 2, 2, 2, 5}; + hsize_t stride_0[SS_DR_MAX_RANK] = {10, 10, 10, 10, 10}; + hsize_t count_0[SS_DR_MAX_RANK] = {1, 1, 1, 1, 1}; + hsize_t block_0[SS_DR_MAX_RANK] = {2, 2, 2, 2, 3}; + + hsize_t start_1[SS_DR_MAX_RANK] = {2, 2, 2, 5, 2}; + hsize_t stride_1[SS_DR_MAX_RANK] = {10, 10, 10, 10, 10}; + hsize_t count_1[SS_DR_MAX_RANK] = {1, 1, 1, 1, 1}; + hsize_t block_1[SS_DR_MAX_RANK] = {2, 2, 2, 3, 2}; + + hsize_t start_2[SS_DR_MAX_RANK] = {2, 2, 5, 2, 2}; + hsize_t stride_2[SS_DR_MAX_RANK] = {10, 10, 10, 10, 10}; + hsize_t count_2[SS_DR_MAX_RANK] = {1, 1, 1, 1, 1}; + hsize_t block_2[SS_DR_MAX_RANK] = {2, 2, 3, 2, 2}; + + hsize_t start_3[SS_DR_MAX_RANK] = {2, 5, 2, 2, 2}; + hsize_t stride_3[SS_DR_MAX_RANK] = {10, 10, 10, 10, 10}; + hsize_t count_3[SS_DR_MAX_RANK] = {1, 1, 1, 1, 1}; + hsize_t block_3[SS_DR_MAX_RANK] = {2, 3, 2, 2, 2}; + + hsize_t start_4[SS_DR_MAX_RANK] = {5, 2, 2, 2, 2}; + hsize_t stride_4[SS_DR_MAX_RANK] = {10, 10, 10, 10, 10}; + hsize_t count_4[SS_DR_MAX_RANK] = {1, 1, 1, 1, 1}; + hsize_t block_4[SS_DR_MAX_RANK] = {3, 2, 2, 2, 2}; + + hsize_t clip_start[SS_DR_MAX_RANK] = {0, 0, 0, 0, 0}; + hsize_t clip_stride[SS_DR_MAX_RANK] = {10, 10, 10, 10, 10}; + hsize_t clip_count[SS_DR_MAX_RANK] = {1, 1, 1, 1, 1}; + hsize_t clip_block[SS_DR_MAX_RANK] = {10, 10, 10, 10, 10}; + + hsize_t *(starts[SS_DR_MAX_RANK]) = {start_0, start_1, start_2, start_3, start_4}; + hsize_t *(strides[SS_DR_MAX_RANK]) = {stride_0, stride_1, stride_2, stride_3, stride_4}; + hsize_t *(counts[SS_DR_MAX_RANK]) = {count_0, count_1, count_2, count_3, count_4}; + hsize_t *(blocks[SS_DR_MAX_RANK]) = {block_0, block_1, block_2, block_3, block_4}; + + hsize_t start[SS_DR_MAX_RANK]; + hsize_t *start_ptr; + hsize_t stride[SS_DR_MAX_RANK]; + hsize_t *stride_ptr; + hsize_t count[SS_DR_MAX_RANK]; + hsize_t *count_ptr; + hsize_t block[SS_DR_MAX_RANK]; + hsize_t *block_ptr; + htri_t check; /* Shape comparison return value */ + herr_t ret; /* Generic return value */ + + HDassert(0 < small_rank); + HDassert(small_rank <= large_rank); + HDassert(large_rank <= SS_DR_MAX_RANK); + HDassert(9 <= edge_size); + HDassert(edge_size <= 1000); + HDassert(0 <= slice_offset); + HDassert(slice_offset < edge_size); + HDassert(-2 <= pattern_offset); + HDassert(pattern_offset <= 2); + + for (i = SS_DR_MAX_RANK - large_rank; i < SS_DR_MAX_RANK; i++) + if (dim_selected[i] == TRUE) + dims_selected++; + + HDassert(dims_selected >= 0); + HDassert(dims_selected <= large_rank); + + HDsnprintf(test_desc_0, sizeof(test_desc_0), + "\tirregular sub set of n-cube slice through m-cube (n <= m) test %d.\n", test_num); + MESSAGE(7, ("%s", test_desc_0)); + + /* This statement must be updated if SS_DR_MAX_RANK is changed */ + HDsnprintf(test_desc_1, sizeof(test_desc_1), + "\tranks: %d/%d edge: %d s/p offset: %d/%d dim_selected: %d/%d/%d/%d/%d:%d.\n", small_rank, + large_rank, edge_size, slice_offset, pattern_offset, (int)dim_selected[0], + (int)dim_selected[1], (int)dim_selected[2], (int)dim_selected[3], (int)dim_selected[4], + dims_selected); + MESSAGE(7, ("%s", test_desc_1)); + + /* copy the edge size into the dims array */ + for (i = 0; i < SS_DR_MAX_RANK; i++) + dims[i] = (hsize_t)edge_size; + + /* Create the small n-cube */ + n_cube_0_sid = H5Screate_simple(small_rank, dims, NULL); + CHECK(n_cube_0_sid, FAIL, "H5Screate_simple"); + + /* Select an "irregular" pattern in the small n-cube. This + * pattern can be though of a set of four 3 x 2 x 2 X 2 + * four dimensional prisims, each parallel to one of the + * axies and none of them intersecting with the other. + * + * In the lesser dimensional cases, this 4D pattern is + * projected onto the lower dimensional space. + * + * In the 1-D case, the projection of the pattern looks + * like this: + * + * - - * * - * * * - - + * 0 1 2 3 4 5 6 7 8 9 x + * + * and in the 2-D case, it would look like this: + * + * + * y + * 9 - - - - - - - - - - + * 8 - - - - - - - - - - + * 7 - - * * - - - - - - + * 6 - - * * - - - - - - + * 5 - - * * - - - - - - + * 4 - - - - - - - - - - + * 3 - - * * - * * * - - + * 2 - - * * - * * * - - + * 1 - - - - - - - - - - + * 0 - - - - - - - - - - + * 0 1 2 3 4 5 6 7 8 9 x + * + * In both cases, asterisks indicate selected elements, + * and dashes indicate unselected elements. + * + * Note that is this case, since the edge size is fixed, + * the pattern does not change. However, we do use the + * displacement parameter to allow it to be moved around + * within the n-cube or hyperslab. + */ + + /* first, ensure that the small n-cube has no selection */ + ret = H5Sselect_none(n_cube_0_sid); + CHECK(ret, FAIL, "H5Sselect_none"); + + /* now, select the irregular pattern */ + for (i = 0; i < SS_DR_MAX_RANK; i++) { + ret = H5Sselect_hyperslab(n_cube_0_sid, H5S_SELECT_OR, starts[i], strides[i], counts[i], blocks[i]); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + } /* end for */ + + /* finally, clip the selection to ensure that it lies fully + * within the n-cube. + */ + ret = H5Sselect_hyperslab(n_cube_0_sid, H5S_SELECT_AND, clip_start, clip_stride, clip_count, clip_block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create the large n-cube */ + n_cube_1_sid = H5Screate_simple(large_rank, dims, NULL); + CHECK(n_cube_1_sid, FAIL, "H5Screate_simple"); + + /* Ensure that the large n-cube has no selection */ + H5Sselect_none(n_cube_1_sid); + CHECK(ret, FAIL, "H5Sselect_none"); + + /* Since large rank may be less than SS_DR_MAX_RANK, we may not + * use the entire start, stride, count, and block arrays. This + * is a problem, since it is inconvenient to set up the dim_selected + * array to reflect the large rank, and thus if large_rank < + * SS_DR_MAX_RANK, we need to hide the lower index entries + * from H5Sselect_hyperslab(). + * + * Do this by setting up pointers to the first valid entry in start, + * stride, count, and block below, and pass these pointers in + * to H5Sselect_hyperslab() instead of the array base addresses. + */ + + i = SS_DR_MAX_RANK - large_rank; + HDassert(i >= 0); + + start_ptr = &(start[i]); + stride_ptr = &(stride[i]); + count_ptr = &(count[i]); + block_ptr = &(block[i]); + + /* Now select the irregular selection in the (possibly larger) n-cube. + * + * Basic idea is to project the pattern used in the smaller n-cube + * onto the dimensions selected in the larger n-cube, with the displacement + * specified. + */ + for (i = 0; i < SS_DR_MAX_RANK; i++) { + j = 0; + for (k = 0; k < SS_DR_MAX_RANK; k++) { + if (dim_selected[k]) { + start[k] = (starts[i])[j] + (hsize_t)pattern_offset; + stride[k] = (strides[i])[j]; + count[k] = (counts[i])[j]; + block[k] = (blocks[i])[j]; + j++; + } /* end if */ + else { + start[k] = (hsize_t)slice_offset; + stride[k] = (hsize_t)(2 * edge_size); + count[k] = 1; + block[k] = 1; + } /* end else */ + } /* end for */ + + /* select the hyperslab */ + ret = H5Sselect_hyperslab(n_cube_1_sid, H5S_SELECT_OR, start_ptr, stride_ptr, count_ptr, block_ptr); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + } /* end for */ + + /* it is possible that the selection extends beyond the dataspace. + * clip the selection to ensure that it doesn't. + */ + ret = H5Sselect_hyperslab(n_cube_1_sid, H5S_SELECT_AND, clip_start, clip_stride, clip_count, clip_block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* setup is done -- run the test: */ + check = H5Sselect_shape_same(n_cube_0_sid, n_cube_1_sid); + VERIFY(check, expected_result, "H5Sselect_shape_same"); + + /* Close dataspaces */ + ret = H5Sclose(n_cube_0_sid); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(n_cube_1_sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_shape_same_dr__irregular() */ + +/**************************************************************** +** +** test_shape_same_dr__run_irregular_tests(): +** +** In this set of tests, we test H5Sselect_shape_same() +** with an "irregular" subselection of 1, 2, 3, and 4 cubes as +** one parameter, and irregular subselections of 1, 2, 3, +** and 4 dimensional slices through a n-cube of rank no more +** than 5 (and at least the rank of the slice) as the other. +** Note that the "irregular" selection may be offset between +** the n-cube and the slice. +** +** All the irregular selections will be identical (modulo rank) +** so H5Sselect_shape_same() should return true iff: +** +** 1) the rank of the n cube equals the number of dimensions +** selected in the irregular slice through the m-cube +** (m >= n). +** +** 2) The dimensions selected in the irregular slice +** through the m-cube are the dimensions with the most +** quickly changing indices. +** +****************************************************************/ +static void +test_shape_same_dr__run_irregular_tests(void) +{ + hbool_t dim_selected[5]; + hbool_t expected_result; + int i, j; + int v, w, x, y, z; + int test_num = 0; + int small_rank; + int large_rank; + + for (large_rank = 1; large_rank <= 5; large_rank++) { + for (small_rank = 1; small_rank <= large_rank; small_rank++) { + v = 0; + do { + if (v == 0) + dim_selected[0] = FALSE; + else + dim_selected[0] = TRUE; + + w = 0; + do { + if (w == 0) + dim_selected[1] = FALSE; + else + dim_selected[1] = TRUE; + + x = 0; + do { + if (x == 0) + dim_selected[2] = FALSE; + else + dim_selected[2] = TRUE; + + y = 0; + do { + if (y == 0) + dim_selected[3] = FALSE; + else + dim_selected[3] = TRUE; + + z = 0; + do { + if (z == 0) + dim_selected[4] = FALSE; + else + dim_selected[4] = TRUE; + + /* compute the expected result: */ + i = 0; + j = 4; + expected_result = TRUE; + while ((i < small_rank) && expected_result) { + if (!dim_selected[j]) + expected_result = FALSE; + i++; + j--; + } /* end while */ + + while ((i < large_rank) && expected_result) { + if (dim_selected[j]) + expected_result = FALSE; + i++; + j--; + } /* end while */ + + /* everything is set up -- run the tests */ + + test_shape_same_dr__irregular(test_num++, small_rank, large_rank, + /* pattern_offset */ -2, + /* slice_offset */ 0, dim_selected, + expected_result); + + test_shape_same_dr__irregular(test_num++, small_rank, large_rank, + /* pattern_offset */ -2, + /* slice_offset */ 4, dim_selected, + expected_result); + + test_shape_same_dr__irregular(test_num++, small_rank, large_rank, + /* pattern_offset */ -2, + /* slice_offset */ 9, dim_selected, + expected_result); + + test_shape_same_dr__irregular(test_num++, small_rank, large_rank, + /* pattern_offset */ 0, + /* slice_offset */ 0, dim_selected, + expected_result); + + test_shape_same_dr__irregular(test_num++, small_rank, large_rank, + /* pattern_offset */ 0, + /* slice_offset */ 6, dim_selected, + expected_result); + + test_shape_same_dr__irregular(test_num++, small_rank, large_rank, + /* pattern_offset */ 0, + /* slice_offset */ 9, dim_selected, + expected_result); + + test_shape_same_dr__irregular(test_num++, small_rank, large_rank, + /* pattern_offset */ 2, + /* slice_offset */ 0, dim_selected, + expected_result); + + test_shape_same_dr__irregular(test_num++, small_rank, large_rank, + /* pattern_offset */ 2, + /* slice_offset */ 5, dim_selected, + expected_result); + + test_shape_same_dr__irregular(test_num++, small_rank, large_rank, + /* pattern_offset */ 2, + /* slice_offset */ 9, dim_selected, + expected_result); + + z++; + } while ((z < 2) && (large_rank >= 1)); + + y++; + } while ((y < 2) && (large_rank >= 2)); + + x++; + } while ((x < 2) && (large_rank >= 3)); + + w++; + } while ((w < 2) && (large_rank >= 4)); + + v++; + } while ((v < 2) && (large_rank >= 5)); + } /* end for */ + } /* end for */ +} /* test_shape_same_dr__run_irregular_tests() */ + +/**************************************************************** +** +** test_shape_same_dr(): Tests selections on dataspace with +** different ranks, to verify that "shape same" routine +** is now handling this case correctly. +** +****************************************************************/ +static void +test_shape_same_dr(void) +{ + /* Output message about test being performed */ + MESSAGE(6, ("Testing Same Shape/Different Rank Comparisons\n")); + + /* first run some smoke checks */ + test_shape_same_dr__smoke_check_1(); + test_shape_same_dr__smoke_check_2(); + test_shape_same_dr__smoke_check_3(); + test_shape_same_dr__smoke_check_4(); + + /* now run more intensive tests. */ + test_shape_same_dr__run_full_space_vs_slice_tests(); + test_shape_same_dr__run_checkerboard_tests(); + test_shape_same_dr__run_irregular_tests(); +} /* test_shape_same_dr() */ + +/**************************************************************** +** +** test_space_rebuild(): Tests selection rebuild routine, +** We will test whether selection in span-tree form can be rebuilt +** into a regular selection. +** +** +****************************************************************/ +static void +test_space_rebuild(void) +{ + /* regular space IDs in span-tree form */ + hid_t sid_reg1, sid_reg2, sid_reg3, sid_reg4, sid_reg5; + + /* Original regular Space IDs */ + hid_t sid_reg_ori1, sid_reg_ori2, sid_reg_ori3, sid_reg_ori4, sid_reg_ori5; + + /* Irregular space IDs */ + hid_t sid_irreg1, sid_irreg2, sid_irreg3, sid_irreg4, sid_irreg5; + + /* rebuild status state */ +#if 0 + H5S_diminfo_valid_t rebuild_stat1, rebuild_stat2; + htri_t rebuild_check; +#endif + herr_t ret; + + /* dimensions of rank 1 to rank 5 */ + hsize_t dims1[] = {SPACERE1_DIM0}; + hsize_t dims2[] = {SPACERE2_DIM0, SPACERE2_DIM1}; + hsize_t dims3[] = {SPACERE3_DIM0, SPACERE3_DIM1, SPACERE3_DIM2}; + hsize_t dims4[] = {SPACERE4_DIM0, SPACERE4_DIM1, SPACERE4_DIM2, SPACERE4_DIM3}; + hsize_t dims5[] = {SPACERE5_DIM0, SPACERE5_DIM1, SPACERE5_DIM2, SPACERE5_DIM3, SPACERE5_DIM4}; + + /* The start of the hyperslab */ + hsize_t start1[SPACERE1_RANK], start2[SPACERE2_RANK], start3[SPACERE3_RANK], start4[SPACERE4_RANK], + start5[SPACERE5_RANK]; + + /* The stride of the hyperslab */ + hsize_t stride1[SPACERE1_RANK], stride2[SPACERE2_RANK], stride3[SPACERE3_RANK], stride4[SPACERE4_RANK], + stride5[SPACERE5_RANK]; + + /* The number of blocks for the hyperslab */ + hsize_t count1[SPACERE1_RANK], count2[SPACERE2_RANK], count3[SPACERE3_RANK], count4[SPACERE4_RANK], + count5[SPACERE5_RANK]; + + /* The size of each block for the hyperslab */ + hsize_t block1[SPACERE1_RANK], block2[SPACERE2_RANK], block3[SPACERE3_RANK], block4[SPACERE4_RANK], + block5[SPACERE5_RANK]; + + /* Declarations for special test of rebuild */ + hid_t sid_spec; + + /* Output message about test being performed */ + MESSAGE(6, ("Testing functionality to rebuild regular hyperslab selection\n")); + + MESSAGE(7, ("Testing functionality to rebuild 1-D hyperslab selection\n")); + + /* Create 1-D dataspace */ + sid_reg1 = H5Screate_simple(SPACERE1_RANK, dims1, NULL); + sid_reg_ori1 = H5Screate_simple(SPACERE1_RANK, dims1, NULL); + + /* Build up the original one dimensional regular selection */ + start1[0] = 1; + count1[0] = 3; + stride1[0] = 5; + block1[0] = 4; + ret = H5Sselect_hyperslab(sid_reg_ori1, H5S_SELECT_SET, start1, stride1, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Build up one dimensional regular selection with H5_SELECT_OR, + inside HDF5, it will be treated as an irregular selection. */ + + start1[0] = 1; + count1[0] = 2; + stride1[0] = 5; + block1[0] = 4; + ret = H5Sselect_hyperslab(sid_reg1, H5S_SELECT_SET, start1, stride1, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start1[0] = 11; + count1[0] = 1; + stride1[0] = 5; + block1[0] = 4; + ret = H5Sselect_hyperslab(sid_reg1, H5S_SELECT_OR, start1, stride1, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + ret = H5S__get_rebuild_status_test(sid_reg1, &rebuild_stat1, &rebuild_stat2); + CHECK(ret, FAIL, "H5S__get_rebuild_status_test"); + /* In this case, rebuild_stat1 and rebuild_stat2 should be + * H5S_DIMINFO_VALID_YES. */ + if (rebuild_stat1 != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } + if (rebuild_stat2 != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } + if (ret != FAIL) { + /* In this case, rebuild_check should be TRUE. */ + rebuild_check = H5Sselect_shape_same(sid_reg1, sid_reg_ori1); + CHECK(rebuild_check, FALSE, "H5Sselect_shape_same"); + } +#endif + /* For irregular hyperslab */ + sid_irreg1 = H5Screate_simple(SPACERE1_RANK, dims1, NULL); + + /* Build up one dimensional irregular selection with H5_SELECT_OR */ + start1[0] = 1; + count1[0] = 2; + stride1[0] = 5; + block1[0] = 4; + ret = H5Sselect_hyperslab(sid_irreg1, H5S_SELECT_SET, start1, stride1, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start1[0] = 12; /* Just one position switch */ + count1[0] = 1; + stride1[0] = 5; + block1[0] = 4; + ret = H5Sselect_hyperslab(sid_irreg1, H5S_SELECT_OR, start1, stride1, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + ret = H5S__get_rebuild_status_test(sid_irreg1, &rebuild_stat1, &rebuild_stat2); + CHECK(ret, FAIL, "H5S__get_rebuild_status_test"); + /* In this case, rebuild_stat1 should be H5S_DIMINFO_VALID_NO and + * rebuild_stat2 should be H5S_DIMINFO_VALID_IMPOSSIBLE. */ + if (rebuild_stat1 != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } + if (rebuild_stat2 != H5S_DIMINFO_VALID_IMPOSSIBLE) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } + /* No need to do shape comparison */ +#endif + + MESSAGE(7, ("Testing functionality to rebuild 2-D hyperslab selection\n")); + /* Create 2-D dataspace */ + sid_reg2 = H5Screate_simple(SPACERE2_RANK, dims2, NULL); + sid_reg_ori2 = H5Screate_simple(SPACERE2_RANK, dims2, NULL); + + /* Build up the original two dimensional regular selection */ + start2[0] = 2; + count2[0] = 2; + stride2[0] = 7; + block2[0] = 5; + start2[1] = 1; + count2[1] = 3; + stride2[1] = 3; + block2[1] = 2; + + ret = H5Sselect_hyperslab(sid_reg_ori2, H5S_SELECT_SET, start2, stride2, count2, block2); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Build up two dimensional regular selection with H5_SELECT_OR, inside HDF5, + it will be treated as an irregular selection. */ + + start2[1] = 1; + count2[1] = 2; + stride2[1] = 3; + block2[1] = 2; + + ret = H5Sselect_hyperslab(sid_reg2, H5S_SELECT_SET, start2, stride2, count2, block2); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start2[1] = 7; /* 7 = start(1) + count(2) * stride(3) */ + count2[1] = 1; + stride2[1] = 3; + block2[1] = 2; + + ret = H5Sselect_hyperslab(sid_reg2, H5S_SELECT_OR, start2, stride2, count2, block2); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + ret = H5S__get_rebuild_status_test(sid_reg2, &rebuild_stat1, &rebuild_stat2); + CHECK(ret, FAIL, "H5S__get_rebuild_status_test"); + /* In this case, rebuild_stat1 and rebuild_stat2 should be + * H5S_DIMINFO_VALID_YES. */ + if (rebuild_stat1 != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } + if (rebuild_stat2 != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } /* end if */ + if (ret != FAIL) { + /* In this case, rebuild_check should be TRUE. */ + rebuild_check = H5Sselect_shape_same(sid_reg2, sid_reg_ori2); + CHECK(rebuild_check, FALSE, "H5Sselect_shape_same"); + } +#endif + /* 2-D irregular case */ + sid_irreg2 = H5Screate_simple(SPACERE2_RANK, dims2, NULL); + /* Build up two dimensional irregular selection with H5_SELECT_OR */ + + start2[0] = 2; + count2[0] = 2; + stride2[0] = 7; + block2[0] = 5; + start2[1] = 1; + count2[1] = 1; + stride2[1] = 3; + block2[1] = 2; + ret = H5Sselect_hyperslab(sid_irreg2, H5S_SELECT_SET, start2, stride2, count2, block2); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start2[1] = 4; + count2[1] = 2; + stride2[1] = 4; + block2[1] = 3; /* Just add one element for the block */ + + ret = H5Sselect_hyperslab(sid_irreg2, H5S_SELECT_OR, start2, stride2, count2, block2); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + ret = H5S__get_rebuild_status_test(sid_irreg2, &rebuild_stat1, &rebuild_stat2); + CHECK(ret, FAIL, "H5S__get_rebuild_status_test"); + /* In this case, rebuild_stat1 should be H5S_DIMINFO_VALID_NO and + * rebuild_stat2 should be H5S_DIMINFO_VALID_IMPOSSIBLE. */ + if (rebuild_stat1 != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } + if (rebuild_stat2 != H5S_DIMINFO_VALID_IMPOSSIBLE) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } + /* No need to do shape comparison */ +#endif + + MESSAGE(7, ("Testing functionality to rebuild 3-D hyperslab selection\n")); + + /* Create 3-D dataspace */ + sid_reg3 = H5Screate_simple(SPACERE3_RANK, dims3, NULL); + sid_reg_ori3 = H5Screate_simple(SPACERE3_RANK, dims3, NULL); + + /* Build up the original three dimensional regular selection */ + start3[0] = 2; + count3[0] = 2; + stride3[0] = 3; + block3[0] = 2; + start3[1] = 1; + count3[1] = 3; + stride3[1] = 3; + block3[1] = 2; + + start3[2] = 1; + count3[2] = 2; + stride3[2] = 4; + block3[2] = 2; + + ret = H5Sselect_hyperslab(sid_reg_ori3, H5S_SELECT_SET, start3, stride3, count3, block3); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Build up three dimensional regular selection with H5_SELECT_OR, inside HDF5, + it will be treated as an irregular selection. */ + start3[2] = 1; + count3[2] = 1; + stride3[2] = 4; + block3[2] = 2; + + ret = H5Sselect_hyperslab(sid_reg3, H5S_SELECT_SET, start3, stride3, count3, block3); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start3[2] = 5; + count3[2] = 1; + stride3[2] = 4; + block3[2] = 2; + + ret = H5Sselect_hyperslab(sid_reg3, H5S_SELECT_OR, start3, stride3, count3, block3); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + ret = H5S__get_rebuild_status_test(sid_reg3, &rebuild_stat1, &rebuild_stat2); + CHECK(ret, FAIL, "H5S__get_rebuild_status_test"); + /* In this case, rebuild_stat1 and rebuild_stat2 should be + * H5S_DIMINFO_VALID_YES. */ + if (rebuild_stat1 != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } + if (rebuild_stat2 != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } + if (ret != FAIL) { + /* In this case, rebuild_check should be TRUE. */ + rebuild_check = H5Sselect_shape_same(sid_reg3, sid_reg_ori3); + CHECK(rebuild_check, FALSE, "H5Sselect_shape_same"); + } +#endif + + sid_irreg3 = H5Screate_simple(SPACERE3_RANK, dims3, NULL); + + /* Build up three dimensional irregular selection with H5_SELECT_OR */ + start3[0] = 2; + count3[0] = 2; + stride3[0] = 3; + block3[0] = 2; + start3[1] = 1; + count3[1] = 3; + stride3[1] = 3; + block3[1] = 2; + + start3[2] = 1; + count3[2] = 2; + stride3[2] = 2; + block3[2] = 1; + + ret = H5Sselect_hyperslab(sid_irreg3, H5S_SELECT_SET, start3, stride3, count3, block3); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start3[2] = 3; + count3[2] = 2; + stride3[2] = 3; /* Just add one element for the stride */ + block3[2] = 1; + + ret = H5Sselect_hyperslab(sid_irreg3, H5S_SELECT_OR, start3, stride3, count3, block3); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + ret = H5S__get_rebuild_status_test(sid_irreg3, &rebuild_stat1, &rebuild_stat2); + CHECK(ret, FAIL, "H5S__get_rebuild_status_test"); + /* In this case, rebuild_stat1 should be H5S_DIMINFO_VALID_NO and + * rebuild_stat2 should be H5S_DIMINFO_VALID_IMPOSSIBLE. */ + if (rebuild_stat1 != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } + if (rebuild_stat2 != H5S_DIMINFO_VALID_IMPOSSIBLE) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } + /* No need to do shape comparison */ +#endif + + MESSAGE(7, ("Testing functionality to rebuild 4-D hyperslab selection\n")); + + /* Create 4-D dataspace */ + sid_reg4 = H5Screate_simple(SPACERE4_RANK, dims4, NULL); + sid_reg_ori4 = H5Screate_simple(SPACERE4_RANK, dims4, NULL); + + /* Build up the original four dimensional regular selection */ + start4[0] = 2; + count4[0] = 2; + stride4[0] = 3; + block4[0] = 2; + + start4[1] = 1; + count4[1] = 3; + stride4[1] = 3; + block4[1] = 2; + + start4[2] = 1; + count4[2] = 2; + stride4[2] = 4; + block4[2] = 2; + + start4[3] = 1; + count4[3] = 2; + stride4[3] = 4; + block4[3] = 2; + + ret = H5Sselect_hyperslab(sid_reg_ori4, H5S_SELECT_SET, start4, stride4, count4, block4); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Build up four dimensional regular selection with H5_SELECT_OR, inside HDF5, + it will be treated as an irregular selection. */ + start4[3] = 1; + count4[3] = 1; + stride4[3] = 4; + block4[3] = 2; + + ret = H5Sselect_hyperslab(sid_reg4, H5S_SELECT_SET, start4, stride4, count4, block4); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start4[3] = 5; + count4[3] = 1; + stride4[3] = 4; + block4[3] = 2; + + ret = H5Sselect_hyperslab(sid_reg4, H5S_SELECT_OR, start4, stride4, count4, block4); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + +#if 0 + ret = H5S__get_rebuild_status_test(sid_reg4, &rebuild_stat1, &rebuild_stat2); + CHECK(ret, FAIL, "H5S__get_rebuild_status_test"); + /* In this case, rebuild_stat1 and rebuild_stat2 should be + * H5S_DIMINFO_VALID_YES. */ + if (rebuild_stat1 != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } + if (rebuild_stat2 != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } + if (ret != FAIL) { + /* In this case, rebuild_check should be TRUE. */ + rebuild_check = H5Sselect_shape_same(sid_reg4, sid_reg_ori4); + CHECK(rebuild_check, FALSE, "H5Sselect_shape_same"); + } +#endif + + /* Testing irregular selection */ + sid_irreg4 = H5Screate_simple(SPACERE4_RANK, dims4, NULL); + + /* Build up four dimensional irregular selection with H5_SELECT_OR */ + start4[0] = 2; + count4[0] = 2; + stride4[0] = 3; + block4[0] = 2; + start4[1] = 1; + count4[1] = 3; + stride4[1] = 3; + block4[1] = 2; + + start4[2] = 1; + count4[2] = 1; + stride4[2] = 4; + block4[2] = 2; + + start4[3] = 1; + count4[3] = 2; + stride4[3] = 4; + block4[3] = 2; /* sub-block is one element difference */ + + ret = H5Sselect_hyperslab(sid_irreg4, H5S_SELECT_SET, start4, stride4, count4, block4); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start4[2] = 5; + count4[2] = 1; + stride4[2] = 4; + block4[2] = 2; + + start4[3] = 1; + count4[3] = 2; + stride4[3] = 4; + block4[3] = 3; /* sub-block is one element difference */ + + ret = H5Sselect_hyperslab(sid_irreg4, H5S_SELECT_OR, start4, stride4, count4, block4); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + ret = H5S__get_rebuild_status_test(sid_irreg4, &rebuild_stat1, &rebuild_stat2); + CHECK(ret, FAIL, "H5S__get_rebuild_status_test"); + /* In this case, rebuild_stat1 should be H5S_DIMINFO_VALID_NO and + * rebuild_stat2 should be H5S_DIMINFO_VALID_IMPOSSIBLE. */ + if (rebuild_stat1 != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } + if (rebuild_stat2 != H5S_DIMINFO_VALID_IMPOSSIBLE) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } + /* No need to do shape comparison */ +#endif + + MESSAGE(7, ("Testing functionality to rebuild 5-D hyperslab selection\n")); + + /* Create 5-D dataspace */ + sid_reg5 = H5Screate_simple(SPACERE5_RANK, dims5, NULL); + sid_reg_ori5 = H5Screate_simple(SPACERE5_RANK, dims5, NULL); + + /* Build up the original five dimensional regular selection */ + start5[0] = 2; + count5[0] = 2; + stride5[0] = 3; + block5[0] = 2; + + start5[1] = 1; + count5[1] = 3; + stride5[1] = 3; + block5[1] = 2; + + start5[2] = 1; + count5[2] = 2; + stride5[2] = 4; + block5[2] = 2; + + start5[3] = 1; + count5[3] = 2; + stride5[3] = 4; + block5[3] = 2; + + start5[4] = 1; + count5[4] = 2; + stride5[4] = 4; + block5[4] = 2; + + ret = H5Sselect_hyperslab(sid_reg_ori5, H5S_SELECT_SET, start5, stride5, count5, block5); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Build up five dimensional regular selection with H5_SELECT_OR, inside HDF5, + it will be treated as an irregular selection. */ + start5[4] = 1; + count5[4] = 1; + stride5[4] = 4; + block5[4] = 2; + + ret = H5Sselect_hyperslab(sid_reg5, H5S_SELECT_SET, start5, stride5, count5, block5); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start5[4] = 5; + count5[4] = 1; + stride5[4] = 4; + block5[4] = 2; + + ret = H5Sselect_hyperslab(sid_reg5, H5S_SELECT_OR, start5, stride5, count5, block5); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + +#if 0 + ret = H5S__get_rebuild_status_test(sid_reg5, &rebuild_stat1, &rebuild_stat2); + CHECK(ret, FAIL, "H5S__get_rebuild_status_test"); + /* In this case, rebuild_stat1 and rebuild_stat2 should be + * H5S_DIMINFO_VALID_YES. */ + if (rebuild_stat1 != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } + if (rebuild_stat2 != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } + if (ret != FAIL) { + /* In this case, rebuild_check should be TRUE. */ + rebuild_check = H5Sselect_shape_same(sid_reg5, sid_reg_ori5); + CHECK(rebuild_check, FALSE, "H5Sselect_shape_same"); + } +#endif + + sid_irreg5 = H5Screate_simple(SPACERE5_RANK, dims5, NULL); + + /* Build up five dimensional irregular selection with H5_SELECT_OR */ + start5[0] = 2; + count5[0] = 2; + stride5[0] = 3; + block5[0] = 2; + + start5[1] = 1; + count5[1] = 3; + stride5[1] = 3; + block5[1] = 2; + + start5[2] = 1; + count5[2] = 2; + stride5[2] = 4; + block5[2] = 2; + + start5[3] = 1; + count5[3] = 1; + stride5[3] = 4; + block5[3] = 2; + + start5[4] = 2; /* One element difference */ + count5[4] = 1; + stride5[4] = 4; + block5[4] = 2; + + ret = H5Sselect_hyperslab(sid_irreg5, H5S_SELECT_SET, start5, stride5, count5, block5); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start5[3] = 5; + count5[3] = 1; + stride5[3] = 4; + block5[3] = 2; + + start5[4] = 1; /* One element difference */ + count5[4] = 2; + stride5[4] = 4; + block5[4] = 2; + + ret = H5Sselect_hyperslab(sid_irreg5, H5S_SELECT_OR, start5, stride5, count5, block5); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + ret = H5S__get_rebuild_status_test(sid_irreg5, &rebuild_stat1, &rebuild_stat2); + CHECK(ret, FAIL, "H5S__get_rebuild_status_test"); + /* In this case, rebuild_stat1 should be H5S_DIMINFO_VALID_NO and + * rebuild_stat2 should be H5S_DIMINFO_VALID_IMPOSSIBLE. */ + if (rebuild_stat1 != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } + if (rebuild_stat2 != H5S_DIMINFO_VALID_IMPOSSIBLE) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } + /* No need to do shape comparison */ +#endif + + /* We use 5-D to test a special case with + rebuilding routine TRUE, FALSE and TRUE */ + sid_spec = H5Screate_simple(SPACERE5_RANK, dims5, NULL); + + /* Build up the original five dimensional regular selection */ + start5[0] = 2; + count5[0] = 2; + stride5[0] = 3; + block5[0] = 2; + + start5[1] = 1; + count5[1] = 3; + stride5[1] = 3; + block5[1] = 2; + + start5[2] = 1; + count5[2] = 2; + stride5[2] = 4; + block5[2] = 2; + + start5[3] = 1; + count5[3] = 2; + stride5[3] = 4; + block5[3] = 2; + + start5[4] = 1; + count5[4] = 1; + stride5[4] = 4; + block5[4] = 2; + + ret = H5Sselect_hyperslab(sid_spec, H5S_SELECT_SET, start5, stride5, count5, block5); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + ret = H5S__get_rebuild_status_test(sid_spec, &rebuild_stat1, &rebuild_stat2); + CHECK(ret, FAIL, "H5S__get_rebuild_status_test"); + /* In this case, rebuild_stat1 and rebuild_stat2 should both be + * H5S_DIMINFO_VALID_YES. */ + if (rebuild_stat1 != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } + if (rebuild_stat2 != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } + /* No need to do shape comparison */ +#endif + + /* Adding some selections to make it real irregular */ + start5[3] = 1; + count5[3] = 1; + stride5[3] = 4; + block5[3] = 2; + + start5[4] = 5; + count5[4] = 1; + stride5[4] = 4; + block5[4] = 2; + + ret = H5Sselect_hyperslab(sid_spec, H5S_SELECT_OR, start5, stride5, count5, block5); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + ret = H5S__get_rebuild_status_test(sid_spec, &rebuild_stat1, &rebuild_stat2); + CHECK(ret, FAIL, "H5S__get_rebuild_status_test"); + /* In this case, rebuild_stat1 should be H5S_DIMINFO_VALID_NO and + * rebuild_stat2 should be H5S_DIMINFO_VALID_IMPOSSIBLE. */ + if (rebuild_stat1 != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } + if (rebuild_stat2 != H5S_DIMINFO_VALID_IMPOSSIBLE) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } + /* No need to do shape comparison */ +#endif + + /* Add more selections to make it regular again */ + start5[3] = 5; + count5[3] = 1; + stride5[3] = 4; + block5[3] = 2; + + start5[4] = 5; + count5[4] = 1; + stride5[4] = 4; + block5[4] = 2; + + ret = H5Sselect_hyperslab(sid_spec, H5S_SELECT_OR, start5, stride5, count5, block5); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + ret = H5S__get_rebuild_status_test(sid_spec, &rebuild_stat1, &rebuild_stat2); + CHECK(ret, FAIL, "H5S__get_rebuild_status_test"); + /* In this case, rebuild_stat1 should be H5S_DIMINFO_VALID_NO and + * rebuild_stat2 should be H5S_DIMINFO_VALID_YES. */ + if (rebuild_stat1 != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } + if (rebuild_stat2 != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } + /* No need to do shape comparison */ +#endif + + H5Sclose(sid_reg1); + CHECK(ret, FAIL, "H5Sclose"); + H5Sclose(sid_irreg1); + CHECK(ret, FAIL, "H5Sclose"); + + H5Sclose(sid_reg2); + CHECK(ret, FAIL, "H5Sclose"); + H5Sclose(sid_irreg2); + CHECK(ret, FAIL, "H5Sclose"); + + H5Sclose(sid_reg3); + CHECK(ret, FAIL, "H5Sclose"); + H5Sclose(sid_irreg3); + CHECK(ret, FAIL, "H5Sclose"); + + H5Sclose(sid_reg4); + CHECK(ret, FAIL, "H5Sclose"); + H5Sclose(sid_irreg4); + CHECK(ret, FAIL, "H5Sclose"); + + H5Sclose(sid_reg5); + CHECK(ret, FAIL, "H5Sclose"); + H5Sclose(sid_irreg5); + CHECK(ret, FAIL, "H5Sclose"); + + H5Sclose(sid_spec); + CHECK(ret, FAIL, "H5Sclose"); +} + +/**************************************************************** +** +** test_space_update_diminfo(): Tests selection diminfo update +** routine. We will test whether regular selections can be +** quickly updated when the selection is modified. +** +** +****************************************************************/ +static void +test_space_update_diminfo(void) +{ + hid_t space_id; /* Dataspace id */ +#if 0 + H5S_diminfo_valid_t diminfo_valid; /* Diminfo status */ + H5S_diminfo_valid_t rebuild_status; /* Diminfo status after rebuid */ +#endif + H5S_sel_type sel_type; /* Selection type */ + herr_t ret; /* Return value */ + + /* dimensions of rank 1 to rank 5 */ + hsize_t dims1[] = {SPACEUD1_DIM0}; + hsize_t dims3[] = {SPACEUD3_DIM0, SPACEUD3_DIM1, SPACEUD3_DIM2}; + + /* The start of the hyperslab */ + hsize_t start1[1], start3[3]; + + /* The stride of the hyperslab */ + hsize_t stride1[1], stride3[3]; + + /* The number of blocks for the hyperslab */ + hsize_t count1[1], count3[3]; + + /* The size of each block for the hyperslab */ + hsize_t block1[1], block3[3]; + + /* Output message about test being performed */ + MESSAGE(6, ("Testing functionality to update hyperslab dimension info\n")); + + MESSAGE(7, ("Testing functionality to update 1-D hyperslab dimension info\n")); + + /* + * Test adding regularly spaced distinct blocks + */ + + /* Create 1-D dataspace */ + space_id = H5Screate_simple(1, dims1, NULL); + + /* Create single block */ + start1[0] = 3; + count1[0] = 1; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Add block after first, with OR */ + start1[0] = 6; + count1[0] = 1; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Add block before first, this time with XOR */ + start1[0] = 0; + count1[0] = 1; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_XOR, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Add two blocks after current block */ + start1[0] = 9; + stride1[0] = 3; + count1[0] = 2; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, stride1, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Add two blocks overlapping current block, with OR */ + start1[0] = 9; + stride1[0] = 3; + count1[0] = 2; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, stride1, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Add two blocks partially overlapping current block, with OR */ + start1[0] = 12; + stride1[0] = 3; + count1[0] = 2; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, stride1, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Add two blocks partially overlapping current block, with XOR */ + start1[0] = 15; + stride1[0] = 3; + count1[0] = 2; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_XOR, start1, stride1, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be NO, after rebuild it should be IMPOSSIBLE */ + ret = H5S__get_rebuild_status_test(space_id, &diminfo_valid, &rebuild_status); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ + if (rebuild_status != H5S_DIMINFO_VALID_IMPOSSIBLE) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } /* end if */ +#endif + + /* Fill in missing block */ + start1[0] = 15; + count1[0] = 1; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_XOR, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be NO, after rebuild it should be YES */ + ret = H5S__get_rebuild_status_test(space_id, &diminfo_valid, &rebuild_status); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ + if (rebuild_status != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } /* end if */ +#endif + /* + * Test adding contiguous blocks + */ + + /* Create single block */ + start1[0] = 3; + count1[0] = 1; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Add block immediately after first, with OR */ + start1[0] = 5; + count1[0] = 1; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Add block immediately before first, with XOR */ + start1[0] = 1; + count1[0] = 1; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Add differently size block immediately after current, with OR */ + start1[0] = 7; + count1[0] = 1; + block1[0] = 7; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* + * Test adding overlapping blocks + */ + + /* Create single block */ + start1[0] = 3; + count1[0] = 1; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Add block completely overlapping first, with OR */ + start1[0] = 3; + count1[0] = 1; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Add block partially overlapping first, with OR */ + start1[0] = 4; + count1[0] = 1; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Add block completely enclosing current, with OR */ + start1[0] = 2; + count1[0] = 1; + block1[0] = 5; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Add block completely enclosed by current, with OR */ + start1[0] = 3; + count1[0] = 1; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Add equally sized block partially overlapping current, with XOR */ + start1[0] = 3; + count1[0] = 1; + block1[0] = 5; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_XOR, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Fill in hole in block */ + start1[0] = 3; + count1[0] = 1; + block1[0] = 4; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be NO, after rebuild it should be YES */ + ret = H5S__get_rebuild_status_test(space_id, &diminfo_valid, &rebuild_status); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ + if (rebuild_status != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } /* end if */ +#endif + + /* Add differently sized block partially overlapping current, with XOR */ + start1[0] = 4; + count1[0] = 1; + block1[0] = 5; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_XOR, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be NO */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Fill in hole in block */ + start1[0] = 4; + count1[0] = 1; + block1[0] = 4; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be NO, after rebuild it should be YES */ + ret = H5S__get_rebuild_status_test(space_id, &diminfo_valid, &rebuild_status); + CHECK(ret, FAIL, "H5S__get_rebuild_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ + if (rebuild_status != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } /* end if */ +#endif + + /* Add block completely overlapping current, with XOR */ + start1[0] = 2; + count1[0] = 1; + block1[0] = 7; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_XOR, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + sel_type = H5Sget_select_type(space_id); + VERIFY(sel_type, H5S_SEL_NONE, "H5Sget_select_type"); + + /* + * Test various conditions that break the fast algorithm + */ + + /* Create multiple blocks */ + start1[0] = 3; + stride1[0] = 3; + count1[0] = 2; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start1, stride1, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Create single block with start out of phase */ + start1[0] = 8; + count1[0] = 1; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be NO */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Create multiple blocks */ + start1[0] = 3; + stride1[0] = 3; + count1[0] = 2; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start1, stride1, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Create multiple blocks with start out of phase */ + start1[0] = 8; + stride1[0] = 3; + count1[0] = 2; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, stride1, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be NO */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Create multiple blocks */ + start1[0] = 3; + stride1[0] = 3; + count1[0] = 2; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start1, stride1, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Create multiple blocks with wrong stride */ + start1[0] = 9; + stride1[0] = 4; + count1[0] = 2; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, stride1, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be NO */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Create single block */ + start1[0] = 3; + count1[0] = 1; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Create single block with wrong size */ + start1[0] = 6; + count1[0] = 1; + block1[0] = 1; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be NO */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Create single block */ + start1[0] = 3; + count1[0] = 1; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Create multiple blocks with wrong size */ + start1[0] = 6; + stride1[0] = 3; + count1[0] = 2; + block1[0] = 1; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, stride1, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be NO */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Create multiple blocks */ + start1[0] = 3; + stride1[0] = 3; + count1[0] = 2; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start1, stride1, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Create single block with wrong size */ + start1[0] = 9; + count1[0] = 1; + block1[0] = 1; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be NO */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Create multiple blocks */ + start1[0] = 3; + stride1[0] = 3; + count1[0] = 2; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start1, stride1, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Create multiple blocks with wrong size */ + start1[0] = 9; + stride1[0] = 3; + count1[0] = 2; + block1[0] = 1; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, stride1, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be NO */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + ret = H5Sclose(space_id); + CHECK(ret, FAIL, "H5Sclose"); + + MESSAGE(7, ("Testing functionality to update 3-D hyperslab dimension info\n")); + + /* Create 3-D dataspace */ + space_id = H5Screate_simple(3, dims3, NULL); + + /* Create multiple blocks */ + start3[0] = 0; + start3[1] = 1; + start3[2] = 2; + stride3[0] = 2; + stride3[1] = 3; + stride3[2] = 4; + count3[0] = 4; + count3[1] = 3; + count3[2] = 2; + block3[0] = 1; + block3[1] = 2; + block3[2] = 3; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start3, stride3, count3, block3); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Add blocks with same values in all dimensions */ + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start3, stride3, count3, block3); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Add blocks with same values in two dimensions */ + start3[0] = 8; + stride3[0] = 1; + count3[0] = 1; + block3[0] = 1; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start3, stride3, count3, block3); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Create multiple blocks */ + start3[0] = 0; + start3[1] = 1; + start3[2] = 2; + stride3[0] = 2; + stride3[1] = 3; + stride3[2] = 4; + count3[0] = 4; + count3[1] = 3; + count3[2] = 2; + block3[0] = 1; + block3[1] = 2; + block3[2] = 3; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start3, stride3, count3, block3); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Add blocks with same values in one dimension */ + start3[0] = 8; + start3[1] = 10; + stride3[0] = 1; + stride3[1] = 1; + count3[0] = 1; + count3[1] = 1; + block3[0] = 1; + block3[1] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start3, stride3, count3, block3); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be NO */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Create multiple blocks */ + start3[0] = 0; + start3[1] = 1; + start3[2] = 2; + stride3[0] = 2; + stride3[1] = 3; + stride3[2] = 4; + count3[0] = 4; + count3[1] = 3; + count3[2] = 2; + block3[0] = 1; + block3[1] = 2; + block3[2] = 3; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start3, stride3, count3, block3); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + /* Add blocks with same values in no dimensions */ + start3[0] = 8; + start3[1] = 10; + start3[2] = 10; + stride3[0] = 1; + stride3[1] = 1; + stride3[2] = 1; + count3[0] = 1; + count3[1] = 1; + count3[2] = 1; + block3[0] = 1; + block3[1] = 2; + block3[2] = 3; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start3, stride3, count3, block3); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); +#if 0 + /* diminfo_valid should be NO */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if (diminfo_valid != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ +#endif + ret = H5Sclose(space_id); + CHECK(ret, FAIL, "H5Sclose"); +} /* end test_space_update_diminfo() */ + +/**************************************************************** +** +** test_select_hyper_chunk_offset(): Tests selections on dataspace, +** verify that offsets for hyperslab selections are working in +** chunked datasets. +** +****************************************************************/ +#if 0 +static void +test_select_hyper_chunk_offset(void) +{ + hid_t fid; /* File ID */ + hid_t sid; /* Dataspace ID */ + hid_t msid; /* Memory dataspace ID */ + hid_t did; /* Dataset ID */ + const hsize_t mem_dims[1] = {SPACE10_DIM1}; /* Dataspace dimensions for memory */ + const hsize_t dims[1] = {0}; /* Dataspace initial dimensions */ + const hsize_t maxdims[1] = {H5S_UNLIMITED}; /* Dataspace mam dims */ + int *wbuf; /* Buffer for writing data */ + int *rbuf; /* Buffer for reading data */ + hid_t dcpl; /* Dataset creation property list ID */ + hsize_t chunks[1] = {SPACE10_CHUNK_SIZE}; /* Chunk size */ + hsize_t start[1] = {0}; /* The start of the hyperslab */ + hsize_t count[1] = {SPACE10_CHUNK_SIZE}; /* The size of the hyperslab */ + int i, j; /* Local index */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(6, ("Testing hyperslab selections using offsets in chunked datasets\n")); + + /* Allocate buffers */ + wbuf = (int *)HDmalloc(sizeof(int) * SPACE10_DIM1); + CHECK_PTR(wbuf, "HDmalloc"); + rbuf = (int *)HDcalloc(sizeof(int), SPACE10_DIM1); + CHECK_PTR(rbuf, "HDcalloc"); + + /* Initialize the write buffer */ + for (i = 0; i < SPACE10_DIM1; i++) + wbuf[i] = i; + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create a dataset creation property list */ + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + + /* Set to chunked storage layout */ + ret = H5Pset_layout(dcpl, H5D_CHUNKED); + CHECK(ret, FAIL, "H5Pset_layout"); + + /* Set the chunk size */ + ret = H5Pset_chunk(dcpl, 1, chunks); + CHECK(ret, FAIL, "H5Pset_chunk"); + + /* Create dataspace for memory */ + msid = H5Screate_simple(1, mem_dims, NULL); + CHECK(msid, FAIL, "H5Screate_simple"); + + /* Select the correct chunk in the memory dataspace */ + ret = H5Sselect_hyperslab(msid, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create dataspace for dataset */ + sid = H5Screate_simple(1, dims, maxdims); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Create the dataset */ + did = H5Dcreate2(fid, "fooData", H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); + + /* Close the dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close the dataset creation property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Loop over writing out each chunk */ + for (i = SPACE10_CHUNK_SIZE; i <= SPACE10_DIM1; i += SPACE10_CHUNK_SIZE) { + hssize_t offset[1]; /* Offset of selection */ + hid_t fsid; /* File dataspace ID */ + hsize_t size[1]; /* The size to extend the dataset to */ + + /* Extend the dataset */ + size[0] = (hsize_t)i; /* The size to extend the dataset to */ + ret = H5Dset_extent(did, size); + CHECK(ret, FAIL, "H5Dset_extent"); + + /* Get the (extended) dataspace from the dataset */ + fsid = H5Dget_space(did); + CHECK(fsid, FAIL, "H5Dget_space"); + + /* Select the correct chunk in the dataset */ + ret = H5Sselect_hyperslab(fsid, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Set the selection offset for the file dataspace */ + offset[0] = i - SPACE10_CHUNK_SIZE; + ret = H5Soffset_simple(fsid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Set the selection offset for the memory dataspace */ + offset[0] = SPACE10_DIM1 - i; + ret = H5Soffset_simple(msid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Write the data to the chunk */ + ret = H5Dwrite(did, H5T_NATIVE_INT, msid, fsid, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close the file dataspace copy */ + ret = H5Sclose(fsid); + CHECK(ret, FAIL, "H5Sclose"); + } + + /* Read the data back in */ + ret = H5Dread(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Verify the information read in */ + for (i = 0; i < SPACE10_DIM1; i += SPACE10_CHUNK_SIZE) + for (j = 0; j < SPACE10_CHUNK_SIZE; j++) + if (wbuf[i + j] != rbuf[((SPACE10_DIM1 - i) - SPACE10_CHUNK_SIZE) + j]) + TestErrPrintf("Line: %d - Error! i=%d, j=%d, rbuf=%d, wbuf=%d\n", __LINE__, i, j, + rbuf[((SPACE10_DIM1 - i) - SPACE10_CHUNK_SIZE) + j], wbuf[i + j]); + + /* Check with 'OR'ed set of hyperslab selections, which makes certain the + * hyperslab spanlist code gets tested. -QAK + */ + + /* Re-initialize the write buffer */ + for (i = 0; i < SPACE10_DIM1; i++) + wbuf[i] = i * 2; + + /* Change the selected the region in the memory dataspace */ + start[0] = 0; + count[0] = SPACE10_CHUNK_SIZE / 3; + ret = H5Sselect_hyperslab(msid, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + start[0] = (2 * SPACE10_CHUNK_SIZE) / 3; + ret = H5Sselect_hyperslab(msid, H5S_SELECT_OR, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Loop over writing out each chunk */ + for (i = SPACE10_CHUNK_SIZE; i <= SPACE10_DIM1; i += SPACE10_CHUNK_SIZE) { + hssize_t offset[1]; /* Offset of selection */ + hid_t fsid; /* File dataspace ID */ + hsize_t size[1]; /* The size to extend the dataset to */ + + /* Extend the dataset */ + size[0] = (hsize_t)i; /* The size to extend the dataset to */ + ret = H5Dset_extent(did, size); + CHECK(ret, FAIL, "H5Dset_extent"); + + /* Get the (extended) dataspace from the dataset */ + fsid = H5Dget_space(did); + CHECK(fsid, FAIL, "H5Dget_space"); + + /* Select the correct region in the dataset */ + start[0] = 0; + ret = H5Sselect_hyperslab(fsid, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + start[0] = (2 * SPACE10_CHUNK_SIZE) / 3; + ret = H5Sselect_hyperslab(fsid, H5S_SELECT_OR, start, NULL, count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Set the selection offset for the file dataspace */ + offset[0] = i - SPACE10_CHUNK_SIZE; + ret = H5Soffset_simple(fsid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Set the selection offset for the memory dataspace */ + offset[0] = SPACE10_DIM1 - i; + ret = H5Soffset_simple(msid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Write the data to the chunk */ + ret = H5Dwrite(did, H5T_NATIVE_INT, msid, fsid, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Close the file dataspace copy */ + ret = H5Sclose(fsid); + CHECK(ret, FAIL, "H5Sclose"); + } + + /* Read the data back in */ + ret = H5Dread(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rbuf); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Verify the information read in */ + for (i = 0; i < SPACE10_DIM1; i += SPACE10_CHUNK_SIZE) + for (j = 0; j < SPACE10_CHUNK_SIZE; j++) + /* We're not writing out the "middle" of each chunk, so don't check that */ + if (j < (SPACE10_CHUNK_SIZE / 3) || j >= ((2 * SPACE10_CHUNK_SIZE) / 3)) + if (wbuf[i + j] != rbuf[((SPACE10_DIM1 - i) - SPACE10_CHUNK_SIZE) + j]) + TestErrPrintf("Line: %d - Error! i=%d, j=%d, rbuf=%d, wbuf=%d\n", __LINE__, i, j, + rbuf[((SPACE10_DIM1 - i) - SPACE10_CHUNK_SIZE) + j], wbuf[i + j]); + + /* Close the memory dataspace */ + ret = H5Sclose(msid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close the dataset */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close the file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free the buffers */ + HDfree(wbuf); + HDfree(rbuf); +} /* test_select_hyper_chunk_offset() */ +#endif +/**************************************************************** +** +** test_select_hyper_chunk_offset2(): Tests selections on dataspace, +** another test to verify that offsets for hyperslab selections are +** working in chunked datasets. +** +****************************************************************/ +#if 0 +static void +test_select_hyper_chunk_offset2(void) +{ + hid_t file, dataset; /* handles */ + hid_t dataspace; + hid_t memspace; + hid_t dcpl; /* Dataset creation property list */ + herr_t status; + unsigned data_out[SPACE12_DIM0]; /* output buffer */ + unsigned data_in[SPACE12_CHUNK_DIM0]; /* input buffer */ + hsize_t dims[SPACE12_RANK] = {SPACE12_DIM0}; /* Dimension size */ + hsize_t chunk_dims[SPACE12_RANK] = {SPACE12_CHUNK_DIM0}; /* Chunk size */ + hsize_t start[SPACE12_RANK]; /* Start of hyperslab */ + hsize_t count[SPACE12_RANK]; /* Size of hyperslab */ + hssize_t offset[SPACE12_RANK]; /* hyperslab offset in the file */ + unsigned u, v; /* Local index variables */ + + /* Output message about test being performed */ + MESSAGE(6, ("Testing more hyperslab selections using offsets in chunked datasets\n")); + + /* Initialize data to write out */ + for (u = 0; u < SPACE12_DIM0; u++) + data_out[u] = u; + + /* Create the file */ + file = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file, FAIL, "H5Fcreate"); + + /* Create dataspace */ + dataspace = H5Screate_simple(SPACE12_RANK, dims, NULL); + CHECK(dataspace, FAIL, "H5Screate_simple"); + + /* Create dataset creation property list */ + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + + /* Set chunk sizes */ + status = H5Pset_chunk(dcpl, SPACE12_RANK, chunk_dims); + CHECK(status, FAIL, "H5Pset_chunk"); + + /* Create dataset */ + dataset = H5Dcreate2(file, DATASETNAME, H5T_NATIVE_UINT, dataspace, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Close DCPL */ + status = H5Pclose(dcpl); + CHECK(status, FAIL, "H5Pclose"); + + /* Write out entire dataset */ + status = H5Dwrite(dataset, H5T_NATIVE_UINT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data_out); + CHECK(status, FAIL, "H5Dclose"); + + /* Create memory dataspace (same size as a chunk) */ + memspace = H5Screate_simple(SPACE12_RANK, chunk_dims, NULL); + CHECK(dataspace, FAIL, "H5Screate_simple"); + + /* + * Define hyperslab in the file dataspace. + */ + start[0] = 0; + count[0] = SPACE12_CHUNK_DIM0; + status = H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(status, FAIL, "H5Sselect_hyperslab"); + + /* Loop through retrieving data from file, checking it against data written */ + for (u = 0; u < SPACE12_DIM0; u += SPACE12_CHUNK_DIM0) { + /* Set the offset of the file selection */ + offset[0] = u; + status = H5Soffset_simple(dataspace, offset); + CHECK(status, FAIL, "H5Soffset_simple"); + + /* Read in buffer of data */ + status = H5Dread(dataset, H5T_NATIVE_UINT, memspace, dataspace, H5P_DEFAULT, data_in); + CHECK(status, FAIL, "H5Dread"); + + /* Check data read in */ + for (v = 0; v < SPACE12_CHUNK_DIM0; v++) + if (data_out[u + v] != data_in[v]) + TestErrPrintf("Error! data_out[%u]=%u, data_in[%u]=%u\n", (unsigned)(u + v), data_out[u + v], + v, data_in[v]); + } /* end for */ + + status = H5Dclose(dataset); + CHECK(status, FAIL, "H5Dclose"); + + status = H5Sclose(dataspace); + CHECK(status, FAIL, "H5Sclose"); + + status = H5Sclose(memspace); + CHECK(status, FAIL, "H5Sclose"); + + status = H5Fclose(file); + CHECK(status, FAIL, "H5Fclose"); +} /* test_select_hyper_chunk_offset2() */ +#endif +/**************************************************************** +** +** test_select_bounds(): Tests selection bounds on dataspaces, +** both with and without offsets. +** +****************************************************************/ +static void +test_select_bounds(void) +{ + hid_t sid; /* Dataspace ID */ + const hsize_t dims[SPACE11_RANK] = {SPACE11_DIM1, SPACE11_DIM2}; /* Dataspace dimensions */ + hsize_t coord[SPACE11_NPOINTS][SPACE11_RANK]; /* Coordinates for point selection */ + hsize_t start[SPACE11_RANK]; /* The start of the hyperslab */ + hsize_t stride[SPACE11_RANK]; /* The stride between block starts for the hyperslab */ + hsize_t count[SPACE11_RANK]; /* The number of blocks for the hyperslab */ + hsize_t block[SPACE11_RANK]; /* The size of each block for the hyperslab */ + hssize_t offset[SPACE11_RANK]; /* Offset amount for selection */ + hsize_t low_bounds[SPACE11_RANK]; /* The low bounds for the selection */ + hsize_t high_bounds[SPACE11_RANK]; /* The high bounds for the selection */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(6, ("Testing selection bounds\n")); + + /* Create dataspace */ + sid = H5Screate_simple(SPACE11_RANK, dims, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Get bounds for 'all' selection */ + ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); + CHECK(ret, FAIL, "H5Sget_select_bounds"); + VERIFY(low_bounds[0], 0, "H5Sget_select_bounds"); + VERIFY(low_bounds[1], 0, "H5Sget_select_bounds"); + VERIFY(high_bounds[0], SPACE11_DIM1 - 1, "H5Sget_select_bounds"); + VERIFY(high_bounds[1], SPACE11_DIM2 - 1, "H5Sget_select_bounds"); + + /* Set offset for selection */ + offset[0] = 1; + offset[1] = 1; + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Get bounds for 'all' selection with offset (which should be ignored) */ + ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); + CHECK(ret, FAIL, "H5Sget_select_bounds"); + VERIFY(low_bounds[0], 0, "H5Sget_select_bounds"); + VERIFY(low_bounds[1], 0, "H5Sget_select_bounds"); + VERIFY(high_bounds[0], SPACE11_DIM1 - 1, "H5Sget_select_bounds"); + VERIFY(high_bounds[1], SPACE11_DIM2 - 1, "H5Sget_select_bounds"); + + /* Reset offset for selection */ + offset[0] = 0; + offset[1] = 0; + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Set 'none' selection */ + ret = H5Sselect_none(sid); + CHECK(ret, FAIL, "H5Sselect_none"); + + /* Get bounds for 'none' selection */ + H5E_BEGIN_TRY + { + ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Sget_select_bounds"); + + /* Set point selection */ + coord[0][0] = 3; + coord[0][1] = 3; + coord[1][0] = 3; + coord[1][1] = 96; + coord[2][0] = 96; + coord[2][1] = 3; + coord[3][0] = 96; + coord[3][1] = 96; + ret = H5Sselect_elements(sid, H5S_SELECT_SET, (size_t)SPACE11_NPOINTS, (const hsize_t *)coord); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Get bounds for point selection */ + ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); + CHECK(ret, FAIL, "H5Sget_select_bounds"); + VERIFY(low_bounds[0], 3, "H5Sget_select_bounds"); + VERIFY(low_bounds[1], 3, "H5Sget_select_bounds"); + VERIFY(high_bounds[0], SPACE11_DIM1 - 4, "H5Sget_select_bounds"); + VERIFY(high_bounds[1], SPACE11_DIM2 - 4, "H5Sget_select_bounds"); + + /* Set bad offset for selection */ + offset[0] = 5; + offset[1] = -5; + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Get bounds for hyperslab selection with negative offset */ + H5E_BEGIN_TRY + { + ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Sget_select_bounds"); + + /* Set valid offset for selection */ + offset[0] = 2; + offset[1] = -2; + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Get bounds for point selection with offset */ + ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); + CHECK(ret, FAIL, "H5Sget_select_bounds"); + VERIFY(low_bounds[0], 5, "H5Sget_select_bounds"); + VERIFY(low_bounds[1], 1, "H5Sget_select_bounds"); + VERIFY(high_bounds[0], SPACE11_DIM1 - 2, "H5Sget_select_bounds"); + VERIFY(high_bounds[1], SPACE11_DIM2 - 6, "H5Sget_select_bounds"); + + /* Reset offset for selection */ + offset[0] = 0; + offset[1] = 0; + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Set "regular" hyperslab selection */ + start[0] = 2; + start[1] = 2; + stride[0] = 10; + stride[1] = 10; + count[0] = 4; + count[1] = 4; + block[0] = 5; + block[1] = 5; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Get bounds for hyperslab selection */ + ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); + CHECK(ret, FAIL, "H5Sget_select_bounds"); + VERIFY(low_bounds[0], 2, "H5Sget_select_bounds"); + VERIFY(low_bounds[1], 2, "H5Sget_select_bounds"); + VERIFY(high_bounds[0], 36, "H5Sget_select_bounds"); + VERIFY(high_bounds[1], 36, "H5Sget_select_bounds"); + + /* Set bad offset for selection */ + offset[0] = 5; + offset[1] = -5; + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Get bounds for hyperslab selection with negative offset */ + H5E_BEGIN_TRY + { + ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Sget_select_bounds"); + + /* Set valid offset for selection */ + offset[0] = 5; + offset[1] = -2; + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Get bounds for hyperslab selection with offset */ + ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); + CHECK(ret, FAIL, "H5Sget_select_bounds"); + VERIFY(low_bounds[0], 7, "H5Sget_select_bounds"); + VERIFY(low_bounds[1], 0, "H5Sget_select_bounds"); + VERIFY(high_bounds[0], 41, "H5Sget_select_bounds"); + VERIFY(high_bounds[1], 34, "H5Sget_select_bounds"); + + /* Reset offset for selection */ + offset[0] = 0; + offset[1] = 0; + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Make "irregular" hyperslab selection */ + start[0] = 20; + start[1] = 20; + stride[0] = 20; + stride[1] = 20; + count[0] = 2; + count[1] = 2; + block[0] = 10; + block[1] = 10; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Get bounds for hyperslab selection */ + ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); + CHECK(ret, FAIL, "H5Sget_select_bounds"); + VERIFY(low_bounds[0], 2, "H5Sget_select_bounds"); + VERIFY(low_bounds[1], 2, "H5Sget_select_bounds"); + VERIFY(high_bounds[0], 49, "H5Sget_select_bounds"); + VERIFY(high_bounds[1], 49, "H5Sget_select_bounds"); + + /* Set bad offset for selection */ + offset[0] = 5; + offset[1] = -5; + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Get bounds for hyperslab selection with negative offset */ + H5E_BEGIN_TRY + { + ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Sget_select_bounds"); + + /* Set valid offset for selection */ + offset[0] = 5; + offset[1] = -2; + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Get bounds for hyperslab selection with offset */ + ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); + CHECK(ret, FAIL, "H5Sget_select_bounds"); + VERIFY(low_bounds[0], 7, "H5Sget_select_bounds"); + VERIFY(low_bounds[1], 0, "H5Sget_select_bounds"); + VERIFY(high_bounds[0], 54, "H5Sget_select_bounds"); + VERIFY(high_bounds[1], 47, "H5Sget_select_bounds"); + + /* Reset offset for selection */ + offset[0] = 0; + offset[1] = 0; + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Close the dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_select_bounds() */ + +/**************************************************************** +** +** test_hyper_regular(): Tests query operations on regular hyperslabs +** +****************************************************************/ +static void +test_hyper_regular(void) +{ + hid_t sid; /* Dataspace ID */ + const hsize_t dims[SPACE13_RANK] = {SPACE13_DIM1, SPACE13_DIM2, SPACE13_DIM3}; /* Dataspace dimensions */ + hsize_t coord[SPACE13_NPOINTS][SPACE13_RANK]; /* Coordinates for point selection */ + hsize_t start[SPACE13_RANK]; /* The start of the hyperslab */ + hsize_t stride[SPACE13_RANK]; /* The stride between block starts for the hyperslab */ + hsize_t count[SPACE13_RANK]; /* The number of blocks for the hyperslab */ + hsize_t block[SPACE13_RANK]; /* The size of each block for the hyperslab */ + hsize_t t_start[SPACE13_RANK]; /* Temporary start of the hyperslab */ + hsize_t t_count[SPACE13_RANK]; /* Temporary number of blocks for the hyperslab */ + hsize_t q_start[SPACE13_RANK]; /* The queried start of the hyperslab */ + hsize_t q_stride[SPACE13_RANK]; /* The queried stride between block starts for the hyperslab */ + hsize_t q_count[SPACE13_RANK]; /* The queried number of blocks for the hyperslab */ + hsize_t q_block[SPACE13_RANK]; /* The queried size of each block for the hyperslab */ + htri_t is_regular; /* Whether a hyperslab selection is regular */ + unsigned u; /* Local index variable */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(6, ("Testing queries on regular hyperslabs\n")); + + /* Create dataspace */ + sid = H5Screate_simple(SPACE13_RANK, dims, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Query if 'all' selection is regular hyperslab (should fail) */ + H5E_BEGIN_TRY + { + is_regular = H5Sis_regular_hyperslab(sid); + } + H5E_END_TRY; + VERIFY(is_regular, FAIL, "H5Sis_regular_hyperslab"); + + /* Query regular hyperslab selection info (should fail) */ + H5E_BEGIN_TRY + { + ret = H5Sget_regular_hyperslab(sid, q_start, q_stride, q_count, q_block); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Sget_regular_hyperslab"); + + /* Set 'none' selection */ + ret = H5Sselect_none(sid); + CHECK(ret, FAIL, "H5Sselect_none"); + + /* Query if 'none' selection is regular hyperslab (should fail) */ + H5E_BEGIN_TRY + { + is_regular = H5Sis_regular_hyperslab(sid); + } + H5E_END_TRY; + VERIFY(is_regular, FAIL, "H5Sis_regular_hyperslab"); + + /* Query regular hyperslab selection info (should fail) */ + H5E_BEGIN_TRY + { + ret = H5Sget_regular_hyperslab(sid, q_start, q_stride, q_count, q_block); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Sget_regular_hyperslab"); + + /* Set point selection */ + coord[0][0] = 3; + coord[0][1] = 3; + coord[0][2] = 3; + coord[1][0] = 3; + coord[1][1] = 48; + coord[1][2] = 48; + coord[2][0] = 48; + coord[2][1] = 3; + coord[2][2] = 3; + coord[3][0] = 48; + coord[3][1] = 48; + coord[3][2] = 48; + ret = H5Sselect_elements(sid, H5S_SELECT_SET, (size_t)SPACE13_NPOINTS, (const hsize_t *)coord); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Query if 'point' selection is regular hyperslab (should fail) */ + H5E_BEGIN_TRY + { + is_regular = H5Sis_regular_hyperslab(sid); + } + H5E_END_TRY; + VERIFY(is_regular, FAIL, "H5Sis_regular_hyperslab"); + + /* Query regular hyperslab selection info (should fail) */ + H5E_BEGIN_TRY + { + ret = H5Sget_regular_hyperslab(sid, q_start, q_stride, q_count, q_block); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Sget_regular_hyperslab"); + + /* Set "regular" hyperslab selection */ + start[0] = 2; + start[1] = 2; + start[2] = 2; + stride[0] = 5; + stride[1] = 5; + stride[2] = 5; + count[0] = 3; + count[1] = 3; + count[2] = 3; + block[0] = 4; + block[1] = 4; + block[2] = 4; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Query if 'hyperslab' selection is regular hyperslab (should be TRUE) */ + is_regular = H5Sis_regular_hyperslab(sid); + VERIFY(is_regular, TRUE, "H5Sis_regular_hyperslab"); + + /* Retrieve the hyperslab parameters */ + ret = H5Sget_regular_hyperslab(sid, q_start, q_stride, q_count, q_block); + CHECK(ret, FAIL, "H5Sget_regular_hyperslab"); + + /* Verify the hyperslab parameters */ + for (u = 0; u < SPACE13_RANK; u++) { + if (start[u] != q_start[u]) + ERROR("H5Sget_regular_hyperslab, start"); + if (stride[u] != q_stride[u]) + ERROR("H5Sget_regular_hyperslab, stride"); + if (count[u] != q_count[u]) + ERROR("H5Sget_regular_hyperslab, count"); + if (block[u] != q_block[u]) + ERROR("H5Sget_regular_hyperslab, block"); + } /* end for */ + + /* 'OR' in another point */ + t_start[0] = 0; + t_start[1] = 0; + t_start[2] = 0; + t_count[0] = 1; + t_count[1] = 1; + t_count[2] = 1; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_OR, t_start, NULL, t_count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Query if 'hyperslab' selection is regular hyperslab (should be FALSE) */ + is_regular = H5Sis_regular_hyperslab(sid); + VERIFY(is_regular, FALSE, "H5Sis_regular_hyperslab"); + + /* Query regular hyperslab selection info (should fail) */ + H5E_BEGIN_TRY + { + ret = H5Sget_regular_hyperslab(sid, q_start, q_stride, q_count, q_block); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Sget_regular_hyperslab"); + + /* 'XOR' in the point again, to remove it, which should make it regular again */ + t_start[0] = 0; + t_start[1] = 0; + t_start[2] = 0; + t_count[0] = 1; + t_count[1] = 1; + t_count[2] = 1; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_XOR, t_start, NULL, t_count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Query if 'hyperslab' selection is regular hyperslab (should be TRUE) */ + is_regular = H5Sis_regular_hyperslab(sid); + VERIFY(is_regular, TRUE, "H5Sis_regular_hyperslab"); + + /* Retrieve the hyperslab parameters */ + ret = H5Sget_regular_hyperslab(sid, q_start, q_stride, q_count, q_block); + CHECK(ret, FAIL, "H5Sget_regular_hyperslab"); + + /* Verify the hyperslab parameters */ + for (u = 0; u < SPACE13_RANK; u++) { + if (start[u] != q_start[u]) + ERROR("H5Sget_regular_hyperslab, start"); + if (stride[u] != q_stride[u]) + ERROR("H5Sget_regular_hyperslab, stride"); + if (count[u] != q_count[u]) + ERROR("H5Sget_regular_hyperslab, count"); + if (block[u] != q_block[u]) + ERROR("H5Sget_regular_hyperslab, block"); + } /* end for */ + + /* Close the dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_hyper_regular() */ + +/**************************************************************** +** +** test_hyper_unlim(): Tests unlimited hyperslab selections +** +****************************************************************/ +static void +test_hyper_unlim_check(hid_t sid, hsize_t *dims, hssize_t endpoints, hssize_t enblocks, hsize_t *eblock1, + hsize_t *eblock2) +{ + hid_t lim_sid; + hsize_t start[3]; + H5S_sel_type sel_type; + hssize_t npoints; + hssize_t nblocks; + hsize_t blocklist[12]; + herr_t ret; + + HDassert(enblocks <= 2); + + /* Copy sid to lim_sid */ + lim_sid = H5Scopy(sid); + CHECK(lim_sid, FAIL, "H5Scopy"); + + /* "And" lim_sid with dims to create limited selection */ + HDmemset(start, 0, sizeof(start)); + ret = H5Sselect_hyperslab(lim_sid, H5S_SELECT_AND, start, NULL, dims, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Check number of elements */ + npoints = H5Sget_select_npoints(lim_sid); + CHECK(npoints, FAIL, "H5Sget_select_npoints"); + VERIFY(npoints, endpoints, "H5Sget_select_npoints"); + + /* Get selection type */ + sel_type = H5Sget_select_type(lim_sid); + CHECK(sel_type, H5S_SEL_ERROR, "H5Sget_select_type"); + + /* Only examine blocks for hyperslab selection */ + if (sel_type == H5S_SEL_HYPERSLABS) { + /* Get number of blocks */ + nblocks = H5Sget_select_hyper_nblocks(lim_sid); + CHECK(nblocks, FAIL, "H5Sget_select_hyper_nblocks"); + VERIFY(nblocks, enblocks, "H5Sget_select_hyper_nblocks"); + + if (nblocks > 0) { + /* Get blocklist */ + ret = H5Sget_select_hyper_blocklist(lim_sid, (hsize_t)0, (hsize_t)nblocks, blocklist); + CHECK(ret, FAIL, "H5Sget_select_hyper_blocklist"); + + /* Verify blocklist */ + if (nblocks == (hssize_t)1) { + if (HDmemcmp(blocklist, eblock1, 6 * sizeof(eblock1[0])) != 0) + ERROR("H5Sget_select_hyper_blocklist"); + } /* end if */ + else { + HDassert(nblocks == (hssize_t)2); + if (HDmemcmp(blocklist, eblock1, 6 * sizeof(eblock1[0])) != 0) { + if (HDmemcmp(blocklist, eblock2, 6 * sizeof(eblock2[0])) != 0) + ERROR("H5Sget_select_hyper_blocklist"); + if (HDmemcmp(&blocklist[6], eblock1, 6 * sizeof(eblock1[0])) != 0) + ERROR("H5Sget_select_hyper_blocklist"); + } /* end if */ + else if (HDmemcmp(&blocklist[6], eblock2, 6 * sizeof(eblock2[0])) != 0) + ERROR("H5Sget_select_hyper_blocklist"); + } /* end else */ + } /* end if */ + } /* end if */ + else if (sel_type != H5S_SEL_NONE) + ERROR("H5Sget_select_type"); + + /* Close the limited dataspace */ + ret = H5Sclose(lim_sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* end test_hyper_unlim_check() */ + +static void +test_hyper_unlim(void) +{ + hid_t sid; + hsize_t dims[3] = {4, 4, 7}; + hsize_t mdims[3] = {4, H5S_UNLIMITED, 7}; + hsize_t start[3] = {1, 2, 1}; + hsize_t stride[3] = {1, 1, 3}; + hsize_t count[3] = {1, 1, 2}; + hsize_t block[3] = {2, H5S_UNLIMITED, 2}; + hsize_t start2[3]; + hsize_t count2[3]; + hsize_t eblock1[6] = {1, 2, 1, 2, 3, 2}; + hsize_t eblock2[6] = {1, 2, 4, 2, 3, 5}; + hssize_t offset[3] = {0, -1, 0}; + hssize_t ssize_out; + herr_t ret; + + /* Output message about test being performed */ + MESSAGE(6, ("Testing unlimited hyperslab selections\n")); + + /* Create dataspace */ + sid = H5Screate_simple(3, dims, mdims); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Select unlimited hyperslab */ + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Check with unlimited dimension clipped to 4 */ + test_hyper_unlim_check(sid, dims, (hssize_t)16, (hssize_t)2, eblock1, eblock2); + + /* Check with unlimited dimension clipped to 3 */ + dims[1] = 3; + eblock1[4] = 2; + eblock2[4] = 2; + test_hyper_unlim_check(sid, dims, (hssize_t)8, (hssize_t)2, eblock1, eblock2); + + /* Check with unlimited dimension clipped to 2 */ + dims[1] = 2; + test_hyper_unlim_check(sid, dims, (hssize_t)0, (hssize_t)0, eblock1, eblock2); + + /* Check with unlimited dimension clipped to 1 */ + dims[1] = 1; + test_hyper_unlim_check(sid, dims, (hssize_t)0, (hssize_t)0, eblock1, eblock2); + + /* Check with unlimited dimension clipped to 7 */ + dims[1] = 7; + eblock1[4] = 6; + eblock2[4] = 6; + test_hyper_unlim_check(sid, dims, (hssize_t)40, (hssize_t)2, eblock1, eblock2); + + /* Set offset of selection */ + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Check with adjusted offset (should not affect result) */ + test_hyper_unlim_check(sid, dims, (hssize_t)40, (hssize_t)2, eblock1, eblock2); + + /* Reset offset of selection */ + offset[1] = (hssize_t)0; + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* + * Now try with multiple blocks in unlimited dimension + */ + stride[1] = 3; + stride[2] = 1; + count[1] = H5S_UNLIMITED; + count[2] = 1; + block[1] = 2; + + /* Select unlimited hyperslab */ + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Check with new selection */ + eblock1[1] = 2; + eblock1[4] = 3; + eblock2[1] = 5; + eblock2[2] = 1; + eblock2[4] = 6; + eblock2[5] = 2; + test_hyper_unlim_check(sid, dims, (hssize_t)16, (hssize_t)2, eblock1, eblock2); + + /* Check with unlimited dimension clipped to 3 */ + dims[1] = 3; + eblock1[4] = 2; + test_hyper_unlim_check(sid, dims, (hssize_t)4, (hssize_t)1, eblock1, eblock2); + + /* Check with unlimited dimension clipped to 4 */ + dims[1] = 4; + eblock1[4] = 3; + test_hyper_unlim_check(sid, dims, (hssize_t)8, (hssize_t)1, eblock1, eblock2); + + /* Check with unlimited dimension clipped to 5 */ + dims[1] = 5; + eblock1[4] = 3; + test_hyper_unlim_check(sid, dims, (hssize_t)8, (hssize_t)1, eblock1, eblock2); + + /* Check with unlimited dimension clipped to 6 */ + dims[1] = 6; + eblock1[4] = 3; + eblock2[4] = 5; + test_hyper_unlim_check(sid, dims, (hssize_t)12, (hssize_t)2, eblock1, eblock2); + + /* Set offset of selection */ + offset[1] = (hssize_t)-1; + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Check with adjusted offset (should not affect result) */ + test_hyper_unlim_check(sid, dims, (hssize_t)12, (hssize_t)2, eblock1, eblock2); + + /* Set offset of selection */ + offset[1] = (hssize_t)3; + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Check with adjusted offset (should not affect result) */ + test_hyper_unlim_check(sid, dims, (hssize_t)12, (hssize_t)2, eblock1, eblock2); + + /* Reset offset of selection */ + offset[1] = (hssize_t)0; + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* + * Now try invalid operations + */ + H5E_BEGIN_TRY + { + /* Try multiple unlimited dimensions */ + start[0] = 1; + start[1] = 2; + start[2] = 1; + stride[0] = 1; + stride[1] = 3; + stride[2] = 3; + count[0] = 1; + count[1] = H5S_UNLIMITED; + count[2] = H5S_UNLIMITED; + block[0] = 2; + block[1] = 2; + block[2] = 2; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + VERIFY(ret, FAIL, "H5Sselect_hyperslab"); + + /* Try unlimited count and block */ + count[2] = 2; + block[1] = H5S_UNLIMITED; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + VERIFY(ret, FAIL, "H5Sselect_hyperslab"); + } + H5E_END_TRY + + /* Try operations with two unlimited selections */ + block[1] = 2; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + H5E_BEGIN_TRY + { + ret = H5Sselect_hyperslab(sid, H5S_SELECT_OR, start, NULL, count, NULL); + VERIFY(ret, FAIL, "H5Sselect_hyperslab"); + ret = H5Sselect_hyperslab(sid, H5S_SELECT_AND, start, NULL, count, NULL); + VERIFY(ret, FAIL, "H5Sselect_hyperslab"); + ret = H5Sselect_hyperslab(sid, H5S_SELECT_XOR, start, NULL, count, NULL); + VERIFY(ret, FAIL, "H5Sselect_hyperslab"); + ret = H5Sselect_hyperslab(sid, H5S_SELECT_NOTB, start, NULL, count, NULL); + VERIFY(ret, FAIL, "H5Sselect_hyperslab"); + ret = H5Sselect_hyperslab(sid, H5S_SELECT_NOTA, start, NULL, count, NULL); + VERIFY(ret, FAIL, "H5Sselect_hyperslab"); + } + H5E_END_TRY + + /* Try invalid combination operations */ + H5E_BEGIN_TRY + { + ret = H5Sselect_hyperslab(sid, H5S_SELECT_OR, start, NULL, block, NULL); + VERIFY(ret, FAIL, "H5Sselect_hyperslab"); + ret = H5Sselect_hyperslab(sid, H5S_SELECT_XOR, start, NULL, block, NULL); + VERIFY(ret, FAIL, "H5Sselect_hyperslab"); + ret = H5Sselect_hyperslab(sid, H5S_SELECT_NOTB, start, NULL, block, NULL); + VERIFY(ret, FAIL, "H5Sselect_hyperslab"); + } + H5E_END_TRY + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, NULL, block, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + H5E_BEGIN_TRY + { + ret = H5Sselect_hyperslab(sid, H5S_SELECT_OR, start, stride, count, block); + VERIFY(ret, FAIL, "H5Sselect_hyperslab"); + ret = H5Sselect_hyperslab(sid, H5S_SELECT_XOR, start, stride, count, block); + VERIFY(ret, FAIL, "H5Sselect_hyperslab"); + ret = H5Sselect_hyperslab(sid, H5S_SELECT_NOTA, start, stride, count, block); + VERIFY(ret, FAIL, "H5Sselect_hyperslab"); + } + H5E_END_TRY + + /* + * Now test valid combination operations + */ + /* unlim AND non-unlim */ + count[0] = 1; + count[1] = H5S_UNLIMITED; + count[2] = 2; + block[0] = 2; + block[1] = 2; + block[2] = 2; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + start2[0] = 2; + start2[1] = 2; + start2[2] = 0; + count2[0] = 5; + count2[1] = 4; + count2[2] = 2; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_AND, start2, NULL, count2, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + eblock1[0] = 2; + eblock1[3] = 2; + eblock1[1] = 2; + eblock1[4] = 3; + eblock1[2] = 1; + eblock1[5] = 1; + eblock2[0] = 2; + eblock2[3] = 2; + eblock2[1] = 5; + eblock2[4] = 5; + eblock2[2] = 1; + eblock2[5] = 1; + dims[0] = 50; + dims[1] = 50; + dims[2] = 50; + test_hyper_unlim_check(sid, dims, (hssize_t)3, (hssize_t)2, eblock1, eblock2); + + /* unlim NOTA non-unlim */ + count[0] = 1; + count[1] = H5S_UNLIMITED; + count[2] = 2; + block[0] = 2; + block[1] = 2; + block[2] = 2; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + start2[0] = 1; + start2[1] = 5; + start2[2] = 2; + count2[0] = 2; + count2[1] = 2; + count2[2] = 6; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_NOTA, start2, NULL, count2, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + eblock1[0] = 1; + eblock1[3] = 2; + eblock1[1] = 5; + eblock1[4] = 6; + eblock1[2] = 3; + eblock1[5] = 3; + eblock2[0] = 1; + eblock2[3] = 2; + eblock2[1] = 5; + eblock2[4] = 6; + eblock2[2] = 6; + eblock2[5] = 7; + dims[0] = 50; + dims[1] = 50; + dims[2] = 50; + test_hyper_unlim_check(sid, dims, (hssize_t)12, (hssize_t)2, eblock1, eblock2); + + /* non-unlim AND unlim */ + start2[0] = 2; + start2[1] = 2; + start2[2] = 0; + count2[0] = 5; + count2[1] = 4; + count2[2] = 2; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start2, NULL, count2, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + count[0] = 1; + count[1] = H5S_UNLIMITED; + count[2] = 2; + block[0] = 2; + block[1] = 2; + block[2] = 2; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_AND, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + eblock1[0] = 2; + eblock1[3] = 2; + eblock1[1] = 2; + eblock1[4] = 3; + eblock1[2] = 1; + eblock1[5] = 1; + eblock2[0] = 2; + eblock2[3] = 2; + eblock2[1] = 5; + eblock2[4] = 5; + eblock2[2] = 1; + eblock2[5] = 1; + dims[0] = 50; + dims[1] = 50; + dims[2] = 50; + test_hyper_unlim_check(sid, dims, (hssize_t)3, (hssize_t)2, eblock1, eblock2); + + /* non-unlim NOTB unlim */ + start2[0] = 1; + start2[1] = 5; + start2[2] = 2; + count2[0] = 2; + count2[1] = 2; + count2[2] = 6; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start2, NULL, count2, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + count[0] = 1; + count[1] = H5S_UNLIMITED; + count[2] = 2; + block[0] = 2; + block[1] = 2; + block[2] = 2; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_NOTB, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + eblock1[0] = 1; + eblock1[3] = 2; + eblock1[1] = 5; + eblock1[4] = 6; + eblock1[2] = 3; + eblock1[5] = 3; + eblock2[0] = 1; + eblock2[3] = 2; + eblock2[1] = 5; + eblock2[4] = 6; + eblock2[2] = 6; + eblock2[5] = 7; + dims[0] = 50; + dims[1] = 50; + dims[2] = 50; + test_hyper_unlim_check(sid, dims, (hssize_t)12, (hssize_t)2, eblock1, eblock2); + + /* Test H5Sget_select_npoints() */ + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + ssize_out = H5Sget_select_npoints(sid); + VERIFY(ssize_out, (hssize_t)H5S_UNLIMITED, "H5Sget_select_npoints"); + + /* Test H5Sget_select_hyper_nblocks() */ + H5E_BEGIN_TRY + { + ssize_out = H5Sget_select_hyper_nblocks(sid); + } + H5E_END_TRY; + VERIFY(ssize_out, (hssize_t)H5S_UNLIMITED, "H5Sget_select_hyper_nblocks"); + + /* Test H5Sget_select_bounds() */ + ret = H5Sget_select_bounds(sid, start2, count2); + CHECK(ret, FAIL, "H5Sget_select_bounds"); + VERIFY(start2[0], start[0], "H5Sget_select_bounds"); + VERIFY(start2[1], start[1], "H5Sget_select_bounds"); + VERIFY(start2[2], start[2], "H5Sget_select_bounds"); + VERIFY(count2[0], (long)(start[0] + (stride[0] * (count[0] - 1)) + block[0] - 1), "H5Sget_select_bounds"); + VERIFY(count2[1], H5S_UNLIMITED, "H5Sget_select_bounds"); + VERIFY(count2[2], (long)(start[2] + (stride[2] * (count[2] - 1)) + block[2] - 1), "H5Sget_select_bounds"); + + /* Close the dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* end test_hyper_unlim() */ + +/**************************************************************** +** +** test_internal_consistency(): Tests selections on dataspace, then +** verify that internal states of data structures of selections are +** consistent. +** +****************************************************************/ +static void +test_internal_consistency(void) +{ + hid_t all_sid; /* Dataspace ID with "all" selection */ + hid_t none_sid; /* Dataspace ID with "none" selection */ + hid_t single_pt_sid; /* Dataspace ID with single point selection */ + hid_t mult_pt_sid; /* Dataspace ID with multiple point selection */ + hid_t single_hyper_sid; /* Dataspace ID with single block hyperslab selection */ + hid_t single_hyper_all_sid; /* Dataspace ID with single block hyperslab + * selection that is the entire dataspace + */ + hid_t single_hyper_pt_sid; /* Dataspace ID with single block hyperslab + * selection that is the same as the single + * point selection + */ + hid_t regular_hyper_sid; /* Dataspace ID with regular hyperslab selection */ + hid_t irreg_hyper_sid; /* Dataspace ID with irregular hyperslab selection */ + hid_t none_hyper_sid; /* Dataspace ID with "no hyperslabs" selection */ + hid_t scalar_all_sid; /* ID for scalar dataspace with "all" selection */ + hid_t scalar_none_sid; /* ID for scalar dataspace with "none" selection */ + hid_t tmp_sid; /* Temporary dataspace ID */ + hsize_t dims[] = {SPACE9_DIM1, SPACE9_DIM2}; + hsize_t coord1[1][SPACE2_RANK]; /* Coordinates for single point selection */ + hsize_t coord2[SPACE9_DIM2][SPACE9_RANK]; /* Coordinates for multiple point selection */ + hsize_t start[SPACE9_RANK]; /* Hyperslab start */ + hsize_t stride[SPACE9_RANK]; /* Hyperslab stride */ + hsize_t count[SPACE9_RANK]; /* Hyperslab block count */ + hsize_t block[SPACE9_RANK]; /* Hyperslab block size */ +#if 0 + htri_t check; /* Shape comparison return value */ +#endif + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(6, ("Testing Consistency of Internal States\n")); + HDassert(SPACE9_DIM2 >= POINT1_NPOINTS); + + /* Create dataspace for "all" selection */ + all_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(all_sid, FAIL, "H5Screate_simple"); + + /* Select entire extent for dataspace */ + ret = H5Sselect_all(all_sid); + CHECK(ret, FAIL, "H5Sselect_all"); + + /* Create dataspace for "none" selection */ + none_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(none_sid, FAIL, "H5Screate_simple"); + + /* Un-Select entire extent for dataspace */ + ret = H5Sselect_none(none_sid); + CHECK(ret, FAIL, "H5Sselect_none"); + + /* Create dataspace for single point selection */ + single_pt_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(single_pt_sid, FAIL, "H5Screate_simple"); + + /* Select sequence of ten points for multiple point selection */ + coord1[0][0] = 2; + coord1[0][1] = 2; + ret = H5Sselect_elements(single_pt_sid, H5S_SELECT_SET, (size_t)1, (const hsize_t *)coord1); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Create dataspace for multiple point selection */ + mult_pt_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(mult_pt_sid, FAIL, "H5Screate_simple"); + + /* Select sequence of ten points for multiple point selection */ + coord2[0][0] = 2; + coord2[0][1] = 2; + coord2[1][0] = 7; + coord2[1][1] = 2; + coord2[2][0] = 1; + coord2[2][1] = 4; + coord2[3][0] = 2; + coord2[3][1] = 6; + coord2[4][0] = 0; + coord2[4][1] = 8; + coord2[5][0] = 3; + coord2[5][1] = 2; + coord2[6][0] = 4; + coord2[6][1] = 4; + coord2[7][0] = 1; + coord2[7][1] = 0; + coord2[8][0] = 5; + coord2[8][1] = 1; + coord2[9][0] = 9; + coord2[9][1] = 3; + ret = H5Sselect_elements(mult_pt_sid, H5S_SELECT_SET, (size_t)POINT1_NPOINTS, (const hsize_t *)coord2); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Create dataspace for single hyperslab selection */ + single_hyper_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(single_hyper_sid, FAIL, "H5Screate_simple"); + + /* Select 10x10 hyperslab for single hyperslab selection */ + start[0] = 1; + start[1] = 1; + stride[0] = 1; + stride[1] = 1; + count[0] = 1; + count[1] = 1; + block[0] = (SPACE9_DIM1 - 2); + block[1] = (SPACE9_DIM2 - 2); + ret = H5Sselect_hyperslab(single_hyper_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create dataspace for single hyperslab selection with entire extent selected */ + single_hyper_all_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(single_hyper_all_sid, FAIL, "H5Screate_simple"); + + /* Select entire extent for hyperslab selection */ + start[0] = 0; + start[1] = 0; + stride[0] = 1; + stride[1] = 1; + count[0] = 1; + count[1] = 1; + block[0] = SPACE9_DIM1; + block[1] = SPACE9_DIM2; + ret = H5Sselect_hyperslab(single_hyper_all_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create dataspace for single hyperslab selection with single point selected */ + single_hyper_pt_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(single_hyper_pt_sid, FAIL, "H5Screate_simple"); + + /* Select entire extent for hyperslab selection */ + start[0] = 2; + start[1] = 2; + stride[0] = 1; + stride[1] = 1; + count[0] = 1; + count[1] = 1; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(single_hyper_pt_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create dataspace for regular hyperslab selection */ + regular_hyper_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(regular_hyper_sid, FAIL, "H5Screate_simple"); + + /* Select regular, strided hyperslab selection */ + start[0] = 2; + start[1] = 2; + stride[0] = 2; + stride[1] = 2; + count[0] = 5; + count[1] = 2; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(regular_hyper_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create dataspace for irregular hyperslab selection */ + irreg_hyper_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(irreg_hyper_sid, FAIL, "H5Screate_simple"); + + /* Create irregular hyperslab selection by OR'ing two blocks together */ + start[0] = 2; + start[1] = 2; + stride[0] = 1; + stride[1] = 1; + count[0] = 1; + count[1] = 1; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(irreg_hyper_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[0] = 4; + start[1] = 4; + stride[0] = 1; + stride[1] = 1; + count[0] = 1; + count[1] = 1; + block[0] = 3; + block[1] = 3; + ret = H5Sselect_hyperslab(irreg_hyper_sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create dataspace for "no" hyperslab selection */ + none_hyper_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(none_hyper_sid, FAIL, "H5Screate_simple"); + + /* Create "no" hyperslab selection by XOR'ing same blocks together */ + start[0] = 2; + start[1] = 2; + stride[0] = 1; + stride[1] = 1; + count[0] = 1; + count[1] = 1; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(none_hyper_sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + ret = H5Sselect_hyperslab(none_hyper_sid, H5S_SELECT_XOR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create scalar dataspace for "all" selection */ + scalar_all_sid = H5Screate(H5S_SCALAR); + CHECK(scalar_all_sid, FAIL, "H5Screate"); + + /* Create scalar dataspace for "none" selection */ + scalar_none_sid = H5Screate(H5S_SCALAR); + CHECK(scalar_none_sid, FAIL, "H5Screate"); + + /* Un-Select entire extent for dataspace */ + ret = H5Sselect_none(scalar_none_sid); + CHECK(ret, FAIL, "H5Sselect_none"); + + /* Test all the selections created */ + + /* Test the copy of itself */ + tmp_sid = H5Scopy(all_sid); + CHECK(tmp_sid, FAIL, "H5Scopy"); +#if 0 + check = H5S__internal_consistency_test(tmp_sid); + VERIFY(check, TRUE, "H5S__internal_consistency_test"); +#endif + ret = H5Sclose(tmp_sid); + CHECK(ret, FAIL, "H5Sclose"); +#if 0 + /* Test "none" selection */ + check = H5S__internal_consistency_test(none_sid); + VERIFY(check, TRUE, "H5S__internal_consistency_test"); + + /* Test single point selection */ + check = H5S__internal_consistency_test(single_pt_sid); + VERIFY(check, TRUE, "H5S__internal_consistency_test"); + + /* Test multiple point selection */ + check = H5S__internal_consistency_test(mult_pt_sid); + VERIFY(check, TRUE, "H5S__internal_consistency_test"); + + /* Test "plain" single hyperslab selection */ + check = H5S__internal_consistency_test(single_hyper_sid); + VERIFY(check, TRUE, "H5S__internal_consistency_test"); + + /* Test "all" single hyperslab selection */ + check = H5S__internal_consistency_test(single_hyper_all_sid); + VERIFY(check, TRUE, "H5S__internal_consistency_test"); + + /* Test "single point" single hyperslab selection */ + check = H5S__internal_consistency_test(single_hyper_pt_sid); + VERIFY(check, TRUE, "H5S__internal_consistency_test"); + + /* Test regular, strided hyperslab selection */ + check = H5S__internal_consistency_test(regular_hyper_sid); + VERIFY(check, TRUE, "H5S__internal_consistency_test"); + + /* Test irregular hyperslab selection */ + check = H5S__internal_consistency_test(irreg_hyper_sid); + VERIFY(check, TRUE, "H5S__internal_consistency_test"); + + /* Test "no" hyperslab selection */ + check = H5S__internal_consistency_test(none_hyper_sid); + VERIFY(check, TRUE, "H5S__internal_consistency_test"); + + /* Test scalar "all" hyperslab selection */ + check = H5S__internal_consistency_test(scalar_all_sid); + VERIFY(check, TRUE, "H5S__internal_consistency_test"); + + /* Test scalar "none" hyperslab selection */ + check = H5S__internal_consistency_test(scalar_none_sid); + VERIFY(check, TRUE, "H5S__internal_consistency_test"); +#endif + + /* Close dataspaces */ + ret = H5Sclose(all_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(none_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(single_pt_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(mult_pt_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(single_hyper_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(single_hyper_all_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(single_hyper_pt_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(regular_hyper_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(irreg_hyper_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(none_hyper_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(scalar_all_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(scalar_none_sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_internal_consistency() */ + +/**************************************************************** +** +** test_irreg_io(): Tests unusual selections on datasets, to stress the +** new hyperslab code. +** +****************************************************************/ +static void +test_irreg_io(void) +{ + hid_t fid; /* File ID */ + hid_t did; /* Dataset ID */ + hid_t dcpl_id; /* Dataset creation property list ID */ + hid_t sid; /* File dataspace ID */ + hid_t mem_sid; /* Memory dataspace ID */ + hsize_t dims[] = {6, 12}; /* Dataspace dimensions */ + hsize_t chunk_dims[] = {2, 2}; /* Chunk dimensions */ + hsize_t mem_dims[] = {32}; /* Memory dataspace dimensions */ + hsize_t start[2]; /* Hyperslab start */ + hsize_t stride[2]; /* Hyperslab stride */ + hsize_t count[2]; /* Hyperslab block count */ + hsize_t block[2]; /* Hyperslab block size */ + unsigned char wbuf[72]; /* Write buffer */ + unsigned char rbuf[32]; /* Read buffer */ + unsigned u; /* Local index variable */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(6, ("Testing Irregular Hyperslab I/O\n")); + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset */ + sid = H5Screate_simple(2, dims, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Set chunk dimensions for dataset */ + dcpl_id = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl_id, FAIL, "H5Pcreate"); + ret = H5Pset_chunk(dcpl_id, 2, chunk_dims); + CHECK(ret, FAIL, "H5Pset_chunk"); + + /* Create a dataset */ + did = H5Dcreate2(fid, SPACE1_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl_id, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); + + /* Initialize the write buffer */ + for (u = 0; u < 72; u++) + wbuf[u] = (unsigned char)u; + + /* Write entire dataset to disk */ + ret = H5Dwrite(did, H5T_NATIVE_UCHAR, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close the DCPL */ + ret = H5Pclose(dcpl_id); + CHECK(ret, FAIL, "H5Pclose"); + + /* Create dataspace for memory selection */ + mem_sid = H5Screate_simple(1, mem_dims, NULL); + CHECK(mem_sid, FAIL, "H5Screate_simple"); + + /* Select 'L'-shaped region within dataset */ + start[0] = 0; + start[1] = 10; + stride[0] = 1; + stride[1] = 1; + count[0] = 4; + count[1] = 2; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[0] = 4; + start[1] = 0; + stride[0] = 1; + stride[1] = 1; + count[0] = 2; + count[1] = 12; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Reset the buffer */ + HDmemset(rbuf, 0, sizeof(rbuf)); + + /* Read selection from disk */ + ret = H5Dread(did, H5T_NATIVE_UCHAR, mem_sid, sid, H5P_DEFAULT, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Close everything */ + ret = H5Sclose(mem_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_irreg_io() */ + +/**************************************************************** +** +** test_sel_iter(): Test selection iterator API routines. +** +****************************************************************/ +static void +test_sel_iter(void) +{ + hid_t sid; /* Dataspace ID */ + hid_t iter_id; /* Dataspace selection iterator ID */ + hsize_t dims1[] = {6, 12}; /* 2-D Dataspace dimensions */ + hsize_t coord1[POINT1_NPOINTS][2]; /* Coordinates for point selection */ + hsize_t start[2]; /* Hyperslab start */ + hsize_t stride[2]; /* Hyperslab stride */ + hsize_t count[2]; /* Hyperslab block count */ + hsize_t block[2]; /* Hyperslab block size */ + size_t nseq; /* # of sequences retrieved */ + size_t nbytes; /* # of bytes retrieved */ + hsize_t off[SEL_ITER_MAX_SEQ]; /* Offsets for retrieved sequences */ + size_t len[SEL_ITER_MAX_SEQ]; /* Lengths for retrieved sequences */ + H5S_sel_type sel_type; /* Selection type */ + unsigned sel_share; /* Whether to share selection with dataspace */ + unsigned sel_iter_flags; /* Flags for selection iterator creation */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(6, ("Testing Dataspace Selection Iterators\n")); + + /* Create dataspace */ + sid = H5Screate_simple(2, dims1, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Try creating selection iterator object with bad parameters */ + H5E_BEGIN_TRY + { /* Bad dataspace ID */ + iter_id = H5Ssel_iter_create(H5I_INVALID_HID, (size_t)1, (unsigned)0); + } + H5E_END_TRY; + VERIFY(iter_id, FAIL, "H5Ssel_iter_create"); + H5E_BEGIN_TRY + { /* Bad element size */ + iter_id = H5Ssel_iter_create(sid, (size_t)0, (unsigned)0); + } + H5E_END_TRY; + VERIFY(iter_id, FAIL, "H5Ssel_iter_create"); + H5E_BEGIN_TRY + { /* Bad flag(s) */ + iter_id = H5Ssel_iter_create(sid, (size_t)1, (unsigned)0xffff); + } + H5E_END_TRY; + VERIFY(iter_id, FAIL, "H5Ssel_iter_create"); + + /* Try closing selection iterator, with bad parameters */ + H5E_BEGIN_TRY + { /* Invalid ID */ + ret = H5Ssel_iter_close(H5I_INVALID_HID); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Ssel_iter_close"); + H5E_BEGIN_TRY + { /* Not a selection iterator ID */ + ret = H5Ssel_iter_close(sid); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Ssel_iter_close"); + + /* Try with no selection sharing, and with sharing */ + for (sel_share = 0; sel_share < 2; sel_share++) { + /* Set selection iterator sharing flags */ + if (sel_share) + sel_iter_flags = H5S_SEL_ITER_SHARE_WITH_DATASPACE; + else + sel_iter_flags = 0; + + /* Create selection iterator object */ + iter_id = H5Ssel_iter_create(sid, (size_t)1, (unsigned)sel_iter_flags); + CHECK(iter_id, FAIL, "H5Ssel_iter_create"); + + /* Close selection iterator */ + ret = H5Ssel_iter_close(iter_id); + CHECK(ret, FAIL, "H5Ssel_iter_close"); + + /* Try closing selection iterator twice */ + H5E_BEGIN_TRY + { /* Invalid ID */ + ret = H5Ssel_iter_close(iter_id); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Ssel_iter_close"); + + /* Create selection iterator object */ + iter_id = H5Ssel_iter_create(sid, (size_t)1, (unsigned)sel_iter_flags); + CHECK(iter_id, FAIL, "H5Ssel_iter_create"); + + /* Try resetting selection iterator with bad parameters */ + H5E_BEGIN_TRY + { + ret = H5Ssel_iter_reset(H5I_INVALID_HID, sid); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Ssel_iter_reset"); + H5E_BEGIN_TRY + { + ret = H5Ssel_iter_reset(iter_id, H5I_INVALID_HID); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Ssel_iter_reset"); + + /* Try retrieving sequences, with bad parameters */ + H5E_BEGIN_TRY + { /* Invalid ID */ + ret = H5Ssel_iter_get_seq_list(H5I_INVALID_HID, (size_t)1, (size_t)1, &nseq, &nbytes, off, len); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Ssel_iter_get_seq_list"); + H5E_BEGIN_TRY + { /* Invalid nseq pointer */ + ret = H5Ssel_iter_get_seq_list(iter_id, (size_t)1, (size_t)1, NULL, &nbytes, off, len); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Ssel_iter_get_seq_list"); + H5E_BEGIN_TRY + { /* Invalid nbytes pointer */ + ret = H5Ssel_iter_get_seq_list(iter_id, (size_t)1, (size_t)1, &nseq, NULL, off, len); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Ssel_iter_get_seq_list"); + H5E_BEGIN_TRY + { /* Invalid offset array */ + ret = H5Ssel_iter_get_seq_list(iter_id, (size_t)1, (size_t)1, &nseq, &nbytes, NULL, len); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Ssel_iter_get_seq_list"); + H5E_BEGIN_TRY + { /* Invalid length array */ + ret = H5Ssel_iter_get_seq_list(iter_id, (size_t)1, (size_t)1, &nseq, &nbytes, off, NULL); + } + H5E_END_TRY; + VERIFY(ret, FAIL, "H5Ssel_iter_get_seq_list"); + + /* Close selection iterator */ + ret = H5Ssel_iter_close(iter_id); + CHECK(ret, FAIL, "H5Ssel_iter_close"); + + /* Test iterators on various basic selection types */ + for (sel_type = H5S_SEL_NONE; sel_type <= H5S_SEL_ALL; sel_type = (H5S_sel_type)(sel_type + 1)) { + switch (sel_type) { + case H5S_SEL_NONE: /* "None" selection */ + ret = H5Sselect_none(sid); + CHECK(ret, FAIL, "H5Sselect_none"); + break; + + case H5S_SEL_POINTS: /* Point selection */ + /* Select sequence of ten points */ + coord1[0][0] = 0; + coord1[0][1] = 9; + coord1[1][0] = 1; + coord1[1][1] = 2; + coord1[2][0] = 2; + coord1[2][1] = 4; + coord1[3][0] = 0; + coord1[3][1] = 6; + coord1[4][0] = 1; + coord1[4][1] = 8; + coord1[5][0] = 2; + coord1[5][1] = 10; + coord1[6][0] = 0; + coord1[6][1] = 11; + coord1[7][0] = 1; + coord1[7][1] = 4; + coord1[8][0] = 2; + coord1[8][1] = 1; + coord1[9][0] = 0; + coord1[9][1] = 3; + ret = H5Sselect_elements(sid, H5S_SELECT_SET, (size_t)POINT1_NPOINTS, + (const hsize_t *)coord1); + CHECK(ret, FAIL, "H5Sselect_elements"); + break; + + case H5S_SEL_HYPERSLABS: /* Hyperslab selection */ + /* Select regular hyperslab */ + start[0] = 3; + start[1] = 0; + stride[0] = 2; + stride[1] = 2; + count[0] = 2; + count[1] = 5; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + break; + + case H5S_SEL_ALL: /* "All" selection */ + ret = H5Sselect_all(sid); + CHECK(ret, FAIL, "H5Sselect_all"); + break; + + case H5S_SEL_ERROR: + case H5S_SEL_N: + default: + HDassert(0 && "Can't occur"); + break; + } /* end switch */ + + /* Create selection iterator object */ + iter_id = H5Ssel_iter_create(sid, (size_t)1, (unsigned)sel_iter_flags); + CHECK(iter_id, FAIL, "H5Ssel_iter_create"); + + /* Try retrieving no sequences, with 0 for maxseq & maxbytes */ + ret = H5Ssel_iter_get_seq_list(iter_id, (size_t)0, (size_t)1, &nseq, &nbytes, off, len); + CHECK(ret, FAIL, "H5Ssel_iter_get_seq_list"); + VERIFY(nseq, 0, "H5Ssel_iter_get_seq_list"); + VERIFY(nbytes, 0, "H5Ssel_iter_get_seq_list"); + ret = H5Ssel_iter_get_seq_list(iter_id, (size_t)1, (size_t)0, &nseq, &nbytes, off, len); + CHECK(ret, FAIL, "H5Ssel_iter_get_seq_list"); + VERIFY(nseq, 0, "H5Ssel_iter_get_seq_list"); + VERIFY(nbytes, 0, "H5Ssel_iter_get_seq_list"); + + /* Try retrieving all sequences */ + ret = H5Ssel_iter_get_seq_list(iter_id, (size_t)SEL_ITER_MAX_SEQ, (size_t)(1024 * 1024), &nseq, + &nbytes, off, len); + CHECK(ret, FAIL, "H5Ssel_iter_get_seq_list"); + + /* Check results from retrieving sequence list */ + switch (sel_type) { + case H5S_SEL_NONE: /* "None" selection */ + VERIFY(nseq, 0, "H5Ssel_iter_get_seq_list"); + VERIFY(nbytes, 0, "H5Ssel_iter_get_seq_list"); + break; + + case H5S_SEL_POINTS: /* Point selection */ + VERIFY(nseq, 10, "H5Ssel_iter_get_seq_list"); + VERIFY(nbytes, 10, "H5Ssel_iter_get_seq_list"); + break; + + case H5S_SEL_HYPERSLABS: /* Hyperslab selection */ + VERIFY(nseq, 10, "H5Ssel_iter_get_seq_list"); + VERIFY(nbytes, 10, "H5Ssel_iter_get_seq_list"); + break; + + case H5S_SEL_ALL: /* "All" selection */ + VERIFY(nseq, 1, "H5Ssel_iter_get_seq_list"); + VERIFY(nbytes, 72, "H5Ssel_iter_get_seq_list"); + break; + + case H5S_SEL_ERROR: + case H5S_SEL_N: + default: + HDassert(0 && "Can't occur"); + break; + } /* end switch */ + + /* Close selection iterator */ + ret = H5Ssel_iter_close(iter_id); + CHECK(ret, FAIL, "H5Ssel_iter_close"); + } /* end for */ + + /* Create selection iterator object */ + iter_id = H5Ssel_iter_create(sid, (size_t)1, (unsigned)sel_iter_flags); + CHECK(iter_id, FAIL, "H5Ssel_iter_create"); + + /* Test iterators on various basic selection types using + * H5Ssel_iter_reset instead of creating multiple iterators */ + for (sel_type = H5S_SEL_NONE; sel_type <= H5S_SEL_ALL; sel_type = (H5S_sel_type)(sel_type + 1)) { + switch (sel_type) { + case H5S_SEL_NONE: /* "None" selection */ + ret = H5Sselect_none(sid); + CHECK(ret, FAIL, "H5Sselect_none"); + break; + + case H5S_SEL_POINTS: /* Point selection */ + /* Select sequence of ten points */ + coord1[0][0] = 0; + coord1[0][1] = 9; + coord1[1][0] = 1; + coord1[1][1] = 2; + coord1[2][0] = 2; + coord1[2][1] = 4; + coord1[3][0] = 0; + coord1[3][1] = 6; + coord1[4][0] = 1; + coord1[4][1] = 8; + coord1[5][0] = 2; + coord1[5][1] = 10; + coord1[6][0] = 0; + coord1[6][1] = 11; + coord1[7][0] = 1; + coord1[7][1] = 4; + coord1[8][0] = 2; + coord1[8][1] = 1; + coord1[9][0] = 0; + coord1[9][1] = 3; + ret = H5Sselect_elements(sid, H5S_SELECT_SET, (size_t)POINT1_NPOINTS, + (const hsize_t *)coord1); + CHECK(ret, FAIL, "H5Sselect_elements"); + break; + + case H5S_SEL_HYPERSLABS: /* Hyperslab selection */ + /* Select regular hyperslab */ + start[0] = 3; + start[1] = 0; + stride[0] = 2; + stride[1] = 2; + count[0] = 2; + count[1] = 5; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + break; + + case H5S_SEL_ALL: /* "All" selection */ + ret = H5Sselect_all(sid); + CHECK(ret, FAIL, "H5Sselect_all"); + break; + + case H5S_SEL_ERROR: + case H5S_SEL_N: + default: + HDassert(0 && "Can't occur"); + break; + } /* end switch */ + + /* Try retrieving no sequences, with 0 for maxseq & maxbytes */ + ret = H5Ssel_iter_get_seq_list(iter_id, (size_t)0, (size_t)1, &nseq, &nbytes, off, len); + CHECK(ret, FAIL, "H5Ssel_iter_get_seq_list"); + VERIFY(nseq, 0, "H5Ssel_iter_get_seq_list"); + VERIFY(nbytes, 0, "H5Ssel_iter_get_seq_list"); + ret = H5Ssel_iter_get_seq_list(iter_id, (size_t)1, (size_t)0, &nseq, &nbytes, off, len); + CHECK(ret, FAIL, "H5Ssel_iter_get_seq_list"); + VERIFY(nseq, 0, "H5Ssel_iter_get_seq_list"); + VERIFY(nbytes, 0, "H5Ssel_iter_get_seq_list"); + + /* Reset iterator */ + ret = H5Ssel_iter_reset(iter_id, sid); + CHECK(ret, FAIL, "H5Ssel_iter_reset"); + + /* Try retrieving all sequences */ + ret = H5Ssel_iter_get_seq_list(iter_id, (size_t)SEL_ITER_MAX_SEQ, (size_t)(1024 * 1024), &nseq, + &nbytes, off, len); + CHECK(ret, FAIL, "H5Ssel_iter_get_seq_list"); + + /* Check results from retrieving sequence list */ + switch (sel_type) { + case H5S_SEL_NONE: /* "None" selection */ + VERIFY(nseq, 0, "H5Ssel_iter_get_seq_list"); + VERIFY(nbytes, 0, "H5Ssel_iter_get_seq_list"); + break; + + case H5S_SEL_POINTS: /* Point selection */ + VERIFY(nseq, 10, "H5Ssel_iter_get_seq_list"); + VERIFY(nbytes, 10, "H5Ssel_iter_get_seq_list"); + break; + + case H5S_SEL_HYPERSLABS: /* Hyperslab selection */ + VERIFY(nseq, 10, "H5Ssel_iter_get_seq_list"); + VERIFY(nbytes, 10, "H5Ssel_iter_get_seq_list"); + break; + + case H5S_SEL_ALL: /* "All" selection */ + VERIFY(nseq, 1, "H5Ssel_iter_get_seq_list"); + VERIFY(nbytes, 72, "H5Ssel_iter_get_seq_list"); + break; + + case H5S_SEL_ERROR: + case H5S_SEL_N: + default: + HDassert(0 && "Can't occur"); + break; + } /* end switch */ + + /* Reset iterator */ + ret = H5Ssel_iter_reset(iter_id, sid); + CHECK(ret, FAIL, "H5Ssel_iter_reset"); + + /* Try retrieving all sequences again */ + ret = H5Ssel_iter_get_seq_list(iter_id, (size_t)SEL_ITER_MAX_SEQ, (size_t)(1024 * 1024), &nseq, + &nbytes, off, len); + CHECK(ret, FAIL, "H5Ssel_iter_get_seq_list"); + + /* Check results from retrieving sequence list */ + switch (sel_type) { + case H5S_SEL_NONE: /* "None" selection */ + VERIFY(nseq, 0, "H5Ssel_iter_get_seq_list"); + VERIFY(nbytes, 0, "H5Ssel_iter_get_seq_list"); + break; + + case H5S_SEL_POINTS: /* Point selection */ + VERIFY(nseq, 10, "H5Ssel_iter_get_seq_list"); + VERIFY(nbytes, 10, "H5Ssel_iter_get_seq_list"); + break; + + case H5S_SEL_HYPERSLABS: /* Hyperslab selection */ + VERIFY(nseq, 10, "H5Ssel_iter_get_seq_list"); + VERIFY(nbytes, 10, "H5Ssel_iter_get_seq_list"); + break; + + case H5S_SEL_ALL: /* "All" selection */ + VERIFY(nseq, 1, "H5Ssel_iter_get_seq_list"); + VERIFY(nbytes, 72, "H5Ssel_iter_get_seq_list"); + break; + + case H5S_SEL_ERROR: + case H5S_SEL_N: + default: + HDassert(0 && "Can't occur"); + break; + } /* end switch */ + + /* Reset iterator */ + ret = H5Ssel_iter_reset(iter_id, sid); + CHECK(ret, FAIL, "H5Ssel_iter_reset"); + } /* end for */ + + /* Close selection iterator */ + ret = H5Ssel_iter_close(iter_id); + CHECK(ret, FAIL, "H5Ssel_iter_close"); + + /* Point selection which will merge into smaller # of sequences */ + coord1[0][0] = 0; + coord1[0][1] = 9; + coord1[1][0] = 0; + coord1[1][1] = 10; + coord1[2][0] = 0; + coord1[2][1] = 11; + coord1[3][0] = 0; + coord1[3][1] = 6; + coord1[4][0] = 1; + coord1[4][1] = 8; + coord1[5][0] = 2; + coord1[5][1] = 10; + coord1[6][0] = 0; + coord1[6][1] = 11; + coord1[7][0] = 1; + coord1[7][1] = 4; + coord1[8][0] = 1; + coord1[8][1] = 5; + coord1[9][0] = 1; + coord1[9][1] = 6; + ret = H5Sselect_elements(sid, H5S_SELECT_SET, (size_t)POINT1_NPOINTS, (const hsize_t *)coord1); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Create selection iterator object */ + iter_id = H5Ssel_iter_create(sid, (size_t)1, (unsigned)sel_iter_flags); + CHECK(iter_id, FAIL, "H5Ssel_iter_create"); + + /* Try retrieving all sequences */ + ret = H5Ssel_iter_get_seq_list(iter_id, (size_t)SEL_ITER_MAX_SEQ, (size_t)(1024 * 1024), &nseq, + &nbytes, off, len); + CHECK(ret, FAIL, "H5Ssel_iter_get_seq_list"); + VERIFY(nseq, 6, "H5Ssel_iter_get_seq_list"); + VERIFY(nbytes, 10, "H5Ssel_iter_get_seq_list"); + + /* Reset iterator */ + ret = H5Ssel_iter_reset(iter_id, sid); + CHECK(ret, FAIL, "H5Ssel_iter_reset"); + + /* Try retrieving all sequences again */ + ret = H5Ssel_iter_get_seq_list(iter_id, (size_t)SEL_ITER_MAX_SEQ, (size_t)(1024 * 1024), &nseq, + &nbytes, off, len); + CHECK(ret, FAIL, "H5Ssel_iter_get_seq_list"); + VERIFY(nseq, 6, "H5Ssel_iter_get_seq_list"); + VERIFY(nbytes, 10, "H5Ssel_iter_get_seq_list"); + + /* Close selection iterator */ + ret = H5Ssel_iter_close(iter_id); + CHECK(ret, FAIL, "H5Ssel_iter_close"); + + /* Select irregular hyperslab, which will merge into smaller # of sequences */ + start[0] = 3; + start[1] = 0; + stride[0] = 2; + stride[1] = 2; + count[0] = 2; + count[1] = 5; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[0] = 3; + start[1] = 3; + stride[0] = 2; + stride[1] = 2; + count[0] = 2; + count[1] = 5; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create selection iterator object */ + iter_id = H5Ssel_iter_create(sid, (size_t)1, (unsigned)sel_iter_flags); + CHECK(iter_id, FAIL, "H5Ssel_iter_create"); + + /* Try retrieving all sequences */ + ret = H5Ssel_iter_get_seq_list(iter_id, (size_t)SEL_ITER_MAX_SEQ, (size_t)(1024 * 1024), &nseq, + &nbytes, off, len); + CHECK(ret, FAIL, "H5Ssel_iter_get_seq_list"); + VERIFY(nseq, 6, "H5Ssel_iter_get_seq_list"); + VERIFY(nbytes, 20, "H5Ssel_iter_get_seq_list"); + + /* Reset iterator */ + ret = H5Ssel_iter_reset(iter_id, sid); + CHECK(ret, FAIL, "H5Ssel_iter_reset"); + + /* Try retrieving all sequences again */ + ret = H5Ssel_iter_get_seq_list(iter_id, (size_t)SEL_ITER_MAX_SEQ, (size_t)(1024 * 1024), &nseq, + &nbytes, off, len); + CHECK(ret, FAIL, "H5Ssel_iter_get_seq_list"); + VERIFY(nseq, 6, "H5Ssel_iter_get_seq_list"); + VERIFY(nbytes, 20, "H5Ssel_iter_get_seq_list"); + + /* Close selection iterator */ + ret = H5Ssel_iter_close(iter_id); + CHECK(ret, FAIL, "H5Ssel_iter_close"); + + } /* end for */ + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_sel_iter() */ + +/**************************************************************** +** +** test_select_intersect_block(): Test selections on dataspace, +** verify that "intersect block" routine is working correctly. +** +****************************************************************/ +static void +test_select_intersect_block(void) +{ + hid_t sid; /* Dataspace ID */ + hsize_t dims1[] = {6, 12}; /* 2-D Dataspace dimensions */ + hsize_t block_start[] = {1, 3}; /* Start offset for block */ + hsize_t block_end[] = {2, 5}; /* End offset for block */ + hsize_t block_end2[] = {0, 5}; /* Bad end offset for block */ + hsize_t block_end3[] = {2, 2}; /* Another bad end offset for block */ + hsize_t block_end4[] = {1, 3}; /* End offset that makes a single element block */ + hsize_t coord[10][2]; /* Coordinates for point selection */ + hsize_t start[2]; /* Starting location of hyperslab */ + hsize_t stride[2]; /* Stride of hyperslab */ + hsize_t count[2]; /* Element count of hyperslab */ + hsize_t block[2]; /* Block size of hyperslab */ + htri_t status; /* Intersection status */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(6, ("Testing Dataspace Selection Block Intersection\n")); + + /* Create dataspace */ + sid = H5Screate_simple(2, dims1, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Try intersection calls with bad parameters */ + H5E_BEGIN_TRY + { /* Bad dataspace ID */ + status = H5Sselect_intersect_block(H5I_INVALID_HID, block_start, block_end); + } + H5E_END_TRY; + VERIFY(status, FAIL, "H5Sselect_intersect_block"); + H5E_BEGIN_TRY + { /* Bad start pointer */ + status = H5Sselect_intersect_block(sid, NULL, block_end); + } + H5E_END_TRY; + VERIFY(status, FAIL, "H5Sselect_intersect_block"); + H5E_BEGIN_TRY + { /* Bad end pointer */ + status = H5Sselect_intersect_block(sid, block_start, NULL); + } + H5E_END_TRY; + VERIFY(status, FAIL, "H5Sselect_intersect_block"); + H5E_BEGIN_TRY + { /* Invalid block */ + status = H5Sselect_intersect_block(sid, block_start, block_end2); + } + H5E_END_TRY; + VERIFY(status, FAIL, "H5Sselect_intersect_block"); + H5E_BEGIN_TRY + { /* Another invalid block */ + status = H5Sselect_intersect_block(sid, block_start, block_end3); + } + H5E_END_TRY; + VERIFY(status, FAIL, "H5Sselect_intersect_block"); + + /* Set selection to 'none' */ + ret = H5Sselect_none(sid); + CHECK(ret, FAIL, "H5Sselect_none"); + + /* Test block intersection with 'none' selection (always false) */ + status = H5Sselect_intersect_block(sid, block_start, block_end); + VERIFY(status, FALSE, "H5Sselect_intersect_block"); + + /* Set selection to 'all' */ + ret = H5Sselect_all(sid); + CHECK(ret, FAIL, "H5Sselect_all"); + + /* Test block intersection with 'all' selection (always true) */ + status = H5Sselect_intersect_block(sid, block_start, block_end); + VERIFY(status, TRUE, "H5Sselect_intersect_block"); + + /* Select sequence of ten points */ + coord[0][0] = 0; + coord[0][1] = 10; + coord[1][0] = 1; + coord[1][1] = 2; + coord[2][0] = 2; + coord[2][1] = 4; + coord[3][0] = 0; + coord[3][1] = 6; + coord[4][0] = 1; + coord[4][1] = 8; + coord[5][0] = 2; + coord[5][1] = 11; + coord[6][0] = 0; + coord[6][1] = 4; + coord[7][0] = 1; + coord[7][1] = 0; + coord[8][0] = 2; + coord[8][1] = 1; + coord[9][0] = 0; + coord[9][1] = 3; + ret = H5Sselect_elements(sid, H5S_SELECT_SET, (size_t)10, (const hsize_t *)coord); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Test block intersection with 'point' selection */ + status = H5Sselect_intersect_block(sid, block_start, block_end); + VERIFY(status, TRUE, "H5Sselect_intersect_block"); + status = H5Sselect_intersect_block(sid, block_start, block_end4); + VERIFY(status, FALSE, "H5Sselect_intersect_block"); + + /* Select single 4x6 hyperslab block at (2,1) */ + start[0] = 2; + start[1] = 1; + stride[0] = 1; + stride[1] = 1; + count[0] = 4; + count[1] = 6; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Test block intersection with single 'hyperslab' selection */ + status = H5Sselect_intersect_block(sid, block_start, block_end); + VERIFY(status, TRUE, "H5Sselect_intersect_block"); + status = H5Sselect_intersect_block(sid, block_start, block_end4); + VERIFY(status, FALSE, "H5Sselect_intersect_block"); + + /* 'OR' another hyperslab block in, making an irregular hyperslab selection */ + start[0] = 3; + start[1] = 2; + stride[0] = 1; + stride[1] = 1; + count[0] = 4; + count[1] = 6; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Test block intersection with 'hyperslab' selection */ + status = H5Sselect_intersect_block(sid, block_start, block_end); + VERIFY(status, TRUE, "H5Sselect_intersect_block"); + status = H5Sselect_intersect_block(sid, block_start, block_end4); + VERIFY(status, FALSE, "H5Sselect_intersect_block"); + + /* Select regular, strided hyperslab selection */ + start[0] = 2; + start[1] = 1; + stride[0] = 2; + stride[1] = 2; + count[0] = 2; + count[1] = 4; + block[0] = 1; + block[1] = 1; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Test block intersection with single 'hyperslab' selection */ + status = H5Sselect_intersect_block(sid, block_start, block_end); + VERIFY(status, TRUE, "H5Sselect_intersect_block"); + status = H5Sselect_intersect_block(sid, block_start, block_end4); + VERIFY(status, FALSE, "H5Sselect_intersect_block"); + + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_select_intersect_block() */ + +/**************************************************************** +** +** test_hyper_io_1d(): +** Test to verify all the selected 10th element in the 1-d file +** dataspace is read correctly into the 1-d contiguous memory space. +** This is modeled after the test scenario described in HDFFV-10585 +** that demonstrated the hyperslab slowness. A fix to speed up +** performance is in place to handle the special case for 1-d disjoint +** file dataspace into 1-d single block contiguous memory space. +** +****************************************************************/ +static void +test_hyper_io_1d(void) +{ + hid_t fid; /* File ID */ + hid_t did; /* Dataset ID */ + hid_t sid, mid; /* Dataspace IDs */ + hid_t dcpl; /* Dataset creation property list ID */ + hsize_t dims[1], maxdims[1], dimsm[1]; /* Dataset dimension sizes */ + hsize_t chunk_dims[1]; /* Chunk dimension size */ + hsize_t offset[1]; /* Starting offset for hyperslab */ + hsize_t stride[1]; /* Distance between blocks in the hyperslab selection */ + hsize_t count[1]; /* # of blocks in the the hyperslab selection */ + hsize_t block[1]; /* Size of block in the hyperslab selection */ + unsigned int wdata[CHUNKSZ]; /* Data to be written */ + unsigned int rdata[NUM_ELEMENTS / 10]; /* Data to be read */ + herr_t ret; /* Generic return value */ + unsigned i; /* Local index variable */ + + /* Output message about test being performed */ + MESSAGE(6, ("Testing Hyperslab I/O for 1-d single block memory space\n")); + + for (i = 0; i < CHUNKSZ; i++) + wdata[i] = i; + + /* Create the file file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, H5I_INVALID_HID, "H5Fcreate"); + + /* Create file dataspace */ + dims[0] = CHUNKSZ; + maxdims[0] = H5S_UNLIMITED; + sid = H5Screate_simple(RANK, dims, maxdims); + CHECK(sid, H5I_INVALID_HID, "H5Pcreate"); + + /* Create memory dataspace */ + dimsm[0] = CHUNKSZ; + mid = H5Screate_simple(RANK, dimsm, NULL); + CHECK(mid, H5I_INVALID_HID, "H5Pcreate"); + + /* Set up to create a chunked dataset */ + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, H5I_INVALID_HID, "H5Pcreate"); + + chunk_dims[0] = CHUNKSZ; + ret = H5Pset_chunk(dcpl, RANK, chunk_dims); + CHECK(ret, FAIL, "H5Pset_chunk"); + + /* Create a chunked dataset */ + did = H5Dcreate2(fid, DNAME, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(did, H5I_INVALID_HID, "H5Dcreate2"); + + /* Set up hyperslab selection for file dataspace */ + offset[0] = 0; + stride[0] = 1; + count[0] = 1; + block[0] = CHUNKSZ; + + /* Write to each chunk in the dataset */ + for (i = 0; i < NUMCHUNKS; i++) { + /* Set the hyperslab selection */ + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, offset, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Write to the dataset */ + ret = H5Dwrite(did, H5T_NATIVE_INT, mid, sid, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Extend the dataset's dataspace */ + if (i < (NUMCHUNKS - 1)) { + offset[0] = offset[0] + CHUNKSZ; + dims[0] = dims[0] + CHUNKSZ; + ret = H5Dset_extent(did, dims); + CHECK(ret, FAIL, "H5Dset_extent"); + + /* Get the dataset's current dataspace */ + sid = H5Dget_space(did); + CHECK(sid, H5I_INVALID_HID, "H5Dget_space"); + } + } + + /* Closing */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(mid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Open the file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid, H5I_INVALID_HID, "H5Fopen"); + + /* Open the dataset */ + did = H5Dopen2(fid, DNAME, H5P_DEFAULT); + CHECK(did, H5I_INVALID_HID, "H5Dopen"); + + /* Set up to read every 10th element in file dataspace */ + offset[0] = 1; + stride[0] = 10; + count[0] = NUM_ELEMENTS / 10; + block[0] = 1; + + /* Get the dataset's dataspace */ + sid = H5Dget_space(did); + CHECK(sid, H5I_INVALID_HID, "H5Dget_space"); + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, offset, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Set up contiguous memory dataspace for the selected elements */ + dimsm[0] = count[0]; + mid = H5Screate_simple(RANK, dimsm, NULL); + CHECK(mid, H5I_INVALID_HID, "H5Screate_simple"); + + /* Read all the selected 10th elements in the dataset into "rdata" */ + ret = H5Dread(did, H5T_NATIVE_INT, mid, sid, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Verify data read is correct */ + for (i = 0; i < 6; i += 2) { + VERIFY(rdata[i], 1, "H5Dread\n"); + VERIFY(rdata[i + 1], 11, "H5Dread\n"); + } + + /* Closing */ + ret = H5Sclose(mid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + +} /* test_hyper_io_1d() */ + +/**************************************************************** +** +** test_h5s_set_extent_none: +** Test to verify the behavior of dataspace code when passed +** a dataspace modified by H5Sset_extent_none(). +** +****************************************************************/ +static void +test_h5s_set_extent_none(void) +{ + hid_t sid = H5I_INVALID_HID; + hid_t dst_sid = H5I_INVALID_HID; + hid_t null_sid = H5I_INVALID_HID; + int rank = 1; + hsize_t current_dims = 123; + H5S_class_t cls; + int out_rank; + hsize_t out_dims; + hsize_t out_maxdims; + hssize_t out_points; + htri_t equal; + herr_t ret; + + /* Specific values here don't matter as we're just going to reset */ + sid = H5Screate_simple(rank, ¤t_dims, NULL); + CHECK(sid, H5I_INVALID_HID, "H5Screate_simple"); + + /* Dataspace class will be H5S_NULL after this. + * In versions prior to 1.10.7 / 1.12.1 this would produce a + * dataspace with the internal H5S_NO_CLASS class. + */ + ret = H5Sset_extent_none(sid); + CHECK(ret, FAIL, "H5Sset_extent_none"); + cls = H5Sget_simple_extent_type(sid); + VERIFY(cls, H5S_NULL, "H5Sget_simple_extent_type"); + + /* Extent getters should generate normal results and not segfault. + */ + out_rank = H5Sget_simple_extent_dims(sid, &out_dims, &out_maxdims); + VERIFY(out_rank, 0, "H5Sget_simple_extent_dims"); + out_rank = H5Sget_simple_extent_ndims(sid); + VERIFY(out_rank, 0, "H5Sget_simple_extent_ndims"); + out_points = H5Sget_simple_extent_npoints(sid); + VERIFY(out_points, 0, "H5Sget_simple_extent_npoints"); + + /* Check that copying the new (non-)extent works. + */ + dst_sid = H5Screate_simple(rank, ¤t_dims, NULL); + CHECK(dst_sid, H5I_INVALID_HID, "H5Screate_simple"); + ret = H5Sextent_copy(dst_sid, sid); + CHECK(ret, FAIL, "H5Sextent_copy"); + + /* Check that H5Sset_extent_none() produces the same extent as + * H5Screate(H5S_NULL). + */ + null_sid = H5Screate(H5S_NULL); + CHECK(null_sid, H5I_INVALID_HID, "H5Screate"); + equal = H5Sextent_equal(sid, null_sid); + VERIFY(equal, TRUE, "H5Sextent_equal"); + + /* Close */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(dst_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(null_sid); + CHECK(ret, FAIL, "H5Sclose"); + +} /* test_h5s_set_extent_none() */ + +/**************************************************************** +** +** test_select(): Main H5S selection testing routine. +** +****************************************************************/ +void +test_select(void) +{ + hid_t plist_id; /* Property list for reading random hyperslabs */ + hid_t fapl; /* Property list accessing the file */ + int mdc_nelmts; /* Metadata number of elements */ + size_t rdcc_nelmts; /* Raw data number of elements */ + size_t rdcc_nbytes; /* Raw data number of bytes */ + double rdcc_w0; /* Raw data write percentage */ + hssize_t offset[SPACE7_RANK] = {1, 1}; /* Offset for testing selection offsets */ + const char *env_h5_drvr; /* File Driver value from environment */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Selections\n")); + + /* Get the VFD to use */ + env_h5_drvr = HDgetenv(HDF5_DRIVER); + if (env_h5_drvr == NULL) + env_h5_drvr = "nomatch"; + + /* Create a dataset transfer property list */ + plist_id = H5Pcreate(H5P_DATASET_XFER); + CHECK(plist_id, FAIL, "H5Pcreate"); + + /* test I/O with a very small buffer for reads */ + ret = H5Pset_buffer(plist_id, (size_t)59, NULL, NULL); + CHECK(ret, FAIL, "H5Pset_buffer"); + + /* These next tests use the same file */ + test_select_hyper(H5P_DEFAULT); /* Test basic H5S hyperslab selection code */ + test_select_hyper(plist_id); /* Test basic H5S hyperslab selection code */ + test_select_point(H5P_DEFAULT); /* Test basic H5S element selection code, also tests appending to existing + element selections */ + test_select_point(plist_id); /* Test basic H5S element selection code, also tests appending to existing + element selections */ + test_select_all(H5P_DEFAULT); /* Test basic all & none selection code */ + test_select_all(plist_id); /* Test basic all & none selection code */ + test_select_all_hyper(H5P_DEFAULT); /* Test basic all & none selection code */ + test_select_all_hyper(plist_id); /* Test basic all & none selection code */ + + /* These next tests use the same file */ + test_select_combo(); /* Test combined hyperslab & element selection code */ + test_select_hyper_stride(H5P_DEFAULT); /* Test strided hyperslab selection code */ + test_select_hyper_stride(plist_id); /* Test strided hyperslab selection code */ + test_select_hyper_contig(H5T_STD_U16LE, H5P_DEFAULT); /* Test contiguous hyperslab selection code */ + test_select_hyper_contig(H5T_STD_U16LE, plist_id); /* Test contiguous hyperslab selection code */ + test_select_hyper_contig(H5T_STD_U16BE, H5P_DEFAULT); /* Test contiguous hyperslab selection code */ + test_select_hyper_contig(H5T_STD_U16BE, plist_id); /* Test contiguous hyperslab selection code */ + test_select_hyper_contig2(H5T_STD_U16LE, + H5P_DEFAULT); /* Test more contiguous hyperslab selection cases */ + test_select_hyper_contig2(H5T_STD_U16LE, plist_id); /* Test more contiguous hyperslab selection cases */ + test_select_hyper_contig2(H5T_STD_U16BE, + H5P_DEFAULT); /* Test more contiguous hyperslab selection cases */ + test_select_hyper_contig2(H5T_STD_U16BE, plist_id); /* Test more contiguous hyperslab selection cases */ + test_select_hyper_contig3(H5T_STD_U16LE, + H5P_DEFAULT); /* Test yet more contiguous hyperslab selection cases */ + test_select_hyper_contig3(H5T_STD_U16LE, + plist_id); /* Test yet more contiguous hyperslab selection cases */ + test_select_hyper_contig3(H5T_STD_U16BE, + H5P_DEFAULT); /* Test yet more contiguous hyperslab selection cases */ + test_select_hyper_contig3(H5T_STD_U16BE, + plist_id); /* Test yet more contiguous hyperslab selection cases */ +#if 0 + test_select_hyper_contig_dr(H5T_STD_U16LE, H5P_DEFAULT); + test_select_hyper_contig_dr(H5T_STD_U16LE, plist_id); + test_select_hyper_contig_dr(H5T_STD_U16BE, H5P_DEFAULT); + test_select_hyper_contig_dr(H5T_STD_U16BE, plist_id); +#else + HDprintf("** SKIPPED a test due to file creation issues\n"); +#endif +#if 0 + test_select_hyper_checker_board_dr(H5T_STD_U16LE, H5P_DEFAULT); + test_select_hyper_checker_board_dr(H5T_STD_U16LE, plist_id); + test_select_hyper_checker_board_dr(H5T_STD_U16BE, H5P_DEFAULT); + test_select_hyper_checker_board_dr(H5T_STD_U16BE, plist_id); +#else + HDprintf("** SKIPPED a test due to assertion in HDF5\n"); +#endif + test_select_hyper_copy(); /* Test hyperslab selection copying code */ + test_select_point_copy(); /* Test point selection copying code */ + test_select_hyper_offset(); /* Test selection offset code with hyperslabs */ + test_select_hyper_offset2(); /* Test more selection offset code with hyperslabs */ + test_select_point_offset(); /* Test selection offset code with elements */ + test_select_hyper_union(); /* Test hyperslab union code */ + + /* Fancy hyperslab API tests */ + test_select_hyper_union_stagger(); /* Test hyperslab union code for staggered slabs */ + test_select_hyper_union_3d(); /* Test hyperslab union code for 3-D dataset */ + test_select_hyper_valid_combination(); /* Test different input combinations */ + + /* The following tests are currently broken with the Direct VFD */ + if (HDstrcmp(env_h5_drvr, "direct") != 0) { + test_select_hyper_and_2d(); /* Test hyperslab intersection (AND) code for 2-D dataset */ + test_select_hyper_xor_2d(); /* Test hyperslab XOR code for 2-D dataset */ + test_select_hyper_notb_2d(); /* Test hyperslab NOTB code for 2-D dataset */ + test_select_hyper_nota_2d(); /* Test hyperslab NOTA code for 2-D dataset */ + } + + /* test the random hyperslab I/O with the default property list for reading */ + test_select_hyper_union_random_5d(H5P_DEFAULT); /* Test hyperslab union code for random 5-D hyperslabs */ + + /* test random hyperslab I/O with a small buffer for reads */ + test_select_hyper_union_random_5d(plist_id); /* Test hyperslab union code for random 5-D hyperslabs */ + + /* Create a dataset transfer property list */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + CHECK(fapl, FAIL, "H5Pcreate"); + + /* Get the default file access properties for caching */ + ret = H5Pget_cache(fapl, &mdc_nelmts, &rdcc_nelmts, &rdcc_nbytes, &rdcc_w0); + CHECK(ret, FAIL, "H5Pget_cache"); + + /* Increase the size of the raw data cache */ + rdcc_nbytes = 10 * 1024 * 1024; + + /* Set the file access properties for caching */ + ret = H5Pset_cache(fapl, mdc_nelmts, rdcc_nelmts, rdcc_nbytes, rdcc_w0); + CHECK(ret, FAIL, "H5Pset_cache"); + + /* Test reading in a large hyperslab with a chunked dataset */ + test_select_hyper_chunk(fapl, H5P_DEFAULT); + + /* Test reading in a large hyperslab with a chunked dataset a small amount at a time */ + test_select_hyper_chunk(fapl, plist_id); + + /* Close file access property list */ + ret = H5Pclose(fapl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close dataset transfer property list */ + ret = H5Pclose(plist_id); + CHECK(ret, FAIL, "H5Pclose"); + + /* More tests for checking validity of selections */ + test_select_valid(); + + /* Tests for combining "all" and "none" selections with hyperslabs */ + test_select_combine(); + + /* Test filling selections */ + /* (Also tests iterating through each selection */ + test_select_fill_all(); + test_select_fill_point(NULL); + test_select_fill_point(offset); + test_select_fill_hyper_simple(NULL); + test_select_fill_hyper_simple(offset); + test_select_fill_hyper_regular(NULL); + test_select_fill_hyper_regular(offset); + test_select_fill_hyper_irregular(NULL); + test_select_fill_hyper_irregular(offset); + + /* Test 0-sized selections */ + test_select_none(); + + /* Test selections on scalar dataspaces */ + test_scalar_select(); + test_scalar_select2(); + test_scalar_select3(); + + /* Test "same shape" routine */ + test_shape_same(); + + /* Test "same shape" routine for selections of different rank */ + test_shape_same_dr(); + + /* Test "re-build" routine */ + test_space_rebuild(); + + /* Test "update diminfo" routine */ + test_space_update_diminfo(); + + /* Test point selections in chunked datasets */ + test_select_point_chunk(); + + /* Test scalar dataspaces in chunked datasets */ + test_select_scalar_chunk(); +#if 0 + /* Test using selection offset on hyperslab in chunked dataset */ + test_select_hyper_chunk_offset(); + test_select_hyper_chunk_offset2(); +#else + HDprintf("** SKIPPED a test due to assertion in HDF5\n"); +#endif + + /* Test selection bounds with & without offsets */ + test_select_bounds(); + + /* Test 'regular' hyperslab query routines */ + test_hyper_regular(); + + /* Test unlimited hyperslab selections */ + test_hyper_unlim(); + + /* Test the consistency of internal data structures of selection */ + test_internal_consistency(); + + /* Test irregular selection I/O */ + test_irreg_io(); + + /* Test selection iterators */ + test_sel_iter(); + + /* Test selection intersection with block */ + test_select_intersect_block(); + + /* Test reading of 1-d disjoint file space to 1-d single block memory space */ + test_hyper_io_1d(); + + /* Test H5Sset_extent_none() functionality after we updated it to set + * the class to H5S_NULL instead of H5S_NO_CLASS. + */ + test_h5s_set_extent_none(); + +} /* test_select() */ + +/*------------------------------------------------------------------------- + * Function: cleanup_select + * + * Purpose: Cleanup temporary test files + * + * Return: none + * + * Programmer: Albert Cheng + * July 2, 1998 + * + *------------------------------------------------------------------------- + */ +void +cleanup_select(void) +{ + H5Fdelete(FILENAME, H5P_DEFAULT); +} diff --git a/test/API/ttime.c b/test/API/ttime.c new file mode 100644 index 0000000..74128fd --- /dev/null +++ b/test/API/ttime.c @@ -0,0 +1,231 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*********************************************************** + * + * Test program: ttime + * + * Test the Time Datatype functionality + * + *************************************************************/ + +#include "testhdf5.h" + +#define DATAFILE "ttime.h5" +#ifdef NOT_YET +#define DATASETNAME "Dataset" +#endif /* NOT_YET */ + +/**************************************************************** +** +** test_time_commit(): Test committing time datatypes to a file +** +****************************************************************/ +static void +test_time_commit(void) +{ + hid_t file_id, tid; /* identifiers */ + herr_t status; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Committing Time Datatypes\n")); + + /* Create a new file using default properties. */ + file_id = H5Fcreate(DATAFILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file_id, FAIL, "H5Fcreate"); + + tid = H5Tcopy(H5T_UNIX_D32LE); + CHECK(tid, FAIL, "H5Tcopy"); + status = H5Tcommit2(file_id, "Committed D32LE type", tid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(status, FAIL, "H5Tcommit2"); + status = H5Tclose(tid); + CHECK(status, FAIL, "H5Tclose"); + + tid = H5Tcopy(H5T_UNIX_D32BE); + CHECK(tid, FAIL, "H5Tcopy"); + status = H5Tcommit2(file_id, "Committed D32BE type", tid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(status, FAIL, "H5Tcommit2"); + status = H5Tclose(tid); + CHECK(status, FAIL, "H5Tclose"); + + tid = H5Tcopy(H5T_UNIX_D64LE); + CHECK(tid, FAIL, "H5Tcopy"); + status = H5Tcommit2(file_id, "Committed D64LE type", tid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(status, FAIL, "H5Tcommit2"); + status = H5Tclose(tid); + CHECK(status, FAIL, "H5Tclose"); + + tid = H5Tcopy(H5T_UNIX_D64BE); + CHECK(tid, FAIL, "H5Tcopy"); + status = H5Tcommit2(file_id, "Committed D64BE type", tid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(status, FAIL, "H5Tcommit2"); + status = H5Tclose(tid); + CHECK(status, FAIL, "H5Tclose"); + + /* Close the file. */ + status = H5Fclose(file_id); + CHECK(status, FAIL, "H5Fclose"); + + file_id = H5Fopen(DATAFILE, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(file_id, FAIL, "H5Fopen"); + + tid = H5Topen2(file_id, "Committed D32LE type", H5P_DEFAULT); + CHECK(tid, FAIL, "H5Topen2"); + + if (!H5Tequal(tid, H5T_UNIX_D32LE)) + TestErrPrintf("H5T_UNIX_D32LE datatype not found\n"); + + status = H5Tclose(tid); + CHECK(status, FAIL, "H5Tclose"); + + tid = H5Topen2(file_id, "Committed D32BE type", H5P_DEFAULT); + CHECK(tid, FAIL, "H5Topen2"); + + if (!H5Tequal(tid, H5T_UNIX_D32BE)) + TestErrPrintf("H5T_UNIX_D32BE datatype not found\n"); + + status = H5Tclose(tid); + CHECK(status, FAIL, "H5Tclose"); + + tid = H5Topen2(file_id, "Committed D64LE type", H5P_DEFAULT); + CHECK(tid, FAIL, "H5Topen2"); + + if (!H5Tequal(tid, H5T_UNIX_D64LE)) + TestErrPrintf("H5T_UNIX_D64LE datatype not found"); + + status = H5Tclose(tid); + CHECK(status, FAIL, "H5Tclose"); + + tid = H5Topen2(file_id, "Committed D64BE type", H5P_DEFAULT); + CHECK(tid, FAIL, "H5Topen2"); + + if (!H5Tequal(tid, H5T_UNIX_D64BE)) + TestErrPrintf("H5T_UNIX_D64BE datatype not found"); + + status = H5Tclose(tid); + CHECK(status, FAIL, "H5Tclose"); + + status = H5Fclose(file_id); + CHECK(status, FAIL, "H5Fclose"); +} + +#ifdef NOT_YET +/**************************************************************** +** +** test_time_io(): Test writing time data to a dataset +** +****************************************************************/ +static void +test_time_io(void) +{ + hid_t fid; /* File identifier */ + hid_t dsid; /* Dataset identifier */ + hid_t tid; /* Datatype identifier */ + hid_t sid; /* Dataspace identifier */ + time_t timenow, timethen; /* Times */ + herr_t status; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Committing Time Datatypes\n")); + + /* Create a new file using default properties. */ + fid = H5Fcreate(DATAFILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create a scalar dataspace */ + sid = H5Screate(H5S_SCALAR); + CHECK(sid, FAIL, "H5Screate"); + + /* Create a dataset with a time datatype */ + dsid = H5Dcreate2(fid, DATASETNAME, H5T_UNIX_D32LE, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dsid, FAIL, "H5Dcreate2"); + + /* Initialize time data value */ + timenow = HDtime(NULL); + + /* Write time to dataset */ + status = H5Dwrite(dsid, H5T_UNIX_D32LE, H5S_ALL, H5S_ALL, H5P_DEFAULT, &timenow); + CHECK(status, FAIL, "H5Dwrite"); + + /* Close objects */ + status = H5Dclose(dsid); + CHECK(status, FAIL, "H5Dclose"); + + status = H5Sclose(sid); + CHECK(status, FAIL, "H5Sclose"); + + status = H5Fclose(fid); + CHECK(status, FAIL, "H5Fclose"); + + /* Open file and dataset, read time back and print it in calendar format */ + fid = H5Fopen(DATAFILE, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + dsid = H5Dopen2(fid, DATASETNAME, H5P_DEFAULT); + CHECK(dsid, FAIL, "H5Dopen2"); + + tid = H5Dget_type(dsid); + CHECK(tid, FAIL, "H5Dget_type"); + if (H5Tget_class(tid) == H5T_TIME) + HDfprintf(stderr, "datatype class is H5T_TIME\n"); + status = H5Tclose(tid); + CHECK(status, FAIL, "H5Tclose"); + + status = H5Dread(dsid, H5T_UNIX_D32LE, H5S_ALL, H5S_ALL, H5P_DEFAULT, &timethen); + CHECK(status, FAIL, "H5Dread"); + HDfprintf(stderr, "time written was: %s\n", HDctime(&timethen)); + + status = H5Dclose(dsid); + CHECK(status, FAIL, "H5Dclose"); + + status = H5Fclose(fid); + CHECK(status, FAIL, "H5Fclose"); +} +#endif /* NOT_YET */ + +/**************************************************************** +** +** test_time(): Main time datatype testing routine. +** +****************************************************************/ +void +test_time(void) +{ + /* Output message about test being performed */ + MESSAGE(5, ("Testing Time Datatypes\n")); + + test_time_commit(); /* Test committing time datatypes to a file */ +#ifdef NOT_YET + test_time_io(); /* Test writing time data to a dataset */ +#endif /* NOT_YET */ + +} /* test_time() */ + +/*------------------------------------------------------------------------- + * Function: cleanup_time + * + * Purpose: Cleanup temporary test files + * + * Return: none + * + * Programmer: Quincey Koziol + * October 19, 2000 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +void +cleanup_time(void) +{ + H5Fdelete(DATAFILE, H5P_DEFAULT); +} diff --git a/test/API/tunicode.c b/test/API/tunicode.c new file mode 100644 index 0000000..fa59456 --- /dev/null +++ b/test/API/tunicode.c @@ -0,0 +1,867 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* Unicode test */ +#include "testhdf5.h" + +#define NUM_CHARS 16 +#define MAX_STRING_LENGTH ((NUM_CHARS * 4) + 1) /* Max length in bytes */ +#define MAX_PATH_LENGTH (MAX_STRING_LENGTH + 20) /* Max length in bytes */ +#define MAX_CODE_POINT 0x200000 +#define FILENAME "unicode.h5" +/* A buffer to hold two copies of the UTF-8 string */ +#define LONG_BUF_SIZE (2 * MAX_STRING_LENGTH + 4) + +#define DSET1_NAME "fl_string_dataset" +#define DSET3_NAME "dataset3" +#define DSET4_NAME "dataset4" +#define VL_DSET1_NAME "vl_dset_1" +#define GROUP1_NAME "group1" +#define GROUP2_NAME "group2" +#define GROUP3_NAME "group3" +#define GROUP4_NAME "group4" + +#define RANK 1 +#define COMP_INT_VAL 7 +#define COMP_FLOAT_VAL (-42.0F) +#define COMP_DOUBLE_VAL 42.0 + +/* Test function prototypes */ +void test_fl_string(hid_t fid, const char *string); +void test_strpad(hid_t fid, const char *string); +void test_vl_string(hid_t fid, const char *string); +void test_objnames(hid_t fid, const char *string); +void test_attrname(hid_t fid, const char *string); +void test_compound(hid_t fid, const char *string); +void test_enum(hid_t fid, const char *string); +void test_opaque(hid_t fid, const char *string); + +/* Utility function prototypes */ +static hid_t mkstr(size_t len, H5T_str_t strpad); +unsigned int write_char(unsigned int c, char *test_string, unsigned int cur_pos); +void dump_string(const char *string); + +/* + * test_fl_string + * Tests that UTF-8 can be used for fixed-length string data. + * Writes the string to a dataset and reads it back again. + */ +void +test_fl_string(hid_t fid, const char *string) +{ + hid_t dtype_id, space_id, dset_id; + hsize_t dims = 1; + char read_buf[MAX_STRING_LENGTH]; + H5T_cset_t cset; + herr_t ret; + + /* Create the datatype, ensure that the character set behaves + * correctly (it should default to ASCII and can be set to UTF8) + */ + dtype_id = H5Tcopy(H5T_C_S1); + CHECK(dtype_id, FAIL, "H5Tcopy"); + ret = H5Tset_size(dtype_id, (size_t)MAX_STRING_LENGTH); + CHECK(ret, FAIL, "H5Tset_size"); + cset = H5Tget_cset(dtype_id); + VERIFY(cset, H5T_CSET_ASCII, "H5Tget_cset"); + ret = H5Tset_cset(dtype_id, H5T_CSET_UTF8); + CHECK(ret, FAIL, "H5Tset_cset"); + cset = H5Tget_cset(dtype_id); + VERIFY(cset, H5T_CSET_UTF8, "H5Tget_cset"); + + /* Create dataspace for a dataset */ + space_id = H5Screate_simple(RANK, &dims, NULL); + CHECK(space_id, FAIL, "H5Screate_simple"); + + /* Create a dataset */ + dset_id = H5Dcreate2(fid, DSET1_NAME, dtype_id, space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dset_id, FAIL, "H5Dcreate2"); + + /* Write UTF-8 string to dataset */ + ret = H5Dwrite(dset_id, dtype_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, string); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Read string back and make sure it is unchanged */ + ret = H5Dread(dset_id, dtype_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, read_buf); + CHECK(ret, FAIL, "H5Dread"); + + VERIFY(HDstrcmp(string, read_buf), 0, "strcmp"); + + /* Close all */ + ret = H5Dclose(dset_id); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Tclose(dtype_id); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Sclose(space_id); + CHECK(ret, FAIL, "H5Sclose"); +} + +/* + * test_strpad + * Tests string padding for a UTF-8 string. + * Converts strings to shorter and then longer strings. + * Borrows heavily from dtypes.c, but is more complicated because + * the string is randomly generated. + */ +void +test_strpad(hid_t H5_ATTR_UNUSED fid, const char *string) +{ + /* buf is used to hold the data that H5Tconvert operates on. */ + char buf[LONG_BUF_SIZE]; + + /* cmpbuf holds the output that H5Tconvert should produce, + * to compare against the actual output. */ + char cmpbuf[LONG_BUF_SIZE]; + + /* new_string is a slightly modified version of the UTF-8 + * string to make the tests run more smoothly. */ + char new_string[MAX_STRING_LENGTH + 2]; + + size_t length; /* Length of new_string in bytes */ + size_t small_len; /* Size of the small datatype */ + size_t big_len; /* Size of the larger datatype */ + hid_t src_type, dst_type; + herr_t ret; + + /* The following tests are simpler if the UTF-8 string contains + * the right number of bytes (even or odd, depending on the test). + * We create a 'new_string' whose length is convenient by prepending + * an 'x' to 'string' when necessary. */ + length = HDstrlen(string); + if (length % 2 != 1) { + HDstrcpy(new_string, "x"); + HDstrcat(new_string, string); + length++; + } + else { + HDstrcpy(new_string, string); + } + + /* Convert a null-terminated string to a shorter and longer null + * terminated string. */ + + /* Create a src_type that holds the UTF-8 string and its final NULL */ + big_len = length + 1; /* +1 byte for final NULL */ + HDassert((2 * big_len) <= sizeof(cmpbuf)); + src_type = mkstr(big_len, H5T_STR_NULLTERM); + CHECK(src_type, FAIL, "mkstr"); + /* Create a dst_type that holds half of the UTF-8 string and a final + * NULL */ + small_len = (length + 1) / 2; + dst_type = mkstr(small_len, H5T_STR_NULLTERM); + CHECK(dst_type, FAIL, "mkstr"); + + /* Fill the buffer with two copies of the UTF-8 string, each with a + * terminating NULL. It will look like "abcdefg\0abcdefg\0". */ + HDstrncpy(buf, new_string, big_len); + HDstrncpy(&buf[big_len], new_string, big_len); + + ret = H5Tconvert(src_type, dst_type, (size_t)2, buf, NULL, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tconvert"); + + /* After conversion, the buffer should look like + * "abc\0abc\0abcdefg\0". Note that this is just what the bytes look + * like; UTF-8 characters may well have been truncated. + * To check that the conversion worked properly, we'll build this + * string manually. */ + HDstrncpy(cmpbuf, new_string, small_len - 1); + cmpbuf[small_len - 1] = '\0'; + HDstrncpy(&cmpbuf[small_len], new_string, small_len - 1); + cmpbuf[2 * small_len - 1] = '\0'; + HDstrcpy(&cmpbuf[2 * small_len], new_string); + + VERIFY(HDmemcmp(buf, cmpbuf, 2 * big_len), 0, "HDmemcmp"); + + /* Now convert from smaller datatype to bigger datatype. This should + * leave our buffer looking like: "abc\0\0\0\0\0abc\0\0\0\0\0" */ + ret = H5Tconvert(dst_type, src_type, (size_t)2, buf, NULL, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tconvert"); + + /* First fill the buffer with NULLs */ + HDmemset(cmpbuf, '\0', (size_t)LONG_BUF_SIZE); + /* Copy in the characters */ + HDstrncpy(cmpbuf, new_string, small_len - 1); + HDstrncpy(&cmpbuf[big_len], new_string, small_len - 1); + + VERIFY(HDmemcmp(buf, cmpbuf, 2 * big_len), 0, "HDmemcmp"); + + ret = H5Tclose(src_type); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Tclose(dst_type); + CHECK(ret, FAIL, "H5Tclose"); + + /* Now test null padding. Null-padded strings do *not* need + * terminating NULLs, so the sizes of the datatypes are slightly + * different and we want a string with an even number of characters. */ + length = HDstrlen(string); + if (length % 2 != 0) { + HDstrcpy(new_string, "x"); + HDstrcat(new_string, string); + length++; + } + else { + HDstrcpy(new_string, string); + } + + /* Create a src_type that holds the UTF-8 string */ + big_len = length; + HDassert((2 * big_len) <= sizeof(cmpbuf)); + src_type = mkstr(big_len, H5T_STR_NULLPAD); + CHECK(src_type, FAIL, "mkstr"); + /* Create a dst_type that holds half of the UTF-8 string */ + small_len = length / 2; + dst_type = mkstr(small_len, H5T_STR_NULLPAD); + CHECK(dst_type, FAIL, "mkstr"); + + /* Fill the buffer with two copies of the UTF-8 string. + * It will look like "abcdefghabcdefgh". */ + HDstrncpy(buf, new_string, big_len); + HDstrncpy(&buf[big_len], new_string, big_len); + + ret = H5Tconvert(src_type, dst_type, (size_t)2, buf, NULL, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tconvert"); + + /* After conversion, the buffer should look like + * "abcdabcdabcdefgh". Note that this is just what the bytes look + * like; UTF-8 characters may well have been truncated. + * To check that the conversion worked properly, we'll build this + * string manually. */ + HDstrncpy(cmpbuf, new_string, small_len); + HDstrncpy(&cmpbuf[small_len], new_string, small_len); + HDstrncpy(&cmpbuf[2 * small_len], new_string, big_len); + + VERIFY(HDmemcmp(buf, cmpbuf, 2 * big_len), 0, "HDmemcmp"); + + /* Now convert from smaller datatype to bigger datatype. This should + * leave our buffer looking like: "abcd\0\0\0\0abcd\0\0\0\0" */ + ret = H5Tconvert(dst_type, src_type, (size_t)2, buf, NULL, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tconvert"); + + /* First fill the buffer with NULLs */ + HDmemset(cmpbuf, '\0', (size_t)LONG_BUF_SIZE); + /* Copy in the characters */ + HDstrncpy(cmpbuf, new_string, small_len); + HDstrncpy(&cmpbuf[big_len], new_string, small_len); + + VERIFY(HDmemcmp(buf, cmpbuf, 2 * big_len), 0, "HDmemcmp"); + + ret = H5Tclose(src_type); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Tclose(dst_type); + CHECK(ret, FAIL, "H5Tclose"); + + /* Test space padding. This is very similar to null-padding; we can + use the same values of length, small_len, and big_len. */ + + src_type = mkstr(big_len, H5T_STR_SPACEPAD); + CHECK(src_type, FAIL, "mkstr"); + dst_type = mkstr(small_len, H5T_STR_SPACEPAD); + CHECK(src_type, FAIL, "mkstr"); + + /* Fill the buffer with two copies of the UTF-8 string. + * It will look like "abcdefghabcdefgh". */ + HDstrcpy(buf, new_string); + HDstrcpy(&buf[big_len], new_string); + + ret = H5Tconvert(src_type, dst_type, (size_t)2, buf, NULL, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tconvert"); + + /* After conversion, the buffer should look like + * "abcdabcdabcdefgh". Note that this is just what the bytes look + * like; UTF-8 characters may have been truncated. + * To check that the conversion worked properly, we'll build this + * string manually. */ + HDstrncpy(cmpbuf, new_string, small_len); + HDstrncpy(&cmpbuf[small_len], new_string, small_len); + HDstrncpy(&cmpbuf[2 * small_len], new_string, big_len); + + VERIFY(HDmemcmp(buf, cmpbuf, 2 * big_len), 0, "HDmemcmp"); + + /* Now convert from smaller datatype to bigger datatype. This should + * leave our buffer looking like: "abcd abcd " */ + ret = H5Tconvert(dst_type, src_type, (size_t)2, buf, NULL, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tconvert"); + + /* First fill the buffer with spaces */ + HDmemset(cmpbuf, ' ', (size_t)LONG_BUF_SIZE); + /* Copy in the characters */ + HDstrncpy(cmpbuf, new_string, small_len); + HDstrncpy(&cmpbuf[big_len], new_string, small_len); + + VERIFY(HDmemcmp(buf, cmpbuf, 2 * big_len), 0, "HDmemcmp"); + + ret = H5Tclose(src_type); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Tclose(dst_type); + CHECK(ret, FAIL, "H5Tclose"); +} + +/* + * test_vl_string + * Tests variable-length string datatype with UTF-8 strings. + */ +void +test_vl_string(hid_t fid, const char *string) +{ + hid_t type_id, space_id, dset_id; + hsize_t dims = 1; + hsize_t size; /* Number of bytes used */ + char *read_buf[1]; + herr_t ret; + + /* Create dataspace for datasets */ + space_id = H5Screate_simple(RANK, &dims, NULL); + CHECK(space_id, FAIL, "H5Screate_simple"); + + /* Create a datatype to refer to */ + type_id = H5Tcopy(H5T_C_S1); + CHECK(type_id, FAIL, "H5Tcopy"); + ret = H5Tset_size(type_id, H5T_VARIABLE); + CHECK(ret, FAIL, "H5Tset_size"); + + /* Create a dataset */ + dset_id = H5Dcreate2(fid, VL_DSET1_NAME, type_id, space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dset_id, FAIL, "H5Dcreate2"); + + /* Write dataset to disk */ + ret = H5Dwrite(dset_id, type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, &string); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Make certain the correct amount of memory will be used */ + ret = H5Dvlen_get_buf_size(dset_id, type_id, space_id, &size); + CHECK(ret, FAIL, "H5Dvlen_get_buf_size"); + VERIFY(size, (hsize_t)HDstrlen(string) + 1, "H5Dvlen_get_buf_size"); + + /* Read dataset from disk */ + ret = H5Dread(dset_id, type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, read_buf); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read in */ + VERIFY(HDstrcmp(string, read_buf[0]), 0, "strcmp"); + + /* Reclaim the read VL data */ + ret = H5Treclaim(type_id, space_id, H5P_DEFAULT, read_buf); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Close all */ + ret = H5Dclose(dset_id); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Tclose(type_id); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Sclose(space_id); + CHECK(ret, FAIL, "H5Sclose"); +} + +/* + * test_objnames + * Tests that UTF-8 can be used for object names in the file. + * Tests groups, datasets, named datatypes, and soft links. + * Note that this test doesn't actually mark the names as being + * in UTF-8. At the time this test was written, that feature + * didn't exist in HDF5, and when the character encoding property + * was added to links it didn't change how they were stored in the file, + * -JML 2/2/2006 + */ +void +test_objnames(hid_t fid, const char *string) +{ + hid_t grp_id, grp1_id, grp2_id, grp3_id; + hid_t type_id, dset_id, space_id; +#if 0 + char read_buf[MAX_STRING_LENGTH]; +#endif + char path_buf[MAX_PATH_LENGTH]; + hsize_t dims = 1; +#if 0 + hobj_ref_t obj_ref; + ssize_t size; +#endif + herr_t ret; + + /* Create a group with a UTF-8 name */ + grp_id = H5Gcreate2(fid, string, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(grp_id, FAIL, "H5Gcreate2"); +#if 0 + /* Set a comment on the group to test that we can access the group + * Also test that UTF-8 comments can be read. + */ + ret = H5Oset_comment_by_name(fid, string, string, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Oset_comment_by_name"); + size = H5Oget_comment_by_name(fid, string, read_buf, (size_t)MAX_STRING_LENGTH, H5P_DEFAULT); + CHECK(size, FAIL, "H5Oget_comment_by_name"); +#endif + ret = H5Gclose(grp_id); + CHECK(ret, FAIL, "H5Gclose"); +#if 0 + VERIFY(HDstrcmp(string, read_buf), 0, "strcmp"); +#endif + /* Create a new dataset with a UTF-8 name */ + grp1_id = H5Gcreate2(fid, GROUP1_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(grp1_id, FAIL, "H5Gcreate2"); + + space_id = H5Screate_simple(RANK, &dims, NULL); + CHECK(space_id, FAIL, "H5Screate_simple"); + dset_id = H5Dcreate2(grp1_id, string, H5T_NATIVE_INT, space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dset_id, FAIL, "H5Dcreate2"); + + /* Make sure that dataset can be opened again */ + ret = H5Dclose(dset_id); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Sclose(space_id); + CHECK(ret, FAIL, "H5Sclose"); + + dset_id = H5Dopen2(grp1_id, string, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Dopen2"); + ret = H5Dclose(dset_id); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Gclose(grp1_id); + CHECK(ret, FAIL, "H5Gclose"); + + /* Do the same for a named datatype */ + grp2_id = H5Gcreate2(fid, GROUP2_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(grp2_id, FAIL, "H5Gcreate2"); + + type_id = H5Tcreate(H5T_OPAQUE, (size_t)1); + CHECK(type_id, FAIL, "H5Tcreate"); + ret = H5Tcommit2(grp2_id, string, type_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(type_id, FAIL, "H5Tcommit2"); + ret = H5Tclose(type_id); + CHECK(type_id, FAIL, "H5Tclose"); + + type_id = H5Topen2(grp2_id, string, H5P_DEFAULT); + CHECK(type_id, FAIL, "H5Topen2"); + ret = H5Tclose(type_id); + CHECK(type_id, FAIL, "H5Tclose"); + + /* Don't close the group -- use it to test that object references + * can refer to objects named in UTF-8 */ +#if 0 + space_id = H5Screate_simple(RANK, &dims, NULL); + CHECK(space_id, FAIL, "H5Screate_simple"); + dset_id = + H5Dcreate2(grp2_id, DSET3_NAME, H5T_STD_REF_OBJ, space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Dcreate2"); + + /* Create reference to named datatype */ + ret = H5Rcreate(&obj_ref, grp2_id, string, H5R_OBJECT, (hid_t)-1); + CHECK(ret, FAIL, "H5Rcreate"); + /* Write selection and read it back*/ + ret = H5Dwrite(dset_id, H5T_STD_REF_OBJ, H5S_ALL, H5S_ALL, H5P_DEFAULT, &obj_ref); + CHECK(ret, FAIL, "H5Dwrite"); + ret = H5Dread(dset_id, H5T_STD_REF_OBJ, H5S_ALL, H5S_ALL, H5P_DEFAULT, &obj_ref); + CHECK(ret, FAIL, "H5Dread"); + + /* Ensure that we can open named datatype using object reference */ + type_id = H5Rdereference2(dset_id, H5P_DEFAULT, H5R_OBJECT, &obj_ref); + CHECK(type_id, FAIL, "H5Rdereference2"); + ret = H5Tcommitted(type_id); + VERIFY(ret, 1, "H5Tcommitted"); + + ret = H5Tclose(type_id); + CHECK(type_id, FAIL, "H5Tclose"); + ret = H5Dclose(dset_id); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Sclose(space_id); + CHECK(ret, FAIL, "H5Sclose"); +#endif + ret = H5Gclose(grp2_id); + CHECK(ret, FAIL, "H5Gclose"); + + /* Create "group3". Build a hard link from group3 to group2, which has + * a datatype with the UTF-8 name. Create a soft link in group3 + * pointing through the hard link to the datatype. Give the soft + * link a name in UTF-8. Ensure that the soft link works. */ + + grp3_id = H5Gcreate2(fid, GROUP3_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(grp3_id, FAIL, "H5Gcreate2"); + + ret = H5Lcreate_hard(fid, GROUP2_NAME, grp3_id, GROUP2_NAME, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lcreate_hard"); + HDstrcpy(path_buf, GROUP2_NAME); + HDstrcat(path_buf, "/"); + HDstrcat(path_buf, string); + ret = H5Lcreate_hard(grp3_id, path_buf, H5L_SAME_LOC, string, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Lcreate_hard"); + + /* Open named datatype using soft link */ + type_id = H5Topen2(grp3_id, string, H5P_DEFAULT); + CHECK(type_id, FAIL, "H5Topen2"); + + ret = H5Tclose(type_id); + CHECK(type_id, FAIL, "H5Tclose"); + ret = H5Gclose(grp3_id); + CHECK(ret, FAIL, "H5Gclose"); +} + +/* + * test_attrname + * Test that attributes can deal with UTF-8 strings + */ +void +test_attrname(hid_t fid, const char *string) +{ + hid_t group_id, attr_id; + hid_t dtype_id, space_id; + hsize_t dims = 1; + char read_buf[MAX_STRING_LENGTH]; + ssize_t size; + herr_t ret; + + /* Create a new group and give it an attribute whose + * name and value are UTF-8 strings. + */ + group_id = H5Gcreate2(fid, GROUP4_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(group_id, FAIL, "H5Gcreate2"); + + space_id = H5Screate_simple(RANK, &dims, NULL); + CHECK(space_id, FAIL, "H5Screate_simple"); + dtype_id = H5Tcopy(H5T_C_S1); + CHECK(dtype_id, FAIL, "H5Tcopy"); + ret = H5Tset_size(dtype_id, (size_t)MAX_STRING_LENGTH); + CHECK(ret, FAIL, "H5Tset_size"); + + /* Create the attribute and check that its name is correct */ + attr_id = H5Acreate2(group_id, string, dtype_id, space_id, H5P_DEFAULT, H5P_DEFAULT); + CHECK(attr_id, FAIL, "H5Acreate2"); + size = H5Aget_name(attr_id, (size_t)MAX_STRING_LENGTH, read_buf); + CHECK(size, FAIL, "H5Aget_name"); + ret = HDstrcmp(read_buf, string); + VERIFY(ret, 0, "strcmp"); + read_buf[0] = '\0'; + + /* Try writing and reading from the attribute */ + ret = H5Awrite(attr_id, dtype_id, string); + CHECK(ret, FAIL, "H5Awrite"); + ret = H5Aread(attr_id, dtype_id, read_buf); + CHECK(ret, FAIL, "H5Aread"); + ret = HDstrcmp(read_buf, string); + VERIFY(ret, 0, "strcmp"); + + /* Clean up */ + ret = H5Aclose(attr_id); + CHECK(ret, FAIL, "H5Aclose"); + ret = H5Tclose(dtype_id); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Sclose(space_id); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Gclose(group_id); + CHECK(ret, FAIL, "H5Gclose"); +} + +/* + * test_compound + * Test that compound datatypes can have UTF-8 field names. + */ +void +test_compound(hid_t fid, const char *string) +{ + /* Define two compound structures, s1_t and s2_t. + * s2_t is a subset of s1_t, with two out of three + * fields. + * This is stolen from the h5_compound example. + */ + typedef struct s1_t { + int a; + double c; + float b; + } s1_t; + typedef struct s2_t { + double c; + int a; + } s2_t; + /* Actual variable declarations */ + s1_t s1; + s2_t s2; + hid_t s1_tid, s2_tid; + hid_t space_id, dset_id; + hsize_t dim = 1; + char *readbuf; + herr_t ret; + + /* Initialize compound data */ + HDmemset(&s1, 0, sizeof(s1_t)); /* To make purify happy */ + s1.a = COMP_INT_VAL; + s1.c = COMP_DOUBLE_VAL; + s1.b = COMP_FLOAT_VAL; + + /* Create compound datatypes using UTF-8 field name */ + s1_tid = H5Tcreate(H5T_COMPOUND, sizeof(s1_t)); + CHECK(s1_tid, FAIL, "H5Tcreate"); + ret = H5Tinsert(s1_tid, string, HOFFSET(s1_t, a), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + /* Check that the field name was stored correctly */ + readbuf = H5Tget_member_name(s1_tid, 0); + ret = HDstrcmp(readbuf, string); + VERIFY(ret, 0, "strcmp"); + H5free_memory(readbuf); + + /* Add the other fields to the datatype */ + ret = H5Tinsert(s1_tid, "c_name", HOFFSET(s1_t, c), H5T_NATIVE_DOUBLE); + CHECK(ret, FAIL, "H5Tinsert"); + ret = H5Tinsert(s1_tid, "b_name", HOFFSET(s1_t, b), H5T_NATIVE_FLOAT); + CHECK(ret, FAIL, "H5Tinsert"); + + /* Create second datatype, with only two fields. */ + s2_tid = H5Tcreate(H5T_COMPOUND, sizeof(s2_t)); + CHECK(s2_tid, FAIL, "H5Tcreate"); + ret = H5Tinsert(s2_tid, "c_name", HOFFSET(s2_t, c), H5T_NATIVE_DOUBLE); + CHECK(ret, FAIL, "H5Tinsert"); + ret = H5Tinsert(s2_tid, string, HOFFSET(s2_t, a), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + + /* Create the dataspace and dataset. */ + space_id = H5Screate_simple(1, &dim, NULL); + CHECK(space_id, FAIL, "H5Screate_simple"); + dset_id = H5Dcreate2(fid, DSET4_NAME, s1_tid, space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dset_id, FAIL, "H5Dcreate2"); + + /* Write data to the dataset. */ + ret = H5Dwrite(dset_id, s1_tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, &s1); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Ensure that data can be read back by field name into s2 struct */ + ret = H5Dread(dset_id, s2_tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, &s2); + CHECK(ret, FAIL, "H5Dread"); + + VERIFY(s2.a, COMP_INT_VAL, "H5Dread"); + VERIFY(s2.c, COMP_DOUBLE_VAL, "H5Dread"); + + /* Clean up */ + ret = H5Tclose(s1_tid); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Tclose(s2_tid); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Sclose(space_id); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Dclose(dset_id); + CHECK(ret, FAIL, "H5Dclose"); +} + +/* + * test_enum + * Test that enumerated datatypes can have UTF-8 member names. + */ +void +test_enum(hid_t H5_ATTR_UNUSED fid, const char *string) +{ + /* Define an enumerated type */ + typedef enum { E1_RED, E1_GREEN, E1_BLUE, E1_WHITE } c_e1; + /* Variable declarations */ + c_e1 val; + herr_t ret; + hid_t type_id; + char readbuf[MAX_STRING_LENGTH]; + + /* Create an enumerated datatype in HDF5 with a UTF-8 member name*/ + type_id = H5Tcreate(H5T_ENUM, sizeof(c_e1)); + CHECK(type_id, FAIL, "H5Tcreate"); + val = E1_RED; + ret = H5Tenum_insert(type_id, "RED", &val); + CHECK(ret, FAIL, "H5Tenum_insert"); + val = E1_GREEN; + ret = H5Tenum_insert(type_id, "GREEN", &val); + CHECK(ret, FAIL, "H5Tenum_insert"); + val = E1_BLUE; + ret = H5Tenum_insert(type_id, "BLUE", &val); + CHECK(ret, FAIL, "H5Tenum_insert"); + val = E1_WHITE; + ret = H5Tenum_insert(type_id, string, &val); + CHECK(ret, FAIL, "H5Tenum_insert"); + + /* Ensure that UTF-8 member name gives the right value and vice versa. */ + ret = H5Tenum_valueof(type_id, string, &val); + CHECK(ret, FAIL, "H5Tenum_valueof"); + VERIFY(val, E1_WHITE, "H5Tenum_valueof"); + ret = H5Tenum_nameof(type_id, &val, readbuf, (size_t)MAX_STRING_LENGTH); + CHECK(ret, FAIL, "H5Tenum_nameof"); + ret = HDstrcmp(readbuf, string); + VERIFY(ret, 0, "strcmp"); + + /* Close the datatype */ + ret = H5Tclose(type_id); + CHECK(ret, FAIL, "H5Tclose"); +} + +/* + * test_opaque + * Test comments on opaque datatypes + */ +void +test_opaque(hid_t H5_ATTR_UNUSED fid, const char *string) +{ + hid_t type_id; + char *read_buf; + herr_t ret; + + /* Create an opaque type and give it a UTF-8 tag */ + type_id = H5Tcreate(H5T_OPAQUE, (size_t)4); + CHECK(type_id, FAIL, "H5Tcreate"); + ret = H5Tset_tag(type_id, string); + CHECK(ret, FAIL, "H5Tset_tag"); + + /* Read the tag back. */ + read_buf = H5Tget_tag(type_id); + ret = HDstrcmp(read_buf, string); + VERIFY(ret, 0, "H5Tget_tag"); + H5free_memory(read_buf); + + ret = H5Tclose(type_id); + CHECK(ret, FAIL, "H5Tclose"); +} + +/*********************/ +/* Utility functions */ +/*********************/ + +/* mkstr + * Borrwed from dtypes.c. + * Creates a new string data type. Used in string padding tests */ +static hid_t +mkstr(size_t len, H5T_str_t strpad) +{ + hid_t t; + if ((t = H5Tcopy(H5T_C_S1)) < 0) + return -1; + if (H5Tset_size(t, len) < 0) + return -1; + if (H5Tset_strpad(t, strpad) < 0) + return -1; + return t; +} + +/* write_char + * Append a unicode code point c to test_string in UTF-8 encoding. + * Return the new end of the string. + */ +unsigned int +write_char(unsigned int c, char *test_string, unsigned int cur_pos) +{ + if (c < 0x80) { + test_string[cur_pos] = (char)c; + cur_pos++; + } + else if (c < 0x800) { + test_string[cur_pos] = (char)(0xC0 | c >> 6); + test_string[cur_pos + 1] = (char)(0x80 | (c & 0x3F)); + cur_pos += 2; + } + else if (c < 0x10000) { + test_string[cur_pos] = (char)(0xE0 | c >> 12); + test_string[cur_pos + 1] = (char)(0x80 | (c >> 6 & 0x3F)); + test_string[cur_pos + 2] = (char)(0x80 | (c & 0x3F)); + cur_pos += 3; + } + else if (c < 0x200000) { + test_string[cur_pos] = (char)(0xF0 | c >> 18); + test_string[cur_pos + 1] = (char)(0x80 | (c >> 12 & 0x3F)); + test_string[cur_pos + 2] = (char)(0x80 | (c >> 6 & 0x3F)); + test_string[cur_pos + 3] = (char)(0x80 | (c & 0x3F)); + cur_pos += 4; + } + + return cur_pos; +} + +/* dump_string + * Print a string both as text (which will look like garbage) and as hex. + * The text display is not guaranteed to be accurate--certain characters + * could confuse printf (e.g., '\n'). */ +void +dump_string(const char *string) +{ + size_t length; + size_t x; + + HDprintf("The string was:\n %s", string); + HDprintf("Or in hex:\n"); + + length = HDstrlen(string); + + for (x = 0; x < length; x++) + HDprintf("%x ", string[x] & (0x000000FF)); + + HDprintf("\n"); +} + +/* Main test. + * Create a string of random Unicode characters, then run each test with + * that string. + */ +void +test_unicode(void) +{ + char test_string[MAX_STRING_LENGTH]; + unsigned int cur_pos = 0; /* Current position in test_string */ + unsigned int unicode_point; /* Unicode code point for a single character */ + hid_t fid; /* ID of file */ + int x; /* Temporary variable */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing UTF-8 Encoding\n")); + + /* Create a random string with length NUM_CHARS */ + HDsrandom((unsigned)HDtime(NULL)); + + HDmemset(test_string, 0, sizeof(test_string)); + for (x = 0; x < NUM_CHARS; x++) { + /* We need to avoid unprintable characters (codes 0-31) and the + * . and / characters, since they aren't allowed in path names. + */ + unicode_point = (unsigned)(HDrandom() % (MAX_CODE_POINT - 32)) + 32; + if (unicode_point != 46 && unicode_point != 47) + cur_pos = write_char(unicode_point, test_string, cur_pos); + } + + /* Avoid unlikely case of the null string */ + if (cur_pos == 0) { + test_string[cur_pos] = 'Q'; + cur_pos++; + } + test_string[cur_pos] = '\0'; + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + test_fl_string(fid, test_string); + test_strpad(fid, "abcdefgh"); + test_strpad(fid, test_string); + test_vl_string(fid, test_string); + test_objnames(fid, test_string); + test_attrname(fid, test_string); + test_compound(fid, test_string); + test_enum(fid, test_string); + test_opaque(fid, test_string); + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* This function could be useful in debugging if certain strings + * create errors. + */ +#ifdef DEBUG + dump_string(test_string); +#endif /* DEBUG */ +} + +/* cleanup_unicode(void) + * Delete the file this test created. + */ +void +cleanup_unicode(void) +{ + H5Fdelete(FILENAME, H5P_DEFAULT); +} diff --git a/test/API/tvlstr.c b/test/API/tvlstr.c new file mode 100644 index 0000000..b05ff66 --- /dev/null +++ b/test/API/tvlstr.c @@ -0,0 +1,1013 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*********************************************************** + * + * Test program: tvlstr + * + * Test the Variable-Length String functionality + * + *************************************************************/ + +#include "testhdf5.h" + +#define DATAFILE "tvlstr.h5" +#define DATAFILE2 "tvlstr2.h5" +#define DATAFILE3 "sel2el.h5" + +#define DATASET "1Darray" + +/* 1-D dataset with fixed dimensions */ +#define SPACE1_RANK 1 +#define SPACE1_DIM1 4 +#define NUMP 4 + +#define VLSTR_TYPE "vl_string_type" + +/* Definitions for the VL re-writing test */ +#define REWRITE_NDATASETS 32 + +/* String for testing attributes */ +static const char *string_att = "This is the string for the attribute"; +static char *string_att_write = NULL; + +void *test_vlstr_alloc_custom(size_t size, void *info); +void test_vlstr_free_custom(void *mem, void *info); + +/**************************************************************** +** +** test_vlstr_alloc_custom(): Test VL datatype custom memory +** allocation routines. This routine just uses malloc to +** allocate the memory and increments the amount of memory +** allocated. +** +****************************************************************/ +void * +test_vlstr_alloc_custom(size_t size, void *info) +{ + void *ret_value = NULL; /* Pointer to return */ + size_t *mem_used = (size_t *)info; /* Get the pointer to the memory used */ + size_t extra; /* Extra space needed */ + + /* + * This weird contortion is required on the DEC Alpha to keep the + * alignment correct - QAK + */ + extra = MAX(sizeof(void *), sizeof(size_t)); + + if ((ret_value = HDmalloc(extra + size)) != NULL) { + *(size_t *)ret_value = size; + *mem_used += size; + } /* end if */ + ret_value = ((unsigned char *)ret_value) + extra; + return (ret_value); +} + +/**************************************************************** +** +** test_vlstr_free_custom(): Test VL datatype custom memory +** allocation routines. This routine just uses free to +** release the memory and decrements the amount of memory +** allocated. +** +****************************************************************/ +void +test_vlstr_free_custom(void *_mem, void *info) +{ + unsigned char *mem; + size_t *mem_used = (size_t *)info; /* Get the pointer to the memory used */ + size_t extra; /* Extra space needed */ + + /* + * This weird contortion is required on the DEC Alpha to keep the + * alignment correct - QAK + */ + extra = MAX(sizeof(void *), sizeof(size_t)); + + if (_mem != NULL) { + mem = ((unsigned char *)_mem) - extra; + *mem_used -= *(size_t *)((void *)mem); + HDfree(mem); + } /* end if */ +} + +/**************************************************************** +** +** test_vlstrings_basic(): Test basic VL string code. +** Tests simple VL string I/O +** +****************************************************************/ +static void +test_vlstrings_basic(void) +{ + /* Information to write */ + const char *wdata[SPACE1_DIM1] = { + "Four score and seven years ago our forefathers brought forth on this continent a new nation,", + "conceived in liberty and dedicated to the proposition that all men are created equal.", + "Now we are engaged in a great civil war,", + "testing whether that nation or any nation so conceived and so dedicated can long endure."}; + + char *rdata[SPACE1_DIM1]; /* Information read in */ + char *wdata2; + hid_t dataspace, dataset2; + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1; /* Dataspace ID */ + hid_t tid1; /* Datatype ID */ + hid_t xfer_pid; /* Dataset transfer property list ID */ + hsize_t dims1[] = {SPACE1_DIM1}; + hsize_t size; /* Number of bytes which will be used */ + unsigned i; /* counting variable */ + size_t str_used; /* String data in memory */ + size_t mem_used = 0; /* Memory used during allocation */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Basic VL String Functionality\n")); + + /* Create file */ + fid1 = H5Fcreate(DATAFILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create a datatype to refer to */ + tid1 = H5Tcopy(H5T_C_S1); + CHECK(tid1, FAIL, "H5Tcopy"); + + ret = H5Tset_size(tid1, H5T_VARIABLE); + CHECK(ret, FAIL, "H5Tset_size"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, "Dataset1", tid1, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write dataset to disk */ + ret = H5Dwrite(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + dataspace = H5Screate(H5S_SCALAR); + + dataset2 = H5Dcreate2(fid1, "Dataset2", tid1, dataspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + wdata2 = (char *)HDcalloc((size_t)65534, sizeof(char)); + HDmemset(wdata2, 'A', (size_t)65533); + + ret = H5Dwrite(dataset2, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, &wdata2); + CHECK(ret, FAIL, "H5Dwrite"); + + H5Sclose(dataspace); + H5Dclose(dataset2); + HDfree(wdata2); + + /* Change to the custom memory allocation routines for reading VL string */ + xfer_pid = H5Pcreate(H5P_DATASET_XFER); + CHECK(xfer_pid, FAIL, "H5Pcreate"); + + ret = H5Pset_vlen_mem_manager(xfer_pid, test_vlstr_alloc_custom, &mem_used, test_vlstr_free_custom, + &mem_used); + CHECK(ret, FAIL, "H5Pset_vlen_mem_manager"); + + /* Make certain the correct amount of memory will be used */ + ret = H5Dvlen_get_buf_size(dataset, tid1, sid1, &size); + CHECK(ret, FAIL, "H5Dvlen_get_buf_size"); + + /* Count the actual number of bytes used by the strings */ + for (i = 0, str_used = 0; i < SPACE1_DIM1; i++) + str_used += HDstrlen(wdata[i]) + 1; + + /* Compare against the strings actually written */ + VERIFY(size, (hsize_t)str_used, "H5Dvlen_get_buf_size"); + + /* Read dataset from disk */ + ret = H5Dread(dataset, tid1, H5S_ALL, H5S_ALL, xfer_pid, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Make certain the correct amount of memory has been used */ + VERIFY(mem_used, str_used, "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < SPACE1_DIM1; i++) { + if (HDstrlen(wdata[i]) != HDstrlen(rdata[i])) { + TestErrPrintf("VL data length don't match!, strlen(wdata[%d])=%d, strlen(rdata[%d])=%d\n", (int)i, + (int)HDstrlen(wdata[i]), (int)i, (int)HDstrlen(rdata[i])); + continue; + } /* end if */ + if (HDstrcmp(wdata[i], rdata[i]) != 0) { + TestErrPrintf("VL data values don't match!, wdata[%d]=%s, rdata[%d]=%s\n", (int)i, wdata[i], + (int)i, rdata[i]); + continue; + } /* end if */ + } /* end for */ + + /* Reclaim the read VL data */ + ret = H5Treclaim(tid1, sid1, xfer_pid, rdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Make certain the VL memory has been freed */ + VERIFY(mem_used, 0, "H5Treclaim"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close dataset transfer property list */ + ret = H5Pclose(xfer_pid); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + +} /* end test_vlstrings_basic() */ + +/**************************************************************** +** +** test_vlstrings_special(): Test VL string code for special +** string cases, nil and zero-sized. +** +****************************************************************/ +static void +test_vlstrings_special(void) +{ + const char *wdata[SPACE1_DIM1] = {"", "two", "three", "\0"}; + const char *wdata2[SPACE1_DIM1] = {NULL, NULL, NULL, NULL}; + char *rdata[SPACE1_DIM1]; /* Information read in */ + char *fill; /* Fill value */ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1; /* Dataspace ID */ + hid_t tid1; /* Datatype ID */ + hid_t dcpl; /* Dataset creation property list ID */ + hsize_t dims1[] = {SPACE1_DIM1}; + unsigned i; /* counting variable */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Special VL Strings\n")); + + /* Create file */ + fid1 = H5Fcreate(DATAFILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create a datatype to refer to */ + tid1 = H5Tcopy(H5T_C_S1); + CHECK(tid1, FAIL, "H5Tcopy"); + + ret = H5Tset_size(tid1, H5T_VARIABLE); + CHECK(ret, FAIL, "H5Tset_size"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, "Dataset3", tid1, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Read from dataset before writing data */ + ret = H5Dread(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Check data read in */ + for (i = 0; i < SPACE1_DIM1; i++) + if (rdata[i] != NULL) + TestErrPrintf("VL doesn't match!, rdata[%d]=%s\n", (int)i, rdata[i]); + + /* Write dataset to disk */ + ret = H5Dwrite(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Read dataset from disk */ + ret = H5Dread(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < SPACE1_DIM1; i++) { + if (HDstrlen(wdata[i]) != HDstrlen(rdata[i])) { + TestErrPrintf("VL data length don't match!, strlen(wdata[%d])=%d, strlen(rdata[%d])=%d\n", (int)i, + (int)HDstrlen(wdata[i]), (int)i, (int)HDstrlen(rdata[i])); + continue; + } /* end if */ + if ((wdata[i] == NULL && rdata[i] != NULL) || (rdata[i] == NULL && wdata[i] != NULL)) { + TestErrPrintf("VL data values don't match!\n"); + continue; + } /* end if */ + if (HDstrcmp(wdata[i], rdata[i]) != 0) { + TestErrPrintf("VL data values don't match!, wdata[%d]=%s, rdata[%d]=%s\n", (int)i, wdata[i], + (int)i, rdata[i]); + continue; + } /* end if */ + } /* end for */ + + /* Reclaim the read VL data */ + ret = H5Treclaim(tid1, sid1, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Create another dataset to test nil strings */ + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + + /* Set the fill value for the second dataset */ + fill = NULL; + ret = H5Pset_fill_value(dcpl, tid1, &fill); + CHECK(ret, FAIL, "H5Pset_fill_value"); + + dataset = H5Dcreate2(fid1, "Dataset4", tid1, sid1, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Close dataset creation property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Read from dataset before writing data */ + ret = H5Dread(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Check data read in */ + for (i = 0; i < SPACE1_DIM1; i++) + if (rdata[i] != NULL) + TestErrPrintf("VL doesn't match!, rdata[%d]=%s\n", (int)i, rdata[i]); + + /* Try to write nil strings to disk. */ + ret = H5Dwrite(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata2); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Read nil strings back from disk */ + ret = H5Dread(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Check data read in */ + for (i = 0; i < SPACE1_DIM1; i++) + if (rdata[i] != NULL) + TestErrPrintf("VL doesn't match!, rdata[%d]=%s\n", (int)i, rdata[i]); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); +} + +/**************************************************************** +** +** test_vlstring_type(): Test VL string type. +** Tests if VL string is treated as string. +** +****************************************************************/ +static void +test_vlstring_type(void) +{ + hid_t fid; /* HDF5 File IDs */ + hid_t tid_vlstr; + H5T_cset_t cset; + H5T_str_t pad; + htri_t vl_str; /* Whether string is VL */ + herr_t ret; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing VL String type\n")); + + /* Open file */ + fid = H5Fopen(DATAFILE, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* Create a datatype to refer to */ + tid_vlstr = H5Tcopy(H5T_C_S1); + CHECK(tid_vlstr, FAIL, "H5Tcopy"); + + /* Change padding and verify it */ + ret = H5Tset_strpad(tid_vlstr, H5T_STR_NULLPAD); + CHECK(ret, FAIL, "H5Tset_strpad"); + pad = H5Tget_strpad(tid_vlstr); + VERIFY(pad, H5T_STR_NULLPAD, "H5Tget_strpad"); + + /* Convert to variable-length string */ + ret = H5Tset_size(tid_vlstr, H5T_VARIABLE); + CHECK(ret, FAIL, "H5Tset_size"); + + /* Check if datatype is VL string */ + ret = H5Tget_class(tid_vlstr); + VERIFY(ret, H5T_STRING, "H5Tget_class"); + ret = H5Tis_variable_str(tid_vlstr); + VERIFY(ret, TRUE, "H5Tis_variable_str"); + + /* Verify that the class detects as a string */ + vl_str = H5Tdetect_class(tid_vlstr, H5T_STRING); + CHECK(vl_str, FAIL, "H5Tdetect_class"); + VERIFY(vl_str, TRUE, "H5Tdetect_class"); + + /* Check default character set and padding */ + cset = H5Tget_cset(tid_vlstr); + VERIFY(cset, H5T_CSET_ASCII, "H5Tget_cset"); + pad = H5Tget_strpad(tid_vlstr); + VERIFY(pad, H5T_STR_NULLPAD, "H5Tget_strpad"); + + /* Commit variable-length string datatype to storage */ + ret = H5Tcommit2(fid, VLSTR_TYPE, tid_vlstr, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Tcommit2"); + + /* Close datatype */ + ret = H5Tclose(tid_vlstr); + CHECK(ret, FAIL, "H5Tclose"); + + tid_vlstr = H5Topen2(fid, VLSTR_TYPE, H5P_DEFAULT); + CHECK(tid_vlstr, FAIL, "H5Topen2"); + + ret = H5Tclose(tid_vlstr); + CHECK(ret, FAIL, "H5Tclose"); + + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + + fid = H5Fopen(DATAFILE, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + + /* Open the variable-length string datatype just created */ + tid_vlstr = H5Topen2(fid, VLSTR_TYPE, H5P_DEFAULT); + CHECK(tid_vlstr, FAIL, "H5Topen2"); + + /* Verify character set and padding */ + cset = H5Tget_cset(tid_vlstr); + VERIFY(cset, H5T_CSET_ASCII, "H5Tget_cset"); + pad = H5Tget_strpad(tid_vlstr); + VERIFY(pad, H5T_STR_NULLPAD, "H5Tget_strpad"); + + /* Close datatype and file */ + ret = H5Tclose(tid_vlstr); + CHECK(ret, FAIL, "H5Tclose"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + +} /* end test_vlstring_type() */ + +/**************************************************************** +** +** test_compact_vlstring(): Test code for storing VL strings in +** compact datasets. +** +****************************************************************/ +static void +test_compact_vlstring(void) +{ + const char *wdata[SPACE1_DIM1] = {"one", "two", "three", "four"}; + char *rdata[SPACE1_DIM1]; /* Information read in */ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1; /* Dataspace ID */ + hid_t tid1; /* Datatype ID */ + hid_t plist; /* Dataset creation property list */ + hsize_t dims1[] = {SPACE1_DIM1}; + unsigned i; /* counting variable */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing VL Strings in compact dataset\n")); + + /* Create file */ + fid1 = H5Fcreate(DATAFILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create a datatype to refer to */ + tid1 = H5Tcopy(H5T_C_S1); + CHECK(tid1, FAIL, "H5Tcopy"); + + ret = H5Tset_size(tid1, H5T_VARIABLE); + CHECK(ret, FAIL, "H5Tset_size"); + + plist = H5Pcreate(H5P_DATASET_CREATE); + CHECK(plist, FAIL, "H5Pcreate"); + + ret = H5Pset_layout(plist, H5D_COMPACT); + CHECK(ret, FAIL, "H5Pset_layout"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, "Dataset5", tid1, sid1, H5P_DEFAULT, plist, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write dataset to disk */ + ret = H5Dwrite(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Read dataset from disk */ + ret = H5Dread(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < SPACE1_DIM1; i++) { + if (HDstrlen(wdata[i]) != HDstrlen(rdata[i])) { + TestErrPrintf("VL data length don't match!, strlen(wdata[%d])=%d, strlen(rdata[%d])=%d\n", (int)i, + (int)HDstrlen(wdata[i]), (int)i, (int)HDstrlen(rdata[i])); + continue; + } /* end if */ + if (HDstrcmp(wdata[i], rdata[i]) != 0) { + TestErrPrintf("VL data values don't match!, wdata[%d]=%s, rdata[%d]=%s\n", (int)i, wdata[i], + (int)i, rdata[i]); + continue; + } /* end if */ + } /* end for */ + + /* Reclaim the read VL data */ + ret = H5Treclaim(tid1, sid1, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close dataset create property list */ + ret = H5Pclose(plist); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); +} /*test_compact_vlstrings*/ + +/**************************************************************** +** +** test_write_vl_string_attribute(): Test basic VL string code. +** Tests writing VL strings as attributes +** +****************************************************************/ +static void +test_write_vl_string_attribute(void) +{ + hid_t file, root, dataspace, att; + hid_t type; + herr_t ret; + char *string_att_check = NULL; + + /* Open the file */ + file = H5Fopen(DATAFILE, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(file, FAIL, "H5Fopen"); + + /* Create a datatype to refer to. */ + type = H5Tcopy(H5T_C_S1); + CHECK(type, FAIL, "H5Tcopy"); + + ret = H5Tset_size(type, H5T_VARIABLE); + CHECK(ret, FAIL, "H5Tset_size"); + + root = H5Gopen2(file, "/", H5P_DEFAULT); + CHECK(root, FAIL, "H5Gopen2"); + + dataspace = H5Screate(H5S_SCALAR); + CHECK(dataspace, FAIL, "H5Screate"); + + /* Test creating a "normal" sized string attribute */ + att = H5Acreate2(root, "test_scalar", type, dataspace, H5P_DEFAULT, H5P_DEFAULT); + CHECK(att, FAIL, "H5Acreate2"); + + ret = H5Awrite(att, type, &string_att); + CHECK(ret, FAIL, "H5Awrite"); + + ret = H5Aread(att, type, &string_att_check); + CHECK(ret, FAIL, "H5Aread"); + + if (HDstrcmp(string_att_check, string_att) != 0) + TestErrPrintf("VL string attributes don't match!, string_att=%s, string_att_check=%s\n", string_att, + string_att_check); + + H5free_memory(string_att_check); + string_att_check = NULL; + + ret = H5Aclose(att); + CHECK(ret, FAIL, "HAclose"); + + /* Test creating a "large" sized string attribute */ + att = H5Acreate2(root, "test_scalar_large", type, dataspace, H5P_DEFAULT, H5P_DEFAULT); + CHECK(att, FAIL, "H5Acreate2"); + + string_att_write = (char *)HDcalloc((size_t)8192, sizeof(char)); + HDmemset(string_att_write, 'A', (size_t)8191); + + ret = H5Awrite(att, type, &string_att_write); + CHECK(ret, FAIL, "H5Awrite"); + + ret = H5Aread(att, type, &string_att_check); + CHECK(ret, FAIL, "H5Aread"); + + if (HDstrcmp(string_att_check, string_att_write) != 0) + TestErrPrintf("VL string attributes don't match!, string_att_write=%s, string_att_check=%s\n", + string_att_write, string_att_check); + + H5free_memory(string_att_check); + string_att_check = NULL; + + /* The attribute string written is freed below, in the test_read_vl_string_attribute() test */ + /* HDfree(string_att_write); */ + + ret = H5Aclose(att); + CHECK(ret, FAIL, "HAclose"); + + ret = H5Gclose(root); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Tclose(type); + CHECK(ret, FAIL, "H5Tclose"); + + ret = H5Sclose(dataspace); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); +} + +/**************************************************************** +** +** test_read_vl_string_attribute(): Test basic VL string code. +** Tests reading VL strings from attributes +** +****************************************************************/ +static void +test_read_vl_string_attribute(void) +{ + hid_t file, root, att; + hid_t type; + herr_t ret; + char *string_att_check = NULL; + + /* Open file */ + file = H5Fopen(DATAFILE, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(file, FAIL, "H5Fopen"); + + /* Create a datatype to refer to. */ + type = H5Tcopy(H5T_C_S1); + CHECK(type, FAIL, "H5Tcopy"); + + ret = H5Tset_size(type, H5T_VARIABLE); + CHECK(ret, FAIL, "H5Tset_size"); + + root = H5Gopen2(file, "/", H5P_DEFAULT); + CHECK(root, FAIL, "H5Gopen2"); + + /* Test reading "normal" sized string attribute */ + att = H5Aopen(root, "test_scalar", H5P_DEFAULT); + CHECK(att, FAIL, "H5Aopen"); + + ret = H5Aread(att, type, &string_att_check); + CHECK(ret, FAIL, "H5Aread"); + + if (HDstrcmp(string_att_check, string_att) != 0) + TestErrPrintf("VL string attributes don't match!, string_att=%s, string_att_check=%s\n", string_att, + string_att_check); + + H5free_memory(string_att_check); + string_att_check = NULL; + + ret = H5Aclose(att); + CHECK(ret, FAIL, "HAclose"); + + /* Test reading "large" sized string attribute */ + att = H5Aopen(root, "test_scalar_large", H5P_DEFAULT); + CHECK(att, FAIL, "H5Aopen"); + + if (string_att_write) { + ret = H5Aread(att, type, &string_att_check); + CHECK(ret, FAIL, "H5Aread"); + + if (HDstrcmp(string_att_check, string_att_write) != 0) + TestErrPrintf("VL string attributes don't match!, string_att_write=%s, string_att_check=%s\n", + string_att_write, string_att_check); + + H5free_memory(string_att_check); + string_att_check = NULL; + } + + /* Free string allocated in test_write_vl_string_attribute */ + if (string_att_write) + HDfree(string_att_write); + + ret = H5Aclose(att); + CHECK(ret, FAIL, "HAclose"); + + ret = H5Tclose(type); + CHECK(ret, FAIL, "H5Tclose"); + + ret = H5Gclose(root); + CHECK(ret, FAIL, "H5Gclose"); + + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); +} + +/* Helper routine for test_vl_rewrite() */ +static void +write_scalar_dset(hid_t file, hid_t type, hid_t space, char *name, char *data) +{ + hid_t dset; + herr_t ret; + + dset = H5Dcreate2(file, name, type, space, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dset, FAIL, "H5Dcreate2"); + + ret = H5Dwrite(dset, type, space, space, H5P_DEFAULT, &data); + CHECK(ret, FAIL, "H5Dwrite"); + + ret = H5Dclose(dset); + CHECK(ret, FAIL, "H5Dclose"); +} + +/* Helper routine for test_vl_rewrite() */ +static void +read_scalar_dset(hid_t file, hid_t type, hid_t space, char *name, char *data) +{ + hid_t dset; + herr_t ret; + char *data_read; + + dset = H5Dopen2(file, name, H5P_DEFAULT); + CHECK(dset, FAIL, "H5Dopen2"); + + ret = H5Dread(dset, type, space, space, H5P_DEFAULT, &data_read); + CHECK(ret, FAIL, "H5Dread"); + + ret = H5Dclose(dset); + CHECK(ret, FAIL, "H5Dclose"); + + if (HDstrcmp(data, data_read) != 0) + TestErrPrintf("Expected %s for dataset %s but read %s\n", data, name, data_read); + + ret = H5Treclaim(type, space, H5P_DEFAULT, &data_read); + CHECK(ret, FAIL, "H5Treclaim"); +} + +/**************************************************************** +** +** test_vl_rewrite(): Test basic VL string code. +** Tests I/O on VL strings when lots of objects in the file +** have been linked/unlinked. +** +****************************************************************/ +static void +test_vl_rewrite(void) +{ + hid_t file1, file2; /* File IDs */ + hid_t type; /* VL string datatype ID */ + hid_t space; /* Scalar dataspace */ + char name[256]; /* Buffer for names & data */ + int i; /* Local index variable */ + herr_t ret; /* Generic return value */ + + /* Create the VL string datatype */ + type = H5Tcopy(H5T_C_S1); + CHECK(type, FAIL, "H5Tcopy"); + + ret = H5Tset_size(type, H5T_VARIABLE); + CHECK(ret, FAIL, "H5Tset_size"); + + /* Create the scalar dataspace */ + space = H5Screate(H5S_SCALAR); + CHECK(space, FAIL, "H5Screate"); + + /* Open the files */ + file1 = H5Fcreate(DATAFILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file1, FAIL, "H5Fcreate"); + + file2 = H5Fcreate(DATAFILE2, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file1, FAIL, "H5Fcreate"); + + /* Create in file 1 */ + for (i = 0; i < REWRITE_NDATASETS; i++) { + HDsnprintf(name, sizeof(name), "/set_%d", i); + write_scalar_dset(file1, type, space, name, name); + } + + /* Effectively copy data from file 1 to 2 */ + for (i = 0; i < REWRITE_NDATASETS; i++) { + HDsnprintf(name, sizeof(name), "/set_%d", i); + read_scalar_dset(file1, type, space, name, name); + write_scalar_dset(file2, type, space, name, name); + } + + /* Read back from file 2 */ + for (i = 0; i < REWRITE_NDATASETS; i++) { + HDsnprintf(name, sizeof(name), "/set_%d", i); + read_scalar_dset(file2, type, space, name, name); + } /* end for */ + + /* Remove from file 2. */ + for (i = 0; i < REWRITE_NDATASETS; i++) { + HDsnprintf(name, sizeof(name), "/set_%d", i); + ret = H5Ldelete(file2, name, H5P_DEFAULT); + CHECK(ret, FAIL, "H5Ldelete"); + } /* end for */ + + /* Effectively copy from file 1 to file 2 */ + for (i = 0; i < REWRITE_NDATASETS; i++) { + HDsnprintf(name, sizeof(name), "/set_%d", i); + read_scalar_dset(file1, type, space, name, name); + write_scalar_dset(file2, type, space, name, name); + } /* end for */ + + /* Close everything */ + ret = H5Tclose(type); + CHECK(ret, FAIL, "H5Tclose"); + + ret = H5Sclose(space); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Fclose(file1); + CHECK(ret, FAIL, "H5Fclose"); + + ret = H5Fclose(file2); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_vl_rewrite() */ + +/**************************************************************** + ** + ** test_write_same_element(): + ** Tests writing to the same element of VL string using + ** H5Sselect_element. + ** + ****************************************************************/ +static void +test_write_same_element(void) +{ +#ifndef NO_WRITE_SAME_ELEMENT_TWICE + hid_t file1, dataset1; + hid_t mspace, fspace, dtype; + hsize_t fdim[] = {SPACE1_DIM1}; + const char *wdata[SPACE1_DIM1] = {"Parting", "is such a", "sweet", "sorrow."}; + const char *val[SPACE1_DIM1] = {"But", "reuniting", "is a", "great joy"}; + hsize_t marray[] = {NUMP}; + hsize_t coord[SPACE1_RANK][NUMP]; + herr_t ret; +#endif + + MESSAGE( + 5, + ("Testing writing to same element of VL string dataset twice - SKIPPED for now due to no support\n")); +#ifndef NO_WRITE_SAME_ELEMENT_TWICE + file1 = H5Fcreate(DATAFILE3, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file1, FAIL, "H5Fcreate"); + + dtype = H5Tcopy(H5T_C_S1); + CHECK(dtype, FAIL, "H5Tcopy"); + + ret = H5Tset_size(dtype, H5T_VARIABLE); + CHECK(ret, FAIL, "H5Tset_size"); + + fspace = H5Screate_simple(SPACE1_RANK, fdim, NULL); + CHECK(fspace, FAIL, "H5Screate_simple"); + + dataset1 = H5Dcreate2(file1, DATASET, dtype, fspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset1, FAIL, "H5Dcreate"); + + ret = H5Dwrite(dataset1, dtype, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + ret = H5Dclose(dataset1); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Tclose(dtype); + CHECK(ret, FAIL, "H5Tclose"); + + ret = H5Sclose(fspace); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Fclose(file1); + CHECK(ret, FAIL, "H5Fclose"); + + /* + * Open the file. Select the same points, write values to those point locations. + */ + file1 = H5Fopen(DATAFILE3, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(file1, FAIL, "H5Fopen"); + + dataset1 = H5Dopen2(file1, DATASET, H5P_DEFAULT); + CHECK(dataset1, FAIL, "H5Dopen"); + + fspace = H5Dget_space(dataset1); + CHECK(fspace, FAIL, "H5Dget_space"); + + dtype = H5Dget_type(dataset1); + CHECK(dtype, FAIL, "H5Dget_type"); + + mspace = H5Screate_simple(1, marray, NULL); + CHECK(mspace, FAIL, "H5Screate_simple"); + + coord[0][0] = 0; + coord[0][1] = 2; + coord[0][2] = 2; + coord[0][3] = 0; + + ret = H5Sselect_elements(fspace, H5S_SELECT_SET, NUMP, (const hsize_t *)&coord); + CHECK(ret, FAIL, "H5Sselect_elements"); + + ret = H5Dwrite(dataset1, dtype, mspace, fspace, H5P_DEFAULT, val); + CHECK(ret, FAIL, "H5Dwrite"); + + ret = H5Tclose(dtype); + CHECK(ret, FAIL, "H5Tclose"); + + ret = H5Dclose(dataset1); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Sclose(fspace); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Sclose(mspace); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Fclose(file1); + CHECK(ret, FAIL, "H5Fclose"); +#endif +} /* test_write_same_element */ + +/**************************************************************** +** +** test_vlstrings(): Main VL string testing routine. +** +****************************************************************/ +void +test_vlstrings(void) +{ + /* Output message about test being performed */ + MESSAGE(5, ("Testing Variable-Length Strings\n")); + + /* These tests use the same file */ + /* Test basic VL string datatype */ + test_vlstrings_basic(); + test_vlstrings_special(); + test_vlstring_type(); + test_compact_vlstring(); + + /* Test using VL strings in attributes */ + test_write_vl_string_attribute(); + test_read_vl_string_attribute(); + + /* Test writing VL datasets in files with lots of unlinking */ + test_vl_rewrite(); + /* Test writing to the same element more than once using H5Sselect_elements */ + test_write_same_element(); +} /* test_vlstrings() */ + +/*------------------------------------------------------------------------- + * Function: cleanup_vlstrings + * + * Purpose: Cleanup temporary test files + * + * Return: none + * + * Programmer: Quincey Koziol + * September 10, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +void +cleanup_vlstrings(void) +{ + H5Fdelete(DATAFILE, H5P_DEFAULT); + H5Fdelete(DATAFILE2, H5P_DEFAULT); + H5Fdelete(DATAFILE3, H5P_DEFAULT); +} diff --git a/test/API/tvltypes.c b/test/API/tvltypes.c new file mode 100644 index 0000000..eca534b --- /dev/null +++ b/test/API/tvltypes.c @@ -0,0 +1,3268 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*********************************************************** + * + * Test program: tvltypes + * + * Test the Variable-Length Datatype functionality + * + *************************************************************/ + +#include "testhdf5.h" + +/* #include "H5Dprivate.h" */ + +#define FILENAME "tvltypes.h5" + +/* 1-D dataset with fixed dimensions */ +#define SPACE1_RANK 1 +#define SPACE1_DIM1 4 + +/* 1-D dataset with fixed dimensions */ +#define SPACE3_RANK 1 +#define SPACE3_DIM1 128 +#define L1_INCM 16 +#define L2_INCM 8 +#define L3_INCM 3 + +/* Default temporary buffer size - Pulled from H5Dprivate.h */ +#define H5D_TEMP_BUF_SIZE (1024 * 1024) + +/* 1-D dataset with fixed dimensions */ +#define SPACE4_RANK 1 +#define SPACE4_DIM_SMALL 128 +#define SPACE4_DIM_LARGE (H5D_TEMP_BUF_SIZE / 64) + +void *test_vltypes_alloc_custom(size_t size, void *info); +void test_vltypes_free_custom(void *mem, void *info); + +/**************************************************************** +** +** test_vltypes_alloc_custom(): Test VL datatype custom memory +** allocation routines. This routine just uses malloc to +** allocate the memory and increments the amount of memory +** allocated. +** +****************************************************************/ +void * +test_vltypes_alloc_custom(size_t size, void *mem_used) +{ + void *ret_value; /* Pointer to return */ + const size_t extra = MAX(sizeof(void *), sizeof(size_t)); /* Extra space needed */ + /* (This weird contortion is required on the + * DEC Alpha to keep the alignment correct - QAK) + */ + + if ((ret_value = HDmalloc(extra + size)) != NULL) { + *(size_t *)ret_value = size; + *(size_t *)mem_used += size; + } /* end if */ + + ret_value = ((unsigned char *)ret_value) + extra; + + return (ret_value); +} + +/**************************************************************** +** +** test_vltypes_free_custom(): Test VL datatype custom memory +** allocation routines. This routine just uses free to +** release the memory and decrements the amount of memory +** allocated. +** +****************************************************************/ +void +test_vltypes_free_custom(void *_mem, void *mem_used) +{ + if (_mem) { + const size_t extra = MAX(sizeof(void *), sizeof(size_t)); /* Extra space needed */ + /* (This weird contortion is required + * on the DEC Alpha to keep the + * alignment correct - QAK) + */ + unsigned char *mem = ((unsigned char *)_mem) - extra; /* Pointer to actual block allocated */ + + *(size_t *)mem_used -= *(size_t *)((void *)mem); + HDfree(mem); + } /* end if */ +} + +/**************************************************************** +** +** test_vltypes_data_create(): Dataset of VL is supposed to +** fail when fill value is never written to dataset. +** +****************************************************************/ +static void +test_vltypes_dataset_create(void) +{ + hid_t fid1; /* HDF5 File IDs */ + hid_t dcpl; /* Dataset Property list */ + hid_t dataset; /* Dataset ID */ + hsize_t dims1[] = {SPACE1_DIM1}; + hid_t sid1; /* Dataspace ID */ + hid_t tid1; /* Datatype ID */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Dataset of VL Datatype Functionality\n")); + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create a datatype to refer to */ + tid1 = H5Tvlen_create(H5T_NATIVE_UINT); + CHECK(tid1, FAIL, "H5Tvlen_create"); + + /* Create dataset property list */ + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + + /* Set fill value writing time to be NEVER */ + ret = H5Pset_fill_time(dcpl, H5D_FILL_TIME_NEVER); + CHECK(ret, FAIL, "H5Pset_fill_time"); + + /* Create a dataset, supposed to fail */ + H5E_BEGIN_TRY + { + dataset = H5Dcreate2(fid1, "Dataset1", tid1, sid1, H5P_DEFAULT, dcpl, H5P_DEFAULT); + } + H5E_END_TRY; + VERIFY(dataset, FAIL, "H5Dcreate2"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close dataset transfer property list */ + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); +} + +/**************************************************************** +** +** test_vltypes_funcs(): Test some type functions that are and +** aren't supposed to work with VL type. +** +****************************************************************/ +static void +test_vltypes_funcs(void) +{ + hid_t type; /* Datatype ID */ + size_t size; + H5T_pad_t inpad; + H5T_norm_t norm; + H5T_cset_t cset; + H5T_str_t strpad; + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing some type functions for VL\n")); + + /* Create a datatype to refer to */ + type = H5Tvlen_create(H5T_IEEE_F32BE); + CHECK(type, FAIL, "H5Tvlen_create"); + + size = H5Tget_precision(type); + CHECK(size, 0, "H5Tget_precision"); + + size = H5Tget_size(type); + CHECK(size, 0, "H5Tget_size"); + + size = H5Tget_ebias(type); + CHECK(size, 0, "H5Tget_ebias"); + + ret = H5Tset_pad(type, H5T_PAD_ZERO, H5T_PAD_ONE); + CHECK(ret, FAIL, "H5Tset_pad"); + + inpad = H5Tget_inpad(type); + CHECK(inpad, FAIL, "H5Tget_inpad"); + + norm = H5Tget_norm(type); + CHECK(norm, FAIL, "H5Tget_norm"); + + ret = H5Tset_offset(type, (size_t)16); + CHECK(ret, FAIL, "H5Tset_offset"); + + H5E_BEGIN_TRY + { + cset = H5Tget_cset(type); + } + H5E_END_TRY; + VERIFY(cset, FAIL, "H5Tget_cset"); + + H5E_BEGIN_TRY + { + strpad = H5Tget_strpad(type); + } + H5E_END_TRY; + VERIFY(strpad, FAIL, "H5Tget_strpad"); + + /* Close datatype */ + ret = H5Tclose(type); + CHECK(ret, FAIL, "H5Tclose"); +} + +/**************************************************************** +** +** test_vltypes_vlen_atomic(): Test basic VL datatype code. +** Tests VL datatypes of atomic datatypes +** +****************************************************************/ +static void +test_vltypes_vlen_atomic(void) +{ + hvl_t wdata[SPACE1_DIM1]; /* Information to write */ + hvl_t wdata2[SPACE1_DIM1]; /* Information to write */ + hvl_t rdata[SPACE1_DIM1]; /* Information read in */ + hvl_t fill; /* Fill value */ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1; /* Dataspace ID */ + hid_t sid2; /* ID of bad dataspace (no extent set) */ + hid_t tid1; /* Datatype ID */ + hid_t dcpl_pid; /* Dataset creation property list ID */ + hid_t xfer_pid; /* Dataset transfer property list ID */ + hsize_t dims1[] = {SPACE1_DIM1}; + hsize_t size; /* Number of bytes which will be used */ + unsigned i, j; /* counting variables */ + size_t mem_used = 0; /* Memory used during allocation */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Basic Atomic VL Datatype Functionality\n")); + + /* Allocate and initialize VL data to write */ + for (i = 0; i < SPACE1_DIM1; i++) { + wdata[i].p = HDmalloc((i + 1) * sizeof(unsigned int)); + wdata[i].len = i + 1; + for (j = 0; j < (i + 1); j++) + ((unsigned int *)wdata[i].p)[j] = i * 10 + j; + + wdata2[i].p = NULL; + wdata2[i].len = 0; + } /* end for */ + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create a datatype to refer to */ + tid1 = H5Tvlen_create(H5T_NATIVE_UINT); + CHECK(tid1, FAIL, "H5Tvlen_create"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, "Dataset1", tid1, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Read from dataset before writing data */ + ret = H5Dread(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Check data read in */ + for (i = 0; i < SPACE1_DIM1; i++) + if (rdata[i].len != 0 || rdata[i].p != NULL) + TestErrPrintf("VL doesn't match!, rdata[%d].len=%u, rdata[%d].p=%p\n", (int)i, + (unsigned)rdata[i].len, (int)i, rdata[i].p); + + /* Write "nil" data to disk */ + ret = H5Dwrite(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata2); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Read from dataset with "nil" data */ + ret = H5Dread(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Check data read in */ + for (i = 0; i < SPACE1_DIM1; i++) + if (rdata[i].len != 0 || rdata[i].p != NULL) + TestErrPrintf("VL doesn't match!, rdata[%d].len=%u, rdata[%d].p=%p\n", (int)i, + (unsigned)rdata[i].len, (int)i, rdata[i].p); + + /* Write dataset to disk */ + ret = H5Dwrite(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Create second dataset, with fill value */ + dcpl_pid = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl_pid, FAIL, "H5Pcreate"); + + /* Set the fill value for the second dataset */ + fill.p = NULL; + fill.len = 0; + ret = H5Pset_fill_value(dcpl_pid, tid1, &fill); + CHECK(ret, FAIL, "H5Pset_fill_value"); + + /* Create a second dataset */ + dataset = H5Dcreate2(fid1, "Dataset2", tid1, sid1, H5P_DEFAULT, dcpl_pid, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Close dataset creation property list */ + ret = H5Pclose(dcpl_pid); + CHECK(ret, FAIL, "H5Pclose"); + + /* Read from dataset before writing data */ + ret = H5Dread(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Check data read in */ + for (i = 0; i < SPACE1_DIM1; i++) + if (rdata[i].len != 0 || rdata[i].p != NULL) + TestErrPrintf("VL doesn't match!, rdata[%d].len=%u, rdata[%d].p=%p\n", (int)i, + (unsigned)rdata[i].len, (int)i, rdata[i].p); + + /* Write "nil" data to disk */ + ret = H5Dwrite(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata2); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Read from dataset with "nil" data */ + ret = H5Dread(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Check data read in */ + for (i = 0; i < SPACE1_DIM1; i++) + if (rdata[i].len != 0 || rdata[i].p != NULL) + TestErrPrintf("VL doesn't match!, rdata[%d].len=%u, rdata[%d].p=%p\n", (int)i, + (unsigned)rdata[i].len, (int)i, rdata[i].p); + + /* Write data to disk */ + ret = H5Dwrite(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Open the file for data checking */ + fid1 = H5Fopen(FILENAME, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Open a dataset */ + dataset = H5Dopen2(fid1, "Dataset1", H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Get dataspace for datasets */ + sid1 = H5Dget_space(dataset); + CHECK(sid1, FAIL, "H5Dget_space"); + + /* Get datatype for dataset */ + tid1 = H5Dget_type(dataset); + CHECK(tid1, FAIL, "H5Dget_type"); + + /* Change to the custom memory allocation routines for reading VL data */ + xfer_pid = H5Pcreate(H5P_DATASET_XFER); + CHECK(xfer_pid, FAIL, "H5Pcreate"); + + ret = H5Pset_vlen_mem_manager(xfer_pid, test_vltypes_alloc_custom, &mem_used, test_vltypes_free_custom, + &mem_used); + CHECK(ret, FAIL, "H5Pset_vlen_mem_manager"); + + /* Make certain the correct amount of memory will be used */ + ret = H5Dvlen_get_buf_size(dataset, tid1, sid1, &size); + CHECK(ret, FAIL, "H5Dvlen_get_buf_size"); + + /* 10 elements allocated = 1 + 2 + 3 + 4 elements for each array position */ + VERIFY(size, ((SPACE1_DIM1 * (SPACE1_DIM1 + 1)) / 2) * sizeof(unsigned int), "H5Dvlen_get_buf_size"); + + /* Read dataset from disk */ + ret = H5Dread(dataset, tid1, H5S_ALL, H5S_ALL, xfer_pid, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Make certain the correct amount of memory has been used */ + /* 10 elements allocated = 1 + 2 + 3 + 4 elements for each array position */ + VERIFY(mem_used, ((SPACE1_DIM1 * (SPACE1_DIM1 + 1)) / 2) * sizeof(unsigned int), "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < SPACE1_DIM1; i++) { + if (wdata[i].len != rdata[i].len) { + TestErrPrintf("%d: VL data lengths don't match!, wdata[%d].len=%d, rdata[%d].len=%d\n", __LINE__, + (int)i, (int)wdata[i].len, (int)i, (int)rdata[i].len); + continue; + } /* end if */ + for (j = 0; j < rdata[i].len; j++) { + if (((unsigned int *)wdata[i].p)[j] != ((unsigned int *)rdata[i].p)[j]) { + TestErrPrintf("VL data values don't match!, wdata[%d].p[%d]=%d, rdata[%d].p[%d]=%d\n", (int)i, + (int)j, (int)((unsigned int *)wdata[i].p)[j], (int)i, (int)j, + (int)((unsigned int *)rdata[i].p)[j]); + continue; + } /* end if */ + } /* end for */ + } /* end for */ + + /* Reclaim the read VL data */ + ret = H5Treclaim(tid1, sid1, xfer_pid, rdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Make certain the VL memory has been freed */ + VERIFY(mem_used, 0, "H5Treclaim"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close dataset transfer property list */ + ret = H5Pclose(xfer_pid); + CHECK(ret, FAIL, "H5Pclose"); + + /* Open second dataset */ + dataset = H5Dopen2(fid1, "Dataset2", H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Get dataspace for datasets */ + sid1 = H5Dget_space(dataset); + CHECK(sid1, FAIL, "H5Dget_space"); + + /* Get datatype for dataset */ + tid1 = H5Dget_type(dataset); + CHECK(tid1, FAIL, "H5Dget_type"); + + /* Create a "bad" dataspace with no extent set */ + sid2 = H5Screate(H5S_SIMPLE); + CHECK(sid2, FAIL, "H5Screate"); + + /* Change to the custom memory allocation routines for reading VL data */ + xfer_pid = H5Pcreate(H5P_DATASET_XFER); + CHECK(xfer_pid, FAIL, "H5Pcreate"); + + ret = H5Pset_vlen_mem_manager(xfer_pid, test_vltypes_alloc_custom, &mem_used, test_vltypes_free_custom, + &mem_used); + CHECK(ret, FAIL, "H5Pset_vlen_mem_manager"); + + /* Make certain the correct amount of memory will be used */ + ret = H5Dvlen_get_buf_size(dataset, tid1, sid1, &size); + CHECK(ret, FAIL, "H5Dvlen_get_buf_size"); + + /* 10 elements allocated = 1 + 2 + 3 + 4 elements for each array position */ + VERIFY(size, ((SPACE1_DIM1 * (SPACE1_DIM1 + 1)) / 2) * sizeof(unsigned int), "H5Dvlen_get_buf_size"); + + /* Try to call H5Dvlen_get_buf with bad dataspace */ + H5E_BEGIN_TRY + { + ret = H5Dvlen_get_buf_size(dataset, tid1, sid2, &size); + } + H5E_END_TRY + VERIFY(ret, FAIL, "H5Dvlen_get_buf_size"); + + /* Read dataset from disk */ + ret = H5Dread(dataset, tid1, H5S_ALL, H5S_ALL, xfer_pid, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Make certain the correct amount of memory has been used */ + /* 10 elements allocated = 1 + 2 + 3 + 4 elements for each array position */ + VERIFY(mem_used, ((SPACE1_DIM1 * (SPACE1_DIM1 + 1)) / 2) * sizeof(unsigned int), "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < SPACE1_DIM1; i++) { + if (wdata[i].len != rdata[i].len) { + TestErrPrintf("%d: VL data lengths don't match!, wdata[%d].len=%d, rdata[%d].len=%d\n", __LINE__, + (int)i, (int)wdata[i].len, (int)i, (int)rdata[i].len); + continue; + } /* end if */ + for (j = 0; j < rdata[i].len; j++) { + if (((unsigned int *)wdata[i].p)[j] != ((unsigned int *)rdata[i].p)[j]) { + TestErrPrintf("VL data values don't match!, wdata[%d].p[%d]=%d, rdata[%d].p[%d]=%d\n", (int)i, + (int)j, (int)((unsigned int *)wdata[i].p)[j], (int)i, (int)j, + (int)((unsigned int *)rdata[i].p)[j]); + continue; + } /* end if */ + } /* end for */ + } /* end for */ + + /* Try to reclaim read data using "bad" dataspace with no extent + * Should fail */ + H5E_BEGIN_TRY + { + ret = H5Treclaim(tid1, sid2, xfer_pid, rdata); + } + H5E_END_TRY + VERIFY(ret, FAIL, "H5Treclaim"); + + /* Reclaim the read VL data */ + ret = H5Treclaim(tid1, sid1, xfer_pid, rdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Make certain the VL memory has been freed */ + VERIFY(mem_used, 0, "H5Treclaim"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Reclaim the write VL data */ + ret = H5Treclaim(tid1, sid1, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close dataset transfer property list */ + ret = H5Pclose(xfer_pid); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + +} /* end test_vltypes_vlen_atomic() */ + +/**************************************************************** +** +** rewrite_vltypes_vlen_atomic(): check memory leak for basic VL datatype. +** Check memory leak for VL datatypes of atomic datatypes +** +****************************************************************/ +static void +rewrite_vltypes_vlen_atomic(void) +{ + hvl_t wdata[SPACE1_DIM1]; /* Information to write */ + hvl_t rdata[SPACE1_DIM1]; /* Information read in */ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1; /* Dataspace ID */ + hid_t tid1; /* Datatype ID */ + hid_t xfer_pid; /* Dataset transfer property list ID */ + hsize_t size; /* Number of bytes which will be used */ + unsigned i, j; /* counting variables */ + size_t mem_used = 0; /* Memory used during allocation */ + unsigned increment = 4; + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Check Memory Leak for Basic Atomic VL Datatype Functionality\n")); + + /* Allocate and initialize VL data to write */ + for (i = 0; i < SPACE1_DIM1; i++) { + wdata[i].p = HDmalloc((i + increment) * sizeof(unsigned int)); + wdata[i].len = i + increment; + for (j = 0; j < (i + increment); j++) + ((unsigned int *)wdata[i].p)[j] = i * 20 + j; + } /* end for */ + + /* Open file created in test_vltypes_vlen_atomic() */ + fid1 = H5Fopen(FILENAME, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Open the dataset created in test_vltypes_vlen_atomic() */ + dataset = H5Dopen2(fid1, "Dataset1", H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Open dataspace for dataset */ + sid1 = H5Dget_space(dataset); + CHECK(sid1, FAIL, "H5Dget_space"); + + /* Get datatype for dataset */ + tid1 = H5Dget_type(dataset); + CHECK(tid1, FAIL, "H5Dget_type"); + + /* Write dataset to disk */ + ret = H5Dwrite(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Open the file for data checking */ + fid1 = H5Fopen(FILENAME, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Open a dataset */ + dataset = H5Dopen2(fid1, "Dataset1", H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Get dataspace for datasets */ + sid1 = H5Dget_space(dataset); + CHECK(sid1, FAIL, "H5Dget_space"); + + /* Get datatype for dataset */ + tid1 = H5Dget_type(dataset); + CHECK(tid1, FAIL, "H5Dget_type"); + + /* Change to the custom memory allocation routines for reading VL data */ + xfer_pid = H5Pcreate(H5P_DATASET_XFER); + CHECK(xfer_pid, FAIL, "H5Pcreate"); + + ret = H5Pset_vlen_mem_manager(xfer_pid, test_vltypes_alloc_custom, &mem_used, test_vltypes_free_custom, + &mem_used); + CHECK(ret, FAIL, "H5Pset_vlen_mem_manager"); + + /* Make certain the correct amount of memory will be used */ + ret = H5Dvlen_get_buf_size(dataset, tid1, sid1, &size); + CHECK(ret, FAIL, "H5Dvlen_get_buf_size"); + + /* 22 elements allocated = 4+5+6+7 elements for each array position */ + VERIFY(size, 22 * sizeof(unsigned int), "H5Dvlen_get_buf_size"); + + /* Read dataset from disk */ + ret = H5Dread(dataset, tid1, H5S_ALL, H5S_ALL, xfer_pid, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Make certain the correct amount of memory has been used */ + /* 22 elements allocated = 4+5+6+7 elements for each array position */ + VERIFY(mem_used, 22 * sizeof(unsigned int), "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < SPACE1_DIM1; i++) { + if (wdata[i].len != rdata[i].len) { + TestErrPrintf("%d: VL data lengths don't match!, wdata[%d].len=%d, rdata[%d].len=%d\n", __LINE__, + (int)i, (int)wdata[i].len, (int)i, (int)rdata[i].len); + continue; + } /* end if */ + for (j = 0; j < rdata[i].len; j++) { + if (((unsigned int *)wdata[i].p)[j] != ((unsigned int *)rdata[i].p)[j]) { + TestErrPrintf("VL data values don't match!, wdata[%d].p[%d]=%d, rdata[%d].p[%d]=%d\n", (int)i, + (int)j, (int)((unsigned int *)wdata[i].p)[j], (int)i, (int)j, + (int)((unsigned int *)rdata[i].p)[j]); + continue; + } /* end if */ + } /* end for */ + } /* end for */ + + /* Reclaim the read VL data */ + ret = H5Treclaim(tid1, sid1, xfer_pid, rdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Make certain the VL memory has been freed */ + VERIFY(mem_used, 0, "H5Treclaim"); + + /* Reclaim the write VL data */ + ret = H5Treclaim(tid1, sid1, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close dataset transfer property list */ + ret = H5Pclose(xfer_pid); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + +} /* end rewrite_vltypes_vlen_atomic() */ + +/**************************************************************** +** +** test_vltypes_vlen_compound(): Test basic VL datatype code. +** Test VL datatypes of compound datatypes +** +****************************************************************/ +static void +test_vltypes_vlen_compound(void) +{ + typedef struct { /* Struct that the VL sequences are composed of */ + int i; + float f; + } s1; + hvl_t wdata[SPACE1_DIM1]; /* Information to write */ + hvl_t rdata[SPACE1_DIM1]; /* Information read in */ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1; /* Dataspace ID */ + hid_t tid1, tid2; /* Datatype IDs */ + hid_t xfer_pid; /* Dataset transfer property list ID */ + hsize_t dims1[] = {SPACE1_DIM1}; + hsize_t size; /* Number of bytes which will be used */ + unsigned i, j; /* counting variables */ + size_t mem_used = 0; /* Memory used during allocation */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Basic Compound VL Datatype Functionality\n")); + + /* Allocate and initialize VL data to write */ + for (i = 0; i < SPACE1_DIM1; i++) { + wdata[i].p = HDmalloc((i + 1) * sizeof(s1)); + wdata[i].len = i + 1; + for (j = 0; j < (i + 1); j++) { + ((s1 *)wdata[i].p)[j].i = (int)(i * 10 + j); + ((s1 *)wdata[i].p)[j].f = (float)(i * 20 + j) / 3.0F; + } /* end for */ + } /* end for */ + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create the base compound type */ + tid2 = H5Tcreate(H5T_COMPOUND, sizeof(s1)); + CHECK(tid2, FAIL, "H5Tcreate"); + + /* Insert fields */ + ret = H5Tinsert(tid2, "i", HOFFSET(s1, i), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + ret = H5Tinsert(tid2, "f", HOFFSET(s1, f), H5T_NATIVE_FLOAT); + CHECK(ret, FAIL, "H5Tinsert"); + + /* Create a datatype to refer to */ + tid1 = H5Tvlen_create(tid2); + CHECK(tid1, FAIL, "H5Tvlen_create"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, "Dataset1", tid1, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write dataset to disk */ + ret = H5Dwrite(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Change to the custom memory allocation routines for reading VL data */ + xfer_pid = H5Pcreate(H5P_DATASET_XFER); + CHECK(xfer_pid, FAIL, "H5Pcreate"); + + ret = H5Pset_vlen_mem_manager(xfer_pid, test_vltypes_alloc_custom, &mem_used, test_vltypes_free_custom, + &mem_used); + CHECK(ret, FAIL, "H5Pset_vlen_mem_manager"); + + /* Make certain the correct amount of memory will be used */ + ret = H5Dvlen_get_buf_size(dataset, tid1, sid1, &size); + CHECK(ret, FAIL, "H5Dvlen_get_buf_size"); + + /* 10 elements allocated = 1 + 2 + 3 + 4 elements for each array position */ + VERIFY(size, ((SPACE1_DIM1 * (SPACE1_DIM1 + 1)) / 2) * sizeof(s1), "H5Dvlen_get_buf_size"); + + /* Read dataset from disk */ + ret = H5Dread(dataset, tid1, H5S_ALL, H5S_ALL, xfer_pid, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Make certain the correct amount of memory has been used */ + /* 10 elements allocated = 1 + 2 + 3 + 4 elements for each array position */ + VERIFY(mem_used, ((SPACE1_DIM1 * (SPACE1_DIM1 + 1)) / 2) * sizeof(s1), "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < SPACE1_DIM1; i++) { + if (wdata[i].len != rdata[i].len) { + TestErrPrintf("%d: VL data length don't match!, wdata[%d].len=%d, rdata[%d].len=%d\n", __LINE__, + (int)i, (int)wdata[i].len, (int)i, (int)rdata[i].len); + continue; + } /* end if */ + for (j = 0; j < rdata[i].len; j++) { + if (((s1 *)wdata[i].p)[j].i != ((s1 *)rdata[i].p)[j].i) { + TestErrPrintf("VL data values don't match!, wdata[%d].p[%d].i=%d, rdata[%d].p[%d].i=%d\n", + (int)i, (int)j, (int)((s1 *)wdata[i].p)[j].i, (int)i, (int)j, + (int)((s1 *)rdata[i].p)[j].i); + continue; + } /* end if */ + if (!H5_FLT_ABS_EQUAL(((s1 *)wdata[i].p)[j].f, ((s1 *)rdata[i].p)[j].f)) { + TestErrPrintf("VL data values don't match!, wdata[%d].p[%d].f=%f, rdata[%d].p[%d].f=%f\n", + (int)i, (int)j, (double)((s1 *)wdata[i].p)[j].f, (int)i, (int)j, + (double)((s1 *)rdata[i].p)[j].f); + continue; + } /* end if */ + } /* end for */ + } /* end for */ + + /* Reclaim the VL data */ + ret = H5Treclaim(tid1, sid1, xfer_pid, rdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Make certain the VL memory has been freed */ + VERIFY(mem_used, 0, "H5Treclaim"); + + /* Reclaim the write VL data */ + ret = H5Treclaim(tid1, sid1, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close datatype */ + ret = H5Tclose(tid2); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close dataset transfer property list */ + ret = H5Pclose(xfer_pid); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + +} /* end test_vltypes_vlen_compound() */ + +/**************************************************************** +** +** rewrite_vltypes_vlen_compound(): Check memory leak for basic VL datatype. +** Checks memory leak for VL datatypes of compound datatypes +** +****************************************************************/ +static void +rewrite_vltypes_vlen_compound(void) +{ + typedef struct { /* Struct that the VL sequences are composed of */ + int i; + float f; + } s1; + hvl_t wdata[SPACE1_DIM1]; /* Information to write */ + hvl_t rdata[SPACE1_DIM1]; /* Information read in */ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1; /* Dataspace ID */ + hid_t tid1, tid2; /* Datatype IDs */ + hid_t xfer_pid; /* Dataset transfer property list ID */ + hsize_t size; /* Number of bytes which will be used */ + unsigned i, j; /* counting variables */ + size_t mem_used = 0; /* Memory used during allocation */ + unsigned increment = 4; + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Check Memory Leak for Basic Compound VL Datatype Functionality\n")); + + /* Allocate and initialize VL data to write */ + for (i = 0; i < SPACE1_DIM1; i++) { + wdata[i].p = HDmalloc((i + increment) * sizeof(s1)); + wdata[i].len = i + increment; + for (j = 0; j < (i + increment); j++) { + ((s1 *)wdata[i].p)[j].i = (int)(i * 40 + j); + ((s1 *)wdata[i].p)[j].f = (float)(i * 60 + j) / 3.0F; + } /* end for */ + } /* end for */ + + /* Create file */ + fid1 = H5Fopen(FILENAME, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Create the base compound type */ + tid2 = H5Tcreate(H5T_COMPOUND, sizeof(s1)); + CHECK(tid2, FAIL, "H5Tcreate"); + + ret = H5Tinsert(tid2, "i", HOFFSET(s1, i), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + ret = H5Tinsert(tid2, "f", HOFFSET(s1, f), H5T_NATIVE_FLOAT); + CHECK(ret, FAIL, "H5Tinsert"); + + /* Create a datatype to refer to */ + tid1 = H5Tvlen_create(tid2); + CHECK(tid1, FAIL, "H5Tvlen_create"); + + /* Create a dataset */ + dataset = H5Dopen2(fid1, "Dataset1", H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Create dataspace for datasets */ + sid1 = H5Dget_space(dataset); + CHECK(sid1, FAIL, "H5Dget_space"); + + /* Write dataset to disk */ + ret = H5Dwrite(dataset, tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Change to the custom memory allocation routines for reading VL data */ + xfer_pid = H5Pcreate(H5P_DATASET_XFER); + CHECK(xfer_pid, FAIL, "H5Pcreate"); + + ret = H5Pset_vlen_mem_manager(xfer_pid, test_vltypes_alloc_custom, &mem_used, test_vltypes_free_custom, + &mem_used); + CHECK(ret, FAIL, "H5Pset_vlen_mem_manager"); + + /* Make certain the correct amount of memory will be used */ + ret = H5Dvlen_get_buf_size(dataset, tid1, sid1, &size); + CHECK(ret, FAIL, "H5Dvlen_get_buf_size"); + + /* 22 elements allocated = 4 + 5 + 6 + 7 elements for each array position */ + VERIFY(size, 22 * sizeof(s1), "H5Dvlen_get_buf_size"); + + /* Read dataset from disk */ + ret = H5Dread(dataset, tid1, H5S_ALL, H5S_ALL, xfer_pid, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Make certain the correct amount of memory has been used */ + /* 22 elements allocated = 4 + 5 + 6 + 7 elements for each array position */ + VERIFY(mem_used, 22 * sizeof(s1), "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < SPACE1_DIM1; i++) { + if (wdata[i].len != rdata[i].len) { + TestErrPrintf("%d: VL data length don't match!, wdata[%d].len=%d, rdata[%d].len=%d\n", __LINE__, + (int)i, (int)wdata[i].len, (int)i, (int)rdata[i].len); + continue; + } /* end if */ + for (j = 0; j < rdata[i].len; j++) { + if (((s1 *)wdata[i].p)[j].i != ((s1 *)rdata[i].p)[j].i) { + TestErrPrintf("VL data values don't match!, wdata[%d].p[%d].i=%d, rdata[%d].p[%d].i=%d\n", + (int)i, (int)j, (int)((s1 *)wdata[i].p)[j].i, (int)i, (int)j, + (int)((s1 *)rdata[i].p)[j].i); + continue; + } /* end if */ + if (!H5_FLT_ABS_EQUAL(((s1 *)wdata[i].p)[j].f, ((s1 *)rdata[i].p)[j].f)) { + TestErrPrintf("VL data values don't match!, wdata[%d].p[%d].f=%f, rdata[%d].p[%d].f=%f\n", + (int)i, (int)j, (double)((s1 *)wdata[i].p)[j].f, (int)i, (int)j, + (double)((s1 *)rdata[i].p)[j].f); + continue; + } /* end if */ + } /* end for */ + } /* end for */ + + /* Reclaim the VL data */ + ret = H5Treclaim(tid1, sid1, xfer_pid, rdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Make certain the VL memory has been freed */ + VERIFY(mem_used, 0, "H5Treclaim"); + + /* Reclaim the write VL data */ + ret = H5Treclaim(tid1, sid1, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close datatype */ + ret = H5Tclose(tid2); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close dataset transfer property list */ + ret = H5Pclose(xfer_pid); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + +} /* end rewrite_vltypes_vlen_compound() */ + +/**************************************************************** +** +** test_vltypes_compound_vlen_vlen(): Test basic VL datatype code. +** Tests compound datatypes with VL datatypes of VL datatypes. +** +****************************************************************/ +static void +test_vltypes_compound_vlen_vlen(void) +{ + typedef struct { /* Struct that the compound type are composed of */ + int i; + float f; + hvl_t v; + } s1; + s1 *wdata; /* data to write */ + s1 *rdata; /* data to read */ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1; /* Dataspace ID */ + hid_t tid1, tid2, tid3; /* Datatype IDs */ + hsize_t dims1[] = {SPACE3_DIM1}; + unsigned i, j, k; /* counting variables */ + hvl_t *t1, *t2; /* Temporary pointer to VL information */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Compound Datatypes with VL Atomic Datatype Component Functionality\n")); + + /* Allocate and initialize VL data to write */ + wdata = (s1 *)HDmalloc(sizeof(s1) * SPACE3_DIM1); + CHECK_PTR(wdata, "HDmalloc"); + rdata = (s1 *)HDmalloc(sizeof(s1) * SPACE3_DIM1); + CHECK_PTR(rdata, "HDmalloc"); + for (i = 0; i < SPACE3_DIM1; i++) { + wdata[i].i = (int)(i * 10); + wdata[i].f = (float)(i * 20) / 3.0F; + wdata[i].v.p = HDmalloc((i + L1_INCM) * sizeof(hvl_t)); + wdata[i].v.len = i + L1_INCM; + for (t1 = (hvl_t *)((wdata[i].v).p), j = 0; j < (i + L1_INCM); j++, t1++) { + t1->p = HDmalloc((j + L2_INCM) * sizeof(unsigned int)); + t1->len = j + L2_INCM; + for (k = 0; k < j + L2_INCM; k++) + ((unsigned int *)t1->p)[k] = i * 100 + j * 10 + k; + } /* end for */ + } /* end for */ + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid1 = H5Screate_simple(SPACE3_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create a VL datatype to refer to */ + tid3 = H5Tvlen_create(H5T_NATIVE_UINT); + CHECK(tid3, FAIL, "H5Tvlen_create"); + + /* Create a VL datatype to refer to */ + tid1 = H5Tvlen_create(tid3); + CHECK(tid1, FAIL, "H5Tvlen_create"); + + /* Create the base compound type */ + tid2 = H5Tcreate(H5T_COMPOUND, sizeof(s1)); + CHECK(tid2, FAIL, "H5Tcreate"); + + /* Insert fields */ + ret = H5Tinsert(tid2, "i", HOFFSET(s1, i), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + ret = H5Tinsert(tid2, "f", HOFFSET(s1, f), H5T_NATIVE_FLOAT); + CHECK(ret, FAIL, "H5Tinsert"); + ret = H5Tinsert(tid2, "v", HOFFSET(s1, v), tid1); + CHECK(ret, FAIL, "H5Tinsert"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, "Dataset1", tid2, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write dataset to disk */ + ret = H5Dwrite(dataset, tid2, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Open file */ + fid1 = H5Fopen(FILENAME, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Open a dataset */ + dataset = H5Dopen2(fid1, "Dataset1", H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Read dataset from disk */ + ret = H5Dread(dataset, tid2, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < SPACE3_DIM1; i++) { + if (wdata[i].i != rdata[i].i) { + TestErrPrintf("Integer components don't match!, wdata[%d].i=%d, rdata[%d].i=%d\n", (int)i, + (int)wdata[i].i, (int)i, (int)rdata[i].i); + continue; + } /* end if */ + if (!H5_FLT_ABS_EQUAL(wdata[i].f, rdata[i].f)) { + TestErrPrintf("Float components don't match!, wdata[%d].f=%f, rdata[%d].f=%f\n", (int)i, + (double)wdata[i].f, (int)i, (double)rdata[i].f); + continue; + } /* end if */ + + if (wdata[i].v.len != rdata[i].v.len) { + TestErrPrintf("%d: VL data length don't match!, wdata[%d].v.len=%d, rdata[%d].v.len=%d\n", + __LINE__, (int)i, (int)wdata[i].v.len, (int)i, (int)rdata[i].v.len); + continue; + } /* end if */ + + for (t1 = (hvl_t *)(wdata[i].v.p), t2 = (hvl_t *)(rdata[i].v.p), j = 0; j < rdata[i].v.len; + j++, t1++, t2++) { + if (t1->len != t2->len) { + TestErrPrintf("%d: VL data length don't match!, i=%d, j=%d, t1->len=%d, t2->len=%d\n", + __LINE__, (int)i, (int)j, (int)t1->len, (int)t2->len); + continue; + } /* end if */ + for (k = 0; k < t2->len; k++) { + if (((unsigned int *)t1->p)[k] != ((unsigned int *)t2->p)[k]) { + TestErrPrintf("VL data values don't match!, t1->p[%d]=%d, t2->p[%d]=%d\n", (int)k, + (int)((unsigned int *)t1->p)[k], (int)k, (int)((unsigned int *)t2->p)[k]); + continue; + } /* end if */ + } /* end for */ + } /* end for */ + } /* end for */ + + /* Reclaim the VL data */ + ret = H5Treclaim(tid2, sid1, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Reclaim the write VL data */ + ret = H5Treclaim(tid2, sid1, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close datatype */ + ret = H5Tclose(tid2); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close datatype */ + ret = H5Tclose(tid3); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Release buffers */ + HDfree(wdata); + HDfree(rdata); +} /* end test_vltypes_compound_vlen_vlen() */ + +/**************************************************************** +** +** test_vltypes_compound_vlstr(): Test VL datatype code. +** Tests VL datatypes of compound datatypes with VL string. +** Dataset is extensible chunked, and data is rewritten with +** shorter VL data. +** +****************************************************************/ +static void +test_vltypes_compound_vlstr(void) +{ + typedef enum { red, blue, green } e1; + typedef struct { + char *string; + e1 color; + } s2; + typedef struct { /* Struct that the compound type are composed of */ + hvl_t v; + } s1; + s1 wdata[SPACE1_DIM1]; /* data to write */ + s1 wdata2[SPACE1_DIM1]; /* data to write */ + s1 rdata[SPACE1_DIM1]; /* data to read */ + s1 rdata2[SPACE1_DIM1]; /* data to read */ + char str[64] = "a\0"; + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset, dset2; /* Dataset ID */ + hid_t sid1, sid2, filespace, filespace2; /* Dataspace ID */ + hid_t tid1, tid2, tid3, tid4, tid5; /* Datatype IDs */ + hid_t cparms; + hsize_t dims1[] = {SPACE1_DIM1}; + hsize_t chunk_dims[] = {SPACE1_DIM1 / 2}; + hsize_t maxdims[] = {H5S_UNLIMITED}; + hsize_t size[] = {SPACE1_DIM1}; + hsize_t offset[] = {0}; + unsigned i, j; /* counting variables */ + s2 *t1, *t2; /* Temporary pointer to VL information */ + int val; + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing VL Datatype of Compound Datatype with VL String Functionality\n")); + + /* Allocate and initialize VL data to write */ + for (i = 0; i < SPACE1_DIM1; i++) { + wdata[i].v.p = (s2 *)HDmalloc((i + L3_INCM) * sizeof(s2)); + wdata[i].v.len = i + L3_INCM; + for (t1 = (s2 *)((wdata[i].v).p), j = 0; j < (i + L3_INCM); j++, t1++) { + HDstrcat(str, "m"); + t1->string = (char *)HDmalloc(HDstrlen(str) * sizeof(char) + 1); + HDstrcpy(t1->string, str); + /*t1->color = red;*/ + t1->color = blue; + } + } /* end for */ + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, maxdims); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create a VL string type*/ + tid4 = H5Tcopy(H5T_C_S1); + CHECK(tid4, FAIL, "H5Tcopy"); + ret = H5Tset_size(tid4, H5T_VARIABLE); + CHECK(ret, FAIL, "H5Tset_size"); + + /* Create an enum type */ + tid3 = H5Tenum_create(H5T_STD_I32LE); + val = 0; + ret = H5Tenum_insert(tid3, "RED", &val); + CHECK(ret, FAIL, "H5Tenum_insert"); + val = 1; + ret = H5Tenum_insert(tid3, "BLUE", &val); + CHECK(ret, FAIL, "H5Tenum_insert"); + val = 2; + ret = H5Tenum_insert(tid3, "GREEN", &val); + CHECK(ret, FAIL, "H5Tenum_insert"); + + /* Create the first layer compound type */ + tid5 = H5Tcreate(H5T_COMPOUND, sizeof(s2)); + CHECK(tid5, FAIL, "H5Tcreate"); + /* Insert fields */ + ret = H5Tinsert(tid5, "string", HOFFSET(s2, string), tid4); + CHECK(ret, FAIL, "H5Tinsert"); + /* Insert fields */ + ret = H5Tinsert(tid5, "enumerate", HOFFSET(s2, color), tid3); + CHECK(ret, FAIL, "H5Tinsert"); + + /* Create a VL datatype of first layer compound type */ + tid1 = H5Tvlen_create(tid5); + CHECK(tid1, FAIL, "H5Tvlen_create"); + + /* Create the base compound type */ + tid2 = H5Tcreate(H5T_COMPOUND, sizeof(s1)); + CHECK(tid2, FAIL, "H5Tcreate"); + + /* Insert fields */ + ret = H5Tinsert(tid2, "v", HOFFSET(s1, v), tid1); + CHECK(ret, FAIL, "H5Tinsert"); + + /* Modify dataset creation properties, i.e. enable chunking */ + cparms = H5Pcreate(H5P_DATASET_CREATE); + ret = H5Pset_chunk(cparms, SPACE1_RANK, chunk_dims); + CHECK(ret, FAIL, "H5Pset_chunk"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, "Dataset1", tid2, sid1, H5P_DEFAULT, cparms, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Extend the dataset. This call assures that dataset is 4.*/ + ret = H5Dset_extent(dataset, size); + CHECK(ret, FAIL, "H5Dset_extent"); + + /* Select a hyperslab */ + filespace = H5Dget_space(dataset); + ret = H5Sselect_hyperslab(filespace, H5S_SELECT_SET, offset, NULL, dims1, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Write dataset to disk */ + ret = H5Dwrite(dataset, tid2, sid1, filespace, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + ret = H5Fflush(fid1, H5F_SCOPE_GLOBAL); + CHECK(ret, FAIL, "H5Fflush"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close disk dataspace */ + ret = H5Sclose(filespace); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close datatype */ + ret = H5Tclose(tid4); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close datatype */ + ret = H5Tclose(tid5); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close datatype */ + ret = H5Tclose(tid3); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close datatype */ + ret = H5Tclose(tid2); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close Property list */ + ret = H5Pclose(cparms); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Open file */ + fid1 = H5Fopen(FILENAME, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Open the dataset */ + dset2 = H5Dopen2(fid1, "Dataset1", H5P_DEFAULT); + CHECK(dset2, FAIL, "H5Dopen2"); + + /* Get the data type */ + tid2 = H5Dget_type(dset2); + CHECK(tid2, FAIL, "H5Dget_type"); + + /* Read dataset from disk */ + ret = H5Dread(dset2, tid2, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < SPACE1_DIM1; i++) { + if (wdata[i].v.len != rdata[i].v.len) { + TestErrPrintf("%d: VL data length don't match!, wdata[%d].v.len=%d, rdata[%d].v.len=%d\n", + __LINE__, (int)i, (int)wdata[i].v.len, (int)i, (int)rdata[i].v.len); + continue; + } /* end if */ + + for (t1 = (s2 *)(wdata[i].v.p), t2 = (s2 *)(rdata[i].v.p), j = 0; j < rdata[i].v.len; + j++, t1++, t2++) { + if (HDstrcmp(t1->string, t2->string) != 0) { + TestErrPrintf("VL data values don't match!, t1->string=%s, t2->string=%s\n", t1->string, + t2->string); + continue; + } /* end if */ + if (t1->color != t2->color) { + TestErrPrintf("VL data values don't match!, t1->color=%d, t2->color=%d\n", t1->color, + t2->color); + continue; + } /* end if */ + } /* end for */ + } /* end for */ + + /* Reclaim the VL data */ + ret = H5Treclaim(tid2, sid1, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Reclaim the write VL data */ + ret = H5Treclaim(tid2, sid1, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Use this part for new data */ + HDstrcpy(str, "bbbbbbbb\0"); + for (i = 0; i < SPACE1_DIM1; i++) { + wdata2[i].v.p = (s2 *)HDmalloc((i + 1) * sizeof(s2)); + wdata2[i].v.len = i + 1; + for (t1 = (s2 *)(wdata2[i].v).p, j = 0; j < i + 1; j++, t1++) { + HDstrcat(str, "pp"); + t1->string = (char *)HDmalloc(HDstrlen(str) * sizeof(char) + 1); + HDstrcpy(t1->string, str); + t1->color = green; + } + } /* end for */ + + /* Select a hyperslab */ + filespace2 = H5Dget_space(dset2); + ret = H5Sselect_hyperslab(filespace2, H5S_SELECT_SET, offset, NULL, dims1, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create dataspace for datasets */ + sid2 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Write dataset to disk */ + ret = H5Dwrite(dset2, tid2, sid2, filespace2, H5P_DEFAULT, &wdata2); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Read dataset from disk */ + ret = H5Dread(dset2, tid2, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata2); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < SPACE1_DIM1; i++) { + if (wdata2[i].v.len != rdata2[i].v.len) { + TestErrPrintf("%d: VL data length don't match!, wdata2[%d].v.len=%d, rdata2[%d].v.len=%d\n", + __LINE__, (int)i, (int)wdata2[i].v.len, (int)i, (int)rdata2[i].v.len); + continue; + } /* end if */ + + for (t1 = (s2 *)(wdata2[i].v.p), t2 = (s2 *)(rdata2[i].v.p), j = 0; j < rdata2[i].v.len; + j++, t1++, t2++) { + if (HDstrcmp(t1->string, t2->string) != 0) { + TestErrPrintf("VL data values don't match!, t1->string=%s, t2->string=%s\n", t1->string, + t2->string); + continue; + } /* end if */ + if (t1->color != t2->color) { + TestErrPrintf("VL data values don't match!, t1->color=%d, t2->color=%d\n", t1->color, + t2->color); + continue; + } /* end if */ + } /* end for */ + } /* end for */ + + /* Reclaim the write VL data */ + ret = H5Treclaim(tid2, sid1, H5P_DEFAULT, wdata2); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Reclaim the VL data */ + ret = H5Treclaim(tid2, sid1, H5P_DEFAULT, rdata2); + CHECK(ret, FAIL, "H5Treclaim"); + + ret = H5Dclose(dset2); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close disk dataspace */ + ret = H5Sclose(filespace2); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close datatype */ + ret = H5Tclose(tid2); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_vltypes_compound_vlstr() */ + +/**************************************************************** +** +** test_vltypes_compound_vlen_atomic(): Test basic VL datatype code. +** Tests compound datatypes with VL datatypes of atomic datatypes. +** +****************************************************************/ +static void +test_vltypes_compound_vlen_atomic(void) +{ + typedef struct { /* Struct that the VL sequences are composed of */ + int i; + float f; + hvl_t v; + } s1; + s1 wdata[SPACE1_DIM1]; /* Information to write */ + s1 rdata[SPACE1_DIM1]; /* Information read in */ + s1 fill; /* Fill value */ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1; /* Dataspace ID */ + hid_t tid1, tid2; /* Datatype IDs */ + hid_t xfer_pid; /* Dataset transfer property list ID */ + hid_t dcpl_pid; /* Dataset creation property list ID */ + hsize_t dims1[] = {SPACE1_DIM1}; + hsize_t size; /* Number of bytes which will be used */ + unsigned i, j; /* counting variables */ + size_t mem_used = 0; /* Memory used during allocation */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Compound Datatypes with VL Atomic Datatype Component Functionality\n")); + + /* Allocate and initialize VL data to write */ + for (i = 0; i < SPACE1_DIM1; i++) { + wdata[i].i = (int)(i * 10); + wdata[i].f = (float)(i * 20) / 3.0F; + wdata[i].v.p = HDmalloc((i + 1) * sizeof(unsigned int)); + wdata[i].v.len = i + 1; + for (j = 0; j < (i + 1); j++) + ((unsigned int *)wdata[i].v.p)[j] = i * 10 + j; + } /* end for */ + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create a VL datatype to refer to */ + tid1 = H5Tvlen_create(H5T_NATIVE_UINT); + CHECK(tid1, FAIL, "H5Tvlen_create"); + + /* Create the base compound type */ + tid2 = H5Tcreate(H5T_COMPOUND, sizeof(s1)); + CHECK(tid2, FAIL, "H5Tcreate"); + + /* Insert fields */ + ret = H5Tinsert(tid2, "i", HOFFSET(s1, i), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + ret = H5Tinsert(tid2, "f", HOFFSET(s1, f), H5T_NATIVE_FLOAT); + CHECK(ret, FAIL, "H5Tinsert"); + ret = H5Tinsert(tid2, "v", HOFFSET(s1, v), tid1); + CHECK(ret, FAIL, "H5Tinsert"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, "Dataset1", tid2, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write dataset to disk */ + ret = H5Dwrite(dataset, tid2, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Change to the custom memory allocation routines for reading VL data */ + xfer_pid = H5Pcreate(H5P_DATASET_XFER); + CHECK(xfer_pid, FAIL, "H5Pcreate"); + + ret = H5Pset_vlen_mem_manager(xfer_pid, test_vltypes_alloc_custom, &mem_used, test_vltypes_free_custom, + &mem_used); + CHECK(ret, FAIL, "H5Pset_vlen_mem_manager"); + + /* Make certain the correct amount of memory will be used */ + ret = H5Dvlen_get_buf_size(dataset, tid2, sid1, &size); + CHECK(ret, FAIL, "H5Dvlen_get_buf_size"); + + /* 10 elements allocated = 1 + 2 + 3 + 4 elements for each array position */ + VERIFY(size, ((SPACE1_DIM1 * (SPACE1_DIM1 + 1)) / 2) * sizeof(unsigned int), "H5Dvlen_get_buf_size"); + + /* Read dataset from disk */ + ret = H5Dread(dataset, tid2, H5S_ALL, H5S_ALL, xfer_pid, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Make certain the correct amount of memory has been used */ + /* 10 elements allocated = 1 + 2 + 3 + 4 elements for each array position */ + VERIFY(mem_used, ((SPACE1_DIM1 * (SPACE1_DIM1 + 1)) / 2) * sizeof(unsigned int), "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < SPACE1_DIM1; i++) { + if (wdata[i].i != rdata[i].i) { + TestErrPrintf("Integer components don't match!, wdata[%d].i=%d, rdata[%d].i=%d\n", (int)i, + (int)wdata[i].i, (int)i, (int)rdata[i].i); + continue; + } /* end if */ + if (!H5_FLT_ABS_EQUAL(wdata[i].f, rdata[i].f)) { + TestErrPrintf("Float components don't match!, wdata[%d].f=%f, rdata[%d].f=%f\n", (int)i, + (double)wdata[i].f, (int)i, (double)rdata[i].f); + continue; + } /* end if */ + if (wdata[i].v.len != rdata[i].v.len) { + TestErrPrintf("%d: VL data length don't match!, wdata[%d].v.len=%d, rdata[%d].v.len=%d\n", + __LINE__, (int)i, (int)wdata[i].v.len, (int)i, (int)rdata[i].v.len); + continue; + } /* end if */ + for (j = 0; j < rdata[i].v.len; j++) { + if (((unsigned int *)wdata[i].v.p)[j] != ((unsigned int *)rdata[i].v.p)[j]) { + TestErrPrintf("VL data values don't match!, wdata[%d].v.p[%d]=%d, rdata[%d].v.p[%d]=%d\n", + (int)i, (int)j, (int)((unsigned int *)wdata[i].v.p)[j], (int)i, (int)j, + (int)((unsigned int *)rdata[i].v.p)[j]); + continue; + } /* end if */ + } /* end for */ + } /* end for */ + + /* Reclaim the VL data */ + ret = H5Treclaim(tid2, sid1, xfer_pid, rdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Make certain the VL memory has been freed */ + VERIFY(mem_used, 0, "H5Treclaim"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Create a second dataset, with a fill value */ + dcpl_pid = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl_pid, FAIL, "H5Pcreate"); + + /* Set the fill value for the second dataset */ + HDmemset(&fill, 0, sizeof(s1)); + ret = H5Pset_fill_value(dcpl_pid, tid2, &fill); + CHECK(ret, FAIL, "H5Pset_fill_value"); + + dataset = H5Dcreate2(fid1, "Dataset2", tid2, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Close dataset creation property list */ + ret = H5Pclose(dcpl_pid); + CHECK(ret, FAIL, "H5Pclose"); + + /* Read from dataset before writing data */ + ret = H5Dread(dataset, tid2, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Check data read in */ + for (i = 0; i < SPACE1_DIM1; i++) + if (rdata[i].i != 0 || !H5_FLT_ABS_EQUAL(rdata[i].f, 0.0F) || rdata[i].v.len != 0 || + rdata[i].v.p != NULL) + TestErrPrintf( + "VL doesn't match!, rdata[%d].i=%d, rdata[%d].f=%f, rdata[%d].v.len=%u, rdata[%d].v.p=%p\n", + (int)i, rdata[i].i, (int)i, (double)rdata[i].f, (int)i, (unsigned)rdata[i].v.len, (int)i, + rdata[i].v.p); + + /* Write dataset to disk */ + ret = H5Dwrite(dataset, tid2, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Read dataset from disk */ + ret = H5Dread(dataset, tid2, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < SPACE1_DIM1; i++) { + if (wdata[i].i != rdata[i].i) { + TestErrPrintf("Integer components don't match!, wdata[%d].i=%d, rdata[%d].i=%d\n", (int)i, + (int)wdata[i].i, (int)i, (int)rdata[i].i); + continue; + } /* end if */ + if (!H5_FLT_ABS_EQUAL(wdata[i].f, rdata[i].f)) { + TestErrPrintf("Float components don't match!, wdata[%d].f=%f, rdata[%d].f=%f\n", (int)i, + (double)wdata[i].f, (int)i, (double)rdata[i].f); + continue; + } /* end if */ + if (wdata[i].v.len != rdata[i].v.len) { + TestErrPrintf("%d: VL data length don't match!, wdata[%d].v.len=%d, rdata[%d].v.len=%d\n", + __LINE__, (int)i, (int)wdata[i].v.len, (int)i, (int)rdata[i].v.len); + continue; + } /* end if */ + for (j = 0; j < rdata[i].v.len; j++) { + if (((unsigned int *)wdata[i].v.p)[j] != ((unsigned int *)rdata[i].v.p)[j]) { + TestErrPrintf("VL data values don't match!, wdata[%d].v.p[%d]=%d, rdata[%d].v.p[%d]=%d\n", + (int)i, (int)j, (int)((unsigned int *)wdata[i].v.p)[j], (int)i, (int)j, + (int)((unsigned int *)rdata[i].v.p)[j]); + continue; + } /* end if */ + } /* end for */ + } /* end for */ + + /* Reclaim the VL data */ + ret = H5Treclaim(tid2, sid1, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Reclaim the write VL data */ + ret = H5Treclaim(tid2, sid1, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Close datatype */ + ret = H5Tclose(tid2); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close dataset transfer property list */ + ret = H5Pclose(xfer_pid); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + +} /* end test_vltypes_compound_vlen_atomic() */ + +/**************************************************************** +** +** rewrite_vltypes_compound_vlen_atomic(): Check memory leak for +** basic VL datatype code. +** Check memory leak for compound datatypes with VL datatypes +** of atomic datatypes. +** +****************************************************************/ +static void +rewrite_vltypes_compound_vlen_atomic(void) +{ + typedef struct { /* Struct that the VL sequences are composed of */ + int i; + float f; + hvl_t v; + } s1; + s1 wdata[SPACE1_DIM1]; /* Information to write */ + s1 rdata[SPACE1_DIM1]; /* Information read in */ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1; /* Dataspace ID */ + hid_t tid1, tid2; /* Datatype IDs */ + hid_t xfer_pid; /* Dataset transfer property list ID */ + hsize_t size; /* Number of bytes which will be used */ + unsigned i, j; /* counting variables */ + size_t mem_used = 0; /* Memory used during allocation */ + unsigned increment = 4; + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, + ("Checking memory leak for compound datatype with VL Atomic Datatype Component Functionality\n")); + + /* Allocate and initialize VL data to write */ + for (i = 0; i < SPACE1_DIM1; i++) { + wdata[i].i = (int)(i * 40); + wdata[i].f = (float)(i * 50) / 3.0F; + wdata[i].v.p = HDmalloc((i + increment) * sizeof(unsigned int)); + wdata[i].v.len = i + increment; + for (j = 0; j < (i + increment); j++) + ((unsigned int *)wdata[i].v.p)[j] = i * 60 + j; + } /* end for */ + + /* Create file */ + fid1 = H5Fopen(FILENAME, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Create a VL datatype to refer to */ + tid1 = H5Tvlen_create(H5T_NATIVE_UINT); + CHECK(tid1, FAIL, "H5Tvlen_create"); + + /* Create the base compound type */ + tid2 = H5Tcreate(H5T_COMPOUND, sizeof(s1)); + CHECK(tid2, FAIL, "H5Tcreate"); + + /* Insert fields */ + ret = H5Tinsert(tid2, "i", HOFFSET(s1, i), H5T_NATIVE_INT); + CHECK(ret, FAIL, "H5Tinsert"); + ret = H5Tinsert(tid2, "f", HOFFSET(s1, f), H5T_NATIVE_FLOAT); + CHECK(ret, FAIL, "H5Tinsert"); + ret = H5Tinsert(tid2, "v", HOFFSET(s1, v), tid1); + CHECK(ret, FAIL, "H5Tinsert"); + + /* Create a dataset */ + dataset = H5Dopen2(fid1, "Dataset1", H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Create dataspace for datasets */ + sid1 = H5Dget_space(dataset); + CHECK(sid1, FAIL, "H5Dget_space"); + + /* Write dataset to disk */ + ret = H5Dwrite(dataset, tid2, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Change to the custom memory allocation routines for reading VL data */ + xfer_pid = H5Pcreate(H5P_DATASET_XFER); + CHECK(xfer_pid, FAIL, "H5Pcreate"); + + ret = H5Pset_vlen_mem_manager(xfer_pid, test_vltypes_alloc_custom, &mem_used, test_vltypes_free_custom, + &mem_used); + CHECK(ret, FAIL, "H5Pset_vlen_mem_manager"); + + /* Make certain the correct amount of memory will be used */ + ret = H5Dvlen_get_buf_size(dataset, tid2, sid1, &size); + CHECK(ret, FAIL, "H5Dvlen_get_buf_size"); + + /* 22 elements allocated = 4+5+6+7 elements for each array position */ + VERIFY(size, 22 * sizeof(unsigned int), "H5Dvlen_get_buf_size"); + + /* Read dataset from disk */ + ret = H5Dread(dataset, tid2, H5S_ALL, H5S_ALL, xfer_pid, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Make certain the correct amount of memory has been used */ + /* 22 elements allocated = 4+5+6+7 elements for each array position */ + VERIFY(mem_used, 22 * sizeof(unsigned int), "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < SPACE1_DIM1; i++) { + if (wdata[i].i != rdata[i].i) { + TestErrPrintf("Integer components don't match!, wdata[%d].i=%d, rdata[%d].i=%d\n", (int)i, + (int)wdata[i].i, (int)i, (int)rdata[i].i); + continue; + } /* end if */ + if (!H5_FLT_ABS_EQUAL(wdata[i].f, rdata[i].f)) { + TestErrPrintf("Float components don't match!, wdata[%d].f=%f, rdata[%d].f=%f\n", (int)i, + (double)wdata[i].f, (int)i, (double)rdata[i].f); + continue; + } /* end if */ + if (wdata[i].v.len != rdata[i].v.len) { + TestErrPrintf("%d: VL data length don't match!, wdata[%d].v.len=%d, rdata[%d].v.len=%d\n", + __LINE__, (int)i, (int)wdata[i].v.len, (int)i, (int)rdata[i].v.len); + continue; + } /* end if */ + for (j = 0; j < rdata[i].v.len; j++) { + if (((unsigned int *)wdata[i].v.p)[j] != ((unsigned int *)rdata[i].v.p)[j]) { + TestErrPrintf("VL data values don't match!, wdata[%d].v.p[%d]=%d, rdata[%d].v.p[%d]=%d\n", + (int)i, (int)j, (int)((unsigned int *)wdata[i].v.p)[j], (int)i, (int)j, + (int)((unsigned int *)rdata[i].v.p)[j]); + continue; + } /* end if */ + } /* end for */ + } /* end for */ + + /* Reclaim the VL data */ + ret = H5Treclaim(tid2, sid1, xfer_pid, rdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Make certain the VL memory has been freed */ + VERIFY(mem_used, 0, "H5Treclaim"); + + /* Reclaim the write VL data */ + ret = H5Treclaim(tid2, sid1, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close datatype */ + ret = H5Tclose(tid2); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close dataset transfer property list */ + ret = H5Pclose(xfer_pid); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + +} /* end rewrite_vltypes_compound_vlen_atomic() */ + +/**************************************************************** +** +** vlen_size_func(): Test basic VL datatype code. +** Tests VL datatype with VL datatypes of atomic datatypes. +** +****************************************************************/ +static size_t +vlen_size_func(unsigned long n) +{ + size_t u = 1; + size_t tmp = 1; + size_t result = 1; + + while (u < n) { + u++; + tmp += u; + result += tmp; + } + return (result); +} + +/**************************************************************** +** +** test_vltypes_vlen_vlen_atomic(): Test basic VL datatype code. +** Tests VL datatype with VL datatypes of atomic datatypes. +** +****************************************************************/ +static void +test_vltypes_vlen_vlen_atomic(void) +{ + hvl_t wdata[SPACE1_DIM1]; /* Information to write */ + hvl_t rdata[SPACE1_DIM1]; /* Information read in */ + hvl_t *t1, *t2; /* Temporary pointer to VL information */ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1; /* Dataspace ID */ + hid_t tid1, tid2; /* Datatype IDs */ + hid_t xfer_pid; /* Dataset transfer property list ID */ + hsize_t dims1[] = {SPACE1_DIM1}; + hsize_t size; /* Number of bytes which will be used */ + unsigned i, j, k; /* counting variables */ + size_t mem_used = 0; /* Memory used during allocation */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Testing VL Datatypes with VL Atomic Datatype Component Functionality\n")); + + /* Allocate and initialize VL data to write */ + for (i = 0; i < SPACE1_DIM1; i++) { + wdata[i].p = HDmalloc((i + 1) * sizeof(hvl_t)); + if (wdata[i].p == NULL) { + TestErrPrintf("Cannot allocate memory for VL data! i=%u\n", i); + return; + } /* end if */ + wdata[i].len = i + 1; + for (t1 = (hvl_t *)(wdata[i].p), j = 0; j < (i + 1); j++, t1++) { + t1->p = HDmalloc((j + 1) * sizeof(unsigned int)); + if (t1->p == NULL) { + TestErrPrintf("Cannot allocate memory for VL data! i=%u, j=%u\n", i, j); + return; + } /* end if */ + t1->len = j + 1; + for (k = 0; k < (j + 1); k++) + ((unsigned int *)t1->p)[k] = i * 100 + j * 10 + k; + } /* end for */ + } /* end for */ + + /* Create file */ + fid1 = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fcreate"); + + /* Create dataspace for datasets */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create a VL datatype to refer to */ + tid1 = H5Tvlen_create(H5T_NATIVE_UINT); + CHECK(tid1, FAIL, "H5Tvlen_create"); + + /* Create the base VL type */ + tid2 = H5Tvlen_create(tid1); + CHECK(tid2, FAIL, "H5Tvlen_create"); + + /* Create a dataset */ + dataset = H5Dcreate2(fid1, "Dataset1", tid2, sid1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Write dataset to disk */ + ret = H5Dwrite(dataset, tid2, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close datatype */ + ret = H5Tclose(tid2); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Open file */ + fid1 = H5Fopen(FILENAME, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Create dataspace for datasets */ + sid1 = H5Screate_simple(SPACE1_RANK, dims1, NULL); + CHECK(sid1, FAIL, "H5Screate_simple"); + + /* Create a VL datatype to refer to */ + tid1 = H5Tvlen_create(H5T_NATIVE_UINT); + CHECK(tid1, FAIL, "H5Tvlen_create"); + + /* Create the base VL type */ + tid2 = H5Tvlen_create(tid1); + CHECK(tid2, FAIL, "H5Tvlen_create"); + + /* Open a dataset */ + dataset = H5Dopen2(fid1, "Dataset1", H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Change to the custom memory allocation routines for reading VL data */ + xfer_pid = H5Pcreate(H5P_DATASET_XFER); + CHECK(xfer_pid, FAIL, "H5Pcreate"); + + ret = H5Pset_vlen_mem_manager(xfer_pid, test_vltypes_alloc_custom, &mem_used, test_vltypes_free_custom, + &mem_used); + CHECK(ret, FAIL, "H5Pset_vlen_mem_manager"); + + /* Make certain the correct amount of memory was used */ + ret = H5Dvlen_get_buf_size(dataset, tid2, sid1, &size); + CHECK(ret, FAIL, "H5Dvlen_get_buf_size"); + + /* 10 hvl_t elements allocated = 1 + 2 + 3 + 4 elements for each array position */ + /* 20 unsigned int elements allocated = 1 + 3 + 6 + 10 elements */ + VERIFY(size, + (hsize_t)(((SPACE1_DIM1 * (SPACE1_DIM1 + 1)) / 2) * sizeof(hvl_t) + + vlen_size_func((unsigned long)SPACE1_DIM1) * sizeof(unsigned int)), + "H5Dvlen_get_buf_size"); + + /* Read dataset from disk */ + ret = H5Dread(dataset, tid2, H5S_ALL, H5S_ALL, xfer_pid, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Make certain the correct amount of memory has been used */ + /* 10 hvl_t elements allocated = 1 + 2 + 3 + 4 elements for each array position */ + /* 20 unsigned int elements allocated = 1 + 3 + 6 + 10 elements */ + VERIFY(mem_used, + (size_t)(((SPACE1_DIM1 * (SPACE1_DIM1 + 1)) / 2) * sizeof(hvl_t) + + vlen_size_func((unsigned long)SPACE1_DIM1) * sizeof(unsigned int)), + "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < SPACE1_DIM1; i++) { + if (wdata[i].len != rdata[i].len) { + TestErrPrintf("%d: VL data length don't match!, wdata[%d].len=%d, rdata[%d].len=%d\n", __LINE__, + (int)i, (int)wdata[i].len, (int)i, (int)rdata[i].len); + continue; + } /* end if */ + for (t1 = (hvl_t *)wdata[i].p, t2 = (hvl_t *)(rdata[i].p), j = 0; j < rdata[i].len; j++, t1++, t2++) { + if (t1->len != t2->len) { + TestErrPrintf("%d: VL data length don't match!, i=%d, j=%d, t1->len=%d, t2->len=%d\n", + __LINE__, (int)i, (int)j, (int)t1->len, (int)t2->len); + continue; + } /* end if */ + for (k = 0; k < t2->len; k++) { + if (((unsigned int *)t1->p)[k] != ((unsigned int *)t2->p)[k]) { + TestErrPrintf("VL data values don't match!, t1->p[%d]=%d, t2->p[%d]=%d\n", (int)k, + (int)((unsigned int *)t1->p)[k], (int)k, (int)((unsigned int *)t2->p)[k]); + continue; + } /* end if */ + } /* end for */ + } /* end for */ + } /* end for */ + + /* Reclaim all the (nested) VL data */ + ret = H5Treclaim(tid2, sid1, xfer_pid, rdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Make certain the VL memory has been freed */ + VERIFY(mem_used, 0, "H5Treclaim"); + + /* Reclaim the write VL data */ + ret = H5Treclaim(tid2, sid1, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close datatype */ + ret = H5Tclose(tid2); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close datatype */ + ret = H5Tclose(tid1); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close dataset transfer property list */ + ret = H5Pclose(xfer_pid); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + +} /* end test_vltypes_vlen_vlen_atomic() */ + +/**************************************************************** +** +** rewrite_longer_vltypes_vlen_vlen_atomic(): Test basic VL datatype code. +** Tests VL datatype with VL datatypes of atomic datatypes. +** +****************************************************************/ +static void +rewrite_longer_vltypes_vlen_vlen_atomic(void) +{ + hvl_t wdata[SPACE1_DIM1]; /* Information to write */ + hvl_t rdata[SPACE1_DIM1]; /* Information read in */ + hvl_t *t1, *t2; /* Temporary pointer to VL information */ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1; /* Dataspace ID */ + hid_t tid2; /* Datatype IDs */ + hid_t xfer_pid; /* Dataset transfer property list ID */ + hsize_t size; /* Number of bytes which will be used */ + unsigned i, j, k; /* counting variables */ + size_t mem_used = 0; /* Memory used during allocation */ + unsigned increment = 1; + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Check memory leak for VL Datatypes with VL Atomic Datatype Component Functionality\n")); + + /* Allocate and initialize VL data to write */ + for (i = 0; i < SPACE1_DIM1; i++) { + wdata[i].p = HDmalloc((i + increment) * sizeof(hvl_t)); + if (wdata[i].p == NULL) { + TestErrPrintf("Cannot allocate memory for VL data! i=%u\n", i); + return; + } /* end if */ + wdata[i].len = i + increment; + for (t1 = (hvl_t *)(wdata[i].p), j = 0; j < (i + increment); j++, t1++) { + t1->p = HDmalloc((j + 1) * sizeof(unsigned int)); + if (t1->p == NULL) { + TestErrPrintf("Cannot allocate memory for VL data! i=%u, j=%u\n", i, j); + return; + } /* end if */ + t1->len = j + 1; + for (k = 0; k < (j + 1); k++) + ((unsigned int *)t1->p)[k] = i * 1000 + j * 100 + k * 10; + } /* end for */ + } /* end for */ + + /* Open file */ + fid1 = H5Fopen(FILENAME, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Open the dataset */ + dataset = H5Dopen2(fid1, "Dataset1", H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Get dataspace for datasets */ + sid1 = H5Dget_space(dataset); + CHECK(sid1, FAIL, "H5Dget_space"); + + /* Open datatype of the dataset */ + tid2 = H5Dget_type(dataset); + CHECK(tid2, FAIL, "H5Dget_type"); + + /* Write dataset to disk */ + ret = H5Dwrite(dataset, tid2, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close datatype */ + ret = H5Tclose(tid2); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Open the file for data checking */ + fid1 = H5Fopen(FILENAME, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Open a dataset */ + dataset = H5Dopen2(fid1, "Dataset1", H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Get dataspace for datasets */ + sid1 = H5Dget_space(dataset); + CHECK(sid1, FAIL, "H5Dget_space"); + + /* Get datatype for dataset */ + tid2 = H5Dget_type(dataset); + CHECK(tid2, FAIL, "H5Dget_type"); + + /* Change to the custom memory allocation routines for reading VL data */ + xfer_pid = H5Pcreate(H5P_DATASET_XFER); + CHECK(xfer_pid, FAIL, "H5Pcreate"); + + ret = H5Pset_vlen_mem_manager(xfer_pid, test_vltypes_alloc_custom, &mem_used, test_vltypes_free_custom, + &mem_used); + CHECK(ret, FAIL, "H5Pset_vlen_mem_manager"); + + /* Make certain the correct amount of memory was used */ + ret = H5Dvlen_get_buf_size(dataset, tid2, sid1, &size); + CHECK(ret, FAIL, "H5Dvlen_get_buf_size"); + + /* 18 hvl_t elements allocated = 3 + 4 + 5 + 6 elements for each array position */ + /* 52 unsigned int elements allocated = 6 + 10 + 15 + 21 elements */ + /*VERIFY(size, 18 * sizeof(hvl_t) + 52 * sizeof(unsigned int), "H5Dvlen_get_buf_size");*/ + + /* Read dataset from disk */ + ret = H5Dread(dataset, tid2, H5S_ALL, H5S_ALL, xfer_pid, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Make certain the correct amount of memory has been used */ + /* 18 hvl_t elements allocated = 3+4+5+6elements for each array position */ + /* 52 unsigned int elements allocated = 6+10+15+21 elements */ + /*VERIFY(mem_used,18*sizeof(hvl_t)+52*sizeof(unsigned int),"H5Dread");*/ + + /* Compare data read in */ + for (i = 0; i < SPACE1_DIM1; i++) { + if (wdata[i].len != rdata[i].len) { + TestErrPrintf("%d: VL data length don't match!, wdata[%d].len=%d, rdata[%d].len=%d\n", __LINE__, + (int)i, (int)wdata[i].len, (int)i, (int)rdata[i].len); + continue; + } /* end if */ + for (t1 = (hvl_t *)(wdata[i].p), t2 = (hvl_t *)(rdata[i].p), j = 0; j < rdata[i].len; + j++, t1++, t2++) { + if (t1->len != t2->len) { + TestErrPrintf("%d: VL data length don't match!, i=%d, j=%d, t1->len=%d, t2->len=%d\n", + __LINE__, (int)i, (int)j, (int)t1->len, (int)t2->len); + continue; + } /* end if */ + for (k = 0; k < t2->len; k++) { + if (((unsigned int *)t1->p)[k] != ((unsigned int *)t2->p)[k]) { + TestErrPrintf("VL data values don't match!, t1->p[%d]=%d, t2->p[%d]=%d\n", (int)k, + (int)((unsigned int *)t1->p)[k], (int)k, (int)((unsigned int *)t2->p)[k]); + continue; + } /* end if */ + } /* end for */ + } /* end for */ + } /* end for */ + + /* Reclaim all the (nested) VL data */ + ret = H5Treclaim(tid2, sid1, xfer_pid, rdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Make certain the VL memory has been freed */ + VERIFY(mem_used, 0, "H5Treclaim"); + + /* Reclaim the write VL data */ + ret = H5Treclaim(tid2, sid1, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close datatype */ + ret = H5Tclose(tid2); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close dataset transfer property list */ + ret = H5Pclose(xfer_pid); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + +} /* end rewrite_longer_vltypes_vlen_vlen_atomic() */ + +/**************************************************************** +** +** rewrite_shorter_vltypes_vlen_vlen_atomic(): Test basic VL datatype code. +** Tests VL datatype with VL datatypes of atomic datatypes. +** +****************************************************************/ +static void +rewrite_shorter_vltypes_vlen_vlen_atomic(void) +{ + hvl_t wdata[SPACE1_DIM1]; /* Information to write */ + hvl_t rdata[SPACE1_DIM1]; /* Information read in */ + hvl_t *t1, *t2; /* Temporary pointer to VL information */ + hid_t fid1; /* HDF5 File IDs */ + hid_t dataset; /* Dataset ID */ + hid_t sid1; /* Dataspace ID */ + hid_t tid2; /* Datatype IDs */ + hid_t xfer_pid; /* Dataset transfer property list ID */ + hsize_t size; /* Number of bytes which will be used */ + unsigned i, j, k; /* counting variables */ + size_t mem_used = 0; /* Memory used during allocation */ + unsigned increment = 1; + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Check memory leak for VL Datatypes with VL Atomic Datatype Component Functionality\n")); + + /* Allocate and initialize VL data to write */ + for (i = 0; i < SPACE1_DIM1; i++) { + wdata[i].p = HDmalloc((i + increment) * sizeof(hvl_t)); + if (wdata[i].p == NULL) { + TestErrPrintf("Cannot allocate memory for VL data! i=%u\n", i); + return; + } /* end if */ + wdata[i].len = i + increment; + for (t1 = (hvl_t *)(wdata[i].p), j = 0; j < (i + increment); j++, t1++) { + t1->p = HDmalloc((j + 1) * sizeof(unsigned int)); + if (t1->p == NULL) { + TestErrPrintf("Cannot allocate memory for VL data! i=%u, j=%u\n", i, j); + return; + } /* end if */ + t1->len = j + 1; + for (k = 0; k < (j + 1); k++) + ((unsigned int *)t1->p)[k] = i * 100000 + j * 1000 + k * 10; + } /* end for */ + } /* end for */ + + /* Open file */ + fid1 = H5Fopen(FILENAME, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Open the dataset */ + dataset = H5Dopen2(fid1, "Dataset1", H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Get dataspace for datasets */ + sid1 = H5Dget_space(dataset); + CHECK(sid1, FAIL, "H5Dget_space"); + + /* Open datatype of the dataset */ + tid2 = H5Dget_type(dataset); + CHECK(tid2, FAIL, "H5Dget_type"); + + /* Write dataset to disk */ + ret = H5Dwrite(dataset, tid2, H5S_ALL, H5S_ALL, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close datatype */ + ret = H5Tclose(tid2); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + + /* Open the file for data checking */ + fid1 = H5Fopen(FILENAME, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid1, FAIL, "H5Fopen"); + + /* Open a dataset */ + dataset = H5Dopen2(fid1, "Dataset1", H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dopen2"); + + /* Get dataspace for datasets */ + sid1 = H5Dget_space(dataset); + CHECK(sid1, FAIL, "H5Dget_space"); + + /* Get datatype for dataset */ + tid2 = H5Dget_type(dataset); + CHECK(tid2, FAIL, "H5Dget_type"); + + /* Change to the custom memory allocation routines for reading VL data */ + xfer_pid = H5Pcreate(H5P_DATASET_XFER); + CHECK(xfer_pid, FAIL, "H5Pcreate"); + + ret = H5Pset_vlen_mem_manager(xfer_pid, test_vltypes_alloc_custom, &mem_used, test_vltypes_free_custom, + &mem_used); + CHECK(ret, FAIL, "H5Pset_vlen_mem_manager"); + + /* Make certain the correct amount of memory was used */ + ret = H5Dvlen_get_buf_size(dataset, tid2, sid1, &size); + CHECK(ret, FAIL, "H5Dvlen_get_buf_size"); + + /* 10 hvl_t elements allocated = 1 + 2 + 3 + 4 elements for each array position */ + /* 20 unsigned int elements allocated = 1 + 3 + 6 + 10 elements */ + VERIFY(size, + (hsize_t)(((SPACE1_DIM1 * (SPACE1_DIM1 + 1)) / 2) * sizeof(hvl_t) + + vlen_size_func((unsigned long)SPACE1_DIM1) * sizeof(unsigned int)), + "H5Dvlen_get_buf_size"); + + /* Read dataset from disk */ + ret = H5Dread(dataset, tid2, H5S_ALL, H5S_ALL, xfer_pid, rdata); + CHECK(ret, FAIL, "H5Dread"); + + /* Make certain the correct amount of memory has been used */ + /* 10 hvl_t elements allocated = 1 + 2 + 3 + 4 elements for each array position */ + /* 20 unsigned int elements allocated = 1 + 3 + 6 + 10 elements */ + VERIFY(mem_used, + (size_t)(((SPACE1_DIM1 * (SPACE1_DIM1 + 1)) / 2) * sizeof(hvl_t) + + vlen_size_func((unsigned long)SPACE1_DIM1) * sizeof(unsigned int)), + "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < SPACE1_DIM1; i++) { + if (wdata[i].len != rdata[i].len) { + TestErrPrintf("%d: VL data length don't match!, wdata[%d].len=%d, rdata[%d].len=%d\n", __LINE__, + (int)i, (int)wdata[i].len, (int)i, (int)rdata[i].len); + continue; + } /* end if */ + for (t1 = (hvl_t *)(wdata[i].p), t2 = (hvl_t *)(rdata[i].p), j = 0; j < rdata[i].len; + j++, t1++, t2++) { + if (t1->len != t2->len) { + TestErrPrintf("%d: VL data length don't match!, i=%d, j=%d, t1->len=%d, t2->len=%d\n", + __LINE__, (int)i, (int)j, (int)t1->len, (int)t2->len); + continue; + } /* end if */ + for (k = 0; k < t2->len; k++) { + if (((unsigned int *)t1->p)[k] != ((unsigned int *)t2->p)[k]) { + TestErrPrintf("VL data values don't match!, t1->p[%d]=%d, t2->p[%d]=%d\n", (int)k, + (int)((unsigned int *)t1->p)[k], (int)k, (int)((unsigned int *)t2->p)[k]); + continue; + } /* end if */ + } /* end for */ + } /* end for */ + } /* end for */ + + /* Reclaim all the (nested) VL data */ + ret = H5Treclaim(tid2, sid1, xfer_pid, rdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Make certain the VL memory has been freed */ + VERIFY(mem_used, 0, "H5Treclaim"); + + /* Reclaim the write VL data */ + ret = H5Treclaim(tid2, sid1, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Close Dataset */ + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close datatype */ + ret = H5Tclose(tid2); + CHECK(ret, FAIL, "H5Tclose"); + + /* Close disk dataspace */ + ret = H5Sclose(sid1); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close dataset transfer property list */ + ret = H5Pclose(xfer_pid); + CHECK(ret, FAIL, "H5Pclose"); + + /* Close file */ + ret = H5Fclose(fid1); + CHECK(ret, FAIL, "H5Fclose"); + +} /* end rewrite_shorter_vltypes_vlen_vlen_atomic() */ + +/**************************************************************** +** +** test_vltypes_fill_value(): Test fill value for VL data. +** One tests data space isn't allocated; another tests data +** space is allocated. +** +****************************************************************/ +static void +test_vltypes_fill_value(void) +{ + typedef struct dtype1_struct { + unsigned int gui; + unsigned int pgui; + const char *str_id; + const char *str_name; + const char *str_desc; + const char *str_orig; + const char *str_stat; + unsigned int ver; + double val; + double ma; + double mi; + const char *str_form; + const char *str_unit; + } dtype1_struct; + + herr_t ret; + hid_t file_id; + hid_t dtype1_id = -1; + hid_t str_id = -1; + hid_t small_dspace_id; /* Dataspace ID for small datasets */ + hid_t large_dspace_id; /* Dataspace ID for large datasets */ + hid_t small_select_dspace_id; /* Dataspace ID for selection in small datasets */ + hid_t large_select_dspace_id; /* Dataspace ID for selection in large datasets */ + hid_t dset_dspace_id = -1; /* Dataspace ID for a particular dataset */ + hid_t dset_select_dspace_id = -1; /* Dataspace ID for selection in a particular dataset */ + hid_t scalar_dspace_id; /* Dataspace ID for scalar dataspace */ + hid_t single_dspace_id; /* Dataspace ID for single element selection */ + hsize_t single_offset[] = {2}; /* Offset of single element selection */ + hsize_t single_block[] = {1}; /* Block size of single element selection */ + hsize_t select_offset[] = {0}; /* Offset of non-contiguous element selection */ + hsize_t select_stride[] = {2}; /* Stride size of non-contiguous element selection */ + hsize_t small_select_count[] = {SPACE4_DIM_SMALL / + 2}; /* Count of small non-contiguous element selection */ + hsize_t large_select_count[] = {SPACE4_DIM_LARGE / + 2}; /* Count of large non-contiguous element selection */ + hsize_t select_block[] = {1}; /* Block size of non-contiguous element selection */ + hid_t dcpl_id, xfer_pid; + hid_t dset_id; + hsize_t small_dims[] = {SPACE4_DIM_SMALL}; + hsize_t large_dims[] = {SPACE4_DIM_LARGE}; + size_t dset_elmts = 0; /* Number of elements in a particular dataset */ + const dtype1_struct fill1 = {1, 2, "foobar", "", NULL, "\0", "dead", + 3, 4.0, 100.0, 1.0, "liquid", "meter"}; + const dtype1_struct wdata = {3, 4, "", NULL, "\0", "foo", "two", 6, 8.0, 200.0, 2.0, "solid", "yard"}; + dtype1_struct *rbuf = NULL; /* Buffer for reading data */ + size_t mem_used = 0; /* Memory used during allocation */ + H5D_layout_t layout; /* Dataset storage layout */ + char dset_name1[64], dset_name2[64]; /* Dataset names */ + unsigned i; + + /* Output message about test being performed */ + MESSAGE(5, ("Check fill value for VL data\n")); + + /* Create a string datatype */ + str_id = H5Tcopy(H5T_C_S1); + CHECK(str_id, FAIL, "H5Tcopy"); + ret = H5Tset_size(str_id, H5T_VARIABLE); + CHECK(ret, FAIL, "H5Tset_size"); + + /* Create a compound data type */ + dtype1_id = H5Tcreate(H5T_COMPOUND, sizeof(struct dtype1_struct)); + CHECK(dtype1_id, FAIL, "H5Tcreate"); + + ret = H5Tinsert(dtype1_id, "guid", HOFFSET(struct dtype1_struct, gui), H5T_NATIVE_UINT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(dtype1_id, "pguid", HOFFSET(struct dtype1_struct, pgui), H5T_NATIVE_UINT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(dtype1_id, "str_id", HOFFSET(dtype1_struct, str_id), str_id); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(dtype1_id, "str_name", HOFFSET(dtype1_struct, str_name), str_id); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(dtype1_id, "str_desc", HOFFSET(dtype1_struct, str_desc), str_id); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(dtype1_id, "str_orig", HOFFSET(dtype1_struct, str_orig), str_id); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(dtype1_id, "str_stat", HOFFSET(dtype1_struct, str_stat), str_id); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(dtype1_id, "ver", HOFFSET(struct dtype1_struct, ver), H5T_NATIVE_UINT); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(dtype1_id, "val", HOFFSET(struct dtype1_struct, val), H5T_NATIVE_DOUBLE); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(dtype1_id, "ma", HOFFSET(struct dtype1_struct, ma), H5T_NATIVE_DOUBLE); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(dtype1_id, "mi", HOFFSET(struct dtype1_struct, mi), H5T_NATIVE_DOUBLE); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(dtype1_id, "str_form", HOFFSET(dtype1_struct, str_form), str_id); + CHECK(ret, FAIL, "H5Tinsert"); + + ret = H5Tinsert(dtype1_id, "str_unit", HOFFSET(dtype1_struct, str_unit), str_id); + CHECK(ret, FAIL, "H5Tinsert"); + + /* Close string datatype */ + ret = H5Tclose(str_id); + CHECK(ret, FAIL, "H5Tclose"); + + /* Allocate space for the buffer to read data */ + rbuf = (dtype1_struct *)HDmalloc(SPACE4_DIM_LARGE * sizeof(dtype1_struct)); + CHECK_PTR(rbuf, "HDmalloc"); + + /* Create the small & large dataspaces to use */ + small_dspace_id = H5Screate_simple(SPACE4_RANK, small_dims, NULL); + CHECK(small_dspace_id, FAIL, "H5Screate_simple"); + + large_dspace_id = H5Screate_simple(SPACE4_RANK, large_dims, NULL); + CHECK(large_dspace_id, FAIL, "H5Screate_simple"); + + /* Create small & large dataspaces w/non-contiguous selections */ + small_select_dspace_id = H5Scopy(small_dspace_id); + CHECK(small_select_dspace_id, FAIL, "H5Scopy"); + + ret = H5Sselect_hyperslab(small_select_dspace_id, H5S_SELECT_SET, select_offset, select_stride, + small_select_count, select_block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + large_select_dspace_id = H5Scopy(large_dspace_id); + CHECK(large_select_dspace_id, FAIL, "H5Scopy"); + + ret = H5Sselect_hyperslab(large_select_dspace_id, H5S_SELECT_SET, select_offset, select_stride, + large_select_count, select_block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create a scalar dataspace */ + scalar_dspace_id = H5Screate(H5S_SCALAR); + CHECK(scalar_dspace_id, FAIL, "H5Screate"); + + /* Create dataset create property list and set the fill value */ + dcpl_id = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl_id, FAIL, "H5Pcreate"); + + ret = H5Pset_fill_value(dcpl_id, dtype1_id, &fill1); + CHECK(ret, FAIL, "H5Pset_fill_value"); + + /* Create the file */ + file_id = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file_id, FAIL, "H5Fcreate"); + + /* Create datasets with different storage layouts */ + for (layout = H5D_COMPACT; layout <= H5D_CHUNKED; layout++) { + unsigned compress_loop; /* # of times to run loop, for testing compressed chunked dataset */ + unsigned test_loop; /* Loop over datasets */ + +#ifdef H5_HAVE_FILTER_DEFLATE + if (layout == H5D_CHUNKED) + compress_loop = 2; + else +#endif /* H5_HAVE_FILTER_DEFLATE */ + compress_loop = 1; + + /* Loop over dataset operations */ + for (test_loop = 0; test_loop < compress_loop; test_loop++) { + hid_t tmp_dcpl_id; /* Temporary copy of the dataset creation property list */ + + /* Make a copy of the dataset creation property list */ + tmp_dcpl_id = H5Pcopy(dcpl_id); + CHECK(tmp_dcpl_id, FAIL, "H5Pcopy"); + + /* Layout specific actions */ + switch (layout) { + case H5D_COMPACT: + HDstrcpy(dset_name1, "dataset1-compact"); + HDstrcpy(dset_name2, "dataset2-compact"); + dset_dspace_id = small_dspace_id; + ret = H5Pset_layout(tmp_dcpl_id, H5D_COMPACT); + CHECK(ret, FAIL, "H5Pset_layout"); + break; + + case H5D_CONTIGUOUS: + HDstrcpy(dset_name1, "dataset1-contig"); + HDstrcpy(dset_name2, "dataset2-contig"); + dset_dspace_id = large_dspace_id; + break; + + case H5D_CHUNKED: { + hsize_t chunk_dims[1] = {SPACE4_DIM_LARGE / 4}; + + dset_dspace_id = large_dspace_id; + ret = H5Pset_chunk(tmp_dcpl_id, 1, chunk_dims); + CHECK(ret, FAIL, "H5Pset_chunk"); +#ifdef H5_HAVE_FILTER_DEFLATE + if (test_loop == 1) { + HDstrcpy(dset_name1, "dataset1-chunked-compressed"); + HDstrcpy(dset_name2, "dataset2-chunked-compressed"); + ret = H5Pset_deflate(tmp_dcpl_id, 3); + CHECK(ret, FAIL, "H5Pset_deflate"); + } /* end if */ + else { +#endif /* H5_HAVE_FILTER_DEFLATE */ + HDstrcpy(dset_name1, "dataset1-chunked"); + HDstrcpy(dset_name2, "dataset2-chunked"); +#ifdef H5_HAVE_FILTER_DEFLATE + } /* end else */ +#endif /* H5_HAVE_FILTER_DEFLATE */ + } break; + + case H5D_VIRTUAL: + HDassert(0 && "Invalid layout type!"); + break; + + case H5D_LAYOUT_ERROR: + case H5D_NLAYOUTS: + default: + HDassert(0 && "Unknown layout type!"); + break; + } /* end switch */ + + /* Create first data set with default setting - no space is allocated */ + dset_id = H5Dcreate2(file_id, dset_name1, dtype1_id, dset_dspace_id, H5P_DEFAULT, tmp_dcpl_id, + H5P_DEFAULT); + CHECK(dset_id, FAIL, "H5Dcreate2"); + + ret = H5Dclose(dset_id); + CHECK(ret, FAIL, "H5Dclose"); + + /* Create a second data set with space allocated and fill value written */ + ret = H5Pset_fill_time(tmp_dcpl_id, H5D_FILL_TIME_IFSET); + CHECK(ret, FAIL, "H5Pset_fill_time"); + + ret = H5Pset_alloc_time(tmp_dcpl_id, H5D_ALLOC_TIME_EARLY); + CHECK(ret, FAIL, "H5Pset_alloc_time"); + + dset_id = H5Dcreate2(file_id, dset_name2, dtype1_id, dset_dspace_id, H5P_DEFAULT, tmp_dcpl_id, + H5P_DEFAULT); + CHECK(dset_id, FAIL, "H5Dcreate2"); + + ret = H5Dclose(dset_id); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close temporary DCPL */ + ret = H5Pclose(tmp_dcpl_id); + CHECK(ret, FAIL, "H5Pclose"); + } /* end for */ + } /* end for */ + + ret = H5Fclose(file_id); + CHECK(ret, FAIL, "H5Fclose"); + + ret = H5Pclose(dcpl_id); + CHECK(ret, FAIL, "H5Pclose"); + + /* Change to the custom memory allocation routines for reading VL data */ + xfer_pid = H5Pcreate(H5P_DATASET_XFER); + CHECK(xfer_pid, FAIL, "H5Pcreate"); + + ret = H5Pset_vlen_mem_manager(xfer_pid, test_vltypes_alloc_custom, &mem_used, test_vltypes_free_custom, + &mem_used); + CHECK(ret, FAIL, "H5Pset_vlen_mem_manager"); + + /* Open the file to check data set value */ + file_id = H5Fopen(FILENAME, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(file_id, FAIL, "H5Fopen"); + + /* Read empty datasets with different storage layouts */ + for (layout = H5D_COMPACT; layout <= H5D_CHUNKED; layout++) { + unsigned compress_loop; /* # of times to run loop, for testing compressed chunked dataset */ + unsigned test_loop; /* Loop over datasets */ + +#ifdef H5_HAVE_FILTER_DEFLATE + if (layout == H5D_CHUNKED) + compress_loop = 2; + else +#endif /* H5_HAVE_FILTER_DEFLATE */ + compress_loop = 1; + + /* Loop over dataset operations */ + for (test_loop = 0; test_loop < compress_loop; test_loop++) { + + /* Layout specific actions */ + switch (layout) { + case H5D_COMPACT: + HDstrcpy(dset_name1, "dataset1-compact"); + HDstrcpy(dset_name2, "dataset2-compact"); + dset_dspace_id = small_dspace_id; + dset_select_dspace_id = small_select_dspace_id; + dset_elmts = SPACE4_DIM_SMALL; + break; + + case H5D_CONTIGUOUS: + HDstrcpy(dset_name1, "dataset1-contig"); + HDstrcpy(dset_name2, "dataset2-contig"); + dset_dspace_id = large_dspace_id; + dset_select_dspace_id = large_select_dspace_id; + dset_elmts = SPACE4_DIM_LARGE; + break; + + case H5D_CHUNKED: +#ifdef H5_HAVE_FILTER_DEFLATE + if (test_loop == 1) { + HDstrcpy(dset_name1, "dataset1-chunked-compressed"); + HDstrcpy(dset_name2, "dataset2-chunked-compressed"); + } /* end if */ + else { +#endif /* H5_HAVE_FILTER_DEFLATE */ + HDstrcpy(dset_name1, "dataset1-chunked"); + HDstrcpy(dset_name2, "dataset2-chunked"); +#ifdef H5_HAVE_FILTER_DEFLATE + } /* end else */ +#endif /* H5_HAVE_FILTER_DEFLATE */ + dset_dspace_id = large_dspace_id; + dset_select_dspace_id = large_select_dspace_id; + dset_elmts = SPACE4_DIM_LARGE; + break; + + case H5D_VIRTUAL: + HDassert(0 && "Invalid layout type!"); + break; + + case H5D_LAYOUT_ERROR: + case H5D_NLAYOUTS: + default: + HDassert(0 && "Unknown layout type!"); + break; + } /* end switch */ + + /* Open first data set */ + dset_id = H5Dopen2(file_id, dset_name1, H5P_DEFAULT); + CHECK(dset_id, FAIL, "H5Dopen2"); + + /* Read in the entire 'empty' dataset of fill value */ + ret = H5Dread(dset_id, dtype1_id, dset_dspace_id, dset_dspace_id, xfer_pid, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < dset_elmts; i++) { + if (HDstrcmp(rbuf[i].str_id, "foobar") != 0 || HDstrcmp(rbuf[i].str_name, "") != 0 || + rbuf[i].str_desc || HDstrcmp(rbuf[i].str_orig, "\0") != 0 || + HDstrcmp(rbuf[i].str_stat, "dead") != 0 || HDstrcmp(rbuf[i].str_form, "liquid") != 0 || + HDstrcmp(rbuf[i].str_unit, "meter") != 0) { + TestErrPrintf("%d: VL data doesn't match!, index(i) = %d\n", __LINE__, (int)i); + continue; + } /* end if */ + } /* end for */ + + /* Release the space */ + ret = H5Treclaim(dtype1_id, dset_dspace_id, xfer_pid, rbuf); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Clear the read buffer */ + HDmemset(rbuf, 0, dset_elmts * sizeof(dtype1_struct)); + + /* Read in non-contiguous selection from 'empty' dataset of fill value */ + ret = H5Dread(dset_id, dtype1_id, dset_select_dspace_id, dset_select_dspace_id, xfer_pid, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < dset_elmts; i++) { + if ((i % 2) == select_offset[0]) { + if (HDstrcmp(rbuf[i].str_id, "foobar") != 0 || HDstrcmp(rbuf[i].str_name, "") != 0 || + rbuf[i].str_desc || HDstrcmp(rbuf[i].str_orig, "\0") != 0 || + HDstrcmp(rbuf[i].str_stat, "dead") != 0 || + HDstrcmp(rbuf[i].str_form, "liquid") != 0 || + HDstrcmp(rbuf[i].str_unit, "meter") != 0) { + TestErrPrintf("%d: VL data doesn't match!, index(i) = %d\n", __LINE__, (int)i); + continue; + } /* end if */ + } /* end if */ + else { + if (rbuf[i].str_id || rbuf[i].str_name || rbuf[i].str_desc || rbuf[i].str_orig || + rbuf[i].str_stat || rbuf[i].str_form || rbuf[i].str_unit) { + TestErrPrintf("%d: VL data doesn't match!, index(i) = %d\n", __LINE__, (int)i); + continue; + } /* end if */ + } /* end else */ + } /* end for */ + + /* Release the space */ + ret = H5Treclaim(dtype1_id, dset_dspace_id, xfer_pid, rbuf); + CHECK(ret, FAIL, "H5Treclaim"); + + ret = H5Dclose(dset_id); + CHECK(ret, FAIL, "H5Dclose"); + + /* Open the second data set to check the value of data */ + dset_id = H5Dopen2(file_id, dset_name2, H5P_DEFAULT); + CHECK(dset_id, FAIL, "H5Dopen2"); + + /* Read in the entire 'empty' dataset of fill value */ + ret = H5Dread(dset_id, dtype1_id, dset_dspace_id, dset_dspace_id, xfer_pid, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < dset_elmts; i++) { + if (HDstrcmp(rbuf[i].str_id, "foobar") != 0 || HDstrcmp(rbuf[i].str_name, "") != 0 || + rbuf[i].str_desc || HDstrcmp(rbuf[i].str_orig, "\0") != 0 || + HDstrcmp(rbuf[i].str_stat, "dead") != 0 || HDstrcmp(rbuf[i].str_form, "liquid") != 0 || + HDstrcmp(rbuf[i].str_unit, "meter") != 0) { + TestErrPrintf("%d: VL data doesn't match!, index(i)=%d\n", __LINE__, (int)i); + continue; + } /* end if */ + } /* end for */ + + /* Release the space */ + ret = H5Treclaim(dtype1_id, dset_dspace_id, xfer_pid, rbuf); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Clear the read buffer */ + HDmemset(rbuf, 0, dset_elmts * sizeof(dtype1_struct)); + + /* Read in non-contiguous selection from 'empty' dataset of fill value */ + ret = H5Dread(dset_id, dtype1_id, dset_select_dspace_id, dset_select_dspace_id, xfer_pid, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < dset_elmts; i++) { + if ((i % 2) == select_offset[0]) { + if (HDstrcmp(rbuf[i].str_id, "foobar") != 0 || HDstrcmp(rbuf[i].str_name, "") != 0 || + rbuf[i].str_desc || HDstrcmp(rbuf[i].str_orig, "\0") != 0 || + HDstrcmp(rbuf[i].str_stat, "dead") != 0 || + HDstrcmp(rbuf[i].str_form, "liquid") != 0 || + HDstrcmp(rbuf[i].str_unit, "meter") != 0) { + TestErrPrintf("%d: VL data doesn't match!, index(i) = %d\n", __LINE__, (int)i); + continue; + } /* end if */ + } /* end if */ + else { + if (rbuf[i].str_id || rbuf[i].str_name || rbuf[i].str_desc || rbuf[i].str_orig || + rbuf[i].str_stat || rbuf[i].str_form || rbuf[i].str_unit) { + TestErrPrintf("%d: VL data doesn't match!, index(i) = %d\n", __LINE__, (int)i); + continue; + } /* end if */ + } /* end else */ + } /* end for */ + + /* Release the space */ + ret = H5Treclaim(dtype1_id, dset_select_dspace_id, xfer_pid, rbuf); + CHECK(ret, FAIL, "H5Treclaim"); + + ret = H5Dclose(dset_id); + CHECK(ret, FAIL, "H5Dclose"); + } /* end for */ + } /* end for */ + + ret = H5Fclose(file_id); + CHECK(ret, FAIL, "H5Fclose"); + + /* Open the file to check data set value */ + file_id = H5Fopen(FILENAME, H5F_ACC_RDWR, H5P_DEFAULT); + CHECK(file_id, FAIL, "H5Fopen"); + + /* Write one element & fill values to datasets with different storage layouts */ + for (layout = H5D_COMPACT; layout <= H5D_CHUNKED; layout++) { + unsigned compress_loop; /* # of times to run loop, for testing compressed chunked dataset */ + unsigned test_loop; /* Loop over datasets */ + +#ifdef H5_HAVE_FILTER_DEFLATE + if (layout == H5D_CHUNKED) + compress_loop = 2; + else +#endif /* H5_HAVE_FILTER_DEFLATE */ + compress_loop = 1; + + /* Loop over dataset operations */ + for (test_loop = 0; test_loop < compress_loop; test_loop++) { + + /* Layout specific actions */ + switch (layout) { + case H5D_COMPACT: + HDstrcpy(dset_name1, "dataset1-compact"); + HDstrcpy(dset_name2, "dataset2-compact"); + dset_dspace_id = small_dspace_id; + dset_select_dspace_id = small_select_dspace_id; + dset_elmts = SPACE4_DIM_SMALL; + break; + + case H5D_CONTIGUOUS: + HDstrcpy(dset_name1, "dataset1-contig"); + HDstrcpy(dset_name2, "dataset2-contig"); + dset_dspace_id = large_dspace_id; + dset_select_dspace_id = large_select_dspace_id; + dset_elmts = SPACE4_DIM_LARGE; + break; + + case H5D_CHUNKED: +#ifdef H5_HAVE_FILTER_DEFLATE + if (test_loop == 1) { + HDstrcpy(dset_name1, "dataset1-chunked-compressed"); + HDstrcpy(dset_name2, "dataset2-chunked-compressed"); + } /* end if */ + else { +#endif /* H5_HAVE_FILTER_DEFLATE */ + HDstrcpy(dset_name1, "dataset1-chunked"); + HDstrcpy(dset_name2, "dataset2-chunked"); +#ifdef H5_HAVE_FILTER_DEFLATE + } /* end else */ +#endif /* H5_HAVE_FILTER_DEFLATE */ + dset_dspace_id = large_dspace_id; + dset_select_dspace_id = large_select_dspace_id; + dset_elmts = SPACE4_DIM_LARGE; + break; + + case H5D_VIRTUAL: + HDassert(0 && "Invalid layout type!"); + break; + + case H5D_LAYOUT_ERROR: + case H5D_NLAYOUTS: + default: + HDassert(0 && "Unknown layout type!"); + break; + } /* end switch */ + + /* Copy the dataset's dataspace */ + single_dspace_id = H5Scopy(dset_dspace_id); + CHECK(single_dspace_id, FAIL, "H5Scopy"); + + /* Set a single element in the dataspace */ + ret = H5Sselect_hyperslab(single_dspace_id, H5S_SELECT_SET, single_offset, NULL, single_block, + NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Open first data set */ + dset_id = H5Dopen2(file_id, dset_name1, H5P_DEFAULT); + CHECK(dset_id, FAIL, "H5Dopen2"); + + /* Write one element in the dataset */ + ret = H5Dwrite(dset_id, dtype1_id, scalar_dspace_id, single_dspace_id, xfer_pid, &wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + ret = H5Dread(dset_id, dtype1_id, dset_dspace_id, dset_dspace_id, xfer_pid, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < dset_elmts; i++) { + if (i == single_offset[0]) { + if (HDstrcmp(rbuf[i].str_id, wdata.str_id) != 0 || rbuf[i].str_name || + HDstrcmp(rbuf[i].str_desc, wdata.str_desc) != 0 || + HDstrcmp(rbuf[i].str_orig, wdata.str_orig) != 0 || + HDstrcmp(rbuf[i].str_stat, wdata.str_stat) != 0 || + HDstrcmp(rbuf[i].str_form, wdata.str_form) != 0 || + HDstrcmp(rbuf[i].str_unit, wdata.str_unit) != 0) { + TestErrPrintf("%d: VL data doesn't match!, index(i)=%d\n", __LINE__, (int)i); + continue; + } /* end if */ + } /* end if */ + else { + if (HDstrcmp(rbuf[i].str_id, "foobar") != 0 || HDstrcmp(rbuf[i].str_name, "") != 0 || + rbuf[i].str_desc || HDstrcmp(rbuf[i].str_orig, "\0") != 0 || + HDstrcmp(rbuf[i].str_stat, "dead") != 0 || + HDstrcmp(rbuf[i].str_form, "liquid") != 0 || + HDstrcmp(rbuf[i].str_unit, "meter") != 0) { + TestErrPrintf("%d: VL data doesn't match!, index(i)=%d\n", __LINE__, (int)i); + continue; + } /* end if */ + } /* end if */ + } /* end for */ + + /* Release the space */ + ret = H5Treclaim(dtype1_id, dset_dspace_id, xfer_pid, rbuf); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Clear the read buffer */ + HDmemset(rbuf, 0, dset_elmts * sizeof(dtype1_struct)); + + /* Read in non-contiguous selection from dataset */ + ret = H5Dread(dset_id, dtype1_id, dset_select_dspace_id, dset_select_dspace_id, xfer_pid, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < dset_elmts; i++) { + if (i == single_offset[0]) { + if (HDstrcmp(rbuf[i].str_id, wdata.str_id) != 0 || rbuf[i].str_name || + HDstrcmp(rbuf[i].str_desc, wdata.str_desc) != 0 || + HDstrcmp(rbuf[i].str_orig, wdata.str_orig) != 0 || + HDstrcmp(rbuf[i].str_stat, wdata.str_stat) != 0 || + HDstrcmp(rbuf[i].str_form, wdata.str_form) != 0 || + HDstrcmp(rbuf[i].str_unit, wdata.str_unit) != 0) { + TestErrPrintf("%d: VL data doesn't match!, index(i)=%d\n", __LINE__, (int)i); + continue; + } /* end if */ + } /* end if */ + else { + if ((i % 2) == select_offset[0]) { + if (HDstrcmp(rbuf[i].str_id, "foobar") != 0 || HDstrcmp(rbuf[i].str_name, "") != 0 || + rbuf[i].str_desc || HDstrcmp(rbuf[i].str_orig, "\0") != 0 || + HDstrcmp(rbuf[i].str_stat, "dead") != 0 || + HDstrcmp(rbuf[i].str_form, "liquid") != 0 || + HDstrcmp(rbuf[i].str_unit, "meter") != 0) { + TestErrPrintf("%d: VL data doesn't match!, index(i) = %d\n", __LINE__, (int)i); + continue; + } /* end if */ + } /* end if */ + else { + if (rbuf[i].str_id || rbuf[i].str_name || rbuf[i].str_desc || rbuf[i].str_orig || + rbuf[i].str_stat || rbuf[i].str_form || rbuf[i].str_unit) { + TestErrPrintf("%d: VL data doesn't match!, index(i) = %d\n", __LINE__, (int)i); + continue; + } /* end if */ + } /* end else */ + } /* end else */ + } /* end for */ + + /* Release the space */ + ret = H5Treclaim(dtype1_id, dset_select_dspace_id, xfer_pid, rbuf); + CHECK(ret, FAIL, "H5Treclaim"); + + ret = H5Dclose(dset_id); + CHECK(ret, FAIL, "H5Dclose"); + + /* Open the second data set to check the value of data */ + dset_id = H5Dopen2(file_id, dset_name2, H5P_DEFAULT); + CHECK(dset_id, FAIL, "H5Dopen2"); + + /* Write one element in the dataset */ + ret = H5Dwrite(dset_id, dtype1_id, scalar_dspace_id, single_dspace_id, xfer_pid, &wdata); + CHECK(ret, FAIL, "H5Dwrite"); + + ret = H5Dread(dset_id, dtype1_id, dset_dspace_id, dset_dspace_id, xfer_pid, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < dset_elmts; i++) { + if (i == single_offset[0]) { + if (HDstrcmp(rbuf[i].str_id, wdata.str_id) != 0 || rbuf[i].str_name || + HDstrcmp(rbuf[i].str_desc, wdata.str_desc) != 0 || + HDstrcmp(rbuf[i].str_orig, wdata.str_orig) != 0 || + HDstrcmp(rbuf[i].str_stat, wdata.str_stat) != 0 || + HDstrcmp(rbuf[i].str_form, wdata.str_form) != 0 || + HDstrcmp(rbuf[i].str_unit, wdata.str_unit) != 0) { + TestErrPrintf("%d: VL data doesn't match!, index(i)=%d\n", __LINE__, (int)i); + continue; + } /* end if */ + } /* end if */ + else { + if (HDstrcmp(rbuf[i].str_id, "foobar") != 0 || HDstrcmp(rbuf[i].str_name, "") != 0 || + rbuf[i].str_desc || HDstrcmp(rbuf[i].str_orig, "\0") != 0 || + HDstrcmp(rbuf[i].str_stat, "dead") != 0 || + HDstrcmp(rbuf[i].str_form, "liquid") != 0 || + HDstrcmp(rbuf[i].str_unit, "meter") != 0) { + TestErrPrintf("%d: VL data doesn't match!, index(i)=%d\n", __LINE__, (int)i); + continue; + } /* end if */ + } /* end if */ + } /* end for */ + + /* Release the space */ + ret = H5Treclaim(dtype1_id, dset_dspace_id, xfer_pid, rbuf); + CHECK(ret, FAIL, "H5Treclaim"); + + /* Clear the read buffer */ + HDmemset(rbuf, 0, dset_elmts * sizeof(dtype1_struct)); + + /* Read in non-contiguous selection from dataset */ + ret = H5Dread(dset_id, dtype1_id, dset_select_dspace_id, dset_select_dspace_id, xfer_pid, rbuf); + CHECK(ret, FAIL, "H5Dread"); + + /* Compare data read in */ + for (i = 0; i < dset_elmts; i++) { + if (i == single_offset[0]) { + if (HDstrcmp(rbuf[i].str_id, wdata.str_id) != 0 || rbuf[i].str_name || + HDstrcmp(rbuf[i].str_desc, wdata.str_desc) != 0 || + HDstrcmp(rbuf[i].str_orig, wdata.str_orig) != 0 || + HDstrcmp(rbuf[i].str_stat, wdata.str_stat) != 0 || + HDstrcmp(rbuf[i].str_form, wdata.str_form) != 0 || + HDstrcmp(rbuf[i].str_unit, wdata.str_unit) != 0) { + TestErrPrintf("%d: VL data doesn't match!, index(i)=%d\n", __LINE__, (int)i); + continue; + } /* end if */ + } /* end if */ + else { + if ((i % 2) == select_offset[0]) { + if (HDstrcmp(rbuf[i].str_id, "foobar") != 0 || HDstrcmp(rbuf[i].str_name, "") != 0 || + rbuf[i].str_desc || HDstrcmp(rbuf[i].str_orig, "\0") != 0 || + HDstrcmp(rbuf[i].str_stat, "dead") != 0 || + HDstrcmp(rbuf[i].str_form, "liquid") != 0 || + HDstrcmp(rbuf[i].str_unit, "meter") != 0) { + TestErrPrintf("%d: VL data doesn't match!, index(i) = %d\n", __LINE__, (int)i); + continue; + } /* end if */ + } /* end if */ + else { + if (rbuf[i].str_id || rbuf[i].str_name || rbuf[i].str_desc || rbuf[i].str_orig || + rbuf[i].str_stat || rbuf[i].str_form || rbuf[i].str_unit) { + TestErrPrintf("%d: VL data doesn't match!, index(i) = %d\n", __LINE__, (int)i); + continue; + } /* end if */ + } /* end else */ + } /* end else */ + } /* end for */ + + /* Release the space */ + ret = H5Treclaim(dtype1_id, dset_select_dspace_id, xfer_pid, rbuf); + CHECK(ret, FAIL, "H5Treclaim"); + + ret = H5Dclose(dset_id); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close the dataspace for the writes */ + ret = H5Sclose(single_dspace_id); + CHECK(ret, FAIL, "H5Sclose"); + } /* end for */ + } /* end for */ + + ret = H5Fclose(file_id); + CHECK(ret, FAIL, "H5Fclose"); + + /* Clean up rest of IDs */ + ret = H5Pclose(xfer_pid); + CHECK(ret, FAIL, "H5Pclose"); + + ret = H5Sclose(small_dspace_id); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(large_dspace_id); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(small_select_dspace_id); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(large_select_dspace_id); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Sclose(scalar_dspace_id); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Tclose(dtype1_id); + CHECK(ret, FAIL, "H5Tclose"); + + /* Release buffer */ + HDfree(rbuf); +} /* end test_vltypes_fill_value() */ + +/**************************************************************** +** +** test_vltypes(): Main VL datatype testing routine. +** +****************************************************************/ +void +test_vltypes(void) +{ + /* Output message about test being performed */ + MESSAGE(5, ("Testing Variable-Length Datatypes\n")); + + /* These next tests use the same file */ + test_vltypes_dataset_create(); /* Check dataset of VL when fill value + * won't be rewritten to it.*/ + test_vltypes_funcs(); /* Test functions with VL types */ + test_vltypes_vlen_atomic(); /* Test VL atomic datatypes */ + rewrite_vltypes_vlen_atomic(); /* Check VL memory leak */ + test_vltypes_vlen_compound(); /* Test VL compound datatypes */ + rewrite_vltypes_vlen_compound(); /* Check VL memory leak */ + test_vltypes_compound_vlen_atomic(); /* Test compound datatypes with VL atomic components */ + rewrite_vltypes_compound_vlen_atomic(); /* Check VL memory leak */ + test_vltypes_vlen_vlen_atomic(); /* Test VL datatype with VL atomic components */ + rewrite_longer_vltypes_vlen_vlen_atomic(); /*overwrite with VL data of longer sequence*/ + rewrite_shorter_vltypes_vlen_vlen_atomic(); /*overwrite with VL data of shorted sequence*/ + test_vltypes_compound_vlen_vlen(); /* Test compound datatypes with VL atomic components */ + test_vltypes_compound_vlstr(); /* Test data rewritten of nested VL data */ + test_vltypes_fill_value(); /* Test fill value for VL data */ +} /* test_vltypes() */ + +/*------------------------------------------------------------------------- + * Function: cleanup_vltypes + * + * Purpose: Cleanup temporary test files + * + * Return: none + * + * Programmer: Quincey Koziol + * June 8, 1999 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +void +cleanup_vltypes(void) +{ + H5Fdelete(FILENAME, H5P_DEFAULT); +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c3365b7..d52beb0 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -395,6 +395,24 @@ if (HDF5_BUILD_UTILS) set (H5_TESTS ${H5_TESTS} mirror_vfd) endif () +set (HDF5_API_TESTS + attribute + dataset + datatype + file + group + link + misc + object +) + +if (HDF5_TEST_API_ENABLE_ASYNC) + set (HDF5_API_TESTS + ${HDF5_API_TESTS} + async + ) +endif () + macro (ADD_H5_EXE file) add_executable (${file} ${HDF5_TEST_SOURCE_DIR}/${file}.c) target_include_directories (${file} PRIVATE "${HDF5_SRC_INCLUDE_DIRS};${HDF5_SRC_BINARY_DIR};${HDF5_TEST_BINARY_DIR};$<$:${MPI_C_INCLUDE_DIRS}>") @@ -879,6 +897,8 @@ if (HDF5_ENABLE_FORMATTERS) clang_format (HDF5_TEST_use_disable_mdc_flushes_FORMAT use_disable_mdc_flushes) endif () +add_subdirectory (API) + if (HDF5_TEST_SERIAL) include (CMakeTests.cmake) endif () diff --git a/test/h5test.c b/test/h5test.c index 1797df9..856de4b 100644 --- a/test/h5test.c +++ b/test/h5test.c @@ -115,6 +115,13 @@ const char *LIBVER_NAMES[] = {"earliest", /* H5F_LIBVER_EARLIEST = 0 */ /* Previous error reporting function */ static H5E_auto2_t err_func = NULL; +/* Global variables for testing */ +size_t n_tests_run_g = 0; +size_t n_tests_passed_g = 0; +size_t n_tests_failed_g = 0; +size_t n_tests_skipped_g = 0; +uint64_t vol_cap_flags_g = H5VL_CAP_FLAG_NONE; + static herr_t h5_errors(hid_t estack, void *client_data); static char *h5_fixname_real(const char *base_name, hid_t fapl, const char *_suffix, char *fullname, size_t size, hbool_t nest_printf, hbool_t subst_for_superblock); diff --git a/test/h5test.h b/test/h5test.h index ea7ab4d..b2c2cda 100644 --- a/test/h5test.h +++ b/test/h5test.h @@ -106,21 +106,25 @@ H5TEST_DLLVAR MPI_Info h5_io_info_g; /* MPI INFO object for IO */ do { \ HDprintf("Testing %-62s", WHAT); \ HDfflush(stdout); \ + n_tests_run_g++; \ } while (0) #define TESTING_2(WHAT) \ do { \ HDprintf(" Testing %-60s", WHAT); \ HDfflush(stdout); \ + n_tests_run_g++; \ } while (0) #define PASSED() \ do { \ HDputs(" PASSED"); \ HDfflush(stdout); \ + n_tests_passed_g++; \ } while (0) #define H5_FAILED() \ do { \ HDputs("*FAILED*"); \ HDfflush(stdout); \ + n_tests_failed_g++; \ } while (0) #define H5_WARNING() \ do { \ @@ -131,6 +135,7 @@ H5TEST_DLLVAR MPI_Info h5_io_info_g; /* MPI INFO object for IO */ do { \ HDputs(" -SKIP-"); \ HDfflush(stdout); \ + n_tests_skipped_g++; \ } while (0) #define PUTS_ERROR(s) \ do { \ @@ -164,6 +169,66 @@ H5TEST_DLLVAR MPI_Info h5_io_info_g; /* MPI INFO object for IO */ goto error; \ } while (0) +/* + * Testing macros used for multi-part tests. + */ +#define TESTING_MULTIPART(WHAT) \ + do { \ + HDprintf("Testing %-62s", WHAT); \ + HDputs(""); \ + HDfflush(stdout); \ + } while (0) + +/* + * Begin and end an entire section of multi-part tests. By placing all the + * parts of a test between these macros, skipping to the 'error' cleanup + * section of a test is deferred until all parts have finished. + */ +#define BEGIN_MULTIPART \ + { \ + int part_nerrors = 0; + +#define END_MULTIPART \ + if (part_nerrors > 0) \ + goto error; \ + } + +/* + * Begin, end and handle errors within a single part of a multi-part test. + * The PART_END macro creates a goto label based on the given "part name". + * When a failure occurs in the current part, the PART_ERROR macro uses + * this label to skip to the next part of the multi-part test. The PART_ERROR + * macro also increments the error count so that the END_MULTIPART macro + * knows to skip to the test's 'error' label once all test parts have finished. + */ +#define PART_BEGIN(part_name) { +#define PART_END(part_name) \ + } \ + part_##part_name##_end: +#define PART_ERROR(part_name) \ + do { \ + n_tests_failed_g++; \ + part_nerrors++; \ + goto part_##part_name##_end; \ + } while (0) +#define PART_TEST_ERROR(part_name) \ + do { \ + H5_FAILED(); \ + AT(); \ + part_nerrors++; \ + goto part_##part_name##_end; \ + } while (0) + +/* + * Simply skips to the goto label for this test part and moves on to the + * next test part. Useful for when a test part needs to be skipped for + * some reason or is currently unimplemented and empty. + */ +#define PART_EMPTY(part_name) \ + do { \ + goto part_##part_name##_end; \ + } while (0) + /* Number of seconds to wait before killing a test (requires alarm(2)) */ #define H5_ALARM_SEC 1200 /* default is 20 minutes */ @@ -285,7 +350,12 @@ H5TEST_DLL char *getenv_all(MPI_Comm comm, int root, const char *name); #endif /* Extern global variables */ -H5TEST_DLLVAR int TestVerbosity; +H5TEST_DLLVAR int TestVerbosity; +H5TEST_DLLVAR size_t n_tests_run_g; +H5TEST_DLLVAR size_t n_tests_passed_g; +H5TEST_DLLVAR size_t n_tests_failed_g; +H5TEST_DLLVAR size_t n_tests_skipped_g; +H5TEST_DLLVAR uint64_t vol_cap_flags_g; H5TEST_DLL void h5_send_message(const char *file, const char *arg1, const char *arg2); H5TEST_DLL herr_t h5_wait_message(const char *file); diff --git a/test/vol.c b/test/vol.c index 29bbb06..6bcae6b 100644 --- a/test/vol.c +++ b/test/vol.c @@ -2076,11 +2076,12 @@ test_async_vol_props(void) hid_t fapl_id = H5I_INVALID_HID; hid_t vol_id = H5I_INVALID_HID; H5VL_pass_through_info_t passthru_info; - uint64_t cap_flags = H5VL_CAP_FLAG_NONE; char *conn_env_str = NULL; TESTING("Async VOL props"); + vol_cap_flags_g = H5VL_CAP_FLAG_NONE; + /* Retrieve the file access property for testing */ fapl_id = h5_fileaccess(); @@ -2104,11 +2105,11 @@ test_async_vol_props(void) /* Test query w/default VOL, which should indicate no async, since native connector * doesn't support async. */ - if (H5Pget_vol_cap_flags(fapl_id, &cap_flags) < 0) + if (H5Pget_vol_cap_flags(fapl_id, &vol_cap_flags_g) < 0) FAIL_STACK_ERROR; - if ((cap_flags & H5VL_CAP_FLAG_ASYNC) > 0) + if ((vol_cap_flags_g & H5VL_CAP_FLAG_ASYNC) > 0) TEST_ERROR; - if ((cap_flags & H5VL_CAP_FLAG_NATIVE_FILES) == 0) + if ((vol_cap_flags_g & H5VL_CAP_FLAG_NATIVE_FILES) == 0) TEST_ERROR; /* Close FAPL */ @@ -2129,12 +2130,12 @@ test_async_vol_props(void) fapl_id = h5_fileaccess(); /* Test query w/fake async VOL, which should succeed */ - cap_flags = H5VL_CAP_FLAG_NONE; - if (H5Pget_vol_cap_flags(fapl_id, &cap_flags) < 0) + vol_cap_flags_g = H5VL_CAP_FLAG_NONE; + if (H5Pget_vol_cap_flags(fapl_id, &vol_cap_flags_g) < 0) FAIL_STACK_ERROR; - if ((cap_flags & H5VL_CAP_FLAG_ASYNC) == 0) + if ((vol_cap_flags_g & H5VL_CAP_FLAG_ASYNC) == 0) TEST_ERROR; - if ((cap_flags & H5VL_CAP_FLAG_NATIVE_FILES) > 0) + if ((vol_cap_flags_g & H5VL_CAP_FLAG_NATIVE_FILES) > 0) TEST_ERROR; /* Reset environment variable & re-init default connector */ @@ -2155,12 +2156,12 @@ test_async_vol_props(void) FAIL_STACK_ERROR; /* Test query w/fake async VOL, which should succeed */ - cap_flags = H5VL_CAP_FLAG_NONE; - if (H5Pget_vol_cap_flags(fapl_id, &cap_flags) < 0) + vol_cap_flags_g = H5VL_CAP_FLAG_NONE; + if (H5Pget_vol_cap_flags(fapl_id, &vol_cap_flags_g) < 0) FAIL_STACK_ERROR; - if ((cap_flags & H5VL_CAP_FLAG_ASYNC) == 0) + if ((vol_cap_flags_g & H5VL_CAP_FLAG_ASYNC) == 0) TEST_ERROR; - if ((cap_flags & H5VL_CAP_FLAG_NATIVE_FILES) > 0) + if ((vol_cap_flags_g & H5VL_CAP_FLAG_NATIVE_FILES) > 0) TEST_ERROR; /* Stack the [internal] passthrough VOL connector on top of the fake async connector */ @@ -2170,12 +2171,12 @@ test_async_vol_props(void) FAIL_STACK_ERROR; /* Test query w/passthru -> fake async VOL, which should succeed */ - cap_flags = H5VL_CAP_FLAG_NONE; - if (H5Pget_vol_cap_flags(fapl_id, &cap_flags) < 0) + vol_cap_flags_g = H5VL_CAP_FLAG_NONE; + if (H5Pget_vol_cap_flags(fapl_id, &vol_cap_flags_g) < 0) FAIL_STACK_ERROR; - if ((cap_flags & H5VL_CAP_FLAG_ASYNC) == 0) + if ((vol_cap_flags_g & H5VL_CAP_FLAG_ASYNC) == 0) TEST_ERROR; - if ((cap_flags & H5VL_CAP_FLAG_NATIVE_FILES) > 0) + if ((vol_cap_flags_g & H5VL_CAP_FLAG_NATIVE_FILES) > 0) TEST_ERROR; /* Unregister the fake async VOL ID */ @@ -2224,14 +2225,15 @@ error: static herr_t test_vol_cap_flags(void) { - hid_t fapl_id = H5I_INVALID_HID; - hid_t vol_id = H5I_INVALID_HID; - uint64_t vol_cap_flags = H5VL_CAP_FLAG_NONE; - char *vol_env = NULL; + hid_t fapl_id = H5I_INVALID_HID; + hid_t vol_id = H5I_INVALID_HID; + char *vol_env = NULL; H5VL_pass_through_info_t passthru_info; TESTING("VOL capability flags"); + vol_cap_flags_g = H5VL_CAP_FLAG_NONE; + /* Register a fake VOL */ if ((vol_id = H5VLregister_connector(&fake_vol_g, H5P_DEFAULT)) < 0) TEST_ERROR; @@ -2243,13 +2245,13 @@ test_vol_cap_flags(void) TEST_ERROR; /* Verify the correctness of the VOL capacity flags */ - if (H5Pget_vol_cap_flags(fapl_id, &vol_cap_flags) < 0) + if (H5Pget_vol_cap_flags(fapl_id, &vol_cap_flags_g) < 0) TEST_ERROR; - if (!(vol_cap_flags & H5VL_CAP_FLAG_FILE_BASIC)) + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC)) TEST_ERROR; - if (vol_cap_flags & H5VL_CAP_FLAG_ATTR_BASIC) + if (vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC) TEST_ERROR; /* If using the native VOL by default, check flags again with H5P_DEFAULT */ @@ -2263,12 +2265,12 @@ test_vol_cap_flags(void) if (NULL == (cls = H5I_object(connector_id))) TEST_ERROR; - vol_cap_flags = H5VL_CAP_FLAG_NONE; + vol_cap_flags_g = H5VL_CAP_FLAG_NONE; - if (H5Pget_vol_cap_flags(H5P_DEFAULT, &vol_cap_flags) < 0) + if (H5Pget_vol_cap_flags(H5P_DEFAULT, &vol_cap_flags_g) < 0) TEST_ERROR; - if (vol_cap_flags != cls->cap_flags) + if (vol_cap_flags_g != cls->cap_flags) TEST_ERROR; if (H5VLclose(connector_id) < 0) @@ -2283,15 +2285,15 @@ test_vol_cap_flags(void) FAIL_STACK_ERROR; /* Verify the correctness of the VOL capacity flags */ - vol_cap_flags = H5VL_CAP_FLAG_NONE; + vol_cap_flags_g = H5VL_CAP_FLAG_NONE; - if (H5Pget_vol_cap_flags(fapl_id, &vol_cap_flags) < 0) + if (H5Pget_vol_cap_flags(fapl_id, &vol_cap_flags_g) < 0) TEST_ERROR; - if (!(vol_cap_flags & H5VL_CAP_FLAG_FILE_BASIC)) + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC)) TEST_ERROR; - if (vol_cap_flags & H5VL_CAP_FLAG_ATTR_BASIC) + if (vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC) TEST_ERROR; if (H5Pclose(fapl_id) < 0) diff --git a/testpar/API/CMakeLists.txt b/testpar/API/CMakeLists.txt new file mode 100644 index 0000000..5eb69c4 --- /dev/null +++ b/testpar/API/CMakeLists.txt @@ -0,0 +1,279 @@ +# Copyright by The HDF Group. +# All rights reserved. +# +# This file is part of HDF5. The full HDF5 copyright notice, including +# terms governing use, modification, and redistribution, is contained in +# the COPYING file, which can be found at the root of the source code +# distribution tree, or in https://www.hdfgroup.org/licenses. +# If you do not have access to either file, you may request a copy from +# help@hdfgroup.org. +# + +#------------------------------------------------------------------------------ +# Set module path +#------------------------------------------------------------------------------ +set(HDF5_TEST_API_CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake") +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${HDF5_TEST_API_CMAKE_MODULE_PATH}) + +#------------------------------------------------------------------------------ +# Setup for API tests +#------------------------------------------------------------------------------ + +# Ported HDF5 tests +set (HDF5_API_PAR_TESTS_EXTRA + t_bigio + t_pshutdown + t_shapesame + testphdf5 +) + +# List of files generated by the HDF5 API tests which +# should be cleaned up in case the test failed to remove +# them +set (HDF5_API_PAR_TESTS_FILES + H5_api_test_parallel.h5 + H5_api_async_test_parallel.h5 + H5_api_async_test_parallel_0.h5 + H5_api_async_test_parallel_1.h5 + H5_api_async_test_parallel_2.h5 + H5_api_async_test_parallel_3.h5 + H5_api_async_test_parallel_4.h5 + test_file_parallel.h5 + split_comm_file.h5 +) + +#----------------------------------------------------------------------------- +# Build the main API test executable +#----------------------------------------------------------------------------- +foreach (api_test ${HDF5_API_TESTS}) + set (HDF5_API_PAR_TEST_SRCS + ${HDF5_API_PAR_TEST_SRCS} + ${CMAKE_CURRENT_SOURCE_DIR}/H5_api_${api_test}_test_parallel.c + ) +endforeach () + +set (HDF5_API_PAR_TEST_SRCS + ${HDF5_API_PAR_TEST_SRCS} + ${CMAKE_CURRENT_SOURCE_DIR}/H5_api_test_parallel.c + ${HDF5_TEST_API_SRC_DIR}/H5_api_test_util.c +) + +add_executable (h5_api_test_parallel ${HDF5_API_PAR_TEST_SRCS}) +target_include_directories ( + h5_api_test_parallel + PRIVATE + "${HDF5_SRC_INCLUDE_DIRS}" + "${HDF5_TEST_PAR_DIR}" + "${HDF5_TEST_API_SRC_DIR}" + "${HDF5_TEST_API_PAR_SRC_DIR}" + "${HDF5_SRC_BINARY_DIR}" + "${HDF5_TEST_BINARY_DIR}" + "${HDF5_TEST_API_SRC_DIR}" + "$<$:${MPI_C_INCLUDE_DIRS}>" +) +target_compile_options ( + h5_api_test_parallel + PRIVATE + "${HDF5_CMAKE_C_FLAGS}" +) +target_compile_definitions ( + h5_api_test_parallel + PRIVATE + $<$:${HDF5_DEVELOPER_DEFS}> +) +if (NOT BUILD_SHARED_LIBS) + TARGET_C_PROPERTIES (h5_api_test_parallel STATIC) + target_link_libraries ( + h5_api_test_parallel + PRIVATE + ${HDF5_TEST_LIB_TARGET} + ${HDF5_LIB_TARGET} + "$<$:MPI::MPI_C>" + ) +else () + TARGET_C_PROPERTIES (h5_api_test_parallel SHARED) + target_link_libraries ( + h5_api_test_parallel + PRIVATE + ${HDF5_TEST_LIBSH_TARGET} + ${HDF5_LIBSH_TARGET} + "$<$:MPI::MPI_C>" + ) +endif () +set_target_properties ( + h5_api_test_parallel + PROPERTIES + FOLDER test/par/API +) +# Add Target to clang-format +if (HDF5_ENABLE_FORMATTERS) + clang_format (HDF5_TEST_h5_api_test_parallel_FORMAT h5_api_test_parallel) +endif () + +#----------------------------------------------------------------------------- +# Build the ported HDF5 test executables +#----------------------------------------------------------------------------- +foreach (api_test_extra ${HDF5_API_PAR_TESTS_EXTRA}) + unset (HDF5_API_PAR_TEST_EXTRA_SRCS) + + set (HDF5_API_PAR_TEST_EXTRA_SRCS + ${HDF5_API_PAR_TEST_EXTRA_SRCS} + ${CMAKE_CURRENT_SOURCE_DIR}/${api_test_extra}.c + ) + + if (${api_test_extra} STREQUAL "testphdf5") + set (HDF5_API_PAR_TEST_EXTRA_SRCS + ${HDF5_API_PAR_TEST_EXTRA_SRCS} + ${CMAKE_CURRENT_SOURCE_DIR}/t_ph5basic.c + ${CMAKE_CURRENT_SOURCE_DIR}/t_file.c + ${CMAKE_CURRENT_SOURCE_DIR}/t_dset.c + ${CMAKE_CURRENT_SOURCE_DIR}/t_mdset.c + ${CMAKE_CURRENT_SOURCE_DIR}/t_coll_chunk.c + ${CMAKE_CURRENT_SOURCE_DIR}/t_span_tree.c + ${CMAKE_CURRENT_SOURCE_DIR}/t_prop.c + ${CMAKE_CURRENT_SOURCE_DIR}/t_file_image.c + ${CMAKE_CURRENT_SOURCE_DIR}/t_coll_md_read.c + ${CMAKE_CURRENT_SOURCE_DIR}/t_chunk_alloc.c + ${CMAKE_CURRENT_SOURCE_DIR}/t_filter_read.c + ) + endif () + + add_executable (h5_api_test_parallel_${api_test_extra} ${HDF5_API_PAR_TEST_EXTRA_SRCS}) + target_include_directories ( + h5_api_test_parallel_${api_test_extra} + PRIVATE + "${HDF5_SRC_INCLUDE_DIRS}" + "${HDF5_TEST_PAR_DIR}" + "${HDF5_TEST_API_SRC_DIR}" + "${HDF5_TEST_API_PAR_SRC_DIR}" + "${HDF5_SRC_BINARY_DIR}" + "${HDF5_TEST_BINARY_DIR}" + "$<$:${MPI_C_INCLUDE_DIRS}>" + ) + target_compile_options ( + h5_api_test_parallel_${api_test_extra} + PRIVATE + "${HDF5_CMAKE_C_FLAGS}" + ) + target_compile_definitions ( + h5_api_test_parallel_${api_test_extra} + PRIVATE + $<$:${HDF5_DEVELOPER_DEFS}> + ) + if (NOT BUILD_SHARED_LIBS) + TARGET_C_PROPERTIES (h5_api_test_parallel_${api_test_extra} STATIC) + target_link_libraries ( + h5_api_test_parallel_${api_test_extra} + PRIVATE + ${HDF5_TEST_LIB_TARGET} + ${HDF5_LIB_TARGET} + "$<$:MPI::MPI_C>" + ) + else () + TARGET_C_PROPERTIES (h5_api_test_parallel_${api_test_extra} SHARED) + target_link_libraries ( + h5_api_test_parallel_${api_test_extra} + PRIVATE + ${HDF5_TEST_LIBSH_TARGET} + ${HDF5_LIBSH_TARGET} + "$<$:MPI::MPI_C>" + ) + endif () + set_target_properties ( + h5_api_test_parallel_${api_test_extra} + PROPERTIES + FOLDER test/par/API + ) + # Add Target to clang-format + if (HDF5_ENABLE_FORMATTERS) + clang_format (HDF5_TEST_h5_api_test_parallel_${api_test_extra}_FORMAT h5_api_test_parallel_${api_test_extra}) + endif () +endforeach () + +#----------------------------------------------------------------------------- +# Add tests if HDF5 parallel testing is enabled +#----------------------------------------------------------------------------- +if (HDF5_TEST_PARALLEL) + if (HDF5_TEST_API_ENABLE_DRIVER) + if ("${HDF5_TEST_API_SERVER}" STREQUAL "") + message (FATAL_ERROR "Please set HDF5_TEST_API_SERVER to point to a server executable for the test driver program.") + endif () + + # Driver options + if (HDF5_TEST_API_SERVER_ALLOW_ERRORS) + set (HDF5_TEST_API_DRIVER_EXTRA_FLAGS --allow-server-errors) + endif () + if (HDF5_TEST_API_CLIENT_HELPER) + set (HDF5_TEST_API_DRIVER_EXTRA_FLAGS ${HDF5_TEST_API_DRIVER_EXTRA_FLAGS} + --client-helper ${HDF5_TEST_API_CLIENT_HELPER} + ) + endif () + if (HDF5_TEST_API_CLIENT_INIT) + set (HDF5_TEST_API_DRIVER_EXTRA_FLAGS ${HDF5_TEST_API_DRIVER_EXTRA_FLAGS} + --client-init ${HDF5_TEST_API_CLIENT_INIT} + ) + endif () + + set(last_api_test "") + foreach (api_test ${HDF5_API_TESTS}) + add_test ( + NAME "h5_api_test_parallel_${api_test}" + COMMAND $ + --server ${HDF5_TEST_API_SERVER} + --client $ "${api_test}" + --serial + ${HDF5_TEST_API_DRIVER_EXTRA_FLAGS} + ) + + set_tests_properties("h5_api_test_parallel_${api_test}" PROPERTIES DEPENDS "${last_api_test}") + + set(last_api_test "h5_api_test_parallel_${api_test}") + endforeach () + + foreach (hdf5_test ${HDF5_API_PAR_TESTS_EXTRA}) + add_test ( + NAME "h5_api_test_parallel_${hdf5_test}" + COMMAND $ + --server ${HDF5_TEST_API_SERVER} + --client $ + --serial + ${HDF5_TEST_API_DRIVER_EXTRA_FLAGS} + ) + endforeach () + + # Hook external tests to same test suite + foreach (ext_api_test ${HDF5_API_EXT_PARALLEL_TESTS}) + add_test ( + NAME "h5_api_ext_test_parallel_${ext_api_test}" + COMMAND $ + --server ${HDF5_TEST_API_SERVER} + --client $ + --serial + ${HDF5_TEST_API_DRIVER_EXTRA_FLAGS} + ) + endforeach () + else () + set(last_api_test "") + foreach (api_test ${HDF5_API_TESTS}) + add_test ( + NAME "h5_api_test_parallel_${api_test}" + COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MPIEXEC_MAX_NUMPROCS} + ${MPIEXEC_PREFLAGS} $ "${api_test}" + ${MPIEXEC_POSTFLAGS} + ) + + set_tests_properties("h5_api_test_parallel_${api_test}" PROPERTIES DEPENDS "${last_api_test}") + + set(last_api_test "h5_api_test_parallel_${api_test}") + endforeach () + + foreach (hdf5_test ${HDF5_API_PAR_TESTS_EXTRA}) + add_test ( + NAME "h5_api_test_parallel_${hdf5_test}" + COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MPIEXEC_MAX_NUMPROCS} + ${MPIEXEC_PREFLAGS} $ + ${MPIEXEC_POSTFLAGS} + ) + endforeach () + endif () +endif () diff --git a/testpar/API/H5_api_async_test_parallel.c b/testpar/API/H5_api_async_test_parallel.c new file mode 100644 index 0000000..dcb5e8d --- /dev/null +++ b/testpar/API/H5_api_async_test_parallel.c @@ -0,0 +1,3668 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "H5_api_async_test_parallel.h" + +#ifdef H5ESpublic_H + +static int test_one_dataset_io(void); +static int test_multi_dataset_io(void); +static int test_multi_file_dataset_io(void); +static int test_multi_file_grp_dset_io(void); +static int test_set_extent(void); +static int test_attribute_exists(void); +static int test_attribute_io(void); +static int test_attribute_io_tconv(void); +static int test_attribute_io_compound(void); +static int test_group(void); +static int test_link(void); +static int test_ocopy_orefresh(void); +static int test_file_reopen(void); + +/* + * The array of parallel async tests to be performed. + */ +static int (*par_async_tests[])(void) = { + test_one_dataset_io, + test_multi_dataset_io, + test_multi_file_dataset_io, + test_multi_file_grp_dset_io, + test_set_extent, + test_attribute_exists, + test_attribute_io, + test_attribute_io_tconv, + test_attribute_io_compound, + test_group, + test_link, + test_ocopy_orefresh, + test_file_reopen, +}; + +hbool_t coll_metadata_read = TRUE; + +/* Highest "printf" file created (starting at 0) */ +int max_printf_file = -1; + +/* + * Create file and dataset. Each rank writes to a portion + * of the dataset. + */ +#define ONE_DATASET_IO_TEST_SPACE_RANK 2 +static int +test_one_dataset_io(void) +{ + hsize_t *dims = NULL; + hsize_t start[ONE_DATASET_IO_TEST_SPACE_RANK]; + hsize_t stride[ONE_DATASET_IO_TEST_SPACE_RANK]; + hsize_t count[ONE_DATASET_IO_TEST_SPACE_RANK]; + hsize_t block[ONE_DATASET_IO_TEST_SPACE_RANK]; + hbool_t op_failed = false; + hbool_t is_native_vol = false; + size_t i, data_size, num_in_progress; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + hid_t es_id = H5I_INVALID_HID; + int *write_buf = NULL; + int *read_buf = NULL; + + TESTING_MULTIPART("single dataset I/O") + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH)) { + if (MAINPROCESS) { + SKIPPED(); + HDprintf( + " API functions for basic file, dataset, or flush aren't supported with this connector\n"); + } + + return 0; + } + + TESTING_2("test setup"); + + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, coll_metadata_read)) < 0) + TEST_ERROR; + + /* Create dataspace */ + if (generate_random_parallel_dimensions(ONE_DATASET_IO_TEST_SPACE_RANK, &dims) < 0) + TEST_ERROR; + + if ((space_id = H5Screate_simple(ONE_DATASET_IO_TEST_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + + /* Create event stack */ + if ((es_id = H5EScreate()) < 0) + TEST_ERROR; + + /* Create file asynchronously */ + if ((file_id = H5Fcreate_async(PAR_ASYNC_API_TEST_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id, es_id)) < 0) + TEST_ERROR; + + /* Find out if the native connector is used */ + if (H5VLobject_is_native(file_id, &is_native_vol) < 0) + TEST_ERROR; + + /* Create the dataset asynchronously */ + if ((dset_id = H5Dcreate_async(file_id, "dset", H5T_NATIVE_INT, space_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Calculate size of data buffers - first dimension is skipped in calculation */ + for (i = 1, data_size = 1; i < ONE_DATASET_IO_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= sizeof(int); + + if (NULL == (write_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + TEST_ERROR; + } + + if (NULL == (read_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + TEST_ERROR; + } + + /* Select this rank's portion of the dataspace */ + for (i = 0; i < ONE_DATASET_IO_TEST_SPACE_RANK; i++) { + if (i == 0) { + start[i] = (hsize_t)mpi_rank; + block[i] = 1; + } + else { + start[i] = 0; + block[i] = dims[i]; + } + + stride[i] = 1; + count[i] = 1; + } + + if (H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start, stride, count, block) < 0) { + H5_FAILED(); + HDprintf(" couldn't select hyperslab for dataset write\n"); + goto error; + } + + /* Setup memory space for write_buf */ + { + hsize_t mdims[] = {data_size / sizeof(int)}; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + goto error; + } + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(single_dset_eswait) + { + TESTING_2("synchronization using H5ESwait()"); + + /* Initialize write_buf */ + for (i = 0; i < data_size / sizeof(int); i++) + ((int *)write_buf)[i] = mpi_rank; + + /* Write the dataset asynchronously */ + if (H5Dwrite_async(dset_id, H5T_NATIVE_INT, mspace_id, space_id, H5P_DEFAULT, write_buf, es_id) < + 0) + PART_TEST_ERROR(single_dset_eswait); + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + PART_TEST_ERROR(single_dset_eswait); + if (op_failed) + PART_TEST_ERROR(single_dset_eswait); + + /* Read the dataset asynchronously */ + if (H5Dread_async(dset_id, H5T_NATIVE_INT, mspace_id, space_id, H5P_DEFAULT, read_buf, es_id) < 0) + PART_TEST_ERROR(single_dset_eswait); + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + PART_TEST_ERROR(single_dset_eswait); + if (op_failed) + PART_TEST_ERROR(single_dset_eswait); + + /* Verify the read data */ + for (i = 0; i < data_size / sizeof(int); i++) + if (write_buf[i] != read_buf[i]) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + PART_ERROR(single_dset_eswait); + } /* end if */ + + PASSED(); + } + PART_END(single_dset_eswait); + + PART_BEGIN(single_dset_dclose) + { + TESTING_2("synchronization using H5Dclose()"); + + /* Initialize write_buf */ + for (i = 0; i < data_size / sizeof(int); i++) + ((int *)write_buf)[i] = (int)i; + + /* Write the dataset asynchronously */ + if (H5Dwrite_async(dset_id, H5T_NATIVE_INT, mspace_id, space_id, H5P_DEFAULT, write_buf, es_id) < + 0) + PART_TEST_ERROR(single_dset_dclose); + + /* Close the dataset synchronously */ + if (H5Dclose(dset_id) < 0) + PART_TEST_ERROR(single_dset_dclose); + + /* Re-open the dataset asynchronously */ + if ((dset_id = H5Dopen_async(file_id, "dset", H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(single_dset_dclose); + + /* Read the dataset asynchronously */ + if (H5Dread_async(dset_id, H5T_NATIVE_INT, mspace_id, space_id, H5P_DEFAULT, read_buf, es_id) < 0) + PART_TEST_ERROR(single_dset_dclose); + + /* Close the dataset synchronously */ + if (H5Dclose(dset_id) < 0) + PART_TEST_ERROR(single_dset_dclose); + + /* Verify the read data */ + for (i = 0; i < data_size / sizeof(int); i++) + if (write_buf[i] != read_buf[i]) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + PART_ERROR(single_dset_dclose); + } /* end if */ + + /* Re-open the dataset asynchronously */ + if ((dset_id = H5Dopen_async(file_id, "dset", H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(single_dset_dclose); + + PASSED(); + } + PART_END(single_dset_dclose); + + PART_BEGIN(single_dset_dflush) + { + TESTING_2("synchronization using H5Oflush_async()"); + + /* Initialize write_buf */ + for (i = 0; i < data_size / sizeof(int); i++) + ((int *)write_buf)[i] = 10 * (int)i; + + /* Write the dataset asynchronously */ + if (H5Dwrite_async(dset_id, H5T_NATIVE_INT, mspace_id, space_id, H5P_DEFAULT, write_buf, es_id) < + 0) + PART_TEST_ERROR(single_dset_dflush); + + /* Flush the dataset asynchronously. This will effectively work as a + * barrier, guaranteeing the read takes place after the write. Skip this + * function because it isn't supported for the native vol in parallel. */ + if (!is_native_vol && H5Oflush_async(dset_id, es_id) < 0) + PART_TEST_ERROR(single_dset_dflush); + + /* Read the dataset asynchronously */ + if (H5Dread_async(dset_id, H5T_NATIVE_INT, mspace_id, space_id, H5P_DEFAULT, read_buf, es_id) < 0) + PART_TEST_ERROR(single_dset_dflush); + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + PART_TEST_ERROR(single_dset_dflush); + if (op_failed) + PART_TEST_ERROR(single_dset_dflush); + + /* Verify the read data */ + for (i = 0; i < data_size / sizeof(int); i++) + if (write_buf[i] != read_buf[i]) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + PART_ERROR(single_dset_dflush); + } /* end if */ + + PASSED(); + } + PART_END(single_dset_dflush); + + PART_BEGIN(single_dset_fclose) + { + TESTING_2("synchronization using H5Fclose()"); + + /* Initialize write_buf */ + for (i = 0; i < data_size / sizeof(int); i++) + ((int *)write_buf)[i] = (int)i + 5; + + /* Write the dataset asynchronously */ + if (H5Dwrite_async(dset_id, H5T_NATIVE_INT, mspace_id, space_id, H5P_DEFAULT, write_buf, es_id) < + 0) + PART_TEST_ERROR(single_dset_fclose); + + /* Close the dataset asynchronously */ + if (H5Dclose_async(dset_id, es_id) < 0) + PART_TEST_ERROR(single_dset_fclose); + + /* Close the file synchronously */ + if (H5Fclose(file_id) < 0) + PART_TEST_ERROR(single_dset_fclose); + + /* Reopen the file asynchronously. */ + if ((file_id = H5Fopen_async(PAR_ASYNC_API_TEST_FILE, H5F_ACC_RDONLY, fapl_id, es_id)) < 0) + PART_TEST_ERROR(single_dset_fclose); + + /* Re-open the dataset asynchronously */ + if ((dset_id = H5Dopen_async(file_id, "dset", H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(single_dset_fclose); + + /* Read the dataset asynchronously */ + if (H5Dread_async(dset_id, H5T_NATIVE_INT, mspace_id, space_id, H5P_DEFAULT, read_buf, es_id) < 0) + PART_TEST_ERROR(single_dset_fclose); + + /* Close the dataset asynchronously */ + if (H5Dclose_async(dset_id, es_id) < 0) + PART_TEST_ERROR(single_dset_fclose); + + /* Close the file synchronously */ + if (H5Fclose(file_id) < 0) + PART_TEST_ERROR(single_dset_fclose); + + /* Verify the read data */ + for (i = 0; i < data_size / sizeof(int); i++) + if (write_buf[i] != read_buf[i]) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + PART_ERROR(single_dset_fclose); + } /* end if */ + + PASSED(); + } + PART_END(single_dset_fclose); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + + if (dims) { + HDfree(dims); + dims = NULL; + } + + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Sclose(mspace_id) < 0) + TEST_ERROR; + if (H5ESclose(es_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (read_buf) + HDfree(read_buf); + if (write_buf) + HDfree(write_buf); + if (dims) + HDfree(dims); + H5Sclose(space_id); + H5Sclose(mspace_id); + H5Dclose(dset_id); + H5Pclose(fapl_id); + H5Fclose(file_id); + H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed); + H5ESclose(es_id); + } + H5E_END_TRY; + + return 1; +} +#undef ONE_DATASET_IO_TEST_SPACE_RANK + +/* + * Create file and multiple datasets. Each rank writes to a + * portion of each dataset and reads back their portion of + * each dataset. + */ +#define MULTI_DATASET_IO_TEST_SPACE_RANK 2 +#define MULTI_DATASET_IO_TEST_NDSETS 5 +static int +test_multi_dataset_io(void) +{ + hsize_t *dims = NULL; + hsize_t start[MULTI_DATASET_IO_TEST_SPACE_RANK]; + hsize_t stride[MULTI_DATASET_IO_TEST_SPACE_RANK]; + hsize_t count[MULTI_DATASET_IO_TEST_SPACE_RANK]; + hsize_t block[MULTI_DATASET_IO_TEST_SPACE_RANK]; + hbool_t op_failed; + size_t i, j, data_size, num_in_progress; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t dset_id[MULTI_DATASET_IO_TEST_NDSETS] = {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, + H5I_INVALID_HID, H5I_INVALID_HID}; + hid_t space_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + hid_t es_id = H5I_INVALID_HID; + char dset_name[32]; + int *write_buf = NULL; + int *read_buf = NULL; + + TESTING_MULTIPART("multi dataset I/O") + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH)) { + if (MAINPROCESS) { + SKIPPED(); + HDprintf( + " API functions for basic file, dataset, or flush aren't supported with this connector\n"); + } + + return 0; + } + + TESTING_2("test setup"); + + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, coll_metadata_read)) < 0) + TEST_ERROR; + + /* Create dataspace */ + if (generate_random_parallel_dimensions(MULTI_DATASET_IO_TEST_SPACE_RANK, &dims) < 0) + TEST_ERROR; + + /* Create dataspace */ + if ((space_id = H5Screate_simple(MULTI_DATASET_IO_TEST_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + + /* Create event stack */ + if ((es_id = H5EScreate()) < 0) + TEST_ERROR; + + /* Create file asynchronously */ + if ((file_id = H5Fcreate_async(PAR_ASYNC_API_TEST_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id, es_id)) < 0) + TEST_ERROR; + + /* Calculate size of data buffers - first dimension is skipped in calculation */ + for (i = 1, data_size = 1; i < MULTI_DATASET_IO_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= sizeof(int); + data_size *= MULTI_DATASET_IO_TEST_NDSETS; + + if (NULL == (write_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + TEST_ERROR; + } + + if (NULL == (read_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + TEST_ERROR; + } + + /* Select this rank's portion of the dataspace */ + for (i = 0; i < MULTI_DATASET_IO_TEST_SPACE_RANK; i++) { + if (i == 0) { + start[i] = (hsize_t)mpi_rank; + block[i] = 1; + } + else { + start[i] = 0; + block[i] = dims[i]; + } + + stride[i] = 1; + count[i] = 1; + } + + if (H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start, stride, count, block) < 0) { + H5_FAILED(); + HDprintf(" couldn't select hyperslab for dataset write\n"); + goto error; + } + + /* Setup memory space for write_buf */ + { + hsize_t mdims[] = {data_size / MULTI_DATASET_IO_TEST_NDSETS / sizeof(int)}; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + goto error; + } + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(multi_dset_open) + { + size_t buf_start_idx; + + TESTING_2("keeping datasets open"); + + /* Loop over datasets */ + for (i = 0; i < MULTI_DATASET_IO_TEST_NDSETS; i++) { + size_t buf_end_idx; + + /* Set dataset name */ + sprintf(dset_name, "dset%d", (int)i); + + /* Create the dataset asynchronously */ + if ((dset_id[i] = H5Dcreate_async(file_id, dset_name, H5T_NATIVE_INT, space_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_dset_open); + + /* Initialize write_buf. Must use a new slice of write_buf for + * each dset since we can't overwrite the buffers until I/O is done. */ + buf_start_idx = i * (data_size / MULTI_DATASET_IO_TEST_NDSETS / sizeof(int)); + buf_end_idx = buf_start_idx + (data_size / MULTI_DATASET_IO_TEST_NDSETS / sizeof(int)); + for (j = buf_start_idx; j < buf_end_idx; j++) + ((int *)write_buf)[j] = mpi_rank; + + /* Write the dataset asynchronously */ + if (H5Dwrite_async(dset_id[i], H5T_NATIVE_INT, mspace_id, space_id, H5P_DEFAULT, + &write_buf[buf_start_idx], es_id) < 0) + PART_TEST_ERROR(multi_dset_open); + } /* end for */ + + /* Flush the file asynchronously. This will effectively work as a + * barrier, guaranteeing the read takes place after the write. */ + if (H5Fflush_async(file_id, H5F_SCOPE_LOCAL, es_id) < 0) + PART_TEST_ERROR(multi_dset_open); + + /* Loop over datasets */ + for (i = 0; i < MULTI_DATASET_IO_TEST_NDSETS; i++) { + buf_start_idx = i * (data_size / MULTI_DATASET_IO_TEST_NDSETS / sizeof(int)); + + /* Read the dataset asynchronously */ + if (H5Dread_async(dset_id[i], H5T_NATIVE_INT, mspace_id, space_id, H5P_DEFAULT, + &read_buf[buf_start_idx], es_id) < 0) + PART_TEST_ERROR(multi_dset_open); + } /* end for */ + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + PART_TEST_ERROR(multi_dset_open); + if (op_failed) + PART_TEST_ERROR(multi_dset_open); + + /* Verify the read data */ + for (i = 0; i < data_size / sizeof(int); i++) + if (write_buf[i] != read_buf[i]) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + PART_ERROR(multi_dset_open); + } /* end if */ + + /* Close the datasets */ + for (i = 0; i < MULTI_DATASET_IO_TEST_NDSETS; i++) + if (H5Dclose(dset_id[i]) < 0) + PART_TEST_ERROR(multi_dset_open); + + PASSED(); + } + PART_END(multi_dset_open); + + PART_BEGIN(multi_dset_close) + { + size_t buf_start_idx; + + TESTING_2("closing datasets between I/O"); + + /* Loop over datasets */ + for (i = 0; i < MULTI_DATASET_IO_TEST_NDSETS; i++) { + size_t buf_end_idx; + + /* Set dataset name */ + sprintf(dset_name, "dset%d", (int)i); + + /* Open the dataset asynchronously */ + if ((dset_id[0] = H5Dopen_async(file_id, dset_name, H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_dset_close); + + /* Initialize write_buf. */ + buf_start_idx = i * (data_size / MULTI_DATASET_IO_TEST_NDSETS / sizeof(int)); + buf_end_idx = buf_start_idx + (data_size / MULTI_DATASET_IO_TEST_NDSETS / sizeof(int)); + for (j = buf_start_idx; j < buf_end_idx; j++) + ((int *)write_buf)[j] = mpi_rank * 10; + + /* Write the dataset asynchronously */ + if (H5Dwrite_async(dset_id[0], H5T_NATIVE_INT, mspace_id, space_id, H5P_DEFAULT, + &write_buf[buf_start_idx], es_id) < 0) + PART_TEST_ERROR(multi_dset_close); + + /* Close the dataset asynchronously */ + if (H5Dclose_async(dset_id[0], es_id) < 0) + PART_TEST_ERROR(multi_dset_close); + } /* end for */ + + /* Flush the file asynchronously. This will effectively work as a + * barrier, guaranteeing the read takes place after the write. */ + if (H5Fflush_async(file_id, H5F_SCOPE_LOCAL, es_id) < 0) + PART_TEST_ERROR(multi_dset_close); + + /* Loop over datasets */ + for (i = 0; i < MULTI_DATASET_IO_TEST_NDSETS; i++) { + /* Set dataset name */ + sprintf(dset_name, "dset%d", (int)i); + + /* Open the dataset asynchronously */ + if ((dset_id[0] = H5Dopen_async(file_id, dset_name, H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_dset_close); + + /* Read the dataset asynchronously */ + buf_start_idx = i * (data_size / MULTI_DATASET_IO_TEST_NDSETS / sizeof(int)); + if (H5Dread_async(dset_id[0], H5T_NATIVE_INT, mspace_id, space_id, H5P_DEFAULT, + &read_buf[buf_start_idx], es_id) < 0) + PART_TEST_ERROR(multi_dset_close); + + /* Close the dataset asynchronously */ + if (H5Dclose_async(dset_id[0], es_id) < 0) + PART_TEST_ERROR(multi_dset_close); + } /* end for */ + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + PART_TEST_ERROR(multi_dset_close); + if (op_failed) + PART_TEST_ERROR(multi_dset_close); + + /* Verify the read data */ + for (i = 0; i < data_size / sizeof(int); i++) + if (write_buf[i] != read_buf[i]) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + PART_ERROR(multi_dset_close); + } /* end if */ + + PASSED(); + } + PART_END(multi_dset_close); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + + if (dims) { + HDfree(dims); + dims = NULL; + } + + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Sclose(mspace_id) < 0) + TEST_ERROR; + if (H5ESclose(es_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (read_buf) + HDfree(read_buf); + if (write_buf) + HDfree(write_buf); + if (dims) + HDfree(dims); + H5Sclose(space_id); + H5Sclose(mspace_id); + for (i = 0; i < MULTI_DATASET_IO_TEST_NDSETS; i++) + H5Dclose(dset_id[i]); + H5Pclose(fapl_id); + H5Fclose(file_id); + H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed); + H5ESclose(es_id); + } + H5E_END_TRY; + + return 1; +} +#undef MULTI_DATASET_IO_TEST_SPACE_RANK +#undef MULTI_DATASET_IO_TEST_NDSETS + +/* + * Create multiple files, each with a single dataset. Each rank writes + * to a portion of each dataset and reads from a portion of each dataset. + */ +#define MULTI_FILE_DATASET_IO_TEST_SPACE_RANK 2 +#define MULTI_FILE_DATASET_IO_TEST_NFILES 5 +static int +test_multi_file_dataset_io(void) +{ + hsize_t *dims = NULL; + hsize_t start[MULTI_FILE_DATASET_IO_TEST_SPACE_RANK]; + hsize_t stride[MULTI_FILE_DATASET_IO_TEST_SPACE_RANK]; + hsize_t count[MULTI_FILE_DATASET_IO_TEST_SPACE_RANK]; + hsize_t block[MULTI_FILE_DATASET_IO_TEST_SPACE_RANK]; + hbool_t op_failed = false; + hbool_t is_native_vol = false; + size_t i, j, data_size, num_in_progress; + hid_t fapl_id = H5I_INVALID_HID; + hid_t file_id[MULTI_FILE_DATASET_IO_TEST_NFILES] = {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, + H5I_INVALID_HID, H5I_INVALID_HID}; + hid_t dset_id[MULTI_FILE_DATASET_IO_TEST_NFILES] = {H5I_INVALID_HID, H5I_INVALID_HID, H5I_INVALID_HID, + H5I_INVALID_HID, H5I_INVALID_HID}; + hid_t space_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + hid_t es_id = H5I_INVALID_HID; + char file_name[32]; + int *write_buf = NULL; + int *read_buf = NULL; + + TESTING_MULTIPART("multi file dataset I/O") + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH)) { + if (MAINPROCESS) { + SKIPPED(); + HDprintf( + " API functions for basic file, dataset, or flush aren't supported with this connector\n"); + } + + return 0; + } + + TESTING_2("test setup"); + + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, coll_metadata_read)) < 0) + TEST_ERROR; + + /* Create dataspace */ + if (generate_random_parallel_dimensions(MULTI_FILE_DATASET_IO_TEST_SPACE_RANK, &dims) < 0) + TEST_ERROR; + + /* Create dataspace */ + if ((space_id = H5Screate_simple(MULTI_FILE_DATASET_IO_TEST_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + + /* Create event stack */ + if ((es_id = H5EScreate()) < 0) + TEST_ERROR; + + /* Calculate size of data buffers - first dimension is skipped in calculation */ + for (i = 1, data_size = 1; i < MULTI_FILE_DATASET_IO_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= sizeof(int); + data_size *= MULTI_FILE_DATASET_IO_TEST_NFILES; + + if (NULL == (write_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + TEST_ERROR; + } + + if (NULL == (read_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + TEST_ERROR; + } + + /* Select this rank's portion of the dataspace */ + for (i = 0; i < MULTI_FILE_DATASET_IO_TEST_SPACE_RANK; i++) { + if (i == 0) { + start[i] = (hsize_t)mpi_rank; + block[i] = 1; + } + else { + start[i] = 0; + block[i] = dims[i]; + } + + stride[i] = 1; + count[i] = 1; + } + + if (H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start, stride, count, block) < 0) { + H5_FAILED(); + HDprintf(" couldn't select hyperslab for dataset write\n"); + goto error; + } + + /* Setup memory space for write_buf */ + { + hsize_t mdims[] = {data_size / MULTI_FILE_DATASET_IO_TEST_NFILES / sizeof(int)}; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + goto error; + } + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(multi_file_dset_open) + { + size_t buf_start_idx; + + TESTING_2("keeping files and datasets open"); + + /* Loop over files */ + for (i = 0; i < MULTI_FILE_DATASET_IO_TEST_NFILES; i++) { + size_t buf_end_idx; + + /* Set file name */ + sprintf(file_name, PAR_ASYNC_API_TEST_FILE_PRINTF, (int)i); + + /* Create file asynchronously */ + if ((file_id[i] = H5Fcreate_async(file_name, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id, es_id)) < 0) + PART_TEST_ERROR(multi_file_dset_open); + if ((int)i > max_printf_file) + max_printf_file = (int)i; + + /* Create the dataset asynchronously */ + if ((dset_id[i] = H5Dcreate_async(file_id[i], "dset", H5T_NATIVE_INT, space_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_file_dset_open); + + /* Initialize write_buf. Must use a new slice of write_buf for + * each dset since we can't overwrite the buffers until I/O is done. */ + buf_start_idx = i * (data_size / MULTI_FILE_DATASET_IO_TEST_NFILES / sizeof(int)); + buf_end_idx = buf_start_idx + (data_size / MULTI_FILE_DATASET_IO_TEST_NFILES / sizeof(int)); + for (j = buf_start_idx; j < buf_end_idx; j++) + ((int *)write_buf)[j] = mpi_rank; + + /* Write the dataset asynchronously */ + if (H5Dwrite_async(dset_id[i], H5T_NATIVE_INT, mspace_id, space_id, H5P_DEFAULT, + &write_buf[buf_start_idx], es_id) < 0) + PART_TEST_ERROR(multi_file_dset_open); + } /* end for */ + + /* Find out if the native connector is used */ + if (H5VLobject_is_native(file_id[0], &is_native_vol) < 0) + PART_TEST_ERROR(multi_file_dset_open); + + /* Loop over files */ + for (i = 0; i < MULTI_FILE_DATASET_IO_TEST_NFILES; i++) { + /* Flush the dataset asynchronously. This will effectively work as a + * barrier, guaranteeing the read takes place after the write. Skip this + * function because it isn't supported for the native vol in parallel. */ + if (!is_native_vol && H5Oflush_async(dset_id[i], es_id) < 0) + PART_TEST_ERROR(multi_file_dset_open); + + /* Read the dataset asynchronously */ + buf_start_idx = i * (data_size / MULTI_FILE_DATASET_IO_TEST_NFILES / sizeof(int)); + if (H5Dread_async(dset_id[i], H5T_NATIVE_INT, mspace_id, space_id, H5P_DEFAULT, + &read_buf[buf_start_idx], es_id) < 0) + PART_TEST_ERROR(multi_file_dset_open); + } /* end for */ + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + PART_TEST_ERROR(multi_file_dset_open); + if (op_failed) + PART_TEST_ERROR(multi_file_dset_open); + + /* Verify the read data */ + for (i = 0; i < data_size / sizeof(int); i++) + if (write_buf[i] != read_buf[i]) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + PART_ERROR(multi_file_dset_open); + } /* end if */ + + /* Close the datasets */ + for (i = 0; i < MULTI_FILE_DATASET_IO_TEST_NFILES; i++) + if (H5Dclose(dset_id[i]) < 0) + PART_TEST_ERROR(multi_file_dset_open); + + PASSED(); + } + PART_END(multi_file_dset_open); + + PART_BEGIN(multi_file_dset_dclose) + { + size_t buf_start_idx; + + TESTING_2("closing datasets between I/O"); + + /* Loop over files */ + for (i = 0; i < MULTI_FILE_DATASET_IO_TEST_NFILES; i++) { + size_t buf_end_idx; + + /* Open the dataset asynchronously */ + if ((dset_id[0] = H5Dopen_async(file_id[i], "dset", H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_file_dset_dclose); + + /* Initialize write_buf. */ + buf_start_idx = i * (data_size / MULTI_FILE_DATASET_IO_TEST_NFILES / sizeof(int)); + buf_end_idx = buf_start_idx + (data_size / MULTI_FILE_DATASET_IO_TEST_NFILES / sizeof(int)); + for (j = buf_start_idx; j < buf_end_idx; j++) + ((int *)write_buf)[j] = mpi_rank * 10; + + /* Write the dataset asynchronously */ + if (H5Dwrite_async(dset_id[0], H5T_NATIVE_INT, mspace_id, space_id, H5P_DEFAULT, + &write_buf[buf_start_idx], es_id) < 0) + PART_TEST_ERROR(multi_file_dset_dclose); + + /* Close the dataset asynchronously */ + if (H5Dclose_async(dset_id[0], es_id) < 0) + PART_TEST_ERROR(multi_file_dset_dclose); + } /* end for */ + + /* Loop over files */ + for (i = 0; i < MULTI_FILE_DATASET_IO_TEST_NFILES; i++) { + /* Flush the file asynchronously. This will effectively work as a + * barrier, guaranteeing the read takes place after the write. */ + if (H5Fflush_async(file_id[i], H5F_SCOPE_LOCAL, es_id) < 0) + PART_TEST_ERROR(multi_file_dset_open); + + /* Open the dataset asynchronously */ + if ((dset_id[0] = H5Dopen_async(file_id[i], "dset", H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_file_dset_dclose); + + /* Read the dataset asynchronously */ + buf_start_idx = i * (data_size / MULTI_FILE_DATASET_IO_TEST_NFILES / sizeof(int)); + if (H5Dread_async(dset_id[0], H5T_NATIVE_INT, mspace_id, space_id, H5P_DEFAULT, + &read_buf[buf_start_idx], es_id) < 0) + PART_TEST_ERROR(multi_file_dset_dclose); + + /* Close the dataset asynchronously */ + if (H5Dclose_async(dset_id[0], es_id) < 0) + PART_TEST_ERROR(multi_file_dset_dclose); + } /* end for */ + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + PART_TEST_ERROR(multi_file_dset_dclose); + if (op_failed) + PART_TEST_ERROR(multi_file_dset_dclose); + + /* Verify the read data */ + for (i = 0; i < data_size / sizeof(int); i++) + if (write_buf[i] != read_buf[i]) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + PART_ERROR(multi_file_dset_dclose); + } /* end if */ + + /* Close the files */ + for (i = 0; i < MULTI_FILE_DATASET_IO_TEST_NFILES; i++) + if (H5Fclose(file_id[i]) < 0) + PART_TEST_ERROR(multi_file_dset_dclose); + + PASSED(); + } + PART_END(multi_file_dset_dclose); + + PART_BEGIN(multi_file_dset_fclose) + { + size_t buf_start_idx; + + TESTING_2("closing files between I/O"); + + /* Loop over files */ + for (i = 0; i < MULTI_FILE_DATASET_IO_TEST_NFILES; i++) { + size_t buf_end_idx; + + /* Set file name */ + sprintf(file_name, PAR_ASYNC_API_TEST_FILE_PRINTF, (int)i); + + /* Open the file asynchronously */ + if ((file_id[0] = H5Fopen_async(file_name, H5F_ACC_RDWR, fapl_id, es_id)) < 0) + PART_TEST_ERROR(multi_file_dset_fclose); + + /* Open the dataset asynchronously */ + if ((dset_id[0] = H5Dopen_async(file_id[0], "dset", H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_file_dset_fclose); + + /* Initialize write_buf. */ + buf_start_idx = i * (data_size / MULTI_FILE_DATASET_IO_TEST_NFILES / sizeof(int)); + buf_end_idx = buf_start_idx + (data_size / MULTI_FILE_DATASET_IO_TEST_NFILES / sizeof(int)); + for (j = buf_start_idx; j < buf_end_idx; j++) + ((int *)write_buf)[j] = mpi_rank + 5; + + /* Write the dataset asynchronously */ + if (H5Dwrite_async(dset_id[0], H5T_NATIVE_INT, mspace_id, space_id, H5P_DEFAULT, + &write_buf[buf_start_idx], es_id) < 0) + PART_TEST_ERROR(multi_file_dset_fclose); + + /* Close the dataset asynchronously */ + if (H5Dclose_async(dset_id[0], es_id) < 0) + PART_TEST_ERROR(multi_file_dset_fclose); + + /* Close the file asynchronously */ + if (H5Fclose_async(file_id[0], es_id) < 0) + PART_TEST_ERROR(multi_file_dset_fclose); + } /* end for */ + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + PART_TEST_ERROR(multi_file_dset_fclose); + if (op_failed) + PART_TEST_ERROR(multi_file_dset_fclose); + + /* Loop over files */ + for (i = 0; i < MULTI_FILE_DATASET_IO_TEST_NFILES; i++) { + /* Set file name */ + sprintf(file_name, PAR_ASYNC_API_TEST_FILE_PRINTF, (int)i); + + /* Open the file asynchronously */ + if ((file_id[0] = H5Fopen_async(file_name, H5F_ACC_RDONLY, fapl_id, es_id)) < 0) + PART_TEST_ERROR(multi_file_dset_fclose); + + /* Open the dataset asynchronously */ + if ((dset_id[0] = H5Dopen_async(file_id[0], "dset", H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_file_dset_fclose); + + /* Read the dataset asynchronously */ + buf_start_idx = i * (data_size / MULTI_FILE_DATASET_IO_TEST_NFILES / sizeof(int)); + if (H5Dread_async(dset_id[0], H5T_NATIVE_INT, mspace_id, space_id, H5P_DEFAULT, + &read_buf[buf_start_idx], es_id) < 0) + PART_TEST_ERROR(multi_file_dset_fclose); + + /* Close the dataset asynchronously */ + if (H5Dclose_async(dset_id[0], es_id) < 0) + PART_TEST_ERROR(multi_file_dset_fclose); + + /* Close the file asynchronously */ + if (H5Fclose_async(file_id[0], es_id) < 0) + PART_TEST_ERROR(multi_file_dset_fclose); + } /* end for */ + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + PART_TEST_ERROR(multi_file_dset_fclose); + if (op_failed) + PART_TEST_ERROR(multi_file_dset_fclose); + + /* Verify the read data */ + for (i = 0; i < data_size / sizeof(int); i++) + if (write_buf[i] != read_buf[i]) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + PART_ERROR(multi_file_dset_fclose); + } /* end if */ + + PASSED(); + } + PART_END(multi_file_dset_fclose); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + + if (dims) { + HDfree(dims); + dims = NULL; + } + + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Sclose(mspace_id) < 0) + TEST_ERROR; + if (H5ESclose(es_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (read_buf) + HDfree(read_buf); + if (write_buf) + HDfree(write_buf); + if (dims) + HDfree(dims); + H5Sclose(space_id); + H5Sclose(mspace_id); + for (i = 0; i < MULTI_FILE_DATASET_IO_TEST_NFILES; i++) { + H5Dclose(dset_id[i]); + H5Fclose(file_id[i]); + } + H5Pclose(fapl_id); + H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed); + H5ESclose(es_id); + } + H5E_END_TRY; + + return 1; +} +#undef MULTI_FILE_DATASET_IO_TEST_SPACE_RANK +#undef MULTI_FILE_DATASET_IO_TEST_NFILES + +/* + * Create multiple files, each with a single group and dataset. Each rank + * writes to a portion of each dataset and reads from a portion of each dataset. + */ +#define MULTI_FILE_GRP_DSET_IO_TEST_SPACE_RANK 2 +#define MULTI_FILE_GRP_DSET_IO_TEST_NFILES 5 +static int +test_multi_file_grp_dset_io(void) +{ + hsize_t *dims = NULL; + hsize_t start[MULTI_FILE_GRP_DSET_IO_TEST_SPACE_RANK]; + hsize_t stride[MULTI_FILE_GRP_DSET_IO_TEST_SPACE_RANK]; + hsize_t count[MULTI_FILE_GRP_DSET_IO_TEST_SPACE_RANK]; + hsize_t block[MULTI_FILE_GRP_DSET_IO_TEST_SPACE_RANK]; + hbool_t op_failed; + size_t i, j, data_size, num_in_progress; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t grp_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + hid_t es_id = H5I_INVALID_HID; + char file_name[32]; + int *write_buf = NULL; + int *read_buf = NULL; + + TESTING_MULTIPART("multi file dataset I/O with groups") + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + if (MAINPROCESS) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + } + + return 0; + } + + TESTING_2("test setup"); + + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, coll_metadata_read)) < 0) + TEST_ERROR; + + /* Create dataspace */ + if (generate_random_parallel_dimensions(MULTI_FILE_GRP_DSET_IO_TEST_SPACE_RANK, &dims) < 0) + TEST_ERROR; + + /* Create dataspace */ + if ((space_id = H5Screate_simple(MULTI_FILE_GRP_DSET_IO_TEST_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + + /* Create event stack */ + if ((es_id = H5EScreate()) < 0) + TEST_ERROR; + + /* Calculate size of data buffers - first dimension is skipped in calculation */ + for (i = 1, data_size = 1; i < MULTI_FILE_GRP_DSET_IO_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= sizeof(int); + data_size *= MULTI_FILE_GRP_DSET_IO_TEST_NFILES; + + if (NULL == (write_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + TEST_ERROR; + } + + if (NULL == (read_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + TEST_ERROR; + } + + /* Select this rank's portion of the dataspace */ + for (i = 0; i < MULTI_FILE_GRP_DSET_IO_TEST_SPACE_RANK; i++) { + if (i == 0) { + start[i] = (hsize_t)mpi_rank; + block[i] = 1; + } + else { + start[i] = 0; + block[i] = dims[i]; + } + + stride[i] = 1; + count[i] = 1; + } + + if (H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start, stride, count, block) < 0) { + H5_FAILED(); + HDprintf(" couldn't select hyperslab for dataset write\n"); + goto error; + } + + /* Setup memory space for write_buf */ + { + hsize_t mdims[] = {data_size / MULTI_FILE_GRP_DSET_IO_TEST_NFILES / sizeof(int)}; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + goto error; + } + } + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(multi_file_grp_dset_no_kick) + { + size_t buf_start_idx; + + TESTING_2("without intermediate calls to H5ESwait()"); + + /* Loop over files */ + for (i = 0; i < MULTI_FILE_GRP_DSET_IO_TEST_NFILES; i++) { + size_t buf_end_idx; + + /* Set file name */ + sprintf(file_name, PAR_ASYNC_API_TEST_FILE_PRINTF, (int)i); + + /* Create file asynchronously */ + if ((file_id = H5Fcreate_async(file_name, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id, es_id)) < 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + if ((int)i > max_printf_file) + max_printf_file = (int)i; + + /* Create the group asynchronously */ + if ((grp_id = H5Gcreate_async(file_id, "grp", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT, es_id)) < + 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + + /* Create the dataset asynchronously */ + if ((dset_id = H5Dcreate_async(grp_id, "dset", H5T_NATIVE_INT, space_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + + /* Initialize write_buf. Must use a new slice of write_buf for + * each dset since we can't overwrite the buffers until I/O is done. */ + buf_start_idx = i * (data_size / MULTI_FILE_GRP_DSET_IO_TEST_NFILES / sizeof(int)); + buf_end_idx = buf_start_idx + (data_size / MULTI_FILE_GRP_DSET_IO_TEST_NFILES / sizeof(int)); + for (j = buf_start_idx; j < buf_end_idx; j++) + ((int *)write_buf)[j] = mpi_rank; + + /* Write the dataset asynchronously */ + if (H5Dwrite_async(dset_id, H5T_NATIVE_INT, mspace_id, space_id, H5P_DEFAULT, + &write_buf[buf_start_idx], es_id) < 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + + /* Close the dataset asynchronously */ + if (H5Dclose_async(dset_id, es_id) < 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + + /* Close the group asynchronously */ + if (H5Gclose_async(grp_id, es_id) < 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + + /* Close the file asynchronously */ + if (H5Fclose_async(file_id, es_id) < 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + } /* end for */ + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + if (op_failed) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + + /* Loop over files */ + for (i = 0; i < MULTI_FILE_GRP_DSET_IO_TEST_NFILES; i++) { + /* Set file name */ + sprintf(file_name, PAR_ASYNC_API_TEST_FILE_PRINTF, (int)i); + + /* Open the file asynchronously */ + if ((file_id = H5Fopen_async(file_name, H5F_ACC_RDONLY, fapl_id, es_id)) < 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + + /* Open the group asynchronously */ + if ((grp_id = H5Gopen_async(file_id, "grp", H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + + /* Open the dataset asynchronously */ + if ((dset_id = H5Dopen_async(grp_id, "dset", H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + + /* Read the dataset asynchronously */ + buf_start_idx = i * (data_size / MULTI_FILE_GRP_DSET_IO_TEST_NFILES / sizeof(int)); + if (H5Dread_async(dset_id, H5T_NATIVE_INT, mspace_id, space_id, H5P_DEFAULT, + &read_buf[buf_start_idx], es_id) < 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + + /* Close the dataset asynchronously */ + if (H5Dclose_async(dset_id, es_id) < 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + + /* Close the group asynchronously */ + if (H5Gclose_async(grp_id, es_id) < 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + + /* Close the file asynchronously */ + if (H5Fclose_async(file_id, es_id) < 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + } /* end for */ + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + if (op_failed) + PART_TEST_ERROR(multi_file_grp_dset_no_kick); + + /* Verify the read data */ + for (i = 0; i < data_size / sizeof(int); i++) + if (write_buf[i] != read_buf[i]) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + PART_ERROR(multi_file_grp_dset_no_kick); + } /* end if */ + + PASSED(); + } + PART_END(multi_file_grp_dset_no_kick); + + PART_BEGIN(multi_file_grp_dset_kick) + { + size_t buf_start_idx; + + TESTING_2("with intermediate calls to H5ESwait() (0 timeout)"); + + /* Loop over files */ + for (i = 0; i < MULTI_FILE_GRP_DSET_IO_TEST_NFILES; i++) { + size_t buf_end_idx; + + /* Set file name */ + sprintf(file_name, PAR_ASYNC_API_TEST_FILE_PRINTF, (int)i); + + /* Create file asynchronously */ + if ((file_id = H5Fcreate_async(file_name, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id, es_id)) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + if ((int)i > max_printf_file) + max_printf_file = (int)i; + + /* Create the group asynchronously */ + if ((grp_id = H5Gcreate_async(file_id, "grp", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT, es_id)) < + 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + + /* Create the dataset asynchronously */ + if ((dset_id = H5Dcreate_async(grp_id, "dset", H5T_NATIVE_INT, space_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + + /* Initialize write_buf. Must use a new slice of write_buf for + * each dset since we can't overwrite the buffers until I/O is done. */ + buf_start_idx = i * (data_size / MULTI_FILE_GRP_DSET_IO_TEST_NFILES / sizeof(int)); + buf_end_idx = buf_start_idx + (data_size / MULTI_FILE_GRP_DSET_IO_TEST_NFILES / sizeof(int)); + for (j = buf_start_idx; j < buf_end_idx; j++) + ((int *)write_buf)[j] = mpi_rank; + + /* Write the dataset asynchronously */ + if (H5Dwrite_async(dset_id, H5T_NATIVE_INT, mspace_id, space_id, H5P_DEFAULT, + &write_buf[buf_start_idx], es_id) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + + /* Close the dataset asynchronously */ + if (H5Dclose_async(dset_id, es_id) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + + /* Close the group asynchronously */ + if (H5Gclose_async(grp_id, es_id) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + + /* Close the file asynchronously */ + if (H5Fclose_async(file_id, es_id) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + + /* Kick the event stack to make progress */ + if (H5ESwait(es_id, 0, &num_in_progress, &op_failed) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + if (op_failed) + PART_TEST_ERROR(multi_file_grp_dset_kick); + } /* end for */ + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + if (op_failed) + PART_TEST_ERROR(multi_file_grp_dset_kick); + + /* Loop over files */ + for (i = 0; i < MULTI_FILE_GRP_DSET_IO_TEST_NFILES; i++) { + /* Set file name */ + sprintf(file_name, PAR_ASYNC_API_TEST_FILE_PRINTF, (int)i); + + /* Open the file asynchronously */ + if ((file_id = H5Fopen_async(file_name, H5F_ACC_RDONLY, fapl_id, es_id)) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + + /* Open the group asynchronously */ + if ((grp_id = H5Gopen_async(file_id, "grp", H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + + /* Open the dataset asynchronously */ + if ((dset_id = H5Dopen_async(grp_id, "dset", H5P_DEFAULT, es_id)) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + + /* Read the dataset asynchronously */ + buf_start_idx = i * (data_size / MULTI_FILE_GRP_DSET_IO_TEST_NFILES / sizeof(int)); + if (H5Dread_async(dset_id, H5T_NATIVE_INT, mspace_id, space_id, H5P_DEFAULT, + &read_buf[buf_start_idx], es_id) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + + /* Close the dataset asynchronously */ + if (H5Dclose_async(dset_id, es_id) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + + /* Close the group asynchronously */ + if (H5Gclose_async(grp_id, es_id) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + + /* Close the file asynchronously */ + if (H5Fclose_async(file_id, es_id) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + + /* Kick the event stack to make progress */ + if (H5ESwait(es_id, 0, &num_in_progress, &op_failed) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + if (op_failed) + PART_TEST_ERROR(multi_file_grp_dset_kick); + } /* end for */ + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + PART_TEST_ERROR(multi_file_grp_dset_kick); + if (op_failed) + PART_TEST_ERROR(multi_file_grp_dset_kick); + + /* Verify the read data */ + for (i = 0; i < data_size / sizeof(int); i++) + if (write_buf[i] != read_buf[i]) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + PART_ERROR(multi_file_grp_dset_kick); + } /* end if */ + + PASSED(); + } + PART_END(multi_file_grp_dset_kick); + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + + if (dims) { + HDfree(dims); + dims = NULL; + } + + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Sclose(mspace_id) < 0) + TEST_ERROR; + if (H5ESclose(es_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (read_buf) + HDfree(read_buf); + if (write_buf) + HDfree(write_buf); + if (dims) + HDfree(dims); + H5Sclose(space_id); + H5Sclose(mspace_id); + H5Dclose(dset_id); + H5Gclose(grp_id); + H5Fclose(file_id); + H5Pclose(fapl_id); + H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed); + H5ESclose(es_id); + } + H5E_END_TRY; + + return 1; +} +#undef MULTI_FILE_GRP_DSET_IO_TEST_SPACE_RANK +#undef MULTI_FILE_GRP_DSET_IO_TEST_NFILES + +/* + * Creates a single file and dataset, then each rank writes to a portion + * of the dataset. Next, the dataset is continually extended in the first + * dimension by 1 "row" per mpi rank and partially written to by each rank. + * Finally, each rank reads from a portion of the dataset. + */ +#define SET_EXTENT_TEST_SPACE_RANK 2 +#define SET_EXTENT_TEST_NUM_EXTENDS 6 +static int +test_set_extent(void) +{ + hsize_t *dims = NULL; + hsize_t *maxdims = NULL; + hsize_t *cdims = NULL; + hsize_t start[SET_EXTENT_TEST_SPACE_RANK]; + hsize_t stride[SET_EXTENT_TEST_SPACE_RANK]; + hsize_t count[SET_EXTENT_TEST_SPACE_RANK]; + hsize_t block[SET_EXTENT_TEST_SPACE_RANK]; + hbool_t op_failed = false; + hbool_t is_native_vol = false; + size_t i, j, data_size, num_in_progress; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dcpl_id = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + hid_t space_id_out = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + hid_t es_id = H5I_INVALID_HID; + htri_t tri_ret; + int *write_buf = NULL; + int *read_buf = NULL; + + TESTING("extending dataset"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAINPROCESS) { + SKIPPED(); + HDprintf(" API functions for basic file, dataset, dataset more, or flush aren't supported " + "with this connector\n"); + } + + return 0; + } + + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, coll_metadata_read)) < 0) + TEST_ERROR; + + /* Create dataspace */ + if (generate_random_parallel_dimensions(SET_EXTENT_TEST_SPACE_RANK, &dims) < 0) + TEST_ERROR; + + if (NULL == (maxdims = HDmalloc(SET_EXTENT_TEST_SPACE_RANK * sizeof(hsize_t)))) { + H5_FAILED(); + HDprintf(" couldn't allocate max dataspace dimension buffer\n"); + TEST_ERROR; + } + + if (NULL == (cdims = HDmalloc(SET_EXTENT_TEST_SPACE_RANK * sizeof(hsize_t)))) { + H5_FAILED(); + HDprintf(" couldn't allocate chunk dimension buffer\n"); + TEST_ERROR; + } + + for (i = 0; i < SET_EXTENT_TEST_SPACE_RANK; i++) { + maxdims[i] = (i == 0) ? dims[i] + (hsize_t)(SET_EXTENT_TEST_NUM_EXTENDS * mpi_size) : dims[i]; + cdims[i] = (dims[i] == 1) ? 1 : dims[i] / 2; + } + + /* Create file dataspace */ + if ((space_id = H5Screate_simple(SET_EXTENT_TEST_SPACE_RANK, dims, maxdims)) < 0) + TEST_ERROR; + + /* Create DCPL */ + if ((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) + TEST_ERROR; + + /* Set chunking */ + if (H5Pset_chunk(dcpl_id, SET_EXTENT_TEST_SPACE_RANK, cdims) < 0) + TEST_ERROR; + + /* Create event stack */ + if ((es_id = H5EScreate()) < 0) + TEST_ERROR; + + /* Create file asynchronously */ + if ((file_id = H5Fcreate_async(PAR_ASYNC_API_TEST_FILE, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id, es_id)) < 0) + TEST_ERROR; + + /* Find out if the native connector is used */ + if (H5VLobject_is_native(file_id, &is_native_vol) < 0) + TEST_ERROR; + + /* Create the dataset asynchronously */ + if ((dset_id = H5Dcreate_async(file_id, "dset", H5T_NATIVE_INT, space_id, H5P_DEFAULT, dcpl_id, + H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Calculate size of data buffers - first dimension is skipped in calculation */ + for (i = 1, data_size = 1; i < SET_EXTENT_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= sizeof(int); + data_size *= SET_EXTENT_TEST_NUM_EXTENDS; + + if (NULL == (write_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + TEST_ERROR; + } + + if (NULL == (read_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + TEST_ERROR; + } + + /* Select this rank's portion of the dataspace */ + for (i = 0; i < SET_EXTENT_TEST_SPACE_RANK; i++) { + if (i == 0) { + start[i] = (hsize_t)mpi_rank; + block[i] = 1; + } + else { + start[i] = 0; + block[i] = dims[i]; + } + + stride[i] = 1; + count[i] = 1; + } + + if (H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start, stride, count, block) < 0) { + H5_FAILED(); + HDprintf(" couldn't select hyperslab for dataset write\n"); + goto error; + } + + /* Setup memory space for write_buf */ + { + hsize_t mdims[] = {data_size / SET_EXTENT_TEST_NUM_EXTENDS / sizeof(int)}; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + goto error; + } + } + + /* Initialize write_buf */ + for (i = 0; i < data_size / sizeof(int); i++) + ((int *)write_buf)[i] = mpi_rank; + + /* Extend the dataset in the first dimension n times, extending by 1 "row" per + * mpi rank involved on each iteration. Each rank will claim one of the new + * "rows" for I/O in an interleaved fashion. */ + for (i = 0; i < SET_EXTENT_TEST_NUM_EXTENDS; i++) { + /* No need to extend on the first iteration */ + if (i) { + /* Extend datapace */ + dims[0] += (hsize_t)mpi_size; + if (H5Sset_extent_simple(space_id, SET_EXTENT_TEST_SPACE_RANK, dims, maxdims) < 0) + TEST_ERROR; + + /* Extend dataset asynchronously */ + if (H5Dset_extent_async(dset_id, dims, es_id) < 0) + TEST_ERROR; + + /* Select hyperslab in file space to match new region */ + for (j = 0; j < SET_EXTENT_TEST_SPACE_RANK; j++) { + if (j == 0) { + start[j] = (hsize_t)mpi_rank; + block[j] = 1; + stride[j] = (hsize_t)mpi_size; + count[j] = i + 1; + } + else { + start[j] = 0; + block[j] = dims[j]; + stride[j] = 1; + count[j] = 1; + } + } + + if (H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start, stride, count, block) < 0) { + H5_FAILED(); + HDprintf(" couldn't select hyperslab for dataset write\n"); + goto error; + } + + /* Adjust memory dataspace to match as well */ + { + hsize_t mdims[] = {(i + 1) * (data_size / SET_EXTENT_TEST_NUM_EXTENDS / sizeof(int))}; + + if (H5Sset_extent_simple(mspace_id, 1, mdims, NULL) < 0) + TEST_ERROR; + + if (H5Sselect_all(mspace_id) < 0) + TEST_ERROR; + } + } /* end if */ + + /* Get dataset dataspace */ + if ((space_id_out = H5Dget_space_async(dset_id, es_id)) < 0) + TEST_ERROR; + + /* Verify extent is correct */ + if ((tri_ret = H5Sextent_equal(space_id, space_id_out)) < 0) + TEST_ERROR; + if (!tri_ret) + FAIL_PUTS_ERROR(" dataspaces are not equal\n"); + + /* Close output dataspace */ + if (H5Sclose(space_id_out) < 0) + TEST_ERROR; + + /* Write the dataset slice asynchronously */ + if (H5Dwrite_async(dset_id, H5T_NATIVE_INT, mspace_id, space_id, H5P_DEFAULT, write_buf, es_id) < 0) + TEST_ERROR; + } + + /* Flush the dataset asynchronously. This will effectively work as a + * barrier, guaranteeing the read takes place after the write. Skip this + * function because it isn't supported for the native vol in parallel. */ + if (!is_native_vol && H5Oflush_async(dset_id, es_id) < 0) + TEST_ERROR; + + /* Read the entire dataset asynchronously */ + if (H5Dread_async(dset_id, H5T_NATIVE_INT, mspace_id, space_id, H5P_DEFAULT, read_buf, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Verify the read data */ + for (i = 0; i < data_size / sizeof(int); i++) + if (write_buf[i] != read_buf[i]) { + H5_FAILED(); + HDprintf(" data verification failed, expected %d but got %d\n", write_buf[i], read_buf[i]); + goto error; + } /* end if */ + + /* Close dataset asynchronously */ + if (H5Dclose_async(dset_id, es_id) < 0) + TEST_ERROR; + + /* Open dataset asynchronously */ + if ((dset_id = H5Dopen_async(file_id, "dset", H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Get dataset dataspace asynchronously */ + if ((space_id_out = H5Dget_space_async(dset_id, es_id)) < 0) + TEST_ERROR; + + /* Verify the extents match */ + if ((tri_ret = H5Sextent_equal(space_id, space_id_out)) < 0) + TEST_ERROR; + if (!tri_ret) + FAIL_PUTS_ERROR(" dataspaces are not equal\n"); + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + + if (cdims) { + HDfree(cdims); + cdims = NULL; + } + + if (maxdims) { + HDfree(maxdims); + maxdims = NULL; + } + + if (dims) { + HDfree(dims); + dims = NULL; + } + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Sclose(mspace_id) < 0) + TEST_ERROR; + if (H5Pclose(dcpl_id) < 0) + TEST_ERROR; + if (H5ESclose(es_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (read_buf) + HDfree(read_buf); + if (write_buf) + HDfree(write_buf); + if (cdims) + HDfree(cdims); + if (maxdims) + HDfree(maxdims); + if (dims) + HDfree(dims); + H5Sclose(space_id); + H5Sclose(mspace_id); + H5Sclose(space_id_out); + H5Dclose(dset_id); + H5Pclose(dcpl_id); + H5Fclose(file_id); + H5Pclose(fapl_id); + H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed); + H5ESclose(es_id); + } + H5E_END_TRY; + + return 1; +} +#undef SET_EXTENT_TEST_SPACE_RANK +#undef SET_EXTENT_TEST_NUM_EXTENDS + +/* + * Creates an attribute on a dataset. All ranks check to see + * if the attribute exists before and after creating the + * attribute on the dataset. + */ +#define ATTRIBUTE_EXISTS_TEST_SPACE_RANK 2 +static int +test_attribute_exists(void) +{ + hsize_t *dims = NULL; + hbool_t op_failed = false; + hbool_t is_native_vol = false; + size_t num_in_progress; + hbool_t exists1 = false; + hbool_t exists2 = false; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + hid_t es_id = H5I_INVALID_HID; + + TESTING("H5Aexists()"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + if (MAINPROCESS) { + SKIPPED(); + HDprintf(" API functions for basic file, dataset, dataset more, attribute, or flush aren't " + "supported with this connector\n"); + } + + return 0; + } + + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, coll_metadata_read)) < 0) + TEST_ERROR; + + /* Create dataspace */ + if (generate_random_parallel_dimensions(ATTRIBUTE_EXISTS_TEST_SPACE_RANK, &dims) < 0) + TEST_ERROR; + + /* Create dataspace */ + if ((space_id = H5Screate_simple(ATTRIBUTE_EXISTS_TEST_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + + /* Create event stack */ + if ((es_id = H5EScreate()) < 0) + TEST_ERROR; + + /* Open file asynchronously */ + if ((file_id = H5Fopen_async(PAR_ASYNC_API_TEST_FILE, H5F_ACC_RDWR, fapl_id, es_id)) < 0) + TEST_ERROR; + + /* Find out if the native connector is used */ + if (H5VLobject_is_native(file_id, &is_native_vol) < 0) + TEST_ERROR; + + /* Create the dataset asynchronously */ + if ((dset_id = H5Dcreate_async(file_id, "attr_exists_dset", H5T_NATIVE_INT, space_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Check if the attribute exists asynchronously */ + if (H5Aexists_async(dset_id, "attr", &exists1, es_id) < 0) + TEST_ERROR; + + /* Flush the dataset asynchronously. This will effectively work as a + * barrier, guaranteeing the create takes place after the existence check. + * Skip this function because it isn't supported for the native vol in parallel. + */ + if (!is_native_vol && H5Oflush_async(dset_id, es_id) < 0) + TEST_ERROR; + + /* Create the attribute asynchronously */ + if ((attr_id = + H5Acreate_async(dset_id, "attr", H5T_NATIVE_INT, space_id, H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Flush the dataset asynchronously. This will effectively work as a + * barrier, guaranteeing the existence check takes place after the create. + * Skip this function because it isn't supported for the native vol in parallel. + */ + if (!is_native_vol && H5Oflush_async(dset_id, es_id) < 0) + TEST_ERROR; + + /* Check if the attribute exists asynchronously */ + if (H5Aexists_async(dset_id, "attr", &exists2, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Check if H5Aexists returned the correct values */ + if (exists1) + FAIL_PUTS_ERROR(" H5Aexists returned TRUE for an attribute that should not exist") + if (!exists2) + FAIL_PUTS_ERROR(" H5Aexists returned FALSE for an attribute that should exist") + + /* Close */ + if (H5Aclose_async(attr_id, es_id) < 0) + TEST_ERROR; + if (H5Dclose_async(dset_id, es_id) < 0) + TEST_ERROR; + if (H5Fclose_async(file_id, es_id) < 0) + TEST_ERROR; + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5Sclose(space_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + if (dims) { + HDfree(dims); + dims = NULL; + } + + if (H5ESclose(es_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (dims) + HDfree(dims); + H5Sclose(space_id); + H5Aclose(attr_id); + H5Dclose(dset_id); + H5Pclose(fapl_id); + H5Fclose(file_id); + H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed); + H5ESclose(es_id); + } + H5E_END_TRY; + + return 1; +} +#undef ATTRIBUTE_EXISTS_TEST_SPACE_RANK + +/* + * Creates a file, dataset and attribute. Each rank writes to + * the attribute. Then, each rank reads the attribute and + * verifies the data is correct. + */ +#define ATTRIBUTE_IO_TEST_SPACE_RANK 2 +static int +test_attribute_io(void) +{ + hsize_t *dims = NULL; + hbool_t op_failed = false; + hbool_t is_native_vol = false; + size_t num_in_progress; + size_t i, data_size; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + hid_t es_id = H5I_INVALID_HID; + int *write_buf = NULL; + int *read_buf = NULL; + + TESTING("attribute I/O"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + if (MAINPROCESS) { + SKIPPED(); + HDprintf(" API functions for basic file, dataset, dataset more, attribute, or flush aren't " + "supported with this connector\n"); + } + + return 0; + } + + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, coll_metadata_read)) < 0) + TEST_ERROR; + + /* Create dataspace */ + if (generate_random_parallel_dimensions(ATTRIBUTE_IO_TEST_SPACE_RANK, &dims) < 0) + TEST_ERROR; + + /* Create dataspace */ + if ((space_id = H5Screate_simple(ATTRIBUTE_IO_TEST_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + + /* Create event stack */ + if ((es_id = H5EScreate()) < 0) + TEST_ERROR; + + /* Open file asynchronously */ + if ((file_id = H5Fopen_async(PAR_ASYNC_API_TEST_FILE, H5F_ACC_RDWR, fapl_id, es_id)) < 0) + TEST_ERROR; + + /* Find out if the native connector is used */ + if (H5VLobject_is_native(file_id, &is_native_vol) < 0) + TEST_ERROR; + + /* Create the dataset asynchronously */ + if ((dset_id = H5Dcreate_async(file_id, "attr_dset", H5T_NATIVE_INT, space_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Create the attribute asynchronously */ + if ((attr_id = + H5Acreate_async(dset_id, "attr", H5T_NATIVE_INT, space_id, H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Calculate size of data buffers */ + for (i = 0, data_size = 1; i < ATTRIBUTE_IO_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= sizeof(int); + + if (NULL == (write_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for attribute write\n"); + TEST_ERROR; + } + + if (NULL == (read_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for attribute read\n"); + TEST_ERROR; + } + + /* Initialize write_buf. */ + for (i = 0; i < data_size / sizeof(int); i++) + write_buf[i] = 10 * (int)i; + + /* Write the attribute asynchronously */ + if (H5Awrite_async(attr_id, H5T_NATIVE_INT, write_buf, es_id) < 0) + TEST_ERROR; + + /* Flush the dataset asynchronously. This will effectively work as a + * barrier, guaranteeing the read takes place after the write. + * Skip this function because it isn't supported for the native vol in parallel. + */ + if (!is_native_vol && H5Oflush_async(dset_id, es_id) < 0) + TEST_ERROR; + + /* Read the attribute asynchronously */ + if (H5Aread_async(attr_id, H5T_NATIVE_INT, read_buf, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Verify the read data */ + for (i = 0; i < data_size / sizeof(int); i++) + if (write_buf[i] != read_buf[i]) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + goto error; + } /* end if */ + + /* Close the attribute asynchronously */ + if (H5Aclose_async(attr_id, es_id) < 0) + TEST_ERROR; + + /* Open the attribute asynchronously */ + if ((attr_id = H5Aopen_async(dset_id, "attr", H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Read the attribute asynchronously */ + if (H5Aread_async(attr_id, H5T_NATIVE_INT, read_buf, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Verify the read data */ + for (i = 0; i < data_size / sizeof(int); i++) + if (write_buf[i] != read_buf[i]) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + goto error; + } /* end if */ + + /* Close out of order to see if it trips things up */ + if (H5Dclose_async(dset_id, es_id) < 0) + TEST_ERROR; + if (H5Aclose_async(attr_id, es_id) < 0) + TEST_ERROR; + if (H5Fclose_async(file_id, es_id) < 0) + TEST_ERROR; + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + + if (dims) { + HDfree(dims); + dims = NULL; + } + + if (H5ESclose(es_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (read_buf) + HDfree(read_buf); + if (write_buf) + HDfree(write_buf); + if (dims) + HDfree(dims); + H5Sclose(space_id); + H5Aclose(attr_id); + H5Dclose(dset_id); + H5Pclose(fapl_id); + H5Fclose(file_id); + H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed); + H5ESclose(es_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * Creates a file, dataset and attribute in parallel. Each rank writes to + * the attribute with datatype conversion involved, then reads back the + * attribute and verifies the data is correct. + */ +#define ATTRIBUTE_IO_TCONV_TEST_SPACE_RANK 2 +static int +test_attribute_io_tconv(void) +{ + hsize_t *dims = NULL; + hbool_t op_failed; + size_t num_in_progress; + size_t i, data_size; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + hid_t es_id = H5I_INVALID_HID; + int *write_buf = NULL; + int *read_buf = NULL; + + TESTING("attribute I/O with type conversion"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + if (MAINPROCESS) { + SKIPPED(); + HDprintf(" API functions for basic file, attribute, or flush aren't supported with this " + "connector\n"); + } + + return 0; + } + + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, coll_metadata_read)) < 0) + TEST_ERROR; + + /* Create dataspace */ + if (generate_random_parallel_dimensions(ATTRIBUTE_IO_TCONV_TEST_SPACE_RANK, &dims) < 0) + TEST_ERROR; + + /* Create dataspace */ + if ((space_id = H5Screate_simple(ATTRIBUTE_IO_TCONV_TEST_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + + /* Create event stack */ + if ((es_id = H5EScreate()) < 0) + TEST_ERROR; + + /* Open file asynchronously */ + if ((file_id = H5Fopen_async(PAR_ASYNC_API_TEST_FILE, H5F_ACC_RDWR, fapl_id, es_id)) < 0) + TEST_ERROR; + + /* Create the attribute asynchronously by name */ + if ((attr_id = H5Acreate_by_name_async(file_id, "attr_dset", "attr_tconv", H5T_STD_U16BE, space_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Calculate size of data buffers */ + for (i = 0, data_size = 1; i < ATTRIBUTE_IO_TCONV_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= sizeof(int); + + if (NULL == (write_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for attribute write\n"); + TEST_ERROR; + } + + if (NULL == (read_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for attribute read\n"); + TEST_ERROR; + } + + /* Initialize write_buf. */ + for (i = 0; i < data_size / sizeof(int); i++) + write_buf[i] = 10 * (int)i; + + /* Write the attribute asynchronously */ + if (H5Awrite_async(attr_id, H5T_NATIVE_INT, write_buf, es_id) < 0) + TEST_ERROR; + + /* Flush the dataset asynchronously. This will effectively work as a + * barrier, guaranteeing the read takes place after the write. */ + if (H5Fflush_async(file_id, H5F_SCOPE_LOCAL, es_id) < 0) + TEST_ERROR; + + /* Read the attribute asynchronously */ + if (H5Aread_async(attr_id, H5T_NATIVE_INT, read_buf, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Verify the read data */ + for (i = 0; i < data_size / sizeof(int); i++) + if (write_buf[i] != read_buf[i]) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + goto error; + } /* end if */ + + /* Close the attribute asynchronously */ + if (H5Aclose_async(attr_id, es_id) < 0) + TEST_ERROR; + + /* Open the attribute asynchronously */ + if ((attr_id = + H5Aopen_by_name_async(file_id, "attr_dset", "attr_tconv", H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Read the attribute asynchronously */ + if (H5Aread_async(attr_id, H5T_NATIVE_INT, read_buf, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Verify the read data */ + for (i = 0; i < data_size / sizeof(int); i++) + if (write_buf[i] != read_buf[i]) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + goto error; + } /* end if */ + + /* Close */ + if (H5Aclose_async(attr_id, es_id) < 0) + TEST_ERROR; + if (H5Fclose_async(file_id, es_id) < 0) + TEST_ERROR; + if (H5Sclose(space_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + + if (dims) { + HDfree(dims); + dims = NULL; + } + + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5ESclose(es_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (read_buf) + HDfree(read_buf); + if (write_buf) + HDfree(write_buf); + if (dims) + HDfree(dims); + H5Sclose(space_id); + H5Aclose(attr_id); + H5Dclose(dset_id); + H5Pclose(fapl_id); + H5Fclose(file_id); + H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed); + H5ESclose(es_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * Creates a file, dataset and attribute in parallel. Each rank writes to + * the attribute with a compound datatype, then reads back the attribute + * and verifies the data is correct. + */ +typedef struct tattr_cmpd_t { + int a; + int b; +} tattr_cmpd_t; + +#define ATTRIBUTE_IO_COMPOUND_TEST_SPACE_RANK 2 +static int +test_attribute_io_compound(void) +{ + hsize_t *dims = NULL; + hbool_t op_failed; + size_t num_in_progress; + size_t i, data_size; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + hid_t mtype_id = H5I_INVALID_HID; + hid_t ftype_id = H5I_INVALID_HID; + hid_t mtypea_id = H5I_INVALID_HID; + hid_t mtypeb_id = H5I_INVALID_HID; + hid_t es_id = H5I_INVALID_HID; + tattr_cmpd_t *write_buf = NULL; + tattr_cmpd_t *read_buf = NULL; + tattr_cmpd_t *fbuf = NULL; + + TESTING("attribute I/O with compound type conversion"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + if (MAINPROCESS) { + SKIPPED(); + HDprintf(" API functions for basic file, dataset, dataset more, attribute, or flush aren't " + "supported with this connector\n"); + } + + return 0; + } + + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, coll_metadata_read)) < 0) + TEST_ERROR; + + /* Create dataspace */ + if (generate_random_parallel_dimensions(ATTRIBUTE_IO_COMPOUND_TEST_SPACE_RANK, &dims) < 0) + TEST_ERROR; + + /* Create datatype */ + if ((mtype_id = H5Tcreate(H5T_COMPOUND, sizeof(tattr_cmpd_t))) < 0) + TEST_ERROR; + if (H5Tinsert(mtype_id, "a_name", HOFFSET(tattr_cmpd_t, a), H5T_NATIVE_INT) < 0) + TEST_ERROR; + if (H5Tinsert(mtype_id, "b_name", HOFFSET(tattr_cmpd_t, b), H5T_NATIVE_INT) < 0) + TEST_ERROR; + + if ((mtypea_id = H5Tcreate(H5T_COMPOUND, sizeof(tattr_cmpd_t))) < 0) + TEST_ERROR; + if (H5Tinsert(mtypea_id, "a_name", HOFFSET(tattr_cmpd_t, a), H5T_NATIVE_INT) < 0) + TEST_ERROR; + + if ((mtypeb_id = H5Tcreate(H5T_COMPOUND, sizeof(tattr_cmpd_t))) < 0) + TEST_ERROR; + if (H5Tinsert(mtypeb_id, "b_name", HOFFSET(tattr_cmpd_t, b), H5T_NATIVE_INT) < 0) + TEST_ERROR; + + if ((ftype_id = H5Tcreate(H5T_COMPOUND, 2 + 8)) < 0) + TEST_ERROR; + if (H5Tinsert(ftype_id, "a_name", 0, H5T_STD_U16BE) < 0) + TEST_ERROR; + if (H5Tinsert(ftype_id, "b_name", 2, H5T_STD_I64LE) < 0) + TEST_ERROR; + + /* Create dataspace */ + if ((space_id = H5Screate_simple(ATTRIBUTE_IO_COMPOUND_TEST_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + + /* Create event stack */ + if ((es_id = H5EScreate()) < 0) + TEST_ERROR; + + /* Open file asynchronously */ + if ((file_id = H5Fopen_async(PAR_ASYNC_API_TEST_FILE, H5F_ACC_RDWR, fapl_id, es_id)) < 0) + TEST_ERROR; + + /* Create the attribute asynchronously by name */ + if ((attr_id = H5Acreate_by_name_async(file_id, "attr_dset", "attr_cmpd", ftype_id, space_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Calculate size of data buffers */ + for (i = 0, data_size = 1; i < ATTRIBUTE_IO_COMPOUND_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= sizeof(tattr_cmpd_t); + + if (NULL == (write_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for attribute write\n"); + TEST_ERROR; + } + + if (NULL == (read_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for attribute read\n"); + TEST_ERROR; + } + + if (NULL == (fbuf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for attribute read verification\n"); + TEST_ERROR; + } + + /* Initialize write_buf. */ + for (i = 0; i < data_size / sizeof(tattr_cmpd_t); i++) { + write_buf[i].a = 10 * (int)i; + write_buf[i].b = (10 * (int)i) + 1; + } + + /* Write the attribute asynchronously */ + if (H5Awrite_async(attr_id, mtype_id, write_buf, es_id) < 0) + TEST_ERROR; + + /* Update fbuf */ + for (i = 0; i < data_size / sizeof(tattr_cmpd_t); i++) { + fbuf[i].a = write_buf[i].a; + fbuf[i].b = write_buf[i].b; + } + + /* Flush the dataset asynchronously. This will effectively work as a + * barrier, guaranteeing the read takes place after the write. */ + if (H5Fflush_async(file_id, H5F_SCOPE_LOCAL, es_id) < 0) + TEST_ERROR; + + /* Read the attribute asynchronously */ + if (H5Aread_async(attr_id, mtype_id, read_buf, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Verify the read data */ + for (i = 0; i < data_size / sizeof(tattr_cmpd_t); i++) { + if (read_buf[i].a != fbuf[i].a) { + H5_FAILED(); + HDprintf(" data verification failed for field 'a'\n"); + goto error; + } /* end if */ + if (read_buf[i].b != fbuf[i].b) { + H5_FAILED(); + HDprintf(" data verification failed for field 'b'\n"); + goto error; + } /* end if */ + } + + /* Clear the read buffer */ + for (i = 0; i < data_size / sizeof(tattr_cmpd_t); i++) { + read_buf[i].a = -2; + read_buf[i].b = -2; + } + + /* Read the attribute asynchronously (element a only) */ + if (H5Aread_async(attr_id, mtypea_id, read_buf, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Verify the read data */ + for (i = 0; i < data_size / sizeof(tattr_cmpd_t); i++) { + if (read_buf[i].a != fbuf[i].a) { + H5_FAILED(); + HDprintf(" data verification failed for field 'a'\n"); + goto error; + } /* end if */ + if (read_buf[i].b != -2) { + H5_FAILED(); + HDprintf(" data verification failed for field 'b'\n"); + goto error; + } /* end if */ + } + + /* Clear the read buffer */ + for (i = 0; i < data_size / sizeof(tattr_cmpd_t); i++) { + read_buf[i].a = -2; + read_buf[i].b = -2; + } + + /* Read the attribute asynchronously (element b only) */ + if (H5Aread_async(attr_id, mtypeb_id, read_buf, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Verify the read data */ + for (i = 0; i < data_size / sizeof(tattr_cmpd_t); i++) { + if (read_buf[i].a != -2) { + H5_FAILED(); + HDprintf(" data verification failed for field 'a'\n"); + goto error; + } /* end if */ + if (read_buf[i].b != fbuf[i].b) { + H5_FAILED(); + HDprintf(" data verification failed for field 'b'\n"); + goto error; + } /* end if */ + } + + if (MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD)) { + H5_FAILED(); + HDprintf(" MPI_Barrier failed\n"); + goto error; + } + + /* Update write_buf */ + for (i = 0; i < data_size / sizeof(tattr_cmpd_t); i++) { + write_buf[i].a += 2 * 6 * 10; + write_buf[i].b += 2 * 6 * 10; + } + + /* Write the attribute asynchronously (element a only) */ + if (H5Awrite_async(attr_id, mtypea_id, write_buf, es_id) < 0) + TEST_ERROR; + + /* Update fbuf */ + for (i = 0; i < data_size / sizeof(tattr_cmpd_t); i++) { + fbuf[i].a = write_buf[i].a; + } + + /* Flush the dataset asynchronously. This will effectively work as a + * barrier, guaranteeing the read takes place after the write. */ + if (H5Fflush_async(file_id, H5F_SCOPE_LOCAL, es_id) < 0) + TEST_ERROR; + + /* Clear the read buffer */ + for (i = 0; i < data_size / sizeof(tattr_cmpd_t); i++) { + read_buf[i].a = -2; + read_buf[i].b = -2; + } + + /* Read the attribute asynchronously */ + if (H5Aread_async(attr_id, mtype_id, read_buf, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Verify the read data */ + for (i = 0; i < data_size / sizeof(tattr_cmpd_t); i++) { + if (read_buf[i].a != fbuf[i].a) { + H5_FAILED(); + HDprintf(" data verification failed for field 'a'\n"); + goto error; + } /* end if */ + if (read_buf[i].b != fbuf[i].b) { + H5_FAILED(); + HDprintf(" data verification failed for field 'b'\n"); + goto error; + } /* end if */ + } + + if (MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD)) { + H5_FAILED(); + HDprintf(" MPI_Barrier failed\n"); + goto error; + } + + /* Update write_buf */ + for (i = 0; i < data_size / sizeof(tattr_cmpd_t); i++) { + write_buf[i].a += 2 * 6 * 10; + write_buf[i].b += 2 * 6 * 10; + } + + /* Write the attribute asynchronously (element b only) */ + if (H5Awrite_async(attr_id, mtypeb_id, write_buf, es_id) < 0) + TEST_ERROR; + + /* Update fbuf */ + for (i = 0; i < data_size / sizeof(tattr_cmpd_t); i++) { + fbuf[i].b = write_buf[i].b; + } + + /* Flush the dataset asynchronously. This will effectively work as a + * barrier, guaranteeing the read takes place after the write. */ + if (H5Fflush_async(file_id, H5F_SCOPE_LOCAL, es_id) < 0) + TEST_ERROR; + + /* Clear the read buffer */ + for (i = 0; i < data_size / sizeof(tattr_cmpd_t); i++) { + read_buf[i].a = -2; + read_buf[i].b = -2; + } + + /* Read the attribute asynchronously */ + if (H5Aread_async(attr_id, mtype_id, read_buf, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Verify the read data */ + for (i = 0; i < data_size / sizeof(tattr_cmpd_t); i++) { + if (read_buf[i].a != fbuf[i].a) { + H5_FAILED(); + HDprintf(" data verification failed for field 'a'\n"); + goto error; + } /* end if */ + if (read_buf[i].b != fbuf[i].b) { + H5_FAILED(); + HDprintf(" data verification failed for field 'b'\n"); + goto error; + } /* end if */ + } + + /* Close */ + if (H5Aclose_async(attr_id, es_id) < 0) + TEST_ERROR; + if (H5Fclose_async(file_id, es_id) < 0) + TEST_ERROR; + if (H5Sclose(space_id) < 0) + TEST_ERROR; + if (H5Tclose(mtype_id) < 0) + TEST_ERROR; + if (H5Tclose(ftype_id) < 0) + TEST_ERROR; + if (H5Tclose(mtypea_id) < 0) + TEST_ERROR; + if (H5Tclose(mtypeb_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + + if (fbuf) { + HDfree(fbuf); + fbuf = NULL; + } + + if (dims) { + HDfree(dims); + dims = NULL; + } + + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5ESclose(es_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (read_buf) + HDfree(read_buf); + if (write_buf) + HDfree(write_buf); + if (fbuf) + HDfree(fbuf); + if (dims) + HDfree(dims); + H5Sclose(space_id); + H5Tclose(mtype_id); + H5Tclose(ftype_id); + H5Tclose(mtypea_id); + H5Tclose(mtypeb_id); + H5Aclose(attr_id); + H5Pclose(fapl_id); + H5Fclose(file_id); + H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed); + H5ESclose(es_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * Tests async group interfaces in parallel + */ +static int +test_group(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t parent_group_id = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t subgroup_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + hid_t es_id = H5I_INVALID_HID; + H5G_info_t info1; + H5G_info_t info2; + H5G_info_t info3; + size_t num_in_progress; + hbool_t op_failed; + + TESTING("group operations"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_MORE) || !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + if (MAINPROCESS) { + SKIPPED(); + HDprintf(" API functions for basic file, group, group more, creation order, or flush aren't " + "supported with this connector\n"); + } + + return 0; + } + + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, coll_metadata_read)) < 0) + TEST_ERROR; + + /* Create GCPL */ + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) + TEST_ERROR; + + /* Track creation order */ + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0) + TEST_ERROR; + + /* Create event stack */ + if ((es_id = H5EScreate()) < 0) + TEST_ERROR; + + /* Open file asynchronously */ + if ((file_id = H5Fopen_async(PAR_ASYNC_API_TEST_FILE, H5F_ACC_RDWR, fapl_id, es_id)) < 0) + TEST_ERROR; + + /* Create the parent group asynchronously */ + if ((parent_group_id = + H5Gcreate_async(file_id, "group_parent", H5P_DEFAULT, gcpl_id, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Create 3 subgroups asynchronously, the first with no sub-subgroups, the + * second with 1, and the third with 2 */ + if ((group_id = + H5Gcreate_async(parent_group_id, "group1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + if (H5Gclose_async(group_id, es_id) < 0) + TEST_ERROR; + + if ((group_id = + H5Gcreate_async(parent_group_id, "group2", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + if ((subgroup_id = H5Gcreate_async(group_id, "subgroup1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT, es_id)) < + 0) + TEST_ERROR; + if (H5Gclose_async(subgroup_id, es_id) < 0) + TEST_ERROR; + if (H5Gclose_async(group_id, es_id) < 0) + TEST_ERROR; + + if ((group_id = + H5Gcreate_async(parent_group_id, "group3", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + if ((subgroup_id = H5Gcreate_async(group_id, "subgroup1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT, es_id)) < + 0) + TEST_ERROR; + if (H5Gclose_async(subgroup_id, es_id) < 0) + TEST_ERROR; + if ((subgroup_id = H5Gcreate_async(group_id, "subgroup2", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT, es_id)) < + 0) + TEST_ERROR; + if (H5Gclose_async(subgroup_id, es_id) < 0) + TEST_ERROR; + if (H5Gclose_async(group_id, es_id) < 0) + TEST_ERROR; + + /* Flush the file asynchronously. This will effectively work as a barrier, + * guaranteeing the read takes place after the write. */ + if (H5Fflush_async(file_id, H5F_SCOPE_LOCAL, es_id) < 0) + TEST_ERROR; + + /* Test H5Gget_info_async */ + /* Open group1 asynchronously */ + if ((group_id = H5Gopen_async(parent_group_id, "group1", H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Get info */ + if (H5Gget_info_async(group_id, &info1, es_id) < 0) + TEST_ERROR; + + /* Test H5Gget_info_by_idx_async */ + if (H5Gget_info_by_idx_async(parent_group_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 1, &info2, + H5P_DEFAULT, es_id) < 0) + TEST_ERROR; + + /* Test H5Gget_info_by_name_async */ + if (H5Gget_info_by_name_async(parent_group_id, "group3", &info3, H5P_DEFAULT, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Verify group infos */ + if (info1.nlinks != 0) + FAIL_PUTS_ERROR(" incorrect number of links") + if (info2.nlinks != 1) + FAIL_PUTS_ERROR(" incorrect number of links") + if (info3.nlinks != 2) + FAIL_PUTS_ERROR(" incorrect number of links") + + /* Close */ + if (H5Gclose_async(group_id, es_id) < 0) + TEST_ERROR; + if (H5Gclose_async(parent_group_id, es_id) < 0) + TEST_ERROR; + if (H5Fclose_async(file_id, es_id) < 0) + TEST_ERROR; + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + if (H5ESclose(es_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(subgroup_id); + H5Gclose(group_id); + H5Gclose(parent_group_id); + H5Fclose(file_id); + H5Pclose(fapl_id); + H5Pclose(gcpl_id); + H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed); + H5ESclose(es_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * Tests async link interfaces in parallel + */ +static int +test_link(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t parent_group_id = H5I_INVALID_HID; + hid_t group_id = H5I_INVALID_HID; + hid_t gcpl_id = H5I_INVALID_HID; + hid_t es_id = H5I_INVALID_HID; + hbool_t existsh1; + hbool_t existsh2; + hbool_t existsh3; + hbool_t existss1; + hbool_t existss2; + hbool_t existss3; + size_t num_in_progress; + hbool_t op_failed = false; + hbool_t is_native_vol = false; + + TESTING("link operations"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_LINK_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_HARD_LINKS) || !(vol_cap_flags_g & H5VL_CAP_FLAG_SOFT_LINKS) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_CREATION_ORDER)) { + if (MAINPROCESS) { + SKIPPED(); + HDprintf(" API functions for basic file, link, hard link, soft link, flush, or creation order " + "aren't supported with this connector\n"); + } + + return 0; + } + + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, coll_metadata_read)) < 0) + TEST_ERROR; + + /* Create GCPL */ + if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) + TEST_ERROR; + + /* Track creation order */ + if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0) + TEST_ERROR; + + /* Create event stack */ + if ((es_id = H5EScreate()) < 0) + TEST_ERROR; + + /* Open file asynchronously */ + if ((file_id = H5Fopen_async(PAR_ASYNC_API_TEST_FILE, H5F_ACC_RDWR, fapl_id, es_id)) < 0) + TEST_ERROR; + + /* Find out if the native connector is used */ + if (H5VLobject_is_native(file_id, &is_native_vol) < 0) + TEST_ERROR; + + /* Create the parent group asynchronously */ + if ((parent_group_id = + H5Gcreate_async(file_id, "link_parent", H5P_DEFAULT, gcpl_id, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Create subgroup asynchronously. */ + if ((group_id = H5Gcreate_async(parent_group_id, "group", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT, es_id)) < + 0) + TEST_ERROR; + if (H5Gclose_async(group_id, es_id) < 0) + TEST_ERROR; + + /* Flush the parent group asynchronously. This will effectively work as a + * barrier, guaranteeing the link to the subgroup is visible to later tasks. + * Skip this function for the native vol because it isn't supported in parallel. + */ + if (!is_native_vol && H5Oflush_async(parent_group_id, es_id) < 0) + TEST_ERROR; + + /* Create hard link asynchronously */ + if (H5Lcreate_hard_async(parent_group_id, "group", parent_group_id, "hard_link", H5P_DEFAULT, H5P_DEFAULT, + es_id) < 0) + TEST_ERROR; + + /* Flush the parent group asynchronously. This will effectively work as a + * barrier, guaranteeing the soft link create takes place after the hard + * link create. Skip this function for the native vol because it isn't supported in parallel. + */ + if (!is_native_vol && H5Oflush_async(parent_group_id, es_id) < 0) + TEST_ERROR; + + /* Create soft link asynchronously */ + if (H5Lcreate_soft_async("/link_parent/group", parent_group_id, "soft_link", H5P_DEFAULT, H5P_DEFAULT, + es_id) < 0) + TEST_ERROR; + + /* Flush the parent group asynchronously. This will effectively work as a + * barrier, guaranteeing the read takes place after the writes. + * Skip this function for the native vol because it isn't supported in parallel. + */ + if (!is_native_vol && H5Oflush_async(parent_group_id, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + if (MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD)) { + H5_FAILED(); + HDprintf(" MPI_Barrier failed\n"); + goto error; + } + + /* Check if hard link exists */ + if (H5Lexists_async(parent_group_id, "hard_link", &existsh1, H5P_DEFAULT, es_id) < 0) + TEST_ERROR; + + /* Check if soft link exists */ + if (H5Lexists_async(parent_group_id, "soft_link", &existss1, H5P_DEFAULT, es_id) < 0) + TEST_ERROR; + + /* Flush the parent group asynchronously. This will effectively work as a + * barrier, guaranteeing the delete takes place after the reads. + * Skip this function for the native vol because it isn't supported in parallel. + */ + if (!is_native_vol && H5Oflush_async(parent_group_id, es_id) < 0) + TEST_ERROR; + + /* Delete soft link by index */ + if (H5Ldelete_by_idx_async(parent_group_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, 2, H5P_DEFAULT, es_id) < + 0) + TEST_ERROR; + + /* Flush the parent group asynchronously. This will effectively work as a + * barrier, guaranteeing the read takes place after the delete. + * Skip this function for the native vol because it isn't supported in parallel. + */ + if (!is_native_vol && H5Oflush_async(parent_group_id, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + if (MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD)) { + H5_FAILED(); + HDprintf(" MPI_Barrier failed\n"); + goto error; + } + + /* Check if hard link exists */ + if (H5Lexists_async(parent_group_id, "hard_link", &existsh2, H5P_DEFAULT, es_id) < 0) + TEST_ERROR; + + /* Check if soft link exists */ + if (H5Lexists_async(parent_group_id, "soft_link", &existss2, H5P_DEFAULT, es_id) < 0) + TEST_ERROR; + + /* Flush the parent group asynchronously. This will effectively work as a + * barrier, guaranteeing the delete takes place after the reads. + * Skip this function for the native vol because it isn't supported in parallel. + */ + if (!is_native_vol && H5Oflush_async(parent_group_id, es_id) < 0) + TEST_ERROR; + + /* Delete hard link */ + if (H5Ldelete_async(parent_group_id, "hard_link", H5P_DEFAULT, es_id) < 0) + TEST_ERROR; + + /* Flush the parent group asynchronously. This will effectively work as a + * barrier, guaranteeing the read takes place after the delete. + * Skip this function for the native vol because it isn't supported in parallel. + */ + if (!is_native_vol && H5Oflush_async(parent_group_id, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + if (MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD)) { + H5_FAILED(); + HDprintf(" MPI_Barrier failed\n"); + goto error; + } + + /* Check if hard link exists */ + if (H5Lexists_async(parent_group_id, "hard_link", &existsh3, H5P_DEFAULT, es_id) < 0) + TEST_ERROR; + + /* Check if soft link exists */ + if (H5Lexists_async(parent_group_id, "soft_link", &existss3, H5P_DEFAULT, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Check if existence returns were correct */ + if (!existsh1) + FAIL_PUTS_ERROR(" link exists returned FALSE for link that should exist") + if (!existss1) + FAIL_PUTS_ERROR(" link exists returned FALSE for link that should exist") + if (!existsh2) + FAIL_PUTS_ERROR(" link exists returned FALSE for link that should exist") + if (existss2) + FAIL_PUTS_ERROR(" link exists returned TRUE for link that should not exist") + if (existsh3) + FAIL_PUTS_ERROR(" link exists returned TRUE for link that should not exist") + if (existsh3) + FAIL_PUTS_ERROR(" link exists returned TRUE for link that should not exist") + + /* Close */ + if (H5Gclose_async(parent_group_id, es_id) < 0) + TEST_ERROR; + if (H5Fclose_async(file_id, es_id) < 0) + TEST_ERROR; + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5Pclose(gcpl_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + if (H5ESclose(es_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Gclose(group_id); + H5Gclose(parent_group_id); + H5Fclose(file_id); + H5Pclose(fapl_id); + H5Pclose(gcpl_id); + H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed); + H5ESclose(es_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * Tests H5Ocopy_async and H5Orefresh_async in parallel + */ +#define OCOPY_REFRESH_TEST_SPACE_RANK 2 +static int +test_ocopy_orefresh(void) +{ + hsize_t *dims = NULL; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t parent_group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + hid_t es_id = H5I_INVALID_HID; + size_t num_in_progress; + hbool_t op_failed = false; + hbool_t is_native_vol = false; + + TESTING("H5Ocopy() and H5Orefresh()"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_OBJECT_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH)) { + if (MAINPROCESS) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, object more, flush, or refresh " + "aren't supported with this connector\n"); + } + + return 0; + } + + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, coll_metadata_read)) < 0) + TEST_ERROR; + + /* Create dataspace */ + if (generate_random_parallel_dimensions(OCOPY_REFRESH_TEST_SPACE_RANK, &dims) < 0) + TEST_ERROR; + + /* Create dataspace */ + if ((space_id = H5Screate_simple(OCOPY_REFRESH_TEST_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + + /* Create event stack */ + if ((es_id = H5EScreate()) < 0) + TEST_ERROR; + + /* Open file asynchronously */ + if ((file_id = H5Fopen_async(PAR_ASYNC_API_TEST_FILE, H5F_ACC_RDWR, fapl_id, es_id)) < 0) + TEST_ERROR; + + /* Find out if the native connector is used */ + if (H5VLobject_is_native(file_id, &is_native_vol) < 0) + TEST_ERROR; + + /* Create the parent group asynchronously */ + if ((parent_group_id = + H5Gcreate_async(file_id, "ocopy_parent", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Create dataset asynchronously. */ + if ((dset_id = H5Dcreate_async(parent_group_id, "dset", H5T_NATIVE_INT, space_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + if (H5Dclose_async(dset_id, es_id) < 0) + TEST_ERROR; + + /* Flush the parent group asynchronously. This will effectively work as a + * barrier, guaranteeing the copy takes place after dataset create. + * Skip this function for the native vol because it isn't supported in parallel. + */ + if (!is_native_vol && H5Oflush_async(parent_group_id, es_id) < 0) + TEST_ERROR; + + /* Copy dataset */ + if (H5Ocopy_async(parent_group_id, "dset", parent_group_id, "copied_dset", H5P_DEFAULT, H5P_DEFAULT, + es_id) < 0) + TEST_ERROR; + + /* Flush the parent group asynchronously. This will effectively work as a + * barrier, guaranteeing the dataset open takes place copy. + * Skip this function for the native vol because it isn't supported in parallel. + */ + if (!is_native_vol && H5Oflush_async(parent_group_id, es_id) < 0) + TEST_ERROR; + + if (!coll_metadata_read) { + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + if (MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD)) { + H5_FAILED(); + HDprintf(" MPI_Barrier failed\n"); + goto error; + } + } + + /* Open the copied dataset asynchronously */ + if ((dset_id = H5Dopen_async(parent_group_id, "copied_dset", H5P_DEFAULT, es_id)) < 0) + TEST_ERROR; + + /* Refresh the copied dataset asynchronously */ + if (H5Orefresh(dset_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Close */ + if (H5Dclose_async(dset_id, es_id) < 0) + TEST_ERROR; + if (H5Gclose_async(parent_group_id, es_id) < 0) + TEST_ERROR; + if (H5Fclose_async(file_id, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + if (dims) { + HDfree(dims); + dims = NULL; + } + + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5ESclose(es_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (dims) + HDfree(dims); + H5Sclose(space_id); + H5Dclose(dset_id); + H5Gclose(parent_group_id); + H5Pclose(fapl_id); + H5Fclose(file_id); + H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed); + H5ESclose(es_id); + } + H5E_END_TRY; + + return 1; +} +#undef OCOPY_REFRESH_TEST_SPACE_RANK + +/* + * Tests H5Freopen_async in parallel + */ +static int +test_file_reopen(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t reopened_file_id = H5I_INVALID_HID; + hid_t es_id = H5I_INVALID_HID; + size_t num_in_progress; + hbool_t op_failed; + + TESTING("H5Freopen()"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_MORE)) { + if (MAINPROCESS) { + SKIPPED(); + HDprintf(" API functions for basic file or file more aren't supported with this connector\n"); + } + + return 0; + } + + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, coll_metadata_read)) < 0) + TEST_ERROR; + + /* Create event stack */ + if ((es_id = H5EScreate()) < 0) + TEST_ERROR; + + /* Open file asynchronously */ + if ((file_id = H5Fopen_async(PAR_ASYNC_API_TEST_FILE, H5F_ACC_RDWR, fapl_id, es_id)) < 0) + TEST_ERROR; + + /* Reopen file asynchronously */ + if ((reopened_file_id = H5Freopen_async(file_id, es_id)) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + /* Close */ + if (H5Fclose_async(reopened_file_id, es_id) < 0) + TEST_ERROR; + if (H5Fclose_async(file_id, es_id) < 0) + TEST_ERROR; + + /* Wait for the event stack to complete */ + if (H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed) < 0) + TEST_ERROR; + if (op_failed) + TEST_ERROR; + + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5ESclose(es_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Fclose(reopened_file_id); + H5Fclose(file_id); + H5Pclose(fapl_id); + H5ESwait(es_id, H5_API_TEST_WAIT_FOREVER, &num_in_progress, &op_failed); + H5ESclose(es_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * Cleanup temporary test files + */ +static void +cleanup_files(void) +{ + char file_name[64]; + int i; + + if (MAINPROCESS) { + H5Fdelete(PAR_ASYNC_API_TEST_FILE, H5P_DEFAULT); + for (i = 0; i <= max_printf_file; i++) { + snprintf(file_name, 64, PAR_ASYNC_API_TEST_FILE_PRINTF, i); + H5Fdelete(file_name, H5P_DEFAULT); + } /* end for */ + } +} + +int +H5_api_async_test_parallel(void) +{ + size_t i; + int nerrors; + + if (MAINPROCESS) { + HDprintf("**********************************************\n"); + HDprintf("* *\n"); + HDprintf("* API Parallel Async Tests *\n"); + HDprintf("* *\n"); + HDprintf("**********************************************\n\n"); + } + + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_ASYNC)) { + if (MAINPROCESS) { + SKIPPED(); + HDprintf(" Async APIs aren't supported with this connector\n"); + } + + return 0; + } + + for (i = 0, nerrors = 0; i < ARRAY_LENGTH(par_async_tests); i++) { + nerrors += (*par_async_tests[i])() ? 1 : 0; + + if (MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD)) { + if (MAINPROCESS) + HDprintf(" MPI_Barrier() failed!\n"); + } + } + + if (MAINPROCESS) { + HDprintf("\n"); + HDprintf("Cleaning up testing files\n"); + } + + cleanup_files(); + + if (MAINPROCESS) { + HDprintf("\n * Re-testing with independent metadata reads *\n"); + } + + coll_metadata_read = FALSE; + + for (i = 0, nerrors = 0; i < ARRAY_LENGTH(par_async_tests); i++) { + nerrors += (*par_async_tests[i])() ? 1 : 0; + + if (MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD)) { + if (MAINPROCESS) + HDprintf(" MPI_Barrier() failed!\n"); + } + } + + if (MAINPROCESS) { + HDprintf("\n"); + HDprintf("Cleaning up testing files\n"); + } + + cleanup_files(); + + return nerrors; +} + +#else /* H5ESpublic_H */ + +int +H5_api_async_test_parallel(void) +{ + if (MAINPROCESS) { + HDprintf("**********************************************\n"); + HDprintf("* *\n"); + HDprintf("* API Parallel Async Tests *\n"); + HDprintf("* *\n"); + HDprintf("**********************************************\n\n"); + } + + HDprintf("SKIPPED due to no async support in HDF5 library\n"); + + return 0; +} + +#endif diff --git a/testpar/API/H5_api_async_test_parallel.h b/testpar/API/H5_api_async_test_parallel.h new file mode 100644 index 0000000..9e4340c --- /dev/null +++ b/testpar/API/H5_api_async_test_parallel.h @@ -0,0 +1,29 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef H5_API_ASYNC_TEST_PARALLEL_H_ +#define H5_API_ASYNC_TEST_PARALLEL_H_ + +#include "H5_api_test_parallel.h" + +int H5_api_async_test_parallel(void); + +/******************************************************** + * * + * API parallel async test defines * + * * + ********************************************************/ + +#define PAR_ASYNC_API_TEST_FILE "H5_api_async_test_parallel.h5" +#define PAR_ASYNC_API_TEST_FILE_PRINTF "H5_api_async_test_parallel_%d.h5" + +#endif /* H5_API_ASYNC_TEST_PARALLEL_H_ */ diff --git a/testpar/API/H5_api_attribute_test_parallel.c b/testpar/API/H5_api_attribute_test_parallel.c new file mode 100644 index 0000000..cffbfcd --- /dev/null +++ b/testpar/API/H5_api_attribute_test_parallel.c @@ -0,0 +1,47 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "H5_api_attribute_test_parallel.h" + +/* + * The array of parallel attribute tests to be performed. + */ +static int (*par_attribute_tests[])(void) = {NULL}; + +int +H5_api_attribute_test_parallel(void) +{ + size_t i; + int nerrors; + + if (MAINPROCESS) { + HDprintf("**********************************************\n"); + HDprintf("* *\n"); + HDprintf("* API Parallel Attribute Tests *\n"); + HDprintf("* *\n"); + HDprintf("**********************************************\n\n"); + } + + for (i = 0, nerrors = 0; i < ARRAY_LENGTH(par_attribute_tests); i++) { + /* nerrors += (*par_attribute_tests[i])() ? 1 : 0; */ + + if (MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD)) { + if (MAINPROCESS) + HDprintf(" MPI_Barrier() failed!\n"); + } + } + + if (MAINPROCESS) + HDprintf("\n"); + + return nerrors; +} diff --git a/testpar/API/H5_api_attribute_test_parallel.h b/testpar/API/H5_api_attribute_test_parallel.h new file mode 100644 index 0000000..81802ae --- /dev/null +++ b/testpar/API/H5_api_attribute_test_parallel.h @@ -0,0 +1,20 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef H5_API_ATTRIBUTE_TEST_PARALLEL_H_ +#define H5_API_ATTRIBUTE_TEST_PARALLEL_H_ + +#include "H5_api_test_parallel.h" + +int H5_api_attribute_test_parallel(void); + +#endif /* H5_API_ATTRIBUTE_TEST_PARALLEL_H_ */ diff --git a/testpar/API/H5_api_dataset_test_parallel.c b/testpar/API/H5_api_dataset_test_parallel.c new file mode 100644 index 0000000..fd02a7f --- /dev/null +++ b/testpar/API/H5_api_dataset_test_parallel.c @@ -0,0 +1,8149 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * XXX: Better documentation for each test about how the selections get + * split up among MPI ranks. + */ +#include "H5_api_dataset_test_parallel.h" + +static int test_write_dataset_data_verification(void); +static int test_write_dataset_independent(void); +static int test_write_dataset_one_proc_0_selection(void); +static int test_write_dataset_one_proc_none_selection(void); +static int test_write_dataset_one_proc_all_selection(void); +static int test_write_dataset_hyper_file_all_mem(void); +static int test_write_dataset_all_file_hyper_mem(void); +static int test_write_dataset_point_file_all_mem(void); +static int test_write_dataset_all_file_point_mem(void); +static int test_write_dataset_hyper_file_point_mem(void); +static int test_write_dataset_point_file_hyper_mem(void); +static int test_read_dataset_one_proc_0_selection(void); +static int test_read_dataset_one_proc_none_selection(void); +static int test_read_dataset_one_proc_all_selection(void); +static int test_read_dataset_hyper_file_all_mem(void); +static int test_read_dataset_all_file_hyper_mem(void); +static int test_read_dataset_point_file_all_mem(void); +static int test_read_dataset_all_file_point_mem(void); +static int test_read_dataset_hyper_file_point_mem(void); +static int test_read_dataset_point_file_hyper_mem(void); + +/* + * Chunking tests + */ +static int test_write_multi_chunk_dataset_same_shape_read(void); +static int test_write_multi_chunk_dataset_diff_shape_read(void); +static int test_overwrite_multi_chunk_dataset_same_shape_read(void); +static int test_overwrite_multi_chunk_dataset_diff_shape_read(void); + +/* + * The array of parallel dataset tests to be performed. + */ +static int (*par_dataset_tests[])(void) = { + test_write_dataset_data_verification, + test_write_dataset_independent, + test_write_dataset_one_proc_0_selection, + test_write_dataset_one_proc_none_selection, + test_write_dataset_one_proc_all_selection, + test_write_dataset_hyper_file_all_mem, + test_write_dataset_all_file_hyper_mem, + test_write_dataset_point_file_all_mem, + test_write_dataset_all_file_point_mem, + test_write_dataset_hyper_file_point_mem, + test_write_dataset_point_file_hyper_mem, + test_read_dataset_one_proc_0_selection, + test_read_dataset_one_proc_none_selection, + test_read_dataset_one_proc_all_selection, + test_read_dataset_hyper_file_all_mem, + test_read_dataset_all_file_hyper_mem, + test_read_dataset_point_file_all_mem, + test_read_dataset_all_file_point_mem, + test_read_dataset_hyper_file_point_mem, + test_read_dataset_point_file_hyper_mem, + test_write_multi_chunk_dataset_same_shape_read, + test_write_multi_chunk_dataset_diff_shape_read, + test_overwrite_multi_chunk_dataset_same_shape_read, + test_overwrite_multi_chunk_dataset_diff_shape_read, +}; + +/* + * A test to ensure that data is read back correctly from + * a dataset after it has been written in parallel. The test + * covers simple examples of using H5S_ALL selections, + * hyperslab selections and point selections. + */ +#define DATASET_WRITE_DATA_VERIFY_TEST_SPACE_RANK 3 +#define DATASET_WRITE_DATA_VERIFY_TEST_NUM_POINTS 10 +#define DATASET_WRITE_DATA_VERIFY_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_WRITE_DATA_VERIFY_TEST_DTYPE_SIZE sizeof(int) +#define DATASET_WRITE_DATA_VERIFY_TEST_GROUP_NAME "dataset_write_data_verification_test" +#define DATASET_WRITE_DATA_VERIFY_TEST_DSET_NAME1 "dataset_write_data_verification_all" +#define DATASET_WRITE_DATA_VERIFY_TEST_DSET_NAME2 "dataset_write_data_verification_hyperslab" +#define DATASET_WRITE_DATA_VERIFY_TEST_DSET_NAME3 "dataset_write_data_verification_points" +static int +test_write_dataset_data_verification(void) +{ + hssize_t space_npoints; + hsize_t *dims = NULL; + hsize_t start[DATASET_WRITE_DATA_VERIFY_TEST_SPACE_RANK]; + hsize_t stride[DATASET_WRITE_DATA_VERIFY_TEST_SPACE_RANK]; + hsize_t count[DATASET_WRITE_DATA_VERIFY_TEST_SPACE_RANK]; + hsize_t block[DATASET_WRITE_DATA_VERIFY_TEST_SPACE_RANK]; + hsize_t *points = NULL; + size_t i, data_size; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + void *write_buf = NULL; + void *read_buf = NULL; + + TESTING_MULTIPART("verification of dataset data using H5Dwrite then H5Dread"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, TRUE)) < 0) + TEST_ERROR; + + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_parallel_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_WRITE_DATA_VERIFY_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", DATASET_WRITE_DATA_VERIFY_TEST_GROUP_NAME); + goto error; + } + + if (generate_random_parallel_dimensions(DATASET_WRITE_DATA_VERIFY_TEST_SPACE_RANK, &dims) < 0) + TEST_ERROR; + + if ((fspace_id = H5Screate_simple(DATASET_WRITE_DATA_VERIFY_TEST_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_WRITE_DATA_VERIFY_TEST_DSET_NAME1, + DATASET_WRITE_DATA_VERIFY_TEST_DSET_DTYPE, fspace_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_WRITE_DATA_VERIFY_TEST_DSET_NAME1); + goto error; + } + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + + if ((dset_id = H5Dcreate2(group_id, DATASET_WRITE_DATA_VERIFY_TEST_DSET_NAME2, + DATASET_WRITE_DATA_VERIFY_TEST_DSET_DTYPE, fspace_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_WRITE_DATA_VERIFY_TEST_DSET_NAME2); + goto error; + } + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + + if ((dset_id = H5Dcreate2(group_id, DATASET_WRITE_DATA_VERIFY_TEST_DSET_NAME3, + DATASET_WRITE_DATA_VERIFY_TEST_DSET_DTYPE, fspace_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_WRITE_DATA_VERIFY_TEST_DSET_NAME3); + goto error; + } + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Dwrite_all_read) + { + hbool_t op_failed = FALSE; + + TESTING_2("H5Dwrite using H5S_ALL then H5Dread"); + + if ((dset_id = H5Dopen2(group_id, DATASET_WRITE_DATA_VERIFY_TEST_DSET_NAME1, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_WRITE_DATA_VERIFY_TEST_DSET_NAME1); + PART_ERROR(H5Dwrite_all_read); + } + + /* + * Write data to dataset on rank 0 only. All ranks will read the data back. + */ + if (MAINPROCESS) { + for (i = 0, data_size = 1; i < DATASET_WRITE_DATA_VERIFY_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_WRITE_DATA_VERIFY_TEST_DTYPE_SIZE; + + if (NULL != (write_buf = HDmalloc(data_size))) { + for (i = 0; i < data_size / DATASET_WRITE_DATA_VERIFY_TEST_DTYPE_SIZE; i++) + ((int *)write_buf)[i] = (int)i; + + if (H5Dwrite(dset_id, DATASET_WRITE_DATA_VERIFY_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, + H5P_DEFAULT, write_buf) < 0) + op_failed = TRUE; + } + else + op_failed = TRUE; + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + } + + if (MPI_SUCCESS != + MPI_Allreduce(MPI_IN_PLACE, &op_failed, 1, MPI_C_BOOL, MPI_LAND, MPI_COMM_WORLD)) { + H5_FAILED(); + HDprintf(" couldn't determine if dataset write on rank 0 succeeded\n"); + PART_ERROR(H5Dwrite_all_read); + } + + if (op_failed == TRUE) { + H5_FAILED(); + HDprintf(" dataset write on rank 0 failed!\n"); + PART_ERROR(H5Dwrite_all_read); + } + + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + /* + * Close and re-open the file to ensure that the data gets written. + */ + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close test's container group\n"); + PART_ERROR(H5Dwrite_all_read); + } + if (H5Gclose(container_group) < 0) { + H5_FAILED(); + HDprintf(" failed to close container group\n"); + PART_ERROR(H5Dwrite_all_read); + } + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close file for data flushing\n"); + PART_ERROR(H5Dwrite_all_read); + } + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't re-open file '%s'\n", H5_api_test_parallel_filename); + PART_ERROR(H5Dwrite_all_read); + } + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + PART_ERROR(H5Dwrite_all_read); + } + if ((group_id = + H5Gopen2(container_group, DATASET_WRITE_DATA_VERIFY_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container sub-group '%s'\n", + DATASET_WRITE_DATA_VERIFY_TEST_GROUP_NAME); + PART_ERROR(H5Dwrite_all_read); + } + + if ((dset_id = H5Dopen2(group_id, DATASET_WRITE_DATA_VERIFY_TEST_DSET_NAME1, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_WRITE_DATA_VERIFY_TEST_DSET_NAME1); + PART_ERROR(H5Dwrite_all_read); + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + PART_ERROR(H5Dwrite_all_read); + } + + if ((space_npoints = H5Sget_simple_extent_npoints(fspace_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataspace num points\n"); + PART_ERROR(H5Dwrite_all_read); + } + + if (NULL == + (read_buf = HDmalloc((hsize_t)space_npoints * DATASET_WRITE_DATA_VERIFY_TEST_DTYPE_SIZE))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + PART_ERROR(H5Dwrite_all_read); + } + + if (H5Dread(dset_id, DATASET_WRITE_DATA_VERIFY_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, H5P_DEFAULT, + read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", DATASET_WRITE_DATA_VERIFY_TEST_DSET_NAME1); + PART_ERROR(H5Dwrite_all_read); + } + + for (i = 0; i < (hsize_t)space_npoints; i++) + if (((int *)read_buf)[i] != (int)i) { + H5_FAILED(); + HDprintf(" H5S_ALL selection data verification failed\n"); + PART_ERROR(H5Dwrite_all_read); + } + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + PASSED(); + } + PART_END(H5Dwrite_all_read); + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + PART_BEGIN(H5Dwrite_hyperslab_read) + { + TESTING_2("H5Dwrite using hyperslab selection then H5Dread"); + + for (i = 1, data_size = 1; i < DATASET_WRITE_DATA_VERIFY_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_WRITE_DATA_VERIFY_TEST_DTYPE_SIZE; + + if (NULL == (write_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + for (i = 0; i < data_size / DATASET_WRITE_DATA_VERIFY_TEST_DTYPE_SIZE; i++) + ((int *)write_buf)[i] = mpi_rank; + + /* Each MPI rank writes to a single row in the second dimension + * and the entirety of the following dimensions. The combined + * selections from all MPI ranks spans the first dimension. + */ + for (i = 0; i < DATASET_WRITE_DATA_VERIFY_TEST_SPACE_RANK; i++) { + if (i == 0) { + start[i] = (hsize_t)mpi_rank; + block[i] = 1; + } + else { + start[i] = 0; + block[i] = dims[i]; + } + + stride[i] = 1; + count[i] = 1; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_WRITE_DATA_VERIFY_TEST_DSET_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_WRITE_DATA_VERIFY_TEST_DSET_NAME2); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + if (H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET, start, stride, count, block) < 0) { + H5_FAILED(); + HDprintf(" couldn't select hyperslab for dataset write\n"); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + { + hsize_t mdims[] = {data_size / DATASET_WRITE_DATA_VERIFY_TEST_DTYPE_SIZE}; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + PART_ERROR(H5Dwrite_hyperslab_read); + } + } + + if (H5Dwrite(dset_id, DATASET_WRITE_DATA_VERIFY_TEST_DSET_DTYPE, mspace_id, fspace_id, + H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", DATASET_WRITE_DATA_VERIFY_TEST_DSET_NAME2); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + if (mspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(mspace_id); + } + H5E_END_TRY; + mspace_id = H5I_INVALID_HID; + } + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + /* + * Close and re-open the file to ensure that the data gets written. + */ + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close test's container group\n"); + PART_ERROR(H5Dwrite_hyperslab_read); + } + if (H5Gclose(container_group) < 0) { + H5_FAILED(); + HDprintf(" failed to close container group\n"); + PART_ERROR(H5Dwrite_hyperslab_read); + } + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close file for data flushing\n"); + PART_ERROR(H5Dwrite_hyperslab_read); + } + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't re-open file '%s'\n", H5_api_test_parallel_filename); + PART_ERROR(H5Dwrite_hyperslab_read); + } + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + PART_ERROR(H5Dwrite_hyperslab_read); + } + if ((group_id = + H5Gopen2(container_group, DATASET_WRITE_DATA_VERIFY_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container sub-group '%s'\n", + DATASET_WRITE_DATA_VERIFY_TEST_GROUP_NAME); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + if ((dset_id = H5Dopen2(group_id, DATASET_WRITE_DATA_VERIFY_TEST_DSET_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_WRITE_DATA_VERIFY_TEST_DSET_NAME2); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + if ((space_npoints = H5Sget_simple_extent_npoints(fspace_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataspace num points\n"); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + if (NULL == + (read_buf = HDmalloc((hsize_t)space_npoints * DATASET_WRITE_DATA_VERIFY_TEST_DTYPE_SIZE))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + if (H5Dread(dset_id, DATASET_WRITE_DATA_VERIFY_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, H5P_DEFAULT, + read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", DATASET_WRITE_DATA_VERIFY_TEST_DSET_NAME2); + PART_ERROR(H5Dwrite_hyperslab_read); + } + + for (i = 0; i < (size_t)mpi_size; i++) { + size_t j; + + for (j = 0; j < data_size / DATASET_WRITE_DATA_VERIFY_TEST_DTYPE_SIZE; j++) { + if (((int *) + read_buf)[j + (i * (data_size / DATASET_WRITE_DATA_VERIFY_TEST_DTYPE_SIZE))] != + (int)i) { + H5_FAILED(); + HDprintf(" hyperslab selection data verification failed\n"); + PART_ERROR(H5Dwrite_hyperslab_read); + } + } + } + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + PASSED(); + } + PART_END(H5Dwrite_hyperslab_read); + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (mspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(mspace_id); + } + H5E_END_TRY; + mspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + PART_BEGIN(H5Dwrite_point_sel_read) + { + TESTING_2("H5Dwrite using point selection then H5Dread"); + + for (i = 1, data_size = 1; i < DATASET_WRITE_DATA_VERIFY_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_WRITE_DATA_VERIFY_TEST_DTYPE_SIZE; + + if (NULL == (write_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + PART_ERROR(H5Dwrite_point_sel_read); + } + + /* Use different data than the previous test to ensure that the data actually changed. */ + for (i = 0; i < data_size / DATASET_WRITE_DATA_VERIFY_TEST_DTYPE_SIZE; i++) + ((int *)write_buf)[i] = mpi_size - mpi_rank; + + if (NULL == (points = HDmalloc(DATASET_WRITE_DATA_VERIFY_TEST_SPACE_RANK * + (data_size / DATASET_WRITE_DATA_VERIFY_TEST_DTYPE_SIZE) * + sizeof(hsize_t)))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for point selection\n"); + PART_ERROR(H5Dwrite_point_sel_read); + } + + /* Each MPI rank writes to a single row in the second dimension + * and the entirety of the following dimensions. The combined + * selections from all MPI ranks spans the first dimension. + */ + for (i = 0; i < data_size / DATASET_WRITE_DATA_VERIFY_TEST_DTYPE_SIZE; i++) { + size_t j; + + for (j = 0; j < DATASET_WRITE_DATA_VERIFY_TEST_SPACE_RANK; j++) { + size_t idx = (i * DATASET_WRITE_DATA_VERIFY_TEST_SPACE_RANK) + j; + + if (j == 0) + points[idx] = (hsize_t)mpi_rank; + else if (j != DATASET_WRITE_DATA_VERIFY_TEST_SPACE_RANK - 1) + points[idx] = i / dims[j + 1]; + else + points[idx] = i % dims[j]; + } + } + + if ((dset_id = H5Dopen2(group_id, DATASET_WRITE_DATA_VERIFY_TEST_DSET_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_WRITE_DATA_VERIFY_TEST_DSET_NAME3); + PART_ERROR(H5Dwrite_point_sel_read); + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + PART_ERROR(H5Dwrite_point_sel_read); + } + + if (H5Sselect_elements(fspace_id, H5S_SELECT_SET, + data_size / DATASET_WRITE_DATA_VERIFY_TEST_DTYPE_SIZE, points) < 0) { + H5_FAILED(); + HDprintf(" couldn't select elements in dataspace\n"); + PART_ERROR(H5Dwrite_point_sel_read); + } + + { + hsize_t mdims[] = {data_size / DATASET_WRITE_DATA_VERIFY_TEST_DTYPE_SIZE}; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + PART_ERROR(H5Dwrite_point_sel_read); + } + } + + if (H5Dwrite(dset_id, DATASET_WRITE_DATA_VERIFY_TEST_DSET_DTYPE, mspace_id, fspace_id, + H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", DATASET_WRITE_DATA_VERIFY_TEST_DSET_NAME3); + PART_ERROR(H5Dwrite_point_sel_read); + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + if (mspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(mspace_id); + } + H5E_END_TRY; + mspace_id = H5I_INVALID_HID; + } + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + /* + * Close and re-open the file to ensure that the data gets written. + */ + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close test's container group\n"); + PART_ERROR(H5Dwrite_point_sel_read); + } + if (H5Gclose(container_group) < 0) { + H5_FAILED(); + HDprintf(" failed to close container group\n"); + PART_ERROR(H5Dwrite_point_sel_read); + } + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close file for data flushing\n"); + PART_ERROR(H5Dwrite_point_sel_read); + } + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't re-open file '%s'\n", H5_api_test_parallel_filename); + PART_ERROR(H5Dwrite_point_sel_read); + } + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + PART_ERROR(H5Dwrite_point_sel_read); + } + if ((group_id = + H5Gopen2(container_group, DATASET_WRITE_DATA_VERIFY_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container sub-group '%s'\n", + DATASET_WRITE_DATA_VERIFY_TEST_GROUP_NAME); + PART_ERROR(H5Dwrite_point_sel_read); + } + + if ((dset_id = H5Dopen2(group_id, DATASET_WRITE_DATA_VERIFY_TEST_DSET_NAME3, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_WRITE_DATA_VERIFY_TEST_DSET_NAME3); + PART_ERROR(H5Dwrite_point_sel_read); + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + PART_ERROR(H5Dwrite_point_sel_read); + } + + if ((space_npoints = H5Sget_simple_extent_npoints(fspace_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataspace num points\n"); + PART_ERROR(H5Dwrite_point_sel_read); + } + + if (NULL == + (read_buf = HDmalloc((hsize_t)space_npoints * DATASET_WRITE_DATA_VERIFY_TEST_DTYPE_SIZE))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + PART_ERROR(H5Dwrite_point_sel_read); + } + + if (H5Dread(dset_id, DATASET_WRITE_DATA_VERIFY_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, H5P_DEFAULT, + read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", DATASET_WRITE_DATA_VERIFY_TEST_DSET_NAME3); + PART_ERROR(H5Dwrite_point_sel_read); + } + + for (i = 0; i < (size_t)mpi_size; i++) { + size_t j; + + for (j = 0; j < data_size / DATASET_WRITE_DATA_VERIFY_TEST_DTYPE_SIZE; j++) { + if (((int *) + read_buf)[j + (i * (data_size / DATASET_WRITE_DATA_VERIFY_TEST_DTYPE_SIZE))] != + (mpi_size - (int)i)) { + H5_FAILED(); + HDprintf(" point selection data verification failed\n"); + PART_ERROR(H5Dwrite_point_sel_read); + } + } + } + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + PASSED(); + } + PART_END(H5Dwrite_point_sel_read); + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + if (points) { + HDfree(points); + points = NULL; + } + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (mspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(mspace_id); + } + H5E_END_TRY; + mspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + + if (points) { + HDfree(points); + points = NULL; + } + + if (dims) { + HDfree(dims); + dims = NULL; + } + + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (read_buf) + HDfree(read_buf); + if (write_buf) + HDfree(write_buf); + if (points) + HDfree(points); + if (dims) + HDfree(dims); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Pclose(fapl_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to ensure that independent dataset writes function + * as expected. First, two datasets are created in the file. + * Then, the even MPI ranks first write to dataset 1, followed + * by dataset 2. The odd MPI ranks first write to dataset 2, + * followed by dataset 1. After this, the data is read back from + * each dataset and verified. + */ +#define DATASET_INDEPENDENT_WRITE_TEST_SPACE_RANK 3 +#define DATASET_INDEPENDENT_WRITE_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_INDEPENDENT_WRITE_TEST_DTYPE_SIZE sizeof(int) +#define DATASET_INDEPENDENT_WRITE_TEST_GROUP_NAME "independent_dataset_write_test" +#define DATASET_INDEPENDENT_WRITE_TEST_DSET_NAME1 "dset1" +#define DATASET_INDEPENDENT_WRITE_TEST_DSET_NAME2 "dset2" +static int +test_write_dataset_independent(void) +{ + hssize_t space_npoints; + hsize_t *dims = NULL; + hsize_t start[DATASET_INDEPENDENT_WRITE_TEST_SPACE_RANK]; + hsize_t stride[DATASET_INDEPENDENT_WRITE_TEST_SPACE_RANK]; + hsize_t count[DATASET_INDEPENDENT_WRITE_TEST_SPACE_RANK]; + hsize_t block[DATASET_INDEPENDENT_WRITE_TEST_SPACE_RANK]; + size_t i, data_size; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id1 = H5I_INVALID_HID, dset_id2 = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + void *write_buf = NULL; + void *read_buf = NULL; + + TESTING("independent writing to different datasets by different ranks"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, TRUE)) < 0) + TEST_ERROR; + + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_parallel_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_INDEPENDENT_WRITE_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", DATASET_INDEPENDENT_WRITE_TEST_GROUP_NAME); + goto error; + } + + /* + * Setup dimensions of overall datasets and slabs local + * to the MPI rank. + */ + if (generate_random_parallel_dimensions(DATASET_INDEPENDENT_WRITE_TEST_SPACE_RANK, &dims) < 0) + TEST_ERROR; + + if ((fspace_id = H5Screate_simple(DATASET_INDEPENDENT_WRITE_TEST_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + + /* create a dataset collectively */ + if ((dset_id1 = H5Dcreate2(group_id, DATASET_INDEPENDENT_WRITE_TEST_DSET_NAME1, + DATASET_INDEPENDENT_WRITE_TEST_DSET_DTYPE, fspace_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to create first dataset\n"); + goto error; + } + if ((dset_id2 = H5Dcreate2(group_id, DATASET_INDEPENDENT_WRITE_TEST_DSET_NAME2, + DATASET_INDEPENDENT_WRITE_TEST_DSET_DTYPE, fspace_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" failed to create second dataset\n"); + goto error; + } + + for (i = 1, data_size = 1; i < DATASET_INDEPENDENT_WRITE_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_INDEPENDENT_WRITE_TEST_DTYPE_SIZE; + + if (NULL == (write_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + goto error; + } + + for (i = 0; i < data_size / DATASET_INDEPENDENT_WRITE_TEST_DTYPE_SIZE; i++) + ((int *)write_buf)[i] = mpi_rank; + + for (i = 0; i < DATASET_INDEPENDENT_WRITE_TEST_SPACE_RANK; i++) { + if (i == 0) { + start[i] = (hsize_t)mpi_rank; + block[i] = 1; + } + else { + start[i] = 0; + block[i] = dims[i]; + } + + stride[i] = 1; + count[i] = 1; + } + + if (H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET, start, stride, count, block) < 0) { + H5_FAILED(); + HDprintf(" couldn't select hyperslab for dataset write\n"); + goto error; + } + + { + hsize_t mdims[] = {data_size / DATASET_INDEPENDENT_WRITE_TEST_DTYPE_SIZE}; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + goto error; + } + } + + /* + * To test the independent orders of writes between processes, all + * even number processes write to dataset1 first, then dataset2. + * All odd number processes write to dataset2 first, then dataset1. + */ + BEGIN_INDEPENDENT_OP(dset_write) + { + if (mpi_rank % 2 == 0) { + if (H5Dwrite(dset_id1, DATASET_INDEPENDENT_WRITE_TEST_DSET_DTYPE, mspace_id, fspace_id, + H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" even ranks failed to write to dataset 1\n"); + INDEPENDENT_OP_ERROR(dset_write); + } + if (H5Dwrite(dset_id2, DATASET_INDEPENDENT_WRITE_TEST_DSET_DTYPE, mspace_id, fspace_id, + H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" even ranks failed to write to dataset 2\n"); + INDEPENDENT_OP_ERROR(dset_write); + } + } + else { + if (H5Dwrite(dset_id2, DATASET_INDEPENDENT_WRITE_TEST_DSET_DTYPE, mspace_id, fspace_id, + H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" odd ranks failed to write to dataset 2\n"); + INDEPENDENT_OP_ERROR(dset_write); + } + if (H5Dwrite(dset_id1, DATASET_INDEPENDENT_WRITE_TEST_DSET_DTYPE, mspace_id, fspace_id, + H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" odd ranks failed to write to dataset 1\n"); + INDEPENDENT_OP_ERROR(dset_write); + } + } + } + END_INDEPENDENT_OP(dset_write); + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + + H5Sclose(mspace_id); + mspace_id = H5I_INVALID_HID; + H5Sclose(fspace_id); + fspace_id = H5I_INVALID_HID; + H5Dclose(dset_id1); + dset_id1 = H5I_INVALID_HID; + H5Dclose(dset_id2); + dset_id2 = H5I_INVALID_HID; + + /* + * Close and re-open the file to ensure that the data gets written. + */ + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close test's container group\n"); + goto error; + } + if (H5Gclose(container_group) < 0) { + H5_FAILED(); + HDprintf(" failed to close container group\n"); + goto error; + } + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close file for data flushing\n"); + goto error; + } + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't re-open file '%s'\n", H5_api_test_parallel_filename); + goto error; + } + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + if ((group_id = H5Gopen2(container_group, DATASET_INDEPENDENT_WRITE_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container sub-group '%s'\n", DATASET_INDEPENDENT_WRITE_TEST_GROUP_NAME); + goto error; + } + + if ((dset_id1 = H5Dopen2(group_id, DATASET_INDEPENDENT_WRITE_TEST_DSET_NAME1, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_INDEPENDENT_WRITE_TEST_DSET_NAME1); + goto error; + } + if ((dset_id2 = H5Dopen2(group_id, DATASET_INDEPENDENT_WRITE_TEST_DSET_NAME2, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_INDEPENDENT_WRITE_TEST_DSET_NAME2); + goto error; + } + + /* + * Verify that data has been written correctly. + */ + if ((fspace_id = H5Dget_space(dset_id1)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + goto error; + } + + if ((space_npoints = H5Sget_simple_extent_npoints(fspace_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataspace num points\n"); + goto error; + } + + if (NULL == (read_buf = HDmalloc((hsize_t)space_npoints * DATASET_INDEPENDENT_WRITE_TEST_DTYPE_SIZE))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + goto error; + } + + if (H5Dread(dset_id1, DATASET_INDEPENDENT_WRITE_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, H5P_DEFAULT, + read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", DATASET_INDEPENDENT_WRITE_TEST_DSET_NAME1); + goto error; + } + + for (i = 0; i < (size_t)mpi_size; i++) { + size_t j; + + for (j = 0; j < data_size / DATASET_INDEPENDENT_WRITE_TEST_DTYPE_SIZE; j++) { + if (((int *)read_buf)[j + (i * (data_size / DATASET_INDEPENDENT_WRITE_TEST_DTYPE_SIZE))] != + (int)i) { + H5_FAILED(); + HDprintf(" dataset 1 data verification failed\n"); + goto error; + } + } + } + + if (H5Dread(dset_id2, DATASET_INDEPENDENT_WRITE_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, H5P_DEFAULT, + read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", DATASET_INDEPENDENT_WRITE_TEST_DSET_NAME2); + goto error; + } + + for (i = 0; i < (size_t)mpi_size; i++) { + size_t j; + + for (j = 0; j < data_size / DATASET_INDEPENDENT_WRITE_TEST_DTYPE_SIZE; j++) { + if (((int *)read_buf)[j + (i * (data_size / DATASET_INDEPENDENT_WRITE_TEST_DTYPE_SIZE))] != + (int)i) { + H5_FAILED(); + HDprintf(" dataset 2 data verification failed\n"); + goto error; + } + } + } + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (dims) { + HDfree(dims); + dims = NULL; + } + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id1) < 0) + TEST_ERROR; + if (H5Dclose(dset_id2) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (read_buf) + HDfree(read_buf); + if (write_buf) + HDfree(write_buf); + if (dims) + HDfree(dims); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id1); + H5Dclose(dset_id2); + H5Gclose(group_id); + H5Gclose(container_group); + H5Pclose(fapl_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to ensure that a dataset can be written to by having + * one of the MPI ranks select 0 rows in a hyperslab selection. + */ +#define DATASET_WRITE_ONE_PROC_0_SEL_TEST_SPACE_RANK 2 +#define DATASET_WRITE_ONE_PROC_0_SEL_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_WRITE_ONE_PROC_0_SEL_TEST_DTYPE_SIZE sizeof(int) +#define DATASET_WRITE_ONE_PROC_0_SEL_TEST_GROUP_NAME "one_rank_0_sel_write_test" +#define DATASET_WRITE_ONE_PROC_0_SEL_TEST_DSET_NAME "one_rank_0_sel_dset" +static int +test_write_dataset_one_proc_0_selection(void) +{ + hssize_t space_npoints; + hsize_t *dims = NULL; + hsize_t start[DATASET_WRITE_ONE_PROC_0_SEL_TEST_SPACE_RANK]; + hsize_t stride[DATASET_WRITE_ONE_PROC_0_SEL_TEST_SPACE_RANK]; + hsize_t count[DATASET_WRITE_ONE_PROC_0_SEL_TEST_SPACE_RANK]; + hsize_t block[DATASET_WRITE_ONE_PROC_0_SEL_TEST_SPACE_RANK]; + size_t i, data_size; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + void *write_buf = NULL; + void *read_buf = NULL; + + TESTING("write to dataset with one rank selecting 0 rows"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, TRUE)) < 0) + TEST_ERROR; + + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_parallel_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_WRITE_ONE_PROC_0_SEL_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_WRITE_ONE_PROC_0_SEL_TEST_GROUP_NAME); + goto error; + } + + if (generate_random_parallel_dimensions(DATASET_WRITE_ONE_PROC_0_SEL_TEST_SPACE_RANK, &dims) < 0) + TEST_ERROR; + + if ((fspace_id = H5Screate_simple(DATASET_WRITE_ONE_PROC_0_SEL_TEST_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_WRITE_ONE_PROC_0_SEL_TEST_DSET_NAME, + DATASET_WRITE_ONE_PROC_0_SEL_TEST_DSET_DTYPE, fspace_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_WRITE_ONE_PROC_0_SEL_TEST_DSET_NAME); + goto error; + } + + for (i = 1, data_size = 1; i < DATASET_WRITE_ONE_PROC_0_SEL_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_WRITE_ONE_PROC_0_SEL_TEST_DTYPE_SIZE; + + BEGIN_INDEPENDENT_OP(write_buf_alloc) + { + if (!MAINPROCESS) { + if (NULL == (write_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + INDEPENDENT_OP_ERROR(write_buf_alloc); + } + + for (i = 0; i < data_size / DATASET_WRITE_ONE_PROC_0_SEL_TEST_DTYPE_SIZE; i++) + ((int *)write_buf)[i] = mpi_rank; + } + } + END_INDEPENDENT_OP(write_buf_alloc); + + for (i = 0; i < DATASET_WRITE_ONE_PROC_0_SEL_TEST_SPACE_RANK; i++) { + if (i == 0) { + start[i] = (hsize_t)mpi_rank; + block[i] = MAINPROCESS ? 0 : 1; + } + else { + start[i] = 0; + block[i] = MAINPROCESS ? 0 : dims[i]; + } + + stride[i] = 1; + count[i] = MAINPROCESS ? 0 : 1; + } + + if (H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET, start, stride, count, block) < 0) { + H5_FAILED(); + HDprintf(" couldn't select hyperslab for dataset write\n"); + goto error; + } + + { + hsize_t mdims[] = {data_size / DATASET_WRITE_ONE_PROC_0_SEL_TEST_DTYPE_SIZE}; + + if (MAINPROCESS) + mdims[0] = 0; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + goto error; + } + } + + BEGIN_INDEPENDENT_OP(dset_write) + { + if (H5Dwrite(dset_id, DATASET_WRITE_ONE_PROC_0_SEL_TEST_DSET_DTYPE, mspace_id, fspace_id, H5P_DEFAULT, + write_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", DATASET_WRITE_ONE_PROC_0_SEL_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_write); + } + } + END_INDEPENDENT_OP(dset_write); + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + if (mspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(mspace_id); + } + H5E_END_TRY; + mspace_id = H5I_INVALID_HID; + } + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + /* + * Close and re-open the file to ensure that the data gets written. + */ + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close test's container group\n"); + goto error; + } + if (H5Gclose(container_group) < 0) { + H5_FAILED(); + HDprintf(" failed to close container group\n"); + goto error; + } + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close file for data flushing\n"); + goto error; + } + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't re-open file '%s'\n", H5_api_test_parallel_filename); + goto error; + } + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + if ((group_id = H5Gopen2(container_group, DATASET_WRITE_ONE_PROC_0_SEL_TEST_GROUP_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't open container sub-group '%s'\n", + DATASET_WRITE_ONE_PROC_0_SEL_TEST_GROUP_NAME); + goto error; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_WRITE_ONE_PROC_0_SEL_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_WRITE_ONE_PROC_0_SEL_TEST_DSET_NAME); + goto error; + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + goto error; + } + + if ((space_npoints = H5Sget_simple_extent_npoints(fspace_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataspace num points\n"); + goto error; + } + + if (NULL == + (read_buf = HDmalloc((hsize_t)space_npoints * DATASET_WRITE_ONE_PROC_0_SEL_TEST_DTYPE_SIZE))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + goto error; + } + + if (H5Dread(dset_id, DATASET_WRITE_ONE_PROC_0_SEL_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, H5P_DEFAULT, + read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", DATASET_WRITE_ONE_PROC_0_SEL_TEST_DSET_NAME); + goto error; + } + + for (i = 0; i < (size_t)mpi_size; i++) { + size_t j; + + if (i != 0) { + for (j = 0; j < data_size / DATASET_WRITE_ONE_PROC_0_SEL_TEST_DTYPE_SIZE; j++) { + if (((int *)read_buf)[j + (i * (data_size / DATASET_WRITE_ONE_PROC_0_SEL_TEST_DTYPE_SIZE))] != + (int)i) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + goto error; + } + } + } + } + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (dims) { + HDfree(dims); + dims = NULL; + } + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (read_buf) + HDfree(read_buf); + if (write_buf) + HDfree(write_buf); + if (dims) + HDfree(dims); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Pclose(fapl_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to ensure that a dataset can be written to by having + * one of the MPI ranks call H5Sselect_none. + */ +#define DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_SPACE_RANK 2 +#define DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_DTYPE_SIZE sizeof(int) +#define DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_GROUP_NAME "one_rank_none_sel_write_test" +#define DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_DSET_NAME "one_rank_none_sel_dset" +static int +test_write_dataset_one_proc_none_selection(void) +{ + hssize_t space_npoints; + hsize_t *dims = NULL; + hsize_t start[DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_SPACE_RANK]; + hsize_t stride[DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_SPACE_RANK]; + hsize_t count[DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_SPACE_RANK]; + hsize_t block[DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_SPACE_RANK]; + size_t i, data_size; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + void *write_buf = NULL; + void *read_buf = NULL; + + TESTING("write to dataset with one rank using 'none' selection"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, TRUE)) < 0) + TEST_ERROR; + + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_parallel_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_GROUP_NAME); + goto error; + } + + if (generate_random_parallel_dimensions(DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_SPACE_RANK, &dims) < 0) + TEST_ERROR; + + if ((fspace_id = H5Screate_simple(DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_DSET_NAME, + DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_DSET_DTYPE, fspace_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_DSET_NAME); + goto error; + } + + for (i = 1, data_size = 1; i < DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_DTYPE_SIZE; + + BEGIN_INDEPENDENT_OP(write_buf_alloc) + { + if (!MAINPROCESS) { + if (NULL == (write_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + INDEPENDENT_OP_ERROR(write_buf_alloc); + } + + for (i = 0; i < data_size / DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_DTYPE_SIZE; i++) + ((int *)write_buf)[i] = mpi_rank; + } + } + END_INDEPENDENT_OP(write_buf_alloc); + + for (i = 0; i < DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_SPACE_RANK; i++) { + if (i == 0) { + start[i] = (hsize_t)mpi_rank; + block[i] = 1; + } + else { + start[i] = 0; + block[i] = dims[i]; + } + + stride[i] = 1; + count[i] = 1; + } + + BEGIN_INDEPENDENT_OP(set_space_sel) + { + if (MAINPROCESS) { + if (H5Sselect_none(fspace_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't set 'none' selection for dataset write\n"); + INDEPENDENT_OP_ERROR(set_space_sel); + } + } + else { + if (H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET, start, stride, count, block) < 0) { + H5_FAILED(); + HDprintf(" couldn't select hyperslab for dataset write\n"); + INDEPENDENT_OP_ERROR(set_space_sel); + } + } + } + END_INDEPENDENT_OP(set_space_sel); + + { + hsize_t mdims[] = {data_size / DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_DTYPE_SIZE}; + + if (MAINPROCESS) + mdims[0] = 0; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + goto error; + } + } + + BEGIN_INDEPENDENT_OP(dset_write) + { + if (H5Dwrite(dset_id, DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_DSET_DTYPE, mspace_id, fspace_id, + H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_write); + } + } + END_INDEPENDENT_OP(dset_write); + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + if (mspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(mspace_id); + } + H5E_END_TRY; + mspace_id = H5I_INVALID_HID; + } + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + /* + * Close and re-open the file to ensure that the data gets written. + */ + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close test's container group\n"); + goto error; + } + if (H5Gclose(container_group) < 0) { + H5_FAILED(); + HDprintf(" failed to close container group\n"); + goto error; + } + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close file for data flushing\n"); + goto error; + } + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't re-open file '%s'\n", H5_api_test_parallel_filename); + goto error; + } + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + if ((group_id = H5Gopen2(container_group, DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_GROUP_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't open container sub-group '%s'\n", + DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_GROUP_NAME); + goto error; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_DSET_NAME); + goto error; + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + goto error; + } + + if ((space_npoints = H5Sget_simple_extent_npoints(fspace_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataspace num points\n"); + goto error; + } + + if (NULL == + (read_buf = HDmalloc((hsize_t)space_npoints * DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_DTYPE_SIZE))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + goto error; + } + + if (H5Dread(dset_id, DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, H5P_DEFAULT, + read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_DSET_NAME); + goto error; + } + + for (i = 0; i < (size_t)mpi_size; i++) { + size_t j; + + if (i != 0) { + for (j = 0; j < data_size / DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_DTYPE_SIZE; j++) { + if (((int *) + read_buf)[j + (i * (data_size / DATASET_WRITE_ONE_PROC_NONE_SEL_TEST_DTYPE_SIZE))] != + (int)i) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + goto error; + } + } + } + } + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (dims) { + HDfree(dims); + dims = NULL; + } + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (read_buf) + HDfree(read_buf); + if (write_buf) + HDfree(write_buf); + if (dims) + HDfree(dims); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Pclose(fapl_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to ensure that a dataset can be written to by having + * one of the MPI ranks use an ALL selection, while the other + * ranks write nothing. + */ +#define DATASET_WRITE_ONE_PROC_ALL_SEL_TEST_SPACE_RANK 2 +#define DATASET_WRITE_ONE_PROC_ALL_SEL_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_WRITE_ONE_PROC_ALL_SEL_TEST_DTYPE_SIZE sizeof(int) +#define DATASET_WRITE_ONE_PROC_ALL_SEL_TEST_GROUP_NAME "one_rank_all_sel_write_test" +#define DATASET_WRITE_ONE_PROC_ALL_SEL_TEST_DSET_NAME "one_rank_all_sel_dset" +static int +test_write_dataset_one_proc_all_selection(void) +{ + hssize_t space_npoints; + hsize_t *dims = NULL; + size_t i, data_size; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + void *write_buf = NULL; + void *read_buf = NULL; + + TESTING("write to dataset with one rank using all selection; others none selection"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, TRUE)) < 0) + TEST_ERROR; + + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_parallel_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_WRITE_ONE_PROC_ALL_SEL_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_WRITE_ONE_PROC_ALL_SEL_TEST_GROUP_NAME); + goto error; + } + + if (generate_random_parallel_dimensions(DATASET_WRITE_ONE_PROC_ALL_SEL_TEST_SPACE_RANK, &dims) < 0) + TEST_ERROR; + + if ((fspace_id = H5Screate_simple(DATASET_WRITE_ONE_PROC_ALL_SEL_TEST_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_WRITE_ONE_PROC_ALL_SEL_TEST_DSET_NAME, + DATASET_WRITE_ONE_PROC_ALL_SEL_TEST_DSET_DTYPE, fspace_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_WRITE_ONE_PROC_ALL_SEL_TEST_DSET_NAME); + goto error; + } + + for (i = 0, data_size = 1; i < DATASET_WRITE_ONE_PROC_ALL_SEL_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_WRITE_ONE_PROC_ALL_SEL_TEST_DTYPE_SIZE; + + BEGIN_INDEPENDENT_OP(write_buf_alloc) + { + if (MAINPROCESS) { + if (NULL == (write_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + INDEPENDENT_OP_ERROR(write_buf_alloc); + } + + for (i = 0; i < data_size / DATASET_WRITE_ONE_PROC_ALL_SEL_TEST_DTYPE_SIZE; i++) + ((int *)write_buf)[i] = (int)i; + } + } + END_INDEPENDENT_OP(write_buf_alloc); + + BEGIN_INDEPENDENT_OP(set_space_sel) + { + if (MAINPROCESS) { + if (H5Sselect_all(fspace_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't set 'all' selection for dataset write\n"); + INDEPENDENT_OP_ERROR(set_space_sel); + } + } + else { + if (H5Sselect_none(fspace_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't set 'none' selection for dataset write\n"); + INDEPENDENT_OP_ERROR(set_space_sel); + } + } + } + END_INDEPENDENT_OP(set_space_sel); + + { + hsize_t mdims[] = {data_size / DATASET_WRITE_ONE_PROC_ALL_SEL_TEST_DTYPE_SIZE}; + + if (!MAINPROCESS) + mdims[0] = 0; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + goto error; + } + } + + BEGIN_INDEPENDENT_OP(dset_write) + { + if (H5Dwrite(dset_id, DATASET_WRITE_ONE_PROC_ALL_SEL_TEST_DSET_DTYPE, mspace_id, fspace_id, + H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", DATASET_WRITE_ONE_PROC_ALL_SEL_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_write); + } + } + END_INDEPENDENT_OP(dset_write); + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + if (mspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(mspace_id); + } + H5E_END_TRY; + mspace_id = H5I_INVALID_HID; + } + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + /* + * Close and re-open the file to ensure that the data gets written. + */ + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close test's container group\n"); + goto error; + } + if (H5Gclose(container_group) < 0) { + H5_FAILED(); + HDprintf(" failed to close container group\n"); + goto error; + } + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close file for data flushing\n"); + goto error; + } + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't re-open file '%s'\n", H5_api_test_parallel_filename); + goto error; + } + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + if ((group_id = H5Gopen2(container_group, DATASET_WRITE_ONE_PROC_ALL_SEL_TEST_GROUP_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't open container sub-group '%s'\n", + DATASET_WRITE_ONE_PROC_ALL_SEL_TEST_GROUP_NAME); + goto error; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_WRITE_ONE_PROC_ALL_SEL_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_WRITE_ONE_PROC_ALL_SEL_TEST_DSET_NAME); + goto error; + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + goto error; + } + + if ((space_npoints = H5Sget_simple_extent_npoints(fspace_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataspace num points\n"); + goto error; + } + + if (NULL == + (read_buf = HDmalloc((hsize_t)space_npoints * DATASET_WRITE_ONE_PROC_ALL_SEL_TEST_DTYPE_SIZE))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + goto error; + } + + if (H5Dread(dset_id, DATASET_WRITE_ONE_PROC_ALL_SEL_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, H5P_DEFAULT, + read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", DATASET_WRITE_ONE_PROC_ALL_SEL_TEST_DSET_NAME); + goto error; + } + + for (i = 0; i < data_size / DATASET_WRITE_ONE_PROC_ALL_SEL_TEST_DTYPE_SIZE; i++) { + if (((int *)read_buf)[i] != (int)i) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + goto error; + } + } + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (dims) { + HDfree(dims); + dims = NULL; + } + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (read_buf) + HDfree(read_buf); + if (write_buf) + HDfree(write_buf); + if (dims) + HDfree(dims); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Pclose(fapl_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to ensure that a dataset can be written to by having + * a hyperslab selection in the file dataspace and an all selection + * in the memory dataspace. + * + * XXX: Currently pulls from invalid memory locations. + */ +#define DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_SPACE_RANK 2 +#define DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_DTYPE_SIZE sizeof(int) +#define DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_GROUP_NAME "hyper_sel_file_all_sel_mem_write_test" +#define DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_DSET_NAME "hyper_sel_file_all_sel_mem_dset" +static int +test_write_dataset_hyper_file_all_mem(void) +{ +#ifdef BROKEN + hssize_t space_npoints; + hsize_t *dims = NULL; + hsize_t start[DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_SPACE_RANK]; + hsize_t stride[DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_SPACE_RANK]; + hsize_t count[DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_SPACE_RANK]; + hsize_t block[DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_SPACE_RANK]; + size_t i, data_size; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + void *write_buf = NULL; + void *read_buf = NULL; +#endif + + TESTING("write to dataset with hyperslab sel. for file space; all sel. for memory"); + +#ifdef BROKEN + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, TRUE)) < 0) + TEST_ERROR; + + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_parallel_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_GROUP_NAME); + goto error; + } + + if (generate_random_parallel_dimensions(DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_SPACE_RANK, &dims) < 0) + TEST_ERROR; + + if ((fspace_id = H5Screate_simple(DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_DSET_NAME, + DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_DSET_DTYPE, fspace_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_DSET_NAME); + goto error; + } + + for (i = 1, data_size = 1; i < DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_DTYPE_SIZE; + + if (NULL == (write_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + goto error; + } + + for (i = 0; i < data_size / DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_DTYPE_SIZE; i++) + ((int *)write_buf)[i] = mpi_rank; + + for (i = 0; i < DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_SPACE_RANK; i++) { + if (i == 0) { + start[i] = mpi_rank; + block[i] = 1; + } + else { + start[i] = 0; + block[i] = dims[i]; + } + + stride[i] = 1; + count[i] = 1; + } + + if (H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET, start, stride, count, block) < 0) { + H5_FAILED(); + HDprintf(" couldn't select hyperslab for dataset write\n"); + goto error; + } + + if (H5Dwrite(dset_id, DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_DSET_DTYPE, H5S_ALL, fspace_id, H5P_DEFAULT, + write_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_DSET_NAME); + goto error; + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + /* + * Close and re-open the file to ensure that the data gets written. + */ + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close test's container group\n"); + goto error; + } + if (H5Gclose(container_group) < 0) { + H5_FAILED(); + HDprintf(" failed to close container group\n"); + goto error; + } + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close file for data flushing\n"); + goto error; + } + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't re-open file '%s'\n", H5_api_test_parallel_filename); + goto error; + } + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + if ((group_id = + H5Gopen2(container_group, DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container sub-group '%s'\n", + DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_GROUP_NAME); + goto error; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_DSET_NAME); + goto error; + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + goto error; + } + + if ((space_npoints = H5Sget_simple_extent_npoints(fspace_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataspace num points\n"); + goto error; + } + + if (NULL == + (read_buf = HDmalloc((hsize_t)space_npoints * DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_DTYPE_SIZE))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + goto error; + } + + if (H5Dread(dset_id, DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, H5P_DEFAULT, + read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_DSET_NAME); + goto error; + } + + for (i = 0; i < (size_t)mpi_size; i++) { + size_t j; + + for (j = 0; j < data_size / DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_DTYPE_SIZE; j++) { + if (((int *)read_buf)[j + (i * (data_size / DATASET_WRITE_HYPER_FILE_ALL_MEM_TEST_DTYPE_SIZE))] != + (int)i) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + goto error; + } + } + } + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (dims) { + HDfree(dims); + dims = NULL; + } + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); +#else + SKIPPED(); +#endif + + return 0; + +#ifdef BROKEN +error: + H5E_BEGIN_TRY + { + if (read_buf) + HDfree(read_buf); + if (write_buf) + HDfree(write_buf); + if (dims) + HDfree(dims); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Pclose(fapl_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +#endif +} + +/* + * A test to ensure that a dataset can be written to by having + * an all selection in the file dataspace and a hyperslab + * selection in the memory dataspace. + */ +#define DATASET_WRITE_ALL_FILE_HYPER_MEM_TEST_SPACE_RANK 2 +#define DATASET_WRITE_ALL_FILE_HYPER_MEM_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_WRITE_ALL_FILE_HYPER_MEM_TEST_DTYPE_SIZE sizeof(int) +#define DATASET_WRITE_ALL_FILE_HYPER_MEM_TEST_GROUP_NAME "all_sel_file_hyper_sel_mem_write_test" +#define DATASET_WRITE_ALL_FILE_HYPER_MEM_TEST_DSET_NAME "all_sel_file_hyper_sel_mem_dset" +static int +test_write_dataset_all_file_hyper_mem(void) +{ + hssize_t space_npoints; + hsize_t *dims = NULL; + size_t i, data_size; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + void *write_buf = NULL; + void *read_buf = NULL; + + TESTING("write to dataset with all sel. for file space; hyperslab sel. for memory"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, TRUE)) < 0) + TEST_ERROR; + + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_parallel_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_WRITE_ALL_FILE_HYPER_MEM_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_WRITE_ALL_FILE_HYPER_MEM_TEST_GROUP_NAME); + goto error; + } + + if (generate_random_parallel_dimensions(DATASET_WRITE_ALL_FILE_HYPER_MEM_TEST_SPACE_RANK, &dims) < 0) + TEST_ERROR; + + if ((fspace_id = H5Screate_simple(DATASET_WRITE_ALL_FILE_HYPER_MEM_TEST_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_WRITE_ALL_FILE_HYPER_MEM_TEST_DSET_NAME, + DATASET_WRITE_ALL_FILE_HYPER_MEM_TEST_DSET_DTYPE, fspace_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_WRITE_ALL_FILE_HYPER_MEM_TEST_DSET_NAME); + goto error; + } + + for (i = 0, data_size = 1; i < DATASET_WRITE_ALL_FILE_HYPER_MEM_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_WRITE_ALL_FILE_HYPER_MEM_TEST_DTYPE_SIZE; + + BEGIN_INDEPENDENT_OP(write_buf_alloc) + { + if (MAINPROCESS) { + /* + * Allocate twice the amount of memory needed and leave "holes" in the memory + * buffer in order to prove that the mapping from hyperslab selection <-> all + * selection works correctly. + */ + if (NULL == (write_buf = HDmalloc(2 * data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + INDEPENDENT_OP_ERROR(write_buf_alloc); + } + + for (i = 0; i < 2 * (data_size / DATASET_WRITE_ALL_FILE_HYPER_MEM_TEST_DTYPE_SIZE); i++) { + /* Write actual data to even indices */ + if (i % 2 == 0) + ((int *)write_buf)[i] = (int)((i / 2) + (i % 2)); + else + ((int *)write_buf)[i] = 0; + } + } + } + END_INDEPENDENT_OP(write_buf_alloc); + + /* + * Only have rank 0 perform the dataset write, as writing the entire dataset on all ranks + * might be stressful on system resources. There's also no guarantee as to what the outcome + * would be, since the writes would be overlapping with each other. + */ + BEGIN_INDEPENDENT_OP(dset_write) + { + if (MAINPROCESS) { + hsize_t start[1] = {0}; + hsize_t stride[1] = {2}; + hsize_t count[1] = {data_size / DATASET_WRITE_ALL_FILE_HYPER_MEM_TEST_DTYPE_SIZE}; + hsize_t block[1] = {1}; + hsize_t mdims[] = {2 * (data_size / DATASET_WRITE_ALL_FILE_HYPER_MEM_TEST_DTYPE_SIZE)}; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + INDEPENDENT_OP_ERROR(dset_write); + } + + if (H5Sselect_hyperslab(mspace_id, H5S_SELECT_SET, start, stride, count, block) < 0) { + H5_FAILED(); + HDprintf(" couldn't select hyperslab for dataset write\n"); + INDEPENDENT_OP_ERROR(dset_write); + } + + if (H5Dwrite(dset_id, DATASET_WRITE_ALL_FILE_HYPER_MEM_TEST_DSET_DTYPE, mspace_id, H5S_ALL, + H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", + DATASET_WRITE_ALL_FILE_HYPER_MEM_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_write); + } + } + } + END_INDEPENDENT_OP(dset_write); + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + if (mspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(mspace_id); + } + H5E_END_TRY; + mspace_id = H5I_INVALID_HID; + } + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + /* + * Close and re-open the file to ensure that the data gets written. + */ + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close test's container group\n"); + goto error; + } + if (H5Gclose(container_group) < 0) { + H5_FAILED(); + HDprintf(" failed to close container group\n"); + goto error; + } + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close file for data flushing\n"); + goto error; + } + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't re-open file '%s'\n", H5_api_test_parallel_filename); + goto error; + } + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + if ((group_id = + H5Gopen2(container_group, DATASET_WRITE_ALL_FILE_HYPER_MEM_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container sub-group '%s'\n", + DATASET_WRITE_ALL_FILE_HYPER_MEM_TEST_GROUP_NAME); + goto error; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_WRITE_ALL_FILE_HYPER_MEM_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_WRITE_ALL_FILE_HYPER_MEM_TEST_DSET_NAME); + goto error; + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + goto error; + } + + if ((space_npoints = H5Sget_simple_extent_npoints(fspace_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataspace num points\n"); + goto error; + } + + if (NULL == + (read_buf = HDmalloc((hsize_t)space_npoints * DATASET_WRITE_ALL_FILE_HYPER_MEM_TEST_DTYPE_SIZE))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + goto error; + } + + if (H5Dread(dset_id, DATASET_WRITE_ALL_FILE_HYPER_MEM_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, H5P_DEFAULT, + read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", DATASET_WRITE_ALL_FILE_HYPER_MEM_TEST_DSET_NAME); + goto error; + } + + for (i = 0; i < data_size / DATASET_WRITE_ALL_FILE_HYPER_MEM_TEST_DTYPE_SIZE; i++) { + if (((int *)read_buf)[i] != (int)i) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + goto error; + } + } + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (dims) { + HDfree(dims); + dims = NULL; + } + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (read_buf) + HDfree(read_buf); + if (write_buf) + HDfree(write_buf); + if (dims) + HDfree(dims); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Pclose(fapl_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to ensure that a dataset can be written to by having + * a point selection in the file dataspace and an all selection + * in the memory dataspace. + */ +static int +test_write_dataset_point_file_all_mem(void) +{ + TESTING("write to dataset with point sel. for file space; all sel. for memory"); + + SKIPPED(); + + return 0; +} + +/* + * A test to ensure that a dataset can be written to by having + * an all selection in the file dataspace and a point selection + * in the memory dataspace. + */ +#define DATASET_WRITE_ALL_FILE_POINT_MEM_TEST_SPACE_RANK 2 +#define DATASET_WRITE_ALL_FILE_POINT_MEM_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_WRITE_ALL_FILE_POINT_MEM_TEST_DTYPE_SIZE sizeof(int) +#define DATASET_WRITE_ALL_FILE_POINT_MEM_TEST_GROUP_NAME "all_sel_file_point_sel_mem_write_test" +#define DATASET_WRITE_ALL_FILE_POINT_MEM_TEST_DSET_NAME "all_sel_file_point_sel_mem_dset" +static int +test_write_dataset_all_file_point_mem(void) +{ + hssize_t space_npoints; + hsize_t *points = NULL; + hsize_t *dims = NULL; + size_t i, data_size; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + void *write_buf = NULL; + void *read_buf = NULL; + + TESTING("write to dataset with all sel. for file space; point sel. for memory"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, TRUE)) < 0) + TEST_ERROR; + + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_parallel_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_WRITE_ALL_FILE_POINT_MEM_TEST_GROUP_NAME, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_WRITE_ALL_FILE_POINT_MEM_TEST_GROUP_NAME); + goto error; + } + + if (generate_random_parallel_dimensions(DATASET_WRITE_ALL_FILE_POINT_MEM_TEST_SPACE_RANK, &dims) < 0) + TEST_ERROR; + + if ((fspace_id = H5Screate_simple(DATASET_WRITE_ALL_FILE_POINT_MEM_TEST_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_WRITE_ALL_FILE_POINT_MEM_TEST_DSET_NAME, + DATASET_WRITE_ALL_FILE_POINT_MEM_TEST_DSET_DTYPE, fspace_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_WRITE_ALL_FILE_POINT_MEM_TEST_DSET_NAME); + goto error; + } + + for (i = 0, data_size = 1; i < DATASET_WRITE_ALL_FILE_POINT_MEM_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_WRITE_ALL_FILE_POINT_MEM_TEST_DTYPE_SIZE; + + BEGIN_INDEPENDENT_OP(write_buf_alloc) + { + if (MAINPROCESS) { + /* + * Allocate twice the amount of memory needed and leave "holes" in the memory + * buffer in order to prove that the mapping from point selection <-> all + * selection works correctly. + */ + if (NULL == (write_buf = HDmalloc(2 * data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + INDEPENDENT_OP_ERROR(write_buf_alloc); + } + + for (i = 0; i < 2 * (data_size / DATASET_WRITE_ALL_FILE_POINT_MEM_TEST_DTYPE_SIZE); i++) { + /* Write actual data to even indices */ + if (i % 2 == 0) + ((int *)write_buf)[i] = (int)((i / 2) + (i % 2)); + else + ((int *)write_buf)[i] = 0; + } + } + } + END_INDEPENDENT_OP(write_buf_alloc); + + /* + * Only have rank 0 perform the dataset write, as writing the entire dataset on all ranks + * might be stressful on system resources. There's also no guarantee as to what the outcome + * would be, since the writes would be overlapping with each other. + */ + BEGIN_INDEPENDENT_OP(dset_write) + { + if (MAINPROCESS) { + hsize_t mdims[] = {2 * (data_size / DATASET_WRITE_ALL_FILE_POINT_MEM_TEST_DTYPE_SIZE)}; + int j; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + INDEPENDENT_OP_ERROR(dset_write); + } + + if (NULL == (points = HDmalloc((data_size / DATASET_WRITE_ALL_FILE_POINT_MEM_TEST_DTYPE_SIZE) * + sizeof(hsize_t)))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for point selection\n"); + INDEPENDENT_OP_ERROR(dset_write); + } + + /* Select every other point in the 1-dimensional memory dataspace */ + for (i = 0, j = 0; i < 2 * (data_size / DATASET_WRITE_ALL_FILE_POINT_MEM_TEST_DTYPE_SIZE); i++) { + if (i % 2 == 0) + points[j++] = (hsize_t)i; + } + + if (H5Sselect_elements(mspace_id, H5S_SELECT_SET, + data_size / DATASET_WRITE_ALL_FILE_POINT_MEM_TEST_DTYPE_SIZE, + points) < 0) { + H5_FAILED(); + HDprintf(" couldn't set point selection for dataset write\n"); + INDEPENDENT_OP_ERROR(dset_write); + } + + if (H5Dwrite(dset_id, DATASET_WRITE_ALL_FILE_POINT_MEM_TEST_DSET_DTYPE, mspace_id, H5S_ALL, + H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", + DATASET_WRITE_ALL_FILE_POINT_MEM_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_write); + } + } + } + END_INDEPENDENT_OP(dset_write); + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + if (points) { + HDfree(points); + points = NULL; + } + if (mspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(mspace_id); + } + H5E_END_TRY; + mspace_id = H5I_INVALID_HID; + } + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + /* + * Close and re-open the file to ensure that the data gets written. + */ + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close test's container group\n"); + goto error; + } + if (H5Gclose(container_group) < 0) { + H5_FAILED(); + HDprintf(" failed to close container group\n"); + goto error; + } + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close file for data flushing\n"); + goto error; + } + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't re-open file '%s'\n", H5_api_test_parallel_filename); + goto error; + } + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + if ((group_id = + H5Gopen2(container_group, DATASET_WRITE_ALL_FILE_POINT_MEM_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container sub-group '%s'\n", + DATASET_WRITE_ALL_FILE_POINT_MEM_TEST_GROUP_NAME); + goto error; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_WRITE_ALL_FILE_POINT_MEM_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_WRITE_ALL_FILE_POINT_MEM_TEST_DSET_NAME); + goto error; + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + goto error; + } + + if ((space_npoints = H5Sget_simple_extent_npoints(fspace_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataspace num points\n"); + goto error; + } + + if (NULL == + (read_buf = HDmalloc((hsize_t)space_npoints * DATASET_WRITE_ALL_FILE_POINT_MEM_TEST_DTYPE_SIZE))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + goto error; + } + + if (H5Dread(dset_id, DATASET_WRITE_ALL_FILE_POINT_MEM_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, H5P_DEFAULT, + read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", DATASET_WRITE_ALL_FILE_POINT_MEM_TEST_DSET_NAME); + goto error; + } + + for (i = 0; i < data_size / DATASET_WRITE_ALL_FILE_POINT_MEM_TEST_DTYPE_SIZE; i++) { + if (((int *)read_buf)[i] != (int)i) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + goto error; + } + } + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (dims) { + HDfree(dims); + dims = NULL; + } + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (read_buf) + HDfree(read_buf); + if (write_buf) + HDfree(write_buf); + if (points) + HDfree(points); + if (dims) + HDfree(dims); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Pclose(fapl_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to ensure that a dataset can be written to by having + * a hyperslab selection in the file dataspace and a point + * selection in the memory dataspace. + */ +#define DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_SPACE_RANK 2 +#define DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_DTYPE_SIZE sizeof(int) +#define DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_GROUP_NAME "hyper_sel_file_point_sel_mem_write_test" +#define DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_DSET_NAME "hyper_sel_file_point_sel_mem_dset" +static int +test_write_dataset_hyper_file_point_mem(void) +{ + hssize_t space_npoints; + hsize_t *dims = NULL; + hsize_t *points = NULL; + hsize_t start[DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_SPACE_RANK]; + hsize_t stride[DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_SPACE_RANK]; + hsize_t count[DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_SPACE_RANK]; + hsize_t block[DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_SPACE_RANK]; + size_t i, data_size; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + void *write_buf = NULL; + void *read_buf = NULL; + + TESTING("write to dataset with hyperslab sel. for file space; point sel. for memory"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, TRUE)) < 0) + TEST_ERROR; + + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_parallel_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_GROUP_NAME); + goto error; + } + + if (generate_random_parallel_dimensions(DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_SPACE_RANK, &dims) < 0) + TEST_ERROR; + + if ((fspace_id = H5Screate_simple(DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_DSET_NAME, + DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_DSET_DTYPE, fspace_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_DSET_NAME); + goto error; + } + + for (i = 1, data_size = 1; i < DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_DTYPE_SIZE; + + /* + * Allocate twice the amount of memory needed and leave "holes" in the memory + * buffer in order to prove that the mapping from point selection <-> hyperslab + * selection works correctly. + */ + if (NULL == (write_buf = HDmalloc(2 * data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + goto error; + } + + for (i = 0; i < 2 * (data_size / DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_DTYPE_SIZE); i++) { + /* Write actual data to even indices */ + if (i % 2 == 0) + ((int *)write_buf)[i] = mpi_rank; + else + ((int *)write_buf)[i] = 0; + } + + for (i = 0; i < DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_SPACE_RANK; i++) { + if (i == 0) { + start[i] = (hsize_t)mpi_rank; + block[i] = 1; + } + else { + start[i] = 0; + block[i] = dims[i]; + } + + stride[i] = 1; + count[i] = 1; + } + + if (H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET, start, stride, count, block) < 0) { + H5_FAILED(); + HDprintf(" couldn't select hyperslab for dataset write\n"); + goto error; + } + + { + hsize_t mdims[] = {2 * (data_size / DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_DTYPE_SIZE)}; + int j; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + goto error; + } + + if (NULL == (points = HDmalloc((data_size / DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_DTYPE_SIZE) * + sizeof(hsize_t)))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for point selection\n"); + goto error; + } + + /* Select every other point in the 1-dimensional memory dataspace */ + for (i = 0, j = 0; i < 2 * (data_size / DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_DTYPE_SIZE); i++) { + if (i % 2 == 0) + points[j++] = (hsize_t)i; + } + + if (H5Sselect_elements(mspace_id, H5S_SELECT_SET, + data_size / DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_DTYPE_SIZE, points) < 0) { + H5_FAILED(); + HDprintf(" couldn't set point selection for dataset write\n"); + goto error; + } + } + + if (H5Dwrite(dset_id, DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_DSET_DTYPE, mspace_id, fspace_id, + H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_DSET_NAME); + goto error; + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + if (points) { + HDfree(points); + points = NULL; + } + if (mspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(mspace_id); + } + H5E_END_TRY; + mspace_id = H5I_INVALID_HID; + } + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + /* + * Close and re-open the file to ensure that the data gets written. + */ + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close test's container group\n"); + goto error; + } + if (H5Gclose(container_group) < 0) { + H5_FAILED(); + HDprintf(" failed to close container group\n"); + goto error; + } + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close file for data flushing\n"); + goto error; + } + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't re-open file '%s'\n", H5_api_test_parallel_filename); + goto error; + } + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + if ((group_id = H5Gopen2(container_group, DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_GROUP_NAME, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container sub-group '%s'\n", + DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_GROUP_NAME); + goto error; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_DSET_NAME); + goto error; + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + goto error; + } + + if ((space_npoints = H5Sget_simple_extent_npoints(fspace_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataspace num points\n"); + goto error; + } + + if (NULL == + (read_buf = HDmalloc((hsize_t)space_npoints * DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_DTYPE_SIZE))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + goto error; + } + + if (H5Dread(dset_id, DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, H5P_DEFAULT, + read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_DSET_NAME); + goto error; + } + + for (i = 0; i < (size_t)mpi_size; i++) { + size_t j; + + for (j = 0; j < data_size / DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_DTYPE_SIZE; j++) { + if (((int *) + read_buf)[j + (i * (data_size / DATASET_WRITE_HYPER_FILE_POINT_MEM_TEST_DTYPE_SIZE))] != + (int)i) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + goto error; + } + } + } + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (dims) { + HDfree(dims); + dims = NULL; + } + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (read_buf) + HDfree(read_buf); + if (write_buf) + HDfree(write_buf); + if (points) + HDfree(points); + if (dims) + HDfree(dims); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Pclose(fapl_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to ensure that a dataset can be written to by having + * a point selection in the file dataspace and a hyperslab + * selection in the memory dataspace. + */ +#define DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_SPACE_RANK 2 +#define DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_DTYPE_SIZE sizeof(int) +#define DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_GROUP_NAME "point_sel_file_hyper_sel_mem_write_test" +#define DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_DSET_NAME "point_sel_file_hyper_sel_mem_dset" +static int +test_write_dataset_point_file_hyper_mem(void) +{ + hssize_t space_npoints; + hsize_t *dims = NULL; + hsize_t *points = NULL; + size_t i, data_size; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + void *write_buf = NULL; + void *read_buf = NULL; + + TESTING("write to dataset with point sel. for file space; hyperslab sel. for memory"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, TRUE)) < 0) + TEST_ERROR; + + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_parallel_filename); + goto error; + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + + if ((group_id = H5Gcreate2(container_group, DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_GROUP_NAME); + goto error; + } + + if (generate_random_parallel_dimensions(DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_SPACE_RANK, &dims) < 0) + TEST_ERROR; + + if ((fspace_id = H5Screate_simple(DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_SPACE_RANK, dims, NULL)) < 0) + TEST_ERROR; + + if ((dset_id = H5Dcreate2(group_id, DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_DSET_NAME, + DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_DSET_DTYPE, fspace_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_DSET_NAME); + goto error; + } + + for (i = 1, data_size = 1; i < DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_DTYPE_SIZE; + + /* + * Allocate twice the amount of memory needed and leave "holes" in the memory + * buffer in order to prove that the mapping from hyperslab selection <-> point + * selection works correctly. + */ + if (NULL == (write_buf = HDmalloc(2 * data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + goto error; + } + + for (i = 0; i < 2 * (data_size / DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_DTYPE_SIZE); i++) { + /* Write actual data to even indices */ + if (i % 2 == 0) + ((int *)write_buf)[i] = mpi_rank; + else + ((int *)write_buf)[i] = 0; + } + + if (NULL == (points = HDmalloc((data_size / DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_DTYPE_SIZE) * + DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_SPACE_RANK * sizeof(hsize_t)))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for point selection\n"); + goto error; + } + + for (i = 0; i < data_size / DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_DTYPE_SIZE; i++) { + size_t j; + + for (j = 0; j < DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_SPACE_RANK; j++) { + size_t idx = (i * (size_t)DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_SPACE_RANK) + j; + + if (j == 0) + points[idx] = (hsize_t)mpi_rank; + else if (j != (size_t)DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_SPACE_RANK - 1) + points[idx] = i / dims[j + 1]; + else + points[idx] = i % dims[j]; + } + } + + if (H5Sselect_elements(fspace_id, H5S_SELECT_SET, + data_size / DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_DTYPE_SIZE, points) < 0) { + H5_FAILED(); + HDprintf(" couldn't set point selection for dataset write\n"); + goto error; + } + + { + hsize_t start[1] = {0}; + hsize_t stride[1] = {2}; + hsize_t count[1] = {data_size / DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_DTYPE_SIZE}; + hsize_t block[1] = {1}; + hsize_t mdims[] = {2 * (data_size / DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_DTYPE_SIZE)}; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + goto error; + } + + if (H5Sselect_hyperslab(mspace_id, H5S_SELECT_SET, start, stride, count, block) < 0) { + H5_FAILED(); + HDprintf(" couldn't set hyperslab selection for dataset write\n"); + goto error; + } + } + + if (H5Dwrite(dset_id, DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_DSET_DTYPE, mspace_id, fspace_id, + H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_DSET_NAME); + goto error; + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + if (points) { + HDfree(points); + points = NULL; + } + if (mspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(mspace_id); + } + H5E_END_TRY; + mspace_id = H5I_INVALID_HID; + } + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + /* + * Close and re-open the file to ensure that the data gets written. + */ + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close test's container group\n"); + goto error; + } + if (H5Gclose(container_group) < 0) { + H5_FAILED(); + HDprintf(" failed to close container group\n"); + goto error; + } + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close file for data flushing\n"); + goto error; + } + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't re-open file '%s'\n", H5_api_test_parallel_filename); + goto error; + } + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + if ((group_id = H5Gopen2(container_group, DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_GROUP_NAME, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container sub-group '%s'\n", + DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_GROUP_NAME); + goto error; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_DSET_NAME); + goto error; + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + goto error; + } + + if ((space_npoints = H5Sget_simple_extent_npoints(fspace_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataspace num points\n"); + goto error; + } + + if (NULL == + (read_buf = HDmalloc((hsize_t)space_npoints * DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_DTYPE_SIZE))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + goto error; + } + + if (H5Dread(dset_id, DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, H5P_DEFAULT, + read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_DSET_NAME); + goto error; + } + + for (i = 0; i < (size_t)mpi_size; i++) { + size_t j; + + for (j = 0; j < data_size / DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_DTYPE_SIZE; j++) { + if (((int *) + read_buf)[j + (i * (data_size / DATASET_WRITE_POINT_FILE_HYPER_MEM_TEST_DTYPE_SIZE))] != + (int)i) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + goto error; + } + } + } + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (dims) { + HDfree(dims); + dims = NULL; + } + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (read_buf) + HDfree(read_buf); + if (write_buf) + HDfree(write_buf); + if (points) + HDfree(points); + if (dims) + HDfree(dims); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Pclose(fapl_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to ensure that a dataset can be read from by having + * one of the MPI ranks select 0 rows in a hyperslab selection. + */ +#define DATASET_READ_ONE_PROC_0_SEL_TEST_SPACE_RANK 2 +#define DATASET_READ_ONE_PROC_0_SEL_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_READ_ONE_PROC_0_SEL_TEST_DTYPE_SIZE sizeof(int) +#define DATASET_READ_ONE_PROC_0_SEL_TEST_GROUP_NAME "one_rank_0_sel_read_test" +#define DATASET_READ_ONE_PROC_0_SEL_TEST_DSET_NAME "one_rank_0_sel_dset" +static int +test_read_dataset_one_proc_0_selection(void) +{ + hssize_t space_npoints; + hsize_t *dims = NULL; + hsize_t start[DATASET_READ_ONE_PROC_0_SEL_TEST_SPACE_RANK]; + hsize_t stride[DATASET_READ_ONE_PROC_0_SEL_TEST_SPACE_RANK]; + hsize_t count[DATASET_READ_ONE_PROC_0_SEL_TEST_SPACE_RANK]; + hsize_t block[DATASET_READ_ONE_PROC_0_SEL_TEST_SPACE_RANK]; + size_t i, data_size, read_buf_size; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + void *write_buf = NULL; + void *read_buf = NULL; + + TESTING("read from dataset with one rank selecting 0 rows"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if (generate_random_parallel_dimensions(DATASET_READ_ONE_PROC_0_SEL_TEST_SPACE_RANK, &dims) < 0) + TEST_ERROR; + + /* + * Have rank 0 create the dataset and completely fill it with data. + */ + BEGIN_INDEPENDENT_OP(dset_create) + { + if (MAINPROCESS) { + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_parallel_filename); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((group_id = H5Gcreate2(container_group, DATASET_READ_ONE_PROC_0_SEL_TEST_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_READ_ONE_PROC_0_SEL_TEST_GROUP_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((fspace_id = H5Screate_simple(DATASET_READ_ONE_PROC_0_SEL_TEST_SPACE_RANK, dims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" failed to create file dataspace for dataset\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((dset_id = H5Dcreate2(group_id, DATASET_READ_ONE_PROC_0_SEL_TEST_DSET_NAME, + DATASET_READ_ONE_PROC_0_SEL_TEST_DSET_DTYPE, fspace_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_READ_ONE_PROC_0_SEL_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + for (i = 0, data_size = 1; i < DATASET_READ_ONE_PROC_0_SEL_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_READ_ONE_PROC_0_SEL_TEST_DTYPE_SIZE; + + if (NULL == (write_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + for (i = 0; i < (size_t)mpi_size; i++) { + size_t j; + size_t elem_per_proc = (data_size / DATASET_READ_ONE_PROC_0_SEL_TEST_DTYPE_SIZE) / dims[0]; + + for (j = 0; j < elem_per_proc; j++) { + size_t idx = (i * elem_per_proc) + j; + + ((int *)write_buf)[idx] = (int)i; + } + } + + { + hsize_t mdims[] = {data_size / DATASET_READ_ONE_PROC_0_SEL_TEST_DTYPE_SIZE}; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + } + + if (H5Dwrite(dset_id, DATASET_READ_ONE_PROC_0_SEL_TEST_DSET_DTYPE, mspace_id, H5S_ALL, + H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", DATASET_READ_ONE_PROC_0_SEL_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + if (mspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(mspace_id); + } + H5E_END_TRY; + mspace_id = H5I_INVALID_HID; + } + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + /* + * Close and re-open the file to ensure that the data gets written. + */ + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close test's container group\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + if (H5Gclose(container_group) < 0) { + H5_FAILED(); + HDprintf(" failed to close container group\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close file for data flushing\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + } + } + END_INDEPENDENT_OP(dset_create); + + /* + * Re-open file on all ranks. + */ + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, TRUE)) < 0) + TEST_ERROR; + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't re-open file '%s'\n", H5_api_test_parallel_filename); + goto error; + } + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + if ((group_id = H5Gopen2(container_group, DATASET_READ_ONE_PROC_0_SEL_TEST_GROUP_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't open container sub-group '%s'\n", DATASET_READ_ONE_PROC_0_SEL_TEST_GROUP_NAME); + goto error; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_READ_ONE_PROC_0_SEL_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_READ_ONE_PROC_0_SEL_TEST_DSET_NAME); + goto error; + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + goto error; + } + + if ((space_npoints = H5Sget_simple_extent_npoints(fspace_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataspace num points\n"); + goto error; + } + + BEGIN_INDEPENDENT_OP(read_buf_alloc) + { + if (!MAINPROCESS) { + read_buf_size = + ((size_t)(space_npoints / mpi_size) * DATASET_READ_ONE_PROC_0_SEL_TEST_DTYPE_SIZE); + + if (NULL == (read_buf = HDmalloc(read_buf_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + INDEPENDENT_OP_ERROR(read_buf_alloc); + } + } + } + END_INDEPENDENT_OP(read_buf_alloc); + + { + hsize_t mdims[] = {(hsize_t)space_npoints / (hsize_t)mpi_size}; + + if (MAINPROCESS) + mdims[0] = 0; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + goto error; + } + } + + for (i = 0; i < DATASET_READ_ONE_PROC_0_SEL_TEST_SPACE_RANK; i++) { + if (i == 0) { + start[i] = (hsize_t)mpi_rank; + block[i] = MAINPROCESS ? 0 : 1; + } + else { + start[i] = 0; + block[i] = MAINPROCESS ? 0 : dims[i]; + } + + stride[i] = 1; + count[i] = MAINPROCESS ? 0 : 1; + } + + if (H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET, start, stride, count, block) < 0) { + H5_FAILED(); + HDprintf(" couldn't select hyperslab for dataset read\n"); + goto error; + } + + BEGIN_INDEPENDENT_OP(dset_read) + { + if (H5Dread(dset_id, DATASET_READ_ONE_PROC_0_SEL_TEST_DSET_DTYPE, mspace_id, fspace_id, H5P_DEFAULT, + read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", DATASET_READ_ONE_PROC_0_SEL_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_read); + } + } + END_INDEPENDENT_OP(dset_read); + + BEGIN_INDEPENDENT_OP(data_verify) + { + if (!MAINPROCESS) { + for (i = 0; i < (size_t)space_npoints / (size_t)mpi_size; i++) { + if (((int *)read_buf)[i] != mpi_rank) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + INDEPENDENT_OP_ERROR(data_verify); + } + } + } + } + END_INDEPENDENT_OP(data_verify); + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (dims) { + HDfree(dims); + dims = NULL; + } + + if (H5Sclose(mspace_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (read_buf) + HDfree(read_buf); + if (write_buf) + HDfree(write_buf); + if (dims) + HDfree(dims); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Pclose(fapl_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to ensure that a dataset can be read from by having + * one of the MPI ranks call H5Sselect_none. + */ +#define DATASET_READ_ONE_PROC_NONE_SEL_TEST_SPACE_RANK 2 +#define DATASET_READ_ONE_PROC_NONE_SEL_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_READ_ONE_PROC_NONE_SEL_TEST_DTYPE_SIZE sizeof(int) +#define DATASET_READ_ONE_PROC_NONE_SEL_TEST_GROUP_NAME "one_rank_none_sel_read_test" +#define DATASET_READ_ONE_PROC_NONE_SEL_TEST_DSET_NAME "one_rank_none_sel_dset" +static int +test_read_dataset_one_proc_none_selection(void) +{ + hssize_t space_npoints; + hsize_t *dims = NULL; + hsize_t start[DATASET_READ_ONE_PROC_NONE_SEL_TEST_SPACE_RANK]; + hsize_t stride[DATASET_READ_ONE_PROC_NONE_SEL_TEST_SPACE_RANK]; + hsize_t count[DATASET_READ_ONE_PROC_NONE_SEL_TEST_SPACE_RANK]; + hsize_t block[DATASET_READ_ONE_PROC_NONE_SEL_TEST_SPACE_RANK]; + size_t i, data_size, read_buf_size; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + void *write_buf = NULL; + void *read_buf = NULL; + + TESTING("read from dataset with one rank using 'none' selection"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if (generate_random_parallel_dimensions(DATASET_READ_ONE_PROC_NONE_SEL_TEST_SPACE_RANK, &dims) < 0) + TEST_ERROR; + + /* + * Have rank 0 create the dataset and completely fill it with data. + */ + BEGIN_INDEPENDENT_OP(dset_create) + { + if (MAINPROCESS) { + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_parallel_filename); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((group_id = H5Gcreate2(container_group, DATASET_READ_ONE_PROC_NONE_SEL_TEST_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_READ_ONE_PROC_NONE_SEL_TEST_GROUP_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((fspace_id = H5Screate_simple(DATASET_READ_ONE_PROC_NONE_SEL_TEST_SPACE_RANK, dims, NULL)) < + 0) { + H5_FAILED(); + HDprintf(" failed to create file dataspace for dataset\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((dset_id = H5Dcreate2(group_id, DATASET_READ_ONE_PROC_NONE_SEL_TEST_DSET_NAME, + DATASET_READ_ONE_PROC_NONE_SEL_TEST_DSET_DTYPE, fspace_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_READ_ONE_PROC_NONE_SEL_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + for (i = 0, data_size = 1; i < DATASET_READ_ONE_PROC_NONE_SEL_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_READ_ONE_PROC_NONE_SEL_TEST_DTYPE_SIZE; + + if (NULL == (write_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + for (i = 0; i < (size_t)mpi_size; i++) { + size_t j; + size_t elem_per_proc = (data_size / DATASET_READ_ONE_PROC_NONE_SEL_TEST_DTYPE_SIZE) / dims[0]; + + for (j = 0; j < elem_per_proc; j++) { + size_t idx = (i * elem_per_proc) + j; + + ((int *)write_buf)[idx] = (int)i; + } + } + + { + hsize_t mdims[] = {data_size / DATASET_READ_ONE_PROC_NONE_SEL_TEST_DTYPE_SIZE}; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + } + + if (H5Dwrite(dset_id, DATASET_READ_ONE_PROC_NONE_SEL_TEST_DSET_DTYPE, mspace_id, H5S_ALL, + H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", + DATASET_READ_ONE_PROC_NONE_SEL_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + if (mspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(mspace_id); + } + H5E_END_TRY; + mspace_id = H5I_INVALID_HID; + } + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + /* + * Close and re-open the file to ensure that the data gets written. + */ + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close test's container group\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + if (H5Gclose(container_group) < 0) { + H5_FAILED(); + HDprintf(" failed to close container group\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close file for data flushing\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + } + } + END_INDEPENDENT_OP(dset_create); + + /* + * Re-open file on all ranks. + */ + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, TRUE)) < 0) + TEST_ERROR; + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't re-open file '%s'\n", H5_api_test_parallel_filename); + goto error; + } + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + if ((group_id = H5Gopen2(container_group, DATASET_READ_ONE_PROC_NONE_SEL_TEST_GROUP_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't open container sub-group '%s'\n", + DATASET_READ_ONE_PROC_NONE_SEL_TEST_GROUP_NAME); + goto error; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_READ_ONE_PROC_NONE_SEL_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_READ_ONE_PROC_NONE_SEL_TEST_DSET_NAME); + goto error; + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + goto error; + } + + if ((space_npoints = H5Sget_simple_extent_npoints(fspace_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataspace num points\n"); + goto error; + } + + BEGIN_INDEPENDENT_OP(read_buf_alloc) + { + if (!MAINPROCESS) { + read_buf_size = + ((size_t)(space_npoints / mpi_size) * DATASET_READ_ONE_PROC_NONE_SEL_TEST_DTYPE_SIZE); + + if (NULL == (read_buf = HDmalloc(read_buf_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + INDEPENDENT_OP_ERROR(read_buf_alloc); + } + } + } + END_INDEPENDENT_OP(read_buf_alloc); + + { + hsize_t mdims[] = {(hsize_t)space_npoints / (hsize_t)mpi_size}; + + if (MAINPROCESS) + mdims[0] = 0; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + goto error; + } + } + + for (i = 0; i < DATASET_READ_ONE_PROC_NONE_SEL_TEST_SPACE_RANK; i++) { + if (i == 0) { + start[i] = (hsize_t)mpi_rank; + block[i] = 1; + } + else { + start[i] = 0; + block[i] = dims[i]; + } + + stride[i] = 1; + count[i] = 1; + } + + BEGIN_INDEPENDENT_OP(set_space_sel) + { + if (MAINPROCESS) { + if (H5Sselect_none(fspace_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't set 'none' selection for dataset read\n"); + INDEPENDENT_OP_ERROR(set_space_sel); + } + } + else { + if (H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET, start, stride, count, block) < 0) { + H5_FAILED(); + HDprintf(" couldn't select hyperslab for dataset read\n"); + INDEPENDENT_OP_ERROR(set_space_sel); + } + } + } + END_INDEPENDENT_OP(set_space_sel); + + BEGIN_INDEPENDENT_OP(dset_read) + { + if (H5Dread(dset_id, DATASET_READ_ONE_PROC_NONE_SEL_TEST_DSET_DTYPE, mspace_id, fspace_id, + H5P_DEFAULT, read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", DATASET_READ_ONE_PROC_NONE_SEL_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_read); + } + } + END_INDEPENDENT_OP(dset_read); + + BEGIN_INDEPENDENT_OP(data_verify) + { + if (!MAINPROCESS) { + for (i = 0; i < (size_t)space_npoints / (size_t)mpi_size; i++) { + if (((int *)read_buf)[i] != mpi_rank) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + INDEPENDENT_OP_ERROR(data_verify); + } + } + } + } + END_INDEPENDENT_OP(data_verify); + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (dims) { + HDfree(dims); + dims = NULL; + } + + if (H5Sclose(mspace_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (read_buf) + HDfree(read_buf); + if (write_buf) + HDfree(write_buf); + if (dims) + HDfree(dims); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Pclose(fapl_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to ensure that a dataset can be read from by having + * one of the MPI ranks use an ALL selection, while the other + * ranks read nothing. + */ +#define DATASET_READ_ONE_PROC_ALL_SEL_TEST_SPACE_RANK 2 +#define DATASET_READ_ONE_PROC_ALL_SEL_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_READ_ONE_PROC_ALL_SEL_TEST_DTYPE_SIZE sizeof(int) +#define DATASET_READ_ONE_PROC_ALL_SEL_TEST_GROUP_NAME "one_rank_all_sel_read_test" +#define DATASET_READ_ONE_PROC_ALL_SEL_TEST_DSET_NAME "one_rank_all_sel_dset" +static int +test_read_dataset_one_proc_all_selection(void) +{ + hssize_t space_npoints; + hsize_t *dims = NULL; + size_t i, data_size, read_buf_size; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + void *write_buf = NULL; + void *read_buf = NULL; + + TESTING("read from dataset with one rank using all selection; others none selection"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if (generate_random_parallel_dimensions(DATASET_READ_ONE_PROC_ALL_SEL_TEST_SPACE_RANK, &dims) < 0) + TEST_ERROR; + + /* + * Have rank 0 create the dataset and completely fill it with data. + */ + BEGIN_INDEPENDENT_OP(dset_create) + { + if (MAINPROCESS) { + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_parallel_filename); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((group_id = H5Gcreate2(container_group, DATASET_READ_ONE_PROC_ALL_SEL_TEST_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_READ_ONE_PROC_ALL_SEL_TEST_GROUP_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((fspace_id = H5Screate_simple(DATASET_READ_ONE_PROC_ALL_SEL_TEST_SPACE_RANK, dims, NULL)) < + 0) { + H5_FAILED(); + HDprintf(" failed to create file dataspace for dataset\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((dset_id = H5Dcreate2(group_id, DATASET_READ_ONE_PROC_ALL_SEL_TEST_DSET_NAME, + DATASET_READ_ONE_PROC_ALL_SEL_TEST_DSET_DTYPE, fspace_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", DATASET_READ_ONE_PROC_ALL_SEL_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + for (i = 0, data_size = 1; i < DATASET_READ_ONE_PROC_ALL_SEL_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_READ_ONE_PROC_ALL_SEL_TEST_DTYPE_SIZE; + + if (NULL == (write_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + for (i = 0; i < (size_t)mpi_size; i++) { + size_t j; + size_t elem_per_proc = (data_size / DATASET_READ_ONE_PROC_ALL_SEL_TEST_DTYPE_SIZE) / dims[0]; + + for (j = 0; j < elem_per_proc; j++) { + size_t idx = (i * elem_per_proc) + j; + + ((int *)write_buf)[idx] = (int)i; + } + } + + { + hsize_t mdims[] = {data_size / DATASET_READ_ONE_PROC_ALL_SEL_TEST_DTYPE_SIZE}; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + } + + if (H5Dwrite(dset_id, DATASET_READ_ONE_PROC_ALL_SEL_TEST_DSET_DTYPE, mspace_id, H5S_ALL, + H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", + DATASET_READ_ONE_PROC_ALL_SEL_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + if (mspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(mspace_id); + } + H5E_END_TRY; + mspace_id = H5I_INVALID_HID; + } + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + /* + * Close and re-open the file to ensure that the data gets written. + */ + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close test's container group\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + if (H5Gclose(container_group) < 0) { + H5_FAILED(); + HDprintf(" failed to close container group\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close file for data flushing\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + } + } + END_INDEPENDENT_OP(dset_create); + + /* + * Re-open file on all ranks. + */ + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, TRUE)) < 0) + TEST_ERROR; + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't re-open file '%s'\n", H5_api_test_parallel_filename); + goto error; + } + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + if ((group_id = H5Gopen2(container_group, DATASET_READ_ONE_PROC_ALL_SEL_TEST_GROUP_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't open container sub-group '%s'\n", + DATASET_READ_ONE_PROC_ALL_SEL_TEST_GROUP_NAME); + goto error; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_READ_ONE_PROC_ALL_SEL_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_READ_ONE_PROC_ALL_SEL_TEST_DSET_NAME); + goto error; + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + goto error; + } + + if ((space_npoints = H5Sget_simple_extent_npoints(fspace_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataspace num points\n"); + goto error; + } + + BEGIN_INDEPENDENT_OP(read_buf_alloc) + { + if (MAINPROCESS) { + read_buf_size = (size_t)space_npoints * DATASET_READ_ONE_PROC_ALL_SEL_TEST_DTYPE_SIZE; + + if (NULL == (read_buf = HDmalloc(read_buf_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + INDEPENDENT_OP_ERROR(read_buf_alloc); + } + } + } + END_INDEPENDENT_OP(read_buf_alloc); + + { + hsize_t mdims[] = {(hsize_t)space_npoints}; + + if (!MAINPROCESS) + mdims[0] = 0; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + goto error; + } + } + + BEGIN_INDEPENDENT_OP(set_space_sel) + { + if (MAINPROCESS) { + if (H5Sselect_all(fspace_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't set 'all' selection for dataset read\n"); + INDEPENDENT_OP_ERROR(set_space_sel); + } + } + else { + if (H5Sselect_none(fspace_id) < 0) { + H5_FAILED(); + HDprintf(" couldn't set 'none' selection for dataset read\n"); + INDEPENDENT_OP_ERROR(set_space_sel); + } + } + } + END_INDEPENDENT_OP(set_space_sel); + + BEGIN_INDEPENDENT_OP(dset_read) + { + if (H5Dread(dset_id, DATASET_READ_ONE_PROC_ALL_SEL_TEST_DSET_DTYPE, mspace_id, fspace_id, H5P_DEFAULT, + read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", DATASET_READ_ONE_PROC_ALL_SEL_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_read); + } + } + END_INDEPENDENT_OP(dset_read); + + BEGIN_INDEPENDENT_OP(data_verify) + { + if (MAINPROCESS) { + for (i = 0; i < (size_t)mpi_size; i++) { + size_t j; + size_t elem_per_proc = (size_t)(space_npoints / mpi_size); + + for (j = 0; j < elem_per_proc; j++) { + int idx = (int)((i * elem_per_proc) + j); + + if (((int *)read_buf)[idx] != (int)i) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + INDEPENDENT_OP_ERROR(data_verify); + } + } + } + } + } + END_INDEPENDENT_OP(data_verify); + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (dims) { + HDfree(dims); + dims = NULL; + } + + if (H5Sclose(mspace_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (read_buf) + HDfree(read_buf); + if (write_buf) + HDfree(write_buf); + if (dims) + HDfree(dims); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Pclose(fapl_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to ensure that a dataset can be read from by having + * a hyperslab selection in the file dataspace and an all + * selection in the memory dataspace. + */ +static int +test_read_dataset_hyper_file_all_mem(void) +{ + TESTING("read from dataset with hyperslab sel. for file space; all sel. for memory"); + + SKIPPED(); + + return 0; +} + +/* + * A test to ensure that a dataset can be read from by having + * an all selection in the file dataspace and a hyperslab + * selection in the memory dataspace. + */ +#define DATASET_READ_ALL_FILE_HYPER_MEM_TEST_SPACE_RANK 2 +#define DATASET_READ_ALL_FILE_HYPER_MEM_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_READ_ALL_FILE_HYPER_MEM_TEST_DTYPE_SIZE sizeof(int) +#define DATASET_READ_ALL_FILE_HYPER_MEM_TEST_GROUP_NAME "all_sel_file_hyper_sel_mem_read_test" +#define DATASET_READ_ALL_FILE_HYPER_MEM_TEST_DSET_NAME "all_sel_file_hyper_sel_mem_dset" +static int +test_read_dataset_all_file_hyper_mem(void) +{ + hssize_t space_npoints; + hsize_t *dims = NULL; + size_t i, data_size, read_buf_size; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + void *write_buf = NULL; + void *read_buf = NULL; + + TESTING("read from dataset with all sel. for file space; hyperslab sel. for memory"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if (generate_random_parallel_dimensions(DATASET_READ_ALL_FILE_HYPER_MEM_TEST_SPACE_RANK, &dims) < 0) + TEST_ERROR; + + /* + * Have rank 0 create the dataset and completely fill it with data. + */ + BEGIN_INDEPENDENT_OP(dset_create) + { + if (MAINPROCESS) { + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_parallel_filename); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((group_id = H5Gcreate2(container_group, DATASET_READ_ALL_FILE_HYPER_MEM_TEST_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_READ_ALL_FILE_HYPER_MEM_TEST_GROUP_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((fspace_id = H5Screate_simple(DATASET_READ_ALL_FILE_HYPER_MEM_TEST_SPACE_RANK, dims, NULL)) < + 0) { + H5_FAILED(); + HDprintf(" failed to create file dataspace for dataset\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((dset_id = H5Dcreate2(group_id, DATASET_READ_ALL_FILE_HYPER_MEM_TEST_DSET_NAME, + DATASET_READ_ALL_FILE_HYPER_MEM_TEST_DSET_DTYPE, fspace_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", + DATASET_READ_ALL_FILE_HYPER_MEM_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + for (i = 0, data_size = 1; i < DATASET_READ_ALL_FILE_HYPER_MEM_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_READ_ALL_FILE_HYPER_MEM_TEST_DTYPE_SIZE; + + if (NULL == (write_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + for (i = 0; i < (size_t)mpi_size; i++) { + size_t j; + size_t elem_per_proc = + (data_size / DATASET_READ_ALL_FILE_HYPER_MEM_TEST_DTYPE_SIZE) / dims[0]; + + for (j = 0; j < elem_per_proc; j++) { + size_t idx = (i * elem_per_proc) + j; + + ((int *)write_buf)[idx] = (int)i; + } + } + + { + hsize_t mdims[] = {data_size / DATASET_READ_ALL_FILE_HYPER_MEM_TEST_DTYPE_SIZE}; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + } + + if (H5Dwrite(dset_id, DATASET_READ_ALL_FILE_HYPER_MEM_TEST_DSET_DTYPE, mspace_id, H5S_ALL, + H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", + DATASET_READ_ALL_FILE_HYPER_MEM_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + if (mspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(mspace_id); + } + H5E_END_TRY; + mspace_id = H5I_INVALID_HID; + } + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + /* + * Close and re-open the file to ensure that the data gets written. + */ + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close test's container group\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + if (H5Gclose(container_group) < 0) { + H5_FAILED(); + HDprintf(" failed to close container group\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close file for data flushing\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + } + } + END_INDEPENDENT_OP(dset_create); + + /* + * Re-open file on all ranks. + */ + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, TRUE)) < 0) + TEST_ERROR; + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't re-open file '%s'\n", H5_api_test_parallel_filename); + goto error; + } + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + if ((group_id = H5Gopen2(container_group, DATASET_READ_ALL_FILE_HYPER_MEM_TEST_GROUP_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't open container sub-group '%s'\n", + DATASET_READ_ALL_FILE_HYPER_MEM_TEST_GROUP_NAME); + goto error; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_READ_ALL_FILE_HYPER_MEM_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_READ_ALL_FILE_HYPER_MEM_TEST_DSET_NAME); + goto error; + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + goto error; + } + + if ((space_npoints = H5Sget_simple_extent_npoints(fspace_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataspace num points\n"); + goto error; + } + + /* + * Only have rank 0 perform the dataset read, as reading the entire dataset on all ranks + * might be stressful on system resources. + */ + BEGIN_INDEPENDENT_OP(dset_read) + { + if (MAINPROCESS) { + hsize_t start[1] = {0}; + hsize_t stride[1] = {2}; + hsize_t count[1] = {(hsize_t)space_npoints}; + hsize_t block[1] = {1}; + hsize_t mdims[] = {(hsize_t)(2 * space_npoints)}; + + /* + * Allocate twice the amount of memory needed and leave "holes" in the memory + * buffer in order to prove that the mapping from all selection <-> hyperslab + * selection works correctly. + */ + read_buf_size = (size_t)(2 * space_npoints) * DATASET_READ_ALL_FILE_HYPER_MEM_TEST_DTYPE_SIZE; + if (NULL == (read_buf = HDcalloc(1, read_buf_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + INDEPENDENT_OP_ERROR(dset_read); + } + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + INDEPENDENT_OP_ERROR(dset_read); + } + + if (H5Sselect_hyperslab(mspace_id, H5S_SELECT_SET, start, stride, count, block) < 0) { + H5_FAILED(); + HDprintf(" couldn't select hyperslab for dataset read\n"); + INDEPENDENT_OP_ERROR(dset_read); + } + + if (H5Dread(dset_id, DATASET_READ_ALL_FILE_HYPER_MEM_TEST_DSET_DTYPE, mspace_id, H5S_ALL, + H5P_DEFAULT, read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", + DATASET_READ_ALL_FILE_HYPER_MEM_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_read); + } + + for (i = 0; i < (size_t)mpi_size; i++) { + size_t j; + size_t elem_per_proc = (size_t)(space_npoints / mpi_size); + + for (j = 0; j < 2 * elem_per_proc; j++) { + size_t idx = (i * 2 * elem_per_proc) + j; + + if (j % 2 == 0) { + if (((int *)read_buf)[idx] != (int)i) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + INDEPENDENT_OP_ERROR(dset_read); + } + } + else { + if (((int *)read_buf)[idx] != 0) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + INDEPENDENT_OP_ERROR(dset_read); + } + } + } + } + } + } + END_INDEPENDENT_OP(dset_read); + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (dims) { + HDfree(dims); + dims = NULL; + } + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (read_buf) + HDfree(read_buf); + if (write_buf) + HDfree(write_buf); + if (dims) + HDfree(dims); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Pclose(fapl_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to ensure that a dataset can be read from by having + * a point selection in the file dataspace and an all selection + * in the memory dataspace. + */ +static int +test_read_dataset_point_file_all_mem(void) +{ + TESTING("read from dataset with point sel. for file space; all sel. for memory"); + + SKIPPED(); + + return 0; +} + +/* + * A test to ensure that a dataset can be read from by having + * an all selection in the file dataspace and a point selection + * in the memory dataspace. + */ +#define DATASET_READ_ALL_FILE_POINT_MEM_TEST_SPACE_RANK 2 +#define DATASET_READ_ALL_FILE_POINT_MEM_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_READ_ALL_FILE_POINT_MEM_TEST_DTYPE_SIZE sizeof(int) +#define DATASET_READ_ALL_FILE_POINT_MEM_TEST_GROUP_NAME "all_sel_file_point_sel_mem_read_test" +#define DATASET_READ_ALL_FILE_POINT_MEM_TEST_DSET_NAME "all_sel_file_point_sel_mem_dset" +static int +test_read_dataset_all_file_point_mem(void) +{ + hssize_t space_npoints; + hsize_t *points = NULL; + hsize_t *dims = NULL; + size_t i, data_size, read_buf_size; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + void *write_buf = NULL; + void *read_buf = NULL; + + TESTING("read from dataset with all sel. for file space; point sel. for memory"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if (generate_random_parallel_dimensions(DATASET_READ_ALL_FILE_POINT_MEM_TEST_SPACE_RANK, &dims) < 0) + TEST_ERROR; + + /* + * Have rank 0 create the dataset and completely fill it with data. + */ + BEGIN_INDEPENDENT_OP(dset_create) + { + if (MAINPROCESS) { + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_parallel_filename); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((group_id = H5Gcreate2(container_group, DATASET_READ_ALL_FILE_POINT_MEM_TEST_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_READ_ALL_FILE_POINT_MEM_TEST_GROUP_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((fspace_id = H5Screate_simple(DATASET_READ_ALL_FILE_POINT_MEM_TEST_SPACE_RANK, dims, NULL)) < + 0) { + H5_FAILED(); + HDprintf(" failed to create file dataspace for dataset\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((dset_id = H5Dcreate2(group_id, DATASET_READ_ALL_FILE_POINT_MEM_TEST_DSET_NAME, + DATASET_READ_ALL_FILE_POINT_MEM_TEST_DSET_DTYPE, fspace_id, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", + DATASET_READ_ALL_FILE_POINT_MEM_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + for (i = 0, data_size = 1; i < DATASET_READ_ALL_FILE_POINT_MEM_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_READ_ALL_FILE_POINT_MEM_TEST_DTYPE_SIZE; + + if (NULL == (write_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + for (i = 0; i < (size_t)mpi_size; i++) { + size_t j; + size_t elem_per_proc = + (data_size / DATASET_READ_ALL_FILE_POINT_MEM_TEST_DTYPE_SIZE) / dims[0]; + + for (j = 0; j < elem_per_proc; j++) { + size_t idx = (i * elem_per_proc) + j; + + ((int *)write_buf)[idx] = (int)i; + } + } + + { + hsize_t mdims[] = {data_size / DATASET_READ_ALL_FILE_POINT_MEM_TEST_DTYPE_SIZE}; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + } + + if (H5Dwrite(dset_id, DATASET_READ_ALL_FILE_POINT_MEM_TEST_DSET_DTYPE, mspace_id, H5S_ALL, + H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", + DATASET_READ_ALL_FILE_POINT_MEM_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + if (mspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(mspace_id); + } + H5E_END_TRY; + mspace_id = H5I_INVALID_HID; + } + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + /* + * Close and re-open the file to ensure that the data gets written. + */ + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close test's container group\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + if (H5Gclose(container_group) < 0) { + H5_FAILED(); + HDprintf(" failed to close container group\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close file for data flushing\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + } + } + END_INDEPENDENT_OP(dset_create); + + /* + * Re-open file on all ranks. + */ + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, TRUE)) < 0) + TEST_ERROR; + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't re-open file '%s'\n", H5_api_test_parallel_filename); + goto error; + } + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + if ((group_id = H5Gopen2(container_group, DATASET_READ_ALL_FILE_POINT_MEM_TEST_GROUP_NAME, H5P_DEFAULT)) < + 0) { + H5_FAILED(); + HDprintf(" couldn't open container sub-group '%s'\n", + DATASET_READ_ALL_FILE_POINT_MEM_TEST_GROUP_NAME); + goto error; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_READ_ALL_FILE_POINT_MEM_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_READ_ALL_FILE_POINT_MEM_TEST_DSET_NAME); + goto error; + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + goto error; + } + + if ((space_npoints = H5Sget_simple_extent_npoints(fspace_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataspace num points\n"); + goto error; + } + + /* + * Only have rank 0 perform the dataset read, as reading the entire dataset on all ranks + * might be stressful on system resources. + */ + BEGIN_INDEPENDENT_OP(dset_read) + { + if (MAINPROCESS) { + hsize_t mdims[] = {(hsize_t)(2 * space_npoints)}; + size_t j; + + /* + * Allocate twice the amount of memory needed and leave "holes" in the memory + * buffer in order to prove that the mapping from all selection <-> point + * selection works correctly. + */ + read_buf_size = (size_t)(2 * space_npoints) * DATASET_READ_ALL_FILE_POINT_MEM_TEST_DTYPE_SIZE; + if (NULL == (read_buf = HDcalloc(1, read_buf_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + INDEPENDENT_OP_ERROR(dset_read); + } + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + INDEPENDENT_OP_ERROR(dset_read); + } + + if (NULL == (points = HDmalloc((size_t)space_npoints * sizeof(hsize_t)))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for point selection\n"); + INDEPENDENT_OP_ERROR(dset_read); + } + + /* Select every other point in the 1-dimensional memory dataspace */ + for (i = 0, j = 0; i < 2 * (size_t)space_npoints; i++) { + if (i % 2 == 0) + points[j++] = (hsize_t)i; + } + + if (H5Sselect_elements(mspace_id, H5S_SELECT_SET, (size_t)space_npoints, points) < 0) { + H5_FAILED(); + HDprintf(" couldn't set point selection for dataset read\n"); + INDEPENDENT_OP_ERROR(dset_read); + } + + if (H5Dread(dset_id, DATASET_READ_ALL_FILE_POINT_MEM_TEST_DSET_DTYPE, mspace_id, H5S_ALL, + H5P_DEFAULT, read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", + DATASET_READ_ALL_FILE_POINT_MEM_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_read); + } + + for (i = 0; i < (size_t)mpi_size; i++) { + size_t elem_per_proc = (size_t)(space_npoints / mpi_size); + + for (j = 0; j < 2 * elem_per_proc; j++) { + size_t idx = (i * 2 * elem_per_proc) + j; + + if (j % 2 == 0) { + if (((int *)read_buf)[idx] != (int)i) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + INDEPENDENT_OP_ERROR(dset_read); + } + } + else { + if (((int *)read_buf)[idx] != 0) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + INDEPENDENT_OP_ERROR(dset_read); + } + } + } + } + } + } + END_INDEPENDENT_OP(dset_read); + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (points) { + HDfree(points); + points = NULL; + } + + if (dims) { + HDfree(dims); + dims = NULL; + } + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (read_buf) + HDfree(read_buf); + if (write_buf) + HDfree(write_buf); + if (points) + HDfree(points); + if (dims) + HDfree(dims); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Pclose(fapl_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to ensure that a dataset can be read from by having + * a hyperslab selection in the file dataspace and a point + * selection in the memory dataspace. + */ +#define DATASET_READ_HYPER_FILE_POINT_MEM_TEST_SPACE_RANK 2 +#define DATASET_READ_HYPER_FILE_POINT_MEM_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_READ_HYPER_FILE_POINT_MEM_TEST_DTYPE_SIZE sizeof(int) +#define DATASET_READ_HYPER_FILE_POINT_MEM_TEST_GROUP_NAME "hyper_sel_file_point_sel_mem_read_test" +#define DATASET_READ_HYPER_FILE_POINT_MEM_TEST_DSET_NAME "hyper_sel_file_point_sel_mem_dset" +static int +test_read_dataset_hyper_file_point_mem(void) +{ + hssize_t space_npoints; + hsize_t *dims = NULL; + hsize_t *points = NULL; + hsize_t start[DATASET_READ_HYPER_FILE_POINT_MEM_TEST_SPACE_RANK]; + hsize_t stride[DATASET_READ_HYPER_FILE_POINT_MEM_TEST_SPACE_RANK]; + hsize_t count[DATASET_READ_HYPER_FILE_POINT_MEM_TEST_SPACE_RANK]; + hsize_t block[DATASET_READ_HYPER_FILE_POINT_MEM_TEST_SPACE_RANK]; + size_t i, data_size, read_buf_size; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + void *write_buf = NULL; + void *read_buf = NULL; + + TESTING("read from dataset with hyperslab sel. for file space; point sel. for memory"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if (generate_random_parallel_dimensions(DATASET_READ_HYPER_FILE_POINT_MEM_TEST_SPACE_RANK, &dims) < 0) + TEST_ERROR; + + /* + * Have rank 0 create the dataset and completely fill it with data. + */ + BEGIN_INDEPENDENT_OP(dset_create) + { + if (MAINPROCESS) { + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_parallel_filename); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((group_id = H5Gcreate2(container_group, DATASET_READ_HYPER_FILE_POINT_MEM_TEST_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_READ_HYPER_FILE_POINT_MEM_TEST_GROUP_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((fspace_id = + H5Screate_simple(DATASET_READ_HYPER_FILE_POINT_MEM_TEST_SPACE_RANK, dims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" failed to create file dataspace for dataset\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((dset_id = H5Dcreate2(group_id, DATASET_READ_HYPER_FILE_POINT_MEM_TEST_DSET_NAME, + DATASET_READ_HYPER_FILE_POINT_MEM_TEST_DSET_DTYPE, fspace_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", + DATASET_READ_HYPER_FILE_POINT_MEM_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + for (i = 0, data_size = 1; i < DATASET_READ_HYPER_FILE_POINT_MEM_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_READ_HYPER_FILE_POINT_MEM_TEST_DTYPE_SIZE; + + if (NULL == (write_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + for (i = 0; i < (size_t)mpi_size; i++) { + size_t j; + size_t elem_per_proc = + (data_size / DATASET_READ_HYPER_FILE_POINT_MEM_TEST_DTYPE_SIZE) / dims[0]; + + for (j = 0; j < elem_per_proc; j++) { + size_t idx = (i * elem_per_proc) + j; + + ((int *)write_buf)[idx] = (int)i; + } + } + + { + hsize_t mdims[] = {data_size / DATASET_READ_HYPER_FILE_POINT_MEM_TEST_DTYPE_SIZE}; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + } + + if (H5Dwrite(dset_id, DATASET_READ_HYPER_FILE_POINT_MEM_TEST_DSET_DTYPE, mspace_id, H5S_ALL, + H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", + DATASET_READ_HYPER_FILE_POINT_MEM_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + if (mspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(mspace_id); + } + H5E_END_TRY; + mspace_id = H5I_INVALID_HID; + } + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + /* + * Close and re-open the file to ensure that the data gets written. + */ + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close test's container group\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + if (H5Gclose(container_group) < 0) { + H5_FAILED(); + HDprintf(" failed to close container group\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close file for data flushing\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + } + } + END_INDEPENDENT_OP(dset_create); + + /* + * Re-open file on all ranks. + */ + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, TRUE)) < 0) + TEST_ERROR; + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't re-open file '%s'\n", H5_api_test_parallel_filename); + goto error; + } + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + if ((group_id = + H5Gopen2(container_group, DATASET_READ_HYPER_FILE_POINT_MEM_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container sub-group '%s'\n", + DATASET_READ_HYPER_FILE_POINT_MEM_TEST_GROUP_NAME); + goto error; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_READ_HYPER_FILE_POINT_MEM_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_READ_HYPER_FILE_POINT_MEM_TEST_DSET_NAME); + goto error; + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + goto error; + } + + if ((space_npoints = H5Sget_simple_extent_npoints(fspace_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataspace num points\n"); + goto error; + } + + /* + * Allocate twice the amount of memory needed and leave "holes" in the memory + * buffer in order to prove that the mapping from hyperslab selection <-> point + * selection works correctly. + */ + read_buf_size = (2 * (size_t)(space_npoints / mpi_size) * DATASET_READ_ONE_PROC_NONE_SEL_TEST_DTYPE_SIZE); + if (NULL == (read_buf = HDcalloc(1, read_buf_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + goto error; + } + + for (i = 0; i < DATASET_READ_HYPER_FILE_POINT_MEM_TEST_SPACE_RANK; i++) { + if (i == 0) { + start[i] = (hsize_t)mpi_rank; + block[i] = 1; + } + else { + start[i] = 0; + block[i] = dims[i]; + } + + stride[i] = 1; + count[i] = 1; + } + + if (H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET, start, stride, count, block) < 0) { + H5_FAILED(); + HDprintf(" couldn't select hyperslab for dataset read\n"); + goto error; + } + + { + hsize_t mdims[] = {(hsize_t)(2 * (space_npoints / mpi_size))}; + size_t j; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + goto error; + } + + if (NULL == (points = HDmalloc((size_t)(space_npoints / mpi_size) * sizeof(hsize_t)))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for point selection\n"); + goto error; + } + + /* Select every other point in the 1-dimensional memory dataspace */ + for (i = 0, j = 0; i < (size_t)(2 * (space_npoints / mpi_size)); i++) { + if (i % 2 == 0) + points[j++] = (hsize_t)i; + } + + if (H5Sselect_elements(mspace_id, H5S_SELECT_SET, (size_t)(space_npoints / mpi_size), points) < 0) { + H5_FAILED(); + HDprintf(" couldn't set point selection for dataset read\n"); + goto error; + } + } + + if (H5Dread(dset_id, DATASET_READ_HYPER_FILE_POINT_MEM_TEST_DSET_DTYPE, mspace_id, fspace_id, H5P_DEFAULT, + read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", DATASET_READ_HYPER_FILE_POINT_MEM_TEST_DSET_NAME); + goto error; + } + + for (i = 0; i < (size_t)(2 * (space_npoints / mpi_size)); i++) { + if (i % 2 == 0) { + if (((int *)read_buf)[i] != (int)mpi_rank) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + goto error; + } + } + else { + if (((int *)read_buf)[i] != 0) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + goto error; + } + } + } + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (points) { + HDfree(points); + points = NULL; + } + + if (dims) { + HDfree(dims); + dims = NULL; + } + + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (read_buf) + HDfree(read_buf); + if (write_buf) + HDfree(write_buf); + if (points) + HDfree(points); + if (dims) + HDfree(dims); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Pclose(fapl_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to ensure that a dataset can be read from by having + * a point selection in the file dataspace and a hyperslab + * selection in the memory dataspace. + */ +#define DATASET_READ_POINT_FILE_HYPER_MEM_TEST_SPACE_RANK 2 +#define DATASET_READ_POINT_FILE_HYPER_MEM_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_READ_POINT_FILE_HYPER_MEM_TEST_DTYPE_SIZE sizeof(int) +#define DATASET_READ_POINT_FILE_HYPER_MEM_TEST_GROUP_NAME "point_sel_file_hyper_sel_mem_read_test" +#define DATASET_READ_POINT_FILE_HYPER_MEM_TEST_DSET_NAME "point_sel_file_hyper_sel_mem_dset" +static int +test_read_dataset_point_file_hyper_mem(void) +{ + hssize_t space_npoints; + hsize_t *dims = NULL; + hsize_t *points = NULL; + size_t i, data_size, read_buf_size; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + void *write_buf = NULL; + void *read_buf = NULL; + + TESTING("read from dataset with point sel. for file space; hyperslab sel. for memory"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + SKIPPED(); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + return 0; + } + + if (generate_random_parallel_dimensions(DATASET_READ_POINT_FILE_HYPER_MEM_TEST_SPACE_RANK, &dims) < 0) + TEST_ERROR; + + /* + * Have rank 0 create the dataset and completely fill it with data. + */ + BEGIN_INDEPENDENT_OP(dset_create) + { + if (MAINPROCESS) { + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_parallel_filename); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((group_id = H5Gcreate2(container_group, DATASET_READ_POINT_FILE_HYPER_MEM_TEST_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_READ_POINT_FILE_HYPER_MEM_TEST_GROUP_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((fspace_id = + H5Screate_simple(DATASET_READ_POINT_FILE_HYPER_MEM_TEST_SPACE_RANK, dims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" failed to create file dataspace for dataset\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((dset_id = H5Dcreate2(group_id, DATASET_READ_POINT_FILE_HYPER_MEM_TEST_DSET_NAME, + DATASET_READ_POINT_FILE_HYPER_MEM_TEST_DSET_DTYPE, fspace_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", + DATASET_READ_POINT_FILE_HYPER_MEM_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + for (i = 0, data_size = 1; i < DATASET_READ_POINT_FILE_HYPER_MEM_TEST_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_READ_POINT_FILE_HYPER_MEM_TEST_DTYPE_SIZE; + + if (NULL == (write_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + for (i = 0; i < (size_t)mpi_size; i++) { + size_t j; + size_t elem_per_proc = + (data_size / DATASET_READ_POINT_FILE_HYPER_MEM_TEST_DTYPE_SIZE) / dims[0]; + + for (j = 0; j < elem_per_proc; j++) { + size_t idx = (i * elem_per_proc) + j; + + ((int *)write_buf)[idx] = (int)i; + } + } + + { + hsize_t mdims[] = {data_size / DATASET_READ_POINT_FILE_HYPER_MEM_TEST_DTYPE_SIZE}; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + } + + if (H5Dwrite(dset_id, DATASET_READ_POINT_FILE_HYPER_MEM_TEST_DSET_DTYPE, mspace_id, H5S_ALL, + H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", + DATASET_READ_POINT_FILE_HYPER_MEM_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + if (mspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(mspace_id); + } + H5E_END_TRY; + mspace_id = H5I_INVALID_HID; + } + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + /* + * Close and re-open the file to ensure that the data gets written. + */ + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close test's container group\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + if (H5Gclose(container_group) < 0) { + H5_FAILED(); + HDprintf(" failed to close container group\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close file for data flushing\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + } + } + END_INDEPENDENT_OP(dset_create); + + /* + * Re-open file on all ranks. + */ + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, TRUE)) < 0) + TEST_ERROR; + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't re-open file '%s'\n", H5_api_test_parallel_filename); + goto error; + } + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + if ((group_id = + H5Gopen2(container_group, DATASET_READ_POINT_FILE_HYPER_MEM_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container sub-group '%s'\n", + DATASET_READ_POINT_FILE_HYPER_MEM_TEST_GROUP_NAME); + goto error; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_READ_POINT_FILE_HYPER_MEM_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", DATASET_READ_POINT_FILE_HYPER_MEM_TEST_DSET_NAME); + goto error; + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + goto error; + } + + if ((space_npoints = H5Sget_simple_extent_npoints(fspace_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataspace num points\n"); + goto error; + } + + /* + * Allocate twice the amount of memory needed and leave "holes" in the memory + * buffer in order to prove that the mapping from point selection <-> hyperslab + * selection works correctly. + */ + read_buf_size = + (2 * (size_t)(space_npoints / mpi_size) * DATASET_READ_POINT_FILE_HYPER_MEM_TEST_DTYPE_SIZE); + if (NULL == (read_buf = HDcalloc(1, read_buf_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset read\n"); + goto error; + } + + if (NULL == (points = HDmalloc((size_t)((space_npoints / mpi_size) * + DATASET_READ_POINT_FILE_HYPER_MEM_TEST_SPACE_RANK) * + sizeof(hsize_t)))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for point selection\n"); + goto error; + } + + for (i = 0; i < (size_t)(space_npoints / mpi_size); i++) { + size_t j; + + for (j = 0; j < DATASET_READ_POINT_FILE_HYPER_MEM_TEST_SPACE_RANK; j++) { + size_t idx = (i * DATASET_READ_POINT_FILE_HYPER_MEM_TEST_SPACE_RANK) + j; + + if (j == 0) + points[idx] = (hsize_t)mpi_rank; + else if (j != DATASET_READ_POINT_FILE_HYPER_MEM_TEST_SPACE_RANK - 1) + points[idx] = i / dims[j + 1]; + else + points[idx] = i % dims[j]; + } + } + + if (H5Sselect_elements(fspace_id, H5S_SELECT_SET, (size_t)(space_npoints / mpi_size), points) < 0) { + H5_FAILED(); + HDprintf(" couldn't set point selection for dataset read\n"); + goto error; + } + + { + hsize_t start[1] = {0}; + hsize_t stride[1] = {2}; + hsize_t count[1] = {(hsize_t)(space_npoints / mpi_size)}; + hsize_t block[1] = {1}; + hsize_t mdims[] = {(hsize_t)(2 * (space_npoints / mpi_size))}; + + if ((mspace_id = H5Screate_simple(1, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create memory dataspace\n"); + goto error; + } + + if (H5Sselect_hyperslab(mspace_id, H5S_SELECT_SET, start, stride, count, block) < 0) { + H5_FAILED(); + HDprintf(" couldn't set hyperslab selection for dataset write\n"); + goto error; + } + } + + if (H5Dread(dset_id, DATASET_READ_POINT_FILE_HYPER_MEM_TEST_DSET_DTYPE, mspace_id, fspace_id, H5P_DEFAULT, + read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", DATASET_READ_POINT_FILE_HYPER_MEM_TEST_DSET_NAME); + goto error; + } + + for (i = 0; i < (size_t)(2 * (space_npoints / mpi_size)); i++) { + if (i % 2 == 0) { + if (((int *)read_buf)[i] != (int)mpi_rank) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + goto error; + } + } + else { + if (((int *)read_buf)[i] != 0) { + H5_FAILED(); + HDprintf(" data verification failed\n"); + goto error; + } + } + } + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + if (points) { + HDfree(points); + points = NULL; + } + + if (dims) { + HDfree(dims); + dims = NULL; + } + + if (H5Sclose(mspace_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (read_buf) + HDfree(read_buf); + if (write_buf) + HDfree(write_buf); + if (points) + HDfree(points); + if (dims) + HDfree(dims); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Pclose(fapl_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a dataset composed of multiple chunks + * can be written and read correctly. When reading back the + * chunks of the dataset, the file dataspace and memory dataspace + * used are the same shape. The dataset's first dimension grows + * with the number of MPI ranks, while the other dimensions are fixed. + */ +#define DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_FIXED_CHUNK_DIMSIZE \ + 100 /* Should be an even divisor of fixed dimension size */ +#define DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_FIXED_DIMSIZE 1000 +#define DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK 2 +#define DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_DTYPESIZE sizeof(int) +#define DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_GROUP_NAME \ + "multi_chunk_dataset_write_same_space_read_test" +#define DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_NAME "multi_chunk_dataset" +static int +test_write_multi_chunk_dataset_same_shape_read(void) +{ + hsize_t *dims = NULL; + hsize_t *chunk_dims = NULL; + hsize_t retrieved_chunk_dims[DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK]; + hsize_t start[DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK]; + hsize_t count[DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK]; + size_t i, data_size, chunk_size, n_chunks_per_rank; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dcpl_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + void *write_buf = NULL; + int read_buf[1][DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_FIXED_CHUNK_DIMSIZE]; + + TESTING("write to dataset with multiple chunks using same shaped dataspaces"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_GET_PLIST)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, or getting property list aren't " + "supported with this connector\n"); + return 0; + } + + if (NULL == + (dims = HDmalloc(DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK * sizeof(hsize_t)))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset dimensionality\n"); + goto error; + } + + if (NULL == (chunk_dims = HDmalloc(DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK * + sizeof(hsize_t)))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset dimensionality\n"); + goto error; + } + + for (i = 0; i < DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; i++) { + if (i == 0) { + dims[i] = (hsize_t)mpi_size; + chunk_dims[i] = 1; + } + else { + dims[i] = DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_FIXED_DIMSIZE; + chunk_dims[i] = DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_FIXED_CHUNK_DIMSIZE; + } + } + + for (i = 0, chunk_size = 1; i < DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; i++) + chunk_size *= chunk_dims[i]; + chunk_size *= DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_DTYPESIZE; + + for (i = 0, data_size = 1; i < DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_DTYPESIZE; + + /* + * Have rank 0 create the dataset and completely fill it with data. + */ + BEGIN_INDEPENDENT_OP(dset_create) + { + if (MAINPROCESS) { + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_parallel_filename); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((group_id = + H5Gcreate2(container_group, DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_GROUP_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((fspace_id = H5Screate_simple(DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK, + dims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" failed to create file dataspace for dataset\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" failed to create DCPL\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + if (H5Pset_chunk(dcpl_id, DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK, + chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" failed to set chunking on DCPL\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((dset_id = H5Dcreate2(group_id, DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_NAME, + DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_DTYPE, fspace_id, + H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", + DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + /* + * See if a copy of the DCPL reports the correct chunking. + */ + if (H5Pclose(dcpl_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close DCPL\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((dcpl_id = H5Dget_create_plist(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve copy of DCPL\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + memset(retrieved_chunk_dims, 0, sizeof(retrieved_chunk_dims)); + if (H5Pget_chunk(dcpl_id, DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK, + retrieved_chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve chunking info\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + for (i = 0; i < DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; i++) { + if (chunk_dims[i] != retrieved_chunk_dims[i]) { + H5_FAILED(); + HDprintf(" chunk dimensionality retrieved from DCPL didn't match originally specified " + "dimensionality\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + } + + if (NULL == (write_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + /* + * Ensure that each underlying chunk contains the values + * + * chunk_index .. (chunk_nelemts - 1) + chunk_index. + * + * That is to say, for a chunk size of 10 x 10, chunk 0 + * contains the values + * + * 0 .. 99 + * + * while the next chunk contains the values + * + * 1 .. 100 + * + * and so on. + */ + for (i = 0; i < data_size / DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_DTYPESIZE; i++) { + size_t j; + size_t base; + size_t tot_adjust; + + /* + * Calculate a starting base value by taking the index value mod + * the size of a chunk in each dimension. + */ + for (j = 0, base = i; j < DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; j++) + if (chunk_dims[j] > 1 && base >= chunk_dims[j]) + base %= chunk_dims[j]; + + /* + * Calculate the adjustment in each dimension. + */ + for (j = 0, tot_adjust = 0; + j < DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; j++) { + if (j == (DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK - 1)) + tot_adjust += (i % dims[j]) / chunk_dims[j]; + else { + size_t k; + size_t n_faster_elemts; + + /* + * Calculate the number of elements in faster dimensions. + */ + for (k = j + 1, n_faster_elemts = 1; + k < DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; k++) + n_faster_elemts *= dims[k]; + + tot_adjust += + (((i / n_faster_elemts) / chunk_dims[j]) * (dims[j + 1] / chunk_dims[j + 1])) + + (((i / n_faster_elemts) % chunk_dims[j]) * chunk_dims[j + 1]); + } + } + + ((int *)write_buf)[i] = (int)(base + tot_adjust); + } + + /* + * Write every chunk in the dataset. + */ + if (H5Dwrite(dset_id, DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, + H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", + DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dcpl_id >= 0) { + H5E_BEGIN_TRY + { + H5Pclose(dcpl_id); + } + H5E_END_TRY; + dcpl_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + /* + * Close and re-open the file to ensure that the data gets written. + */ + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close test's container group\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + if (H5Gclose(container_group) < 0) { + H5_FAILED(); + HDprintf(" failed to close container group\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close file for data flushing\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + } + } + END_INDEPENDENT_OP(dset_create); + + /* + * Re-open file on all ranks. + */ + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, TRUE)) < 0) + TEST_ERROR; + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't re-open file '%s'\n", H5_api_test_parallel_filename); + goto error; + } + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + if ((group_id = H5Gopen2(container_group, DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_GROUP_NAME, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container sub-group '%s'\n", + DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_GROUP_NAME); + goto error; + } + + if ((dset_id = + H5Dopen2(group_id, DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", + DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_NAME); + goto error; + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + goto error; + } + + /* + * Create 2-dimensional memory dataspace for read buffer. + */ + { + hsize_t mdims[] = {chunk_dims[0], chunk_dims[1]}; + + if ((mspace_id = H5Screate_simple(2, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" failed to create memory dataspace\n"); + goto error; + } + } + + for (i = 0; i < DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; i++) { + count[i] = chunk_dims[i]; + } + + /* + * Each rank reads their respective chunks in the dataset, checking the data for each one. + */ + if (MAINPROCESS) + HDprintf("\n"); + for (i = 0, n_chunks_per_rank = (data_size / (size_t)mpi_size) / chunk_size; i < n_chunks_per_rank; i++) { + size_t j, k; + + if (MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD)) { + H5_FAILED(); + HDprintf(" MPI_Barrier failed\n"); + goto error; + } + + if (MAINPROCESS) + HDprintf("\r All ranks reading chunk %zu", i); + + for (j = 0; j < DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; j++) { + if (j == 0) + start[j] = (hsize_t)mpi_rank; + else if (j == (DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK - 1)) + /* Fastest changing dimension */ + start[j] = (i * chunk_dims[j]) % dims[j]; + else + start[j] = ((i * chunk_dims[j + 1]) / dims[j + 1]) * (chunk_dims[j]); + } + + /* + * Adjust file dataspace selection for next chunk. + */ + if (H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET, start, NULL, count, NULL) < 0) { + H5_FAILED(); + HDprintf(" failed to set hyperslab selection\n"); + goto error; + } + + for (j = 0; j < chunk_dims[0]; j++) + for (k = 0; k < chunk_dims[1]; k++) + read_buf[j][k] = 0; + + if (H5Dread(dset_id, DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_DTYPE, mspace_id, fspace_id, + H5P_DEFAULT, read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", + DATASET_MULTI_CHUNK_WRITE_SAME_SPACE_READ_TEST_DSET_NAME); + goto error; + } + + for (j = 0; j < chunk_dims[0]; j++) { + for (k = 0; k < chunk_dims[1]; k++) { + size_t val = + ((j * chunk_dims[0]) + k + i) + + ((hsize_t)mpi_rank * n_chunks_per_rank); /* Additional value offset for each rank */ + if (read_buf[j][k] != (int)val) { + H5_FAILED(); + HDprintf(" data verification failed for chunk %lld\n", (long long)i); + goto error; + } + } + } + } + + if (chunk_dims) { + HDfree(chunk_dims); + chunk_dims = NULL; + } + + if (dims) { + HDfree(dims); + dims = NULL; + } + + if (H5Sclose(mspace_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (write_buf) + HDfree(write_buf); + if (chunk_dims) + HDfree(chunk_dims); + if (dims) + HDfree(dims); + H5Pclose(dcpl_id); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Pclose(fapl_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a dataset composed of multiple chunks + * can be written and read correctly. When reading back the + * chunks of the dataset, the file dataspace and memory dataspace + * used are differently shaped. The dataset's first dimension grows + * with the number of MPI ranks, while the other dimensions are fixed. + */ +#define DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_FIXED_CHUNK_DIMSIZE \ + 100 /* Should be an even divisor of fixed dimension size */ +#define DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_READ_BUF_DIMSIZE \ + (DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_FIXED_CHUNK_DIMSIZE / 10) +#define DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_FIXED_DIMSIZE 1000 +#define DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK 2 +#define DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_DTYPESIZE sizeof(int) +#define DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_GROUP_NAME \ + "multi_chunk_dataset_write_diff_space_read_test" +#define DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_NAME "multi_chunk_dataset" +static int +test_write_multi_chunk_dataset_diff_shape_read(void) +{ + hsize_t *dims = NULL; + hsize_t *chunk_dims = NULL; + hsize_t retrieved_chunk_dims[DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK]; + hsize_t start[DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK]; + hsize_t count[DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK]; + size_t i, data_size, chunk_size, n_chunks_per_rank; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dcpl_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + void *write_buf = NULL; + int read_buf[DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_READ_BUF_DIMSIZE] + [DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_READ_BUF_DIMSIZE]; + + TESTING("write to dataset with multiple chunks using differently shaped dataspaces"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_GET_PLIST)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, or getting property list aren't " + "supported with this connector\n"); + return 0; + } + + if (NULL == + (dims = HDmalloc(DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK * sizeof(hsize_t)))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset dimensionality\n"); + goto error; + } + + if (NULL == (chunk_dims = HDmalloc(DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK * + sizeof(hsize_t)))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset dimensionality\n"); + goto error; + } + + for (i = 0; i < DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; i++) { + if (i == 0) { + dims[i] = (hsize_t)mpi_size; + chunk_dims[i] = 1; + } + else { + dims[i] = DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_FIXED_DIMSIZE; + chunk_dims[i] = DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_FIXED_CHUNK_DIMSIZE; + } + } + + for (i = 0, chunk_size = 1; i < DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; i++) + chunk_size *= chunk_dims[i]; + chunk_size *= DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_DTYPESIZE; + + for (i = 0, data_size = 1; i < DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_DTYPESIZE; + + /* + * Have rank 0 create the dataset and completely fill it with data. + */ + BEGIN_INDEPENDENT_OP(dset_create) + { + if (MAINPROCESS) { + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_parallel_filename); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((group_id = + H5Gcreate2(container_group, DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_GROUP_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((fspace_id = H5Screate_simple(DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK, + dims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" failed to create file dataspace for dataset\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" failed to create DCPL\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + if (H5Pset_chunk(dcpl_id, DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK, + chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" failed to set chunking on DCPL\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((dset_id = H5Dcreate2(group_id, DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_NAME, + DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_DTYPE, fspace_id, + H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", + DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + /* + * See if a copy of the DCPL reports the correct chunking. + */ + if (H5Pclose(dcpl_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close DCPL\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((dcpl_id = H5Dget_create_plist(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve copy of DCPL\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + memset(retrieved_chunk_dims, 0, sizeof(retrieved_chunk_dims)); + if (H5Pget_chunk(dcpl_id, DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK, + retrieved_chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve chunking info\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + for (i = 0; i < DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; i++) { + if (chunk_dims[i] != retrieved_chunk_dims[i]) { + H5_FAILED(); + HDprintf(" chunk dimensionality retrieved from DCPL didn't match originally specified " + "dimensionality\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + } + + if (NULL == (write_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + /* + * Ensure that each underlying chunk contains the values + * + * chunk_index .. (chunk_nelemts - 1) + chunk_index. + * + * That is to say, for a chunk size of 10 x 10, chunk 0 + * contains the values + * + * 0 .. 99 + * + * while the next chunk contains the values + * + * 1 .. 100 + * + * and so on. + */ + for (i = 0; i < data_size / DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_DTYPESIZE; i++) { + size_t j; + size_t base; + size_t tot_adjust; + + /* + * Calculate a starting base value by taking the index value mod + * the size of a chunk in each dimension. + */ + for (j = 0, base = i; j < DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; j++) + if (chunk_dims[j] > 1 && base >= chunk_dims[j]) + base %= chunk_dims[j]; + + /* + * Calculate the adjustment in each dimension. + */ + for (j = 0, tot_adjust = 0; + j < DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; j++) { + if (j == (DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK - 1)) + tot_adjust += (i % dims[j]) / chunk_dims[j]; + else { + size_t k; + size_t n_faster_elemts; + + /* + * Calculate the number of elements in faster dimensions. + */ + for (k = j + 1, n_faster_elemts = 1; + k < DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; k++) + n_faster_elemts *= dims[k]; + + tot_adjust += + (((i / n_faster_elemts) / chunk_dims[j]) * (dims[j + 1] / chunk_dims[j + 1])) + + (((i / n_faster_elemts) % chunk_dims[j]) * chunk_dims[j + 1]); + } + } + + ((int *)write_buf)[i] = (int)(base + tot_adjust); + } + + /* + * Write every chunk in the dataset. + */ + if (H5Dwrite(dset_id, DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_DTYPE, H5S_ALL, H5S_ALL, + H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", + DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dcpl_id >= 0) { + H5E_BEGIN_TRY + { + H5Pclose(dcpl_id); + } + H5E_END_TRY; + dcpl_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + /* + * Close and re-open the file to ensure that the data gets written. + */ + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close test's container group\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + if (H5Gclose(container_group) < 0) { + H5_FAILED(); + HDprintf(" failed to close container group\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close file for data flushing\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + } + } + END_INDEPENDENT_OP(dset_create); + + /* + * Re-open file on all ranks. + */ + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, TRUE)) < 0) + TEST_ERROR; + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't re-open file '%s'\n", H5_api_test_parallel_filename); + goto error; + } + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + if ((group_id = H5Gopen2(container_group, DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_GROUP_NAME, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container sub-group '%s'\n", + DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_GROUP_NAME); + goto error; + } + + if ((dset_id = + H5Dopen2(group_id, DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", + DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_NAME); + goto error; + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + goto error; + } + + /* + * Create memory dataspace for read buffer. + */ + { + hsize_t mdims[] = {DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_READ_BUF_DIMSIZE, + DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_READ_BUF_DIMSIZE}; + + if ((mspace_id = H5Screate_simple(DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK, + mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" failed to create memory dataspace\n"); + goto error; + } + } + + for (i = 0; i < DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; i++) { + count[i] = chunk_dims[i]; + } + + /* + * Each rank reads their respective chunks in the dataset, checking the data for each one. + */ + if (MAINPROCESS) + HDprintf("\n"); + for (i = 0, n_chunks_per_rank = (data_size / (size_t)mpi_size) / chunk_size; i < n_chunks_per_rank; i++) { + size_t j, k; + + if (MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD)) { + H5_FAILED(); + HDprintf(" MPI_Barrier failed\n"); + goto error; + } + + if (MAINPROCESS) + HDprintf("\r All ranks reading chunk %zu", i); + + for (j = 0; j < DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; j++) { + if (j == 0) + start[j] = (hsize_t)mpi_rank; + else if (j == (DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK - 1)) + /* Fastest changing dimension */ + start[j] = (i * chunk_dims[j]) % dims[j]; + else + start[j] = ((i * chunk_dims[j + 1]) / dims[j + 1]) * (chunk_dims[j]); + } + + /* + * Adjust file dataspace selection for next chunk. + */ + if (H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET, start, NULL, count, NULL) < 0) { + H5_FAILED(); + HDprintf(" failed to set hyperslab selection\n"); + goto error; + } + + for (j = 0; j < DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_READ_BUF_DIMSIZE; j++) + for (k = 0; k < DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_READ_BUF_DIMSIZE; k++) + read_buf[j][k] = 0; + + if (H5Dread(dset_id, DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_DTYPE, mspace_id, fspace_id, + H5P_DEFAULT, read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", + DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_DSET_NAME); + goto error; + } + + for (j = 0; j < DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_READ_BUF_DIMSIZE; j++) { + for (k = 0; k < DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_READ_BUF_DIMSIZE; k++) { + size_t val = ((j * DATASET_MULTI_CHUNK_WRITE_DIFF_SPACE_READ_TEST_READ_BUF_DIMSIZE) + k + i) + + ((hsize_t)mpi_rank * n_chunks_per_rank); + + if (read_buf[j][k] != (int)val) { + H5_FAILED(); + HDprintf(" data verification failed for chunk %lld\n", (long long)i); + goto error; + } + } + } + } + + if (chunk_dims) { + HDfree(chunk_dims); + chunk_dims = NULL; + } + + if (dims) { + HDfree(dims); + dims = NULL; + } + + if (H5Sclose(mspace_id) < 0) + TEST_ERROR; + if (H5Sclose(fspace_id) < 0) + TEST_ERROR; + if (H5Dclose(dset_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (write_buf) + HDfree(write_buf); + if (chunk_dims) + HDfree(chunk_dims); + if (dims) + HDfree(dims); + H5Pclose(dcpl_id); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Pclose(fapl_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a dataset composed of multiple chunks + * can be written and read correctly several times in a row. + * When reading back the chunks of the dataset, the file + * dataspace and memory dataspace used are the same shape. + * The dataset's first dimension grows with the number of MPI + * ranks, while the other dimensions are fixed. + */ +#define DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_FIXED_CHUNK_DIMSIZE \ + 100 /* Should be an even divisor of fixed dimension size */ +#define DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_FIXED_DIMSIZE 1000 +#define DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK 2 +#define DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_DTYPESIZE sizeof(int) +#define DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_GROUP_NAME \ + "multi_chunk_dataset_same_space_overwrite_test" +#define DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_NAME "multi_chunk_dataset" +#define DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_NITERS 10 +static int +test_overwrite_multi_chunk_dataset_same_shape_read(void) +{ + hsize_t *dims = NULL; + hsize_t *chunk_dims = NULL; + hsize_t retrieved_chunk_dims[DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK]; + hsize_t start[DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK]; + hsize_t count[DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK]; + size_t i, data_size, chunk_size, n_chunks_per_rank; + size_t niter; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dcpl_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + void *write_buf = NULL; + int read_buf[1][DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_FIXED_CHUNK_DIMSIZE]; + + TESTING("several overwrites to dataset with multiple chunks using same shaped dataspaces"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_GET_PLIST)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, or getting property list aren't " + "supported with this connector\n"); + return 0; + } + + if (NULL == (dims = HDmalloc(DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK * + sizeof(hsize_t)))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset dimensionality\n"); + goto error; + } + + if (NULL == (chunk_dims = HDmalloc(DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK * + sizeof(hsize_t)))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset dimensionality\n"); + goto error; + } + + for (i = 0; i < DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; i++) { + if (i == 0) { + dims[i] = (hsize_t)mpi_size; + chunk_dims[i] = 1; + } + else { + dims[i] = DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_FIXED_DIMSIZE; + chunk_dims[i] = DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_FIXED_CHUNK_DIMSIZE; + } + } + + for (i = 0, chunk_size = 1; i < DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; i++) + chunk_size *= chunk_dims[i]; + chunk_size *= DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_DTYPESIZE; + + for (i = 0, data_size = 1; i < DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_DTYPESIZE; + + /* + * Have rank 0 create the dataset, but don't fill it with data yet. + */ + BEGIN_INDEPENDENT_OP(dset_create) + { + if (MAINPROCESS) { + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_parallel_filename); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((group_id = H5Gcreate2(container_group, + DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_GROUP_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((fspace_id = H5Screate_simple( + DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK, dims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" failed to create file dataspace for dataset\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" failed to create DCPL\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + if (H5Pset_chunk(dcpl_id, DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK, + chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" failed to set chunking on DCPL\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + /* Set dataset space allocation time to Early to ensure all chunk-related metadata is available to + * all other processes when they open the dataset */ + if (H5Pset_alloc_time(dcpl_id, H5D_ALLOC_TIME_EARLY) < 0) { + H5_FAILED(); + HDprintf(" failed to set allocation time on DCPL\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((dset_id = H5Dcreate2(group_id, DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_NAME, + DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_DTYPE, + fspace_id, H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", + DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + /* + * See if a copy of the DCPL reports the correct chunking. + */ + if (H5Pclose(dcpl_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close DCPL\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((dcpl_id = H5Dget_create_plist(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve copy of DCPL\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + memset(retrieved_chunk_dims, 0, sizeof(retrieved_chunk_dims)); + if (H5Pget_chunk(dcpl_id, DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK, + retrieved_chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve chunking info\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + for (i = 0; i < DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; i++) { + if (chunk_dims[i] != retrieved_chunk_dims[i]) { + H5_FAILED(); + HDprintf(" chunk dimensionality retrieved from DCPL didn't match originally specified " + "dimensionality\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + } + + if (NULL == (write_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dcpl_id >= 0) { + H5E_BEGIN_TRY + { + H5Pclose(dcpl_id); + } + H5E_END_TRY; + dcpl_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + /* + * Close and re-open the file on all ranks. + */ + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close test's container group\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + if (H5Gclose(container_group) < 0) { + H5_FAILED(); + HDprintf(" failed to close container group\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close file for data flushing\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + } + } + END_INDEPENDENT_OP(dset_create); + + /* + * Re-open file on all ranks. + */ + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, TRUE)) < 0) + TEST_ERROR; + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't re-open file '%s'\n", H5_api_test_parallel_filename); + goto error; + } + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + if ((group_id = H5Gopen2(container_group, DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_GROUP_NAME, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container sub-group '%s'\n", + DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_GROUP_NAME); + goto error; + } + + /* + * Create 2-dimensional memory dataspace for read buffer. + */ + { + hsize_t mdims[] = {chunk_dims[0], chunk_dims[1]}; + + if ((mspace_id = H5Screate_simple(2, mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" failed to create memory dataspace\n"); + goto error; + } + } + + for (i = 0; i < DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; i++) { + count[i] = chunk_dims[i]; + } + + if (MAINPROCESS) + HDprintf("\n"); + for (niter = 0; niter < DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_NITERS; niter++) { + if ((dset_id = H5Dopen2(group_id, DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_NAME, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", + DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_NAME); + goto error; + } + + BEGIN_INDEPENDENT_OP(dset_write) + { + if (MAINPROCESS) { + memset(write_buf, 0, data_size); + + /* + * Ensure that each underlying chunk contains the values + * + * chunk_index .. (chunk_nelemts - 1) + chunk_index. + * + * That is to say, for a chunk size of 10 x 10, chunk 0 + * contains the values + * + * 0 .. 99 + * + * while the next chunk contains the values + * + * 1 .. 100 + * + * and so on. On each iteration, we add 1 to the previous + * values. + */ + for (i = 0; i < data_size / DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_DTYPESIZE; + i++) { + size_t j; + size_t base; + size_t tot_adjust; + + /* + * Calculate a starting base value by taking the index value mod + * the size of a chunk in each dimension. + */ + for (j = 0, base = i; + j < DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; j++) + if (chunk_dims[j] > 1 && base >= chunk_dims[j]) + base %= chunk_dims[j]; + + /* + * Calculate the adjustment in each dimension. + */ + for (j = 0, tot_adjust = 0; + j < DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; j++) { + if (j == (DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK - 1)) + tot_adjust += (i % dims[j]) / chunk_dims[j]; + else { + size_t k; + size_t n_faster_elemts; + + /* + * Calculate the number of elements in faster dimensions. + */ + for (k = j + 1, n_faster_elemts = 1; + k < DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; k++) + n_faster_elemts *= dims[k]; + + tot_adjust += (((i / n_faster_elemts) / chunk_dims[j]) * + (dims[j + 1] / chunk_dims[j + 1])) + + (((i / n_faster_elemts) % chunk_dims[j]) * chunk_dims[j + 1]); + } + } + + ((int *)write_buf)[i] = (int)(base + tot_adjust + niter); + } + + /* + * Write every chunk in the dataset. + */ + if (H5Dwrite(dset_id, DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_DTYPE, H5S_ALL, + H5S_ALL, H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", + DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_write); + } + } + } + END_INDEPENDENT_OP(dset_write); + + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + if (MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD)) { + H5_FAILED(); + HDprintf(" MPI_Barrier failed\n"); + goto error; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_NAME, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", + DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_NAME); + goto error; + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + goto error; + } + + /* + * Each rank reads their respective chunks in the dataset, checking the data for each one. + */ + for (i = 0, n_chunks_per_rank = (data_size / (size_t)mpi_size) / chunk_size; i < n_chunks_per_rank; + i++) { + size_t j, k; + + if (MAINPROCESS) + HDprintf("\r All ranks reading chunk %zu", i); + + for (j = 0; j < DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK; j++) { + if (j == 0) + start[j] = (hsize_t)mpi_rank; + else if (j == (DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK - 1)) + /* Fastest changing dimension */ + start[j] = (i * chunk_dims[j]) % dims[j]; + else + start[j] = ((i * chunk_dims[j + 1]) / dims[j + 1]) * (chunk_dims[j]); + } + + /* + * Adjust file dataspace selection for next chunk. + */ + if (H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET, start, NULL, count, NULL) < 0) { + H5_FAILED(); + HDprintf(" failed to set hyperslab selection\n"); + goto error; + } + + for (j = 0; j < chunk_dims[0]; j++) + for (k = 0; k < chunk_dims[1]; k++) + read_buf[j][k] = 0; + + if (H5Dread(dset_id, DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_DTYPE, mspace_id, + fspace_id, H5P_DEFAULT, read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", + DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_NAME); + goto error; + } + + for (j = 0; j < chunk_dims[0]; j++) { + for (k = 0; k < chunk_dims[1]; k++) { + size_t val = + ((j * chunk_dims[0]) + k + i) + + ((hsize_t)mpi_rank * n_chunks_per_rank) /* Additional value offset for each rank */ + + niter; + if (read_buf[j][k] != (int)val) { + H5_FAILED(); + HDprintf(" data verification failed for chunk %lld\n", (long long)i); + goto error; + } + } + } + } + + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + if (MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD)) { + H5_FAILED(); + HDprintf(" MPI_Barrier failed\n"); + goto error; + } + } + + if (chunk_dims) { + HDfree(chunk_dims); + chunk_dims = NULL; + } + + if (dims) { + HDfree(dims); + dims = NULL; + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + + if (H5Sclose(mspace_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (write_buf) + HDfree(write_buf); + if (chunk_dims) + HDfree(chunk_dims); + if (dims) + HDfree(dims); + H5Pclose(dcpl_id); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Pclose(fapl_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to check that a dataset composed of multiple chunks + * can be written and read correctly several times in a row. + * When reading back the chunks of the dataset, the file + * dataspace and memory dataspace used are differently shaped. + * The dataset's first dimension grows with the number of MPI + * ranks, while the other dimensions are fixed. + */ +#define DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_FIXED_CHUNK_DIMSIZE \ + 100 /* Should be an even divisor of fixed dimension size */ +#define DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_READ_BUF_DIMSIZE \ + (DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_FIXED_CHUNK_DIMSIZE / 10) +#define DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_FIXED_DIMSIZE 1000 +#define DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK 2 +#define DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_DTYPESIZE sizeof(int) +#define DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_DTYPE H5T_NATIVE_INT +#define DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_GROUP_NAME \ + "multi_chunk_dataset_diff_space_overwrite_test" +#define DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_NAME "multi_chunk_dataset" +#define DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_NITERS 10 +static int +test_overwrite_multi_chunk_dataset_diff_shape_read(void) +{ + hsize_t *dims = NULL; + hsize_t *chunk_dims = NULL; + hsize_t retrieved_chunk_dims[DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK]; + hsize_t start[DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK]; + hsize_t count[DATASET_MULTI_CHUNK_OVERWRITE_SAME_SPACE_READ_TEST_DSET_SPACE_RANK]; + size_t i, data_size, chunk_size, n_chunks_per_rank; + size_t niter; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t container_group = H5I_INVALID_HID, group_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dcpl_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + void *write_buf = NULL; + int read_buf[DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_READ_BUF_DIMSIZE] + [DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_READ_BUF_DIMSIZE]; + + TESTING("several overwrites to dataset with multiple chunks using differently shaped dataspaces"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_GET_PLIST)) { + SKIPPED(); + HDprintf(" API functions for basic file, group, dataset, or getting property list aren't " + "supported with this connector\n"); + return 0; + } + + if (NULL == (dims = HDmalloc(DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK * + sizeof(hsize_t)))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset dimensionality\n"); + goto error; + } + + if (NULL == (chunk_dims = HDmalloc(DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK * + sizeof(hsize_t)))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset dimensionality\n"); + goto error; + } + + for (i = 0; i < DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; i++) { + if (i == 0) { + dims[i] = (hsize_t)mpi_size; + chunk_dims[i] = 1; + } + else { + dims[i] = DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_FIXED_DIMSIZE; + chunk_dims[i] = DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_FIXED_CHUNK_DIMSIZE; + } + } + + for (i = 0, chunk_size = 1; i < DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; i++) + chunk_size *= chunk_dims[i]; + chunk_size *= DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_DTYPESIZE; + + for (i = 0, data_size = 1; i < DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; i++) + data_size *= dims[i]; + data_size *= DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_DTYPESIZE; + + /* + * Have rank 0 create the dataset, but don't fill it with data yet. + */ + BEGIN_INDEPENDENT_OP(dset_create) + { + if (MAINPROCESS) { + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open file '%s'\n", H5_api_test_parallel_filename); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((group_id = H5Gcreate2(container_group, + DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_GROUP_NAME, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create container sub-group '%s'\n", + DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_GROUP_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((fspace_id = H5Screate_simple( + DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK, dims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" failed to create file dataspace for dataset\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0) { + H5_FAILED(); + HDprintf(" failed to create DCPL\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + if (H5Pset_chunk(dcpl_id, DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK, + chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" failed to set chunking on DCPL\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + /* Set dataset space allocation time to Early to ensure all chunk-related metadata is available to + * all other processes when they open the dataset */ + if (H5Pset_alloc_time(dcpl_id, H5D_ALLOC_TIME_EARLY) < 0) { + H5_FAILED(); + HDprintf(" failed to set allocation time on DCPL\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((dset_id = H5Dcreate2(group_id, DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_NAME, + DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_DTYPE, + fspace_id, H5P_DEFAULT, dcpl_id, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create dataset '%s'\n", + DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_create); + } + + /* + * See if a copy of the DCPL reports the correct chunking. + */ + if (H5Pclose(dcpl_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close DCPL\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + if ((dcpl_id = H5Dget_create_plist(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve copy of DCPL\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + memset(retrieved_chunk_dims, 0, sizeof(retrieved_chunk_dims)); + if (H5Pget_chunk(dcpl_id, DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK, + retrieved_chunk_dims) < 0) { + H5_FAILED(); + HDprintf(" failed to retrieve chunking info\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + for (i = 0; i < DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; i++) { + if (chunk_dims[i] != retrieved_chunk_dims[i]) { + H5_FAILED(); + HDprintf(" chunk dimensionality retrieved from DCPL didn't match originally specified " + "dimensionality\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + } + + if (NULL == (write_buf = HDmalloc(data_size))) { + H5_FAILED(); + HDprintf(" couldn't allocate buffer for dataset write\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dcpl_id >= 0) { + H5E_BEGIN_TRY + { + H5Pclose(dcpl_id); + } + H5E_END_TRY; + dcpl_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + /* + * Close and re-open the file on all ranks. + */ + if (H5Gclose(group_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close test's container group\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + if (H5Gclose(container_group) < 0) { + H5_FAILED(); + HDprintf(" failed to close container group\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close file for data flushing\n"); + INDEPENDENT_OP_ERROR(dset_create); + } + } + } + END_INDEPENDENT_OP(dset_create); + + /* + * Re-open file on all ranks. + */ + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, TRUE)) < 0) + TEST_ERROR; + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't re-open file '%s'\n", H5_api_test_parallel_filename); + goto error; + } + if ((container_group = H5Gopen2(file_id, DATASET_TEST_GROUP_NAME, H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container group '%s'\n", DATASET_TEST_GROUP_NAME); + goto error; + } + if ((group_id = H5Gopen2(container_group, DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_GROUP_NAME, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open container sub-group '%s'\n", + DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_GROUP_NAME); + goto error; + } + + /* + * Create memory dataspace for read buffer. + */ + { + hsize_t mdims[] = {DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_READ_BUF_DIMSIZE, + DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_READ_BUF_DIMSIZE}; + + if ((mspace_id = H5Screate_simple(DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK, + mdims, NULL)) < 0) { + H5_FAILED(); + HDprintf(" failed to create memory dataspace\n"); + goto error; + } + } + + for (i = 0; i < DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; i++) { + count[i] = chunk_dims[i]; + } + + if (MAINPROCESS) + HDprintf("\n"); + for (niter = 0; niter < DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_NITERS; niter++) { + if ((dset_id = H5Dopen2(group_id, DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_NAME, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", + DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_NAME); + goto error; + } + + BEGIN_INDEPENDENT_OP(dset_write) + { + if (MAINPROCESS) { + memset(write_buf, 0, data_size); + + /* + * Ensure that each underlying chunk contains the values + * + * chunk_index .. (chunk_nelemts - 1) + chunk_index. + * + * That is to say, for a chunk size of 10 x 10, chunk 0 + * contains the values + * + * 0 .. 99 + * + * while the next chunk contains the values + * + * 1 .. 100 + * + * and so on. On each iteration, we add 1 to the previous + * values. + */ + for (i = 0; i < data_size / DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_DTYPESIZE; + i++) { + size_t j; + size_t base; + size_t tot_adjust; + + /* + * Calculate a starting base value by taking the index value mod + * the size of a chunk in each dimension. + */ + for (j = 0, base = i; + j < DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; j++) + if (chunk_dims[j] > 1 && base >= chunk_dims[j]) + base %= chunk_dims[j]; + + /* + * Calculate the adjustment in each dimension. + */ + for (j = 0, tot_adjust = 0; + j < DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; j++) { + if (j == (DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK - 1)) + tot_adjust += (i % dims[j]) / chunk_dims[j]; + else { + size_t k; + size_t n_faster_elemts; + + /* + * Calculate the number of elements in faster dimensions. + */ + for (k = j + 1, n_faster_elemts = 1; + k < DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; k++) + n_faster_elemts *= dims[k]; + + tot_adjust += (((i / n_faster_elemts) / chunk_dims[j]) * + (dims[j + 1] / chunk_dims[j + 1])) + + (((i / n_faster_elemts) % chunk_dims[j]) * chunk_dims[j + 1]); + } + } + + ((int *)write_buf)[i] = (int)(base + tot_adjust + niter); + } + + /* + * Write every chunk in the dataset. + */ + if (H5Dwrite(dset_id, DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_DTYPE, H5S_ALL, + H5S_ALL, H5P_DEFAULT, write_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't write to dataset '%s'\n", + DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_NAME); + INDEPENDENT_OP_ERROR(dset_write); + } + } + } + END_INDEPENDENT_OP(dset_write); + + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + if (MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD)) { + H5_FAILED(); + HDprintf(" MPI_Barrier failed\n"); + goto error; + } + + if ((dset_id = H5Dopen2(group_id, DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_NAME, + H5P_DEFAULT)) < 0) { + H5_FAILED(); + HDprintf(" couldn't open dataset '%s'\n", + DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_NAME); + goto error; + } + + if ((fspace_id = H5Dget_space(dset_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't get dataset dataspace\n"); + goto error; + } + + /* + * Each rank reads their respective chunks in the dataset, checking the data for each one. + */ + for (i = 0, n_chunks_per_rank = (data_size / (size_t)mpi_size) / chunk_size; i < n_chunks_per_rank; + i++) { + size_t j, k; + + if (MAINPROCESS) + HDprintf("\r All ranks reading chunk %zu", i); + + for (j = 0; j < DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK; j++) { + if (j == 0) + start[j] = (hsize_t)mpi_rank; + else if (j == (DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_SPACE_RANK - 1)) + /* Fastest changing dimension */ + start[j] = (i * chunk_dims[j]) % dims[j]; + else + start[j] = ((i * chunk_dims[j + 1]) / dims[j + 1]) * (chunk_dims[j]); + } + + /* + * Adjust file dataspace selection for next chunk. + */ + if (H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET, start, NULL, count, NULL) < 0) { + H5_FAILED(); + HDprintf(" failed to set hyperslab selection\n"); + goto error; + } + + for (j = 0; j < DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_READ_BUF_DIMSIZE; j++) + for (k = 0; k < DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_READ_BUF_DIMSIZE; k++) + read_buf[j][k] = 0; + + if (H5Dread(dset_id, DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_DTYPE, mspace_id, + fspace_id, H5P_DEFAULT, read_buf) < 0) { + H5_FAILED(); + HDprintf(" couldn't read from dataset '%s'\n", + DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_DSET_NAME); + goto error; + } + + for (j = 0; j < DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_READ_BUF_DIMSIZE; j++) { + for (k = 0; k < DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_READ_BUF_DIMSIZE; k++) { + size_t val = + ((j * DATASET_MULTI_CHUNK_OVERWRITE_DIFF_SPACE_READ_TEST_READ_BUF_DIMSIZE) + k + i) + + ((hsize_t)mpi_rank * n_chunks_per_rank) + niter; + + if (read_buf[j][k] != (int)val) { + H5_FAILED(); + HDprintf(" data verification failed for chunk %lld\n", (long long)i); + goto error; + } + } + } + } + + if (fspace_id >= 0) { + H5E_BEGIN_TRY + { + H5Sclose(fspace_id); + } + H5E_END_TRY; + fspace_id = H5I_INVALID_HID; + } + if (dset_id >= 0) { + H5E_BEGIN_TRY + { + H5Dclose(dset_id); + } + H5E_END_TRY; + dset_id = H5I_INVALID_HID; + } + + if (MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD)) { + H5_FAILED(); + HDprintf(" MPI_Barrier failed\n"); + goto error; + } + } + + if (chunk_dims) { + HDfree(chunk_dims); + chunk_dims = NULL; + } + + if (dims) { + HDfree(dims); + dims = NULL; + } + + if (write_buf) { + HDfree(write_buf); + write_buf = NULL; + } + + if (H5Sclose(mspace_id) < 0) + TEST_ERROR; + if (H5Gclose(group_id) < 0) + TEST_ERROR; + if (H5Gclose(container_group) < 0) + TEST_ERROR; + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + if (write_buf) + HDfree(write_buf); + if (chunk_dims) + HDfree(chunk_dims); + if (dims) + HDfree(dims); + H5Pclose(dcpl_id); + H5Sclose(mspace_id); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Gclose(group_id); + H5Gclose(container_group); + H5Pclose(fapl_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +int +H5_api_dataset_test_parallel(void) +{ + size_t i; + int nerrors; + + if (MAINPROCESS) { + HDprintf("**********************************************\n"); + HDprintf("* *\n"); + HDprintf("* API Parallel Dataset Tests *\n"); + HDprintf("* *\n"); + HDprintf("**********************************************\n\n"); + } + + for (i = 0, nerrors = 0; i < ARRAY_LENGTH(par_dataset_tests); i++) { + nerrors += (*par_dataset_tests[i])() ? 1 : 0; + + if (MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD)) { + if (MAINPROCESS) + HDprintf(" MPI_Barrier() failed!\n"); + } + } + + if (MAINPROCESS) + HDprintf("\n"); + + return nerrors; +} diff --git a/testpar/API/H5_api_dataset_test_parallel.h b/testpar/API/H5_api_dataset_test_parallel.h new file mode 100644 index 0000000..1e2cbd0 --- /dev/null +++ b/testpar/API/H5_api_dataset_test_parallel.h @@ -0,0 +1,20 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef H5_API_DATASET_TEST_PARALLEL_H_ +#define H5_API_DATASET_TEST_PARALLEL_H_ + +#include "H5_api_test_parallel.h" + +int H5_api_dataset_test_parallel(void); + +#endif /* H5_API_DATASET_TEST_PARALLEL_H_ */ diff --git a/testpar/API/H5_api_datatype_test_parallel.c b/testpar/API/H5_api_datatype_test_parallel.c new file mode 100644 index 0000000..7d090c0 --- /dev/null +++ b/testpar/API/H5_api_datatype_test_parallel.c @@ -0,0 +1,47 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "H5_api_datatype_test_parallel.h" + +/* + * The array of parallel datatype tests to be performed. + */ +static int (*par_datatype_tests[])(void) = {NULL}; + +int +H5_api_datatype_test_parallel(void) +{ + size_t i; + int nerrors; + + if (MAINPROCESS) { + HDprintf("**********************************************\n"); + HDprintf("* *\n"); + HDprintf("* API Parallel Datatype Tests *\n"); + HDprintf("* *\n"); + HDprintf("**********************************************\n\n"); + } + + for (i = 0, nerrors = 0; i < ARRAY_LENGTH(par_datatype_tests); i++) { + /* nerrors += (*par_datatype_tests[i])() ? 1 : 0; */ + + if (MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD)) { + if (MAINPROCESS) + HDprintf(" MPI_Barrier() failed!\n"); + } + } + + if (MAINPROCESS) + HDprintf("\n"); + + return nerrors; +} diff --git a/testpar/API/H5_api_datatype_test_parallel.h b/testpar/API/H5_api_datatype_test_parallel.h new file mode 100644 index 0000000..0a2ba50 --- /dev/null +++ b/testpar/API/H5_api_datatype_test_parallel.h @@ -0,0 +1,20 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef H5_API_DATATYPE_TEST_PARALLEL_H_ +#define H5_API_DATATYPE_TEST_PARALLEL_H_ + +#include "H5_api_test_parallel.h" + +int H5_api_datatype_test_parallel(void); + +#endif /* H5_API_DATATYPE_TEST_PARALLEL_H_ */ diff --git a/testpar/API/H5_api_file_test_parallel.c b/testpar/API/H5_api_file_test_parallel.c new file mode 100644 index 0000000..20fb2ba --- /dev/null +++ b/testpar/API/H5_api_file_test_parallel.c @@ -0,0 +1,367 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "H5_api_file_test_parallel.h" + +static int test_create_file(void); +static int test_open_file(void); +static int test_split_comm_file_access(void); + +/* + * The array of parallel file tests to be performed. + */ +static int (*par_file_tests[])(void) = { + test_create_file, + test_open_file, + test_split_comm_file_access, +}; + +/* + * A test to ensure that a file can be created in parallel. + */ +#define FILE_CREATE_TEST_FILENAME "test_file_parallel.h5" +static int +test_create_file(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + + TESTING("H5Fcreate"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file aren't supported with this connector\n"); + return 0; + } + + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, TRUE)) < 0) + TEST_ERROR; + + if ((file_id = H5Fcreate(FILE_CREATE_TEST_FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s'\n", FILE_CREATE_TEST_FILENAME); + goto error; + } + + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + if (H5Fclose(file_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(fapl_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * A test to ensure that a file can be opened in parallel. + */ +static int +test_open_file(void) +{ + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + + TESTING_MULTIPART("H5Fopen"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file aren't supported with this connector\n"); + return 0; + } + + TESTING_2("test setup"); + + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, TRUE)) < 0) + TEST_ERROR; + + PASSED(); + + BEGIN_MULTIPART + { + PART_BEGIN(H5Fopen_rdonly) + { + TESTING_2("H5Fopen in read-only mode"); + + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDONLY, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" unable to open file '%s' in read-only mode\n", H5_api_test_parallel_filename); + PART_ERROR(H5Fopen_rdonly); + } + + PASSED(); + } + PART_END(H5Fopen_rdonly); + + if (file_id >= 0) { + H5E_BEGIN_TRY + { + H5Fclose(file_id); + } + H5E_END_TRY; + file_id = H5I_INVALID_HID; + } + + PART_BEGIN(H5Fopen_rdwrite) + { + TESTING_2("H5Fopen in read-write mode"); + + if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" unable to open file '%s' in read-write mode\n", H5_api_test_parallel_filename); + PART_ERROR(H5Fopen_rdwrite); + } + + PASSED(); + } + PART_END(H5Fopen_rdwrite); + + if (file_id >= 0) { + H5E_BEGIN_TRY + { + H5Fclose(file_id); + } + H5E_END_TRY; + file_id = H5I_INVALID_HID; + } + + /* + * XXX: SWMR open flags + */ + } + END_MULTIPART; + + TESTING_2("test cleanup"); + + if (H5Pclose(fapl_id) < 0) + TEST_ERROR; + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(fapl_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * Tests file access by a communicator other than MPI_COMM_WORLD. + * + * Splits MPI_COMM_WORLD into two groups, where one (even_comm) contains + * the original processes of even ranks. The other (odd_comm) contains + * the original processes of odd ranks. Processes in even_comm create a + * file, then close it, using even_comm. Processes in old_comm just do + * a barrier using odd_comm. Then they all do a barrier using MPI_COMM_WORLD. + * If the file creation and close does not do correct collective action + * according to the communicator argument, the processes will freeze up + * sooner or later due to MPI_Barrier calls being mixed up. + */ +#define SPLIT_FILE_COMM_TEST_FILE_NAME "split_comm_file.h5" +static int +test_split_comm_file_access(void) +{ + MPI_Comm comm; + MPI_Info info = MPI_INFO_NULL; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + int is_old; + int newrank; + int err_occurred = 0; + + TESTING("file access with a split communicator"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC)) { + SKIPPED(); + HDprintf(" API functions for basic file aren't supported with this connector\n"); + return 0; + } + + /* set up MPI parameters */ + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + is_old = mpi_rank % 2; + if (MPI_SUCCESS != MPI_Comm_split(MPI_COMM_WORLD, is_old, mpi_rank, &comm)) { + H5_FAILED(); + HDprintf(" failed to split communicator!\n"); + goto error; + } + MPI_Comm_rank(comm, &newrank); + + if (is_old) { + /* odd-rank processes */ + if (MPI_SUCCESS != MPI_Barrier(comm)) { + err_occurred = 1; + goto access_end; + } + } + else { + /* even-rank processes */ + int sub_mpi_rank; /* rank in the sub-comm */ + + MPI_Comm_rank(comm, &sub_mpi_rank); + + /* setup file access template */ + if ((fapl_id = create_mpi_fapl(comm, info, TRUE)) < 0) { + err_occurred = 1; + goto access_end; + } + + /* create the file collectively */ + if ((file_id = H5Fcreate(SPLIT_FILE_COMM_TEST_FILE_NAME, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0) { + H5_FAILED(); + HDprintf(" couldn't create file '%s'\n", SPLIT_FILE_COMM_TEST_FILE_NAME); + err_occurred = 1; + goto access_end; + } + + /* close the file */ + if (H5Fclose(file_id) < 0) { + H5_FAILED(); + HDprintf(" failed to close file '%s'\n", SPLIT_FILE_COMM_TEST_FILE_NAME); + err_occurred = 1; + goto access_end; + } + + /* delete the test file */ + if (H5Fdelete(SPLIT_FILE_COMM_TEST_FILE_NAME, fapl_id) < 0) { + H5_FAILED(); + HDprintf(" failed to delete file '%s'\n", SPLIT_FILE_COMM_TEST_FILE_NAME); + err_occurred = 1; + goto access_end; + } + + /* Release file-access template */ + if (H5Pclose(fapl_id) < 0) { + err_occurred = 1; + goto access_end; + } + } +access_end: + + /* Get the collective results about whether an error occurred */ + if (MPI_SUCCESS != MPI_Allreduce(MPI_IN_PLACE, &err_occurred, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD)) { + H5_FAILED(); + HDprintf(" MPI_Allreduce failed\n"); + goto error; + } + + if (err_occurred) { + H5_FAILED(); + HDprintf(" an error occurred on only some ranks during split-communicator file access! - " + "collectively failing\n"); + goto error; + } + + if (MPI_SUCCESS != MPI_Comm_free(&comm)) { + H5_FAILED(); + HDprintf(" MPI_Comm_free failed\n"); + goto error; + } + + if (MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD)) { + H5_FAILED(); + HDprintf(" MPI_Barrier on MPI_COMM_WORLD failed\n"); + goto error; + } + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY + { + H5Pclose(fapl_id); + H5Fclose(file_id); + } + H5E_END_TRY; + + return 1; +} + +/* + * Cleanup temporary test files + */ +static void +cleanup_files(void) +{ + hid_t fapl_id = H5I_INVALID_HID; + + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, TRUE)) < 0) { + if (MAINPROCESS) + HDprintf(" failed to create FAPL for deleting test files\n"); + return; + } + + H5Fdelete(FILE_CREATE_TEST_FILENAME, fapl_id); + + /* The below file is deleted as part of the test */ + /* H5Fdelete(SPLIT_FILE_COMM_TEST_FILE_NAME, H5P_DEFAULT); */ + + if (H5Pclose(fapl_id) < 0) { + if (MAINPROCESS) + HDprintf(" failed to close FAPL used for deleting test files\n"); + return; + } +} + +int +H5_api_file_test_parallel(void) +{ + size_t i; + int nerrors; + + if (MAINPROCESS) { + HDprintf("**********************************************\n"); + HDprintf("* *\n"); + HDprintf("* API Parallel File Tests *\n"); + HDprintf("* *\n"); + HDprintf("**********************************************\n\n"); + } + + for (i = 0, nerrors = 0; i < ARRAY_LENGTH(par_file_tests); i++) { + nerrors += (*par_file_tests[i])() ? 1 : 0; + + if (MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD)) { + if (MAINPROCESS) + HDprintf(" MPI_Barrier() failed!\n"); + } + } + + if (MAINPROCESS) { + HDprintf("\n"); + HDprintf("Cleaning up testing files\n"); + } + + cleanup_files(); + + return nerrors; +} diff --git a/testpar/API/H5_api_file_test_parallel.h b/testpar/API/H5_api_file_test_parallel.h new file mode 100644 index 0000000..aac9800 --- /dev/null +++ b/testpar/API/H5_api_file_test_parallel.h @@ -0,0 +1,20 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef H5_API_FILE_TEST_PARALLEL_H_ +#define H5_API_FILE_TEST_PARALLEL_H_ + +#include "H5_api_test_parallel.h" + +int H5_api_file_test_parallel(void); + +#endif /* H5_API_FILE_TEST_PARALLEL_H_ */ diff --git a/testpar/API/H5_api_group_test_parallel.c b/testpar/API/H5_api_group_test_parallel.c new file mode 100644 index 0000000..d6d8f18 --- /dev/null +++ b/testpar/API/H5_api_group_test_parallel.c @@ -0,0 +1,47 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "H5_api_group_test_parallel.h" + +/* + * The array of parallel group tests to be performed. + */ +static int (*par_group_tests[])(void) = {NULL}; + +int +H5_api_group_test_parallel(void) +{ + size_t i; + int nerrors; + + if (MAINPROCESS) { + HDprintf("**********************************************\n"); + HDprintf("* *\n"); + HDprintf("* API Parallel Group Tests *\n"); + HDprintf("* *\n"); + HDprintf("**********************************************\n\n"); + } + + for (i = 0, nerrors = 0; i < ARRAY_LENGTH(par_group_tests); i++) { + /* nerrors += (*par_group_tests[i])() ? 1 : 0; */ + + if (MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD)) { + if (MAINPROCESS) + HDprintf(" MPI_Barrier() failed!\n"); + } + } + + if (MAINPROCESS) + HDprintf("\n"); + + return nerrors; +} diff --git a/testpar/API/H5_api_group_test_parallel.h b/testpar/API/H5_api_group_test_parallel.h new file mode 100644 index 0000000..87dd24f --- /dev/null +++ b/testpar/API/H5_api_group_test_parallel.h @@ -0,0 +1,20 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef H5_API_GROUP_TEST_PARALLEL_H_ +#define H5_API_GROUP_TEST_PARALLEL_H_ + +#include "H5_api_test_parallel.h" + +int H5_api_group_test_parallel(void); + +#endif /* H5_API_GROUP_TEST_PARALLEL_H_ */ diff --git a/testpar/API/H5_api_link_test_parallel.c b/testpar/API/H5_api_link_test_parallel.c new file mode 100644 index 0000000..fb865a0 --- /dev/null +++ b/testpar/API/H5_api_link_test_parallel.c @@ -0,0 +1,47 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "H5_api_link_test_parallel.h" + +/* + * The array of parallel link tests to be performed. + */ +static int (*par_link_tests[])(void) = {NULL}; + +int +H5_api_link_test_parallel(void) +{ + size_t i; + int nerrors; + + if (MAINPROCESS) { + HDprintf("**********************************************\n"); + HDprintf("* *\n"); + HDprintf("* API Parallel Link Tests *\n"); + HDprintf("* *\n"); + HDprintf("**********************************************\n\n"); + } + + for (i = 0, nerrors = 0; i < ARRAY_LENGTH(par_link_tests); i++) { + /* nerrors += (*par_link_tests[i])() ? 1 : 0; */ + + if (MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD)) { + if (MAINPROCESS) + HDprintf(" MPI_Barrier() failed!\n"); + } + } + + if (MAINPROCESS) + HDprintf("\n"); + + return nerrors; +} diff --git a/testpar/API/H5_api_link_test_parallel.h b/testpar/API/H5_api_link_test_parallel.h new file mode 100644 index 0000000..dbf0fc7 --- /dev/null +++ b/testpar/API/H5_api_link_test_parallel.h @@ -0,0 +1,20 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef H5_API_LINK_TEST_PARALLEL_H_ +#define H5_API_LINK_TEST_PARALLEL_H_ + +#include "H5_api_test_parallel.h" + +int H5_api_link_test_parallel(void); + +#endif /* H5_API_LINK_TEST_PARALLEL_H_ */ diff --git a/testpar/API/H5_api_misc_test_parallel.c b/testpar/API/H5_api_misc_test_parallel.c new file mode 100644 index 0000000..0dc85eb --- /dev/null +++ b/testpar/API/H5_api_misc_test_parallel.c @@ -0,0 +1,47 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "H5_api_misc_test_parallel.h" + +/* + * The array of parallel miscellaneous tests to be performed. + */ +static int (*par_misc_tests[])(void) = {NULL}; + +int +H5_api_misc_test_parallel(void) +{ + size_t i; + int nerrors; + + if (MAINPROCESS) { + HDprintf("**********************************************\n"); + HDprintf("* *\n"); + HDprintf("* API Parallel Miscellaneous Tests *\n"); + HDprintf("* *\n"); + HDprintf("**********************************************\n\n"); + } + + for (i = 0, nerrors = 0; i < ARRAY_LENGTH(par_misc_tests); i++) { + /* nerrors += (*par_misc_tests[i])() ? 1 : 0; */ + + if (MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD)) { + if (MAINPROCESS) + HDprintf(" MPI_Barrier() failed!\n"); + } + } + + if (MAINPROCESS) + HDprintf("\n"); + + return nerrors; +} diff --git a/testpar/API/H5_api_misc_test_parallel.h b/testpar/API/H5_api_misc_test_parallel.h new file mode 100644 index 0000000..84553a9 --- /dev/null +++ b/testpar/API/H5_api_misc_test_parallel.h @@ -0,0 +1,20 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef H5_API_MISC_TEST_PARALLEL_H_ +#define H5_API_MISC_TEST_PARALLEL_H_ + +#include "H5_api_test_parallel.h" + +int H5_api_misc_test_parallel(void); + +#endif /* H5_API_MISC_TEST_PARALLEL_H_ */ diff --git a/testpar/API/H5_api_object_test_parallel.c b/testpar/API/H5_api_object_test_parallel.c new file mode 100644 index 0000000..a264eb2 --- /dev/null +++ b/testpar/API/H5_api_object_test_parallel.c @@ -0,0 +1,47 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "H5_api_object_test_parallel.h" + +/* + * The array of parallel object tests to be performed. + */ +static int (*par_object_tests[])(void) = {NULL}; + +int +H5_api_object_test_parallel(void) +{ + size_t i; + int nerrors; + + if (MAINPROCESS) { + HDprintf("**********************************************\n"); + HDprintf("* *\n"); + HDprintf("* API Parallel Object Tests *\n"); + HDprintf("* *\n"); + HDprintf("**********************************************\n\n"); + } + + for (i = 0, nerrors = 0; i < ARRAY_LENGTH(par_object_tests); i++) { + /* nerrors += (*par_object_tests[i])() ? 1 : 0; */ + + if (MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD)) { + if (MAINPROCESS) + HDprintf(" MPI_Barrier() failed!\n"); + } + } + + if (MAINPROCESS) + HDprintf("\n"); + + return nerrors; +} diff --git a/testpar/API/H5_api_object_test_parallel.h b/testpar/API/H5_api_object_test_parallel.h new file mode 100644 index 0000000..6a8569f --- /dev/null +++ b/testpar/API/H5_api_object_test_parallel.h @@ -0,0 +1,20 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef H5_API_OBJECT_TEST_PARALLEL_H_ +#define H5_API_OBJECT_TEST_PARALLEL_H_ + +#include "H5_api_test_parallel.h" + +int H5_api_object_test_parallel(void); + +#endif /* H5_API_OBJECT_TEST_PARALLEL_H_ */ diff --git a/testpar/API/H5_api_test_parallel.c b/testpar/API/H5_api_test_parallel.c new file mode 100644 index 0000000..45fa4ec --- /dev/null +++ b/testpar/API/H5_api_test_parallel.c @@ -0,0 +1,338 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "H5_api_test_util.h" +#include "H5_api_test_parallel.h" + +#include "H5_api_attribute_test_parallel.h" +#include "H5_api_dataset_test_parallel.h" +#include "H5_api_datatype_test_parallel.h" +#include "H5_api_file_test_parallel.h" +#include "H5_api_group_test_parallel.h" +#include "H5_api_link_test_parallel.h" +#include "H5_api_misc_test_parallel.h" +#include "H5_api_object_test_parallel.h" +#ifdef H5_API_TEST_HAVE_ASYNC +#include "H5_api_async_test_parallel.h" +#endif + +char H5_api_test_parallel_filename[H5_API_TEST_FILENAME_MAX_LENGTH]; + +const char *test_path_prefix; + +size_t n_tests_run_g; +size_t n_tests_passed_g; +size_t n_tests_failed_g; +size_t n_tests_skipped_g; + +int mpi_size; +int mpi_rank; + +/* X-macro to define the following for each test: + * - enum type + * - name + * - test function + * - enabled by default + */ +#ifdef H5_API_TEST_HAVE_ASYNC +#define H5_API_PARALLEL_TESTS \ + X(H5_API_TEST_NULL, "", NULL, 0) \ + X(H5_API_TEST_FILE, "file", H5_api_file_test_parallel, 1) \ + X(H5_API_TEST_GROUP, "group", H5_api_group_test_parallel, 1) \ + X(H5_API_TEST_DATASET, "dataset", H5_api_dataset_test_parallel, 1) \ + X(H5_API_TEST_DATATYPE, "datatype", H5_api_datatype_test_parallel, 1) \ + X(H5_API_TEST_ATTRIBUTE, "attribute", H5_api_attribute_test_parallel, 1) \ + X(H5_API_TEST_LINK, "link", H5_api_link_test_parallel, 1) \ + X(H5_API_TEST_OBJECT, "object", H5_api_object_test_parallel, 1) \ + X(H5_API_TEST_MISC, "misc", H5_api_misc_test_parallel, 1) \ + X(H5_API_TEST_ASYNC, "async", H5_api_async_test_parallel, 1) \ + X(H5_API_TEST_MAX, "", NULL, 0) +#else +#define H5_API_PARALLEL_TESTS \ + X(H5_API_TEST_NULL, "", NULL, 0) \ + X(H5_API_TEST_FILE, "file", H5_api_file_test_parallel, 1) \ + X(H5_API_TEST_GROUP, "group", H5_api_group_test_parallel, 1) \ + X(H5_API_TEST_DATASET, "dataset", H5_api_dataset_test_parallel, 1) \ + X(H5_API_TEST_DATATYPE, "datatype", H5_api_datatype_test_parallel, 1) \ + X(H5_API_TEST_ATTRIBUTE, "attribute", H5_api_attribute_test_parallel, 1) \ + X(H5_API_TEST_LINK, "link", H5_api_link_test_parallel, 1) \ + X(H5_API_TEST_OBJECT, "object", H5_api_object_test_parallel, 1) \ + X(H5_API_TEST_MISC, "misc", H5_api_misc_test_parallel, 1) \ + X(H5_API_TEST_MAX, "", NULL, 0) +#endif + +#define X(a, b, c, d) a, +enum H5_api_test_type { H5_API_PARALLEL_TESTS }; +#undef X +#define X(a, b, c, d) b, +static const char *const H5_api_test_name[] = {H5_API_PARALLEL_TESTS}; +#undef X +#define X(a, b, c, d) c, +static int (*H5_api_test_func[])(void) = {H5_API_PARALLEL_TESTS}; +#undef X +#define X(a, b, c, d) d, +static int H5_api_test_enabled[] = {H5_API_PARALLEL_TESTS}; +#undef X + +static enum H5_api_test_type +H5_api_test_name_to_type(const char *test_name) +{ + enum H5_api_test_type i = 0; + + while (strcmp(H5_api_test_name[i], test_name) && i != H5_API_TEST_MAX) + i++; + + return ((i == H5_API_TEST_MAX) ? H5_API_TEST_NULL : i); +} + +static void +H5_api_test_run(void) +{ + enum H5_api_test_type i; + + for (i = H5_API_TEST_FILE; i < H5_API_TEST_MAX; i++) + if (H5_api_test_enabled[i]) + (void)H5_api_test_func[i](); +} + +hid_t +create_mpi_fapl(MPI_Comm comm, MPI_Info info, hbool_t coll_md_read) +{ + hid_t ret_pl = H5I_INVALID_HID; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + if ((ret_pl = H5Pcreate(H5P_FILE_ACCESS)) < 0) + goto error; + + if (H5Pset_fapl_mpio(ret_pl, comm, info) < 0) + goto error; + if (H5Pset_all_coll_metadata_ops(ret_pl, coll_md_read) < 0) + goto error; + if (H5Pset_coll_metadata_write(ret_pl, TRUE) < 0) + goto error; + + return ret_pl; + +error: + return H5I_INVALID_HID; +} /* end create_mpi_fapl() */ + +/* + * Generates random dimensions for a dataspace. The first dimension + * is always `mpi_size` to allow for convenient subsetting; the rest + * of the dimensions are randomized. + */ +int +generate_random_parallel_dimensions(int space_rank, hsize_t **dims_out) +{ + hsize_t *dims = NULL; + size_t i; + + if (space_rank <= 0) + goto error; + + if (NULL == (dims = HDmalloc((size_t)space_rank * sizeof(hsize_t)))) + goto error; + if (MAINPROCESS) { + for (i = 0; i < (size_t)space_rank; i++) { + if (i == 0) + dims[i] = (hsize_t)mpi_size; + else + dims[i] = (hsize_t)((rand() % MAX_DIM_SIZE) + 1); + } + } + + /* + * Ensure that the dataset dimensions are uniform across ranks. + */ + if (MPI_SUCCESS != MPI_Bcast(dims, space_rank, MPI_UNSIGNED_LONG_LONG, 0, MPI_COMM_WORLD)) + goto error; + + *dims_out = dims; + + return 0; + +error: + if (dims) + HDfree(dims); + + return -1; +} + +int +main(int argc, char **argv) +{ + const char *vol_connector_name; + unsigned seed; + hid_t fapl_id = H5I_INVALID_HID; + + MPI_Init(&argc, &argv); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + + /* Simple argument checking, TODO can improve that later */ + if (argc > 1) { + enum H5_api_test_type i = H5_api_test_name_to_type(argv[1]); + if (i != H5_API_TEST_NULL) { + /* Run only specific API test */ + memset(H5_api_test_enabled, 0, sizeof(H5_api_test_enabled)); + H5_api_test_enabled[i] = 1; + } + } + + /* + * Make sure that HDF5 is initialized on all MPI ranks before proceeding. + * This is important for certain VOL connectors which may require a + * collective initialization. + */ + H5open(); + + n_tests_run_g = 0; + n_tests_passed_g = 0; + n_tests_failed_g = 0; + n_tests_skipped_g = 0; + + if (MAINPROCESS) { + seed = (unsigned)HDtime(NULL); + } + + if (mpi_size > 1) { + if (MPI_SUCCESS != MPI_Bcast(&seed, 1, MPI_UNSIGNED, 0, MPI_COMM_WORLD)) { + if (MAINPROCESS) + HDprintf("Couldn't broadcast test seed\n"); + goto error; + } + } + + srand(seed); + + if (NULL == (test_path_prefix = HDgetenv(HDF5_API_TEST_PATH_PREFIX))) + test_path_prefix = ""; + + HDsnprintf(H5_api_test_parallel_filename, H5_API_TEST_FILENAME_MAX_LENGTH, "%s%s", test_path_prefix, + PARALLEL_TEST_FILE_NAME); + + if (NULL == (vol_connector_name = HDgetenv(HDF5_VOL_CONNECTOR))) { + if (MAINPROCESS) + HDprintf("No VOL connector selected; using native VOL connector\n"); + vol_connector_name = "native"; + } + + if (MAINPROCESS) { + HDprintf("Running parallel API tests with VOL connector '%s'\n\n", vol_connector_name); + HDprintf("Test parameters:\n"); + HDprintf(" - Test file name: '%s'\n", H5_api_test_parallel_filename); + HDprintf(" - Number of MPI ranks: %d\n", mpi_size); + HDprintf(" - Test seed: %u\n", seed); + HDprintf("\n\n"); + } + + /* Retrieve the VOL cap flags - work around an HDF5 + * library issue by creating a FAPL + */ + BEGIN_INDEPENDENT_OP(get_capability_flags) + { + if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, FALSE)) < 0) { + if (MAINPROCESS) + HDfprintf(stderr, "Unable to create FAPL\n"); + INDEPENDENT_OP_ERROR(get_capability_flags); + } + + vol_cap_flags_g = H5VL_CAP_FLAG_NONE; + if (H5Pget_vol_cap_flags(fapl_id, &vol_cap_flags_g) < 0) { + if (MAINPROCESS) + HDfprintf(stderr, "Unable to retrieve VOL connector capability flags\n"); + INDEPENDENT_OP_ERROR(get_capability_flags); + } + } + END_INDEPENDENT_OP(get_capability_flags); + + /* + * Create the file that will be used for all of the tests, + * except for those which test file creation. + */ + BEGIN_INDEPENDENT_OP(create_test_container) + { + if (MAINPROCESS) { + if (create_test_container(H5_api_test_parallel_filename, vol_cap_flags_g) < 0) { + HDprintf(" failed to create testing container file '%s'\n", H5_api_test_parallel_filename); + INDEPENDENT_OP_ERROR(create_test_container); + } + } + } + END_INDEPENDENT_OP(create_test_container); + + /* Run all the tests that are enabled */ + H5_api_test_run(); + + if (MAINPROCESS) + HDprintf("Cleaning up testing files\n"); + H5Fdelete(H5_api_test_parallel_filename, fapl_id); + + if (n_tests_run_g > 0) { + if (MAINPROCESS) + HDprintf("The below statistics are minimum values due to the possibility of some ranks failing a " + "test while others pass:\n"); + + if (MPI_SUCCESS != MPI_Allreduce(MPI_IN_PLACE, &n_tests_passed_g, 1, MPI_UNSIGNED_LONG_LONG, MPI_MIN, + MPI_COMM_WORLD)) { + if (MAINPROCESS) + HDprintf(" failed to collect consensus about the minimum number of tests that passed -- " + "reporting rank 0's (possibly inaccurate) value\n"); + } + + if (MAINPROCESS) + HDprintf("%s%zu/%zu (%.2f%%) API tests passed across all ranks with VOL connector '%s'\n", + n_tests_passed_g > 0 ? "At least " : "", n_tests_passed_g, n_tests_run_g, + ((double)n_tests_passed_g / (double)n_tests_run_g * 100.0), vol_connector_name); + + if (MPI_SUCCESS != MPI_Allreduce(MPI_IN_PLACE, &n_tests_failed_g, 1, MPI_UNSIGNED_LONG_LONG, MPI_MIN, + MPI_COMM_WORLD)) { + if (MAINPROCESS) + HDprintf(" failed to collect consensus about the minimum number of tests that failed -- " + "reporting rank 0's (possibly inaccurate) value\n"); + } + + if (MAINPROCESS) { + HDprintf("%s%zu/%zu (%.2f%%) API tests did not pass across all ranks with VOL connector '%s'\n", + n_tests_failed_g > 0 ? "At least " : "", n_tests_failed_g, n_tests_run_g, + ((double)n_tests_failed_g / (double)n_tests_run_g * 100.0), vol_connector_name); + + HDprintf("%zu/%zu (%.2f%%) API tests were skipped with VOL connector '%s'\n", n_tests_skipped_g, + n_tests_run_g, ((double)n_tests_skipped_g / (double)n_tests_run_g * 100.0), + vol_connector_name); + } + } + + if (fapl_id >= 0 && H5Pclose(fapl_id) < 0) { + if (MAINPROCESS) + HDprintf(" failed to close MPI FAPL\n"); + } + + H5close(); + + MPI_Finalize(); + + HDexit(EXIT_SUCCESS); + +error: + H5E_BEGIN_TRY + { + H5Pclose(fapl_id); + } + H5E_END_TRY; + + MPI_Finalize(); + + HDexit(EXIT_FAILURE); +} diff --git a/testpar/API/H5_api_test_parallel.h b/testpar/API/H5_api_test_parallel.h new file mode 100644 index 0000000..6df83e8 --- /dev/null +++ b/testpar/API/H5_api_test_parallel.h @@ -0,0 +1,188 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef H5_API_TEST_PARALLEL_H +#define H5_API_TEST_PARALLEL_H + +#include + +#include "testpar.h" + +#include "H5_api_test.h" + +/* Define H5VL_VERSION if not already defined */ +#ifndef H5VL_VERSION +#define H5VL_VERSION 0 +#endif + +/* Define macro to wait forever depending on version */ +#if H5VL_VERSION >= 2 +#define H5_API_TEST_WAIT_FOREVER H5ES_WAIT_FOREVER +#else +#define H5_API_TEST_WAIT_FOREVER UINT64_MAX +#endif + +#define PARALLEL_TEST_FILE_NAME "H5_api_test_parallel.h5" +extern char H5_api_test_parallel_filename[]; + +#undef TESTING +#undef TESTING_2 +#undef PASSED +#undef H5_FAILED +#undef H5_WARNING +#undef SKIPPED +#undef PUTS_ERROR +#undef TEST_ERROR +#undef STACK_ERROR +#undef FAIL_STACK_ERROR +#undef FAIL_PUTS_ERROR +#undef TESTING_MULTIPART + +#define TESTING(WHAT) \ + { \ + if (MAINPROCESS) { \ + printf("Testing %-62s", WHAT); \ + fflush(stdout); \ + } \ + n_tests_run_g++; \ + } +#define TESTING_2(WHAT) \ + { \ + if (MAINPROCESS) { \ + printf(" Testing %-60s", WHAT); \ + fflush(stdout); \ + } \ + n_tests_run_g++; \ + } +#define PASSED() \ + { \ + if (MAINPROCESS) { \ + puts(" PASSED"); \ + fflush(stdout); \ + } \ + n_tests_passed_g++; \ + } +#define H5_FAILED() \ + { \ + if (MAINPROCESS) { \ + puts("*FAILED*"); \ + fflush(stdout); \ + } \ + n_tests_failed_g++; \ + } +#define H5_WARNING() \ + { \ + if (MAINPROCESS) { \ + puts("*WARNING*"); \ + fflush(stdout); \ + } \ + } +#define SKIPPED() \ + { \ + if (MAINPROCESS) { \ + puts(" -SKIP-"); \ + fflush(stdout); \ + } \ + n_tests_skipped_g++; \ + } +#define PUTS_ERROR(s) \ + { \ + if (MAINPROCESS) { \ + puts(s); \ + AT(); \ + } \ + goto error; \ + } +#define TEST_ERROR \ + { \ + H5_FAILED(); \ + if (MAINPROCESS) { \ + AT(); \ + } \ + goto error; \ + } +#define STACK_ERROR \ + { \ + if (MAINPROCESS) { \ + H5Eprint2(H5E_DEFAULT, stdout); \ + } \ + goto error; \ + } +#define FAIL_STACK_ERROR \ + { \ + H5_FAILED(); \ + if (MAINPROCESS) { \ + AT(); \ + H5Eprint2(H5E_DEFAULT, stdout); \ + } \ + goto error; \ + } +#define FAIL_PUTS_ERROR(s) \ + { \ + H5_FAILED(); \ + if (MAINPROCESS) { \ + AT(); \ + puts(s); \ + } \ + goto error; \ + } +#define TESTING_MULTIPART(WHAT) \ + { \ + if (MAINPROCESS) { \ + printf("Testing %-62s", WHAT); \ + HDputs(""); \ + fflush(stdout); \ + } \ + } + +/* + * Macros to surround an action that will be performed non-collectively. Once the + * operation has completed, a consensus will be formed by all ranks on whether the + * operation failed. + */ +#define BEGIN_INDEPENDENT_OP(op_name) \ + { \ + hbool_t ind_op_failed = FALSE; \ + \ + { + +#define END_INDEPENDENT_OP(op_name) \ + } \ + \ + op_##op_name##_end : if (MPI_SUCCESS != MPI_Allreduce(MPI_IN_PLACE, &ind_op_failed, 1, MPI_C_BOOL, \ + MPI_LOR, MPI_COMM_WORLD)) \ + { \ + if (MAINPROCESS) \ + HDprintf( \ + " failed to collect consensus about whether non-collective operation was successful\n"); \ + goto error; \ + } \ + \ + if (ind_op_failed) { \ + if (MAINPROCESS) \ + HDprintf(" failure detected during non-collective operation - all other ranks will now fail " \ + "too\n"); \ + goto error; \ + } \ + } + +#define INDEPENDENT_OP_ERROR(op_name) \ + ind_op_failed = TRUE; \ + goto op_##op_name##_end; + +hid_t create_mpi_fapl(MPI_Comm comm, MPI_Info info, hbool_t coll_md_read); +int generate_random_parallel_dimensions(int space_rank, hsize_t **dims_out); + +extern int mpi_size; +extern int mpi_rank; + +#endif diff --git a/testpar/API/t_bigio.c b/testpar/API/t_bigio.c new file mode 100644 index 0000000..3e18c8f --- /dev/null +++ b/testpar/API/t_bigio.c @@ -0,0 +1,1942 @@ + +#include "hdf5.h" +#include "testphdf5.h" + +#if 0 +#include "H5Dprivate.h" /* For Chunk tests */ +#endif + +/* FILENAME and filenames must have the same number of names */ +const char *FILENAME[3] = {"bigio_test.h5", "single_rank_independent_io.h5", NULL}; + +/* Constants definitions */ +#define MAX_ERR_REPORT 10 /* Maximum number of errors reported */ + +/* Define some handy debugging shorthands, routines, ... */ +/* debugging tools */ + +#define MAIN_PROCESS (mpi_rank_g == 0) /* define process 0 as main process */ + +/* Constants definitions */ +#define RANK 2 + +#define IN_ORDER 1 +#define OUT_OF_ORDER 2 + +#define DATASET1 "DSET1" +#define DATASET2 "DSET2" +#define DATASET3 "DSET3" +#define DATASET4 "DSET4" +#define DXFER_COLLECTIVE_IO 0x1 /* Collective IO*/ +#define DXFER_INDEPENDENT_IO 0x2 /* Independent IO collectively */ +#define DXFER_BIGCOUNT (1 << 29) + +#define HYPER 1 +#define POINT 2 +#define ALL 3 + +/* Dataset data type. Int's can be easily octo dumped. */ +typedef hsize_t B_DATATYPE; + +int facc_type = FACC_MPIO; /*Test file access type */ +int dxfer_coll_type = DXFER_COLLECTIVE_IO; +size_t bigcount = (size_t) /* DXFER_BIGCOUNT */ 1310720; +int nerrors = 0; +static int mpi_size_g, mpi_rank_g; + +hsize_t space_dim1 = SPACE_DIM1 * 256; // 4096 +hsize_t space_dim2 = SPACE_DIM2; + +static void coll_chunktest(const char *filename, int chunk_factor, int select_factor, int api_option, + int file_selection, int mem_selection, int mode); + +/* + * Setup the coordinates for point selection. + */ +static void +set_coords(hsize_t start[], hsize_t count[], hsize_t stride[], hsize_t block[], size_t num_points, + hsize_t coords[], int order) +{ + hsize_t i, j, k = 0, m, n, s1, s2; + + if (OUT_OF_ORDER == order) + k = (num_points * RANK) - 1; + else if (IN_ORDER == order) + k = 0; + + s1 = start[0]; + s2 = start[1]; + + for (i = 0; i < count[0]; i++) + for (j = 0; j < count[1]; j++) + for (m = 0; m < block[0]; m++) + for (n = 0; n < block[1]; n++) + if (OUT_OF_ORDER == order) { + coords[k--] = s2 + (stride[1] * j) + n; + coords[k--] = s1 + (stride[0] * i) + m; + } + else if (IN_ORDER == order) { + coords[k++] = s1 + stride[0] * i + m; + coords[k++] = s2 + stride[1] * j + n; + } +} + +/* + * Fill the dataset with trivial data for testing. + * Assume dimension rank is 2 and data is stored contiguous. + */ +static void +fill_datasets(hsize_t start[], hsize_t block[], B_DATATYPE *dataset) +{ + B_DATATYPE *dataptr = dataset; + hsize_t i, j; + + /* put some trivial data in the data_array */ + for (i = 0; i < block[0]; i++) { + for (j = 0; j < block[1]; j++) { + *dataptr = (B_DATATYPE)((i + start[0]) * 100 + (j + start[1] + 1)); + dataptr++; + } + } +} + +/* + * Setup the coordinates for point selection. + */ +void +point_set(hsize_t start[], hsize_t count[], hsize_t stride[], hsize_t block[], size_t num_points, + hsize_t coords[], int order) +{ + hsize_t i, j, k = 0, m, n, s1, s2; + + HDcompile_assert(RANK == 2); + + if (OUT_OF_ORDER == order) + k = (num_points * RANK) - 1; + else if (IN_ORDER == order) + k = 0; + + s1 = start[0]; + s2 = start[1]; + + for (i = 0; i < count[0]; i++) + for (j = 0; j < count[1]; j++) + for (m = 0; m < block[0]; m++) + for (n = 0; n < block[1]; n++) + if (OUT_OF_ORDER == order) { + coords[k--] = s2 + (stride[1] * j) + n; + coords[k--] = s1 + (stride[0] * i) + m; + } + else if (IN_ORDER == order) { + coords[k++] = s1 + stride[0] * i + m; + coords[k++] = s2 + stride[1] * j + n; + } + + if (VERBOSE_MED) { + HDprintf("start[]=(%" PRIuHSIZE ", %" PRIuHSIZE "), " + "count[]=(%" PRIuHSIZE ", %" PRIuHSIZE "), " + "stride[]=(%" PRIuHSIZE ", %" PRIuHSIZE "), " + "block[]=(%" PRIuHSIZE ", %" PRIuHSIZE "), " + "total datapoints=%" PRIuHSIZE "\n", + start[0], start[1], count[0], count[1], stride[0], stride[1], block[0], block[1], + block[0] * block[1] * count[0] * count[1]); + k = 0; + for (i = 0; i < num_points; i++) { + HDprintf("(%d, %d)\n", (int)coords[k], (int)coords[k + 1]); + k += 2; + } + } +} + +/* + * Print the content of the dataset. + */ +static void +dataset_print(hsize_t start[], hsize_t block[], B_DATATYPE *dataset) +{ + B_DATATYPE *dataptr = dataset; + hsize_t i, j; + + /* print the column heading */ + HDprintf("%-8s", "Cols:"); + for (j = 0; j < block[1]; j++) { + HDprintf("%3" PRIuHSIZE " ", start[1] + j); + } + HDprintf("\n"); + + /* print the slab data */ + for (i = 0; i < block[0]; i++) { + HDprintf("Row %2" PRIuHSIZE ": ", i + start[0]); + for (j = 0; j < block[1]; j++) { + HDprintf("%" PRIuHSIZE " ", *dataptr++); + } + HDprintf("\n"); + } +} + +/* + * Print the content of the dataset. + */ +static int +verify_data(hsize_t start[], hsize_t count[], hsize_t stride[], hsize_t block[], B_DATATYPE *dataset, + B_DATATYPE *original) +{ + hsize_t i, j; + int vrfyerrs; + + /* print it if VERBOSE_MED */ + if (VERBOSE_MED) { + HDprintf("verify_data dumping:::\n"); + HDprintf("start(%" PRIuHSIZE ", %" PRIuHSIZE "), " + "count(%" PRIuHSIZE ", %" PRIuHSIZE "), " + "stride(%" PRIuHSIZE ", %" PRIuHSIZE "), " + "block(%" PRIuHSIZE ", %" PRIuHSIZE ")\n", + start[0], start[1], count[0], count[1], stride[0], stride[1], block[0], block[1]); + HDprintf("original values:\n"); + dataset_print(start, block, original); + HDprintf("compared values:\n"); + dataset_print(start, block, dataset); + } + + vrfyerrs = 0; + for (i = 0; i < block[0]; i++) { + for (j = 0; j < block[1]; j++) { + if (*dataset != *original) { + if (vrfyerrs++ < MAX_ERR_REPORT || VERBOSE_MED) { + HDprintf("Dataset Verify failed at [%" PRIuHSIZE "][%" PRIuHSIZE "]" + "(row %" PRIuHSIZE ", col %" PRIuHSIZE "): " + "expect %" PRIuHSIZE ", got %" PRIuHSIZE "\n", + i, j, i + start[0], j + start[1], *(original), *(dataset)); + } + dataset++; + original++; + } + } + } + if (vrfyerrs > MAX_ERR_REPORT && !VERBOSE_MED) + HDprintf("[more errors ...]\n"); + if (vrfyerrs) + HDprintf("%d errors found in verify_data\n", vrfyerrs); + return (vrfyerrs); +} + +/* Set up the selection */ +static void +ccslab_set(int mpi_rank, int mpi_size, hsize_t start[], hsize_t count[], hsize_t stride[], hsize_t block[], + int mode) +{ + + switch (mode) { + + case BYROW_CONT: + /* Each process takes a slabs of rows. */ + block[0] = 1; + block[1] = 1; + stride[0] = 1; + stride[1] = 1; + count[0] = space_dim1; + count[1] = space_dim2; + start[0] = (hsize_t)mpi_rank * count[0]; + start[1] = 0; + + break; + + case BYROW_DISCONT: + /* Each process takes several disjoint blocks. */ + block[0] = 1; + block[1] = 1; + stride[0] = 3; + stride[1] = 3; + count[0] = space_dim1 / (stride[0] * block[0]); + count[1] = (space_dim2) / (stride[1] * block[1]); + start[0] = space_dim1 * (hsize_t)mpi_rank; + start[1] = 0; + + break; + + case BYROW_SELECTNONE: + /* Each process takes a slabs of rows, there are + no selections for the last process. */ + block[0] = 1; + block[1] = 1; + stride[0] = 1; + stride[1] = 1; + count[0] = ((mpi_rank >= MAX(1, (mpi_size - 2))) ? 0 : space_dim1); + count[1] = space_dim2; + start[0] = (hsize_t)mpi_rank * count[0]; + start[1] = 0; + + break; + + case BYROW_SELECTUNBALANCE: + /* The first one-third of the number of processes only + select top half of the domain, The rest will select the bottom + half of the domain. */ + + block[0] = 1; + count[0] = 2; + stride[0] = (hsize_t)(space_dim1 * (hsize_t)mpi_size / 4 + 1); + block[1] = space_dim2; + count[1] = 1; + start[1] = 0; + stride[1] = 1; + if ((mpi_rank * 3) < (mpi_size * 2)) + start[0] = (hsize_t)mpi_rank; + else + start[0] = 1 + space_dim1 * (hsize_t)mpi_size / 2 + (hsize_t)(mpi_rank - 2 * mpi_size / 3); + break; + + case BYROW_SELECTINCHUNK: + /* Each process will only select one chunk */ + + block[0] = 1; + count[0] = 1; + start[0] = (hsize_t)mpi_rank * space_dim1; + stride[0] = 1; + block[1] = space_dim2; + count[1] = 1; + stride[1] = 1; + start[1] = 0; + + break; + + default: + /* Unknown mode. Set it to cover the whole dataset. */ + block[0] = space_dim1 * (hsize_t)mpi_size; + block[1] = space_dim2; + stride[0] = block[0]; + stride[1] = block[1]; + count[0] = 1; + count[1] = 1; + start[0] = 0; + start[1] = 0; + + break; + } + if (VERBOSE_MED) { + HDprintf("start[]=(%lu,%lu), count[]=(%lu,%lu), stride[]=(%lu,%lu), block[]=(%lu,%lu), total " + "datapoints=%lu\n", + (unsigned long)start[0], (unsigned long)start[1], (unsigned long)count[0], + (unsigned long)count[1], (unsigned long)stride[0], (unsigned long)stride[1], + (unsigned long)block[0], (unsigned long)block[1], + (unsigned long)(block[0] * block[1] * count[0] * count[1])); + } +} + +/* + * Fill the dataset with trivial data for testing. + * Assume dimension rank is 2. + */ +static void +ccdataset_fill(hsize_t start[], hsize_t stride[], hsize_t count[], hsize_t block[], DATATYPE *dataset, + int mem_selection) +{ + DATATYPE *dataptr = dataset; + DATATYPE *tmptr; + hsize_t i, j, k1, k2, k = 0; + /* put some trivial data in the data_array */ + tmptr = dataptr; + + /* assign the disjoint block (two-dimensional)data array value + through the pointer */ + + for (k1 = 0; k1 < count[0]; k1++) { + for (i = 0; i < block[0]; i++) { + for (k2 = 0; k2 < count[1]; k2++) { + for (j = 0; j < block[1]; j++) { + + if (ALL != mem_selection) { + dataptr = tmptr + ((start[0] + k1 * stride[0] + i) * space_dim2 + start[1] + + k2 * stride[1] + j); + } + else { + dataptr = tmptr + k; + k++; + } + + *dataptr = (DATATYPE)(k1 + k2 + i + j); + } + } + } + } +} + +/* + * Print the first block of the content of the dataset. + */ +static void +ccdataset_print(hsize_t start[], hsize_t block[], DATATYPE *dataset) + +{ + DATATYPE *dataptr = dataset; + hsize_t i, j; + + /* print the column heading */ + HDprintf("Print only the first block of the dataset\n"); + HDprintf("%-8s", "Cols:"); + for (j = 0; j < block[1]; j++) { + HDprintf("%3lu ", (unsigned long)(start[1] + j)); + } + HDprintf("\n"); + + /* print the slab data */ + for (i = 0; i < block[0]; i++) { + HDprintf("Row %2lu: ", (unsigned long)(i + start[0])); + for (j = 0; j < block[1]; j++) { + HDprintf("%03d ", *dataptr++); + } + HDprintf("\n"); + } +} + +/* + * Print the content of the dataset. + */ +static int +ccdataset_vrfy(hsize_t start[], hsize_t count[], hsize_t stride[], hsize_t block[], DATATYPE *dataset, + DATATYPE *original, int mem_selection) +{ + hsize_t i, j, k1, k2, k = 0; + int vrfyerrs; + DATATYPE *dataptr, *oriptr; + + /* print it if VERBOSE_MED */ + if (VERBOSE_MED) { + HDprintf("dataset_vrfy dumping:::\n"); + HDprintf("start(%lu, %lu), count(%lu, %lu), stride(%lu, %lu), block(%lu, %lu)\n", + (unsigned long)start[0], (unsigned long)start[1], (unsigned long)count[0], + (unsigned long)count[1], (unsigned long)stride[0], (unsigned long)stride[1], + (unsigned long)block[0], (unsigned long)block[1]); + HDprintf("original values:\n"); + ccdataset_print(start, block, original); + HDprintf("compared values:\n"); + ccdataset_print(start, block, dataset); + } + + vrfyerrs = 0; + + for (k1 = 0; k1 < count[0]; k1++) { + for (i = 0; i < block[0]; i++) { + for (k2 = 0; k2 < count[1]; k2++) { + for (j = 0; j < block[1]; j++) { + if (ALL != mem_selection) { + dataptr = dataset + ((start[0] + k1 * stride[0] + i) * space_dim2 + start[1] + + k2 * stride[1] + j); + oriptr = original + ((start[0] + k1 * stride[0] + i) * space_dim2 + start[1] + + k2 * stride[1] + j); + } + else { + dataptr = dataset + k; + oriptr = original + k; + k++; + } + if (*dataptr != *oriptr) { + if (vrfyerrs++ < MAX_ERR_REPORT || VERBOSE_MED) { + HDprintf("Dataset Verify failed at [%lu][%lu]: expect %d, got %d\n", + (unsigned long)i, (unsigned long)j, *(oriptr), *(dataptr)); + } + } + } + } + } + } + if (vrfyerrs > MAX_ERR_REPORT && !VERBOSE_MED) + HDprintf("[more errors ...]\n"); + if (vrfyerrs) + HDprintf("%d errors found in ccdataset_vrfy\n", vrfyerrs); + return (vrfyerrs); +} + +/* + * Example of using the parallel HDF5 library to create two datasets + * in one HDF5 file with collective parallel access support. + * The Datasets are of sizes (number-of-mpi-processes x dim0) x dim1. + * Each process controls only a slab of size dim0 x dim1 within each + * dataset. [Note: not so yet. Datasets are of sizes dim0xdim1 and + * each process controls a hyperslab within.] + */ + +static void +dataset_big_write(void) +{ + + hid_t xfer_plist; /* Dataset transfer properties list */ + hid_t sid; /* Dataspace ID */ + hid_t file_dataspace; /* File dataspace ID */ + hid_t mem_dataspace; /* memory dataspace ID */ + hid_t dataset; + hsize_t dims[RANK]; /* dataset dim sizes */ + hsize_t start[RANK]; /* for hyperslab setting */ + hsize_t count[RANK], stride[RANK]; /* for hyperslab setting */ + hsize_t block[RANK]; /* for hyperslab setting */ + hsize_t *coords = NULL; + herr_t ret; /* Generic return value */ + hid_t fid; /* HDF5 file ID */ + hid_t acc_tpl; /* File access templates */ + size_t num_points; + B_DATATYPE *wdata; + + /* allocate memory for data buffer */ + wdata = (B_DATATYPE *)HDmalloc(bigcount * sizeof(B_DATATYPE)); + VRFY_G((wdata != NULL), "wdata malloc succeeded"); + + /* setup file access template */ + acc_tpl = H5Pcreate(H5P_FILE_ACCESS); + VRFY_G((acc_tpl >= 0), "H5P_FILE_ACCESS"); + H5Pset_fapl_mpio(acc_tpl, MPI_COMM_WORLD, MPI_INFO_NULL); + + /* create the file collectively */ + fid = H5Fcreate(FILENAME[0], H5F_ACC_TRUNC, H5P_DEFAULT, acc_tpl); + VRFY_G((fid >= 0), "H5Fcreate succeeded"); + + /* Release file-access template */ + ret = H5Pclose(acc_tpl); + VRFY_G((ret >= 0), ""); + + /* Each process takes a slabs of rows. */ + if (mpi_rank_g == 0) + HDprintf("\nTesting Dataset1 write by ROW\n"); + /* Create a large dataset */ + dims[0] = bigcount; + dims[1] = (hsize_t)mpi_size_g; + + sid = H5Screate_simple(RANK, dims, NULL); + VRFY_G((sid >= 0), "H5Screate_simple succeeded"); + dataset = H5Dcreate2(fid, DATASET1, H5T_NATIVE_LLONG, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY_G((dataset >= 0), "H5Dcreate2 succeeded"); + H5Sclose(sid); + + block[0] = dims[0] / (hsize_t)mpi_size_g; + block[1] = dims[1]; + stride[0] = block[0]; + stride[1] = block[1]; + count[0] = 1; + count[1] = 1; + start[0] = (hsize_t)mpi_rank_g * block[0]; + start[1] = 0; + + /* create a file dataspace independently */ + file_dataspace = H5Dget_space(dataset); + VRFY_G((file_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY_G((ret >= 0), "H5Sset_hyperslab succeeded"); + + /* create a memory dataspace independently */ + mem_dataspace = H5Screate_simple(RANK, block, NULL); + VRFY_G((mem_dataspace >= 0), ""); + + /* fill the local slab with some trivial data */ + fill_datasets(start, block, wdata); + MESG("data_array initialized"); + if (VERBOSE_MED) { + MESG("data_array created"); + dataset_print(start, block, wdata); + } + + /* set up the collective transfer properties list */ + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY_G((xfer_plist >= 0), "H5Pcreate xfer succeeded"); + ret = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY_G((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(xfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY_G((ret >= 0), "set independent IO collectively succeeded"); + } + + ret = H5Dwrite(dataset, H5T_NATIVE_LLONG, mem_dataspace, file_dataspace, xfer_plist, wdata); + VRFY_G((ret >= 0), "H5Dwrite dataset1 succeeded"); + + /* release all temporary handles. */ + H5Sclose(file_dataspace); + H5Sclose(mem_dataspace); + H5Pclose(xfer_plist); + + ret = H5Dclose(dataset); + VRFY_G((ret >= 0), "H5Dclose1 succeeded"); + + /* Each process takes a slabs of cols. */ + if (mpi_rank_g == 0) + HDprintf("\nTesting Dataset2 write by COL\n"); + /* Create a large dataset */ + dims[0] = bigcount; + dims[1] = (hsize_t)mpi_size_g; + + sid = H5Screate_simple(RANK, dims, NULL); + VRFY_G((sid >= 0), "H5Screate_simple succeeded"); + dataset = H5Dcreate2(fid, DATASET2, H5T_NATIVE_LLONG, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY_G((dataset >= 0), "H5Dcreate2 succeeded"); + H5Sclose(sid); + + block[0] = dims[0]; + block[1] = dims[1] / (hsize_t)mpi_size_g; + stride[0] = block[0]; + stride[1] = block[1]; + count[0] = 1; + count[1] = 1; + start[0] = 0; + start[1] = (hsize_t)mpi_rank_g * block[1]; + + /* create a file dataspace independently */ + file_dataspace = H5Dget_space(dataset); + VRFY_G((file_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY_G((ret >= 0), "H5Sset_hyperslab succeeded"); + + /* create a memory dataspace independently */ + mem_dataspace = H5Screate_simple(RANK, block, NULL); + VRFY_G((mem_dataspace >= 0), ""); + + /* fill the local slab with some trivial data */ + fill_datasets(start, block, wdata); + MESG("data_array initialized"); + if (VERBOSE_MED) { + MESG("data_array created"); + dataset_print(start, block, wdata); + } + + /* set up the collective transfer properties list */ + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY_G((xfer_plist >= 0), "H5Pcreate xfer succeeded"); + ret = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY_G((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(xfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY_G((ret >= 0), "set independent IO collectively succeeded"); + } + + ret = H5Dwrite(dataset, H5T_NATIVE_LLONG, mem_dataspace, file_dataspace, xfer_plist, wdata); + VRFY_G((ret >= 0), "H5Dwrite dataset1 succeeded"); + + /* release all temporary handles. */ + H5Sclose(file_dataspace); + H5Sclose(mem_dataspace); + H5Pclose(xfer_plist); + + ret = H5Dclose(dataset); + VRFY_G((ret >= 0), "H5Dclose1 succeeded"); + + /* ALL selection */ + if (mpi_rank_g == 0) + HDprintf("\nTesting Dataset3 write select ALL proc 0, NONE others\n"); + /* Create a large dataset */ + dims[0] = bigcount; + dims[1] = 1; + + sid = H5Screate_simple(RANK, dims, NULL); + VRFY_G((sid >= 0), "H5Screate_simple succeeded"); + dataset = H5Dcreate2(fid, DATASET3, H5T_NATIVE_LLONG, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY_G((dataset >= 0), "H5Dcreate2 succeeded"); + H5Sclose(sid); + + /* create a file dataspace independently */ + file_dataspace = H5Dget_space(dataset); + VRFY_G((file_dataspace >= 0), "H5Dget_space succeeded"); + if (mpi_rank_g == 0) { + ret = H5Sselect_all(file_dataspace); + VRFY_G((ret >= 0), "H5Sset_all succeeded"); + } + else { + ret = H5Sselect_none(file_dataspace); + VRFY_G((ret >= 0), "H5Sset_none succeeded"); + } + + /* create a memory dataspace independently */ + mem_dataspace = H5Screate_simple(RANK, dims, NULL); + VRFY_G((mem_dataspace >= 0), ""); + if (mpi_rank_g != 0) { + ret = H5Sselect_none(mem_dataspace); + VRFY_G((ret >= 0), "H5Sset_none succeeded"); + } + + /* set up the collective transfer properties list */ + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY_G((xfer_plist >= 0), "H5Pcreate xfer succeeded"); + ret = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY_G((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(xfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY_G((ret >= 0), "set independent IO collectively succeeded"); + } + + /* fill the local slab with some trivial data */ + fill_datasets(start, dims, wdata); + MESG("data_array initialized"); + if (VERBOSE_MED) { + MESG("data_array created"); + } + + ret = H5Dwrite(dataset, H5T_NATIVE_LLONG, mem_dataspace, file_dataspace, xfer_plist, wdata); + VRFY_G((ret >= 0), "H5Dwrite dataset1 succeeded"); + + /* release all temporary handles. */ + H5Sclose(file_dataspace); + H5Sclose(mem_dataspace); + H5Pclose(xfer_plist); + + ret = H5Dclose(dataset); + VRFY_G((ret >= 0), "H5Dclose1 succeeded"); + + /* Point selection */ + if (mpi_rank_g == 0) + HDprintf("\nTesting Dataset4 write point selection\n"); + /* Create a large dataset */ + dims[0] = bigcount; + dims[1] = (hsize_t)(mpi_size_g * 4); + + sid = H5Screate_simple(RANK, dims, NULL); + VRFY_G((sid >= 0), "H5Screate_simple succeeded"); + dataset = H5Dcreate2(fid, DATASET4, H5T_NATIVE_LLONG, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY_G((dataset >= 0), "H5Dcreate2 succeeded"); + H5Sclose(sid); + + block[0] = dims[0] / 2; + block[1] = 2; + stride[0] = dims[0] / 2; + stride[1] = 2; + count[0] = 1; + count[1] = 1; + start[0] = 0; + start[1] = dims[1] / (hsize_t)mpi_size_g * (hsize_t)mpi_rank_g; + + num_points = bigcount; + + coords = (hsize_t *)HDmalloc(num_points * RANK * sizeof(hsize_t)); + VRFY_G((coords != NULL), "coords malloc succeeded"); + + set_coords(start, count, stride, block, num_points, coords, IN_ORDER); + /* create a file dataspace */ + file_dataspace = H5Dget_space(dataset); + VRFY_G((file_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sselect_elements(file_dataspace, H5S_SELECT_SET, num_points, coords); + VRFY_G((ret >= 0), "H5Sselect_elements succeeded"); + + if (coords) + free(coords); + + fill_datasets(start, block, wdata); + MESG("data_array initialized"); + if (VERBOSE_MED) { + MESG("data_array created"); + dataset_print(start, block, wdata); + } + + /* create a memory dataspace */ + /* Warning: H5Screate_simple requires an array of hsize_t elements + * even if we only pass only a single value. Attempting anything else + * appears to cause problems with 32 bit compilers. + */ + mem_dataspace = H5Screate_simple(1, dims, NULL); + VRFY_G((mem_dataspace >= 0), ""); + + /* set up the collective transfer properties list */ + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY_G((xfer_plist >= 0), "H5Pcreate xfer succeeded"); + ret = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY_G((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(xfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY_G((ret >= 0), "set independent IO collectively succeeded"); + } + + ret = H5Dwrite(dataset, H5T_NATIVE_LLONG, mem_dataspace, file_dataspace, xfer_plist, wdata); + VRFY_G((ret >= 0), "H5Dwrite dataset1 succeeded"); + + /* release all temporary handles. */ + H5Sclose(file_dataspace); + H5Sclose(mem_dataspace); + H5Pclose(xfer_plist); + + ret = H5Dclose(dataset); + VRFY_G((ret >= 0), "H5Dclose1 succeeded"); + + HDfree(wdata); + H5Fclose(fid); +} + +/* + * Example of using the parallel HDF5 library to read two datasets + * in one HDF5 file with collective parallel access support. + * The Datasets are of sizes (number-of-mpi-processes x dim0) x dim1. + * Each process controls only a slab of size dim0 x dim1 within each + * dataset. [Note: not so yet. Datasets are of sizes dim0xdim1 and + * each process controls a hyperslab within.] + */ + +static void +dataset_big_read(void) +{ + hid_t fid; /* HDF5 file ID */ + hid_t acc_tpl; /* File access templates */ + hid_t xfer_plist; /* Dataset transfer properties list */ + hid_t file_dataspace; /* File dataspace ID */ + hid_t mem_dataspace; /* memory dataspace ID */ + hid_t dataset; + B_DATATYPE *rdata = NULL; /* data buffer */ + B_DATATYPE *wdata = NULL; /* expected data buffer */ + hsize_t dims[RANK]; /* dataset dim sizes */ + hsize_t start[RANK]; /* for hyperslab setting */ + hsize_t count[RANK], stride[RANK]; /* for hyperslab setting */ + hsize_t block[RANK]; /* for hyperslab setting */ + size_t num_points; + hsize_t *coords = NULL; + herr_t ret; /* Generic return value */ + + /* allocate memory for data buffer */ + rdata = (B_DATATYPE *)HDmalloc(bigcount * sizeof(B_DATATYPE)); + VRFY_G((rdata != NULL), "rdata malloc succeeded"); + wdata = (B_DATATYPE *)HDmalloc(bigcount * sizeof(B_DATATYPE)); + VRFY_G((wdata != NULL), "wdata malloc succeeded"); + + HDmemset(rdata, 0, bigcount * sizeof(B_DATATYPE)); + + /* setup file access template */ + acc_tpl = H5Pcreate(H5P_FILE_ACCESS); + VRFY_G((acc_tpl >= 0), "H5P_FILE_ACCESS"); + H5Pset_fapl_mpio(acc_tpl, MPI_COMM_WORLD, MPI_INFO_NULL); + + /* open the file collectively */ + fid = H5Fopen(FILENAME[0], H5F_ACC_RDONLY, acc_tpl); + VRFY_G((fid >= 0), "H5Fopen succeeded"); + + /* Release file-access template */ + ret = H5Pclose(acc_tpl); + VRFY_G((ret >= 0), ""); + + if (mpi_rank_g == 0) + HDprintf("\nRead Testing Dataset1 by COL\n"); + + dataset = H5Dopen2(fid, DATASET1, H5P_DEFAULT); + VRFY_G((dataset >= 0), "H5Dopen2 succeeded"); + + dims[0] = bigcount; + dims[1] = (hsize_t)mpi_size_g; + /* Each process takes a slabs of cols. */ + block[0] = dims[0]; + block[1] = dims[1] / (hsize_t)mpi_size_g; + stride[0] = block[0]; + stride[1] = block[1]; + count[0] = 1; + count[1] = 1; + start[0] = 0; + start[1] = (hsize_t)mpi_rank_g * block[1]; + + /* create a file dataspace independently */ + file_dataspace = H5Dget_space(dataset); + VRFY_G((file_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY_G((ret >= 0), "H5Sset_hyperslab succeeded"); + + /* create a memory dataspace independently */ + mem_dataspace = H5Screate_simple(RANK, block, NULL); + VRFY_G((mem_dataspace >= 0), ""); + + /* fill dataset with test data */ + fill_datasets(start, block, wdata); + MESG("data_array initialized"); + if (VERBOSE_MED) { + MESG("data_array created"); + } + + /* set up the collective transfer properties list */ + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY_G((xfer_plist >= 0), ""); + ret = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY_G((ret >= 0), "H5Pcreate xfer succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(xfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY_G((ret >= 0), "set independent IO collectively succeeded"); + } + + /* read data collectively */ + ret = H5Dread(dataset, H5T_NATIVE_LLONG, mem_dataspace, file_dataspace, xfer_plist, rdata); + VRFY_G((ret >= 0), "H5Dread dataset1 succeeded"); + + /* verify the read data with original expected data */ + ret = verify_data(start, count, stride, block, rdata, wdata); + if (ret) { + HDfprintf(stderr, "verify failed\n"); + exit(1); + } + + /* release all temporary handles. */ + H5Sclose(file_dataspace); + H5Sclose(mem_dataspace); + H5Pclose(xfer_plist); + ret = H5Dclose(dataset); + VRFY_G((ret >= 0), "H5Dclose1 succeeded"); + + if (mpi_rank_g == 0) + HDprintf("\nRead Testing Dataset2 by ROW\n"); + HDmemset(rdata, 0, bigcount * sizeof(B_DATATYPE)); + dataset = H5Dopen2(fid, DATASET2, H5P_DEFAULT); + VRFY_G((dataset >= 0), "H5Dopen2 succeeded"); + + dims[0] = bigcount; + dims[1] = (hsize_t)mpi_size_g; + /* Each process takes a slabs of rows. */ + block[0] = dims[0] / (hsize_t)mpi_size_g; + block[1] = dims[1]; + stride[0] = block[0]; + stride[1] = block[1]; + count[0] = 1; + count[1] = 1; + start[0] = (hsize_t)mpi_rank_g * block[0]; + start[1] = 0; + + /* create a file dataspace independently */ + file_dataspace = H5Dget_space(dataset); + VRFY_G((file_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY_G((ret >= 0), "H5Sset_hyperslab succeeded"); + + /* create a memory dataspace independently */ + mem_dataspace = H5Screate_simple(RANK, block, NULL); + VRFY_G((mem_dataspace >= 0), ""); + + /* fill dataset with test data */ + fill_datasets(start, block, wdata); + MESG("data_array initialized"); + if (VERBOSE_MED) { + MESG("data_array created"); + } + + /* set up the collective transfer properties list */ + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY_G((xfer_plist >= 0), ""); + ret = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY_G((ret >= 0), "H5Pcreate xfer succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(xfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY_G((ret >= 0), "set independent IO collectively succeeded"); + } + + /* read data collectively */ + ret = H5Dread(dataset, H5T_NATIVE_LLONG, mem_dataspace, file_dataspace, xfer_plist, rdata); + VRFY_G((ret >= 0), "H5Dread dataset2 succeeded"); + + /* verify the read data with original expected data */ + ret = verify_data(start, count, stride, block, rdata, wdata); + if (ret) { + HDfprintf(stderr, "verify failed\n"); + exit(1); + } + + /* release all temporary handles. */ + H5Sclose(file_dataspace); + H5Sclose(mem_dataspace); + H5Pclose(xfer_plist); + ret = H5Dclose(dataset); + VRFY_G((ret >= 0), "H5Dclose1 succeeded"); + + if (mpi_rank_g == 0) + HDprintf("\nRead Testing Dataset3 read select ALL proc 0, NONE others\n"); + HDmemset(rdata, 0, bigcount * sizeof(B_DATATYPE)); + dataset = H5Dopen2(fid, DATASET3, H5P_DEFAULT); + VRFY_G((dataset >= 0), "H5Dopen2 succeeded"); + + dims[0] = bigcount; + dims[1] = 1; + + /* create a file dataspace independently */ + file_dataspace = H5Dget_space(dataset); + VRFY_G((file_dataspace >= 0), "H5Dget_space succeeded"); + if (mpi_rank_g == 0) { + ret = H5Sselect_all(file_dataspace); + VRFY_G((ret >= 0), "H5Sset_all succeeded"); + } + else { + ret = H5Sselect_none(file_dataspace); + VRFY_G((ret >= 0), "H5Sset_none succeeded"); + } + + /* create a memory dataspace independently */ + mem_dataspace = H5Screate_simple(RANK, dims, NULL); + VRFY_G((mem_dataspace >= 0), ""); + if (mpi_rank_g != 0) { + ret = H5Sselect_none(mem_dataspace); + VRFY_G((ret >= 0), "H5Sset_none succeeded"); + } + + /* fill dataset with test data */ + fill_datasets(start, dims, wdata); + MESG("data_array initialized"); + if (VERBOSE_MED) { + MESG("data_array created"); + } + + /* set up the collective transfer properties list */ + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY_G((xfer_plist >= 0), ""); + ret = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY_G((ret >= 0), "H5Pcreate xfer succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(xfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY_G((ret >= 0), "set independent IO collectively succeeded"); + } + + /* read data collectively */ + ret = H5Dread(dataset, H5T_NATIVE_LLONG, mem_dataspace, file_dataspace, xfer_plist, rdata); + VRFY_G((ret >= 0), "H5Dread dataset3 succeeded"); + + if (mpi_rank_g == 0) { + /* verify the read data with original expected data */ + ret = verify_data(start, count, stride, block, rdata, wdata); + if (ret) { + HDfprintf(stderr, "verify failed\n"); + exit(1); + } + } + + /* release all temporary handles. */ + H5Sclose(file_dataspace); + H5Sclose(mem_dataspace); + H5Pclose(xfer_plist); + ret = H5Dclose(dataset); + VRFY_G((ret >= 0), "H5Dclose1 succeeded"); + + if (mpi_rank_g == 0) + HDprintf("\nRead Testing Dataset4 with Point selection\n"); + dataset = H5Dopen2(fid, DATASET4, H5P_DEFAULT); + VRFY_G((dataset >= 0), "H5Dopen2 succeeded"); + + dims[0] = bigcount; + dims[1] = (hsize_t)(mpi_size_g * 4); + + block[0] = dims[0] / 2; + block[1] = 2; + stride[0] = dims[0] / 2; + stride[1] = 2; + count[0] = 1; + count[1] = 1; + start[0] = 0; + start[1] = dims[1] / (hsize_t)mpi_size_g * (hsize_t)mpi_rank_g; + + fill_datasets(start, block, wdata); + MESG("data_array initialized"); + if (VERBOSE_MED) { + MESG("data_array created"); + dataset_print(start, block, wdata); + } + + num_points = bigcount; + + coords = (hsize_t *)HDmalloc(num_points * RANK * sizeof(hsize_t)); + VRFY_G((coords != NULL), "coords malloc succeeded"); + + set_coords(start, count, stride, block, num_points, coords, IN_ORDER); + /* create a file dataspace */ + file_dataspace = H5Dget_space(dataset); + VRFY_G((file_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sselect_elements(file_dataspace, H5S_SELECT_SET, num_points, coords); + VRFY_G((ret >= 0), "H5Sselect_elements succeeded"); + + if (coords) + HDfree(coords); + + /* create a memory dataspace */ + /* Warning: H5Screate_simple requires an array of hsize_t elements + * even if we only pass only a single value. Attempting anything else + * appears to cause problems with 32 bit compilers. + */ + mem_dataspace = H5Screate_simple(1, dims, NULL); + VRFY_G((mem_dataspace >= 0), ""); + + /* set up the collective transfer properties list */ + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY_G((xfer_plist >= 0), ""); + ret = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY_G((ret >= 0), "H5Pcreate xfer succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(xfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY_G((ret >= 0), "set independent IO collectively succeeded"); + } + + /* read data collectively */ + ret = H5Dread(dataset, H5T_NATIVE_LLONG, mem_dataspace, file_dataspace, xfer_plist, rdata); + VRFY_G((ret >= 0), "H5Dread dataset1 succeeded"); + + ret = verify_data(start, count, stride, block, rdata, wdata); + if (ret) { + HDfprintf(stderr, "verify failed\n"); + exit(1); + } + + /* release all temporary handles. */ + H5Sclose(file_dataspace); + H5Sclose(mem_dataspace); + H5Pclose(xfer_plist); + ret = H5Dclose(dataset); + VRFY_G((ret >= 0), "H5Dclose1 succeeded"); + + HDfree(wdata); + HDfree(rdata); + + wdata = NULL; + rdata = NULL; + /* We never wrote Dataset5 in the write section, so we can't + * expect to read it... + */ + file_dataspace = -1; + mem_dataspace = -1; + xfer_plist = -1; + dataset = -1; + + /* release all temporary handles. */ + if (file_dataspace != -1) + H5Sclose(file_dataspace); + if (mem_dataspace != -1) + H5Sclose(mem_dataspace); + if (xfer_plist != -1) + H5Pclose(xfer_plist); + if (dataset != -1) { + ret = H5Dclose(dataset); + VRFY_G((ret >= 0), "H5Dclose1 succeeded"); + } + H5Fclose(fid); + + /* release data buffers */ + if (rdata) + HDfree(rdata); + if (wdata) + HDfree(wdata); + +} /* dataset_large_readAll */ + +static void +single_rank_independent_io(void) +{ + if (mpi_rank_g == 0) + HDprintf("single_rank_independent_io\n"); + + if (MAIN_PROCESS) { + hsize_t dims[1]; + hid_t file_id = -1; + hid_t fapl_id = -1; + hid_t dset_id = -1; + hid_t fspace_id = -1; + herr_t ret; + int *data = NULL; + uint64_t i; + + fapl_id = H5Pcreate(H5P_FILE_ACCESS); + VRFY_G((fapl_id >= 0), "H5P_FILE_ACCESS"); + + H5Pset_fapl_mpio(fapl_id, MPI_COMM_SELF, MPI_INFO_NULL); + file_id = H5Fcreate(FILENAME[1], H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id); + VRFY_G((file_id >= 0), "H5Dcreate2 succeeded"); + + /* + * Calculate the number of elements needed to exceed + * MPI's INT_MAX limitation + */ + dims[0] = (INT_MAX / sizeof(int)) + 10; + + fspace_id = H5Screate_simple(1, dims, NULL); + VRFY_G((fspace_id >= 0), "H5Screate_simple fspace_id succeeded"); + + /* + * Create and write to a >2GB dataset from a single rank. + */ + dset_id = H5Dcreate2(file_id, "test_dset", H5T_NATIVE_INT, fspace_id, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT); + + VRFY_G((dset_id >= 0), "H5Dcreate2 succeeded"); + + data = malloc(dims[0] * sizeof(int)); + + /* Initialize data */ + for (i = 0; i < dims[0]; i++) + data[i] = (int)(i % (uint64_t)DXFER_BIGCOUNT); + + /* Write data */ + ret = H5Dwrite(dset_id, H5T_NATIVE_INT, H5S_BLOCK, fspace_id, H5P_DEFAULT, data); + VRFY_G((ret >= 0), "H5Dwrite succeeded"); + + /* Wipe buffer */ + HDmemset(data, 0, dims[0] * sizeof(int)); + + /* Read data back */ + ret = H5Dread(dset_id, H5T_NATIVE_INT, H5S_BLOCK, fspace_id, H5P_DEFAULT, data); + VRFY_G((ret >= 0), "H5Dread succeeded"); + + /* Verify data */ + for (i = 0; i < dims[0]; i++) + if (data[i] != (int)(i % (uint64_t)DXFER_BIGCOUNT)) { + HDfprintf(stderr, "verify failed\n"); + exit(1); + } + + free(data); + H5Sclose(fspace_id); + H5Dclose(dset_id); + H5Fclose(file_id); + + H5Fdelete(FILENAME[1], fapl_id); + + H5Pclose(fapl_id); + } + MPI_Barrier(MPI_COMM_WORLD); +} + +/* + * Create the appropriate File access property list + */ +hid_t +create_faccess_plist(MPI_Comm comm, MPI_Info info, int l_facc_type) +{ + hid_t ret_pl = -1; + herr_t ret; /* generic return value */ + int mpi_rank; /* mpi variables */ + + /* need the rank for error checking macros */ + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + ret_pl = H5Pcreate(H5P_FILE_ACCESS); + VRFY_G((ret_pl >= 0), "H5P_FILE_ACCESS"); + + if (l_facc_type == FACC_DEFAULT) + return (ret_pl); + + if (l_facc_type == FACC_MPIO) { + /* set Parallel access with communicator */ + ret = H5Pset_fapl_mpio(ret_pl, comm, info); + VRFY_G((ret >= 0), ""); + ret = H5Pset_all_coll_metadata_ops(ret_pl, TRUE); + VRFY_G((ret >= 0), ""); + ret = H5Pset_coll_metadata_write(ret_pl, TRUE); + VRFY_G((ret >= 0), ""); + return (ret_pl); + } + + if (l_facc_type == (FACC_MPIO | FACC_SPLIT)) { + hid_t mpio_pl; + + mpio_pl = H5Pcreate(H5P_FILE_ACCESS); + VRFY_G((mpio_pl >= 0), ""); + /* set Parallel access with communicator */ + ret = H5Pset_fapl_mpio(mpio_pl, comm, info); + VRFY_G((ret >= 0), ""); + + /* setup file access template */ + ret_pl = H5Pcreate(H5P_FILE_ACCESS); + VRFY_G((ret_pl >= 0), ""); + /* set Parallel access with communicator */ + ret = H5Pset_fapl_split(ret_pl, ".meta", mpio_pl, ".raw", mpio_pl); + VRFY_G((ret >= 0), "H5Pset_fapl_split succeeded"); + H5Pclose(mpio_pl); + return (ret_pl); + } + + /* unknown file access types */ + return (ret_pl); +} + +/*------------------------------------------------------------------------- + * Function: coll_chunk1 + * + * Purpose: Wrapper to test the collective chunk IO for regular JOINT + selection with a single chunk + * + * Return: Success: 0 + * + * Failure: -1 + * + * Programmer: Unknown + * July 12th, 2004 + * + *------------------------------------------------------------------------- + */ + +/* ------------------------------------------------------------------------ + * Descriptions for the selection: One big singular selection inside one chunk + * Two dimensions, + * + * dim1 = space_dim1(5760)*mpi_size + * dim2 = space_dim2(3) + * chunk_dim1 = dim1 + * chunk_dim2 = dim2 + * block = 1 for all dimensions + * stride = 1 for all dimensions + * count0 = space_dim1(5760) + * count1 = space_dim2(3) + * start0 = mpi_rank*space_dim1 + * start1 = 0 + * ------------------------------------------------------------------------ + */ + +void +coll_chunk1(void) +{ + const char *filename = FILENAME[0]; + if (mpi_rank_g == 0) + HDprintf("coll_chunk1\n"); + + coll_chunktest(filename, 1, BYROW_CONT, API_NONE, HYPER, HYPER, OUT_OF_ORDER); + coll_chunktest(filename, 1, BYROW_CONT, API_NONE, HYPER, POINT, OUT_OF_ORDER); + coll_chunktest(filename, 1, BYROW_CONT, API_NONE, POINT, ALL, OUT_OF_ORDER); + coll_chunktest(filename, 1, BYROW_CONT, API_NONE, POINT, POINT, OUT_OF_ORDER); + coll_chunktest(filename, 1, BYROW_CONT, API_NONE, POINT, HYPER, OUT_OF_ORDER); + + coll_chunktest(filename, 1, BYROW_CONT, API_NONE, POINT, ALL, IN_ORDER); + coll_chunktest(filename, 1, BYROW_CONT, API_NONE, POINT, POINT, IN_ORDER); + coll_chunktest(filename, 1, BYROW_CONT, API_NONE, POINT, HYPER, IN_ORDER); +} + +/*------------------------------------------------------------------------- + * Function: coll_chunk2 + * + * Purpose: Wrapper to test the collective chunk IO for regular DISJOINT + selection with a single chunk + * + * Return: Success: 0 + * + * Failure: -1 + * + * Programmer: Unknown + * July 12th, 2004 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ + +/* ------------------------------------------------------------------------ + * Descriptions for the selection: many disjoint selections inside one chunk + * Two dimensions, + * + * dim1 = space_dim1*mpi_size(5760) + * dim2 = space_dim2(3) + * chunk_dim1 = dim1 + * chunk_dim2 = dim2 + * block = 1 for all dimensions + * stride = 3 for all dimensions + * count0 = space_dim1/stride0(5760/3) + * count1 = space_dim2/stride(3/3 = 1) + * start0 = mpi_rank*space_dim1 + * start1 = 0 + * + * ------------------------------------------------------------------------ + */ +void +coll_chunk2(void) +{ + const char *filename = FILENAME[0]; + if (mpi_rank_g == 0) + HDprintf("coll_chunk2\n"); + + coll_chunktest(filename, 1, BYROW_DISCONT, API_NONE, HYPER, HYPER, OUT_OF_ORDER); + coll_chunktest(filename, 1, BYROW_DISCONT, API_NONE, HYPER, POINT, OUT_OF_ORDER); + coll_chunktest(filename, 1, BYROW_DISCONT, API_NONE, POINT, ALL, OUT_OF_ORDER); + coll_chunktest(filename, 1, BYROW_DISCONT, API_NONE, POINT, POINT, OUT_OF_ORDER); + coll_chunktest(filename, 1, BYROW_DISCONT, API_NONE, POINT, HYPER, OUT_OF_ORDER); + + coll_chunktest(filename, 1, BYROW_DISCONT, API_NONE, POINT, ALL, IN_ORDER); + coll_chunktest(filename, 1, BYROW_DISCONT, API_NONE, POINT, POINT, IN_ORDER); + coll_chunktest(filename, 1, BYROW_DISCONT, API_NONE, POINT, HYPER, IN_ORDER); +} + +/*------------------------------------------------------------------------- + * Function: coll_chunk3 + * + * Purpose: Wrapper to test the collective chunk IO for regular JOINT + selection with at least number of 2*mpi_size chunks + * + * Return: Success: 0 + * + * Failure: -1 + * + * Programmer: Unknown + * July 12th, 2004 + * + *------------------------------------------------------------------------- + */ + +/* ------------------------------------------------------------------------ + * Descriptions for the selection: one singular selection across many chunks + * Two dimensions, Num of chunks = 2* mpi_size + * + * dim1 = space_dim1*mpi_size + * dim2 = space_dim2(3) + * chunk_dim1 = space_dim1 + * chunk_dim2 = dim2/2 + * block = 1 for all dimensions + * stride = 1 for all dimensions + * count0 = space_dim1 + * count1 = space_dim2(3) + * start0 = mpi_rank*space_dim1 + * start1 = 0 + * + * ------------------------------------------------------------------------ + */ + +void +coll_chunk3(void) +{ + const char *filename = FILENAME[0]; + if (mpi_rank_g == 0) + HDprintf("coll_chunk3\n"); + + coll_chunktest(filename, mpi_size_g, BYROW_CONT, API_NONE, HYPER, HYPER, OUT_OF_ORDER); + coll_chunktest(filename, mpi_size_g, BYROW_CONT, API_NONE, HYPER, POINT, OUT_OF_ORDER); + coll_chunktest(filename, mpi_size_g, BYROW_CONT, API_NONE, POINT, ALL, OUT_OF_ORDER); + coll_chunktest(filename, mpi_size_g, BYROW_CONT, API_NONE, POINT, POINT, OUT_OF_ORDER); + coll_chunktest(filename, mpi_size_g, BYROW_CONT, API_NONE, POINT, HYPER, OUT_OF_ORDER); + + coll_chunktest(filename, mpi_size_g, BYROW_CONT, API_NONE, POINT, ALL, IN_ORDER); + coll_chunktest(filename, mpi_size_g, BYROW_CONT, API_NONE, POINT, POINT, IN_ORDER); + coll_chunktest(filename, mpi_size_g, BYROW_CONT, API_NONE, POINT, HYPER, IN_ORDER); +} + +//------------------------------------------------------------------------- +// Borrowed/Modified (slightly) from t_coll_chunk.c +/*------------------------------------------------------------------------- + * Function: coll_chunktest + * + * Purpose: The real testing routine for regular selection of collective + chunking storage + testing both write and read, + If anything fails, it may be read or write. There is no + separation test between read and write. + * + * Return: Success: 0 + * + * Failure: -1 + * + * Programmer: Unknown + * July 12th, 2004 + * + *------------------------------------------------------------------------- + */ + +static void +coll_chunktest(const char *filename, int chunk_factor, int select_factor, int api_option, int file_selection, + int mem_selection, int mode) +{ + hid_t file, dataset, file_dataspace, mem_dataspace; + hid_t acc_plist, xfer_plist, crp_plist; + + hsize_t dims[RANK], chunk_dims[RANK]; + int *data_array1 = NULL; + int *data_origin1 = NULL; + + hsize_t start[RANK], count[RANK], stride[RANK], block[RANK]; + +#ifdef H5_HAVE_INSTRUMENTED_LIBRARY + unsigned prop_value; +#endif /* H5_HAVE_INSTRUMENTED_LIBRARY */ + + herr_t status; + MPI_Comm comm = MPI_COMM_WORLD; + MPI_Info info = MPI_INFO_NULL; + + size_t num_points; /* for point selection */ + hsize_t *coords = NULL; /* for point selection */ + + /* Create the data space */ + + acc_plist = create_faccess_plist(comm, info, facc_type); + VRFY_G((acc_plist >= 0), ""); + + file = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, acc_plist); + VRFY_G((file >= 0), "H5Fcreate succeeded"); + + status = H5Pclose(acc_plist); + VRFY_G((status >= 0), ""); + + /* setup dimensionality object */ + dims[0] = space_dim1 * (hsize_t)mpi_size_g; + dims[1] = space_dim2; + + /* allocate memory for data buffer */ + data_array1 = (int *)HDmalloc(dims[0] * dims[1] * sizeof(int)); + VRFY_G((data_array1 != NULL), "data_array1 malloc succeeded"); + + /* set up dimensions of the slab this process accesses */ + ccslab_set(mpi_rank_g, mpi_size_g, start, count, stride, block, select_factor); + + /* set up the coords array selection */ + num_points = block[0] * block[1] * count[0] * count[1]; + coords = (hsize_t *)HDmalloc(num_points * RANK * sizeof(hsize_t)); + VRFY_G((coords != NULL), "coords malloc succeeded"); + point_set(start, count, stride, block, num_points, coords, mode); + + /* Warning: H5Screate_simple requires an array of hsize_t elements + * even if we only pass only a single value. Attempting anything else + * appears to cause problems with 32 bit compilers. + */ + file_dataspace = H5Screate_simple(2, dims, NULL); + VRFY_G((file_dataspace >= 0), "file dataspace created succeeded"); + + if (ALL != mem_selection) { + mem_dataspace = H5Screate_simple(2, dims, NULL); + VRFY_G((mem_dataspace >= 0), "mem dataspace created succeeded"); + } + else { + /* Putting the warning about H5Screate_simple (above) into practice... */ + hsize_t dsdims[1] = {num_points}; + mem_dataspace = H5Screate_simple(1, dsdims, NULL); + VRFY_G((mem_dataspace >= 0), "mem_dataspace create succeeded"); + } + + crp_plist = H5Pcreate(H5P_DATASET_CREATE); + VRFY_G((crp_plist >= 0), ""); + + /* Set up chunk information. */ + chunk_dims[0] = dims[0] / (hsize_t)chunk_factor; + + /* to decrease the testing time, maintain bigger chunk size */ + (chunk_factor == 1) ? (chunk_dims[1] = space_dim2) : (chunk_dims[1] = space_dim2 / 2); + status = H5Pset_chunk(crp_plist, 2, chunk_dims); + VRFY_G((status >= 0), "chunk creation property list succeeded"); + + dataset = H5Dcreate2(file, DSET_COLLECTIVE_CHUNK_NAME, H5T_NATIVE_INT, file_dataspace, H5P_DEFAULT, + crp_plist, H5P_DEFAULT); + VRFY_G((dataset >= 0), "dataset created succeeded"); + + status = H5Pclose(crp_plist); + VRFY_G((status >= 0), ""); + + /*put some trivial data in the data array */ + ccdataset_fill(start, stride, count, block, data_array1, mem_selection); + + MESG("data_array initialized"); + + switch (file_selection) { + case HYPER: + status = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY_G((status >= 0), "hyperslab selection succeeded"); + break; + + case POINT: + if (num_points) { + status = H5Sselect_elements(file_dataspace, H5S_SELECT_SET, num_points, coords); + VRFY_G((status >= 0), "Element selection succeeded"); + } + else { + status = H5Sselect_none(file_dataspace); + VRFY_G((status >= 0), "none selection succeeded"); + } + break; + + case ALL: + status = H5Sselect_all(file_dataspace); + VRFY_G((status >= 0), "H5Sselect_all succeeded"); + break; + } + + switch (mem_selection) { + case HYPER: + status = H5Sselect_hyperslab(mem_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY_G((status >= 0), "hyperslab selection succeeded"); + break; + + case POINT: + if (num_points) { + status = H5Sselect_elements(mem_dataspace, H5S_SELECT_SET, num_points, coords); + VRFY_G((status >= 0), "Element selection succeeded"); + } + else { + status = H5Sselect_none(mem_dataspace); + VRFY_G((status >= 0), "none selection succeeded"); + } + break; + + case ALL: + status = H5Sselect_all(mem_dataspace); + VRFY_G((status >= 0), "H5Sselect_all succeeded"); + break; + } + + /* set up the collective transfer property list */ + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY_G((xfer_plist >= 0), ""); + + status = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY_G((status >= 0), "MPIO collective transfer property succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + status = H5Pset_dxpl_mpio_collective_opt(xfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY_G((status >= 0), "set independent IO collectively succeeded"); + } + + switch (api_option) { + case API_LINK_HARD: + status = H5Pset_dxpl_mpio_chunk_opt(xfer_plist, H5FD_MPIO_CHUNK_ONE_IO); + VRFY_G((status >= 0), "collective chunk optimization succeeded"); + break; + + case API_MULTI_HARD: + status = H5Pset_dxpl_mpio_chunk_opt(xfer_plist, H5FD_MPIO_CHUNK_MULTI_IO); + VRFY_G((status >= 0), "collective chunk optimization succeeded "); + break; + + case API_LINK_TRUE: + status = H5Pset_dxpl_mpio_chunk_opt_num(xfer_plist, 2); + VRFY_G((status >= 0), "collective chunk optimization set chunk number succeeded"); + break; + + case API_LINK_FALSE: + status = H5Pset_dxpl_mpio_chunk_opt_num(xfer_plist, 6); + VRFY_G((status >= 0), "collective chunk optimization set chunk number succeeded"); + break; + + case API_MULTI_COLL: + status = H5Pset_dxpl_mpio_chunk_opt_num(xfer_plist, 8); /* make sure it is using multi-chunk IO */ + VRFY_G((status >= 0), "collective chunk optimization set chunk number succeeded"); + status = H5Pset_dxpl_mpio_chunk_opt_ratio(xfer_plist, 50); + VRFY_G((status >= 0), "collective chunk optimization set chunk ratio succeeded"); + break; + + case API_MULTI_IND: + status = H5Pset_dxpl_mpio_chunk_opt_num(xfer_plist, 8); /* make sure it is using multi-chunk IO */ + VRFY_G((status >= 0), "collective chunk optimization set chunk number succeeded"); + status = H5Pset_dxpl_mpio_chunk_opt_ratio(xfer_plist, 100); + VRFY_G((status >= 0), "collective chunk optimization set chunk ratio succeeded"); + break; + + default:; + } + +#ifdef H5_HAVE_INSTRUMENTED_LIBRARY + if (facc_type == FACC_MPIO) { + switch (api_option) { + case API_LINK_HARD: + prop_value = H5D_XFER_COLL_CHUNK_DEF; + status = H5Pinsert2(xfer_plist, H5D_XFER_COLL_CHUNK_LINK_HARD_NAME, H5D_XFER_COLL_CHUNK_SIZE, + &prop_value, NULL, NULL, NULL, NULL, NULL, NULL); + VRFY_G((status >= 0), "testing property list inserted succeeded"); + break; + + case API_MULTI_HARD: + prop_value = H5D_XFER_COLL_CHUNK_DEF; + status = H5Pinsert2(xfer_plist, H5D_XFER_COLL_CHUNK_MULTI_HARD_NAME, H5D_XFER_COLL_CHUNK_SIZE, + &prop_value, NULL, NULL, NULL, NULL, NULL, NULL); + VRFY_G((status >= 0), "testing property list inserted succeeded"); + break; + + case API_LINK_TRUE: + prop_value = H5D_XFER_COLL_CHUNK_DEF; + status = + H5Pinsert2(xfer_plist, H5D_XFER_COLL_CHUNK_LINK_NUM_TRUE_NAME, H5D_XFER_COLL_CHUNK_SIZE, + &prop_value, NULL, NULL, NULL, NULL, NULL, NULL); + VRFY_G((status >= 0), "testing property list inserted succeeded"); + break; + + case API_LINK_FALSE: + prop_value = H5D_XFER_COLL_CHUNK_DEF; + status = + H5Pinsert2(xfer_plist, H5D_XFER_COLL_CHUNK_LINK_NUM_FALSE_NAME, H5D_XFER_COLL_CHUNK_SIZE, + &prop_value, NULL, NULL, NULL, NULL, NULL, NULL); + VRFY_G((status >= 0), "testing property list inserted succeeded"); + break; + + case API_MULTI_COLL: + prop_value = H5D_XFER_COLL_CHUNK_DEF; + status = + H5Pinsert2(xfer_plist, H5D_XFER_COLL_CHUNK_MULTI_RATIO_COLL_NAME, + H5D_XFER_COLL_CHUNK_SIZE, &prop_value, NULL, NULL, NULL, NULL, NULL, NULL); + VRFY_G((status >= 0), "testing property list inserted succeeded"); + break; + + case API_MULTI_IND: + prop_value = H5D_XFER_COLL_CHUNK_DEF; + status = + H5Pinsert2(xfer_plist, H5D_XFER_COLL_CHUNK_MULTI_RATIO_IND_NAME, H5D_XFER_COLL_CHUNK_SIZE, + &prop_value, NULL, NULL, NULL, NULL, NULL, NULL); + VRFY_G((status >= 0), "testing property list inserted succeeded"); + break; + + default:; + } + } +#endif + + /* write data collectively */ + status = H5Dwrite(dataset, H5T_NATIVE_INT, mem_dataspace, file_dataspace, xfer_plist, data_array1); + VRFY_G((status >= 0), "dataset write succeeded"); + +#ifdef H5_HAVE_INSTRUMENTED_LIBRARY + if (facc_type == FACC_MPIO) { + switch (api_option) { + case API_LINK_HARD: + status = H5Pget(xfer_plist, H5D_XFER_COLL_CHUNK_LINK_HARD_NAME, &prop_value); + VRFY_G((status >= 0), "testing property list get succeeded"); + VRFY_G((prop_value == 0), "API to set LINK COLLECTIVE IO directly succeeded"); + break; + + case API_MULTI_HARD: + status = H5Pget(xfer_plist, H5D_XFER_COLL_CHUNK_MULTI_HARD_NAME, &prop_value); + VRFY_G((status >= 0), "testing property list get succeeded"); + VRFY_G((prop_value == 0), "API to set MULTI-CHUNK COLLECTIVE IO optimization succeeded"); + break; + + case API_LINK_TRUE: + status = H5Pget(xfer_plist, H5D_XFER_COLL_CHUNK_LINK_NUM_TRUE_NAME, &prop_value); + VRFY_G((status >= 0), "testing property list get succeeded"); + VRFY_G((prop_value == 0), "API to set LINK COLLECTIVE IO succeeded"); + break; + + case API_LINK_FALSE: + status = H5Pget(xfer_plist, H5D_XFER_COLL_CHUNK_LINK_NUM_FALSE_NAME, &prop_value); + VRFY_G((status >= 0), "testing property list get succeeded"); + VRFY_G((prop_value == 0), "API to set LINK IO transferring to multi-chunk IO succeeded"); + break; + + case API_MULTI_COLL: + status = H5Pget(xfer_plist, H5D_XFER_COLL_CHUNK_MULTI_RATIO_COLL_NAME, &prop_value); + VRFY_G((status >= 0), "testing property list get succeeded"); + VRFY_G((prop_value == 0), "API to set MULTI-CHUNK COLLECTIVE IO with optimization succeeded"); + break; + + case API_MULTI_IND: + status = H5Pget(xfer_plist, H5D_XFER_COLL_CHUNK_MULTI_RATIO_IND_NAME, &prop_value); + VRFY_G((status >= 0), "testing property list get succeeded"); + VRFY_G((prop_value == 0), + "API to set MULTI-CHUNK IO transferring to independent IO succeeded"); + break; + + default:; + } + } +#endif + + status = H5Dclose(dataset); + VRFY_G((status >= 0), ""); + + status = H5Pclose(xfer_plist); + VRFY_G((status >= 0), "property list closed"); + + status = H5Sclose(file_dataspace); + VRFY_G((status >= 0), ""); + + status = H5Sclose(mem_dataspace); + VRFY_G((status >= 0), ""); + + status = H5Fclose(file); + VRFY_G((status >= 0), ""); + + if (data_array1) + HDfree(data_array1); + + /* Use collective read to verify the correctness of collective write. */ + + /* allocate memory for data buffer */ + data_array1 = (int *)HDmalloc(dims[0] * dims[1] * sizeof(int)); + VRFY_G((data_array1 != NULL), "data_array1 malloc succeeded"); + + /* allocate memory for data buffer */ + data_origin1 = (int *)HDmalloc(dims[0] * dims[1] * sizeof(int)); + VRFY_G((data_origin1 != NULL), "data_origin1 malloc succeeded"); + + acc_plist = create_faccess_plist(comm, info, facc_type); + VRFY_G((acc_plist >= 0), "MPIO creation property list succeeded"); + + file = H5Fopen(FILENAME[0], H5F_ACC_RDONLY, acc_plist); + VRFY_G((file >= 0), "H5Fcreate succeeded"); + + status = H5Pclose(acc_plist); + VRFY_G((status >= 0), ""); + + /* open the collective dataset*/ + dataset = H5Dopen2(file, DSET_COLLECTIVE_CHUNK_NAME, H5P_DEFAULT); + VRFY_G((dataset >= 0), ""); + + /* set up dimensions of the slab this process accesses */ + ccslab_set(mpi_rank_g, mpi_size_g, start, count, stride, block, select_factor); + + /* obtain the file and mem dataspace*/ + file_dataspace = H5Dget_space(dataset); + VRFY_G((file_dataspace >= 0), ""); + + if (ALL != mem_selection) { + mem_dataspace = H5Dget_space(dataset); + VRFY_G((mem_dataspace >= 0), ""); + } + else { + /* Warning: H5Screate_simple requires an array of hsize_t elements + * even if we only pass only a single value. Attempting anything else + * appears to cause problems with 32 bit compilers. + */ + hsize_t dsdims[1] = {num_points}; + mem_dataspace = H5Screate_simple(1, dsdims, NULL); + VRFY_G((mem_dataspace >= 0), "mem_dataspace create succeeded"); + } + + switch (file_selection) { + case HYPER: + status = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY_G((status >= 0), "hyperslab selection succeeded"); + break; + + case POINT: + if (num_points) { + status = H5Sselect_elements(file_dataspace, H5S_SELECT_SET, num_points, coords); + VRFY_G((status >= 0), "Element selection succeeded"); + } + else { + status = H5Sselect_none(file_dataspace); + VRFY_G((status >= 0), "none selection succeeded"); + } + break; + + case ALL: + status = H5Sselect_all(file_dataspace); + VRFY_G((status >= 0), "H5Sselect_all succeeded"); + break; + } + + switch (mem_selection) { + case HYPER: + status = H5Sselect_hyperslab(mem_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY_G((status >= 0), "hyperslab selection succeeded"); + break; + + case POINT: + if (num_points) { + status = H5Sselect_elements(mem_dataspace, H5S_SELECT_SET, num_points, coords); + VRFY_G((status >= 0), "Element selection succeeded"); + } + else { + status = H5Sselect_none(mem_dataspace); + VRFY_G((status >= 0), "none selection succeeded"); + } + break; + + case ALL: + status = H5Sselect_all(mem_dataspace); + VRFY_G((status >= 0), "H5Sselect_all succeeded"); + break; + } + + /* fill dataset with test data */ + ccdataset_fill(start, stride, count, block, data_origin1, mem_selection); + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY_G((xfer_plist >= 0), ""); + + status = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY_G((status >= 0), "MPIO collective transfer property succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + status = H5Pset_dxpl_mpio_collective_opt(xfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY_G((status >= 0), "set independent IO collectively succeeded"); + } + + status = H5Dread(dataset, H5T_NATIVE_INT, mem_dataspace, file_dataspace, xfer_plist, data_array1); + VRFY_G((status >= 0), "dataset read succeeded"); + + /* verify the read data with original expected data */ + status = ccdataset_vrfy(start, count, stride, block, data_array1, data_origin1, mem_selection); + if (status) + nerrors++; + + status = H5Pclose(xfer_plist); + VRFY_G((status >= 0), "property list closed"); + + /* close dataset collectively */ + status = H5Dclose(dataset); + VRFY_G((status >= 0), "H5Dclose"); + + /* release all IDs created */ + status = H5Sclose(file_dataspace); + VRFY_G((status >= 0), "H5Sclose"); + + status = H5Sclose(mem_dataspace); + VRFY_G((status >= 0), "H5Sclose"); + + /* close the file collectively */ + status = H5Fclose(file); + VRFY_G((status >= 0), "H5Fclose"); + + /* release data buffers */ + if (coords) + HDfree(coords); + if (data_array1) + HDfree(data_array1); + if (data_origin1) + HDfree(data_origin1); +} + +int +main(int argc, char **argv) +{ + hid_t acc_plist = H5I_INVALID_HID; + + MPI_Init(&argc, &argv); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size_g); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank_g); + + /* Attempt to turn off atexit post processing so that in case errors + * happen during the test and the process is aborted, it will not get + * hang in the atexit post processing in which it may try to make MPI + * calls. By then, MPI calls may not work. + */ + if (H5dont_atexit() < 0) + HDprintf("Failed to turn off atexit processing. Continue.\n"); + + /* set alarm. */ + /* TestAlarmOn(); */ + + acc_plist = create_faccess_plist(MPI_COMM_WORLD, MPI_INFO_NULL, facc_type); + + /* Get the capability flag of the VOL connector being used */ + if (H5Pget_vol_cap_flags(acc_plist, &vol_cap_flags_g) < 0) { + if (MAIN_PROCESS) + HDprintf("Failed to get the capability flag of the VOL connector being used\n"); + + MPI_Finalize(); + return 0; + } + + /* Make sure the connector supports the API functions being tested. This test only + * uses a few API functions, such as H5Fcreate/open/close/delete, H5Dcreate/write/read/close, + * and H5Dget_space. */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAIN_PROCESS) + HDprintf( + "API functions for basic file, dataset basic or more aren't supported with this connector\n"); + + MPI_Finalize(); + return 0; + } + + dataset_big_write(); + MPI_Barrier(MPI_COMM_WORLD); + + dataset_big_read(); + MPI_Barrier(MPI_COMM_WORLD); + + coll_chunk1(); + MPI_Barrier(MPI_COMM_WORLD); + coll_chunk2(); + MPI_Barrier(MPI_COMM_WORLD); + coll_chunk3(); + MPI_Barrier(MPI_COMM_WORLD); + + single_rank_independent_io(); + + /* turn off alarm */ + /* TestAlarmOff(); */ + + if (mpi_rank_g == 0) { + hid_t fapl_id = H5Pcreate(H5P_FILE_ACCESS); + + H5Pset_fapl_mpio(fapl_id, MPI_COMM_SELF, MPI_INFO_NULL); + + H5E_BEGIN_TRY + { + H5Fdelete(FILENAME[0], fapl_id); + H5Fdelete(FILENAME[1], fapl_id); + } + H5E_END_TRY; + + H5Pclose(fapl_id); + } + + H5Pclose(acc_plist); + + /* close HDF5 library */ + H5close(); + + MPI_Finalize(); + + return 0; +} diff --git a/testpar/API/t_chunk_alloc.c b/testpar/API/t_chunk_alloc.c new file mode 100644 index 0000000..dd78225 --- /dev/null +++ b/testpar/API/t_chunk_alloc.c @@ -0,0 +1,512 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * This verifies if the storage space allocation methods are compatible between + * serial and parallel modes. + * + * Created by: Christian Chilan and Albert Cheng + * Date: 2006/05/25 + */ + +#include "hdf5.h" +#include "testphdf5.h" +static int mpi_size, mpi_rank; + +#define DSET_NAME "ExtendibleArray" +#define CHUNK_SIZE 1000 /* #elements per chunk */ +#define CHUNK_FACTOR 200 /* default dataset size in terms of chunks */ +#define CLOSE 1 +#define NO_CLOSE 0 + +#if 0 +static MPI_Offset +get_filesize(const char *filename) +{ + int mpierr; + MPI_File fd; + MPI_Offset filesize; + + mpierr = MPI_File_open(MPI_COMM_SELF, filename, MPI_MODE_RDONLY, MPI_INFO_NULL, &fd); + VRFY((mpierr == MPI_SUCCESS), ""); + + mpierr = MPI_File_get_size(fd, &filesize); + VRFY((mpierr == MPI_SUCCESS), ""); + + mpierr = MPI_File_close(&fd); + VRFY((mpierr == MPI_SUCCESS), ""); + + return (filesize); +} +#endif + +typedef enum write_pattern { none, sec_last, all } write_type; + +typedef enum access_ { write_all, open_only, extend_only } access_type; + +/* + * This creates a dataset serially with chunks, each of CHUNK_SIZE + * elements. The allocation time is set to H5D_ALLOC_TIME_EARLY. Another + * routine will open this in parallel for extension test. + */ +static void +create_chunked_dataset(const char *filename, int chunk_factor, write_type write_pattern) +{ + hid_t file_id, dataset; /* handles */ + hid_t dataspace, memspace; + hid_t cparms; + hsize_t dims[1]; + hsize_t maxdims[1] = {H5S_UNLIMITED}; + + hsize_t chunk_dims[1] = {CHUNK_SIZE}; + hsize_t count[1]; + hsize_t stride[1]; + hsize_t block[1]; + hsize_t offset[1]; /* Selection offset within dataspace */ + /* Variables used in reading data back */ + char buffer[CHUNK_SIZE]; + long nchunks; + herr_t hrc; +#if 0 + MPI_Offset filesize, /* actual file size */ + est_filesize; /* estimated file size */ +#endif + /* set up MPI parameters */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Only MAINPROCESS should create the file. Others just wait. */ + if (MAINPROCESS) { + nchunks = chunk_factor * mpi_size; + dims[0] = (hsize_t)(nchunks * CHUNK_SIZE); + /* Create the data space with unlimited dimensions. */ + dataspace = H5Screate_simple(1, dims, maxdims); + VRFY((dataspace >= 0), ""); + + memspace = H5Screate_simple(1, chunk_dims, NULL); + VRFY((memspace >= 0), ""); + + /* Create a new file. If file exists its contents will be overwritten. */ + file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + VRFY((file_id >= 0), "H5Fcreate"); + + /* Modify dataset creation properties, i.e. enable chunking */ + cparms = H5Pcreate(H5P_DATASET_CREATE); + VRFY((cparms >= 0), ""); + + hrc = H5Pset_alloc_time(cparms, H5D_ALLOC_TIME_EARLY); + VRFY((hrc >= 0), ""); + + hrc = H5Pset_chunk(cparms, 1, chunk_dims); + VRFY((hrc >= 0), ""); + + /* Create a new dataset within the file using cparms creation properties. */ + dataset = + H5Dcreate2(file_id, DSET_NAME, H5T_NATIVE_UCHAR, dataspace, H5P_DEFAULT, cparms, H5P_DEFAULT); + VRFY((dataset >= 0), ""); + + if (write_pattern == sec_last) { + HDmemset(buffer, 100, CHUNK_SIZE); + + count[0] = 1; + stride[0] = 1; + block[0] = chunk_dims[0]; + offset[0] = (hsize_t)(nchunks - 2) * chunk_dims[0]; + + hrc = H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, offset, stride, count, block); + VRFY((hrc >= 0), ""); + + /* Write sec_last chunk */ + hrc = H5Dwrite(dataset, H5T_NATIVE_UCHAR, memspace, dataspace, H5P_DEFAULT, buffer); + VRFY((hrc >= 0), "H5Dwrite"); + } /* end if */ + + /* Close resources */ + hrc = H5Dclose(dataset); + VRFY((hrc >= 0), ""); + dataset = -1; + + hrc = H5Sclose(dataspace); + VRFY((hrc >= 0), ""); + + hrc = H5Sclose(memspace); + VRFY((hrc >= 0), ""); + + hrc = H5Pclose(cparms); + VRFY((hrc >= 0), ""); + + hrc = H5Fclose(file_id); + VRFY((hrc >= 0), ""); + file_id = -1; + +#if 0 + /* verify file size */ + filesize = get_filesize(filename); + est_filesize = (MPI_Offset)nchunks * (MPI_Offset)CHUNK_SIZE * (MPI_Offset)sizeof(unsigned char); + VRFY((filesize >= est_filesize), "file size check"); +#endif + } + + /* Make sure all processes are done before exiting this routine. Otherwise, + * other tests may start and change the test data file before some processes + * of this test are still accessing the file. + */ + + MPI_Barrier(MPI_COMM_WORLD); +} + +/* + * This program performs three different types of parallel access. It writes on + * the entire dataset, it extends the dataset to nchunks*CHUNK_SIZE, and it only + * opens the dataset. At the end, it verifies the size of the dataset to be + * consistent with argument 'chunk_factor'. + */ +static void +parallel_access_dataset(const char *filename, int chunk_factor, access_type action, hid_t *file_id, + hid_t *dataset) +{ + /* HDF5 gubbins */ + hid_t memspace, dataspace; /* HDF5 file identifier */ + hid_t access_plist; /* HDF5 ID for file access property list */ + herr_t hrc; /* HDF5 return code */ + hsize_t size[1]; + + hsize_t chunk_dims[1] = {CHUNK_SIZE}; + hsize_t count[1]; + hsize_t stride[1]; + hsize_t block[1]; + hsize_t offset[1]; /* Selection offset within dataspace */ + hsize_t dims[1]; + hsize_t maxdims[1]; + + /* Variables used in reading data back */ + char buffer[CHUNK_SIZE]; + int i; + long nchunks; +#if 0 + /* MPI Gubbins */ + MPI_Offset filesize, /* actual file size */ + est_filesize; /* estimated file size */ +#endif + + /* Initialize MPI */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + nchunks = chunk_factor * mpi_size; + + /* Set up MPIO file access property lists */ + access_plist = H5Pcreate(H5P_FILE_ACCESS); + VRFY((access_plist >= 0), ""); + + hrc = H5Pset_fapl_mpio(access_plist, MPI_COMM_WORLD, MPI_INFO_NULL); + VRFY((hrc >= 0), ""); + + /* Open the file */ + if (*file_id < 0) { + *file_id = H5Fopen(filename, H5F_ACC_RDWR, access_plist); + VRFY((*file_id >= 0), ""); + } + + /* Open dataset*/ + if (*dataset < 0) { + *dataset = H5Dopen2(*file_id, DSET_NAME, H5P_DEFAULT); + VRFY((*dataset >= 0), ""); + } + + /* Make sure all processes are done before continuing. Otherwise, one + * process could change the dataset extent before another finishes opening + * it, resulting in only some of the processes calling H5Dset_extent(). */ + MPI_Barrier(MPI_COMM_WORLD); + + memspace = H5Screate_simple(1, chunk_dims, NULL); + VRFY((memspace >= 0), ""); + + dataspace = H5Dget_space(*dataset); + VRFY((dataspace >= 0), ""); + + size[0] = (hsize_t)nchunks * CHUNK_SIZE; + + switch (action) { + + /* all chunks are written by all the processes in an interleaved way*/ + case write_all: + + HDmemset(buffer, mpi_rank + 1, CHUNK_SIZE); + count[0] = 1; + stride[0] = 1; + block[0] = chunk_dims[0]; + for (i = 0; i < nchunks / mpi_size; i++) { + offset[0] = (hsize_t)(i * mpi_size + mpi_rank) * chunk_dims[0]; + + hrc = H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, offset, stride, count, block); + VRFY((hrc >= 0), ""); + + /* Write the buffer out */ + hrc = H5Dwrite(*dataset, H5T_NATIVE_UCHAR, memspace, dataspace, H5P_DEFAULT, buffer); + VRFY((hrc >= 0), "H5Dwrite"); + } + + break; + + /* only extends the dataset */ + case extend_only: + /* check if new size is larger than old size */ + hrc = H5Sget_simple_extent_dims(dataspace, dims, maxdims); + VRFY((hrc >= 0), ""); + + /* Extend dataset*/ + if (size[0] > dims[0]) { + hrc = H5Dset_extent(*dataset, size); + VRFY((hrc >= 0), ""); + } + break; + + /* only opens the *dataset */ + case open_only: + break; + default: + HDassert(0); + } + + /* Close up */ + hrc = H5Dclose(*dataset); + VRFY((hrc >= 0), ""); + *dataset = -1; + + hrc = H5Sclose(dataspace); + VRFY((hrc >= 0), ""); + + hrc = H5Sclose(memspace); + VRFY((hrc >= 0), ""); + + hrc = H5Fclose(*file_id); + VRFY((hrc >= 0), ""); + *file_id = -1; + +#if 0 + /* verify file size */ + filesize = get_filesize(filename); + est_filesize = (MPI_Offset)nchunks * (MPI_Offset)CHUNK_SIZE * (MPI_Offset)sizeof(unsigned char); + VRFY((filesize >= est_filesize), "file size check"); +#endif + + /* Can close some plists */ + hrc = H5Pclose(access_plist); + VRFY((hrc >= 0), ""); + + /* Make sure all processes are done before exiting this routine. Otherwise, + * other tests may start and change the test data file before some processes + * of this test are still accessing the file. + */ + MPI_Barrier(MPI_COMM_WORLD); +} + +/* + * This routine verifies the data written in the dataset. It does one of the + * three cases according to the value of parameter `write_pattern'. + * 1. it returns correct fill values though the dataset has not been written; + * 2. it still returns correct fill values though only a small part is written; + * 3. it returns correct values when the whole dataset has been written in an + * interleaved pattern. + */ +static void +verify_data(const char *filename, int chunk_factor, write_type write_pattern, int vclose, hid_t *file_id, + hid_t *dataset) +{ + /* HDF5 gubbins */ + hid_t dataspace, memspace; /* HDF5 file identifier */ + hid_t access_plist; /* HDF5 ID for file access property list */ + herr_t hrc; /* HDF5 return code */ + + hsize_t chunk_dims[1] = {CHUNK_SIZE}; + hsize_t count[1]; + hsize_t stride[1]; + hsize_t block[1]; + hsize_t offset[1]; /* Selection offset within dataspace */ + /* Variables used in reading data back */ + char buffer[CHUNK_SIZE]; + int value, i; + int index_l; + long nchunks; + /* Initialize MPI */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + nchunks = chunk_factor * mpi_size; + + /* Set up MPIO file access property lists */ + access_plist = H5Pcreate(H5P_FILE_ACCESS); + VRFY((access_plist >= 0), ""); + + hrc = H5Pset_fapl_mpio(access_plist, MPI_COMM_WORLD, MPI_INFO_NULL); + VRFY((hrc >= 0), ""); + + /* Open the file */ + if (*file_id < 0) { + *file_id = H5Fopen(filename, H5F_ACC_RDWR, access_plist); + VRFY((*file_id >= 0), ""); + } + + /* Open dataset*/ + if (*dataset < 0) { + *dataset = H5Dopen2(*file_id, DSET_NAME, H5P_DEFAULT); + VRFY((*dataset >= 0), ""); + } + + memspace = H5Screate_simple(1, chunk_dims, NULL); + VRFY((memspace >= 0), ""); + + dataspace = H5Dget_space(*dataset); + VRFY((dataspace >= 0), ""); + + /* all processes check all chunks. */ + count[0] = 1; + stride[0] = 1; + block[0] = chunk_dims[0]; + for (i = 0; i < nchunks; i++) { + /* reset buffer values */ + HDmemset(buffer, -1, CHUNK_SIZE); + + offset[0] = (hsize_t)i * chunk_dims[0]; + + hrc = H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, offset, stride, count, block); + VRFY((hrc >= 0), ""); + + /* Read the chunk */ + hrc = H5Dread(*dataset, H5T_NATIVE_UCHAR, memspace, dataspace, H5P_DEFAULT, buffer); + VRFY((hrc >= 0), "H5Dread"); + + /* set expected value according the write pattern */ + switch (write_pattern) { + case all: + value = i % mpi_size + 1; + break; + case none: + value = 0; + break; + case sec_last: + if (i == nchunks - 2) + value = 100; + else + value = 0; + break; + default: + HDassert(0); + } + + /* verify content of the chunk */ + for (index_l = 0; index_l < CHUNK_SIZE; index_l++) + VRFY((buffer[index_l] == value), "data verification"); + } + + hrc = H5Sclose(dataspace); + VRFY((hrc >= 0), ""); + + hrc = H5Sclose(memspace); + VRFY((hrc >= 0), ""); + + /* Can close some plists */ + hrc = H5Pclose(access_plist); + VRFY((hrc >= 0), ""); + + /* Close up */ + if (vclose) { + hrc = H5Dclose(*dataset); + VRFY((hrc >= 0), ""); + *dataset = -1; + + hrc = H5Fclose(*file_id); + VRFY((hrc >= 0), ""); + *file_id = -1; + } + + /* Make sure all processes are done before exiting this routine. Otherwise, + * other tests may start and change the test data file before some processes + * of this test are still accessing the file. + */ + MPI_Barrier(MPI_COMM_WORLD); +} + +/* + * Test following possible scenarios, + * Case 1: + * Sequential create a file and dataset with H5D_ALLOC_TIME_EARLY and large + * size, no write, close, reopen in parallel, read to verify all return + * the fill value. + * Case 2: + * Sequential create a file and dataset with H5D_ALLOC_TIME_EARLY but small + * size, no write, close, reopen in parallel, extend to large size, then close, + * then reopen in parallel and read to verify all return the fill value. + * Case 3: + * Sequential create a file and dataset with H5D_ALLOC_TIME_EARLY and large + * size, write just a small part of the dataset (second to the last), close, + * then reopen in parallel, read to verify all return the fill value except + * those small portion that has been written. Without closing it, writes + * all parts of the dataset in a interleave pattern, close it, and reopen + * it, read to verify all data are as written. + */ +void +test_chunk_alloc(void) +{ + const char *filename; + hid_t file_id, dataset; + + file_id = dataset = -1; + + /* Initialize MPI */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, dataset, or dataset more aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + filename = (const char *)PARATESTFILE /* GetTestParameters() */; + if (VERBOSE_MED) + HDprintf("Extend Chunked allocation test on file %s\n", filename); + + /* Case 1 */ + /* Create chunked dataset without writing anything.*/ + create_chunked_dataset(filename, CHUNK_FACTOR, none); + /* reopen dataset in parallel and check for file size */ + parallel_access_dataset(filename, CHUNK_FACTOR, open_only, &file_id, &dataset); + /* reopen dataset in parallel, read and verify the data */ + verify_data(filename, CHUNK_FACTOR, none, CLOSE, &file_id, &dataset); + + /* Case 2 */ + /* Create chunked dataset without writing anything */ + create_chunked_dataset(filename, 20, none); + /* reopen dataset in parallel and only extend it */ + parallel_access_dataset(filename, CHUNK_FACTOR, extend_only, &file_id, &dataset); + /* reopen dataset in parallel, read and verify the data */ + verify_data(filename, CHUNK_FACTOR, none, CLOSE, &file_id, &dataset); + + /* Case 3 */ + /* Create chunked dataset and write in the second to last chunk */ + create_chunked_dataset(filename, CHUNK_FACTOR, sec_last); + /* Reopen dataset in parallel, read and verify the data. The file and dataset are not closed*/ + verify_data(filename, CHUNK_FACTOR, sec_last, NO_CLOSE, &file_id, &dataset); + /* All processes write in all the chunks in a interleaved way */ + parallel_access_dataset(filename, CHUNK_FACTOR, write_all, &file_id, &dataset); + /* reopen dataset in parallel, read and verify the data */ + verify_data(filename, CHUNK_FACTOR, all, CLOSE, &file_id, &dataset); +} diff --git a/testpar/API/t_coll_chunk.c b/testpar/API/t_coll_chunk.c new file mode 100644 index 0000000..57ee605 --- /dev/null +++ b/testpar/API/t_coll_chunk.c @@ -0,0 +1,1417 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "hdf5.h" +#include "testphdf5.h" + +#define HYPER 1 +#define POINT 2 +#define ALL 3 + +/* some commonly used routines for collective chunk IO tests*/ + +static void ccslab_set(int mpi_rank, int mpi_size, hsize_t start[], hsize_t count[], hsize_t stride[], + hsize_t block[], int mode); + +static void ccdataset_fill(hsize_t start[], hsize_t count[], hsize_t stride[], hsize_t block[], + DATATYPE *dataset, int mem_selection); + +static void ccdataset_print(hsize_t start[], hsize_t block[], DATATYPE *dataset); + +static int ccdataset_vrfy(hsize_t start[], hsize_t count[], hsize_t stride[], hsize_t block[], + DATATYPE *dataset, DATATYPE *original, int mem_selection); + +static void coll_chunktest(const char *filename, int chunk_factor, int select_factor, int api_option, + int file_selection, int mem_selection, int mode); + +/*------------------------------------------------------------------------- + * Function: coll_chunk1 + * + * Purpose: Wrapper to test the collective chunk IO for regular JOINT + selection with a single chunk + * + * Return: Success: 0 + * + * Failure: -1 + * + * Programmer: Unknown + * July 12th, 2004 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ + +/* ------------------------------------------------------------------------ + * Descriptions for the selection: One big singular selection inside one chunk + * Two dimensions, + * + * dim1 = SPACE_DIM1(5760)*mpi_size + * dim2 = SPACE_DIM2(3) + * chunk_dim1 = dim1 + * chunk_dim2 = dim2 + * block = 1 for all dimensions + * stride = 1 for all dimensions + * count0 = SPACE_DIM1(5760) + * count1 = SPACE_DIM2(3) + * start0 = mpi_rank*SPACE_DIM1 + * start1 = 0 + * ------------------------------------------------------------------------ + */ + +void +coll_chunk1(void) +{ + const char *filename = PARATESTFILE /* GetTestParameters() */; + int mpi_rank; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, dataset or dataset more aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + coll_chunktest(filename, 1, BYROW_CONT, API_NONE, HYPER, HYPER, OUT_OF_ORDER); + coll_chunktest(filename, 1, BYROW_CONT, API_NONE, HYPER, POINT, OUT_OF_ORDER); + coll_chunktest(filename, 1, BYROW_CONT, API_NONE, POINT, ALL, OUT_OF_ORDER); + coll_chunktest(filename, 1, BYROW_CONT, API_NONE, POINT, POINT, OUT_OF_ORDER); + coll_chunktest(filename, 1, BYROW_CONT, API_NONE, POINT, HYPER, OUT_OF_ORDER); + + coll_chunktest(filename, 1, BYROW_CONT, API_NONE, POINT, ALL, IN_ORDER); + coll_chunktest(filename, 1, BYROW_CONT, API_NONE, POINT, POINT, IN_ORDER); + coll_chunktest(filename, 1, BYROW_CONT, API_NONE, POINT, HYPER, IN_ORDER); +} + +/*------------------------------------------------------------------------- + * Function: coll_chunk2 + * + * Purpose: Wrapper to test the collective chunk IO for regular DISJOINT + selection with a single chunk + * + * Return: Success: 0 + * + * Failure: -1 + * + * Programmer: Unknown + * July 12th, 2004 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ + +/* ------------------------------------------------------------------------ + * Descriptions for the selection: many disjoint selections inside one chunk + * Two dimensions, + * + * dim1 = SPACE_DIM1*mpi_size(5760) + * dim2 = SPACE_DIM2(3) + * chunk_dim1 = dim1 + * chunk_dim2 = dim2 + * block = 1 for all dimensions + * stride = 3 for all dimensions + * count0 = SPACE_DIM1/stride0(5760/3) + * count1 = SPACE_DIM2/stride(3/3 = 1) + * start0 = mpi_rank*SPACE_DIM1 + * start1 = 0 + * + * ------------------------------------------------------------------------ + */ +void +coll_chunk2(void) +{ + const char *filename = PARATESTFILE /* GetTestParameters() */; + int mpi_rank; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, dataset or dataset more aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + coll_chunktest(filename, 1, BYROW_DISCONT, API_NONE, HYPER, HYPER, OUT_OF_ORDER); + coll_chunktest(filename, 1, BYROW_DISCONT, API_NONE, HYPER, POINT, OUT_OF_ORDER); + coll_chunktest(filename, 1, BYROW_DISCONT, API_NONE, POINT, ALL, OUT_OF_ORDER); + coll_chunktest(filename, 1, BYROW_DISCONT, API_NONE, POINT, POINT, OUT_OF_ORDER); + coll_chunktest(filename, 1, BYROW_DISCONT, API_NONE, POINT, HYPER, OUT_OF_ORDER); + + coll_chunktest(filename, 1, BYROW_DISCONT, API_NONE, POINT, ALL, IN_ORDER); + coll_chunktest(filename, 1, BYROW_DISCONT, API_NONE, POINT, POINT, IN_ORDER); + coll_chunktest(filename, 1, BYROW_DISCONT, API_NONE, POINT, HYPER, IN_ORDER); +} + +/*------------------------------------------------------------------------- + * Function: coll_chunk3 + * + * Purpose: Wrapper to test the collective chunk IO for regular JOINT + selection with at least number of 2*mpi_size chunks + * + * Return: Success: 0 + * + * Failure: -1 + * + * Programmer: Unknown + * July 12th, 2004 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ + +/* ------------------------------------------------------------------------ + * Descriptions for the selection: one singular selection across many chunks + * Two dimensions, Num of chunks = 2* mpi_size + * + * dim1 = SPACE_DIM1*mpi_size + * dim2 = SPACE_DIM2(3) + * chunk_dim1 = SPACE_DIM1 + * chunk_dim2 = dim2/2 + * block = 1 for all dimensions + * stride = 1 for all dimensions + * count0 = SPACE_DIM1 + * count1 = SPACE_DIM2(3) + * start0 = mpi_rank*SPACE_DIM1 + * start1 = 0 + * + * ------------------------------------------------------------------------ + */ + +void +coll_chunk3(void) +{ + const char *filename = PARATESTFILE /* GetTestParameters() */; + int mpi_size; + int mpi_rank; + + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, dataset or dataset more aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + coll_chunktest(filename, mpi_size, BYROW_CONT, API_NONE, HYPER, HYPER, OUT_OF_ORDER); + coll_chunktest(filename, mpi_size, BYROW_CONT, API_NONE, HYPER, POINT, OUT_OF_ORDER); + coll_chunktest(filename, mpi_size, BYROW_CONT, API_NONE, POINT, ALL, OUT_OF_ORDER); + coll_chunktest(filename, mpi_size, BYROW_CONT, API_NONE, POINT, POINT, OUT_OF_ORDER); + coll_chunktest(filename, mpi_size, BYROW_CONT, API_NONE, POINT, HYPER, OUT_OF_ORDER); + + coll_chunktest(filename, mpi_size, BYROW_CONT, API_NONE, POINT, ALL, IN_ORDER); + coll_chunktest(filename, mpi_size, BYROW_CONT, API_NONE, POINT, POINT, IN_ORDER); + coll_chunktest(filename, mpi_size, BYROW_CONT, API_NONE, POINT, HYPER, IN_ORDER); +} + +/*------------------------------------------------------------------------- + * Function: coll_chunk4 + * + * Purpose: Wrapper to test the collective chunk IO for regular JOINT + selection with at least number of 2*mpi_size chunks + * + * Return: Success: 0 + * + * Failure: -1 + * + * Programmer: Unknown + * July 12th, 2004 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ + +/* ------------------------------------------------------------------------ + * Descriptions for the selection: one singular selection across many chunks + * Two dimensions, Num of chunks = 2* mpi_size + * + * dim1 = SPACE_DIM1*mpi_size + * dim2 = SPACE_DIM2 + * chunk_dim1 = dim1 + * chunk_dim2 = dim2 + * block = 1 for all dimensions + * stride = 1 for all dimensions + * count0 = SPACE_DIM1 + * count1 = SPACE_DIM2(3) + * start0 = mpi_rank*SPACE_DIM1 + * start1 = 0 + * + * ------------------------------------------------------------------------ + */ + +void +coll_chunk4(void) +{ + const char *filename = PARATESTFILE /* GetTestParameters() */; + int mpi_rank; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, dataset or dataset more aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + coll_chunktest(filename, 1, BYROW_SELECTNONE, API_NONE, HYPER, HYPER, OUT_OF_ORDER); + coll_chunktest(filename, 1, BYROW_SELECTNONE, API_NONE, HYPER, POINT, OUT_OF_ORDER); + coll_chunktest(filename, 1, BYROW_SELECTNONE, API_NONE, POINT, ALL, OUT_OF_ORDER); + coll_chunktest(filename, 1, BYROW_SELECTNONE, API_NONE, POINT, POINT, OUT_OF_ORDER); + coll_chunktest(filename, 1, BYROW_SELECTNONE, API_NONE, POINT, HYPER, OUT_OF_ORDER); + + coll_chunktest(filename, 1, BYROW_SELECTNONE, API_NONE, POINT, ALL, IN_ORDER); + coll_chunktest(filename, 1, BYROW_SELECTNONE, API_NONE, POINT, POINT, IN_ORDER); + coll_chunktest(filename, 1, BYROW_SELECTNONE, API_NONE, POINT, HYPER, IN_ORDER); +} + +/*------------------------------------------------------------------------- + * Function: coll_chunk4 + * + * Purpose: Wrapper to test the collective chunk IO for regular JOINT + selection with at least number of 2*mpi_size chunks + * + * Return: Success: 0 + * + * Failure: -1 + * + * Programmer: Unknown + * July 12th, 2004 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ + +/* ------------------------------------------------------------------------ + * Descriptions for the selection: one singular selection across many chunks + * Two dimensions, Num of chunks = 2* mpi_size + * + * dim1 = SPACE_DIM1*mpi_size + * dim2 = SPACE_DIM2 + * chunk_dim1 = dim1 + * chunk_dim2 = dim2 + * block = 1 for all dimensions + * stride = 1 for all dimensions + * count0 = SPACE_DIM1 + * count1 = SPACE_DIM2(3) + * start0 = mpi_rank*SPACE_DIM1 + * start1 = 0 + * + * ------------------------------------------------------------------------ + */ + +void +coll_chunk5(void) +{ + const char *filename = PARATESTFILE /* GetTestParameters() */; + int mpi_rank; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, dataset or dataset more aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_HARD, HYPER, HYPER, OUT_OF_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_HARD, HYPER, POINT, OUT_OF_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_HARD, POINT, ALL, OUT_OF_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_HARD, POINT, POINT, OUT_OF_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_HARD, POINT, HYPER, OUT_OF_ORDER); + + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_HARD, POINT, ALL, IN_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_HARD, POINT, POINT, IN_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_HARD, POINT, HYPER, IN_ORDER); +} + +/*------------------------------------------------------------------------- + * Function: coll_chunk6 + * + * Purpose: Test direct request for multi-chunk-io. + * Wrapper to test the collective chunk IO for regular JOINT + * selection with at least number of 2*mpi_size chunks + * Test for direct to Multi Chunk I/O. + * + * Return: Success: 0 + * + * Failure: -1 + * + * Programmer: Unknown + * July 12th, 2004 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ + +/* ------------------------------------------------------------------------ + * Descriptions for the selection: one singular selection across many chunks + * Two dimensions, Num of chunks = 2* mpi_size + * + * dim1 = SPACE_DIM1*mpi_size + * dim2 = SPACE_DIM2 + * chunk_dim1 = dim1 + * chunk_dim2 = dim2 + * block = 1 for all dimensions + * stride = 1 for all dimensions + * count0 = SPACE_DIM1 + * count1 = SPACE_DIM2(3) + * start0 = mpi_rank*SPACE_DIM1 + * start1 = 0 + * + * ------------------------------------------------------------------------ + */ + +void +coll_chunk6(void) +{ + const char *filename = PARATESTFILE /* GetTestParameters() */; + int mpi_rank; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, dataset or dataset more aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_HARD, HYPER, HYPER, OUT_OF_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_HARD, HYPER, POINT, OUT_OF_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_HARD, POINT, ALL, OUT_OF_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_HARD, POINT, POINT, OUT_OF_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_HARD, POINT, HYPER, OUT_OF_ORDER); + + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_HARD, POINT, ALL, IN_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_HARD, POINT, POINT, IN_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_HARD, POINT, HYPER, IN_ORDER); +} + +/*------------------------------------------------------------------------- + * Function: coll_chunk7 + * + * Purpose: Wrapper to test the collective chunk IO for regular JOINT + selection with at least number of 2*mpi_size chunks + * + * Return: Success: 0 + * + * Failure: -1 + * + * Programmer: Unknown + * July 12th, 2004 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ + +/* ------------------------------------------------------------------------ + * Descriptions for the selection: one singular selection across many chunks + * Two dimensions, Num of chunks = 2* mpi_size + * + * dim1 = SPACE_DIM1*mpi_size + * dim2 = SPACE_DIM2 + * chunk_dim1 = dim1 + * chunk_dim2 = dim2 + * block = 1 for all dimensions + * stride = 1 for all dimensions + * count0 = SPACE_DIM1 + * count1 = SPACE_DIM2(3) + * start0 = mpi_rank*SPACE_DIM1 + * start1 = 0 + * + * ------------------------------------------------------------------------ + */ + +void +coll_chunk7(void) +{ + const char *filename = PARATESTFILE /* GetTestParameters() */; + int mpi_rank; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, dataset or dataset more aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_TRUE, HYPER, HYPER, OUT_OF_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_TRUE, HYPER, POINT, OUT_OF_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_TRUE, POINT, ALL, OUT_OF_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_TRUE, POINT, POINT, OUT_OF_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_TRUE, POINT, HYPER, OUT_OF_ORDER); + + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_TRUE, POINT, ALL, IN_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_TRUE, POINT, POINT, IN_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_TRUE, POINT, HYPER, IN_ORDER); +} + +/*------------------------------------------------------------------------- + * Function: coll_chunk8 + * + * Purpose: Wrapper to test the collective chunk IO for regular JOINT + selection with at least number of 2*mpi_size chunks + * + * Return: Success: 0 + * + * Failure: -1 + * + * Programmer: Unknown + * July 12th, 2004 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ + +/* ------------------------------------------------------------------------ + * Descriptions for the selection: one singular selection across many chunks + * Two dimensions, Num of chunks = 2* mpi_size + * + * dim1 = SPACE_DIM1*mpi_size + * dim2 = SPACE_DIM2 + * chunk_dim1 = dim1 + * chunk_dim2 = dim2 + * block = 1 for all dimensions + * stride = 1 for all dimensions + * count0 = SPACE_DIM1 + * count1 = SPACE_DIM2(3) + * start0 = mpi_rank*SPACE_DIM1 + * start1 = 0 + * + * ------------------------------------------------------------------------ + */ + +void +coll_chunk8(void) +{ + const char *filename = PARATESTFILE /* GetTestParameters() */; + int mpi_rank; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, dataset or dataset more aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_FALSE, HYPER, HYPER, OUT_OF_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_FALSE, HYPER, POINT, OUT_OF_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_FALSE, POINT, ALL, OUT_OF_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_FALSE, POINT, POINT, OUT_OF_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_FALSE, POINT, HYPER, OUT_OF_ORDER); + + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_FALSE, POINT, ALL, IN_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_FALSE, POINT, POINT, IN_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_LINK_FALSE, POINT, HYPER, IN_ORDER); +} + +/*------------------------------------------------------------------------- + * Function: coll_chunk9 + * + * Purpose: Wrapper to test the collective chunk IO for regular JOINT + selection with at least number of 2*mpi_size chunks + * + * Return: Success: 0 + * + * Failure: -1 + * + * Programmer: Unknown + * July 12th, 2004 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ + +/* ------------------------------------------------------------------------ + * Descriptions for the selection: one singular selection across many chunks + * Two dimensions, Num of chunks = 2* mpi_size + * + * dim1 = SPACE_DIM1*mpi_size + * dim2 = SPACE_DIM2 + * chunk_dim1 = dim1 + * chunk_dim2 = dim2 + * block = 1 for all dimensions + * stride = 1 for all dimensions + * count0 = SPACE_DIM1 + * count1 = SPACE_DIM2(3) + * start0 = mpi_rank*SPACE_DIM1 + * start1 = 0 + * + * ------------------------------------------------------------------------ + */ + +void +coll_chunk9(void) +{ + const char *filename = PARATESTFILE /* GetTestParameters() */; + int mpi_rank; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, dataset or dataset more aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_COLL, HYPER, HYPER, OUT_OF_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_COLL, HYPER, POINT, OUT_OF_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_COLL, POINT, ALL, OUT_OF_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_COLL, POINT, POINT, OUT_OF_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_COLL, POINT, HYPER, OUT_OF_ORDER); + + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_COLL, POINT, ALL, IN_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_COLL, POINT, POINT, IN_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTUNBALANCE, API_MULTI_COLL, POINT, HYPER, IN_ORDER); +} + +/*------------------------------------------------------------------------- + * Function: coll_chunk10 + * + * Purpose: Wrapper to test the collective chunk IO for regular JOINT + selection with at least number of 2*mpi_size chunks + * + * Return: Success: 0 + * + * Failure: -1 + * + * Programmer: Unknown + * July 12th, 2004 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ + +/* ------------------------------------------------------------------------ + * Descriptions for the selection: one singular selection across many chunks + * Two dimensions, Num of chunks = 2* mpi_size + * + * dim1 = SPACE_DIM1*mpi_size + * dim2 = SPACE_DIM2 + * chunk_dim1 = dim1 + * chunk_dim2 = dim2 + * block = 1 for all dimensions + * stride = 1 for all dimensions + * count0 = SPACE_DIM1 + * count1 = SPACE_DIM2(3) + * start0 = mpi_rank*SPACE_DIM1 + * start1 = 0 + * + * ------------------------------------------------------------------------ + */ + +void +coll_chunk10(void) +{ + const char *filename = PARATESTFILE /* GetTestParameters() */; + int mpi_rank; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, dataset or dataset more aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + coll_chunktest(filename, 4, BYROW_SELECTINCHUNK, API_MULTI_IND, HYPER, HYPER, OUT_OF_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTINCHUNK, API_MULTI_IND, HYPER, POINT, OUT_OF_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTINCHUNK, API_MULTI_IND, POINT, ALL, OUT_OF_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTINCHUNK, API_MULTI_IND, POINT, POINT, OUT_OF_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTINCHUNK, API_MULTI_IND, POINT, HYPER, OUT_OF_ORDER); + + coll_chunktest(filename, 4, BYROW_SELECTINCHUNK, API_MULTI_IND, POINT, ALL, IN_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTINCHUNK, API_MULTI_IND, POINT, POINT, IN_ORDER); + coll_chunktest(filename, 4, BYROW_SELECTINCHUNK, API_MULTI_IND, POINT, HYPER, IN_ORDER); +} + +/*------------------------------------------------------------------------- + * Function: coll_chunktest + * + * Purpose: The real testing routine for regular selection of collective + chunking storage + testing both write and read, + If anything fails, it may be read or write. There is no + separation test between read and write. + * + * Return: Success: 0 + * + * Failure: -1 + * + * Modifications: + * Remove invalid temporary property checkings for API_LINK_HARD and + * API_LINK_TRUE cases. + * Programmer: Jonathan Kim + * Date: 2012-10-10 + * + * Programmer: Unknown + * July 12th, 2004 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ + +static void +coll_chunktest(const char *filename, int chunk_factor, int select_factor, int api_option, int file_selection, + int mem_selection, int mode) +{ + hid_t file, dataset, file_dataspace, mem_dataspace; + hid_t acc_plist, xfer_plist, crp_plist; + + hsize_t dims[RANK], chunk_dims[RANK]; + int *data_array1 = NULL; + int *data_origin1 = NULL; + + hsize_t start[RANK], count[RANK], stride[RANK], block[RANK]; + +#ifdef H5_HAVE_INSTRUMENTED_LIBRARY + unsigned prop_value; +#endif /* H5_HAVE_INSTRUMENTED_LIBRARY */ + + int mpi_size, mpi_rank; + + herr_t status; + MPI_Comm comm = MPI_COMM_WORLD; + MPI_Info info = MPI_INFO_NULL; + + size_t num_points; /* for point selection */ + hsize_t *coords = NULL; /* for point selection */ + hsize_t current_dims; /* for point selection */ + + /* set up MPI parameters */ + MPI_Comm_size(comm, &mpi_size); + MPI_Comm_rank(comm, &mpi_rank); + + /* Create the data space */ + + acc_plist = create_faccess_plist(comm, info, facc_type); + VRFY((acc_plist >= 0), ""); + + file = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, acc_plist); + VRFY((file >= 0), "H5Fcreate succeeded"); + + status = H5Pclose(acc_plist); + VRFY((status >= 0), ""); + + /* setup dimensionality object */ + dims[0] = (hsize_t)(SPACE_DIM1 * mpi_size); + dims[1] = SPACE_DIM2; + + /* allocate memory for data buffer */ + data_array1 = (int *)HDmalloc(dims[0] * dims[1] * sizeof(int)); + VRFY((data_array1 != NULL), "data_array1 malloc succeeded"); + + /* set up dimensions of the slab this process accesses */ + ccslab_set(mpi_rank, mpi_size, start, count, stride, block, select_factor); + + /* set up the coords array selection */ + num_points = block[0] * block[1] * count[0] * count[1]; + coords = (hsize_t *)HDmalloc(num_points * RANK * sizeof(hsize_t)); + VRFY((coords != NULL), "coords malloc succeeded"); + point_set(start, count, stride, block, num_points, coords, mode); + + file_dataspace = H5Screate_simple(2, dims, NULL); + VRFY((file_dataspace >= 0), "file dataspace created succeeded"); + + if (ALL != mem_selection) { + mem_dataspace = H5Screate_simple(2, dims, NULL); + VRFY((mem_dataspace >= 0), "mem dataspace created succeeded"); + } + else { + current_dims = num_points; + mem_dataspace = H5Screate_simple(1, ¤t_dims, NULL); + VRFY((mem_dataspace >= 0), "mem_dataspace create succeeded"); + } + + crp_plist = H5Pcreate(H5P_DATASET_CREATE); + VRFY((crp_plist >= 0), ""); + + /* Set up chunk information. */ + chunk_dims[0] = dims[0] / (hsize_t)chunk_factor; + + /* to decrease the testing time, maintain bigger chunk size */ + (chunk_factor == 1) ? (chunk_dims[1] = SPACE_DIM2) : (chunk_dims[1] = SPACE_DIM2 / 2); + status = H5Pset_chunk(crp_plist, 2, chunk_dims); + VRFY((status >= 0), "chunk creation property list succeeded"); + + dataset = H5Dcreate2(file, DSET_COLLECTIVE_CHUNK_NAME, H5T_NATIVE_INT, file_dataspace, H5P_DEFAULT, + crp_plist, H5P_DEFAULT); + VRFY((dataset >= 0), "dataset created succeeded"); + + status = H5Pclose(crp_plist); + VRFY((status >= 0), ""); + + /*put some trivial data in the data array */ + ccdataset_fill(start, stride, count, block, data_array1, mem_selection); + + MESG("data_array initialized"); + + switch (file_selection) { + case HYPER: + status = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((status >= 0), "hyperslab selection succeeded"); + break; + + case POINT: + if (num_points) { + status = H5Sselect_elements(file_dataspace, H5S_SELECT_SET, num_points, coords); + VRFY((status >= 0), "Element selection succeeded"); + } + else { + status = H5Sselect_none(file_dataspace); + VRFY((status >= 0), "none selection succeeded"); + } + break; + + case ALL: + status = H5Sselect_all(file_dataspace); + VRFY((status >= 0), "H5Sselect_all succeeded"); + break; + } + + switch (mem_selection) { + case HYPER: + status = H5Sselect_hyperslab(mem_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((status >= 0), "hyperslab selection succeeded"); + break; + + case POINT: + if (num_points) { + status = H5Sselect_elements(mem_dataspace, H5S_SELECT_SET, num_points, coords); + VRFY((status >= 0), "Element selection succeeded"); + } + else { + status = H5Sselect_none(mem_dataspace); + VRFY((status >= 0), "none selection succeeded"); + } + break; + + case ALL: + status = H5Sselect_all(mem_dataspace); + VRFY((status >= 0), "H5Sselect_all succeeded"); + break; + } + + /* set up the collective transfer property list */ + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY((xfer_plist >= 0), ""); + + status = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY((status >= 0), "MPIO collective transfer property succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + status = H5Pset_dxpl_mpio_collective_opt(xfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY((status >= 0), "set independent IO collectively succeeded"); + } + + switch (api_option) { + case API_LINK_HARD: + status = H5Pset_dxpl_mpio_chunk_opt(xfer_plist, H5FD_MPIO_CHUNK_ONE_IO); + VRFY((status >= 0), "collective chunk optimization succeeded"); + break; + + case API_MULTI_HARD: + status = H5Pset_dxpl_mpio_chunk_opt(xfer_plist, H5FD_MPIO_CHUNK_MULTI_IO); + VRFY((status >= 0), "collective chunk optimization succeeded "); + break; + + case API_LINK_TRUE: + status = H5Pset_dxpl_mpio_chunk_opt_num(xfer_plist, 2); + VRFY((status >= 0), "collective chunk optimization set chunk number succeeded"); + break; + + case API_LINK_FALSE: + status = H5Pset_dxpl_mpio_chunk_opt_num(xfer_plist, 6); + VRFY((status >= 0), "collective chunk optimization set chunk number succeeded"); + break; + + case API_MULTI_COLL: + status = H5Pset_dxpl_mpio_chunk_opt_num(xfer_plist, 8); /* make sure it is using multi-chunk IO */ + VRFY((status >= 0), "collective chunk optimization set chunk number succeeded"); + status = H5Pset_dxpl_mpio_chunk_opt_ratio(xfer_plist, 50); + VRFY((status >= 0), "collective chunk optimization set chunk ratio succeeded"); + break; + + case API_MULTI_IND: + status = H5Pset_dxpl_mpio_chunk_opt_num(xfer_plist, 8); /* make sure it is using multi-chunk IO */ + VRFY((status >= 0), "collective chunk optimization set chunk number succeeded"); + status = H5Pset_dxpl_mpio_chunk_opt_ratio(xfer_plist, 100); + VRFY((status >= 0), "collective chunk optimization set chunk ratio succeeded"); + break; + + default:; + } + +#ifdef H5_HAVE_INSTRUMENTED_LIBRARY + if (facc_type == FACC_MPIO) { + switch (api_option) { + case API_LINK_HARD: + prop_value = H5D_XFER_COLL_CHUNK_DEF; + status = H5Pinsert2(xfer_plist, H5D_XFER_COLL_CHUNK_LINK_HARD_NAME, H5D_XFER_COLL_CHUNK_SIZE, + &prop_value, NULL, NULL, NULL, NULL, NULL, NULL); + VRFY((status >= 0), "testing property list inserted succeeded"); + break; + + case API_MULTI_HARD: + prop_value = H5D_XFER_COLL_CHUNK_DEF; + status = H5Pinsert2(xfer_plist, H5D_XFER_COLL_CHUNK_MULTI_HARD_NAME, H5D_XFER_COLL_CHUNK_SIZE, + &prop_value, NULL, NULL, NULL, NULL, NULL, NULL); + VRFY((status >= 0), "testing property list inserted succeeded"); + break; + + case API_LINK_TRUE: + prop_value = H5D_XFER_COLL_CHUNK_DEF; + status = + H5Pinsert2(xfer_plist, H5D_XFER_COLL_CHUNK_LINK_NUM_TRUE_NAME, H5D_XFER_COLL_CHUNK_SIZE, + &prop_value, NULL, NULL, NULL, NULL, NULL, NULL); + VRFY((status >= 0), "testing property list inserted succeeded"); + break; + + case API_LINK_FALSE: + prop_value = H5D_XFER_COLL_CHUNK_DEF; + status = + H5Pinsert2(xfer_plist, H5D_XFER_COLL_CHUNK_LINK_NUM_FALSE_NAME, H5D_XFER_COLL_CHUNK_SIZE, + &prop_value, NULL, NULL, NULL, NULL, NULL, NULL); + VRFY((status >= 0), "testing property list inserted succeeded"); + break; + + case API_MULTI_COLL: + prop_value = H5D_XFER_COLL_CHUNK_DEF; + status = + H5Pinsert2(xfer_plist, H5D_XFER_COLL_CHUNK_MULTI_RATIO_COLL_NAME, + H5D_XFER_COLL_CHUNK_SIZE, &prop_value, NULL, NULL, NULL, NULL, NULL, NULL); + VRFY((status >= 0), "testing property list inserted succeeded"); + break; + + case API_MULTI_IND: + prop_value = H5D_XFER_COLL_CHUNK_DEF; + status = + H5Pinsert2(xfer_plist, H5D_XFER_COLL_CHUNK_MULTI_RATIO_IND_NAME, H5D_XFER_COLL_CHUNK_SIZE, + &prop_value, NULL, NULL, NULL, NULL, NULL, NULL); + VRFY((status >= 0), "testing property list inserted succeeded"); + break; + + default:; + } + } +#endif + + /* write data collectively */ + status = H5Dwrite(dataset, H5T_NATIVE_INT, mem_dataspace, file_dataspace, xfer_plist, data_array1); + VRFY((status >= 0), "dataset write succeeded"); + +#ifdef H5_HAVE_INSTRUMENTED_LIBRARY + /* Only check chunk optimization mode if selection I/O is not being used - + * selection I/O bypasses this IO mode decision - it's effectively always + * multi chunk currently */ + if (facc_type == FACC_MPIO && /* !H5_use_selection_io_g */ TRUE) { + switch (api_option) { + case API_LINK_HARD: + status = H5Pget(xfer_plist, H5D_XFER_COLL_CHUNK_LINK_HARD_NAME, &prop_value); + VRFY((status >= 0), "testing property list get succeeded"); + VRFY((prop_value == 0), "API to set LINK COLLECTIVE IO directly succeeded"); + break; + + case API_MULTI_HARD: + status = H5Pget(xfer_plist, H5D_XFER_COLL_CHUNK_MULTI_HARD_NAME, &prop_value); + VRFY((status >= 0), "testing property list get succeeded"); + VRFY((prop_value == 0), "API to set MULTI-CHUNK COLLECTIVE IO optimization succeeded"); + break; + + case API_LINK_TRUE: + status = H5Pget(xfer_plist, H5D_XFER_COLL_CHUNK_LINK_NUM_TRUE_NAME, &prop_value); + VRFY((status >= 0), "testing property list get succeeded"); + VRFY((prop_value == 0), "API to set LINK COLLECTIVE IO succeeded"); + break; + + case API_LINK_FALSE: + status = H5Pget(xfer_plist, H5D_XFER_COLL_CHUNK_LINK_NUM_FALSE_NAME, &prop_value); + VRFY((status >= 0), "testing property list get succeeded"); + VRFY((prop_value == 0), "API to set LINK IO transferring to multi-chunk IO succeeded"); + break; + + case API_MULTI_COLL: + status = H5Pget(xfer_plist, H5D_XFER_COLL_CHUNK_MULTI_RATIO_COLL_NAME, &prop_value); + VRFY((status >= 0), "testing property list get succeeded"); + VRFY((prop_value == 0), "API to set MULTI-CHUNK COLLECTIVE IO with optimization succeeded"); + break; + + case API_MULTI_IND: + status = H5Pget(xfer_plist, H5D_XFER_COLL_CHUNK_MULTI_RATIO_IND_NAME, &prop_value); + VRFY((status >= 0), "testing property list get succeeded"); + VRFY((prop_value == 0), + "API to set MULTI-CHUNK IO transferring to independent IO succeeded"); + break; + + default:; + } + } +#endif + + status = H5Dclose(dataset); + VRFY((status >= 0), ""); + + status = H5Pclose(xfer_plist); + VRFY((status >= 0), "property list closed"); + + status = H5Sclose(file_dataspace); + VRFY((status >= 0), ""); + + status = H5Sclose(mem_dataspace); + VRFY((status >= 0), ""); + + status = H5Fclose(file); + VRFY((status >= 0), ""); + + if (data_array1) + HDfree(data_array1); + + /* Use collective read to verify the correctness of collective write. */ + + /* allocate memory for data buffer */ + data_array1 = (int *)HDmalloc(dims[0] * dims[1] * sizeof(int)); + VRFY((data_array1 != NULL), "data_array1 malloc succeeded"); + + /* allocate memory for data buffer */ + data_origin1 = (int *)HDmalloc(dims[0] * dims[1] * sizeof(int)); + VRFY((data_origin1 != NULL), "data_origin1 malloc succeeded"); + + acc_plist = create_faccess_plist(comm, info, facc_type); + VRFY((acc_plist >= 0), "MPIO creation property list succeeded"); + + file = H5Fopen(filename, H5F_ACC_RDONLY, acc_plist); + VRFY((file >= 0), "H5Fcreate succeeded"); + + status = H5Pclose(acc_plist); + VRFY((status >= 0), ""); + + /* open the collective dataset*/ + dataset = H5Dopen2(file, DSET_COLLECTIVE_CHUNK_NAME, H5P_DEFAULT); + VRFY((dataset >= 0), ""); + + /* set up dimensions of the slab this process accesses */ + ccslab_set(mpi_rank, mpi_size, start, count, stride, block, select_factor); + + /* obtain the file and mem dataspace*/ + file_dataspace = H5Dget_space(dataset); + VRFY((file_dataspace >= 0), ""); + + if (ALL != mem_selection) { + mem_dataspace = H5Dget_space(dataset); + VRFY((mem_dataspace >= 0), ""); + } + else { + current_dims = num_points; + mem_dataspace = H5Screate_simple(1, ¤t_dims, NULL); + VRFY((mem_dataspace >= 0), "mem_dataspace create succeeded"); + } + + switch (file_selection) { + case HYPER: + status = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((status >= 0), "hyperslab selection succeeded"); + break; + + case POINT: + if (num_points) { + status = H5Sselect_elements(file_dataspace, H5S_SELECT_SET, num_points, coords); + VRFY((status >= 0), "Element selection succeeded"); + } + else { + status = H5Sselect_none(file_dataspace); + VRFY((status >= 0), "none selection succeeded"); + } + break; + + case ALL: + status = H5Sselect_all(file_dataspace); + VRFY((status >= 0), "H5Sselect_all succeeded"); + break; + } + + switch (mem_selection) { + case HYPER: + status = H5Sselect_hyperslab(mem_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((status >= 0), "hyperslab selection succeeded"); + break; + + case POINT: + if (num_points) { + status = H5Sselect_elements(mem_dataspace, H5S_SELECT_SET, num_points, coords); + VRFY((status >= 0), "Element selection succeeded"); + } + else { + status = H5Sselect_none(mem_dataspace); + VRFY((status >= 0), "none selection succeeded"); + } + break; + + case ALL: + status = H5Sselect_all(mem_dataspace); + VRFY((status >= 0), "H5Sselect_all succeeded"); + break; + } + + /* fill dataset with test data */ + ccdataset_fill(start, stride, count, block, data_origin1, mem_selection); + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY((xfer_plist >= 0), ""); + + status = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY((status >= 0), "MPIO collective transfer property succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + status = H5Pset_dxpl_mpio_collective_opt(xfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY((status >= 0), "set independent IO collectively succeeded"); + } + + status = H5Dread(dataset, H5T_NATIVE_INT, mem_dataspace, file_dataspace, xfer_plist, data_array1); + VRFY((status >= 0), "dataset read succeeded"); + + /* verify the read data with original expected data */ + status = ccdataset_vrfy(start, count, stride, block, data_array1, data_origin1, mem_selection); + if (status) + nerrors++; + + status = H5Pclose(xfer_plist); + VRFY((status >= 0), "property list closed"); + + /* close dataset collectively */ + status = H5Dclose(dataset); + VRFY((status >= 0), "H5Dclose"); + + /* release all IDs created */ + status = H5Sclose(file_dataspace); + VRFY((status >= 0), "H5Sclose"); + + status = H5Sclose(mem_dataspace); + VRFY((status >= 0), "H5Sclose"); + + /* close the file collectively */ + status = H5Fclose(file); + VRFY((status >= 0), "H5Fclose"); + + /* release data buffers */ + if (coords) + HDfree(coords); + if (data_array1) + HDfree(data_array1); + if (data_origin1) + HDfree(data_origin1); +} + +/* Set up the selection */ +static void +ccslab_set(int mpi_rank, int mpi_size, hsize_t start[], hsize_t count[], hsize_t stride[], hsize_t block[], + int mode) +{ + + switch (mode) { + + case BYROW_CONT: + /* Each process takes a slabs of rows. */ + block[0] = 1; + block[1] = 1; + stride[0] = 1; + stride[1] = 1; + count[0] = SPACE_DIM1; + count[1] = SPACE_DIM2; + start[0] = (hsize_t)mpi_rank * count[0]; + start[1] = 0; + + break; + + case BYROW_DISCONT: + /* Each process takes several disjoint blocks. */ + block[0] = 1; + block[1] = 1; + stride[0] = 3; + stride[1] = 3; + count[0] = SPACE_DIM1 / (stride[0] * block[0]); + count[1] = (SPACE_DIM2) / (stride[1] * block[1]); + start[0] = (hsize_t)SPACE_DIM1 * (hsize_t)mpi_rank; + start[1] = 0; + + break; + + case BYROW_SELECTNONE: + /* Each process takes a slabs of rows, there are + no selections for the last process. */ + block[0] = 1; + block[1] = 1; + stride[0] = 1; + stride[1] = 1; + count[0] = ((mpi_rank >= MAX(1, (mpi_size - 2))) ? 0 : SPACE_DIM1); + count[1] = SPACE_DIM2; + start[0] = (hsize_t)mpi_rank * count[0]; + start[1] = 0; + + break; + + case BYROW_SELECTUNBALANCE: + /* The first one-third of the number of processes only + select top half of the domain, The rest will select the bottom + half of the domain. */ + + block[0] = 1; + count[0] = 2; + stride[0] = (hsize_t)SPACE_DIM1 * (hsize_t)mpi_size / 4 + 1; + block[1] = SPACE_DIM2; + count[1] = 1; + start[1] = 0; + stride[1] = 1; + if ((mpi_rank * 3) < (mpi_size * 2)) + start[0] = (hsize_t)mpi_rank; + else + start[0] = (hsize_t)(1 + SPACE_DIM1 * mpi_size / 2 + (mpi_rank - 2 * mpi_size / 3)); + break; + + case BYROW_SELECTINCHUNK: + /* Each process will only select one chunk */ + + block[0] = 1; + count[0] = 1; + start[0] = (hsize_t)(mpi_rank * SPACE_DIM1); + stride[0] = 1; + block[1] = SPACE_DIM2; + count[1] = 1; + stride[1] = 1; + start[1] = 0; + + break; + + default: + /* Unknown mode. Set it to cover the whole dataset. */ + block[0] = (hsize_t)SPACE_DIM1 * (hsize_t)mpi_size; + block[1] = SPACE_DIM2; + stride[0] = block[0]; + stride[1] = block[1]; + count[0] = 1; + count[1] = 1; + start[0] = 0; + start[1] = 0; + + break; + } + if (VERBOSE_MED) { + HDprintf("start[]=(%lu,%lu), count[]=(%lu,%lu), stride[]=(%lu,%lu), block[]=(%lu,%lu), total " + "datapoints=%lu\n", + (unsigned long)start[0], (unsigned long)start[1], (unsigned long)count[0], + (unsigned long)count[1], (unsigned long)stride[0], (unsigned long)stride[1], + (unsigned long)block[0], (unsigned long)block[1], + (unsigned long)(block[0] * block[1] * count[0] * count[1])); + } +} + +/* + * Fill the dataset with trivial data for testing. + * Assume dimension rank is 2. + */ +static void +ccdataset_fill(hsize_t start[], hsize_t stride[], hsize_t count[], hsize_t block[], DATATYPE *dataset, + int mem_selection) +{ + DATATYPE *dataptr = dataset; + DATATYPE *tmptr; + hsize_t i, j, k1, k2, k = 0; + /* put some trivial data in the data_array */ + tmptr = dataptr; + + /* assign the disjoint block (two-dimensional)data array value + through the pointer */ + + for (k1 = 0; k1 < count[0]; k1++) { + for (i = 0; i < block[0]; i++) { + for (k2 = 0; k2 < count[1]; k2++) { + for (j = 0; j < block[1]; j++) { + + if (ALL != mem_selection) { + dataptr = tmptr + ((start[0] + k1 * stride[0] + i) * SPACE_DIM2 + start[1] + + k2 * stride[1] + j); + } + else { + dataptr = tmptr + k; + k++; + } + + *dataptr = (DATATYPE)(k1 + k2 + i + j); + } + } + } + } +} + +/* + * Print the first block of the content of the dataset. + */ +static void +ccdataset_print(hsize_t start[], hsize_t block[], DATATYPE *dataset) + +{ + DATATYPE *dataptr = dataset; + hsize_t i, j; + + /* print the column heading */ + HDprintf("Print only the first block of the dataset\n"); + HDprintf("%-8s", "Cols:"); + for (j = 0; j < block[1]; j++) { + HDprintf("%3lu ", (unsigned long)(start[1] + j)); + } + HDprintf("\n"); + + /* print the slab data */ + for (i = 0; i < block[0]; i++) { + HDprintf("Row %2lu: ", (unsigned long)(i + start[0])); + for (j = 0; j < block[1]; j++) { + HDprintf("%03d ", *dataptr++); + } + HDprintf("\n"); + } +} + +/* + * Print the content of the dataset. + */ +static int +ccdataset_vrfy(hsize_t start[], hsize_t count[], hsize_t stride[], hsize_t block[], DATATYPE *dataset, + DATATYPE *original, int mem_selection) +{ + hsize_t i, j, k1, k2, k = 0; + int vrfyerrs; + DATATYPE *dataptr, *oriptr; + + /* print it if VERBOSE_MED */ + if (VERBOSE_MED) { + HDprintf("dataset_vrfy dumping:::\n"); + HDprintf("start(%lu, %lu), count(%lu, %lu), stride(%lu, %lu), block(%lu, %lu)\n", + (unsigned long)start[0], (unsigned long)start[1], (unsigned long)count[0], + (unsigned long)count[1], (unsigned long)stride[0], (unsigned long)stride[1], + (unsigned long)block[0], (unsigned long)block[1]); + HDprintf("original values:\n"); + ccdataset_print(start, block, original); + HDprintf("compared values:\n"); + ccdataset_print(start, block, dataset); + } + + vrfyerrs = 0; + + for (k1 = 0; k1 < count[0]; k1++) { + for (i = 0; i < block[0]; i++) { + for (k2 = 0; k2 < count[1]; k2++) { + for (j = 0; j < block[1]; j++) { + if (ALL != mem_selection) { + dataptr = dataset + ((start[0] + k1 * stride[0] + i) * SPACE_DIM2 + start[1] + + k2 * stride[1] + j); + oriptr = original + ((start[0] + k1 * stride[0] + i) * SPACE_DIM2 + start[1] + + k2 * stride[1] + j); + } + else { + dataptr = dataset + k; + oriptr = original + k; + k++; + } + if (*dataptr != *oriptr) { + if (vrfyerrs++ < MAX_ERR_REPORT || VERBOSE_MED) { + HDprintf("Dataset Verify failed at [%lu][%lu]: expect %d, got %d\n", + (unsigned long)i, (unsigned long)j, *(oriptr), *(dataptr)); + } + } + } + } + } + } + if (vrfyerrs > MAX_ERR_REPORT && !VERBOSE_MED) + HDprintf("[more errors ...]\n"); + if (vrfyerrs) + HDprintf("%d errors found in ccdataset_vrfy\n", vrfyerrs); + return (vrfyerrs); +} diff --git a/testpar/API/t_coll_md_read.c b/testpar/API/t_coll_md_read.c new file mode 100644 index 0000000..f6f99bf --- /dev/null +++ b/testpar/API/t_coll_md_read.c @@ -0,0 +1,654 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * A test suite to test HDF5's collective metadata read and write capabilities, + * as enabled by making a call to H5Pset_all_coll_metadata_ops() and/or + * H5Pset_coll_metadata_write(). + */ + +#include "hdf5.h" +#include "testphdf5.h" + +#include +#include +#include + +/* + * Define the non-participating process as the "last" + * rank to avoid any weirdness potentially caused by + * an if (mpi_rank == 0) check. + */ +#define PARTIAL_NO_SELECTION_NO_SEL_PROCESS (mpi_rank == mpi_size - 1) +#define PARTIAL_NO_SELECTION_DATASET_NAME "partial_no_selection_dset" +#define PARTIAL_NO_SELECTION_DATASET_NDIMS 2 +#define PARTIAL_NO_SELECTION_Y_DIM_SCALE 5 +#define PARTIAL_NO_SELECTION_X_DIM_SCALE 5 + +#define MULTI_CHUNK_IO_ADDRMAP_ISSUE_DIMS 2 + +#define LINK_CHUNK_IO_SORT_CHUNK_ISSUE_COLL_THRESH_NUM 10000 +#define LINK_CHUNK_IO_SORT_CHUNK_ISSUE_DATASET_NAME "linked_chunk_io_sort_chunk_issue" +#define LINK_CHUNK_IO_SORT_CHUNK_ISSUE_DIMS 1 + +#define COLL_GHEAP_WRITE_ATTR_NELEMS 10 +#define COLL_GHEAP_WRITE_ATTR_NAME "coll_gheap_write_attr" +#define COLL_GHEAP_WRITE_ATTR_DIMS 1 + +/* + * A test for issue HDFFV-10501. A parallel hang was reported which occurred + * in linked-chunk I/O when collective metadata reads are enabled and some ranks + * do not have any selection in a dataset's dataspace, while others do. The ranks + * which have no selection during the read/write operation called H5D__chunk_addrmap() + * to retrieve the lowest chunk address, since we require that the read/write be done + * in strictly non-decreasing order of chunk address. For version 1 and 2 B-trees, + * this caused the non-participating ranks to issue a collective MPI_Bcast() call + * which the other ranks did not issue, thus causing a hang. + * + * However, since these ranks are not actually reading/writing anything, this call + * can simply be removed and the address used for the read/write can be set to an + * arbitrary number (0 was chosen). + */ +void +test_partial_no_selection_coll_md_read(void) +{ + const char *filename; + hsize_t *dataset_dims = NULL; + hsize_t max_dataset_dims[PARTIAL_NO_SELECTION_DATASET_NDIMS]; + hsize_t sel_dims[1]; + hsize_t chunk_dims[PARTIAL_NO_SELECTION_DATASET_NDIMS] = {PARTIAL_NO_SELECTION_Y_DIM_SCALE, + PARTIAL_NO_SELECTION_X_DIM_SCALE}; + hsize_t start[PARTIAL_NO_SELECTION_DATASET_NDIMS]; + hsize_t stride[PARTIAL_NO_SELECTION_DATASET_NDIMS]; + hsize_t count[PARTIAL_NO_SELECTION_DATASET_NDIMS]; + hsize_t block[PARTIAL_NO_SELECTION_DATASET_NDIMS]; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dcpl_id = H5I_INVALID_HID; + hid_t dxpl_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + int mpi_rank, mpi_size; + void *data = NULL; + void *read_buf = NULL; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, dataset or file flush aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + filename = PARATESTFILE /* GetTestParameters() */; + + fapl_id = create_faccess_plist(MPI_COMM_WORLD, MPI_INFO_NULL, facc_type); + VRFY((fapl_id >= 0), "create_faccess_plist succeeded"); + + /* + * Even though the testphdf5 framework currently sets collective metadata reads + * on the FAPL, we call it here just to be sure this is futureproof, since + * demonstrating this issue relies upon it. + */ + VRFY((H5Pset_all_coll_metadata_ops(fapl_id, true) >= 0), "Set collective metadata reads succeeded"); + + file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id); + VRFY((file_id >= 0), "H5Fcreate succeeded"); + + dataset_dims = HDmalloc(PARTIAL_NO_SELECTION_DATASET_NDIMS * sizeof(*dataset_dims)); + VRFY((dataset_dims != NULL), "malloc succeeded"); + + dataset_dims[0] = (hsize_t)PARTIAL_NO_SELECTION_Y_DIM_SCALE * (hsize_t)mpi_size; + dataset_dims[1] = (hsize_t)PARTIAL_NO_SELECTION_X_DIM_SCALE * (hsize_t)mpi_size; + max_dataset_dims[0] = H5S_UNLIMITED; + max_dataset_dims[1] = H5S_UNLIMITED; + + fspace_id = H5Screate_simple(PARTIAL_NO_SELECTION_DATASET_NDIMS, dataset_dims, max_dataset_dims); + VRFY((fspace_id >= 0), "H5Screate_simple succeeded"); + + /* + * Set up chunking on the dataset in order to reproduce the problem. + */ + dcpl_id = H5Pcreate(H5P_DATASET_CREATE); + VRFY((dcpl_id >= 0), "H5Pcreate succeeded"); + + VRFY((H5Pset_chunk(dcpl_id, PARTIAL_NO_SELECTION_DATASET_NDIMS, chunk_dims) >= 0), + "H5Pset_chunk succeeded"); + + dset_id = H5Dcreate2(file_id, PARTIAL_NO_SELECTION_DATASET_NAME, H5T_NATIVE_INT, fspace_id, H5P_DEFAULT, + dcpl_id, H5P_DEFAULT); + VRFY((dset_id >= 0), "H5Dcreate2 succeeded"); + + /* + * Setup hyperslab selection to split the dataset among the ranks. + * + * The ranks will write rows across the dataset. + */ + start[0] = (hsize_t)PARTIAL_NO_SELECTION_Y_DIM_SCALE * (hsize_t)mpi_rank; + start[1] = 0; + stride[0] = PARTIAL_NO_SELECTION_Y_DIM_SCALE; + stride[1] = PARTIAL_NO_SELECTION_X_DIM_SCALE; + count[0] = 1; + count[1] = (hsize_t)mpi_size; + block[0] = PARTIAL_NO_SELECTION_Y_DIM_SCALE; + block[1] = PARTIAL_NO_SELECTION_X_DIM_SCALE; + + VRFY((H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET, start, stride, count, block) >= 0), + "H5Sselect_hyperslab succeeded"); + + sel_dims[0] = count[1] * (PARTIAL_NO_SELECTION_Y_DIM_SCALE * PARTIAL_NO_SELECTION_X_DIM_SCALE); + + mspace_id = H5Screate_simple(1, sel_dims, NULL); + VRFY((mspace_id >= 0), "H5Screate_simple succeeded"); + + data = HDcalloc(1, count[1] * (PARTIAL_NO_SELECTION_Y_DIM_SCALE * PARTIAL_NO_SELECTION_X_DIM_SCALE) * + sizeof(int)); + VRFY((data != NULL), "calloc succeeded"); + + dxpl_id = H5Pcreate(H5P_DATASET_XFER); + VRFY((dxpl_id >= 0), "H5Pcreate succeeded"); + + /* + * Enable collective access for the data transfer. + */ + VRFY((H5Pset_dxpl_mpio(dxpl_id, H5FD_MPIO_COLLECTIVE) >= 0), "H5Pset_dxpl_mpio succeeded"); + + VRFY((H5Dwrite(dset_id, H5T_NATIVE_INT, mspace_id, fspace_id, dxpl_id, data) >= 0), "H5Dwrite succeeded"); + + VRFY((H5Fflush(file_id, H5F_SCOPE_GLOBAL) >= 0), "H5Fflush succeeded"); + + /* + * Ensure that linked-chunk I/O is performed since this is + * the particular code path where the issue lies and we don't + * want the library doing multi-chunk I/O behind our backs. + */ + VRFY((H5Pset_dxpl_mpio_chunk_opt(dxpl_id, H5FD_MPIO_CHUNK_ONE_IO) >= 0), + "H5Pset_dxpl_mpio_chunk_opt succeeded"); + + read_buf = HDmalloc(count[1] * (PARTIAL_NO_SELECTION_Y_DIM_SCALE * PARTIAL_NO_SELECTION_X_DIM_SCALE) * + sizeof(int)); + VRFY((read_buf != NULL), "malloc succeeded"); + + /* + * Make sure to call H5Sselect_none() on the non-participating process. + */ + if (PARTIAL_NO_SELECTION_NO_SEL_PROCESS) { + VRFY((H5Sselect_none(fspace_id) >= 0), "H5Sselect_none succeeded"); + VRFY((H5Sselect_none(mspace_id) >= 0), "H5Sselect_none succeeded"); + } + + /* + * Finally have each rank read their section of data back from the dataset. + */ + VRFY((H5Dread(dset_id, H5T_NATIVE_INT, mspace_id, fspace_id, dxpl_id, read_buf) >= 0), + "H5Dread succeeded"); + + /* + * Check data integrity just to be sure. + */ + if (!PARTIAL_NO_SELECTION_NO_SEL_PROCESS) { + VRFY((!HDmemcmp(data, read_buf, + count[1] * (PARTIAL_NO_SELECTION_Y_DIM_SCALE * PARTIAL_NO_SELECTION_X_DIM_SCALE) * + sizeof(int))), + "memcmp succeeded"); + } + + if (dataset_dims) { + HDfree(dataset_dims); + dataset_dims = NULL; + } + + if (data) { + HDfree(data); + data = NULL; + } + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + VRFY((H5Sclose(fspace_id) >= 0), "H5Sclose succeeded"); + VRFY((H5Sclose(mspace_id) >= 0), "H5Sclose succeeded"); + VRFY((H5Pclose(dcpl_id) >= 0), "H5Pclose succeeded"); + VRFY((H5Pclose(dxpl_id) >= 0), "H5Pclose succeeded"); + VRFY((H5Dclose(dset_id) >= 0), "H5Dclose succeeded"); + VRFY((H5Pclose(fapl_id) >= 0), "H5Pclose succeeded"); + VRFY((H5Fclose(file_id) >= 0), "H5Fclose succeeded"); +} + +/* + * A test for HDFFV-10562 which attempts to verify that using multi-chunk + * I/O with collective metadata reads enabled doesn't causes issues due to + * collective metadata reads being made only by process 0 in H5D__chunk_addrmap(). + * + * Failure in this test may either cause a hang, or, due to how the MPI calls + * pertaining to this issue might mistakenly match up, may cause an MPI error + * message similar to: + * + * #008: H5Dmpio.c line 2546 in H5D__obtain_mpio_mode(): MPI_BCast failed + * major: Internal error (too specific to document in detail) + * minor: Some MPI function failed + * #009: H5Dmpio.c line 2546 in H5D__obtain_mpio_mode(): Message truncated, error stack: + *PMPI_Bcast(1600)..................: MPI_Bcast(buf=0x1df98e0, count=18, MPI_BYTE, root=0, comm=0x84000006) + *failed MPIR_Bcast_impl(1452).............: MPIR_Bcast(1476)..................: + *MPIR_Bcast_intra(1249)............: + *MPIR_SMP_Bcast(1088)..............: + *MPIR_Bcast_binomial(239)..........: + *MPIDI_CH3U_Receive_data_found(131): Message from rank 0 and tag 2 truncated; 2616 bytes received but buffer + *size is 18 major: Internal error (too specific to document in detail) minor: MPI Error String + * + */ +void +test_multi_chunk_io_addrmap_issue(void) +{ + const char *filename; + hsize_t start[MULTI_CHUNK_IO_ADDRMAP_ISSUE_DIMS]; + hsize_t stride[MULTI_CHUNK_IO_ADDRMAP_ISSUE_DIMS]; + hsize_t count[MULTI_CHUNK_IO_ADDRMAP_ISSUE_DIMS]; + hsize_t block[MULTI_CHUNK_IO_ADDRMAP_ISSUE_DIMS]; + hsize_t dims[MULTI_CHUNK_IO_ADDRMAP_ISSUE_DIMS] = {10, 5}; + hsize_t chunk_dims[MULTI_CHUNK_IO_ADDRMAP_ISSUE_DIMS] = {5, 5}; + hsize_t max_dims[MULTI_CHUNK_IO_ADDRMAP_ISSUE_DIMS] = {H5S_UNLIMITED, H5S_UNLIMITED}; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dcpl_id = H5I_INVALID_HID; + hid_t dxpl_id = H5I_INVALID_HID; + hid_t space_id = H5I_INVALID_HID; + void *read_buf = NULL; + int mpi_rank; + int data[5][5] = {{0, 1, 2, 3, 4}, {0, 1, 2, 3, 4}, {0, 1, 2, 3, 4}, {0, 1, 2, 3, 4}, {0, 1, 2, 3, 4}}; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, dataset or file flush aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + filename = PARATESTFILE /* GetTestParameters() */; + + fapl_id = create_faccess_plist(MPI_COMM_WORLD, MPI_INFO_NULL, facc_type); + VRFY((fapl_id >= 0), "create_faccess_plist succeeded"); + + /* + * Even though the testphdf5 framework currently sets collective metadata reads + * on the FAPL, we call it here just to be sure this is futureproof, since + * demonstrating this issue relies upon it. + */ + VRFY((H5Pset_all_coll_metadata_ops(fapl_id, true) >= 0), "Set collective metadata reads succeeded"); + + file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id); + VRFY((file_id >= 0), "H5Fcreate succeeded"); + + space_id = H5Screate_simple(MULTI_CHUNK_IO_ADDRMAP_ISSUE_DIMS, dims, max_dims); + VRFY((space_id >= 0), "H5Screate_simple succeeded"); + + dcpl_id = H5Pcreate(H5P_DATASET_CREATE); + VRFY((dcpl_id >= 0), "H5Pcreate succeeded"); + + VRFY((H5Pset_chunk(dcpl_id, MULTI_CHUNK_IO_ADDRMAP_ISSUE_DIMS, chunk_dims) >= 0), + "H5Pset_chunk succeeded"); + + dset_id = H5Dcreate2(file_id, "dset", H5T_NATIVE_INT, space_id, H5P_DEFAULT, dcpl_id, H5P_DEFAULT); + VRFY((dset_id >= 0), "H5Dcreate2 succeeded"); + + dxpl_id = H5Pcreate(H5P_DATASET_XFER); + VRFY((dxpl_id >= 0), "H5Pcreate succeeded"); + + VRFY((H5Pset_dxpl_mpio(dxpl_id, H5FD_MPIO_COLLECTIVE) >= 0), "H5Pset_dxpl_mpio succeeded"); + VRFY((H5Pset_dxpl_mpio_chunk_opt(dxpl_id, H5FD_MPIO_CHUNK_MULTI_IO) >= 0), + "H5Pset_dxpl_mpio_chunk_opt succeeded"); + + start[1] = 0; + stride[0] = stride[1] = 1; + count[0] = count[1] = 5; + block[0] = block[1] = 1; + + if (mpi_rank == 0) + start[0] = 0; + else + start[0] = 5; + + VRFY((H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start, stride, count, block) >= 0), + "H5Sselect_hyperslab succeeded"); + if (mpi_rank != 0) + VRFY((H5Sselect_none(space_id) >= 0), "H5Sselect_none succeeded"); + + VRFY((H5Dwrite(dset_id, H5T_NATIVE_INT, H5S_ALL, space_id, dxpl_id, data) >= 0), "H5Dwrite succeeded"); + + VRFY((H5Fflush(file_id, H5F_SCOPE_GLOBAL) >= 0), "H5Fflush succeeded"); + + read_buf = HDmalloc(50 * sizeof(int)); + VRFY((read_buf != NULL), "malloc succeeded"); + + VRFY((H5Dread(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, dxpl_id, read_buf) >= 0), "H5Dread succeeded"); + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + VRFY((H5Sclose(space_id) >= 0), "H5Sclose succeeded"); + VRFY((H5Pclose(dcpl_id) >= 0), "H5Pclose succeeded"); + VRFY((H5Pclose(dxpl_id) >= 0), "H5Pclose succeeded"); + VRFY((H5Dclose(dset_id) >= 0), "H5Dclose succeeded"); + VRFY((H5Pclose(fapl_id) >= 0), "H5Pclose succeeded"); + VRFY((H5Fclose(file_id) >= 0), "H5Fclose succeeded"); +} + +/* + * A test for HDFFV-10562 which attempts to verify that using linked-chunk + * I/O with collective metadata reads enabled doesn't cause issues due to + * collective metadata reads being made only by process 0 in H5D__sort_chunk(). + * + * NOTE: Due to the way that the threshold value which pertains to this test + * is currently calculated within HDF5, the following two conditions must be + * true to trigger the issue: + * + * Condition 1: A certain threshold ratio must be met in order to have HDF5 + * obtain all chunk addresses collectively inside H5D__sort_chunk(). This is + * given by the following: + * + * (sum_chunk * 100) / (dataset_nchunks * mpi_size) >= 30% + * + * where: + * * `sum_chunk` is the combined sum of the number of chunks selected in + * the dataset by all ranks (chunks selected by more than one rank count + * individually toward the sum for each rank selecting that chunk) + * * `dataset_nchunks` is the number of chunks in the dataset (selected + * or not) + * * `mpi_size` is the size of the MPI Communicator + * + * Condition 2: `sum_chunk` divided by `mpi_size` must exceed or equal a certain + * threshold (as of this writing, 10000). + * + * To satisfy both these conditions, we #define a macro, + * LINK_CHUNK_IO_SORT_CHUNK_ISSUE_COLL_THRESH_NUM, which corresponds to the + * value of the H5D_ALL_CHUNK_ADDR_THRES_COL_NUM macro in H5Dmpio.c (the + * 10000 threshold from condition 2). We then create a dataset of that many + * chunks and have each MPI rank write to and read from a piece of every single + * chunk in the dataset. This ensures chunk utilization is the max possible + * and exceeds our 30% target ratio, while always exactly matching the numeric + * chunk threshold value of condition 2. + * + * Failure in this test may either cause a hang, or, due to how the MPI calls + * pertaining to this issue might mistakenly match up, may cause an MPI error + * message similar to: + * + * #008: H5Dmpio.c line 2338 in H5D__sort_chunk(): MPI_BCast failed + * major: Internal error (too specific to document in detail) + * minor: Some MPI function failed + * #009: H5Dmpio.c line 2338 in H5D__sort_chunk(): Other MPI error, error stack: + *PMPI_Bcast(1600)........: MPI_Bcast(buf=0x7eae610, count=320000, MPI_BYTE, root=0, comm=0x84000006) failed + *MPIR_Bcast_impl(1452)...: + *MPIR_Bcast(1476)........: + *MPIR_Bcast_intra(1249)..: + *MPIR_SMP_Bcast(1088)....: + *MPIR_Bcast_binomial(250): message sizes do not match across processes in the collective routine: Received + *2096 but expected 320000 major: Internal error (too specific to document in detail) minor: MPI Error String + */ +void +test_link_chunk_io_sort_chunk_issue(void) +{ + const char *filename; + hsize_t dataset_dims[LINK_CHUNK_IO_SORT_CHUNK_ISSUE_DIMS]; + hsize_t sel_dims[LINK_CHUNK_IO_SORT_CHUNK_ISSUE_DIMS]; + hsize_t chunk_dims[LINK_CHUNK_IO_SORT_CHUNK_ISSUE_DIMS]; + hsize_t start[LINK_CHUNK_IO_SORT_CHUNK_ISSUE_DIMS]; + hsize_t stride[LINK_CHUNK_IO_SORT_CHUNK_ISSUE_DIMS]; + hsize_t count[LINK_CHUNK_IO_SORT_CHUNK_ISSUE_DIMS]; + hsize_t block[LINK_CHUNK_IO_SORT_CHUNK_ISSUE_DIMS]; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t dset_id = H5I_INVALID_HID; + hid_t dcpl_id = H5I_INVALID_HID; + hid_t dxpl_id = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hid_t mspace_id = H5I_INVALID_HID; + int mpi_rank, mpi_size; + void *data = NULL; + void *read_buf = NULL; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, dataset or file flush aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + filename = PARATESTFILE /* GetTestParameters() */; + + fapl_id = create_faccess_plist(MPI_COMM_WORLD, MPI_INFO_NULL, facc_type); + VRFY((fapl_id >= 0), "create_faccess_plist succeeded"); + + /* + * Even though the testphdf5 framework currently sets collective metadata reads + * on the FAPL, we call it here just to be sure this is futureproof, since + * demonstrating this issue relies upon it. + */ + VRFY((H5Pset_all_coll_metadata_ops(fapl_id, true) >= 0), "Set collective metadata reads succeeded"); + + file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id); + VRFY((file_id >= 0), "H5Fcreate succeeded"); + + /* + * Create a one-dimensional dataset of exactly LINK_CHUNK_IO_SORT_CHUNK_ISSUE_COLL_THRESH_NUM + * chunks, where every rank writes to a piece of every single chunk to keep utilization high. + */ + dataset_dims[0] = (hsize_t)mpi_size * (hsize_t)LINK_CHUNK_IO_SORT_CHUNK_ISSUE_COLL_THRESH_NUM; + + fspace_id = H5Screate_simple(LINK_CHUNK_IO_SORT_CHUNK_ISSUE_DIMS, dataset_dims, NULL); + VRFY((fspace_id >= 0), "H5Screate_simple succeeded"); + + /* + * Set up chunking on the dataset in order to reproduce the problem. + */ + dcpl_id = H5Pcreate(H5P_DATASET_CREATE); + VRFY((dcpl_id >= 0), "H5Pcreate succeeded"); + + /* Chunk size is equal to MPI size since each rank writes to a piece of every chunk */ + chunk_dims[0] = (hsize_t)mpi_size; + + VRFY((H5Pset_chunk(dcpl_id, LINK_CHUNK_IO_SORT_CHUNK_ISSUE_DIMS, chunk_dims) >= 0), + "H5Pset_chunk succeeded"); + + dset_id = H5Dcreate2(file_id, LINK_CHUNK_IO_SORT_CHUNK_ISSUE_DATASET_NAME, H5T_NATIVE_INT, fspace_id, + H5P_DEFAULT, dcpl_id, H5P_DEFAULT); + VRFY((dset_id >= 0), "H5Dcreate2 succeeded"); + + /* + * Setup hyperslab selection to split the dataset among the ranks. + */ + start[0] = (hsize_t)mpi_rank; + stride[0] = (hsize_t)mpi_size; + count[0] = LINK_CHUNK_IO_SORT_CHUNK_ISSUE_COLL_THRESH_NUM; + block[0] = 1; + + VRFY((H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET, start, stride, count, block) >= 0), + "H5Sselect_hyperslab succeeded"); + + sel_dims[0] = count[0]; + + mspace_id = H5Screate_simple(1, sel_dims, NULL); + VRFY((mspace_id >= 0), "H5Screate_simple succeeded"); + + data = HDcalloc(1, count[0] * sizeof(int)); + VRFY((data != NULL), "calloc succeeded"); + + dxpl_id = H5Pcreate(H5P_DATASET_XFER); + VRFY((dxpl_id >= 0), "H5Pcreate succeeded"); + + /* + * Enable collective access for the data transfer. + */ + VRFY((H5Pset_dxpl_mpio(dxpl_id, H5FD_MPIO_COLLECTIVE) >= 0), "H5Pset_dxpl_mpio succeeded"); + + VRFY((H5Dwrite(dset_id, H5T_NATIVE_INT, mspace_id, fspace_id, dxpl_id, data) >= 0), "H5Dwrite succeeded"); + + VRFY((H5Fflush(file_id, H5F_SCOPE_GLOBAL) >= 0), "H5Fflush succeeded"); + + /* + * Ensure that linked-chunk I/O is performed since this is + * the particular code path where the issue lies and we don't + * want the library doing multi-chunk I/O behind our backs. + */ + VRFY((H5Pset_dxpl_mpio_chunk_opt(dxpl_id, H5FD_MPIO_CHUNK_ONE_IO) >= 0), + "H5Pset_dxpl_mpio_chunk_opt succeeded"); + + read_buf = HDmalloc(count[0] * sizeof(int)); + VRFY((read_buf != NULL), "malloc succeeded"); + + VRFY((H5Sselect_hyperslab(fspace_id, H5S_SELECT_SET, start, stride, count, block) >= 0), + "H5Sselect_hyperslab succeeded"); + + sel_dims[0] = count[0]; + + VRFY((H5Sclose(mspace_id) >= 0), "H5Sclose succeeded"); + + mspace_id = H5Screate_simple(1, sel_dims, NULL); + VRFY((mspace_id >= 0), "H5Screate_simple succeeded"); + + /* + * Finally have each rank read their section of data back from the dataset. + */ + VRFY((H5Dread(dset_id, H5T_NATIVE_INT, mspace_id, fspace_id, dxpl_id, read_buf) >= 0), + "H5Dread succeeded"); + + if (data) { + HDfree(data); + data = NULL; + } + + if (read_buf) { + HDfree(read_buf); + read_buf = NULL; + } + + VRFY((H5Sclose(fspace_id) >= 0), "H5Sclose succeeded"); + VRFY((H5Sclose(mspace_id) >= 0), "H5Sclose succeeded"); + VRFY((H5Pclose(dcpl_id) >= 0), "H5Pclose succeeded"); + VRFY((H5Pclose(dxpl_id) >= 0), "H5Pclose succeeded"); + VRFY((H5Dclose(dset_id) >= 0), "H5Dclose succeeded"); + VRFY((H5Pclose(fapl_id) >= 0), "H5Pclose succeeded"); + VRFY((H5Fclose(file_id) >= 0), "H5Fclose succeeded"); +} + +/* + * A test for GitHub issue #2433 which causes a collective metadata write + * of global heap data. This test is meant to ensure that global heap data + * gets correctly mapped as raw data during a collective metadata write + * using vector I/O. + * + * An assertion exists in the library that should be triggered if global + * heap data is not correctly mapped as raw data. + */ +void +test_collective_global_heap_write(void) +{ + const char *filename; + hsize_t attr_dims[COLL_GHEAP_WRITE_ATTR_DIMS]; + hid_t file_id = H5I_INVALID_HID; + hid_t fapl_id = H5I_INVALID_HID; + hid_t attr_id = H5I_INVALID_HID; + hid_t vl_type = H5I_INVALID_HID; + hid_t fspace_id = H5I_INVALID_HID; + hvl_t vl_data; + int mpi_rank, mpi_size; + int data_buf[COLL_GHEAP_WRITE_ATTR_NELEMS]; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, dataset or file flush aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + filename = PARATESTFILE /* GetTestParameters() */; + + fapl_id = create_faccess_plist(MPI_COMM_WORLD, MPI_INFO_NULL, facc_type); + VRFY((fapl_id >= 0), "create_faccess_plist succeeded"); + + /* + * Even though the testphdf5 framework currently sets collective metadata + * writes on the FAPL, we call it here just to be sure this is futureproof, + * since demonstrating this issue relies upon it. + */ + VRFY((H5Pset_coll_metadata_write(fapl_id, true) >= 0), "Set collective metadata writes succeeded"); + + file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id); + VRFY((file_id >= 0), "H5Fcreate succeeded"); + + attr_dims[0] = 1; + + fspace_id = H5Screate_simple(COLL_GHEAP_WRITE_ATTR_DIMS, attr_dims, NULL); + VRFY((fspace_id >= 0), "H5Screate_simple succeeded"); + + vl_type = H5Tvlen_create(H5T_NATIVE_INT); + VRFY((vl_type >= 0), "H5Tvlen_create succeeded"); + + vl_data.len = COLL_GHEAP_WRITE_ATTR_NELEMS; + vl_data.p = data_buf; + + /* + * Create a variable-length attribute that will get written to the global heap + */ + attr_id = H5Acreate2(file_id, COLL_GHEAP_WRITE_ATTR_NAME, vl_type, fspace_id, H5P_DEFAULT, H5P_DEFAULT); + VRFY((attr_id >= 0), "H5Acreate2 succeeded"); + + for (size_t i = 0; i < COLL_GHEAP_WRITE_ATTR_NELEMS; i++) + data_buf[i] = (int)i; + + VRFY((H5Awrite(attr_id, vl_type, &vl_data) >= 0), "H5Awrite succeeded"); + + VRFY((H5Sclose(fspace_id) >= 0), "H5Sclose succeeded"); + VRFY((H5Tclose(vl_type) >= 0), "H5Sclose succeeded"); + VRFY((H5Aclose(attr_id) >= 0), "H5Aclose succeeded"); + VRFY((H5Pclose(fapl_id) >= 0), "H5Pclose succeeded"); + VRFY((H5Fclose(file_id) >= 0), "H5Fclose succeeded"); +} diff --git a/testpar/API/t_dset.c b/testpar/API/t_dset.c new file mode 100644 index 0000000..d005243 --- /dev/null +++ b/testpar/API/t_dset.c @@ -0,0 +1,4335 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Parallel tests for datasets + */ + +/* + * Example of using the parallel HDF5 library to access datasets. + * + * This program contains three major parts. Part 1 tests fixed dimension + * datasets, for both independent and collective transfer modes. + * Part 2 tests extendible datasets, for independent transfer mode + * only. + * Part 3 tests extendible datasets, for collective transfer mode + * only. + */ + +#include "hdf5.h" +#include "testphdf5.h" + +/* + * The following are various utility routines used by the tests. + */ + +/* + * Setup the dimensions of the hyperslab. + * Two modes--by rows or by columns. + * Assume dimension rank is 2. + * BYROW divide into slabs of rows + * BYCOL divide into blocks of columns + * ZROW same as BYROW except process 0 gets 0 rows + * ZCOL same as BYCOL except process 0 gets 0 columns + */ +static void +slab_set(int mpi_rank, int mpi_size, hsize_t start[], hsize_t count[], hsize_t stride[], hsize_t block[], + int mode) +{ + switch (mode) { + case BYROW: + /* Each process takes a slabs of rows. */ + block[0] = (hsize_t)(dim0 / mpi_size); + block[1] = (hsize_t)dim1; + stride[0] = block[0]; + stride[1] = block[1]; + count[0] = 1; + count[1] = 1; + start[0] = (hsize_t)mpi_rank * block[0]; + start[1] = 0; + if (VERBOSE_MED) + HDprintf("slab_set BYROW\n"); + break; + case BYCOL: + /* Each process takes a block of columns. */ + block[0] = (hsize_t)dim0; + block[1] = (hsize_t)(dim1 / mpi_size); + stride[0] = block[0]; + stride[1] = block[1]; + count[0] = 1; + count[1] = 1; + start[0] = 0; + start[1] = (hsize_t)mpi_rank * block[1]; + if (VERBOSE_MED) + HDprintf("slab_set BYCOL\n"); + break; + case ZROW: + /* Similar to BYROW except process 0 gets 0 row */ + block[0] = (hsize_t)(mpi_rank ? dim0 / mpi_size : 0); + block[1] = (hsize_t)dim1; + stride[0] = (mpi_rank ? block[0] : 1); /* avoid setting stride to 0 */ + stride[1] = block[1]; + count[0] = 1; + count[1] = 1; + start[0] = (mpi_rank ? (hsize_t)mpi_rank * block[0] : 0); + start[1] = 0; + if (VERBOSE_MED) + HDprintf("slab_set ZROW\n"); + break; + case ZCOL: + /* Similar to BYCOL except process 0 gets 0 column */ + block[0] = (hsize_t)dim0; + block[1] = (hsize_t)(mpi_rank ? dim1 / mpi_size : 0); + stride[0] = block[0]; + stride[1] = (hsize_t)(mpi_rank ? block[1] : 1); /* avoid setting stride to 0 */ + count[0] = 1; + count[1] = 1; + start[0] = 0; + start[1] = (mpi_rank ? (hsize_t)mpi_rank * block[1] : 0); + if (VERBOSE_MED) + HDprintf("slab_set ZCOL\n"); + break; + default: + /* Unknown mode. Set it to cover the whole dataset. */ + HDprintf("unknown slab_set mode (%d)\n", mode); + block[0] = (hsize_t)dim0; + block[1] = (hsize_t)dim1; + stride[0] = block[0]; + stride[1] = block[1]; + count[0] = 1; + count[1] = 1; + start[0] = 0; + start[1] = 0; + if (VERBOSE_MED) + HDprintf("slab_set wholeset\n"); + break; + } + if (VERBOSE_MED) { + HDprintf("start[]=(%lu,%lu), count[]=(%lu,%lu), stride[]=(%lu,%lu), block[]=(%lu,%lu), total " + "datapoints=%lu\n", + (unsigned long)start[0], (unsigned long)start[1], (unsigned long)count[0], + (unsigned long)count[1], (unsigned long)stride[0], (unsigned long)stride[1], + (unsigned long)block[0], (unsigned long)block[1], + (unsigned long)(block[0] * block[1] * count[0] * count[1])); + } +} + +/* + * Setup the coordinates for point selection. + */ +void +point_set(hsize_t start[], hsize_t count[], hsize_t stride[], hsize_t block[], size_t num_points, + hsize_t coords[], int order) +{ + hsize_t i, j, k = 0, m, n, s1, s2; + + HDcompile_assert(RANK == 2); + + if (OUT_OF_ORDER == order) + k = (num_points * RANK) - 1; + else if (IN_ORDER == order) + k = 0; + + s1 = start[0]; + s2 = start[1]; + + for (i = 0; i < count[0]; i++) + for (j = 0; j < count[1]; j++) + for (m = 0; m < block[0]; m++) + for (n = 0; n < block[1]; n++) + if (OUT_OF_ORDER == order) { + coords[k--] = s2 + (stride[1] * j) + n; + coords[k--] = s1 + (stride[0] * i) + m; + } + else if (IN_ORDER == order) { + coords[k++] = s1 + stride[0] * i + m; + coords[k++] = s2 + stride[1] * j + n; + } + + if (VERBOSE_MED) { + HDprintf("start[]=(%lu, %lu), count[]=(%lu, %lu), stride[]=(%lu, %lu), block[]=(%lu, %lu), total " + "datapoints=%lu\n", + (unsigned long)start[0], (unsigned long)start[1], (unsigned long)count[0], + (unsigned long)count[1], (unsigned long)stride[0], (unsigned long)stride[1], + (unsigned long)block[0], (unsigned long)block[1], + (unsigned long)(block[0] * block[1] * count[0] * count[1])); + k = 0; + for (i = 0; i < num_points; i++) { + HDprintf("(%d, %d)\n", (int)coords[k], (int)coords[k + 1]); + k += 2; + } + } +} + +/* + * Fill the dataset with trivial data for testing. + * Assume dimension rank is 2 and data is stored contiguous. + */ +static void +dataset_fill(hsize_t start[], hsize_t block[], DATATYPE *dataset) +{ + DATATYPE *dataptr = dataset; + hsize_t i, j; + + /* put some trivial data in the data_array */ + for (i = 0; i < block[0]; i++) { + for (j = 0; j < block[1]; j++) { + *dataptr = (DATATYPE)((i + start[0]) * 100 + (j + start[1] + 1)); + dataptr++; + } + } +} + +/* + * Print the content of the dataset. + */ +static void +dataset_print(hsize_t start[], hsize_t block[], DATATYPE *dataset) +{ + DATATYPE *dataptr = dataset; + hsize_t i, j; + + /* print the column heading */ + HDprintf("%-8s", "Cols:"); + for (j = 0; j < block[1]; j++) { + HDprintf("%3lu ", (unsigned long)(start[1] + j)); + } + HDprintf("\n"); + + /* print the slab data */ + for (i = 0; i < block[0]; i++) { + HDprintf("Row %2lu: ", (unsigned long)(i + start[0])); + for (j = 0; j < block[1]; j++) { + HDprintf("%03d ", *dataptr++); + } + HDprintf("\n"); + } +} + +/* + * Print the content of the dataset. + */ +int +dataset_vrfy(hsize_t start[], hsize_t count[], hsize_t stride[], hsize_t block[], DATATYPE *dataset, + DATATYPE *original) +{ + hsize_t i, j; + int vrfyerrs; + + /* print it if VERBOSE_MED */ + if (VERBOSE_MED) { + HDprintf("dataset_vrfy dumping:::\n"); + HDprintf("start(%lu, %lu), count(%lu, %lu), stride(%lu, %lu), block(%lu, %lu)\n", + (unsigned long)start[0], (unsigned long)start[1], (unsigned long)count[0], + (unsigned long)count[1], (unsigned long)stride[0], (unsigned long)stride[1], + (unsigned long)block[0], (unsigned long)block[1]); + HDprintf("original values:\n"); + dataset_print(start, block, original); + HDprintf("compared values:\n"); + dataset_print(start, block, dataset); + } + + vrfyerrs = 0; + for (i = 0; i < block[0]; i++) { + for (j = 0; j < block[1]; j++) { + if (*dataset != *original) { + if (vrfyerrs++ < MAX_ERR_REPORT || VERBOSE_MED) { + HDprintf("Dataset Verify failed at [%lu][%lu](row %lu, col %lu): expect %d, got %d\n", + (unsigned long)i, (unsigned long)j, (unsigned long)(i + start[0]), + (unsigned long)(j + start[1]), *(original), *(dataset)); + } + dataset++; + original++; + } + } + } + if (vrfyerrs > MAX_ERR_REPORT && !VERBOSE_MED) + HDprintf("[more errors ...]\n"); + if (vrfyerrs) + HDprintf("%d errors found in dataset_vrfy\n", vrfyerrs); + return (vrfyerrs); +} + +/* + * Part 1.a--Independent read/write for fixed dimension datasets. + */ + +/* + * Example of using the parallel HDF5 library to create two datasets + * in one HDF5 files with parallel MPIO access support. + * The Datasets are of sizes (number-of-mpi-processes x dim0) x dim1. + * Each process controls only a slab of size dim0 x dim1 within each + * dataset. + */ + +void +dataset_writeInd(void) +{ + hid_t fid; /* HDF5 file ID */ + hid_t acc_tpl; /* File access templates */ + hid_t sid; /* Dataspace ID */ + hid_t file_dataspace; /* File dataspace ID */ + hid_t mem_dataspace; /* memory dataspace ID */ + hid_t dataset1, dataset2; /* Dataset ID */ + hsize_t dims[RANK]; /* dataset dim sizes */ + DATATYPE *data_array1 = NULL; /* data buffer */ + const char *filename; + + hsize_t start[RANK]; /* for hyperslab setting */ + hsize_t count[RANK], stride[RANK]; /* for hyperslab setting */ + hsize_t block[RANK]; /* for hyperslab setting */ + + herr_t ret; /* Generic return value */ + int mpi_size, mpi_rank; + + MPI_Comm comm = MPI_COMM_WORLD; + MPI_Info info = MPI_INFO_NULL; + + filename = PARATESTFILE /* GetTestParameters() */; + if (VERBOSE_MED) + HDprintf("Independent write test on file %s\n", filename); + + /* set up MPI parameters */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, basic dataset, or more aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + /* allocate memory for data buffer */ + data_array1 = (DATATYPE *)HDmalloc((size_t)dim0 * (size_t)dim1 * sizeof(DATATYPE)); + VRFY((data_array1 != NULL), "data_array1 HDmalloc succeeded"); + + /* ---------------------------------------- + * CREATE AN HDF5 FILE WITH PARALLEL ACCESS + * ---------------------------------------*/ + /* setup file access template */ + acc_tpl = create_faccess_plist(comm, info, facc_type); + VRFY((acc_tpl >= 0), ""); + + /* create the file collectively */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, acc_tpl); + VRFY((fid >= 0), "H5Fcreate succeeded"); + + /* Release file-access template */ + ret = H5Pclose(acc_tpl); + VRFY((ret >= 0), ""); + + /* --------------------------------------------- + * Define the dimensions of the overall datasets + * and the slabs local to the MPI process. + * ------------------------------------------- */ + /* setup dimensionality object */ + dims[0] = (hsize_t)dim0; + dims[1] = (hsize_t)dim1; + sid = H5Screate_simple(RANK, dims, NULL); + VRFY((sid >= 0), "H5Screate_simple succeeded"); + + /* create a dataset collectively */ + dataset1 = H5Dcreate2(fid, DATASETNAME1, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((dataset1 >= 0), "H5Dcreate2 succeeded"); + + /* create another dataset collectively */ + dataset2 = H5Dcreate2(fid, DATASETNAME2, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((dataset2 >= 0), "H5Dcreate2 succeeded"); + + /* + * To test the independent orders of writes between processes, all + * even number processes write to dataset1 first, then dataset2. + * All odd number processes write to dataset2 first, then dataset1. + */ + + /* set up dimensions of the slab this process accesses */ + slab_set(mpi_rank, mpi_size, start, count, stride, block, BYROW); + + /* put some trivial data in the data_array */ + dataset_fill(start, block, data_array1); + MESG("data_array initialized"); + + /* create a file dataspace independently */ + file_dataspace = H5Dget_space(dataset1); + VRFY((file_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab succeeded"); + + /* create a memory dataspace independently */ + mem_dataspace = H5Screate_simple(RANK, block, NULL); + VRFY((mem_dataspace >= 0), ""); + + /* write data independently */ + ret = H5Dwrite(dataset1, H5T_NATIVE_INT, mem_dataspace, file_dataspace, H5P_DEFAULT, data_array1); + VRFY((ret >= 0), "H5Dwrite dataset1 succeeded"); + /* write data independently */ + ret = H5Dwrite(dataset2, H5T_NATIVE_INT, mem_dataspace, file_dataspace, H5P_DEFAULT, data_array1); + VRFY((ret >= 0), "H5Dwrite dataset2 succeeded"); + + /* setup dimensions again to write with zero rows for process 0 */ + if (VERBOSE_MED) + HDprintf("writeInd by some with zero row\n"); + slab_set(mpi_rank, mpi_size, start, count, stride, block, ZROW); + ret = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab succeeded"); + /* need to make mem_dataspace to match for process 0 */ + if (MAINPROCESS) { + ret = H5Sselect_hyperslab(mem_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab mem_dataspace succeeded"); + } + MESG("writeInd by some with zero row"); + if ((mpi_rank / 2) * 2 != mpi_rank) { + ret = H5Dwrite(dataset1, H5T_NATIVE_INT, mem_dataspace, file_dataspace, H5P_DEFAULT, data_array1); + VRFY((ret >= 0), "H5Dwrite dataset1 by ZROW succeeded"); + } +#ifdef BARRIER_CHECKS + MPI_Barrier(MPI_COMM_WORLD); +#endif /* BARRIER_CHECKS */ + + /* release dataspace ID */ + H5Sclose(file_dataspace); + + /* close dataset collectively */ + ret = H5Dclose(dataset1); + VRFY((ret >= 0), "H5Dclose1 succeeded"); + ret = H5Dclose(dataset2); + VRFY((ret >= 0), "H5Dclose2 succeeded"); + + /* release all IDs created */ + H5Sclose(sid); + + /* close the file collectively */ + H5Fclose(fid); + + /* release data buffers */ + if (data_array1) + HDfree(data_array1); +} + +/* Example of using the parallel HDF5 library to read a dataset */ +void +dataset_readInd(void) +{ + hid_t fid; /* HDF5 file ID */ + hid_t acc_tpl; /* File access templates */ + hid_t file_dataspace; /* File dataspace ID */ + hid_t mem_dataspace; /* memory dataspace ID */ + hid_t dataset1, dataset2; /* Dataset ID */ + DATATYPE *data_array1 = NULL; /* data buffer */ + DATATYPE *data_origin1 = NULL; /* expected data buffer */ + const char *filename; + + hsize_t start[RANK]; /* for hyperslab setting */ + hsize_t count[RANK], stride[RANK]; /* for hyperslab setting */ + hsize_t block[RANK]; /* for hyperslab setting */ + + herr_t ret; /* Generic return value */ + int mpi_size, mpi_rank; + + MPI_Comm comm = MPI_COMM_WORLD; + MPI_Info info = MPI_INFO_NULL; + + filename = PARATESTFILE /* GetTestParameters() */; + if (VERBOSE_MED) + HDprintf("Independent read test on file %s\n", filename); + + /* set up MPI parameters */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, basic dataset, or more aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + /* allocate memory for data buffer */ + data_array1 = (DATATYPE *)HDmalloc((size_t)dim0 * (size_t)dim1 * sizeof(DATATYPE)); + VRFY((data_array1 != NULL), "data_array1 HDmalloc succeeded"); + data_origin1 = (DATATYPE *)HDmalloc((size_t)dim0 * (size_t)dim1 * sizeof(DATATYPE)); + VRFY((data_origin1 != NULL), "data_origin1 HDmalloc succeeded"); + + /* setup file access template */ + acc_tpl = create_faccess_plist(comm, info, facc_type); + VRFY((acc_tpl >= 0), ""); + + /* open the file collectively */ + fid = H5Fopen(filename, H5F_ACC_RDONLY, acc_tpl); + VRFY((fid >= 0), ""); + + /* Release file-access template */ + ret = H5Pclose(acc_tpl); + VRFY((ret >= 0), ""); + + /* open the dataset1 collectively */ + dataset1 = H5Dopen2(fid, DATASETNAME1, H5P_DEFAULT); + VRFY((dataset1 >= 0), ""); + + /* open another dataset collectively */ + dataset2 = H5Dopen2(fid, DATASETNAME1, H5P_DEFAULT); + VRFY((dataset2 >= 0), ""); + + /* set up dimensions of the slab this process accesses */ + slab_set(mpi_rank, mpi_size, start, count, stride, block, BYROW); + + /* create a file dataspace independently */ + file_dataspace = H5Dget_space(dataset1); + VRFY((file_dataspace >= 0), ""); + ret = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), ""); + + /* create a memory dataspace independently */ + mem_dataspace = H5Screate_simple(RANK, block, NULL); + VRFY((mem_dataspace >= 0), ""); + + /* fill dataset with test data */ + dataset_fill(start, block, data_origin1); + + /* read data independently */ + ret = H5Dread(dataset1, H5T_NATIVE_INT, mem_dataspace, file_dataspace, H5P_DEFAULT, data_array1); + VRFY((ret >= 0), ""); + + /* verify the read data with original expected data */ + ret = dataset_vrfy(start, count, stride, block, data_array1, data_origin1); + if (ret) + nerrors++; + + /* read data independently */ + ret = H5Dread(dataset2, H5T_NATIVE_INT, mem_dataspace, file_dataspace, H5P_DEFAULT, data_array1); + VRFY((ret >= 0), ""); + + /* verify the read data with original expected data */ + ret = dataset_vrfy(start, count, stride, block, data_array1, data_origin1); + if (ret) + nerrors++; + + /* close dataset collectively */ + ret = H5Dclose(dataset1); + VRFY((ret >= 0), ""); + ret = H5Dclose(dataset2); + VRFY((ret >= 0), ""); + + /* release all IDs created */ + H5Sclose(file_dataspace); + + /* close the file collectively */ + H5Fclose(fid); + + /* release data buffers */ + if (data_array1) + HDfree(data_array1); + if (data_origin1) + HDfree(data_origin1); +} + +/* + * Part 1.b--Collective read/write for fixed dimension datasets. + */ + +/* + * Example of using the parallel HDF5 library to create two datasets + * in one HDF5 file with collective parallel access support. + * The Datasets are of sizes (number-of-mpi-processes x dim0) x dim1. + * Each process controls only a slab of size dim0 x dim1 within each + * dataset. [Note: not so yet. Datasets are of sizes dim0xdim1 and + * each process controls a hyperslab within.] + */ + +void +dataset_writeAll(void) +{ + hid_t fid; /* HDF5 file ID */ + hid_t acc_tpl; /* File access templates */ + hid_t xfer_plist; /* Dataset transfer properties list */ + hid_t sid; /* Dataspace ID */ + hid_t file_dataspace; /* File dataspace ID */ + hid_t mem_dataspace; /* memory dataspace ID */ + hid_t dataset1, dataset2, dataset3, dataset4; /* Dataset ID */ + hid_t dataset5, dataset6, dataset7; /* Dataset ID */ + hid_t datatype; /* Datatype ID */ + hsize_t dims[RANK]; /* dataset dim sizes */ + DATATYPE *data_array1 = NULL; /* data buffer */ + const char *filename; + + hsize_t start[RANK]; /* for hyperslab setting */ + hsize_t count[RANK], stride[RANK]; /* for hyperslab setting */ + hsize_t block[RANK]; /* for hyperslab setting */ + + size_t num_points; /* for point selection */ + hsize_t *coords = NULL; /* for point selection */ + hsize_t current_dims; /* for point selection */ + + herr_t ret; /* Generic return value */ + int mpi_size, mpi_rank; + + MPI_Comm comm = MPI_COMM_WORLD; + MPI_Info info = MPI_INFO_NULL; + + filename = PARATESTFILE /* GetTestParameters() */; + if (VERBOSE_MED) + HDprintf("Collective write test on file %s\n", filename); + + /* set up MPI parameters */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, basic dataset, or more aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + /* set up the coords array selection */ + num_points = (size_t)dim1; + coords = (hsize_t *)HDmalloc((size_t)dim1 * (size_t)RANK * sizeof(hsize_t)); + VRFY((coords != NULL), "coords malloc succeeded"); + + /* allocate memory for data buffer */ + data_array1 = (DATATYPE *)HDmalloc((size_t)dim0 * (size_t)dim1 * sizeof(DATATYPE)); + VRFY((data_array1 != NULL), "data_array1 HDmalloc succeeded"); + + /* ------------------- + * START AN HDF5 FILE + * -------------------*/ + /* setup file access template */ + acc_tpl = create_faccess_plist(comm, info, facc_type); + VRFY((acc_tpl >= 0), ""); + + /* create the file collectively */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, acc_tpl); + VRFY((fid >= 0), "H5Fcreate succeeded"); + + /* Release file-access template */ + ret = H5Pclose(acc_tpl); + VRFY((ret >= 0), ""); + + /* -------------------------- + * Define the dimensions of the overall datasets + * and create the dataset + * ------------------------- */ + /* setup 2-D dimensionality object */ + dims[0] = (hsize_t)dim0; + dims[1] = (hsize_t)dim1; + sid = H5Screate_simple(RANK, dims, NULL); + VRFY((sid >= 0), "H5Screate_simple succeeded"); + + /* create a dataset collectively */ + dataset1 = H5Dcreate2(fid, DATASETNAME1, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((dataset1 >= 0), "H5Dcreate2 succeeded"); + + /* create another dataset collectively */ + datatype = H5Tcopy(H5T_NATIVE_INT); + ret = H5Tset_order(datatype, H5T_ORDER_LE); + VRFY((ret >= 0), "H5Tset_order succeeded"); + + dataset2 = H5Dcreate2(fid, DATASETNAME2, datatype, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((dataset2 >= 0), "H5Dcreate2 2 succeeded"); + + /* create a third dataset collectively */ + dataset3 = H5Dcreate2(fid, DATASETNAME3, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((dataset3 >= 0), "H5Dcreate2 succeeded"); + + dataset5 = H5Dcreate2(fid, DATASETNAME7, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((dataset5 >= 0), "H5Dcreate2 succeeded"); + dataset6 = H5Dcreate2(fid, DATASETNAME8, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((dataset6 >= 0), "H5Dcreate2 succeeded"); + dataset7 = H5Dcreate2(fid, DATASETNAME9, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((dataset7 >= 0), "H5Dcreate2 succeeded"); + + /* release 2-D space ID created */ + H5Sclose(sid); + + /* setup scalar dimensionality object */ + sid = H5Screate(H5S_SCALAR); + VRFY((sid >= 0), "H5Screate succeeded"); + + /* create a fourth dataset collectively */ + dataset4 = H5Dcreate2(fid, DATASETNAME4, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((dataset4 >= 0), "H5Dcreate2 succeeded"); + + /* release scalar space ID created */ + H5Sclose(sid); + + /* + * Set up dimensions of the slab this process accesses. + */ + + /* Dataset1: each process takes a block of rows. */ + slab_set(mpi_rank, mpi_size, start, count, stride, block, BYROW); + + /* create a file dataspace independently */ + file_dataspace = H5Dget_space(dataset1); + VRFY((file_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab succeeded"); + + /* create a memory dataspace independently */ + mem_dataspace = H5Screate_simple(RANK, block, NULL); + VRFY((mem_dataspace >= 0), ""); + + /* fill the local slab with some trivial data */ + dataset_fill(start, block, data_array1); + MESG("data_array initialized"); + if (VERBOSE_MED) { + MESG("data_array created"); + dataset_print(start, block, data_array1); + } + + /* set up the collective transfer properties list */ + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY((xfer_plist >= 0), "H5Pcreate xfer succeeded"); + ret = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(xfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY((ret >= 0), "set independent IO collectively succeeded"); + } + + /* write data collectively */ + MESG("writeAll by Row"); + ret = H5Dwrite(dataset1, H5T_NATIVE_INT, mem_dataspace, file_dataspace, xfer_plist, data_array1); + VRFY((ret >= 0), "H5Dwrite dataset1 succeeded"); + + /* setup dimensions again to writeAll with zero rows for process 0 */ + if (VERBOSE_MED) + HDprintf("writeAll by some with zero row\n"); + slab_set(mpi_rank, mpi_size, start, count, stride, block, ZROW); + ret = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab succeeded"); + /* need to make mem_dataspace to match for process 0 */ + if (MAINPROCESS) { + ret = H5Sselect_hyperslab(mem_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab mem_dataspace succeeded"); + } + MESG("writeAll by some with zero row"); + ret = H5Dwrite(dataset1, H5T_NATIVE_INT, mem_dataspace, file_dataspace, xfer_plist, data_array1); + VRFY((ret >= 0), "H5Dwrite dataset1 by ZROW succeeded"); + + /* release all temporary handles. */ + /* Could have used them for dataset2 but it is cleaner */ + /* to create them again.*/ + H5Sclose(file_dataspace); + H5Sclose(mem_dataspace); + H5Pclose(xfer_plist); + + /* Dataset2: each process takes a block of columns. */ + slab_set(mpi_rank, mpi_size, start, count, stride, block, BYCOL); + + /* put some trivial data in the data_array */ + dataset_fill(start, block, data_array1); + MESG("data_array initialized"); + if (VERBOSE_MED) { + MESG("data_array created"); + dataset_print(start, block, data_array1); + } + + /* create a file dataspace independently */ + file_dataspace = H5Dget_space(dataset1); + VRFY((file_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab succeeded"); + + /* create a memory dataspace independently */ + mem_dataspace = H5Screate_simple(RANK, block, NULL); + VRFY((mem_dataspace >= 0), ""); + + /* fill the local slab with some trivial data */ + dataset_fill(start, block, data_array1); + MESG("data_array initialized"); + if (VERBOSE_MED) { + MESG("data_array created"); + dataset_print(start, block, data_array1); + } + + /* set up the collective transfer properties list */ + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY((xfer_plist >= 0), ""); + ret = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pcreate xfer succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(xfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY((ret >= 0), "set independent IO collectively succeeded"); + } + + /* write data independently */ + ret = H5Dwrite(dataset2, H5T_NATIVE_INT, mem_dataspace, file_dataspace, xfer_plist, data_array1); + VRFY((ret >= 0), "H5Dwrite dataset2 succeeded"); + + /* setup dimensions again to writeAll with zero columns for process 0 */ + if (VERBOSE_MED) + HDprintf("writeAll by some with zero col\n"); + slab_set(mpi_rank, mpi_size, start, count, stride, block, ZCOL); + ret = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab succeeded"); + /* need to make mem_dataspace to match for process 0 */ + if (MAINPROCESS) { + ret = H5Sselect_hyperslab(mem_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab mem_dataspace succeeded"); + } + MESG("writeAll by some with zero col"); + ret = H5Dwrite(dataset1, H5T_NATIVE_INT, mem_dataspace, file_dataspace, xfer_plist, data_array1); + VRFY((ret >= 0), "H5Dwrite dataset1 by ZCOL succeeded"); + + /* release all temporary handles. */ + /* Could have used them for dataset3 but it is cleaner */ + /* to create them again.*/ + H5Sclose(file_dataspace); + H5Sclose(mem_dataspace); + H5Pclose(xfer_plist); + + /* Dataset3: each process takes a block of rows, except process zero uses "none" selection. */ + slab_set(mpi_rank, mpi_size, start, count, stride, block, BYROW); + + /* create a file dataspace independently */ + file_dataspace = H5Dget_space(dataset3); + VRFY((file_dataspace >= 0), "H5Dget_space succeeded"); + if (MAINPROCESS) { + ret = H5Sselect_none(file_dataspace); + VRFY((ret >= 0), "H5Sselect_none file_dataspace succeeded"); + } /* end if */ + else { + ret = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sselect_hyperslab succeeded"); + } /* end else */ + + /* create a memory dataspace independently */ + mem_dataspace = H5Screate_simple(RANK, block, NULL); + VRFY((mem_dataspace >= 0), ""); + if (MAINPROCESS) { + ret = H5Sselect_none(mem_dataspace); + VRFY((ret >= 0), "H5Sselect_none mem_dataspace succeeded"); + } /* end if */ + + /* fill the local slab with some trivial data */ + dataset_fill(start, block, data_array1); + MESG("data_array initialized"); + if (VERBOSE_MED) { + MESG("data_array created"); + dataset_print(start, block, data_array1); + } /* end if */ + + /* set up the collective transfer properties list */ + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY((xfer_plist >= 0), ""); + ret = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pcreate xfer succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(xfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY((ret >= 0), "set independent IO collectively succeeded"); + } + + /* write data collectively */ + MESG("writeAll with none"); + ret = H5Dwrite(dataset3, H5T_NATIVE_INT, mem_dataspace, file_dataspace, xfer_plist, data_array1); + VRFY((ret >= 0), "H5Dwrite dataset3 succeeded"); + + /* write data collectively (with datatype conversion) */ + MESG("writeAll with none"); + ret = H5Dwrite(dataset3, H5T_NATIVE_UCHAR, mem_dataspace, file_dataspace, xfer_plist, data_array1); + VRFY((ret >= 0), "H5Dwrite dataset3 succeeded"); + + /* release all temporary handles. */ + /* Could have used them for dataset4 but it is cleaner */ + /* to create them again.*/ + H5Sclose(file_dataspace); + H5Sclose(mem_dataspace); + H5Pclose(xfer_plist); + + /* Dataset4: each process writes no data, except process zero uses "all" selection. */ + /* Additionally, these are in a scalar dataspace */ + + /* create a file dataspace independently */ + file_dataspace = H5Dget_space(dataset4); + VRFY((file_dataspace >= 0), "H5Dget_space succeeded"); + if (MAINPROCESS) { + ret = H5Sselect_none(file_dataspace); + VRFY((ret >= 0), "H5Sselect_all file_dataspace succeeded"); + } /* end if */ + else { + ret = H5Sselect_all(file_dataspace); + VRFY((ret >= 0), "H5Sselect_none succeeded"); + } /* end else */ + + /* create a memory dataspace independently */ + mem_dataspace = H5Screate(H5S_SCALAR); + VRFY((mem_dataspace >= 0), ""); + if (MAINPROCESS) { + ret = H5Sselect_none(mem_dataspace); + VRFY((ret >= 0), "H5Sselect_all mem_dataspace succeeded"); + } /* end if */ + else { + ret = H5Sselect_all(mem_dataspace); + VRFY((ret >= 0), "H5Sselect_none succeeded"); + } /* end else */ + + /* fill the local slab with some trivial data */ + dataset_fill(start, block, data_array1); + MESG("data_array initialized"); + if (VERBOSE_MED) { + MESG("data_array created"); + dataset_print(start, block, data_array1); + } /* end if */ + + /* set up the collective transfer properties list */ + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY((xfer_plist >= 0), ""); + ret = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pcreate xfer succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(xfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY((ret >= 0), "set independent IO collectively succeeded"); + } + + /* write data collectively */ + MESG("writeAll with scalar dataspace"); + ret = H5Dwrite(dataset4, H5T_NATIVE_INT, mem_dataspace, file_dataspace, xfer_plist, data_array1); + VRFY((ret >= 0), "H5Dwrite dataset4 succeeded"); + + /* write data collectively (with datatype conversion) */ + MESG("writeAll with scalar dataspace"); + ret = H5Dwrite(dataset4, H5T_NATIVE_UCHAR, mem_dataspace, file_dataspace, xfer_plist, data_array1); + VRFY((ret >= 0), "H5Dwrite dataset4 succeeded"); + + /* release all temporary handles. */ + H5Sclose(file_dataspace); + H5Sclose(mem_dataspace); + H5Pclose(xfer_plist); + + if (data_array1) + free(data_array1); + data_array1 = (DATATYPE *)HDmalloc((size_t)dim0 * (size_t)dim1 * sizeof(DATATYPE)); + VRFY((data_array1 != NULL), "data_array1 malloc succeeded"); + + block[0] = 1; + block[1] = (hsize_t)dim1; + stride[0] = 1; + stride[1] = (hsize_t)dim1; + count[0] = 1; + count[1] = 1; + start[0] = (hsize_t)(dim0 / mpi_size * mpi_rank); + start[1] = 0; + + dataset_fill(start, block, data_array1); + MESG("data_array initialized"); + if (VERBOSE_MED) { + MESG("data_array created"); + dataset_print(start, block, data_array1); + } + + /* Dataset5: point selection in File - Hyperslab selection in Memory*/ + /* create a file dataspace independently */ + point_set(start, count, stride, block, num_points, coords, OUT_OF_ORDER); + file_dataspace = H5Dget_space(dataset5); + VRFY((file_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sselect_elements(file_dataspace, H5S_SELECT_SET, num_points, coords); + VRFY((ret >= 0), "H5Sselect_elements succeeded"); + + start[0] = 0; + start[1] = 0; + mem_dataspace = H5Dget_space(dataset5); + VRFY((mem_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sselect_hyperslab(mem_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab succeeded"); + + /* set up the collective transfer properties list */ + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY((xfer_plist >= 0), ""); + ret = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pcreate xfer succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(xfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY((ret >= 0), "set independent IO collectively succeeded"); + } + + /* write data collectively */ + ret = H5Dwrite(dataset5, H5T_NATIVE_INT, mem_dataspace, file_dataspace, xfer_plist, data_array1); + VRFY((ret >= 0), "H5Dwrite dataset5 succeeded"); + + /* release all temporary handles. */ + H5Sclose(file_dataspace); + H5Sclose(mem_dataspace); + H5Pclose(xfer_plist); + + /* Dataset6: point selection in File - Point selection in Memory*/ + /* create a file dataspace independently */ + start[0] = (hsize_t)(dim0 / mpi_size * mpi_rank); + start[1] = 0; + point_set(start, count, stride, block, num_points, coords, OUT_OF_ORDER); + file_dataspace = H5Dget_space(dataset6); + VRFY((file_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sselect_elements(file_dataspace, H5S_SELECT_SET, num_points, coords); + VRFY((ret >= 0), "H5Sselect_elements succeeded"); + + start[0] = 0; + start[1] = 0; + point_set(start, count, stride, block, num_points, coords, IN_ORDER); + mem_dataspace = H5Dget_space(dataset6); + VRFY((mem_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sselect_elements(mem_dataspace, H5S_SELECT_SET, num_points, coords); + VRFY((ret >= 0), "H5Sselect_elements succeeded"); + + /* set up the collective transfer properties list */ + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY((xfer_plist >= 0), ""); + ret = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pcreate xfer succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(xfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY((ret >= 0), "set independent IO collectively succeeded"); + } + + /* write data collectively */ + ret = H5Dwrite(dataset6, H5T_NATIVE_INT, mem_dataspace, file_dataspace, xfer_plist, data_array1); + VRFY((ret >= 0), "H5Dwrite dataset6 succeeded"); + + /* release all temporary handles. */ + H5Sclose(file_dataspace); + H5Sclose(mem_dataspace); + H5Pclose(xfer_plist); + + /* Dataset7: point selection in File - All selection in Memory*/ + /* create a file dataspace independently */ + start[0] = (hsize_t)(dim0 / mpi_size * mpi_rank); + start[1] = 0; + point_set(start, count, stride, block, num_points, coords, IN_ORDER); + file_dataspace = H5Dget_space(dataset7); + VRFY((file_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sselect_elements(file_dataspace, H5S_SELECT_SET, num_points, coords); + VRFY((ret >= 0), "H5Sselect_elements succeeded"); + + current_dims = num_points; + mem_dataspace = H5Screate_simple(1, ¤t_dims, NULL); + VRFY((mem_dataspace >= 0), "mem_dataspace create succeeded"); + + ret = H5Sselect_all(mem_dataspace); + VRFY((ret >= 0), "H5Sselect_all succeeded"); + + /* set up the collective transfer properties list */ + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY((xfer_plist >= 0), ""); + ret = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pcreate xfer succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(xfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY((ret >= 0), "set independent IO collectively succeeded"); + } + + /* write data collectively */ + ret = H5Dwrite(dataset7, H5T_NATIVE_INT, mem_dataspace, file_dataspace, xfer_plist, data_array1); + VRFY((ret >= 0), "H5Dwrite dataset7 succeeded"); + + /* release all temporary handles. */ + H5Sclose(file_dataspace); + H5Sclose(mem_dataspace); + H5Pclose(xfer_plist); + + /* + * All writes completed. Close datasets collectively + */ + ret = H5Dclose(dataset1); + VRFY((ret >= 0), "H5Dclose1 succeeded"); + ret = H5Dclose(dataset2); + VRFY((ret >= 0), "H5Dclose2 succeeded"); + ret = H5Dclose(dataset3); + VRFY((ret >= 0), "H5Dclose3 succeeded"); + ret = H5Dclose(dataset4); + VRFY((ret >= 0), "H5Dclose4 succeeded"); + ret = H5Dclose(dataset5); + VRFY((ret >= 0), "H5Dclose5 succeeded"); + ret = H5Dclose(dataset6); + VRFY((ret >= 0), "H5Dclose6 succeeded"); + ret = H5Dclose(dataset7); + VRFY((ret >= 0), "H5Dclose7 succeeded"); + + /* close the file collectively */ + H5Fclose(fid); + + /* release data buffers */ + if (coords) + HDfree(coords); + if (data_array1) + HDfree(data_array1); +} + +/* + * Example of using the parallel HDF5 library to read two datasets + * in one HDF5 file with collective parallel access support. + * The Datasets are of sizes (number-of-mpi-processes x dim0) x dim1. + * Each process controls only a slab of size dim0 x dim1 within each + * dataset. [Note: not so yet. Datasets are of sizes dim0xdim1 and + * each process controls a hyperslab within.] + */ + +void +dataset_readAll(void) +{ + hid_t fid; /* HDF5 file ID */ + hid_t acc_tpl; /* File access templates */ + hid_t xfer_plist; /* Dataset transfer properties list */ + hid_t file_dataspace; /* File dataspace ID */ + hid_t mem_dataspace; /* memory dataspace ID */ + hid_t dataset1, dataset2, dataset5, dataset6, dataset7; /* Dataset ID */ + DATATYPE *data_array1 = NULL; /* data buffer */ + DATATYPE *data_origin1 = NULL; /* expected data buffer */ + const char *filename; + + hsize_t start[RANK]; /* for hyperslab setting */ + hsize_t count[RANK], stride[RANK]; /* for hyperslab setting */ + hsize_t block[RANK]; /* for hyperslab setting */ + + size_t num_points; /* for point selection */ + hsize_t *coords = NULL; /* for point selection */ + int i, j, k; + + herr_t ret; /* Generic return value */ + int mpi_size, mpi_rank; + + MPI_Comm comm = MPI_COMM_WORLD; + MPI_Info info = MPI_INFO_NULL; + + filename = PARATESTFILE /* GetTestParameters() */; + if (VERBOSE_MED) + HDprintf("Collective read test on file %s\n", filename); + + /* set up MPI parameters */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, basic dataset, or more aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + /* set up the coords array selection */ + num_points = (size_t)dim1; + coords = (hsize_t *)HDmalloc((size_t)dim0 * (size_t)dim1 * RANK * sizeof(hsize_t)); + VRFY((coords != NULL), "coords malloc succeeded"); + + /* allocate memory for data buffer */ + data_array1 = (DATATYPE *)HDmalloc((size_t)dim0 * (size_t)dim1 * sizeof(DATATYPE)); + VRFY((data_array1 != NULL), "data_array1 HDmalloc succeeded"); + data_origin1 = (DATATYPE *)HDmalloc((size_t)dim0 * (size_t)dim1 * sizeof(DATATYPE)); + VRFY((data_origin1 != NULL), "data_origin1 HDmalloc succeeded"); + + /* ------------------- + * OPEN AN HDF5 FILE + * -------------------*/ + /* setup file access template */ + acc_tpl = create_faccess_plist(comm, info, facc_type); + VRFY((acc_tpl >= 0), ""); + + /* open the file collectively */ + fid = H5Fopen(filename, H5F_ACC_RDONLY, acc_tpl); + VRFY((fid >= 0), "H5Fopen succeeded"); + + /* Release file-access template */ + ret = H5Pclose(acc_tpl); + VRFY((ret >= 0), ""); + + /* -------------------------- + * Open the datasets in it + * ------------------------- */ + /* open the dataset1 collectively */ + dataset1 = H5Dopen2(fid, DATASETNAME1, H5P_DEFAULT); + VRFY((dataset1 >= 0), "H5Dopen2 succeeded"); + + /* open another dataset collectively */ + dataset2 = H5Dopen2(fid, DATASETNAME2, H5P_DEFAULT); + VRFY((dataset2 >= 0), "H5Dopen2 2 succeeded"); + + /* open another dataset collectively */ + dataset5 = H5Dopen2(fid, DATASETNAME7, H5P_DEFAULT); + VRFY((dataset5 >= 0), "H5Dopen2 5 succeeded"); + dataset6 = H5Dopen2(fid, DATASETNAME8, H5P_DEFAULT); + VRFY((dataset6 >= 0), "H5Dopen2 6 succeeded"); + dataset7 = H5Dopen2(fid, DATASETNAME9, H5P_DEFAULT); + VRFY((dataset7 >= 0), "H5Dopen2 7 succeeded"); + + /* + * Set up dimensions of the slab this process accesses. + */ + + /* Dataset1: each process takes a block of columns. */ + slab_set(mpi_rank, mpi_size, start, count, stride, block, BYCOL); + + /* create a file dataspace independently */ + file_dataspace = H5Dget_space(dataset1); + VRFY((file_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab succeeded"); + + /* create a memory dataspace independently */ + mem_dataspace = H5Screate_simple(RANK, block, NULL); + VRFY((mem_dataspace >= 0), ""); + + /* fill dataset with test data */ + dataset_fill(start, block, data_origin1); + MESG("data_array initialized"); + if (VERBOSE_MED) { + MESG("data_array created"); + dataset_print(start, block, data_origin1); + } + + /* set up the collective transfer properties list */ + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY((xfer_plist >= 0), ""); + ret = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pcreate xfer succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(xfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY((ret >= 0), "set independent IO collectively succeeded"); + } + + /* read data collectively */ + ret = H5Dread(dataset1, H5T_NATIVE_INT, mem_dataspace, file_dataspace, xfer_plist, data_array1); + VRFY((ret >= 0), "H5Dread dataset1 succeeded"); + + /* verify the read data with original expected data */ + ret = dataset_vrfy(start, count, stride, block, data_array1, data_origin1); + if (ret) + nerrors++; + + /* setup dimensions again to readAll with zero columns for process 0 */ + if (VERBOSE_MED) + HDprintf("readAll by some with zero col\n"); + slab_set(mpi_rank, mpi_size, start, count, stride, block, ZCOL); + ret = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab succeeded"); + /* need to make mem_dataspace to match for process 0 */ + if (MAINPROCESS) { + ret = H5Sselect_hyperslab(mem_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab mem_dataspace succeeded"); + } + MESG("readAll by some with zero col"); + ret = H5Dread(dataset1, H5T_NATIVE_INT, mem_dataspace, file_dataspace, xfer_plist, data_array1); + VRFY((ret >= 0), "H5Dread dataset1 by ZCOL succeeded"); + + /* verify the read data with original expected data */ + ret = dataset_vrfy(start, count, stride, block, data_array1, data_origin1); + if (ret) + nerrors++; + + /* release all temporary handles. */ + /* Could have used them for dataset2 but it is cleaner */ + /* to create them again.*/ + H5Sclose(file_dataspace); + H5Sclose(mem_dataspace); + H5Pclose(xfer_plist); + + /* Dataset2: each process takes a block of rows. */ + slab_set(mpi_rank, mpi_size, start, count, stride, block, BYROW); + + /* create a file dataspace independently */ + file_dataspace = H5Dget_space(dataset1); + VRFY((file_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab succeeded"); + + /* create a memory dataspace independently */ + mem_dataspace = H5Screate_simple(RANK, block, NULL); + VRFY((mem_dataspace >= 0), ""); + + /* fill dataset with test data */ + dataset_fill(start, block, data_origin1); + MESG("data_array initialized"); + if (VERBOSE_MED) { + MESG("data_array created"); + dataset_print(start, block, data_origin1); + } + + /* set up the collective transfer properties list */ + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY((xfer_plist >= 0), ""); + ret = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pcreate xfer succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(xfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY((ret >= 0), "set independent IO collectively succeeded"); + } + + /* read data collectively */ + ret = H5Dread(dataset2, H5T_NATIVE_INT, mem_dataspace, file_dataspace, xfer_plist, data_array1); + VRFY((ret >= 0), "H5Dread dataset2 succeeded"); + + /* verify the read data with original expected data */ + ret = dataset_vrfy(start, count, stride, block, data_array1, data_origin1); + if (ret) + nerrors++; + + /* setup dimensions again to readAll with zero rows for process 0 */ + if (VERBOSE_MED) + HDprintf("readAll by some with zero row\n"); + slab_set(mpi_rank, mpi_size, start, count, stride, block, ZROW); + ret = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab succeeded"); + /* need to make mem_dataspace to match for process 0 */ + if (MAINPROCESS) { + ret = H5Sselect_hyperslab(mem_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab mem_dataspace succeeded"); + } + MESG("readAll by some with zero row"); + ret = H5Dread(dataset1, H5T_NATIVE_INT, mem_dataspace, file_dataspace, xfer_plist, data_array1); + VRFY((ret >= 0), "H5Dread dataset1 by ZROW succeeded"); + + /* verify the read data with original expected data */ + ret = dataset_vrfy(start, count, stride, block, data_array1, data_origin1); + if (ret) + nerrors++; + + /* release all temporary handles. */ + H5Sclose(file_dataspace); + H5Sclose(mem_dataspace); + H5Pclose(xfer_plist); + + if (data_array1) + free(data_array1); + if (data_origin1) + free(data_origin1); + data_array1 = (DATATYPE *)HDmalloc((size_t)dim0 * (size_t)dim1 * sizeof(DATATYPE)); + VRFY((data_array1 != NULL), "data_array1 malloc succeeded"); + data_origin1 = (DATATYPE *)HDmalloc((size_t)dim0 * (size_t)dim1 * sizeof(DATATYPE)); + VRFY((data_origin1 != NULL), "data_origin1 malloc succeeded"); + + block[0] = 1; + block[1] = (hsize_t)dim1; + stride[0] = 1; + stride[1] = (hsize_t)dim1; + count[0] = 1; + count[1] = 1; + start[0] = (hsize_t)(dim0 / mpi_size * mpi_rank); + start[1] = 0; + + dataset_fill(start, block, data_origin1); + MESG("data_array initialized"); + if (VERBOSE_MED) { + MESG("data_array created"); + dataset_print(start, block, data_origin1); + } + + /* Dataset5: point selection in memory - Hyperslab selection in file*/ + /* create a file dataspace independently */ + file_dataspace = H5Dget_space(dataset5); + VRFY((file_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab succeeded"); + + start[0] = 0; + start[1] = 0; + point_set(start, count, stride, block, num_points, coords, OUT_OF_ORDER); + mem_dataspace = H5Dget_space(dataset5); + VRFY((mem_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sselect_elements(mem_dataspace, H5S_SELECT_SET, num_points, coords); + VRFY((ret >= 0), "H5Sselect_elements succeeded"); + + /* set up the collective transfer properties list */ + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY((xfer_plist >= 0), ""); + ret = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pcreate xfer succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(xfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY((ret >= 0), "set independent IO collectively succeeded"); + } + + /* read data collectively */ + ret = H5Dread(dataset5, H5T_NATIVE_INT, mem_dataspace, file_dataspace, xfer_plist, data_array1); + VRFY((ret >= 0), "H5Dread dataset5 succeeded"); + + ret = dataset_vrfy(start, count, stride, block, data_array1, data_origin1); + if (ret) + nerrors++; + + /* release all temporary handles. */ + H5Sclose(file_dataspace); + H5Sclose(mem_dataspace); + H5Pclose(xfer_plist); + + if (data_array1) + free(data_array1); + data_array1 = (DATATYPE *)HDmalloc((size_t)dim0 * (size_t)dim1 * sizeof(DATATYPE)); + VRFY((data_array1 != NULL), "data_array1 malloc succeeded"); + + /* Dataset6: point selection in File - Point selection in Memory*/ + /* create a file dataspace independently */ + start[0] = (hsize_t)(dim0 / mpi_size * mpi_rank); + start[1] = 0; + point_set(start, count, stride, block, num_points, coords, IN_ORDER); + file_dataspace = H5Dget_space(dataset6); + VRFY((file_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sselect_elements(file_dataspace, H5S_SELECT_SET, num_points, coords); + VRFY((ret >= 0), "H5Sselect_elements succeeded"); + + start[0] = 0; + start[1] = 0; + point_set(start, count, stride, block, num_points, coords, OUT_OF_ORDER); + mem_dataspace = H5Dget_space(dataset6); + VRFY((mem_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sselect_elements(mem_dataspace, H5S_SELECT_SET, num_points, coords); + VRFY((ret >= 0), "H5Sselect_elements succeeded"); + + /* set up the collective transfer properties list */ + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY((xfer_plist >= 0), ""); + ret = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pcreate xfer succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(xfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY((ret >= 0), "set independent IO collectively succeeded"); + } + + /* read data collectively */ + ret = H5Dread(dataset6, H5T_NATIVE_INT, mem_dataspace, file_dataspace, xfer_plist, data_array1); + VRFY((ret >= 0), "H5Dread dataset6 succeeded"); + + ret = dataset_vrfy(start, count, stride, block, data_array1, data_origin1); + if (ret) + nerrors++; + + /* release all temporary handles. */ + H5Sclose(file_dataspace); + H5Sclose(mem_dataspace); + H5Pclose(xfer_plist); + + if (data_array1) + free(data_array1); + data_array1 = (DATATYPE *)HDmalloc((size_t)dim0 * (size_t)dim1 * sizeof(DATATYPE)); + VRFY((data_array1 != NULL), "data_array1 malloc succeeded"); + + /* Dataset7: point selection in memory - All selection in file*/ + /* create a file dataspace independently */ + file_dataspace = H5Dget_space(dataset7); + VRFY((file_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sselect_all(file_dataspace); + VRFY((ret >= 0), "H5Sselect_all succeeded"); + + num_points = (size_t)(dim0 * dim1); + k = 0; + for (i = 0; i < dim0; i++) { + for (j = 0; j < dim1; j++) { + coords[k++] = (hsize_t)i; + coords[k++] = (hsize_t)j; + } + } + mem_dataspace = H5Dget_space(dataset7); + VRFY((mem_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sselect_elements(mem_dataspace, H5S_SELECT_SET, num_points, coords); + VRFY((ret >= 0), "H5Sselect_elements succeeded"); + + /* set up the collective transfer properties list */ + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY((xfer_plist >= 0), ""); + ret = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pcreate xfer succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(xfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY((ret >= 0), "set independent IO collectively succeeded"); + } + + /* read data collectively */ + ret = H5Dread(dataset7, H5T_NATIVE_INT, mem_dataspace, file_dataspace, xfer_plist, data_array1); + VRFY((ret >= 0), "H5Dread dataset7 succeeded"); + + start[0] = (hsize_t)(dim0 / mpi_size * mpi_rank); + start[1] = 0; + ret = dataset_vrfy(start, count, stride, block, data_array1 + (dim0 / mpi_size * dim1 * mpi_rank), + data_origin1); + if (ret) + nerrors++; + + /* release all temporary handles. */ + H5Sclose(file_dataspace); + H5Sclose(mem_dataspace); + H5Pclose(xfer_plist); + + /* + * All reads completed. Close datasets collectively + */ + ret = H5Dclose(dataset1); + VRFY((ret >= 0), "H5Dclose1 succeeded"); + ret = H5Dclose(dataset2); + VRFY((ret >= 0), "H5Dclose2 succeeded"); + ret = H5Dclose(dataset5); + VRFY((ret >= 0), "H5Dclose5 succeeded"); + ret = H5Dclose(dataset6); + VRFY((ret >= 0), "H5Dclose6 succeeded"); + ret = H5Dclose(dataset7); + VRFY((ret >= 0), "H5Dclose7 succeeded"); + + /* close the file collectively */ + H5Fclose(fid); + + /* release data buffers */ + if (coords) + HDfree(coords); + if (data_array1) + HDfree(data_array1); + if (data_origin1) + HDfree(data_origin1); +} + +/* + * Part 2--Independent read/write for extendible datasets. + */ + +/* + * Example of using the parallel HDF5 library to create two extendible + * datasets in one HDF5 file with independent parallel MPIO access support. + * The Datasets are of sizes (number-of-mpi-processes x dim0) x dim1. + * Each process controls only a slab of size dim0 x dim1 within each + * dataset. + */ + +void +extend_writeInd(void) +{ + hid_t fid; /* HDF5 file ID */ + hid_t acc_tpl; /* File access templates */ + hid_t sid; /* Dataspace ID */ + hid_t file_dataspace; /* File dataspace ID */ + hid_t mem_dataspace; /* memory dataspace ID */ + hid_t dataset1, dataset2; /* Dataset ID */ + const char *filename; + hsize_t dims[RANK]; /* dataset dim sizes */ + hsize_t max_dims[RANK] = {H5S_UNLIMITED, H5S_UNLIMITED}; /* dataset maximum dim sizes */ + DATATYPE *data_array1 = NULL; /* data buffer */ + hsize_t chunk_dims[RANK]; /* chunk sizes */ + hid_t dataset_pl; /* dataset create prop. list */ + + hsize_t start[RANK]; /* for hyperslab setting */ + hsize_t count[RANK]; /* for hyperslab setting */ + hsize_t stride[RANK]; /* for hyperslab setting */ + hsize_t block[RANK]; /* for hyperslab setting */ + + herr_t ret; /* Generic return value */ + int mpi_size, mpi_rank; + + MPI_Comm comm = MPI_COMM_WORLD; + MPI_Info info = MPI_INFO_NULL; + + filename = PARATESTFILE /* GetTestParameters() */; + if (VERBOSE_MED) + HDprintf("Extend independent write test on file %s\n", filename); + + /* set up MPI parameters */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, basic dataset, or more aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + /* setup chunk-size. Make sure sizes are > 0 */ + chunk_dims[0] = (hsize_t)chunkdim0; + chunk_dims[1] = (hsize_t)chunkdim1; + + /* allocate memory for data buffer */ + data_array1 = (DATATYPE *)HDmalloc((size_t)dim0 * (size_t)dim1 * sizeof(DATATYPE)); + VRFY((data_array1 != NULL), "data_array1 HDmalloc succeeded"); + + /* ------------------- + * START AN HDF5 FILE + * -------------------*/ + /* setup file access template */ + acc_tpl = create_faccess_plist(comm, info, facc_type); + VRFY((acc_tpl >= 0), ""); + + /* Reduce the number of metadata cache slots, so that there are cache + * collisions during the raw data I/O on the chunked dataset. This stresses + * the metadata cache and tests for cache bugs. -QAK + */ + { + int mdc_nelmts; + size_t rdcc_nelmts; + size_t rdcc_nbytes; + double rdcc_w0; + + ret = H5Pget_cache(acc_tpl, &mdc_nelmts, &rdcc_nelmts, &rdcc_nbytes, &rdcc_w0); + VRFY((ret >= 0), "H5Pget_cache succeeded"); + mdc_nelmts = 4; + ret = H5Pset_cache(acc_tpl, mdc_nelmts, rdcc_nelmts, rdcc_nbytes, rdcc_w0); + VRFY((ret >= 0), "H5Pset_cache succeeded"); + } + + /* create the file collectively */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, acc_tpl); + VRFY((fid >= 0), "H5Fcreate succeeded"); + + /* Release file-access template */ + ret = H5Pclose(acc_tpl); + VRFY((ret >= 0), ""); + + /* -------------------------------------------------------------- + * Define the dimensions of the overall datasets and create them. + * ------------------------------------------------------------- */ + + /* set up dataset storage chunk sizes and creation property list */ + if (VERBOSE_MED) + HDprintf("chunks[]=%lu,%lu\n", (unsigned long)chunk_dims[0], (unsigned long)chunk_dims[1]); + dataset_pl = H5Pcreate(H5P_DATASET_CREATE); + VRFY((dataset_pl >= 0), "H5Pcreate succeeded"); + ret = H5Pset_chunk(dataset_pl, RANK, chunk_dims); + VRFY((ret >= 0), "H5Pset_chunk succeeded"); + + /* setup dimensionality object */ + /* start out with no rows, extend it later. */ + dims[0] = dims[1] = 0; + sid = H5Screate_simple(RANK, dims, max_dims); + VRFY((sid >= 0), "H5Screate_simple succeeded"); + + /* create an extendible dataset collectively */ + dataset1 = H5Dcreate2(fid, DATASETNAME1, H5T_NATIVE_INT, sid, H5P_DEFAULT, dataset_pl, H5P_DEFAULT); + VRFY((dataset1 >= 0), "H5Dcreate2 succeeded"); + + /* create another extendible dataset collectively */ + dataset2 = H5Dcreate2(fid, DATASETNAME2, H5T_NATIVE_INT, sid, H5P_DEFAULT, dataset_pl, H5P_DEFAULT); + VRFY((dataset2 >= 0), "H5Dcreate2 succeeded"); + + /* release resource */ + H5Sclose(sid); + H5Pclose(dataset_pl); + + /* ------------------------- + * Test writing to dataset1 + * -------------------------*/ + /* set up dimensions of the slab this process accesses */ + slab_set(mpi_rank, mpi_size, start, count, stride, block, BYROW); + + /* put some trivial data in the data_array */ + dataset_fill(start, block, data_array1); + MESG("data_array initialized"); + if (VERBOSE_MED) { + MESG("data_array created"); + dataset_print(start, block, data_array1); + } + + /* create a memory dataspace independently */ + mem_dataspace = H5Screate_simple(RANK, block, NULL); + VRFY((mem_dataspace >= 0), ""); + + /* Extend its current dim sizes before writing */ + dims[0] = (hsize_t)dim0; + dims[1] = (hsize_t)dim1; + ret = H5Dset_extent(dataset1, dims); + VRFY((ret >= 0), "H5Dset_extent succeeded"); + + /* create a file dataspace independently */ + file_dataspace = H5Dget_space(dataset1); + VRFY((file_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab succeeded"); + + /* write data independently */ + ret = H5Dwrite(dataset1, H5T_NATIVE_INT, mem_dataspace, file_dataspace, H5P_DEFAULT, data_array1); + VRFY((ret >= 0), "H5Dwrite succeeded"); + + /* release resource */ + H5Sclose(file_dataspace); + H5Sclose(mem_dataspace); + + /* ------------------------- + * Test writing to dataset2 + * -------------------------*/ + /* set up dimensions of the slab this process accesses */ + slab_set(mpi_rank, mpi_size, start, count, stride, block, BYCOL); + + /* put some trivial data in the data_array */ + dataset_fill(start, block, data_array1); + MESG("data_array initialized"); + if (VERBOSE_MED) { + MESG("data_array created"); + dataset_print(start, block, data_array1); + } + + /* create a memory dataspace independently */ + mem_dataspace = H5Screate_simple(RANK, block, NULL); + VRFY((mem_dataspace >= 0), ""); + + /* Try write to dataset2 beyond its current dim sizes. Should fail. */ + + /* create a file dataspace independently */ + file_dataspace = H5Dget_space(dataset2); + VRFY((file_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab succeeded"); + + /* write data independently. Should fail. */ + H5E_BEGIN_TRY + { + ret = H5Dwrite(dataset2, H5T_NATIVE_INT, mem_dataspace, file_dataspace, H5P_DEFAULT, data_array1); + } + H5E_END_TRY + VRFY((ret < 0), "H5Dwrite failed as expected"); + + H5Sclose(file_dataspace); + + /* Extend dataset2 and try again. Should succeed. */ + dims[0] = (hsize_t)dim0; + dims[1] = (hsize_t)dim1; + ret = H5Dset_extent(dataset2, dims); + VRFY((ret >= 0), "H5Dset_extent succeeded"); + + /* create a file dataspace independently */ + file_dataspace = H5Dget_space(dataset2); + VRFY((file_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab succeeded"); + + /* write data independently */ + ret = H5Dwrite(dataset2, H5T_NATIVE_INT, mem_dataspace, file_dataspace, H5P_DEFAULT, data_array1); + VRFY((ret >= 0), "H5Dwrite succeeded"); + + /* release resource */ + ret = H5Sclose(file_dataspace); + VRFY((ret >= 0), "H5Sclose succeeded"); + ret = H5Sclose(mem_dataspace); + VRFY((ret >= 0), "H5Sclose succeeded"); + + /* close dataset collectively */ + ret = H5Dclose(dataset1); + VRFY((ret >= 0), "H5Dclose1 succeeded"); + ret = H5Dclose(dataset2); + VRFY((ret >= 0), "H5Dclose2 succeeded"); + + /* close the file collectively */ + H5Fclose(fid); + + /* release data buffers */ + if (data_array1) + HDfree(data_array1); +} + +/* + * Example of using the parallel HDF5 library to create an extendable dataset + * and perform I/O on it in a way that verifies that the chunk cache is + * bypassed for parallel I/O. + */ + +void +extend_writeInd2(void) +{ + const char *filename; + hid_t fid; /* HDF5 file ID */ + hid_t fapl; /* File access templates */ + hid_t fs; /* File dataspace ID */ + hid_t ms; /* Memory dataspace ID */ + hid_t dataset; /* Dataset ID */ + hsize_t orig_size = 10; /* Original dataset dim size */ + hsize_t new_size = 20; /* Extended dataset dim size */ + hsize_t one = 1; + hsize_t max_size = H5S_UNLIMITED; /* dataset maximum dim size */ + hsize_t chunk_size = 16384; /* chunk size */ + hid_t dcpl; /* dataset create prop. list */ + int written[10], /* Data to write */ + retrieved[10]; /* Data read in */ + int mpi_size, mpi_rank; /* MPI settings */ + int i; /* Local index variable */ + herr_t ret; /* Generic return value */ + + filename = PARATESTFILE /* GetTestParameters() */; + if (VERBOSE_MED) + HDprintf("Extend independent write test #2 on file %s\n", filename); + + /* set up MPI parameters */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, basic dataset, or more aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + /* ------------------- + * START AN HDF5 FILE + * -------------------*/ + /* setup file access template */ + fapl = create_faccess_plist(MPI_COMM_WORLD, MPI_INFO_NULL, facc_type); + VRFY((fapl >= 0), "create_faccess_plist succeeded"); + + /* create the file collectively */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + VRFY((fid >= 0), "H5Fcreate succeeded"); + + /* Release file-access template */ + ret = H5Pclose(fapl); + VRFY((ret >= 0), "H5Pclose succeeded"); + + /* -------------------------------------------------------------- + * Define the dimensions of the overall datasets and create them. + * ------------------------------------------------------------- */ + + /* set up dataset storage chunk sizes and creation property list */ + dcpl = H5Pcreate(H5P_DATASET_CREATE); + VRFY((dcpl >= 0), "H5Pcreate succeeded"); + ret = H5Pset_chunk(dcpl, 1, &chunk_size); + VRFY((ret >= 0), "H5Pset_chunk succeeded"); + + /* setup dimensionality object */ + fs = H5Screate_simple(1, &orig_size, &max_size); + VRFY((fs >= 0), "H5Screate_simple succeeded"); + + /* create an extendible dataset collectively */ + dataset = H5Dcreate2(fid, DATASETNAME1, H5T_NATIVE_INT, fs, H5P_DEFAULT, dcpl, H5P_DEFAULT); + VRFY((dataset >= 0), "H5Dcreat2e succeeded"); + + /* release resource */ + ret = H5Pclose(dcpl); + VRFY((ret >= 0), "H5Pclose succeeded"); + + /* ------------------------- + * Test writing to dataset + * -------------------------*/ + /* create a memory dataspace independently */ + ms = H5Screate_simple(1, &orig_size, &max_size); + VRFY((ms >= 0), "H5Screate_simple succeeded"); + + /* put some trivial data in the data_array */ + for (i = 0; i < (int)orig_size; i++) + written[i] = i; + MESG("data array initialized"); + if (VERBOSE_MED) { + MESG("writing at offset zero: "); + for (i = 0; i < (int)orig_size; i++) + HDprintf("%s%d", i ? ", " : "", written[i]); + HDprintf("\n"); + } + ret = H5Dwrite(dataset, H5T_NATIVE_INT, ms, fs, H5P_DEFAULT, written); + VRFY((ret >= 0), "H5Dwrite succeeded"); + + /* ------------------------- + * Read initial data from dataset. + * -------------------------*/ + ret = H5Dread(dataset, H5T_NATIVE_INT, ms, fs, H5P_DEFAULT, retrieved); + VRFY((ret >= 0), "H5Dread succeeded"); + for (i = 0; i < (int)orig_size; i++) + if (written[i] != retrieved[i]) { + HDprintf("Line #%d: written!=retrieved: written[%d]=%d, retrieved[%d]=%d\n", __LINE__, i, + written[i], i, retrieved[i]); + nerrors++; + } + if (VERBOSE_MED) { + MESG("read at offset zero: "); + for (i = 0; i < (int)orig_size; i++) + HDprintf("%s%d", i ? ", " : "", retrieved[i]); + HDprintf("\n"); + } + + /* ------------------------- + * Extend the dataset & retrieve new dataspace + * -------------------------*/ + ret = H5Dset_extent(dataset, &new_size); + VRFY((ret >= 0), "H5Dset_extent succeeded"); + ret = H5Sclose(fs); + VRFY((ret >= 0), "H5Sclose succeeded"); + fs = H5Dget_space(dataset); + VRFY((fs >= 0), "H5Dget_space succeeded"); + + /* ------------------------- + * Write to the second half of the dataset + * -------------------------*/ + for (i = 0; i < (int)orig_size; i++) + written[i] = (int)orig_size + i; + MESG("data array re-initialized"); + if (VERBOSE_MED) { + MESG("writing at offset 10: "); + for (i = 0; i < (int)orig_size; i++) + HDprintf("%s%d", i ? ", " : "", written[i]); + HDprintf("\n"); + } + ret = H5Sselect_hyperslab(fs, H5S_SELECT_SET, &orig_size, NULL, &one, &orig_size); + VRFY((ret >= 0), "H5Sselect_hyperslab succeeded"); + ret = H5Dwrite(dataset, H5T_NATIVE_INT, ms, fs, H5P_DEFAULT, written); + VRFY((ret >= 0), "H5Dwrite succeeded"); + + /* ------------------------- + * Read the new data + * -------------------------*/ + ret = H5Dread(dataset, H5T_NATIVE_INT, ms, fs, H5P_DEFAULT, retrieved); + VRFY((ret >= 0), "H5Dread succeeded"); + for (i = 0; i < (int)orig_size; i++) + if (written[i] != retrieved[i]) { + HDprintf("Line #%d: written!=retrieved: written[%d]=%d, retrieved[%d]=%d\n", __LINE__, i, + written[i], i, retrieved[i]); + nerrors++; + } + if (VERBOSE_MED) { + MESG("read at offset 10: "); + for (i = 0; i < (int)orig_size; i++) + HDprintf("%s%d", i ? ", " : "", retrieved[i]); + HDprintf("\n"); + } + + /* Close dataset collectively */ + ret = H5Dclose(dataset); + VRFY((ret >= 0), "H5Dclose succeeded"); + + /* Close the file collectively */ + ret = H5Fclose(fid); + VRFY((ret >= 0), "H5Fclose succeeded"); +} + +/* Example of using the parallel HDF5 library to read an extendible dataset */ +void +extend_readInd(void) +{ + hid_t fid; /* HDF5 file ID */ + hid_t acc_tpl; /* File access templates */ + hid_t file_dataspace; /* File dataspace ID */ + hid_t mem_dataspace; /* memory dataspace ID */ + hid_t dataset1, dataset2; /* Dataset ID */ + hsize_t dims[RANK]; /* dataset dim sizes */ + DATATYPE *data_array1 = NULL; /* data buffer */ + DATATYPE *data_array2 = NULL; /* data buffer */ + DATATYPE *data_origin1 = NULL; /* expected data buffer */ + const char *filename; + + hsize_t start[RANK]; /* for hyperslab setting */ + hsize_t count[RANK], stride[RANK]; /* for hyperslab setting */ + hsize_t block[RANK]; /* for hyperslab setting */ + + herr_t ret; /* Generic return value */ + int mpi_size, mpi_rank; + + MPI_Comm comm = MPI_COMM_WORLD; + MPI_Info info = MPI_INFO_NULL; + + filename = PARATESTFILE /* GetTestParameters() */; + if (VERBOSE_MED) + HDprintf("Extend independent read test on file %s\n", filename); + + /* set up MPI parameters */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, basic dataset, or more aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + /* allocate memory for data buffer */ + data_array1 = (DATATYPE *)HDmalloc((size_t)dim0 * (size_t)dim1 * sizeof(DATATYPE)); + VRFY((data_array1 != NULL), "data_array1 HDmalloc succeeded"); + data_array2 = (DATATYPE *)HDmalloc((size_t)dim0 * (size_t)dim1 * sizeof(DATATYPE)); + VRFY((data_array2 != NULL), "data_array2 HDmalloc succeeded"); + data_origin1 = (DATATYPE *)HDmalloc((size_t)dim0 * (size_t)dim1 * sizeof(DATATYPE)); + VRFY((data_origin1 != NULL), "data_origin1 HDmalloc succeeded"); + + /* ------------------- + * OPEN AN HDF5 FILE + * -------------------*/ + /* setup file access template */ + acc_tpl = create_faccess_plist(comm, info, facc_type); + VRFY((acc_tpl >= 0), ""); + + /* open the file collectively */ + fid = H5Fopen(filename, H5F_ACC_RDONLY, acc_tpl); + VRFY((fid >= 0), ""); + + /* Release file-access template */ + ret = H5Pclose(acc_tpl); + VRFY((ret >= 0), ""); + + /* open the dataset1 collectively */ + dataset1 = H5Dopen2(fid, DATASETNAME1, H5P_DEFAULT); + VRFY((dataset1 >= 0), ""); + + /* open another dataset collectively */ + dataset2 = H5Dopen2(fid, DATASETNAME1, H5P_DEFAULT); + VRFY((dataset2 >= 0), ""); + + /* Try extend dataset1 which is open RDONLY. Should fail. */ + + file_dataspace = H5Dget_space(dataset1); + VRFY((file_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sget_simple_extent_dims(file_dataspace, dims, NULL); + VRFY((ret > 0), "H5Sget_simple_extent_dims succeeded"); + dims[0]++; + H5E_BEGIN_TRY + { + ret = H5Dset_extent(dataset1, dims); + } + H5E_END_TRY + VRFY((ret < 0), "H5Dset_extent failed as expected"); + + H5Sclose(file_dataspace); + + /* Read dataset1 using BYROW pattern */ + /* set up dimensions of the slab this process accesses */ + slab_set(mpi_rank, mpi_size, start, count, stride, block, BYROW); + + /* create a file dataspace independently */ + file_dataspace = H5Dget_space(dataset1); + VRFY((file_dataspace >= 0), ""); + ret = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), ""); + + /* create a memory dataspace independently */ + mem_dataspace = H5Screate_simple(RANK, block, NULL); + VRFY((mem_dataspace >= 0), ""); + + /* fill dataset with test data */ + dataset_fill(start, block, data_origin1); + if (VERBOSE_MED) { + MESG("data_array created"); + dataset_print(start, block, data_array1); + } + + /* read data independently */ + ret = H5Dread(dataset1, H5T_NATIVE_INT, mem_dataspace, file_dataspace, H5P_DEFAULT, data_array1); + VRFY((ret >= 0), "H5Dread succeeded"); + + /* verify the read data with original expected data */ + ret = dataset_vrfy(start, count, stride, block, data_array1, data_origin1); + VRFY((ret == 0), "dataset1 read verified correct"); + if (ret) + nerrors++; + + H5Sclose(mem_dataspace); + H5Sclose(file_dataspace); + + /* Read dataset2 using BYCOL pattern */ + /* set up dimensions of the slab this process accesses */ + slab_set(mpi_rank, mpi_size, start, count, stride, block, BYCOL); + + /* create a file dataspace independently */ + file_dataspace = H5Dget_space(dataset2); + VRFY((file_dataspace >= 0), ""); + ret = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), ""); + + /* create a memory dataspace independently */ + mem_dataspace = H5Screate_simple(RANK, block, NULL); + VRFY((mem_dataspace >= 0), ""); + + /* fill dataset with test data */ + dataset_fill(start, block, data_origin1); + if (VERBOSE_MED) { + MESG("data_array created"); + dataset_print(start, block, data_array1); + } + + /* read data independently */ + ret = H5Dread(dataset2, H5T_NATIVE_INT, mem_dataspace, file_dataspace, H5P_DEFAULT, data_array1); + VRFY((ret >= 0), "H5Dread succeeded"); + + /* verify the read data with original expected data */ + ret = dataset_vrfy(start, count, stride, block, data_array1, data_origin1); + VRFY((ret == 0), "dataset2 read verified correct"); + if (ret) + nerrors++; + + H5Sclose(mem_dataspace); + H5Sclose(file_dataspace); + + /* close dataset collectively */ + ret = H5Dclose(dataset1); + VRFY((ret >= 0), ""); + ret = H5Dclose(dataset2); + VRFY((ret >= 0), ""); + + /* close the file collectively */ + H5Fclose(fid); + + /* release data buffers */ + if (data_array1) + HDfree(data_array1); + if (data_array2) + HDfree(data_array2); + if (data_origin1) + HDfree(data_origin1); +} + +/* + * Part 3--Collective read/write for extendible datasets. + */ + +/* + * Example of using the parallel HDF5 library to create two extendible + * datasets in one HDF5 file with collective parallel MPIO access support. + * The Datasets are of sizes (number-of-mpi-processes x dim0) x dim1. + * Each process controls only a slab of size dim0 x dim1 within each + * dataset. + */ + +void +extend_writeAll(void) +{ + hid_t fid; /* HDF5 file ID */ + hid_t acc_tpl; /* File access templates */ + hid_t xfer_plist; /* Dataset transfer properties list */ + hid_t sid; /* Dataspace ID */ + hid_t file_dataspace; /* File dataspace ID */ + hid_t mem_dataspace; /* memory dataspace ID */ + hid_t dataset1, dataset2; /* Dataset ID */ + const char *filename; + hsize_t dims[RANK]; /* dataset dim sizes */ + hsize_t max_dims[RANK] = {H5S_UNLIMITED, H5S_UNLIMITED}; /* dataset maximum dim sizes */ + DATATYPE *data_array1 = NULL; /* data buffer */ + hsize_t chunk_dims[RANK]; /* chunk sizes */ + hid_t dataset_pl; /* dataset create prop. list */ + + hsize_t start[RANK]; /* for hyperslab setting */ + hsize_t count[RANK]; /* for hyperslab setting */ + hsize_t stride[RANK]; /* for hyperslab setting */ + hsize_t block[RANK]; /* for hyperslab setting */ + + herr_t ret; /* Generic return value */ + int mpi_size, mpi_rank; + + MPI_Comm comm = MPI_COMM_WORLD; + MPI_Info info = MPI_INFO_NULL; + + filename = PARATESTFILE /* GetTestParameters() */; + if (VERBOSE_MED) + HDprintf("Extend independent write test on file %s\n", filename); + + /* set up MPI parameters */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, basic dataset, or more aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + /* setup chunk-size. Make sure sizes are > 0 */ + chunk_dims[0] = (hsize_t)chunkdim0; + chunk_dims[1] = (hsize_t)chunkdim1; + + /* allocate memory for data buffer */ + data_array1 = (DATATYPE *)HDmalloc((size_t)dim0 * (size_t)dim1 * sizeof(DATATYPE)); + VRFY((data_array1 != NULL), "data_array1 HDmalloc succeeded"); + + /* ------------------- + * START AN HDF5 FILE + * -------------------*/ + /* setup file access template */ + acc_tpl = create_faccess_plist(comm, info, facc_type); + VRFY((acc_tpl >= 0), ""); + + /* Reduce the number of metadata cache slots, so that there are cache + * collisions during the raw data I/O on the chunked dataset. This stresses + * the metadata cache and tests for cache bugs. -QAK + */ + { + int mdc_nelmts; + size_t rdcc_nelmts; + size_t rdcc_nbytes; + double rdcc_w0; + + ret = H5Pget_cache(acc_tpl, &mdc_nelmts, &rdcc_nelmts, &rdcc_nbytes, &rdcc_w0); + VRFY((ret >= 0), "H5Pget_cache succeeded"); + mdc_nelmts = 4; + ret = H5Pset_cache(acc_tpl, mdc_nelmts, rdcc_nelmts, rdcc_nbytes, rdcc_w0); + VRFY((ret >= 0), "H5Pset_cache succeeded"); + } + + /* create the file collectively */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, acc_tpl); + VRFY((fid >= 0), "H5Fcreate succeeded"); + + /* Release file-access template */ + ret = H5Pclose(acc_tpl); + VRFY((ret >= 0), ""); + + /* -------------------------------------------------------------- + * Define the dimensions of the overall datasets and create them. + * ------------------------------------------------------------- */ + + /* set up dataset storage chunk sizes and creation property list */ + if (VERBOSE_MED) + HDprintf("chunks[]=%lu,%lu\n", (unsigned long)chunk_dims[0], (unsigned long)chunk_dims[1]); + dataset_pl = H5Pcreate(H5P_DATASET_CREATE); + VRFY((dataset_pl >= 0), "H5Pcreate succeeded"); + ret = H5Pset_chunk(dataset_pl, RANK, chunk_dims); + VRFY((ret >= 0), "H5Pset_chunk succeeded"); + + /* setup dimensionality object */ + /* start out with no rows, extend it later. */ + dims[0] = dims[1] = 0; + sid = H5Screate_simple(RANK, dims, max_dims); + VRFY((sid >= 0), "H5Screate_simple succeeded"); + + /* create an extendible dataset collectively */ + dataset1 = H5Dcreate2(fid, DATASETNAME1, H5T_NATIVE_INT, sid, H5P_DEFAULT, dataset_pl, H5P_DEFAULT); + VRFY((dataset1 >= 0), "H5Dcreate2 succeeded"); + + /* create another extendible dataset collectively */ + dataset2 = H5Dcreate2(fid, DATASETNAME2, H5T_NATIVE_INT, sid, H5P_DEFAULT, dataset_pl, H5P_DEFAULT); + VRFY((dataset2 >= 0), "H5Dcreate2 succeeded"); + + /* release resource */ + H5Sclose(sid); + H5Pclose(dataset_pl); + + /* ------------------------- + * Test writing to dataset1 + * -------------------------*/ + /* set up dimensions of the slab this process accesses */ + slab_set(mpi_rank, mpi_size, start, count, stride, block, BYROW); + + /* put some trivial data in the data_array */ + dataset_fill(start, block, data_array1); + MESG("data_array initialized"); + if (VERBOSE_MED) { + MESG("data_array created"); + dataset_print(start, block, data_array1); + } + + /* create a memory dataspace independently */ + mem_dataspace = H5Screate_simple(RANK, block, NULL); + VRFY((mem_dataspace >= 0), ""); + + /* Extend its current dim sizes before writing */ + dims[0] = (hsize_t)dim0; + dims[1] = (hsize_t)dim1; + ret = H5Dset_extent(dataset1, dims); + VRFY((ret >= 0), "H5Dset_extent succeeded"); + + /* create a file dataspace independently */ + file_dataspace = H5Dget_space(dataset1); + VRFY((file_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab succeeded"); + + /* set up the collective transfer properties list */ + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY((xfer_plist >= 0), "H5Pcreate xfer succeeded"); + ret = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(xfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY((ret >= 0), "set independent IO collectively succeeded"); + } + + /* write data collectively */ + ret = H5Dwrite(dataset1, H5T_NATIVE_INT, mem_dataspace, file_dataspace, xfer_plist, data_array1); + VRFY((ret >= 0), "H5Dwrite succeeded"); + + /* release resource */ + H5Sclose(file_dataspace); + H5Sclose(mem_dataspace); + H5Pclose(xfer_plist); + + /* ------------------------- + * Test writing to dataset2 + * -------------------------*/ + /* set up dimensions of the slab this process accesses */ + slab_set(mpi_rank, mpi_size, start, count, stride, block, BYCOL); + + /* put some trivial data in the data_array */ + dataset_fill(start, block, data_array1); + MESG("data_array initialized"); + if (VERBOSE_MED) { + MESG("data_array created"); + dataset_print(start, block, data_array1); + } + + /* create a memory dataspace independently */ + mem_dataspace = H5Screate_simple(RANK, block, NULL); + VRFY((mem_dataspace >= 0), ""); + + /* set up the collective transfer properties list */ + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY((xfer_plist >= 0), "H5Pcreate xfer succeeded"); + ret = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(xfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY((ret >= 0), "set independent IO collectively succeeded"); + } + + /* Try write to dataset2 beyond its current dim sizes. Should fail. */ + + /* create a file dataspace independently */ + file_dataspace = H5Dget_space(dataset2); + VRFY((file_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab succeeded"); + + /* write data independently. Should fail. */ + H5E_BEGIN_TRY + { + ret = H5Dwrite(dataset2, H5T_NATIVE_INT, mem_dataspace, file_dataspace, xfer_plist, data_array1); + } + H5E_END_TRY + VRFY((ret < 0), "H5Dwrite failed as expected"); + + H5Sclose(file_dataspace); + + /* Extend dataset2 and try again. Should succeed. */ + dims[0] = (hsize_t)dim0; + dims[1] = (hsize_t)dim1; + ret = H5Dset_extent(dataset2, dims); + VRFY((ret >= 0), "H5Dset_extent succeeded"); + + /* create a file dataspace independently */ + file_dataspace = H5Dget_space(dataset2); + VRFY((file_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab succeeded"); + + /* write data independently */ + ret = H5Dwrite(dataset2, H5T_NATIVE_INT, mem_dataspace, file_dataspace, xfer_plist, data_array1); + VRFY((ret >= 0), "H5Dwrite succeeded"); + + /* release resource */ + ret = H5Sclose(file_dataspace); + VRFY((ret >= 0), "H5Sclose succeeded"); + ret = H5Sclose(mem_dataspace); + VRFY((ret >= 0), "H5Sclose succeeded"); + ret = H5Pclose(xfer_plist); + VRFY((ret >= 0), "H5Pclose succeeded"); + + /* close dataset collectively */ + ret = H5Dclose(dataset1); + VRFY((ret >= 0), "H5Dclose1 succeeded"); + ret = H5Dclose(dataset2); + VRFY((ret >= 0), "H5Dclose2 succeeded"); + + /* close the file collectively */ + H5Fclose(fid); + + /* release data buffers */ + if (data_array1) + HDfree(data_array1); +} + +/* Example of using the parallel HDF5 library to read an extendible dataset */ +void +extend_readAll(void) +{ + hid_t fid; /* HDF5 file ID */ + hid_t acc_tpl; /* File access templates */ + hid_t xfer_plist; /* Dataset transfer properties list */ + hid_t file_dataspace; /* File dataspace ID */ + hid_t mem_dataspace; /* memory dataspace ID */ + hid_t dataset1, dataset2; /* Dataset ID */ + const char *filename; + hsize_t dims[RANK]; /* dataset dim sizes */ + DATATYPE *data_array1 = NULL; /* data buffer */ + DATATYPE *data_array2 = NULL; /* data buffer */ + DATATYPE *data_origin1 = NULL; /* expected data buffer */ + + hsize_t start[RANK]; /* for hyperslab setting */ + hsize_t count[RANK], stride[RANK]; /* for hyperslab setting */ + hsize_t block[RANK]; /* for hyperslab setting */ + + herr_t ret; /* Generic return value */ + int mpi_size, mpi_rank; + + MPI_Comm comm = MPI_COMM_WORLD; + MPI_Info info = MPI_INFO_NULL; + + filename = PARATESTFILE /* GetTestParameters() */; + if (VERBOSE_MED) + HDprintf("Extend independent read test on file %s\n", filename); + + /* set up MPI parameters */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, basic dataset, or more aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + /* allocate memory for data buffer */ + data_array1 = (DATATYPE *)HDmalloc((size_t)dim0 * (size_t)dim1 * sizeof(DATATYPE)); + VRFY((data_array1 != NULL), "data_array1 HDmalloc succeeded"); + data_array2 = (DATATYPE *)HDmalloc((size_t)dim0 * (size_t)dim1 * sizeof(DATATYPE)); + VRFY((data_array2 != NULL), "data_array2 HDmalloc succeeded"); + data_origin1 = (DATATYPE *)HDmalloc((size_t)dim0 * (size_t)dim1 * sizeof(DATATYPE)); + VRFY((data_origin1 != NULL), "data_origin1 HDmalloc succeeded"); + + /* ------------------- + * OPEN AN HDF5 FILE + * -------------------*/ + /* setup file access template */ + acc_tpl = create_faccess_plist(comm, info, facc_type); + VRFY((acc_tpl >= 0), ""); + + /* open the file collectively */ + fid = H5Fopen(filename, H5F_ACC_RDONLY, acc_tpl); + VRFY((fid >= 0), ""); + + /* Release file-access template */ + ret = H5Pclose(acc_tpl); + VRFY((ret >= 0), ""); + + /* open the dataset1 collectively */ + dataset1 = H5Dopen2(fid, DATASETNAME1, H5P_DEFAULT); + VRFY((dataset1 >= 0), ""); + + /* open another dataset collectively */ + dataset2 = H5Dopen2(fid, DATASETNAME1, H5P_DEFAULT); + VRFY((dataset2 >= 0), ""); + + /* Try extend dataset1 which is open RDONLY. Should fail. */ + + file_dataspace = H5Dget_space(dataset1); + VRFY((file_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sget_simple_extent_dims(file_dataspace, dims, NULL); + VRFY((ret > 0), "H5Sget_simple_extent_dims succeeded"); + dims[0]++; + H5E_BEGIN_TRY + { + ret = H5Dset_extent(dataset1, dims); + } + H5E_END_TRY + VRFY((ret < 0), "H5Dset_extent failed as expected"); + + H5Sclose(file_dataspace); + + /* Read dataset1 using BYROW pattern */ + /* set up dimensions of the slab this process accesses */ + slab_set(mpi_rank, mpi_size, start, count, stride, block, BYROW); + + /* create a file dataspace independently */ + file_dataspace = H5Dget_space(dataset1); + VRFY((file_dataspace >= 0), ""); + ret = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), ""); + + /* create a memory dataspace independently */ + mem_dataspace = H5Screate_simple(RANK, block, NULL); + VRFY((mem_dataspace >= 0), ""); + + /* fill dataset with test data */ + dataset_fill(start, block, data_origin1); + if (VERBOSE_MED) { + MESG("data_array created"); + dataset_print(start, block, data_array1); + } + + /* set up the collective transfer properties list */ + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY((xfer_plist >= 0), "H5Pcreate xfer succeeded"); + ret = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(xfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY((ret >= 0), "set independent IO collectively succeeded"); + } + + /* read data collectively */ + ret = H5Dread(dataset1, H5T_NATIVE_INT, mem_dataspace, file_dataspace, xfer_plist, data_array1); + VRFY((ret >= 0), "H5Dread succeeded"); + + /* verify the read data with original expected data */ + ret = dataset_vrfy(start, count, stride, block, data_array1, data_origin1); + VRFY((ret == 0), "dataset1 read verified correct"); + if (ret) + nerrors++; + + H5Sclose(mem_dataspace); + H5Sclose(file_dataspace); + H5Pclose(xfer_plist); + + /* Read dataset2 using BYCOL pattern */ + /* set up dimensions of the slab this process accesses */ + slab_set(mpi_rank, mpi_size, start, count, stride, block, BYCOL); + + /* create a file dataspace independently */ + file_dataspace = H5Dget_space(dataset2); + VRFY((file_dataspace >= 0), ""); + ret = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), ""); + + /* create a memory dataspace independently */ + mem_dataspace = H5Screate_simple(RANK, block, NULL); + VRFY((mem_dataspace >= 0), ""); + + /* fill dataset with test data */ + dataset_fill(start, block, data_origin1); + if (VERBOSE_MED) { + MESG("data_array created"); + dataset_print(start, block, data_array1); + } + + /* set up the collective transfer properties list */ + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY((xfer_plist >= 0), "H5Pcreate xfer succeeded"); + ret = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(xfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY((ret >= 0), "set independent IO collectively succeeded"); + } + + /* read data collectively */ + ret = H5Dread(dataset2, H5T_NATIVE_INT, mem_dataspace, file_dataspace, xfer_plist, data_array1); + VRFY((ret >= 0), "H5Dread succeeded"); + + /* verify the read data with original expected data */ + ret = dataset_vrfy(start, count, stride, block, data_array1, data_origin1); + VRFY((ret == 0), "dataset2 read verified correct"); + if (ret) + nerrors++; + + H5Sclose(mem_dataspace); + H5Sclose(file_dataspace); + H5Pclose(xfer_plist); + + /* close dataset collectively */ + ret = H5Dclose(dataset1); + VRFY((ret >= 0), ""); + ret = H5Dclose(dataset2); + VRFY((ret >= 0), ""); + + /* close the file collectively */ + H5Fclose(fid); + + /* release data buffers */ + if (data_array1) + HDfree(data_array1); + if (data_array2) + HDfree(data_array2); + if (data_origin1) + HDfree(data_origin1); +} + +#ifdef H5_HAVE_FILTER_DEFLATE +static const char * +h5_rmprefix(const char *filename) +{ + const char *ret_ptr; + + if ((ret_ptr = HDstrstr(filename, ":")) == NULL) + ret_ptr = filename; + else + ret_ptr++; + + return (ret_ptr); +} + +/* + * Example of using the parallel HDF5 library to read a compressed + * dataset in an HDF5 file with collective parallel access support. + */ +void +compress_readAll(void) +{ + hid_t fid; /* HDF5 file ID */ + hid_t acc_tpl; /* File access templates */ + hid_t dcpl; /* Dataset creation property list */ + hid_t xfer_plist; /* Dataset transfer properties list */ + hid_t dataspace; /* Dataspace ID */ + hid_t dataset; /* Dataset ID */ + int rank = 1; /* Dataspace rank */ + hsize_t dim = (hsize_t)dim0; /* Dataspace dimensions */ + unsigned u; /* Local index variable */ + unsigned chunk_opts; /* Chunk options */ + unsigned disable_partial_chunk_filters; /* Whether filters are disabled on partial chunks */ + DATATYPE *data_read = NULL; /* data buffer */ + DATATYPE *data_orig = NULL; /* expected data buffer */ + const char *filename; + MPI_Comm comm = MPI_COMM_WORLD; + MPI_Info info = MPI_INFO_NULL; + int mpi_size, mpi_rank; + herr_t ret; /* Generic return value */ + + filename = PARATESTFILE /* GetTestParameters() */; + if (VERBOSE_MED) + HDprintf("Collective chunked dataset read test on file %s\n", filename); + + /* Retrieve MPI parameters */ + MPI_Comm_size(comm, &mpi_size); + MPI_Comm_rank(comm, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file or dataset aren't supported with this connector\n"); + fflush(stdout); + } + + return; + } + + /* Allocate data buffer */ + data_orig = (DATATYPE *)HDmalloc((size_t)dim * sizeof(DATATYPE)); + VRFY((data_orig != NULL), "data_origin1 HDmalloc succeeded"); + data_read = (DATATYPE *)HDmalloc((size_t)dim * sizeof(DATATYPE)); + VRFY((data_read != NULL), "data_array1 HDmalloc succeeded"); + + /* Initialize data buffers */ + for (u = 0; u < dim; u++) + data_orig[u] = (DATATYPE)u; + + /* Run test both with and without filters disabled on partial chunks */ + for (disable_partial_chunk_filters = 0; disable_partial_chunk_filters <= 1; + disable_partial_chunk_filters++) { + /* Process zero creates the file with a compressed, chunked dataset */ + if (mpi_rank == 0) { + hsize_t chunk_dim; /* Chunk dimensions */ + + /* Create the file */ + fid = H5Fcreate(h5_rmprefix(filename), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + VRFY((fid > 0), "H5Fcreate succeeded"); + + /* Create property list for chunking and compression */ + dcpl = H5Pcreate(H5P_DATASET_CREATE); + VRFY((dcpl > 0), "H5Pcreate succeeded"); + + ret = H5Pset_layout(dcpl, H5D_CHUNKED); + VRFY((ret >= 0), "H5Pset_layout succeeded"); + + /* Use eight chunks */ + chunk_dim = dim / 8; + ret = H5Pset_chunk(dcpl, rank, &chunk_dim); + VRFY((ret >= 0), "H5Pset_chunk succeeded"); + + /* Set chunk options appropriately */ + if (disable_partial_chunk_filters) { + ret = H5Pget_chunk_opts(dcpl, &chunk_opts); + VRFY((ret >= 0), "H5Pget_chunk_opts succeeded"); + + chunk_opts |= H5D_CHUNK_DONT_FILTER_PARTIAL_CHUNKS; + + ret = H5Pset_chunk_opts(dcpl, chunk_opts); + VRFY((ret >= 0), "H5Pset_chunk_opts succeeded"); + } /* end if */ + + ret = H5Pset_deflate(dcpl, 9); + VRFY((ret >= 0), "H5Pset_deflate succeeded"); + + /* Create dataspace */ + dataspace = H5Screate_simple(rank, &dim, NULL); + VRFY((dataspace > 0), "H5Screate_simple succeeded"); + + /* Create dataset */ + dataset = + H5Dcreate2(fid, "compressed_data", H5T_NATIVE_INT, dataspace, H5P_DEFAULT, dcpl, H5P_DEFAULT); + VRFY((dataset > 0), "H5Dcreate2 succeeded"); + + /* Write compressed data */ + ret = H5Dwrite(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data_orig); + VRFY((ret >= 0), "H5Dwrite succeeded"); + + /* Close objects */ + ret = H5Pclose(dcpl); + VRFY((ret >= 0), "H5Pclose succeeded"); + ret = H5Sclose(dataspace); + VRFY((ret >= 0), "H5Sclose succeeded"); + ret = H5Dclose(dataset); + VRFY((ret >= 0), "H5Dclose succeeded"); + ret = H5Fclose(fid); + VRFY((ret >= 0), "H5Fclose succeeded"); + } + + /* Wait for file to be created */ + MPI_Barrier(comm); + + /* ------------------- + * OPEN AN HDF5 FILE + * -------------------*/ + + /* setup file access template */ + acc_tpl = create_faccess_plist(comm, info, facc_type); + VRFY((acc_tpl >= 0), ""); + + /* open the file collectively */ + fid = H5Fopen(filename, H5F_ACC_RDWR, acc_tpl); + VRFY((fid > 0), "H5Fopen succeeded"); + + /* Release file-access template */ + ret = H5Pclose(acc_tpl); + VRFY((ret >= 0), "H5Pclose succeeded"); + + /* Open dataset with compressed chunks */ + dataset = H5Dopen2(fid, "compressed_data", H5P_DEFAULT); + VRFY((dataset > 0), "H5Dopen2 succeeded"); + + /* Try reading & writing data */ + if (dataset > 0) { + /* Create dataset transfer property list */ + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY((xfer_plist > 0), "H5Pcreate succeeded"); + + ret = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(xfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY((ret >= 0), "set independent IO collectively succeeded"); + } + + /* Try reading the data */ + ret = H5Dread(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, xfer_plist, data_read); + VRFY((ret >= 0), "H5Dread succeeded"); + + /* Verify data read */ + for (u = 0; u < dim; u++) + if (data_orig[u] != data_read[u]) { + HDprintf("Line #%d: written!=retrieved: data_orig[%u]=%d, data_read[%u]=%d\n", __LINE__, + (unsigned)u, data_orig[u], (unsigned)u, data_read[u]); + nerrors++; + } + +#ifdef H5_HAVE_PARALLEL_FILTERED_WRITES + ret = H5Dwrite(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, xfer_plist, data_read); + VRFY((ret >= 0), "H5Dwrite succeeded"); +#endif + + ret = H5Pclose(xfer_plist); + VRFY((ret >= 0), "H5Pclose succeeded"); + ret = H5Dclose(dataset); + VRFY((ret >= 0), "H5Dclose succeeded"); + } /* end if */ + + /* Close file */ + ret = H5Fclose(fid); + VRFY((ret >= 0), "H5Fclose succeeded"); + } /* end for */ + + /* release data buffers */ + if (data_read) + HDfree(data_read); + if (data_orig) + HDfree(data_orig); +} +#endif /* H5_HAVE_FILTER_DEFLATE */ + +/* + * Part 4--Non-selection for chunked dataset + */ + +/* + * Example of using the parallel HDF5 library to create chunked + * dataset in one HDF5 file with collective and independent parallel + * MPIO access support. The Datasets are of sizes dim0 x dim1. + * Each process controls only a slab of size dim0 x dim1 within the + * dataset with the exception that one processor selects no element. + */ + +void +none_selection_chunk(void) +{ + hid_t fid; /* HDF5 file ID */ + hid_t acc_tpl; /* File access templates */ + hid_t xfer_plist; /* Dataset transfer properties list */ + hid_t sid; /* Dataspace ID */ + hid_t file_dataspace; /* File dataspace ID */ + hid_t mem_dataspace; /* memory dataspace ID */ + hid_t dataset1, dataset2; /* Dataset ID */ + const char *filename; + hsize_t dims[RANK]; /* dataset dim sizes */ + DATATYPE *data_origin = NULL; /* data buffer */ + DATATYPE *data_array = NULL; /* data buffer */ + hsize_t chunk_dims[RANK]; /* chunk sizes */ + hid_t dataset_pl; /* dataset create prop. list */ + + hsize_t start[RANK]; /* for hyperslab setting */ + hsize_t count[RANK]; /* for hyperslab setting */ + hsize_t stride[RANK]; /* for hyperslab setting */ + hsize_t block[RANK]; /* for hyperslab setting */ + hsize_t mstart[RANK]; /* for data buffer in memory */ + + herr_t ret; /* Generic return value */ + int mpi_size, mpi_rank; + + MPI_Comm comm = MPI_COMM_WORLD; + MPI_Info info = MPI_INFO_NULL; + + filename = PARATESTFILE /* GetTestParameters() */; + if (VERBOSE_MED) + HDprintf("Extend independent write test on file %s\n", filename); + + /* set up MPI parameters */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file or dataset aren't supported with this connector\n"); + fflush(stdout); + } + + return; + } + + /* setup chunk-size. Make sure sizes are > 0 */ + chunk_dims[0] = (hsize_t)chunkdim0; + chunk_dims[1] = (hsize_t)chunkdim1; + + /* ------------------- + * START AN HDF5 FILE + * -------------------*/ + /* setup file access template */ + acc_tpl = create_faccess_plist(comm, info, facc_type); + VRFY((acc_tpl >= 0), ""); + + /* create the file collectively */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, acc_tpl); + VRFY((fid >= 0), "H5Fcreate succeeded"); + + /* Release file-access template */ + ret = H5Pclose(acc_tpl); + VRFY((ret >= 0), ""); + + /* -------------------------------------------------------------- + * Define the dimensions of the overall datasets and create them. + * ------------------------------------------------------------- */ + + /* set up dataset storage chunk sizes and creation property list */ + if (VERBOSE_MED) + HDprintf("chunks[]=%lu,%lu\n", (unsigned long)chunk_dims[0], (unsigned long)chunk_dims[1]); + dataset_pl = H5Pcreate(H5P_DATASET_CREATE); + VRFY((dataset_pl >= 0), "H5Pcreate succeeded"); + ret = H5Pset_chunk(dataset_pl, RANK, chunk_dims); + VRFY((ret >= 0), "H5Pset_chunk succeeded"); + + /* setup dimensionality object */ + dims[0] = (hsize_t)dim0; + dims[1] = (hsize_t)dim1; + sid = H5Screate_simple(RANK, dims, NULL); + VRFY((sid >= 0), "H5Screate_simple succeeded"); + + /* create an extendible dataset collectively */ + dataset1 = H5Dcreate2(fid, DATASETNAME1, H5T_NATIVE_INT, sid, H5P_DEFAULT, dataset_pl, H5P_DEFAULT); + VRFY((dataset1 >= 0), "H5Dcreate2 succeeded"); + + /* create another extendible dataset collectively */ + dataset2 = H5Dcreate2(fid, DATASETNAME2, H5T_NATIVE_INT, sid, H5P_DEFAULT, dataset_pl, H5P_DEFAULT); + VRFY((dataset2 >= 0), "H5Dcreate2 succeeded"); + + /* release resource */ + H5Sclose(sid); + H5Pclose(dataset_pl); + + /* ------------------------- + * Test collective writing to dataset1 + * -------------------------*/ + /* set up dimensions of the slab this process accesses */ + slab_set(mpi_rank, mpi_size, start, count, stride, block, BYROW); + + /* allocate memory for data buffer. Only allocate enough buffer for + * each processor's data. */ + if (mpi_rank) { + data_origin = (DATATYPE *)HDmalloc(block[0] * block[1] * sizeof(DATATYPE)); + VRFY((data_origin != NULL), "data_origin HDmalloc succeeded"); + + data_array = (DATATYPE *)HDmalloc(block[0] * block[1] * sizeof(DATATYPE)); + VRFY((data_array != NULL), "data_array HDmalloc succeeded"); + + /* put some trivial data in the data_array */ + mstart[0] = mstart[1] = 0; + dataset_fill(mstart, block, data_origin); + MESG("data_array initialized"); + if (VERBOSE_MED) { + MESG("data_array created"); + dataset_print(mstart, block, data_origin); + } + } + + /* create a memory dataspace independently */ + mem_dataspace = H5Screate_simple(RANK, block, NULL); + VRFY((mem_dataspace >= 0), ""); + + /* Process 0 has no selection */ + if (!mpi_rank) { + ret = H5Sselect_none(mem_dataspace); + VRFY((ret >= 0), "H5Sselect_none succeeded"); + } + + /* create a file dataspace independently */ + file_dataspace = H5Dget_space(dataset1); + VRFY((file_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab succeeded"); + + /* Process 0 has no selection */ + if (!mpi_rank) { + ret = H5Sselect_none(file_dataspace); + VRFY((ret >= 0), "H5Sselect_none succeeded"); + } + + /* set up the collective transfer properties list */ + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY((xfer_plist >= 0), "H5Pcreate xfer succeeded"); + ret = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + + /* write data collectively */ + ret = H5Dwrite(dataset1, H5T_NATIVE_INT, mem_dataspace, file_dataspace, xfer_plist, data_origin); + VRFY((ret >= 0), "H5Dwrite succeeded"); + + /* read data independently */ + ret = H5Dread(dataset1, H5T_NATIVE_INT, mem_dataspace, file_dataspace, H5P_DEFAULT, data_array); + VRFY((ret >= 0), ""); + + /* verify the read data with original expected data */ + if (mpi_rank) { + ret = dataset_vrfy(mstart, count, stride, block, data_array, data_origin); + if (ret) + nerrors++; + } + + /* ------------------------- + * Test independent writing to dataset2 + * -------------------------*/ + ret = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_INDEPENDENT); + VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + + /* write data collectively */ + ret = H5Dwrite(dataset2, H5T_NATIVE_INT, mem_dataspace, file_dataspace, xfer_plist, data_origin); + VRFY((ret >= 0), "H5Dwrite succeeded"); + + /* read data independently */ + ret = H5Dread(dataset2, H5T_NATIVE_INT, mem_dataspace, file_dataspace, H5P_DEFAULT, data_array); + VRFY((ret >= 0), ""); + + /* verify the read data with original expected data */ + if (mpi_rank) { + ret = dataset_vrfy(mstart, count, stride, block, data_array, data_origin); + if (ret) + nerrors++; + } + + /* release resource */ + ret = H5Sclose(file_dataspace); + VRFY((ret >= 0), "H5Sclose succeeded"); + ret = H5Sclose(mem_dataspace); + VRFY((ret >= 0), "H5Sclose succeeded"); + ret = H5Pclose(xfer_plist); + VRFY((ret >= 0), "H5Pclose succeeded"); + + /* close dataset collectively */ + ret = H5Dclose(dataset1); + VRFY((ret >= 0), "H5Dclose1 succeeded"); + ret = H5Dclose(dataset2); + VRFY((ret >= 0), "H5Dclose2 succeeded"); + + /* close the file collectively */ + H5Fclose(fid); + + /* release data buffers */ + if (data_origin) + HDfree(data_origin); + if (data_array) + HDfree(data_array); +} + +/* Function: test_actual_io_mode + * + * Purpose: tests one specific case of collective I/O and checks that the + * actual_chunk_opt_mode property and the actual_io_mode + * properties in the DXPL have the correct values. + * + * Input: selection_mode: changes the way processes select data from the space, as well + * as some dxpl flags to get collective I/O to break in different ways. + * + * The relevant I/O function and expected response for each mode: + * TEST_ACTUAL_IO_MULTI_CHUNK_IND: + * H5D_mpi_chunk_collective_io, each process reports independent I/O + * + * TEST_ACTUAL_IO_MULTI_CHUNK_COL: + * H5D_mpi_chunk_collective_io, each process reports collective I/O + * + * TEST_ACTUAL_IO_MULTI_CHUNK_MIX: + * H5D_mpi_chunk_collective_io, each process reports mixed I/O + * + * TEST_ACTUAL_IO_MULTI_CHUNK_MIX_DISAGREE: + * H5D_mpi_chunk_collective_io, processes disagree. The root reports + * collective, the rest report independent I/O + * + * TEST_ACTUAL_IO_DIRECT_MULTI_CHUNK_IND: + * Same test TEST_ACTUAL_IO_MULTI_CHUNK_IND. + * Set directly go to multi-chunk-io without num threshold calc. + * TEST_ACTUAL_IO_DIRECT_MULTI_CHUNK_COL: + * Same test TEST_ACTUAL_IO_MULTI_CHUNK_COL. + * Set directly go to multi-chunk-io without num threshold calc. + * + * TEST_ACTUAL_IO_LINK_CHUNK: + * H5D_link_chunk_collective_io, processes report linked chunk I/O + * + * TEST_ACTUAL_IO_CONTIGUOUS: + * H5D__contig_collective_write or H5D__contig_collective_read + * each process reports contiguous collective I/O + * + * TEST_ACTUAL_IO_NO_COLLECTIVE: + * Simple independent I/O. This tests that the defaults are properly set. + * + * TEST_ACTUAL_IO_RESET: + * Performs collective and then independent I/O with hthe same dxpl to + * make sure the peroperty is correctly reset to the default on each use. + * Specifically, this test runs TEST_ACTUAL_IO_MULTI_CHUNK_NO_OPT_MIX_DISAGREE + * (The most complex case that works on all builds) and then performs + * an independent read and write with the same dxpls. + * + * Note: DIRECT_MULTI_CHUNK_MIX and DIRECT_MULTI_CHUNK_MIX_DISAGREE + * is not needed as they are covered by DIRECT_CHUNK_MIX and + * MULTI_CHUNK_MIX_DISAGREE cases. _DIRECT_ cases are only for testing + * path way to multi-chunk-io by H5FD_MPIO_CHUNK_MULTI_IO instead of num-threshold. + * + * Modification: + * - Refctore to remove multi-chunk-without-opimization test and update for + * testing direct to multi-chunk-io + * Programmer: Jonathan Kim + * Date: 2012-10-10 + * + * + * Programmer: Jacob Gruber + * Date: 2011-04-06 + */ +static void +test_actual_io_mode(int selection_mode) +{ + H5D_mpio_actual_chunk_opt_mode_t actual_chunk_opt_mode_write = H5D_MPIO_NO_CHUNK_OPTIMIZATION; + H5D_mpio_actual_chunk_opt_mode_t actual_chunk_opt_mode_read = H5D_MPIO_NO_CHUNK_OPTIMIZATION; + H5D_mpio_actual_chunk_opt_mode_t actual_chunk_opt_mode_expected = H5D_MPIO_NO_CHUNK_OPTIMIZATION; + H5D_mpio_actual_io_mode_t actual_io_mode_write = H5D_MPIO_NO_COLLECTIVE; + H5D_mpio_actual_io_mode_t actual_io_mode_read = H5D_MPIO_NO_COLLECTIVE; + H5D_mpio_actual_io_mode_t actual_io_mode_expected = H5D_MPIO_NO_COLLECTIVE; + const char *filename; + const char *test_name; + hbool_t direct_multi_chunk_io; + hbool_t multi_chunk_io; + hbool_t is_chunked; + hbool_t is_collective; + int mpi_size = -1; + int mpi_rank = -1; + int length; + int *buffer; + int i; + MPI_Comm mpi_comm = MPI_COMM_NULL; + MPI_Info mpi_info = MPI_INFO_NULL; + hid_t fid = -1; + hid_t sid = -1; + hid_t dataset = -1; + hid_t data_type = H5T_NATIVE_INT; + hid_t fapl = -1; + hid_t mem_space = -1; + hid_t file_space = -1; + hid_t dcpl = -1; + hid_t dxpl_write = -1; + hid_t dxpl_read = -1; + hsize_t dims[RANK]; + hsize_t chunk_dims[RANK]; + hsize_t start[RANK]; + hsize_t stride[RANK]; + hsize_t count[RANK]; + hsize_t block[RANK]; + char message[256]; + herr_t ret; + + /* Set up some flags to make some future if statements slightly more readable */ + direct_multi_chunk_io = (selection_mode == TEST_ACTUAL_IO_DIRECT_MULTI_CHUNK_IND || + selection_mode == TEST_ACTUAL_IO_DIRECT_MULTI_CHUNK_COL); + + /* Note: RESET performs the same tests as MULTI_CHUNK_MIX_DISAGREE and then + * tests independent I/O + */ + multi_chunk_io = + (selection_mode == TEST_ACTUAL_IO_MULTI_CHUNK_IND || + selection_mode == TEST_ACTUAL_IO_MULTI_CHUNK_COL || + selection_mode == TEST_ACTUAL_IO_MULTI_CHUNK_MIX || + selection_mode == TEST_ACTUAL_IO_MULTI_CHUNK_MIX_DISAGREE || selection_mode == TEST_ACTUAL_IO_RESET); + + is_chunked = + (selection_mode != TEST_ACTUAL_IO_CONTIGUOUS && selection_mode != TEST_ACTUAL_IO_NO_COLLECTIVE); + + is_collective = selection_mode != TEST_ACTUAL_IO_NO_COLLECTIVE; + + /* Set up MPI parameters */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file or dataset aren't supported with this connector\n"); + fflush(stdout); + } + + return; + } + + MPI_Barrier(MPI_COMM_WORLD); + + HDassert(mpi_size >= 1); + + mpi_comm = MPI_COMM_WORLD; + mpi_info = MPI_INFO_NULL; + + filename = (const char *)PARATESTFILE /* GetTestParameters() */; + HDassert(filename != NULL); + + /* Setup the file access template */ + fapl = create_faccess_plist(mpi_comm, mpi_info, facc_type); + VRFY((fapl >= 0), "create_faccess_plist() succeeded"); + + /* Create the file */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + VRFY((fid >= 0), "H5Fcreate succeeded"); + + /* Create the basic Space */ + dims[0] = (hsize_t)dim0; + dims[1] = (hsize_t)dim1; + sid = H5Screate_simple(RANK, dims, NULL); + VRFY((sid >= 0), "H5Screate_simple succeeded"); + + /* Create the dataset creation plist */ + dcpl = H5Pcreate(H5P_DATASET_CREATE); + VRFY((dcpl >= 0), "dataset creation plist created successfully"); + + /* If we are not testing contiguous datasets */ + if (is_chunked) { + /* Set up chunk information. */ + chunk_dims[0] = dims[0] / (hsize_t)mpi_size; + chunk_dims[1] = dims[1]; + ret = H5Pset_chunk(dcpl, 2, chunk_dims); + VRFY((ret >= 0), "chunk creation property list succeeded"); + } + + /* Create the dataset */ + dataset = H5Dcreate2(fid, "actual_io", data_type, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + VRFY((dataset >= 0), "H5Dcreate2() dataset succeeded"); + + /* Create the file dataspace */ + file_space = H5Dget_space(dataset); + VRFY((file_space >= 0), "H5Dget_space succeeded"); + + /* Choose a selection method based on the type of I/O we want to occur, + * and also set up some selection-dependeent test info. */ + switch (selection_mode) { + + /* Independent I/O with optimization */ + case TEST_ACTUAL_IO_MULTI_CHUNK_IND: + case TEST_ACTUAL_IO_DIRECT_MULTI_CHUNK_IND: + /* Since the dataset is chunked by row and each process selects a row, + * each process writes to a different chunk. This forces all I/O to be + * independent. + */ + slab_set(mpi_rank, mpi_size, start, count, stride, block, BYROW); + + test_name = "Multi Chunk - Independent"; + actual_chunk_opt_mode_expected = H5D_MPIO_MULTI_CHUNK; + actual_io_mode_expected = H5D_MPIO_CHUNK_INDEPENDENT; + break; + + /* Collective I/O with optimization */ + case TEST_ACTUAL_IO_MULTI_CHUNK_COL: + case TEST_ACTUAL_IO_DIRECT_MULTI_CHUNK_COL: + /* The dataset is chunked by rows, so each process takes a column which + * spans all chunks. Since the processes write non-overlapping regular + * selections to each chunk, the operation is purely collective. + */ + slab_set(mpi_rank, mpi_size, start, count, stride, block, BYCOL); + + test_name = "Multi Chunk - Collective"; + actual_chunk_opt_mode_expected = H5D_MPIO_MULTI_CHUNK; + if (mpi_size > 1) + actual_io_mode_expected = H5D_MPIO_CHUNK_COLLECTIVE; + else + actual_io_mode_expected = H5D_MPIO_CHUNK_INDEPENDENT; + break; + + /* Mixed I/O with optimization */ + case TEST_ACTUAL_IO_MULTI_CHUNK_MIX: + /* A chunk will be assigned collective I/O only if it is selected by each + * process. To get mixed I/O, have the root select all chunks and each + * subsequent process select the first and nth chunk. The first chunk, + * accessed by all, will be assigned collective I/O while each other chunk + * will be accessed only by the root and the nth process and will be + * assigned independent I/O. Each process will access one chunk collectively + * and at least one chunk independently, reporting mixed I/O. + */ + + if (mpi_rank == 0) { + /* Select the first column */ + slab_set(mpi_rank, mpi_size, start, count, stride, block, BYCOL); + } + else { + /* Select the first and the nth chunk in the nth column */ + block[0] = (hsize_t)(dim0 / mpi_size); + block[1] = (hsize_t)(dim1 / mpi_size); + count[0] = 2; + count[1] = 1; + stride[0] = (hsize_t)mpi_rank * block[0]; + stride[1] = 1; + start[0] = 0; + start[1] = (hsize_t)mpi_rank * block[1]; + } + + test_name = "Multi Chunk - Mixed"; + actual_chunk_opt_mode_expected = H5D_MPIO_MULTI_CHUNK; + actual_io_mode_expected = H5D_MPIO_CHUNK_MIXED; + break; + + /* RESET tests that the properties are properly reset to defaults each time I/O is + * performed. To achieve this, we have RESET perform collective I/O (which would change + * the values from the defaults) followed by independent I/O (which should report the + * default values). RESET doesn't need to have a unique selection, so we reuse + * MULTI_CHUMK_MIX_DISAGREE, which was chosen because it is a complex case that works + * on all builds. The independent section of RESET can be found at the end of this function. + */ + case TEST_ACTUAL_IO_RESET: + + /* Mixed I/O with optimization and internal disagreement */ + case TEST_ACTUAL_IO_MULTI_CHUNK_MIX_DISAGREE: + /* A chunk will be assigned collective I/O only if it is selected by each + * process. To get mixed I/O with disagreement, assign process n to the + * first chunk and the nth chunk. The first chunk, selected by all, is + * assgigned collective I/O, while each other process gets independent I/O. + * Since the root process with only access the first chunk, it will report + * collective I/O. The subsequent processes will access the first chunk + * collectively, and their other chunk independently, reporting mixed I/O. + */ + + if (mpi_rank == 0) { + /* Select the first chunk in the first column */ + slab_set(mpi_rank, mpi_size, start, count, stride, block, BYCOL); + block[0] = block[0] / (hsize_t)mpi_size; + } + else { + /* Select the first and the nth chunk in the nth column */ + block[0] = (hsize_t)(dim0 / mpi_size); + block[1] = (hsize_t)(dim1 / mpi_size); + count[0] = 2; + count[1] = 1; + stride[0] = (hsize_t)mpi_rank * block[0]; + stride[1] = 1; + start[0] = 0; + start[1] = (hsize_t)mpi_rank * block[1]; + } + + /* If the testname was not already set by the RESET case */ + if (selection_mode == TEST_ACTUAL_IO_RESET) + test_name = "RESET"; + else + test_name = "Multi Chunk - Mixed (Disagreement)"; + + actual_chunk_opt_mode_expected = H5D_MPIO_MULTI_CHUNK; + if (mpi_size > 1) { + if (mpi_rank == 0) + actual_io_mode_expected = H5D_MPIO_CHUNK_COLLECTIVE; + else + actual_io_mode_expected = H5D_MPIO_CHUNK_MIXED; + } + else + actual_io_mode_expected = H5D_MPIO_CHUNK_INDEPENDENT; + + break; + + /* Linked Chunk I/O */ + case TEST_ACTUAL_IO_LINK_CHUNK: + /* Nothing special; link chunk I/O is forced in the dxpl settings. */ + slab_set(mpi_rank, mpi_size, start, count, stride, block, BYROW); + + test_name = "Link Chunk"; + actual_chunk_opt_mode_expected = H5D_MPIO_LINK_CHUNK; + actual_io_mode_expected = H5D_MPIO_CHUNK_COLLECTIVE; + break; + + /* Contiguous Dataset */ + case TEST_ACTUAL_IO_CONTIGUOUS: + /* A non overlapping, regular selection in a contiguous dataset leads to + * collective I/O */ + slab_set(mpi_rank, mpi_size, start, count, stride, block, BYROW); + + test_name = "Contiguous"; + actual_chunk_opt_mode_expected = H5D_MPIO_NO_CHUNK_OPTIMIZATION; + actual_io_mode_expected = H5D_MPIO_CONTIGUOUS_COLLECTIVE; + break; + + case TEST_ACTUAL_IO_NO_COLLECTIVE: + slab_set(mpi_rank, mpi_size, start, count, stride, block, BYROW); + + test_name = "Independent"; + actual_chunk_opt_mode_expected = H5D_MPIO_NO_CHUNK_OPTIMIZATION; + actual_io_mode_expected = H5D_MPIO_NO_COLLECTIVE; + break; + + default: + test_name = "Undefined Selection Mode"; + actual_chunk_opt_mode_expected = H5D_MPIO_NO_CHUNK_OPTIMIZATION; + actual_io_mode_expected = H5D_MPIO_NO_COLLECTIVE; + break; + } + + ret = H5Sselect_hyperslab(file_space, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab succeeded"); + + /* Create a memory dataspace mirroring the dataset and select the same hyperslab + * as in the file space. + */ + mem_space = H5Screate_simple(RANK, dims, NULL); + VRFY((mem_space >= 0), "mem_space created"); + + ret = H5Sselect_hyperslab(mem_space, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab succeeded"); + + /* Get the number of elements in the selection */ + length = dim0 * dim1; + + /* Allocate and initialize the buffer */ + buffer = (int *)HDmalloc(sizeof(int) * (size_t)length); + VRFY((buffer != NULL), "HDmalloc of buffer succeeded"); + for (i = 0; i < length; i++) + buffer[i] = i; + + /* Set up the dxpl for the write */ + dxpl_write = H5Pcreate(H5P_DATASET_XFER); + VRFY((dxpl_write >= 0), "H5Pcreate(H5P_DATASET_XFER) succeeded"); + + /* Set collective I/O properties in the dxpl. */ + if (is_collective) { + /* Request collective I/O */ + ret = H5Pset_dxpl_mpio(dxpl_write, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + + /* Set the threshold number of processes per chunk to twice mpi_size. + * This will prevent the threshold from ever being met, thus forcing + * multi chunk io instead of link chunk io. + * This is via default. + */ + if (multi_chunk_io) { + /* force multi-chunk-io by threshold */ + ret = H5Pset_dxpl_mpio_chunk_opt_num(dxpl_write, (unsigned)mpi_size * 2); + VRFY((ret >= 0), "H5Pset_dxpl_mpio_chunk_opt_num succeeded"); + + /* set this to manipulate testing scenario about allocating processes + * to chunks */ + ret = H5Pset_dxpl_mpio_chunk_opt_ratio(dxpl_write, (unsigned)99); + VRFY((ret >= 0), "H5Pset_dxpl_mpio_chunk_opt_ratio succeeded"); + } + + /* Set directly go to multi-chunk-io without threshold calc. */ + if (direct_multi_chunk_io) { + /* set for multi chunk io by property*/ + ret = H5Pset_dxpl_mpio_chunk_opt(dxpl_write, H5FD_MPIO_CHUNK_MULTI_IO); + VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + } + } + + /* Make a copy of the dxpl to test the read operation */ + dxpl_read = H5Pcopy(dxpl_write); + VRFY((dxpl_read >= 0), "H5Pcopy succeeded"); + + /* Write */ + ret = H5Dwrite(dataset, data_type, mem_space, file_space, dxpl_write, buffer); + if (ret < 0) + H5Eprint2(H5E_DEFAULT, stdout); + VRFY((ret >= 0), "H5Dwrite() dataset multichunk write succeeded"); + + /* Retrieve Actual io values */ + ret = H5Pget_mpio_actual_io_mode(dxpl_write, &actual_io_mode_write); + VRFY((ret >= 0), "retrieving actual io mode succeeded"); + + ret = H5Pget_mpio_actual_chunk_opt_mode(dxpl_write, &actual_chunk_opt_mode_write); + VRFY((ret >= 0), "retrieving actual chunk opt mode succeeded"); + + /* Read */ + ret = H5Dread(dataset, data_type, mem_space, file_space, dxpl_read, buffer); + if (ret < 0) + H5Eprint2(H5E_DEFAULT, stdout); + VRFY((ret >= 0), "H5Dread() dataset multichunk read succeeded"); + + /* Retrieve Actual io values */ + ret = H5Pget_mpio_actual_io_mode(dxpl_read, &actual_io_mode_read); + VRFY((ret >= 0), "retrieving actual io mode succeeded"); + + ret = H5Pget_mpio_actual_chunk_opt_mode(dxpl_read, &actual_chunk_opt_mode_read); + VRFY((ret >= 0), "retrieving actual chunk opt mode succeeded"); + + /* Check write vs read */ + VRFY((actual_io_mode_read == actual_io_mode_write), + "reading and writing are the same for actual_io_mode"); + VRFY((actual_chunk_opt_mode_read == actual_chunk_opt_mode_write), + "reading and writing are the same for actual_chunk_opt_mode"); + + /* Test values */ + if (actual_chunk_opt_mode_expected != (H5D_mpio_actual_chunk_opt_mode_t)-1 && + actual_io_mode_expected != (H5D_mpio_actual_io_mode_t)-1) { + HDsnprintf(message, sizeof(message), "Actual Chunk Opt Mode has the correct value for %s.\n", + test_name); + VRFY((actual_chunk_opt_mode_write == actual_chunk_opt_mode_expected), message); + HDsnprintf(message, sizeof(message), "Actual IO Mode has the correct value for %s.\n", test_name); + VRFY((actual_io_mode_write == actual_io_mode_expected), message); + } + else { + HDfprintf(stderr, "%s %d -> (%d,%d)\n", test_name, mpi_rank, actual_chunk_opt_mode_write, + actual_io_mode_write); + } + + /* To test that the property is successfully reset to the default, we perform some + * independent I/O after the collective I/O + */ + if (selection_mode == TEST_ACTUAL_IO_RESET) { + if (mpi_rank == 0) { + /* Switch to independent io */ + ret = H5Pset_dxpl_mpio(dxpl_write, H5FD_MPIO_INDEPENDENT); + VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + ret = H5Pset_dxpl_mpio(dxpl_read, H5FD_MPIO_INDEPENDENT); + VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + + /* Write */ + ret = H5Dwrite(dataset, data_type, H5S_ALL, H5S_ALL, dxpl_write, buffer); + VRFY((ret >= 0), "H5Dwrite() dataset multichunk write succeeded"); + + /* Check Properties */ + ret = H5Pget_mpio_actual_io_mode(dxpl_write, &actual_io_mode_write); + VRFY((ret >= 0), "retrieving actual io mode succeeded"); + ret = H5Pget_mpio_actual_chunk_opt_mode(dxpl_write, &actual_chunk_opt_mode_write); + VRFY((ret >= 0), "retrieving actual chunk opt mode succeeded"); + + VRFY(actual_chunk_opt_mode_write == H5D_MPIO_NO_CHUNK_OPTIMIZATION, + "actual_chunk_opt_mode has correct value for reset write (independent)"); + VRFY(actual_io_mode_write == H5D_MPIO_NO_COLLECTIVE, + "actual_io_mode has correct value for reset write (independent)"); + + /* Read */ + ret = H5Dread(dataset, data_type, H5S_ALL, H5S_ALL, dxpl_read, buffer); + VRFY((ret >= 0), "H5Dwrite() dataset multichunk write succeeded"); + + /* Check Properties */ + ret = H5Pget_mpio_actual_io_mode(dxpl_read, &actual_io_mode_read); + VRFY((ret >= 0), "retrieving actual io mode succeeded"); + ret = H5Pget_mpio_actual_chunk_opt_mode(dxpl_read, &actual_chunk_opt_mode_read); + VRFY((ret >= 0), "retrieving actual chunk opt mode succeeded"); + + VRFY(actual_chunk_opt_mode_read == H5D_MPIO_NO_CHUNK_OPTIMIZATION, + "actual_chunk_opt_mode has correct value for reset read (independent)"); + VRFY(actual_io_mode_read == H5D_MPIO_NO_COLLECTIVE, + "actual_io_mode has correct value for reset read (independent)"); + } + } + + /* Release some resources */ + ret = H5Sclose(sid); + VRFY((ret >= 0), "H5Sclose succeeded"); + ret = H5Pclose(fapl); + VRFY((ret >= 0), "H5Pclose succeeded"); + ret = H5Pclose(dcpl); + VRFY((ret >= 0), "H5Pclose succeeded"); + ret = H5Pclose(dxpl_write); + VRFY((ret >= 0), "H5Pclose succeeded"); + ret = H5Pclose(dxpl_read); + VRFY((ret >= 0), "H5Pclose succeeded"); + ret = H5Dclose(dataset); + VRFY((ret >= 0), "H5Dclose succeeded"); + ret = H5Sclose(mem_space); + VRFY((ret >= 0), "H5Sclose succeeded"); + ret = H5Sclose(file_space); + VRFY((ret >= 0), "H5Sclose succeeded"); + ret = H5Fclose(fid); + VRFY((ret >= 0), "H5Fclose succeeded"); + HDfree(buffer); + return; +} + +/* Function: actual_io_mode_tests + * + * Purpose: Tests all possible cases of the actual_io_mode property. + * + * Programmer: Jacob Gruber + * Date: 2011-04-06 + */ +void +actual_io_mode_tests(void) +{ + int mpi_size = -1; + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + + /* Only run these tests if selection I/O is not being used - selection I/O + * bypasses this IO mode decision - it's effectively always multi chunk + * currently */ + if (/* !H5_use_selection_io_g */ TRUE) { + test_actual_io_mode(TEST_ACTUAL_IO_NO_COLLECTIVE); + + /* + * Test multi-chunk-io via proc_num threshold + */ + test_actual_io_mode(TEST_ACTUAL_IO_MULTI_CHUNK_IND); + test_actual_io_mode(TEST_ACTUAL_IO_MULTI_CHUNK_COL); + + /* The Multi Chunk Mixed test requires at least three processes. */ + if (mpi_size > 2) + test_actual_io_mode(TEST_ACTUAL_IO_MULTI_CHUNK_MIX); + else + HDfprintf(stdout, "Multi Chunk Mixed test requires 3 processes minimum\n"); + + test_actual_io_mode(TEST_ACTUAL_IO_MULTI_CHUNK_MIX_DISAGREE); + + /* + * Test multi-chunk-io via setting direct property + */ + test_actual_io_mode(TEST_ACTUAL_IO_DIRECT_MULTI_CHUNK_IND); + test_actual_io_mode(TEST_ACTUAL_IO_DIRECT_MULTI_CHUNK_COL); + + test_actual_io_mode(TEST_ACTUAL_IO_LINK_CHUNK); + test_actual_io_mode(TEST_ACTUAL_IO_CONTIGUOUS); + + test_actual_io_mode(TEST_ACTUAL_IO_RESET); + } + + return; +} + +/* + * Function: test_no_collective_cause_mode + * + * Purpose: + * tests cases for broken collective I/O and checks that the + * H5Pget_mpio_no_collective_cause properties in the DXPL have the correct values. + * + * Input: + * selection_mode: various mode to cause broken collective I/O + * Note: Originally, each TEST case is supposed to be used alone. + * After some discussion, this is updated to take multiple TEST cases + * with '|'. However there is no error check for any of combined + * test cases, so a tester is responsible to understand and feed + * proper combination of TESTs if needed. + * + * + * TEST_COLLECTIVE: + * Test for regular collective I/O without cause of breaking. + * Just to test normal behavior. + * + * TEST_SET_INDEPENDENT: + * Test for Independent I/O as the cause of breaking collective I/O. + * + * TEST_DATATYPE_CONVERSION: + * Test for Data Type Conversion as the cause of breaking collective I/O. + * + * TEST_DATA_TRANSFORMS: + * Test for Data Transform feature as the cause of breaking collective I/O. + * + * TEST_NOT_SIMPLE_OR_SCALAR_DATASPACES: + * Test for NULL dataspace as the cause of breaking collective I/O. + * + * TEST_NOT_CONTIGUOUS_OR_CHUNKED_DATASET_COMPACT: + * Test for Compact layout as the cause of breaking collective I/O. + * + * TEST_NOT_CONTIGUOUS_OR_CHUNKED_DATASET_EXTERNAL: + * Test for Externl-File storage as the cause of breaking collective I/O. + * + * Programmer: Jonathan Kim + * Date: Aug, 2012 + */ +#ifdef LATER +#define DSET_NOCOLCAUSE "nocolcause" +#endif +#define FILE_EXTERNAL "nocolcause_extern.data" +static void +test_no_collective_cause_mode(int selection_mode) +{ + uint32_t no_collective_cause_local_write = 0; + uint32_t no_collective_cause_local_read = 0; + uint32_t no_collective_cause_local_expected = 0; + uint32_t no_collective_cause_global_write = 0; + uint32_t no_collective_cause_global_read = 0; + uint32_t no_collective_cause_global_expected = 0; + + const char *filename; + const char *test_name; + hbool_t is_chunked = 1; + hbool_t is_independent = 0; + int mpi_size = -1; + int mpi_rank = -1; + int length; + int *buffer; + int i; + MPI_Comm mpi_comm; + MPI_Info mpi_info; + hid_t fid = -1; + hid_t sid = -1; + hid_t dataset = -1; + hid_t data_type = H5T_NATIVE_INT; + hid_t fapl = -1; + hid_t dcpl = -1; + hid_t dxpl_write = -1; + hid_t dxpl_read = -1; + hsize_t dims[RANK]; + hid_t mem_space = -1; + hid_t file_space = -1; + hsize_t chunk_dims[RANK]; + herr_t ret; + /* set to global value as default */ + int l_facc_type = facc_type; + char message[256]; + + /* Set up MPI parameters */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + MPI_Barrier(MPI_COMM_WORLD); + + HDassert(mpi_size >= 1); + + mpi_comm = MPI_COMM_WORLD; + mpi_info = MPI_INFO_NULL; + + /* Create the dataset creation plist */ + dcpl = H5Pcreate(H5P_DATASET_CREATE); + VRFY((dcpl >= 0), "dataset creation plist created successfully"); + + if (selection_mode & TEST_NOT_CONTIGUOUS_OR_CHUNKED_DATASET_COMPACT) { + ret = H5Pset_layout(dcpl, H5D_COMPACT); + VRFY((ret >= 0), "set COMPACT layout succeeded"); + is_chunked = 0; + } + + if (selection_mode & TEST_NOT_CONTIGUOUS_OR_CHUNKED_DATASET_EXTERNAL) { + ret = H5Pset_external(dcpl, FILE_EXTERNAL, (off_t)0, H5F_UNLIMITED); + VRFY((ret >= 0), "set EXTERNAL file layout succeeded"); + is_chunked = 0; + } + + if (selection_mode & TEST_NOT_SIMPLE_OR_SCALAR_DATASPACES) { + sid = H5Screate(H5S_NULL); + VRFY((sid >= 0), "H5Screate_simple succeeded"); + is_chunked = 0; + } + else { + /* Create the basic Space */ + /* if this is a compact dataset, create a small dataspace that does not exceed 64K */ + if (selection_mode & TEST_NOT_CONTIGUOUS_OR_CHUNKED_DATASET_COMPACT) { + dims[0] = ROW_FACTOR * 6; + dims[1] = COL_FACTOR * 6; + } + else { + dims[0] = (hsize_t)dim0; + dims[1] = (hsize_t)dim1; + } + sid = H5Screate_simple(RANK, dims, NULL); + VRFY((sid >= 0), "H5Screate_simple succeeded"); + } + + filename = (const char *)PARATESTFILE /* GetTestParameters() */; + HDassert(filename != NULL); + + /* Setup the file access template */ + fapl = create_faccess_plist(mpi_comm, mpi_info, l_facc_type); + VRFY((fapl >= 0), "create_faccess_plist() succeeded"); + + /* Create the file */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + + VRFY((fid >= 0), "H5Fcreate succeeded"); + + /* If we are not testing contiguous datasets */ + if (is_chunked) { + /* Set up chunk information. */ + chunk_dims[0] = dims[0] / (hsize_t)mpi_size; + chunk_dims[1] = dims[1]; + ret = H5Pset_chunk(dcpl, 2, chunk_dims); + VRFY((ret >= 0), "chunk creation property list succeeded"); + } + + /* Create the dataset */ + dataset = H5Dcreate2(fid, "nocolcause", data_type, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + VRFY((dataset >= 0), "H5Dcreate2() dataset succeeded"); + + /* + * Set expected causes and some tweaks based on the type of test + */ + if (selection_mode & TEST_DATATYPE_CONVERSION) { + test_name = "Broken Collective I/O - Datatype Conversion"; + no_collective_cause_local_expected |= H5D_MPIO_DATATYPE_CONVERSION; + no_collective_cause_global_expected |= H5D_MPIO_DATATYPE_CONVERSION; + /* set different sign to trigger type conversion */ + data_type = H5T_NATIVE_UINT; + } + + if (selection_mode & TEST_DATA_TRANSFORMS) { + test_name = "Broken Collective I/O - DATA Transforms"; + no_collective_cause_local_expected |= H5D_MPIO_DATA_TRANSFORMS; + no_collective_cause_global_expected |= H5D_MPIO_DATA_TRANSFORMS; + } + + if (selection_mode & TEST_NOT_SIMPLE_OR_SCALAR_DATASPACES) { + test_name = "Broken Collective I/O - No Simple or Scalar DataSpace"; + no_collective_cause_local_expected |= H5D_MPIO_NOT_SIMPLE_OR_SCALAR_DATASPACES; + no_collective_cause_global_expected |= H5D_MPIO_NOT_SIMPLE_OR_SCALAR_DATASPACES; + } + + if (selection_mode & TEST_NOT_CONTIGUOUS_OR_CHUNKED_DATASET_COMPACT || + selection_mode & TEST_NOT_CONTIGUOUS_OR_CHUNKED_DATASET_EXTERNAL) { + test_name = "Broken Collective I/O - No CONTI or CHUNKED Dataset"; + no_collective_cause_local_expected |= H5D_MPIO_NOT_CONTIGUOUS_OR_CHUNKED_DATASET; + no_collective_cause_global_expected |= H5D_MPIO_NOT_CONTIGUOUS_OR_CHUNKED_DATASET; + } + + if (selection_mode & TEST_COLLECTIVE) { + test_name = "Broken Collective I/O - Not Broken"; + no_collective_cause_local_expected = H5D_MPIO_COLLECTIVE; + no_collective_cause_global_expected = H5D_MPIO_COLLECTIVE; + } + + if (selection_mode & TEST_SET_INDEPENDENT) { + test_name = "Broken Collective I/O - Independent"; + no_collective_cause_local_expected = H5D_MPIO_SET_INDEPENDENT; + no_collective_cause_global_expected = H5D_MPIO_SET_INDEPENDENT; + /* switch to independent io */ + is_independent = 1; + } + + /* use all spaces for certain tests */ + if (selection_mode & TEST_NOT_SIMPLE_OR_SCALAR_DATASPACES || + selection_mode & TEST_NOT_CONTIGUOUS_OR_CHUNKED_DATASET_EXTERNAL) { + file_space = H5S_ALL; + mem_space = H5S_ALL; + } + else { + /* Get the file dataspace */ + file_space = H5Dget_space(dataset); + VRFY((file_space >= 0), "H5Dget_space succeeded"); + + /* Create the memory dataspace */ + mem_space = H5Screate_simple(RANK, dims, NULL); + VRFY((mem_space >= 0), "mem_space created"); + } + + /* Get the number of elements in the selection */ + length = (int)(dims[0] * dims[1]); + + /* Allocate and initialize the buffer */ + buffer = (int *)HDmalloc(sizeof(int) * (size_t)length); + VRFY((buffer != NULL), "HDmalloc of buffer succeeded"); + for (i = 0; i < length; i++) + buffer[i] = i; + + /* Set up the dxpl for the write */ + dxpl_write = H5Pcreate(H5P_DATASET_XFER); + VRFY((dxpl_write >= 0), "H5Pcreate(H5P_DATASET_XFER) succeeded"); + + if (is_independent) { + /* Set Independent I/O */ + ret = H5Pset_dxpl_mpio(dxpl_write, H5FD_MPIO_INDEPENDENT); + VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + } + else { + /* Set Collective I/O */ + ret = H5Pset_dxpl_mpio(dxpl_write, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + } + + if (selection_mode & TEST_DATA_TRANSFORMS) { + ret = H5Pset_data_transform(dxpl_write, "x+1"); + VRFY((ret >= 0), "H5Pset_data_transform succeeded"); + } + + /*--------------------- + * Test Write access + *---------------------*/ + + /* Write */ + ret = H5Dwrite(dataset, data_type, mem_space, file_space, dxpl_write, buffer); + if (ret < 0) + H5Eprint2(H5E_DEFAULT, stdout); + VRFY((ret >= 0), "H5Dwrite() dataset multichunk write succeeded"); + + /* Get the cause of broken collective I/O */ + ret = H5Pget_mpio_no_collective_cause(dxpl_write, &no_collective_cause_local_write, + &no_collective_cause_global_write); + VRFY((ret >= 0), "retrieving no collective cause succeeded"); + + /*--------------------- + * Test Read access + *---------------------*/ + + /* Make a copy of the dxpl to test the read operation */ + dxpl_read = H5Pcopy(dxpl_write); + VRFY((dxpl_read >= 0), "H5Pcopy succeeded"); + + /* Read */ + ret = H5Dread(dataset, data_type, mem_space, file_space, dxpl_read, buffer); + + if (ret < 0) + H5Eprint2(H5E_DEFAULT, stdout); + VRFY((ret >= 0), "H5Dread() dataset multichunk read succeeded"); + + /* Get the cause of broken collective I/O */ + ret = H5Pget_mpio_no_collective_cause(dxpl_read, &no_collective_cause_local_read, + &no_collective_cause_global_read); + VRFY((ret >= 0), "retrieving no collective cause succeeded"); + + /* Check write vs read */ + VRFY((no_collective_cause_local_read == no_collective_cause_local_write), + "reading and writing are the same for local cause of Broken Collective I/O"); + VRFY((no_collective_cause_global_read == no_collective_cause_global_write), + "reading and writing are the same for global cause of Broken Collective I/O"); + + /* Test values */ + HDmemset(message, 0, sizeof(message)); + HDsnprintf(message, sizeof(message), + "Local cause of Broken Collective I/O has the correct value for %s.\n", test_name); + VRFY((no_collective_cause_local_write == no_collective_cause_local_expected), message); + HDmemset(message, 0, sizeof(message)); + HDsnprintf(message, sizeof(message), + "Global cause of Broken Collective I/O has the correct value for %s.\n", test_name); + VRFY((no_collective_cause_global_write == no_collective_cause_global_expected), message); + + /* Release some resources */ + if (sid) + H5Sclose(sid); + if (dcpl) + H5Pclose(dcpl); + if (dxpl_write) + H5Pclose(dxpl_write); + if (dxpl_read) + H5Pclose(dxpl_read); + if (dataset) + H5Dclose(dataset); + if (mem_space) + H5Sclose(mem_space); + if (file_space) + H5Sclose(file_space); + if (fid) + H5Fclose(fid); + HDfree(buffer); + + /* clean up external file */ + if (selection_mode & TEST_NOT_CONTIGUOUS_OR_CHUNKED_DATASET_EXTERNAL) + H5Fdelete(FILE_EXTERNAL, fapl); + + if (fapl) + H5Pclose(fapl); + + return; +} + +/* Function: no_collective_cause_tests + * + * Purpose: Tests cases for broken collective IO. + * + * Programmer: Jonathan Kim + * Date: Aug, 2012 + */ +void +no_collective_cause_tests(void) +{ + /* + * Test individual cause + */ + test_no_collective_cause_mode(TEST_COLLECTIVE); + test_no_collective_cause_mode(TEST_SET_INDEPENDENT); + test_no_collective_cause_mode(TEST_DATATYPE_CONVERSION); + test_no_collective_cause_mode(TEST_DATA_TRANSFORMS); + test_no_collective_cause_mode(TEST_NOT_SIMPLE_OR_SCALAR_DATASPACES); + test_no_collective_cause_mode(TEST_NOT_CONTIGUOUS_OR_CHUNKED_DATASET_COMPACT); + test_no_collective_cause_mode(TEST_NOT_CONTIGUOUS_OR_CHUNKED_DATASET_EXTERNAL); + + /* + * Test combined causes + */ + test_no_collective_cause_mode(TEST_NOT_CONTIGUOUS_OR_CHUNKED_DATASET_EXTERNAL | TEST_DATATYPE_CONVERSION); + test_no_collective_cause_mode(TEST_DATATYPE_CONVERSION | TEST_DATA_TRANSFORMS); + test_no_collective_cause_mode(TEST_NOT_CONTIGUOUS_OR_CHUNKED_DATASET_EXTERNAL | TEST_DATATYPE_CONVERSION | + TEST_DATA_TRANSFORMS); + + return; +} + +/* + * Test consistency semantics of atomic mode + */ + +/* + * Example of using the parallel HDF5 library to create a dataset, + * where process 0 writes and the other processes read at the same + * time. If atomic mode is set correctly, the other processes should + * read the old values in the dataset or the new ones. + */ + +void +dataset_atomicity(void) +{ + hid_t fid; /* HDF5 file ID */ + hid_t acc_tpl; /* File access templates */ + hid_t sid; /* Dataspace ID */ + hid_t dataset1; /* Dataset IDs */ + hsize_t dims[RANK]; /* dataset dim sizes */ + int *write_buf = NULL; /* data buffer */ + int *read_buf = NULL; /* data buffer */ + int buf_size; + hid_t dataset2; + hid_t file_dataspace; /* File dataspace ID */ + hid_t mem_dataspace; /* Memory dataspace ID */ + hsize_t start[RANK]; + hsize_t stride[RANK]; + hsize_t count[RANK]; + hsize_t block[RANK]; + const char *filename; + herr_t ret; /* Generic return value */ + int mpi_size, mpi_rank; + int i, j, k; + hbool_t atomicity = FALSE; + MPI_Comm comm = MPI_COMM_WORLD; + MPI_Info info = MPI_INFO_NULL; + + dim0 = 64; + dim1 = 32; + filename = PARATESTFILE /* GetTestParameters() */; + if (facc_type != FACC_MPIO) { + HDprintf("Atomicity tests will not work without the MPIO VFD\n"); + return; + } + if (VERBOSE_MED) + HDprintf("atomic writes to file %s\n", filename); + + /* set up MPI parameters */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, basic dataset, or more aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + buf_size = dim0 * dim1; + /* allocate memory for data buffer */ + write_buf = (int *)HDcalloc((size_t)buf_size, sizeof(int)); + VRFY((write_buf != NULL), "write_buf HDcalloc succeeded"); + /* allocate memory for data buffer */ + read_buf = (int *)HDcalloc((size_t)buf_size, sizeof(int)); + VRFY((read_buf != NULL), "read_buf HDcalloc succeeded"); + + /* setup file access template */ + acc_tpl = create_faccess_plist(comm, info, facc_type); + VRFY((acc_tpl >= 0), ""); + + /* create the file collectively */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, acc_tpl); + VRFY((fid >= 0), "H5Fcreate succeeded"); + + /* Release file-access template */ + ret = H5Pclose(acc_tpl); + VRFY((ret >= 0), "H5Pclose succeeded"); + + /* setup dimensionality object */ + dims[0] = (hsize_t)dim0; + dims[1] = (hsize_t)dim1; + sid = H5Screate_simple(RANK, dims, NULL); + VRFY((sid >= 0), "H5Screate_simple succeeded"); + + /* create datasets */ + dataset1 = H5Dcreate2(fid, DATASETNAME5, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((dataset1 >= 0), "H5Dcreate2 succeeded"); + + dataset2 = H5Dcreate2(fid, DATASETNAME6, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((dataset2 >= 0), "H5Dcreate2 succeeded"); + + /* initialize datasets to 0s */ + if (0 == mpi_rank) { + ret = H5Dwrite(dataset1, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, write_buf); + VRFY((ret >= 0), "H5Dwrite dataset1 succeeded"); + + ret = H5Dwrite(dataset2, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, write_buf); + VRFY((ret >= 0), "H5Dwrite dataset2 succeeded"); + } + + ret = H5Dclose(dataset1); + VRFY((ret >= 0), "H5Dclose succeeded"); + ret = H5Dclose(dataset2); + VRFY((ret >= 0), "H5Dclose succeeded"); + ret = H5Sclose(sid); + VRFY((ret >= 0), "H5Sclose succeeded"); + ret = H5Fclose(fid); + VRFY((ret >= 0), "H5Fclose succeeded"); + + MPI_Barrier(comm); + + /* make sure setting atomicity fails on a serial file ID */ + /* file locking allows only one file open (serial) for writing */ + if (MAINPROCESS) { + fid = H5Fopen(filename, H5F_ACC_RDWR, H5P_DEFAULT); + VRFY((fid >= 0), "H5Fopen succeeded"); + + /* should fail */ + H5E_BEGIN_TRY + { + ret = H5Fset_mpi_atomicity(fid, TRUE); + } + H5E_END_TRY + VRFY((ret == FAIL), "H5Fset_mpi_atomicity failed"); + + ret = H5Fclose(fid); + VRFY((ret >= 0), "H5Fclose succeeded"); + } + + MPI_Barrier(comm); + + /* setup file access template */ + acc_tpl = create_faccess_plist(comm, info, facc_type); + VRFY((acc_tpl >= 0), ""); + + /* open the file collectively */ + fid = H5Fopen(filename, H5F_ACC_RDWR, acc_tpl); + VRFY((fid >= 0), "H5Fopen succeeded"); + + /* Release file-access template */ + ret = H5Pclose(acc_tpl); + VRFY((ret >= 0), "H5Pclose succeeded"); + + ret = H5Fset_mpi_atomicity(fid, TRUE); + VRFY((ret >= 0), "H5Fset_mpi_atomicity succeeded"); + + /* open dataset1 (contiguous case) */ + dataset1 = H5Dopen2(fid, DATASETNAME5, H5P_DEFAULT); + VRFY((dataset1 >= 0), "H5Dopen2 succeeded"); + + if (0 == mpi_rank) { + for (i = 0; i < buf_size; i++) { + write_buf[i] = 5; + } + } + else { + for (i = 0; i < buf_size; i++) { + read_buf[i] = 8; + } + } + + /* check that the atomicity flag is set */ + ret = H5Fget_mpi_atomicity(fid, &atomicity); + VRFY((ret >= 0), "atomcity get failed"); + VRFY((atomicity == TRUE), "atomcity set failed"); + + MPI_Barrier(comm); + + /* Process 0 writes contiguously to the entire dataset */ + if (0 == mpi_rank) { + ret = H5Dwrite(dataset1, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, write_buf); + VRFY((ret >= 0), "H5Dwrite dataset1 succeeded"); + } + /* The other processes read the entire dataset */ + else { + ret = H5Dread(dataset1, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, read_buf); + VRFY((ret >= 0), "H5Dwrite() dataset multichunk write succeeded"); + } + + if (VERBOSE_MED) { + i = 0; + j = 0; + k = 0; + for (i = 0; i < dim0; i++) { + HDprintf("\n"); + for (j = 0; j < dim1; j++) + HDprintf("%d ", read_buf[k++]); + } + } + + /* The processes that read the dataset must either read all values + as 0 (read happened before process 0 wrote to dataset 1), or 5 + (read happened after process 0 wrote to dataset 1) */ + if (0 != mpi_rank) { + int compare = read_buf[0]; + + VRFY((compare == 0 || compare == 5), + "Atomicity Test Failed Process %d: Value read should be 0 or 5\n"); + for (i = 1; i < buf_size; i++) { + if (read_buf[i] != compare) { + HDprintf("Atomicity Test Failed Process %d: read_buf[%d] is %d, should be %d\n", mpi_rank, i, + read_buf[i], compare); + nerrors++; + } + } + } + + ret = H5Dclose(dataset1); + VRFY((ret >= 0), "H5D close succeeded"); + + /* release data buffers */ + if (write_buf) + HDfree(write_buf); + if (read_buf) + HDfree(read_buf); + + /* open dataset2 (non-contiguous case) */ + dataset2 = H5Dopen2(fid, DATASETNAME6, H5P_DEFAULT); + VRFY((dataset2 >= 0), "H5Dopen2 succeeded"); + + /* allocate memory for data buffer */ + write_buf = (int *)HDcalloc((size_t)buf_size, sizeof(int)); + VRFY((write_buf != NULL), "write_buf HDcalloc succeeded"); + /* allocate memory for data buffer */ + read_buf = (int *)HDcalloc((size_t)buf_size, sizeof(int)); + VRFY((read_buf != NULL), "read_buf HDcalloc succeeded"); + + for (i = 0; i < buf_size; i++) { + write_buf[i] = 5; + } + for (i = 0; i < buf_size; i++) { + read_buf[i] = 8; + } + + atomicity = FALSE; + /* check that the atomicity flag is set */ + ret = H5Fget_mpi_atomicity(fid, &atomicity); + VRFY((ret >= 0), "atomcity get failed"); + VRFY((atomicity == TRUE), "atomcity set failed"); + + block[0] = (hsize_t)(dim0 / mpi_size - 1); + block[1] = (hsize_t)(dim1 / mpi_size - 1); + stride[0] = block[0] + 1; + stride[1] = block[1] + 1; + count[0] = (hsize_t)mpi_size; + count[1] = (hsize_t)mpi_size; + start[0] = 0; + start[1] = 0; + + /* create a file dataspace */ + file_dataspace = H5Dget_space(dataset2); + VRFY((file_dataspace >= 0), "H5Dget_space succeeded"); + ret = H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab succeeded"); + + /* create a memory dataspace */ + mem_dataspace = H5Screate_simple(RANK, dims, NULL); + VRFY((mem_dataspace >= 0), ""); + + ret = H5Sselect_hyperslab(mem_dataspace, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab succeeded"); + + MPI_Barrier(comm); + + /* Process 0 writes to the dataset */ + if (0 == mpi_rank) { + ret = H5Dwrite(dataset2, H5T_NATIVE_INT, mem_dataspace, file_dataspace, H5P_DEFAULT, write_buf); + VRFY((ret >= 0), "H5Dwrite dataset2 succeeded"); + } + /* All processes wait for the write to finish. This works because + atomicity is set to true */ + MPI_Barrier(comm); + /* The other processes read the entire dataset */ + if (0 != mpi_rank) { + ret = H5Dread(dataset2, H5T_NATIVE_INT, mem_dataspace, file_dataspace, H5P_DEFAULT, read_buf); + VRFY((ret >= 0), "H5Dread dataset2 succeeded"); + } + + if (VERBOSE_MED) { + if (mpi_rank == 1) { + i = 0; + j = 0; + k = 0; + for (i = 0; i < dim0; i++) { + HDprintf("\n"); + for (j = 0; j < dim1; j++) + HDprintf("%d ", read_buf[k++]); + } + HDprintf("\n"); + } + } + + /* The processes that read the dataset must either read all values + as 5 (read happened after process 0 wrote to dataset 1) */ + if (0 != mpi_rank) { + int compare; + i = 0; + j = 0; + k = 0; + + compare = 5; + + for (i = 0; i < dim0; i++) { + if (i >= mpi_rank * ((int)block[0] + 1)) { + break; + } + if ((i + 1) % ((int)block[0] + 1) == 0) { + k += dim1; + continue; + } + for (j = 0; j < dim1; j++) { + if (j >= mpi_rank * ((int)block[1] + 1)) { + k += dim1 - mpi_rank * ((int)block[1] + 1); + break; + } + if ((j + 1) % ((int)block[1] + 1) == 0) { + k++; + continue; + } + else if (compare != read_buf[k]) { + HDprintf("Atomicity Test Failed Process %d: read_buf[%d] is %d, should be %d\n", mpi_rank, + k, read_buf[k], compare); + nerrors++; + } + k++; + } + } + } + + ret = H5Dclose(dataset2); + VRFY((ret >= 0), "H5Dclose succeeded"); + ret = H5Sclose(file_dataspace); + VRFY((ret >= 0), "H5Sclose succeeded"); + ret = H5Sclose(mem_dataspace); + VRFY((ret >= 0), "H5Sclose succeeded"); + + /* release data buffers */ + if (write_buf) + HDfree(write_buf); + if (read_buf) + HDfree(read_buf); + + ret = H5Fclose(fid); + VRFY((ret >= 0), "H5Fclose succeeded"); +} + +/* Function: dense_attr_test + * + * Purpose: Test cases for writing dense attributes in parallel + * + * Programmer: Quincey Koziol + * Date: April, 2013 + */ +void +test_dense_attr(void) +{ + int mpi_size, mpi_rank; + hid_t fpid, fid; + hid_t gid, gpid; + hid_t atFileSpace, atid; + hsize_t atDims[1] = {10000}; + herr_t status; + const char *filename; + + /* set up MPI parameters */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, group, dataset, or attribute aren't supported with " + "this connector\n"); + fflush(stdout); + } + + return; + } + + /* get filename */ + filename = (const char *)PARATESTFILE /* GetTestParameters() */; + HDassert(filename != NULL); + + fpid = H5Pcreate(H5P_FILE_ACCESS); + VRFY((fpid > 0), "H5Pcreate succeeded"); + status = H5Pset_libver_bounds(fpid, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST); + VRFY((status >= 0), "H5Pset_libver_bounds succeeded"); + status = H5Pset_fapl_mpio(fpid, MPI_COMM_WORLD, MPI_INFO_NULL); + VRFY((status >= 0), "H5Pset_fapl_mpio succeeded"); + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fpid); + VRFY((fid > 0), "H5Fcreate succeeded"); + status = H5Pclose(fpid); + VRFY((status >= 0), "H5Pclose succeeded"); + + gpid = H5Pcreate(H5P_GROUP_CREATE); + VRFY((gpid > 0), "H5Pcreate succeeded"); + status = H5Pset_attr_phase_change(gpid, 0, 0); + VRFY((status >= 0), "H5Pset_attr_phase_change succeeded"); + gid = H5Gcreate2(fid, "foo", H5P_DEFAULT, gpid, H5P_DEFAULT); + VRFY((gid > 0), "H5Gcreate2 succeeded"); + status = H5Pclose(gpid); + VRFY((status >= 0), "H5Pclose succeeded"); + + atFileSpace = H5Screate_simple(1, atDims, NULL); + VRFY((atFileSpace > 0), "H5Screate_simple succeeded"); + atid = H5Acreate2(gid, "bar", H5T_STD_U64LE, atFileSpace, H5P_DEFAULT, H5P_DEFAULT); + VRFY((atid > 0), "H5Acreate succeeded"); + status = H5Sclose(atFileSpace); + VRFY((status >= 0), "H5Sclose succeeded"); + + status = H5Aclose(atid); + VRFY((status >= 0), "H5Aclose succeeded"); + + status = H5Gclose(gid); + VRFY((status >= 0), "H5Gclose succeeded"); + status = H5Fclose(fid); + VRFY((status >= 0), "H5Fclose succeeded"); + + return; +} diff --git a/testpar/API/t_file.c b/testpar/API/t_file.c new file mode 100644 index 0000000..936454a --- /dev/null +++ b/testpar/API/t_file.c @@ -0,0 +1,1032 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Parallel tests for file operations + */ + +#include "hdf5.h" +#include "testphdf5.h" + +#if 0 +#include "H5CXprivate.h" /* API Contexts */ +#include "H5Iprivate.h" +#include "H5PBprivate.h" + +/* + * This file needs to access private information from the H5F package. + */ +#define H5AC_FRIEND /*suppress error about including H5ACpkg */ +#include "H5ACpkg.h" +#define H5C_FRIEND /*suppress error about including H5Cpkg */ +#include "H5Cpkg.h" +#define H5F_FRIEND /*suppress error about including H5Fpkg */ +#define H5F_TESTING +#include "H5Fpkg.h" +#define H5MF_FRIEND /*suppress error about including H5MFpkg */ +#include "H5MFpkg.h" +#endif + +#define NUM_DSETS 5 + +int mpi_size, mpi_rank; + +#if 0 +static int create_file(const char *filename, hid_t fcpl, hid_t fapl, int metadata_write_strategy); +static int open_file(const char *filename, hid_t fapl, int metadata_write_strategy, hsize_t page_size, + size_t page_buffer_size); +#endif + +/* + * test file access by communicator besides COMM_WORLD. + * Split COMM_WORLD into two, one (even_comm) contains the original + * processes of even ranks. The other (odd_comm) contains the original + * processes of odd ranks. Processes in even_comm creates a file, then + * cloose it, using even_comm. Processes in old_comm just do a barrier + * using odd_comm. Then they all do a barrier using COMM_WORLD. + * If the file creation and cloose does not do correct collective action + * according to the communicator argument, the processes will freeze up + * sooner or later due to barrier mixed up. + */ +void +test_split_comm_access(void) +{ + MPI_Comm comm; + MPI_Info info = MPI_INFO_NULL; + int is_old, mrc; + int newrank, newprocs; + hid_t fid; /* file IDs */ + hid_t acc_tpl; /* File access properties */ + herr_t ret; /* generic return value */ + const char *filename; + + filename = (const char *)PARATESTFILE /* GetTestParameters()*/; + if (VERBOSE_MED) + HDprintf("Split Communicator access test on file %s\n", filename); + + /* set up MPI parameters */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file aren't supported with this connector\n"); + fflush(stdout); + } + + return; + } + + is_old = mpi_rank % 2; + mrc = MPI_Comm_split(MPI_COMM_WORLD, is_old, mpi_rank, &comm); + VRFY((mrc == MPI_SUCCESS), ""); + MPI_Comm_size(comm, &newprocs); + MPI_Comm_rank(comm, &newrank); + + if (is_old) { + /* odd-rank processes */ + mrc = MPI_Barrier(comm); + VRFY((mrc == MPI_SUCCESS), ""); + } + else { + /* even-rank processes */ + int sub_mpi_rank; /* rank in the sub-comm */ + MPI_Comm_rank(comm, &sub_mpi_rank); + + /* setup file access template */ + acc_tpl = create_faccess_plist(comm, info, facc_type); + VRFY((acc_tpl >= 0), ""); + + /* create the file collectively */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, acc_tpl); + VRFY((fid >= 0), "H5Fcreate succeeded"); + + /* close the file */ + ret = H5Fclose(fid); + VRFY((ret >= 0), ""); + + /* delete the test file */ + ret = H5Fdelete(filename, acc_tpl); + VRFY((ret >= 0), "H5Fdelete succeeded"); + + /* Release file-access template */ + ret = H5Pclose(acc_tpl); + VRFY((ret >= 0), ""); + } + mrc = MPI_Comm_free(&comm); + VRFY((mrc == MPI_SUCCESS), "MPI_Comm_free succeeded"); + mrc = MPI_Barrier(MPI_COMM_WORLD); + VRFY((mrc == MPI_SUCCESS), "final MPI_Barrier succeeded"); +} + +#if 0 +void +test_page_buffer_access(void) +{ + hid_t file_id = -1; /* File ID */ + hid_t fcpl, fapl; + size_t page_count = 0; + int i, num_elements = 200; + haddr_t raw_addr, meta_addr; + int *data; + H5F_t *f = NULL; + herr_t ret; /* generic return value */ + const char *filename; + hbool_t api_ctx_pushed = FALSE; /* Whether API context pushed */ + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + + filename = (const char *)GetTestParameters(); + + if (VERBOSE_MED) + HDprintf("Page Buffer Usage in Parallel %s\n", filename); + + fapl = create_faccess_plist(MPI_COMM_WORLD, MPI_INFO_NULL, facc_type); + VRFY((fapl >= 0), "create_faccess_plist succeeded"); + fcpl = H5Pcreate(H5P_FILE_CREATE); + VRFY((fcpl >= 0), ""); + + ret = H5Pset_file_space_strategy(fcpl, H5F_FSPACE_STRATEGY_PAGE, 1, (hsize_t)0); + VRFY((ret == 0), ""); + ret = H5Pset_file_space_page_size(fcpl, sizeof(int) * 128); + VRFY((ret == 0), ""); + ret = H5Pset_page_buffer_size(fapl, sizeof(int) * 100000, 0, 0); + VRFY((ret == 0), ""); + + /* This should fail because collective metadata writes are not supported with page buffering */ + H5E_BEGIN_TRY + { + file_id = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl, fapl); + } + H5E_END_TRY; + VRFY((file_id < 0), "H5Fcreate failed"); + + /* disable collective metadata writes for page buffering to work */ + ret = H5Pset_coll_metadata_write(fapl, FALSE); + VRFY((ret >= 0), ""); + + ret = create_file(filename, fcpl, fapl, H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED); + VRFY((ret == 0), ""); + ret = open_file(filename, fapl, H5AC_METADATA_WRITE_STRATEGY__DISTRIBUTED, sizeof(int) * 100, + sizeof(int) * 100000); + VRFY((ret == 0), ""); + + ret = create_file(filename, fcpl, fapl, H5AC_METADATA_WRITE_STRATEGY__PROCESS_0_ONLY); + VRFY((ret == 0), ""); + ret = open_file(filename, fapl, H5AC_METADATA_WRITE_STRATEGY__PROCESS_0_ONLY, sizeof(int) * 100, + sizeof(int) * 100000); + VRFY((ret == 0), ""); + + ret = H5Pset_file_space_page_size(fcpl, sizeof(int) * 100); + VRFY((ret == 0), ""); + + data = (int *)HDmalloc(sizeof(int) * (size_t)num_elements); + + /* initialize all the elements to have a value of -1 */ + for (i = 0; i < num_elements; i++) + data[i] = -1; + if (MAINPROCESS) { + hid_t fapl_self = H5I_INVALID_HID; + fapl_self = create_faccess_plist(MPI_COMM_SELF, MPI_INFO_NULL, facc_type); + + ret = H5Pset_page_buffer_size(fapl_self, sizeof(int) * 1000, 0, 0); + VRFY((ret == 0), ""); + /* collective metadata writes do not work with page buffering */ + ret = H5Pset_coll_metadata_write(fapl_self, FALSE); + VRFY((ret >= 0), ""); + + file_id = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl, fapl_self); + VRFY((file_id >= 0), ""); + + /* Push API context */ + ret = H5CX_push(); + VRFY((ret == 0), "H5CX_push()"); + api_ctx_pushed = TRUE; + + /* Get a pointer to the internal file object */ + f = (H5F_t *)H5I_object(file_id); + + VRFY((f->shared->page_buf != NULL), "Page Buffer created with 1 process"); + + /* allocate space for 200 raw elements */ + raw_addr = H5MF_alloc(f, H5FD_MEM_DRAW, sizeof(int) * (size_t)num_elements); + VRFY((raw_addr != HADDR_UNDEF), ""); + + /* allocate space for 200 metadata elements */ + meta_addr = H5MF_alloc(f, H5FD_MEM_SUPER, sizeof(int) * (size_t)num_elements); + VRFY((meta_addr != HADDR_UNDEF), ""); + + page_count = 0; + + ret = H5F_block_write(f, H5FD_MEM_SUPER, meta_addr, sizeof(int) * (size_t)num_elements, data); + VRFY((ret == 0), ""); + ret = H5F_block_write(f, H5FD_MEM_SUPER, meta_addr, sizeof(int) * (size_t)num_elements, data); + ret = H5F_block_write(f, H5FD_MEM_DRAW, raw_addr, sizeof(int) * (size_t)num_elements, data); + VRFY((ret == 0), ""); + + VRFY((H5SL_count(f->shared->page_buf->slist_ptr) == page_count), "Wrong number of pages in PB"); + + /* update the first 50 elements */ + for (i = 0; i < 50; i++) + data[i] = i; + ret = H5F_block_write(f, H5FD_MEM_DRAW, raw_addr, sizeof(int) * 50, data); + H5Eprint2(H5E_DEFAULT, stderr); + VRFY((ret == 0), ""); + ret = H5F_block_write(f, H5FD_MEM_SUPER, meta_addr, sizeof(int) * 50, data); + VRFY((ret == 0), ""); + page_count += 2; + VRFY((H5SL_count(f->shared->page_buf->slist_ptr) == page_count), "Wrong number of pages in PB"); + + /* update the second 50 elements */ + for (i = 0; i < 50; i++) + data[i] = i + 50; + ret = H5F_block_write(f, H5FD_MEM_DRAW, raw_addr + (sizeof(int) * 50), sizeof(int) * 50, data); + VRFY((ret == 0), ""); + ret = H5F_block_write(f, H5FD_MEM_SUPER, meta_addr + (sizeof(int) * 50), sizeof(int) * 50, data); + VRFY((ret == 0), ""); + VRFY((H5SL_count(f->shared->page_buf->slist_ptr) == page_count), "Wrong number of pages in PB"); + + /* update 100 - 200 */ + for (i = 0; i < 100; i++) + data[i] = i + 100; + ret = H5F_block_write(f, H5FD_MEM_DRAW, raw_addr + (sizeof(int) * 100), sizeof(int) * 100, data); + VRFY((ret == 0), ""); + ret = H5F_block_write(f, H5FD_MEM_SUPER, meta_addr + (sizeof(int) * 100), sizeof(int) * 100, data); + VRFY((ret == 0), ""); + VRFY((H5SL_count(f->shared->page_buf->slist_ptr) == page_count), "Wrong number of pages in PB"); + + ret = H5PB_flush(f->shared); + VRFY((ret == 0), ""); + + /* read elements 0 - 200 */ + ret = H5F_block_read(f, H5FD_MEM_DRAW, raw_addr, sizeof(int) * 200, data); + VRFY((ret == 0), ""); + VRFY((H5SL_count(f->shared->page_buf->slist_ptr) == page_count), "Wrong number of pages in PB"); + for (i = 0; i < 200; i++) + VRFY((data[i] == i), "Read different values than written"); + ret = H5F_block_read(f, H5FD_MEM_SUPER, meta_addr, sizeof(int) * 200, data); + VRFY((ret == 0), ""); + VRFY((H5SL_count(f->shared->page_buf->slist_ptr) == page_count), "Wrong number of pages in PB"); + for (i = 0; i < 200; i++) + VRFY((data[i] == i), "Read different values than written"); + + /* read elements 0 - 50 */ + ret = H5F_block_read(f, H5FD_MEM_DRAW, raw_addr, sizeof(int) * 50, data); + VRFY((ret == 0), ""); + VRFY((H5SL_count(f->shared->page_buf->slist_ptr) == page_count), "Wrong number of pages in PB"); + for (i = 0; i < 50; i++) + VRFY((data[i] == i), "Read different values than written"); + ret = H5F_block_read(f, H5FD_MEM_SUPER, meta_addr, sizeof(int) * 50, data); + VRFY((ret == 0), ""); + VRFY((H5SL_count(f->shared->page_buf->slist_ptr) == page_count), "Wrong number of pages in PB"); + for (i = 0; i < 50; i++) + VRFY((data[i] == i), "Read different values than written"); + + /* close the file */ + ret = H5Fclose(file_id); + VRFY((ret >= 0), "H5Fclose succeeded"); + ret = H5Pclose(fapl_self); + VRFY((ret >= 0), "H5Pclose succeeded"); + + /* Pop API context */ + if (api_ctx_pushed) { + ret = H5CX_pop(FALSE); + VRFY((ret == 0), "H5CX_pop()"); + api_ctx_pushed = FALSE; + } + } + + MPI_Barrier(MPI_COMM_WORLD); + + if (mpi_size > 1) { + ret = H5Pset_page_buffer_size(fapl, sizeof(int) * 1000, 0, 0); + VRFY((ret == 0), ""); + /* collective metadata writes do not work with page buffering */ + ret = H5Pset_coll_metadata_write(fapl, FALSE); + VRFY((ret >= 0), ""); + + file_id = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl, fapl); + VRFY((file_id >= 0), ""); + + /* Push API context */ + ret = H5CX_push(); + VRFY((ret == 0), "H5CX_push()"); + api_ctx_pushed = TRUE; + + /* Get a pointer to the internal file object */ + f = (H5F_t *)H5I_object(file_id); + + VRFY((f->shared->page_buf != NULL), "Page Buffer created with 1 process"); + + /* allocate space for 200 raw elements */ + raw_addr = H5MF_alloc(f, H5FD_MEM_DRAW, sizeof(int) * (size_t)num_elements); + VRFY((raw_addr != HADDR_UNDEF), ""); + /* allocate space for 200 metadata elements */ + meta_addr = H5MF_alloc(f, H5FD_MEM_SUPER, sizeof(int) * (size_t)num_elements); + VRFY((meta_addr != HADDR_UNDEF), ""); + + page_count = 0; + + ret = H5F_block_write(f, H5FD_MEM_SUPER, meta_addr, sizeof(int) * (size_t)num_elements, data); + VRFY((ret == 0), ""); + ret = H5F_block_write(f, H5FD_MEM_DRAW, raw_addr, sizeof(int) * (size_t)num_elements, data); + VRFY((ret == 0), ""); + + VRFY((H5SL_count(f->shared->page_buf->slist_ptr) == page_count), "Wrong number of pages in PB"); + + /* update the first 50 elements */ + for (i = 0; i < 50; i++) + data[i] = i; + ret = H5F_block_write(f, H5FD_MEM_DRAW, raw_addr, sizeof(int) * 50, data); + VRFY((ret == 0), ""); + ret = H5F_block_write(f, H5FD_MEM_SUPER, meta_addr, sizeof(int) * 50, data); + VRFY((ret == 0), ""); + VRFY((H5SL_count(f->shared->page_buf->slist_ptr) == page_count), "Wrong number of pages in PB"); + + /* update the second 50 elements */ + for (i = 0; i < 50; i++) + data[i] = i + 50; + ret = H5F_block_write(f, H5FD_MEM_DRAW, raw_addr + (sizeof(int) * 50), sizeof(int) * 50, data); + VRFY((ret == 0), ""); + ret = H5F_block_write(f, H5FD_MEM_SUPER, meta_addr + (sizeof(int) * 50), sizeof(int) * 50, data); + VRFY((ret == 0), ""); + VRFY((H5SL_count(f->shared->page_buf->slist_ptr) == page_count), "Wrong number of pages in PB"); + + /* update 100 - 200 */ + for (i = 0; i < 100; i++) + data[i] = i + 100; + ret = H5F_block_write(f, H5FD_MEM_DRAW, raw_addr + (sizeof(int) * 100), sizeof(int) * 100, data); + VRFY((ret == 0), ""); + ret = H5F_block_write(f, H5FD_MEM_SUPER, meta_addr + (sizeof(int) * 100), sizeof(int) * 100, data); + VRFY((ret == 0), ""); + VRFY((H5SL_count(f->shared->page_buf->slist_ptr) == page_count), "Wrong number of pages in PB"); + + ret = H5Fflush(file_id, H5F_SCOPE_GLOBAL); + VRFY((ret == 0), ""); + + /* read elements 0 - 200 */ + ret = H5F_block_read(f, H5FD_MEM_DRAW, raw_addr, sizeof(int) * 200, data); + VRFY((ret == 0), ""); + VRFY((H5SL_count(f->shared->page_buf->slist_ptr) == page_count), "Wrong number of pages in PB"); + for (i = 0; i < 200; i++) + VRFY((data[i] == i), "Read different values than written"); + ret = H5F_block_read(f, H5FD_MEM_SUPER, meta_addr, sizeof(int) * 200, data); + VRFY((ret == 0), ""); + VRFY((H5SL_count(f->shared->page_buf->slist_ptr) == page_count), "Wrong number of pages in PB"); + for (i = 0; i < 200; i++) + VRFY((data[i] == i), "Read different values than written"); + + /* read elements 0 - 50 */ + ret = H5F_block_read(f, H5FD_MEM_DRAW, raw_addr, sizeof(int) * 50, data); + VRFY((ret == 0), ""); + VRFY((H5SL_count(f->shared->page_buf->slist_ptr) == page_count), "Wrong number of pages in PB"); + for (i = 0; i < 50; i++) + VRFY((data[i] == i), "Read different values than written"); + ret = H5F_block_read(f, H5FD_MEM_SUPER, meta_addr, sizeof(int) * 50, data); + VRFY((ret == 0), ""); + page_count += 1; + VRFY((H5SL_count(f->shared->page_buf->slist_ptr) == page_count), "Wrong number of pages in PB"); + for (i = 0; i < 50; i++) + VRFY((data[i] == i), "Read different values than written"); + + MPI_Barrier(MPI_COMM_WORLD); + /* reset the first 50 elements to -1*/ + for (i = 0; i < 50; i++) + data[i] = -1; + ret = H5F_block_write(f, H5FD_MEM_DRAW, raw_addr, sizeof(int) * 50, data); + VRFY((ret == 0), ""); + VRFY((H5SL_count(f->shared->page_buf->slist_ptr) == page_count), "Wrong number of pages in PB"); + ret = H5F_block_write(f, H5FD_MEM_SUPER, meta_addr, sizeof(int) * 50, data); + VRFY((ret == 0), ""); + VRFY((H5SL_count(f->shared->page_buf->slist_ptr) == page_count), "Wrong number of pages in PB"); + + /* read elements 0 - 50 */ + ret = H5F_block_read(f, H5FD_MEM_DRAW, raw_addr, sizeof(int) * 50, data); + VRFY((ret == 0), ""); + VRFY((H5SL_count(f->shared->page_buf->slist_ptr) == page_count), "Wrong number of pages in PB"); + for (i = 0; i < 50; i++) + VRFY((data[i] == -1), "Read different values than written"); + ret = H5F_block_read(f, H5FD_MEM_SUPER, meta_addr, sizeof(int) * 50, data); + VRFY((ret == 0), ""); + VRFY((H5SL_count(f->shared->page_buf->slist_ptr) == page_count), "Wrong number of pages in PB"); + for (i = 0; i < 50; i++) + VRFY((data[i] == -1), "Read different values than written"); + + /* close the file */ + ret = H5Fclose(file_id); + VRFY((ret >= 0), "H5Fclose succeeded"); + } + + ret = H5Pclose(fapl); + VRFY((ret >= 0), "H5Pclose succeeded"); + ret = H5Pclose(fcpl); + VRFY((ret >= 0), "H5Pclose succeeded"); + + /* Pop API context */ + if (api_ctx_pushed) { + ret = H5CX_pop(FALSE); + VRFY((ret == 0), "H5CX_pop()"); + api_ctx_pushed = FALSE; + } + + HDfree(data); + data = NULL; + MPI_Barrier(MPI_COMM_WORLD); +} + +static int +create_file(const char *filename, hid_t fcpl, hid_t fapl, int metadata_write_strategy) +{ + hid_t file_id, dset_id, grp_id; + hid_t sid, mem_dataspace; + hsize_t start[RANK]; + hsize_t count[RANK]; + hsize_t stride[RANK]; + hsize_t block[RANK]; + DATATYPE *data_array = NULL; + hsize_t dims[RANK], i; + hsize_t num_elements; + int k; + char dset_name[20]; + H5F_t *f = NULL; + H5C_t *cache_ptr = NULL; + H5AC_cache_config_t config; + hbool_t api_ctx_pushed = FALSE; /* Whether API context pushed */ + herr_t ret; + + file_id = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl, fapl); + VRFY((file_id >= 0), ""); + + ret = H5Fflush(file_id, H5F_SCOPE_GLOBAL); + VRFY((ret == 0), ""); + + /* Push API context */ + ret = H5CX_push(); + VRFY((ret == 0), "H5CX_push()"); + api_ctx_pushed = TRUE; + + f = (H5F_t *)H5I_object(file_id); + VRFY((f != NULL), ""); + + cache_ptr = f->shared->cache; + VRFY((cache_ptr->magic == H5C__H5C_T_MAGIC), ""); + + cache_ptr->ignore_tags = TRUE; + H5C_stats__reset(cache_ptr); + config.version = H5AC__CURR_CACHE_CONFIG_VERSION; + + ret = H5AC_get_cache_auto_resize_config(cache_ptr, &config); + VRFY((ret == 0), ""); + + config.metadata_write_strategy = metadata_write_strategy; + + ret = H5AC_set_cache_auto_resize_config(cache_ptr, &config); + VRFY((ret == 0), ""); + + grp_id = H5Gcreate2(file_id, "GROUP", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((grp_id >= 0), ""); + + dims[0] = (hsize_t)(ROW_FACTOR * mpi_size); + dims[1] = (hsize_t)(COL_FACTOR * mpi_size); + sid = H5Screate_simple(RANK, dims, NULL); + VRFY((sid >= 0), "H5Screate_simple succeeded"); + + /* Each process takes a slabs of rows. */ + block[0] = dims[0] / (hsize_t)mpi_size; + block[1] = dims[1]; + stride[0] = block[0]; + stride[1] = block[1]; + count[0] = 1; + count[1] = 1; + start[0] = (hsize_t)mpi_rank * block[0]; + start[1] = 0; + + num_elements = block[0] * block[1]; + /* allocate memory for data buffer */ + data_array = (DATATYPE *)HDmalloc(num_elements * sizeof(DATATYPE)); + VRFY((data_array != NULL), "data_array HDmalloc succeeded"); + /* put some trivial data in the data_array */ + for (i = 0; i < num_elements; i++) + data_array[i] = mpi_rank + 1; + + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab succeeded"); + + /* create a memory dataspace independently */ + mem_dataspace = H5Screate_simple(1, &num_elements, NULL); + VRFY((mem_dataspace >= 0), ""); + + for (k = 0; k < NUM_DSETS; k++) { + HDsnprintf(dset_name, sizeof(dset_name), "D1dset%d", k); + dset_id = H5Dcreate2(grp_id, dset_name, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((dset_id >= 0), ""); + ret = H5Dclose(dset_id); + VRFY((ret == 0), ""); + + HDsnprintf(dset_name, sizeof(dset_name), "D2dset%d", k); + dset_id = H5Dcreate2(grp_id, dset_name, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((dset_id >= 0), ""); + ret = H5Dclose(dset_id); + VRFY((ret == 0), ""); + + HDsnprintf(dset_name, sizeof(dset_name), "D3dset%d", k); + dset_id = H5Dcreate2(grp_id, dset_name, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((dset_id >= 0), ""); + ret = H5Dclose(dset_id); + VRFY((ret == 0), ""); + + HDsnprintf(dset_name, sizeof(dset_name), "dset%d", k); + dset_id = H5Dcreate2(grp_id, dset_name, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((dset_id >= 0), ""); + + ret = H5Dwrite(dset_id, H5T_NATIVE_INT, mem_dataspace, sid, H5P_DEFAULT, data_array); + VRFY((ret == 0), ""); + + ret = H5Dclose(dset_id); + VRFY((ret == 0), ""); + + HDmemset(data_array, 0, num_elements * sizeof(DATATYPE)); + dset_id = H5Dopen2(grp_id, dset_name, H5P_DEFAULT); + VRFY((dset_id >= 0), ""); + + ret = H5Dread(dset_id, H5T_NATIVE_INT, mem_dataspace, sid, H5P_DEFAULT, data_array); + VRFY((ret == 0), ""); + + ret = H5Dclose(dset_id); + VRFY((ret == 0), ""); + + for (i = 0; i < num_elements; i++) + VRFY((data_array[i] == mpi_rank + 1), "Dataset Verify failed"); + + HDsnprintf(dset_name, sizeof(dset_name), "D1dset%d", k); + ret = H5Ldelete(grp_id, dset_name, H5P_DEFAULT); + VRFY((ret == 0), ""); + HDsnprintf(dset_name, sizeof(dset_name), "D2dset%d", k); + ret = H5Ldelete(grp_id, dset_name, H5P_DEFAULT); + VRFY((ret == 0), ""); + HDsnprintf(dset_name, sizeof(dset_name), "D3dset%d", k); + ret = H5Ldelete(grp_id, dset_name, H5P_DEFAULT); + VRFY((ret == 0), ""); + } + + ret = H5Gclose(grp_id); + VRFY((ret == 0), ""); + ret = H5Fclose(file_id); + VRFY((ret == 0), ""); + ret = H5Sclose(sid); + VRFY((ret == 0), ""); + ret = H5Sclose(mem_dataspace); + VRFY((ret == 0), ""); + + /* Pop API context */ + if (api_ctx_pushed) { + ret = H5CX_pop(FALSE); + VRFY((ret == 0), "H5CX_pop()"); + api_ctx_pushed = FALSE; + } + + MPI_Barrier(MPI_COMM_WORLD); + HDfree(data_array); + return 0; +} /* create_file */ + +static int +open_file(const char *filename, hid_t fapl, int metadata_write_strategy, hsize_t page_size, + size_t page_buffer_size) +{ + hid_t file_id, dset_id, grp_id, grp_id2; + hid_t sid, mem_dataspace; + DATATYPE *data_array = NULL; + hsize_t dims[RANK]; + hsize_t start[RANK]; + hsize_t count[RANK]; + hsize_t stride[RANK]; + hsize_t block[RANK]; + int i, k, ndims; + hsize_t num_elements; + char dset_name[20]; + H5F_t *f = NULL; + H5C_t *cache_ptr = NULL; + H5AC_cache_config_t config; + hbool_t api_ctx_pushed = FALSE; /* Whether API context pushed */ + herr_t ret; + + config.version = H5AC__CURR_CACHE_CONFIG_VERSION; + ret = H5Pget_mdc_config(fapl, &config); + VRFY((ret == 0), ""); + + config.metadata_write_strategy = metadata_write_strategy; + + ret = H5Pget_mdc_config(fapl, &config); + VRFY((ret == 0), ""); + + file_id = H5Fopen(filename, H5F_ACC_RDWR, fapl); + H5Eprint2(H5E_DEFAULT, stderr); + VRFY((file_id >= 0), ""); + + /* Push API context */ + ret = H5CX_push(); + VRFY((ret == 0), "H5CX_push()"); + api_ctx_pushed = TRUE; + + ret = H5Fflush(file_id, H5F_SCOPE_GLOBAL); + VRFY((ret == 0), ""); + + f = (H5F_t *)H5I_object(file_id); + VRFY((f != NULL), ""); + + cache_ptr = f->shared->cache; + VRFY((cache_ptr->magic == H5C__H5C_T_MAGIC), ""); + + MPI_Barrier(MPI_COMM_WORLD); + + VRFY((f->shared->page_buf != NULL), ""); + VRFY((f->shared->page_buf->page_size == page_size), ""); + VRFY((f->shared->page_buf->max_size == page_buffer_size), ""); + + grp_id = H5Gopen2(file_id, "GROUP", H5P_DEFAULT); + VRFY((grp_id >= 0), ""); + + dims[0] = (hsize_t)(ROW_FACTOR * mpi_size); + dims[1] = (hsize_t)(COL_FACTOR * mpi_size); + + /* Each process takes a slabs of rows. */ + block[0] = dims[0] / (hsize_t)mpi_size; + block[1] = dims[1]; + stride[0] = block[0]; + stride[1] = block[1]; + count[0] = 1; + count[1] = 1; + start[0] = (hsize_t)mpi_rank * block[0]; + start[1] = 0; + + num_elements = block[0] * block[1]; + /* allocate memory for data buffer */ + data_array = (DATATYPE *)HDmalloc(num_elements * sizeof(DATATYPE)); + VRFY((data_array != NULL), "data_array HDmalloc succeeded"); + + /* create a memory dataspace independently */ + mem_dataspace = H5Screate_simple(1, &num_elements, NULL); + VRFY((mem_dataspace >= 0), ""); + + for (k = 0; k < NUM_DSETS; k++) { + HDsnprintf(dset_name, sizeof(dset_name), "dset%d", k); + dset_id = H5Dopen2(grp_id, dset_name, H5P_DEFAULT); + VRFY((dset_id >= 0), ""); + + sid = H5Dget_space(dset_id); + VRFY((dset_id >= 0), "H5Dget_space succeeded"); + + ndims = H5Sget_simple_extent_dims(sid, dims, NULL); + VRFY((ndims == 2), "H5Sget_simple_extent_dims succeeded"); + VRFY(dims[0] == (hsize_t)(ROW_FACTOR * mpi_size), "Wrong dataset dimensions"); + VRFY(dims[1] == (hsize_t)(COL_FACTOR * mpi_size), "Wrong dataset dimensions"); + + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab succeeded"); + + ret = H5Dread(dset_id, H5T_NATIVE_INT, mem_dataspace, sid, H5P_DEFAULT, data_array); + VRFY((ret >= 0), ""); + + ret = H5Dclose(dset_id); + VRFY((ret >= 0), ""); + ret = H5Sclose(sid); + VRFY((ret == 0), ""); + + for (i = 0; i < (int)num_elements; i++) + VRFY((data_array[i] == mpi_rank + 1), "Dataset Verify failed"); + } + + grp_id2 = H5Gcreate2(file_id, "GROUP/GROUP2", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((grp_id2 >= 0), ""); + ret = H5Gclose(grp_id2); + VRFY((ret == 0), ""); + + ret = H5Fflush(file_id, H5F_SCOPE_GLOBAL); + VRFY((ret == 0), ""); + + MPI_Barrier(MPI_COMM_WORLD); + /* flush invalidate each ring, starting from the outermost ring and + * working inward. + */ + for (i = 0; i < H5C__HASH_TABLE_LEN; i++) { + H5C_cache_entry_t *entry_ptr = NULL; + + entry_ptr = cache_ptr->index[i]; + + while (entry_ptr != NULL) { + HDassert(entry_ptr->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC); + HDassert(entry_ptr->is_dirty == FALSE); + + if (!entry_ptr->is_pinned && !entry_ptr->is_protected) { + ret = H5AC_expunge_entry(f, entry_ptr->type, entry_ptr->addr, 0); + VRFY((ret == 0), ""); + } + + entry_ptr = entry_ptr->ht_next; + } + } + MPI_Barrier(MPI_COMM_WORLD); + + grp_id2 = H5Gopen2(file_id, "GROUP/GROUP2", H5P_DEFAULT); + H5Eprint2(H5E_DEFAULT, stderr); + VRFY((grp_id2 >= 0), ""); + ret = H5Gclose(grp_id2); + H5Eprint2(H5E_DEFAULT, stderr); + VRFY((ret == 0), ""); + + ret = H5Gclose(grp_id); + VRFY((ret == 0), ""); + ret = H5Fclose(file_id); + VRFY((ret == 0), ""); + ret = H5Sclose(mem_dataspace); + VRFY((ret == 0), ""); + + /* Pop API context */ + if (api_ctx_pushed) { + ret = H5CX_pop(FALSE); + VRFY((ret == 0), "H5CX_pop()"); + api_ctx_pushed = FALSE; + } + + HDfree(data_array); + + return nerrors; +} +#endif + +/* + * NOTE: See HDFFV-10894 and add tests later to verify MPI-specific properties in the + * incoming fapl that could conflict with the existing values in H5F_shared_t on + * multiple opens of the same file. + */ +void +test_file_properties(void) +{ + hid_t fid = H5I_INVALID_HID; /* HDF5 file ID */ + hid_t fapl_id = H5I_INVALID_HID; /* File access plist */ + hid_t fapl_copy_id = H5I_INVALID_HID; /* File access plist */ + hbool_t is_coll; + htri_t are_equal; + const char *filename; + MPI_Comm comm = MPI_COMM_WORLD; + MPI_Info info = MPI_INFO_NULL; + MPI_Comm comm_out = MPI_COMM_NULL; + MPI_Info info_out = MPI_INFO_NULL; + herr_t ret; /* Generic return value */ + int mpi_ret; /* MPI return value */ + int cmp; /* Compare value */ + + /* set up MPI parameters */ + mpi_ret = MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + VRFY((mpi_ret >= 0), "MPI_Comm_size succeeded"); + mpi_ret = MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + VRFY((mpi_ret >= 0), "MPI_Comm_rank succeeded"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file aren't supported with this connector\n"); + fflush(stdout); + } + + return; + } + + filename = (const char *)PARATESTFILE /* GetTestParameters() */; + + mpi_ret = MPI_Info_create(&info); + VRFY((mpi_ret >= 0), "MPI_Info_create succeeded"); + mpi_ret = MPI_Info_set(info, "hdf_info_prop1", "xyz"); + VRFY((mpi_ret == MPI_SUCCESS), "MPI_Info_set"); + + /* setup file access plist */ + fapl_id = H5Pcreate(H5P_FILE_ACCESS); + VRFY((fapl_id != H5I_INVALID_HID), "H5Pcreate"); + ret = H5Pset_fapl_mpio(fapl_id, comm, info); + VRFY((ret >= 0), "H5Pset_fapl_mpio"); + + /* Check getting and setting MPI properties + * (for use in VOL connectors, not the MPI-I/O VFD) + */ + ret = H5Pset_mpi_params(fapl_id, comm, info); + VRFY((ret >= 0), "H5Pset_mpi_params succeeded"); + ret = H5Pget_mpi_params(fapl_id, &comm_out, &info_out); + VRFY((ret >= 0), "H5Pget_mpi_params succeeded"); + + /* Check the communicator */ + VRFY((comm != comm_out), "Communicators should not be bitwise identical"); + cmp = MPI_UNEQUAL; + mpi_ret = MPI_Comm_compare(comm, comm_out, &cmp); + VRFY((ret >= 0), "MPI_Comm_compare succeeded"); + VRFY((cmp == MPI_CONGRUENT), "Communicators should be congruent via MPI_Comm_compare"); + + /* Check the info object */ + VRFY((info != info_out), "Info objects should not be bitwise identical"); + + /* Free the obtained comm and info object */ + mpi_ret = MPI_Comm_free(&comm_out); + VRFY((mpi_ret >= 0), "MPI_Comm_free succeeded"); + mpi_ret = MPI_Info_free(&info_out); + VRFY((mpi_ret >= 0), "MPI_Info_free succeeded"); + + /* Copy the fapl and ensure it's equal to the original */ + fapl_copy_id = H5Pcopy(fapl_id); + VRFY((fapl_copy_id != H5I_INVALID_HID), "H5Pcopy"); + are_equal = H5Pequal(fapl_id, fapl_copy_id); + VRFY((TRUE == are_equal), "H5Pequal"); + + /* Add a property to the copy and ensure it's different now */ + mpi_ret = MPI_Info_set(info, "hdf_info_prop2", "abc"); + VRFY((mpi_ret == MPI_SUCCESS), "MPI_Info_set"); + ret = H5Pset_mpi_params(fapl_copy_id, comm, info); + VRFY((ret >= 0), "H5Pset_mpi_params succeeded"); + are_equal = H5Pequal(fapl_id, fapl_copy_id); + VRFY((FALSE == are_equal), "H5Pequal"); + + /* Add a property with the same key but a different value to the original + * and ensure they are still different. + */ + mpi_ret = MPI_Info_set(info, "hdf_info_prop2", "ijk"); + VRFY((mpi_ret == MPI_SUCCESS), "MPI_Info_set"); + ret = H5Pset_mpi_params(fapl_id, comm, info); + VRFY((ret >= 0), "H5Pset_mpi_params succeeded"); + are_equal = H5Pequal(fapl_id, fapl_copy_id); + VRFY((FALSE == are_equal), "H5Pequal"); + + /* Set the second property in the original to the same + * value as the copy and ensure they are the same now. + */ + mpi_ret = MPI_Info_set(info, "hdf_info_prop2", "abc"); + VRFY((mpi_ret == MPI_SUCCESS), "MPI_Info_set"); + ret = H5Pset_mpi_params(fapl_id, comm, info); + VRFY((ret >= 0), "H5Pset_mpi_params succeeded"); + are_equal = H5Pequal(fapl_id, fapl_copy_id); + VRFY((TRUE == are_equal), "H5Pequal"); + + /* create the file */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id); + VRFY((fid != H5I_INVALID_HID), "H5Fcreate succeeded"); + + /* verify settings for file access properties */ + + /* Collective metadata writes */ + ret = H5Pget_coll_metadata_write(fapl_id, &is_coll); + VRFY((ret >= 0), "H5Pget_coll_metadata_write succeeded"); + VRFY((is_coll == FALSE), "Incorrect property setting for coll metadata writes"); + + /* Collective metadata read API calling requirement */ + ret = H5Pget_all_coll_metadata_ops(fapl_id, &is_coll); + VRFY((ret >= 0), "H5Pget_all_coll_metadata_ops succeeded"); + VRFY((is_coll == FALSE), "Incorrect property setting for coll metadata API calls requirement"); + + ret = H5Fclose(fid); + VRFY((ret >= 0), "H5Fclose succeeded"); + + /* Open the file with the MPI-IO driver */ + ret = H5Pset_fapl_mpio(fapl_id, comm, info); + VRFY((ret >= 0), "H5Pset_fapl_mpio failed"); + fid = H5Fopen(filename, H5F_ACC_RDWR, fapl_id); + VRFY((fid != H5I_INVALID_HID), "H5Fcreate succeeded"); + + /* verify settings for file access properties */ + + /* Collective metadata writes */ + ret = H5Pget_coll_metadata_write(fapl_id, &is_coll); + VRFY((ret >= 0), "H5Pget_coll_metadata_write succeeded"); + VRFY((is_coll == FALSE), "Incorrect property setting for coll metadata writes"); + + /* Collective metadata read API calling requirement */ + ret = H5Pget_all_coll_metadata_ops(fapl_id, &is_coll); + VRFY((ret >= 0), "H5Pget_all_coll_metadata_ops succeeded"); + VRFY((is_coll == FALSE), "Incorrect property setting for coll metadata API calls requirement"); + + ret = H5Fclose(fid); + VRFY((ret >= 0), "H5Fclose succeeded"); + + /* Open the file with the MPI-IO driver w/ collective settings */ + ret = H5Pset_fapl_mpio(fapl_id, comm, info); + VRFY((ret >= 0), "H5Pset_fapl_mpio failed"); + /* Collective metadata writes */ + ret = H5Pset_coll_metadata_write(fapl_id, TRUE); + VRFY((ret >= 0), "H5Pget_coll_metadata_write succeeded"); + /* Collective metadata read API calling requirement */ + ret = H5Pset_all_coll_metadata_ops(fapl_id, TRUE); + VRFY((ret >= 0), "H5Pget_all_coll_metadata_ops succeeded"); + fid = H5Fopen(filename, H5F_ACC_RDWR, fapl_id); + VRFY((fid != H5I_INVALID_HID), "H5Fcreate succeeded"); + + /* verify settings for file access properties */ + + /* Collective metadata writes */ + ret = H5Pget_coll_metadata_write(fapl_id, &is_coll); + VRFY((ret >= 0), "H5Pget_coll_metadata_write succeeded"); + VRFY((is_coll == TRUE), "Incorrect property setting for coll metadata writes"); + + /* Collective metadata read API calling requirement */ + ret = H5Pget_all_coll_metadata_ops(fapl_id, &is_coll); + VRFY((ret >= 0), "H5Pget_all_coll_metadata_ops succeeded"); + VRFY((is_coll == TRUE), "Incorrect property setting for coll metadata API calls requirement"); + + /* close fapl and retrieve it from file */ + ret = H5Pclose(fapl_id); + VRFY((ret >= 0), "H5Pclose succeeded"); + fapl_id = H5I_INVALID_HID; + + fapl_id = H5Fget_access_plist(fid); + VRFY((fapl_id != H5I_INVALID_HID), "H5P_FILE_ACCESS"); + + /* verify settings for file access properties */ + + /* Collective metadata writes */ + ret = H5Pget_coll_metadata_write(fapl_id, &is_coll); + VRFY((ret >= 0), "H5Pget_coll_metadata_write succeeded"); + VRFY((is_coll == TRUE), "Incorrect property setting for coll metadata writes"); + + /* Collective metadata read API calling requirement */ + ret = H5Pget_all_coll_metadata_ops(fapl_id, &is_coll); + VRFY((ret >= 0), "H5Pget_all_coll_metadata_ops succeeded"); + VRFY((is_coll == TRUE), "Incorrect property setting for coll metadata API calls requirement"); + + /* close file */ + ret = H5Fclose(fid); + VRFY((ret >= 0), "H5Fclose succeeded"); + + /* Release file-access plist */ + ret = H5Pclose(fapl_id); + VRFY((ret >= 0), "H5Pclose succeeded"); + ret = H5Pclose(fapl_copy_id); + VRFY((ret >= 0), "H5Pclose succeeded"); + + /* Free the MPI info object */ + mpi_ret = MPI_Info_free(&info); + VRFY((mpi_ret >= 0), "MPI_Info_free succeeded"); + +} /* end test_file_properties() */ + +void +test_delete(void) +{ + hid_t fid = H5I_INVALID_HID; /* HDF5 file ID */ + hid_t fapl_id = H5I_INVALID_HID; /* File access plist */ + const char *filename = NULL; + MPI_Comm comm = MPI_COMM_WORLD; + MPI_Info info = MPI_INFO_NULL; + htri_t is_hdf5 = FAIL; /* Whether a file is an HDF5 file */ + herr_t ret; /* Generic return value */ + + filename = (const char *)PARATESTFILE /* GetTestParameters() */; + + /* set up MPI parameters */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* setup file access plist */ + fapl_id = H5Pcreate(H5P_FILE_ACCESS); + VRFY((fapl_id != H5I_INVALID_HID), "H5Pcreate"); + ret = H5Pset_fapl_mpio(fapl_id, comm, info); + VRFY((SUCCEED == ret), "H5Pset_fapl_mpio"); + + /* create the file */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id); + VRFY((fid != H5I_INVALID_HID), "H5Fcreate"); + + /* close the file */ + ret = H5Fclose(fid); + VRFY((SUCCEED == ret), "H5Fclose"); + + /* Verify that the file is an HDF5 file */ + is_hdf5 = H5Fis_accessible(filename, fapl_id); + VRFY((TRUE == is_hdf5), "H5Fis_accessible"); + + /* Delete the file */ + ret = H5Fdelete(filename, fapl_id); + VRFY((SUCCEED == ret), "H5Fdelete"); + + /* Verify that the file is NO LONGER an HDF5 file */ + /* This should fail since there is no file */ + H5E_BEGIN_TRY + { + is_hdf5 = H5Fis_accessible(filename, fapl_id); + } + H5E_END_TRY; + VRFY((is_hdf5 != SUCCEED), "H5Fis_accessible"); + + /* Release file-access plist */ + ret = H5Pclose(fapl_id); + VRFY((SUCCEED == ret), "H5Pclose"); + +} /* end test_delete() */ diff --git a/testpar/API/t_file_image.c b/testpar/API/t_file_image.c new file mode 100644 index 0000000..4f4fa96 --- /dev/null +++ b/testpar/API/t_file_image.c @@ -0,0 +1,371 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Parallel tests for file image operations + */ + +#include "hdf5.h" +#include "testphdf5.h" + +/* file_image_daisy_chain_test + * + * Process zero: + * + * 1) Creates a core file with an integer vector data set of + * length n (= mpi_size), + * + * 2) Initializes the vector to zero in * location 0, and to -1 + * everywhere else. + * + * 3) Flushes the core file, and gets an image of it. Closes + * the core file. + * + * 4) Sends the image to process 1. + * + * 5) Awaits receipt on a file image from process n-1. + * + * 6) opens the image received from process n-1, verifies that + * it contains a vector of length equal to mpi_size, and + * that the vector contains (0, 1, 2, ... n-1) + * + * 7) closes the core file and exits. + * + * Process i (0 < i < n) + * + * 1) Await receipt of file image from process (i - 1). + * + * 2) Open the image with the core file driver, verify that i + * contains a vector v of length, and that v[j] = j for + * 0 <= j < i, and that v[j] == -1 for i <= j < n + * + * 3) Set v[i] = i in the core file. + * + * 4) Flush the core file and send it to process (i + 1) % n. + * + * 5) close the core file and exit. + * + * Test fails on a hang (if an image is not received), or on invalid data. + * + * JRM -- 11/28/11 + */ +void +file_image_daisy_chain_test(void) +{ + char file_name[1024] = "\0"; + int mpi_size, mpi_rank; + int mpi_result; + int i; + int space_ndims; + MPI_Status rcvstat; + int *vector_ptr = NULL; + hid_t fapl_id = -1; + hid_t file_id; /* file IDs */ + hid_t dset_id = -1; + hid_t dset_type_id = -1; + hid_t space_id = -1; + herr_t err; + hsize_t dims[1]; + void *image_ptr = NULL; + ssize_t bytes_read; + ssize_t image_len; + hbool_t vector_ok = TRUE; + htri_t tri_result; + + /* set up MPI parameters */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* setup file name */ + HDsnprintf(file_name, 1024, "file_image_daisy_chain_test_%05d.h5", (int)mpi_rank); + + if (mpi_rank == 0) { + + /* 1) Creates a core file with an integer vector data set + * of length mpi_size, + */ + fapl_id = H5Pcreate(H5P_FILE_ACCESS); + VRFY((fapl_id >= 0), "creating fapl"); + + err = H5Pset_fapl_core(fapl_id, (size_t)(64 * 1024), FALSE); + VRFY((err >= 0), "setting core file driver in fapl."); + + file_id = H5Fcreate(file_name, 0, H5P_DEFAULT, fapl_id); + VRFY((file_id >= 0), "created core file"); + + dims[0] = (hsize_t)mpi_size; + space_id = H5Screate_simple(1, dims, dims); + VRFY((space_id >= 0), "created data space"); + + dset_id = H5Dcreate2(file_id, "v", H5T_NATIVE_INT, space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((dset_id >= 0), "created data set"); + + /* 2) Initialize the vector to zero in location 0, and + * to -1 everywhere else. + */ + + vector_ptr = (int *)HDmalloc((size_t)(mpi_size) * sizeof(int)); + VRFY((vector_ptr != NULL), "allocated in memory representation of vector"); + + vector_ptr[0] = 0; + for (i = 1; i < mpi_size; i++) + vector_ptr[i] = -1; + + err = H5Dwrite(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, (void *)vector_ptr); + VRFY((err >= 0), "wrote initial data to vector."); + + HDfree(vector_ptr); + vector_ptr = NULL; + + /* 3) Flush the core file, and get an image of it. Close + * the core file. + */ + err = H5Fflush(file_id, H5F_SCOPE_GLOBAL); + VRFY((err >= 0), "flushed core file."); + + image_len = H5Fget_file_image(file_id, NULL, (size_t)0); + VRFY((image_len > 0), "got image file size"); + + image_ptr = (void *)HDmalloc((size_t)image_len); + VRFY(image_ptr != NULL, "allocated file image buffer."); + + bytes_read = H5Fget_file_image(file_id, image_ptr, (size_t)image_len); + VRFY(bytes_read == image_len, "wrote file into image buffer"); + + err = H5Sclose(space_id); + VRFY((err >= 0), "closed data space."); + + err = H5Dclose(dset_id); + VRFY((err >= 0), "closed data set."); + + err = H5Fclose(file_id); + VRFY((err >= 0), "closed core file(1)."); + + err = H5Pclose(fapl_id); + VRFY((err >= 0), "closed fapl(1)."); + + /* 4) Send the image to process 1. */ + + mpi_result = MPI_Ssend((void *)(&image_len), (int)sizeof(ssize_t), MPI_BYTE, 1, 0, MPI_COMM_WORLD); + VRFY((mpi_result == MPI_SUCCESS), "sent image size to process 1"); + + mpi_result = MPI_Ssend((void *)image_ptr, (int)image_len, MPI_BYTE, 1, 0, MPI_COMM_WORLD); + VRFY((mpi_result == MPI_SUCCESS), "sent image to process 1"); + + HDfree(image_ptr); + image_ptr = NULL; + image_len = 0; + + /* 5) Await receipt on a file image from process n-1. */ + + mpi_result = MPI_Recv((void *)(&image_len), (int)sizeof(ssize_t), MPI_BYTE, mpi_size - 1, 0, + MPI_COMM_WORLD, &rcvstat); + VRFY((mpi_result == MPI_SUCCESS), "received image len from process n-1"); + + image_ptr = (void *)HDmalloc((size_t)image_len); + VRFY(image_ptr != NULL, "allocated file image receive buffer."); + + mpi_result = + MPI_Recv((void *)image_ptr, (int)image_len, MPI_BYTE, mpi_size - 1, 0, MPI_COMM_WORLD, &rcvstat); + VRFY((mpi_result == MPI_SUCCESS), "received file image from process n-1"); + + /* 6) open the image received from process n-1, verify that + * it contains a vector of length equal to mpi_size, and + * that the vector contains (0, 1, 2, ... n-1). + */ + fapl_id = H5Pcreate(H5P_FILE_ACCESS); + VRFY((fapl_id >= 0), "creating fapl"); + + err = H5Pset_fapl_core(fapl_id, (size_t)(64 * 1024), FALSE); + VRFY((err >= 0), "setting core file driver in fapl."); + + err = H5Pset_file_image(fapl_id, image_ptr, (size_t)image_len); + VRFY((err >= 0), "set file image in fapl."); + + file_id = H5Fopen(file_name, H5F_ACC_RDWR, fapl_id); + VRFY((file_id >= 0), "opened received file image file"); + + dset_id = H5Dopen2(file_id, "v", H5P_DEFAULT); + VRFY((dset_id >= 0), "opened data set"); + + dset_type_id = H5Dget_type(dset_id); + VRFY((dset_type_id >= 0), "obtained data set type"); + + tri_result = H5Tequal(dset_type_id, H5T_NATIVE_INT); + VRFY((tri_result == TRUE), "verified data set type"); + + space_id = H5Dget_space(dset_id); + VRFY((space_id >= 0), "opened data space"); + + space_ndims = H5Sget_simple_extent_ndims(space_id); + VRFY((space_ndims == 1), "verified data space num dims(1)"); + + space_ndims = H5Sget_simple_extent_dims(space_id, dims, NULL); + VRFY((space_ndims == 1), "verified data space num dims(2)"); + VRFY((dims[0] == (hsize_t)mpi_size), "verified data space dims"); + + vector_ptr = (int *)HDmalloc((size_t)(mpi_size) * sizeof(int)); + VRFY((vector_ptr != NULL), "allocated in memory rep of vector"); + + err = H5Dread(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, (void *)vector_ptr); + VRFY((err >= 0), "read received vector."); + + vector_ok = TRUE; + for (i = 0; i < mpi_size; i++) + if (vector_ptr[i] != i) + vector_ok = FALSE; + VRFY((vector_ok), "verified received vector."); + + HDfree(vector_ptr); + vector_ptr = NULL; + + /* 7) closes the core file and exit. */ + + err = H5Sclose(space_id); + VRFY((err >= 0), "closed data space."); + + err = H5Dclose(dset_id); + VRFY((err >= 0), "closed data set."); + + err = H5Fclose(file_id); + VRFY((err >= 0), "closed core file(1)."); + + err = H5Pclose(fapl_id); + VRFY((err >= 0), "closed fapl(1)."); + + HDfree(image_ptr); + image_ptr = NULL; + image_len = 0; + } + else { + /* 1) Await receipt of file image from process (i - 1). */ + + mpi_result = MPI_Recv((void *)(&image_len), (int)sizeof(ssize_t), MPI_BYTE, mpi_rank - 1, 0, + MPI_COMM_WORLD, &rcvstat); + VRFY((mpi_result == MPI_SUCCESS), "received image size from process mpi_rank-1"); + + image_ptr = (void *)HDmalloc((size_t)image_len); + VRFY(image_ptr != NULL, "allocated file image receive buffer."); + + mpi_result = + MPI_Recv((void *)image_ptr, (int)image_len, MPI_BYTE, mpi_rank - 1, 0, MPI_COMM_WORLD, &rcvstat); + VRFY((mpi_result == MPI_SUCCESS), "received file image from process mpi_rank-1"); + + /* 2) Open the image with the core file driver, verify that it + * contains a vector v of length, and that v[j] = j for + * 0 <= j < i, and that v[j] == -1 for i <= j < n + */ + fapl_id = H5Pcreate(H5P_FILE_ACCESS); + VRFY((fapl_id >= 0), "creating fapl"); + + err = H5Pset_fapl_core(fapl_id, (size_t)(64 * 1024), FALSE); + VRFY((err >= 0), "setting core file driver in fapl."); + + err = H5Pset_file_image(fapl_id, image_ptr, (size_t)image_len); + VRFY((err >= 0), "set file image in fapl."); + + file_id = H5Fopen(file_name, H5F_ACC_RDWR, fapl_id); + H5Eprint2(H5P_DEFAULT, stderr); + VRFY((file_id >= 0), "opened received file image file"); + + dset_id = H5Dopen2(file_id, "v", H5P_DEFAULT); + VRFY((dset_id >= 0), "opened data set"); + + dset_type_id = H5Dget_type(dset_id); + VRFY((dset_type_id >= 0), "obtained data set type"); + + tri_result = H5Tequal(dset_type_id, H5T_NATIVE_INT); + VRFY((tri_result == TRUE), "verified data set type"); + + space_id = H5Dget_space(dset_id); + VRFY((space_id >= 0), "opened data space"); + + space_ndims = H5Sget_simple_extent_ndims(space_id); + VRFY((space_ndims == 1), "verified data space num dims(1)"); + + space_ndims = H5Sget_simple_extent_dims(space_id, dims, NULL); + VRFY((space_ndims == 1), "verified data space num dims(2)"); + VRFY((dims[0] == (hsize_t)mpi_size), "verified data space dims"); + + vector_ptr = (int *)HDmalloc((size_t)(mpi_size) * sizeof(int)); + VRFY((vector_ptr != NULL), "allocated in memory rep of vector"); + + err = H5Dread(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, (void *)vector_ptr); + VRFY((err >= 0), "read received vector."); + + vector_ok = TRUE; + for (i = 0; i < mpi_size; i++) { + if (i < mpi_rank) { + if (vector_ptr[i] != i) + vector_ok = FALSE; + } + else { + if (vector_ptr[i] != -1) + vector_ok = FALSE; + } + } + VRFY((vector_ok), "verified received vector."); + + /* 3) Set v[i] = i in the core file. */ + + vector_ptr[mpi_rank] = mpi_rank; + + err = H5Dwrite(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, (void *)vector_ptr); + VRFY((err >= 0), "wrote modified data to vector."); + + HDfree(vector_ptr); + vector_ptr = NULL; + + /* 4) Flush the core file and send it to process (mpi_rank + 1) % n. */ + + err = H5Fflush(file_id, H5F_SCOPE_GLOBAL); + VRFY((err >= 0), "flushed core file."); + + image_len = H5Fget_file_image(file_id, NULL, (size_t)0); + VRFY((image_len > 0), "got (possibly modified) image file len"); + + image_ptr = (void *)HDrealloc((void *)image_ptr, (size_t)image_len); + VRFY(image_ptr != NULL, "re-allocated file image buffer."); + + bytes_read = H5Fget_file_image(file_id, image_ptr, (size_t)image_len); + VRFY(bytes_read == image_len, "wrote file into image buffer"); + + mpi_result = MPI_Ssend((void *)(&image_len), (int)sizeof(ssize_t), MPI_BYTE, + (mpi_rank + 1) % mpi_size, 0, MPI_COMM_WORLD); + VRFY((mpi_result == MPI_SUCCESS), "sent image size to process (mpi_rank + 1) % mpi_size"); + + mpi_result = MPI_Ssend((void *)image_ptr, (int)image_len, MPI_BYTE, (mpi_rank + 1) % mpi_size, 0, + MPI_COMM_WORLD); + VRFY((mpi_result == MPI_SUCCESS), "sent image to process (mpi_rank + 1) % mpi_size"); + + HDfree(image_ptr); + image_ptr = NULL; + image_len = 0; + + /* 5) close the core file and exit. */ + + err = H5Sclose(space_id); + VRFY((err >= 0), "closed data space."); + + err = H5Dclose(dset_id); + VRFY((err >= 0), "closed data set."); + + err = H5Fclose(file_id); + VRFY((err >= 0), "closed core file(1)."); + + err = H5Pclose(fapl_id); + VRFY((err >= 0), "closed fapl(1)."); + } + + return; + +} /* file_image_daisy_chain_test() */ diff --git a/testpar/API/t_filter_read.c b/testpar/API/t_filter_read.c new file mode 100644 index 0000000..f32c21b --- /dev/null +++ b/testpar/API/t_filter_read.c @@ -0,0 +1,564 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * This verifies the correctness of parallel reading of a dataset that has been + * written serially using filters. + * + * Created by: Christian Chilan + * Date: 2007/05/15 + */ + +#include "hdf5.h" +#include "testphdf5.h" + +#ifdef H5_HAVE_SZLIB_H +#include "szlib.h" +#endif + +static int mpi_size, mpi_rank; + +/* Chunk sizes */ +#define CHUNK_DIM1 7 +#define CHUNK_DIM2 27 + +/* Sizes of the vertical hyperslabs. Total dataset size is + {HS_DIM1, HS_DIM2 * mpi_size } */ +#define HS_DIM1 200 +#define HS_DIM2 100 + +const char * +h5_rmprefix(const char *filename) +{ + const char *ret_ptr; + + if ((ret_ptr = HDstrstr(filename, ":")) == NULL) + ret_ptr = filename; + else + ret_ptr++; + + return (ret_ptr); +} + +#ifdef H5_HAVE_FILTER_SZIP + +/*------------------------------------------------------------------------- + * Function: h5_szip_can_encode + * + * Purpose: Retrieve the filter config flags for szip, tell if + * encoder is available. + * + * Return: 1: decode+encode is enabled + * 0: only decode is enabled + * -1: other + * + * Programmer: + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +int +h5_szip_can_encode(void) +{ + unsigned int filter_config_flags; + + H5Zget_filter_info(H5Z_FILTER_SZIP, &filter_config_flags); + if ((filter_config_flags & (H5Z_FILTER_CONFIG_ENCODE_ENABLED | H5Z_FILTER_CONFIG_DECODE_ENABLED)) == 0) { + /* filter present but neither encode nor decode is supported (???) */ + return -1; + } + else if ((filter_config_flags & (H5Z_FILTER_CONFIG_ENCODE_ENABLED | H5Z_FILTER_CONFIG_DECODE_ENABLED)) == + H5Z_FILTER_CONFIG_DECODE_ENABLED) { + /* decoder only: read but not write */ + return 0; + } + else if ((filter_config_flags & (H5Z_FILTER_CONFIG_ENCODE_ENABLED | H5Z_FILTER_CONFIG_DECODE_ENABLED)) == + H5Z_FILTER_CONFIG_ENCODE_ENABLED) { + /* encoder only: write but not read (???) */ + return -1; + } + else if ((filter_config_flags & (H5Z_FILTER_CONFIG_ENCODE_ENABLED | H5Z_FILTER_CONFIG_DECODE_ENABLED)) == + (H5Z_FILTER_CONFIG_ENCODE_ENABLED | H5Z_FILTER_CONFIG_DECODE_ENABLED)) { + return 1; + } + return (-1); +} +#endif /* H5_HAVE_FILTER_SZIP */ + +/*------------------------------------------------------------------------- + * Function: filter_read_internal + * + * Purpose: Tests parallel reading of a 2D dataset written serially using + * filters. During the parallel reading phase, the dataset is + * divided evenly among the processors in vertical hyperslabs. + * + * Programmer: Christian Chilan + * Tuesday, May 15, 2007 + * + *------------------------------------------------------------------------- + */ +static void +filter_read_internal(const char *filename, hid_t dcpl, hsize_t *dset_size) +{ + hid_t file, dataset; /* HDF5 IDs */ + hid_t access_plist; /* Access property list ID */ + hid_t sid, memspace; /* Dataspace IDs */ + hsize_t size[2]; /* Dataspace dimensions */ + hsize_t hs_offset[2]; /* Hyperslab offset */ + hsize_t hs_size[2]; /* Hyperslab size */ + size_t i, j; /* Local index variables */ + char name[32] = "dataset"; + herr_t hrc; /* Error status */ + int *points = NULL; /* Writing buffer for entire dataset */ + int *check = NULL; /* Reading buffer for selected hyperslab */ + + (void)dset_size; /* silence compiler */ + + /* set up MPI parameters */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* set sizes for dataset and hyperslabs */ + hs_size[0] = size[0] = HS_DIM1; + hs_size[1] = HS_DIM2; + + size[1] = hs_size[1] * (hsize_t)mpi_size; + + hs_offset[0] = 0; + hs_offset[1] = hs_size[1] * (hsize_t)mpi_rank; + + /* Create the data space */ + sid = H5Screate_simple(2, size, NULL); + VRFY(sid >= 0, "H5Screate_simple"); + + /* Create buffers */ + points = (int *)HDmalloc(size[0] * size[1] * sizeof(int)); + VRFY(points != NULL, "HDmalloc"); + + check = (int *)HDmalloc(hs_size[0] * hs_size[1] * sizeof(int)); + VRFY(check != NULL, "HDmalloc"); + + /* Initialize writing buffer with random data */ + for (i = 0; i < size[0]; i++) + for (j = 0; j < size[1]; j++) + points[i * size[1] + j] = (int)(i + j + 7); + + VRFY(H5Pall_filters_avail(dcpl), "Incorrect filter availability"); + + /* Serial write phase */ + if (MAINPROCESS) { + + file = H5Fcreate(h5_rmprefix(filename), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + VRFY(file >= 0, "H5Fcreate"); + + /* Create the dataset */ + dataset = H5Dcreate2(file, name, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + VRFY(dataset >= 0, "H5Dcreate2"); + + hrc = H5Dwrite(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, points); + VRFY(hrc >= 0, "H5Dwrite"); +#if 0 + *dset_size = H5Dget_storage_size(dataset); + VRFY(*dset_size > 0, "H5Dget_storage_size"); +#endif + + hrc = H5Dclose(dataset); + VRFY(hrc >= 0, "H5Dclose"); + + hrc = H5Fclose(file); + VRFY(hrc >= 0, "H5Fclose"); + } + + MPI_Barrier(MPI_COMM_WORLD); + + /* Parallel read phase */ + /* Set up MPIO file access property lists */ + access_plist = H5Pcreate(H5P_FILE_ACCESS); + VRFY((access_plist >= 0), "H5Pcreate"); + + hrc = H5Pset_fapl_mpio(access_plist, MPI_COMM_WORLD, MPI_INFO_NULL); + VRFY((hrc >= 0), "H5Pset_fapl_mpio"); + + /* Open the file */ + file = H5Fopen(filename, H5F_ACC_RDWR, access_plist); + VRFY((file >= 0), "H5Fopen"); + + dataset = H5Dopen2(file, name, H5P_DEFAULT); + VRFY((dataset >= 0), "H5Dopen2"); + + hrc = H5Sselect_hyperslab(sid, H5S_SELECT_SET, hs_offset, NULL, hs_size, NULL); + VRFY(hrc >= 0, "H5Sselect_hyperslab"); + + memspace = H5Screate_simple(2, hs_size, NULL); + VRFY(memspace >= 0, "H5Screate_simple"); + + hrc = H5Dread(dataset, H5T_NATIVE_INT, memspace, sid, H5P_DEFAULT, check); + VRFY(hrc >= 0, "H5Dread"); + + /* Check that the values read are the same as the values written */ + for (i = 0; i < hs_size[0]; i++) { + for (j = 0; j < hs_size[1]; j++) { + if (points[i * size[1] + (size_t)hs_offset[1] + j] != check[i * hs_size[1] + j]) { + HDfprintf(stderr, " Read different values than written.\n"); + HDfprintf(stderr, " At index %lu,%lu\n", (unsigned long)(i), + (unsigned long)(hs_offset[1] + j)); + HDfprintf(stderr, " At original: %d\n", + (int)points[i * size[1] + (size_t)hs_offset[1] + j]); + HDfprintf(stderr, " At returned: %d\n", (int)check[i * hs_size[1] + j]); + VRFY(FALSE, ""); + } + } + } +#if 0 + /* Get the storage size of the dataset */ + *dset_size = H5Dget_storage_size(dataset); + VRFY(*dset_size != 0, "H5Dget_storage_size"); +#endif + + /* Clean up objects used for this test */ + hrc = H5Dclose(dataset); + VRFY(hrc >= 0, "H5Dclose"); + + hrc = H5Sclose(sid); + VRFY(hrc >= 0, "H5Sclose"); + + hrc = H5Sclose(memspace); + VRFY(hrc >= 0, "H5Sclose"); + + hrc = H5Pclose(access_plist); + VRFY(hrc >= 0, "H5Pclose"); + + hrc = H5Fclose(file); + VRFY(hrc >= 0, "H5Fclose"); + + HDfree(points); + HDfree(check); + + MPI_Barrier(MPI_COMM_WORLD); +} + +/*------------------------------------------------------------------------- + * Function: test_filter_read + * + * Purpose: Tests parallel reading of datasets written serially using + * several (combinations of) filters. + * + * Programmer: Christian Chilan + * Tuesday, May 15, 2007 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ + +void +test_filter_read(void) +{ + hid_t dc; /* HDF5 IDs */ + const hsize_t chunk_size[2] = {CHUNK_DIM1, CHUNK_DIM2}; /* Chunk dimensions */ +#if 0 + hsize_t null_size; /* Size of dataset without filters */ +#endif + unsigned chunk_opts; /* Chunk options */ + unsigned disable_partial_chunk_filters; /* Whether filters are disabled on partial chunks */ + herr_t hrc; + const char *filename; +#ifdef H5_HAVE_FILTER_FLETCHER32 + hsize_t fletcher32_size; /* Size of dataset with Fletcher32 checksum */ +#endif + +#ifdef H5_HAVE_FILTER_DEFLATE + hsize_t deflate_size; /* Size of dataset with deflate filter */ +#endif /* H5_HAVE_FILTER_DEFLATE */ + +#ifdef H5_HAVE_FILTER_SZIP + hsize_t szip_size; /* Size of dataset with szip filter */ + unsigned szip_options_mask = H5_SZIP_NN_OPTION_MASK; + unsigned szip_pixels_per_block = 4; +#endif /* H5_HAVE_FILTER_SZIP */ + +#if 0 + hsize_t shuffle_size; /* Size of dataset with shuffle filter */ +#endif + +#if (defined H5_HAVE_FILTER_DEFLATE || defined H5_HAVE_FILTER_SZIP) + hsize_t combo_size; /* Size of dataset with multiple filters */ +#endif /* H5_HAVE_FILTER_DEFLATE || H5_HAVE_FILTER_SZIP */ + + filename = PARATESTFILE /* GetTestParameters() */; + + if (VERBOSE_MED) + HDprintf("Parallel reading of dataset written with filters %s\n", filename); + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_FILTERS)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf( + " API functions for basic file, dataset or filter aren't supported with this connector\n"); + fflush(stdout); + } + + return; + } + + /*---------------------------------------------------------- + * STEP 0: Test without filters. + *---------------------------------------------------------- + */ + dc = H5Pcreate(H5P_DATASET_CREATE); + VRFY(dc >= 0, "H5Pcreate"); + + hrc = H5Pset_chunk(dc, 2, chunk_size); + VRFY(hrc >= 0, "H5Pset_chunk"); + + filter_read_internal(filename, dc, /* &null_size */ NULL); + + /* Clean up objects used for this test */ + hrc = H5Pclose(dc); + VRFY(hrc >= 0, "H5Pclose"); + + /* Run steps 1-3 both with and without filters disabled on partial chunks */ + for (disable_partial_chunk_filters = 0; disable_partial_chunk_filters <= 1; + disable_partial_chunk_filters++) { + /* Set chunk options appropriately */ + dc = H5Pcreate(H5P_DATASET_CREATE); + VRFY(dc >= 0, "H5Pcreate"); + + hrc = H5Pset_chunk(dc, 2, chunk_size); + VRFY(hrc >= 0, "H5Pset_filter"); + + hrc = H5Pget_chunk_opts(dc, &chunk_opts); + VRFY(hrc >= 0, "H5Pget_chunk_opts"); + + if (disable_partial_chunk_filters) + chunk_opts |= H5D_CHUNK_DONT_FILTER_PARTIAL_CHUNKS; + + hrc = H5Pclose(dc); + VRFY(hrc >= 0, "H5Pclose"); + + /*---------------------------------------------------------- + * STEP 1: Test Fletcher32 Checksum by itself. + *---------------------------------------------------------- + */ +#ifdef H5_HAVE_FILTER_FLETCHER32 + + dc = H5Pcreate(H5P_DATASET_CREATE); + VRFY(dc >= 0, "H5Pset_filter"); + + hrc = H5Pset_chunk(dc, 2, chunk_size); + VRFY(hrc >= 0, "H5Pset_filter"); + + hrc = H5Pset_chunk_opts(dc, chunk_opts); + VRFY(hrc >= 0, "H5Pset_chunk_opts"); + + hrc = H5Pset_filter(dc, H5Z_FILTER_FLETCHER32, 0, 0, NULL); + VRFY(hrc >= 0, "H5Pset_filter"); + + filter_read_internal(filename, dc, &fletcher32_size); + VRFY(fletcher32_size > null_size, "Size after checksumming is incorrect."); + + /* Clean up objects used for this test */ + hrc = H5Pclose(dc); + VRFY(hrc >= 0, "H5Pclose"); + +#endif /* H5_HAVE_FILTER_FLETCHER32 */ + + /*---------------------------------------------------------- + * STEP 2: Test deflation by itself. + *---------------------------------------------------------- + */ +#ifdef H5_HAVE_FILTER_DEFLATE + + dc = H5Pcreate(H5P_DATASET_CREATE); + VRFY(dc >= 0, "H5Pcreate"); + + hrc = H5Pset_chunk(dc, 2, chunk_size); + VRFY(hrc >= 0, "H5Pset_chunk"); + + hrc = H5Pset_chunk_opts(dc, chunk_opts); + VRFY(hrc >= 0, "H5Pset_chunk_opts"); + + hrc = H5Pset_deflate(dc, 6); + VRFY(hrc >= 0, "H5Pset_deflate"); + + filter_read_internal(filename, dc, &deflate_size); + + /* Clean up objects used for this test */ + hrc = H5Pclose(dc); + VRFY(hrc >= 0, "H5Pclose"); + +#endif /* H5_HAVE_FILTER_DEFLATE */ + + /*---------------------------------------------------------- + * STEP 3: Test szip compression by itself. + *---------------------------------------------------------- + */ +#ifdef H5_HAVE_FILTER_SZIP + if (h5_szip_can_encode() == 1) { + dc = H5Pcreate(H5P_DATASET_CREATE); + VRFY(dc >= 0, "H5Pcreate"); + + hrc = H5Pset_chunk(dc, 2, chunk_size); + VRFY(hrc >= 0, "H5Pset_chunk"); + + hrc = H5Pset_chunk_opts(dc, chunk_opts); + VRFY(hrc >= 0, "H5Pset_chunk_opts"); + + hrc = H5Pset_szip(dc, szip_options_mask, szip_pixels_per_block); + VRFY(hrc >= 0, "H5Pset_szip"); + + filter_read_internal(filename, dc, &szip_size); + + /* Clean up objects used for this test */ + hrc = H5Pclose(dc); + VRFY(hrc >= 0, "H5Pclose"); + } +#endif /* H5_HAVE_FILTER_SZIP */ + } /* end for */ + + /*---------------------------------------------------------- + * STEP 4: Test shuffling by itself. + *---------------------------------------------------------- + */ + + dc = H5Pcreate(H5P_DATASET_CREATE); + VRFY(dc >= 0, "H5Pcreate"); + + hrc = H5Pset_chunk(dc, 2, chunk_size); + VRFY(hrc >= 0, "H5Pset_chunk"); + + hrc = H5Pset_shuffle(dc); + VRFY(hrc >= 0, "H5Pset_shuffle"); + + filter_read_internal(filename, dc, /* &shuffle_size */ NULL); +#if 0 + VRFY(shuffle_size == null_size, "Shuffled size not the same as uncompressed size."); +#endif + + /* Clean up objects used for this test */ + hrc = H5Pclose(dc); + VRFY(hrc >= 0, "H5Pclose"); + + /*---------------------------------------------------------- + * STEP 5: Test shuffle + deflate + checksum in any order. + *---------------------------------------------------------- + */ +#ifdef H5_HAVE_FILTER_DEFLATE + /* Testing shuffle+deflate+checksum filters (checksum first) */ + dc = H5Pcreate(H5P_DATASET_CREATE); + VRFY(dc >= 0, "H5Pcreate"); + + hrc = H5Pset_chunk(dc, 2, chunk_size); + VRFY(hrc >= 0, "H5Pset_chunk"); + + hrc = H5Pset_fletcher32(dc); + VRFY(hrc >= 0, "H5Pset_fletcher32"); + + hrc = H5Pset_shuffle(dc); + VRFY(hrc >= 0, "H5Pset_shuffle"); + + hrc = H5Pset_deflate(dc, 6); + VRFY(hrc >= 0, "H5Pset_deflate"); + + filter_read_internal(filename, dc, &combo_size); + + /* Clean up objects used for this test */ + hrc = H5Pclose(dc); + VRFY(hrc >= 0, "H5Pclose"); + + /* Testing shuffle+deflate+checksum filters (checksum last) */ + dc = H5Pcreate(H5P_DATASET_CREATE); + VRFY(dc >= 0, "H5Pcreate"); + + hrc = H5Pset_chunk(dc, 2, chunk_size); + VRFY(hrc >= 0, "H5Pset_chunk"); + + hrc = H5Pset_shuffle(dc); + VRFY(hrc >= 0, "H5Pset_shuffle"); + + hrc = H5Pset_deflate(dc, 6); + VRFY(hrc >= 0, "H5Pset_deflate"); + + hrc = H5Pset_fletcher32(dc); + VRFY(hrc >= 0, "H5Pset_fletcher32"); + + filter_read_internal(filename, dc, &combo_size); + + /* Clean up objects used for this test */ + hrc = H5Pclose(dc); + VRFY(hrc >= 0, "H5Pclose"); + +#endif /* H5_HAVE_FILTER_DEFLATE */ + + /*---------------------------------------------------------- + * STEP 6: Test shuffle + szip + checksum in any order. + *---------------------------------------------------------- + */ +#ifdef H5_HAVE_FILTER_SZIP + + /* Testing shuffle+szip(with encoder)+checksum filters(checksum first) */ + dc = H5Pcreate(H5P_DATASET_CREATE); + VRFY(dc >= 0, "H5Pcreate"); + + hrc = H5Pset_chunk(dc, 2, chunk_size); + VRFY(hrc >= 0, "H5Pset_chunk"); + + hrc = H5Pset_fletcher32(dc); + VRFY(hrc >= 0, "H5Pset_fletcher32"); + + hrc = H5Pset_shuffle(dc); + VRFY(hrc >= 0, "H5Pset_shuffle"); + + /* Make sure encoding is enabled */ + if (h5_szip_can_encode() == 1) { + hrc = H5Pset_szip(dc, szip_options_mask, szip_pixels_per_block); + VRFY(hrc >= 0, "H5Pset_szip"); + + filter_read_internal(filename, dc, &combo_size); + } + + /* Clean up objects used for this test */ + hrc = H5Pclose(dc); + VRFY(hrc >= 0, "H5Pclose"); + + /* Testing shuffle+szip(with encoder)+checksum filters(checksum last) */ + /* Make sure encoding is enabled */ + if (h5_szip_can_encode() == 1) { + dc = H5Pcreate(H5P_DATASET_CREATE); + VRFY(dc >= 0, "H5Pcreate"); + + hrc = H5Pset_chunk(dc, 2, chunk_size); + VRFY(hrc >= 0, "H5Pset_chunk"); + + hrc = H5Pset_shuffle(dc); + VRFY(hrc >= 0, "H5Pset_shuffle"); + + hrc = H5Pset_szip(dc, szip_options_mask, szip_pixels_per_block); + VRFY(hrc >= 0, "H5Pset_szip"); + + hrc = H5Pset_fletcher32(dc); + VRFY(hrc >= 0, "H5Pset_fletcher32"); + + filter_read_internal(filename, dc, &combo_size); + + /* Clean up objects used for this test */ + hrc = H5Pclose(dc); + VRFY(hrc >= 0, "H5Pclose"); + } + +#endif /* H5_HAVE_FILTER_SZIP */ +} diff --git a/testpar/API/t_mdset.c b/testpar/API/t_mdset.c new file mode 100644 index 0000000..e11818f --- /dev/null +++ b/testpar/API/t_mdset.c @@ -0,0 +1,2814 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "hdf5.h" +#include "testphdf5.h" + +#if 0 +#include "H5Dprivate.h" +#include "H5private.h" +#endif + +#define DIM 2 +#define SIZE 32 +#define NDATASET 4 +#define GROUP_DEPTH 32 +enum obj_type { is_group, is_dset }; + +static int get_size(void); +static void write_dataset(hid_t, hid_t, hid_t); +static int read_dataset(hid_t, hid_t, hid_t); +static void create_group_recursive(hid_t, hid_t, hid_t, int); +static void recursive_read_group(hid_t, hid_t, hid_t, int); +static void group_dataset_read(hid_t fid, int mpi_rank, int m); +static void write_attribute(hid_t, int, int); +static int read_attribute(hid_t, int, int); +static int check_value(DATATYPE *, DATATYPE *, int); +static void get_slab(hsize_t[], hsize_t[], hsize_t[], hsize_t[], int); + +/* + * The size value computed by this function is used extensively in + * configuring tests for the current number of processes. + * + * This function was created as part of an effort to allow the + * test functions in this file to run on an arbitrary number of + * processors. + * JRM - 8/11/04 + */ + +static int +get_size(void) +{ + int mpi_rank; + int mpi_size; + int size = SIZE; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); /* needed for VRFY */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + + if (mpi_size > size) { + if ((mpi_size % 2) == 0) { + size = mpi_size; + } + else { + size = mpi_size + 1; + } + } + + VRFY((mpi_size <= size), "mpi_size <= size"); + VRFY(((size % 2) == 0), "size isn't even"); + + return (size); + +} /* get_size() */ + +/* + * Example of using PHDF5 to create a zero sized dataset. + * + */ +void +zero_dim_dset(void) +{ + int mpi_size, mpi_rank; + const char *filename; + hid_t fid, plist, dcpl, dsid, sid; + hsize_t dim, chunk_dim; + herr_t ret; + int data[1]; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file or dataset aren't supported with this connector\n"); + fflush(stdout); + } + + return; + } + + filename = PARATESTFILE /* GetTestParameters() */; + + plist = create_faccess_plist(MPI_COMM_WORLD, MPI_INFO_NULL, facc_type); + VRFY((plist >= 0), "create_faccess_plist succeeded"); + + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, plist); + VRFY((fid >= 0), "H5Fcreate succeeded"); + ret = H5Pclose(plist); + VRFY((ret >= 0), "H5Pclose succeeded"); + + dcpl = H5Pcreate(H5P_DATASET_CREATE); + VRFY((dcpl >= 0), "failed H5Pcreate"); + + /* Set 1 chunk size */ + chunk_dim = 1; + ret = H5Pset_chunk(dcpl, 1, &chunk_dim); + VRFY((ret >= 0), "failed H5Pset_chunk"); + + /* Create 1D dataspace with 0 dim size */ + dim = 0; + sid = H5Screate_simple(1, &dim, NULL); + VRFY((sid >= 0), "failed H5Screate_simple"); + + /* Create chunked dataset */ + dsid = H5Dcreate2(fid, "dset", H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + VRFY((dsid >= 0), "failed H5Dcreate2"); + + /* write 0 elements from dataset */ + ret = H5Dwrite(dsid, H5T_NATIVE_INT, sid, sid, H5P_DEFAULT, data); + VRFY((ret >= 0), "failed H5Dwrite"); + + /* Read 0 elements from dataset */ + ret = H5Dread(dsid, H5T_NATIVE_INT, sid, sid, H5P_DEFAULT, data); + VRFY((ret >= 0), "failed H5Dread"); + + H5Pclose(dcpl); + H5Dclose(dsid); + H5Sclose(sid); + H5Fclose(fid); +} + +/* + * Example of using PHDF5 to create ndatasets datasets. Each process write + * a slab of array to the file. + */ +void +multiple_dset_write(void) +{ + int i, j, n, mpi_size, mpi_rank, size; + hid_t iof, plist, dataset, memspace, filespace; + hid_t dcpl; /* Dataset creation property list */ + hsize_t chunk_origin[DIM]; + hsize_t chunk_dims[DIM], file_dims[DIM]; + hsize_t count[DIM] = {1, 1}; + double *outme = NULL; + double fill = 1.0; /* Fill value */ + char dname[100]; + herr_t ret; +#if 0 + const H5Ptest_param_t *pt; +#endif + char *filename; + int ndatasets; + +#if 0 + pt = GetTestParameters(); +#endif + /* filename = pt->name; */ filename = PARATESTFILE; + /* ndatasets = pt->count; */ ndatasets = NDATASETS; + + size = get_size(); + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file or dataset aren't supported with this connector\n"); + fflush(stdout); + } + + return; + } + + outme = HDmalloc((size_t)size * (size_t)size * sizeof(double)); + VRFY((outme != NULL), "HDmalloc succeeded for outme"); + + plist = create_faccess_plist(MPI_COMM_WORLD, MPI_INFO_NULL, facc_type); + VRFY((plist >= 0), "create_faccess_plist succeeded"); + iof = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, plist); + VRFY((iof >= 0), "H5Fcreate succeeded"); + ret = H5Pclose(plist); + VRFY((ret >= 0), "H5Pclose succeeded"); + + /* decide the hyperslab according to process number. */ + get_slab(chunk_origin, chunk_dims, count, file_dims, size); + + memspace = H5Screate_simple(DIM, chunk_dims, NULL); + filespace = H5Screate_simple(DIM, file_dims, NULL); + ret = H5Sselect_hyperslab(filespace, H5S_SELECT_SET, chunk_origin, chunk_dims, count, chunk_dims); + VRFY((ret >= 0), "mdata hyperslab selection"); + + /* Create a dataset creation property list */ + dcpl = H5Pcreate(H5P_DATASET_CREATE); + VRFY((dcpl >= 0), "dataset creation property list succeeded"); + + ret = H5Pset_fill_value(dcpl, H5T_NATIVE_DOUBLE, &fill); + VRFY((ret >= 0), "set fill-value succeeded"); + + for (n = 0; n < ndatasets; n++) { + HDsnprintf(dname, sizeof(dname), "dataset %d", n); + dataset = H5Dcreate2(iof, dname, H5T_NATIVE_DOUBLE, filespace, H5P_DEFAULT, dcpl, H5P_DEFAULT); + VRFY((dataset > 0), dname); + + /* calculate data to write */ + for (i = 0; i < size; i++) + for (j = 0; j < size; j++) + outme[(i * size) + j] = n * 1000 + mpi_rank; + + H5Dwrite(dataset, H5T_NATIVE_DOUBLE, memspace, filespace, H5P_DEFAULT, outme); + + H5Dclose(dataset); +#ifdef BARRIER_CHECKS + if (!((n + 1) % 10)) { + HDprintf("created %d datasets\n", n + 1); + MPI_Barrier(MPI_COMM_WORLD); + } +#endif /* BARRIER_CHECKS */ + } + + H5Sclose(filespace); + H5Sclose(memspace); + H5Pclose(dcpl); + H5Fclose(iof); + + HDfree(outme); +} + +/* Example of using PHDF5 to create, write, and read compact dataset. + */ +void +compact_dataset(void) +{ + int i, j, mpi_size, mpi_rank, size, err_num = 0; + hid_t iof, plist, dcpl, dxpl, dataset, filespace; + hsize_t file_dims[DIM]; + double *outme; + double *inme; + char dname[] = "dataset"; + herr_t ret; + const char *filename; +#ifdef H5_HAVE_INSTRUMENTED_LIBRARY + hbool_t prop_value; +#endif + + size = get_size(); + + for (i = 0; i < DIM; i++) + file_dims[i] = (hsize_t)size; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file or dataset aren't supported with this connector\n"); + fflush(stdout); + } + + return; + } + + outme = HDmalloc((size_t)((size_t)size * (size_t)size * sizeof(double))); + VRFY((outme != NULL), "HDmalloc succeeded for outme"); + + inme = HDmalloc((size_t)size * (size_t)size * sizeof(double)); + VRFY((outme != NULL), "HDmalloc succeeded for inme"); + + filename = PARATESTFILE /* GetTestParameters() */; + VRFY((mpi_size <= size), "mpi_size <= size"); + + plist = create_faccess_plist(MPI_COMM_WORLD, MPI_INFO_NULL, facc_type); + iof = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, plist); + + /* Define data space */ + filespace = H5Screate_simple(DIM, file_dims, NULL); + + /* Create a compact dataset */ + dcpl = H5Pcreate(H5P_DATASET_CREATE); + VRFY((dcpl >= 0), "dataset creation property list succeeded"); + ret = H5Pset_layout(dcpl, H5D_COMPACT); + VRFY((dcpl >= 0), "set property list for compact dataset"); + ret = H5Pset_alloc_time(dcpl, H5D_ALLOC_TIME_EARLY); + VRFY((ret >= 0), "set space allocation time for compact dataset"); + + dataset = H5Dcreate2(iof, dname, H5T_NATIVE_DOUBLE, filespace, H5P_DEFAULT, dcpl, H5P_DEFAULT); + VRFY((dataset >= 0), "H5Dcreate2 succeeded"); + + /* set up the collective transfer properties list */ + dxpl = H5Pcreate(H5P_DATASET_XFER); + VRFY((dxpl >= 0), ""); + ret = H5Pset_dxpl_mpio(dxpl, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pcreate xfer succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(dxpl, H5FD_MPIO_INDIVIDUAL_IO); + VRFY((ret >= 0), "set independent IO collectively succeeded"); + } + + /* Recalculate data to write. Each process writes the same data. */ + for (i = 0; i < size; i++) + for (j = 0; j < size; j++) + outme[(i * size) + j] = (i + j) * 1000; + + ret = H5Dwrite(dataset, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, dxpl, outme); + VRFY((ret >= 0), "H5Dwrite succeeded"); + + H5Pclose(dcpl); + H5Pclose(plist); + H5Dclose(dataset); + H5Sclose(filespace); + H5Fclose(iof); + + /* Open the file and dataset, read and compare the data. */ + plist = create_faccess_plist(MPI_COMM_WORLD, MPI_INFO_NULL, facc_type); + iof = H5Fopen(filename, H5F_ACC_RDONLY, plist); + VRFY((iof >= 0), "H5Fopen succeeded"); + + /* set up the collective transfer properties list */ + dxpl = H5Pcreate(H5P_DATASET_XFER); + VRFY((dxpl >= 0), ""); + ret = H5Pset_dxpl_mpio(dxpl, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pcreate xfer succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(dxpl, H5FD_MPIO_INDIVIDUAL_IO); + VRFY((ret >= 0), "set independent IO collectively succeeded"); + } + + dataset = H5Dopen2(iof, dname, H5P_DEFAULT); + VRFY((dataset >= 0), "H5Dopen2 succeeded"); + +#ifdef H5_HAVE_INSTRUMENTED_LIBRARY + prop_value = H5D_XFER_COLL_RANK0_BCAST_DEF; + ret = H5Pinsert2(dxpl, H5D_XFER_COLL_RANK0_BCAST_NAME, H5D_XFER_COLL_RANK0_BCAST_SIZE, &prop_value, NULL, + NULL, NULL, NULL, NULL, NULL); + VRFY((ret >= 0), "H5Pinsert2() succeeded"); +#endif /* H5_HAVE_INSTRUMENTED_LIBRARY */ + + ret = H5Dread(dataset, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, dxpl, inme); + VRFY((ret >= 0), "H5Dread succeeded"); + +#ifdef H5_HAVE_INSTRUMENTED_LIBRARY + prop_value = FALSE; + ret = H5Pget(dxpl, H5D_XFER_COLL_RANK0_BCAST_NAME, &prop_value); + VRFY((ret >= 0), "H5Pget succeeded"); + VRFY((prop_value == FALSE && dxfer_coll_type == DXFER_COLLECTIVE_IO), + "rank 0 Bcast optimization was performed for a compact dataset"); +#endif /* H5_HAVE_INSTRUMENTED_LIBRARY */ + + /* Verify data value */ + for (i = 0; i < size; i++) + for (j = 0; j < size; j++) + if (!H5_DBL_ABS_EQUAL(inme[(i * size) + j], outme[(i * size) + j])) + if (err_num++ < MAX_ERR_REPORT || VERBOSE_MED) + HDprintf("Dataset Verify failed at [%d][%d]: expect %f, got %f\n", i, j, + outme[(i * size) + j], inme[(i * size) + j]); + + H5Pclose(plist); + H5Pclose(dxpl); + H5Dclose(dataset); + H5Fclose(iof); + HDfree(inme); + HDfree(outme); +} + +/* + * Example of using PHDF5 to create, write, and read dataset and attribute + * of Null dataspace. + */ +void +null_dataset(void) +{ + int mpi_size, mpi_rank; + hid_t iof, plist, dxpl, dataset, attr, sid; + unsigned uval = 2; /* Buffer for writing to dataset */ + int val = 1; /* Buffer for writing to attribute */ + hssize_t nelem; + char dname[] = "dataset"; + char attr_name[] = "attribute"; + herr_t ret; + const char *filename; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, dataset, or attribute aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + filename = PARATESTFILE /* GetTestParameters() */; + + plist = create_faccess_plist(MPI_COMM_WORLD, MPI_INFO_NULL, facc_type); + iof = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, plist); + + /* Define data space */ + sid = H5Screate(H5S_NULL); + + /* Check that the null dataspace actually has 0 elements */ + nelem = H5Sget_simple_extent_npoints(sid); + VRFY((nelem == 0), "H5Sget_simple_extent_npoints"); + + /* Create a compact dataset */ + dataset = H5Dcreate2(iof, dname, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((dataset >= 0), "H5Dcreate2 succeeded"); + + /* set up the collective transfer properties list */ + dxpl = H5Pcreate(H5P_DATASET_XFER); + VRFY((dxpl >= 0), ""); + ret = H5Pset_dxpl_mpio(dxpl, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pcreate xfer succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(dxpl, H5FD_MPIO_INDIVIDUAL_IO); + VRFY((ret >= 0), "set independent IO collectively succeeded"); + } + + /* Write "nothing" to the dataset(with type conversion) */ + ret = H5Dwrite(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, dxpl, &uval); + VRFY((ret >= 0), "H5Dwrite succeeded"); + + /* Create an attribute for the group */ + attr = H5Acreate2(dataset, attr_name, H5T_NATIVE_UINT, sid, H5P_DEFAULT, H5P_DEFAULT); + VRFY((attr >= 0), "H5Acreate2"); + + /* Write "nothing" to the attribute(with type conversion) */ + ret = H5Awrite(attr, H5T_NATIVE_INT, &val); + VRFY((ret >= 0), "H5Awrite"); + + H5Aclose(attr); + H5Dclose(dataset); + H5Pclose(plist); + H5Sclose(sid); + H5Fclose(iof); + + /* Open the file and dataset, read and compare the data. */ + plist = create_faccess_plist(MPI_COMM_WORLD, MPI_INFO_NULL, facc_type); + iof = H5Fopen(filename, H5F_ACC_RDONLY, plist); + VRFY((iof >= 0), "H5Fopen succeeded"); + + /* set up the collective transfer properties list */ + dxpl = H5Pcreate(H5P_DATASET_XFER); + VRFY((dxpl >= 0), ""); + ret = H5Pset_dxpl_mpio(dxpl, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pcreate xfer succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(dxpl, H5FD_MPIO_INDIVIDUAL_IO); + VRFY((ret >= 0), "set independent IO collectively succeeded"); + } + + dataset = H5Dopen2(iof, dname, H5P_DEFAULT); + VRFY((dataset >= 0), "H5Dopen2 succeeded"); + + /* Try reading from the dataset(make certain our buffer is unmodified) */ + ret = H5Dread(dataset, H5T_NATIVE_UINT, H5S_ALL, H5S_ALL, dxpl, &uval); + VRFY((ret >= 0), "H5Dread"); + VRFY((uval == 2), "H5Dread"); + + /* Open the attribute for the dataset */ + attr = H5Aopen(dataset, attr_name, H5P_DEFAULT); + VRFY((attr >= 0), "H5Aopen"); + + /* Try reading from the attribute(make certain our buffer is unmodified) */ ret = + H5Aread(attr, H5T_NATIVE_INT, &val); + VRFY((ret >= 0), "H5Aread"); + VRFY((val == 1), "H5Aread"); + + H5Pclose(plist); + H5Pclose(dxpl); + H5Aclose(attr); + H5Dclose(dataset); + H5Fclose(iof); +} + +/* Example of using PHDF5 to create "large" datasets. (>2GB, >4GB, >8GB) + * Actual data is _not_ written to these datasets. Dataspaces are exact + * sizes(2GB, 4GB, etc.), but the metadata for the file pushes the file over + * the boundary of interest. + */ +void +big_dataset(void) +{ + int mpi_size, mpi_rank; /* MPI info */ + hid_t iof, /* File ID */ + fapl, /* File access property list ID */ + dataset, /* Dataset ID */ + filespace; /* Dataset's dataspace ID */ + hsize_t file_dims[4]; /* Dimensions of dataspace */ + char dname[] = "dataset"; /* Name of dataset */ +#if 0 + MPI_Offset file_size; /* Size of file on disk */ +#endif + herr_t ret; /* Generic return value */ + const char *filename; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file or dataset aren't supported with this connector\n"); + fflush(stdout); + } + + return; + } + + /* Verify MPI_Offset can handle larger than 2GB sizes */ + VRFY((sizeof(MPI_Offset) > 4), "sizeof(MPI_Offset)>4"); + + filename = PARATESTFILE /* GetTestParameters() */; + + fapl = create_faccess_plist(MPI_COMM_WORLD, MPI_INFO_NULL, facc_type); + VRFY((fapl >= 0), "create_faccess_plist succeeded"); + + /* + * Create >2GB HDF5 file + */ + iof = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + VRFY((iof >= 0), "H5Fcreate succeeded"); + + /* Define dataspace for 2GB dataspace */ + file_dims[0] = 2; + file_dims[1] = 1024; + file_dims[2] = 1024; + file_dims[3] = 1024; + filespace = H5Screate_simple(4, file_dims, NULL); + VRFY((filespace >= 0), "H5Screate_simple succeeded"); + + dataset = H5Dcreate2(iof, dname, H5T_NATIVE_UCHAR, filespace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((dataset >= 0), "H5Dcreate2 succeeded"); + + /* Close all file objects */ + ret = H5Dclose(dataset); + VRFY((ret >= 0), "H5Dclose succeeded"); + ret = H5Sclose(filespace); + VRFY((ret >= 0), "H5Sclose succeeded"); + ret = H5Fclose(iof); + VRFY((ret >= 0), "H5Fclose succeeded"); + +#if 0 + /* Check that file of the correct size was created */ + file_size = h5_get_file_size(filename, fapl); + VRFY((file_size == 2147485696ULL), "File is correct size(~2GB)"); +#endif + + /* + * Create >4GB HDF5 file + */ + iof = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + VRFY((iof >= 0), "H5Fcreate succeeded"); + + /* Define dataspace for 4GB dataspace */ + file_dims[0] = 4; + file_dims[1] = 1024; + file_dims[2] = 1024; + file_dims[3] = 1024; + filespace = H5Screate_simple(4, file_dims, NULL); + VRFY((filespace >= 0), "H5Screate_simple succeeded"); + + dataset = H5Dcreate2(iof, dname, H5T_NATIVE_UCHAR, filespace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((dataset >= 0), "H5Dcreate2 succeeded"); + + /* Close all file objects */ + ret = H5Dclose(dataset); + VRFY((ret >= 0), "H5Dclose succeeded"); + ret = H5Sclose(filespace); + VRFY((ret >= 0), "H5Sclose succeeded"); + ret = H5Fclose(iof); + VRFY((ret >= 0), "H5Fclose succeeded"); +#if 0 + /* Check that file of the correct size was created */ + file_size = h5_get_file_size(filename, fapl); + VRFY((file_size == 4294969344ULL), "File is correct size(~4GB)"); +#endif + + /* + * Create >8GB HDF5 file + */ + iof = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + VRFY((iof >= 0), "H5Fcreate succeeded"); + + /* Define dataspace for 8GB dataspace */ + file_dims[0] = 8; + file_dims[1] = 1024; + file_dims[2] = 1024; + file_dims[3] = 1024; + filespace = H5Screate_simple(4, file_dims, NULL); + VRFY((filespace >= 0), "H5Screate_simple succeeded"); + + dataset = H5Dcreate2(iof, dname, H5T_NATIVE_UCHAR, filespace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((dataset >= 0), "H5Dcreate2 succeeded"); + + /* Close all file objects */ + ret = H5Dclose(dataset); + VRFY((ret >= 0), "H5Dclose succeeded"); + ret = H5Sclose(filespace); + VRFY((ret >= 0), "H5Sclose succeeded"); + ret = H5Fclose(iof); + VRFY((ret >= 0), "H5Fclose succeeded"); +#if 0 + /* Check that file of the correct size was created */ + file_size = h5_get_file_size(filename, fapl); + VRFY((file_size == 8589936640ULL), "File is correct size(~8GB)"); +#endif + + /* Close fapl */ + ret = H5Pclose(fapl); + VRFY((ret >= 0), "H5Pclose succeeded"); +} + +/* Example of using PHDF5 to read a partial written dataset. The dataset does + * not have actual data written to the entire raw data area and relies on the + * default fill value of zeros to work correctly. + */ +void +dataset_fillvalue(void) +{ + int mpi_size, mpi_rank; /* MPI info */ + int err_num; /* Number of errors */ + hid_t iof, /* File ID */ + fapl, /* File access property list ID */ + dxpl, /* Data transfer property list ID */ + dataset, /* Dataset ID */ + memspace, /* Memory dataspace ID */ + filespace; /* Dataset's dataspace ID */ + char dname[] = "dataset"; /* Name of dataset */ + hsize_t dset_dims[4] = {0, 6, 7, 8}; + hsize_t req_start[4] = {0, 0, 0, 0}; + hsize_t req_count[4] = {1, 6, 7, 8}; + hsize_t dset_size; /* Dataset size */ + int *rdata, *wdata; /* Buffers for data to read and write */ + int *twdata, *trdata; /* Temporary pointer into buffer */ + int acc, i, ii, j, k, l; /* Local index variables */ + herr_t ret; /* Generic return value */ + const char *filename; +#ifdef H5_HAVE_INSTRUMENTED_LIBRARY + hbool_t prop_value; +#endif + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file or dataset aren't supported with this connector\n"); + fflush(stdout); + } + + return; + } + + filename = PARATESTFILE /* GetTestParameters() */; + + /* Set the dataset dimension to be one row more than number of processes */ + /* and calculate the actual dataset size. */ + dset_dims[0] = (hsize_t)(mpi_size + 1); + dset_size = dset_dims[0] * dset_dims[1] * dset_dims[2] * dset_dims[3]; + + /* Allocate space for the buffers */ + rdata = HDmalloc((size_t)(dset_size * sizeof(int))); + VRFY((rdata != NULL), "HDcalloc succeeded for read buffer"); + wdata = HDmalloc((size_t)(dset_size * sizeof(int))); + VRFY((wdata != NULL), "HDmalloc succeeded for write buffer"); + + fapl = create_faccess_plist(MPI_COMM_WORLD, MPI_INFO_NULL, facc_type); + VRFY((fapl >= 0), "create_faccess_plist succeeded"); + + /* + * Create HDF5 file + */ + iof = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + VRFY((iof >= 0), "H5Fcreate succeeded"); + + filespace = H5Screate_simple(4, dset_dims, NULL); + VRFY((filespace >= 0), "File H5Screate_simple succeeded"); + + dataset = H5Dcreate2(iof, dname, H5T_NATIVE_INT, filespace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((dataset >= 0), "H5Dcreate2 succeeded"); + + memspace = H5Screate_simple(4, dset_dims, NULL); + VRFY((memspace >= 0), "Memory H5Screate_simple succeeded"); + + /* + * Read dataset before any data is written. + */ + + /* Create DXPL for I/O */ + dxpl = H5Pcreate(H5P_DATASET_XFER); + VRFY((dxpl >= 0), "H5Pcreate succeeded"); + +#ifdef H5_HAVE_INSTRUMENTED_LIBRARY + prop_value = H5D_XFER_COLL_RANK0_BCAST_DEF; + ret = H5Pinsert2(dxpl, H5D_XFER_COLL_RANK0_BCAST_NAME, H5D_XFER_COLL_RANK0_BCAST_SIZE, &prop_value, NULL, + NULL, NULL, NULL, NULL, NULL); + VRFY((ret >= 0), "testing property list inserted succeeded"); +#endif /* H5_HAVE_INSTRUMENTED_LIBRARY */ + + for (ii = 0; ii < 2; ii++) { + + if (ii == 0) + ret = H5Pset_dxpl_mpio(dxpl, H5FD_MPIO_INDEPENDENT); + else + ret = H5Pset_dxpl_mpio(dxpl, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + + /* set entire read buffer with the constant 2 */ + HDmemset(rdata, 2, (size_t)(dset_size * sizeof(int))); + + /* Read the entire dataset back */ + ret = H5Dread(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, dxpl, rdata); + VRFY((ret >= 0), "H5Dread succeeded"); + +#ifdef H5_HAVE_INSTRUMENTED_LIBRARY + prop_value = FALSE; + ret = H5Pget(dxpl, H5D_XFER_COLL_RANK0_BCAST_NAME, &prop_value); + VRFY((ret >= 0), "testing property list get succeeded"); + if (ii == 0) + VRFY((prop_value == FALSE), "correctly handled rank 0 Bcast"); + else + VRFY((prop_value == TRUE), "correctly handled rank 0 Bcast"); +#endif /* H5_HAVE_INSTRUMENTED_LIBRARY */ + + /* Verify all data read are the fill value 0 */ + trdata = rdata; + err_num = 0; + for (i = 0; i < (int)dset_dims[0]; i++) + for (j = 0; j < (int)dset_dims[1]; j++) + for (k = 0; k < (int)dset_dims[2]; k++) + for (l = 0; l < (int)dset_dims[3]; l++, trdata++) + if (*trdata != 0) + if (err_num++ < MAX_ERR_REPORT || VERBOSE_MED) + HDprintf( + "Rank %d: Dataset Verify failed at [%d][%d][%d][%d]: expect 0, got %d\n", + mpi_rank, i, j, k, l, *trdata); + if (err_num > MAX_ERR_REPORT && !VERBOSE_MED) + HDprintf("Rank %d: [more errors ...]\n", mpi_rank); + if (err_num) { + HDprintf("Rank %d: %d errors found in check_value\n", mpi_rank, err_num); + nerrors++; + } + } + + /* Barrier to ensure all processes have completed the above test. */ + MPI_Barrier(MPI_COMM_WORLD); + + /* + * Each process writes 1 row of data. Thus last row is not written. + */ + /* Create hyperslabs in memory and file dataspaces */ + req_start[0] = (hsize_t)mpi_rank; + ret = H5Sselect_hyperslab(filespace, H5S_SELECT_SET, req_start, NULL, req_count, NULL); + VRFY((ret >= 0), "H5Sselect_hyperslab succeeded on memory dataspace"); + ret = H5Sselect_hyperslab(memspace, H5S_SELECT_SET, req_start, NULL, req_count, NULL); + VRFY((ret >= 0), "H5Sselect_hyperslab succeeded on memory dataspace"); + + ret = H5Pset_dxpl_mpio(dxpl, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(dxpl, H5FD_MPIO_INDIVIDUAL_IO); + VRFY((ret >= 0), "set independent IO collectively succeeded"); + } + + /* Fill write buffer with some values */ + twdata = wdata; + for (i = 0, acc = 0; i < (int)dset_dims[0]; i++) + for (j = 0; j < (int)dset_dims[1]; j++) + for (k = 0; k < (int)dset_dims[2]; k++) + for (l = 0; l < (int)dset_dims[3]; l++) + *twdata++ = acc++; + + /* Collectively write a hyperslab of data to the dataset */ + ret = H5Dwrite(dataset, H5T_NATIVE_INT, memspace, filespace, dxpl, wdata); + VRFY((ret >= 0), "H5Dwrite succeeded"); + + /* Barrier here, to allow processes to sync */ + MPI_Barrier(MPI_COMM_WORLD); + + /* + * Read dataset after partial write. + */ + +#ifdef H5_HAVE_INSTRUMENTED_LIBRARY + prop_value = H5D_XFER_COLL_RANK0_BCAST_DEF; + ret = H5Pset(dxpl, H5D_XFER_COLL_RANK0_BCAST_NAME, &prop_value); + VRFY((ret >= 0), " H5Pset succeeded"); +#endif /* H5_HAVE_INSTRUMENTED_LIBRARY */ + + for (ii = 0; ii < 2; ii++) { + + if (ii == 0) + ret = H5Pset_dxpl_mpio(dxpl, H5FD_MPIO_INDEPENDENT); + else + ret = H5Pset_dxpl_mpio(dxpl, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + + /* set entire read buffer with the constant 2 */ + HDmemset(rdata, 2, (size_t)(dset_size * sizeof(int))); + + /* Read the entire dataset back */ + ret = H5Dread(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, dxpl, rdata); + VRFY((ret >= 0), "H5Dread succeeded"); + +#ifdef H5_HAVE_INSTRUMENTED_LIBRARY + prop_value = FALSE; + ret = H5Pget(dxpl, H5D_XFER_COLL_RANK0_BCAST_NAME, &prop_value); + VRFY((ret >= 0), "testing property list get succeeded"); + if (ii == 0) + VRFY((prop_value == FALSE), "correctly handled rank 0 Bcast"); + else + VRFY((prop_value == TRUE), "correctly handled rank 0 Bcast"); +#endif /* H5_HAVE_INSTRUMENTED_LIBRARY */ + + /* Verify correct data read */ + twdata = wdata; + trdata = rdata; + err_num = 0; + for (i = 0; i < (int)dset_dims[0]; i++) + for (j = 0; j < (int)dset_dims[1]; j++) + for (k = 0; k < (int)dset_dims[2]; k++) + for (l = 0; l < (int)dset_dims[3]; l++, twdata++, trdata++) + if (i < mpi_size) { + if (*twdata != *trdata) + if (err_num++ < MAX_ERR_REPORT || VERBOSE_MED) + HDprintf("Dataset Verify failed at [%d][%d][%d][%d]: expect %d, got %d\n", + i, j, k, l, *twdata, *trdata); + } /* end if */ + else { + if (*trdata != 0) + if (err_num++ < MAX_ERR_REPORT || VERBOSE_MED) + HDprintf("Dataset Verify failed at [%d][%d][%d][%d]: expect 0, got %d\n", + i, j, k, l, *trdata); + } /* end else */ + if (err_num > MAX_ERR_REPORT && !VERBOSE_MED) + HDprintf("[more errors ...]\n"); + if (err_num) { + HDprintf("%d errors found in check_value\n", err_num); + nerrors++; + } + } + + /* Close all file objects */ + ret = H5Dclose(dataset); + VRFY((ret >= 0), "H5Dclose succeeded"); + ret = H5Sclose(filespace); + VRFY((ret >= 0), "H5Sclose succeeded"); + ret = H5Fclose(iof); + VRFY((ret >= 0), "H5Fclose succeeded"); + + /* Close memory dataspace */ + ret = H5Sclose(memspace); + VRFY((ret >= 0), "H5Sclose succeeded"); + + /* Close dxpl */ + ret = H5Pclose(dxpl); + VRFY((ret >= 0), "H5Pclose succeeded"); + + /* Close fapl */ + ret = H5Pclose(fapl); + VRFY((ret >= 0), "H5Pclose succeeded"); + + /* free the buffers */ + HDfree(rdata); + HDfree(wdata); +} + +/* combined cngrpw and ingrpr tests because ingrpr reads file created by cngrpw. */ +void +collective_group_write_independent_group_read(void) +{ + collective_group_write(); + independent_group_read(); +} + +/* Write multiple groups with a chunked dataset in each group collectively. + * These groups and datasets are for testing independent read later. + */ +void +collective_group_write(void) +{ + int mpi_rank, mpi_size, size; + int i, j, m; + char gname[64], dname[32]; + hid_t fid, gid, did, plist, dcpl, memspace, filespace; + DATATYPE *outme = NULL; + hsize_t chunk_origin[DIM]; + hsize_t chunk_dims[DIM], file_dims[DIM], count[DIM]; + hsize_t chunk_size[2]; /* Chunk dimensions - computed shortly */ + herr_t ret1, ret2; +#if 0 + const H5Ptest_param_t *pt; +#endif + char *filename; + int ngroups; + +#if 0 + pt = GetTestParameters(); +#endif + /* filename = pt->name; */ filename = PARATESTFILE; + /* ngroups = pt->count; */ ngroups = NGROUPS; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + fflush(stdout); + } + + return; + } + + size = get_size(); + + chunk_size[0] = (hsize_t)(size / 2); + chunk_size[1] = (hsize_t)(size / 2); + + outme = HDmalloc((size_t)size * (size_t)size * sizeof(DATATYPE)); + VRFY((outme != NULL), "HDmalloc succeeded for outme"); + + plist = create_faccess_plist(MPI_COMM_WORLD, MPI_INFO_NULL, facc_type); + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, plist); + VRFY((fid >= 0), "H5Fcreate"); + H5Pclose(plist); + + /* decide the hyperslab according to process number. */ + get_slab(chunk_origin, chunk_dims, count, file_dims, size); + + /* select hyperslab in memory and file spaces. These two operations are + * identical since the datasets are the same. */ + memspace = H5Screate_simple(DIM, file_dims, NULL); + ret1 = H5Sselect_hyperslab(memspace, H5S_SELECT_SET, chunk_origin, chunk_dims, count, chunk_dims); + filespace = H5Screate_simple(DIM, file_dims, NULL); + ret2 = H5Sselect_hyperslab(filespace, H5S_SELECT_SET, chunk_origin, chunk_dims, count, chunk_dims); + VRFY((memspace >= 0), "memspace"); + VRFY((filespace >= 0), "filespace"); + VRFY((ret1 == 0), "mgroup memspace selection"); + VRFY((ret2 == 0), "mgroup filespace selection"); + + dcpl = H5Pcreate(H5P_DATASET_CREATE); + ret1 = H5Pset_chunk(dcpl, 2, chunk_size); + VRFY((dcpl >= 0), "dataset creation property"); + VRFY((ret1 == 0), "set chunk for dataset creation property"); + + /* creates ngroups groups under the root group, writes chunked + * datasets in parallel. */ + for (m = 0; m < ngroups; m++) { + HDsnprintf(gname, sizeof(gname), "group%d", m); + gid = H5Gcreate2(fid, gname, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((gid > 0), gname); + + HDsnprintf(dname, sizeof(dname), "dataset%d", m); + did = H5Dcreate2(gid, dname, H5T_NATIVE_INT, filespace, H5P_DEFAULT, dcpl, H5P_DEFAULT); + VRFY((did > 0), dname); + + for (i = 0; i < size; i++) + for (j = 0; j < size; j++) + outme[(i * size) + j] = (i + j) * 1000 + mpi_rank; + + ret1 = H5Dwrite(did, H5T_NATIVE_INT, memspace, filespace, H5P_DEFAULT, outme); + VRFY((ret1 == 0), "H5Dwrite"); + + ret1 = H5Dclose(did); + VRFY((ret1 == 0), "H5Dclose"); + + ret1 = H5Gclose(gid); + VRFY((ret1 == 0), "H5Gclose"); + +#ifdef BARRIER_CHECKS + if (!((m + 1) % 10)) { + HDprintf("created %d groups\n", m + 1); + MPI_Barrier(MPI_COMM_WORLD); + } +#endif /* BARRIER_CHECKS */ + } + + H5Pclose(dcpl); + H5Sclose(filespace); + H5Sclose(memspace); + + ret1 = H5Fclose(fid); + VRFY((ret1 == 0), "H5Fclose"); + + HDfree(outme); +} + +/* Let two sets of processes open and read different groups and chunked + * datasets independently. + */ +void +independent_group_read(void) +{ + int mpi_rank, m; + hid_t plist, fid; +#if 0 + const H5Ptest_param_t *pt; +#endif + char *filename; + int ngroups; + herr_t ret; + +#if 0 + pt = GetTestParameters(); +#endif + /* filename = pt->name; */ filename = PARATESTFILE; + /* ngroups = pt->count; */ ngroups = NGROUPS; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + plist = create_faccess_plist(MPI_COMM_WORLD, MPI_INFO_NULL, facc_type); + H5Pset_all_coll_metadata_ops(plist, FALSE); + + fid = H5Fopen(filename, H5F_ACC_RDONLY, plist); + VRFY((fid > 0), "H5Fopen"); + H5Pclose(plist); + + /* open groups and read datasets. Odd number processes read even number + * groups from the end; even number processes read odd number groups + * from the beginning. */ + if (mpi_rank % 2 == 0) { + for (m = ngroups - 1; m == 0; m -= 2) + group_dataset_read(fid, mpi_rank, m); + } + else { + for (m = 0; m < ngroups; m += 2) + group_dataset_read(fid, mpi_rank, m); + } + + ret = H5Fclose(fid); + VRFY((ret == 0), "H5Fclose"); +} + +/* Open and read datasets and compare data + */ +static void +group_dataset_read(hid_t fid, int mpi_rank, int m) +{ + int ret, i, j, size; + char gname[64], dname[32]; + hid_t gid, did; + DATATYPE *outdata = NULL; + DATATYPE *indata = NULL; + + size = get_size(); + + indata = (DATATYPE *)HDmalloc((size_t)size * (size_t)size * sizeof(DATATYPE)); + VRFY((indata != NULL), "HDmalloc succeeded for indata"); + + outdata = (DATATYPE *)HDmalloc((size_t)size * (size_t)size * sizeof(DATATYPE)); + VRFY((outdata != NULL), "HDmalloc succeeded for outdata"); + + /* open every group under root group. */ + HDsnprintf(gname, sizeof(gname), "group%d", m); + gid = H5Gopen2(fid, gname, H5P_DEFAULT); + VRFY((gid > 0), gname); + + /* check the data. */ + HDsnprintf(dname, sizeof(dname), "dataset%d", m); + did = H5Dopen2(gid, dname, H5P_DEFAULT); + VRFY((did > 0), dname); + + H5Dread(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, indata); + + /* this is the original value */ + for (i = 0; i < size; i++) + for (j = 0; j < size; j++) + outdata[(i * size) + j] = (i + j) * 1000 + mpi_rank; + + /* compare the original value(outdata) to the value in file(indata).*/ + ret = check_value(indata, outdata, size); + VRFY((ret == 0), "check the data"); + + ret = H5Dclose(did); + VRFY((ret == 0), "H5Dclose"); + ret = H5Gclose(gid); + VRFY((ret == 0), "H5Gclose"); + + HDfree(indata); + HDfree(outdata); +} + +/* + * Example of using PHDF5 to create multiple groups. Under the root group, + * it creates ngroups groups. Under the first group just created, it creates + * recursive subgroups of depth GROUP_DEPTH. In each created group, it + * generates NDATASETS datasets. Each process write a hyperslab of an array + * into the file. The structure is like + * + * root group + * | + * ---------------------------- ... ... ------------------------ + * | | | ... ... | | + * group0*+' group1*+' group2*+' ... ... group ngroups*+' + * | + * 1st_child_group*' + * | + * 2nd_child_group*' + * | + * : + * : + * | + * GROUP_DEPTHth_child_group*' + * + * * means the group has dataset(s). + * + means the group has attribute(s). + * ' means the datasets in the groups have attribute(s). + * + */ +void +multiple_group_write(void) +{ + int mpi_rank, mpi_size, size; + int m; + char gname[64]; + hid_t fid, gid, plist, memspace, filespace; + hsize_t chunk_origin[DIM]; + hsize_t chunk_dims[DIM], file_dims[DIM], count[DIM]; + herr_t ret; +#if 0 + const H5Ptest_param_t *pt; +#endif + char *filename; + int ngroups; + +#if 0 + pt = GetTestParameters(); +#endif + /* filename = pt->name; */ filename = PARATESTFILE; + /* ngroups = pt->count; */ ngroups = NGROUPS; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, group, dataset, or attribute aren't supported with " + "this connector\n"); + fflush(stdout); + } + + return; + } + + size = get_size(); + + plist = create_faccess_plist(MPI_COMM_WORLD, MPI_INFO_NULL, facc_type); + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, plist); + H5Pclose(plist); + + /* decide the hyperslab according to process number. */ + get_slab(chunk_origin, chunk_dims, count, file_dims, size); + + /* select hyperslab in memory and file spaces. These two operations are + * identical since the datasets are the same. */ + memspace = H5Screate_simple(DIM, file_dims, NULL); + VRFY((memspace >= 0), "memspace"); + ret = H5Sselect_hyperslab(memspace, H5S_SELECT_SET, chunk_origin, chunk_dims, count, chunk_dims); + VRFY((ret >= 0), "mgroup memspace selection"); + + filespace = H5Screate_simple(DIM, file_dims, NULL); + VRFY((filespace >= 0), "filespace"); + ret = H5Sselect_hyperslab(filespace, H5S_SELECT_SET, chunk_origin, chunk_dims, count, chunk_dims); + VRFY((ret >= 0), "mgroup filespace selection"); + + /* creates ngroups groups under the root group, writes datasets in + * parallel. */ + for (m = 0; m < ngroups; m++) { + HDsnprintf(gname, sizeof(gname), "group%d", m); + gid = H5Gcreate2(fid, gname, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((gid > 0), gname); + + /* create attribute for these groups. */ + write_attribute(gid, is_group, m); + + if (m != 0) + write_dataset(memspace, filespace, gid); + + H5Gclose(gid); + +#ifdef BARRIER_CHECKS + if (!((m + 1) % 10)) { + HDprintf("created %d groups\n", m + 1); + MPI_Barrier(MPI_COMM_WORLD); + } +#endif /* BARRIER_CHECKS */ + } + + /* recursively creates subgroups under the first group. */ + gid = H5Gopen2(fid, "group0", H5P_DEFAULT); + create_group_recursive(memspace, filespace, gid, 0); + ret = H5Gclose(gid); + VRFY((ret >= 0), "H5Gclose"); + + ret = H5Sclose(filespace); + VRFY((ret >= 0), "H5Sclose"); + ret = H5Sclose(memspace); + VRFY((ret >= 0), "H5Sclose"); + ret = H5Fclose(fid); + VRFY((ret >= 0), "H5Fclose"); +} + +/* + * In a group, creates NDATASETS datasets. Each process writes a hyperslab + * of a data array to the file. + */ +static void +write_dataset(hid_t memspace, hid_t filespace, hid_t gid) +{ + int i, j, n, size; + int mpi_rank, mpi_size; + char dname[32]; + DATATYPE *outme = NULL; + hid_t did; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + + size = get_size(); + + outme = HDmalloc((size_t)size * (size_t)size * sizeof(double)); + VRFY((outme != NULL), "HDmalloc succeeded for outme"); + + for (n = 0; n < NDATASET; n++) { + HDsnprintf(dname, sizeof(dname), "dataset%d", n); + did = H5Dcreate2(gid, dname, H5T_NATIVE_INT, filespace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((did > 0), dname); + + for (i = 0; i < size; i++) + for (j = 0; j < size; j++) + outme[(i * size) + j] = n * 1000 + mpi_rank; + + H5Dwrite(did, H5T_NATIVE_INT, memspace, filespace, H5P_DEFAULT, outme); + + /* create attribute for these datasets.*/ + write_attribute(did, is_dset, n); + + H5Dclose(did); + } + HDfree(outme); +} + +/* + * Creates subgroups of depth GROUP_DEPTH recursively. Also writes datasets + * in parallel in each group. + */ +static void +create_group_recursive(hid_t memspace, hid_t filespace, hid_t gid, int counter) +{ + hid_t child_gid; + int mpi_rank; + char gname[64]; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + +#ifdef BARRIER_CHECKS + if (!((counter + 1) % 10)) { + HDprintf("created %dth child groups\n", counter + 1); + MPI_Barrier(MPI_COMM_WORLD); + } +#endif /* BARRIER_CHECKS */ + + HDsnprintf(gname, sizeof(gname), "%dth_child_group", counter + 1); + child_gid = H5Gcreate2(gid, gname, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((child_gid > 0), gname); + + /* write datasets in parallel. */ + write_dataset(memspace, filespace, gid); + + if (counter < GROUP_DEPTH) + create_group_recursive(memspace, filespace, child_gid, counter + 1); + + H5Gclose(child_gid); +} + +/* + * This function is to verify the data from multiple group testing. It opens + * every dataset in every group and check their correctness. + */ +void +multiple_group_read(void) +{ + int mpi_rank, mpi_size, error_num, size; + int m; + char gname[64]; + hid_t plist, fid, gid, memspace, filespace; + hsize_t chunk_origin[DIM]; + hsize_t chunk_dims[DIM], file_dims[DIM], count[DIM]; +#if 0 + const H5Ptest_param_t *pt; +#endif + char *filename; + int ngroups; + +#if 0 + pt = GetTestParameters(); +#endif + /* filename = pt->name; */ filename = PARATESTFILE; + /* ngroups = pt->count; */ ngroups = NGROUPS; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, group, dataset, or attribute aren't supported with " + "this connector\n"); + fflush(stdout); + } + + return; + } + + size = get_size(); + + plist = create_faccess_plist(MPI_COMM_WORLD, MPI_INFO_NULL, facc_type); + fid = H5Fopen(filename, H5F_ACC_RDONLY, plist); + H5Pclose(plist); + + /* decide hyperslab for each process */ + get_slab(chunk_origin, chunk_dims, count, file_dims, size); + + /* select hyperslab for memory and file space */ + memspace = H5Screate_simple(DIM, file_dims, NULL); + H5Sselect_hyperslab(memspace, H5S_SELECT_SET, chunk_origin, chunk_dims, count, chunk_dims); + filespace = H5Screate_simple(DIM, file_dims, NULL); + H5Sselect_hyperslab(filespace, H5S_SELECT_SET, chunk_origin, chunk_dims, count, chunk_dims); + + /* open every group under root group. */ + for (m = 0; m < ngroups; m++) { + HDsnprintf(gname, sizeof(gname), "group%d", m); + gid = H5Gopen2(fid, gname, H5P_DEFAULT); + VRFY((gid > 0), gname); + + /* check the data. */ + if (m != 0) + if ((error_num = read_dataset(memspace, filespace, gid)) > 0) + nerrors += error_num; + + /* check attribute.*/ + error_num = 0; + if ((error_num = read_attribute(gid, is_group, m)) > 0) + nerrors += error_num; + + H5Gclose(gid); + +#ifdef BARRIER_CHECKS + if (!((m + 1) % 10)) + MPI_Barrier(MPI_COMM_WORLD); +#endif /* BARRIER_CHECKS */ + } + + /* open all the groups in vertical direction. */ + gid = H5Gopen2(fid, "group0", H5P_DEFAULT); + VRFY((gid > 0), "group0"); + recursive_read_group(memspace, filespace, gid, 0); + H5Gclose(gid); + + H5Sclose(filespace); + H5Sclose(memspace); + H5Fclose(fid); +} + +/* + * This function opens all the datasets in a certain, checks the data using + * dataset_vrfy function. + */ +static int +read_dataset(hid_t memspace, hid_t filespace, hid_t gid) +{ + int i, j, n, mpi_rank, mpi_size, size, attr_errors = 0, vrfy_errors = 0; + char dname[32]; + DATATYPE *outdata = NULL, *indata = NULL; + hid_t did; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + + size = get_size(); + + indata = (DATATYPE *)HDmalloc((size_t)size * (size_t)size * sizeof(DATATYPE)); + VRFY((indata != NULL), "HDmalloc succeeded for indata"); + + outdata = (DATATYPE *)HDmalloc((size_t)size * (size_t)size * sizeof(DATATYPE)); + VRFY((outdata != NULL), "HDmalloc succeeded for outdata"); + + for (n = 0; n < NDATASET; n++) { + HDsnprintf(dname, sizeof(dname), "dataset%d", n); + did = H5Dopen2(gid, dname, H5P_DEFAULT); + VRFY((did > 0), dname); + + H5Dread(did, H5T_NATIVE_INT, memspace, filespace, H5P_DEFAULT, indata); + + /* this is the original value */ + for (i = 0; i < size; i++) + for (j = 0; j < size; j++) { + *outdata = n * 1000 + mpi_rank; + outdata++; + } + outdata -= size * size; + + /* compare the original value(outdata) to the value in file(indata).*/ + vrfy_errors = check_value(indata, outdata, size); + + /* check attribute.*/ + if ((attr_errors = read_attribute(did, is_dset, n)) > 0) + vrfy_errors += attr_errors; + + H5Dclose(did); + } + + HDfree(indata); + HDfree(outdata); + + return vrfy_errors; +} + +/* + * This recursive function opens all the groups in vertical direction and + * checks the data. + */ +static void +recursive_read_group(hid_t memspace, hid_t filespace, hid_t gid, int counter) +{ + hid_t child_gid; + int mpi_rank, err_num = 0; + char gname[64]; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); +#ifdef BARRIER_CHECKS + if ((counter + 1) % 10) + MPI_Barrier(MPI_COMM_WORLD); +#endif /* BARRIER_CHECKS */ + + if ((err_num = read_dataset(memspace, filespace, gid))) + nerrors += err_num; + + if (counter < GROUP_DEPTH) { + HDsnprintf(gname, sizeof(gname), "%dth_child_group", counter + 1); + child_gid = H5Gopen2(gid, gname, H5P_DEFAULT); + VRFY((child_gid > 0), gname); + recursive_read_group(memspace, filespace, child_gid, counter + 1); + H5Gclose(child_gid); + } +} + +/* Create and write attribute for a group or a dataset. For groups, attribute + * is a scalar datum; for dataset, it is a one-dimensional array. + */ +static void +write_attribute(hid_t obj_id, int this_type, int num) +{ + hid_t sid, aid; + hsize_t dspace_dims[1] = {8}; + int i, mpi_rank, attr_data[8], dspace_rank = 1; + char attr_name[32]; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + if (this_type == is_group) { + HDsnprintf(attr_name, sizeof(attr_name), "Group Attribute %d", num); + sid = H5Screate(H5S_SCALAR); + aid = H5Acreate2(obj_id, attr_name, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT); + H5Awrite(aid, H5T_NATIVE_INT, &num); + H5Aclose(aid); + H5Sclose(sid); + } /* end if */ + else if (this_type == is_dset) { + HDsnprintf(attr_name, sizeof(attr_name), "Dataset Attribute %d", num); + for (i = 0; i < 8; i++) + attr_data[i] = i; + sid = H5Screate_simple(dspace_rank, dspace_dims, NULL); + aid = H5Acreate2(obj_id, attr_name, H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT); + H5Awrite(aid, H5T_NATIVE_INT, attr_data); + H5Aclose(aid); + H5Sclose(sid); + } /* end else-if */ +} + +/* Read and verify attribute for group or dataset. */ +static int +read_attribute(hid_t obj_id, int this_type, int num) +{ + hid_t aid; + hsize_t group_block[2] = {1, 1}, dset_block[2] = {1, 8}; + int i, mpi_rank, in_num, in_data[8], out_data[8], vrfy_errors = 0; + char attr_name[32]; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + if (this_type == is_group) { + HDsnprintf(attr_name, sizeof(attr_name), "Group Attribute %d", num); + aid = H5Aopen(obj_id, attr_name, H5P_DEFAULT); + H5Aread(aid, H5T_NATIVE_INT, &in_num); + vrfy_errors = dataset_vrfy(NULL, NULL, NULL, group_block, &in_num, &num); + H5Aclose(aid); + } + else if (this_type == is_dset) { + HDsnprintf(attr_name, sizeof(attr_name), "Dataset Attribute %d", num); + for (i = 0; i < 8; i++) + out_data[i] = i; + aid = H5Aopen(obj_id, attr_name, H5P_DEFAULT); + H5Aread(aid, H5T_NATIVE_INT, in_data); + vrfy_errors = dataset_vrfy(NULL, NULL, NULL, dset_block, in_data, out_data); + H5Aclose(aid); + } + + return vrfy_errors; +} + +/* This functions compares the original data with the read-in data for its + * hyperslab part only by process ID. + */ +static int +check_value(DATATYPE *indata, DATATYPE *outdata, int size) +{ + int mpi_rank, mpi_size, err_num = 0; + hsize_t i, j; + hsize_t chunk_origin[DIM]; + hsize_t chunk_dims[DIM], count[DIM]; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + + get_slab(chunk_origin, chunk_dims, count, NULL, size); + + indata += chunk_origin[0] * (hsize_t)size; + outdata += chunk_origin[0] * (hsize_t)size; + for (i = chunk_origin[0]; i < (chunk_origin[0] + chunk_dims[0]); i++) + for (j = chunk_origin[1]; j < (chunk_origin[1] + chunk_dims[1]); j++) { + if (*indata != *outdata) + if (err_num++ < MAX_ERR_REPORT || VERBOSE_MED) + HDprintf("Dataset Verify failed at [%lu][%lu](row %lu, col%lu): expect %d, got %d\n", + (unsigned long)i, (unsigned long)j, (unsigned long)i, (unsigned long)j, *outdata, + *indata); + } + if (err_num > MAX_ERR_REPORT && !VERBOSE_MED) + HDprintf("[more errors ...]\n"); + if (err_num) + HDprintf("%d errors found in check_value\n", err_num); + return err_num; +} + +/* Decide the portion of data chunk in dataset by process ID. + */ + +static void +get_slab(hsize_t chunk_origin[], hsize_t chunk_dims[], hsize_t count[], hsize_t file_dims[], int size) +{ + int mpi_rank, mpi_size; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + + if (chunk_origin != NULL) { + chunk_origin[0] = (hsize_t)mpi_rank * (hsize_t)(size / mpi_size); + chunk_origin[1] = 0; + } + if (chunk_dims != NULL) { + chunk_dims[0] = (hsize_t)(size / mpi_size); + chunk_dims[1] = (hsize_t)size; + } + if (file_dims != NULL) + file_dims[0] = file_dims[1] = (hsize_t)size; + if (count != NULL) + count[0] = count[1] = 1; +} + +/* + * This function is based on bug demonstration code provided by Thomas + * Guignon(thomas.guignon@ifp.fr), and is intended to verify the + * correctness of my fix for that bug. + * + * In essence, the bug appeared when at least one process attempted to + * write a point selection -- for which collective I/O is not supported, + * and at least one other attempted to write some other type of selection + * for which collective I/O is supported. + * + * Since the processes did not compare notes before performing the I/O, + * some would attempt collective I/O while others performed independent + * I/O. A hang resulted. + * + * This function reproduces this situation. At present the test hangs + * on failure. + * JRM - 9/13/04 + */ + +#define N 4 + +void +io_mode_confusion(void) +{ + /* + * HDF5 APIs definitions + */ + + const int rank = 1; + const char *dataset_name = "IntArray"; + + hid_t file_id, dset_id; /* file and dataset identifiers */ + hid_t filespace, memspace; /* file and memory dataspace */ + /* identifiers */ + hsize_t dimsf[1]; /* dataset dimensions */ + int data[N] = {1}; /* pointer to data buffer to write */ + hsize_t coord[N] = {0L, 1L, 2L, 3L}; + hid_t plist_id; /* property list identifier */ + herr_t status; + + /* + * MPI variables + */ + + int mpi_size, mpi_rank; + + /* + * test bed related variables + */ + + const char *fcn_name = "io_mode_confusion"; + const hbool_t verbose = FALSE; +#if 0 + const H5Ptest_param_t *pt; +#endif + char *filename; + +#if 0 + pt = GetTestParameters(); +#endif + /* filename = pt->name; */ filename = PARATESTFILE; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, dataset, or dataset more aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + /* + * Set up file access property list with parallel I/O access + */ + + if (verbose) + HDfprintf(stdout, "%0d:%s: Setting up property list.\n", mpi_rank, fcn_name); + + plist_id = H5Pcreate(H5P_FILE_ACCESS); + VRFY((plist_id != -1), "H5Pcreate() failed"); + + status = H5Pset_fapl_mpio(plist_id, MPI_COMM_WORLD, MPI_INFO_NULL); + VRFY((status >= 0), "H5Pset_fapl_mpio() failed"); + + /* + * Create a new file collectively and release property list identifier. + */ + + if (verbose) + HDfprintf(stdout, "%0d:%s: Creating new file.\n", mpi_rank, fcn_name); + + file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, plist_id); + VRFY((file_id >= 0), "H5Fcreate() failed"); + + status = H5Pclose(plist_id); + VRFY((status >= 0), "H5Pclose() failed"); + + /* + * Create the dataspace for the dataset. + */ + + if (verbose) + HDfprintf(stdout, "%0d:%s: Creating the dataspace for the dataset.\n", mpi_rank, fcn_name); + + dimsf[0] = N; + filespace = H5Screate_simple(rank, dimsf, NULL); + VRFY((filespace >= 0), "H5Screate_simple() failed."); + + /* + * Create the dataset with default properties and close filespace. + */ + + if (verbose) + HDfprintf(stdout, "%0d:%s: Creating the dataset, and closing filespace.\n", mpi_rank, fcn_name); + + dset_id = + H5Dcreate2(file_id, dataset_name, H5T_NATIVE_INT, filespace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((dset_id >= 0), "H5Dcreate2() failed"); + + status = H5Sclose(filespace); + VRFY((status >= 0), "H5Sclose() failed"); + + if (verbose) + HDfprintf(stdout, "%0d:%s: Calling H5Screate_simple().\n", mpi_rank, fcn_name); + + memspace = H5Screate_simple(rank, dimsf, NULL); + VRFY((memspace >= 0), "H5Screate_simple() failed."); + + if (mpi_rank == 0) { + if (verbose) + HDfprintf(stdout, "%0d:%s: Calling H5Sselect_all(memspace).\n", mpi_rank, fcn_name); + + status = H5Sselect_all(memspace); + VRFY((status >= 0), "H5Sselect_all() failed"); + } + else { + if (verbose) + HDfprintf(stdout, "%0d:%s: Calling H5Sselect_none(memspace).\n", mpi_rank, fcn_name); + + status = H5Sselect_none(memspace); + VRFY((status >= 0), "H5Sselect_none() failed"); + } + + if (verbose) + HDfprintf(stdout, "%0d:%s: Calling MPI_Barrier().\n", mpi_rank, fcn_name); + + MPI_Barrier(MPI_COMM_WORLD); + + if (verbose) + HDfprintf(stdout, "%0d:%s: Calling H5Dget_space().\n", mpi_rank, fcn_name); + + filespace = H5Dget_space(dset_id); + VRFY((filespace >= 0), "H5Dget_space() failed"); + + /* select all */ + if (mpi_rank == 0) { + if (verbose) + HDfprintf(stdout, "%0d:%s: Calling H5Sselect_elements() -- set up hang?\n", mpi_rank, fcn_name); + + status = H5Sselect_elements(filespace, H5S_SELECT_SET, N, (const hsize_t *)&coord); + VRFY((status >= 0), "H5Sselect_elements() failed"); + } + else { /* select nothing */ + if (verbose) + HDfprintf(stdout, "%0d:%s: Calling H5Sselect_none().\n", mpi_rank, fcn_name); + + status = H5Sselect_none(filespace); + VRFY((status >= 0), "H5Sselect_none() failed"); + } + + if (verbose) + HDfprintf(stdout, "%0d:%s: Calling MPI_Barrier().\n", mpi_rank, fcn_name); + + MPI_Barrier(MPI_COMM_WORLD); + + if (verbose) + HDfprintf(stdout, "%0d:%s: Calling H5Pcreate().\n", mpi_rank, fcn_name); + + plist_id = H5Pcreate(H5P_DATASET_XFER); + VRFY((plist_id != -1), "H5Pcreate() failed"); + + if (verbose) + HDfprintf(stdout, "%0d:%s: Calling H5Pset_dxpl_mpio().\n", mpi_rank, fcn_name); + + status = H5Pset_dxpl_mpio(plist_id, H5FD_MPIO_COLLECTIVE); + VRFY((status >= 0), "H5Pset_dxpl_mpio() failed"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + status = H5Pset_dxpl_mpio_collective_opt(plist_id, H5FD_MPIO_INDIVIDUAL_IO); + VRFY((status >= 0), "set independent IO collectively succeeded"); + } + + if (verbose) + HDfprintf(stdout, "%0d:%s: Calling H5Dwrite() -- hang here?.\n", mpi_rank, fcn_name); + + status = H5Dwrite(dset_id, H5T_NATIVE_INT, memspace, filespace, plist_id, data); + + if (verbose) + HDfprintf(stdout, "%0d:%s: Returned from H5Dwrite(), status=%d.\n", mpi_rank, fcn_name, status); + VRFY((status >= 0), "H5Dwrite() failed"); + + /* + * Close/release resources. + */ + + if (verbose) + HDfprintf(stdout, "%0d:%s: Cleaning up from test.\n", mpi_rank, fcn_name); + + status = H5Dclose(dset_id); + VRFY((status >= 0), "H5Dclose() failed"); + + status = H5Sclose(filespace); + VRFY((status >= 0), "H5Dclose() failed"); + + status = H5Sclose(memspace); + VRFY((status >= 0), "H5Sclose() failed"); + + status = H5Pclose(plist_id); + VRFY((status >= 0), "H5Pclose() failed"); + + status = H5Fclose(file_id); + VRFY((status >= 0), "H5Fclose() failed"); + + if (verbose) + HDfprintf(stdout, "%0d:%s: Done.\n", mpi_rank, fcn_name); + + return; + +} /* io_mode_confusion() */ + +#undef N + +/* + * At present, the object header code maintains an image of its on disk + * representation, which is updates as necessary instead of generating on + * request. + * + * Prior to the fix that this test in designed to verify, the image of the + * on disk representation was only updated on flush -- not when the object + * header was marked clean. + * + * This worked perfectly well as long as all writes of a given object + * header were written from a single process. However, with the implementation + * of round robin metadata data writes in parallel HDF5, this is no longer + * the case -- it is possible for a given object header to be flushed from + * several different processes, with the object header simply being marked + * clean in all other processes on each flush. This resulted in NULL or + * out of data object header information being written to disk. + * + * To repair this, I modified the object header code to update its + * on disk image both on flush on when marked clean. + * + * This test is directed at verifying that the fix performs as expected. + * + * The test functions by creating a HDF5 file with several small datasets, + * and then flushing the file. This should result of at least one of + * the associated object headers being flushed by a process other than + * process 0. + * + * Then for each data set, add an attribute and flush the file again. + * + * Close the file and re-open it. + * + * Open the each of the data sets in turn. If all opens are successful, + * the test passes. Otherwise the test fails. + * + * Note that this test will probably become irrelevant shortly, when we + * land the journaling modifications on the trunk -- at which point all + * cache clients will have to construct on disk images on demand. + * + * JRM -- 10/13/10 + */ + +#define NUM_DATA_SETS 4 +#define LOCAL_DATA_SIZE 4 +#define LARGE_ATTR_SIZE 256 +/* Since all even and odd processes are split into writer and reader comm + * respectively, process 0 and 1 in COMM_WORLD become the root process of + * the writer and reader comm respectively. + */ +#define Writer_Root 0 +#define Reader_Root 1 +#define Reader_wait(mpi_err, xsteps) mpi_err = MPI_Bcast(&xsteps, 1, MPI_INT, Writer_Root, MPI_COMM_WORLD) +#define Reader_result(mpi_err, xsteps_done) \ + mpi_err = MPI_Bcast(&xsteps_done, 1, MPI_INT, Reader_Root, MPI_COMM_WORLD) +#define Reader_check(mpi_err, xsteps, xsteps_done) \ + { \ + Reader_wait(mpi_err, xsteps); \ + Reader_result(mpi_err, xsteps_done); \ + } + +/* object names used by both rr_obj_hdr_flush_confusion and + * rr_obj_hdr_flush_confusion_reader. + */ +const char *dataset_name[NUM_DATA_SETS] = {"dataset_0", "dataset_1", "dataset_2", "dataset_3"}; +const char *att_name[NUM_DATA_SETS] = {"attribute_0", "attribute_1", "attribute_2", "attribute_3"}; +const char *lg_att_name[NUM_DATA_SETS] = {"large_attribute_0", "large_attribute_1", "large_attribute_2", + "large_attribute_3"}; + +void +rr_obj_hdr_flush_confusion(void) +{ + /* MPI variables */ + /* private communicator size and rank */ + int mpi_size; + int mpi_rank; + int mrc; /* mpi error code */ + int is_reader; /* 1 for reader process; 0 for writer process. */ + MPI_Comm comm; + + /* test bed related variables */ + const char *fcn_name = "rr_obj_hdr_flush_confusion"; + const hbool_t verbose = FALSE; + + /* Create two new private communicators from MPI_COMM_WORLD. + * Even and odd ranked processes go to comm_writers and comm_readers + * respectively. + */ + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_FLUSH_REFRESH) || !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_MORE)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, dataset, attribute, dataset more, attribute more, or " + "file flush aren't supported with this connector\n"); + fflush(stdout); + } + + return; + } + + HDassert(mpi_size > 2); + + is_reader = mpi_rank % 2; + mrc = MPI_Comm_split(MPI_COMM_WORLD, is_reader, mpi_rank, &comm); + VRFY((mrc == MPI_SUCCESS), "MPI_Comm_split"); + + /* The reader processes branches off to do reading + * while the writer processes continues to do writing + * Whenever writers finish one writing step, including a H5Fflush, + * they inform the readers, via MPI_COMM_WORLD, to verify. + * They will wait for the result from the readers before doing the next + * step. When all steps are done, they inform readers to end. + */ + if (is_reader) + rr_obj_hdr_flush_confusion_reader(comm); + else + rr_obj_hdr_flush_confusion_writer(comm); + + MPI_Comm_free(&comm); + if (verbose) + HDfprintf(stdout, "%0d:%s: Done.\n", mpi_rank, fcn_name); + + return; + +} /* rr_obj_hdr_flush_confusion() */ + +void +rr_obj_hdr_flush_confusion_writer(MPI_Comm comm) +{ + int i; + int j; + hid_t file_id = -1; + hid_t fapl_id = -1; + hid_t dxpl_id = -1; + hid_t att_id[NUM_DATA_SETS]; + hid_t att_space[NUM_DATA_SETS]; + hid_t lg_att_id[NUM_DATA_SETS]; + hid_t lg_att_space[NUM_DATA_SETS]; + hid_t disk_space[NUM_DATA_SETS]; + hid_t mem_space[NUM_DATA_SETS]; + hid_t dataset[NUM_DATA_SETS]; + hsize_t att_size[1]; + hsize_t lg_att_size[1]; + hsize_t disk_count[1]; + hsize_t disk_size[1]; + hsize_t disk_start[1]; + hsize_t mem_count[1]; + hsize_t mem_size[1]; + hsize_t mem_start[1]; + herr_t err; + double data[LOCAL_DATA_SIZE]; + double att[LOCAL_DATA_SIZE]; + double lg_att[LARGE_ATTR_SIZE]; + + /* MPI variables */ + /* world communication size and rank */ + int mpi_world_size; + int mpi_world_rank; + /* private communicator size and rank */ + int mpi_size; + int mpi_rank; + int mrc; /* mpi error code */ + /* steps to verify and have been verified */ + int steps = 0; + int steps_done = 0; + + /* test bed related variables */ + const char *fcn_name = "rr_obj_hdr_flush_confusion_writer"; + const hbool_t verbose = FALSE; +#if 0 + const H5Ptest_param_t *pt; +#endif + char *filename; + + /* + * setup test bed related variables: + */ + +#if 0 + pt = (const H5Ptest_param_t *)GetTestParameters(); +#endif + /* filename = pt->name; */ filename = PARATESTFILE; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_world_rank); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_world_size); + MPI_Comm_rank(comm, &mpi_rank); + MPI_Comm_size(comm, &mpi_size); + + /* + * Set up file access property list with parallel I/O access + */ + + if (verbose) + HDfprintf(stdout, "%0d:%s: Setting up property list.\n", mpi_rank, fcn_name); + + fapl_id = H5Pcreate(H5P_FILE_ACCESS); + VRFY((fapl_id != -1), "H5Pcreate(H5P_FILE_ACCESS) failed"); + + err = H5Pset_fapl_mpio(fapl_id, comm, MPI_INFO_NULL); + VRFY((err >= 0), "H5Pset_fapl_mpio() failed"); + + /* + * Create a new file collectively and release property list identifier. + */ + + if (verbose) + HDfprintf(stdout, "%0d:%s: Creating new file \"%s\".\n", mpi_rank, fcn_name, filename); + + file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id); + VRFY((file_id >= 0), "H5Fcreate() failed"); + + err = H5Pclose(fapl_id); + VRFY((err >= 0), "H5Pclose(fapl_id) failed"); + + /* + * Step 1: create the data sets and write data. + */ + + if (verbose) + HDfprintf(stdout, "%0d:%s: Creating the datasets.\n", mpi_rank, fcn_name); + + disk_size[0] = (hsize_t)(LOCAL_DATA_SIZE * mpi_size); + mem_size[0] = (hsize_t)(LOCAL_DATA_SIZE); + + for (i = 0; i < NUM_DATA_SETS; i++) { + + disk_space[i] = H5Screate_simple(1, disk_size, NULL); + VRFY((disk_space[i] >= 0), "H5Screate_simple(1) failed.\n"); + + dataset[i] = H5Dcreate2(file_id, dataset_name[i], H5T_NATIVE_DOUBLE, disk_space[i], H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT); + + VRFY((dataset[i] >= 0), "H5Dcreate(1) failed.\n"); + } + + /* + * setup data transfer property list + */ + + if (verbose) + HDfprintf(stdout, "%0d:%s: Setting up dxpl.\n", mpi_rank, fcn_name); + + dxpl_id = H5Pcreate(H5P_DATASET_XFER); + VRFY((dxpl_id != -1), "H5Pcreate(H5P_DATASET_XFER) failed.\n"); + + err = H5Pset_dxpl_mpio(dxpl_id, H5FD_MPIO_COLLECTIVE); + VRFY((err >= 0), "H5Pset_dxpl_mpio(dxpl_id, H5FD_MPIO_COLLECTIVE) failed.\n"); + + /* + * write data to the data sets + */ + + if (verbose) + HDfprintf(stdout, "%0d:%s: Writing datasets.\n", mpi_rank, fcn_name); + + disk_count[0] = (hsize_t)(LOCAL_DATA_SIZE); + disk_start[0] = (hsize_t)(LOCAL_DATA_SIZE * mpi_rank); + mem_count[0] = (hsize_t)(LOCAL_DATA_SIZE); + mem_start[0] = (hsize_t)(0); + + for (j = 0; j < LOCAL_DATA_SIZE; j++) { + data[j] = (double)(mpi_rank + 1); + } + + for (i = 0; i < NUM_DATA_SETS; i++) { + err = H5Sselect_hyperslab(disk_space[i], H5S_SELECT_SET, disk_start, NULL, disk_count, NULL); + VRFY((err >= 0), "H5Sselect_hyperslab(1) failed.\n"); + mem_space[i] = H5Screate_simple(1, mem_size, NULL); + VRFY((mem_space[i] >= 0), "H5Screate_simple(2) failed.\n"); + err = H5Sselect_hyperslab(mem_space[i], H5S_SELECT_SET, mem_start, NULL, mem_count, NULL); + VRFY((err >= 0), "H5Sselect_hyperslab(2) failed.\n"); + err = H5Dwrite(dataset[i], H5T_NATIVE_DOUBLE, mem_space[i], disk_space[i], dxpl_id, data); + VRFY((err >= 0), "H5Dwrite(1) failed.\n"); + for (j = 0; j < LOCAL_DATA_SIZE; j++) + data[j] *= 10.0; + } + + /* + * close the data spaces + */ + + if (verbose) + HDfprintf(stdout, "%0d:%s: closing dataspaces.\n", mpi_rank, fcn_name); + + for (i = 0; i < NUM_DATA_SETS; i++) { + err = H5Sclose(disk_space[i]); + VRFY((err >= 0), "H5Sclose(disk_space[i]) failed.\n"); + err = H5Sclose(mem_space[i]); + VRFY((err >= 0), "H5Sclose(mem_space[i]) failed.\n"); + } + + /* End of Step 1: create the data sets and write data. */ + + /* + * flush the metadata cache + */ + + if (verbose) + HDfprintf(stdout, "%0d:%s: flushing metadata cache.\n", mpi_rank, fcn_name); + err = H5Fflush(file_id, H5F_SCOPE_GLOBAL); + VRFY((err >= 0), "H5Fflush(1) failed.\n"); + + /* Tell the reader to check the file up to steps. */ + steps++; + Reader_check(mrc, steps, steps_done); + VRFY((MPI_SUCCESS == mrc), "Reader_check failed"); + + /* + * Step 2: write attributes to each dataset + */ + + if (verbose) + HDfprintf(stdout, "%0d:%s: writing attributes.\n", mpi_rank, fcn_name); + + att_size[0] = (hsize_t)(LOCAL_DATA_SIZE); + for (j = 0; j < LOCAL_DATA_SIZE; j++) { + att[j] = (double)(j + 1); + } + + for (i = 0; i < NUM_DATA_SETS; i++) { + att_space[i] = H5Screate_simple(1, att_size, NULL); + VRFY((att_space[i] >= 0), "H5Screate_simple(3) failed.\n"); + att_id[i] = + H5Acreate2(dataset[i], att_name[i], H5T_NATIVE_DOUBLE, att_space[i], H5P_DEFAULT, H5P_DEFAULT); + VRFY((att_id[i] >= 0), "H5Acreate(1) failed.\n"); + err = H5Awrite(att_id[i], H5T_NATIVE_DOUBLE, att); + VRFY((err >= 0), "H5Awrite(1) failed.\n"); + for (j = 0; j < LOCAL_DATA_SIZE; j++) { + att[j] /= 10.0; + } + } + + /* + * close attribute IDs and spaces + */ + + if (verbose) + HDfprintf(stdout, "%0d:%s: closing attr ids and spaces .\n", mpi_rank, fcn_name); + + for (i = 0; i < NUM_DATA_SETS; i++) { + err = H5Sclose(att_space[i]); + VRFY((err >= 0), "H5Sclose(att_space[i]) failed.\n"); + err = H5Aclose(att_id[i]); + VRFY((err >= 0), "H5Aclose(att_id[i]) failed.\n"); + } + + /* End of Step 2: write attributes to each dataset */ + + /* + * flush the metadata cache again + */ + + if (verbose) + HDfprintf(stdout, "%0d:%s: flushing metadata cache.\n", mpi_rank, fcn_name); + err = H5Fflush(file_id, H5F_SCOPE_GLOBAL); + VRFY((err >= 0), "H5Fflush(2) failed.\n"); + + /* Tell the reader to check the file up to steps. */ + steps++; + Reader_check(mrc, steps, steps_done); + VRFY((MPI_SUCCESS == mrc), "Reader_check failed"); + + /* + * Step 3: write large attributes to each dataset + */ + + if (verbose) + HDfprintf(stdout, "%0d:%s: writing large attributes.\n", mpi_rank, fcn_name); + + lg_att_size[0] = (hsize_t)(LARGE_ATTR_SIZE); + + for (j = 0; j < LARGE_ATTR_SIZE; j++) { + lg_att[j] = (double)(j + 1); + } + + for (i = 0; i < NUM_DATA_SETS; i++) { + lg_att_space[i] = H5Screate_simple(1, lg_att_size, NULL); + VRFY((lg_att_space[i] >= 0), "H5Screate_simple(4) failed.\n"); + lg_att_id[i] = H5Acreate2(dataset[i], lg_att_name[i], H5T_NATIVE_DOUBLE, lg_att_space[i], H5P_DEFAULT, + H5P_DEFAULT); + VRFY((lg_att_id[i] >= 0), "H5Acreate(2) failed.\n"); + err = H5Awrite(lg_att_id[i], H5T_NATIVE_DOUBLE, lg_att); + VRFY((err >= 0), "H5Awrite(2) failed.\n"); + for (j = 0; j < LARGE_ATTR_SIZE; j++) { + lg_att[j] /= 10.0; + } + } + + /* Step 3: write large attributes to each dataset */ + + /* + * flush the metadata cache yet again to clean the object headers. + * + * This is an attempt to create a situation where we have dirty + * object header continuation chunks, but clean object headers + * to verify a speculative bug fix -- it doesn't seem to work, + * but I will leave the code in anyway, as the object header + * code is going to change a lot in the near future. + */ + + if (verbose) + HDfprintf(stdout, "%0d:%s: flushing metadata cache.\n", mpi_rank, fcn_name); + err = H5Fflush(file_id, H5F_SCOPE_GLOBAL); + VRFY((err >= 0), "H5Fflush(3) failed.\n"); + + /* Tell the reader to check the file up to steps. */ + steps++; + Reader_check(mrc, steps, steps_done); + VRFY((MPI_SUCCESS == mrc), "Reader_check failed"); + + /* + * Step 4: write different large attributes to each dataset + */ + + if (verbose) + HDfprintf(stdout, "%0d:%s: writing different large attributes.\n", mpi_rank, fcn_name); + + for (j = 0; j < LARGE_ATTR_SIZE; j++) { + lg_att[j] = (double)(j + 2); + } + + for (i = 0; i < NUM_DATA_SETS; i++) { + err = H5Awrite(lg_att_id[i], H5T_NATIVE_DOUBLE, lg_att); + VRFY((err >= 0), "H5Awrite(2) failed.\n"); + for (j = 0; j < LARGE_ATTR_SIZE; j++) { + lg_att[j] /= 10.0; + } + } + + /* End of Step 4: write different large attributes to each dataset */ + + /* + * flush the metadata cache again + */ + if (verbose) + HDfprintf(stdout, "%0d:%s: flushing metadata cache.\n", mpi_rank, fcn_name); + err = H5Fflush(file_id, H5F_SCOPE_GLOBAL); + VRFY((err >= 0), "H5Fflush(3) failed.\n"); + + /* Tell the reader to check the file up to steps. */ + steps++; + Reader_check(mrc, steps, steps_done); + VRFY((MPI_SUCCESS == mrc), "Reader_check failed"); + + /* Step 5: Close all objects and the file */ + + /* + * close large attribute IDs and spaces + */ + + if (verbose) + HDfprintf(stdout, "%0d:%s: closing large attr ids and spaces .\n", mpi_rank, fcn_name); + + for (i = 0; i < NUM_DATA_SETS; i++) { + + err = H5Sclose(lg_att_space[i]); + VRFY((err >= 0), "H5Sclose(lg_att_space[i]) failed.\n"); + err = H5Aclose(lg_att_id[i]); + VRFY((err >= 0), "H5Aclose(lg_att_id[i]) failed.\n"); + } + + /* + * close the data sets + */ + + if (verbose) + HDfprintf(stdout, "%0d:%s: closing datasets .\n", mpi_rank, fcn_name); + + for (i = 0; i < NUM_DATA_SETS; i++) { + err = H5Dclose(dataset[i]); + VRFY((err >= 0), "H5Dclose(dataset[i])1 failed.\n"); + } + + /* + * close the data transfer property list. + */ + + if (verbose) + HDfprintf(stdout, "%0d:%s: closing dxpl .\n", mpi_rank, fcn_name); + + err = H5Pclose(dxpl_id); + VRFY((err >= 0), "H5Pclose(dxpl_id) failed.\n"); + + /* + * Close file. + */ + + if (verbose) + HDfprintf(stdout, "%0d:%s: closing file.\n", mpi_rank, fcn_name); + + err = H5Fclose(file_id); + VRFY((err >= 0), "H5Fclose(1) failed"); + + /* End of Step 5: Close all objects and the file */ + /* Tell the reader to check the file up to steps. */ + steps++; + Reader_check(mrc, steps, steps_done); + VRFY((MPI_SUCCESS == mrc), "Reader_check failed"); + + /* All done. Inform reader to end. */ + steps = 0; + Reader_check(mrc, steps, steps_done); + VRFY((MPI_SUCCESS == mrc), "Reader_check failed"); + + if (verbose) + HDfprintf(stdout, "%0d:%s: Done.\n", mpi_rank, fcn_name); + + return; + +} /* rr_obj_hdr_flush_confusion_writer() */ + +void +rr_obj_hdr_flush_confusion_reader(MPI_Comm comm) +{ + int i; + int j; + hid_t file_id = -1; + hid_t fapl_id = -1; + hid_t dxpl_id = -1; + hid_t lg_att_id[NUM_DATA_SETS]; + hid_t lg_att_type[NUM_DATA_SETS]; + hid_t disk_space[NUM_DATA_SETS]; + hid_t mem_space[NUM_DATA_SETS]; + hid_t dataset[NUM_DATA_SETS]; + hsize_t disk_count[1]; + hsize_t disk_start[1]; + hsize_t mem_count[1]; + hsize_t mem_size[1]; + hsize_t mem_start[1]; + herr_t err; + htri_t tri_err; + double data[LOCAL_DATA_SIZE]; + double data_read[LOCAL_DATA_SIZE]; + double att[LOCAL_DATA_SIZE]; + double att_read[LOCAL_DATA_SIZE]; + double lg_att[LARGE_ATTR_SIZE]; + double lg_att_read[LARGE_ATTR_SIZE]; + + /* MPI variables */ + /* world communication size and rank */ + int mpi_world_size; + int mpi_world_rank; + /* private communicator size and rank */ + int mpi_size; + int mpi_rank; + int mrc; /* mpi error code */ + int steps = -1; /* How far (steps) to verify the file */ + int steps_done = -1; /* How far (steps) have been verified */ + + /* test bed related variables */ + const char *fcn_name = "rr_obj_hdr_flush_confusion_reader"; + const hbool_t verbose = FALSE; +#if 0 + const H5Ptest_param_t *pt; +#endif + char *filename; + + /* + * setup test bed related variables: + */ + +#if 0 + pt = (const H5Ptest_param_t *)GetTestParameters(); +#endif + /* filename = pt->name; */ filename = PARATESTFILE; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_world_rank); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_world_size); + MPI_Comm_rank(comm, &mpi_rank); + MPI_Comm_size(comm, &mpi_size); + + /* Repeatedly re-open the file and verify its contents until it is */ + /* told to end (when steps=0). */ + while (steps_done != 0) { + Reader_wait(mrc, steps); + VRFY((mrc >= 0), "Reader_wait failed"); + steps_done = 0; + + if (steps > 0) { + /* + * Set up file access property list with parallel I/O access + */ + + if (verbose) + HDfprintf(stdout, "%0d:%s: Setting up property list.\n", mpi_rank, fcn_name); + + fapl_id = H5Pcreate(H5P_FILE_ACCESS); + VRFY((fapl_id != -1), "H5Pcreate(H5P_FILE_ACCESS) failed"); + err = H5Pset_fapl_mpio(fapl_id, comm, MPI_INFO_NULL); + VRFY((err >= 0), "H5Pset_fapl_mpio() failed"); + + /* + * Create a new file collectively and release property list identifier. + */ + + if (verbose) + HDfprintf(stdout, "%0d:%s: Re-open file \"%s\".\n", mpi_rank, fcn_name, filename); + + file_id = H5Fopen(filename, H5F_ACC_RDONLY, fapl_id); + VRFY((file_id >= 0), "H5Fopen() failed"); + err = H5Pclose(fapl_id); + VRFY((err >= 0), "H5Pclose(fapl_id) failed"); + +#if 1 + if (steps >= 1) { + /*=====================================================* + * Step 1: open the data sets and read data. + *=====================================================*/ + + if (verbose) + HDfprintf(stdout, "%0d:%s: opening the datasets.\n", mpi_rank, fcn_name); + + for (i = 0; i < NUM_DATA_SETS; i++) { + dataset[i] = -1; + } + + for (i = 0; i < NUM_DATA_SETS; i++) { + dataset[i] = H5Dopen2(file_id, dataset_name[i], H5P_DEFAULT); + VRFY((dataset[i] >= 0), "H5Dopen(1) failed.\n"); + disk_space[i] = H5Dget_space(dataset[i]); + VRFY((disk_space[i] >= 0), "H5Dget_space failed.\n"); + } + + /* + * setup data transfer property list + */ + + if (verbose) + HDfprintf(stdout, "%0d:%s: Setting up dxpl.\n", mpi_rank, fcn_name); + + dxpl_id = H5Pcreate(H5P_DATASET_XFER); + VRFY((dxpl_id != -1), "H5Pcreate(H5P_DATASET_XFER) failed.\n"); + err = H5Pset_dxpl_mpio(dxpl_id, H5FD_MPIO_COLLECTIVE); + VRFY((err >= 0), "H5Pset_dxpl_mpio(dxpl_id, H5FD_MPIO_COLLECTIVE) failed.\n"); + + /* + * read data from the data sets + */ + + if (verbose) + HDfprintf(stdout, "%0d:%s: Reading datasets.\n", mpi_rank, fcn_name); + + disk_count[0] = (hsize_t)(LOCAL_DATA_SIZE); + disk_start[0] = (hsize_t)(LOCAL_DATA_SIZE * mpi_rank); + + mem_size[0] = (hsize_t)(LOCAL_DATA_SIZE); + + mem_count[0] = (hsize_t)(LOCAL_DATA_SIZE); + mem_start[0] = (hsize_t)(0); + + /* set up expected data for verification */ + for (j = 0; j < LOCAL_DATA_SIZE; j++) { + data[j] = (double)(mpi_rank + 1); + } + + for (i = 0; i < NUM_DATA_SETS; i++) { + err = H5Sselect_hyperslab(disk_space[i], H5S_SELECT_SET, disk_start, NULL, disk_count, + NULL); + VRFY((err >= 0), "H5Sselect_hyperslab(1) failed.\n"); + mem_space[i] = H5Screate_simple(1, mem_size, NULL); + VRFY((mem_space[i] >= 0), "H5Screate_simple(2) failed.\n"); + err = H5Sselect_hyperslab(mem_space[i], H5S_SELECT_SET, mem_start, NULL, mem_count, NULL); + VRFY((err >= 0), "H5Sselect_hyperslab(2) failed.\n"); + err = H5Dread(dataset[i], H5T_NATIVE_DOUBLE, mem_space[i], disk_space[i], dxpl_id, + data_read); + VRFY((err >= 0), "H5Dread(1) failed.\n"); + + /* compare read data with expected data */ + for (j = 0; j < LOCAL_DATA_SIZE; j++) + if (!H5_DBL_ABS_EQUAL(data_read[j], data[j])) { + HDfprintf(stdout, + "%0d:%s: Reading datasets value failed in " + "Dataset %d, at position %d: expect %f, got %f.\n", + mpi_rank, fcn_name, i, j, data[j], data_read[j]); + nerrors++; + } + for (j = 0; j < LOCAL_DATA_SIZE; j++) + data[j] *= 10.0; + } + + /* + * close the data spaces + */ + + if (verbose) + HDfprintf(stdout, "%0d:%s: closing dataspaces.\n", mpi_rank, fcn_name); + + for (i = 0; i < NUM_DATA_SETS; i++) { + err = H5Sclose(disk_space[i]); + VRFY((err >= 0), "H5Sclose(disk_space[i]) failed.\n"); + err = H5Sclose(mem_space[i]); + VRFY((err >= 0), "H5Sclose(mem_space[i]) failed.\n"); + } + steps_done++; + } + /* End of Step 1: open the data sets and read data. */ +#endif + +#if 1 + /*=====================================================* + * Step 2: reading attributes from each dataset + *=====================================================*/ + + if (steps >= 2) { + if (verbose) + HDfprintf(stdout, "%0d:%s: reading attributes.\n", mpi_rank, fcn_name); + + for (j = 0; j < LOCAL_DATA_SIZE; j++) { + att[j] = (double)(j + 1); + } + + for (i = 0; i < NUM_DATA_SETS; i++) { + hid_t att_id, att_type; + + att_id = H5Aopen(dataset[i], att_name[i], H5P_DEFAULT); + VRFY((att_id >= 0), "H5Aopen failed.\n"); + att_type = H5Aget_type(att_id); + VRFY((att_type >= 0), "H5Aget_type failed.\n"); + tri_err = H5Tequal(att_type, H5T_NATIVE_DOUBLE); + VRFY((tri_err >= 0), "H5Tequal failed.\n"); + if (tri_err == 0) { + HDfprintf(stdout, "%0d:%s: Mismatched Attribute type of Dataset %d.\n", mpi_rank, + fcn_name, i); + nerrors++; + } + else { + /* should verify attribute size before H5Aread */ + err = H5Aread(att_id, H5T_NATIVE_DOUBLE, att_read); + VRFY((err >= 0), "H5Aread failed.\n"); + /* compare read attribute data with expected data */ + for (j = 0; j < LOCAL_DATA_SIZE; j++) + if (!H5_DBL_ABS_EQUAL(att_read[j], att[j])) { + HDfprintf(stdout, + "%0d:%s: Mismatched attribute data read in Dataset %d, at position " + "%d: expect %f, got %f.\n", + mpi_rank, fcn_name, i, j, att[j], att_read[j]); + nerrors++; + } + for (j = 0; j < LOCAL_DATA_SIZE; j++) { + att[j] /= 10.0; + } + } + err = H5Aclose(att_id); + VRFY((err >= 0), "H5Aclose failed.\n"); + } + steps_done++; + } + /* End of Step 2: reading attributes from each dataset */ +#endif + +#if 1 + /*=====================================================* + * Step 3 or 4: read large attributes from each dataset. + * Step 4 has different attribute value from step 3. + *=====================================================*/ + + if (steps >= 3) { + if (verbose) + HDfprintf(stdout, "%0d:%s: reading large attributes.\n", mpi_rank, fcn_name); + + for (j = 0; j < LARGE_ATTR_SIZE; j++) { + lg_att[j] = (steps == 3) ? (double)(j + 1) : (double)(j + 2); + } + + for (i = 0; i < NUM_DATA_SETS; i++) { + lg_att_id[i] = H5Aopen(dataset[i], lg_att_name[i], H5P_DEFAULT); + VRFY((lg_att_id[i] >= 0), "H5Aopen(2) failed.\n"); + lg_att_type[i] = H5Aget_type(lg_att_id[i]); + VRFY((err >= 0), "H5Aget_type failed.\n"); + tri_err = H5Tequal(lg_att_type[i], H5T_NATIVE_DOUBLE); + VRFY((tri_err >= 0), "H5Tequal failed.\n"); + if (tri_err == 0) { + HDfprintf(stdout, "%0d:%s: Mismatched Large attribute type of Dataset %d.\n", + mpi_rank, fcn_name, i); + nerrors++; + } + else { + /* should verify large attribute size before H5Aread */ + err = H5Aread(lg_att_id[i], H5T_NATIVE_DOUBLE, lg_att_read); + VRFY((err >= 0), "H5Aread failed.\n"); + /* compare read attribute data with expected data */ + for (j = 0; j < LARGE_ATTR_SIZE; j++) + if (!H5_DBL_ABS_EQUAL(lg_att_read[j], lg_att[j])) { + HDfprintf(stdout, + "%0d:%s: Mismatched large attribute data read in Dataset %d, at " + "position %d: expect %f, got %f.\n", + mpi_rank, fcn_name, i, j, lg_att[j], lg_att_read[j]); + nerrors++; + } + for (j = 0; j < LARGE_ATTR_SIZE; j++) { + + lg_att[j] /= 10.0; + } + } + err = H5Tclose(lg_att_type[i]); + VRFY((err >= 0), "H5Tclose failed.\n"); + err = H5Aclose(lg_att_id[i]); + VRFY((err >= 0), "H5Aclose failed.\n"); + } + /* Both step 3 and 4 use this same read checking code. */ + steps_done = (steps == 3) ? 3 : 4; + } + + /* End of Step 3 or 4: read large attributes from each dataset */ +#endif + + /*=====================================================* + * Step 5: read all objects from the file + *=====================================================*/ + if (steps >= 5) { + /* nothing extra to verify. The file is closed normally. */ + /* Just increment steps_done */ + steps_done++; + } + + /* + * Close the data sets + */ + + if (verbose) + HDfprintf(stdout, "%0d:%s: closing datasets again.\n", mpi_rank, fcn_name); + + for (i = 0; i < NUM_DATA_SETS; i++) { + if (dataset[i] >= 0) { + err = H5Dclose(dataset[i]); + VRFY((err >= 0), "H5Dclose(dataset[i])1 failed.\n"); + } + } + + /* + * close the data transfer property list. + */ + + if (verbose) + HDfprintf(stdout, "%0d:%s: closing dxpl .\n", mpi_rank, fcn_name); + + err = H5Pclose(dxpl_id); + VRFY((err >= 0), "H5Pclose(dxpl_id) failed.\n"); + + /* + * Close the file + */ + if (verbose) + HDfprintf(stdout, "%0d:%s: closing file again.\n", mpi_rank, fcn_name); + err = H5Fclose(file_id); + VRFY((err >= 0), "H5Fclose(1) failed"); + + } /* else if (steps_done==0) */ + Reader_result(mrc, steps_done); + } /* end while(1) */ + + if (verbose) + HDfprintf(stdout, "%0d:%s: Done.\n", mpi_rank, fcn_name); + + return; +} /* rr_obj_hdr_flush_confusion_reader() */ + +#undef NUM_DATA_SETS +#undef LOCAL_DATA_SIZE +#undef LARGE_ATTR_SIZE +#undef Reader_check +#undef Reader_wait +#undef Reader_result +#undef Writer_Root +#undef Reader_Root + +/* + * Test creating a chunked dataset in parallel in a file with an alignment set + * and an alignment threshold large enough to avoid aligning the chunks but + * small enough that the raw data aggregator will be aligned if it is treated as + * an object that must be aligned by the library + */ +#define CHUNK_SIZE 72 +#define NCHUNKS 32 +#define AGGR_SIZE 2048 +#define EXTRA_ALIGN 100 + +void +chunk_align_bug_1(void) +{ + int mpi_rank; + hid_t file_id, dset_id, fapl_id, dcpl_id, space_id; + hsize_t dims = CHUNK_SIZE * NCHUNKS, cdims = CHUNK_SIZE; +#if 0 + h5_stat_size_t file_size; + hsize_t align; +#endif + herr_t ret; + const char *filename; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file or dataset aren't supported with this connector\n"); + fflush(stdout); + } + + return; + } + + filename = (const char *)PARATESTFILE /* GetTestParameters() */; + + /* Create file without alignment */ + fapl_id = create_faccess_plist(MPI_COMM_WORLD, MPI_INFO_NULL, facc_type); + VRFY((fapl_id >= 0), "create_faccess_plist succeeded"); + file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id); + VRFY((file_id >= 0), "H5Fcreate succeeded"); + + /* Close file */ + ret = H5Fclose(file_id); + VRFY((ret >= 0), "H5Fclose succeeded"); +#if 0 + /* Get file size */ + file_size = h5_get_file_size(filename, fapl_id); + VRFY((file_size >= 0), "h5_get_file_size succeeded"); + + /* Calculate alignment value, set to allow a chunk to squeak in between the + * original EOF and the aligned location of the aggregator. Add some space + * for the dataset metadata */ + align = (hsize_t)file_size + CHUNK_SIZE + EXTRA_ALIGN; +#endif + + /* Set aggregator size and alignment, disable metadata aggregator */ + HDassert(AGGR_SIZE > CHUNK_SIZE); + ret = H5Pset_small_data_block_size(fapl_id, AGGR_SIZE); + VRFY((ret >= 0), "H5Pset_small_data_block_size succeeded"); + ret = H5Pset_meta_block_size(fapl_id, 0); + VRFY((ret >= 0), "H5Pset_meta_block_size succeeded"); +#if 0 + ret = H5Pset_alignment(fapl_id, CHUNK_SIZE + 1, align); + VRFY((ret >= 0), "H5Pset_small_data_block_size succeeded"); +#endif + + /* Reopen file with new settings */ + file_id = H5Fopen(filename, H5F_ACC_RDWR, fapl_id); + VRFY((file_id >= 0), "H5Fopen succeeded"); + + /* Create dataset */ + space_id = H5Screate_simple(1, &dims, NULL); + VRFY((space_id >= 0), "H5Screate_simple succeeded"); + dcpl_id = H5Pcreate(H5P_DATASET_CREATE); + VRFY((dcpl_id >= 0), "H5Pcreate succeeded"); + ret = H5Pset_chunk(dcpl_id, 1, &cdims); + VRFY((ret >= 0), "H5Pset_chunk succeeded"); + dset_id = H5Dcreate2(file_id, "dset", H5T_NATIVE_CHAR, space_id, H5P_DEFAULT, dcpl_id, H5P_DEFAULT); + VRFY((dset_id >= 0), "H5Dcreate2 succeeded"); + + /* Close ids */ + ret = H5Dclose(dset_id); + VRFY((dset_id >= 0), "H5Dclose succeeded"); + ret = H5Sclose(space_id); + VRFY((space_id >= 0), "H5Sclose succeeded"); + ret = H5Pclose(dcpl_id); + VRFY((dcpl_id >= 0), "H5Pclose succeeded"); + ret = H5Pclose(fapl_id); + VRFY((fapl_id >= 0), "H5Pclose succeeded"); + + /* Close file */ + ret = H5Fclose(file_id); + VRFY((ret >= 0), "H5Fclose succeeded"); + + return; +} /* end chunk_align_bug_1() */ + +/*============================================================================= + * End of t_mdset.c + *===========================================================================*/ diff --git a/testpar/API/t_ph5basic.c b/testpar/API/t_ph5basic.c new file mode 100644 index 0000000..1639aff --- /dev/null +++ b/testpar/API/t_ph5basic.c @@ -0,0 +1,192 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Test parallel HDF5 basic components + */ + +#include "hdf5.h" +#include "testphdf5.h" + +/*------------------------------------------------------------------------- + * Function: test_fapl_mpio_dup + * + * Purpose: Test if fapl_mpio property list keeps a duplicate of the + * communicator and INFO objects given when set; and returns + * duplicates of its components when H5Pget_fapl_mpio is called. + * + * Return: Success: None + * Failure: Abort + * + * Programmer: Albert Cheng + * January 9, 2003 + * + *------------------------------------------------------------------------- + */ +void +test_fapl_mpio_dup(void) +{ + int mpi_size, mpi_rank; + MPI_Comm comm, comm_tmp; + int mpi_size_old, mpi_rank_old; + int mpi_size_tmp, mpi_rank_tmp; + MPI_Info info = MPI_INFO_NULL; + MPI_Info info_tmp = MPI_INFO_NULL; + int mrc; /* MPI return value */ + hid_t acc_pl; /* File access properties */ + herr_t ret; /* HDF5 return value */ + int nkeys, nkeys_tmp; + + if (VERBOSE_MED) + HDprintf("Verify fapl_mpio duplicates communicator and INFO objects\n"); + + /* set up MPI parameters */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + if (VERBOSE_MED) + HDprintf("rank/size of MPI_COMM_WORLD are %d/%d\n", mpi_rank, mpi_size); + + /* Create a new communicator that has the same processes as MPI_COMM_WORLD. + * Use MPI_Comm_split because it is simpler than MPI_Comm_create + */ + mrc = MPI_Comm_split(MPI_COMM_WORLD, 0, 0, &comm); + VRFY((mrc == MPI_SUCCESS), "MPI_Comm_split"); + MPI_Comm_size(comm, &mpi_size_old); + MPI_Comm_rank(comm, &mpi_rank_old); + if (VERBOSE_MED) + HDprintf("rank/size of comm are %d/%d\n", mpi_rank_old, mpi_size_old); + + /* create a new INFO object with some trivial information. */ + mrc = MPI_Info_create(&info); + VRFY((mrc == MPI_SUCCESS), "MPI_Info_create"); + mrc = MPI_Info_set(info, "hdf_info_name", "XYZ"); + VRFY((mrc == MPI_SUCCESS), "MPI_Info_set"); + if (MPI_INFO_NULL != info) { + mrc = MPI_Info_get_nkeys(info, &nkeys); + VRFY((mrc == MPI_SUCCESS), "MPI_Info_get_nkeys"); + } +#if 0 + if (VERBOSE_MED) + h5_dump_info_object(info); +#endif + + acc_pl = H5Pcreate(H5P_FILE_ACCESS); + VRFY((acc_pl >= 0), "H5P_FILE_ACCESS"); + + ret = H5Pset_fapl_mpio(acc_pl, comm, info); + VRFY((ret >= 0), ""); + + /* Case 1: + * Free the created communicator and INFO object. + * Check if the access property list is still valid and can return + * valid communicator and INFO object. + */ + mrc = MPI_Comm_free(&comm); + VRFY((mrc == MPI_SUCCESS), "MPI_Comm_free"); + if (MPI_INFO_NULL != info) { + mrc = MPI_Info_free(&info); + VRFY((mrc == MPI_SUCCESS), "MPI_Info_free"); + } + + ret = H5Pget_fapl_mpio(acc_pl, &comm_tmp, &info_tmp); + VRFY((ret >= 0), "H5Pget_fapl_mpio"); + MPI_Comm_size(comm_tmp, &mpi_size_tmp); + MPI_Comm_rank(comm_tmp, &mpi_rank_tmp); + if (VERBOSE_MED) + HDprintf("After H5Pget_fapl_mpio: rank/size of comm are %d/%d\n", mpi_rank_tmp, mpi_size_tmp); + VRFY((mpi_size_tmp == mpi_size), "MPI_Comm_size"); + VRFY((mpi_rank_tmp == mpi_rank), "MPI_Comm_rank"); + if (MPI_INFO_NULL != info_tmp) { + mrc = MPI_Info_get_nkeys(info_tmp, &nkeys_tmp); + VRFY((mrc == MPI_SUCCESS), "MPI_Info_get_nkeys"); + VRFY((nkeys_tmp == nkeys), "new and old nkeys equal"); + } +#if 0 + if (VERBOSE_MED) + h5_dump_info_object(info_tmp); +#endif + + /* Case 2: + * Free the retrieved communicator and INFO object. + * Check if the access property list is still valid and can return + * valid communicator and INFO object. + * Also verify the NULL argument option. + */ + mrc = MPI_Comm_free(&comm_tmp); + VRFY((mrc == MPI_SUCCESS), "MPI_Comm_free"); + if (MPI_INFO_NULL != info_tmp) { + mrc = MPI_Info_free(&info_tmp); + VRFY((mrc == MPI_SUCCESS), "MPI_Info_free"); + } + + /* check NULL argument options. */ + ret = H5Pget_fapl_mpio(acc_pl, &comm_tmp, NULL); + VRFY((ret >= 0), "H5Pget_fapl_mpio Comm only"); + mrc = MPI_Comm_free(&comm_tmp); + VRFY((mrc == MPI_SUCCESS), "MPI_Comm_free"); + + ret = H5Pget_fapl_mpio(acc_pl, NULL, &info_tmp); + VRFY((ret >= 0), "H5Pget_fapl_mpio Info only"); + if (MPI_INFO_NULL != info_tmp) { + mrc = MPI_Info_free(&info_tmp); + VRFY((mrc == MPI_SUCCESS), "MPI_Info_free"); + } + + ret = H5Pget_fapl_mpio(acc_pl, NULL, NULL); + VRFY((ret >= 0), "H5Pget_fapl_mpio neither"); + + /* now get both and check validity too. */ + /* Do not free the returned objects which are used in the next case. */ + ret = H5Pget_fapl_mpio(acc_pl, &comm_tmp, &info_tmp); + VRFY((ret >= 0), "H5Pget_fapl_mpio"); + MPI_Comm_size(comm_tmp, &mpi_size_tmp); + MPI_Comm_rank(comm_tmp, &mpi_rank_tmp); + if (VERBOSE_MED) + HDprintf("After second H5Pget_fapl_mpio: rank/size of comm are %d/%d\n", mpi_rank_tmp, mpi_size_tmp); + VRFY((mpi_size_tmp == mpi_size), "MPI_Comm_size"); + VRFY((mpi_rank_tmp == mpi_rank), "MPI_Comm_rank"); + if (MPI_INFO_NULL != info_tmp) { + mrc = MPI_Info_get_nkeys(info_tmp, &nkeys_tmp); + VRFY((mrc == MPI_SUCCESS), "MPI_Info_get_nkeys"); + VRFY((nkeys_tmp == nkeys), "new and old nkeys equal"); + } +#if 0 + if (VERBOSE_MED) + h5_dump_info_object(info_tmp); +#endif + + /* Case 3: + * Close the property list and verify the retrieved communicator and INFO + * object are still valid. + */ + H5Pclose(acc_pl); + MPI_Comm_size(comm_tmp, &mpi_size_tmp); + MPI_Comm_rank(comm_tmp, &mpi_rank_tmp); + if (VERBOSE_MED) + HDprintf("After Property list closed: rank/size of comm are %d/%d\n", mpi_rank_tmp, mpi_size_tmp); + if (MPI_INFO_NULL != info_tmp) { + mrc = MPI_Info_get_nkeys(info_tmp, &nkeys_tmp); + VRFY((mrc == MPI_SUCCESS), "MPI_Info_get_nkeys"); + } +#if 0 + if (VERBOSE_MED) + h5_dump_info_object(info_tmp); +#endif + + /* clean up */ + mrc = MPI_Comm_free(&comm_tmp); + VRFY((mrc == MPI_SUCCESS), "MPI_Comm_free"); + if (MPI_INFO_NULL != info_tmp) { + mrc = MPI_Info_free(&info_tmp); + VRFY((mrc == MPI_SUCCESS), "MPI_Info_free"); + } +} /* end test_fapl_mpio_dup() */ diff --git a/testpar/API/t_prop.c b/testpar/API/t_prop.c new file mode 100644 index 0000000..3659501 --- /dev/null +++ b/testpar/API/t_prop.c @@ -0,0 +1,646 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Parallel tests for encoding/decoding plists sent between processes + */ + +#include "hdf5.h" +#include "testphdf5.h" + +#if 0 +#include "H5ACprivate.h" +#include "H5Pprivate.h" +#endif + +static int +test_encode_decode(hid_t orig_pl, int mpi_rank, int recv_proc) +{ + MPI_Request req[2]; + MPI_Status status; + hid_t pl; /* Decoded property list */ + size_t buf_size = 0; + void *sbuf = NULL; + herr_t ret; /* Generic return value */ + + if (mpi_rank == 0) { + int send_size = 0; + + /* first call to encode returns only the size of the buffer needed */ + ret = H5Pencode2(orig_pl, NULL, &buf_size, H5P_DEFAULT); + VRFY((ret >= 0), "H5Pencode succeeded"); + + sbuf = (uint8_t *)HDmalloc(buf_size); + + ret = H5Pencode2(orig_pl, sbuf, &buf_size, H5P_DEFAULT); + VRFY((ret >= 0), "H5Pencode succeeded"); + + /* this is a temp fix to send this size_t */ + send_size = (int)buf_size; + + MPI_Isend(&send_size, 1, MPI_INT, recv_proc, 123, MPI_COMM_WORLD, &req[0]); + MPI_Isend(sbuf, send_size, MPI_BYTE, recv_proc, 124, MPI_COMM_WORLD, &req[1]); + } /* end if */ + + if (mpi_rank == recv_proc) { + int recv_size; + void *rbuf; + + MPI_Recv(&recv_size, 1, MPI_INT, 0, 123, MPI_COMM_WORLD, &status); + VRFY((recv_size >= 0), "MPI_Recv succeeded"); + buf_size = (size_t)recv_size; + rbuf = (uint8_t *)HDmalloc(buf_size); + MPI_Recv(rbuf, recv_size, MPI_BYTE, 0, 124, MPI_COMM_WORLD, &status); + + pl = H5Pdecode(rbuf); + VRFY((pl >= 0), "H5Pdecode succeeded"); + + VRFY(H5Pequal(orig_pl, pl), "Property List Equal Succeeded"); + + ret = H5Pclose(pl); + VRFY((ret >= 0), "H5Pclose succeeded"); + + if (NULL != rbuf) + HDfree(rbuf); + } /* end if */ + + if (0 == mpi_rank) { + /* gcc 11 complains about passing MPI_STATUSES_IGNORE as an MPI_Status + * array. See the discussion here: + * + * https://github.com/pmodels/mpich/issues/5687 + */ + /* H5_GCC_DIAG_OFF("stringop-overflow") */ + MPI_Waitall(2, req, MPI_STATUSES_IGNORE); + /* H5_GCC_DIAG_ON("stringop-overflow") */ + } + + if (NULL != sbuf) + HDfree(sbuf); + + MPI_Barrier(MPI_COMM_WORLD); + return 0; +} + +void +test_plist_ed(void) +{ + hid_t dcpl; /* dataset create prop. list */ + hid_t dapl; /* dataset access prop. list */ + hid_t dxpl; /* dataset transfer prop. list */ + hid_t gcpl; /* group create prop. list */ + hid_t lcpl; /* link create prop. list */ + hid_t lapl; /* link access prop. list */ + hid_t ocpypl; /* object copy prop. list */ + hid_t ocpl; /* object create prop. list */ + hid_t fapl; /* file access prop. list */ + hid_t fcpl; /* file create prop. list */ + hid_t strcpl; /* string create prop. list */ + hid_t acpl; /* attribute create prop. list */ + + int mpi_size, mpi_rank, recv_proc; + + hsize_t chunk_size = 16384; /* chunk size */ + double fill = 2.7; /* Fill value */ + size_t nslots = 521 * 2; + size_t nbytes = 1048576 * 10; + double w0 = 0.5; + unsigned max_compact; + unsigned min_dense; + hsize_t max_size[1]; /*data space maximum size */ + const char *c_to_f = "x+32"; + H5AC_cache_config_t my_cache_config = {H5AC__CURR_CACHE_CONFIG_VERSION, + TRUE, + FALSE, + FALSE, + "temp", + TRUE, + FALSE, + (2 * 2048 * 1024), + 0.3, + (64 * 1024 * 1024), + (4 * 1024 * 1024), + 60000, + H5C_incr__threshold, + 0.8, + 3.0, + TRUE, + (8 * 1024 * 1024), + H5C_flash_incr__add_space, + 2.0, + 0.25, + H5C_decr__age_out_with_threshold, + 0.997, + 0.8, + TRUE, + (3 * 1024 * 1024), + 3, + FALSE, + 0.2, + (256 * 2048), + 1 /* H5AC__DEFAULT_METADATA_WRITE_STRATEGY */}; + + herr_t ret; /* Generic return value */ + + if (VERBOSE_MED) + HDprintf("Encode/Decode DCPLs\n"); + + /* set up MPI parameters */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + if (mpi_size == 1) + recv_proc = 0; + else + recv_proc = 1; + + dcpl = H5Pcreate(H5P_DATASET_CREATE); + VRFY((dcpl >= 0), "H5Pcreate succeeded"); + + ret = H5Pset_chunk(dcpl, 1, &chunk_size); + VRFY((ret >= 0), "H5Pset_chunk succeeded"); + + ret = H5Pset_alloc_time(dcpl, H5D_ALLOC_TIME_LATE); + VRFY((ret >= 0), "H5Pset_alloc_time succeeded"); + + ret = H5Pset_fill_value(dcpl, H5T_NATIVE_DOUBLE, &fill); + VRFY((ret >= 0), "set fill-value succeeded"); + + max_size[0] = 100; + ret = H5Pset_external(dcpl, "ext1.data", (off_t)0, (hsize_t)(max_size[0] * sizeof(int) / 4)); + VRFY((ret >= 0), "set external succeeded"); + ret = H5Pset_external(dcpl, "ext2.data", (off_t)0, (hsize_t)(max_size[0] * sizeof(int) / 4)); + VRFY((ret >= 0), "set external succeeded"); + ret = H5Pset_external(dcpl, "ext3.data", (off_t)0, (hsize_t)(max_size[0] * sizeof(int) / 4)); + VRFY((ret >= 0), "set external succeeded"); + ret = H5Pset_external(dcpl, "ext4.data", (off_t)0, (hsize_t)(max_size[0] * sizeof(int) / 4)); + VRFY((ret >= 0), "set external succeeded"); + + ret = test_encode_decode(dcpl, mpi_rank, recv_proc); + VRFY((ret >= 0), "test_encode_decode succeeded"); + + ret = H5Pclose(dcpl); + VRFY((ret >= 0), "H5Pclose succeeded"); + + /******* ENCODE/DECODE DAPLS *****/ + dapl = H5Pcreate(H5P_DATASET_ACCESS); + VRFY((dapl >= 0), "H5Pcreate succeeded"); + + ret = H5Pset_chunk_cache(dapl, nslots, nbytes, w0); + VRFY((ret >= 0), "H5Pset_chunk_cache succeeded"); + + ret = test_encode_decode(dapl, mpi_rank, recv_proc); + VRFY((ret >= 0), "test_encode_decode succeeded"); + + ret = H5Pclose(dapl); + VRFY((ret >= 0), "H5Pclose succeeded"); + + /******* ENCODE/DECODE OCPLS *****/ + ocpl = H5Pcreate(H5P_OBJECT_CREATE); + VRFY((ocpl >= 0), "H5Pcreate succeeded"); + + ret = H5Pset_attr_creation_order(ocpl, (H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED)); + VRFY((ret >= 0), "H5Pset_attr_creation_order succeeded"); + + ret = H5Pset_attr_phase_change(ocpl, 110, 105); + VRFY((ret >= 0), "H5Pset_attr_phase_change succeeded"); + + ret = H5Pset_filter(ocpl, H5Z_FILTER_FLETCHER32, 0, (size_t)0, NULL); + VRFY((ret >= 0), "H5Pset_filter succeeded"); + + ret = test_encode_decode(ocpl, mpi_rank, recv_proc); + VRFY((ret >= 0), "test_encode_decode succeeded"); + + ret = H5Pclose(ocpl); + VRFY((ret >= 0), "H5Pclose succeeded"); + + /******* ENCODE/DECODE DXPLS *****/ + dxpl = H5Pcreate(H5P_DATASET_XFER); + VRFY((dxpl >= 0), "H5Pcreate succeeded"); + + ret = H5Pset_btree_ratios(dxpl, 0.2, 0.6, 0.2); + VRFY((ret >= 0), "H5Pset_btree_ratios succeeded"); + + ret = H5Pset_hyper_vector_size(dxpl, 5); + VRFY((ret >= 0), "H5Pset_hyper_vector_size succeeded"); + + ret = H5Pset_dxpl_mpio(dxpl, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + + ret = H5Pset_dxpl_mpio_collective_opt(dxpl, H5FD_MPIO_INDIVIDUAL_IO); + VRFY((ret >= 0), "H5Pset_dxpl_mpio_collective_opt succeeded"); + + ret = H5Pset_dxpl_mpio_chunk_opt(dxpl, H5FD_MPIO_CHUNK_MULTI_IO); + VRFY((ret >= 0), "H5Pset_dxpl_mpio_chunk_opt succeeded"); + + ret = H5Pset_dxpl_mpio_chunk_opt_ratio(dxpl, 30); + VRFY((ret >= 0), "H5Pset_dxpl_mpio_chunk_opt_ratio succeeded"); + + ret = H5Pset_dxpl_mpio_chunk_opt_num(dxpl, 40); + VRFY((ret >= 0), "H5Pset_dxpl_mpio_chunk_opt_num succeeded"); + + ret = H5Pset_edc_check(dxpl, H5Z_DISABLE_EDC); + VRFY((ret >= 0), "H5Pset_edc_check succeeded"); + + ret = H5Pset_data_transform(dxpl, c_to_f); + VRFY((ret >= 0), "H5Pset_data_transform succeeded"); + + ret = test_encode_decode(dxpl, mpi_rank, recv_proc); + VRFY((ret >= 0), "test_encode_decode succeeded"); + + ret = H5Pclose(dxpl); + VRFY((ret >= 0), "H5Pclose succeeded"); + + /******* ENCODE/DECODE GCPLS *****/ + gcpl = H5Pcreate(H5P_GROUP_CREATE); + VRFY((gcpl >= 0), "H5Pcreate succeeded"); + + ret = H5Pset_local_heap_size_hint(gcpl, 256); + VRFY((ret >= 0), "H5Pset_local_heap_size_hint succeeded"); + + ret = H5Pset_link_phase_change(gcpl, 2, 2); + VRFY((ret >= 0), "H5Pset_link_phase_change succeeded"); + + /* Query the group creation properties */ + ret = H5Pget_link_phase_change(gcpl, &max_compact, &min_dense); + VRFY((ret >= 0), "H5Pget_est_link_info succeeded"); + + ret = H5Pset_est_link_info(gcpl, 3, 9); + VRFY((ret >= 0), "H5Pset_est_link_info succeeded"); + + ret = H5Pset_link_creation_order(gcpl, (H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED)); + VRFY((ret >= 0), "H5Pset_link_creation_order succeeded"); + + ret = test_encode_decode(gcpl, mpi_rank, recv_proc); + VRFY((ret >= 0), "test_encode_decode succeeded"); + + ret = H5Pclose(gcpl); + VRFY((ret >= 0), "H5Pclose succeeded"); + + /******* ENCODE/DECODE LCPLS *****/ + lcpl = H5Pcreate(H5P_LINK_CREATE); + VRFY((lcpl >= 0), "H5Pcreate succeeded"); + + ret = H5Pset_create_intermediate_group(lcpl, TRUE); + VRFY((ret >= 0), "H5Pset_create_intermediate_group succeeded"); + + ret = test_encode_decode(lcpl, mpi_rank, recv_proc); + VRFY((ret >= 0), "test_encode_decode succeeded"); + + ret = H5Pclose(lcpl); + VRFY((ret >= 0), "H5Pclose succeeded"); + + /******* ENCODE/DECODE LAPLS *****/ + lapl = H5Pcreate(H5P_LINK_ACCESS); + VRFY((lapl >= 0), "H5Pcreate succeeded"); + + ret = H5Pset_nlinks(lapl, (size_t)134); + VRFY((ret >= 0), "H5Pset_nlinks succeeded"); + + ret = H5Pset_elink_acc_flags(lapl, H5F_ACC_RDONLY); + VRFY((ret >= 0), "H5Pset_elink_acc_flags succeeded"); + + ret = H5Pset_elink_prefix(lapl, "/tmpasodiasod"); + VRFY((ret >= 0), "H5Pset_nlinks succeeded"); + + /* Create FAPL for the elink FAPL */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + VRFY((fapl >= 0), "H5Pcreate succeeded"); + ret = H5Pset_alignment(fapl, 2, 1024); + VRFY((ret >= 0), "H5Pset_alignment succeeded"); + + ret = H5Pset_elink_fapl(lapl, fapl); + VRFY((ret >= 0), "H5Pset_elink_fapl succeeded"); + + /* Close the elink's FAPL */ + ret = H5Pclose(fapl); + VRFY((ret >= 0), "H5Pclose succeeded"); + + ret = test_encode_decode(lapl, mpi_rank, recv_proc); + VRFY((ret >= 0), "test_encode_decode succeeded"); + + ret = H5Pclose(lapl); + VRFY((ret >= 0), "H5Pclose succeeded"); + + /******* ENCODE/DECODE OCPYPLS *****/ + ocpypl = H5Pcreate(H5P_OBJECT_COPY); + VRFY((ocpypl >= 0), "H5Pcreate succeeded"); + + ret = H5Pset_copy_object(ocpypl, H5O_COPY_EXPAND_EXT_LINK_FLAG); + VRFY((ret >= 0), "H5Pset_copy_object succeeded"); + + ret = H5Padd_merge_committed_dtype_path(ocpypl, "foo"); + VRFY((ret >= 0), "H5Padd_merge_committed_dtype_path succeeded"); + + ret = H5Padd_merge_committed_dtype_path(ocpypl, "bar"); + VRFY((ret >= 0), "H5Padd_merge_committed_dtype_path succeeded"); + + ret = test_encode_decode(ocpypl, mpi_rank, recv_proc); + VRFY((ret >= 0), "test_encode_decode succeeded"); + + ret = H5Pclose(ocpypl); + VRFY((ret >= 0), "H5Pclose succeeded"); + + /******* ENCODE/DECODE FAPLS *****/ + fapl = H5Pcreate(H5P_FILE_ACCESS); + VRFY((fapl >= 0), "H5Pcreate succeeded"); + + ret = H5Pset_family_offset(fapl, 1024); + VRFY((ret >= 0), "H5Pset_family_offset succeeded"); + + ret = H5Pset_meta_block_size(fapl, 2098452); + VRFY((ret >= 0), "H5Pset_meta_block_size succeeded"); + + ret = H5Pset_sieve_buf_size(fapl, 1048576); + VRFY((ret >= 0), "H5Pset_sieve_buf_size succeeded"); + + ret = H5Pset_alignment(fapl, 2, 1024); + VRFY((ret >= 0), "H5Pset_alignment succeeded"); + + ret = H5Pset_cache(fapl, 1024, 128, 10485760, 0.3); + VRFY((ret >= 0), "H5Pset_cache succeeded"); + + ret = H5Pset_elink_file_cache_size(fapl, 10485760); + VRFY((ret >= 0), "H5Pset_elink_file_cache_size succeeded"); + + ret = H5Pset_gc_references(fapl, 1); + VRFY((ret >= 0), "H5Pset_gc_references succeeded"); + + ret = H5Pset_small_data_block_size(fapl, 2048); + VRFY((ret >= 0), "H5Pset_small_data_block_size succeeded"); + + ret = H5Pset_libver_bounds(fapl, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST); + VRFY((ret >= 0), "H5Pset_libver_bounds succeeded"); + + ret = H5Pset_fclose_degree(fapl, H5F_CLOSE_WEAK); + VRFY((ret >= 0), "H5Pset_fclose_degree succeeded"); + + ret = H5Pset_multi_type(fapl, H5FD_MEM_GHEAP); + VRFY((ret >= 0), "H5Pset_multi_type succeeded"); + + ret = H5Pset_mdc_config(fapl, &my_cache_config); + VRFY((ret >= 0), "H5Pset_mdc_config succeeded"); + + ret = test_encode_decode(fapl, mpi_rank, recv_proc); + VRFY((ret >= 0), "test_encode_decode succeeded"); + + ret = H5Pclose(fapl); + VRFY((ret >= 0), "H5Pclose succeeded"); + + /******* ENCODE/DECODE FCPLS *****/ + fcpl = H5Pcreate(H5P_FILE_CREATE); + VRFY((fcpl >= 0), "H5Pcreate succeeded"); + + ret = H5Pset_userblock(fcpl, 1024); + VRFY((ret >= 0), "H5Pset_userblock succeeded"); + + ret = H5Pset_istore_k(fcpl, 3); + VRFY((ret >= 0), "H5Pset_istore_k succeeded"); + + ret = H5Pset_sym_k(fcpl, 4, 5); + VRFY((ret >= 0), "H5Pset_sym_k succeeded"); + + ret = H5Pset_shared_mesg_nindexes(fcpl, 8); + VRFY((ret >= 0), "H5Pset_shared_mesg_nindexes succeeded"); + + ret = H5Pset_shared_mesg_index(fcpl, 1, H5O_SHMESG_SDSPACE_FLAG, 32); + VRFY((ret >= 0), "H5Pset_shared_mesg_index succeeded"); + + ret = H5Pset_shared_mesg_phase_change(fcpl, 60, 20); + VRFY((ret >= 0), "H5Pset_shared_mesg_phase_change succeeded"); + + ret = H5Pset_sizes(fcpl, 8, 4); + VRFY((ret >= 0), "H5Pset_sizes succeeded"); + + ret = test_encode_decode(fcpl, mpi_rank, recv_proc); + VRFY((ret >= 0), "test_encode_decode succeeded"); + + ret = H5Pclose(fcpl); + VRFY((ret >= 0), "H5Pclose succeeded"); + + /******* ENCODE/DECODE STRCPLS *****/ + strcpl = H5Pcreate(H5P_STRING_CREATE); + VRFY((strcpl >= 0), "H5Pcreate succeeded"); + + ret = H5Pset_char_encoding(strcpl, H5T_CSET_UTF8); + VRFY((ret >= 0), "H5Pset_char_encoding succeeded"); + + ret = test_encode_decode(strcpl, mpi_rank, recv_proc); + VRFY((ret >= 0), "test_encode_decode succeeded"); + + ret = H5Pclose(strcpl); + VRFY((ret >= 0), "H5Pclose succeeded"); + + /******* ENCODE/DECODE ACPLS *****/ + acpl = H5Pcreate(H5P_ATTRIBUTE_CREATE); + VRFY((acpl >= 0), "H5Pcreate succeeded"); + + ret = H5Pset_char_encoding(acpl, H5T_CSET_UTF8); + VRFY((ret >= 0), "H5Pset_char_encoding succeeded"); + + ret = test_encode_decode(acpl, mpi_rank, recv_proc); + VRFY((ret >= 0), "test_encode_decode succeeded"); + + ret = H5Pclose(acpl); + VRFY((ret >= 0), "H5Pclose succeeded"); +} + +#if 0 +void +external_links(void) +{ + hid_t lcpl = H5I_INVALID_HID; /* link create prop. list */ + hid_t lapl = H5I_INVALID_HID; /* link access prop. list */ + hid_t fapl = H5I_INVALID_HID; /* file access prop. list */ + hid_t gapl = H5I_INVALID_HID; /* group access prop. list */ + hid_t fid = H5I_INVALID_HID; /* file id */ + hid_t group = H5I_INVALID_HID; /* group id */ + int mpi_size, mpi_rank; + + MPI_Comm comm; + int doIO; + int i, mrc; + + herr_t ret; /* Generic return value */ + htri_t tri_status; /* tri return value */ + + const char *filename = "HDF5test.h5"; + const char *filename_ext = "HDF5test_ext.h5"; + const char *group_path = "/Base/Block/Step"; + const char *link_name = "link"; /* external link */ + char link_path[50]; + + if (VERBOSE_MED) + HDprintf("Check external links\n"); + + /* set up MPI parameters */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Check MPI communicator access properties are passed to + linked external files */ + + if (mpi_rank == 0) { + + lcpl = H5Pcreate(H5P_LINK_CREATE); + VRFY((lcpl >= 0), "H5Pcreate succeeded"); + + ret = H5Pset_create_intermediate_group(lcpl, 1); + VRFY((ret >= 0), "H5Pset_create_intermediate_group succeeded"); + + /* Create file to serve as target for external link.*/ + fid = H5Fcreate(filename_ext, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + VRFY((fid >= 0), "H5Fcreate succeeded"); + + group = H5Gcreate2(fid, group_path, lcpl, H5P_DEFAULT, H5P_DEFAULT); + VRFY((group >= 0), "H5Gcreate succeeded"); + + ret = H5Gclose(group); + VRFY((ret >= 0), "H5Gclose succeeded"); + + ret = H5Fclose(fid); + VRFY((ret >= 0), "H5Fclose succeeded"); + + fapl = H5Pcreate(H5P_FILE_ACCESS); + VRFY((fapl >= 0), "H5Pcreate succeeded"); + + /* Create a new file using the file access property list. */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + VRFY((fid >= 0), "H5Fcreate succeeded"); + + ret = H5Pclose(fapl); + VRFY((ret >= 0), "H5Pclose succeeded"); + + group = H5Gcreate2(fid, group_path, lcpl, H5P_DEFAULT, H5P_DEFAULT); + VRFY((group >= 0), "H5Gcreate succeeded"); + + /* Create external links to the target files. */ + ret = H5Lcreate_external(filename_ext, group_path, group, link_name, H5P_DEFAULT, H5P_DEFAULT); + VRFY((ret >= 0), "H5Lcreate_external succeeded"); + + /* Close and release resources. */ + ret = H5Pclose(lcpl); + VRFY((ret >= 0), "H5Pclose succeeded"); + ret = H5Gclose(group); + VRFY((ret >= 0), "H5Gclose succeeded"); + ret = H5Fclose(fid); + VRFY((ret >= 0), "H5Fclose succeeded"); + } + + MPI_Barrier(MPI_COMM_WORLD); + + /* + * For the first case, use all the processes. For the second case + * use a sub-communicator to verify the correct communicator is + * being used for the externally linked files. + * There is no way to determine if MPI info is being used for the + * externally linked files. + */ + + for (i = 0; i < 2; i++) { + + comm = MPI_COMM_WORLD; + + if (i == 0) + doIO = 1; + else { + doIO = mpi_rank % 2; + mrc = MPI_Comm_split(MPI_COMM_WORLD, doIO, mpi_rank, &comm); + VRFY((mrc == MPI_SUCCESS), ""); + } + + if (doIO) { + fapl = H5Pcreate(H5P_FILE_ACCESS); + VRFY((fapl >= 0), "H5Pcreate succeeded"); + ret = H5Pset_fapl_mpio(fapl, comm, MPI_INFO_NULL); + VRFY((fapl >= 0), "H5Pset_fapl_mpio succeeded"); + + fid = H5Fopen(filename, H5F_ACC_RDWR, fapl); + VRFY((fid >= 0), "H5Fopen succeeded"); + + /* test opening a group that is to an external link, the external linked + file should inherit the source file's access properties */ + HDsnprintf(link_path, sizeof(link_path), "%s%s%s", group_path, "/", link_name); + group = H5Gopen2(fid, link_path, H5P_DEFAULT); + VRFY((group >= 0), "H5Gopen succeeded"); + ret = H5Gclose(group); + VRFY((ret >= 0), "H5Gclose succeeded"); + + /* test opening a group that is external link by setting group + creation property */ + gapl = H5Pcreate(H5P_GROUP_ACCESS); + VRFY((gapl >= 0), "H5Pcreate succeeded"); + + ret = H5Pset_elink_fapl(gapl, fapl); + VRFY((ret >= 0), "H5Pset_elink_fapl succeeded"); + + group = H5Gopen2(fid, link_path, gapl); + VRFY((group >= 0), "H5Gopen succeeded"); + + ret = H5Gclose(group); + VRFY((ret >= 0), "H5Gclose succeeded"); + + ret = H5Pclose(gapl); + VRFY((ret >= 0), "H5Pclose succeeded"); + + /* test link APIs */ + lapl = H5Pcreate(H5P_LINK_ACCESS); + VRFY((lapl >= 0), "H5Pcreate succeeded"); + + ret = H5Pset_elink_fapl(lapl, fapl); + VRFY((ret >= 0), "H5Pset_elink_fapl succeeded"); + + tri_status = H5Lexists(fid, link_path, H5P_DEFAULT); + VRFY((tri_status == TRUE), "H5Lexists succeeded"); + + tri_status = H5Lexists(fid, link_path, lapl); + VRFY((tri_status == TRUE), "H5Lexists succeeded"); + + group = H5Oopen(fid, link_path, H5P_DEFAULT); + VRFY((group >= 0), "H5Oopen succeeded"); + + ret = H5Oclose(group); + VRFY((ret >= 0), "H5Oclose succeeded"); + + group = H5Oopen(fid, link_path, lapl); + VRFY((group >= 0), "H5Oopen succeeded"); + + ret = H5Oclose(group); + VRFY((ret >= 0), "H5Oclose succeeded"); + + ret = H5Pclose(lapl); + VRFY((ret >= 0), "H5Pclose succeeded"); + + /* close the remaining resources */ + + ret = H5Pclose(fapl); + VRFY((ret >= 0), "H5Pclose succeeded"); + + ret = H5Fclose(fid); + VRFY((ret >= 0), "H5Fclose succeeded"); + } + + if (comm != MPI_COMM_WORLD) { + mrc = MPI_Comm_free(&comm); + VRFY((mrc == MPI_SUCCESS), "MPI_Comm_free succeeded"); + } + } + + MPI_Barrier(MPI_COMM_WORLD); + + /* delete the test files */ + if (mpi_rank == 0) { + MPI_File_delete(filename, MPI_INFO_NULL); + MPI_File_delete(filename_ext, MPI_INFO_NULL); + } +} +#endif diff --git a/testpar/API/t_pshutdown.c b/testpar/API/t_pshutdown.c new file mode 100644 index 0000000..48a8005 --- /dev/null +++ b/testpar/API/t_pshutdown.c @@ -0,0 +1,150 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Programmer: Mohamad Chaarawi + * February 2015 + * + * Purpose: This test creates a file and a bunch of objects in the + * file and then calls MPI_Finalize without closing anything. The + * library should exercise the attribute callback destroy attached to + * MPI_COMM_SELF and terminate the HDF5 library closing all open + * objects. The t_prestart test will read back the file and make sure + * all created objects are there. + */ + +#include "hdf5.h" +#include "testphdf5.h" + +int nerrors = 0; /* errors count */ + +const char *FILENAME[] = {"shutdown.h5", NULL}; + +int +main(int argc, char **argv) +{ + hid_t file_id, dset_id, grp_id; + hid_t fapl, sid, mem_dataspace; + hsize_t dims[RANK], i; + herr_t ret; +#if 0 + char filename[1024]; +#endif + int mpi_size, mpi_rank; + MPI_Comm comm = MPI_COMM_WORLD; + MPI_Info info = MPI_INFO_NULL; + hsize_t start[RANK]; + hsize_t count[RANK]; + hsize_t stride[RANK]; + hsize_t block[RANK]; + DATATYPE *data_array = NULL; /* data buffer */ + + MPI_Init(&argc, &argv); + MPI_Comm_size(comm, &mpi_size); + MPI_Comm_rank(comm, &mpi_rank); + + if (MAINPROCESS) { + printf("Testing %-62s", "proper shutdown of HDF5 library"); + fflush(stdout); + } + + /* Set up file access property list with parallel I/O access */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + VRFY((fapl >= 0), "H5Pcreate succeeded"); + + /* Get the capability flag of the VOL connector being used */ + ret = H5Pget_vol_cap_flags(fapl, &vol_cap_flags_g); + VRFY((ret >= 0), "H5Pget_vol_cap_flags succeeded"); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_GROUP_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + if (MAINPROCESS) { + puts("SKIPPED"); + HDprintf( + " API functions for basic file, group, or dataset aren't supported with this connector\n"); + fflush(stdout); + } + + MPI_Finalize(); + return 0; + } + + ret = H5Pset_fapl_mpio(fapl, comm, info); + VRFY((ret >= 0), ""); + +#if 0 + h5_fixname(FILENAME[0], fapl, filename, sizeof filename); +#endif + file_id = H5Fcreate(FILENAME[0], H5F_ACC_TRUNC, H5P_DEFAULT, fapl); + VRFY((file_id >= 0), "H5Fcreate succeeded"); + grp_id = H5Gcreate2(file_id, "Group", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((grp_id >= 0), "H5Gcreate succeeded"); + + dims[0] = (hsize_t)ROW_FACTOR * (hsize_t)mpi_size; + dims[1] = (hsize_t)COL_FACTOR * (hsize_t)mpi_size; + sid = H5Screate_simple(RANK, dims, NULL); + VRFY((sid >= 0), "H5Screate_simple succeeded"); + + dset_id = H5Dcreate2(grp_id, "Dataset", H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + VRFY((dset_id >= 0), "H5Dcreate succeeded"); + + /* allocate memory for data buffer */ + data_array = (DATATYPE *)HDmalloc(dims[0] * dims[1] * sizeof(DATATYPE)); + VRFY((data_array != NULL), "data_array HDmalloc succeeded"); + + /* Each process takes a slabs of rows. */ + block[0] = dims[0] / (hsize_t)mpi_size; + block[1] = dims[1]; + stride[0] = block[0]; + stride[1] = block[1]; + count[0] = 1; + count[1] = 1; + start[0] = (hsize_t)mpi_rank * block[0]; + start[1] = 0; + + /* put some trivial data in the data_array */ + for (i = 0; i < dims[0] * dims[1]; i++) + data_array[i] = mpi_rank + 1; + + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sset_hyperslab succeeded"); + + /* create a memory dataspace independently */ + mem_dataspace = H5Screate_simple(RANK, block, NULL); + VRFY((mem_dataspace >= 0), ""); + + /* write data independently */ + ret = H5Dwrite(dset_id, H5T_NATIVE_INT, mem_dataspace, sid, H5P_DEFAULT, data_array); + VRFY((ret >= 0), "H5Dwrite succeeded"); + + /* release data buffers */ + if (data_array) + HDfree(data_array); + + MPI_Finalize(); + + /* nerrors += GetTestNumErrs(); */ + + if (MAINPROCESS) { + if (0 == nerrors) { + puts(" PASSED"); + fflush(stdout); + } + else { + puts("*FAILED*"); + fflush(stdout); + } + } + + return (nerrors != 0); +} diff --git a/testpar/API/t_shapesame.c b/testpar/API/t_shapesame.c new file mode 100644 index 0000000..340e89e --- /dev/null +++ b/testpar/API/t_shapesame.c @@ -0,0 +1,4516 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + This program will test independent and collective reads and writes between + selections of different rank that non-the-less are deemed as having the + same shape by H5Sselect_shape_same(). + */ + +#define H5S_FRIEND /*suppress error about including H5Spkg */ + +/* Define this macro to indicate that the testing APIs should be available */ +#define H5S_TESTING + +#if 0 +#include "H5Spkg.h" /* Dataspaces */ +#endif + +#include "hdf5.h" +#include "testphdf5.h" + +/* FILENAME and filenames must have the same number of names. + * Use PARATESTFILE in general and use a separated filename only if the file + * created in one test is accessed by a different test. + * filenames[0] is reserved as the file name for PARATESTFILE. + */ +#define NFILENAME 2 +const char *FILENAME[NFILENAME] = {"ShapeSameTest.h5", NULL}; +char filenames[NFILENAME][PATH_MAX]; +hid_t fapl; /* file access property list */ + +/* On Lustre (and perhaps other parallel file systems?), we have severe + * slow downs if two or more processes attempt to access the same file system + * block. To minimize this problem, we set alignment in the shape same tests + * to the default Lustre block size -- which greatly reduces contention in + * the chunked dataset case. + */ + +#define SHAPE_SAME_TEST_ALIGNMENT ((hsize_t)(4 * 1024 * 1024)) + +#define PAR_SS_DR_MAX_RANK 5 /* must update code if this changes */ + +struct hs_dr_pio_test_vars_t { + int mpi_size; + int mpi_rank; + MPI_Comm mpi_comm; + MPI_Info mpi_info; + int test_num; + int edge_size; + int checker_edge_size; + int chunk_edge_size; + int small_rank; + int large_rank; + hid_t dset_type; + uint32_t *small_ds_buf_0; + uint32_t *small_ds_buf_1; + uint32_t *small_ds_buf_2; + uint32_t *small_ds_slice_buf; + uint32_t *large_ds_buf_0; + uint32_t *large_ds_buf_1; + uint32_t *large_ds_buf_2; + uint32_t *large_ds_slice_buf; + int small_ds_offset; + int large_ds_offset; + hid_t fid; /* HDF5 file ID */ + hid_t xfer_plist; + hid_t full_mem_small_ds_sid; + hid_t full_file_small_ds_sid; + hid_t mem_small_ds_sid; + hid_t file_small_ds_sid_0; + hid_t file_small_ds_sid_1; + hid_t small_ds_slice_sid; + hid_t full_mem_large_ds_sid; + hid_t full_file_large_ds_sid; + hid_t mem_large_ds_sid; + hid_t file_large_ds_sid_0; + hid_t file_large_ds_sid_1; + hid_t file_large_ds_process_slice_sid; + hid_t mem_large_ds_process_slice_sid; + hid_t large_ds_slice_sid; + hid_t small_dataset; /* Dataset ID */ + hid_t large_dataset; /* Dataset ID */ + size_t small_ds_size; + size_t small_ds_slice_size; + size_t large_ds_size; + size_t large_ds_slice_size; + hsize_t dims[PAR_SS_DR_MAX_RANK]; + hsize_t chunk_dims[PAR_SS_DR_MAX_RANK]; + hsize_t start[PAR_SS_DR_MAX_RANK]; + hsize_t stride[PAR_SS_DR_MAX_RANK]; + hsize_t count[PAR_SS_DR_MAX_RANK]; + hsize_t block[PAR_SS_DR_MAX_RANK]; + hsize_t *start_ptr; + hsize_t *stride_ptr; + hsize_t *count_ptr; + hsize_t *block_ptr; + int skips; + int max_skips; + int64_t total_tests; + int64_t tests_run; + int64_t tests_skipped; +}; + +/*------------------------------------------------------------------------- + * Function: hs_dr_pio_test__setup() + * + * Purpose: Do setup for tests of I/O to/from hyperslab selections of + * different rank in the parallel case. + * + * Return: void + * + * Programmer: JRM -- 8/9/11 + * + *------------------------------------------------------------------------- + */ + +#define CONTIG_HS_DR_PIO_TEST__SETUP__DEBUG 0 + +static void +hs_dr_pio_test__setup(const int test_num, const int edge_size, const int checker_edge_size, + const int chunk_edge_size, const int small_rank, const int large_rank, + const hbool_t use_collective_io, const hid_t dset_type, const int express_test, + struct hs_dr_pio_test_vars_t *tv_ptr) +{ +#if CONTIG_HS_DR_PIO_TEST__SETUP__DEBUG + const char *fcnName = "hs_dr_pio_test__setup()"; +#endif /* CONTIG_HS_DR_PIO_TEST__SETUP__DEBUG */ + const char *filename; + hbool_t mis_match = FALSE; + int i; + int mrc; + int mpi_rank; /* needed by the VRFY macro */ + uint32_t expected_value; + uint32_t *ptr_0; + uint32_t *ptr_1; + hid_t acc_tpl; /* File access templates */ + hid_t small_ds_dcpl_id = H5P_DEFAULT; + hid_t large_ds_dcpl_id = H5P_DEFAULT; + herr_t ret; /* Generic return value */ + + HDassert(edge_size >= 6); + HDassert(edge_size >= chunk_edge_size); + HDassert((chunk_edge_size == 0) || (chunk_edge_size >= 3)); + HDassert(1 < small_rank); + HDassert(small_rank < large_rank); + HDassert(large_rank <= PAR_SS_DR_MAX_RANK); + + tv_ptr->test_num = test_num; + tv_ptr->edge_size = edge_size; + tv_ptr->checker_edge_size = checker_edge_size; + tv_ptr->chunk_edge_size = chunk_edge_size; + tv_ptr->small_rank = small_rank; + tv_ptr->large_rank = large_rank; + tv_ptr->dset_type = dset_type; + + MPI_Comm_size(MPI_COMM_WORLD, &(tv_ptr->mpi_size)); + MPI_Comm_rank(MPI_COMM_WORLD, &(tv_ptr->mpi_rank)); + /* the VRFY() macro needs the local variable mpi_rank -- set it up now */ + mpi_rank = tv_ptr->mpi_rank; + + HDassert(tv_ptr->mpi_size >= 1); + + tv_ptr->mpi_comm = MPI_COMM_WORLD; + tv_ptr->mpi_info = MPI_INFO_NULL; + + for (i = 0; i < tv_ptr->small_rank - 1; i++) { + tv_ptr->small_ds_size *= (size_t)(tv_ptr->edge_size); + tv_ptr->small_ds_slice_size *= (size_t)(tv_ptr->edge_size); + } + tv_ptr->small_ds_size *= (size_t)(tv_ptr->mpi_size + 1); + + /* used by checker board tests only */ + tv_ptr->small_ds_offset = PAR_SS_DR_MAX_RANK - tv_ptr->small_rank; + + HDassert(0 < tv_ptr->small_ds_offset); + HDassert(tv_ptr->small_ds_offset < PAR_SS_DR_MAX_RANK); + + for (i = 0; i < tv_ptr->large_rank - 1; i++) { + + tv_ptr->large_ds_size *= (size_t)(tv_ptr->edge_size); + tv_ptr->large_ds_slice_size *= (size_t)(tv_ptr->edge_size); + } + tv_ptr->large_ds_size *= (size_t)(tv_ptr->mpi_size + 1); + + /* used by checker board tests only */ + tv_ptr->large_ds_offset = PAR_SS_DR_MAX_RANK - tv_ptr->large_rank; + + HDassert(0 <= tv_ptr->large_ds_offset); + HDassert(tv_ptr->large_ds_offset < PAR_SS_DR_MAX_RANK); + + /* set up the start, stride, count, and block pointers */ + /* used by contiguous tests only */ + tv_ptr->start_ptr = &(tv_ptr->start[PAR_SS_DR_MAX_RANK - tv_ptr->large_rank]); + tv_ptr->stride_ptr = &(tv_ptr->stride[PAR_SS_DR_MAX_RANK - tv_ptr->large_rank]); + tv_ptr->count_ptr = &(tv_ptr->count[PAR_SS_DR_MAX_RANK - tv_ptr->large_rank]); + tv_ptr->block_ptr = &(tv_ptr->block[PAR_SS_DR_MAX_RANK - tv_ptr->large_rank]); + + /* Allocate buffers */ + tv_ptr->small_ds_buf_0 = (uint32_t *)HDmalloc(sizeof(uint32_t) * tv_ptr->small_ds_size); + VRFY((tv_ptr->small_ds_buf_0 != NULL), "malloc of small_ds_buf_0 succeeded"); + + tv_ptr->small_ds_buf_1 = (uint32_t *)HDmalloc(sizeof(uint32_t) * tv_ptr->small_ds_size); + VRFY((tv_ptr->small_ds_buf_1 != NULL), "malloc of small_ds_buf_1 succeeded"); + + tv_ptr->small_ds_buf_2 = (uint32_t *)HDmalloc(sizeof(uint32_t) * tv_ptr->small_ds_size); + VRFY((tv_ptr->small_ds_buf_2 != NULL), "malloc of small_ds_buf_2 succeeded"); + + tv_ptr->small_ds_slice_buf = (uint32_t *)HDmalloc(sizeof(uint32_t) * tv_ptr->small_ds_slice_size); + VRFY((tv_ptr->small_ds_slice_buf != NULL), "malloc of small_ds_slice_buf succeeded"); + + tv_ptr->large_ds_buf_0 = (uint32_t *)HDmalloc(sizeof(uint32_t) * tv_ptr->large_ds_size); + VRFY((tv_ptr->large_ds_buf_0 != NULL), "malloc of large_ds_buf_0 succeeded"); + + tv_ptr->large_ds_buf_1 = (uint32_t *)HDmalloc(sizeof(uint32_t) * tv_ptr->large_ds_size); + VRFY((tv_ptr->large_ds_buf_1 != NULL), "malloc of large_ds_buf_1 succeeded"); + + tv_ptr->large_ds_buf_2 = (uint32_t *)HDmalloc(sizeof(uint32_t) * tv_ptr->large_ds_size); + VRFY((tv_ptr->large_ds_buf_2 != NULL), "malloc of large_ds_buf_2 succeeded"); + + tv_ptr->large_ds_slice_buf = (uint32_t *)HDmalloc(sizeof(uint32_t) * tv_ptr->large_ds_slice_size); + VRFY((tv_ptr->large_ds_slice_buf != NULL), "malloc of large_ds_slice_buf succeeded"); + + /* initialize the buffers */ + + ptr_0 = tv_ptr->small_ds_buf_0; + for (i = 0; i < (int)(tv_ptr->small_ds_size); i++) + *ptr_0++ = (uint32_t)i; + HDmemset(tv_ptr->small_ds_buf_1, 0, sizeof(uint32_t) * tv_ptr->small_ds_size); + HDmemset(tv_ptr->small_ds_buf_2, 0, sizeof(uint32_t) * tv_ptr->small_ds_size); + + HDmemset(tv_ptr->small_ds_slice_buf, 0, sizeof(uint32_t) * tv_ptr->small_ds_slice_size); + + ptr_0 = tv_ptr->large_ds_buf_0; + for (i = 0; i < (int)(tv_ptr->large_ds_size); i++) + *ptr_0++ = (uint32_t)i; + HDmemset(tv_ptr->large_ds_buf_1, 0, sizeof(uint32_t) * tv_ptr->large_ds_size); + HDmemset(tv_ptr->large_ds_buf_2, 0, sizeof(uint32_t) * tv_ptr->large_ds_size); + + HDmemset(tv_ptr->large_ds_slice_buf, 0, sizeof(uint32_t) * tv_ptr->large_ds_slice_size); + + filename = filenames[0]; /* (const char *)GetTestParameters(); */ + HDassert(filename != NULL); +#if CONTIG_HS_DR_PIO_TEST__SETUP__DEBUG + if (MAINPROCESS) { + + HDfprintf(stdout, "%d: test num = %d.\n", tv_ptr->mpi_rank, tv_ptr->test_num); + HDfprintf(stdout, "%d: mpi_size = %d.\n", tv_ptr->mpi_rank, tv_ptr->mpi_size); + HDfprintf(stdout, "%d: small/large rank = %d/%d, use_collective_io = %d.\n", tv_ptr->mpi_rank, + tv_ptr->small_rank, tv_ptr->large_rank, (int)use_collective_io); + HDfprintf(stdout, "%d: edge_size = %d, chunk_edge_size = %d.\n", tv_ptr->mpi_rank, tv_ptr->edge_size, + tv_ptr->chunk_edge_size); + HDfprintf(stdout, "%d: checker_edge_size = %d.\n", tv_ptr->mpi_rank, tv_ptr->checker_edge_size); + HDfprintf(stdout, "%d: small_ds_size = %d, large_ds_size = %d.\n", tv_ptr->mpi_rank, + (int)(tv_ptr->small_ds_size), (int)(tv_ptr->large_ds_size)); + HDfprintf(stdout, "%d: filename = %s.\n", tv_ptr->mpi_rank, filename); + } +#endif /* CONTIG_HS_DR_PIO_TEST__SETUP__DEBUG */ + /* ---------------------------------------- + * CREATE AN HDF5 FILE WITH PARALLEL ACCESS + * ---------------------------------------*/ + /* setup file access template */ + acc_tpl = create_faccess_plist(tv_ptr->mpi_comm, tv_ptr->mpi_info, facc_type); + VRFY((acc_tpl >= 0), "create_faccess_plist() succeeded"); + + /* set the alignment -- need it large so that we aren't always hitting the + * the same file system block. Do this only if express_test is greater + * than zero. + */ + if (express_test > 0) { + + ret = H5Pset_alignment(acc_tpl, (hsize_t)0, SHAPE_SAME_TEST_ALIGNMENT); + VRFY((ret != FAIL), "H5Pset_alignment() succeeded"); + } + + /* create the file collectively */ + tv_ptr->fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, acc_tpl); + VRFY((tv_ptr->fid >= 0), "H5Fcreate succeeded"); + + MESG("File opened."); + + /* Release file-access template */ + ret = H5Pclose(acc_tpl); + VRFY((ret >= 0), "H5Pclose(acc_tpl) succeeded"); + + /* setup dims: */ + tv_ptr->dims[0] = (hsize_t)(tv_ptr->mpi_size + 1); + tv_ptr->dims[1] = tv_ptr->dims[2] = tv_ptr->dims[3] = tv_ptr->dims[4] = (hsize_t)(tv_ptr->edge_size); + + /* Create small ds dataspaces */ + tv_ptr->full_mem_small_ds_sid = H5Screate_simple(tv_ptr->small_rank, tv_ptr->dims, NULL); + VRFY((tv_ptr->full_mem_small_ds_sid != 0), "H5Screate_simple() full_mem_small_ds_sid succeeded"); + + tv_ptr->full_file_small_ds_sid = H5Screate_simple(tv_ptr->small_rank, tv_ptr->dims, NULL); + VRFY((tv_ptr->full_file_small_ds_sid != 0), "H5Screate_simple() full_file_small_ds_sid succeeded"); + + tv_ptr->mem_small_ds_sid = H5Screate_simple(tv_ptr->small_rank, tv_ptr->dims, NULL); + VRFY((tv_ptr->mem_small_ds_sid != 0), "H5Screate_simple() mem_small_ds_sid succeeded"); + + tv_ptr->file_small_ds_sid_0 = H5Screate_simple(tv_ptr->small_rank, tv_ptr->dims, NULL); + VRFY((tv_ptr->file_small_ds_sid_0 != 0), "H5Screate_simple() file_small_ds_sid_0 succeeded"); + + /* used by checker board tests only */ + tv_ptr->file_small_ds_sid_1 = H5Screate_simple(tv_ptr->small_rank, tv_ptr->dims, NULL); + VRFY((tv_ptr->file_small_ds_sid_1 != 0), "H5Screate_simple() file_small_ds_sid_1 succeeded"); + + tv_ptr->small_ds_slice_sid = H5Screate_simple(tv_ptr->small_rank - 1, &(tv_ptr->dims[1]), NULL); + VRFY((tv_ptr->small_ds_slice_sid != 0), "H5Screate_simple() small_ds_slice_sid succeeded"); + + /* Create large ds dataspaces */ + tv_ptr->full_mem_large_ds_sid = H5Screate_simple(tv_ptr->large_rank, tv_ptr->dims, NULL); + VRFY((tv_ptr->full_mem_large_ds_sid != 0), "H5Screate_simple() full_mem_large_ds_sid succeeded"); + + tv_ptr->full_file_large_ds_sid = H5Screate_simple(tv_ptr->large_rank, tv_ptr->dims, NULL); + VRFY((tv_ptr->full_file_large_ds_sid != FAIL), "H5Screate_simple() full_file_large_ds_sid succeeded"); + + tv_ptr->mem_large_ds_sid = H5Screate_simple(tv_ptr->large_rank, tv_ptr->dims, NULL); + VRFY((tv_ptr->mem_large_ds_sid != FAIL), "H5Screate_simple() mem_large_ds_sid succeeded"); + + tv_ptr->file_large_ds_sid_0 = H5Screate_simple(tv_ptr->large_rank, tv_ptr->dims, NULL); + VRFY((tv_ptr->file_large_ds_sid_0 != FAIL), "H5Screate_simple() file_large_ds_sid_0 succeeded"); + + /* used by checker board tests only */ + tv_ptr->file_large_ds_sid_1 = H5Screate_simple(tv_ptr->large_rank, tv_ptr->dims, NULL); + VRFY((tv_ptr->file_large_ds_sid_1 != FAIL), "H5Screate_simple() file_large_ds_sid_1 succeeded"); + + tv_ptr->mem_large_ds_process_slice_sid = H5Screate_simple(tv_ptr->large_rank, tv_ptr->dims, NULL); + VRFY((tv_ptr->mem_large_ds_process_slice_sid != FAIL), + "H5Screate_simple() mem_large_ds_process_slice_sid succeeded"); + + tv_ptr->file_large_ds_process_slice_sid = H5Screate_simple(tv_ptr->large_rank, tv_ptr->dims, NULL); + VRFY((tv_ptr->file_large_ds_process_slice_sid != FAIL), + "H5Screate_simple() file_large_ds_process_slice_sid succeeded"); + + tv_ptr->large_ds_slice_sid = H5Screate_simple(tv_ptr->large_rank - 1, &(tv_ptr->dims[1]), NULL); + VRFY((tv_ptr->large_ds_slice_sid != 0), "H5Screate_simple() large_ds_slice_sid succeeded"); + + /* if chunk edge size is greater than zero, set up the small and + * large data set creation property lists to specify chunked + * datasets. + */ + if (tv_ptr->chunk_edge_size > 0) { + + /* Under Lustre (and perhaps other parallel file systems?) we get + * locking delays when two or more processes attempt to access the + * same file system block. + * + * To minimize this problem, I have changed chunk_dims[0] + * from (mpi_size + 1) to just when any sort of express test is + * selected. Given the structure of the test, and assuming we + * set the alignment large enough, this avoids the contention + * issue by seeing to it that each chunk is only accessed by one + * process. + * + * One can argue as to whether this is a good thing to do in our + * tests, but for now it is necessary if we want the test to complete + * in a reasonable amount of time. + * + * JRM -- 9/16/10 + */ + + tv_ptr->chunk_dims[0] = 1; + + tv_ptr->chunk_dims[1] = tv_ptr->chunk_dims[2] = tv_ptr->chunk_dims[3] = tv_ptr->chunk_dims[4] = + (hsize_t)(tv_ptr->chunk_edge_size); + + small_ds_dcpl_id = H5Pcreate(H5P_DATASET_CREATE); + VRFY((ret != FAIL), "H5Pcreate() small_ds_dcpl_id succeeded"); + + ret = H5Pset_layout(small_ds_dcpl_id, H5D_CHUNKED); + VRFY((ret != FAIL), "H5Pset_layout() small_ds_dcpl_id succeeded"); + + ret = H5Pset_chunk(small_ds_dcpl_id, tv_ptr->small_rank, tv_ptr->chunk_dims); + VRFY((ret != FAIL), "H5Pset_chunk() small_ds_dcpl_id succeeded"); + + large_ds_dcpl_id = H5Pcreate(H5P_DATASET_CREATE); + VRFY((ret != FAIL), "H5Pcreate() large_ds_dcpl_id succeeded"); + + ret = H5Pset_layout(large_ds_dcpl_id, H5D_CHUNKED); + VRFY((ret != FAIL), "H5Pset_layout() large_ds_dcpl_id succeeded"); + + ret = H5Pset_chunk(large_ds_dcpl_id, tv_ptr->large_rank, tv_ptr->chunk_dims); + VRFY((ret != FAIL), "H5Pset_chunk() large_ds_dcpl_id succeeded"); + } + + /* create the small dataset */ + tv_ptr->small_dataset = + H5Dcreate2(tv_ptr->fid, "small_dataset", tv_ptr->dset_type, tv_ptr->file_small_ds_sid_0, H5P_DEFAULT, + small_ds_dcpl_id, H5P_DEFAULT); + VRFY((ret != FAIL), "H5Dcreate2() small_dataset succeeded"); + + /* create the large dataset */ + tv_ptr->large_dataset = + H5Dcreate2(tv_ptr->fid, "large_dataset", tv_ptr->dset_type, tv_ptr->file_large_ds_sid_0, H5P_DEFAULT, + large_ds_dcpl_id, H5P_DEFAULT); + VRFY((ret != FAIL), "H5Dcreate2() large_dataset succeeded"); + + /* setup xfer property list */ + tv_ptr->xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY((tv_ptr->xfer_plist >= 0), "H5Pcreate(H5P_DATASET_XFER) succeeded"); + + if (use_collective_io) { + ret = H5Pset_dxpl_mpio(tv_ptr->xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + } + + /* setup selection to write initial data to the small and large data sets */ + tv_ptr->start[0] = (hsize_t)(tv_ptr->mpi_rank); + tv_ptr->stride[0] = (hsize_t)(2 * (tv_ptr->mpi_size + 1)); + tv_ptr->count[0] = 1; + tv_ptr->block[0] = 1; + + for (i = 1; i < tv_ptr->large_rank; i++) { + + tv_ptr->start[i] = 0; + tv_ptr->stride[i] = (hsize_t)(2 * tv_ptr->edge_size); + tv_ptr->count[i] = 1; + tv_ptr->block[i] = (hsize_t)(tv_ptr->edge_size); + } + + /* setup selections for writing initial data to the small data set */ + ret = H5Sselect_hyperslab(tv_ptr->mem_small_ds_sid, H5S_SELECT_SET, tv_ptr->start, tv_ptr->stride, + tv_ptr->count, tv_ptr->block); + VRFY((ret >= 0), "H5Sselect_hyperslab(mem_small_ds_sid, set) succeeded"); + + ret = H5Sselect_hyperslab(tv_ptr->file_small_ds_sid_0, H5S_SELECT_SET, tv_ptr->start, tv_ptr->stride, + tv_ptr->count, tv_ptr->block); + VRFY((ret >= 0), "H5Sselect_hyperslab(file_small_ds_sid_0, set) succeeded"); + + if (MAINPROCESS) { /* add an additional slice to the selections */ + + tv_ptr->start[0] = (hsize_t)(tv_ptr->mpi_size); + + ret = H5Sselect_hyperslab(tv_ptr->mem_small_ds_sid, H5S_SELECT_OR, tv_ptr->start, tv_ptr->stride, + tv_ptr->count, tv_ptr->block); + VRFY((ret >= 0), "H5Sselect_hyperslab(mem_small_ds_sid, or) succeeded"); + + ret = H5Sselect_hyperslab(tv_ptr->file_small_ds_sid_0, H5S_SELECT_OR, tv_ptr->start, tv_ptr->stride, + tv_ptr->count, tv_ptr->block); + VRFY((ret >= 0), "H5Sselect_hyperslab(file_small_ds_sid_0, or) succeeded"); + } + + /* write the initial value of the small data set to file */ + ret = H5Dwrite(tv_ptr->small_dataset, tv_ptr->dset_type, tv_ptr->mem_small_ds_sid, + tv_ptr->file_small_ds_sid_0, tv_ptr->xfer_plist, tv_ptr->small_ds_buf_0); + + VRFY((ret >= 0), "H5Dwrite() small_dataset initial write succeeded"); + + /* sync with the other processes before checking data */ + mrc = MPI_Barrier(MPI_COMM_WORLD); + VRFY((mrc == MPI_SUCCESS), "Sync after small dataset writes"); + + /* read the small data set back to verify that it contains the + * expected data. Note that each process reads in the entire + * data set and verifies it. + */ + ret = H5Dread(tv_ptr->small_dataset, H5T_NATIVE_UINT32, tv_ptr->full_mem_small_ds_sid, + tv_ptr->full_file_small_ds_sid, tv_ptr->xfer_plist, tv_ptr->small_ds_buf_1); + VRFY((ret >= 0), "H5Dread() small_dataset initial read succeeded"); + + /* verify that the correct data was written to the small data set */ + expected_value = 0; + mis_match = FALSE; + ptr_1 = tv_ptr->small_ds_buf_1; + + i = 0; + for (i = 0; i < (int)(tv_ptr->small_ds_size); i++) { + + if (*ptr_1 != expected_value) { + + mis_match = TRUE; + } + ptr_1++; + expected_value++; + } + VRFY((mis_match == FALSE), "small ds init data good."); + + /* setup selections for writing initial data to the large data set */ + + tv_ptr->start[0] = (hsize_t)(tv_ptr->mpi_rank); + + ret = H5Sselect_hyperslab(tv_ptr->mem_large_ds_sid, H5S_SELECT_SET, tv_ptr->start, tv_ptr->stride, + tv_ptr->count, tv_ptr->block); + VRFY((ret >= 0), "H5Sselect_hyperslab(mem_large_ds_sid, set) succeeded"); + + ret = H5Sselect_hyperslab(tv_ptr->file_large_ds_sid_0, H5S_SELECT_SET, tv_ptr->start, tv_ptr->stride, + tv_ptr->count, tv_ptr->block); + VRFY((ret >= 0), "H5Sselect_hyperslab(file_large_ds_sid_0, set) succeeded"); + + /* In passing, setup the process slice dataspaces as well */ + + ret = H5Sselect_hyperslab(tv_ptr->mem_large_ds_process_slice_sid, H5S_SELECT_SET, tv_ptr->start, + tv_ptr->stride, tv_ptr->count, tv_ptr->block); + VRFY((ret >= 0), "H5Sselect_hyperslab(mem_large_ds_process_slice_sid, set) succeeded"); + + ret = H5Sselect_hyperslab(tv_ptr->file_large_ds_process_slice_sid, H5S_SELECT_SET, tv_ptr->start, + tv_ptr->stride, tv_ptr->count, tv_ptr->block); + VRFY((ret >= 0), "H5Sselect_hyperslab(file_large_ds_process_slice_sid, set) succeeded"); + + if (MAINPROCESS) { /* add an additional slice to the selections */ + + tv_ptr->start[0] = (hsize_t)(tv_ptr->mpi_size); + + ret = H5Sselect_hyperslab(tv_ptr->mem_large_ds_sid, H5S_SELECT_OR, tv_ptr->start, tv_ptr->stride, + tv_ptr->count, tv_ptr->block); + VRFY((ret >= 0), "H5Sselect_hyperslab(mem_large_ds_sid, or) succeeded"); + + ret = H5Sselect_hyperslab(tv_ptr->file_large_ds_sid_0, H5S_SELECT_OR, tv_ptr->start, tv_ptr->stride, + tv_ptr->count, tv_ptr->block); + VRFY((ret >= 0), "H5Sselect_hyperslab(file_large_ds_sid_0, or) succeeded"); + } + + /* write the initial value of the large data set to file */ + ret = H5Dwrite(tv_ptr->large_dataset, tv_ptr->dset_type, tv_ptr->mem_large_ds_sid, + tv_ptr->file_large_ds_sid_0, tv_ptr->xfer_plist, tv_ptr->large_ds_buf_0); + if (ret < 0) + H5Eprint2(H5E_DEFAULT, stderr); + VRFY((ret >= 0), "H5Dwrite() large_dataset initial write succeeded"); + + /* sync with the other processes before checking data */ + mrc = MPI_Barrier(MPI_COMM_WORLD); + VRFY((mrc == MPI_SUCCESS), "Sync after large dataset writes"); + + /* read the large data set back to verify that it contains the + * expected data. Note that each process reads in the entire + * data set. + */ + ret = H5Dread(tv_ptr->large_dataset, H5T_NATIVE_UINT32, tv_ptr->full_mem_large_ds_sid, + tv_ptr->full_file_large_ds_sid, tv_ptr->xfer_plist, tv_ptr->large_ds_buf_1); + VRFY((ret >= 0), "H5Dread() large_dataset initial read succeeded"); + + /* verify that the correct data was written to the large data set */ + expected_value = 0; + mis_match = FALSE; + ptr_1 = tv_ptr->large_ds_buf_1; + + i = 0; + for (i = 0; i < (int)(tv_ptr->large_ds_size); i++) { + + if (*ptr_1 != expected_value) { + + mis_match = TRUE; + } + ptr_1++; + expected_value++; + } + VRFY((mis_match == FALSE), "large ds init data good."); + + /* sync with the other processes before changing data */ + mrc = MPI_Barrier(MPI_COMM_WORLD); + VRFY((mrc == MPI_SUCCESS), "Sync initial values check"); + + return; + +} /* hs_dr_pio_test__setup() */ + +/*------------------------------------------------------------------------- + * Function: hs_dr_pio_test__takedown() + * + * Purpose: Do takedown after tests of I/O to/from hyperslab selections + * of different rank in the parallel case. + * + * Return: void + * + * Programmer: JRM -- 9/18/09 + * + *------------------------------------------------------------------------- + */ + +#define HS_DR_PIO_TEST__TAKEDOWN__DEBUG 0 + +static void +hs_dr_pio_test__takedown(struct hs_dr_pio_test_vars_t *tv_ptr) +{ +#if HS_DR_PIO_TEST__TAKEDOWN__DEBUG + const char *fcnName = "hs_dr_pio_test__takedown()"; +#endif /* HS_DR_PIO_TEST__TAKEDOWN__DEBUG */ + int mpi_rank; /* needed by the VRFY macro */ + herr_t ret; /* Generic return value */ + + /* initialize the local copy of mpi_rank */ + mpi_rank = tv_ptr->mpi_rank; + + /* Close property lists */ + if (tv_ptr->xfer_plist != H5P_DEFAULT) { + ret = H5Pclose(tv_ptr->xfer_plist); + VRFY((ret != FAIL), "H5Pclose(xfer_plist) succeeded"); + } + + /* Close dataspaces */ + ret = H5Sclose(tv_ptr->full_mem_small_ds_sid); + VRFY((ret != FAIL), "H5Sclose(full_mem_small_ds_sid) succeeded"); + + ret = H5Sclose(tv_ptr->full_file_small_ds_sid); + VRFY((ret != FAIL), "H5Sclose(full_file_small_ds_sid) succeeded"); + + ret = H5Sclose(tv_ptr->mem_small_ds_sid); + VRFY((ret != FAIL), "H5Sclose(mem_small_ds_sid) succeeded"); + + ret = H5Sclose(tv_ptr->file_small_ds_sid_0); + VRFY((ret != FAIL), "H5Sclose(file_small_ds_sid_0) succeeded"); + + ret = H5Sclose(tv_ptr->file_small_ds_sid_1); + VRFY((ret != FAIL), "H5Sclose(file_small_ds_sid_1) succeeded"); + + ret = H5Sclose(tv_ptr->small_ds_slice_sid); + VRFY((ret != FAIL), "H5Sclose(small_ds_slice_sid) succeeded"); + + ret = H5Sclose(tv_ptr->full_mem_large_ds_sid); + VRFY((ret != FAIL), "H5Sclose(full_mem_large_ds_sid) succeeded"); + + ret = H5Sclose(tv_ptr->full_file_large_ds_sid); + VRFY((ret != FAIL), "H5Sclose(full_file_large_ds_sid) succeeded"); + + ret = H5Sclose(tv_ptr->mem_large_ds_sid); + VRFY((ret != FAIL), "H5Sclose(mem_large_ds_sid) succeeded"); + + ret = H5Sclose(tv_ptr->file_large_ds_sid_0); + VRFY((ret != FAIL), "H5Sclose(file_large_ds_sid_0) succeeded"); + + ret = H5Sclose(tv_ptr->file_large_ds_sid_1); + VRFY((ret != FAIL), "H5Sclose(file_large_ds_sid_1) succeeded"); + + ret = H5Sclose(tv_ptr->mem_large_ds_process_slice_sid); + VRFY((ret != FAIL), "H5Sclose(mem_large_ds_process_slice_sid) succeeded"); + + ret = H5Sclose(tv_ptr->file_large_ds_process_slice_sid); + VRFY((ret != FAIL), "H5Sclose(file_large_ds_process_slice_sid) succeeded"); + + ret = H5Sclose(tv_ptr->large_ds_slice_sid); + VRFY((ret != FAIL), "H5Sclose(large_ds_slice_sid) succeeded"); + + /* Close Datasets */ + ret = H5Dclose(tv_ptr->small_dataset); + VRFY((ret != FAIL), "H5Dclose(small_dataset) succeeded"); + + ret = H5Dclose(tv_ptr->large_dataset); + VRFY((ret != FAIL), "H5Dclose(large_dataset) succeeded"); + + /* close the file collectively */ + MESG("about to close file."); + ret = H5Fclose(tv_ptr->fid); + VRFY((ret != FAIL), "file close succeeded"); + + /* Free memory buffers */ + + if (tv_ptr->small_ds_buf_0 != NULL) + HDfree(tv_ptr->small_ds_buf_0); + if (tv_ptr->small_ds_buf_1 != NULL) + HDfree(tv_ptr->small_ds_buf_1); + if (tv_ptr->small_ds_buf_2 != NULL) + HDfree(tv_ptr->small_ds_buf_2); + if (tv_ptr->small_ds_slice_buf != NULL) + HDfree(tv_ptr->small_ds_slice_buf); + + if (tv_ptr->large_ds_buf_0 != NULL) + HDfree(tv_ptr->large_ds_buf_0); + if (tv_ptr->large_ds_buf_1 != NULL) + HDfree(tv_ptr->large_ds_buf_1); + if (tv_ptr->large_ds_buf_2 != NULL) + HDfree(tv_ptr->large_ds_buf_2); + if (tv_ptr->large_ds_slice_buf != NULL) + HDfree(tv_ptr->large_ds_slice_buf); + + return; + +} /* hs_dr_pio_test__takedown() */ + +/*------------------------------------------------------------------------- + * Function: contig_hs_dr_pio_test__d2m_l2s() + * + * Purpose: Part one of a series of tests of I/O to/from hyperslab + * selections of different rank in the parallel. + * + * Verify that we can read from disk correctly using + * selections of different rank that H5Sselect_shape_same() + * views as being of the same shape. + * + * In this function, we test this by reading small_rank - 1 + * slices from the on disk large cube, and verifying that the + * data read is correct. Verify that H5Sselect_shape_same() + * returns true on the memory and file selections. + * + * Return: void + * + * Programmer: JRM -- 9/10/11 + * + *------------------------------------------------------------------------- + */ + +#define CONTIG_HS_DR_PIO_TEST__D2M_L2S__DEBUG 0 + +static void +contig_hs_dr_pio_test__d2m_l2s(struct hs_dr_pio_test_vars_t *tv_ptr) +{ +#if CONTIG_HS_DR_PIO_TEST__D2M_L2S__DEBUG + const char *fcnName = "contig_hs_dr_pio_test__run_test()"; +#endif /* CONTIG_HS_DR_PIO_TEST__D2M_L2S__DEBUG */ + hbool_t mis_match = FALSE; + int i, j, k, l; + size_t n; + int mpi_rank; /* needed by the VRFY macro */ + uint32_t expected_value; + uint32_t *ptr_1; + htri_t check; /* Shape comparison return value */ + herr_t ret; /* Generic return value */ + + /* initialize the local copy of mpi_rank */ + mpi_rank = tv_ptr->mpi_rank; + + /* We have already done a H5Sselect_all() on the dataspace + * small_ds_slice_sid in the initialization phase, so no need to + * call H5Sselect_all() again. + */ + + /* set up start, stride, count, and block -- note that we will + * change start[] so as to read slices of the large cube. + */ + for (i = 0; i < PAR_SS_DR_MAX_RANK; i++) { + + tv_ptr->start[i] = 0; + tv_ptr->stride[i] = (hsize_t)(2 * tv_ptr->edge_size); + tv_ptr->count[i] = 1; + if ((PAR_SS_DR_MAX_RANK - i) > (tv_ptr->small_rank - 1)) { + + tv_ptr->block[i] = 1; + } + else { + + tv_ptr->block[i] = (hsize_t)(tv_ptr->edge_size); + } + } + + /* zero out the buffer we will be reading into */ + HDmemset(tv_ptr->small_ds_slice_buf, 0, sizeof(uint32_t) * tv_ptr->small_ds_slice_size); + +#if CONTIG_HS_DR_PIO_TEST__D2M_L2S__DEBUG + HDfprintf(stdout, "%s reading slices from big cube on disk into small cube slice.\n", fcnName); +#endif /* CONTIG_HS_DR_PIO_TEST__D2M_L2S__DEBUG */ + + /* in serial versions of this test, we loop through all the dimensions + * of the large data set. However, in the parallel version, each + * process only works with that slice of the large cube indicated + * by its rank -- hence we set the most slowly changing index to + * mpi_rank, and don't iterate over it. + */ + + if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 0) { + + i = tv_ptr->mpi_rank; + } + else { + + i = 0; + } + + /* since large_rank is at most PAR_SS_DR_MAX_RANK, no need to + * loop over it -- either we are setting i to mpi_rank, or + * we are setting it to zero. It will not change during the + * test. + */ + + if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 1) { + + j = tv_ptr->mpi_rank; + } + else { + + j = 0; + } + + do { + if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 2) { + + k = tv_ptr->mpi_rank; + } + else { + + k = 0; + } + + do { + /* since small rank >= 2 and large_rank > small_rank, we + * have large_rank >= 3. Since PAR_SS_DR_MAX_RANK == 5 + * (baring major re-orgaization), this gives us: + * + * (PAR_SS_DR_MAX_RANK - large_rank) <= 2 + * + * so no need to repeat the test in the outer loops -- + * just set l = 0. + */ + + l = 0; + do { + if ((tv_ptr->skips)++ < tv_ptr->max_skips) { /* skip the test */ + + (tv_ptr->tests_skipped)++; + } + else { /* run the test */ + + tv_ptr->skips = 0; /* reset the skips counter */ + + /* we know that small_rank - 1 >= 1 and that + * large_rank > small_rank by the assertions at the head + * of this function. Thus no need for another inner loop. + */ + tv_ptr->start[0] = (hsize_t)i; + tv_ptr->start[1] = (hsize_t)j; + tv_ptr->start[2] = (hsize_t)k; + tv_ptr->start[3] = (hsize_t)l; + tv_ptr->start[4] = 0; + + ret = H5Sselect_hyperslab(tv_ptr->file_large_ds_sid_0, H5S_SELECT_SET, tv_ptr->start_ptr, + tv_ptr->stride_ptr, tv_ptr->count_ptr, tv_ptr->block_ptr); + VRFY((ret != FAIL), "H5Sselect_hyperslab(file_large_cube_sid) succeeded"); + + /* verify that H5Sselect_shape_same() reports the two + * selections as having the same shape. + */ + check = H5Sselect_shape_same(tv_ptr->small_ds_slice_sid, tv_ptr->file_large_ds_sid_0); + VRFY((check == TRUE), "H5Sselect_shape_same passed"); + + /* Read selection from disk */ +#if CONTIG_HS_DR_PIO_TEST__D2M_L2S__DEBUG + HDfprintf(stdout, "%s:%d: start = %d %d %d %d %d.\n", fcnName, (int)(tv_ptr->mpi_rank), + (int)(tv_ptr->start[0]), (int)(tv_ptr->start[1]), (int)(tv_ptr->start[2]), + (int)(tv_ptr->start[3]), (int)(tv_ptr->start[4])); + HDfprintf(stdout, "%s slice/file extent dims = %d/%d.\n", fcnName, + H5Sget_simple_extent_ndims(tv_ptr->small_ds_slice_sid), + H5Sget_simple_extent_ndims(tv_ptr->file_large_ds_sid_0)); +#endif /* CONTIG_HS_DR_PIO_TEST__D2M_L2S__DEBUG */ + ret = + H5Dread(tv_ptr->large_dataset, H5T_NATIVE_UINT32, tv_ptr->small_ds_slice_sid, + tv_ptr->file_large_ds_sid_0, tv_ptr->xfer_plist, tv_ptr->small_ds_slice_buf); + VRFY((ret >= 0), "H5Dread() slice from large ds succeeded."); + + /* verify that expected data is retrieved */ + + mis_match = FALSE; + ptr_1 = tv_ptr->small_ds_slice_buf; + expected_value = + (uint32_t)((i * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size * + tv_ptr->edge_size) + + (j * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size) + + (k * tv_ptr->edge_size * tv_ptr->edge_size) + (l * tv_ptr->edge_size)); + + for (n = 0; n < tv_ptr->small_ds_slice_size; n++) { + + if (*ptr_1 != expected_value) { + + mis_match = TRUE; + } + + *ptr_1 = 0; /* zero data for next use */ + + ptr_1++; + expected_value++; + } + + VRFY((mis_match == FALSE), "small slice read from large ds data good."); + + (tv_ptr->tests_run)++; + } + + l++; + + (tv_ptr->total_tests)++; + + } while ((tv_ptr->large_rank > 2) && ((tv_ptr->small_rank - 1) <= 1) && (l < tv_ptr->edge_size)); + k++; + } while ((tv_ptr->large_rank > 3) && ((tv_ptr->small_rank - 1) <= 2) && (k < tv_ptr->edge_size)); + j++; + } while ((tv_ptr->large_rank > 4) && ((tv_ptr->small_rank - 1) <= 3) && (j < tv_ptr->edge_size)); + + return; + +} /* contig_hs_dr_pio_test__d2m_l2s() */ + +/*------------------------------------------------------------------------- + * Function: contig_hs_dr_pio_test__d2m_s2l() + * + * Purpose: Part two of a series of tests of I/O to/from hyperslab + * selections of different rank in the parallel. + * + * Verify that we can read from disk correctly using + * selections of different rank that H5Sselect_shape_same() + * views as being of the same shape. + * + * In this function, we test this by reading slices of the + * on disk small data set into slices through the in memory + * large data set, and verify that the correct data (and + * only the correct data) is read. + * + * Return: void + * + * Programmer: JRM -- 8/10/11 + * + *------------------------------------------------------------------------- + */ + +#define CONTIG_HS_DR_PIO_TEST__D2M_S2L__DEBUG 0 + +static void +contig_hs_dr_pio_test__d2m_s2l(struct hs_dr_pio_test_vars_t *tv_ptr) +{ +#if CONTIG_HS_DR_PIO_TEST__D2M_S2L__DEBUG + const char *fcnName = "contig_hs_dr_pio_test__d2m_s2l()"; +#endif /* CONTIG_HS_DR_PIO_TEST__D2M_S2L__DEBUG */ + hbool_t mis_match = FALSE; + int i, j, k, l; + size_t n; + int mpi_rank; /* needed by the VRFY macro */ + size_t start_index; + size_t stop_index; + uint32_t expected_value; + uint32_t *ptr_1; + htri_t check; /* Shape comparison return value */ + herr_t ret; /* Generic return value */ + + /* initialize the local copy of mpi_rank */ + mpi_rank = tv_ptr->mpi_rank; + + /* Read slices of the on disk small data set into slices + * through the in memory large data set, and verify that the correct + * data (and only the correct data) is read. + */ + + tv_ptr->start[0] = (hsize_t)(tv_ptr->mpi_rank); + tv_ptr->stride[0] = (hsize_t)(2 * (tv_ptr->mpi_size + 1)); + tv_ptr->count[0] = 1; + tv_ptr->block[0] = 1; + + for (i = 1; i < tv_ptr->large_rank; i++) { + + tv_ptr->start[i] = 0; + tv_ptr->stride[i] = (hsize_t)(2 * tv_ptr->edge_size); + tv_ptr->count[i] = 1; + tv_ptr->block[i] = (hsize_t)(tv_ptr->edge_size); + } + + ret = H5Sselect_hyperslab(tv_ptr->file_small_ds_sid_0, H5S_SELECT_SET, tv_ptr->start, tv_ptr->stride, + tv_ptr->count, tv_ptr->block); + VRFY((ret >= 0), "H5Sselect_hyperslab(file_small_ds_sid_0, set) succeeded"); + +#if CONTIG_HS_DR_PIO_TEST__D2M_S2L__DEBUG + HDfprintf(stdout, "%s reading slices of on disk small data set into slices of big data set.\n", fcnName); +#endif /* CONTIG_HS_DR_PIO_TEST__D2M_S2L__DEBUG */ + + /* zero out the in memory large ds */ + HDmemset(tv_ptr->large_ds_buf_1, 0, sizeof(uint32_t) * tv_ptr->large_ds_size); + + /* set up start, stride, count, and block -- note that we will + * change start[] so as to read slices of the large cube. + */ + for (i = 0; i < PAR_SS_DR_MAX_RANK; i++) { + + tv_ptr->start[i] = 0; + tv_ptr->stride[i] = (hsize_t)(2 * tv_ptr->edge_size); + tv_ptr->count[i] = 1; + if ((PAR_SS_DR_MAX_RANK - i) > (tv_ptr->small_rank - 1)) { + + tv_ptr->block[i] = 1; + } + else { + + tv_ptr->block[i] = (hsize_t)(tv_ptr->edge_size); + } + } + + /* in serial versions of this test, we loop through all the dimensions + * of the large data set that don't appear in the small data set. + * + * However, in the parallel version, each process only works with that + * slice of the large (and small) data set indicated by its rank -- hence + * we set the most slowly changing index to mpi_rank, and don't iterate + * over it. + */ + + if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 0) { + + i = tv_ptr->mpi_rank; + } + else { + + i = 0; + } + + /* since large_rank is at most PAR_SS_DR_MAX_RANK, no need to + * loop over it -- either we are setting i to mpi_rank, or + * we are setting it to zero. It will not change during the + * test. + */ + + if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 1) { + + j = tv_ptr->mpi_rank; + } + else { + + j = 0; + } + + do { + if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 2) { + + k = tv_ptr->mpi_rank; + } + else { + + k = 0; + } + + do { + /* since small rank >= 2 and large_rank > small_rank, we + * have large_rank >= 3. Since PAR_SS_DR_MAX_RANK == 5 + * (baring major re-orgaization), this gives us: + * + * (PAR_SS_DR_MAX_RANK - large_rank) <= 2 + * + * so no need to repeat the test in the outer loops -- + * just set l = 0. + */ + + l = 0; + do { + if ((tv_ptr->skips)++ < tv_ptr->max_skips) { /* skip the test */ + + (tv_ptr->tests_skipped)++; + } + else { /* run the test */ + + tv_ptr->skips = 0; /* reset the skips counter */ + + /* we know that small_rank >= 1 and that large_rank > small_rank + * by the assertions at the head of this function. Thus no + * need for another inner loop. + */ + tv_ptr->start[0] = (hsize_t)i; + tv_ptr->start[1] = (hsize_t)j; + tv_ptr->start[2] = (hsize_t)k; + tv_ptr->start[3] = (hsize_t)l; + tv_ptr->start[4] = 0; + + ret = H5Sselect_hyperslab(tv_ptr->mem_large_ds_sid, H5S_SELECT_SET, tv_ptr->start_ptr, + tv_ptr->stride_ptr, tv_ptr->count_ptr, tv_ptr->block_ptr); + VRFY((ret != FAIL), "H5Sselect_hyperslab(mem_large_ds_sid) succeeded"); + + /* verify that H5Sselect_shape_same() reports the two + * selections as having the same shape. + */ + check = H5Sselect_shape_same(tv_ptr->file_small_ds_sid_0, tv_ptr->mem_large_ds_sid); + VRFY((check == TRUE), "H5Sselect_shape_same passed"); + + /* Read selection from disk */ +#if CONTIG_HS_DR_PIO_TEST__D2M_S2L__DEBUG + HDfprintf(stdout, "%s:%d: start = %d %d %d %d %d.\n", fcnName, (int)(tv_ptr->mpi_rank), + (int)(tv_ptr->start[0]), (int)(tv_ptr->start[1]), (int)(tv_ptr->start[2]), + (int)(tv_ptr->start[3]), (int)(tv_ptr->start[4])); + HDfprintf(stdout, "%s:%d: mem/file extent dims = %d/%d.\n", fcnName, tv_ptr->mpi_rank, + H5Sget_simple_extent_ndims(tv_ptr->mem_large_ds_sid), + H5Sget_simple_extent_ndims(tv_ptr->file_small_ds_sid_0)); +#endif /* CONTIG_HS_DR_PIO_TEST__D2M_S2L__DEBUG */ + ret = H5Dread(tv_ptr->small_dataset, H5T_NATIVE_UINT32, tv_ptr->mem_large_ds_sid, + tv_ptr->file_small_ds_sid_0, tv_ptr->xfer_plist, tv_ptr->large_ds_buf_1); + VRFY((ret >= 0), "H5Dread() slice from small ds succeeded."); + + /* verify that the expected data and only the + * expected data was read. + */ + ptr_1 = tv_ptr->large_ds_buf_1; + expected_value = (uint32_t)((size_t)(tv_ptr->mpi_rank) * tv_ptr->small_ds_slice_size); + start_index = + (size_t)((i * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size * + tv_ptr->edge_size) + + (j * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size) + + (k * tv_ptr->edge_size * tv_ptr->edge_size) + (l * tv_ptr->edge_size)); + stop_index = start_index + tv_ptr->small_ds_slice_size - 1; + + HDassert(start_index < stop_index); + HDassert(stop_index <= tv_ptr->large_ds_size); + + for (n = 0; n < tv_ptr->large_ds_size; n++) { + + if ((n >= start_index) && (n <= stop_index)) { + + if (*ptr_1 != expected_value) { + + mis_match = TRUE; + } + expected_value++; + } + else { + + if (*ptr_1 != 0) { + + mis_match = TRUE; + } + } + /* zero out the value for the next pass */ + *ptr_1 = 0; + + ptr_1++; + } + + VRFY((mis_match == FALSE), "small slice read from large ds data good."); + + (tv_ptr->tests_run)++; + } + + l++; + + (tv_ptr->total_tests)++; + + } while ((tv_ptr->large_rank > 2) && ((tv_ptr->small_rank - 1) <= 1) && (l < tv_ptr->edge_size)); + k++; + } while ((tv_ptr->large_rank > 3) && ((tv_ptr->small_rank - 1) <= 2) && (k < tv_ptr->edge_size)); + j++; + } while ((tv_ptr->large_rank > 4) && ((tv_ptr->small_rank - 1) <= 3) && (j < tv_ptr->edge_size)); + + return; + +} /* contig_hs_dr_pio_test__d2m_s2l() */ + +/*------------------------------------------------------------------------- + * Function: contig_hs_dr_pio_test__m2d_l2s() + * + * Purpose: Part three of a series of tests of I/O to/from hyperslab + * selections of different rank in the parallel. + * + * Verify that we can write from memory to file using + * selections of different rank that H5Sselect_shape_same() + * views as being of the same shape. + * + * Do this by writing small_rank - 1 dimensional slices from + * the in memory large data set to the on disk small cube + * dataset. After each write, read the slice of the small + * dataset back from disk, and verify that it contains + * the expected data. Verify that H5Sselect_shape_same() + * returns true on the memory and file selections. + * + * Return: void + * + * Programmer: JRM -- 8/10/11 + * + *------------------------------------------------------------------------- + */ + +#define CONTIG_HS_DR_PIO_TEST__M2D_L2S__DEBUG 0 + +static void +contig_hs_dr_pio_test__m2d_l2s(struct hs_dr_pio_test_vars_t *tv_ptr) +{ +#if CONTIG_HS_DR_PIO_TEST__M2D_L2S__DEBUG + const char *fcnName = "contig_hs_dr_pio_test__m2d_l2s()"; +#endif /* CONTIG_HS_DR_PIO_TEST__M2D_L2S__DEBUG */ + hbool_t mis_match = FALSE; + int i, j, k, l; + size_t n; + int mpi_rank; /* needed by the VRFY macro */ + size_t start_index; + size_t stop_index; + uint32_t expected_value; + uint32_t *ptr_1; + htri_t check; /* Shape comparison return value */ + herr_t ret; /* Generic return value */ + + /* initialize the local copy of mpi_rank */ + mpi_rank = tv_ptr->mpi_rank; + + /* now we go in the opposite direction, verifying that we can write + * from memory to file using selections of different rank that + * H5Sselect_shape_same() views as being of the same shape. + * + * Start by writing small_rank - 1 dimensional slices from the in memory large + * data set to the on disk small cube dataset. After each write, read the + * slice of the small dataset back from disk, and verify that it contains + * the expected data. Verify that H5Sselect_shape_same() returns true on + * the memory and file selections. + */ + + tv_ptr->start[0] = (hsize_t)(tv_ptr->mpi_rank); + tv_ptr->stride[0] = (hsize_t)(2 * (tv_ptr->mpi_size + 1)); + tv_ptr->count[0] = 1; + tv_ptr->block[0] = 1; + + for (i = 1; i < tv_ptr->large_rank; i++) { + + tv_ptr->start[i] = 0; + tv_ptr->stride[i] = (hsize_t)(2 * tv_ptr->edge_size); + tv_ptr->count[i] = 1; + tv_ptr->block[i] = (hsize_t)(tv_ptr->edge_size); + } + + ret = H5Sselect_hyperslab(tv_ptr->file_small_ds_sid_0, H5S_SELECT_SET, tv_ptr->start, tv_ptr->stride, + tv_ptr->count, tv_ptr->block); + VRFY((ret >= 0), "H5Sselect_hyperslab(file_small_ds_sid_0, set) succeeded"); + + ret = H5Sselect_hyperslab(tv_ptr->mem_small_ds_sid, H5S_SELECT_SET, tv_ptr->start, tv_ptr->stride, + tv_ptr->count, tv_ptr->block); + VRFY((ret >= 0), "H5Sselect_hyperslab(mem_small_ds_sid, set) succeeded"); + + /* set up start, stride, count, and block -- note that we will + * change start[] so as to read slices of the large cube. + */ + for (i = 0; i < PAR_SS_DR_MAX_RANK; i++) { + + tv_ptr->start[i] = 0; + tv_ptr->stride[i] = (hsize_t)(2 * tv_ptr->edge_size); + tv_ptr->count[i] = 1; + if ((PAR_SS_DR_MAX_RANK - i) > (tv_ptr->small_rank - 1)) { + + tv_ptr->block[i] = 1; + } + else { + + tv_ptr->block[i] = (hsize_t)(tv_ptr->edge_size); + } + } + + /* zero out the in memory small ds */ + HDmemset(tv_ptr->small_ds_buf_1, 0, sizeof(uint32_t) * tv_ptr->small_ds_size); + +#if CONTIG_HS_DR_PIO_TEST__M2D_L2S__DEBUG + HDfprintf(stdout, "%s writing slices from big ds to slices of small ds on disk.\n", fcnName); +#endif /* CONTIG_HS_DR_PIO_TEST__M2D_L2S__DEBUG */ + + /* in serial versions of this test, we loop through all the dimensions + * of the large data set that don't appear in the small data set. + * + * However, in the parallel version, each process only works with that + * slice of the large (and small) data set indicated by its rank -- hence + * we set the most slowly changing index to mpi_rank, and don't iterate + * over it. + */ + + if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 0) { + + i = tv_ptr->mpi_rank; + } + else { + + i = 0; + } + + /* since large_rank is at most PAR_SS_DR_MAX_RANK, no need to + * loop over it -- either we are setting i to mpi_rank, or + * we are setting it to zero. It will not change during the + * test. + */ + + if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 1) { + + j = tv_ptr->mpi_rank; + } + else { + + j = 0; + } + + j = 0; + do { + if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 2) { + + k = tv_ptr->mpi_rank; + } + else { + + k = 0; + } + + do { + /* since small rank >= 2 and large_rank > small_rank, we + * have large_rank >= 3. Since PAR_SS_DR_MAX_RANK == 5 + * (baring major re-orgaization), this gives us: + * + * (PAR_SS_DR_MAX_RANK - large_rank) <= 2 + * + * so no need to repeat the test in the outer loops -- + * just set l = 0. + */ + + l = 0; + do { + if ((tv_ptr->skips)++ < tv_ptr->max_skips) { /* skip the test */ + + (tv_ptr->tests_skipped)++; + } + else { /* run the test */ + + tv_ptr->skips = 0; /* reset the skips counter */ + + /* we know that small_rank >= 1 and that large_rank > small_rank + * by the assertions at the head of this function. Thus no + * need for another inner loop. + */ + + /* zero out this rank's slice of the on disk small data set */ + ret = H5Dwrite(tv_ptr->small_dataset, H5T_NATIVE_UINT32, tv_ptr->mem_small_ds_sid, + tv_ptr->file_small_ds_sid_0, tv_ptr->xfer_plist, tv_ptr->small_ds_buf_2); + VRFY((ret >= 0), "H5Dwrite() zero slice to small ds succeeded."); + + /* select the portion of the in memory large cube from which we + * are going to write data. + */ + tv_ptr->start[0] = (hsize_t)i; + tv_ptr->start[1] = (hsize_t)j; + tv_ptr->start[2] = (hsize_t)k; + tv_ptr->start[3] = (hsize_t)l; + tv_ptr->start[4] = 0; + + ret = H5Sselect_hyperslab(tv_ptr->mem_large_ds_sid, H5S_SELECT_SET, tv_ptr->start_ptr, + tv_ptr->stride_ptr, tv_ptr->count_ptr, tv_ptr->block_ptr); + VRFY((ret >= 0), "H5Sselect_hyperslab() mem_large_ds_sid succeeded."); + + /* verify that H5Sselect_shape_same() reports the in + * memory slice through the cube selection and the + * on disk full square selections as having the same shape. + */ + check = H5Sselect_shape_same(tv_ptr->file_small_ds_sid_0, tv_ptr->mem_large_ds_sid); + VRFY((check == TRUE), "H5Sselect_shape_same passed."); + + /* write the slice from the in memory large data set to the + * slice of the on disk small dataset. */ +#if CONTIG_HS_DR_PIO_TEST__M2D_L2S__DEBUG + HDfprintf(stdout, "%s:%d: start = %d %d %d %d %d.\n", fcnName, (int)(tv_ptr->mpi_rank), + (int)(tv_ptr->start[0]), (int)(tv_ptr->start[1]), (int)(tv_ptr->start[2]), + (int)(tv_ptr->start[3]), (int)(tv_ptr->start[4])); + HDfprintf(stdout, "%s:%d: mem/file extent dims = %d/%d.\n", fcnName, tv_ptr->mpi_rank, + H5Sget_simple_extent_ndims(tv_ptr->mem_large_ds_sid), + H5Sget_simple_extent_ndims(tv_ptr->file_small_ds_sid_0)); +#endif /* CONTIG_HS_DR_PIO_TEST__M2D_L2S__DEBUG */ + ret = H5Dwrite(tv_ptr->small_dataset, H5T_NATIVE_UINT32, tv_ptr->mem_large_ds_sid, + tv_ptr->file_small_ds_sid_0, tv_ptr->xfer_plist, tv_ptr->large_ds_buf_0); + VRFY((ret >= 0), "H5Dwrite() slice to large ds succeeded."); + + /* read the on disk square into memory */ + ret = H5Dread(tv_ptr->small_dataset, H5T_NATIVE_UINT32, tv_ptr->mem_small_ds_sid, + tv_ptr->file_small_ds_sid_0, tv_ptr->xfer_plist, tv_ptr->small_ds_buf_1); + VRFY((ret >= 0), "H5Dread() slice from small ds succeeded."); + + /* verify that expected data is retrieved */ + + mis_match = FALSE; + ptr_1 = tv_ptr->small_ds_buf_1; + + expected_value = + (uint32_t)((i * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size * + tv_ptr->edge_size) + + (j * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size) + + (k * tv_ptr->edge_size * tv_ptr->edge_size) + (l * tv_ptr->edge_size)); + + start_index = (size_t)(tv_ptr->mpi_rank) * tv_ptr->small_ds_slice_size; + stop_index = start_index + tv_ptr->small_ds_slice_size - 1; + + HDassert(start_index < stop_index); + HDassert(stop_index <= tv_ptr->small_ds_size); + + for (n = 0; n < tv_ptr->small_ds_size; n++) { + + if ((n >= start_index) && (n <= stop_index)) { + + if (*ptr_1 != expected_value) { + + mis_match = TRUE; + } + expected_value++; + } + else { + + if (*ptr_1 != 0) { + + mis_match = TRUE; + } + } + /* zero out the value for the next pass */ + *ptr_1 = 0; + + ptr_1++; + } + + VRFY((mis_match == FALSE), "small slice write from large ds data good."); + + (tv_ptr->tests_run)++; + } + + l++; + + (tv_ptr->total_tests)++; + + } while ((tv_ptr->large_rank > 2) && ((tv_ptr->small_rank - 1) <= 1) && (l < tv_ptr->edge_size)); + k++; + } while ((tv_ptr->large_rank > 3) && ((tv_ptr->small_rank - 1) <= 2) && (k < tv_ptr->edge_size)); + j++; + } while ((tv_ptr->large_rank > 4) && ((tv_ptr->small_rank - 1) <= 3) && (j < tv_ptr->edge_size)); + + return; + +} /* contig_hs_dr_pio_test__m2d_l2s() */ + +/*------------------------------------------------------------------------- + * Function: contig_hs_dr_pio_test__m2d_s2l() + * + * Purpose: Part four of a series of tests of I/O to/from hyperslab + * selections of different rank in the parallel. + * + * Verify that we can write from memory to file using + * selections of different rank that H5Sselect_shape_same() + * views as being of the same shape. + * + * Do this by writing the contents of the process's slice of + * the in memory small data set to slices of the on disk + * large data set. After each write, read the process's + * slice of the large data set back into memory, and verify + * that it contains the expected data. + * + * Verify that H5Sselect_shape_same() returns true on the + * memory and file selections. + * + * Return: void + * + * Programmer: JRM -- 8/10/11 + * + *------------------------------------------------------------------------- + */ + +#define CONTIG_HS_DR_PIO_TEST__M2D_S2L__DEBUG 0 + +static void +contig_hs_dr_pio_test__m2d_s2l(struct hs_dr_pio_test_vars_t *tv_ptr) +{ +#if CONTIG_HS_DR_PIO_TEST__M2D_S2L__DEBUG + const char *fcnName = "contig_hs_dr_pio_test__m2d_s2l()"; +#endif /* CONTIG_HS_DR_PIO_TEST__M2D_S2L__DEBUG */ + hbool_t mis_match = FALSE; + int i, j, k, l; + size_t n; + int mpi_rank; /* needed by the VRFY macro */ + size_t start_index; + size_t stop_index; + uint32_t expected_value; + uint32_t *ptr_1; + htri_t check; /* Shape comparison return value */ + herr_t ret; /* Generic return value */ + + /* initialize the local copy of mpi_rank */ + mpi_rank = tv_ptr->mpi_rank; + + /* Now write the contents of the process's slice of the in memory + * small data set to slices of the on disk large data set. After + * each write, read the process's slice of the large data set back + * into memory, and verify that it contains the expected data. + * Verify that H5Sselect_shape_same() returns true on the memory + * and file selections. + */ + + /* select the slice of the in memory small data set associated with + * the process's mpi rank. + */ + tv_ptr->start[0] = (hsize_t)(tv_ptr->mpi_rank); + tv_ptr->stride[0] = (hsize_t)(2 * (tv_ptr->mpi_size + 1)); + tv_ptr->count[0] = 1; + tv_ptr->block[0] = 1; + + for (i = 1; i < tv_ptr->large_rank; i++) { + + tv_ptr->start[i] = 0; + tv_ptr->stride[i] = (hsize_t)(2 * tv_ptr->edge_size); + tv_ptr->count[i] = 1; + tv_ptr->block[i] = (hsize_t)(tv_ptr->edge_size); + } + + ret = H5Sselect_hyperslab(tv_ptr->mem_small_ds_sid, H5S_SELECT_SET, tv_ptr->start, tv_ptr->stride, + tv_ptr->count, tv_ptr->block); + VRFY((ret >= 0), "H5Sselect_hyperslab(mem_small_ds_sid, set) succeeded"); + + /* set up start, stride, count, and block -- note that we will + * change start[] so as to write slices of the small data set to + * slices of the large data set. + */ + for (i = 0; i < PAR_SS_DR_MAX_RANK; i++) { + + tv_ptr->start[i] = 0; + tv_ptr->stride[i] = (hsize_t)(2 * tv_ptr->edge_size); + tv_ptr->count[i] = 1; + if ((PAR_SS_DR_MAX_RANK - i) > (tv_ptr->small_rank - 1)) { + + tv_ptr->block[i] = 1; + } + else { + + tv_ptr->block[i] = (hsize_t)(tv_ptr->edge_size); + } + } + + /* zero out the in memory large ds */ + HDmemset(tv_ptr->large_ds_buf_1, 0, sizeof(uint32_t) * tv_ptr->large_ds_size); + +#if CONTIG_HS_DR_PIO_TEST__M2D_S2L__DEBUG + HDfprintf(stdout, "%s writing process slices of small ds to slices of large ds on disk.\n", fcnName); +#endif /* CONTIG_HS_DR_PIO_TEST__M2D_S2L__DEBUG */ + + if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 0) { + + i = tv_ptr->mpi_rank; + } + else { + + i = 0; + } + + /* since large_rank is at most PAR_SS_DR_MAX_RANK, no need to + * loop over it -- either we are setting i to mpi_rank, or + * we are setting it to zero. It will not change during the + * test. + */ + + if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 1) { + + j = tv_ptr->mpi_rank; + } + else { + + j = 0; + } + + do { + if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 2) { + + k = tv_ptr->mpi_rank; + } + else { + + k = 0; + } + + do { + /* since small rank >= 2 and large_rank > small_rank, we + * have large_rank >= 3. Since PAR_SS_DR_MAX_RANK == 5 + * (baring major re-orgaization), this gives us: + * + * (PAR_SS_DR_MAX_RANK - large_rank) <= 2 + * + * so no need to repeat the test in the outer loops -- + * just set l = 0. + */ + + l = 0; + do { + if ((tv_ptr->skips)++ < tv_ptr->max_skips) { /* skip the test */ + + (tv_ptr->tests_skipped)++; + +#if CONTIG_HS_DR_PIO_TEST__M2D_S2L__DEBUG + tv_ptr->start[0] = (hsize_t)i; + tv_ptr->start[1] = (hsize_t)j; + tv_ptr->start[2] = (hsize_t)k; + tv_ptr->start[3] = (hsize_t)l; + tv_ptr->start[4] = 0; + + HDfprintf(stdout, "%s:%d: skipping test with start = %d %d %d %d %d.\n", fcnName, + (int)(tv_ptr->mpi_rank), (int)(tv_ptr->start[0]), (int)(tv_ptr->start[1]), + (int)(tv_ptr->start[2]), (int)(tv_ptr->start[3]), (int)(tv_ptr->start[4])); + HDfprintf(stdout, "%s:%d: mem/file extent dims = %d/%d.\n", fcnName, tv_ptr->mpi_rank, + H5Sget_simple_extent_ndims(tv_ptr->mem_small_ds_sid), + H5Sget_simple_extent_ndims(tv_ptr->file_large_ds_sid_0)); +#endif /* CONTIG_HS_DR_PIO_TEST__M2D_S2L__DEBUG */ + } + else { /* run the test */ + + tv_ptr->skips = 0; /* reset the skips counter */ + + /* we know that small_rank >= 1 and that large_rank > small_rank + * by the assertions at the head of this function. Thus no + * need for another inner loop. + */ + + /* Zero out this processes slice of the on disk large data set. + * Note that this will leave one slice with its original data + * as there is one more slice than processes. + */ + ret = H5Dwrite(tv_ptr->large_dataset, H5T_NATIVE_UINT32, tv_ptr->large_ds_slice_sid, + tv_ptr->file_large_ds_process_slice_sid, tv_ptr->xfer_plist, + tv_ptr->large_ds_buf_2); + VRFY((ret != FAIL), "H5Dwrite() to zero large ds succeeded"); + + /* select the portion of the in memory large cube to which we + * are going to write data. + */ + tv_ptr->start[0] = (hsize_t)i; + tv_ptr->start[1] = (hsize_t)j; + tv_ptr->start[2] = (hsize_t)k; + tv_ptr->start[3] = (hsize_t)l; + tv_ptr->start[4] = 0; + + ret = H5Sselect_hyperslab(tv_ptr->file_large_ds_sid_0, H5S_SELECT_SET, tv_ptr->start_ptr, + tv_ptr->stride_ptr, tv_ptr->count_ptr, tv_ptr->block_ptr); + VRFY((ret != FAIL), "H5Sselect_hyperslab() target large ds slice succeeded"); + + /* verify that H5Sselect_shape_same() reports the in + * memory small data set slice selection and the + * on disk slice through the large data set selection + * as having the same shape. + */ + check = H5Sselect_shape_same(tv_ptr->mem_small_ds_sid, tv_ptr->file_large_ds_sid_0); + VRFY((check == TRUE), "H5Sselect_shape_same passed"); + + /* write the small data set slice from memory to the + * target slice of the disk data set + */ +#if CONTIG_HS_DR_PIO_TEST__M2D_S2L__DEBUG + HDfprintf(stdout, "%s:%d: start = %d %d %d %d %d.\n", fcnName, (int)(tv_ptr->mpi_rank), + (int)(tv_ptr->start[0]), (int)(tv_ptr->start[1]), (int)(tv_ptr->start[2]), + (int)(tv_ptr->start[3]), (int)(tv_ptr->start[4])); + HDfprintf(stdout, "%s:%d: mem/file extent dims = %d/%d.\n", fcnName, tv_ptr->mpi_rank, + H5Sget_simple_extent_ndims(tv_ptr->mem_small_ds_sid), + H5Sget_simple_extent_ndims(tv_ptr->file_large_ds_sid_0)); +#endif /* CONTIG_HS_DR_PIO_TEST__M2D_S2L__DEBUG */ + ret = H5Dwrite(tv_ptr->large_dataset, H5T_NATIVE_UINT32, tv_ptr->mem_small_ds_sid, + tv_ptr->file_large_ds_sid_0, tv_ptr->xfer_plist, tv_ptr->small_ds_buf_0); + VRFY((ret != FAIL), "H5Dwrite of small ds slice to large ds succeeded"); + + /* read this processes slice on the on disk large + * data set into memory. + */ + + ret = H5Dread( + tv_ptr->large_dataset, H5T_NATIVE_UINT32, tv_ptr->mem_large_ds_process_slice_sid, + tv_ptr->file_large_ds_process_slice_sid, tv_ptr->xfer_plist, tv_ptr->large_ds_buf_1); + VRFY((ret != FAIL), "H5Dread() of process slice of large ds succeeded"); + + /* verify that the expected data and only the + * expected data was read. + */ + ptr_1 = tv_ptr->large_ds_buf_1; + expected_value = (uint32_t)((size_t)(tv_ptr->mpi_rank) * tv_ptr->small_ds_slice_size); + + start_index = + (size_t)((i * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size * + tv_ptr->edge_size) + + (j * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size) + + (k * tv_ptr->edge_size * tv_ptr->edge_size) + (l * tv_ptr->edge_size)); + stop_index = start_index + tv_ptr->small_ds_slice_size - 1; + + HDassert(start_index < stop_index); + HDassert(stop_index < tv_ptr->large_ds_size); + + for (n = 0; n < tv_ptr->large_ds_size; n++) { + + if ((n >= start_index) && (n <= stop_index)) { + + if (*ptr_1 != expected_value) { + + mis_match = TRUE; + } + + expected_value++; + } + else { + + if (*ptr_1 != 0) { + + mis_match = TRUE; + } + } + /* zero out buffer for next test */ + *ptr_1 = 0; + ptr_1++; + } + + VRFY((mis_match == FALSE), "small ds slice write to large ds slice data good."); + + (tv_ptr->tests_run)++; + } + + l++; + + (tv_ptr->total_tests)++; + + } while ((tv_ptr->large_rank > 2) && ((tv_ptr->small_rank - 1) <= 1) && (l < tv_ptr->edge_size)); + k++; + } while ((tv_ptr->large_rank > 3) && ((tv_ptr->small_rank - 1) <= 2) && (k < tv_ptr->edge_size)); + j++; + } while ((tv_ptr->large_rank > 4) && ((tv_ptr->small_rank - 1) <= 3) && (j < tv_ptr->edge_size)); + + return; + +} /* contig_hs_dr_pio_test__m2d_s2l() */ + +/*------------------------------------------------------------------------- + * Function: contig_hs_dr_pio_test__run_test() + * + * Purpose: Test I/O to/from hyperslab selections of different rank in + * the parallel. + * + * Return: void + * + * Programmer: JRM -- 9/18/09 + * + *------------------------------------------------------------------------- + */ + +#define CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG 0 + +static void +contig_hs_dr_pio_test__run_test(const int test_num, const int edge_size, const int chunk_edge_size, + const int small_rank, const int large_rank, const hbool_t use_collective_io, + const hid_t dset_type, int express_test, int *skips_ptr, int max_skips, + int64_t *total_tests_ptr, int64_t *tests_run_ptr, int64_t *tests_skipped_ptr, + int mpi_rank) +{ +#if CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG + const char *fcnName = "contig_hs_dr_pio_test__run_test()"; +#endif /* CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG */ + struct hs_dr_pio_test_vars_t test_vars = { + /* int mpi_size = */ -1, + /* int mpi_rank = */ -1, + /* MPI_Comm mpi_comm = */ MPI_COMM_NULL, + /* MPI_Inf mpi_info = */ MPI_INFO_NULL, + /* int test_num = */ -1, + /* int edge_size = */ -1, + /* int checker_edge_size = */ -1, + /* int chunk_edge_size = */ -1, + /* int small_rank = */ -1, + /* int large_rank = */ -1, + /* hid_t dset_type = */ -1, + /* uint32_t * small_ds_buf_0 = */ NULL, + /* uint32_t * small_ds_buf_1 = */ NULL, + /* uint32_t * small_ds_buf_2 = */ NULL, + /* uint32_t * small_ds_slice_buf = */ NULL, + /* uint32_t * large_ds_buf_0 = */ NULL, + /* uint32_t * large_ds_buf_1 = */ NULL, + /* uint32_t * large_ds_buf_2 = */ NULL, + /* uint32_t * large_ds_slice_buf = */ NULL, + /* int small_ds_offset = */ -1, + /* int large_ds_offset = */ -1, + /* hid_t fid = */ -1, /* HDF5 file ID */ + /* hid_t xfer_plist = */ H5P_DEFAULT, + /* hid_t full_mem_small_ds_sid = */ -1, + /* hid_t full_file_small_ds_sid = */ -1, + /* hid_t mem_small_ds_sid = */ -1, + /* hid_t file_small_ds_sid_0 = */ -1, + /* hid_t file_small_ds_sid_1 = */ -1, + /* hid_t small_ds_slice_sid = */ -1, + /* hid_t full_mem_large_ds_sid = */ -1, + /* hid_t full_file_large_ds_sid = */ -1, + /* hid_t mem_large_ds_sid = */ -1, + /* hid_t file_large_ds_sid_0 = */ -1, + /* hid_t file_large_ds_sid_1 = */ -1, + /* hid_t file_large_ds_process_slice_sid = */ -1, + /* hid_t mem_large_ds_process_slice_sid = */ -1, + /* hid_t large_ds_slice_sid = */ -1, + /* hid_t small_dataset = */ -1, /* Dataset ID */ + /* hid_t large_dataset = */ -1, /* Dataset ID */ + /* size_t small_ds_size = */ 1, + /* size_t small_ds_slice_size = */ 1, + /* size_t large_ds_size = */ 1, + /* size_t large_ds_slice_size = */ 1, + /* hsize_t dims[PAR_SS_DR_MAX_RANK] = */ {0, 0, 0, 0, 0}, + /* hsize_t chunk_dims[PAR_SS_DR_MAX_RANK] = */ {0, 0, 0, 0, 0}, + /* hsize_t start[PAR_SS_DR_MAX_RANK] = */ {0, 0, 0, 0, 0}, + /* hsize_t stride[PAR_SS_DR_MAX_RANK] = */ {0, 0, 0, 0, 0}, + /* hsize_t count[PAR_SS_DR_MAX_RANK] = */ {0, 0, 0, 0, 0}, + /* hsize_t block[PAR_SS_DR_MAX_RANK] = */ {0, 0, 0, 0, 0}, + /* hsize_t * start_ptr = */ NULL, + /* hsize_t * stride_ptr = */ NULL, + /* hsize_t * count_ptr = */ NULL, + /* hsize_t * block_ptr = */ NULL, + /* int skips = */ 0, + /* int max_skips = */ 0, + /* int64_t total_tests = */ 0, + /* int64_t tests_run = */ 0, + /* int64_t tests_skipped = */ 0}; + struct hs_dr_pio_test_vars_t *tv_ptr = &test_vars; + + if (MAINPROCESS) + printf("\r - running test #%lld: small rank = %d, large rank = %d", (long long)(test_num + 1), + small_rank, large_rank); + + hs_dr_pio_test__setup(test_num, edge_size, -1, chunk_edge_size, small_rank, large_rank, use_collective_io, + dset_type, express_test, tv_ptr); + + /* initialize skips & max_skips */ + tv_ptr->skips = *skips_ptr; + tv_ptr->max_skips = max_skips; + +#if CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG + if (MAINPROCESS) { + HDfprintf(stdout, "test %d: small rank = %d, large rank = %d.\n", test_num, small_rank, large_rank); + HDfprintf(stdout, "test %d: Initialization complete.\n", test_num); + } +#endif /* CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG */ + + /* first, verify that we can read from disk correctly using selections + * of different rank that H5Sselect_shape_same() views as being of the + * same shape. + * + * Start by reading small_rank - 1 dimensional slice from the on disk + * large cube, and verifying that the data read is correct. Verify that + * H5Sselect_shape_same() returns true on the memory and file selections. + */ + +#if CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG + if (MAINPROCESS) { + HDfprintf(stdout, "test %d: running contig_hs_dr_pio_test__d2m_l2s.\n", test_num); + } +#endif /* CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG */ + contig_hs_dr_pio_test__d2m_l2s(tv_ptr); + + /* Second, read slices of the on disk small data set into slices + * through the in memory large data set, and verify that the correct + * data (and only the correct data) is read. + */ + +#if CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG + if (MAINPROCESS) { + HDfprintf(stdout, "test %d: running contig_hs_dr_pio_test__d2m_s2l.\n", test_num); + } +#endif /* CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG */ + contig_hs_dr_pio_test__d2m_s2l(tv_ptr); + + /* now we go in the opposite direction, verifying that we can write + * from memory to file using selections of different rank that + * H5Sselect_shape_same() views as being of the same shape. + * + * Start by writing small_rank - 1 D slices from the in memory large data + * set to the on disk small cube dataset. After each write, read the + * slice of the small dataset back from disk, and verify that it contains + * the expected data. Verify that H5Sselect_shape_same() returns true on + * the memory and file selections. + */ + +#if CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG + if (MAINPROCESS) { + HDfprintf(stdout, "test %d: running contig_hs_dr_pio_test__m2d_l2s.\n", test_num); + } +#endif /* CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG */ + contig_hs_dr_pio_test__m2d_l2s(tv_ptr); + + /* Now write the contents of the process's slice of the in memory + * small data set to slices of the on disk large data set. After + * each write, read the process's slice of the large data set back + * into memory, and verify that it contains the expected data. + * Verify that H5Sselect_shape_same() returns true on the memory + * and file selections. + */ + +#if CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG + if (MAINPROCESS) { + HDfprintf(stdout, "test %d: running contig_hs_dr_pio_test__m2d_s2l.\n", test_num); + } +#endif /* CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG */ + contig_hs_dr_pio_test__m2d_s2l(tv_ptr); + +#if CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG + if (MAINPROCESS) { + HDfprintf(stdout, "test %d: Subtests complete -- tests run/skipped/total = %lld/%lld/%lld.\n", + test_num, (long long)(tv_ptr->tests_run), (long long)(tv_ptr->tests_skipped), + (long long)(tv_ptr->total_tests)); + } +#endif /* CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG */ + + hs_dr_pio_test__takedown(tv_ptr); + +#if CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG + if (MAINPROCESS) { + HDfprintf(stdout, "test %d: Takedown complete.\n", test_num); + } +#endif /* CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG */ + + *skips_ptr = tv_ptr->skips; + *total_tests_ptr += tv_ptr->total_tests; + *tests_run_ptr += tv_ptr->tests_run; + *tests_skipped_ptr += tv_ptr->tests_skipped; + + return; + +} /* contig_hs_dr_pio_test__run_test() */ + +/*------------------------------------------------------------------------- + * Function: contig_hs_dr_pio_test(ShapeSameTestMethods sstest_type) + * + * Purpose: Test I/O to/from hyperslab selections of different rank in + * the parallel case. + * + * Return: void + * + * Programmer: JRM -- 9/18/09 + * + *------------------------------------------------------------------------- + */ + +#define CONTIG_HS_DR_PIO_TEST__DEBUG 0 + +static void +contig_hs_dr_pio_test(ShapeSameTestMethods sstest_type) +{ + int express_test; + int local_express_test; + int mpi_rank = -1; + int mpi_size; + int test_num = 0; + int edge_size; + int chunk_edge_size = 0; + int small_rank; + int large_rank; + int mpi_result; + int skips = 0; + int max_skips = 0; + /* The following table list the number of sub-tests skipped between + * each test that is actually executed as a function of the express + * test level. Note that any value in excess of 4880 will cause all + * sub tests to be skipped. + */ + int max_skips_tbl[4] = {0, 4, 64, 1024}; + hid_t dset_type = H5T_NATIVE_UINT; + int64_t total_tests = 0; + int64_t tests_run = 0; + int64_t tests_skipped = 0; + + HDcompile_assert(sizeof(uint32_t) == sizeof(unsigned)); + + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + edge_size = (mpi_size > 6 ? mpi_size : 6); + + local_express_test = EXPRESS_MODE; /* GetTestExpress(); */ + + mpi_result = MPI_Allreduce((void *)&local_express_test, (void *)&express_test, 1, MPI_INT, MPI_MAX, + MPI_COMM_WORLD); + + VRFY((mpi_result == MPI_SUCCESS), "MPI_Allreduce(0) succeeded"); + + if (local_express_test < 0) { + max_skips = max_skips_tbl[0]; + } + else if (local_express_test > 3) { + max_skips = max_skips_tbl[3]; + } + else { + max_skips = max_skips_tbl[local_express_test]; + } + + for (large_rank = 3; large_rank <= PAR_SS_DR_MAX_RANK; large_rank++) { + + for (small_rank = 2; small_rank < large_rank; small_rank++) { + + switch (sstest_type) { + case IND_CONTIG: + /* contiguous data set, independent I/O */ + chunk_edge_size = 0; + + contig_hs_dr_pio_test__run_test( + test_num, edge_size, chunk_edge_size, small_rank, large_rank, FALSE, dset_type, + express_test, &skips, max_skips, &total_tests, &tests_run, &tests_skipped, mpi_rank); + test_num++; + break; + /* end of case IND_CONTIG */ + + case COL_CONTIG: + /* contiguous data set, collective I/O */ + chunk_edge_size = 0; + + contig_hs_dr_pio_test__run_test( + test_num, edge_size, chunk_edge_size, small_rank, large_rank, TRUE, dset_type, + express_test, &skips, max_skips, &total_tests, &tests_run, &tests_skipped, mpi_rank); + test_num++; + break; + /* end of case COL_CONTIG */ + + case IND_CHUNKED: + /* chunked data set, independent I/O */ + chunk_edge_size = 5; + + contig_hs_dr_pio_test__run_test( + test_num, edge_size, chunk_edge_size, small_rank, large_rank, FALSE, dset_type, + express_test, &skips, max_skips, &total_tests, &tests_run, &tests_skipped, mpi_rank); + test_num++; + break; + /* end of case IND_CHUNKED */ + + case COL_CHUNKED: + /* chunked data set, collective I/O */ + chunk_edge_size = 5; + + contig_hs_dr_pio_test__run_test( + test_num, edge_size, chunk_edge_size, small_rank, large_rank, TRUE, dset_type, + express_test, &skips, max_skips, &total_tests, &tests_run, &tests_skipped, mpi_rank); + test_num++; + break; + /* end of case COL_CHUNKED */ + + default: + VRFY((FALSE), "unknown test type"); + break; + + } /* end of switch(sstest_type) */ +#if CONTIG_HS_DR_PIO_TEST__DEBUG + if ((MAINPROCESS) && (tests_skipped > 0)) { + HDfprintf(stdout, " run/skipped/total = %lld/%lld/%lld.\n", tests_run, tests_skipped, + total_tests); + } +#endif /* CONTIG_HS_DR_PIO_TEST__DEBUG */ + } + } + + if (MAINPROCESS) { + if (tests_skipped > 0) { + HDfprintf(stdout, " %" PRId64 " of %" PRId64 " subtests skipped to expedite testing.\n", + tests_skipped, total_tests); + } + else + HDprintf("\n"); + } + + return; + +} /* contig_hs_dr_pio_test() */ + +/**************************************************************** +** +** ckrbrd_hs_dr_pio_test__slct_ckrbrd(): +** Given a dataspace of tgt_rank, and dimensions: +** +** (mpi_size + 1), edge_size, ... , edge_size +** +** edge_size, and a checker_edge_size, select a checker +** board selection of a sel_rank (sel_rank < tgt_rank) +** dimensional slice through the dataspace parallel to the +** sel_rank fastest changing indices, with origin (in the +** higher indices) as indicated by the start array. +** +** Note that this function, like all its relatives, is +** hard coded to presume a maximum dataspace rank of 5. +** While this maximum is declared as a constant, increasing +** it will require extensive coding in addition to changing +** the value of the constant. +** +** JRM -- 10/8/09 +** +****************************************************************/ + +#define CKRBRD_HS_DR_PIO_TEST__SELECT_CHECKER_BOARD__DEBUG 0 + +static void +ckrbrd_hs_dr_pio_test__slct_ckrbrd(const int mpi_rank, const hid_t tgt_sid, const int tgt_rank, + const int edge_size, const int checker_edge_size, const int sel_rank, + hsize_t sel_start[]) +{ +#if CKRBRD_HS_DR_PIO_TEST__SELECT_CHECKER_BOARD__DEBUG + const char *fcnName = "ckrbrd_hs_dr_pio_test__slct_ckrbrd():"; +#endif + hbool_t first_selection = TRUE; + int i, j, k, l, m; + int n_cube_offset; + int sel_offset; + const int test_max_rank = PAR_SS_DR_MAX_RANK; /* must update code if */ + /* this changes */ + hsize_t base_count; + hsize_t offset_count; + hsize_t start[PAR_SS_DR_MAX_RANK]; + hsize_t stride[PAR_SS_DR_MAX_RANK]; + hsize_t count[PAR_SS_DR_MAX_RANK]; + hsize_t block[PAR_SS_DR_MAX_RANK]; + herr_t ret; /* Generic return value */ + + HDassert(edge_size >= 6); + HDassert(0 < checker_edge_size); + HDassert(checker_edge_size <= edge_size); + HDassert(0 < sel_rank); + HDassert(sel_rank <= tgt_rank); + HDassert(tgt_rank <= test_max_rank); + HDassert(test_max_rank <= PAR_SS_DR_MAX_RANK); + + sel_offset = test_max_rank - sel_rank; + HDassert(sel_offset >= 0); + + n_cube_offset = test_max_rank - tgt_rank; + HDassert(n_cube_offset >= 0); + HDassert(n_cube_offset <= sel_offset); + +#if CKRBRD_HS_DR_PIO_TEST__SELECT_CHECKER_BOARD__DEBUG + HDfprintf(stdout, "%s:%d: edge_size/checker_edge_size = %d/%d\n", fcnName, mpi_rank, edge_size, + checker_edge_size); + HDfprintf(stdout, "%s:%d: sel_rank/sel_offset = %d/%d.\n", fcnName, mpi_rank, sel_rank, sel_offset); + HDfprintf(stdout, "%s:%d: tgt_rank/n_cube_offset = %d/%d.\n", fcnName, mpi_rank, tgt_rank, n_cube_offset); +#endif /* CKRBRD_HS_DR_PIO_TEST__SELECT_CHECKER_BOARD__DEBUG */ + + /* First, compute the base count (which assumes start == 0 + * for the associated offset) and offset_count (which + * assumes start == checker_edge_size for the associated + * offset). + * + * Note that the following computation depends on the C99 + * requirement that integer division discard any fraction + * (truncation towards zero) to function correctly. As we + * now require C99, this shouldn't be a problem, but noting + * it may save us some pain if we are ever obliged to support + * pre-C99 compilers again. + */ + + base_count = (hsize_t)(edge_size / (checker_edge_size * 2)); + + if ((edge_size % (checker_edge_size * 2)) > 0) { + + base_count++; + } + + offset_count = (hsize_t)((edge_size - checker_edge_size) / (checker_edge_size * 2)); + + if (((edge_size - checker_edge_size) % (checker_edge_size * 2)) > 0) { + + offset_count++; + } + + /* Now set up the stride and block arrays, and portions of the start + * and count arrays that will not be altered during the selection of + * the checker board. + */ + i = 0; + while (i < n_cube_offset) { + + /* these values should never be used */ + start[i] = 0; + stride[i] = 0; + count[i] = 0; + block[i] = 0; + + i++; + } + + while (i < sel_offset) { + + start[i] = sel_start[i]; + stride[i] = (hsize_t)(2 * edge_size); + count[i] = 1; + block[i] = 1; + + i++; + } + + while (i < test_max_rank) { + + stride[i] = (hsize_t)(2 * checker_edge_size); + block[i] = (hsize_t)checker_edge_size; + + i++; + } + + i = 0; + do { + if (0 >= sel_offset) { + + if (i == 0) { + + start[0] = 0; + count[0] = base_count; + } + else { + + start[0] = (hsize_t)checker_edge_size; + count[0] = offset_count; + } + } + + j = 0; + do { + if (1 >= sel_offset) { + + if (j == 0) { + + start[1] = 0; + count[1] = base_count; + } + else { + + start[1] = (hsize_t)checker_edge_size; + count[1] = offset_count; + } + } + + k = 0; + do { + if (2 >= sel_offset) { + + if (k == 0) { + + start[2] = 0; + count[2] = base_count; + } + else { + + start[2] = (hsize_t)checker_edge_size; + count[2] = offset_count; + } + } + + l = 0; + do { + if (3 >= sel_offset) { + + if (l == 0) { + + start[3] = 0; + count[3] = base_count; + } + else { + + start[3] = (hsize_t)checker_edge_size; + count[3] = offset_count; + } + } + + m = 0; + do { + if (4 >= sel_offset) { + + if (m == 0) { + + start[4] = 0; + count[4] = base_count; + } + else { + + start[4] = (hsize_t)checker_edge_size; + count[4] = offset_count; + } + } + + if (((i + j + k + l + m) % 2) == 0) { + +#if CKRBRD_HS_DR_PIO_TEST__SELECT_CHECKER_BOARD__DEBUG + HDfprintf(stdout, "%s%d: *** first_selection = %d ***\n", fcnName, mpi_rank, + (int)first_selection); + HDfprintf(stdout, "%s:%d: i/j/k/l/m = %d/%d/%d/%d/%d\n", fcnName, mpi_rank, i, j, + k, l, m); + HDfprintf(stdout, "%s:%d: start = %d %d %d %d %d.\n", fcnName, mpi_rank, + (int)start[0], (int)start[1], (int)start[2], (int)start[3], + (int)start[4]); + HDfprintf(stdout, "%s:%d: stride = %d %d %d %d %d.\n", fcnName, mpi_rank, + (int)stride[0], (int)stride[1], (int)stride[2], (int)stride[3], + (int)stride[4]); + HDfprintf(stdout, "%s:%d: count = %d %d %d %d %d.\n", fcnName, mpi_rank, + (int)count[0], (int)count[1], (int)count[2], (int)count[3], + (int)count[4]); + HDfprintf(stdout, "%s:%d: block = %d %d %d %d %d.\n", fcnName, mpi_rank, + (int)block[0], (int)block[1], (int)block[2], (int)block[3], + (int)block[4]); + HDfprintf(stdout, "%s:%d: n-cube extent dims = %d.\n", fcnName, mpi_rank, + H5Sget_simple_extent_ndims(tgt_sid)); + HDfprintf(stdout, "%s:%d: selection rank = %d.\n", fcnName, mpi_rank, sel_rank); +#endif + + if (first_selection) { + + first_selection = FALSE; + + ret = H5Sselect_hyperslab(tgt_sid, H5S_SELECT_SET, &(start[n_cube_offset]), + &(stride[n_cube_offset]), &(count[n_cube_offset]), + &(block[n_cube_offset])); + + VRFY((ret != FAIL), "H5Sselect_hyperslab(SET) succeeded"); + } + else { + + ret = H5Sselect_hyperslab(tgt_sid, H5S_SELECT_OR, &(start[n_cube_offset]), + &(stride[n_cube_offset]), &(count[n_cube_offset]), + &(block[n_cube_offset])); + + VRFY((ret != FAIL), "H5Sselect_hyperslab(OR) succeeded"); + } + } + + m++; + + } while ((m <= 1) && (4 >= sel_offset)); + + l++; + + } while ((l <= 1) && (3 >= sel_offset)); + + k++; + + } while ((k <= 1) && (2 >= sel_offset)); + + j++; + + } while ((j <= 1) && (1 >= sel_offset)); + + i++; + + } while ((i <= 1) && (0 >= sel_offset)); + +#if CKRBRD_HS_DR_PIO_TEST__SELECT_CHECKER_BOARD__DEBUG + HDfprintf(stdout, "%s%d: H5Sget_select_npoints(tgt_sid) = %d.\n", fcnName, mpi_rank, + (int)H5Sget_select_npoints(tgt_sid)); +#endif /* CKRBRD_HS_DR_PIO_TEST__SELECT_CHECKER_BOARD__DEBUG */ + + /* Clip the selection back to the dataspace proper. */ + + for (i = 0; i < test_max_rank; i++) { + + start[i] = 0; + stride[i] = (hsize_t)edge_size; + count[i] = 1; + block[i] = (hsize_t)edge_size; + } + + ret = H5Sselect_hyperslab(tgt_sid, H5S_SELECT_AND, start, stride, count, block); + + VRFY((ret != FAIL), "H5Sselect_hyperslab(AND) succeeded"); + +#if CKRBRD_HS_DR_PIO_TEST__SELECT_CHECKER_BOARD__DEBUG + HDfprintf(stdout, "%s%d: H5Sget_select_npoints(tgt_sid) = %d.\n", fcnName, mpi_rank, + (int)H5Sget_select_npoints(tgt_sid)); + HDfprintf(stdout, "%s%d: done.\n", fcnName, mpi_rank); +#endif /* CKRBRD_HS_DR_PIO_TEST__SELECT_CHECKER_BOARD__DEBUG */ + + return; + +} /* ckrbrd_hs_dr_pio_test__slct_ckrbrd() */ + +/**************************************************************** +** +** ckrbrd_hs_dr_pio_test__verify_data(): +** +** Examine the supplied buffer to see if it contains the +** expected data. Return TRUE if it does, and FALSE +** otherwise. +** +** The supplied buffer is presumed to this process's slice +** of the target data set. Each such slice will be an +** n-cube of rank (rank -1) and the supplied edge_size with +** origin (mpi_rank, 0, ... , 0) in the target data set. +** +** Further, the buffer is presumed to be the result of reading +** or writing a checker board selection of an m (1 <= m < +** rank) dimensional slice through this processes slice +** of the target data set. Also, this slice must be parallel +** to the fastest changing indices. +** +** It is further presumed that the buffer was zeroed before +** the read/write, and that the full target data set (i.e. +** the buffer/data set for all processes) was initialized +** with the natural numbers listed in order from the origin +** along the fastest changing axis. +** +** Thus for a 20x10x10 dataset, the value stored in location +** (x, y, z) (assuming that z is the fastest changing index +** and x the slowest) is assumed to be: +** +** (10 * 10 * x) + (10 * y) + z +** +** Further, supposing that this is process 10, this process's +** slice of the dataset would be a 10 x 10 2-cube with origin +** (10, 0, 0) in the data set, and would be initialize (prior +** to the checkerboard selection) as follows: +** +** 1000, 1001, 1002, ... 1008, 1009 +** 1010, 1011, 1012, ... 1018, 1019 +** . . . . . +** . . . . . +** . . . . . +** 1090, 1091, 1092, ... 1098, 1099 +** +** In the case of a read from the processors slice of another +** data set of different rank, the values expected will have +** to be adjusted accordingly. This is done via the +** first_expected_val parameter. +** +** Finally, the function presumes that the first element +** of the buffer resides either at the origin of either +** a selected or an unselected checker. (Translation: +** if partial checkers appear in the buffer, they will +** intersect the edges of the n-cube opposite the origin.) +** +****************************************************************/ + +#define CKRBRD_HS_DR_PIO_TEST__VERIFY_DATA__DEBUG 0 + +static hbool_t +ckrbrd_hs_dr_pio_test__verify_data(uint32_t *buf_ptr, const int rank, const int edge_size, + const int checker_edge_size, uint32_t first_expected_val, + hbool_t buf_starts_in_checker) +{ +#if CKRBRD_HS_DR_PIO_TEST__VERIFY_DATA__DEBUG + const char *fcnName = "ckrbrd_hs_dr_pio_test__verify_data():"; +#endif + hbool_t good_data = TRUE; + hbool_t in_checker; + hbool_t start_in_checker[5]; + uint32_t expected_value; + uint32_t *val_ptr; + int i, j, k, l, m; /* to track position in n-cube */ + int v, w, x, y, z; /* to track position in checker */ + const int test_max_rank = 5; /* code changes needed if this is increased */ + + HDassert(buf_ptr != NULL); + HDassert(0 < rank); + HDassert(rank <= test_max_rank); + HDassert(edge_size >= 6); + HDassert(0 < checker_edge_size); + HDassert(checker_edge_size <= edge_size); + HDassert(test_max_rank <= PAR_SS_DR_MAX_RANK); + +#if CKRBRD_HS_DR_PIO_TEST__VERIFY_DATA__DEBUG + + int mpi_rank; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + HDfprintf(stdout, "%s mpi_rank = %d.\n", fcnName, mpi_rank); + HDfprintf(stdout, "%s rank = %d.\n", fcnName, rank); + HDfprintf(stdout, "%s edge_size = %d.\n", fcnName, edge_size); + HDfprintf(stdout, "%s checker_edge_size = %d.\n", fcnName, checker_edge_size); + HDfprintf(stdout, "%s first_expected_val = %d.\n", fcnName, (int)first_expected_val); + HDfprintf(stdout, "%s starts_in_checker = %d.\n", fcnName, (int)buf_starts_in_checker); +} +#endif + +val_ptr = buf_ptr; +expected_value = first_expected_val; + +i = 0; +v = 0; +start_in_checker[0] = buf_starts_in_checker; +do { + if (v >= checker_edge_size) { + + start_in_checker[0] = !start_in_checker[0]; + v = 0; + } + + j = 0; + w = 0; + start_in_checker[1] = start_in_checker[0]; + do { + if (w >= checker_edge_size) { + + start_in_checker[1] = !start_in_checker[1]; + w = 0; + } + + k = 0; + x = 0; + start_in_checker[2] = start_in_checker[1]; + do { + if (x >= checker_edge_size) { + + start_in_checker[2] = !start_in_checker[2]; + x = 0; + } + + l = 0; + y = 0; + start_in_checker[3] = start_in_checker[2]; + do { + if (y >= checker_edge_size) { + + start_in_checker[3] = !start_in_checker[3]; + y = 0; + } + + m = 0; + z = 0; +#if CKRBRD_HS_DR_PIO_TEST__VERIFY_DATA__DEBUG + HDfprintf(stdout, "%d, %d, %d, %d, %d:", i, j, k, l, m); +#endif + in_checker = start_in_checker[3]; + do { +#if CKRBRD_HS_DR_PIO_TEST__VERIFY_DATA__DEBUG + HDfprintf(stdout, " %d", (int)(*val_ptr)); +#endif + if (z >= checker_edge_size) { + + in_checker = !in_checker; + z = 0; + } + + if (in_checker) { + + if (*val_ptr != expected_value) { + + good_data = FALSE; + } + + /* zero out buffer for re-use */ + *val_ptr = 0; + } + else if (*val_ptr != 0) { + + good_data = FALSE; + + /* zero out buffer for re-use */ + *val_ptr = 0; + } + + val_ptr++; + expected_value++; + m++; + z++; + + } while ((rank >= (test_max_rank - 4)) && (m < edge_size)); +#if CKRBRD_HS_DR_PIO_TEST__VERIFY_DATA__DEBUG + HDfprintf(stdout, "\n"); +#endif + l++; + y++; + } while ((rank >= (test_max_rank - 3)) && (l < edge_size)); + k++; + x++; + } while ((rank >= (test_max_rank - 2)) && (k < edge_size)); + j++; + w++; + } while ((rank >= (test_max_rank - 1)) && (j < edge_size)); + i++; + v++; +} while ((rank >= test_max_rank) && (i < edge_size)); + +return (good_data); + +} /* ckrbrd_hs_dr_pio_test__verify_data() */ + +/*------------------------------------------------------------------------- + * Function: ckrbrd_hs_dr_pio_test__d2m_l2s() + * + * Purpose: Part one of a series of tests of I/O to/from hyperslab + * selections of different rank in the parallel. + * + * Verify that we can read from disk correctly using checker + * board selections of different rank that + * H5Sselect_shape_same() views as being of the same shape. + * + * In this function, we test this by reading small_rank - 1 + * checker board slices from the on disk large cube, and + * verifying that the data read is correct. Verify that + * H5Sselect_shape_same() returns true on the memory and + * file selections. + * + * Return: void + * + * Programmer: JRM -- 9/15/11 + * + *------------------------------------------------------------------------- + */ + +#define CHECKER_BOARD_HS_DR_PIO_TEST__D2M_L2S__DEBUG 0 + +static void +ckrbrd_hs_dr_pio_test__d2m_l2s(struct hs_dr_pio_test_vars_t *tv_ptr) +{ +#if CHECKER_BOARD_HS_DR_PIO_TEST__D2M_L2S__DEBUG + const char *fcnName = "ckrbrd_hs_dr_pio_test__d2m_l2s()"; + uint32_t *ptr_0; +#endif /* CHECKER_BOARD_HS_DR_PIO_TEST__D2M_L2S__DEBUG */ + hbool_t data_ok = FALSE; + int i, j, k, l; + uint32_t expected_value; + int mpi_rank; /* needed by VRFY */ + hsize_t sel_start[PAR_SS_DR_MAX_RANK]; + htri_t check; /* Shape comparison return value */ + herr_t ret; /* Generic return value */ + + /* initialize the local copy of mpi_rank */ + mpi_rank = tv_ptr->mpi_rank; + + /* first, verify that we can read from disk correctly using selections + * of different rank that H5Sselect_shape_same() views as being of the + * same shape. + * + * Start by reading a (small_rank - 1)-D checker board slice from this + * processes slice of the on disk large data set, and verifying that the + * data read is correct. Verify that H5Sselect_shape_same() returns + * true on the memory and file selections. + * + * The first step is to set up the needed checker board selection in the + * in memory small small cube + */ + + sel_start[0] = sel_start[1] = sel_start[2] = sel_start[3] = sel_start[4] = 0; + sel_start[tv_ptr->small_ds_offset] = (hsize_t)(tv_ptr->mpi_rank); + + ckrbrd_hs_dr_pio_test__slct_ckrbrd(tv_ptr->mpi_rank, tv_ptr->small_ds_slice_sid, tv_ptr->small_rank - 1, + tv_ptr->edge_size, tv_ptr->checker_edge_size, tv_ptr->small_rank - 1, + sel_start); + + /* zero out the buffer we will be reading into */ + HDmemset(tv_ptr->small_ds_slice_buf, 0, sizeof(uint32_t) * tv_ptr->small_ds_slice_size); + +#if CHECKER_BOARD_HS_DR_PIO_TEST__D2M_L2S__DEBUG + HDfprintf(stdout, "%s:%d: initial small_ds_slice_buf = ", fcnName, tv_ptr->mpi_rank); + ptr_0 = tv_ptr->small_ds_slice_buf; + for (i = 0; i < (int)(tv_ptr->small_ds_slice_size); i++) { + HDfprintf(stdout, "%d ", (int)(*ptr_0)); + ptr_0++; + } + HDfprintf(stdout, "\n"); +#endif /* CHECKER_BOARD_HS_DR_PIO_TEST__D2M_L2S__DEBUG */ + + /* set up start, stride, count, and block -- note that we will + * change start[] so as to read slices of the large cube. + */ + for (i = 0; i < PAR_SS_DR_MAX_RANK; i++) { + + tv_ptr->start[i] = 0; + tv_ptr->stride[i] = (hsize_t)(2 * tv_ptr->edge_size); + tv_ptr->count[i] = 1; + if ((PAR_SS_DR_MAX_RANK - i) > (tv_ptr->small_rank - 1)) { + + tv_ptr->block[i] = 1; + } + else { + + tv_ptr->block[i] = (hsize_t)(tv_ptr->edge_size); + } + } + +#if CHECKER_BOARD_HS_DR_PIO_TEST__D2M_L2S__DEBUG + HDfprintf(stdout, "%s:%d: reading slice from big ds on disk into small ds slice.\n", fcnName, + tv_ptr->mpi_rank); +#endif /* CHECKER_BOARD_HS_DR_PIO_TEST__D2M_L2S__DEBUG */ + /* in serial versions of this test, we loop through all the dimensions + * of the large data set. However, in the parallel version, each + * process only works with that slice of the large cube indicated + * by its rank -- hence we set the most slowly changing index to + * mpi_rank, and don't iterate over it. + */ + + if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 0) { + + i = tv_ptr->mpi_rank; + } + else { + + i = 0; + } + + /* since large_rank is at most PAR_SS_DR_MAX_RANK, no need to + * loop over it -- either we are setting i to mpi_rank, or + * we are setting it to zero. It will not change during the + * test. + */ + + if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 1) { + + j = tv_ptr->mpi_rank; + } + else { + + j = 0; + } + + do { + if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 2) { + + k = tv_ptr->mpi_rank; + } + else { + + k = 0; + } + + do { + /* since small rank >= 2 and large_rank > small_rank, we + * have large_rank >= 3. Since PAR_SS_DR_MAX_RANK == 5 + * (baring major re-orgaization), this gives us: + * + * (PAR_SS_DR_MAX_RANK - large_rank) <= 2 + * + * so no need to repeat the test in the outer loops -- + * just set l = 0. + */ + + l = 0; + do { + if ((tv_ptr->skips)++ < tv_ptr->max_skips) { /* skip the test */ + + (tv_ptr->tests_skipped)++; + } + else { /* run the test */ + + tv_ptr->skips = 0; /* reset the skips counter */ + + /* we know that small_rank - 1 >= 1 and that + * large_rank > small_rank by the assertions at the head + * of this function. Thus no need for another inner loop. + */ + tv_ptr->start[0] = (hsize_t)i; + tv_ptr->start[1] = (hsize_t)j; + tv_ptr->start[2] = (hsize_t)k; + tv_ptr->start[3] = (hsize_t)l; + tv_ptr->start[4] = 0; + + HDassert((tv_ptr->start[0] == 0) || (0 < tv_ptr->small_ds_offset + 1)); + HDassert((tv_ptr->start[1] == 0) || (1 < tv_ptr->small_ds_offset + 1)); + HDassert((tv_ptr->start[2] == 0) || (2 < tv_ptr->small_ds_offset + 1)); + HDassert((tv_ptr->start[3] == 0) || (3 < tv_ptr->small_ds_offset + 1)); + HDassert((tv_ptr->start[4] == 0) || (4 < tv_ptr->small_ds_offset + 1)); + + ckrbrd_hs_dr_pio_test__slct_ckrbrd( + tv_ptr->mpi_rank, tv_ptr->file_large_ds_sid_0, tv_ptr->large_rank, tv_ptr->edge_size, + tv_ptr->checker_edge_size, tv_ptr->small_rank - 1, tv_ptr->start); + + /* verify that H5Sselect_shape_same() reports the two + * selections as having the same shape. + */ + check = H5Sselect_shape_same(tv_ptr->small_ds_slice_sid, tv_ptr->file_large_ds_sid_0); + VRFY((check == TRUE), "H5Sselect_shape_same passed"); + + /* Read selection from disk */ +#if CHECKER_BOARD_HS_DR_PIO_TEST__D2M_L2S__DEBUG + HDfprintf(stdout, "%s:%d: start = %d %d %d %d %d.\n", fcnName, tv_ptr->mpi_rank, + tv_ptr->start[0], tv_ptr->start[1], tv_ptr->start[2], tv_ptr->start[3], + tv_ptr->start[4]); + HDfprintf(stdout, "%s slice/file extent dims = %d/%d.\n", fcnName, + H5Sget_simple_extent_ndims(tv_ptr->small_ds_slice_sid), + H5Sget_simple_extent_ndims(tv_ptr->file_large_ds_sid_0)); +#endif /* CHECKER_BOARD_HS_DR_PIO_TEST__D2M_L2S__DEBUG */ + + ret = + H5Dread(tv_ptr->large_dataset, H5T_NATIVE_UINT32, tv_ptr->small_ds_slice_sid, + tv_ptr->file_large_ds_sid_0, tv_ptr->xfer_plist, tv_ptr->small_ds_slice_buf); + VRFY((ret >= 0), "H5Dread() slice from large ds succeeded."); + +#if CHECKER_BOARD_HS_DR_PIO_TEST__D2M_L2S__DEBUG + HDfprintf(stdout, "%s:%d: H5Dread() returns.\n", fcnName, tv_ptr->mpi_rank); +#endif /* CHECKER_BOARD_HS_DR_PIO_TEST__D2M_L2S__DEBUG */ + + /* verify that expected data is retrieved */ + + expected_value = + (uint32_t)((i * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size * + tv_ptr->edge_size) + + (j * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size) + + (k * tv_ptr->edge_size * tv_ptr->edge_size) + (l * tv_ptr->edge_size)); + + data_ok = ckrbrd_hs_dr_pio_test__verify_data( + tv_ptr->small_ds_slice_buf, tv_ptr->small_rank - 1, tv_ptr->edge_size, + tv_ptr->checker_edge_size, expected_value, (hbool_t)TRUE); + + VRFY((data_ok == TRUE), "small slice read from large ds data good."); + + (tv_ptr->tests_run)++; + } + + l++; + + (tv_ptr->total_tests)++; + + } while ((tv_ptr->large_rank > 2) && ((tv_ptr->small_rank - 1) <= 1) && (l < tv_ptr->edge_size)); + k++; + } while ((tv_ptr->large_rank > 3) && ((tv_ptr->small_rank - 1) <= 2) && (k < tv_ptr->edge_size)); + j++; + } while ((tv_ptr->large_rank > 4) && ((tv_ptr->small_rank - 1) <= 3) && (j < tv_ptr->edge_size)); + + return; + +} /* ckrbrd_hs_dr_pio_test__d2m_l2s() */ + +/*------------------------------------------------------------------------- + * Function: ckrbrd_hs_dr_pio_test__d2m_s2l() + * + * Purpose: Part two of a series of tests of I/O to/from hyperslab + * selections of different rank in the parallel. + * + * Verify that we can read from disk correctly using + * selections of different rank that H5Sselect_shape_same() + * views as being of the same shape. + * + * In this function, we test this by reading checker board + * slices of the on disk small data set into slices through + * the in memory large data set, and verify that the correct + * data (and only the correct data) is read. + * + * Return: void + * + * Programmer: JRM -- 8/15/11 + * + *------------------------------------------------------------------------- + */ + +#define CHECKER_BOARD_HS_DR_PIO_TEST__D2M_S2L__DEBUG 0 + +static void +ckrbrd_hs_dr_pio_test__d2m_s2l(struct hs_dr_pio_test_vars_t *tv_ptr) +{ +#if CHECKER_BOARD_HS_DR_PIO_TEST__D2M_S2L__DEBUG + const char *fcnName = "ckrbrd_hs_dr_pio_test__d2m_s2l()"; +#endif /* CHECKER_BOARD_HS_DR_PIO_TEST__D2M_S2L__DEBUG */ + hbool_t data_ok = FALSE; + int i, j, k, l; + size_t u; + size_t start_index; + size_t stop_index; + uint32_t expected_value; + uint32_t *ptr_1; + int mpi_rank; /* needed by VRFY */ + hsize_t sel_start[PAR_SS_DR_MAX_RANK]; + htri_t check; /* Shape comparison return value */ + herr_t ret; /* Generic return value */ + + /* initialize the local copy of mpi_rank */ + mpi_rank = tv_ptr->mpi_rank; + + /* similarly, read slices of the on disk small data set into slices + * through the in memory large data set, and verify that the correct + * data (and only the correct data) is read. + */ + + sel_start[0] = sel_start[1] = sel_start[2] = sel_start[3] = sel_start[4] = 0; + sel_start[tv_ptr->small_ds_offset] = (hsize_t)(tv_ptr->mpi_rank); + + ckrbrd_hs_dr_pio_test__slct_ckrbrd(tv_ptr->mpi_rank, tv_ptr->file_small_ds_sid_0, tv_ptr->small_rank, + tv_ptr->edge_size, tv_ptr->checker_edge_size, tv_ptr->small_rank - 1, + sel_start); + +#if CHECKER_BOARD_HS_DR_PIO_TEST__D2M_S2L__DEBUG + HDfprintf(stdout, "%s reading slices of on disk small data set into slices of big data set.\n", fcnName); +#endif /* CHECKER_BOARD_HS_DR_PIO_TEST__D2M_S2L__DEBUG */ + + /* zero out the buffer we will be reading into */ + HDmemset(tv_ptr->large_ds_buf_1, 0, sizeof(uint32_t) * tv_ptr->large_ds_size); + + /* set up start, stride, count, and block -- note that we will + * change start[] so as to read the slice of the small data set + * into different slices of the process slice of the large data + * set. + */ + for (i = 0; i < PAR_SS_DR_MAX_RANK; i++) { + + tv_ptr->start[i] = 0; + tv_ptr->stride[i] = (hsize_t)(2 * tv_ptr->edge_size); + tv_ptr->count[i] = 1; + if ((PAR_SS_DR_MAX_RANK - i) > (tv_ptr->small_rank - 1)) { + + tv_ptr->block[i] = 1; + } + else { + + tv_ptr->block[i] = (hsize_t)(tv_ptr->edge_size); + } + } + + /* in serial versions of this test, we loop through all the dimensions + * of the large data set that don't appear in the small data set. + * + * However, in the parallel version, each process only works with that + * slice of the large (and small) data set indicated by its rank -- hence + * we set the most slowly changing index to mpi_rank, and don't iterate + * over it. + */ + + if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 0) { + + i = tv_ptr->mpi_rank; + } + else { + + i = 0; + } + + /* since large_rank is at most PAR_SS_DR_MAX_RANK, no need to + * loop over it -- either we are setting i to mpi_rank, or + * we are setting it to zero. It will not change during the + * test. + */ + + if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 1) { + + j = tv_ptr->mpi_rank; + } + else { + + j = 0; + } + + do { + if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 2) { + + k = tv_ptr->mpi_rank; + } + else { + + k = 0; + } + + do { + /* since small rank >= 2 and large_rank > small_rank, we + * have large_rank >= 3. Since PAR_SS_DR_MAX_RANK == 5 + * (baring major re-orgaization), this gives us: + * + * (PAR_SS_DR_MAX_RANK - large_rank) <= 2 + * + * so no need to repeat the test in the outer loops -- + * just set l = 0. + */ + + l = 0; + do { + if ((tv_ptr->skips)++ < tv_ptr->max_skips) { /* skip the test */ + + (tv_ptr->tests_skipped)++; + } + else { /* run the test */ + + tv_ptr->skips = 0; /* reset the skips counter */ + + /* we know that small_rank >= 1 and that large_rank > small_rank + * by the assertions at the head of this function. Thus no + * need for another inner loop. + */ + tv_ptr->start[0] = (hsize_t)i; + tv_ptr->start[1] = (hsize_t)j; + tv_ptr->start[2] = (hsize_t)k; + tv_ptr->start[3] = (hsize_t)l; + tv_ptr->start[4] = 0; + + HDassert((tv_ptr->start[0] == 0) || (0 < tv_ptr->small_ds_offset + 1)); + HDassert((tv_ptr->start[1] == 0) || (1 < tv_ptr->small_ds_offset + 1)); + HDassert((tv_ptr->start[2] == 0) || (2 < tv_ptr->small_ds_offset + 1)); + HDassert((tv_ptr->start[3] == 0) || (3 < tv_ptr->small_ds_offset + 1)); + HDassert((tv_ptr->start[4] == 0) || (4 < tv_ptr->small_ds_offset + 1)); + + ckrbrd_hs_dr_pio_test__slct_ckrbrd( + tv_ptr->mpi_rank, tv_ptr->mem_large_ds_sid, tv_ptr->large_rank, tv_ptr->edge_size, + tv_ptr->checker_edge_size, tv_ptr->small_rank - 1, tv_ptr->start); + + /* verify that H5Sselect_shape_same() reports the two + * selections as having the same shape. + */ + check = H5Sselect_shape_same(tv_ptr->file_small_ds_sid_0, tv_ptr->mem_large_ds_sid); + VRFY((check == TRUE), "H5Sselect_shape_same passed"); + + /* Read selection from disk */ +#if CHECKER_BOARD_HS_DR_PIO_TEST__D2M_S2L__DEBUG + HDfprintf(stdout, "%s:%d: start = %d %d %d %d %d.\n", fcnName, tv_ptr->mpi_rank, + tv_ptr->start[0], tv_ptr->start[1], tv_ptr->start[2], tv_ptr->start[3], + tv_ptr->start[4]); + HDfprintf(stdout, "%s:%d: mem/file extent dims = %d/%d.\n", fcnName, tv_ptr->mpi_rank, + H5Sget_simple_extent_ndims(tv_ptr->large_ds_slice_sid), + H5Sget_simple_extent_ndims(tv_ptr->file_small_ds_sid_0)); +#endif /* CHECKER_BOARD_HS_DR_PIO_TEST__D2M_S2L__DEBUG */ + ret = H5Dread(tv_ptr->small_dataset, H5T_NATIVE_UINT32, tv_ptr->mem_large_ds_sid, + tv_ptr->file_small_ds_sid_0, tv_ptr->xfer_plist, tv_ptr->large_ds_buf_1); + VRFY((ret >= 0), "H5Dread() slice from small ds succeeded."); + + /* verify that the expected data and only the + * expected data was read. + */ + data_ok = TRUE; + ptr_1 = tv_ptr->large_ds_buf_1; + expected_value = (uint32_t)((size_t)(tv_ptr->mpi_rank) * tv_ptr->small_ds_slice_size); + start_index = + (size_t)((i * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size * + tv_ptr->edge_size) + + (j * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size) + + (k * tv_ptr->edge_size * tv_ptr->edge_size) + (l * tv_ptr->edge_size)); + stop_index = start_index + tv_ptr->small_ds_slice_size - 1; + +#if CHECKER_BOARD_HS_DR_PIO_TEST__D2M_S2L__DEBUG + { + int m, n; + + HDfprintf(stdout, "%s:%d: expected_value = %d.\n", fcnName, tv_ptr->mpi_rank, + expected_value); + HDfprintf(stdout, "%s:%d: start/stop index = %d/%d.\n", fcnName, tv_ptr->mpi_rank, + start_index, stop_index); + n = 0; + for (m = 0; (unsigned)m < tv_ptr->large_ds_size; m++) { + HDfprintf(stdout, "%d ", (int)(*ptr_1)); + ptr_1++; + n++; + if (n >= tv_ptr->edge_size) { + HDfprintf(stdout, "\n"); + n = 0; + } + } + HDfprintf(stdout, "\n"); + ptr_1 = tv_ptr->large_ds_buf_1; + } +#endif /* CHECKER_BOARD_HS_DR_PIO_TEST__D2M_S2L__DEBUG */ + + HDassert(start_index < stop_index); + HDassert(stop_index <= tv_ptr->large_ds_size); + + for (u = 0; u < start_index; u++) { + + if (*ptr_1 != 0) { + + data_ok = FALSE; + } + + /* zero out the value for the next pass */ + *ptr_1 = 0; + + ptr_1++; + } + + VRFY((data_ok == TRUE), "slice read from small to large ds data good(1)."); + + data_ok = ckrbrd_hs_dr_pio_test__verify_data(ptr_1, tv_ptr->small_rank - 1, + tv_ptr->edge_size, tv_ptr->checker_edge_size, + expected_value, (hbool_t)TRUE); + + VRFY((data_ok == TRUE), "slice read from small to large ds data good(2)."); + + ptr_1 = tv_ptr->large_ds_buf_1 + stop_index + 1; + + for (u = stop_index + 1; u < tv_ptr->large_ds_size; u++) { + + if (*ptr_1 != 0) { + + data_ok = FALSE; + } + + /* zero out the value for the next pass */ + *ptr_1 = 0; + + ptr_1++; + } + + VRFY((data_ok == TRUE), "slice read from small to large ds data good(3)."); + + (tv_ptr->tests_run)++; + } + + l++; + + (tv_ptr->total_tests)++; + + } while ((tv_ptr->large_rank > 2) && ((tv_ptr->small_rank - 1) <= 1) && (l < tv_ptr->edge_size)); + k++; + } while ((tv_ptr->large_rank > 3) && ((tv_ptr->small_rank - 1) <= 2) && (k < tv_ptr->edge_size)); + j++; + } while ((tv_ptr->large_rank > 4) && ((tv_ptr->small_rank - 1) <= 3) && (j < tv_ptr->edge_size)); + + return; + +} /* ckrbrd_hs_dr_pio_test__d2m_s2l() */ + +/*------------------------------------------------------------------------- + * Function: ckrbrd_hs_dr_pio_test__m2d_l2s() + * + * Purpose: Part three of a series of tests of I/O to/from checker + * board hyperslab selections of different rank in the + * parallel. + * + * Verify that we can write from memory to file using checker + * board selections of different rank that + * H5Sselect_shape_same() views as being of the same shape. + * + * Do this by writing small_rank - 1 dimensional checker + * board slices from the in memory large data set to the on + * disk small cube dataset. After each write, read the + * slice of the small dataset back from disk, and verify + * that it contains the expected data. Verify that + * H5Sselect_shape_same() returns true on the memory and + * file selections. + * + * Return: void + * + * Programmer: JRM -- 8/15/11 + * + *------------------------------------------------------------------------- + */ + +#define CHECKER_BOARD_HS_DR_PIO_TEST__M2D_L2S__DEBUG 0 + +static void +ckrbrd_hs_dr_pio_test__m2d_l2s(struct hs_dr_pio_test_vars_t *tv_ptr) +{ +#if CHECKER_BOARD_HS_DR_PIO_TEST__M2D_L2S__DEBUG + const char *fcnName = "ckrbrd_hs_dr_pio_test__m2d_l2s()"; +#endif /* CHECKER_BOARD_HS_DR_PIO_TEST__M2D_L2S__DEBUG */ + hbool_t data_ok = FALSE; + int i, j, k, l; + size_t u; + size_t start_index; + size_t stop_index; + uint32_t expected_value; + uint32_t *ptr_1; + int mpi_rank; /* needed by VRFY */ + hsize_t sel_start[PAR_SS_DR_MAX_RANK]; + htri_t check; /* Shape comparison return value */ + herr_t ret; /* Generic return value */ + + /* initialize the local copy of mpi_rank */ + mpi_rank = tv_ptr->mpi_rank; + + /* now we go in the opposite direction, verifying that we can write + * from memory to file using selections of different rank that + * H5Sselect_shape_same() views as being of the same shape. + * + * Start by writing small_rank - 1 D slices from the in memory large data + * set to the on disk small dataset. After each write, read the slice of + * the small dataset back from disk, and verify that it contains the + * expected data. Verify that H5Sselect_shape_same() returns true on + * the memory and file selections. + */ + + tv_ptr->start[0] = (hsize_t)(tv_ptr->mpi_rank); + tv_ptr->stride[0] = (hsize_t)(2 * (tv_ptr->mpi_size + 1)); + tv_ptr->count[0] = 1; + tv_ptr->block[0] = 1; + + for (i = 1; i < tv_ptr->large_rank; i++) { + + tv_ptr->start[i] = 0; + tv_ptr->stride[i] = (hsize_t)(2 * tv_ptr->edge_size); + tv_ptr->count[i] = 1; + tv_ptr->block[i] = (hsize_t)(tv_ptr->edge_size); + } + + ret = H5Sselect_hyperslab(tv_ptr->file_small_ds_sid_0, H5S_SELECT_SET, tv_ptr->start, tv_ptr->stride, + tv_ptr->count, tv_ptr->block); + VRFY((ret >= 0), "H5Sselect_hyperslab(file_small_ds_sid_0, set) succeeded"); + + ret = H5Sselect_hyperslab(tv_ptr->mem_small_ds_sid, H5S_SELECT_SET, tv_ptr->start, tv_ptr->stride, + tv_ptr->count, tv_ptr->block); + VRFY((ret >= 0), "H5Sselect_hyperslab(mem_small_ds_sid, set) succeeded"); + + sel_start[0] = sel_start[1] = sel_start[2] = sel_start[3] = sel_start[4] = 0; + sel_start[tv_ptr->small_ds_offset] = (hsize_t)(tv_ptr->mpi_rank); + + ckrbrd_hs_dr_pio_test__slct_ckrbrd(tv_ptr->mpi_rank, tv_ptr->file_small_ds_sid_1, tv_ptr->small_rank, + tv_ptr->edge_size, tv_ptr->checker_edge_size, tv_ptr->small_rank - 1, + sel_start); + + /* set up start, stride, count, and block -- note that we will + * change start[] so as to read slices of the large cube. + */ + for (i = 0; i < PAR_SS_DR_MAX_RANK; i++) { + + tv_ptr->start[i] = 0; + tv_ptr->stride[i] = (hsize_t)(2 * tv_ptr->edge_size); + tv_ptr->count[i] = 1; + if ((PAR_SS_DR_MAX_RANK - i) > (tv_ptr->small_rank - 1)) { + + tv_ptr->block[i] = 1; + } + else { + + tv_ptr->block[i] = (hsize_t)(tv_ptr->edge_size); + } + } + + /* zero out the in memory small ds */ + HDmemset(tv_ptr->small_ds_buf_1, 0, sizeof(uint32_t) * tv_ptr->small_ds_size); + +#if CHECKER_BOARD_HS_DR_PIO_TEST__M2D_L2S__DEBUG + HDfprintf(stdout, + "%s writing checker boards selections of slices from big ds to slices of small ds on disk.\n", + fcnName); +#endif /* CHECKER_BOARD_HS_DR_PIO_TEST__M2D_L2S__DEBUG */ + + /* in serial versions of this test, we loop through all the dimensions + * of the large data set that don't appear in the small data set. + * + * However, in the parallel version, each process only works with that + * slice of the large (and small) data set indicated by its rank -- hence + * we set the most slowly changing index to mpi_rank, and don't iterate + * over it. + */ + + if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 0) { + + i = tv_ptr->mpi_rank; + } + else { + + i = 0; + } + + /* since large_rank is at most PAR_SS_DR_MAX_RANK, no need to + * loop over it -- either we are setting i to mpi_rank, or + * we are setting it to zero. It will not change during the + * test. + */ + + if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 1) { + + j = tv_ptr->mpi_rank; + } + else { + + j = 0; + } + + j = 0; + do { + if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 2) { + + k = tv_ptr->mpi_rank; + } + else { + + k = 0; + } + + do { + /* since small rank >= 2 and large_rank > small_rank, we + * have large_rank >= 3. Since PAR_SS_DR_MAX_RANK == 5 + * (baring major re-orgaization), this gives us: + * + * (PAR_SS_DR_MAX_RANK - large_rank) <= 2 + * + * so no need to repeat the test in the outer loops -- + * just set l = 0. + */ + + l = 0; + do { + if ((tv_ptr->skips)++ < tv_ptr->max_skips) { /* skip the test */ + + (tv_ptr->tests_skipped)++; + } + else { /* run the test */ + + tv_ptr->skips = 0; /* reset the skips counter */ + + /* we know that small_rank >= 1 and that large_rank > small_rank + * by the assertions at the head of this function. Thus no + * need for another inner loop. + */ + + /* zero out this rank's slice of the on disk small data set */ + ret = H5Dwrite(tv_ptr->small_dataset, H5T_NATIVE_UINT32, tv_ptr->mem_small_ds_sid, + tv_ptr->file_small_ds_sid_0, tv_ptr->xfer_plist, tv_ptr->small_ds_buf_2); + VRFY((ret >= 0), "H5Dwrite() zero slice to small ds succeeded."); + + /* select the portion of the in memory large cube from which we + * are going to write data. + */ + tv_ptr->start[0] = (hsize_t)i; + tv_ptr->start[1] = (hsize_t)j; + tv_ptr->start[2] = (hsize_t)k; + tv_ptr->start[3] = (hsize_t)l; + tv_ptr->start[4] = 0; + + HDassert((tv_ptr->start[0] == 0) || (0 < tv_ptr->small_ds_offset + 1)); + HDassert((tv_ptr->start[1] == 0) || (1 < tv_ptr->small_ds_offset + 1)); + HDassert((tv_ptr->start[2] == 0) || (2 < tv_ptr->small_ds_offset + 1)); + HDassert((tv_ptr->start[3] == 0) || (3 < tv_ptr->small_ds_offset + 1)); + HDassert((tv_ptr->start[4] == 0) || (4 < tv_ptr->small_ds_offset + 1)); + + ckrbrd_hs_dr_pio_test__slct_ckrbrd( + tv_ptr->mpi_rank, tv_ptr->mem_large_ds_sid, tv_ptr->large_rank, tv_ptr->edge_size, + tv_ptr->checker_edge_size, tv_ptr->small_rank - 1, tv_ptr->start); + + /* verify that H5Sselect_shape_same() reports the in + * memory checkerboard selection of the slice through the + * large dataset and the checkerboard selection of the process + * slice of the small data set as having the same shape. + */ + check = H5Sselect_shape_same(tv_ptr->file_small_ds_sid_1, tv_ptr->mem_large_ds_sid); + VRFY((check == TRUE), "H5Sselect_shape_same passed."); + + /* write the checker board selection of the slice from the in + * memory large data set to the slice of the on disk small + * dataset. + */ +#if CHECKER_BOARD_HS_DR_PIO_TEST__M2D_L2S__DEBUG + HDfprintf(stdout, "%s:%d: start = %d %d %d %d %d.\n", fcnName, tv_ptr->mpi_rank, + tv_ptr->start[0], tv_ptr->start[1], tv_ptr->start[2], tv_ptr->start[3], + tv_ptr->start[4]); + HDfprintf(stdout, "%s:%d: mem/file extent dims = %d/%d.\n", fcnName, tv_ptr->mpi_rank, + H5Sget_simple_extent_ndims(tv_ptr->mem_large_ds_sid), + H5Sget_simple_extent_ndims(tv_ptr->file_small_ds_sid_1)); +#endif /* CHECKER_BOARD_HS_DR_PIO_TEST__M2D_L2S__DEBUG */ + ret = H5Dwrite(tv_ptr->small_dataset, H5T_NATIVE_UINT32, tv_ptr->mem_large_ds_sid, + tv_ptr->file_small_ds_sid_1, tv_ptr->xfer_plist, tv_ptr->large_ds_buf_0); + VRFY((ret >= 0), "H5Dwrite() slice to large ds succeeded."); + + /* read the on disk process slice of the small dataset into memory */ + ret = H5Dread(tv_ptr->small_dataset, H5T_NATIVE_UINT32, tv_ptr->mem_small_ds_sid, + tv_ptr->file_small_ds_sid_0, tv_ptr->xfer_plist, tv_ptr->small_ds_buf_1); + VRFY((ret >= 0), "H5Dread() slice from small ds succeeded."); + + /* verify that expected data is retrieved */ + + expected_value = + (uint32_t)((i * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size * + tv_ptr->edge_size) + + (j * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size) + + (k * tv_ptr->edge_size * tv_ptr->edge_size) + (l * tv_ptr->edge_size)); + + start_index = (size_t)(tv_ptr->mpi_rank) * tv_ptr->small_ds_slice_size; + stop_index = start_index + tv_ptr->small_ds_slice_size - 1; + + HDassert(start_index < stop_index); + HDassert(stop_index <= tv_ptr->small_ds_size); + + data_ok = TRUE; + + ptr_1 = tv_ptr->small_ds_buf_1; + for (u = 0; u < start_index; u++, ptr_1++) { + + if (*ptr_1 != 0) { + + data_ok = FALSE; + *ptr_1 = 0; + } + } + + data_ok &= ckrbrd_hs_dr_pio_test__verify_data( + tv_ptr->small_ds_buf_1 + start_index, tv_ptr->small_rank - 1, tv_ptr->edge_size, + tv_ptr->checker_edge_size, expected_value, (hbool_t)TRUE); + + ptr_1 = tv_ptr->small_ds_buf_1; + for (u = stop_index; u < tv_ptr->small_ds_size; u++, ptr_1++) { + + if (*ptr_1 != 0) { + + data_ok = FALSE; + *ptr_1 = 0; + } + } + + VRFY((data_ok == TRUE), "large slice write slice to small slice data good."); + + (tv_ptr->tests_run)++; + } + + l++; + + (tv_ptr->total_tests)++; + + } while ((tv_ptr->large_rank > 2) && ((tv_ptr->small_rank - 1) <= 1) && (l < tv_ptr->edge_size)); + k++; + } while ((tv_ptr->large_rank > 3) && ((tv_ptr->small_rank - 1) <= 2) && (k < tv_ptr->edge_size)); + j++; + } while ((tv_ptr->large_rank > 4) && ((tv_ptr->small_rank - 1) <= 3) && (j < tv_ptr->edge_size)); + + return; + +} /* ckrbrd_hs_dr_pio_test__m2d_l2s() */ + +/*------------------------------------------------------------------------- + * Function: ckrbrd_hs_dr_pio_test__m2d_s2l() + * + * Purpose: Part four of a series of tests of I/O to/from checker + * board hyperslab selections of different rank in the parallel. + * + * Verify that we can write from memory to file using + * selections of different rank that H5Sselect_shape_same() + * views as being of the same shape. + * + * Do this by writing checker board selections of the contents + * of the process's slice of the in memory small data set to + * slices of the on disk large data set. After each write, + * read the process's slice of the large data set back into + * memory, and verify that it contains the expected data. + * + * Verify that H5Sselect_shape_same() returns true on the + * memory and file selections. + * + * Return: void + * + * Programmer: JRM -- 8/15/11 + * + *------------------------------------------------------------------------- + */ + +#define CHECKER_BOARD_HS_DR_PIO_TEST__M2D_S2L__DEBUG 0 + +static void +ckrbrd_hs_dr_pio_test__m2d_s2l(struct hs_dr_pio_test_vars_t *tv_ptr) +{ +#if CHECKER_BOARD_HS_DR_PIO_TEST__M2D_S2L__DEBUG + const char *fcnName = "ckrbrd_hs_dr_pio_test__m2d_s2l()"; +#endif /* CONTIG_HS_DR_PIO_TEST__M2D_S2L__DEBUG */ + hbool_t data_ok = FALSE; + int i, j, k, l; + size_t u; + size_t start_index; + size_t stop_index; + uint32_t expected_value; + uint32_t *ptr_1; + int mpi_rank; /* needed by VRFY */ + hsize_t sel_start[PAR_SS_DR_MAX_RANK]; + htri_t check; /* Shape comparison return value */ + herr_t ret; /* Generic return value */ + + /* initialize the local copy of mpi_rank */ + mpi_rank = tv_ptr->mpi_rank; + + /* Now write the contents of the process's slice of the in memory + * small data set to slices of the on disk large data set. After + * each write, read the process's slice of the large data set back + * into memory, and verify that it contains the expected data. + * Verify that H5Sselect_shape_same() returns true on the memory + * and file selections. + */ + + tv_ptr->start[0] = (hsize_t)(tv_ptr->mpi_rank); + tv_ptr->stride[0] = (hsize_t)(2 * (tv_ptr->mpi_size + 1)); + tv_ptr->count[0] = 1; + tv_ptr->block[0] = 1; + + for (i = 1; i < tv_ptr->large_rank; i++) { + + tv_ptr->start[i] = 0; + tv_ptr->stride[i] = (hsize_t)(2 * tv_ptr->edge_size); + tv_ptr->count[i] = 1; + tv_ptr->block[i] = (hsize_t)(tv_ptr->edge_size); + } + + ret = H5Sselect_hyperslab(tv_ptr->file_large_ds_sid_0, H5S_SELECT_SET, tv_ptr->start, tv_ptr->stride, + tv_ptr->count, tv_ptr->block); + VRFY((ret >= 0), "H5Sselect_hyperslab(file_large_ds_sid_0, set) succeeded"); + + ret = H5Sselect_hyperslab(tv_ptr->mem_large_ds_sid, H5S_SELECT_SET, tv_ptr->start, tv_ptr->stride, + tv_ptr->count, tv_ptr->block); + VRFY((ret >= 0), "H5Sselect_hyperslab(tv_ptr->mem_large_ds_sid, set) succeeded"); + + /* setup a checkerboard selection of the slice of the in memory small + * data set associated with the process's mpi rank. + */ + + sel_start[0] = sel_start[1] = sel_start[2] = sel_start[3] = sel_start[4] = 0; + sel_start[tv_ptr->small_ds_offset] = (hsize_t)(tv_ptr->mpi_rank); + + ckrbrd_hs_dr_pio_test__slct_ckrbrd(tv_ptr->mpi_rank, tv_ptr->mem_small_ds_sid, tv_ptr->small_rank, + tv_ptr->edge_size, tv_ptr->checker_edge_size, tv_ptr->small_rank - 1, + sel_start); + + /* set up start, stride, count, and block -- note that we will + * change start[] so as to write checkerboard selections of slices + * of the small data set to slices of the large data set. + */ + for (i = 0; i < PAR_SS_DR_MAX_RANK; i++) { + + tv_ptr->start[i] = 0; + tv_ptr->stride[i] = (hsize_t)(2 * tv_ptr->edge_size); + tv_ptr->count[i] = 1; + if ((PAR_SS_DR_MAX_RANK - i) > (tv_ptr->small_rank - 1)) { + + tv_ptr->block[i] = 1; + } + else { + + tv_ptr->block[i] = (hsize_t)(tv_ptr->edge_size); + } + } + + /* zero out the in memory large ds */ + HDmemset(tv_ptr->large_ds_buf_1, 0, sizeof(uint32_t) * tv_ptr->large_ds_size); + +#if CHECKER_BOARD_HS_DR_PIO_TEST__M2D_S2L__DEBUG + HDfprintf(stdout, + "%s writing process checkerboard selections of slices of small ds to process slices of large " + "ds on disk.\n", + fcnName); +#endif /* CHECKER_BOARD_HS_DR_PIO_TEST__M2D_S2L__DEBUG */ + + if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 0) { + + i = tv_ptr->mpi_rank; + } + else { + + i = 0; + } + + /* since large_rank is at most PAR_SS_DR_MAX_RANK, no need to + * loop over it -- either we are setting i to mpi_rank, or + * we are setting it to zero. It will not change during the + * test. + */ + + if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 1) { + + j = tv_ptr->mpi_rank; + } + else { + + j = 0; + } + + do { + if (PAR_SS_DR_MAX_RANK - tv_ptr->large_rank == 2) { + + k = tv_ptr->mpi_rank; + } + else { + + k = 0; + } + + do { + /* since small rank >= 2 and large_rank > small_rank, we + * have large_rank >= 3. Since PAR_SS_DR_MAX_RANK == 5 + * (baring major re-orgaization), this gives us: + * + * (PAR_SS_DR_MAX_RANK - large_rank) <= 2 + * + * so no need to repeat the test in the outer loops -- + * just set l = 0. + */ + + l = 0; + do { + if ((tv_ptr->skips)++ < tv_ptr->max_skips) { /* skip the test */ + + (tv_ptr->tests_skipped)++; + } + else { /* run the test */ + + tv_ptr->skips = 0; /* reset the skips counter */ + + /* we know that small_rank >= 1 and that large_rank > small_rank + * by the assertions at the head of this function. Thus no + * need for another inner loop. + */ + + /* Zero out this processes slice of the on disk large data set. + * Note that this will leave one slice with its original data + * as there is one more slice than processes. + */ + ret = H5Dwrite(tv_ptr->large_dataset, H5T_NATIVE_UINT32, tv_ptr->mem_large_ds_sid, + tv_ptr->file_large_ds_sid_0, tv_ptr->xfer_plist, tv_ptr->large_ds_buf_2); + VRFY((ret != FAIL), "H5Dwrite() to zero large ds succeeded"); + + /* select the portion of the in memory large cube to which we + * are going to write data. + */ + tv_ptr->start[0] = (hsize_t)i; + tv_ptr->start[1] = (hsize_t)j; + tv_ptr->start[2] = (hsize_t)k; + tv_ptr->start[3] = (hsize_t)l; + tv_ptr->start[4] = 0; + + HDassert((tv_ptr->start[0] == 0) || (0 < tv_ptr->small_ds_offset + 1)); + HDassert((tv_ptr->start[1] == 0) || (1 < tv_ptr->small_ds_offset + 1)); + HDassert((tv_ptr->start[2] == 0) || (2 < tv_ptr->small_ds_offset + 1)); + HDassert((tv_ptr->start[3] == 0) || (3 < tv_ptr->small_ds_offset + 1)); + HDassert((tv_ptr->start[4] == 0) || (4 < tv_ptr->small_ds_offset + 1)); + + ckrbrd_hs_dr_pio_test__slct_ckrbrd( + tv_ptr->mpi_rank, tv_ptr->file_large_ds_sid_1, tv_ptr->large_rank, tv_ptr->edge_size, + tv_ptr->checker_edge_size, tv_ptr->small_rank - 1, tv_ptr->start); + + /* verify that H5Sselect_shape_same() reports the in + * memory small data set slice selection and the + * on disk slice through the large data set selection + * as having the same shape. + */ + check = H5Sselect_shape_same(tv_ptr->mem_small_ds_sid, tv_ptr->file_large_ds_sid_1); + VRFY((check == TRUE), "H5Sselect_shape_same passed"); + + /* write the small data set slice from memory to the + * target slice of the disk data set + */ +#if CHECKER_BOARD_HS_DR_PIO_TEST__M2D_S2L__DEBUG + HDfprintf(stdout, "%s:%d: start = %d %d %d %d %d.\n", fcnName, tv_ptr->mpi_rank, + tv_ptr->start[0], tv_ptr->start[1], tv_ptr->start[2], tv_ptr->start[3], + tv_ptr->start[4]); + HDfprintf(stdout, "%s:%d: mem/file extent dims = %d/%d.\n", fcnName, tv_ptr->mpi_rank, + H5Sget_simple_extent_ndims(tv_ptr->mem_small_ds_sid), + H5Sget_simple_extent_ndims(tv_ptr->file_large_ds_sid_1)); +#endif /* CHECKER_BOARD_HS_DR_PIO_TEST__M2D_S2L__DEBUG */ + ret = H5Dwrite(tv_ptr->large_dataset, H5T_NATIVE_UINT32, tv_ptr->mem_small_ds_sid, + tv_ptr->file_large_ds_sid_1, tv_ptr->xfer_plist, tv_ptr->small_ds_buf_0); + VRFY((ret != FAIL), "H5Dwrite of small ds slice to large ds succeeded"); + + /* read this processes slice on the on disk large + * data set into memory. + */ + + ret = H5Dread(tv_ptr->large_dataset, H5T_NATIVE_UINT32, tv_ptr->mem_large_ds_sid, + tv_ptr->file_large_ds_sid_0, tv_ptr->xfer_plist, tv_ptr->large_ds_buf_1); + VRFY((ret != FAIL), "H5Dread() of process slice of large ds succeeded"); + + /* verify that the expected data and only the + * expected data was read. + */ + expected_value = (uint32_t)((size_t)(tv_ptr->mpi_rank) * tv_ptr->small_ds_slice_size); + + start_index = + (size_t)((i * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size * + tv_ptr->edge_size) + + (j * tv_ptr->edge_size * tv_ptr->edge_size * tv_ptr->edge_size) + + (k * tv_ptr->edge_size * tv_ptr->edge_size) + (l * tv_ptr->edge_size)); + stop_index = start_index + tv_ptr->small_ds_slice_size - 1; + + HDassert(start_index < stop_index); + HDassert(stop_index < tv_ptr->large_ds_size); + + data_ok = TRUE; + + ptr_1 = tv_ptr->large_ds_buf_1; + for (u = 0; u < start_index; u++, ptr_1++) { + + if (*ptr_1 != 0) { + + data_ok = FALSE; + *ptr_1 = 0; + } + } + + data_ok &= ckrbrd_hs_dr_pio_test__verify_data( + tv_ptr->large_ds_buf_1 + start_index, tv_ptr->small_rank - 1, tv_ptr->edge_size, + tv_ptr->checker_edge_size, expected_value, (hbool_t)TRUE); + + ptr_1 = tv_ptr->large_ds_buf_1; + for (u = stop_index; u < tv_ptr->small_ds_size; u++, ptr_1++) { + + if (*ptr_1 != 0) { + + data_ok = FALSE; + *ptr_1 = 0; + } + } + + VRFY((data_ok == TRUE), "small ds cb slice write to large ds slice data good."); + + (tv_ptr->tests_run)++; + } + + l++; + + (tv_ptr->total_tests)++; + + } while ((tv_ptr->large_rank > 2) && ((tv_ptr->small_rank - 1) <= 1) && (l < tv_ptr->edge_size)); + k++; + } while ((tv_ptr->large_rank > 3) && ((tv_ptr->small_rank - 1) <= 2) && (k < tv_ptr->edge_size)); + j++; + } while ((tv_ptr->large_rank > 4) && ((tv_ptr->small_rank - 1) <= 3) && (j < tv_ptr->edge_size)); + + return; + +} /* ckrbrd_hs_dr_pio_test__m2d_s2l() */ + +/*------------------------------------------------------------------------- + * Function: ckrbrd_hs_dr_pio_test__run_test() + * + * Purpose: Test I/O to/from checkerboard selections of hyperslabs of + * different rank in the parallel. + * + * Return: void + * + * Programmer: JRM -- 10/10/09 + * + *------------------------------------------------------------------------- + */ + +#define CKRBRD_HS_DR_PIO_TEST__RUN_TEST__DEBUG 0 + +static void +ckrbrd_hs_dr_pio_test__run_test(const int test_num, const int edge_size, const int checker_edge_size, + const int chunk_edge_size, const int small_rank, const int large_rank, + const hbool_t use_collective_io, const hid_t dset_type, + const int express_test, int *skips_ptr, int max_skips, + int64_t *total_tests_ptr, int64_t *tests_run_ptr, int64_t *tests_skipped_ptr, + int mpi_rank) + +{ +#if CKRBRD_HS_DR_PIO_TEST__RUN_TEST__DEBUG + const char *fcnName = "ckrbrd_hs_dr_pio_test__run_test()"; +#endif /* CKRBRD_HS_DR_PIO_TEST__RUN_TEST__DEBUG */ + struct hs_dr_pio_test_vars_t test_vars = { + /* int mpi_size = */ -1, + /* int mpi_rank = */ -1, + /* MPI_Comm mpi_comm = */ MPI_COMM_NULL, + /* MPI_Inf mpi_info = */ MPI_INFO_NULL, + /* int test_num = */ -1, + /* int edge_size = */ -1, + /* int checker_edge_size = */ -1, + /* int chunk_edge_size = */ -1, + /* int small_rank = */ -1, + /* int large_rank = */ -1, + /* hid_t dset_type = */ -1, + /* uint32_t * small_ds_buf_0 = */ NULL, + /* uint32_t * small_ds_buf_1 = */ NULL, + /* uint32_t * small_ds_buf_2 = */ NULL, + /* uint32_t * small_ds_slice_buf = */ NULL, + /* uint32_t * large_ds_buf_0 = */ NULL, + /* uint32_t * large_ds_buf_1 = */ NULL, + /* uint32_t * large_ds_buf_2 = */ NULL, + /* uint32_t * large_ds_slice_buf = */ NULL, + /* int small_ds_offset = */ -1, + /* int large_ds_offset = */ -1, + /* hid_t fid = */ -1, /* HDF5 file ID */ + /* hid_t xfer_plist = */ H5P_DEFAULT, + /* hid_t full_mem_small_ds_sid = */ -1, + /* hid_t full_file_small_ds_sid = */ -1, + /* hid_t mem_small_ds_sid = */ -1, + /* hid_t file_small_ds_sid_0 = */ -1, + /* hid_t file_small_ds_sid_1 = */ -1, + /* hid_t small_ds_slice_sid = */ -1, + /* hid_t full_mem_large_ds_sid = */ -1, + /* hid_t full_file_large_ds_sid = */ -1, + /* hid_t mem_large_ds_sid = */ -1, + /* hid_t file_large_ds_sid_0 = */ -1, + /* hid_t file_large_ds_sid_1 = */ -1, + /* hid_t file_large_ds_process_slice_sid = */ -1, + /* hid_t mem_large_ds_process_slice_sid = */ -1, + /* hid_t large_ds_slice_sid = */ -1, + /* hid_t small_dataset = */ -1, /* Dataset ID */ + /* hid_t large_dataset = */ -1, /* Dataset ID */ + /* size_t small_ds_size = */ 1, + /* size_t small_ds_slice_size = */ 1, + /* size_t large_ds_size = */ 1, + /* size_t large_ds_slice_size = */ 1, + /* hsize_t dims[PAR_SS_DR_MAX_RANK] = */ {0, 0, 0, 0, 0}, + /* hsize_t chunk_dims[PAR_SS_DR_MAX_RANK] = */ {0, 0, 0, 0, 0}, + /* hsize_t start[PAR_SS_DR_MAX_RANK] = */ {0, 0, 0, 0, 0}, + /* hsize_t stride[PAR_SS_DR_MAX_RANK] = */ {0, 0, 0, 0, 0}, + /* hsize_t count[PAR_SS_DR_MAX_RANK] = */ {0, 0, 0, 0, 0}, + /* hsize_t block[PAR_SS_DR_MAX_RANK] = */ {0, 0, 0, 0, 0}, + /* hsize_t * start_ptr = */ NULL, + /* hsize_t * stride_ptr = */ NULL, + /* hsize_t * count_ptr = */ NULL, + /* hsize_t * block_ptr = */ NULL, + /* int skips = */ 0, + /* int max_skips = */ 0, + /* int64_t total_tests = */ 0, + /* int64_t tests_run = */ 0, + /* int64_t tests_skipped = */ 0}; + struct hs_dr_pio_test_vars_t *tv_ptr = &test_vars; + + if (MAINPROCESS) + printf("\r - running test #%lld: small rank = %d, large rank = %d", (long long)(test_num + 1), + small_rank, large_rank); + + hs_dr_pio_test__setup(test_num, edge_size, checker_edge_size, chunk_edge_size, small_rank, large_rank, + use_collective_io, dset_type, express_test, tv_ptr); + + /* initialize skips & max_skips */ + tv_ptr->skips = *skips_ptr; + tv_ptr->max_skips = max_skips; + +#if CKRBRD_HS_DR_PIO_TEST__RUN_TEST__DEBUG + if (MAINPROCESS) { + HDfprintf(stdout, "test %d: small rank = %d, large rank = %d.\n", test_num, small_rank, large_rank); + HDfprintf(stdout, "test %d: Initialization complete.\n", test_num); + } +#endif /* CKRBRD_HS_DR_PIO_TEST__RUN_TEST__DEBUG */ + + /* first, verify that we can read from disk correctly using selections + * of different rank that H5Sselect_shape_same() views as being of the + * same shape. + * + * Start by reading a (small_rank - 1)-D slice from this processes slice + * of the on disk large data set, and verifying that the data read is + * correct. Verify that H5Sselect_shape_same() returns true on the + * memory and file selections. + * + * The first step is to set up the needed checker board selection in the + * in memory small small cube + */ + + ckrbrd_hs_dr_pio_test__d2m_l2s(tv_ptr); + + /* similarly, read slices of the on disk small data set into slices + * through the in memory large data set, and verify that the correct + * data (and only the correct data) is read. + */ + + ckrbrd_hs_dr_pio_test__d2m_s2l(tv_ptr); + + /* now we go in the opposite direction, verifying that we can write + * from memory to file using selections of different rank that + * H5Sselect_shape_same() views as being of the same shape. + * + * Start by writing small_rank - 1 D slices from the in memory large data + * set to the on disk small dataset. After each write, read the slice of + * the small dataset back from disk, and verify that it contains the + * expected data. Verify that H5Sselect_shape_same() returns true on + * the memory and file selections. + */ + + ckrbrd_hs_dr_pio_test__m2d_l2s(tv_ptr); + + /* Now write the contents of the process's slice of the in memory + * small data set to slices of the on disk large data set. After + * each write, read the process's slice of the large data set back + * into memory, and verify that it contains the expected data. + * Verify that H5Sselect_shape_same() returns true on the memory + * and file selections. + */ + + ckrbrd_hs_dr_pio_test__m2d_s2l(tv_ptr); + +#if CKRBRD_HS_DR_PIO_TEST__RUN_TEST__DEBUG + if (MAINPROCESS) { + HDfprintf(stdout, "test %d: Subtests complete -- tests run/skipped/total = %lld/%lld/%lld.\n", + test_num, (long long)(tv_ptr->tests_run), (long long)(tv_ptr->tests_skipped), + (long long)(tv_ptr->total_tests)); + } +#endif /* CKRBRD_HS_DR_PIO_TEST__RUN_TEST__DEBUG */ + + hs_dr_pio_test__takedown(tv_ptr); + +#if CKRBRD_HS_DR_PIO_TEST__RUN_TEST__DEBUG + if (MAINPROCESS) { + HDfprintf(stdout, "test %d: Takedown complete.\n", test_num); + } +#endif /* CKRBRD_HS_DR_PIO_TEST__RUN_TEST__DEBUG */ + + *skips_ptr = tv_ptr->skips; + *total_tests_ptr += tv_ptr->total_tests; + *tests_run_ptr += tv_ptr->tests_run; + *tests_skipped_ptr += tv_ptr->tests_skipped; + + return; + +} /* ckrbrd_hs_dr_pio_test__run_test() */ + +/*------------------------------------------------------------------------- + * Function: ckrbrd_hs_dr_pio_test() + * + * Purpose: Test I/O to/from hyperslab selections of different rank in + * the parallel case. + * + * Return: void + * + * Programmer: JRM -- 9/18/09 + * + *------------------------------------------------------------------------- + */ + +static void +ckrbrd_hs_dr_pio_test(ShapeSameTestMethods sstest_type) +{ + int express_test; + int local_express_test; + int mpi_size = -1; + int mpi_rank = -1; + int test_num = 0; + int edge_size; + int checker_edge_size = 3; + int chunk_edge_size = 0; + int small_rank = 3; + int large_rank = 4; + int mpi_result; + hid_t dset_type = H5T_NATIVE_UINT; + int skips = 0; + int max_skips = 0; + /* The following table list the number of sub-tests skipped between + * each test that is actually executed as a function of the express + * test level. Note that any value in excess of 4880 will cause all + * sub tests to be skipped. + */ + int max_skips_tbl[4] = {0, 4, 64, 1024}; + int64_t total_tests = 0; + int64_t tests_run = 0; + int64_t tests_skipped = 0; + + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + edge_size = (mpi_size > 6 ? mpi_size : 6); + + local_express_test = EXPRESS_MODE; /* GetTestExpress(); */ + + HDcompile_assert(sizeof(uint32_t) == sizeof(unsigned)); + + mpi_result = MPI_Allreduce((void *)&local_express_test, (void *)&express_test, 1, MPI_INT, MPI_MAX, + MPI_COMM_WORLD); + + VRFY((mpi_result == MPI_SUCCESS), "MPI_Allreduce(0) succeeded"); + + if (local_express_test < 0) { + max_skips = max_skips_tbl[0]; + } + else if (local_express_test > 3) { + max_skips = max_skips_tbl[3]; + } + else { + max_skips = max_skips_tbl[local_express_test]; + } + +#if 0 + { + int DebugWait = 1; + + while (DebugWait) ; + } +#endif + + for (large_rank = 3; large_rank <= PAR_SS_DR_MAX_RANK; large_rank++) { + + for (small_rank = 2; small_rank < large_rank; small_rank++) { + switch (sstest_type) { + case IND_CONTIG: + /* contiguous data set, independent I/O */ + chunk_edge_size = 0; + ckrbrd_hs_dr_pio_test__run_test(test_num, edge_size, checker_edge_size, chunk_edge_size, + small_rank, large_rank, FALSE, dset_type, express_test, + &skips, max_skips, &total_tests, &tests_run, + &tests_skipped, mpi_rank); + test_num++; + break; + /* end of case IND_CONTIG */ + + case COL_CONTIG: + /* contiguous data set, collective I/O */ + chunk_edge_size = 0; + ckrbrd_hs_dr_pio_test__run_test(test_num, edge_size, checker_edge_size, chunk_edge_size, + small_rank, large_rank, TRUE, dset_type, express_test, + &skips, max_skips, &total_tests, &tests_run, + &tests_skipped, mpi_rank); + test_num++; + break; + /* end of case COL_CONTIG */ + + case IND_CHUNKED: + /* chunked data set, independent I/O */ + chunk_edge_size = 5; + ckrbrd_hs_dr_pio_test__run_test(test_num, edge_size, checker_edge_size, chunk_edge_size, + small_rank, large_rank, FALSE, dset_type, express_test, + &skips, max_skips, &total_tests, &tests_run, + &tests_skipped, mpi_rank); + test_num++; + break; + /* end of case IND_CHUNKED */ + + case COL_CHUNKED: + /* chunked data set, collective I/O */ + chunk_edge_size = 5; + ckrbrd_hs_dr_pio_test__run_test(test_num, edge_size, checker_edge_size, chunk_edge_size, + small_rank, large_rank, TRUE, dset_type, express_test, + &skips, max_skips, &total_tests, &tests_run, + &tests_skipped, mpi_rank); + test_num++; + break; + /* end of case COL_CHUNKED */ + + default: + VRFY((FALSE), "unknown test type"); + break; + + } /* end of switch(sstest_type) */ +#if CONTIG_HS_DR_PIO_TEST__DEBUG + if ((MAINPROCESS) && (tests_skipped > 0)) { + HDfprintf(stdout, " run/skipped/total = %" PRId64 "/%" PRId64 "/%" PRId64 ".\n", + tests_run, tests_skipped, total_tests); + } +#endif /* CONTIG_HS_DR_PIO_TEST__DEBUG */ + } + } + + if (MAINPROCESS) { + if (tests_skipped > 0) { + HDfprintf(stdout, " %" PRId64 " of %" PRId64 " subtests skipped to expedite testing.\n", + tests_skipped, total_tests); + } + else + HDprintf("\n"); + } + + return; + +} /* ckrbrd_hs_dr_pio_test() */ + +/* Main Body. Here for now, may have to move them to a separated file later. */ + +/* + * Main driver of the Parallel HDF5 tests + */ + +#include "testphdf5.h" + +#ifndef PATH_MAX +#define PATH_MAX 512 +#endif /* !PATH_MAX */ + +/* global variables */ +int dim0; +int dim1; +int chunkdim0; +int chunkdim1; +int nerrors = 0; /* errors count */ +int ndatasets = 300; /* number of datasets to create*/ +int ngroups = 512; /* number of groups to create in root + * group. */ +int facc_type = FACC_MPIO; /*Test file access type */ +int dxfer_coll_type = DXFER_COLLECTIVE_IO; + +H5E_auto2_t old_func; /* previous error handler */ +void *old_client_data; /* previous error handler arg.*/ + +/* other option flags */ + +#ifdef USE_PAUSE +/* pause the process for a moment to allow debugger to attach if desired. */ +/* Will pause more if greenlight file is not persent but will eventually */ +/* continue. */ +#include +#include + +void +pause_proc(void) +{ + + int pid; + h5_stat_t statbuf; + char greenlight[] = "go"; + int maxloop = 10; + int loops = 0; + int time_int = 10; + + /* mpi variables */ + int mpi_size, mpi_rank; + int mpi_namelen; + char mpi_name[MPI_MAX_PROCESSOR_NAME]; + + pid = getpid(); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + MPI_Get_processor_name(mpi_name, &mpi_namelen); + + if (MAINPROCESS) + while ((HDstat(greenlight, &statbuf) == -1) && loops < maxloop) { + if (!loops++) { + HDprintf("Proc %d (%*s, %d): to debug, attach %d\n", mpi_rank, mpi_namelen, mpi_name, pid, + pid); + } + HDprintf("waiting(%ds) for file %s ...\n", time_int, greenlight); + fflush(stdout); + HDsleep(time_int); + } + MPI_Barrier(MPI_COMM_WORLD); +} + +/* Use the Profile feature of MPI to call the pause_proc() */ +int +MPI_Init(int *argc, char ***argv) +{ + int ret_code; + ret_code = PMPI_Init(argc, argv); + pause_proc(); + return (ret_code); +} +#endif /* USE_PAUSE */ + +/* + * Show command usage + */ +static void +usage(void) +{ + HDprintf(" [-r] [-w] [-m] [-n] " + "[-o] [-f ] [-d ]\n"); + HDprintf("\t-m" + "\tset number of datasets for the multiple dataset test\n"); + HDprintf("\t-n" + "\tset number of groups for the multiple group test\n"); +#if 0 + HDprintf("\t-f \tfilename prefix\n"); +#endif + HDprintf("\t-2\t\tuse Split-file together with MPIO\n"); + HDprintf("\t-d \tdataset dimensions factors. Defaults (%d,%d)\n", ROW_FACTOR, + COL_FACTOR); + HDprintf("\t-c \tdataset chunk dimensions. Defaults (dim0/10,dim1/10)\n"); + HDprintf("\n"); +} + +/* + * parse the command line options + */ +static int +parse_options(int argc, char **argv) +{ + int mpi_size, mpi_rank; /* mpi variables */ + + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* setup default chunk-size. Make sure sizes are > 0 */ + + chunkdim0 = (dim0 + 9) / 10; + chunkdim1 = (dim1 + 9) / 10; + + while (--argc) { + if (**(++argv) != '-') { + break; + } + else { + switch (*(*argv + 1)) { + case 'm': + ndatasets = atoi((*argv + 1) + 1); + if (ndatasets < 0) { + nerrors++; + return (1); + } + break; + case 'n': + ngroups = atoi((*argv + 1) + 1); + if (ngroups < 0) { + nerrors++; + return (1); + } + break; +#if 0 + case 'f': if (--argc < 1) { + nerrors++; + return(1); + } + if (**(++argv) == '-') { + nerrors++; + return(1); + } + paraprefix = *argv; + break; +#endif + case 'i': /* Collective MPI-IO access with independent IO */ + dxfer_coll_type = DXFER_INDEPENDENT_IO; + break; + case '2': /* Use the split-file driver with MPIO access */ + /* Can use $HDF5_METAPREFIX to define the */ + /* meta-file-prefix. */ + facc_type = FACC_MPIO | FACC_SPLIT; + break; + case 'd': /* dimensizes */ + if (--argc < 2) { + nerrors++; + return (1); + } + dim0 = atoi(*(++argv)) * mpi_size; + argc--; + dim1 = atoi(*(++argv)) * mpi_size; + /* set default chunkdim sizes too */ + chunkdim0 = (dim0 + 9) / 10; + chunkdim1 = (dim1 + 9) / 10; + break; + case 'c': /* chunk dimensions */ + if (--argc < 2) { + nerrors++; + return (1); + } + chunkdim0 = atoi(*(++argv)); + argc--; + chunkdim1 = atoi(*(++argv)); + break; + case 'h': /* print help message--return with nerrors set */ + return (1); + default: + HDprintf("Illegal option(%s)\n", *argv); + nerrors++; + return (1); + } + } + } /*while*/ + + /* check validity of dimension and chunk sizes */ + if (dim0 <= 0 || dim1 <= 0) { + HDprintf("Illegal dim sizes (%d, %d)\n", dim0, dim1); + nerrors++; + return (1); + } + if (chunkdim0 <= 0 || chunkdim1 <= 0) { + HDprintf("Illegal chunkdim sizes (%d, %d)\n", chunkdim0, chunkdim1); + nerrors++; + return (1); + } + + /* Make sure datasets can be divided into equal portions by the processes */ + if ((dim0 % mpi_size) || (dim1 % mpi_size)) { + if (MAINPROCESS) + HDprintf("dim0(%d) and dim1(%d) must be multiples of processes(%d)\n", dim0, dim1, mpi_size); + nerrors++; + return (1); + } + + /* compose the test filenames */ + { + int i, n; + + n = sizeof(FILENAME) / sizeof(FILENAME[0]) - 1; /* exclude the NULL */ + + for (i = 0; i < n; i++) + strncpy(filenames[i], FILENAME[i], PATH_MAX); +#if 0 /* no support for VFDs right now */ + if (h5_fixname(FILENAME[i], fapl, filenames[i], PATH_MAX) == NULL) { + HDprintf("h5_fixname failed\n"); + nerrors++; + return (1); + } +#endif + if (MAINPROCESS) { + HDprintf("Test filenames are:\n"); + for (i = 0; i < n; i++) + HDprintf(" %s\n", filenames[i]); + } + } + + return (0); +} + +/* + * Create the appropriate File access property list + */ +hid_t +create_faccess_plist(MPI_Comm comm, MPI_Info info, int l_facc_type) +{ + hid_t ret_pl = -1; + herr_t ret; /* generic return value */ + int mpi_rank; /* mpi variables */ + + /* need the rank for error checking macros */ + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + ret_pl = H5Pcreate(H5P_FILE_ACCESS); + VRFY((ret_pl >= 0), "H5P_FILE_ACCESS"); + + if (l_facc_type == FACC_DEFAULT) + return (ret_pl); + + if (l_facc_type == FACC_MPIO) { + /* set Parallel access with communicator */ + ret = H5Pset_fapl_mpio(ret_pl, comm, info); + VRFY((ret >= 0), ""); + ret = H5Pset_all_coll_metadata_ops(ret_pl, TRUE); + VRFY((ret >= 0), ""); + ret = H5Pset_coll_metadata_write(ret_pl, TRUE); + VRFY((ret >= 0), ""); + return (ret_pl); + } + + if (l_facc_type == (FACC_MPIO | FACC_SPLIT)) { + hid_t mpio_pl; + + mpio_pl = H5Pcreate(H5P_FILE_ACCESS); + VRFY((mpio_pl >= 0), ""); + /* set Parallel access with communicator */ + ret = H5Pset_fapl_mpio(mpio_pl, comm, info); + VRFY((ret >= 0), ""); + + /* setup file access template */ + ret_pl = H5Pcreate(H5P_FILE_ACCESS); + VRFY((ret_pl >= 0), ""); + /* set Parallel access with communicator */ + ret = H5Pset_fapl_split(ret_pl, ".meta", mpio_pl, ".raw", mpio_pl); + VRFY((ret >= 0), "H5Pset_fapl_split succeeded"); + H5Pclose(mpio_pl); + return (ret_pl); + } + + /* unknown file access types */ + return (ret_pl); +} + +/* Shape Same test using contiguous hyperslab using independent IO on contiguous datasets */ +static void +sscontig1(void) +{ + contig_hs_dr_pio_test(IND_CONTIG); +} + +/* Shape Same test using contiguous hyperslab using collective IO on contiguous datasets */ +static void +sscontig2(void) +{ + contig_hs_dr_pio_test(COL_CONTIG); +} + +/* Shape Same test using contiguous hyperslab using independent IO on chunked datasets */ +static void +sscontig3(void) +{ + contig_hs_dr_pio_test(IND_CHUNKED); +} + +/* Shape Same test using contiguous hyperslab using collective IO on chunked datasets */ +static void +sscontig4(void) +{ + contig_hs_dr_pio_test(COL_CHUNKED); +} + +/* Shape Same test using checker hyperslab using independent IO on contiguous datasets */ +static void +sschecker1(void) +{ + ckrbrd_hs_dr_pio_test(IND_CONTIG); +} + +/* Shape Same test using checker hyperslab using collective IO on contiguous datasets */ +static void +sschecker2(void) +{ + ckrbrd_hs_dr_pio_test(COL_CONTIG); +} + +/* Shape Same test using checker hyperslab using independent IO on chunked datasets */ +static void +sschecker3(void) +{ + ckrbrd_hs_dr_pio_test(IND_CHUNKED); +} + +/* Shape Same test using checker hyperslab using collective IO on chunked datasets */ +static void +sschecker4(void) +{ + ckrbrd_hs_dr_pio_test(COL_CHUNKED); +} + +int +main(int argc, char **argv) +{ + int mpi_size, mpi_rank; /* mpi variables */ + +#ifndef H5_HAVE_WIN32_API + /* Un-buffer the stdout and stderr */ + HDsetbuf(stderr, NULL); + HDsetbuf(stdout, NULL); +#endif + + MPI_Init(&argc, &argv); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + dim0 = ROW_FACTOR * mpi_size; + dim1 = COL_FACTOR * mpi_size; + + if (MAINPROCESS) { + HDprintf("===================================\n"); + HDprintf("Shape Same Tests Start\n"); + HDprintf(" express_test = %d.\n", EXPRESS_MODE /* GetTestExpress() */); + HDprintf("===================================\n"); + } + + /* Attempt to turn off atexit post processing so that in case errors + * happen during the test and the process is aborted, it will not get + * hang in the atexit post processing in which it may try to make MPI + * calls. By then, MPI calls may not work. + */ + if (H5dont_atexit() < 0) { + if (MAINPROCESS) + HDprintf("%d: Failed to turn off atexit processing. Continue.\n", mpi_rank); + }; + H5open(); + /* h5_show_hostname(); */ + + fapl = H5Pcreate(H5P_FILE_ACCESS); + + /* Get the capability flag of the VOL connector being used */ + if (H5Pget_vol_cap_flags(fapl, &vol_cap_flags_g) < 0) { + if (MAINPROCESS) + HDprintf("Failed to get the capability flag of the VOL connector being used\n"); + + MPI_Finalize(); + return 0; + } + + /* Make sure the connector supports the API functions being tested. This test only + * uses a few API functions, such as H5Fcreate/close/delete, H5Dcreate/write/read/close, + */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + if (MAINPROCESS) + HDprintf("API functions for basic file and dataset aren't supported with this connector\n"); + + MPI_Finalize(); + return 0; + } + +#if 0 + HDmemset(filenames, 0, sizeof(filenames)); + for (int i = 0; i < NFILENAME; i++) { + if (NULL == (filenames[i] = HDmalloc(PATH_MAX))) { + HDprintf("couldn't allocate filename array\n"); + MPI_Abort(MPI_COMM_WORLD, -1); + } + } +#endif + + /* Initialize testing framework */ + /* TestInit(argv[0], usage, parse_options); */ + + if (parse_options(argc, argv)) { + usage(); + return 1; + } + + if (dxfer_coll_type == DXFER_INDEPENDENT_IO && MAINPROCESS) { + HDprintf("===================================\n" + " Using Independent I/O with file set view to replace collective I/O \n" + "===================================\n"); + } + + /* Shape Same tests using contiguous hyperslab */ +#if 0 + AddTest("sscontig1", sscontig1, NULL, + "Cntg hslab, ind IO, cntg dsets", filenames[0]); + AddTest("sscontig2", sscontig2, NULL, + "Cntg hslab, col IO, cntg dsets", filenames[0]); + AddTest("sscontig3", sscontig3, NULL, + "Cntg hslab, ind IO, chnk dsets", filenames[0]); + AddTest("sscontig4", sscontig4, NULL, + "Cntg hslab, col IO, chnk dsets", filenames[0]); +#endif + if (MAINPROCESS) { + printf("Cntg hslab, ind IO, cntg dsets\n"); + fflush(stdout); + } + sscontig1(); + if (MAINPROCESS) { + printf("Cntg hslab, col IO, cntg dsets\n"); + fflush(stdout); + } + sscontig2(); + if (MAINPROCESS) { + printf("Cntg hslab, ind IO, chnk dsets\n"); + fflush(stdout); + } + sscontig3(); + if (MAINPROCESS) { + printf("Cntg hslab, col IO, chnk dsets\n"); + fflush(stdout); + } + sscontig4(); + + /* Shape Same tests using checker board hyperslab */ +#if 0 + AddTest("sschecker1", sschecker1, NULL, + "Check hslab, ind IO, cntg dsets", filenames[0]); + AddTest("sschecker2", sschecker2, NULL, + "Check hslab, col IO, cntg dsets", filenames[0]); + AddTest("sschecker3", sschecker3, NULL, + "Check hslab, ind IO, chnk dsets", filenames[0]); + AddTest("sschecker4", sschecker4, NULL, + "Check hslab, col IO, chnk dsets", filenames[0]); +#endif + if (MAINPROCESS) { + printf("Check hslab, ind IO, cntg dsets\n"); + fflush(stdout); + } + sschecker1(); + if (MAINPROCESS) { + printf("Check hslab, col IO, cntg dsets\n"); + fflush(stdout); + } + sschecker2(); + if (MAINPROCESS) { + printf("Check hslab, ind IO, chnk dsets\n"); + fflush(stdout); + } + sschecker3(); + if (MAINPROCESS) { + printf("Check hslab, col IO, chnk dsets\n"); + fflush(stdout); + } + sschecker4(); + + /* Display testing information */ + /* TestInfo(argv[0]); */ + + /* setup file access property list */ + H5Pset_fapl_mpio(fapl, MPI_COMM_WORLD, MPI_INFO_NULL); + + /* Parse command line arguments */ + /* TestParseCmdLine(argc, argv); */ + + /* Perform requested testing */ + /* PerformTests(); */ + + /* make sure all processes are finished before final report, cleanup + * and exit. + */ + MPI_Barrier(MPI_COMM_WORLD); + + /* Display test summary, if requested */ + /* if (MAINPROCESS && GetTestSummary()) + TestSummary(); */ + + /* Clean up test files */ + /* h5_clean_files(FILENAME, fapl); */ + H5Fdelete(FILENAME[0], fapl); + H5Pclose(fapl); + + /* nerrors += GetTestNumErrs(); */ + + /* Gather errors from all processes */ + { + int temp; + MPI_Allreduce(&nerrors, &temp, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD); + nerrors = temp; + } + + if (MAINPROCESS) { /* only process 0 reports */ + HDprintf("===================================\n"); + if (nerrors) + HDprintf("***Shape Same tests detected %d errors***\n", nerrors); + else + HDprintf("Shape Same tests finished successfully\n"); + HDprintf("===================================\n"); + } + +#if 0 + for (int i = 0; i < NFILENAME; i++) { + HDfree(filenames[i]); + filenames[i] = NULL; + } +#endif + + /* close HDF5 library */ + H5close(); + + /* Release test infrastructure */ + /* TestShutdown(); */ + + MPI_Finalize(); + + /* cannot just return (nerrors) because exit code is limited to 1byte */ + return (nerrors != 0); +} diff --git a/testpar/API/t_span_tree.c b/testpar/API/t_span_tree.c new file mode 100644 index 0000000..5aafb0b --- /dev/null +++ b/testpar/API/t_span_tree.c @@ -0,0 +1,2622 @@ + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + This program will test irregular hyperslab selections with collective write and read. + The way to test whether collective write and read works is to use independent IO + output to verify the collective output. + + 1) We will write two datasets with the same hyperslab selection settings; + one in independent mode, + one in collective mode, + 2) We will read two datasets with the same hyperslab selection settings, + 1. independent read to read independent output, + independent read to read collecive output, + Compare the result, + If the result is the same, then collective write succeeds. + 2. collective read to read independent output, + independent read to read independent output, + Compare the result, + If the result is the same, then collective read succeeds. + + */ + +#include "hdf5.h" +#if 0 +#include "H5private.h" +#endif +#include "testphdf5.h" + +#define LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG 0 + +static void coll_write_test(int chunk_factor); +static void coll_read_test(void); + +/*------------------------------------------------------------------------- + * Function: coll_irregular_cont_write + * + * Purpose: Wrapper to test the collectively irregular hyperslab write in + * contiguous storage + * + * Return: Success: 0 + * + * Failure: -1 + * + * Programmer: Unknown + * Dec 2nd, 2004 + * + *------------------------------------------------------------------------- + */ +void +coll_irregular_cont_write(void) +{ + int mpi_rank; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file dataset, or dataset more aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + coll_write_test(0); +} + +/*------------------------------------------------------------------------- + * Function: coll_irregular_cont_read + * + * Purpose: Wrapper to test the collectively irregular hyperslab read in + * contiguous storage + * + * Return: Success: 0 + * + * Failure: -1 + * + * Programmer: Unknown + * Dec 2nd, 2004 + * + *------------------------------------------------------------------------- + */ +void +coll_irregular_cont_read(void) +{ + int mpi_rank; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file dataset, or dataset more aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + coll_read_test(); +} + +/*------------------------------------------------------------------------- + * Function: coll_irregular_simple_chunk_write + * + * Purpose: Wrapper to test the collectively irregular hyperslab write in + * chunk storage(1 chunk) + * + * Return: Success: 0 + * + * Failure: -1 + * + * Programmer: Unknown + * Dec 2nd, 2004 + * + *------------------------------------------------------------------------- + */ +void +coll_irregular_simple_chunk_write(void) +{ + int mpi_rank; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file dataset, or dataset more aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + coll_write_test(1); +} + +/*------------------------------------------------------------------------- + * Function: coll_irregular_simple_chunk_read + * + * Purpose: Wrapper to test the collectively irregular hyperslab read in chunk + * storage(1 chunk) + * + * Return: Success: 0 + * + * Failure: -1 + * + * Programmer: Unknown + * Dec 2nd, 2004 + * + *------------------------------------------------------------------------- + */ +void +coll_irregular_simple_chunk_read(void) +{ + int mpi_rank; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file dataset, or dataset more aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + coll_read_test(); +} + +/*------------------------------------------------------------------------- + * Function: coll_irregular_complex_chunk_write + * + * Purpose: Wrapper to test the collectively irregular hyperslab write in chunk + * storage(4 chunks) + * + * Return: Success: 0 + * + * Failure: -1 + * + * Programmer: Unknown + * Dec 2nd, 2004 + * + *------------------------------------------------------------------------- + */ +void +coll_irregular_complex_chunk_write(void) +{ + int mpi_rank; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file dataset, or dataset more aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + coll_write_test(4); +} + +/*------------------------------------------------------------------------- + * Function: coll_irregular_complex_chunk_read + * + * Purpose: Wrapper to test the collectively irregular hyperslab read in chunk + * storage(1 chunk) + * + * Return: Success: 0 + * + * Failure: -1 + * + * Programmer: Unknown + * Dec 2nd, 2004 + * + *------------------------------------------------------------------------- + */ +void +coll_irregular_complex_chunk_read(void) +{ + int mpi_rank; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file dataset, or dataset more aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + coll_read_test(); +} + +/*------------------------------------------------------------------------- + * Function: coll_write_test + * + * Purpose: To test the collectively irregular hyperslab write in chunk + * storage + * Input: number of chunks on each dimension + * if number is equal to 0, contiguous storage + * Return: Success: 0 + * + * Failure: -1 + * + * Programmer: Unknown + * Dec 2nd, 2004 + * + *------------------------------------------------------------------------- + */ +void +coll_write_test(int chunk_factor) +{ + + const char *filename; + hid_t facc_plist, dxfer_plist, dcrt_plist; + hid_t file, datasetc, dataseti; /* File and dataset identifiers */ + hid_t mspaceid1, mspaceid, fspaceid, fspaceid1; /* Dataspace identifiers */ + + hsize_t mdim1[1]; /* Dimension size of the first dataset (in memory) */ + hsize_t fsdim[2]; /* Dimension sizes of the dataset (on disk) */ + hsize_t mdim[2]; /* Dimension sizes of the dataset in memory when we + * read selection from the dataset on the disk + */ + + hsize_t start[2]; /* Start of hyperslab */ + hsize_t stride[2]; /* Stride of hyperslab */ + hsize_t count[2]; /* Block count */ + hsize_t block[2]; /* Block sizes */ + hsize_t chunk_dims[2]; + + herr_t ret; + int i; + int fillvalue = 0; /* Fill value for the dataset */ + + int *matrix_out = NULL; + int *matrix_out1 = NULL; /* Buffer to read from the dataset */ + int *vector = NULL; + + int mpi_size, mpi_rank; + + MPI_Comm comm = MPI_COMM_WORLD; + MPI_Info info = MPI_INFO_NULL; + + /*set up MPI parameters */ + MPI_Comm_size(comm, &mpi_size); + MPI_Comm_rank(comm, &mpi_rank); + + /* Obtain file name */ + filename = PARATESTFILE /* GetTestParameters() */; + + /* + * Buffers' initialization. + */ + + mdim1[0] = (hsize_t)(MSPACE1_DIM * mpi_size); + mdim[0] = MSPACE_DIM1; + mdim[1] = (hsize_t)(MSPACE_DIM2 * mpi_size); + fsdim[0] = FSPACE_DIM1; + fsdim[1] = (hsize_t)(FSPACE_DIM2 * mpi_size); + + vector = (int *)HDmalloc(sizeof(int) * (size_t)mdim1[0] * (size_t)mpi_size); + matrix_out = (int *)HDmalloc(sizeof(int) * (size_t)mdim[0] * (size_t)mdim[1] * (size_t)mpi_size); + matrix_out1 = (int *)HDmalloc(sizeof(int) * (size_t)mdim[0] * (size_t)mdim[1] * (size_t)mpi_size); + + HDmemset(vector, 0, sizeof(int) * (size_t)mdim1[0] * (size_t)mpi_size); + vector[0] = vector[MSPACE1_DIM * mpi_size - 1] = -1; + for (i = 1; i < MSPACE1_DIM * mpi_size - 1; i++) + vector[i] = (int)i; + + /* Grab file access property list */ + facc_plist = create_faccess_plist(comm, info, facc_type); + VRFY((facc_plist >= 0), ""); + + /* + * Create a file. + */ + file = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, facc_plist); + VRFY((file >= 0), "H5Fcreate succeeded"); + + /* + * Create property list for a dataset and set up fill values. + */ + dcrt_plist = H5Pcreate(H5P_DATASET_CREATE); + VRFY((dcrt_plist >= 0), ""); + + ret = H5Pset_fill_value(dcrt_plist, H5T_NATIVE_INT, &fillvalue); + VRFY((ret >= 0), "Fill value creation property list succeeded"); + + if (chunk_factor != 0) { + chunk_dims[0] = fsdim[0] / (hsize_t)chunk_factor; + chunk_dims[1] = fsdim[1] / (hsize_t)chunk_factor; + ret = H5Pset_chunk(dcrt_plist, 2, chunk_dims); + VRFY((ret >= 0), "chunk creation property list succeeded"); + } + + /* + * + * Create dataspace for the first dataset in the disk. + * dim1 = 9 + * dim2 = 3600 + * + * + */ + fspaceid = H5Screate_simple(FSPACE_RANK, fsdim, NULL); + VRFY((fspaceid >= 0), "file dataspace created succeeded"); + + /* + * Create dataset in the file. Notice that creation + * property list dcrt_plist is used. + */ + datasetc = + H5Dcreate2(file, "collect_write", H5T_NATIVE_INT, fspaceid, H5P_DEFAULT, dcrt_plist, H5P_DEFAULT); + VRFY((datasetc >= 0), "dataset created succeeded"); + + dataseti = + H5Dcreate2(file, "independ_write", H5T_NATIVE_INT, fspaceid, H5P_DEFAULT, dcrt_plist, H5P_DEFAULT); + VRFY((dataseti >= 0), "dataset created succeeded"); + + /* The First selection for FILE + * + * block (3,2) + * stride(4,3) + * count (1,768/mpi_size) + * start (0,1+768*3*mpi_rank/mpi_size) + * + */ + + start[0] = FHSTART0; + start[1] = (hsize_t)(FHSTART1 + mpi_rank * FHSTRIDE1 * FHCOUNT1); + stride[0] = FHSTRIDE0; + stride[1] = FHSTRIDE1; + count[0] = FHCOUNT0; + count[1] = FHCOUNT1; + block[0] = FHBLOCK0; + block[1] = FHBLOCK1; + + ret = H5Sselect_hyperslab(fspaceid, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "hyperslab selection succeeded"); + + /* The Second selection for FILE + * + * block (3,768) + * stride (1,1) + * count (1,1) + * start (4,768*mpi_rank/mpi_size) + * + */ + + start[0] = SHSTART0; + start[1] = (hsize_t)(SHSTART1 + SHCOUNT1 * SHBLOCK1 * mpi_rank); + stride[0] = SHSTRIDE0; + stride[1] = SHSTRIDE1; + count[0] = SHCOUNT0; + count[1] = SHCOUNT1; + block[0] = SHBLOCK0; + block[1] = SHBLOCK1; + + ret = H5Sselect_hyperslab(fspaceid, H5S_SELECT_OR, start, stride, count, block); + VRFY((ret >= 0), "hyperslab selection succeeded"); + + /* + * Create dataspace for the first dataset in the memory + * dim1 = 27000 + * + */ + mspaceid1 = H5Screate_simple(MSPACE1_RANK, mdim1, NULL); + VRFY((mspaceid1 >= 0), "memory dataspace created succeeded"); + + /* + * Memory space is 1-D, this is a good test to check + * whether a span-tree derived datatype needs to be built. + * block 1 + * stride 1 + * count 6912/mpi_size + * start 1 + * + */ + start[0] = MHSTART0; + stride[0] = MHSTRIDE0; + count[0] = MHCOUNT0; + block[0] = MHBLOCK0; + + ret = H5Sselect_hyperslab(mspaceid1, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "hyperslab selection succeeded"); + + /* independent write */ + ret = H5Dwrite(dataseti, H5T_NATIVE_INT, mspaceid1, fspaceid, H5P_DEFAULT, vector); + VRFY((ret >= 0), "dataset independent write succeed"); + + dxfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY((dxfer_plist >= 0), ""); + + ret = H5Pset_dxpl_mpio(dxfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "MPIO data transfer property list succeed"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(dxfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY((ret >= 0), "set independent IO collectively succeeded"); + } + + /* collective write */ + ret = H5Dwrite(datasetc, H5T_NATIVE_INT, mspaceid1, fspaceid, dxfer_plist, vector); + VRFY((ret >= 0), "dataset collective write succeed"); + + ret = H5Sclose(mspaceid1); + VRFY((ret >= 0), ""); + + ret = H5Sclose(fspaceid); + VRFY((ret >= 0), ""); + + /* + * Close dataset. + */ + ret = H5Dclose(datasetc); + VRFY((ret >= 0), ""); + + ret = H5Dclose(dataseti); + VRFY((ret >= 0), ""); + + /* + * Close the file. + */ + ret = H5Fclose(file); + VRFY((ret >= 0), ""); + /* + * Close property list + */ + + ret = H5Pclose(facc_plist); + VRFY((ret >= 0), ""); + ret = H5Pclose(dxfer_plist); + VRFY((ret >= 0), ""); + ret = H5Pclose(dcrt_plist); + VRFY((ret >= 0), ""); + + /* + * Open the file. + */ + + /*** + + For testing collective hyperslab selection write + In this test, we are using independent read to check + the correctedness of collective write compared with + independent write, + + In order to thoroughly test this feature, we choose + a different selection set for reading the data out. + + + ***/ + + /* Obtain file access property list with MPI-IO driver */ + facc_plist = create_faccess_plist(comm, info, facc_type); + VRFY((facc_plist >= 0), ""); + + file = H5Fopen(filename, H5F_ACC_RDONLY, facc_plist); + VRFY((file >= 0), "H5Fopen succeeded"); + + /* + * Open the dataset. + */ + datasetc = H5Dopen2(file, "collect_write", H5P_DEFAULT); + VRFY((datasetc >= 0), "H5Dopen2 succeeded"); + + dataseti = H5Dopen2(file, "independ_write", H5P_DEFAULT); + VRFY((dataseti >= 0), "H5Dopen2 succeeded"); + + /* + * Get dataspace of the open dataset. + */ + fspaceid = H5Dget_space(datasetc); + VRFY((fspaceid >= 0), "file dataspace obtained succeeded"); + + fspaceid1 = H5Dget_space(dataseti); + VRFY((fspaceid1 >= 0), "file dataspace obtained succeeded"); + + /* The First selection for FILE to read + * + * block (1,1) + * stride(1.1) + * count (3,768/mpi_size) + * start (1,2+768*mpi_rank/mpi_size) + * + */ + start[0] = RFFHSTART0; + start[1] = (hsize_t)(RFFHSTART1 + mpi_rank * RFFHCOUNT1); + block[0] = RFFHBLOCK0; + block[1] = RFFHBLOCK1; + stride[0] = RFFHSTRIDE0; + stride[1] = RFFHSTRIDE1; + count[0] = RFFHCOUNT0; + count[1] = RFFHCOUNT1; + + /* The first selection of the dataset generated by collective write */ + ret = H5Sselect_hyperslab(fspaceid, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "hyperslab selection succeeded"); + + /* The first selection of the dataset generated by independent write */ + ret = H5Sselect_hyperslab(fspaceid1, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "hyperslab selection succeeded"); + + /* The Second selection for FILE to read + * + * block (1,1) + * stride(1.1) + * count (3,1536/mpi_size) + * start (2,4+1536*mpi_rank/mpi_size) + * + */ + + start[0] = RFSHSTART0; + start[1] = (hsize_t)(RFSHSTART1 + RFSHCOUNT1 * mpi_rank); + block[0] = RFSHBLOCK0; + block[1] = RFSHBLOCK1; + stride[0] = RFSHSTRIDE0; + stride[1] = RFSHSTRIDE0; + count[0] = RFSHCOUNT0; + count[1] = RFSHCOUNT1; + + /* The second selection of the dataset generated by collective write */ + ret = H5Sselect_hyperslab(fspaceid, H5S_SELECT_OR, start, stride, count, block); + VRFY((ret >= 0), "hyperslab selection succeeded"); + + /* The second selection of the dataset generated by independent write */ + ret = H5Sselect_hyperslab(fspaceid1, H5S_SELECT_OR, start, stride, count, block); + VRFY((ret >= 0), "hyperslab selection succeeded"); + + /* + * Create memory dataspace. + * rank = 2 + * mdim1 = 9 + * mdim2 = 3600 + * + */ + mspaceid = H5Screate_simple(MSPACE_RANK, mdim, NULL); + + /* + * Select two hyperslabs in memory. Hyperslabs has the same + * size and shape as the selected hyperslabs for the file dataspace + * Only the starting point is different. + * The first selection + * block (1,1) + * stride(1.1) + * count (3,768/mpi_size) + * start (0,768*mpi_rank/mpi_size) + * + */ + + start[0] = RMFHSTART0; + start[1] = (hsize_t)(RMFHSTART1 + mpi_rank * RMFHCOUNT1); + block[0] = RMFHBLOCK0; + block[1] = RMFHBLOCK1; + stride[0] = RMFHSTRIDE0; + stride[1] = RMFHSTRIDE1; + count[0] = RMFHCOUNT0; + count[1] = RMFHCOUNT1; + + ret = H5Sselect_hyperslab(mspaceid, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "hyperslab selection succeeded"); + + /* + * Select two hyperslabs in memory. Hyperslabs has the same + * size and shape as the selected hyperslabs for the file dataspace + * Only the starting point is different. + * The second selection + * block (1,1) + * stride(1,1) + * count (3,1536/mpi_size) + * start (1,2+1536*mpi_rank/mpi_size) + * + */ + start[0] = RMSHSTART0; + start[1] = (hsize_t)(RMSHSTART1 + mpi_rank * RMSHCOUNT1); + block[0] = RMSHBLOCK0; + block[1] = RMSHBLOCK1; + stride[0] = RMSHSTRIDE0; + stride[1] = RMSHSTRIDE1; + count[0] = RMSHCOUNT0; + count[1] = RMSHCOUNT1; + + ret = H5Sselect_hyperslab(mspaceid, H5S_SELECT_OR, start, stride, count, block); + VRFY((ret >= 0), "hyperslab selection succeeded"); + + /* + * Initialize data buffer. + */ + + HDmemset(matrix_out, 0, sizeof(int) * (size_t)MSPACE_DIM1 * (size_t)MSPACE_DIM2 * (size_t)mpi_size); + HDmemset(matrix_out1, 0, sizeof(int) * (size_t)MSPACE_DIM1 * (size_t)MSPACE_DIM2 * (size_t)mpi_size); + /* + * Read data back to the buffer matrix_out. + */ + + ret = H5Dread(datasetc, H5T_NATIVE_INT, mspaceid, fspaceid, H5P_DEFAULT, matrix_out); + VRFY((ret >= 0), "H5D independent read succeed"); + + ret = H5Dread(dataseti, H5T_NATIVE_INT, mspaceid, fspaceid, H5P_DEFAULT, matrix_out1); + VRFY((ret >= 0), "H5D independent read succeed"); + + ret = 0; + + for (i = 0; i < MSPACE_DIM1 * MSPACE_DIM2 * mpi_size; i++) { + if (matrix_out[i] != matrix_out1[i]) + ret = -1; + if (ret < 0) + break; + } + + VRFY((ret >= 0), "H5D irregular collective write succeed"); + + /* + * Close memory file and memory dataspaces. + */ + ret = H5Sclose(mspaceid); + VRFY((ret >= 0), ""); + ret = H5Sclose(fspaceid); + VRFY((ret >= 0), ""); + + /* + * Close dataset. + */ + ret = H5Dclose(dataseti); + VRFY((ret >= 0), ""); + + ret = H5Dclose(datasetc); + VRFY((ret >= 0), ""); + + /* + * Close property list + */ + + ret = H5Pclose(facc_plist); + VRFY((ret >= 0), ""); + + /* + * Close the file. + */ + ret = H5Fclose(file); + VRFY((ret >= 0), ""); + + if (vector) + HDfree(vector); + if (matrix_out) + HDfree(matrix_out); + if (matrix_out1) + HDfree(matrix_out1); + + return; +} + +/*------------------------------------------------------------------------- + * Function: coll_read_test + * + * Purpose: To test the collectively irregular hyperslab read in chunk + * storage + * Input: number of chunks on each dimension + * if number is equal to 0, contiguous storage + * Return: Success: 0 + * + * Failure: -1 + * + * Programmer: Unknown + * Dec 2nd, 2004 + * + *------------------------------------------------------------------------- + */ +static void +coll_read_test(void) +{ + + const char *filename; + hid_t facc_plist, dxfer_plist; + hid_t file, dataseti; /* File and dataset identifiers */ + hid_t mspaceid, fspaceid1; /* Dataspace identifiers */ + + /* Dimension sizes of the dataset (on disk) */ + hsize_t mdim[2]; /* Dimension sizes of the dataset in memory when we + * read selection from the dataset on the disk + */ + + hsize_t start[2]; /* Start of hyperslab */ + hsize_t stride[2]; /* Stride of hyperslab */ + hsize_t count[2]; /* Block count */ + hsize_t block[2]; /* Block sizes */ + herr_t ret; + + int i; + + int *matrix_out; + int *matrix_out1; /* Buffer to read from the dataset */ + + int mpi_size, mpi_rank; + + MPI_Comm comm = MPI_COMM_WORLD; + MPI_Info info = MPI_INFO_NULL; + + /*set up MPI parameters */ + MPI_Comm_size(comm, &mpi_size); + MPI_Comm_rank(comm, &mpi_rank); + + /* Obtain file name */ + filename = PARATESTFILE /* GetTestParameters() */; + + /* Initialize the buffer */ + + mdim[0] = MSPACE_DIM1; + mdim[1] = (hsize_t)(MSPACE_DIM2 * mpi_size); + matrix_out = (int *)HDmalloc(sizeof(int) * (size_t)MSPACE_DIM1 * (size_t)MSPACE_DIM2 * (size_t)mpi_size); + matrix_out1 = (int *)HDmalloc(sizeof(int) * (size_t)MSPACE_DIM1 * (size_t)MSPACE_DIM2 * (size_t)mpi_size); + + /*** For testing collective hyperslab selection read ***/ + + /* Obtain file access property list */ + facc_plist = create_faccess_plist(comm, info, facc_type); + VRFY((facc_plist >= 0), ""); + + /* + * Open the file. + */ + file = H5Fopen(filename, H5F_ACC_RDONLY, facc_plist); + VRFY((file >= 0), "H5Fopen succeeded"); + + /* + * Open the dataset. + */ + dataseti = H5Dopen2(file, "independ_write", H5P_DEFAULT); + VRFY((dataseti >= 0), "H5Dopen2 succeeded"); + + /* + * Get dataspace of the open dataset. + */ + fspaceid1 = H5Dget_space(dataseti); + VRFY((fspaceid1 >= 0), "file dataspace obtained succeeded"); + + /* The First selection for FILE to read + * + * block (1,1) + * stride(1.1) + * count (3,768/mpi_size) + * start (1,2+768*mpi_rank/mpi_size) + * + */ + start[0] = RFFHSTART0; + start[1] = (hsize_t)(RFFHSTART1 + mpi_rank * RFFHCOUNT1); + block[0] = RFFHBLOCK0; + block[1] = RFFHBLOCK1; + stride[0] = RFFHSTRIDE0; + stride[1] = RFFHSTRIDE1; + count[0] = RFFHCOUNT0; + count[1] = RFFHCOUNT1; + + ret = H5Sselect_hyperslab(fspaceid1, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "hyperslab selection succeeded"); + + /* The Second selection for FILE to read + * + * block (1,1) + * stride(1.1) + * count (3,1536/mpi_size) + * start (2,4+1536*mpi_rank/mpi_size) + * + */ + start[0] = RFSHSTART0; + start[1] = (hsize_t)(RFSHSTART1 + RFSHCOUNT1 * mpi_rank); + block[0] = RFSHBLOCK0; + block[1] = RFSHBLOCK1; + stride[0] = RFSHSTRIDE0; + stride[1] = RFSHSTRIDE0; + count[0] = RFSHCOUNT0; + count[1] = RFSHCOUNT1; + + ret = H5Sselect_hyperslab(fspaceid1, H5S_SELECT_OR, start, stride, count, block); + VRFY((ret >= 0), "hyperslab selection succeeded"); + + /* + * Create memory dataspace. + */ + mspaceid = H5Screate_simple(MSPACE_RANK, mdim, NULL); + + /* + * Select two hyperslabs in memory. Hyperslabs has the same + * size and shape as the selected hyperslabs for the file dataspace. + * Only the starting point is different. + * The first selection + * block (1,1) + * stride(1.1) + * count (3,768/mpi_size) + * start (0,768*mpi_rank/mpi_size) + * + */ + + start[0] = RMFHSTART0; + start[1] = (hsize_t)(RMFHSTART1 + mpi_rank * RMFHCOUNT1); + block[0] = RMFHBLOCK0; + block[1] = RMFHBLOCK1; + stride[0] = RMFHSTRIDE0; + stride[1] = RMFHSTRIDE1; + count[0] = RMFHCOUNT0; + count[1] = RMFHCOUNT1; + ret = H5Sselect_hyperslab(mspaceid, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "hyperslab selection succeeded"); + + /* + * Select two hyperslabs in memory. Hyperslabs has the same + * size and shape as the selected hyperslabs for the file dataspace + * Only the starting point is different. + * The second selection + * block (1,1) + * stride(1,1) + * count (3,1536/mpi_size) + * start (1,2+1536*mpi_rank/mpi_size) + * + */ + start[0] = RMSHSTART0; + start[1] = (hsize_t)(RMSHSTART1 + mpi_rank * RMSHCOUNT1); + block[0] = RMSHBLOCK0; + block[1] = RMSHBLOCK1; + stride[0] = RMSHSTRIDE0; + stride[1] = RMSHSTRIDE1; + count[0] = RMSHCOUNT0; + count[1] = RMSHCOUNT1; + ret = H5Sselect_hyperslab(mspaceid, H5S_SELECT_OR, start, stride, count, block); + VRFY((ret >= 0), "hyperslab selection succeeded"); + + /* + * Initialize data buffer. + */ + + HDmemset(matrix_out, 0, sizeof(int) * (size_t)MSPACE_DIM1 * (size_t)MSPACE_DIM2 * (size_t)mpi_size); + HDmemset(matrix_out1, 0, sizeof(int) * (size_t)MSPACE_DIM1 * (size_t)MSPACE_DIM2 * (size_t)mpi_size); + + /* + * Read data back to the buffer matrix_out. + */ + + dxfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY((dxfer_plist >= 0), ""); + + ret = H5Pset_dxpl_mpio(dxfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "MPIO data transfer property list succeed"); + if (dxfer_coll_type == DXFER_INDEPENDENT_IO) { + ret = H5Pset_dxpl_mpio_collective_opt(dxfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY((ret >= 0), "set independent IO collectively succeeded"); + } + + /* Collective read */ + ret = H5Dread(dataseti, H5T_NATIVE_INT, mspaceid, fspaceid1, dxfer_plist, matrix_out); + VRFY((ret >= 0), "H5D collecive read succeed"); + + ret = H5Pclose(dxfer_plist); + VRFY((ret >= 0), ""); + + /* Independent read */ + ret = H5Dread(dataseti, H5T_NATIVE_INT, mspaceid, fspaceid1, H5P_DEFAULT, matrix_out1); + VRFY((ret >= 0), "H5D independent read succeed"); + + ret = 0; + for (i = 0; i < MSPACE_DIM1 * MSPACE_DIM2 * mpi_size; i++) { + if (matrix_out[i] != matrix_out1[i]) + ret = -1; + if (ret < 0) + break; + } + VRFY((ret >= 0), "H5D contiguous irregular collective read succeed"); + + /* + * Free read buffers. + */ + HDfree(matrix_out); + HDfree(matrix_out1); + + /* + * Close memory file and memory dataspaces. + */ + ret = H5Sclose(mspaceid); + VRFY((ret >= 0), ""); + ret = H5Sclose(fspaceid1); + VRFY((ret >= 0), ""); + + /* + * Close dataset. + */ + ret = H5Dclose(dataseti); + VRFY((ret >= 0), ""); + + /* + * Close property list + */ + ret = H5Pclose(facc_plist); + VRFY((ret >= 0), ""); + + /* + * Close the file. + */ + ret = H5Fclose(file); + VRFY((ret >= 0), ""); + + return; +} + +/**************************************************************** +** +** lower_dim_size_comp_test__select_checker_board(): +** +** Given a dataspace of tgt_rank, and dimensions: +** +** (mpi_size + 1), edge_size, ... , edge_size +** +** edge_size, and a checker_edge_size, select a checker +** board selection of a sel_rank (sel_rank < tgt_rank) +** dimensional slice through the dataspace parallel to the +** sel_rank fastest changing indices, with origin (in the +** higher indices) as indicated by the start array. +** +** Note that this function, is hard coded to presume a +** maximum dataspace rank of 5. +** +** While this maximum is declared as a constant, increasing +** it will require extensive coding in addition to changing +** the value of the constant. +** +** JRM -- 11/11/09 +** +****************************************************************/ + +#define LDSCT_DS_RANK 5 +#if LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG +#define LOWER_DIM_SIZE_COMP_TEST_DEBUG_TARGET_RANK 0 +#endif + +#define LOWER_DIM_SIZE_COMP_TEST__SELECT_CHECKER_BOARD__DEBUG 0 + +static void +lower_dim_size_comp_test__select_checker_board(const int mpi_rank, const hid_t tgt_sid, const int tgt_rank, + const hsize_t dims[LDSCT_DS_RANK], const int checker_edge_size, + const int sel_rank, hsize_t sel_start[]) +{ +#if LOWER_DIM_SIZE_COMP_TEST__SELECT_CHECKER_BOARD__DEBUG + const char *fcnName = "lower_dim_size_comp_test__select_checker_board():"; +#endif + hbool_t first_selection = TRUE; + int i, j, k, l, m; + int ds_offset; + int sel_offset; + const int test_max_rank = LDSCT_DS_RANK; /* must update code if */ + /* this changes */ + hsize_t base_count; + hsize_t offset_count; + hsize_t start[LDSCT_DS_RANK]; + hsize_t stride[LDSCT_DS_RANK]; + hsize_t count[LDSCT_DS_RANK]; + hsize_t block[LDSCT_DS_RANK]; + herr_t ret; /* Generic return value */ + +#if LOWER_DIM_SIZE_COMP_TEST__SELECT_CHECKER_BOARD__DEBUG + if (mpi_rank == LOWER_DIM_SIZE_COMP_TEST_DEBUG_TARGET_RANK) { + HDfprintf(stdout, "%s:%d: dims/checker_edge_size = %d %d %d %d %d / %d\n", fcnName, mpi_rank, + (int)dims[0], (int)dims[1], (int)dims[2], (int)dims[3], (int)dims[4], checker_edge_size); + } +#endif /* LOWER_DIM_SIZE_COMP_TEST__SELECT_CHECKER_BOARD__DEBUG */ + + HDassert(0 < checker_edge_size); + HDassert(0 < sel_rank); + HDassert(sel_rank <= tgt_rank); + HDassert(tgt_rank <= test_max_rank); + HDassert(test_max_rank <= LDSCT_DS_RANK); + + sel_offset = test_max_rank - sel_rank; + HDassert(sel_offset >= 0); + + ds_offset = test_max_rank - tgt_rank; + HDassert(ds_offset >= 0); + HDassert(ds_offset <= sel_offset); + + HDassert((hsize_t)checker_edge_size <= dims[sel_offset]); + HDassert(dims[sel_offset] == 10); + +#if LOWER_DIM_SIZE_COMP_TEST__SELECT_CHECKER_BOARD__DEBUG + if (mpi_rank == LOWER_DIM_SIZE_COMP_TEST_DEBUG_TARGET_RANK) { + HDfprintf(stdout, "%s:%d: sel_rank/sel_offset = %d/%d.\n", fcnName, mpi_rank, sel_rank, sel_offset); + HDfprintf(stdout, "%s:%d: tgt_rank/ds_offset = %d/%d.\n", fcnName, mpi_rank, tgt_rank, ds_offset); + } +#endif /* LOWER_DIM_SIZE_COMP_TEST__SELECT_CHECKER_BOARD__DEBUG */ + + /* First, compute the base count (which assumes start == 0 + * for the associated offset) and offset_count (which + * assumes start == checker_edge_size for the associated + * offset). + * + * Note that the following computation depends on the C99 + * requirement that integer division discard any fraction + * (truncation towards zero) to function correctly. As we + * now require C99, this shouldn't be a problem, but noting + * it may save us some pain if we are ever obliged to support + * pre-C99 compilers again. + */ + + base_count = dims[sel_offset] / (hsize_t)(checker_edge_size * 2); + + if ((dims[sel_rank] % (hsize_t)(checker_edge_size * 2)) > 0) { + + base_count++; + } + + offset_count = + (hsize_t)((dims[sel_offset] - (hsize_t)checker_edge_size) / ((hsize_t)(checker_edge_size * 2))); + + if (((dims[sel_rank] - (hsize_t)checker_edge_size) % ((hsize_t)(checker_edge_size * 2))) > 0) { + + offset_count++; + } + +#if LOWER_DIM_SIZE_COMP_TEST__SELECT_CHECKER_BOARD__DEBUG + if (mpi_rank == LOWER_DIM_SIZE_COMP_TEST_DEBUG_TARGET_RANK) { + HDfprintf(stdout, "%s:%d: base_count/offset_count = %d/%d.\n", fcnName, mpi_rank, base_count, + offset_count); + } +#endif /* LOWER_DIM_SIZE_COMP_TEST__SELECT_CHECKER_BOARD__DEBUG */ + + /* Now set up the stride and block arrays, and portions of the start + * and count arrays that will not be altered during the selection of + * the checker board. + */ + i = 0; + while (i < ds_offset) { + + /* these values should never be used */ + start[i] = 0; + stride[i] = 0; + count[i] = 0; + block[i] = 0; + + i++; + } + + while (i < sel_offset) { + + start[i] = sel_start[i]; + stride[i] = 2 * dims[i]; + count[i] = 1; + block[i] = 1; + + i++; + } + + while (i < test_max_rank) { + + stride[i] = (hsize_t)(2 * checker_edge_size); + block[i] = (hsize_t)checker_edge_size; + + i++; + } + + i = 0; + do { + if (0 >= sel_offset) { + + if (i == 0) { + + start[0] = 0; + count[0] = base_count; + } + else { + + start[0] = (hsize_t)checker_edge_size; + count[0] = offset_count; + } + } + + j = 0; + do { + if (1 >= sel_offset) { + + if (j == 0) { + + start[1] = 0; + count[1] = base_count; + } + else { + + start[1] = (hsize_t)checker_edge_size; + count[1] = offset_count; + } + } + + k = 0; + do { + if (2 >= sel_offset) { + + if (k == 0) { + + start[2] = 0; + count[2] = base_count; + } + else { + + start[2] = (hsize_t)checker_edge_size; + count[2] = offset_count; + } + } + + l = 0; + do { + if (3 >= sel_offset) { + + if (l == 0) { + + start[3] = 0; + count[3] = base_count; + } + else { + + start[3] = (hsize_t)checker_edge_size; + count[3] = offset_count; + } + } + + m = 0; + do { + if (4 >= sel_offset) { + + if (m == 0) { + + start[4] = 0; + count[4] = base_count; + } + else { + + start[4] = (hsize_t)checker_edge_size; + count[4] = offset_count; + } + } + + if (((i + j + k + l + m) % 2) == 0) { + +#if LOWER_DIM_SIZE_COMP_TEST__SELECT_CHECKER_BOARD__DEBUG + if (mpi_rank == LOWER_DIM_SIZE_COMP_TEST_DEBUG_TARGET_RANK) { + + HDfprintf(stdout, "%s%d: *** first_selection = %d ***\n", fcnName, mpi_rank, + (int)first_selection); + HDfprintf(stdout, "%s:%d: i/j/k/l/m = %d/%d/%d/%d/%d\n", fcnName, mpi_rank, i, + j, k, l, m); + HDfprintf(stdout, "%s:%d: start = %d %d %d %d %d.\n", fcnName, mpi_rank, + (int)start[0], (int)start[1], (int)start[2], (int)start[3], + (int)start[4]); + HDfprintf(stdout, "%s:%d: stride = %d %d %d %d %d.\n", fcnName, mpi_rank, + (int)stride[0], (int)stride[1], (int)stride[2], (int)stride[3], + (int)stride[4]); + HDfprintf(stdout, "%s:%d: count = %d %d %d %d %d.\n", fcnName, mpi_rank, + (int)count[0], (int)count[1], (int)count[2], (int)count[3], + (int)count[4]); + HDfprintf(stdout, "%s:%d: block = %d %d %d %d %d.\n", fcnName, mpi_rank, + (int)block[0], (int)block[1], (int)block[2], (int)block[3], + (int)block[4]); + HDfprintf(stdout, "%s:%d: n-cube extent dims = %d.\n", fcnName, mpi_rank, + H5Sget_simple_extent_ndims(tgt_sid)); + HDfprintf(stdout, "%s:%d: selection rank = %d.\n", fcnName, mpi_rank, + sel_rank); + } +#endif + + if (first_selection) { + + first_selection = FALSE; + + ret = H5Sselect_hyperslab(tgt_sid, H5S_SELECT_SET, &(start[ds_offset]), + &(stride[ds_offset]), &(count[ds_offset]), + &(block[ds_offset])); + + VRFY((ret != FAIL), "H5Sselect_hyperslab(SET) succeeded"); + } + else { + + ret = H5Sselect_hyperslab(tgt_sid, H5S_SELECT_OR, &(start[ds_offset]), + &(stride[ds_offset]), &(count[ds_offset]), + &(block[ds_offset])); + + VRFY((ret != FAIL), "H5Sselect_hyperslab(OR) succeeded"); + } + } + + m++; + + } while ((m <= 1) && (4 >= sel_offset)); + + l++; + + } while ((l <= 1) && (3 >= sel_offset)); + + k++; + + } while ((k <= 1) && (2 >= sel_offset)); + + j++; + + } while ((j <= 1) && (1 >= sel_offset)); + + i++; + + } while ((i <= 1) && (0 >= sel_offset)); + +#if LOWER_DIM_SIZE_COMP_TEST__SELECT_CHECKER_BOARD__DEBUG + if (mpi_rank == LOWER_DIM_SIZE_COMP_TEST_DEBUG_TARGET_RANK) { + HDfprintf(stdout, "%s%d: H5Sget_select_npoints(tgt_sid) = %d.\n", fcnName, mpi_rank, + (int)H5Sget_select_npoints(tgt_sid)); + } +#endif /* LOWER_DIM_SIZE_COMP_TEST__SELECT_CHECKER_BOARD__DEBUG */ + + /* Clip the selection back to the dataspace proper. */ + + for (i = 0; i < test_max_rank; i++) { + + start[i] = 0; + stride[i] = dims[i]; + count[i] = 1; + block[i] = dims[i]; + } + + ret = H5Sselect_hyperslab(tgt_sid, H5S_SELECT_AND, start, stride, count, block); + + VRFY((ret != FAIL), "H5Sselect_hyperslab(AND) succeeded"); + +#if LOWER_DIM_SIZE_COMP_TEST__SELECT_CHECKER_BOARD__DEBUG + if (mpi_rank == LOWER_DIM_SIZE_COMP_TEST_DEBUG_TARGET_RANK) { + HDfprintf(stdout, "%s%d: H5Sget_select_npoints(tgt_sid) = %d.\n", fcnName, mpi_rank, + (int)H5Sget_select_npoints(tgt_sid)); + HDfprintf(stdout, "%s%d: done.\n", fcnName, mpi_rank); + } +#endif /* LOWER_DIM_SIZE_COMP_TEST__SELECT_CHECKER_BOARD__DEBUG */ + + return; + +} /* lower_dim_size_comp_test__select_checker_board() */ + +/**************************************************************** +** +** lower_dim_size_comp_test__verify_data(): +** +** Examine the supplied buffer to see if it contains the +** expected data. Return TRUE if it does, and FALSE +** otherwise. +** +** The supplied buffer is presumed to this process's slice +** of the target data set. Each such slice will be an +** n-cube of rank (rank -1) and the supplied edge_size with +** origin (mpi_rank, 0, ... , 0) in the target data set. +** +** Further, the buffer is presumed to be the result of reading +** or writing a checker board selection of an m (1 <= m < +** rank) dimensional slice through this processes slice +** of the target data set. Also, this slice must be parallel +** to the fastest changing indices. +** +** It is further presumed that the buffer was zeroed before +** the read/write, and that the full target data set (i.e. +** the buffer/data set for all processes) was initialized +** with the natural numbers listed in order from the origin +** along the fastest changing axis. +** +** Thus for a 20x10x10 dataset, the value stored in location +** (x, y, z) (assuming that z is the fastest changing index +** and x the slowest) is assumed to be: +** +** (10 * 10 * x) + (10 * y) + z +** +** Further, supposing that this is process 10, this process's +** slice of the dataset would be a 10 x 10 2-cube with origin +** (10, 0, 0) in the data set, and would be initialize (prior +** to the checkerboard selection) as follows: +** +** 1000, 1001, 1002, ... 1008, 1009 +** 1010, 1011, 1012, ... 1018, 1019 +** . . . . . +** . . . . . +** . . . . . +** 1090, 1091, 1092, ... 1098, 1099 +** +** In the case of a read from the processors slice of another +** data set of different rank, the values expected will have +** to be adjusted accordingly. This is done via the +** first_expected_val parameter. +** +** Finally, the function presumes that the first element +** of the buffer resides either at the origin of either +** a selected or an unselected checker. (Translation: +** if partial checkers appear in the buffer, they will +** intersect the edges of the n-cube opposite the origin.) +** +****************************************************************/ + +#define LOWER_DIM_SIZE_COMP_TEST__VERIFY_DATA__DEBUG 0 + +static hbool_t +lower_dim_size_comp_test__verify_data(uint32_t *buf_ptr, +#if LOWER_DIM_SIZE_COMP_TEST__VERIFY_DATA__DEBUG + const int mpi_rank, +#endif /* LOWER_DIM_SIZE_COMP_TEST__VERIFY_DATA__DEBUG */ + const int rank, const int edge_size, const int checker_edge_size, + uint32_t first_expected_val, hbool_t buf_starts_in_checker) +{ +#if LOWER_DIM_SIZE_COMP_TEST__VERIFY_DATA__DEBUG + const char *fcnName = "lower_dim_size_comp_test__verify_data():"; +#endif + hbool_t good_data = TRUE; + hbool_t in_checker; + hbool_t start_in_checker[5]; + uint32_t expected_value; + uint32_t *val_ptr; + int i, j, k, l, m; /* to track position in n-cube */ + int v, w, x, y, z; /* to track position in checker */ + const int test_max_rank = 5; /* code changes needed if this is increased */ + + HDassert(buf_ptr != NULL); + HDassert(0 < rank); + HDassert(rank <= test_max_rank); + HDassert(edge_size >= 6); + HDassert(0 < checker_edge_size); + HDassert(checker_edge_size <= edge_size); + HDassert(test_max_rank <= LDSCT_DS_RANK); + +#if LOWER_DIM_SIZE_COMP_TEST__VERIFY_DATA__DEBUG + if (mpi_rank == LOWER_DIM_SIZE_COMP_TEST_DEBUG_TARGET_RANK) { + HDfprintf(stdout, "%s mpi_rank = %d.\n", fcnName, mpi_rank); + HDfprintf(stdout, "%s rank = %d.\n", fcnName, rank); + HDfprintf(stdout, "%s edge_size = %d.\n", fcnName, edge_size); + HDfprintf(stdout, "%s checker_edge_size = %d.\n", fcnName, checker_edge_size); + HDfprintf(stdout, "%s first_expected_val = %d.\n", fcnName, (int)first_expected_val); + HDfprintf(stdout, "%s starts_in_checker = %d.\n", fcnName, (int)buf_starts_in_checker); + } +#endif + + val_ptr = buf_ptr; + expected_value = first_expected_val; + + i = 0; + v = 0; + start_in_checker[0] = buf_starts_in_checker; + do { + if (v >= checker_edge_size) { + + start_in_checker[0] = !start_in_checker[0]; + v = 0; + } + + j = 0; + w = 0; + start_in_checker[1] = start_in_checker[0]; + do { + if (w >= checker_edge_size) { + + start_in_checker[1] = !start_in_checker[1]; + w = 0; + } + + k = 0; + x = 0; + start_in_checker[2] = start_in_checker[1]; + do { + if (x >= checker_edge_size) { + + start_in_checker[2] = !start_in_checker[2]; + x = 0; + } + + l = 0; + y = 0; + start_in_checker[3] = start_in_checker[2]; + do { + if (y >= checker_edge_size) { + + start_in_checker[3] = !start_in_checker[3]; + y = 0; + } + + m = 0; + z = 0; +#if LOWER_DIM_SIZE_COMP_TEST__VERIFY_DATA__DEBUG + if (mpi_rank == LOWER_DIM_SIZE_COMP_TEST_DEBUG_TARGET_RANK) { + HDfprintf(stdout, "%d, %d, %d, %d, %d:", i, j, k, l, m); + } +#endif + in_checker = start_in_checker[3]; + do { +#if LOWER_DIM_SIZE_COMP_TEST__VERIFY_DATA__DEBUG + if (mpi_rank == LOWER_DIM_SIZE_COMP_TEST_DEBUG_TARGET_RANK) { + HDfprintf(stdout, " %d", (int)(*val_ptr)); + } +#endif + if (z >= checker_edge_size) { + + in_checker = !in_checker; + z = 0; + } + + if (in_checker) { + + if (*val_ptr != expected_value) { + + good_data = FALSE; + } + + /* zero out buffer for re-use */ + *val_ptr = 0; + } + else if (*val_ptr != 0) { + + good_data = FALSE; + + /* zero out buffer for re-use */ + *val_ptr = 0; + } + + val_ptr++; + expected_value++; + m++; + z++; + + } while ((rank >= (test_max_rank - 4)) && (m < edge_size)); +#if LOWER_DIM_SIZE_COMP_TEST__VERIFY_DATA__DEBUG + if (mpi_rank == LOWER_DIM_SIZE_COMP_TEST_DEBUG_TARGET_RANK) { + HDfprintf(stdout, "\n"); + } +#endif + l++; + y++; + } while ((rank >= (test_max_rank - 3)) && (l < edge_size)); + k++; + x++; + } while ((rank >= (test_max_rank - 2)) && (k < edge_size)); + j++; + w++; + } while ((rank >= (test_max_rank - 1)) && (j < edge_size)); + i++; + v++; + } while ((rank >= test_max_rank) && (i < edge_size)); + + return (good_data); + +} /* lower_dim_size_comp_test__verify_data() */ + +/*------------------------------------------------------------------------- + * Function: lower_dim_size_comp_test__run_test() + * + * Purpose: Verify that a bug in the computation of the size of the + * lower dimensions of a dataspace in H5S_obtain_datatype() + * has been corrected. + * + * Return: void + * + * Programmer: JRM -- 11/11/09 + * + *------------------------------------------------------------------------- + */ + +#define LDSCT_DS_RANK 5 + +static void +lower_dim_size_comp_test__run_test(const int chunk_edge_size, const hbool_t use_collective_io, + const hid_t dset_type) +{ +#if LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG + const char *fcnName = "lower_dim_size_comp_test__run_test()"; + int rank; + hsize_t dims[32]; + hsize_t max_dims[32]; +#endif /* LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG */ + const char *filename; + hbool_t data_ok = FALSE; + hbool_t mis_match = FALSE; + int i; + int start_index; + int stop_index; + int mrc; + int mpi_rank; + int mpi_size; + MPI_Comm mpi_comm = MPI_COMM_NULL; + MPI_Info mpi_info = MPI_INFO_NULL; + hid_t fid; /* HDF5 file ID */ + hid_t acc_tpl; /* File access templates */ + hid_t xfer_plist = H5P_DEFAULT; + size_t small_ds_size; + size_t small_ds_slice_size; + size_t large_ds_size; +#if LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG + size_t large_ds_slice_size; +#endif + uint32_t expected_value; + uint32_t *small_ds_buf_0 = NULL; + uint32_t *small_ds_buf_1 = NULL; + uint32_t *large_ds_buf_0 = NULL; + uint32_t *large_ds_buf_1 = NULL; + uint32_t *ptr_0; + uint32_t *ptr_1; + hsize_t small_chunk_dims[LDSCT_DS_RANK]; + hsize_t large_chunk_dims[LDSCT_DS_RANK]; + hsize_t small_dims[LDSCT_DS_RANK]; + hsize_t large_dims[LDSCT_DS_RANK]; + hsize_t start[LDSCT_DS_RANK]; + hsize_t stride[LDSCT_DS_RANK]; + hsize_t count[LDSCT_DS_RANK]; + hsize_t block[LDSCT_DS_RANK]; + hsize_t small_sel_start[LDSCT_DS_RANK]; + hsize_t large_sel_start[LDSCT_DS_RANK]; + hid_t full_mem_small_ds_sid; + hid_t full_file_small_ds_sid; + hid_t mem_small_ds_sid; + hid_t file_small_ds_sid; + hid_t full_mem_large_ds_sid; + hid_t full_file_large_ds_sid; + hid_t mem_large_ds_sid; + hid_t file_large_ds_sid; + hid_t small_ds_dcpl_id = H5P_DEFAULT; + hid_t large_ds_dcpl_id = H5P_DEFAULT; + hid_t small_dataset; /* Dataset ID */ + hid_t large_dataset; /* Dataset ID */ + htri_t check; /* Shape comparison return value */ + herr_t ret; /* Generic return value */ + + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + HDassert(mpi_size >= 1); + + mpi_comm = MPI_COMM_WORLD; + mpi_info = MPI_INFO_NULL; + +#if LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG + if (mpi_rank == LOWER_DIM_SIZE_COMP_TEST_DEBUG_TARGET_RANK) { + HDfprintf(stdout, "%s:%d: chunk_edge_size = %d.\n", fcnName, mpi_rank, (int)chunk_edge_size); + HDfprintf(stdout, "%s:%d: use_collective_io = %d.\n", fcnName, mpi_rank, (int)use_collective_io); + } +#endif /* LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG */ + + small_ds_size = (size_t)((mpi_size + 1) * 1 * 1 * 10 * 10); + small_ds_slice_size = (size_t)(1 * 1 * 10 * 10); + large_ds_size = (size_t)((mpi_size + 1) * 10 * 10 * 10 * 10); + +#if LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG + large_ds_slice_size = (size_t)(10 * 10 * 10 * 10); + + if (mpi_rank == LOWER_DIM_SIZE_COMP_TEST_DEBUG_TARGET_RANK) { + HDfprintf(stdout, "%s:%d: small ds size / slice size = %d / %d.\n", fcnName, mpi_rank, + (int)small_ds_size, (int)small_ds_slice_size); + HDfprintf(stdout, "%s:%d: large ds size / slice size = %d / %d.\n", fcnName, mpi_rank, + (int)large_ds_size, (int)large_ds_slice_size); + } +#endif /* LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG */ + + /* Allocate buffers */ + small_ds_buf_0 = (uint32_t *)HDmalloc(sizeof(uint32_t) * small_ds_size); + VRFY((small_ds_buf_0 != NULL), "malloc of small_ds_buf_0 succeeded"); + + small_ds_buf_1 = (uint32_t *)HDmalloc(sizeof(uint32_t) * small_ds_size); + VRFY((small_ds_buf_1 != NULL), "malloc of small_ds_buf_1 succeeded"); + + large_ds_buf_0 = (uint32_t *)HDmalloc(sizeof(uint32_t) * large_ds_size); + VRFY((large_ds_buf_0 != NULL), "malloc of large_ds_buf_0 succeeded"); + + large_ds_buf_1 = (uint32_t *)HDmalloc(sizeof(uint32_t) * large_ds_size); + VRFY((large_ds_buf_1 != NULL), "malloc of large_ds_buf_1 succeeded"); + + /* initialize the buffers */ + + ptr_0 = small_ds_buf_0; + ptr_1 = small_ds_buf_1; + + for (i = 0; i < (int)small_ds_size; i++) { + + *ptr_0 = (uint32_t)i; + *ptr_1 = 0; + + ptr_0++; + ptr_1++; + } + + ptr_0 = large_ds_buf_0; + ptr_1 = large_ds_buf_1; + + for (i = 0; i < (int)large_ds_size; i++) { + + *ptr_0 = (uint32_t)i; + *ptr_1 = 0; + + ptr_0++; + ptr_1++; + } + + /* get the file name */ + + filename = (const char *)PARATESTFILE /* GetTestParameters() */; + HDassert(filename != NULL); + + /* ---------------------------------------- + * CREATE AN HDF5 FILE WITH PARALLEL ACCESS + * ---------------------------------------*/ + /* setup file access template */ + acc_tpl = create_faccess_plist(mpi_comm, mpi_info, facc_type); + VRFY((acc_tpl >= 0), "create_faccess_plist() succeeded"); + + /* create the file collectively */ + fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, acc_tpl); + VRFY((fid >= 0), "H5Fcreate succeeded"); + + MESG("File opened."); + + /* Release file-access template */ + ret = H5Pclose(acc_tpl); + VRFY((ret >= 0), "H5Pclose(acc_tpl) succeeded"); + + /* setup dims: */ + small_dims[0] = (hsize_t)(mpi_size + 1); + small_dims[1] = 1; + small_dims[2] = 1; + small_dims[3] = 10; + small_dims[4] = 10; + + large_dims[0] = (hsize_t)(mpi_size + 1); + large_dims[1] = 10; + large_dims[2] = 10; + large_dims[3] = 10; + large_dims[4] = 10; + +#if LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG + if (mpi_rank == LOWER_DIM_SIZE_COMP_TEST_DEBUG_TARGET_RANK) { + HDfprintf(stdout, "%s:%d: small_dims[] = %d %d %d %d %d\n", fcnName, mpi_rank, (int)small_dims[0], + (int)small_dims[1], (int)small_dims[2], (int)small_dims[3], (int)small_dims[4]); + HDfprintf(stdout, "%s:%d: large_dims[] = %d %d %d %d %d\n", fcnName, mpi_rank, (int)large_dims[0], + (int)large_dims[1], (int)large_dims[2], (int)large_dims[3], (int)large_dims[4]); + } +#endif + + /* create dataspaces */ + + full_mem_small_ds_sid = H5Screate_simple(5, small_dims, NULL); + VRFY((full_mem_small_ds_sid != 0), "H5Screate_simple() full_mem_small_ds_sid succeeded"); + + full_file_small_ds_sid = H5Screate_simple(5, small_dims, NULL); + VRFY((full_file_small_ds_sid != 0), "H5Screate_simple() full_file_small_ds_sid succeeded"); + + mem_small_ds_sid = H5Screate_simple(5, small_dims, NULL); + VRFY((mem_small_ds_sid != 0), "H5Screate_simple() mem_small_ds_sid succeeded"); + + file_small_ds_sid = H5Screate_simple(5, small_dims, NULL); + VRFY((file_small_ds_sid != 0), "H5Screate_simple() file_small_ds_sid succeeded"); + + full_mem_large_ds_sid = H5Screate_simple(5, large_dims, NULL); + VRFY((full_mem_large_ds_sid != 0), "H5Screate_simple() full_mem_large_ds_sid succeeded"); + + full_file_large_ds_sid = H5Screate_simple(5, large_dims, NULL); + VRFY((full_file_large_ds_sid != 0), "H5Screate_simple() full_file_large_ds_sid succeeded"); + + mem_large_ds_sid = H5Screate_simple(5, large_dims, NULL); + VRFY((mem_large_ds_sid != 0), "H5Screate_simple() mem_large_ds_sid succeeded"); + + file_large_ds_sid = H5Screate_simple(5, large_dims, NULL); + VRFY((file_large_ds_sid != 0), "H5Screate_simple() file_large_ds_sid succeeded"); + + /* Select the entire extent of the full small ds dataspaces */ + ret = H5Sselect_all(full_mem_small_ds_sid); + VRFY((ret != FAIL), "H5Sselect_all(full_mem_small_ds_sid) succeeded"); + + ret = H5Sselect_all(full_file_small_ds_sid); + VRFY((ret != FAIL), "H5Sselect_all(full_file_small_ds_sid) succeeded"); + + /* Select the entire extent of the full large ds dataspaces */ + ret = H5Sselect_all(full_mem_large_ds_sid); + VRFY((ret != FAIL), "H5Sselect_all(full_mem_large_ds_sid) succeeded"); + + ret = H5Sselect_all(full_file_large_ds_sid); + VRFY((ret != FAIL), "H5Sselect_all(full_file_large_ds_sid) succeeded"); + + /* if chunk edge size is greater than zero, set up the small and + * large data set creation property lists to specify chunked + * datasets. + */ + if (chunk_edge_size > 0) { + + small_chunk_dims[0] = (hsize_t)(1); + small_chunk_dims[1] = small_chunk_dims[2] = (hsize_t)1; + small_chunk_dims[3] = small_chunk_dims[4] = (hsize_t)chunk_edge_size; + +#if LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG + if (mpi_rank == LOWER_DIM_SIZE_COMP_TEST_DEBUG_TARGET_RANK) { + HDfprintf(stdout, "%s:%d: small chunk dims[] = %d %d %d %d %d\n", fcnName, mpi_rank, + (int)small_chunk_dims[0], (int)small_chunk_dims[1], (int)small_chunk_dims[2], + (int)small_chunk_dims[3], (int)small_chunk_dims[4]); + } +#endif + + small_ds_dcpl_id = H5Pcreate(H5P_DATASET_CREATE); + VRFY((ret != FAIL), "H5Pcreate() small_ds_dcpl_id succeeded"); + + ret = H5Pset_layout(small_ds_dcpl_id, H5D_CHUNKED); + VRFY((ret != FAIL), "H5Pset_layout() small_ds_dcpl_id succeeded"); + + ret = H5Pset_chunk(small_ds_dcpl_id, 5, small_chunk_dims); + VRFY((ret != FAIL), "H5Pset_chunk() small_ds_dcpl_id succeeded"); + + large_chunk_dims[0] = (hsize_t)(1); + large_chunk_dims[1] = large_chunk_dims[2] = large_chunk_dims[3] = large_chunk_dims[4] = + (hsize_t)chunk_edge_size; + +#if LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG + if (mpi_rank == LOWER_DIM_SIZE_COMP_TEST_DEBUG_TARGET_RANK) { + HDfprintf(stdout, "%s:%d: large chunk dims[] = %d %d %d %d %d\n", fcnName, mpi_rank, + (int)large_chunk_dims[0], (int)large_chunk_dims[1], (int)large_chunk_dims[2], + (int)large_chunk_dims[3], (int)large_chunk_dims[4]); + } +#endif + + large_ds_dcpl_id = H5Pcreate(H5P_DATASET_CREATE); + VRFY((ret != FAIL), "H5Pcreate() large_ds_dcpl_id succeeded"); + + ret = H5Pset_layout(large_ds_dcpl_id, H5D_CHUNKED); + VRFY((ret != FAIL), "H5Pset_layout() large_ds_dcpl_id succeeded"); + + ret = H5Pset_chunk(large_ds_dcpl_id, 5, large_chunk_dims); + VRFY((ret != FAIL), "H5Pset_chunk() large_ds_dcpl_id succeeded"); + } + + /* create the small dataset */ + small_dataset = H5Dcreate2(fid, "small_dataset", dset_type, file_small_ds_sid, H5P_DEFAULT, + small_ds_dcpl_id, H5P_DEFAULT); + VRFY((ret >= 0), "H5Dcreate2() small_dataset succeeded"); + + /* create the large dataset */ + large_dataset = H5Dcreate2(fid, "large_dataset", dset_type, file_large_ds_sid, H5P_DEFAULT, + large_ds_dcpl_id, H5P_DEFAULT); + VRFY((ret >= 0), "H5Dcreate2() large_dataset succeeded"); + +#if LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG + if (mpi_rank == LOWER_DIM_SIZE_COMP_TEST_DEBUG_TARGET_RANK) { + HDfprintf(stdout, "%s:%d: small/large ds id = %d / %d.\n", fcnName, mpi_rank, (int)small_dataset, + (int)large_dataset); + } +#endif /* LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG */ + + /* setup xfer property list */ + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY((xfer_plist >= 0), "H5Pcreate(H5P_DATASET_XFER) succeeded"); + + ret = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + + if (!use_collective_io) { + + ret = H5Pset_dxpl_mpio_collective_opt(xfer_plist, H5FD_MPIO_INDIVIDUAL_IO); + VRFY((ret >= 0), "H5Pset_dxpl_mpio_collective_opt() succeeded"); + } + + /* setup selection to write initial data to the small data sets */ + start[0] = (hsize_t)(mpi_rank + 1); + start[1] = start[2] = start[3] = start[4] = 0; + + stride[0] = (hsize_t)(2 * (mpi_size + 1)); + stride[1] = stride[2] = 2; + stride[3] = stride[4] = 2 * 10; + + count[0] = count[1] = count[2] = count[3] = count[4] = 1; + + block[0] = block[1] = block[2] = 1; + block[3] = block[4] = 10; + +#if LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG + if (mpi_rank == LOWER_DIM_SIZE_COMP_TEST_DEBUG_TARGET_RANK) { + HDfprintf(stdout, "%s:%d: settings for small data set initialization.\n", fcnName, mpi_rank); + HDfprintf(stdout, "%s:%d: start[] = %d %d %d %d %d\n", fcnName, mpi_rank, (int)start[0], + (int)start[1], (int)start[2], (int)start[3], (int)start[4]); + HDfprintf(stdout, "%s:%d: stride[] = %d %d %d %d %d\n", fcnName, mpi_rank, (int)stride[0], + (int)stride[1], (int)stride[2], (int)stride[3], (int)stride[4]); + HDfprintf(stdout, "%s:%d: count[] = %d %d %d %d %d\n", fcnName, mpi_rank, (int)count[0], + (int)count[1], (int)count[2], (int)count[3], (int)count[4]); + HDfprintf(stdout, "%s:%d: block[] = %d %d %d %d %d\n", fcnName, mpi_rank, (int)block[0], + (int)block[1], (int)block[2], (int)block[3], (int)block[4]); + } +#endif /* LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG */ + + /* setup selections for writing initial data to the small data set */ + ret = H5Sselect_hyperslab(mem_small_ds_sid, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sselect_hyperslab(mem_small_ds_sid, set) succeeded"); + + ret = H5Sselect_hyperslab(file_small_ds_sid, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sselect_hyperslab(file_small_ds_sid, set) succeeded"); + + if (MAINPROCESS) { /* add an additional slice to the selections */ + + start[0] = 0; + +#if LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG + if (mpi_rank == LOWER_DIM_SIZE_COMP_TEST_DEBUG_TARGET_RANK) { + HDfprintf(stdout, "%s:%d: added settings for main process.\n", fcnName, mpi_rank); + HDfprintf(stdout, "%s:%d: start[] = %d %d %d %d %d\n", fcnName, mpi_rank, (int)start[0], + (int)start[1], (int)start[2], (int)start[3], (int)start[4]); + HDfprintf(stdout, "%s:%d: stride[] = %d %d %d %d %d\n", fcnName, mpi_rank, (int)stride[0], + (int)stride[1], (int)stride[2], (int)stride[3], (int)stride[4]); + HDfprintf(stdout, "%s:%d: count[] = %d %d %d %d %d\n", fcnName, mpi_rank, (int)count[0], + (int)count[1], (int)count[2], (int)count[3], (int)count[4]); + HDfprintf(stdout, "%s:%d: block[] = %d %d %d %d %d\n", fcnName, mpi_rank, (int)block[0], + (int)block[1], (int)block[2], (int)block[3], (int)block[4]); + } +#endif /* LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG */ + + ret = H5Sselect_hyperslab(mem_small_ds_sid, H5S_SELECT_OR, start, stride, count, block); + VRFY((ret >= 0), "H5Sselect_hyperslab(mem_small_ds_sid, or) succeeded"); + + ret = H5Sselect_hyperslab(file_small_ds_sid, H5S_SELECT_OR, start, stride, count, block); + VRFY((ret >= 0), "H5Sselect_hyperslab(file_small_ds_sid, or) succeeded"); + } + + check = H5Sselect_valid(mem_small_ds_sid); + VRFY((check == TRUE), "H5Sselect_valid(mem_small_ds_sid) returns TRUE"); + + check = H5Sselect_valid(file_small_ds_sid); + VRFY((check == TRUE), "H5Sselect_valid(file_small_ds_sid) returns TRUE"); + + /* write the initial value of the small data set to file */ +#if LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG + if (mpi_rank == LOWER_DIM_SIZE_COMP_TEST_DEBUG_TARGET_RANK) { + HDfprintf(stdout, "%s:%d: writing init value of small ds to file.\n", fcnName, mpi_rank); + } +#endif /* LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG */ + ret = H5Dwrite(small_dataset, dset_type, mem_small_ds_sid, file_small_ds_sid, xfer_plist, small_ds_buf_0); + VRFY((ret >= 0), "H5Dwrite() small_dataset initial write succeeded"); + + /* sync with the other processes before reading data */ + mrc = MPI_Barrier(MPI_COMM_WORLD); + VRFY((mrc == MPI_SUCCESS), "Sync after small dataset writes"); + + /* read the small data set back to verify that it contains the + * expected data. Note that each process reads in the entire + * data set and verifies it. + */ + ret = H5Dread(small_dataset, H5T_NATIVE_UINT32, full_mem_small_ds_sid, full_file_small_ds_sid, xfer_plist, + small_ds_buf_1); + VRFY((ret >= 0), "H5Dread() small_dataset initial read succeeded"); + + /* sync with the other processes before checking data */ + mrc = MPI_Barrier(MPI_COMM_WORLD); + VRFY((mrc == MPI_SUCCESS), "Sync after small dataset writes"); + + /* verify that the correct data was written to the small data set, + * and reset the buffer to zero in passing. + */ + expected_value = 0; + mis_match = FALSE; + ptr_1 = small_ds_buf_1; + + i = 0; + for (i = 0; i < (int)small_ds_size; i++) { + + if (*ptr_1 != expected_value) { + + mis_match = TRUE; + } + + *ptr_1 = (uint32_t)0; + + ptr_1++; + expected_value++; + } + VRFY((mis_match == FALSE), "small ds init data good."); + + /* setup selections for writing initial data to the large data set */ + start[0] = (hsize_t)(mpi_rank + 1); + start[1] = start[2] = start[3] = start[4] = (hsize_t)0; + + stride[0] = (hsize_t)(2 * (mpi_size + 1)); + stride[1] = stride[2] = stride[3] = stride[4] = (hsize_t)(2 * 10); + + count[0] = count[1] = count[2] = count[3] = count[4] = (hsize_t)1; + + block[0] = (hsize_t)1; + block[1] = block[2] = block[3] = block[4] = (hsize_t)10; + +#if LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG + if (mpi_rank == LOWER_DIM_SIZE_COMP_TEST_DEBUG_TARGET_RANK) { + HDfprintf(stdout, "%s:%d: settings for large data set initialization.\n", fcnName, mpi_rank); + HDfprintf(stdout, "%s:%d: start[] = %d %d %d %d %d\n", fcnName, mpi_rank, (int)start[0], + (int)start[1], (int)start[2], (int)start[3], (int)start[4]); + HDfprintf(stdout, "%s:%d: stride[] = %d %d %d %d %d\n", fcnName, mpi_rank, (int)stride[0], + (int)stride[1], (int)stride[2], (int)stride[3], (int)stride[4]); + HDfprintf(stdout, "%s:%d: count[] = %d %d %d %d %d\n", fcnName, mpi_rank, (int)count[0], + (int)count[1], (int)count[2], (int)count[3], (int)count[4]); + HDfprintf(stdout, "%s:%d: block[] = %d %d %d %d %d\n", fcnName, mpi_rank, (int)block[0], + (int)block[1], (int)block[2], (int)block[3], (int)block[4]); + } +#endif /* LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG */ + + ret = H5Sselect_hyperslab(mem_large_ds_sid, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sselect_hyperslab(mem_large_ds_sid, set) succeeded"); + + ret = H5Sselect_hyperslab(file_large_ds_sid, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sselect_hyperslab(file_large_ds_sid, set) succeeded"); + +#if LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG + if (mpi_rank == LOWER_DIM_SIZE_COMP_TEST_DEBUG_TARGET_RANK) { + HDfprintf(stdout, "%s%d: H5Sget_select_npoints(mem_large_ds_sid) = %d.\n", fcnName, mpi_rank, + (int)H5Sget_select_npoints(mem_large_ds_sid)); + HDfprintf(stdout, "%s%d: H5Sget_select_npoints(file_large_ds_sid) = %d.\n", fcnName, mpi_rank, + (int)H5Sget_select_npoints(file_large_ds_sid)); + } +#endif /* LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG */ + + if (MAINPROCESS) { /* add an additional slice to the selections */ + + start[0] = (hsize_t)0; + +#if LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG + if (mpi_rank == LOWER_DIM_SIZE_COMP_TEST_DEBUG_TARGET_RANK) { + HDfprintf(stdout, "%s:%d: added settings for main process.\n", fcnName, mpi_rank); + HDfprintf(stdout, "%s:%d: start[] = %d %d %d %d %d\n", fcnName, mpi_rank, (int)start[0], + (int)start[1], (int)start[2], (int)start[3], (int)start[4]); + HDfprintf(stdout, "%s:%d: stride[] = %d %d %d %d %d\n", fcnName, mpi_rank, (int)stride[0], + (int)stride[1], (int)stride[2], (int)stride[3], (int)stride[4]); + HDfprintf(stdout, "%s:%d: count[] = %d %d %d %d %d\n", fcnName, mpi_rank, (int)count[0], + (int)count[1], (int)count[2], (int)count[3], (int)count[4]); + HDfprintf(stdout, "%s:%d: block[] = %d %d %d %d %d\n", fcnName, mpi_rank, (int)block[0], + (int)block[1], (int)block[2], (int)block[3], (int)block[4]); + } +#endif /* LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG */ + + ret = H5Sselect_hyperslab(mem_large_ds_sid, H5S_SELECT_OR, start, stride, count, block); + VRFY((ret >= 0), "H5Sselect_hyperslab(mem_large_ds_sid, or) succeeded"); + + ret = H5Sselect_hyperslab(file_large_ds_sid, H5S_SELECT_OR, start, stride, count, block); + VRFY((ret >= 0), "H5Sselect_hyperslab(file_large_ds_sid, or) succeeded"); + +#if LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG + if (mpi_rank == LOWER_DIM_SIZE_COMP_TEST_DEBUG_TARGET_RANK) { + HDfprintf(stdout, "%s%d: H5Sget_select_npoints(mem_large_ds_sid) = %d.\n", fcnName, mpi_rank, + (int)H5Sget_select_npoints(mem_large_ds_sid)); + HDfprintf(stdout, "%s%d: H5Sget_select_npoints(file_large_ds_sid) = %d.\n", fcnName, mpi_rank, + (int)H5Sget_select_npoints(file_large_ds_sid)); + } +#endif /* LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG */ + } + + /* try clipping the selection back to the large dataspace proper */ + start[0] = start[1] = start[2] = start[3] = start[4] = (hsize_t)0; + + stride[0] = (hsize_t)(2 * (mpi_size + 1)); + stride[1] = stride[2] = stride[3] = stride[4] = (hsize_t)(2 * 10); + + count[0] = count[1] = count[2] = count[3] = count[4] = (hsize_t)1; + + block[0] = (hsize_t)(mpi_size + 1); + block[1] = block[2] = block[3] = block[4] = (hsize_t)10; + + ret = H5Sselect_hyperslab(mem_large_ds_sid, H5S_SELECT_AND, start, stride, count, block); + VRFY((ret != FAIL), "H5Sselect_hyperslab(mem_large_ds_sid, and) succeeded"); + + ret = H5Sselect_hyperslab(file_large_ds_sid, H5S_SELECT_AND, start, stride, count, block); + VRFY((ret != FAIL), "H5Sselect_hyperslab(file_large_ds_sid, and) succeeded"); + +#if LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG + if (mpi_rank == LOWER_DIM_SIZE_COMP_TEST_DEBUG_TARGET_RANK) { + + rank = H5Sget_simple_extent_dims(mem_large_ds_sid, dims, max_dims); + HDfprintf(stdout, "%s:%d: mem_large_ds_sid dims[%d] = %d %d %d %d %d\n", fcnName, mpi_rank, rank, + (int)dims[0], (int)dims[1], (int)dims[2], (int)dims[3], (int)dims[4]); + + rank = H5Sget_simple_extent_dims(file_large_ds_sid, dims, max_dims); + HDfprintf(stdout, "%s:%d: file_large_ds_sid dims[%d] = %d %d %d %d %d\n", fcnName, mpi_rank, rank, + (int)dims[0], (int)dims[1], (int)dims[2], (int)dims[3], (int)dims[4]); + } +#endif /* LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG */ + + check = H5Sselect_valid(mem_large_ds_sid); + VRFY((check == TRUE), "H5Sselect_valid(mem_large_ds_sid) returns TRUE"); + + check = H5Sselect_valid(file_large_ds_sid); + VRFY((check == TRUE), "H5Sselect_valid(file_large_ds_sid) returns TRUE"); + + /* write the initial value of the large data set to file */ +#if LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG + if (mpi_rank == LOWER_DIM_SIZE_COMP_TEST_DEBUG_TARGET_RANK) { + HDfprintf(stdout, "%s:%d: writing init value of large ds to file.\n", fcnName, mpi_rank); + HDfprintf(stdout, "%s:%d: large_dataset = %d.\n", fcnName, mpi_rank, (int)large_dataset); + HDfprintf(stdout, "%s:%d: mem_large_ds_sid = %d, file_large_ds_sid = %d.\n", fcnName, mpi_rank, + (int)mem_large_ds_sid, (int)file_large_ds_sid); + } +#endif /* LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG */ + + ret = H5Dwrite(large_dataset, dset_type, mem_large_ds_sid, file_large_ds_sid, xfer_plist, large_ds_buf_0); + + if (ret < 0) + H5Eprint2(H5E_DEFAULT, stderr); + VRFY((ret >= 0), "H5Dwrite() large_dataset initial write succeeded"); + + /* sync with the other processes before checking data */ + mrc = MPI_Barrier(MPI_COMM_WORLD); + VRFY((mrc == MPI_SUCCESS), "Sync after large dataset writes"); + + /* read the large data set back to verify that it contains the + * expected data. Note that each process reads in the entire + * data set. + */ + ret = H5Dread(large_dataset, H5T_NATIVE_UINT32, full_mem_large_ds_sid, full_file_large_ds_sid, xfer_plist, + large_ds_buf_1); + VRFY((ret >= 0), "H5Dread() large_dataset initial read succeeded"); + + /* verify that the correct data was written to the large data set. + * in passing, reset the buffer to zeros + */ + expected_value = 0; + mis_match = FALSE; + ptr_1 = large_ds_buf_1; + + i = 0; + for (i = 0; i < (int)large_ds_size; i++) { + + if (*ptr_1 != expected_value) { + + mis_match = TRUE; + } + + *ptr_1 = (uint32_t)0; + + ptr_1++; + expected_value++; + } + VRFY((mis_match == FALSE), "large ds init data good."); + + /***********************************/ + /***** INITIALIZATION COMPLETE *****/ + /***********************************/ + + /* read a checkerboard selection of the process slice of the + * small on disk data set into the process slice of the large + * in memory data set, and verify the data read. + */ + + small_sel_start[0] = (hsize_t)(mpi_rank + 1); + small_sel_start[1] = small_sel_start[2] = small_sel_start[3] = small_sel_start[4] = 0; + + lower_dim_size_comp_test__select_checker_board(mpi_rank, file_small_ds_sid, + /* tgt_rank = */ 5, small_dims, + /* checker_edge_size = */ 3, + /* sel_rank */ 2, small_sel_start); + + expected_value = + (uint32_t)((small_sel_start[0] * small_dims[1] * small_dims[2] * small_dims[3] * small_dims[4]) + + (small_sel_start[1] * small_dims[2] * small_dims[3] * small_dims[4]) + + (small_sel_start[2] * small_dims[3] * small_dims[4]) + + (small_sel_start[3] * small_dims[4]) + (small_sel_start[4])); + + large_sel_start[0] = (hsize_t)(mpi_rank + 1); + large_sel_start[1] = 5; + large_sel_start[2] = large_sel_start[3] = large_sel_start[4] = 0; + + lower_dim_size_comp_test__select_checker_board(mpi_rank, mem_large_ds_sid, + /* tgt_rank = */ 5, large_dims, + /* checker_edge_size = */ 3, + /* sel_rank = */ 2, large_sel_start); + + /* verify that H5Sselect_shape_same() reports the two + * selections as having the same shape. + */ + check = H5Sselect_shape_same(mem_large_ds_sid, file_small_ds_sid); + VRFY((check == TRUE), "H5Sselect_shape_same passed (1)"); + + ret = H5Dread(small_dataset, H5T_NATIVE_UINT32, mem_large_ds_sid, file_small_ds_sid, xfer_plist, + large_ds_buf_1); + + VRFY((ret >= 0), "H5Sread() slice from small ds succeeded."); + +#if LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG + if (mpi_rank == LOWER_DIM_SIZE_COMP_TEST_DEBUG_TARGET_RANK) { + HDfprintf(stdout, "%s:%d: H5Dread() returns.\n", fcnName, mpi_rank); + } +#endif /* LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG */ + + /* verify that expected data is retrieved */ + + data_ok = TRUE; + + start_index = (int)((large_sel_start[0] * large_dims[1] * large_dims[2] * large_dims[3] * large_dims[4]) + + (large_sel_start[1] * large_dims[2] * large_dims[3] * large_dims[4]) + + (large_sel_start[2] * large_dims[3] * large_dims[4]) + + (large_sel_start[3] * large_dims[4]) + (large_sel_start[4])); + + stop_index = start_index + (int)small_ds_slice_size; + + HDassert(0 <= start_index); + HDassert(start_index < stop_index); + HDassert(stop_index <= (int)large_ds_size); + + ptr_1 = large_ds_buf_1; + + for (i = 0; i < start_index; i++) { + + if (*ptr_1 != (uint32_t)0) { + + data_ok = FALSE; + *ptr_1 = (uint32_t)0; + } + + ptr_1++; + } + + VRFY((data_ok == TRUE), "slice read from small ds data good(1)."); + + data_ok = lower_dim_size_comp_test__verify_data(ptr_1, +#if LOWER_DIM_SIZE_COMP_TEST__VERIFY_DATA__DEBUG + mpi_rank, +#endif /* LOWER_DIM_SIZE_COMP_TEST__VERIFY_DATA__DEBUG */ + /* rank */ 2, + /* edge_size */ 10, + /* checker_edge_size */ 3, expected_value, + /* buf_starts_in_checker */ TRUE); + + VRFY((data_ok == TRUE), "slice read from small ds data good(2)."); + + data_ok = TRUE; + + ptr_1 += small_ds_slice_size; + + for (i = stop_index; i < (int)large_ds_size; i++) { + + if (*ptr_1 != (uint32_t)0) { + + data_ok = FALSE; + *ptr_1 = (uint32_t)0; + } + + ptr_1++; + } + + VRFY((data_ok == TRUE), "slice read from small ds data good(3)."); + + /* read a checkerboard selection of a slice of the process slice of + * the large on disk data set into the process slice of the small + * in memory data set, and verify the data read. + */ + + small_sel_start[0] = (hsize_t)(mpi_rank + 1); + small_sel_start[1] = small_sel_start[2] = small_sel_start[3] = small_sel_start[4] = 0; + + lower_dim_size_comp_test__select_checker_board(mpi_rank, mem_small_ds_sid, + /* tgt_rank = */ 5, small_dims, + /* checker_edge_size = */ 3, + /* sel_rank */ 2, small_sel_start); + + large_sel_start[0] = (hsize_t)(mpi_rank + 1); + large_sel_start[1] = 5; + large_sel_start[2] = large_sel_start[3] = large_sel_start[4] = 0; + + lower_dim_size_comp_test__select_checker_board(mpi_rank, file_large_ds_sid, + /* tgt_rank = */ 5, large_dims, + /* checker_edge_size = */ 3, + /* sel_rank = */ 2, large_sel_start); + + /* verify that H5Sselect_shape_same() reports the two + * selections as having the same shape. + */ + check = H5Sselect_shape_same(mem_small_ds_sid, file_large_ds_sid); + VRFY((check == TRUE), "H5Sselect_shape_same passed (2)"); + + ret = H5Dread(large_dataset, H5T_NATIVE_UINT32, mem_small_ds_sid, file_large_ds_sid, xfer_plist, + small_ds_buf_1); + + VRFY((ret >= 0), "H5Sread() slice from large ds succeeded."); + +#if LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG + if (mpi_rank == LOWER_DIM_SIZE_COMP_TEST_DEBUG_TARGET_RANK) { + HDfprintf(stdout, "%s:%d: H5Dread() returns.\n", fcnName, mpi_rank); + } +#endif /* LOWER_DIM_SIZE_COMP_TEST__RUN_TEST__DEBUG */ + + /* verify that expected data is retrieved */ + + data_ok = TRUE; + + expected_value = + (uint32_t)((large_sel_start[0] * large_dims[1] * large_dims[2] * large_dims[3] * large_dims[4]) + + (large_sel_start[1] * large_dims[2] * large_dims[3] * large_dims[4]) + + (large_sel_start[2] * large_dims[3] * large_dims[4]) + + (large_sel_start[3] * large_dims[4]) + (large_sel_start[4])); + + start_index = (int)(mpi_rank + 1) * (int)small_ds_slice_size; + + stop_index = start_index + (int)small_ds_slice_size; + + HDassert(0 <= start_index); + HDassert(start_index < stop_index); + HDassert(stop_index <= (int)small_ds_size); + + ptr_1 = small_ds_buf_1; + + for (i = 0; i < start_index; i++) { + + if (*ptr_1 != (uint32_t)0) { + + data_ok = FALSE; + *ptr_1 = (uint32_t)0; + } + + ptr_1++; + } + + VRFY((data_ok == TRUE), "slice read from large ds data good(1)."); + + data_ok = lower_dim_size_comp_test__verify_data(ptr_1, +#if LOWER_DIM_SIZE_COMP_TEST__VERIFY_DATA__DEBUG + mpi_rank, +#endif /* LOWER_DIM_SIZE_COMP_TEST__VERIFY_DATA__DEBUG */ + /* rank */ 2, + /* edge_size */ 10, + /* checker_edge_size */ 3, expected_value, + /* buf_starts_in_checker */ TRUE); + + VRFY((data_ok == TRUE), "slice read from large ds data good(2)."); + + data_ok = TRUE; + + ptr_1 += small_ds_slice_size; + + for (i = stop_index; i < (int)small_ds_size; i++) { + + if (*ptr_1 != (uint32_t)0) { + +#if LOWER_DIM_SIZE_COMP_TEST__VERIFY_DATA__DEBUG + if (mpi_rank == LOWER_DIM_SIZE_COMP_TEST_DEBUG_TARGET_RANK) { + HDfprintf(stdout, "%s:%d: unexpected value at index %d: %d.\n", fcnName, mpi_rank, (int)i, + (int)(*ptr_1)); + } +#endif /* LOWER_DIM_SIZE_COMP_TEST__VERIFY_DATA__DEBUG */ + + data_ok = FALSE; + *ptr_1 = (uint32_t)0; + } + + ptr_1++; + } + + VRFY((data_ok == TRUE), "slice read from large ds data good(3)."); + + /* Close dataspaces */ + ret = H5Sclose(full_mem_small_ds_sid); + VRFY((ret != FAIL), "H5Sclose(full_mem_small_ds_sid) succeeded"); + + ret = H5Sclose(full_file_small_ds_sid); + VRFY((ret != FAIL), "H5Sclose(full_file_small_ds_sid) succeeded"); + + ret = H5Sclose(mem_small_ds_sid); + VRFY((ret != FAIL), "H5Sclose(mem_small_ds_sid) succeeded"); + + ret = H5Sclose(file_small_ds_sid); + VRFY((ret != FAIL), "H5Sclose(file_small_ds_sid) succeeded"); + + ret = H5Sclose(full_mem_large_ds_sid); + VRFY((ret != FAIL), "H5Sclose(full_mem_large_ds_sid) succeeded"); + + ret = H5Sclose(full_file_large_ds_sid); + VRFY((ret != FAIL), "H5Sclose(full_file_large_ds_sid) succeeded"); + + ret = H5Sclose(mem_large_ds_sid); + VRFY((ret != FAIL), "H5Sclose(mem_large_ds_sid) succeeded"); + + ret = H5Sclose(file_large_ds_sid); + VRFY((ret != FAIL), "H5Sclose(file_large_ds_sid) succeeded"); + + /* Close Datasets */ + ret = H5Dclose(small_dataset); + VRFY((ret != FAIL), "H5Dclose(small_dataset) succeeded"); + + ret = H5Dclose(large_dataset); + VRFY((ret != FAIL), "H5Dclose(large_dataset) succeeded"); + + /* close the file collectively */ + MESG("about to close file."); + ret = H5Fclose(fid); + VRFY((ret != FAIL), "file close succeeded"); + + /* Free memory buffers */ + if (small_ds_buf_0 != NULL) + HDfree(small_ds_buf_0); + if (small_ds_buf_1 != NULL) + HDfree(small_ds_buf_1); + + if (large_ds_buf_0 != NULL) + HDfree(large_ds_buf_0); + if (large_ds_buf_1 != NULL) + HDfree(large_ds_buf_1); + + return; + +} /* lower_dim_size_comp_test__run_test() */ + +/*------------------------------------------------------------------------- + * Function: lower_dim_size_comp_test() + * + * Purpose: Test to see if an error in the computation of the size + * of the lower dimensions in H5S_obtain_datatype() has + * been corrected. + * + * Return: void + * + * Programmer: JRM -- 11/11/09 + * + *------------------------------------------------------------------------- + */ + +void +lower_dim_size_comp_test(void) +{ + /* const char *fcnName = "lower_dim_size_comp_test()"; */ + int chunk_edge_size = 0; + int use_collective_io; + int mpi_rank; + + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file or dataset aren't supported with this connector\n"); + fflush(stdout); + } + + return; + } + + HDcompile_assert(sizeof(uint32_t) == sizeof(unsigned)); + for (use_collective_io = 0; use_collective_io <= 1; use_collective_io++) { + chunk_edge_size = 0; + lower_dim_size_comp_test__run_test(chunk_edge_size, (hbool_t)use_collective_io, H5T_NATIVE_UINT); + + chunk_edge_size = 5; + lower_dim_size_comp_test__run_test(chunk_edge_size, (hbool_t)use_collective_io, H5T_NATIVE_UINT); + } /* end for */ + + return; +} /* lower_dim_size_comp_test() */ + +/*------------------------------------------------------------------------- + * Function: link_chunk_collective_io_test() + * + * Purpose: Test to verify that an error in MPI type management in + * H5D_link_chunk_collective_io() has been corrected. + * In this bug, we used to free MPI types regardless of + * whether they were basic or derived. + * + * This test is based on a bug report kindly provided by + * Rob Latham of the MPICH team and ANL. + * + * The basic thrust of the test is to cause a process + * to participate in a collective I/O in which it: + * + * 1) Reads or writes exactly one chunk, + * + * 2) Has no in memory buffer for any other chunk. + * + * The test differers from Rob Latham's bug report in + * that is runs with an arbitrary number of proceeses, + * and uses a 1 dimensional dataset. + * + * Return: void + * + * Programmer: JRM -- 12/16/09 + * + *------------------------------------------------------------------------- + */ + +#define LINK_CHUNK_COLLECTIVE_IO_TEST_CHUNK_SIZE 16 + +void +link_chunk_collective_io_test(void) +{ + /* const char *fcnName = "link_chunk_collective_io_test()"; */ + const char *filename; + hbool_t mis_match = FALSE; + int i; + int mrc; + int mpi_rank; + int mpi_size; + MPI_Comm mpi_comm = MPI_COMM_WORLD; + MPI_Info mpi_info = MPI_INFO_NULL; + hsize_t count[1] = {1}; + hsize_t stride[1] = {2 * LINK_CHUNK_COLLECTIVE_IO_TEST_CHUNK_SIZE}; + hsize_t block[1] = {LINK_CHUNK_COLLECTIVE_IO_TEST_CHUNK_SIZE}; + hsize_t start[1]; + hsize_t dims[1]; + hsize_t chunk_dims[1] = {LINK_CHUNK_COLLECTIVE_IO_TEST_CHUNK_SIZE}; + herr_t ret; /* Generic return value */ + hid_t file_id; + hid_t acc_tpl; + hid_t dset_id; + hid_t file_ds_sid; + hid_t write_mem_ds_sid; + hid_t read_mem_ds_sid; + hid_t ds_dcpl_id; + hid_t xfer_plist; + double diff; + double expected_value; + double local_data_written[LINK_CHUNK_COLLECTIVE_IO_TEST_CHUNK_SIZE]; + double local_data_read[LINK_CHUNK_COLLECTIVE_IO_TEST_CHUNK_SIZE]; + + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file or dataset aren't supported with this connector\n"); + fflush(stdout); + } + + return; + } + + HDassert(mpi_size > 0); + + /* get the file name */ + filename = (const char *)PARATESTFILE /* GetTestParameters() */; + HDassert(filename != NULL); + + /* setup file access template */ + acc_tpl = create_faccess_plist(mpi_comm, mpi_info, facc_type); + VRFY((acc_tpl >= 0), "create_faccess_plist() succeeded"); + + /* create the file collectively */ + file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, acc_tpl); + VRFY((file_id >= 0), "H5Fcreate succeeded"); + + MESG("File opened."); + + /* Release file-access template */ + ret = H5Pclose(acc_tpl); + VRFY((ret >= 0), "H5Pclose(acc_tpl) succeeded"); + + /* setup dims */ + dims[0] = ((hsize_t)mpi_size) * ((hsize_t)(LINK_CHUNK_COLLECTIVE_IO_TEST_CHUNK_SIZE)); + + /* setup mem and file dataspaces */ + write_mem_ds_sid = H5Screate_simple(1, chunk_dims, NULL); + VRFY((write_mem_ds_sid != 0), "H5Screate_simple() write_mem_ds_sid succeeded"); + + read_mem_ds_sid = H5Screate_simple(1, chunk_dims, NULL); + VRFY((read_mem_ds_sid != 0), "H5Screate_simple() read_mem_ds_sid succeeded"); + + file_ds_sid = H5Screate_simple(1, dims, NULL); + VRFY((file_ds_sid != 0), "H5Screate_simple() file_ds_sid succeeded"); + + /* setup data set creation property list */ + ds_dcpl_id = H5Pcreate(H5P_DATASET_CREATE); + VRFY((ds_dcpl_id != FAIL), "H5Pcreate() ds_dcpl_id succeeded"); + + ret = H5Pset_layout(ds_dcpl_id, H5D_CHUNKED); + VRFY((ret != FAIL), "H5Pset_layout() ds_dcpl_id succeeded"); + + ret = H5Pset_chunk(ds_dcpl_id, 1, chunk_dims); + VRFY((ret != FAIL), "H5Pset_chunk() small_ds_dcpl_id succeeded"); + + /* create the data set */ + dset_id = + H5Dcreate2(file_id, "dataset", H5T_NATIVE_DOUBLE, file_ds_sid, H5P_DEFAULT, ds_dcpl_id, H5P_DEFAULT); + VRFY((dset_id >= 0), "H5Dcreate2() dataset succeeded"); + + /* close the dataset creation property list */ + ret = H5Pclose(ds_dcpl_id); + VRFY((ret >= 0), "H5Pclose(ds_dcpl_id) succeeded"); + + /* setup local data */ + expected_value = (double)(LINK_CHUNK_COLLECTIVE_IO_TEST_CHUNK_SIZE) * (double)(mpi_rank); + for (i = 0; i < LINK_CHUNK_COLLECTIVE_IO_TEST_CHUNK_SIZE; i++) { + + local_data_written[i] = expected_value; + local_data_read[i] = 0.0; + expected_value += 1.0; + } + + /* select the file and mem spaces */ + start[0] = (hsize_t)(mpi_rank * LINK_CHUNK_COLLECTIVE_IO_TEST_CHUNK_SIZE); + ret = H5Sselect_hyperslab(file_ds_sid, H5S_SELECT_SET, start, stride, count, block); + VRFY((ret >= 0), "H5Sselect_hyperslab(file_ds_sid, set) succeeded"); + + ret = H5Sselect_all(write_mem_ds_sid); + VRFY((ret != FAIL), "H5Sselect_all(mem_ds_sid) succeeded"); + + /* Note that we use NO SELECTION on the read memory dataspace */ + + /* setup xfer property list */ + xfer_plist = H5Pcreate(H5P_DATASET_XFER); + VRFY((xfer_plist >= 0), "H5Pcreate(H5P_DATASET_XFER) succeeded"); + + ret = H5Pset_dxpl_mpio(xfer_plist, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + + /* write the data set */ + ret = H5Dwrite(dset_id, H5T_NATIVE_DOUBLE, write_mem_ds_sid, file_ds_sid, xfer_plist, local_data_written); + + VRFY((ret >= 0), "H5Dwrite() dataset initial write succeeded"); + + /* sync with the other processes before checking data */ + mrc = MPI_Barrier(MPI_COMM_WORLD); + VRFY((mrc == MPI_SUCCESS), "Sync after dataset write"); + + /* read this processes slice of the dataset back in */ + ret = H5Dread(dset_id, H5T_NATIVE_DOUBLE, read_mem_ds_sid, file_ds_sid, xfer_plist, local_data_read); + VRFY((ret >= 0), "H5Dread() dataset read succeeded"); + + /* close the xfer property list */ + ret = H5Pclose(xfer_plist); + VRFY((ret >= 0), "H5Pclose(xfer_plist) succeeded"); + + /* verify the data */ + mis_match = FALSE; + for (i = 0; i < LINK_CHUNK_COLLECTIVE_IO_TEST_CHUNK_SIZE; i++) { + + diff = local_data_written[i] - local_data_read[i]; + diff = fabs(diff); + + if (diff >= 0.001) { + + mis_match = TRUE; + } + } + VRFY((mis_match == FALSE), "dataset data good."); + + /* Close dataspaces */ + ret = H5Sclose(write_mem_ds_sid); + VRFY((ret != FAIL), "H5Sclose(write_mem_ds_sid) succeeded"); + + ret = H5Sclose(read_mem_ds_sid); + VRFY((ret != FAIL), "H5Sclose(read_mem_ds_sid) succeeded"); + + ret = H5Sclose(file_ds_sid); + VRFY((ret != FAIL), "H5Sclose(file_ds_sid) succeeded"); + + /* Close Dataset */ + ret = H5Dclose(dset_id); + VRFY((ret != FAIL), "H5Dclose(dset_id) succeeded"); + + /* close the file collectively */ + ret = H5Fclose(file_id); + VRFY((ret != FAIL), "file close succeeded"); + + return; + +} /* link_chunk_collective_io_test() */ diff --git a/testpar/API/testphdf5.c b/testpar/API/testphdf5.c new file mode 100644 index 0000000..ec5dae2 --- /dev/null +++ b/testpar/API/testphdf5.c @@ -0,0 +1,1007 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Main driver of the Parallel HDF5 tests + */ + +#include "hdf5.h" +#include "testphdf5.h" + +#ifndef PATH_MAX +#define PATH_MAX 512 +#endif /* !PATH_MAX */ + +/* global variables */ +int dim0; +int dim1; +int chunkdim0; +int chunkdim1; +int nerrors = 0; /* errors count */ +int ndatasets = 300; /* number of datasets to create*/ +int ngroups = 512; /* number of groups to create in root + * group. */ +int facc_type = FACC_MPIO; /*Test file access type */ +int dxfer_coll_type = DXFER_COLLECTIVE_IO; + +H5E_auto2_t old_func; /* previous error handler */ +void *old_client_data; /* previous error handler arg.*/ + +/* other option flags */ + +/* FILENAME and filenames must have the same number of names. + * Use PARATESTFILE in general and use a separated filename only if the file + * created in one test is accessed by a different test. + * filenames[0] is reserved as the file name for PARATESTFILE. + */ +#define NFILENAME 2 +/* #define PARATESTFILE filenames[0] */ +const char *FILENAME[NFILENAME] = {"ParaTest.h5", NULL}; +char filenames[NFILENAME][PATH_MAX]; +hid_t fapl; /* file access property list */ + +#ifdef USE_PAUSE +/* pause the process for a moment to allow debugger to attach if desired. */ +/* Will pause more if greenlight file is not persent but will eventually */ +/* continue. */ +#include +#include + +void +pause_proc(void) +{ + + int pid; + h5_stat_t statbuf; + char greenlight[] = "go"; + int maxloop = 10; + int loops = 0; + int time_int = 10; + + /* mpi variables */ + int mpi_size, mpi_rank; + int mpi_namelen; + char mpi_name[MPI_MAX_PROCESSOR_NAME]; + + pid = getpid(); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + MPI_Get_processor_name(mpi_name, &mpi_namelen); + + if (MAINPROCESS) + while ((HDstat(greenlight, &statbuf) == -1) && loops < maxloop) { + if (!loops++) { + HDprintf("Proc %d (%*s, %d): to debug, attach %d\n", mpi_rank, mpi_namelen, mpi_name, pid, + pid); + } + HDprintf("waiting(%ds) for file %s ...\n", time_int, greenlight); + HDfflush(stdout); + HDsleep(time_int); + } + MPI_Barrier(MPI_COMM_WORLD); +} + +/* Use the Profile feature of MPI to call the pause_proc() */ +int +MPI_Init(int *argc, char ***argv) +{ + int ret_code; + ret_code = PMPI_Init(argc, argv); + pause_proc(); + return (ret_code); +} +#endif /* USE_PAUSE */ + +/* + * Show command usage + */ +static void +usage(void) +{ + HDprintf(" [-r] [-w] [-m] [-n] " + "[-o] [-f ] [-d ]\n"); + HDprintf("\t-m" + "\tset number of datasets for the multiple dataset test\n"); + HDprintf("\t-n" + "\tset number of groups for the multiple group test\n"); +#if 0 + HDprintf("\t-f \tfilename prefix\n"); +#endif + HDprintf("\t-2\t\tuse Split-file together with MPIO\n"); + HDprintf("\t-d \tdataset dimensions factors. Defaults (%d,%d)\n", ROW_FACTOR, + COL_FACTOR); + HDprintf("\t-c \tdataset chunk dimensions. Defaults (dim0/10,dim1/10)\n"); + HDprintf("\n"); +} + +/* + * parse the command line options + */ +static int +parse_options(int argc, char **argv) +{ + int mpi_size, mpi_rank; /* mpi variables */ + + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* setup default chunk-size. Make sure sizes are > 0 */ + + chunkdim0 = (dim0 + 9) / 10; + chunkdim1 = (dim1 + 9) / 10; + + while (--argc) { + if (**(++argv) != '-') { + break; + } + else { + switch (*(*argv + 1)) { + case 'm': + ndatasets = atoi((*argv + 1) + 1); + if (ndatasets < 0) { + nerrors++; + return (1); + } + break; + case 'n': + ngroups = atoi((*argv + 1) + 1); + if (ngroups < 0) { + nerrors++; + return (1); + } + break; +#if 0 + case 'f': if (--argc < 1) { + nerrors++; + return(1); + } + if (**(++argv) == '-') { + nerrors++; + return(1); + } + paraprefix = *argv; + break; +#endif + case 'i': /* Collective MPI-IO access with independent IO */ + dxfer_coll_type = DXFER_INDEPENDENT_IO; + break; + case '2': /* Use the split-file driver with MPIO access */ + /* Can use $HDF5_METAPREFIX to define the */ + /* meta-file-prefix. */ + facc_type = FACC_MPIO | FACC_SPLIT; + break; + case 'd': /* dimensizes */ + if (--argc < 2) { + nerrors++; + return (1); + } + dim0 = atoi(*(++argv)) * mpi_size; + argc--; + dim1 = atoi(*(++argv)) * mpi_size; + /* set default chunkdim sizes too */ + chunkdim0 = (dim0 + 9) / 10; + chunkdim1 = (dim1 + 9) / 10; + break; + case 'c': /* chunk dimensions */ + if (--argc < 2) { + nerrors++; + return (1); + } + chunkdim0 = atoi(*(++argv)); + argc--; + chunkdim1 = atoi(*(++argv)); + break; + case 'h': /* print help message--return with nerrors set */ + return (1); + default: + HDprintf("Illegal option(%s)\n", *argv); + nerrors++; + return (1); + } + } + } /*while*/ + + /* check validity of dimension and chunk sizes */ + if (dim0 <= 0 || dim1 <= 0) { + HDprintf("Illegal dim sizes (%d, %d)\n", dim0, dim1); + nerrors++; + return (1); + } + if (chunkdim0 <= 0 || chunkdim1 <= 0) { + HDprintf("Illegal chunkdim sizes (%d, %d)\n", chunkdim0, chunkdim1); + nerrors++; + return (1); + } + + /* Make sure datasets can be divided into equal portions by the processes */ + if ((dim0 % mpi_size) || (dim1 % mpi_size)) { + if (MAINPROCESS) + HDprintf("dim0(%d) and dim1(%d) must be multiples of processes(%d)\n", dim0, dim1, mpi_size); + nerrors++; + return (1); + } + + /* compose the test filenames */ + { + int i, n; + + n = sizeof(FILENAME) / sizeof(FILENAME[0]) - 1; /* exclude the NULL */ + + for (i = 0; i < n; i++) + strncpy(filenames[i], FILENAME[i], PATH_MAX); +#if 0 /* no support for VFDs right now */ + if (h5_fixname(FILENAME[i], fapl, filenames[i], PATH_MAX) == NULL) { + HDprintf("h5_fixname failed\n"); + nerrors++; + return (1); + } +#endif + if (MAINPROCESS) { + HDprintf("Test filenames are:\n"); + for (i = 0; i < n; i++) + HDprintf(" %s\n", filenames[i]); + } + } + + return (0); +} + +/* + * Create the appropriate File access property list + */ +hid_t +create_faccess_plist(MPI_Comm comm, MPI_Info info, int l_facc_type) +{ + hid_t ret_pl = -1; + herr_t ret; /* generic return value */ + int mpi_rank; /* mpi variables */ + + /* need the rank for error checking macros */ + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + ret_pl = H5Pcreate(H5P_FILE_ACCESS); + VRFY((ret_pl >= 0), "H5P_FILE_ACCESS"); + + if (l_facc_type == FACC_DEFAULT) + return (ret_pl); + + if (l_facc_type == FACC_MPIO) { + /* set Parallel access with communicator */ + ret = H5Pset_fapl_mpio(ret_pl, comm, info); + VRFY((ret >= 0), ""); + ret = H5Pset_all_coll_metadata_ops(ret_pl, TRUE); + VRFY((ret >= 0), ""); + ret = H5Pset_coll_metadata_write(ret_pl, TRUE); + VRFY((ret >= 0), ""); + return (ret_pl); + } + + if (l_facc_type == (FACC_MPIO | FACC_SPLIT)) { + hid_t mpio_pl; + + mpio_pl = H5Pcreate(H5P_FILE_ACCESS); + VRFY((mpio_pl >= 0), ""); + /* set Parallel access with communicator */ + ret = H5Pset_fapl_mpio(mpio_pl, comm, info); + VRFY((ret >= 0), ""); + + /* setup file access template */ + ret_pl = H5Pcreate(H5P_FILE_ACCESS); + VRFY((ret_pl >= 0), ""); + /* set Parallel access with communicator */ + ret = H5Pset_fapl_split(ret_pl, ".meta", mpio_pl, ".raw", mpio_pl); + VRFY((ret >= 0), "H5Pset_fapl_split succeeded"); + H5Pclose(mpio_pl); + return (ret_pl); + } + + /* unknown file access types */ + return (ret_pl); +} + +int +main(int argc, char **argv) +{ + int mpi_size, mpi_rank; /* mpi variables */ + herr_t ret; + +#if 0 + H5Ptest_param_t ndsets_params, ngroups_params; + H5Ptest_param_t collngroups_params; + H5Ptest_param_t io_mode_confusion_params; + H5Ptest_param_t rr_obj_flush_confusion_params; +#endif + +#ifndef H5_HAVE_WIN32_API + /* Un-buffer the stdout and stderr */ + HDsetbuf(stderr, NULL); + HDsetbuf(stdout, NULL); +#endif + + MPI_Init(&argc, &argv); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + dim0 = ROW_FACTOR * mpi_size; + dim1 = COL_FACTOR * mpi_size; + + if (MAINPROCESS) { + HDprintf("===================================\n"); + HDprintf("PHDF5 TESTS START\n"); + HDprintf("===================================\n"); + } + + /* Attempt to turn off atexit post processing so that in case errors + * happen during the test and the process is aborted, it will not get + * hang in the atexit post processing in which it may try to make MPI + * calls. By then, MPI calls may not work. + */ + if (H5dont_atexit() < 0) { + HDprintf("Failed to turn off atexit processing. Continue.\n"); + }; + H5open(); + /* h5_show_hostname(); */ + +#if 0 + HDmemset(filenames, 0, sizeof(filenames)); + for (int i = 0; i < NFILENAME; i++) { + if (NULL == (filenames[i] = HDmalloc(PATH_MAX))) { + HDprintf("couldn't allocate filename array\n"); + MPI_Abort(MPI_COMM_WORLD, -1); + } + } +#endif + + /* Set up file access property list with parallel I/O access */ + fapl = H5Pcreate(H5P_FILE_ACCESS); + VRFY((fapl >= 0), "H5Pcreate succeeded"); + + vol_cap_flags_g = H5VL_CAP_FLAG_NONE; + + /* Get the capability flag of the VOL connector being used */ + ret = H5Pget_vol_cap_flags(fapl, &vol_cap_flags_g); + VRFY((ret >= 0), "H5Pget_vol_cap_flags succeeded"); + + /* Initialize testing framework */ + /* TestInit(argv[0], usage, parse_options); */ + + if (parse_options(argc, argv)) { + usage(); + return 1; + } + + /* Tests are generally arranged from least to most complexity... */ +#if 0 + AddTest("mpiodup", test_fapl_mpio_dup, NULL, + "fapl_mpio duplicate", NULL); +#endif + + if (MAINPROCESS) { + printf("fapl_mpio duplicate\n"); + fflush(stdout); + } + test_fapl_mpio_dup(); + +#if 0 + AddTest("split", test_split_comm_access, NULL, + "dataset using split communicators", PARATESTFILE); + AddTest("props", test_file_properties, NULL, + "Coll Metadata file property settings", PARATESTFILE); +#endif + + if (MAINPROCESS) { + printf("dataset using split communicators\n"); + fflush(stdout); + } + test_split_comm_access(); + + if (MAINPROCESS) { + printf("Coll Metadata file property settings\n"); + fflush(stdout); + } + test_file_properties(); + +#if 0 + AddTest("idsetw", dataset_writeInd, NULL, + "dataset independent write", PARATESTFILE); + AddTest("idsetr", dataset_readInd, NULL, + "dataset independent read", PARATESTFILE); +#endif + + if (MAINPROCESS) { + printf("dataset independent write\n"); + fflush(stdout); + } + dataset_writeInd(); + if (MAINPROCESS) { + printf("dataset independent read\n"); + fflush(stdout); + } + dataset_readInd(); + +#if 0 + AddTest("cdsetw", dataset_writeAll, NULL, + "dataset collective write", PARATESTFILE); + AddTest("cdsetr", dataset_readAll, NULL, + "dataset collective read", PARATESTFILE); +#endif + + if (MAINPROCESS) { + printf("dataset collective write\n"); + fflush(stdout); + } + dataset_writeAll(); + if (MAINPROCESS) { + printf("dataset collective read\n"); + fflush(stdout); + } + dataset_readAll(); + +#if 0 + AddTest("eidsetw", extend_writeInd, NULL, + "extendible dataset independent write", PARATESTFILE); + AddTest("eidsetr", extend_readInd, NULL, + "extendible dataset independent read", PARATESTFILE); + AddTest("ecdsetw", extend_writeAll, NULL, + "extendible dataset collective write", PARATESTFILE); + AddTest("ecdsetr", extend_readAll, NULL, + "extendible dataset collective read", PARATESTFILE); + AddTest("eidsetw2", extend_writeInd2, NULL, + "extendible dataset independent write #2", PARATESTFILE); + AddTest("selnone", none_selection_chunk, NULL, + "chunked dataset with none-selection", PARATESTFILE); + AddTest("calloc", test_chunk_alloc, NULL, + "parallel extend Chunked allocation on serial file", PARATESTFILE); + AddTest("fltread", test_filter_read, NULL, + "parallel read of dataset written serially with filters", PARATESTFILE); +#endif + + if (MAINPROCESS) { + printf("extendible dataset independent write\n"); + fflush(stdout); + } + extend_writeInd(); + if (MAINPROCESS) { + printf("extendible dataset independent read\n"); + fflush(stdout); + } + extend_readInd(); + if (MAINPROCESS) { + printf("extendible dataset collective write\n"); + fflush(stdout); + } + extend_writeAll(); + if (MAINPROCESS) { + printf("extendible dataset collective read\n"); + fflush(stdout); + } + extend_readAll(); + if (MAINPROCESS) { + printf("extendible dataset independent write #2\n"); + fflush(stdout); + } + extend_writeInd2(); + if (MAINPROCESS) { + printf("chunked dataset with none-selection\n"); + fflush(stdout); + } + none_selection_chunk(); + if (MAINPROCESS) { + printf("parallel extend Chunked allocation on serial file\n"); + fflush(stdout); + } + test_chunk_alloc(); + if (MAINPROCESS) { + printf("parallel read of dataset written serially with filters\n"); + fflush(stdout); + } + test_filter_read(); + +#ifdef H5_HAVE_FILTER_DEFLATE +#if 0 + AddTest("cmpdsetr", compress_readAll, NULL, + "compressed dataset collective read", PARATESTFILE); +#endif + + if (MAINPROCESS) { + printf("compressed dataset collective read\n"); + fflush(stdout); + } + compress_readAll(); +#endif /* H5_HAVE_FILTER_DEFLATE */ + +#if 0 + AddTest("zerodsetr", zero_dim_dset, NULL, + "zero dim dset", PARATESTFILE); +#endif + + if (MAINPROCESS) { + printf("zero dim dset\n"); + fflush(stdout); + } + zero_dim_dset(); + +#if 0 + ndsets_params.name = PARATESTFILE; + ndsets_params.count = ndatasets; + AddTest("ndsetw", multiple_dset_write, NULL, + "multiple datasets write", &ndsets_params); +#endif + + if (MAINPROCESS) { + printf("multiple datasets write\n"); + fflush(stdout); + } + multiple_dset_write(); + +#if 0 + ngroups_params.name = PARATESTFILE; + ngroups_params.count = ngroups; + AddTest("ngrpw", multiple_group_write, NULL, + "multiple groups write", &ngroups_params); + AddTest("ngrpr", multiple_group_read, NULL, + "multiple groups read", &ngroups_params); +#endif + + if (MAINPROCESS) { + printf("multiple groups write\n"); + fflush(stdout); + } + multiple_group_write(); + if (MAINPROCESS) { + printf("multiple groups read\n"); + fflush(stdout); + } + multiple_group_read(); + +#if 0 + AddTest("compact", compact_dataset, NULL, + "compact dataset test", PARATESTFILE); +#endif + + if (MAINPROCESS) { + printf("compact dataset test\n"); + fflush(stdout); + } + compact_dataset(); + +#if 0 + collngroups_params.name = PARATESTFILE; + collngroups_params.count = ngroups; + /* combined cngrpw and ingrpr tests because ingrpr reads file created by cngrpw. */ + AddTest("cngrpw-ingrpr", collective_group_write_independent_group_read, NULL, + "collective grp/dset write - independent grp/dset read", + &collngroups_params); +#ifndef H5_HAVE_WIN32_API + AddTest("bigdset", big_dataset, NULL, + "big dataset test", PARATESTFILE); +#else + HDprintf("big dataset test will be skipped on Windows (JIRA HDDFV-8064)\n"); +#endif +#endif + + if (MAINPROCESS) { + printf("collective grp/dset write - independent grp/dset read\n"); + fflush(stdout); + } + collective_group_write_independent_group_read(); + if (MAINPROCESS) { + printf("big dataset test\n"); + fflush(stdout); + } + big_dataset(); + +#if 0 + AddTest("fill", dataset_fillvalue, NULL, + "dataset fill value", PARATESTFILE); +#endif + + if (MAINPROCESS) { + printf("dataset fill value\n"); + fflush(stdout); + } + dataset_fillvalue(); + +#if 0 + AddTest("cchunk1", + coll_chunk1,NULL, "simple collective chunk io",PARATESTFILE); + AddTest("cchunk2", + coll_chunk2,NULL, "noncontiguous collective chunk io",PARATESTFILE); + AddTest("cchunk3", + coll_chunk3,NULL, "multi-chunk collective chunk io",PARATESTFILE); + AddTest("cchunk4", + coll_chunk4,NULL, "collective chunk io with partial non-selection ",PARATESTFILE); +#endif + + if (MAINPROCESS) { + printf("simple collective chunk io\n"); + fflush(stdout); + } + coll_chunk1(); + if (MAINPROCESS) { + printf("noncontiguous collective chunk io\n"); + fflush(stdout); + } + coll_chunk2(); + if (MAINPROCESS) { + printf("multi-chunk collective chunk io\n"); + fflush(stdout); + } + coll_chunk3(); + if (MAINPROCESS) { + printf("collective chunk io with partial non-selection\n"); + fflush(stdout); + } + coll_chunk4(); + + if ((mpi_size < 3) && MAINPROCESS) { + HDprintf("Collective chunk IO optimization APIs "); + HDprintf("needs at least 3 processes to participate\n"); + HDprintf("Collective chunk IO API tests will be skipped \n"); + } + +#if 0 + AddTest((mpi_size <3)? "-cchunk5":"cchunk5" , + coll_chunk5,NULL, + "linked chunk collective IO without optimization",PARATESTFILE); + AddTest((mpi_size < 3)? "-cchunk6" : "cchunk6", + coll_chunk6,NULL, + "multi-chunk collective IO with direct request",PARATESTFILE); + AddTest((mpi_size < 3)? "-cchunk7" : "cchunk7", + coll_chunk7,NULL, + "linked chunk collective IO with optimization",PARATESTFILE); + AddTest((mpi_size < 3)? "-cchunk8" : "cchunk8", + coll_chunk8,NULL, + "linked chunk collective IO transferring to multi-chunk",PARATESTFILE); + AddTest((mpi_size < 3)? "-cchunk9" : "cchunk9", + coll_chunk9,NULL, + "multiple chunk collective IO with optimization",PARATESTFILE); + AddTest((mpi_size < 3)? "-cchunk10" : "cchunk10", + coll_chunk10,NULL, + "multiple chunk collective IO transferring to independent IO",PARATESTFILE); +#endif + + if (mpi_size >= 3) { + if (MAINPROCESS) { + printf("linked chunk collective IO without optimization\n"); + fflush(stdout); + } + coll_chunk5(); + if (MAINPROCESS) { + printf("multi-chunk collective IO with direct request\n"); + fflush(stdout); + } + coll_chunk6(); + if (MAINPROCESS) { + printf("linked chunk collective IO with optimization\n"); + fflush(stdout); + } + coll_chunk7(); + if (MAINPROCESS) { + printf("linked chunk collective IO transferring to multi-chunk\n"); + fflush(stdout); + } + coll_chunk8(); + if (MAINPROCESS) { + printf("multiple chunk collective IO with optimization\n"); + fflush(stdout); + } + coll_chunk9(); + if (MAINPROCESS) { + printf("multiple chunk collective IO transferring to independent IO\n"); + fflush(stdout); + } + coll_chunk10(); + } + +#if 0 + /* irregular collective IO tests*/ + AddTest("ccontw", + coll_irregular_cont_write,NULL, + "collective irregular contiguous write",PARATESTFILE); + AddTest("ccontr", + coll_irregular_cont_read,NULL, + "collective irregular contiguous read",PARATESTFILE); + AddTest("cschunkw", + coll_irregular_simple_chunk_write,NULL, + "collective irregular simple chunk write",PARATESTFILE); + AddTest("cschunkr", + coll_irregular_simple_chunk_read,NULL, + "collective irregular simple chunk read",PARATESTFILE); + AddTest("ccchunkw", + coll_irregular_complex_chunk_write,NULL, + "collective irregular complex chunk write",PARATESTFILE); + AddTest("ccchunkr", + coll_irregular_complex_chunk_read,NULL, + "collective irregular complex chunk read",PARATESTFILE); +#endif + + if (MAINPROCESS) { + printf("collective irregular contiguous write\n"); + fflush(stdout); + } + coll_irregular_cont_write(); + if (MAINPROCESS) { + printf("collective irregular contiguous read\n"); + fflush(stdout); + } + coll_irregular_cont_read(); + if (MAINPROCESS) { + printf("collective irregular simple chunk write\n"); + fflush(stdout); + } + coll_irregular_simple_chunk_write(); + if (MAINPROCESS) { + printf("collective irregular simple chunk read\n"); + fflush(stdout); + } + coll_irregular_simple_chunk_read(); + if (MAINPROCESS) { + printf("collective irregular complex chunk write\n"); + fflush(stdout); + } + coll_irregular_complex_chunk_write(); + if (MAINPROCESS) { + printf("collective irregular complex chunk read\n"); + fflush(stdout); + } + coll_irregular_complex_chunk_read(); + +#if 0 + AddTest("null", null_dataset, NULL, + "null dataset test", PARATESTFILE); +#endif + + if (MAINPROCESS) { + printf("null dataset test\n"); + fflush(stdout); + } + null_dataset(); + +#if 0 + io_mode_confusion_params.name = PARATESTFILE; + io_mode_confusion_params.count = 0; /* value not used */ + + AddTest("I/Omodeconf", io_mode_confusion, NULL, + "I/O mode confusion test", + &io_mode_confusion_params); +#endif + + if (MAINPROCESS) { + printf("I/O mode confusion test\n"); + fflush(stdout); + } + io_mode_confusion(); + + if ((mpi_size < 3) && MAINPROCESS) { + HDprintf("rr_obj_hdr_flush_confusion test needs at least 3 processes.\n"); + HDprintf("rr_obj_hdr_flush_confusion test will be skipped \n"); + } + + if (mpi_size > 2) { +#if 0 + rr_obj_flush_confusion_params.name = PARATESTFILE; + rr_obj_flush_confusion_params.count = 0; /* value not used */ + AddTest("rrobjflushconf", rr_obj_hdr_flush_confusion, NULL, + "round robin object header flush confusion test", + &rr_obj_flush_confusion_params); +#endif + + if (MAINPROCESS) { + printf("round robin object header flush confusion test\n"); + fflush(stdout); + } + rr_obj_hdr_flush_confusion(); + } + +#if 0 + AddTest("alnbg1", + chunk_align_bug_1, NULL, + "Chunk allocation with alignment bug.", + PARATESTFILE); + + AddTest("tldsc", + lower_dim_size_comp_test, NULL, + "test lower dim size comp in span tree to mpi derived type", + PARATESTFILE); + + AddTest("lccio", + link_chunk_collective_io_test, NULL, + "test mpi derived type management", + PARATESTFILE); + + AddTest("actualio", actual_io_mode_tests, NULL, + "test actual io mode proprerty", + PARATESTFILE); + + AddTest("nocolcause", no_collective_cause_tests, NULL, + "test cause for broken collective io", + PARATESTFILE); + + AddTest("edpl", test_plist_ed, NULL, + "encode/decode Property Lists", NULL); +#endif + + if (MAINPROCESS) { + printf("Chunk allocation with alignment bug\n"); + fflush(stdout); + } + chunk_align_bug_1(); + if (MAINPROCESS) { + printf("test lower dim size comp in span tree to mpi derived type\n"); + fflush(stdout); + } + lower_dim_size_comp_test(); + if (MAINPROCESS) { + printf("test mpi derived type management\n"); + fflush(stdout); + } + link_chunk_collective_io_test(); + if (MAINPROCESS) { + printf("test actual io mode property - SKIPPED currently due to native-specific testing\n"); + fflush(stdout); + } + /* actual_io_mode_tests(); */ + if (MAINPROCESS) { + printf("test cause for broken collective io - SKIPPED currently due to native-specific testing\n"); + fflush(stdout); + } + /* no_collective_cause_tests(); */ + if (MAINPROCESS) { + printf("encode/decode Property Lists\n"); + fflush(stdout); + } + test_plist_ed(); + + if ((mpi_size < 2) && MAINPROCESS) { + HDprintf("File Image Ops daisy chain test needs at least 2 processes.\n"); + HDprintf("File Image Ops daisy chain test will be skipped \n"); + } + +#if 0 + AddTest((mpi_size < 2)? "-fiodc" : "fiodc", file_image_daisy_chain_test, NULL, + "file image ops daisy chain", NULL); +#endif + + if (mpi_size >= 2) { + if (MAINPROCESS) { + printf("file image ops daisy chain - SKIPPED currently due to native-specific testing\n"); + fflush(stdout); + } + /* file_image_daisy_chain_test(); */ + } + + if ((mpi_size < 2) && MAINPROCESS) { + HDprintf("Atomicity tests need at least 2 processes to participate\n"); + HDprintf("8 is more recommended.. Atomicity tests will be skipped \n"); + } + else if (facc_type != FACC_MPIO && MAINPROCESS) { + HDprintf("Atomicity tests will not work with a non MPIO VFD\n"); + } + else if (mpi_size >= 2 && facc_type == FACC_MPIO) { +#if 0 + AddTest("atomicity", dataset_atomicity, NULL, + "dataset atomic updates", PARATESTFILE); +#endif + + if (MAINPROCESS) { + printf("dataset atomic updates - SKIPPED currently due to native-specific testing\n"); + fflush(stdout); + } + /* dataset_atomicity(); */ + } + +#if 0 + AddTest("denseattr", test_dense_attr, NULL, + "Store Dense Attributes", PARATESTFILE); +#endif + + if (MAINPROCESS) { + printf("Store Dense Attributes\n"); + fflush(stdout); + } + test_dense_attr(); + +#if 0 + AddTest("noselcollmdread", test_partial_no_selection_coll_md_read, NULL, + "Collective Metadata read with some ranks having no selection", PARATESTFILE); + AddTest("MC_coll_MD_read", test_multi_chunk_io_addrmap_issue, NULL, + "Collective MD read with multi chunk I/O (H5D__chunk_addrmap)", PARATESTFILE); + AddTest("LC_coll_MD_read", test_link_chunk_io_sort_chunk_issue, NULL, + "Collective MD read with link chunk I/O (H5D__sort_chunk)", PARATESTFILE); +#endif + + if (MAINPROCESS) { + printf("Collective Metadata read with some ranks having no selection\n"); + fflush(stdout); + } + test_partial_no_selection_coll_md_read(); + if (MAINPROCESS) { + printf("Collective MD read with multi chunk I/O\n"); + fflush(stdout); + } + test_multi_chunk_io_addrmap_issue(); + if (MAINPROCESS) { + printf("Collective MD read with link chunk I/O\n"); + fflush(stdout); + } + test_link_chunk_io_sort_chunk_issue(); + + /* Display testing information */ + /* TestInfo(argv[0]); */ + + /* setup file access property list */ + H5Pset_fapl_mpio(fapl, MPI_COMM_WORLD, MPI_INFO_NULL); + + /* Parse command line arguments */ + /* TestParseCmdLine(argc, argv); */ + + if (dxfer_coll_type == DXFER_INDEPENDENT_IO && MAINPROCESS) { + HDprintf("===================================\n" + " Using Independent I/O with file set view to replace collective I/O \n" + "===================================\n"); + } + + /* Perform requested testing */ + /* PerformTests(); */ + + /* make sure all processes are finished before final report, cleanup + * and exit. + */ + MPI_Barrier(MPI_COMM_WORLD); + + /* Display test summary, if requested */ + /* if (MAINPROCESS && GetTestSummary()) + TestSummary(); */ + + /* Clean up test files */ + /* h5_clean_files(FILENAME, fapl); */ + H5Fdelete(FILENAME[0], fapl); + H5Pclose(fapl); + + /* nerrors += GetTestNumErrs(); */ + + /* Gather errors from all processes */ + { + int temp; + MPI_Allreduce(&nerrors, &temp, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD); + nerrors = temp; + } + + if (MAINPROCESS) { /* only process 0 reports */ + HDprintf("===================================\n"); + if (nerrors) + HDprintf("***PHDF5 tests detected %d errors***\n", nerrors); + else + HDprintf("PHDF5 tests finished successfully\n"); + HDprintf("===================================\n"); + } + +#if 0 + for (int i = 0; i < NFILENAME; i++) { + HDfree(filenames[i]); + filenames[i] = NULL; + } +#endif + + /* close HDF5 library */ + H5close(); + + /* Release test infrastructure */ + /* TestShutdown(); */ + + /* MPI_Finalize must be called AFTER H5close which may use MPI calls */ + MPI_Finalize(); + + /* cannot just return (nerrors) because exit code is limited to 1byte */ + return (nerrors != 0); +} diff --git a/testpar/API/testphdf5.h b/testpar/API/testphdf5.h new file mode 100644 index 0000000..27d53e2 --- /dev/null +++ b/testpar/API/testphdf5.h @@ -0,0 +1,343 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* common definitions used by all parallel hdf5 test programs. */ + +#ifndef PHDF5TEST_H +#define PHDF5TEST_H + +#include "H5private.h" +#include "testpar.h" +#include "H5_api_tests_disabled.h" + +/* + * Define parameters for various tests since we do not have access to + * passing parameters to tests via the testphdf5 test framework. + */ +#define PARATESTFILE "ParaTest.h5" +#define NDATASETS 300 +#define NGROUPS 256 + +/* Disable express testing by default */ +#define EXPRESS_MODE 0 + +enum H5TEST_COLL_CHUNK_API { + API_NONE = 0, + API_LINK_HARD, + API_MULTI_HARD, + API_LINK_TRUE, + API_LINK_FALSE, + API_MULTI_COLL, + API_MULTI_IND +}; + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +/* Constants definitions */ +#define DIM0 600 /* Default dataset sizes. */ +#define DIM1 1200 /* Values are from a monitor pixel sizes */ +#define ROW_FACTOR 8 /* Nominal row factor for dataset size */ +#define COL_FACTOR 16 /* Nominal column factor for dataset size */ +#define RANK 2 +#define DATASETNAME1 "Data1" +#define DATASETNAME2 "Data2" +#define DATASETNAME3 "Data3" +#define DATASETNAME4 "Data4" +#define DATASETNAME5 "Data5" +#define DATASETNAME6 "Data6" +#define DATASETNAME7 "Data7" +#define DATASETNAME8 "Data8" +#define DATASETNAME9 "Data9" + +/* point selection order */ +#define IN_ORDER 1 +#define OUT_OF_ORDER 2 + +/* Hyperslab layout styles */ +#define BYROW 1 /* divide into slabs of rows */ +#define BYCOL 2 /* divide into blocks of columns */ +#define ZROW 3 /* same as BYCOL except process 0 gets 0 rows */ +#define ZCOL 4 /* same as BYCOL except process 0 gets 0 columns */ + +/* File_Access_type bits */ +#define FACC_DEFAULT 0x0 /* default */ +#define FACC_MPIO 0x1 /* MPIO */ +#define FACC_SPLIT 0x2 /* Split File */ + +#define DXFER_COLLECTIVE_IO 0x1 /* Collective IO*/ +#define DXFER_INDEPENDENT_IO 0x2 /* Independent IO collectively */ +/*Constants for collective chunk definitions */ +#define SPACE_DIM1 24 +#define SPACE_DIM2 4 +#define BYROW_CONT 1 +#define BYROW_DISCONT 2 +#define BYROW_SELECTNONE 3 +#define BYROW_SELECTUNBALANCE 4 +#define BYROW_SELECTINCHUNK 5 + +#define DIMO_NUM_CHUNK 4 +#define DIM1_NUM_CHUNK 2 +#define LINK_TRUE_NUM_CHUNK 2 +#define LINK_FALSE_NUM_CHUNK 6 +#define MULTI_TRUE_PERCENT 50 +#define LINK_TRUE_CHUNK_NAME "h5_link_chunk_true" +#define LINK_FALSE_CHUNK_NAME "h5_link_chunk_false" +#define LINK_HARD_CHUNK_NAME "h5_link_chunk_hard" +#define MULTI_HARD_CHUNK_NAME "h5_multi_chunk_hard" +#define MULTI_COLL_CHUNK_NAME "h5_multi_chunk_coll" +#define MULTI_INDP_CHUNK_NAME "h5_multi_chunk_indp" + +#define DSET_COLLECTIVE_CHUNK_NAME "coll_chunk_name" + +/*Constants for MPI derived data type generated from span tree */ + +#define MSPACE1_RANK 1 /* Rank of the first dataset in memory */ +#define MSPACE1_DIM 27000 /* Dataset size in memory */ +#define FSPACE_RANK 2 /* Dataset rank as it is stored in the file */ +#define FSPACE_DIM1 9 /* Dimension sizes of the dataset as it is stored in the file */ +#define FSPACE_DIM2 3600 +/* We will read dataset back from the file to the dataset in memory with these dataspace parameters. */ +#define MSPACE_RANK 2 +#define MSPACE_DIM1 9 +#define MSPACE_DIM2 3600 +#define FHCOUNT0 1 /* Count of the first dimension of the first hyperslab selection*/ +#define FHCOUNT1 768 /* Count of the second dimension of the first hyperslab selection*/ +#define FHSTRIDE0 4 /* Stride of the first dimension of the first hyperslab selection*/ +#define FHSTRIDE1 3 /* Stride of the second dimension of the first hyperslab selection*/ +#define FHBLOCK0 3 /* Block of the first dimension of the first hyperslab selection*/ +#define FHBLOCK1 2 /* Block of the second dimension of the first hyperslab selection*/ +#define FHSTART0 0 /* start of the first dimension of the first hyperslab selection*/ +#define FHSTART1 1 /* start of the second dimension of the first hyperslab selection*/ + +#define SHCOUNT0 1 /* Count of the first dimension of the first hyperslab selection*/ +#define SHCOUNT1 1 /* Count of the second dimension of the first hyperslab selection*/ +#define SHSTRIDE0 1 /* Stride of the first dimension of the first hyperslab selection*/ +#define SHSTRIDE1 1 /* Stride of the second dimension of the first hyperslab selection*/ +#define SHBLOCK0 3 /* Block of the first dimension of the first hyperslab selection*/ +#define SHBLOCK1 768 /* Block of the second dimension of the first hyperslab selection*/ +#define SHSTART0 4 /* start of the first dimension of the first hyperslab selection*/ +#define SHSTART1 0 /* start of the second dimension of the first hyperslab selection*/ + +#define MHCOUNT0 6912 /* Count of the first dimension of the first hyperslab selection*/ +#define MHSTRIDE0 1 /* Stride of the first dimension of the first hyperslab selection*/ +#define MHBLOCK0 1 /* Block of the first dimension of the first hyperslab selection*/ +#define MHSTART0 1 /* start of the first dimension of the first hyperslab selection*/ + +#define RFFHCOUNT0 3 /* Count of the first dimension of the first hyperslab selection*/ +#define RFFHCOUNT1 768 /* Count of the second dimension of the first hyperslab selection*/ +#define RFFHSTRIDE0 1 /* Stride of the first dimension of the first hyperslab selection*/ +#define RFFHSTRIDE1 1 /* Stride of the second dimension of the first hyperslab selection*/ +#define RFFHBLOCK0 1 /* Block of the first dimension of the first hyperslab selection*/ +#define RFFHBLOCK1 1 /* Block of the second dimension of the first hyperslab selection*/ +#define RFFHSTART0 1 /* start of the first dimension of the first hyperslab selection*/ +#define RFFHSTART1 2 /* start of the second dimension of the first hyperslab selection*/ + +#define RFSHCOUNT0 3 /* Count of the first dimension of the first hyperslab selection*/ +#define RFSHCOUNT1 1536 /* Count of the second dimension of the first hyperslab selection*/ +#define RFSHSTRIDE0 1 /* Stride of the first dimension of the first hyperslab selection*/ +#define RFSHSTRIDE1 1 /* Stride of the second dimension of the first hyperslab selection*/ +#define RFSHBLOCK0 1 /* Block of the first dimension of the first hyperslab selection*/ +#define RFSHBLOCK1 1 /* Block of the second dimension of the first hyperslab selection*/ +#define RFSHSTART0 2 /* start of the first dimension of the first hyperslab selection*/ +#define RFSHSTART1 4 /* start of the second dimension of the first hyperslab selection*/ + +#define RMFHCOUNT0 3 /* Count of the first dimension of the first hyperslab selection*/ +#define RMFHCOUNT1 768 /* Count of the second dimension of the first hyperslab selection*/ +#define RMFHSTRIDE0 1 /* Stride of the first dimension of the first hyperslab selection*/ +#define RMFHSTRIDE1 1 /* Stride of the second dimension of the first hyperslab selection*/ +#define RMFHBLOCK0 1 /* Block of the first dimension of the first hyperslab selection*/ +#define RMFHBLOCK1 1 /* Block of the second dimension of the first hyperslab selection*/ +#define RMFHSTART0 0 /* start of the first dimension of the first hyperslab selection*/ +#define RMFHSTART1 0 /* start of the second dimension of the first hyperslab selection*/ + +#define RMSHCOUNT0 3 /* Count of the first dimension of the first hyperslab selection*/ +#define RMSHCOUNT1 1536 /* Count of the second dimension of the first hyperslab selection*/ +#define RMSHSTRIDE0 1 /* Stride of the first dimension of the first hyperslab selection*/ +#define RMSHSTRIDE1 1 /* Stride of the second dimension of the first hyperslab selection*/ +#define RMSHBLOCK0 1 /* Block of the first dimension of the first hyperslab selection*/ +#define RMSHBLOCK1 1 /* Block of the second dimension of the first hyperslab selection*/ +#define RMSHSTART0 1 /* start of the first dimension of the first hyperslab selection*/ +#define RMSHSTART1 2 /* start of the second dimension of the first hyperslab selection*/ + +#define NPOINTS \ + 4 /* Number of points that will be selected \ + and overwritten */ + +/* Definitions of the selection mode for the test_actual_io_function. */ +#define TEST_ACTUAL_IO_NO_COLLECTIVE 0 +#define TEST_ACTUAL_IO_RESET 1 +#define TEST_ACTUAL_IO_MULTI_CHUNK_IND 2 +#define TEST_ACTUAL_IO_MULTI_CHUNK_COL 3 +#define TEST_ACTUAL_IO_MULTI_CHUNK_MIX 4 +#define TEST_ACTUAL_IO_MULTI_CHUNK_MIX_DISAGREE 5 +#define TEST_ACTUAL_IO_DIRECT_MULTI_CHUNK_IND 6 +#define TEST_ACTUAL_IO_DIRECT_MULTI_CHUNK_COL 7 +#define TEST_ACTUAL_IO_LINK_CHUNK 8 +#define TEST_ACTUAL_IO_CONTIGUOUS 9 + +/* Definitions of the selection mode for the no_collective_cause_tests function. */ +#define TEST_COLLECTIVE 0x001 +#define TEST_SET_INDEPENDENT 0x002 +#define TEST_DATATYPE_CONVERSION 0x004 +#define TEST_DATA_TRANSFORMS 0x008 +#define TEST_NOT_SIMPLE_OR_SCALAR_DATASPACES 0x010 +#define TEST_NOT_CONTIGUOUS_OR_CHUNKED_DATASET_COMPACT 0x020 +#define TEST_NOT_CONTIGUOUS_OR_CHUNKED_DATASET_EXTERNAL 0x040 + +/* Don't erase these lines, they are put here for debugging purposes */ +/* +#define MSPACE1_RANK 1 +#define MSPACE1_DIM 50 +#define MSPACE2_RANK 1 +#define MSPACE2_DIM 4 +#define FSPACE_RANK 2 +#define FSPACE_DIM1 8 +#define FSPACE_DIM2 12 +#define MSPACE_RANK 2 +#define MSPACE_DIM1 8 +#define MSPACE_DIM2 9 +#define NPOINTS 4 +*/ /* end of debugging macro */ + +#ifdef H5_HAVE_INSTRUMENTED_LIBRARY +/* Collective chunk instrumentation properties */ +#define H5D_XFER_COLL_CHUNK_LINK_HARD_NAME "coll_chunk_link_hard" +#define H5D_XFER_COLL_CHUNK_MULTI_HARD_NAME "coll_chunk_multi_hard" +#define H5D_XFER_COLL_CHUNK_LINK_NUM_TRUE_NAME "coll_chunk_link_true" +#define H5D_XFER_COLL_CHUNK_LINK_NUM_FALSE_NAME "coll_chunk_link_false" +#define H5D_XFER_COLL_CHUNK_MULTI_RATIO_COLL_NAME "coll_chunk_multi_coll" +#define H5D_XFER_COLL_CHUNK_MULTI_RATIO_IND_NAME "coll_chunk_multi_ind" + +/* Definitions for all collective chunk instrumentation properties */ +#define H5D_XFER_COLL_CHUNK_SIZE sizeof(unsigned) +#define H5D_XFER_COLL_CHUNK_DEF 1 + +/* General collective I/O instrumentation properties */ +#define H5D_XFER_COLL_RANK0_BCAST_NAME "coll_rank0_bcast" + +/* Definitions for general collective I/O instrumentation properties */ +#define H5D_XFER_COLL_RANK0_BCAST_SIZE sizeof(hbool_t) +#define H5D_XFER_COLL_RANK0_BCAST_DEF FALSE +#endif /* H5_HAVE_INSTRUMENTED_LIBRARY */ + +/* type definitions */ +typedef struct H5Ptest_param_t /* holds extra test parameters */ +{ + char *name; + int count; +} H5Ptest_param_t; + +/* Dataset data type. Int's can be easily octo dumped. */ +typedef int DATATYPE; + +/* Shape Same Tests Definitions */ +typedef enum { + IND_CONTIG, /* Independent IO on contiguous datasets */ + COL_CONTIG, /* Collective IO on contiguous datasets */ + IND_CHUNKED, /* Independent IO on chunked datasets */ + COL_CHUNKED /* Collective IO on chunked datasets */ +} ShapeSameTestMethods; + +/* Shared global variables */ +extern int dim0, dim1; /*Dataset dimensions */ +extern int chunkdim0, chunkdim1; /*Chunk dimensions */ +extern int nerrors; /*errors count */ +extern H5E_auto2_t old_func; /* previous error handler */ +extern void *old_client_data; /*previous error handler arg.*/ +extern int facc_type; /*Test file access type */ +extern int dxfer_coll_type; + +/* Test program prototypes */ +void test_plist_ed(void); +#if 0 +void external_links(void); +#endif +void zero_dim_dset(void); +void test_file_properties(void); +void test_delete(void); +void multiple_dset_write(void); +void multiple_group_write(void); +void multiple_group_read(void); +void collective_group_write_independent_group_read(void); +void collective_group_write(void); +void independent_group_read(void); +void test_fapl_mpio_dup(void); +void test_split_comm_access(void); +void test_page_buffer_access(void); +void dataset_atomicity(void); +void dataset_writeInd(void); +void dataset_writeAll(void); +void extend_writeInd(void); +void extend_writeInd2(void); +void extend_writeAll(void); +void dataset_readInd(void); +void dataset_readAll(void); +void extend_readInd(void); +void extend_readAll(void); +void none_selection_chunk(void); +void actual_io_mode_tests(void); +void no_collective_cause_tests(void); +void test_chunk_alloc(void); +void test_filter_read(void); +void compact_dataset(void); +void null_dataset(void); +void big_dataset(void); +void dataset_fillvalue(void); +void coll_chunk1(void); +void coll_chunk2(void); +void coll_chunk3(void); +void coll_chunk4(void); +void coll_chunk5(void); +void coll_chunk6(void); +void coll_chunk7(void); +void coll_chunk8(void); +void coll_chunk9(void); +void coll_chunk10(void); +void coll_irregular_cont_read(void); +void coll_irregular_cont_write(void); +void coll_irregular_simple_chunk_read(void); +void coll_irregular_simple_chunk_write(void); +void coll_irregular_complex_chunk_read(void); +void coll_irregular_complex_chunk_write(void); +void io_mode_confusion(void); +void rr_obj_hdr_flush_confusion(void); +void rr_obj_hdr_flush_confusion_reader(MPI_Comm comm); +void rr_obj_hdr_flush_confusion_writer(MPI_Comm comm); +void chunk_align_bug_1(void); +void lower_dim_size_comp_test(void); +void link_chunk_collective_io_test(void); +void contig_hyperslab_dr_pio_test(ShapeSameTestMethods sstest_type); +void checker_board_hyperslab_dr_pio_test(ShapeSameTestMethods sstest_type); +void file_image_daisy_chain_test(void); +#ifdef H5_HAVE_FILTER_DEFLATE +void compress_readAll(void); +#endif /* H5_HAVE_FILTER_DEFLATE */ +void test_dense_attr(void); +void test_partial_no_selection_coll_md_read(void); +void test_multi_chunk_io_addrmap_issue(void); +void test_link_chunk_io_sort_chunk_issue(void); +void test_collective_global_heap_write(void); + +/* commonly used prototypes */ +hid_t create_faccess_plist(MPI_Comm comm, MPI_Info info, int l_facc_type); +MPI_Offset h5_mpi_get_file_size(const char *filename, MPI_Comm comm, MPI_Info info); +int dataset_vrfy(hsize_t start[], hsize_t count[], hsize_t stride[], hsize_t block[], DATATYPE *dataset, + DATATYPE *original); +void point_set(hsize_t start[], hsize_t count[], hsize_t stride[], hsize_t block[], size_t num_points, + hsize_t coords[], int order); +#endif /* PHDF5TEST_H */ diff --git a/testpar/CMakeLists.txt b/testpar/CMakeLists.txt index 3a44fca..d34b800 100644 --- a/testpar/CMakeLists.txt +++ b/testpar/CMakeLists.txt @@ -104,10 +104,30 @@ set (H5P_TESTS t_vfd ) +set (HDF5_API_TESTS + attribute + dataset + datatype + file + group + link + misc + object +) + +if (HDF5_TEST_API_ENABLE_ASYNC) + set (HDF5_API_TESTS + ${HDF5_API_TESTS} + async + ) +endif () + foreach (h5_testp ${H5P_TESTS}) ADD_H5P_EXE(${h5_testp}) endforeach () +add_subdirectory (API) + if (HDF5_TEST_PARALLEL) include (CMakeTests.cmake) endif () -- cgit v0.12 From 7df92eee39e904bb38e74ce5f7971ebc4886472b Mon Sep 17 00:00:00 2001 From: Allen Byrne <50328838+byrnHDF@users.noreply.github.com> Date: Wed, 3 May 2023 11:45:16 -0500 Subject: Changes to isolate API Test option files and use fetchcontent (#2880) --- config/cmake/cacheinit.cmake | 11 + doxygen/dox/Overview.dox | 2 +- test/API/CMake/CheckAsan.cmake | 37 - test/API/CMake/CheckUbsan.cmake | 37 - test/API/CMakeLists.txt | 38 +- test/API/driver/CMakeLists.txt | 37 +- test/API/driver/kwsys/.clang-format | 22 - test/API/driver/kwsys/.hooks-config | 2 - test/API/driver/kwsys/Base64.c | 225 - test/API/driver/kwsys/Base64.h.in | 110 - test/API/driver/kwsys/CMakeLists.txt | 1260 ----- test/API/driver/kwsys/CONTRIBUTING.rst | 49 - test/API/driver/kwsys/CTestConfig.cmake | 9 - test/API/driver/kwsys/CTestCustom.cmake.in | 14 - test/API/driver/kwsys/CommandLineArguments.cxx | 768 --- test/API/driver/kwsys/CommandLineArguments.hxx.in | 270 - test/API/driver/kwsys/Configure.h.in | 89 - test/API/driver/kwsys/Configure.hxx.in | 65 - test/API/driver/kwsys/ConsoleBuf.hxx.in | 398 -- test/API/driver/kwsys/Copyright.txt | 38 - test/API/driver/kwsys/Directory.cxx | 236 - test/API/driver/kwsys/Directory.hxx.in | 72 - test/API/driver/kwsys/DynamicLoader.cxx | 495 -- test/API/driver/kwsys/DynamicLoader.hxx.in | 106 - test/API/driver/kwsys/Encoding.h.in | 69 - test/API/driver/kwsys/Encoding.hxx.in | 80 - test/API/driver/kwsys/EncodingC.c | 72 - test/API/driver/kwsys/EncodingCXX.cxx | 288 -- test/API/driver/kwsys/ExtraTest.cmake.in | 1 - test/API/driver/kwsys/FStream.cxx | 55 - test/API/driver/kwsys/FStream.hxx.in | 278 - test/API/driver/kwsys/GitSetup/.gitattributes | 6 - test/API/driver/kwsys/GitSetup/LICENSE | 202 - test/API/driver/kwsys/GitSetup/NOTICE | 5 - test/API/driver/kwsys/GitSetup/README | 87 - test/API/driver/kwsys/GitSetup/config | 4 - test/API/driver/kwsys/GitSetup/config.sample | 32 - test/API/driver/kwsys/GitSetup/git-gerrit-push | 74 - test/API/driver/kwsys/GitSetup/git-gitlab-push | 177 - test/API/driver/kwsys/GitSetup/pre-commit | 26 - test/API/driver/kwsys/GitSetup/setup-aliases | 6 - test/API/driver/kwsys/GitSetup/setup-gerrit | 147 - test/API/driver/kwsys/GitSetup/setup-gitlab | 140 - test/API/driver/kwsys/GitSetup/setup-hooks | 64 - test/API/driver/kwsys/GitSetup/setup-ssh | 111 - test/API/driver/kwsys/GitSetup/setup-stage | 82 - test/API/driver/kwsys/GitSetup/setup-upstream | 104 - test/API/driver/kwsys/GitSetup/setup-user | 39 - test/API/driver/kwsys/GitSetup/tips | 55 - test/API/driver/kwsys/Glob.cxx | 448 -- test/API/driver/kwsys/Glob.hxx.in | 134 - test/API/driver/kwsys/IOStream.cxx | 255 - test/API/driver/kwsys/IOStream.hxx.in | 126 - test/API/driver/kwsys/MD5.c | 494 -- test/API/driver/kwsys/MD5.h.in | 97 - test/API/driver/kwsys/Process.h.in | 544 -- test/API/driver/kwsys/ProcessUNIX.c | 2920 ----------- test/API/driver/kwsys/ProcessWin32.c | 2786 ---------- test/API/driver/kwsys/README.rst | 37 - test/API/driver/kwsys/RegularExpression.cxx | 1218 ----- test/API/driver/kwsys/RegularExpression.hxx.in | 562 -- test/API/driver/kwsys/SetupForDevelopment.sh | 20 - test/API/driver/kwsys/SharedForward.h.in | 879 ---- test/API/driver/kwsys/String.c | 100 - test/API/driver/kwsys/String.h.in | 57 - test/API/driver/kwsys/String.hxx.in | 65 - test/API/driver/kwsys/System.c | 236 - test/API/driver/kwsys/System.h.in | 60 - test/API/driver/kwsys/SystemInformation.cxx | 5466 -------------------- test/API/driver/kwsys/SystemInformation.hxx.in | 170 - test/API/driver/kwsys/SystemTools.cxx | 4703 ----------------- test/API/driver/kwsys/SystemTools.hxx.in | 981 ---- test/API/driver/kwsys/Terminal.c | 414 -- test/API/driver/kwsys/Terminal.h.in | 170 - test/API/driver/kwsys/clang-format.bash | 128 - test/API/driver/kwsys/hash_fun.hxx.in | 166 - test/API/driver/kwsys/hash_map.hxx.in | 423 -- test/API/driver/kwsys/hash_set.hxx.in | 392 -- test/API/driver/kwsys/hashtable.hxx.in | 995 ---- test/API/driver/kwsys/kwsysHeaderDump.pl | 41 - test/API/driver/kwsys/kwsysPlatformTests.cmake | 216 - test/API/driver/kwsys/kwsysPlatformTestsC.c | 108 - test/API/driver/kwsys/kwsysPlatformTestsCXX.cxx | 335 -- test/API/driver/kwsys/kwsysPrivate.h | 34 - test/API/driver/kwsys/testCommandLineArguments.cxx | 209 - .../API/driver/kwsys/testCommandLineArguments1.cxx | 93 - test/API/driver/kwsys/testConfigure.cxx | 30 - test/API/driver/kwsys/testConsoleBuf.cxx | 782 --- test/API/driver/kwsys/testConsoleBuf.hxx | 17 - test/API/driver/kwsys/testConsoleBufChild.cxx | 55 - test/API/driver/kwsys/testDirectory.cxx | 110 - test/API/driver/kwsys/testDynamicLoader.cxx | 133 - test/API/driver/kwsys/testDynload.c | 13 - test/API/driver/kwsys/testDynloadImpl.c | 10 - test/API/driver/kwsys/testDynloadImpl.h | 15 - test/API/driver/kwsys/testDynloadUse.c | 15 - test/API/driver/kwsys/testEncode.c | 67 - test/API/driver/kwsys/testEncoding.cxx | 286 - test/API/driver/kwsys/testFStream.cxx | 113 - test/API/driver/kwsys/testFail.c | 24 - test/API/driver/kwsys/testHashSTL.cxx | 64 - test/API/driver/kwsys/testProcess.c | 728 --- test/API/driver/kwsys/testSharedForward.c.in | 27 - test/API/driver/kwsys/testSystemInformation.cxx | 106 - test/API/driver/kwsys/testSystemTools.bin | Bin 766 -> 0 bytes test/API/driver/kwsys/testSystemTools.cxx | 1128 ---- test/API/driver/kwsys/testSystemTools.h.in | 12 - test/API/driver/kwsys/testTerminal.c | 22 - test/API/driver/kwsys/update-gitsetup.bash | 20 - test/API/driver/kwsys/update-third-party.bash | 169 - test/CMakeLists.txt | 24 +- testpar/API/CMakeLists.txt | 27 +- testpar/CMakeLists.txt | 24 +- 113 files changed, 89 insertions(+), 36608 deletions(-) delete mode 100644 test/API/CMake/CheckAsan.cmake delete mode 100644 test/API/CMake/CheckUbsan.cmake delete mode 100644 test/API/driver/kwsys/.clang-format delete mode 100644 test/API/driver/kwsys/.hooks-config delete mode 100644 test/API/driver/kwsys/Base64.c delete mode 100644 test/API/driver/kwsys/Base64.h.in delete mode 100644 test/API/driver/kwsys/CMakeLists.txt delete mode 100644 test/API/driver/kwsys/CONTRIBUTING.rst delete mode 100644 test/API/driver/kwsys/CTestConfig.cmake delete mode 100644 test/API/driver/kwsys/CTestCustom.cmake.in delete mode 100644 test/API/driver/kwsys/CommandLineArguments.cxx delete mode 100644 test/API/driver/kwsys/CommandLineArguments.hxx.in delete mode 100644 test/API/driver/kwsys/Configure.h.in delete mode 100644 test/API/driver/kwsys/Configure.hxx.in delete mode 100644 test/API/driver/kwsys/ConsoleBuf.hxx.in delete mode 100644 test/API/driver/kwsys/Copyright.txt delete mode 100644 test/API/driver/kwsys/Directory.cxx delete mode 100644 test/API/driver/kwsys/Directory.hxx.in delete mode 100644 test/API/driver/kwsys/DynamicLoader.cxx delete mode 100644 test/API/driver/kwsys/DynamicLoader.hxx.in delete mode 100644 test/API/driver/kwsys/Encoding.h.in delete mode 100644 test/API/driver/kwsys/Encoding.hxx.in delete mode 100644 test/API/driver/kwsys/EncodingC.c delete mode 100644 test/API/driver/kwsys/EncodingCXX.cxx delete mode 100644 test/API/driver/kwsys/ExtraTest.cmake.in delete mode 100644 test/API/driver/kwsys/FStream.cxx delete mode 100644 test/API/driver/kwsys/FStream.hxx.in delete mode 100644 test/API/driver/kwsys/GitSetup/.gitattributes delete mode 100644 test/API/driver/kwsys/GitSetup/LICENSE delete mode 100644 test/API/driver/kwsys/GitSetup/NOTICE delete mode 100644 test/API/driver/kwsys/GitSetup/README delete mode 100644 test/API/driver/kwsys/GitSetup/config delete mode 100644 test/API/driver/kwsys/GitSetup/config.sample delete mode 100644 test/API/driver/kwsys/GitSetup/git-gerrit-push delete mode 100644 test/API/driver/kwsys/GitSetup/git-gitlab-push delete mode 100644 test/API/driver/kwsys/GitSetup/pre-commit delete mode 100644 test/API/driver/kwsys/GitSetup/setup-aliases delete mode 100644 test/API/driver/kwsys/GitSetup/setup-gerrit delete mode 100644 test/API/driver/kwsys/GitSetup/setup-gitlab delete mode 100644 test/API/driver/kwsys/GitSetup/setup-hooks delete mode 100644 test/API/driver/kwsys/GitSetup/setup-ssh delete mode 100644 test/API/driver/kwsys/GitSetup/setup-stage delete mode 100644 test/API/driver/kwsys/GitSetup/setup-upstream delete mode 100644 test/API/driver/kwsys/GitSetup/setup-user delete mode 100644 test/API/driver/kwsys/GitSetup/tips delete mode 100644 test/API/driver/kwsys/Glob.cxx delete mode 100644 test/API/driver/kwsys/Glob.hxx.in delete mode 100644 test/API/driver/kwsys/IOStream.cxx delete mode 100644 test/API/driver/kwsys/IOStream.hxx.in delete mode 100644 test/API/driver/kwsys/MD5.c delete mode 100644 test/API/driver/kwsys/MD5.h.in delete mode 100644 test/API/driver/kwsys/Process.h.in delete mode 100644 test/API/driver/kwsys/ProcessUNIX.c delete mode 100644 test/API/driver/kwsys/ProcessWin32.c delete mode 100644 test/API/driver/kwsys/README.rst delete mode 100644 test/API/driver/kwsys/RegularExpression.cxx delete mode 100644 test/API/driver/kwsys/RegularExpression.hxx.in delete mode 100644 test/API/driver/kwsys/SetupForDevelopment.sh delete mode 100644 test/API/driver/kwsys/SharedForward.h.in delete mode 100644 test/API/driver/kwsys/String.c delete mode 100644 test/API/driver/kwsys/String.h.in delete mode 100644 test/API/driver/kwsys/String.hxx.in delete mode 100644 test/API/driver/kwsys/System.c delete mode 100644 test/API/driver/kwsys/System.h.in delete mode 100644 test/API/driver/kwsys/SystemInformation.cxx delete mode 100644 test/API/driver/kwsys/SystemInformation.hxx.in delete mode 100644 test/API/driver/kwsys/SystemTools.cxx delete mode 100644 test/API/driver/kwsys/SystemTools.hxx.in delete mode 100644 test/API/driver/kwsys/Terminal.c delete mode 100644 test/API/driver/kwsys/Terminal.h.in delete mode 100644 test/API/driver/kwsys/clang-format.bash delete mode 100644 test/API/driver/kwsys/hash_fun.hxx.in delete mode 100644 test/API/driver/kwsys/hash_map.hxx.in delete mode 100644 test/API/driver/kwsys/hash_set.hxx.in delete mode 100644 test/API/driver/kwsys/hashtable.hxx.in delete mode 100644 test/API/driver/kwsys/kwsysHeaderDump.pl delete mode 100644 test/API/driver/kwsys/kwsysPlatformTests.cmake delete mode 100644 test/API/driver/kwsys/kwsysPlatformTestsC.c delete mode 100644 test/API/driver/kwsys/kwsysPlatformTestsCXX.cxx delete mode 100644 test/API/driver/kwsys/kwsysPrivate.h delete mode 100644 test/API/driver/kwsys/testCommandLineArguments.cxx delete mode 100644 test/API/driver/kwsys/testCommandLineArguments1.cxx delete mode 100644 test/API/driver/kwsys/testConfigure.cxx delete mode 100644 test/API/driver/kwsys/testConsoleBuf.cxx delete mode 100644 test/API/driver/kwsys/testConsoleBuf.hxx delete mode 100644 test/API/driver/kwsys/testConsoleBufChild.cxx delete mode 100644 test/API/driver/kwsys/testDirectory.cxx delete mode 100644 test/API/driver/kwsys/testDynamicLoader.cxx delete mode 100644 test/API/driver/kwsys/testDynload.c delete mode 100644 test/API/driver/kwsys/testDynloadImpl.c delete mode 100644 test/API/driver/kwsys/testDynloadImpl.h delete mode 100644 test/API/driver/kwsys/testDynloadUse.c delete mode 100644 test/API/driver/kwsys/testEncode.c delete mode 100644 test/API/driver/kwsys/testEncoding.cxx delete mode 100644 test/API/driver/kwsys/testFStream.cxx delete mode 100644 test/API/driver/kwsys/testFail.c delete mode 100644 test/API/driver/kwsys/testHashSTL.cxx delete mode 100644 test/API/driver/kwsys/testProcess.c delete mode 100644 test/API/driver/kwsys/testSharedForward.c.in delete mode 100644 test/API/driver/kwsys/testSystemInformation.cxx delete mode 100644 test/API/driver/kwsys/testSystemTools.bin delete mode 100644 test/API/driver/kwsys/testSystemTools.cxx delete mode 100644 test/API/driver/kwsys/testSystemTools.h.in delete mode 100644 test/API/driver/kwsys/testTerminal.c delete mode 100644 test/API/driver/kwsys/update-gitsetup.bash delete mode 100644 test/API/driver/kwsys/update-third-party.bash diff --git a/config/cmake/cacheinit.cmake b/config/cmake/cacheinit.cmake index 4460891..376b28f 100644 --- a/config/cmake/cacheinit.cmake +++ b/config/cmake/cacheinit.cmake @@ -49,6 +49,10 @@ set (HDF5_MINGW_STATIC_GCC_LIBS ON CACHE BOOL "Statically link libgcc/libstdc++" set (HDF5_ALLOW_EXTERNAL_SUPPORT "TGZ" CACHE STRING "Allow External Library Building (NO GIT TGZ)" FORCE) set_property (CACHE HDF5_ALLOW_EXTERNAL_SUPPORT PROPERTY STRINGS NO GIT TGZ) +######################## +# compression options +######################## + set (ZLIB_PACKAGE_NAME "zlib" CACHE STRING "Name of ZLIB package" FORCE) set (ZLIB_TGZ_NAME "ZLib.tar.gz" CACHE STRING "Use HDF5_ZLib from compressed file" FORCE) set (ZLIB_TGZ_ORIGPATH "https://github.com/madler/zlib/releases/download/v1.2.13" CACHE STRING "Use ZLIB from original location" FORCE) @@ -62,6 +66,13 @@ set (LIBAEC_TGZ_ORIGNAME "libaec-v1.0.6.tar.gz" CACHE STRING "Use LIBAEC from or set (LIBAEC_USE_LOCALCONTENT OFF CACHE BOOL "Use local file for LIBAEC FetchContent" FORCE) ######################## +# API test options +######################## +set (KWSYS_TGZ_ORIGPATH "https://gitlab.kitware.com/utils/kwsys/-/archive/master/kwsys-master.tar.gz" CACHE STRING "Use KWSYS from original location" FORCE) +set (KWSYS_TGZ_ORIGNAME "kwsys-master.tar.gz" CACHE STRING "Use KWSYS from original compressed file" FORCE) +set (KWSYS_USE_LOCALCONTENT OFF CACHE BOOL "Use local file for KWSYS FetchContent" FORCE) + +######################## # filter plugin options ######################## diff --git a/doxygen/dox/Overview.dox b/doxygen/dox/Overview.dox index 70974ec..f909d8d 100644 --- a/doxygen/dox/Overview.dox +++ b/doxygen/dox/Overview.dox @@ -23,8 +23,8 @@ documents cover a mix of tasks, concepts, and reference, to help a specific \par Versions Version-specific documentation (see the version in the title area) can be found here: - - HDF5 1.14.x (this site) - HDF5 develop branch + - HDF5 1.14.x (this site) - HDF5 1.12.x - HDF5 1.10.x - HDF5 1.8.x diff --git a/test/API/CMake/CheckAsan.cmake b/test/API/CMake/CheckAsan.cmake deleted file mode 100644 index 32f4b45..0000000 --- a/test/API/CMake/CheckAsan.cmake +++ /dev/null @@ -1,37 +0,0 @@ -set(ASAN_FLAG "-fsanitize=address") -set(ASAN_C_FLAGS "-O1 -g ${ASAN_FLAG} -fsanitize-address-use-after-scope -fno-omit-frame-pointer -fno-optimize-sibling-calls") -set(ASAN_CXX_FLAGS ${ASAN_C_FLAGS}) - -get_property(ASAN_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) -foreach(lang ${ASAN_LANGUAGES}) - set(ASAN_${lang}_LANG_ENABLED 1) -endforeach() - -if(ASAN_C_LANG_ENABLED) - include(CheckCCompilerFlag) - set(CMAKE_REQUIRED_LINK_OPTIONS ${ASAN_FLAG}) - check_c_compiler_flag(${ASAN_FLAG} ASAN_C_FLAG_SUPPORTED) - if(NOT ASAN_C_FLAG_SUPPORTED) - message(STATUS "Asan flags are not supported by the C compiler.") - else() - if(NOT CMAKE_C_FLAGS_ASAN) - set(CMAKE_C_FLAGS_ASAN ${ASAN_C_FLAGS} CACHE STRING "Flags used by the C compiler during ASAN builds." FORCE) - endif() - endif() - unset(CMAKE_REQUIRED_LINK_OPTIONS) -endif() - -if(ASAN_CXX_LANG_ENABLED) - include(CheckCXXCompilerFlag) - set(CMAKE_REQUIRED_LINK_OPTIONS ${ASAN_FLAG}) - check_cxx_compiler_flag(${ASAN_FLAG} ASAN_CXX_FLAG_SUPPORTED) - if(NOT ASAN_CXX_FLAG_SUPPORTED) - message(STATUS "Asan flags are not supported by the CXX compiler.") - else() - if(NOT CMAKE_CXX_FLAGS_ASAN) - set(CMAKE_CXX_FLAGS_ASAN ${ASAN_CXX_FLAGS} CACHE STRING "Flags used by the CXX compiler during ASAN builds." FORCE) - endif() - endif() - unset(CMAKE_REQUIRED_LINK_OPTIONS) -endif() - diff --git a/test/API/CMake/CheckUbsan.cmake b/test/API/CMake/CheckUbsan.cmake deleted file mode 100644 index f2b9c2c..0000000 --- a/test/API/CMake/CheckUbsan.cmake +++ /dev/null @@ -1,37 +0,0 @@ -set(UBSAN_FLAG "-fsanitize=undefined") -set(UBSAN_C_FLAGS "-O1 -g ${UBSAN_FLAG} -fno-omit-frame-pointer") -set(UBSAN_CXX_FLAGS ${UBSAN_C_FLAGS}) - -get_property(UBSAN_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) -foreach(lang ${UBSAN_LANGUAGES}) - set(UBSAN_${lang}_LANG_ENABLED 1) -endforeach() - -if(UBSAN_C_LANG_ENABLED) - include(CheckCCompilerFlag) - set(CMAKE_REQUIRED_LINK_OPTIONS ${UBSAN_FLAG}) - check_c_compiler_flag(${UBSAN_FLAG} UBSAN_C_FLAG_SUPPORTED) - if(NOT UBSAN_C_FLAG_SUPPORTED) - message(STATUS "Ubsan flags are not supported by the C compiler.") - else() - if(NOT CMAKE_C_FLAGS_UBSAN) - set(CMAKE_C_FLAGS_UBSAN ${UBSAN_C_FLAGS} CACHE STRING "Flags used by the C compiler during UBSAN builds." FORCE) - endif() - endif() - unset(CMAKE_REQUIRED_LINK_OPTIONS) -endif() - -if(UBSAN_CXX_LANG_ENABLED) - include(CheckCXXCompilerFlag) - set(CMAKE_REQUIRED_LINK_OPTIONS ${UBSAN_FLAG}) - check_cxx_compiler_flag(${UBSAN_FLAG} UBSAN_CXX_FLAG_SUPPORTED) - if(NOT UBSAN_CXX_FLAG_SUPPORTED) - message(STATUS "Ubsan flags are not supported by the CXX compiler.") - else() - if(NOT CMAKE_CXX_FLAGS_UBSAN) - set(CMAKE_CXX_FLAGS_UBSAN ${UBSAN_CXX_FLAGS} CACHE STRING "Flags used by the CXX compiler during UBSAN builds." FORCE) - endif() - endif() - unset(CMAKE_REQUIRED_LINK_OPTIONS) -endif() - diff --git a/test/API/CMakeLists.txt b/test/API/CMakeLists.txt index d189d67..c2f95bd 100644 --- a/test/API/CMakeLists.txt +++ b/test/API/CMakeLists.txt @@ -9,26 +9,12 @@ # help@hdfgroup.org. # -#------------------------------------------------------------------------------ -# Set module path -#------------------------------------------------------------------------------ -set(HDF5_TEST_API_CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake") -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${HDF5_TEST_API_CMAKE_MODULE_PATH}) - -# TODO: probably not necessary -#------------------------------------------------------------------------------ -# Setup CMake Environment -#------------------------------------------------------------------------------ -if (WIN32) - message("The HDF5 API test suite is currently not supported on this platform." FATAL_ERROR) -endif () +cmake_minimum_required (VERSION 3.18) +project (HDF5_TEST_API C) #------------------------------------------------------------------------------ # Setup testing configuration file #------------------------------------------------------------------------------ -if (HDF5_TEST_PARALLEL) - set (HDF5_TEST_API_HAVE_PARALLEL 1) -endif () if (HDF5_TEST_API_ENABLE_ASYNC) set (H5_API_TEST_HAVE_ASYNC 1) endif () @@ -46,9 +32,27 @@ if (HDF5_TEST_API_ENABLE_DRIVER) endif () #------------------------------------------------------------------------------ -# Setup for API tests +# Define for API tests #------------------------------------------------------------------------------ +set (HDF5_API_TESTS + attribute + dataset + datatype + file + group + link + misc + object +) + +if (HDF5_TEST_API_ENABLE_ASYNC) + set (HDF5_API_TESTS + ${HDF5_API_TESTS} + async + ) +endif () + # Ported HDF5 tests set (HDF5_API_TESTS_EXTRA testhdf5 diff --git a/test/API/driver/CMakeLists.txt b/test/API/driver/CMakeLists.txt index 2210068..23ba053 100644 --- a/test/API/driver/CMakeLists.txt +++ b/test/API/driver/CMakeLists.txt @@ -1,17 +1,34 @@ -cmake_minimum_required(VERSION 2.8.12.2 FATAL_ERROR) +cmake_minimum_required (VERSION 3.18) project(H5_API_TEST_DRIVER CXX) -include(CheckAsan) -include(CheckUbsan) +if (NOT KWSYS_USE_LOCALCONTENT) + set (KWSYS_URL ${KWSYS_TGZ_ORIGPATH}/${KWSYS_TGZ_ORIGNAME}) +else () + set (KWSYS_URL ${TGZPATH}/${KWSYS_TGZ_ORIGNAME}) +endif () +# Only tgz files +FetchContent_Declare (KWSYS + URL ${KWSYS_URL} + URL_HASH "" +) +FetchContent_GetProperties(KWSYS) +if(NOT kwsys_POPULATED) + FetchContent_Populate(KWSYS) -set(CMAKE_CXX_STANDARD 11) + # Copy an additional/replacement files into the populated source + #file(COPY ${HDF_RESOURCES_DIR}/KWSYS/CMakeLists.txt DESTINATION ${hdf5_kwsys_SOURCE_DIR}) -set(KWSYS_NAMESPACE h5_api_test_sys) -set(KWSYS_USE_SystemTools 1) -set(KWSYS_USE_Process 1) -set(KWSYS_USE_RegularExpression 1) -add_subdirectory(kwsys) -include_directories(${CMAKE_CURRENT_BINARY_DIR}/kwsys) + set(CMAKE_CXX_STANDARD 11) + + set(KWSYS_NAMESPACE h5_api_test_sys) + set(KWSYS_USE_SystemTools 1) + set(KWSYS_USE_Process 1) + set(KWSYS_USE_RegularExpression 1) + + add_subdirectory(${hdf5_kwsysb_SOURCE_DIR} ${hdf5_kwsys_BINARY_DIR}) +endif() + +include_directories(${hdf5_kwsys_BINARY_DIR}) add_executable(h5_api_test_driver h5_api_test_driver.cxx) target_link_libraries(h5_api_test_driver h5_api_test_sys) diff --git a/test/API/driver/kwsys/.clang-format b/test/API/driver/kwsys/.clang-format deleted file mode 100644 index 588b790..0000000 --- a/test/API/driver/kwsys/.clang-format +++ /dev/null @@ -1,22 +0,0 @@ ---- -# This configuration requires clang-format version 6.0 exactly. -BasedOnStyle: Mozilla -AlignOperands: false -AllowShortFunctionsOnASingleLine: InlineOnly -AlwaysBreakAfterDefinitionReturnType: None -AlwaysBreakAfterReturnType: None -BinPackArguments: true -BinPackParameters: true -BraceWrapping: - AfterClass: true - AfterEnum: true - AfterFunction: true - AfterStruct: true - AfterUnion: true -BreakBeforeBraces: Custom -ColumnLimit: 79 -IndentPPDirectives: AfterHash -SortUsingDeclarations: false -SpaceAfterTemplateKeyword: true -Standard: Cpp03 -... diff --git a/test/API/driver/kwsys/.hooks-config b/test/API/driver/kwsys/.hooks-config deleted file mode 100644 index 739cdd2..0000000 --- a/test/API/driver/kwsys/.hooks-config +++ /dev/null @@ -1,2 +0,0 @@ -[hooks "chain"] - pre-commit = GitSetup/pre-commit diff --git a/test/API/driver/kwsys/Base64.c b/test/API/driver/kwsys/Base64.c deleted file mode 100644 index bf876f2..0000000 --- a/test/API/driver/kwsys/Base64.c +++ /dev/null @@ -1,225 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include "kwsysPrivate.h" -#include KWSYS_HEADER(Base64.h) - -/* Work-around CMake dependency scanning limitation. This must - duplicate the above list of headers. */ -#if 0 -# include "Base64.h.in" -#endif - -static const unsigned char kwsysBase64EncodeTable[65] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - -static const unsigned char kwsysBase64DecodeTable[256] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xFF, 0xFF, 0x3F, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, - 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, - 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, - 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - /*------------------------------------*/ - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -}; - -static unsigned char kwsysBase64EncodeChar(int c) -{ - return kwsysBase64EncodeTable[(unsigned char)c]; -} - -static unsigned char kwsysBase64DecodeChar(unsigned char c) -{ - return kwsysBase64DecodeTable[c]; -} - -/* Encode 3 bytes into a 4 byte string. */ -void kwsysBase64_Encode3(const unsigned char* src, unsigned char* dest) -{ - dest[0] = kwsysBase64EncodeChar((src[0] >> 2) & 0x3F); - dest[1] = - kwsysBase64EncodeChar(((src[0] << 4) & 0x30) | ((src[1] >> 4) & 0x0F)); - dest[2] = - kwsysBase64EncodeChar(((src[1] << 2) & 0x3C) | ((src[2] >> 6) & 0x03)); - dest[3] = kwsysBase64EncodeChar(src[2] & 0x3F); -} - -/* Encode 2 bytes into a 4 byte string. */ -void kwsysBase64_Encode2(const unsigned char* src, unsigned char* dest) -{ - dest[0] = kwsysBase64EncodeChar((src[0] >> 2) & 0x3F); - dest[1] = - kwsysBase64EncodeChar(((src[0] << 4) & 0x30) | ((src[1] >> 4) & 0x0F)); - dest[2] = kwsysBase64EncodeChar(((src[1] << 2) & 0x3C)); - dest[3] = '='; -} - -/* Encode 1 bytes into a 4 byte string. */ -void kwsysBase64_Encode1(const unsigned char* src, unsigned char* dest) -{ - dest[0] = kwsysBase64EncodeChar((src[0] >> 2) & 0x3F); - dest[1] = kwsysBase64EncodeChar(((src[0] << 4) & 0x30)); - dest[2] = '='; - dest[3] = '='; -} - -/* Encode 'length' bytes from the input buffer and store the - encoded stream into the output buffer. Return the length of the encoded - buffer (output). Note that the output buffer must be allocated by the caller - (length * 1.5 should be a safe estimate). If 'mark_end' is true than an - extra set of 4 bytes is added to the end of the stream if the input is a - multiple of 3 bytes. These bytes are invalid chars and therefore they will - stop the decoder thus enabling the caller to decode a stream without - actually knowing how much data to expect (if the input is not a multiple of - 3 bytes then the extra padding needed to complete the encode 4 bytes will - stop the decoding anyway). */ -size_t kwsysBase64_Encode(const unsigned char* input, size_t length, - unsigned char* output, int mark_end) -{ - const unsigned char* ptr = input; - const unsigned char* end = input + length; - unsigned char* optr = output; - - /* Encode complete triplet */ - - while ((end - ptr) >= 3) { - kwsysBase64_Encode3(ptr, optr); - ptr += 3; - optr += 4; - } - - /* Encodes a 2-byte ending into 3 bytes and 1 pad byte and writes. */ - - if (end - ptr == 2) { - kwsysBase64_Encode2(ptr, optr); - optr += 4; - } - - /* Encodes a 1-byte ending into 2 bytes and 2 pad bytes */ - - else if (end - ptr == 1) { - kwsysBase64_Encode1(ptr, optr); - optr += 4; - } - - /* Do we need to mark the end */ - - else if (mark_end) { - optr[0] = optr[1] = optr[2] = optr[3] = '='; - optr += 4; - } - - return (size_t)(optr - output); -} - -/* Decode 4 bytes into a 3 byte string. */ -int kwsysBase64_Decode3(const unsigned char* src, unsigned char* dest) -{ - unsigned char d0, d1, d2, d3; - - d0 = kwsysBase64DecodeChar(src[0]); - d1 = kwsysBase64DecodeChar(src[1]); - d2 = kwsysBase64DecodeChar(src[2]); - d3 = kwsysBase64DecodeChar(src[3]); - - /* Make sure all characters were valid */ - - if (d0 == 0xFF || d1 == 0xFF || d2 == 0xFF || d3 == 0xFF) { - return 0; - } - - /* Decode the 3 bytes */ - - dest[0] = (unsigned char)(((d0 << 2) & 0xFC) | ((d1 >> 4) & 0x03)); - dest[1] = (unsigned char)(((d1 << 4) & 0xF0) | ((d2 >> 2) & 0x0F)); - dest[2] = (unsigned char)(((d2 << 6) & 0xC0) | ((d3 >> 0) & 0x3F)); - - /* Return the number of bytes actually decoded */ - - if (src[2] == '=') { - return 1; - } - if (src[3] == '=') { - return 2; - } - return 3; -} - -/* Decode bytes from the input buffer and store the decoded stream - into the output buffer until 'length' bytes have been decoded. Return the - real length of the decoded stream (which should be equal to 'length'). Note - that the output buffer must be allocated by the caller. If - 'max_input_length' is not null, then it specifies the number of encoded - bytes that should be at most read from the input buffer. In that case the - 'length' parameter is ignored. This enables the caller to decode a stream - without actually knowing how much decoded data to expect (of course, the - buffer must be large enough). */ -size_t kwsysBase64_Decode(const unsigned char* input, size_t length, - unsigned char* output, size_t max_input_length) -{ - const unsigned char* ptr = input; - unsigned char* optr = output; - - /* Decode complete triplet */ - - if (max_input_length) { - const unsigned char* end = input + max_input_length; - while (ptr < end) { - int len = kwsysBase64_Decode3(ptr, optr); - optr += len; - if (len < 3) { - return (size_t)(optr - output); - } - ptr += 4; - } - } else { - unsigned char* oend = output + length; - while ((oend - optr) >= 3) { - int len = kwsysBase64_Decode3(ptr, optr); - optr += len; - if (len < 3) { - return (size_t)(optr - output); - } - ptr += 4; - } - - /* Decode the last triplet */ - - if (oend - optr == 2) { - unsigned char temp[3]; - int len = kwsysBase64_Decode3(ptr, temp); - if (len >= 2) { - optr[0] = temp[0]; - optr[1] = temp[1]; - optr += 2; - } else if (len > 0) { - optr[0] = temp[0]; - optr += 1; - } - } else if (oend - optr == 1) { - unsigned char temp[3]; - int len = kwsysBase64_Decode3(ptr, temp); - if (len > 0) { - optr[0] = temp[0]; - optr += 1; - } - } - } - - return (size_t)(optr - output); -} diff --git a/test/API/driver/kwsys/Base64.h.in b/test/API/driver/kwsys/Base64.h.in deleted file mode 100644 index 729f972..0000000 --- a/test/API/driver/kwsys/Base64.h.in +++ /dev/null @@ -1,110 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifndef @KWSYS_NAMESPACE@_Base64_h -#define @KWSYS_NAMESPACE@_Base64_h - -#include <@KWSYS_NAMESPACE@/Configure.h> - -#include /* size_t */ - -/* Redefine all public interface symbol names to be in the proper - namespace. These macros are used internally to kwsys only, and are - not visible to user code. Use kwsysHeaderDump.pl to reproduce - these macros after making changes to the interface. */ -#if !defined(KWSYS_NAMESPACE) -# define kwsys_ns(x) @KWSYS_NAMESPACE@##x -# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT -#endif -#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS -# define kwsysBase64 kwsys_ns(Base64) -# define kwsysBase64_Decode kwsys_ns(Base64_Decode) -# define kwsysBase64_Decode3 kwsys_ns(Base64_Decode3) -# define kwsysBase64_Encode kwsys_ns(Base64_Encode) -# define kwsysBase64_Encode1 kwsys_ns(Base64_Encode1) -# define kwsysBase64_Encode2 kwsys_ns(Base64_Encode2) -# define kwsysBase64_Encode3 kwsys_ns(Base64_Encode3) -#endif - -#if defined(__cplusplus) -extern "C" { -#endif - -/** - * Encode 3 bytes into a 4 byte string. - */ -kwsysEXPORT void kwsysBase64_Encode3(const unsigned char* src, - unsigned char* dest); - -/** - * Encode 2 bytes into a 4 byte string. - */ -kwsysEXPORT void kwsysBase64_Encode2(const unsigned char* src, - unsigned char* dest); - -/** - * Encode 1 bytes into a 4 byte string. - */ -kwsysEXPORT void kwsysBase64_Encode1(const unsigned char* src, - unsigned char* dest); - -/** - * Encode 'length' bytes from the input buffer and store the encoded - * stream into the output buffer. Return the length of the encoded - * buffer (output). Note that the output buffer must be allocated by - * the caller (length * 1.5 should be a safe estimate). If 'mark_end' - * is true than an extra set of 4 bytes is added to the end of the - * stream if the input is a multiple of 3 bytes. These bytes are - * invalid chars and therefore they will stop the decoder thus - * enabling the caller to decode a stream without actually knowing how - * much data to expect (if the input is not a multiple of 3 bytes then - * the extra padding needed to complete the encode 4 bytes will stop - * the decoding anyway). - */ -kwsysEXPORT size_t kwsysBase64_Encode(const unsigned char* input, - size_t length, unsigned char* output, - int mark_end); - -/** - * Decode 4 bytes into a 3 byte string. Returns the number of bytes - * actually decoded. - */ -kwsysEXPORT int kwsysBase64_Decode3(const unsigned char* src, - unsigned char* dest); - -/** - * Decode bytes from the input buffer and store the decoded stream - * into the output buffer until 'length' bytes have been decoded. - * Return the real length of the decoded stream (which should be equal - * to 'length'). Note that the output buffer must be allocated by the - * caller. If 'max_input_length' is not null, then it specifies the - * number of encoded bytes that should be at most read from the input - * buffer. In that case the 'length' parameter is ignored. This - * enables the caller to decode a stream without actually knowing how - * much decoded data to expect (of course, the buffer must be large - * enough). - */ -kwsysEXPORT size_t kwsysBase64_Decode(const unsigned char* input, - size_t length, unsigned char* output, - size_t max_input_length); - -#if defined(__cplusplus) -} /* extern "C" */ -#endif - -/* If we are building a kwsys .c or .cxx file, let it use these macros. - Otherwise, undefine them to keep the namespace clean. */ -#if !defined(KWSYS_NAMESPACE) -# undef kwsys_ns -# undef kwsysEXPORT -# if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS -# undef kwsysBase64 -# undef kwsysBase64_Decode -# undef kwsysBase64_Decode3 -# undef kwsysBase64_Encode -# undef kwsysBase64_Encode1 -# undef kwsysBase64_Encode2 -# undef kwsysBase64_Encode3 -# endif -#endif - -#endif diff --git a/test/API/driver/kwsys/CMakeLists.txt b/test/API/driver/kwsys/CMakeLists.txt deleted file mode 100644 index 09bcdb9..0000000 --- a/test/API/driver/kwsys/CMakeLists.txt +++ /dev/null @@ -1,1260 +0,0 @@ -# Distributed under the OSI-approved BSD 3-Clause License. See accompanying -# file Copyright.txt or https://cmake.org/licensing#kwsys for details. - -# The Kitware System Library is intended to be included in other -# projects. It is completely configurable in that the library's -# namespace can be configured and the components that are included can -# be selected invididually. - -# Typical usage is to import the kwsys directory tree into a -# subdirectory under a parent project and enable the classes that will -# be used. All classes are disabled by default. The CMake listfile -# above this one configures the library as follows: -# -# SET(KWSYS_NAMESPACE foosys) -# SET(KWSYS_USE_Directory 1) # Enable Directory class. -# SUBDIRS(kwsys) -# -# Optional settings are as follows: -# -# KWSYS_HEADER_ROOT = The directory into which to generate the kwsys headers. -# A directory called "${KWSYS_NAMESPACE}" will be -# created under this root directory to hold the files. -# KWSYS_SPLIT_OBJECTS_FROM_INTERFACE -# = Instead of creating a single ${KWSYS_NAMESPACE} library -# target, create three separate targets: -# ${KWSYS_NAMESPACE} -# - An INTERFACE library only containing usage -# requirements. -# ${KWSYS_NAMESPACE}_objects -# - An OBJECT library for the built kwsys objects. -# Note: This is omitted from the install rules -# ${KWSYS_NAMESPACE}_private -# - An INTERFACE library combining both that is -# appropriate for use with PRIVATE linking in -# target_link_libraries. Because of how interface -# properties propagate, this target is not suitable -# for use with PUBLIC or INTERFACE linking. -# KWSYS_ALIAS_TARGET = The name of an alias target to create to the actual target. -# -# Example: -# -# SET(KWSYS_HEADER_ROOT ${PROJECT_BINARY_DIR}) -# INCLUDE_DIRECTORIES(${PROJECT_BINARY_DIR}) -# -# KWSYS_CXX_STANDARD = A value for CMAKE_CXX_STANDARD within KWSys. -# Set to empty string to use no default value. -# KWSYS_CXX_COMPILE_FEATURES = target_compile_features arguments for KWSys. -# -# Optional settings to setup install rules are as follows: -# -# KWSYS_INSTALL_BIN_DIR = The installation target directories into -# KWSYS_INSTALL_LIB_DIR which the libraries and headers from -# KWSYS_INSTALL_INCLUDE_DIR kwsys should be installed by a "make install". -# The values should be specified relative to -# the installation prefix and NOT start with '/'. -# KWSYS_INSTALL_DOC_DIR = The installation target directory for documentation -# such as copyright information. -# -# KWSYS_INSTALL_COMPONENT_NAME_RUNTIME = Name of runtime and development -# KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT installation components. -# If not given the install rules -# will not be in any component. -# -# KWSYS_INSTALL_EXPORT_NAME = The EXPORT option value for install(TARGETS) calls. -# -# Example: -# -# SET(KWSYS_INSTALL_BIN_DIR bin) -# SET(KWSYS_INSTALL_LIB_DIR lib) -# SET(KWSYS_INSTALL_INCLUDE_DIR include) -# SET(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME Runtime) -# SET(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT Development) - -# Once configured, kwsys should be used as follows from C or C++ code: -# -# #include -# ... -# foosys::Directory directory; -# - -# NOTE: This library is intended for internal use by Kitware-driven -# projects. In order to keep it simple no attempt will be made to -# maintain backward compatibility when changes are made to KWSys. -# When an incompatible change is made Kitware's projects that use -# KWSys will be fixed, but no notification will necessarily be sent to -# any outside mailing list and no documentation of the change will be -# written. - -CMAKE_MINIMUM_REQUIRED(VERSION 3.1 FATAL_ERROR) -FOREACH(p - CMP0056 # CMake 3.2, Honor link flags in try_compile() source-file signature. - CMP0063 # CMake 3.3, Honor visibility properties for all target types. - CMP0067 # CMake 3.8, Honor language standard in try_compile source-file signature. - CMP0069 # CMake 3.9, INTERPROCEDURAL_OPTIMIZATION is enforced when enabled. - ) - IF(POLICY ${p}) - CMAKE_POLICY(SET ${p} NEW) - ENDIF() -ENDFOREACH() - -#----------------------------------------------------------------------------- -# If a namespace is not specified, use "kwsys" and enable testing. -# This should be the case only when kwsys is not included inside -# another project and is being tested. -IF(NOT KWSYS_NAMESPACE) - SET(KWSYS_NAMESPACE "kwsys") - SET(KWSYS_STANDALONE 1) -ENDIF() - -#----------------------------------------------------------------------------- -# The project name is that of the specified namespace. -PROJECT(${KWSYS_NAMESPACE}) - -# Tell CMake how to follow dependencies of sources in this directory. -SET_PROPERTY(DIRECTORY - PROPERTY IMPLICIT_DEPENDS_INCLUDE_TRANSFORM - "KWSYS_HEADER(%)=<${KWSYS_NAMESPACE}/%>" - ) - -if(KWSYS_CXX_STANDARD) - set(CMAKE_CXX_STANDARD "${KWSYS_CXX_STANDARD}") -elseif(NOT DEFINED CMAKE_CXX_STANDARD AND NOT DEFINED KWSYS_CXX_STANDARD) - if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" - AND CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC" - AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU" - ) - set(CMAKE_CXX_STANDARD 14) - else() - set(CMAKE_CXX_STANDARD 11) - endif() -endif() - -# Select library components. -IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) - SET(KWSYS_ENABLE_C 1) - # Enable all components. - SET(KWSYS_USE_Base64 1) - SET(KWSYS_USE_Directory 1) - SET(KWSYS_USE_DynamicLoader 1) - SET(KWSYS_USE_Encoding 1) - SET(KWSYS_USE_Glob 1) - SET(KWSYS_USE_MD5 1) - SET(KWSYS_USE_Process 1) - SET(KWSYS_USE_RegularExpression 1) - SET(KWSYS_USE_System 1) - SET(KWSYS_USE_SystemTools 1) - SET(KWSYS_USE_CommandLineArguments 1) - SET(KWSYS_USE_Terminal 1) - SET(KWSYS_USE_IOStream 1) - SET(KWSYS_USE_FStream 1) - SET(KWSYS_USE_String 1) - SET(KWSYS_USE_SystemInformation 1) - SET(KWSYS_USE_ConsoleBuf 1) -ENDIF() - -# Enforce component dependencies. -IF(KWSYS_USE_SystemTools) - SET(KWSYS_USE_Directory 1) - SET(KWSYS_USE_FStream 1) - SET(KWSYS_USE_Encoding 1) -ENDIF() -IF(KWSYS_USE_Glob) - SET(KWSYS_USE_Directory 1) - SET(KWSYS_USE_SystemTools 1) - SET(KWSYS_USE_RegularExpression 1) - SET(KWSYS_USE_FStream 1) - SET(KWSYS_USE_Encoding 1) -ENDIF() -IF(KWSYS_USE_Process) - SET(KWSYS_USE_System 1) - SET(KWSYS_USE_Encoding 1) -ENDIF() -IF(KWSYS_USE_SystemInformation) - SET(KWSYS_USE_Process 1) -ENDIF() -IF(KWSYS_USE_System) - SET(KWSYS_USE_Encoding 1) -ENDIF() -IF(KWSYS_USE_Directory) - SET(KWSYS_USE_Encoding 1) -ENDIF() -IF(KWSYS_USE_DynamicLoader) - SET(KWSYS_USE_Encoding 1) -ENDIF() -IF(KWSYS_USE_FStream) - SET(KWSYS_USE_Encoding 1) -ENDIF() -IF(KWSYS_USE_ConsoleBuf) - SET(KWSYS_USE_Encoding 1) -ENDIF() - -# Specify default 8 bit encoding for Windows -IF(NOT KWSYS_ENCODING_DEFAULT_CODEPAGE) - SET(KWSYS_ENCODING_DEFAULT_CODEPAGE CP_ACP) -ENDIF() - -# Enable testing if building standalone. -IF(KWSYS_STANDALONE) - INCLUDE(Dart) - MARK_AS_ADVANCED(BUILD_TESTING DART_ROOT TCL_TCLSH) - IF(BUILD_TESTING) - ENABLE_TESTING() - ENDIF() -ENDIF() - -# Choose default shared/static build if not specified. -IF(NOT DEFINED KWSYS_BUILD_SHARED) - SET(KWSYS_BUILD_SHARED ${BUILD_SHARED_LIBS}) -ENDIF() - -# Include helper macros. -INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/kwsysPlatformTests.cmake) -INCLUDE(CheckTypeSize) - -# Do full dependency headers. -INCLUDE_REGULAR_EXPRESSION("^.*$") - -# Use new KWSYS_INSTALL_*_DIR variable names to control installation. -# Take defaults from the old names. Note that there was no old name -# for the bin dir, so we take the old lib dir name so DLLs will be -# installed in a compatible way for old code. -IF(NOT KWSYS_INSTALL_INCLUDE_DIR) - STRING(REGEX REPLACE "^/" "" KWSYS_INSTALL_INCLUDE_DIR - "${KWSYS_HEADER_INSTALL_DIR}") -ENDIF() -IF(NOT KWSYS_INSTALL_LIB_DIR) - STRING(REGEX REPLACE "^/" "" KWSYS_INSTALL_LIB_DIR - "${KWSYS_LIBRARY_INSTALL_DIR}") -ENDIF() -IF(NOT KWSYS_INSTALL_BIN_DIR) - STRING(REGEX REPLACE "^/" "" KWSYS_INSTALL_BIN_DIR - "${KWSYS_LIBRARY_INSTALL_DIR}") -ENDIF() - -# Setup header install rules. -SET(KWSYS_INSTALL_INCLUDE_OPTIONS) -IF(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT) - SET(KWSYS_INSTALL_INCLUDE_OPTIONS ${KWSYS_INSTALL_INCLUDE_OPTIONS} - COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT} - ) -ENDIF() - -# Setup library install rules. -SET(KWSYS_INSTALL_LIBRARY_RULE) -SET(KWSYS_INSTALL_NAMELINK_RULE) -IF(KWSYS_INSTALL_LIB_DIR) - IF(KWSYS_INSTALL_EXPORT_NAME) - LIST(APPEND KWSYS_INSTALL_LIBRARY_RULE EXPORT ${KWSYS_INSTALL_EXPORT_NAME}) - ENDIF() - # Install the shared library to the lib directory. - SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE} - LIBRARY DESTINATION ${KWSYS_INSTALL_LIB_DIR} NAMELINK_SKIP - ) - # Assign the shared library to the runtime component. - IF(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME) - SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE} - COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_RUNTIME} - ) - ENDIF() - IF(KWSYS_BUILD_SHARED) - SET(KWSYS_INSTALL_NAMELINK_RULE ${KWSYS_INSTALL_NAMELINK_RULE} - LIBRARY DESTINATION ${KWSYS_INSTALL_LIB_DIR} NAMELINK_ONLY - ) - # Assign the namelink to the development component. - IF(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT) - SET(KWSYS_INSTALL_NAMELINK_RULE ${KWSYS_INSTALL_NAMELINK_RULE} - COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT} - ) - ENDIF() - ENDIF() - - # Install the archive to the lib directory. - SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE} - ARCHIVE DESTINATION ${KWSYS_INSTALL_LIB_DIR} - ) - # Assign the archive to the development component. - IF(KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT) - SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE} - COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_DEVELOPMENT} - ) - ENDIF() -ENDIF() -IF(KWSYS_INSTALL_BIN_DIR) - # Install the runtime library to the bin directory. - SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE} - RUNTIME DESTINATION ${KWSYS_INSTALL_BIN_DIR} - ) - # Assign the runtime library to the runtime component. - IF(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME) - SET(KWSYS_INSTALL_LIBRARY_RULE ${KWSYS_INSTALL_LIBRARY_RULE} - COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_RUNTIME} - ) - ENDIF() -ENDIF() - -# Do not support old KWSYS_*a_INSTALL_DIR variable names. -SET(KWSYS_HEADER_INSTALL_DIR) -SET(KWSYS_LIBRARY_INSTALL_DIR) - -# Generated source files will need this header. -STRING(COMPARE EQUAL "${PROJECT_SOURCE_DIR}" "${PROJECT_BINARY_DIR}" - KWSYS_IN_SOURCE_BUILD) -IF(NOT KWSYS_IN_SOURCE_BUILD) - CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/kwsysPrivate.h - ${PROJECT_BINARY_DIR}/kwsysPrivate.h COPYONLY IMMEDIATE) -ENDIF() - -# Select plugin module file name convention. -IF(NOT KWSYS_DynamicLoader_PREFIX) - SET(KWSYS_DynamicLoader_PREFIX ${CMAKE_SHARED_MODULE_PREFIX}) -ENDIF() -IF(NOT KWSYS_DynamicLoader_SUFFIX) - SET(KWSYS_DynamicLoader_SUFFIX ${CMAKE_SHARED_MODULE_SUFFIX}) -ENDIF() - -#----------------------------------------------------------------------------- -# We require ANSI support from the C compiler. Add any needed flags. -IF(CMAKE_ANSI_CFLAGS) - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_ANSI_CFLAGS}") -ENDIF() - -#----------------------------------------------------------------------------- -# Adjust compiler flags for some platforms. -IF(NOT CMAKE_COMPILER_IS_GNUCXX) - IF(CMAKE_SYSTEM MATCHES "OSF1-V.*") - STRING(REGEX MATCH "-timplicit_local" - KWSYS_CXX_FLAGS_HAVE_IMPLICIT_LOCAL "${CMAKE_CXX_FLAGS}") - STRING(REGEX MATCH "-no_implicit_include" - KWSYS_CXX_FLAGS_HAVE_NO_IMPLICIT_INCLUDE "${CMAKE_CXX_FLAGS}") - IF(NOT KWSYS_CXX_FLAGS_HAVE_IMPLICIT_LOCAL) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -timplicit_local") - ENDIF() - IF(NOT KWSYS_CXX_FLAGS_HAVE_NO_IMPLICIT_INCLUDE) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -no_implicit_include") - ENDIF() - ENDIF() - IF(CMAKE_SYSTEM MATCHES "HP-UX") - SET(KWSYS_PLATFORM_CXX_TEST_EXTRA_FLAGS "+p") - IF(CMAKE_CXX_COMPILER_ID MATCHES "HP") - # it is known that version 3.85 fails and 6.25 works without these flags - IF(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4) - # use new C++ library and improved template support - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -AA +hpxstd98") - ENDIF() - ENDIF() - ENDIF() -ENDIF() -IF(KWSYS_STANDALONE) - IF(CMAKE_CXX_COMPILER_ID STREQUAL SunPro) - IF(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.13) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++03") - ELSE() - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -library=stlport4") - ENDIF() - ENDIF() -ENDIF() - -#----------------------------------------------------------------------------- -# Configure the standard library header wrappers based on compiler's -# capabilities and parent project's request. Enforce 0/1 as only -# possible values for configuration into Configure.hxx. - -# Check existence and uniqueness of long long and __int64. -KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_LONG_LONG - "Checking whether C++ compiler has 'long long'" DIRECT) -KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS___INT64 - "Checking whether C++ compiler has '__int64'" DIRECT) -IF(KWSYS_CXX_HAS___INT64) - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_SAME_LONG_AND___INT64 - "Checking whether long and __int64 are the same type" DIRECT) - IF(KWSYS_CXX_HAS_LONG_LONG) - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_SAME_LONG_LONG_AND___INT64 - "Checking whether long long and __int64 are the same type" DIRECT) - ENDIF() -ENDIF() - -# Enable the "long long" type if it is available. It is standard in -# C99 and C++03 but not in earlier standards. -IF(KWSYS_CXX_HAS_LONG_LONG) - SET(KWSYS_USE_LONG_LONG 1) -ELSE() - SET(KWSYS_USE_LONG_LONG 0) -ENDIF() - -# Enable the "__int64" type if it is available and unique. It is not -# standard. -SET(KWSYS_USE___INT64 0) -IF(KWSYS_CXX_HAS___INT64) - IF(NOT KWSYS_CXX_SAME_LONG_AND___INT64) - IF(NOT KWSYS_CXX_SAME_LONG_LONG_AND___INT64) - SET(KWSYS_USE___INT64 1) - ENDIF() - ENDIF() -ENDIF() - -IF(KWSYS_USE_Encoding) - # Look for type size helper macros. - KWSYS_PLATFORM_CXX_TEST(KWSYS_STL_HAS_WSTRING - "Checking whether wstring is available" DIRECT) -ENDIF() - -IF(KWSYS_USE_IOStream) - # Determine whether iostreams support long long. - IF(KWSYS_CXX_HAS_LONG_LONG) - KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_ISTREAM_LONG_LONG - "Checking if istream supports long long" DIRECT) - KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_OSTREAM_LONG_LONG - "Checking if ostream supports long long" DIRECT) - ELSE() - SET(KWSYS_IOS_HAS_ISTREAM_LONG_LONG 0) - SET(KWSYS_IOS_HAS_OSTREAM_LONG_LONG 0) - ENDIF() - IF(KWSYS_CXX_HAS___INT64) - KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_ISTREAM___INT64 - "Checking if istream supports __int64" DIRECT) - KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_OSTREAM___INT64 - "Checking if ostream supports __int64" DIRECT) - ELSE() - SET(KWSYS_IOS_HAS_ISTREAM___INT64 0) - SET(KWSYS_IOS_HAS_OSTREAM___INT64 0) - ENDIF() -ENDIF() - -IF(KWSYS_NAMESPACE MATCHES "^kwsys$") - SET(KWSYS_NAME_IS_KWSYS 1) -ELSE() - SET(KWSYS_NAME_IS_KWSYS 0) -ENDIF() - -IF(KWSYS_BUILD_SHARED) - SET(KWSYS_BUILD_SHARED 1) - SET(KWSYS_LIBRARY_TYPE SHARED) -ELSE() - SET(KWSYS_BUILD_SHARED 0) - SET(KWSYS_LIBRARY_TYPE STATIC) -ENDIF() - -if(NOT DEFINED KWSYS_BUILD_PIC) - set(KWSYS_BUILD_PIC 0) -endif() - -#----------------------------------------------------------------------------- -# Configure some implementation details. - -KWSYS_PLATFORM_C_TEST(KWSYS_C_HAS_PTRDIFF_T - "Checking whether C compiler has ptrdiff_t in stddef.h" DIRECT) -KWSYS_PLATFORM_C_TEST(KWSYS_C_HAS_SSIZE_T - "Checking whether C compiler has ssize_t in unistd.h" DIRECT) -IF(KWSYS_USE_Process) - KWSYS_PLATFORM_C_TEST(KWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC - "Checking whether C compiler has clock_gettime" DIRECT) -ENDIF() - -SET_SOURCE_FILES_PROPERTIES(ProcessUNIX.c System.c PROPERTIES - COMPILE_FLAGS "-DKWSYS_C_HAS_PTRDIFF_T=${KWSYS_C_HAS_PTRDIFF_T} -DKWSYS_C_HAS_SSIZE_T=${KWSYS_C_HAS_SSIZE_T} -DKWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC=${KWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC}" - ) - -IF(DEFINED KWSYS_PROCESS_USE_SELECT) - GET_PROPERTY(ProcessUNIX_FLAGS SOURCE ProcessUNIX.c PROPERTY COMPILE_FLAGS) - SET_PROPERTY(SOURCE ProcessUNIX.c PROPERTY COMPILE_FLAGS "${ProcessUNIX_FLAGS} -DKWSYSPE_USE_SELECT=${KWSYSPE_USE_SELECT}") -ENDIF() - -IF(KWSYS_USE_DynamicLoader) - GET_PROPERTY(KWSYS_SUPPORTS_SHARED_LIBS GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS) - IF(KWSYS_SUPPORTS_SHARED_LIBS) - SET(KWSYS_SUPPORTS_SHARED_LIBS 1) - ELSE() - SET(KWSYS_SUPPORTS_SHARED_LIBS 0) - ENDIF() - SET_PROPERTY(SOURCE DynamicLoader.cxx APPEND PROPERTY COMPILE_DEFINITIONS - KWSYS_SUPPORTS_SHARED_LIBS=${KWSYS_SUPPORTS_SHARED_LIBS}) -ENDIF() - -IF(KWSYS_USE_SystemTools) - if (NOT DEFINED KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP) - set(KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP 1) - endif () - if (KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP) - set(KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP 1) - else () - set(KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP 0) - endif () - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_SETENV - "Checking whether CXX compiler has setenv" DIRECT) - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_UNSETENV - "Checking whether CXX compiler has unsetenv" DIRECT) - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H - "Checking whether CXX compiler has environ in stdlib.h" DIRECT) - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_UTIMES - "Checking whether CXX compiler has utimes" DIRECT) - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_UTIMENSAT - "Checking whether CXX compiler has utimensat" DIRECT) - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_STAT_HAS_ST_MTIM - "Checking whether CXX compiler struct stat has st_mtim member" DIRECT) - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_STAT_HAS_ST_MTIMESPEC - "Checking whether CXX compiler struct stat has st_mtimespec member" DIRECT) - SET_PROPERTY(SOURCE SystemTools.cxx APPEND PROPERTY COMPILE_DEFINITIONS - KWSYS_CXX_HAS_SETENV=${KWSYS_CXX_HAS_SETENV} - KWSYS_CXX_HAS_UNSETENV=${KWSYS_CXX_HAS_UNSETENV} - KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H=${KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H} - KWSYS_CXX_HAS_UTIMES=${KWSYS_CXX_HAS_UTIMES} - KWSYS_CXX_HAS_UTIMENSAT=${KWSYS_CXX_HAS_UTIMENSAT} - KWSYS_CXX_STAT_HAS_ST_MTIM=${KWSYS_CXX_STAT_HAS_ST_MTIM} - KWSYS_CXX_STAT_HAS_ST_MTIMESPEC=${KWSYS_CXX_STAT_HAS_ST_MTIMESPEC} - ) - IF(NOT WIN32) - IF(KWSYS_STANDALONE) - OPTION(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES "If true, Windows paths will be supported on Unix as well" ON) - ENDIF() - IF(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES) - SET_PROPERTY(SOURCE SystemTools.cxx testSystemTools.cxx APPEND PROPERTY COMPILE_DEFINITIONS - KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES - ) - ENDIF() - ENDIF() - - # Disable getpwnam for static linux builds since it depends on shared glibc - GET_PROPERTY(SHARED_LIBS_SUPPORTED GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS) - IF(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT SHARED_LIBS_SUPPORTED) - SET_PROPERTY(SOURCE SystemTools.cxx APPEND PROPERTY COMPILE_DEFINITIONS - HAVE_GETPWNAM=0 - ) - ENDIF() -ENDIF() - -IF(KWSYS_USE_SystemInformation) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS SIZEOF_VOID_P=${CMAKE_SIZEOF_VOID_P}) - IF(NOT CYGWIN) - INCLUDE(CheckIncludeFiles) - CHECK_INCLUDE_FILES("sys/types.h;ifaddrs.h" KWSYS_SYS_HAS_IFADDRS_H) - IF(KWSYS_SYS_HAS_IFADDRS_H) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_SYS_HAS_IFADDRS_H=1) - ENDIF() - ENDIF() - IF(WIN32) - INCLUDE(CheckSymbolExists) - SET(CMAKE_REQUIRED_LIBRARIES Psapi) - CHECK_SYMBOL_EXISTS(GetProcessMemoryInfo "windows.h;psapi.h" KWSYS_SYS_HAS_PSAPI) - UNSET(CMAKE_REQUIRED_LIBRARIES) - IF(KWSYS_SYS_HAS_PSAPI) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_SYS_HAS_PSAPI=1) - IF(MSVC70 OR MSVC71) - # Suppress LNK4089: all references to 'PSAPI.DLL' discarded by /OPT:REF - SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /IGNORE:4089") - ENDIF() - ENDIF() - ENDIF() - IF(CMAKE_SYSTEM MATCHES "HP-UX") - CHECK_INCLUDE_FILES("sys/mpctl.h" KWSYS_SYS_HAS_MPCTL_H) - IF(KWSYS_SYS_HAS_MPCTL_H) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_SYS_HAS_MPCTL_H=1) - ENDIF() - ENDIF() - IF(CMAKE_SYSTEM MATCHES "BSD") - CHECK_INCLUDE_FILES("machine/cpu.h" KWSYS_SYS_HAS_MACHINE_CPU_H) - IF(KWSYS_SYS_HAS_MACHINE_CPU_H) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_SYS_HAS_MACHINE_CPU_H=1) - ENDIF() - ENDIF() - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_RLIMIT64 - "Checking whether CXX compiler has rlimit64" DIRECT) - SET(KWSYS_PLATFORM_CXX_TEST_DEFINES) - IF(KWSYS_CXX_HAS_RLIMIT64) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_CXX_HAS_RLIMIT64=1) - ENDIF() - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_ATOL - "Checking whether CXX compiler has atol" DIRECT) - IF(KWSYS_CXX_HAS_ATOL) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_CXX_HAS_ATOL=1) - ENDIF() - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_ATOLL - "Checking whether CXX compiler has atoll" DIRECT) - IF(KWSYS_CXX_HAS_ATOLL) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_CXX_HAS_ATOLL=1) - ENDIF() - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS__ATOI64 - "Checking whether CXX compiler has _atoi64" DIRECT) - IF(KWSYS_CXX_HAS__ATOI64) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_CXX_HAS__ATOI64=1) - ENDIF() - IF(UNIX) - INCLUDE(CheckIncludeFileCXX) - # check for simple stack trace - # usually it's in libc but on FreeBSD - # it's in libexecinfo - FIND_LIBRARY(EXECINFO_LIB "execinfo") - MARK_AS_ADVANCED(EXECINFO_LIB) - IF (NOT EXECINFO_LIB) - SET(EXECINFO_LIB "") - ENDIF() - CHECK_INCLUDE_FILE_CXX("execinfo.h" KWSYS_CXX_HAS_EXECINFOH) - IF (KWSYS_CXX_HAS_EXECINFOH) - # we have the backtrace header check if it - # can be used with this compiler - SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES ${EXECINFO_LIB}) - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_BACKTRACE - "Checking whether backtrace works with this C++ compiler" DIRECT) - SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES) - IF (KWSYS_CXX_HAS_BACKTRACE) - # backtrace is supported by this system and compiler. - # now check for the more advanced capabilities. - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE=1) - # check for symbol lookup using dladdr - CHECK_INCLUDE_FILE_CXX("dlfcn.h" KWSYS_CXX_HAS_DLFCNH) - IF (KWSYS_CXX_HAS_DLFCNH) - # we have symbol lookup libraries and headers - # check if they can be used with this compiler - SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES ${CMAKE_DL_LIBS}) - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_DLADDR - "Checking whether dladdr works with this C++ compiler" DIRECT) - SET(KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES) - IF (KWSYS_CXX_HAS_DLADDR) - # symbol lookup is supported by this system - # and compiler. - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP=1) - ENDIF() - ENDIF() - # c++ demangling support - # check for cxxabi headers - CHECK_INCLUDE_FILE_CXX("cxxabi.h" KWSYS_CXX_HAS_CXXABIH) - IF (KWSYS_CXX_HAS_CXXABIH) - # check if cxxabi can be used with this - # system and compiler. - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_CXXABI - "Checking whether cxxabi works with this C++ compiler" DIRECT) - IF (KWSYS_CXX_HAS_CXXABI) - # c++ demangle using cxxabi is supported with - # this system and compiler - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE=1) - ENDIF() - ENDIF() - # basic backtrace works better with release build - # don't bother with advanced features for release - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS_DEBUG KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD=1) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS_RELWITHDEBINFO KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD=1) - ENDIF() - ENDIF() - ENDIF() - IF(BORLAND) - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_BORLAND_ASM - "Checking whether Borland CXX compiler supports assembler instructions" DIRECT) - IF(KWSYS_CXX_HAS_BORLAND_ASM) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_CXX_HAS_BORLAND_ASM=1) - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_BORLAND_ASM_CPUID - "Checking whether Borland CXX compiler supports CPUID assembler instruction" DIRECT) - IF(KWSYS_CXX_HAS_BORLAND_ASM_CPUID) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_CXX_HAS_BORLAND_ASM_CPUID=1) - ENDIF() - ENDIF() - ENDIF() - IF(KWSYS_USE___INT64) - SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_USE___INT64=1) - ENDIF() - IF(KWSYS_USE_LONG_LONG) - SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_USE_LONG_LONG=1) - ENDIF() - IF(KWSYS_IOS_HAS_OSTREAM_LONG_LONG) - SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_IOS_HAS_OSTREAM_LONG_LONG=1) - ENDIF() - IF(KWSYS_IOS_HAS_OSTREAM___INT64) - SET_PROPERTY(SOURCE SystemInformation.cxx testSystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_IOS_HAS_OSTREAM___INT64=1) - ENDIF() - IF(KWSYS_BUILD_SHARED) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_BUILD_SHARED=1) - ENDIF() - - IF(UNIX AND NOT CYGWIN) - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_GETLOADAVG - "Checking whether CXX compiler has getloadavg" DIRECT) - IF(KWSYS_CXX_HAS_GETLOADAVG) - SET_PROPERTY(SOURCE SystemInformation.cxx APPEND PROPERTY - COMPILE_DEFINITIONS KWSYS_CXX_HAS_GETLOADAVG=1) - ENDIF() - ENDIF() -ENDIF() - -IF(KWSYS_USE_FStream) - KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H - "Checking whether is available" DIRECT) -ENDIF() - -#----------------------------------------------------------------------------- -# Choose a directory for the generated headers. -IF(NOT KWSYS_HEADER_ROOT) - SET(KWSYS_HEADER_ROOT "${PROJECT_BINARY_DIR}") -ENDIF() -SET(KWSYS_HEADER_DIR "${KWSYS_HEADER_ROOT}/${KWSYS_NAMESPACE}") -INCLUDE_DIRECTORIES(${KWSYS_HEADER_ROOT}) - -#----------------------------------------------------------------------------- -IF(KWSYS_INSTALL_DOC_DIR) - # Assign the license to the runtime component since it must be - # distributed with binary forms of this software. - IF(KWSYS_INSTALL_COMPONENT_NAME_RUNTIME) - SET(KWSYS_INSTALL_LICENSE_OPTIONS ${KWSYS_INSTALL_LICENSE_OPTIONS} - COMPONENT ${KWSYS_INSTALL_COMPONENT_NAME_RUNTIME} - ) - ENDIF() - - # Install the license under the documentation directory. - INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/Copyright.txt - DESTINATION ${KWSYS_INSTALL_DOC_DIR}/${KWSYS_NAMESPACE} - ${KWSYS_INSTALL_LICENSE_OPTIONS}) -ENDIF() - -#----------------------------------------------------------------------------- -# Build a list of classes and headers we need to implement the -# selected components. Initialize with required components. -SET(KWSYS_CLASSES) -SET(KWSYS_H_FILES Configure SharedForward) -SET(KWSYS_HXX_FILES Configure String) - -IF(NOT CMake_SOURCE_DIR) - SET(KWSYS_HXX_FILES ${KWSYS_HXX_FILES} - hashtable hash_fun hash_map hash_set - ) -ENDIF() - -# Add selected C++ classes. -SET(cppclasses - Directory DynamicLoader Encoding Glob RegularExpression SystemTools - CommandLineArguments IOStream FStream SystemInformation ConsoleBuf - ) -FOREACH(cpp ${cppclasses}) - IF(KWSYS_USE_${cpp}) - # Use the corresponding class. - SET(KWSYS_CLASSES ${KWSYS_CLASSES} ${cpp}) - - # Load component-specific CMake code. - IF(EXISTS ${PROJECT_SOURCE_DIR}/kwsys${cpp}.cmake) - INCLUDE(${PROJECT_SOURCE_DIR}/kwsys${cpp}.cmake) - ENDIF() - ENDIF() -ENDFOREACH() - -# Add selected C components. -FOREACH(c - Process Base64 Encoding MD5 Terminal System String - ) - IF(KWSYS_USE_${c}) - # Use the corresponding header file. - SET(KWSYS_H_FILES ${KWSYS_H_FILES} ${c}) - - # Load component-specific CMake code. - IF(EXISTS ${PROJECT_SOURCE_DIR}/kwsys${c}.cmake) - INCLUDE(${PROJECT_SOURCE_DIR}/kwsys${c}.cmake) - ENDIF() - ENDIF() -ENDFOREACH() - -#----------------------------------------------------------------------------- -# Build a list of sources for the library based on components that are -# included. -SET(KWSYS_C_SRCS) -SET(KWSYS_CXX_SRCS) - -# Add the proper sources for this platform's Process implementation. -IF(KWSYS_USE_Process) - IF(NOT UNIX) - # Use the Windows implementation. - SET(KWSYS_C_SRCS ${KWSYS_C_SRCS} ProcessWin32.c) - ELSE() - # Use the UNIX implementation. - SET(KWSYS_C_SRCS ${KWSYS_C_SRCS} ProcessUNIX.c) - ENDIF() -ENDIF() - -# Add selected C sources. -FOREACH(c Base64 Encoding MD5 Terminal System String) - IF(KWSYS_USE_${c}) - IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${c}C.c) - LIST(APPEND KWSYS_C_SRCS ${c}C.c) - ELSE() - LIST(APPEND KWSYS_C_SRCS ${c}.c) - ENDIF() - ENDIF() -ENDFOREACH() - -# Configure headers of C++ classes and construct the list of sources. -FOREACH(c ${KWSYS_CLASSES}) - # Add this source to the list of source files for the library. - IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${c}CXX.cxx) - LIST(APPEND KWSYS_CXX_SRCS ${c}CXX.cxx) - ELSEIF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${c}.cxx) - LIST(APPEND KWSYS_CXX_SRCS ${c}.cxx) - ENDIF() - - # Configure the header for this class. - CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/${c}.hxx.in ${KWSYS_HEADER_DIR}/${c}.hxx - @ONLY IMMEDIATE) - SET(KWSYS_CXX_SRCS ${KWSYS_CXX_SRCS} ${KWSYS_HEADER_DIR}/${c}.hxx) - - # Create an install target for the header. - IF(KWSYS_INSTALL_INCLUDE_DIR) - INSTALL(FILES ${KWSYS_HEADER_DIR}/${c}.hxx - DESTINATION ${KWSYS_INSTALL_INCLUDE_DIR}/${KWSYS_NAMESPACE} - ${KWSYS_INSTALL_INCLUDE_OPTIONS}) - ENDIF() -ENDFOREACH() - -# Configure C headers. -FOREACH(h ${KWSYS_H_FILES}) - # Configure the header into the given directory. - CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/${h}.h.in ${KWSYS_HEADER_DIR}/${h}.h - @ONLY IMMEDIATE) - SET(KWSYS_C_SRCS ${KWSYS_C_SRCS} ${KWSYS_HEADER_DIR}/${h}.h) - - # Create an install target for the header. - IF(KWSYS_INSTALL_INCLUDE_DIR) - INSTALL(FILES ${KWSYS_HEADER_DIR}/${h}.h - DESTINATION ${KWSYS_INSTALL_INCLUDE_DIR}/${KWSYS_NAMESPACE} - ${KWSYS_INSTALL_INCLUDE_OPTIONS}) - ENDIF() -ENDFOREACH() - -# Configure other C++ headers. -FOREACH(h ${KWSYS_HXX_FILES}) - # Configure the header into the given directory. - CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/${h}.hxx.in ${KWSYS_HEADER_DIR}/${h}.hxx - @ONLY IMMEDIATE) - SET(KWSYS_CXX_SRCS ${KWSYS_CXX_SRCS} ${KWSYS_HEADER_DIR}/${h}.hxx) - - # Create an install target for the header. - IF(KWSYS_INSTALL_INCLUDE_DIR) - INSTALL(FILES ${KWSYS_HEADER_DIR}/${h}.hxx - DESTINATION ${KWSYS_INSTALL_INCLUDE_DIR}/${KWSYS_NAMESPACE} - ${KWSYS_INSTALL_INCLUDE_OPTIONS}) - ENDIF() -ENDFOREACH() - -#----------------------------------------------------------------------------- -# Add the library with the configured name and list of sources. -IF(KWSYS_C_SRCS OR KWSYS_CXX_SRCS) - IF(KWSYS_SPLIT_OBJECTS_FROM_INTERFACE) - SET(KWSYS_TARGET_INTERFACE ${KWSYS_NAMESPACE}) - SET(KWSYS_TARGET_OBJECT ${KWSYS_NAMESPACE}_objects) - SET(KWSYS_TARGET_LINK ${KWSYS_NAMESPACE}_private) - SET(KWSYS_TARGET_INSTALL ${KWSYS_TARGET_INTERFACE} ${KWSYS_TARGET_LINK}) - SET(KWSYS_LINK_DEPENDENCY INTERFACE) - ADD_LIBRARY(${KWSYS_TARGET_OBJECT} OBJECT - ${KWSYS_C_SRCS} ${KWSYS_CXX_SRCS}) - IF(KWSYS_BUILD_SHARED OR KWSYS_BUILD_PIC) - SET_PROPERTY(TARGET ${KWSYS_TARGET_OBJECT} PROPERTY - POSITION_INDEPENDENT_CODE TRUE) - ENDIF() - ADD_LIBRARY(${KWSYS_TARGET_INTERFACE} INTERFACE) - ADD_LIBRARY(${KWSYS_TARGET_LINK} INTERFACE) - TARGET_LINK_LIBRARIES(${KWSYS_TARGET_LINK} INTERFACE - ${KWSYS_TARGET_INTERFACE}) - TARGET_SOURCES(${KWSYS_TARGET_LINK} INTERFACE - $) - target_compile_features(${KWSYS_TARGET_OBJECT} PRIVATE ${KWSYS_CXX_COMPILE_FEATURES}) - target_compile_features(${KWSYS_TARGET_INTERFACE} INTERFACE ${KWSYS_CXX_COMPILE_FEATURES}) - ELSE() - SET(KWSYS_TARGET_INTERFACE ${KWSYS_NAMESPACE}) - SET(KWSYS_TARGET_OBJECT ${KWSYS_NAMESPACE}) - SET(KWSYS_TARGET_LINK ${KWSYS_NAMESPACE}) - set(KWSYS_TARGET_INSTALL ${KWSYS_TARGET_LINK}) - SET(KWSYS_LINK_DEPENDENCY PUBLIC) - ADD_LIBRARY(${KWSYS_TARGET_INTERFACE} ${KWSYS_LIBRARY_TYPE} - ${KWSYS_C_SRCS} ${KWSYS_CXX_SRCS}) - target_compile_features(${KWSYS_TARGET_INTERFACE} PUBLIC ${KWSYS_CXX_COMPILE_FEATURES}) - ENDIF() - if (KWSYS_ALIAS_TARGET) - add_library(${KWSYS_ALIAS_TARGET} ALIAS ${KWSYS_TARGET_INTERFACE}) - endif () - SET_TARGET_PROPERTIES(${KWSYS_TARGET_OBJECT} PROPERTIES - C_CLANG_TIDY "" - CXX_CLANG_TIDY "" - C_INCLUDE_WHAT_YOU_USE "" - CXX_INCLUDE_WHAT_YOU_USE "" - LABELS "${KWSYS_LABELS_LIB}") - IF(KWSYS_USE_DynamicLoader) - IF(UNIX) - TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} - ${CMAKE_DL_LIBS}) - ENDIF() - ENDIF() - - IF(KWSYS_USE_SystemInformation) - IF(WIN32) - TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} ws2_32) - # link in dbghelp.dll for symbol lookup if MSVC 1800 or later - # Note that the dbghelp runtime is part of MS Windows OS - IF(MSVC_VERSION AND NOT MSVC_VERSION VERSION_LESS 1800) - TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} dbghelp) - ENDIF() - IF(KWSYS_SYS_HAS_PSAPI) - TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} - Psapi) - ENDIF() - ELSEIF(UNIX) - IF (EXECINFO_LIB AND KWSYS_CXX_HAS_BACKTRACE) - # backtrace on FreeBSD is not in libc - TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} - ${EXECINFO_LIB}) - ENDIF() - IF (KWSYS_CXX_HAS_DLADDR) - # for symbol lookup using dladdr - TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} - ${CMAKE_DL_LIBS}) - ENDIF() - IF (CMAKE_SYSTEM_NAME STREQUAL "SunOS") - TARGET_LINK_LIBRARIES(${KWSYS_TARGET_INTERFACE} ${KWSYS_LINK_DEPENDENCY} - socket) - ENDIF() - ENDIF() - ENDIF() - - # Apply user-defined target properties to the library. - IF(KWSYS_PROPERTIES_CXX) - SET_TARGET_PROPERTIES(${KWSYS_TARGET_INTERFACE} PROPERTIES - ${KWSYS_PROPERTIES_CXX}) - ENDIF() - - # Set up include usage requirement - IF(COMMAND TARGET_INCLUDE_DIRECTORIES) - TARGET_INCLUDE_DIRECTORIES(${KWSYS_TARGET_INTERFACE} INTERFACE - $) - IF(KWSYS_INSTALL_INCLUDE_DIR) - TARGET_INCLUDE_DIRECTORIES(${KWSYS_TARGET_INTERFACE} INTERFACE - $) - ENDIF() - ENDIF() - - # Create an install target for the library. - IF(KWSYS_INSTALL_LIBRARY_RULE) - INSTALL(TARGETS ${KWSYS_TARGET_INSTALL} ${KWSYS_INSTALL_LIBRARY_RULE}) - ENDIF() - IF(KWSYS_INSTALL_NAMELINK_RULE) - INSTALL(TARGETS ${KWSYS_TARGET_INSTALL} ${KWSYS_INSTALL_NAMELINK_RULE}) - ENDIF() -ENDIF() - -# Add a C-only library if requested. -IF(KWSYS_ENABLE_C AND KWSYS_C_SRCS) - IF(KWSYS_SPLIT_OBJECTS_FROM_INTERFACE) - SET(KWSYS_TARGET_C_INTERFACE ${KWSYS_NAMESPACE}_c) - SET(KWSYS_TARGET_C_OBJECT ${KWSYS_NAMESPACE}_c_objects) - SET(KWSYS_TARGET_C_LINK ${KWSYS_NAMESPACE}_c_private) - SET(KWSYS_TARGET_C_INSTALL - ${KWSYS_TARGET_C_INTERFACE} ${KWSYS_TARGET_C_LINK}) - SET(KWSYS_LINK_DEPENDENCY INTERFACE) - ADD_LIBRARY(${KWSYS_TARGET_C_OBJECT} OBJECT ${KWSYS_C_SRCS}) - IF(KWSYS_BUILD_SHARED OR KWSYS_BUILD_PIC) - SET_PROPERTY(TARGET ${KWSYS_TARGET_C_OBJECT} PROPERTY - POSITION_INDEPENDENT_CODE TRUE) - ENDIF() - ADD_LIBRARY(${KWSYS_TARGET_C_INTERFACE} INTERFACE) - ADD_LIBRARY(${KWSYS_TARGET_C_LINK} INTERFACE) - TARGET_LINK_LIBRARIES(${KWSYS_TARGET_C_LINK} INTERFACE - ${KWSYS_TARGET_C_INTERFACE}) - TARGET_SOURCES(${KWSYS_TARGET_C_LINK} INTERFACE - $) - ELSE() - SET(KWSYS_TARGET_C_INTERFACE ${KWSYS_NAMESPACE}_c) - SET(KWSYS_TARGET_C_OBJECT ${KWSYS_NAMESPACE}_c) - SET(KWSYS_TARGET_C_LINK ${KWSYS_NAMESPACE}_c) - SET(KWSYS_TARGET_C_INSTALL ${KWSYS_TARGET_C_LINK}) - SET(KWSYS_LINK_DEPENDENCY PUBLIC) - ADD_LIBRARY(${KWSYS_TARGET_C_INTERFACE} ${KWSYS_LIBRARY_TYPE} - ${KWSYS_C_SRCS}) - ENDIF() - SET_TARGET_PROPERTIES(${KWSYS_TARGET_C_OBJECT} PROPERTIES - LABELS "${KWSYS_LABELS_LIB}") - - # Apply user-defined target properties to the library. - IF(KWSYS_PROPERTIES_C) - SET_TARGET_PROPERTIES(${KWSYS_TARGET_C_INTERFACE} PROPERTIES - ${KWSYS_PROPERTIES_C}) - ENDIF() - - # Set up include usage requirement - IF(COMMAND TARGET_INCLUDE_DIRECTORIES) - TARGET_INCLUDE_DIRECTORIES(${KWSYS_TARGET_C_INTERFACE} INTERFACE - $) - IF(KWSYS_INSTALL_INCLUDE_DIR) - TARGET_INCLUDE_DIRECTORIES(${KWSYS_TARGET_C_INTERFACE} INTERFACE - $) - ENDIF() - ENDIF() - - # Create an install target for the library. - IF(KWSYS_INSTALL_LIBRARY_RULE) - INSTALL(TARGETS ${KWSYS_TARGET_C_INSTALL}) - ENDIF() -ENDIF() - -# For building kwsys itself, we use a macro defined on the command -# line to configure the namespace in the C and C++ source files. -ADD_DEFINITIONS("-DKWSYS_NAMESPACE=${KWSYS_NAMESPACE}") - -# Disable deprecation warnings for standard C functions. -IF(MSVC OR (WIN32 AND (CMAKE_C_COMPILER_ID STREQUAL "Intel" OR - (CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")))) - ADD_DEFINITIONS( - -D_CRT_NONSTDC_NO_DEPRECATE - -D_CRT_SECURE_NO_DEPRECATE - -D_CRT_SECURE_NO_WARNINGS - -D_SCL_SECURE_NO_DEPRECATE - ) -ENDIF() - -IF(WIN32) - # Help enforce the use of wide Windows apis. - ADD_DEFINITIONS(-DUNICODE -D_UNICODE) -ENDIF() - -IF(KWSYS_USE_String) - # Activate code in "String.c". See the comment in the source. - SET_SOURCE_FILES_PROPERTIES(String.c PROPERTIES - COMPILE_FLAGS "-DKWSYS_STRING_C") -ENDIF() - -IF(KWSYS_USE_Encoding) - # Set default 8 bit encoding in "EndcodingC.c". - SET_PROPERTY(SOURCE EncodingC.c EncodingCXX.cxx APPEND PROPERTY COMPILE_DEFINITIONS - KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE}) -ENDIF() - -#----------------------------------------------------------------------------- -# Setup testing if not being built as part of another project. -IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) - IF(BUILD_TESTING) - # Compute the location of executables. - SET(EXEC_DIR "${CMAKE_CURRENT_BINARY_DIR}") - IF(EXECUTABLE_OUTPUT_PATH) - SET(EXEC_DIR "${EXECUTABLE_OUTPUT_PATH}") - ENDIF() - - # C tests - SET(KWSYS_C_TESTS - testEncode.c - testTerminal.c - ) - IF(KWSYS_STANDALONE) - SET(KWSYS_C_TESTS ${KWSYS_C_TESTS} testFail.c) - ENDIF() - CREATE_TEST_SOURCELIST( - KWSYS_C_TEST_SRCS ${KWSYS_NAMESPACE}TestsC.c - ${KWSYS_C_TESTS} - ) - ADD_EXECUTABLE(${KWSYS_NAMESPACE}TestsC ${KWSYS_C_TEST_SRCS}) - SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsC PROPERTY LABELS ${KWSYS_LABELS_EXE}) - TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE}TestsC ${KWSYS_TARGET_C_LINK}) - FOREACH(testfile ${KWSYS_C_TESTS}) - get_filename_component(test "${testfile}" NAME_WE) - ADD_TEST(kwsys.${test} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestsC ${test} ${KWSYS_TEST_ARGS_${test}}) - SET_PROPERTY(TEST kwsys.${test} PROPERTY LABELS ${KWSYS_LABELS_TEST}) - ENDFOREACH() - - # C++ tests - IF(NOT WATCOM AND NOT CMake_SOURCE_DIR) - SET(KWSYS_CXX_TESTS - testHashSTL.cxx - ) - ENDIF() - SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} - testConfigure.cxx - testSystemTools.cxx - testCommandLineArguments.cxx - testCommandLineArguments1.cxx - testDirectory.cxx - ) - IF(KWSYS_STL_HAS_WSTRING) - SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} - testEncoding.cxx - ) - ENDIF() - IF(KWSYS_USE_FStream) - SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} - testFStream.cxx - ) - ENDIF() - IF(KWSYS_USE_ConsoleBuf) - ADD_EXECUTABLE(testConsoleBufChild testConsoleBufChild.cxx) - SET_PROPERTY(TARGET testConsoleBufChild PROPERTY C_CLANG_TIDY "") - SET_PROPERTY(TARGET testConsoleBufChild PROPERTY CXX_CLANG_TIDY "") - SET_PROPERTY(TARGET testConsoleBufChild PROPERTY C_INCLUDE_WHAT_YOU_USE "") - SET_PROPERTY(TARGET testConsoleBufChild PROPERTY CXX_INCLUDE_WHAT_YOU_USE "") - SET_PROPERTY(TARGET testConsoleBufChild PROPERTY LABELS ${KWSYS_LABELS_EXE}) - TARGET_LINK_LIBRARIES(testConsoleBufChild ${KWSYS_TARGET_LINK}) - SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} - testConsoleBuf.cxx - ) - IF(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND - CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "19.0.23506") - set_property(SOURCE testConsoleBuf.cxx testConsoleBufChild.cxx PROPERTY COMPILE_FLAGS /utf-8) - ENDIF() - SET_PROPERTY(SOURCE testConsoleBuf.cxx APPEND PROPERTY COMPILE_DEFINITIONS - KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE}) - ENDIF() - IF(KWSYS_USE_SystemInformation) - SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testSystemInformation.cxx) - ENDIF() - IF(KWSYS_USE_DynamicLoader) - SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testDynamicLoader.cxx) - # If kwsys contains the DynamicLoader, need extra library - ADD_LIBRARY(${KWSYS_NAMESPACE}TestDynload MODULE testDynload.c) - SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestDynload PROPERTY LABELS ${KWSYS_LABELS_LIB}) - ADD_DEPENDENCIES(${KWSYS_NAMESPACE}TestDynload ${KWSYS_TARGET_INTERFACE}) - - if (WIN32) - # Windows tests supported flags. - add_library(${KWSYS_NAMESPACE}TestDynloadImpl SHARED testDynloadImpl.c) - set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadImpl PROPERTY LABELS ${KWSYS_LABELS_LIB}) - set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadImpl PROPERTY DEFINE_SYMBOL BUILDING_TestDynloadImpl) - set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadImpl PROPERTY RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynloaddir") - add_dependencies(${KWSYS_NAMESPACE}TestDynloadImpl ${KWSYS_TARGET_INTERFACE}) - add_library(${KWSYS_NAMESPACE}TestDynloadUse MODULE testDynloadUse.c) - set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadUse PROPERTY LABELS ${KWSYS_LABELS_LIB}) - set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadUse PROPERTY LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynloaddir") - add_dependencies(${KWSYS_NAMESPACE}TestDynloadUse ${KWSYS_TARGET_INTERFACE}) - target_link_libraries(${KWSYS_NAMESPACE}TestDynloadUse PRIVATE ${KWSYS_NAMESPACE}TestDynloadImpl) - endif () - ENDIF() - CREATE_TEST_SOURCELIST( - KWSYS_CXX_TEST_SRCS ${KWSYS_NAMESPACE}TestsCxx.cxx - ${KWSYS_CXX_TESTS} - ) - ADD_EXECUTABLE(${KWSYS_NAMESPACE}TestsCxx ${KWSYS_CXX_TEST_SRCS}) - SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY C_CLANG_TIDY "") - SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY CXX_CLANG_TIDY "") - SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY C_INCLUDE_WHAT_YOU_USE "") - SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY CXX_INCLUDE_WHAT_YOU_USE "") - SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY LABELS ${KWSYS_LABELS_EXE}) - TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE}TestsCxx ${KWSYS_TARGET_LINK}) - - SET(TEST_SYSTEMTOOLS_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") - SET(TEST_SYSTEMTOOLS_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}") - CONFIGURE_FILE( - ${PROJECT_SOURCE_DIR}/testSystemTools.h.in - ${PROJECT_BINARY_DIR}/testSystemTools.h) - INCLUDE_DIRECTORIES(${PROJECT_BINARY_DIR}) - - IF(CTEST_TEST_KWSYS) - CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/ExtraTest.cmake.in" - "${CMAKE_CURRENT_BINARY_DIR}/ExtraTest.cmake") - SET_DIRECTORY_PROPERTIES(PROPERTIES TEST_INCLUDE_FILE "${CMAKE_CURRENT_BINARY_DIR}/ExtraTest.cmake") - ENDIF() - - SET(KWSYS_TEST_ARGS_testCommandLineArguments - --another-bool-variable - --long3=opt - --set-bool-arg1 - -SSS ken brad bill andy - --some-bool-variable=true - --some-double-variable12.5 - --some-int-variable 14 - "--some-string-variable=test string with space" - --some-multi-argument 5 1 8 3 7 1 3 9 7 1 - -N 12.5 -SS=andy -N 1.31 -N 22 - -SS=bill -BBtrue -SS=brad - -BBtrue - -BBfalse - -SS=ken - -A - -C=test - --long2 hello - ) - SET(KWSYS_TEST_ARGS_testCommandLineArguments1 - --ignored - -n 24 - --second-ignored - "-m=test value" - third-ignored - -p - some junk at the end - ) - FOREACH(testfile ${KWSYS_CXX_TESTS}) - get_filename_component(test "${testfile}" NAME_WE) - ADD_TEST(kwsys.${test} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestsCxx ${test} ${KWSYS_TEST_ARGS_${test}}) - SET_PROPERTY(TEST kwsys.${test} PROPERTY LABELS ${KWSYS_LABELS_TEST}) - ENDFOREACH() - - # Process tests. - ADD_EXECUTABLE(${KWSYS_NAMESPACE}TestProcess testProcess.c) - SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestProcess PROPERTY LABELS ${KWSYS_LABELS_EXE}) - TARGET_LINK_LIBRARIES(${KWSYS_NAMESPACE}TestProcess ${KWSYS_TARGET_C_LINK}) - IF(NOT CYGWIN) - SET(KWSYS_TEST_PROCESS_7 7) - ENDIF() - FOREACH(n 1 2 3 4 5 6 ${KWSYS_TEST_PROCESS_7} 9 10) - ADD_TEST(kwsys.testProcess-${n} ${EXEC_DIR}/${KWSYS_NAMESPACE}TestProcess ${n}) - SET_PROPERTY(TEST kwsys.testProcess-${n} PROPERTY LABELS ${KWSYS_LABELS_TEST}) - SET_TESTS_PROPERTIES(kwsys.testProcess-${n} PROPERTIES TIMEOUT 120) - ENDFOREACH() - - SET(testProcess_COMPILE_FLAGS "") - # Some Apple compilers produce bad optimizations in this source. - IF(APPLE AND CMAKE_C_COMPILER_ID MATCHES "^(GNU|LLVM)$") - SET(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -O0") - ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "XL") - # Tell IBM XL not to warn about our test infinite loop - IF(CMAKE_SYSTEM MATCHES "Linux.*ppc64le" - AND CMAKE_C_COMPILER_VERSION VERSION_LESS "16.1.0" - AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS "13.1.1") - # v13.1.[1-6] on Linux ppc64le is clang based and does not accept - # the -qsuppress option, so just suppress all warnings. - SET(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -w") - ELSE() - SET(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -qsuppress=1500-010") - ENDIF() - ENDIF() - IF(CMAKE_C_FLAGS MATCHES "-fsanitize=") - SET(testProcess_COMPILE_FLAGS "${testProcess_COMPILE_FLAGS} -DCRASH_USING_ABORT") - ENDIF() - SET_PROPERTY(SOURCE testProcess.c PROPERTY COMPILE_FLAGS "${testProcess_COMPILE_FLAGS}") - - # Test SharedForward - CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/testSharedForward.c.in - ${PROJECT_BINARY_DIR}/testSharedForward.c @ONLY IMMEDIATE) - ADD_EXECUTABLE(${KWSYS_NAMESPACE}TestSharedForward - ${PROJECT_BINARY_DIR}/testSharedForward.c) - SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestSharedForward PROPERTY LABELS ${KWSYS_LABELS_EXE}) - ADD_DEPENDENCIES(${KWSYS_NAMESPACE}TestSharedForward ${KWSYS_TARGET_C_LINK}) - ADD_TEST(kwsys.testSharedForward ${EXEC_DIR}/${KWSYS_NAMESPACE}TestSharedForward 1) - SET_PROPERTY(TEST kwsys.testSharedForward PROPERTY LABELS ${KWSYS_LABELS_TEST}) - - # Configure some test properties. - IF(KWSYS_STANDALONE) - # We expect test to fail - SET_TESTS_PROPERTIES(kwsys.testFail PROPERTIES WILL_FAIL ON) - GET_TEST_PROPERTY(kwsys.testFail WILL_FAIL wfv) - SET_TESTS_PROPERTIES(kwsys.testFail PROPERTIES MEASUREMENT "Some Key=Some Value") - MESSAGE(STATUS "GET_TEST_PROPERTY returned: ${wfv}") - ENDIF() - - # Set up ctest custom configuration file. - CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/CTestCustom.cmake.in - ${PROJECT_BINARY_DIR}/CTestCustom.cmake @ONLY) - - # Suppress known consistent failures on buggy systems. - IF(KWSYS_TEST_BOGUS_FAILURES) - SET_TESTS_PROPERTIES(${KWSYS_TEST_BOGUS_FAILURES} PROPERTIES WILL_FAIL ON) - ENDIF() - - ENDIF() -ENDIF() diff --git a/test/API/driver/kwsys/CONTRIBUTING.rst b/test/API/driver/kwsys/CONTRIBUTING.rst deleted file mode 100644 index 32e7b83..0000000 --- a/test/API/driver/kwsys/CONTRIBUTING.rst +++ /dev/null @@ -1,49 +0,0 @@ -Contributing to KWSys -********************* - -Patches -======= - -KWSys is kept in its own Git repository and shared by several projects -via copies in their source trees. Changes to KWSys should not be made -directly in a host project, except perhaps in maintenance branches. - -KWSys uses `Kitware's GitLab Instance`_ to manage development and code review. -To contribute patches: - -#. Fork the upstream `KWSys Repository`_ into a personal account. -#. Base all new work on the upstream ``master`` branch. -#. Run ``./SetupForDevelopment.sh`` in new local work trees. -#. Create commits making incremental, distinct, logically complete changes. -#. Push a topic branch to a personal repository fork on GitLab. -#. Create a GitLab Merge Request targeting the upstream ``master`` branch. - -Once changes are reviewed, tested, and integrated to KWSys upstream then -copies of KWSys within dependent projects can be updated to get the changes. - -.. _`Kitware's GitLab Instance`: https://gitlab.kitware.com -.. _`KWSys Repository`: https://gitlab.kitware.com/utils/kwsys - -Code Style -========== - -We use `clang-format`_ version **6.0** to define our style for C++ code in -the KWSys source tree. See the `.clang-format`_ configuration file for -our style settings. Use the `clang-format.bash`_ script to format source -code. It automatically runs ``clang-format`` on the set of source files -for which we enforce style. The script also has options to format only -a subset of files, such as those that are locally modified. - -.. _`clang-format`: http://clang.llvm.org/docs/ClangFormat.html -.. _`.clang-format`: .clang-format -.. _`clang-format.bash`: clang-format.bash - -License -======= - -We do not require any formal copyright assignment or contributor license -agreement. Any contributions intentionally sent upstream are presumed -to be offered under terms of the OSI-approved BSD 3-clause License. -See `Copyright.txt`_ for details. - -.. _`Copyright.txt`: Copyright.txt diff --git a/test/API/driver/kwsys/CTestConfig.cmake b/test/API/driver/kwsys/CTestConfig.cmake deleted file mode 100644 index 1339ffc..0000000 --- a/test/API/driver/kwsys/CTestConfig.cmake +++ /dev/null @@ -1,9 +0,0 @@ -# Distributed under the OSI-approved BSD 3-Clause License. See accompanying -# file Copyright.txt or https://cmake.org/licensing#kwsys for details. - -set(CTEST_PROJECT_NAME "KWSys") -set(CTEST_NIGHTLY_START_TIME "21:00:00 EDT") -set(CTEST_DROP_METHOD "http") -set(CTEST_DROP_SITE "open.cdash.org") -set(CTEST_DROP_LOCATION "/submit.php?project=KWSys") -set(CTEST_DROP_SITE_CDASH TRUE) diff --git a/test/API/driver/kwsys/CTestCustom.cmake.in b/test/API/driver/kwsys/CTestCustom.cmake.in deleted file mode 100644 index 760221b..0000000 --- a/test/API/driver/kwsys/CTestCustom.cmake.in +++ /dev/null @@ -1,14 +0,0 @@ -# kwsys.testProcess-10 involves sending SIGINT to a child process, which then -# exits abnormally via a call to _exit(). (On Windows, a call to ExitProcess). -# Naturally, this results in plenty of memory being "leaked" by this child -# process - the memory check results are not meaningful in this case. -# -# kwsys.testProcess-9 also tests sending SIGINT to a child process. However, -# normal operation of that test involves the child process timing out, and the -# host process kills (SIGKILL) it as a result. Since it was SIGKILL'ed, the -# resulting memory leaks are not logged by valgrind anyway. Therefore, we -# don't have to exclude it. - -list(APPEND CTEST_CUSTOM_MEMCHECK_IGNORE - kwsys.testProcess-10 - ) diff --git a/test/API/driver/kwsys/CommandLineArguments.cxx b/test/API/driver/kwsys/CommandLineArguments.cxx deleted file mode 100644 index 3fd1955..0000000 --- a/test/API/driver/kwsys/CommandLineArguments.cxx +++ /dev/null @@ -1,768 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include "kwsysPrivate.h" -#include KWSYS_HEADER(CommandLineArguments.hxx) - -#include KWSYS_HEADER(Configure.hxx) -#include KWSYS_HEADER(String.hxx) - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -# include "CommandLineArguments.hxx.in" -# include "Configure.hxx.in" -# include "String.hxx.in" -#endif - -#include -#include -#include -#include -#include - -#include -#include -#include - -#ifdef _MSC_VER -# pragma warning(disable : 4786) -#endif - -#if defined(__sgi) && !defined(__GNUC__) -# pragma set woff 1375 /* base class destructor not virtual */ -#endif - -#if 0 -# define CommandLineArguments_DEBUG(x) \ - std::cout << __LINE__ << " CLA: " << x << std::endl -#else -# define CommandLineArguments_DEBUG(x) -#endif - -namespace KWSYS_NAMESPACE { - -struct CommandLineArgumentsCallbackStructure -{ - const char* Argument; - int ArgumentType; - CommandLineArguments::CallbackType Callback; - void* CallData; - void* Variable; - int VariableType; - const char* Help; -}; - -class CommandLineArgumentsVectorOfStrings : public std::vector -{ -}; -class CommandLineArgumentsSetOfStrings : public std::set -{ -}; -class CommandLineArgumentsMapOfStrucs - : public std::map -{ -}; - -class CommandLineArgumentsInternal -{ -public: - CommandLineArgumentsInternal() - : UnknownArgumentCallback{ nullptr } - , ClientData{ nullptr } - , LastArgument{ 0 } - { - } - - typedef CommandLineArgumentsVectorOfStrings VectorOfStrings; - typedef CommandLineArgumentsMapOfStrucs CallbacksMap; - typedef kwsys::String String; - typedef CommandLineArgumentsSetOfStrings SetOfStrings; - - VectorOfStrings Argv; - String Argv0; - CallbacksMap Callbacks; - - CommandLineArguments::ErrorCallbackType UnknownArgumentCallback; - void* ClientData; - - VectorOfStrings::size_type LastArgument; - - VectorOfStrings UnusedArguments; -}; - -CommandLineArguments::CommandLineArguments() -{ - this->Internals = new CommandLineArguments::Internal; - this->Help = ""; - this->LineLength = 80; - this->StoreUnusedArgumentsFlag = false; -} - -CommandLineArguments::~CommandLineArguments() -{ - delete this->Internals; -} - -void CommandLineArguments::Initialize(int argc, const char* const argv[]) -{ - int cc; - - this->Initialize(); - this->Internals->Argv0 = argv[0]; - for (cc = 1; cc < argc; cc++) { - this->ProcessArgument(argv[cc]); - } -} - -void CommandLineArguments::Initialize(int argc, char* argv[]) -{ - this->Initialize(argc, static_cast(argv)); -} - -void CommandLineArguments::Initialize() -{ - this->Internals->Argv.clear(); - this->Internals->LastArgument = 0; -} - -void CommandLineArguments::ProcessArgument(const char* arg) -{ - this->Internals->Argv.push_back(arg); -} - -bool CommandLineArguments::GetMatchedArguments( - std::vector* matches, const std::string& arg) -{ - matches->clear(); - CommandLineArguments::Internal::CallbacksMap::iterator it; - - // Does the argument match to any we know about? - for (it = this->Internals->Callbacks.begin(); - it != this->Internals->Callbacks.end(); it++) { - const CommandLineArguments::Internal::String& parg = it->first; - CommandLineArgumentsCallbackStructure* cs = &it->second; - if (cs->ArgumentType == CommandLineArguments::NO_ARGUMENT || - cs->ArgumentType == CommandLineArguments::SPACE_ARGUMENT) { - if (arg == parg) { - matches->push_back(parg); - } - } else if (arg.find(parg) == 0) { - matches->push_back(parg); - } - } - return !matches->empty(); -} - -int CommandLineArguments::Parse() -{ - std::vector::size_type cc; - std::vector matches; - if (this->StoreUnusedArgumentsFlag) { - this->Internals->UnusedArguments.clear(); - } - for (cc = 0; cc < this->Internals->Argv.size(); cc++) { - const std::string& arg = this->Internals->Argv[cc]; - CommandLineArguments_DEBUG("Process argument: " << arg); - this->Internals->LastArgument = cc; - if (this->GetMatchedArguments(&matches, arg)) { - // Ok, we found one or more arguments that match what user specified. - // Let's find the longest one. - CommandLineArguments::Internal::VectorOfStrings::size_type kk; - CommandLineArguments::Internal::VectorOfStrings::size_type maxidx = 0; - CommandLineArguments::Internal::String::size_type maxlen = 0; - for (kk = 0; kk < matches.size(); kk++) { - if (matches[kk].size() > maxlen) { - maxlen = matches[kk].size(); - maxidx = kk; - } - } - // So, the longest one is probably the right one. Now see if it has any - // additional value - CommandLineArgumentsCallbackStructure* cs = - &this->Internals->Callbacks[matches[maxidx]]; - const std::string& sarg = matches[maxidx]; - if (cs->Argument != sarg) { - abort(); - } - switch (cs->ArgumentType) { - case NO_ARGUMENT: - // No value - if (!this->PopulateVariable(cs, nullptr)) { - return 0; - } - break; - case SPACE_ARGUMENT: - if (cc == this->Internals->Argv.size() - 1) { - this->Internals->LastArgument--; - return 0; - } - CommandLineArguments_DEBUG("This is a space argument: " - << arg << " value: " - << this->Internals->Argv[cc + 1]); - // Value is the next argument - if (!this->PopulateVariable(cs, - this->Internals->Argv[cc + 1].c_str())) { - return 0; - } - cc++; - break; - case EQUAL_ARGUMENT: - if (arg.size() == sarg.size() || arg.at(sarg.size()) != '=') { - this->Internals->LastArgument--; - return 0; - } - // Value is everythng followed the '=' sign - if (!this->PopulateVariable(cs, arg.c_str() + sarg.size() + 1)) { - return 0; - } - break; - case CONCAT_ARGUMENT: - // Value is whatever follows the argument - if (!this->PopulateVariable(cs, arg.c_str() + sarg.size())) { - return 0; - } - break; - case MULTI_ARGUMENT: - // Suck in all the rest of the arguments - CommandLineArguments_DEBUG("This is a multi argument: " << arg); - for (cc++; cc < this->Internals->Argv.size(); ++cc) { - const std::string& marg = this->Internals->Argv[cc]; - CommandLineArguments_DEBUG( - " check multi argument value: " << marg); - if (this->GetMatchedArguments(&matches, marg)) { - CommandLineArguments_DEBUG("End of multi argument " - << arg << " with value: " << marg); - break; - } - CommandLineArguments_DEBUG( - " populate multi argument value: " << marg); - if (!this->PopulateVariable(cs, marg.c_str())) { - return 0; - } - } - if (cc != this->Internals->Argv.size()) { - CommandLineArguments_DEBUG("Again End of multi argument " << arg); - cc--; - continue; - } - break; - default: - std::cerr << "Got unknown argument type: \"" << cs->ArgumentType - << "\"" << std::endl; - this->Internals->LastArgument--; - return 0; - } - } else { - // Handle unknown arguments - if (this->Internals->UnknownArgumentCallback) { - if (!this->Internals->UnknownArgumentCallback( - arg.c_str(), this->Internals->ClientData)) { - this->Internals->LastArgument--; - return 0; - } - return 1; - } else if (this->StoreUnusedArgumentsFlag) { - CommandLineArguments_DEBUG("Store unused argument " << arg); - this->Internals->UnusedArguments.push_back(arg); - } else { - std::cerr << "Got unknown argument: \"" << arg << "\"" << std::endl; - this->Internals->LastArgument--; - return 0; - } - } - } - return 1; -} - -void CommandLineArguments::GetRemainingArguments(int* argc, char*** argv) -{ - CommandLineArguments::Internal::VectorOfStrings::size_type size = - this->Internals->Argv.size() - this->Internals->LastArgument + 1; - CommandLineArguments::Internal::VectorOfStrings::size_type cc; - - // Copy Argv0 as the first argument - char** args = new char*[size]; - args[0] = new char[this->Internals->Argv0.size() + 1]; - strcpy(args[0], this->Internals->Argv0.c_str()); - int cnt = 1; - - // Copy everything after the LastArgument, since that was not parsed. - for (cc = this->Internals->LastArgument + 1; - cc < this->Internals->Argv.size(); cc++) { - args[cnt] = new char[this->Internals->Argv[cc].size() + 1]; - strcpy(args[cnt], this->Internals->Argv[cc].c_str()); - cnt++; - } - *argc = cnt; - *argv = args; -} - -void CommandLineArguments::GetUnusedArguments(int* argc, char*** argv) -{ - CommandLineArguments::Internal::VectorOfStrings::size_type size = - this->Internals->UnusedArguments.size() + 1; - CommandLineArguments::Internal::VectorOfStrings::size_type cc; - - // Copy Argv0 as the first argument - char** args = new char*[size]; - args[0] = new char[this->Internals->Argv0.size() + 1]; - strcpy(args[0], this->Internals->Argv0.c_str()); - int cnt = 1; - - // Copy everything after the LastArgument, since that was not parsed. - for (cc = 0; cc < this->Internals->UnusedArguments.size(); cc++) { - kwsys::String& str = this->Internals->UnusedArguments[cc]; - args[cnt] = new char[str.size() + 1]; - strcpy(args[cnt], str.c_str()); - cnt++; - } - *argc = cnt; - *argv = args; -} - -void CommandLineArguments::DeleteRemainingArguments(int argc, char*** argv) -{ - int cc; - for (cc = 0; cc < argc; ++cc) { - delete[](*argv)[cc]; - } - delete[] * argv; -} - -void CommandLineArguments::AddCallback(const char* argument, - ArgumentTypeEnum type, - CallbackType callback, void* call_data, - const char* help) -{ - CommandLineArgumentsCallbackStructure s; - s.Argument = argument; - s.ArgumentType = type; - s.Callback = callback; - s.CallData = call_data; - s.VariableType = CommandLineArguments::NO_VARIABLE_TYPE; - s.Variable = nullptr; - s.Help = help; - - this->Internals->Callbacks[argument] = s; - this->GenerateHelp(); -} - -void CommandLineArguments::AddArgument(const char* argument, - ArgumentTypeEnum type, - VariableTypeEnum vtype, void* variable, - const char* help) -{ - CommandLineArgumentsCallbackStructure s; - s.Argument = argument; - s.ArgumentType = type; - s.Callback = nullptr; - s.CallData = nullptr; - s.VariableType = vtype; - s.Variable = variable; - s.Help = help; - - this->Internals->Callbacks[argument] = s; - this->GenerateHelp(); -} - -#define CommandLineArgumentsAddArgumentMacro(type, ctype) \ - void CommandLineArguments::AddArgument(const char* argument, \ - ArgumentTypeEnum type, \ - ctype* variable, const char* help) \ - { \ - this->AddArgument(argument, type, CommandLineArguments::type##_TYPE, \ - variable, help); \ - } - -/* clang-format off */ -CommandLineArgumentsAddArgumentMacro(BOOL, bool) -CommandLineArgumentsAddArgumentMacro(INT, int) -CommandLineArgumentsAddArgumentMacro(DOUBLE, double) -CommandLineArgumentsAddArgumentMacro(STRING, char*) -CommandLineArgumentsAddArgumentMacro(STL_STRING, std::string) - -CommandLineArgumentsAddArgumentMacro(VECTOR_BOOL, std::vector) -CommandLineArgumentsAddArgumentMacro(VECTOR_INT, std::vector) -CommandLineArgumentsAddArgumentMacro(VECTOR_DOUBLE, std::vector) -CommandLineArgumentsAddArgumentMacro(VECTOR_STRING, std::vector) -CommandLineArgumentsAddArgumentMacro(VECTOR_STL_STRING, - std::vector) -#ifdef HELP_CLANG_FORMAT -; -#endif -/* clang-format on */ - -#define CommandLineArgumentsAddBooleanArgumentMacro(type, ctype) \ - void CommandLineArguments::AddBooleanArgument( \ - const char* argument, ctype* variable, const char* help) \ - { \ - this->AddArgument(argument, CommandLineArguments::NO_ARGUMENT, \ - CommandLineArguments::type##_TYPE, variable, help); \ - } - -/* clang-format off */ -CommandLineArgumentsAddBooleanArgumentMacro(BOOL, bool) -CommandLineArgumentsAddBooleanArgumentMacro(INT, int) -CommandLineArgumentsAddBooleanArgumentMacro(DOUBLE, double) -CommandLineArgumentsAddBooleanArgumentMacro(STRING, char*) -CommandLineArgumentsAddBooleanArgumentMacro(STL_STRING, std::string) -#ifdef HELP_CLANG_FORMAT -; -#endif -/* clang-format on */ - -void CommandLineArguments::SetClientData(void* client_data) -{ - this->Internals->ClientData = client_data; -} - -void CommandLineArguments::SetUnknownArgumentCallback( - CommandLineArguments::ErrorCallbackType callback) -{ - this->Internals->UnknownArgumentCallback = callback; -} - -const char* CommandLineArguments::GetHelp(const char* arg) -{ - CommandLineArguments::Internal::CallbacksMap::iterator it = - this->Internals->Callbacks.find(arg); - if (it == this->Internals->Callbacks.end()) { - return nullptr; - } - - // Since several arguments may point to the same argument, find the one this - // one point to if this one is pointing to another argument. - CommandLineArgumentsCallbackStructure* cs = &(it->second); - for (;;) { - CommandLineArguments::Internal::CallbacksMap::iterator hit = - this->Internals->Callbacks.find(cs->Help); - if (hit == this->Internals->Callbacks.end()) { - break; - } - cs = &(hit->second); - } - return cs->Help; -} - -void CommandLineArguments::SetLineLength(unsigned int ll) -{ - if (ll < 9 || ll > 1000) { - return; - } - this->LineLength = ll; - this->GenerateHelp(); -} - -const char* CommandLineArguments::GetArgv0() -{ - return this->Internals->Argv0.c_str(); -} - -unsigned int CommandLineArguments::GetLastArgument() -{ - return static_cast(this->Internals->LastArgument + 1); -} - -void CommandLineArguments::GenerateHelp() -{ - std::ostringstream str; - - // Collapse all arguments into the map of vectors of all arguments that do - // the same thing. - CommandLineArguments::Internal::CallbacksMap::iterator it; - typedef std::map - MapArgs; - MapArgs mp; - MapArgs::iterator mpit, smpit; - for (it = this->Internals->Callbacks.begin(); - it != this->Internals->Callbacks.end(); it++) { - CommandLineArgumentsCallbackStructure* cs = &(it->second); - mpit = mp.find(cs->Help); - if (mpit != mp.end()) { - mpit->second.insert(it->first); - mp[it->first].insert(it->first); - } else { - mp[it->first].insert(it->first); - } - } - for (it = this->Internals->Callbacks.begin(); - it != this->Internals->Callbacks.end(); it++) { - CommandLineArgumentsCallbackStructure* cs = &(it->second); - mpit = mp.find(cs->Help); - if (mpit != mp.end()) { - mpit->second.insert(it->first); - smpit = mp.find(it->first); - CommandLineArguments::Internal::SetOfStrings::iterator sit; - for (sit = smpit->second.begin(); sit != smpit->second.end(); sit++) { - mpit->second.insert(*sit); - } - mp.erase(smpit); - } else { - mp[it->first].insert(it->first); - } - } - - // Find the length of the longest string - CommandLineArguments::Internal::String::size_type maxlen = 0; - for (mpit = mp.begin(); mpit != mp.end(); mpit++) { - CommandLineArguments::Internal::SetOfStrings::iterator sit; - for (sit = mpit->second.begin(); sit != mpit->second.end(); sit++) { - CommandLineArguments::Internal::String::size_type clen = sit->size(); - switch (this->Internals->Callbacks[*sit].ArgumentType) { - case CommandLineArguments::NO_ARGUMENT: - clen += 0; - break; - case CommandLineArguments::CONCAT_ARGUMENT: - clen += 3; - break; - case CommandLineArguments::SPACE_ARGUMENT: - clen += 4; - break; - case CommandLineArguments::EQUAL_ARGUMENT: - clen += 4; - break; - } - if (clen > maxlen) { - maxlen = clen; - } - } - } - - CommandLineArguments::Internal::String::size_type maxstrlen = maxlen; - maxlen += 4; // For the space before and after the option - - // Print help for each option - for (mpit = mp.begin(); mpit != mp.end(); mpit++) { - CommandLineArguments::Internal::SetOfStrings::iterator sit; - for (sit = mpit->second.begin(); sit != mpit->second.end(); sit++) { - str << std::endl; - std::string argument = *sit; - switch (this->Internals->Callbacks[*sit].ArgumentType) { - case CommandLineArguments::NO_ARGUMENT: - break; - case CommandLineArguments::CONCAT_ARGUMENT: - argument += "opt"; - break; - case CommandLineArguments::SPACE_ARGUMENT: - argument += " opt"; - break; - case CommandLineArguments::EQUAL_ARGUMENT: - argument += "=opt"; - break; - case CommandLineArguments::MULTI_ARGUMENT: - argument += " opt opt ..."; - break; - } - str << " " << argument.substr(0, maxstrlen) << " "; - } - const char* ptr = this->Internals->Callbacks[mpit->first].Help; - size_t len = strlen(ptr); - int cnt = 0; - while (len > 0) { - // If argument with help is longer than line length, split it on previous - // space (or tab) and continue on the next line - CommandLineArguments::Internal::String::size_type cc; - for (cc = 0; ptr[cc]; cc++) { - if (*ptr == ' ' || *ptr == '\t') { - ptr++; - len--; - } - } - if (cnt > 0) { - for (cc = 0; cc < maxlen; cc++) { - str << " "; - } - } - CommandLineArguments::Internal::String::size_type skip = len; - if (skip > this->LineLength - maxlen) { - skip = this->LineLength - maxlen; - for (cc = skip - 1; cc > 0; cc--) { - if (ptr[cc] == ' ' || ptr[cc] == '\t') { - break; - } - } - if (cc != 0) { - skip = cc; - } - } - str.write(ptr, static_cast(skip)); - str << std::endl; - ptr += skip; - len -= skip; - cnt++; - } - } - /* - // This can help debugging help string - str << endl; - unsigned int cc; - for ( cc = 0; cc < this->LineLength; cc ++ ) - { - str << cc % 10; - } - str << endl; - */ - this->Help = str.str(); -} - -void CommandLineArguments::PopulateVariable(bool* variable, - const std::string& value) -{ - if (value == "1" || value == "ON" || value == "on" || value == "On" || - value == "TRUE" || value == "true" || value == "True" || - value == "yes" || value == "Yes" || value == "YES") { - *variable = true; - } else { - *variable = false; - } -} - -void CommandLineArguments::PopulateVariable(int* variable, - const std::string& value) -{ - char* res = nullptr; - *variable = static_cast(strtol(value.c_str(), &res, 10)); - // if ( res && *res ) - // { - // Can handle non-int - // } -} - -void CommandLineArguments::PopulateVariable(double* variable, - const std::string& value) -{ - char* res = nullptr; - *variable = strtod(value.c_str(), &res); - // if ( res && *res ) - // { - // Can handle non-double - // } -} - -void CommandLineArguments::PopulateVariable(char** variable, - const std::string& value) -{ - delete[] * variable; - *variable = new char[value.size() + 1]; - strcpy(*variable, value.c_str()); -} - -void CommandLineArguments::PopulateVariable(std::string* variable, - const std::string& value) -{ - *variable = value; -} - -void CommandLineArguments::PopulateVariable(std::vector* variable, - const std::string& value) -{ - bool val = false; - if (value == "1" || value == "ON" || value == "on" || value == "On" || - value == "TRUE" || value == "true" || value == "True" || - value == "yes" || value == "Yes" || value == "YES") { - val = true; - } - variable->push_back(val); -} - -void CommandLineArguments::PopulateVariable(std::vector* variable, - const std::string& value) -{ - char* res = nullptr; - variable->push_back(static_cast(strtol(value.c_str(), &res, 10))); - // if ( res && *res ) - // { - // Can handle non-int - // } -} - -void CommandLineArguments::PopulateVariable(std::vector* variable, - const std::string& value) -{ - char* res = nullptr; - variable->push_back(strtod(value.c_str(), &res)); - // if ( res && *res ) - // { - // Can handle non-int - // } -} - -void CommandLineArguments::PopulateVariable(std::vector* variable, - const std::string& value) -{ - char* var = new char[value.size() + 1]; - strcpy(var, value.c_str()); - variable->push_back(var); -} - -void CommandLineArguments::PopulateVariable(std::vector* variable, - const std::string& value) -{ - variable->push_back(value); -} - -bool CommandLineArguments::PopulateVariable( - CommandLineArgumentsCallbackStructure* cs, const char* value) -{ - // Call the callback - if (cs->Callback) { - if (!cs->Callback(cs->Argument, value, cs->CallData)) { - this->Internals->LastArgument--; - return 0; - } - } - CommandLineArguments_DEBUG("Set argument: " << cs->Argument << " to " - << value); - if (cs->Variable) { - std::string var = "1"; - if (value) { - var = value; - } - switch (cs->VariableType) { - case CommandLineArguments::INT_TYPE: - this->PopulateVariable(static_cast(cs->Variable), var); - break; - case CommandLineArguments::DOUBLE_TYPE: - this->PopulateVariable(static_cast(cs->Variable), var); - break; - case CommandLineArguments::STRING_TYPE: - this->PopulateVariable(static_cast(cs->Variable), var); - break; - case CommandLineArguments::STL_STRING_TYPE: - this->PopulateVariable(static_cast(cs->Variable), var); - break; - case CommandLineArguments::BOOL_TYPE: - this->PopulateVariable(static_cast(cs->Variable), var); - break; - case CommandLineArguments::VECTOR_BOOL_TYPE: - this->PopulateVariable(static_cast*>(cs->Variable), - var); - break; - case CommandLineArguments::VECTOR_INT_TYPE: - this->PopulateVariable(static_cast*>(cs->Variable), - var); - break; - case CommandLineArguments::VECTOR_DOUBLE_TYPE: - this->PopulateVariable(static_cast*>(cs->Variable), - var); - break; - case CommandLineArguments::VECTOR_STRING_TYPE: - this->PopulateVariable(static_cast*>(cs->Variable), - var); - break; - case CommandLineArguments::VECTOR_STL_STRING_TYPE: - this->PopulateVariable( - static_cast*>(cs->Variable), var); - break; - default: - std::cerr << "Got unknown variable type: \"" << cs->VariableType - << "\"" << std::endl; - this->Internals->LastArgument--; - return 0; - } - } - return 1; -} - -} // namespace KWSYS_NAMESPACE diff --git a/test/API/driver/kwsys/CommandLineArguments.hxx.in b/test/API/driver/kwsys/CommandLineArguments.hxx.in deleted file mode 100644 index 7db9015..0000000 --- a/test/API/driver/kwsys/CommandLineArguments.hxx.in +++ /dev/null @@ -1,270 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifndef @KWSYS_NAMESPACE@_CommandLineArguments_hxx -#define @KWSYS_NAMESPACE@_CommandLineArguments_hxx - -#include <@KWSYS_NAMESPACE@/Configure.h> -#include <@KWSYS_NAMESPACE@/Configure.hxx> - -#include -#include - -namespace @KWSYS_NAMESPACE@ { - -class CommandLineArgumentsInternal; -struct CommandLineArgumentsCallbackStructure; - -/** \class CommandLineArguments - * \brief Command line arguments processing code. - * - * Find specified arguments with optional options and execute specified methods - * or set given variables. - * - * The two interfaces it knows are callback based and variable based. For - * callback based, you have to register callback for particular argument using - * AddCallback method. When that argument is passed, the callback will be - * called with argument, value, and call data. For boolean (NO_ARGUMENT) - * arguments, the value is "1". If the callback returns 0 the argument parsing - * will stop with an error. - * - * For the variable interface you associate variable with each argument. When - * the argument is specified, the variable is set to the specified value casted - * to the appropriate type. For boolean (NO_ARGUMENT), the value is "1". - * - * Both interfaces can be used at the same time. - * - * Possible argument types are: - * NO_ARGUMENT - The argument takes no value : --A - * CONCAT_ARGUMENT - The argument takes value after no space : --Aval - * SPACE_ARGUMENT - The argument takes value after space : --A val - * EQUAL_ARGUMENT - The argument takes value after equal : --A=val - * MULTI_ARGUMENT - The argument takes values after space : --A val1 val2 - * val3 ... - * - * Example use: - * - * kwsys::CommandLineArguments arg; - * arg.Initialize(argc, argv); - * typedef kwsys::CommandLineArguments argT; - * arg.AddArgument("--something", argT::EQUAL_ARGUMENT, &some_variable, - * "This is help string for --something"); - * if ( !arg.Parse() ) - * { - * std::cerr << "Problem parsing arguments" << std::endl; - * res = 1; - * } - * - */ - -class @KWSYS_NAMESPACE@_EXPORT CommandLineArguments -{ -public: - CommandLineArguments(); - ~CommandLineArguments(); - - CommandLineArguments(const CommandLineArguments&) = delete; - CommandLineArguments& operator=(const CommandLineArguments&) = delete; - - /** - * Various argument types. - */ - enum ArgumentTypeEnum - { - NO_ARGUMENT, - CONCAT_ARGUMENT, - SPACE_ARGUMENT, - EQUAL_ARGUMENT, - MULTI_ARGUMENT - }; - - /** - * Various variable types. When using the variable interface, this specifies - * what type the variable is. - */ - enum VariableTypeEnum - { - NO_VARIABLE_TYPE = 0, // The variable is not specified - INT_TYPE, // The variable is integer (int) - BOOL_TYPE, // The variable is boolean (bool) - DOUBLE_TYPE, // The variable is float (double) - STRING_TYPE, // The variable is string (char*) - STL_STRING_TYPE, // The variable is string (char*) - VECTOR_INT_TYPE, // The variable is integer (int) - VECTOR_BOOL_TYPE, // The variable is boolean (bool) - VECTOR_DOUBLE_TYPE, // The variable is float (double) - VECTOR_STRING_TYPE, // The variable is string (char*) - VECTOR_STL_STRING_TYPE, // The variable is string (char*) - LAST_VARIABLE_TYPE - }; - - /** - * Prototypes for callbacks for callback interface. - */ - typedef int (*CallbackType)(const char* argument, const char* value, - void* call_data); - typedef int (*ErrorCallbackType)(const char* argument, void* client_data); - - /** - * Initialize internal data structures. This should be called before parsing. - */ - void Initialize(int argc, const char* const argv[]); - void Initialize(int argc, char* argv[]); - - /** - * Initialize internal data structure and pass arguments one by one. This is - * convenience method for use from scripting languages where argc and argv - * are not available. - */ - void Initialize(); - void ProcessArgument(const char* arg); - - /** - * This method will parse arguments and call appropriate methods. - */ - int Parse(); - - /** - * This method will add a callback for a specific argument. The arguments to - * it are argument, argument type, callback method, and call data. The - * argument help specifies the help string used with this option. The - * callback and call_data can be skipped. - */ - void AddCallback(const char* argument, ArgumentTypeEnum type, - CallbackType callback, void* call_data, const char* help); - - /** - * Add handler for argument which is going to set the variable to the - * specified value. If the argument is specified, the option is casted to the - * appropriate type. - */ - void AddArgument(const char* argument, ArgumentTypeEnum type, bool* variable, - const char* help); - void AddArgument(const char* argument, ArgumentTypeEnum type, int* variable, - const char* help); - void AddArgument(const char* argument, ArgumentTypeEnum type, - double* variable, const char* help); - void AddArgument(const char* argument, ArgumentTypeEnum type, - char** variable, const char* help); - void AddArgument(const char* argument, ArgumentTypeEnum type, - std::string* variable, const char* help); - - /** - * Add handler for argument which is going to set the variable to the - * specified value. If the argument is specified, the option is casted to the - * appropriate type. This will handle the multi argument values. - */ - void AddArgument(const char* argument, ArgumentTypeEnum type, - std::vector* variable, const char* help); - void AddArgument(const char* argument, ArgumentTypeEnum type, - std::vector* variable, const char* help); - void AddArgument(const char* argument, ArgumentTypeEnum type, - std::vector* variable, const char* help); - void AddArgument(const char* argument, ArgumentTypeEnum type, - std::vector* variable, const char* help); - void AddArgument(const char* argument, ArgumentTypeEnum type, - std::vector* variable, const char* help); - - /** - * Add handler for boolean argument. The argument does not take any option - * and if it is specified, the value of the variable is true/1, otherwise it - * is false/0. - */ - void AddBooleanArgument(const char* argument, bool* variable, - const char* help); - void AddBooleanArgument(const char* argument, int* variable, - const char* help); - void AddBooleanArgument(const char* argument, double* variable, - const char* help); - void AddBooleanArgument(const char* argument, char** variable, - const char* help); - void AddBooleanArgument(const char* argument, std::string* variable, - const char* help); - - /** - * Set the callbacks for error handling. - */ - void SetClientData(void* client_data); - void SetUnknownArgumentCallback(ErrorCallbackType callback); - - /** - * Get remaining arguments. It allocates space for argv, so you have to call - * delete[] on it. - */ - void GetRemainingArguments(int* argc, char*** argv); - void DeleteRemainingArguments(int argc, char*** argv); - - /** - * If StoreUnusedArguments is set to true, then all unknown arguments will be - * stored and the user can access the modified argc, argv without known - * arguments. - */ - void StoreUnusedArguments(bool val) { this->StoreUnusedArgumentsFlag = val; } - void GetUnusedArguments(int* argc, char*** argv); - - /** - * Return string containing help. If the argument is specified, only return - * help for that argument. - */ - const char* GetHelp() { return this->Help.c_str(); } - const char* GetHelp(const char* arg); - - /** - * Get / Set the help line length. This length is used when generating the - * help page. Default length is 80. - */ - void SetLineLength(unsigned int); - unsigned int GetLineLength(); - - /** - * Get the executable name (argv0). This is only available when using - * Initialize with argc/argv. - */ - const char* GetArgv0(); - - /** - * Get index of the last argument parsed. This is the last argument that was - * parsed ok in the original argc/argv list. - */ - unsigned int GetLastArgument(); - -protected: - void GenerateHelp(); - - //! This is internal method that registers variable with argument - void AddArgument(const char* argument, ArgumentTypeEnum type, - VariableTypeEnum vtype, void* variable, const char* help); - - bool GetMatchedArguments(std::vector* matches, - const std::string& arg); - - //! Populate individual variables - bool PopulateVariable(CommandLineArgumentsCallbackStructure* cs, - const char* value); - - //! Populate individual variables of type ... - void PopulateVariable(bool* variable, const std::string& value); - void PopulateVariable(int* variable, const std::string& value); - void PopulateVariable(double* variable, const std::string& value); - void PopulateVariable(char** variable, const std::string& value); - void PopulateVariable(std::string* variable, const std::string& value); - void PopulateVariable(std::vector* variable, const std::string& value); - void PopulateVariable(std::vector* variable, const std::string& value); - void PopulateVariable(std::vector* variable, - const std::string& value); - void PopulateVariable(std::vector* variable, - const std::string& value); - void PopulateVariable(std::vector* variable, - const std::string& value); - - typedef CommandLineArgumentsInternal Internal; - Internal* Internals; - std::string Help; - - unsigned int LineLength; - - bool StoreUnusedArgumentsFlag; -}; - -} // namespace @KWSYS_NAMESPACE@ - -#endif diff --git a/test/API/driver/kwsys/Configure.h.in b/test/API/driver/kwsys/Configure.h.in deleted file mode 100644 index 5323c57..0000000 --- a/test/API/driver/kwsys/Configure.h.in +++ /dev/null @@ -1,89 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifndef @KWSYS_NAMESPACE@_Configure_h -#define @KWSYS_NAMESPACE@_Configure_h - -/* If we are building a kwsys .c or .cxx file, let it use the kwsys - namespace. When not building a kwsys source file these macros are - temporarily defined inside the headers that use them. */ -#if defined(KWSYS_NAMESPACE) -# define kwsys_ns(x) @KWSYS_NAMESPACE@##x -# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT -#endif - -/* Disable some warnings inside kwsys source files. */ -#if defined(KWSYS_NAMESPACE) -# if defined(__BORLANDC__) -# pragma warn - 8027 /* function not inlined. */ -# endif -# if defined(__INTEL_COMPILER) -# pragma warning(disable : 1572) /* floating-point equality test */ -# endif -# if defined(__sgi) && !defined(__GNUC__) -# pragma set woff 3970 /* pointer to int conversion */ -# pragma set woff 3968 /* 64 bit conversion */ -# endif -#endif - -/* Whether kwsys namespace is "kwsys". */ -#define @KWSYS_NAMESPACE@_NAME_IS_KWSYS @KWSYS_NAME_IS_KWSYS@ - -/* Setup the export macro. */ -#if @KWSYS_BUILD_SHARED@ -# if defined(_WIN32) || defined(__CYGWIN__) -# if defined(@KWSYS_NAMESPACE@_EXPORTS) -# define @KWSYS_NAMESPACE@_EXPORT __declspec(dllexport) -# else -# define @KWSYS_NAMESPACE@_EXPORT __declspec(dllimport) -# endif -# elif __GNUC__ >= 4 -# define @KWSYS_NAMESPACE@_EXPORT __attribute__((visibility("default"))) -# else -# define @KWSYS_NAMESPACE@_EXPORT -# endif -#else -# define @KWSYS_NAMESPACE@_EXPORT -#endif - -/* Enable warnings that are off by default but are useful. */ -#if !defined(@KWSYS_NAMESPACE@_NO_WARNING_ENABLE) -# if defined(_MSC_VER) -# pragma warning(default : 4263) /* no override, call convention differs \ - */ -# endif -#endif - -/* Disable warnings that are on by default but occur in valid code. */ -#if !defined(@KWSYS_NAMESPACE@_NO_WARNING_DISABLE) -# if defined(_MSC_VER) -# pragma warning(disable : 4097) /* typedef is synonym for class */ -# pragma warning(disable : 4127) /* conditional expression is constant */ -# pragma warning(disable : 4244) /* possible loss in conversion */ -# pragma warning(disable : 4251) /* missing DLL-interface */ -# pragma warning(disable : 4305) /* truncation from type1 to type2 */ -# pragma warning(disable : 4309) /* truncation of constant value */ -# pragma warning(disable : 4514) /* unreferenced inline function */ -# pragma warning(disable : 4706) /* assignment in conditional expression \ - */ -# pragma warning(disable : 4710) /* function not inlined */ -# pragma warning(disable : 4786) /* identifier truncated in debug info */ -# endif -# if defined(__BORLANDC__) && !defined(__cplusplus) -/* Code has no effect; raised by winnt.h in C (not C++) when ignoring an - unused parameter using "(param)" syntax (i.e. no cast to void). */ -# pragma warn - 8019 -# endif -#endif - -/* MSVC 6.0 in release mode will warn about code it produces with its - optimizer. Disable the warnings specifically for this - configuration. Real warnings will be revealed by a debug build or - by other compilers. */ -#if !defined(@KWSYS_NAMESPACE@_NO_WARNING_DISABLE_BOGUS) -# if defined(_MSC_VER) && (_MSC_VER < 1300) && defined(NDEBUG) -# pragma warning(disable : 4701) /* Variable may be used uninitialized. */ -# pragma warning(disable : 4702) /* Unreachable code. */ -# endif -#endif - -#endif diff --git a/test/API/driver/kwsys/Configure.hxx.in b/test/API/driver/kwsys/Configure.hxx.in deleted file mode 100644 index 29a2dd1..0000000 --- a/test/API/driver/kwsys/Configure.hxx.in +++ /dev/null @@ -1,65 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifndef @KWSYS_NAMESPACE@_Configure_hxx -#define @KWSYS_NAMESPACE@_Configure_hxx - -/* Include C configuration. */ -#include <@KWSYS_NAMESPACE@/Configure.h> - -/* Whether wstring is available. */ -#define @KWSYS_NAMESPACE@_STL_HAS_WSTRING @KWSYS_STL_HAS_WSTRING@ -/* Whether is available. */ -#define @KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H \ - @KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H@ -/* Whether the translation map is available or not. */ -#define @KWSYS_NAMESPACE@_SYSTEMTOOLS_USE_TRANSLATION_MAP \ - @KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP@ - -#if defined(__SUNPRO_CC) && __SUNPRO_CC > 0x5130 && defined(__has_attribute) -# define @KWSYS_NAMESPACE@__has_cpp_attribute(x) __has_attribute(x) -#elif defined(__has_cpp_attribute) -# define @KWSYS_NAMESPACE@__has_cpp_attribute(x) __has_cpp_attribute(x) -#else -# define @KWSYS_NAMESPACE@__has_cpp_attribute(x) 0 -#endif - -#if __cplusplus >= 201103L -# define @KWSYS_NAMESPACE@_NULLPTR nullptr -#else -# define @KWSYS_NAMESPACE@_NULLPTR 0 -#endif - -#ifndef @KWSYS_NAMESPACE@_FALLTHROUGH -# if __cplusplus >= 201703L && \ - @KWSYS_NAMESPACE@__has_cpp_attribute(fallthrough) -# define @KWSYS_NAMESPACE@_FALLTHROUGH [[fallthrough]] -# elif __cplusplus >= 201103L && \ - @KWSYS_NAMESPACE@__has_cpp_attribute(gnu::fallthrough) -# define @KWSYS_NAMESPACE@_FALLTHROUGH [[gnu::fallthrough]] -# elif __cplusplus >= 201103L && \ - @KWSYS_NAMESPACE@__has_cpp_attribute(clang::fallthrough) -# define @KWSYS_NAMESPACE@_FALLTHROUGH [[clang::fallthrough]] -# endif -#endif -#ifndef @KWSYS_NAMESPACE@_FALLTHROUGH -# define @KWSYS_NAMESPACE@_FALLTHROUGH static_cast(0) -#endif - -#undef @KWSYS_NAMESPACE@__has_cpp_attribute - -/* If building a C++ file in kwsys itself, give the source file - access to the macros without a configured namespace. */ -#if defined(KWSYS_NAMESPACE) -# if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS -# define kwsys @KWSYS_NAMESPACE@ -# endif -# define KWSYS_NAME_IS_KWSYS @KWSYS_NAMESPACE@_NAME_IS_KWSYS -# define KWSYS_STL_HAS_WSTRING @KWSYS_NAMESPACE@_STL_HAS_WSTRING -# define KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H \ - @KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H -# define KWSYS_FALLTHROUGH @KWSYS_NAMESPACE@_FALLTHROUGH -# define KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP \ - @KWSYS_NAMESPACE@_SYSTEMTOOLS_USE_TRANSLATION_MAP -#endif - -#endif diff --git a/test/API/driver/kwsys/ConsoleBuf.hxx.in b/test/API/driver/kwsys/ConsoleBuf.hxx.in deleted file mode 100644 index 49dbdf7..0000000 --- a/test/API/driver/kwsys/ConsoleBuf.hxx.in +++ /dev/null @@ -1,398 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifndef @KWSYS_NAMESPACE@_ConsoleBuf_hxx -#define @KWSYS_NAMESPACE@_ConsoleBuf_hxx - -#include <@KWSYS_NAMESPACE@/Configure.hxx> - -#include <@KWSYS_NAMESPACE@/Encoding.hxx> - -#include -#include -#include -#include -#include -#include - -#if defined(_WIN32) -# include -# if __cplusplus >= 201103L -# include -# endif -#endif - -namespace @KWSYS_NAMESPACE@ { -#if defined(_WIN32) - -template > -class BasicConsoleBuf : public std::basic_streambuf -{ -public: - typedef typename Traits::int_type int_type; - typedef typename Traits::char_type char_type; - - class Manager - { - public: - Manager(std::basic_ios& ios, const bool err = false) - : m_consolebuf(0) - { - m_ios = &ios; - try { - m_consolebuf = new BasicConsoleBuf(err); - m_streambuf = m_ios->rdbuf(m_consolebuf); - } catch (const std::runtime_error& ex) { - std::cerr << "Failed to create ConsoleBuf!" << std::endl - << ex.what() << std::endl; - }; - } - - BasicConsoleBuf* GetConsoleBuf() { return m_consolebuf; } - - void SetUTF8Pipes() - { - if (m_consolebuf) { - m_consolebuf->input_pipe_codepage = CP_UTF8; - m_consolebuf->output_pipe_codepage = CP_UTF8; - m_consolebuf->activateCodepageChange(); - } - } - - ~Manager() - { - if (m_consolebuf) { - delete m_consolebuf; - m_ios->rdbuf(m_streambuf); - } - } - - private: - std::basic_ios* m_ios; - std::basic_streambuf* m_streambuf; - BasicConsoleBuf* m_consolebuf; - }; - - BasicConsoleBuf(const bool err = false) - : flush_on_newline(true) - , input_pipe_codepage(0) - , output_pipe_codepage(0) - , input_file_codepage(CP_UTF8) - , output_file_codepage(CP_UTF8) - , m_consolesCodepage(0) - { - m_hInput = ::GetStdHandle(STD_INPUT_HANDLE); - checkHandle(true, "STD_INPUT_HANDLE"); - if (!setActiveInputCodepage()) { - throw std::runtime_error("setActiveInputCodepage failed!"); - } - m_hOutput = err ? ::GetStdHandle(STD_ERROR_HANDLE) - : ::GetStdHandle(STD_OUTPUT_HANDLE); - checkHandle(false, err ? "STD_ERROR_HANDLE" : "STD_OUTPUT_HANDLE"); - if (!setActiveOutputCodepage()) { - throw std::runtime_error("setActiveOutputCodepage failed!"); - } - _setg(); - _setp(); - } - - ~BasicConsoleBuf() throw() { sync(); } - - bool activateCodepageChange() - { - return setActiveInputCodepage() && setActiveOutputCodepage(); - } - -protected: - virtual int sync() - { - bool success = true; - if (m_hInput && m_isConsoleInput && - ::FlushConsoleInputBuffer(m_hInput) == 0) { - success = false; - } - if (m_hOutput && !m_obuffer.empty()) { - const std::wstring wbuffer = getBuffer(m_obuffer); - if (m_isConsoleOutput) { - DWORD charsWritten; - success = - ::WriteConsoleW(m_hOutput, wbuffer.c_str(), (DWORD)wbuffer.size(), - &charsWritten, nullptr) == 0 - ? false - : true; - } else { - DWORD bytesWritten; - std::string buffer; - success = encodeOutputBuffer(wbuffer, buffer); - if (success) { - success = - ::WriteFile(m_hOutput, buffer.c_str(), (DWORD)buffer.size(), - &bytesWritten, nullptr) == 0 - ? false - : true; - } - } - } - m_ibuffer.clear(); - m_obuffer.clear(); - _setg(); - _setp(); - return success ? 0 : -1; - } - - virtual int_type underflow() - { - if (this->gptr() >= this->egptr()) { - if (!m_hInput) { - _setg(true); - return Traits::eof(); - } - if (m_isConsoleInput) { - // ReadConsole doesn't tell if there's more input available - // don't support reading more characters than this - wchar_t wbuffer[8192]; - DWORD charsRead; - if (ReadConsoleW(m_hInput, wbuffer, - (sizeof(wbuffer) / sizeof(wbuffer[0])), &charsRead, - nullptr) == 0 || - charsRead == 0) { - _setg(true); - return Traits::eof(); - } - setBuffer(std::wstring(wbuffer, charsRead), m_ibuffer); - } else { - std::wstring wbuffer; - std::string strbuffer; - DWORD bytesRead; - LARGE_INTEGER size; - if (GetFileSizeEx(m_hInput, &size) == 0) { - _setg(true); - return Traits::eof(); - } - char* buffer = new char[size.LowPart]; - while (ReadFile(m_hInput, buffer, size.LowPart, &bytesRead, nullptr) == - 0) { - if (GetLastError() == ERROR_MORE_DATA) { - strbuffer += std::string(buffer, bytesRead); - continue; - } - _setg(true); - delete[] buffer; - return Traits::eof(); - } - if (bytesRead > 0) { - strbuffer += std::string(buffer, bytesRead); - } - delete[] buffer; - if (!decodeInputBuffer(strbuffer, wbuffer)) { - _setg(true); - return Traits::eof(); - } - setBuffer(wbuffer, m_ibuffer); - } - _setg(); - } - return Traits::to_int_type(*this->gptr()); - } - - virtual int_type overflow(int_type ch = Traits::eof()) - { - if (!Traits::eq_int_type(ch, Traits::eof())) { - char_type chr = Traits::to_char_type(ch); - m_obuffer += chr; - if ((flush_on_newline && Traits::eq(chr, '\n')) || - Traits::eq_int_type(ch, 0x00)) { - sync(); - } - return ch; - } - sync(); - return Traits::eof(); - } - -public: - bool flush_on_newline; - UINT input_pipe_codepage; - UINT output_pipe_codepage; - UINT input_file_codepage; - UINT output_file_codepage; - -private: - HANDLE m_hInput; - HANDLE m_hOutput; - std::basic_string m_ibuffer; - std::basic_string m_obuffer; - bool m_isConsoleInput; - bool m_isConsoleOutput; - UINT m_activeInputCodepage; - UINT m_activeOutputCodepage; - UINT m_consolesCodepage; - void checkHandle(bool input, std::string handleName) - { - if ((input && m_hInput == INVALID_HANDLE_VALUE) || - (!input && m_hOutput == INVALID_HANDLE_VALUE)) { - std::string errmsg = - "GetStdHandle(" + handleName + ") returned INVALID_HANDLE_VALUE"; -# if __cplusplus >= 201103L - throw std::system_error(::GetLastError(), std::system_category(), - errmsg); -# else - throw std::runtime_error(errmsg); -# endif - } - } - UINT getConsolesCodepage() - { - if (!m_consolesCodepage) { - m_consolesCodepage = GetConsoleCP(); - if (!m_consolesCodepage) { - m_consolesCodepage = GetACP(); - } - } - return m_consolesCodepage; - } - bool setActiveInputCodepage() - { - m_isConsoleInput = false; - switch (GetFileType(m_hInput)) { - case FILE_TYPE_DISK: - m_activeInputCodepage = input_file_codepage; - break; - case FILE_TYPE_CHAR: - // Check for actual console. - DWORD consoleMode; - m_isConsoleInput = - GetConsoleMode(m_hInput, &consoleMode) == 0 ? false : true; - if (m_isConsoleInput) { - break; - } - @KWSYS_NAMESPACE@_FALLTHROUGH; - case FILE_TYPE_PIPE: - m_activeInputCodepage = input_pipe_codepage; - break; - default: - return false; - } - if (!m_isConsoleInput && m_activeInputCodepage == 0) { - m_activeInputCodepage = getConsolesCodepage(); - } - return true; - } - bool setActiveOutputCodepage() - { - m_isConsoleOutput = false; - switch (GetFileType(m_hOutput)) { - case FILE_TYPE_DISK: - m_activeOutputCodepage = output_file_codepage; - break; - case FILE_TYPE_CHAR: - // Check for actual console. - DWORD consoleMode; - m_isConsoleOutput = - GetConsoleMode(m_hOutput, &consoleMode) == 0 ? false : true; - if (m_isConsoleOutput) { - break; - } - @KWSYS_NAMESPACE@_FALLTHROUGH; - case FILE_TYPE_PIPE: - m_activeOutputCodepage = output_pipe_codepage; - break; - default: - return false; - } - if (!m_isConsoleOutput && m_activeOutputCodepage == 0) { - m_activeOutputCodepage = getConsolesCodepage(); - } - return true; - } - void _setg(bool empty = false) - { - if (!empty) { - this->setg((char_type*)m_ibuffer.data(), (char_type*)m_ibuffer.data(), - (char_type*)m_ibuffer.data() + m_ibuffer.size()); - } else { - this->setg((char_type*)m_ibuffer.data(), - (char_type*)m_ibuffer.data() + m_ibuffer.size(), - (char_type*)m_ibuffer.data() + m_ibuffer.size()); - } - } - void _setp() - { - this->setp((char_type*)m_obuffer.data(), - (char_type*)m_obuffer.data() + m_obuffer.size()); - } - bool encodeOutputBuffer(const std::wstring wbuffer, std::string& buffer) - { - if (wbuffer.size() == 0) { - buffer = std::string(); - return true; - } - const int length = - WideCharToMultiByte(m_activeOutputCodepage, 0, wbuffer.c_str(), - (int)wbuffer.size(), nullptr, 0, nullptr, nullptr); - char* buf = new char[length]; - const bool success = - WideCharToMultiByte(m_activeOutputCodepage, 0, wbuffer.c_str(), - (int)wbuffer.size(), buf, length, nullptr, - nullptr) > 0 - ? true - : false; - buffer = std::string(buf, length); - delete[] buf; - return success; - } - bool decodeInputBuffer(const std::string buffer, std::wstring& wbuffer) - { - size_t length = buffer.length(); - if (length == 0) { - wbuffer = std::wstring(); - return true; - } - int actualCodepage = m_activeInputCodepage; - const char BOM_UTF8[] = { char(0xEF), char(0xBB), char(0xBF) }; - const char* data = buffer.data(); - const size_t BOMsize = sizeof(BOM_UTF8); - if (length >= BOMsize && std::memcmp(data, BOM_UTF8, BOMsize) == 0) { - // PowerShell uses UTF-8 with BOM for pipes - actualCodepage = CP_UTF8; - data += BOMsize; - length -= BOMsize; - } - const size_t wlength = static_cast(MultiByteToWideChar( - actualCodepage, 0, data, static_cast(length), nullptr, 0)); - wchar_t* wbuf = new wchar_t[wlength]; - const bool success = - MultiByteToWideChar(actualCodepage, 0, data, static_cast(length), - wbuf, static_cast(wlength)) > 0 - ? true - : false; - wbuffer = std::wstring(wbuf, wlength); - delete[] wbuf; - return success; - } - std::wstring getBuffer(const std::basic_string buffer) - { - return Encoding::ToWide(buffer); - } - std::wstring getBuffer(const std::basic_string buffer) - { - return buffer; - } - void setBuffer(const std::wstring wbuffer, std::basic_string& target) - { - target = Encoding::ToNarrow(wbuffer); - } - void setBuffer(const std::wstring wbuffer, - std::basic_string& target) - { - target = wbuffer; - } - -}; // BasicConsoleBuf class - -typedef BasicConsoleBuf ConsoleBuf; -typedef BasicConsoleBuf WConsoleBuf; - -#endif -} // KWSYS_NAMESPACE - -#endif diff --git a/test/API/driver/kwsys/Copyright.txt b/test/API/driver/kwsys/Copyright.txt deleted file mode 100644 index 33d7fb4..0000000 --- a/test/API/driver/kwsys/Copyright.txt +++ /dev/null @@ -1,38 +0,0 @@ -KWSys - Kitware System Library -Copyright 2000-2016 Kitware, Inc. and Contributors -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -* Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -* Neither the name of Kitware, Inc. nor the names of Contributors - may be used to endorse or promote products derived from this - software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------------------------- - -The following individuals and institutions are among the Contributors: - -* Insight Software Consortium - -See version control history for details of individual contributions. diff --git a/test/API/driver/kwsys/Directory.cxx b/test/API/driver/kwsys/Directory.cxx deleted file mode 100644 index e379182..0000000 --- a/test/API/driver/kwsys/Directory.cxx +++ /dev/null @@ -1,236 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include "kwsysPrivate.h" -#include KWSYS_HEADER(Directory.hxx) - -#include KWSYS_HEADER(Configure.hxx) - -#include KWSYS_HEADER(Encoding.hxx) - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -# include "Configure.hxx.in" -# include "Directory.hxx.in" -# include "Encoding.hxx.in" -#endif - -#include -#include - -namespace KWSYS_NAMESPACE { - -class DirectoryInternals -{ -public: - // Array of Files - std::vector Files; - - // Path to Open'ed directory - std::string Path; -}; - -Directory::Directory() -{ - this->Internal = new DirectoryInternals; -} - -Directory::~Directory() -{ - delete this->Internal; -} - -unsigned long Directory::GetNumberOfFiles() const -{ - return static_cast(this->Internal->Files.size()); -} - -const char* Directory::GetFile(unsigned long dindex) const -{ - if (dindex >= this->Internal->Files.size()) { - return nullptr; - } - return this->Internal->Files[dindex].c_str(); -} - -const char* Directory::GetPath() const -{ - return this->Internal->Path.c_str(); -} - -void Directory::Clear() -{ - this->Internal->Path.resize(0); - this->Internal->Files.clear(); -} - -} // namespace KWSYS_NAMESPACE - -// First Windows platforms - -#if defined(_WIN32) && !defined(__CYGWIN__) -# include - -# include -# include -# include -# include -# include -# include -# include -# include - -// Wide function names can vary depending on compiler: -# ifdef __BORLANDC__ -# define _wfindfirst_func __wfindfirst -# define _wfindnext_func __wfindnext -# else -# define _wfindfirst_func _wfindfirst -# define _wfindnext_func _wfindnext -# endif - -namespace KWSYS_NAMESPACE { - -bool Directory::Load(const std::string& name) -{ - this->Clear(); -# if (defined(_MSC_VER) && _MSC_VER < 1300) || defined(__BORLANDC__) - // Older Visual C++ and Embarcadero compilers. - long srchHandle; -# else // Newer Visual C++ - intptr_t srchHandle; -# endif - char* buf; - size_t n = name.size(); - if (name.back() == '/' || name.back() == '\\') { - buf = new char[n + 1 + 1]; - sprintf(buf, "%s*", name.c_str()); - } else { - // Make sure the slashes in the wildcard suffix are consistent with the - // rest of the path - buf = new char[n + 2 + 1]; - if (name.find('\\') != std::string::npos) { - sprintf(buf, "%s\\*", name.c_str()); - } else { - sprintf(buf, "%s/*", name.c_str()); - } - } - struct _wfinddata_t data; // data of current file - - // Now put them into the file array - srchHandle = _wfindfirst_func( - (wchar_t*)Encoding::ToWindowsExtendedPath(buf).c_str(), &data); - delete[] buf; - - if (srchHandle == -1) { - return 0; - } - - // Loop through names - do { - this->Internal->Files.push_back(Encoding::ToNarrow(data.name)); - } while (_wfindnext_func(srchHandle, &data) != -1); - this->Internal->Path = name; - return _findclose(srchHandle) != -1; -} - -unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name) -{ -# if (defined(_MSC_VER) && _MSC_VER < 1300) || defined(__BORLANDC__) - // Older Visual C++ and Embarcadero compilers. - long srchHandle; -# else // Newer Visual C++ - intptr_t srchHandle; -# endif - char* buf; - size_t n = name.size(); - if (name.back() == '/') { - buf = new char[n + 1 + 1]; - sprintf(buf, "%s*", name.c_str()); - } else { - buf = new char[n + 2 + 1]; - sprintf(buf, "%s/*", name.c_str()); - } - struct _wfinddata_t data; // data of current file - - // Now put them into the file array - srchHandle = - _wfindfirst_func((wchar_t*)Encoding::ToWide(buf).c_str(), &data); - delete[] buf; - - if (srchHandle == -1) { - return 0; - } - - // Loop through names - unsigned long count = 0; - do { - count++; - } while (_wfindnext_func(srchHandle, &data) != -1); - _findclose(srchHandle); - return count; -} - -} // namespace KWSYS_NAMESPACE - -#else - -// Now the POSIX style directory access - -# include - -# include - -// PGI with glibc has trouble with dirent and large file support: -// http://www.pgroup.com/userforum/viewtopic.php? -// p=1992&sid=f16167f51964f1a68fe5041b8eb213b6 -// Work around the problem by mapping dirent the same way as readdir. -# if defined(__PGI) && defined(__GLIBC__) -# define kwsys_dirent_readdir dirent -# define kwsys_dirent_readdir64 dirent64 -# define kwsys_dirent kwsys_dirent_lookup(readdir) -# define kwsys_dirent_lookup(x) kwsys_dirent_lookup_delay(x) -# define kwsys_dirent_lookup_delay(x) kwsys_dirent_##x -# else -# define kwsys_dirent dirent -# endif - -namespace KWSYS_NAMESPACE { - -bool Directory::Load(const std::string& name) -{ - this->Clear(); - - DIR* dir = opendir(name.c_str()); - - if (!dir) { - return 0; - } - - for (kwsys_dirent* d = readdir(dir); d; d = readdir(dir)) { - this->Internal->Files.push_back(d->d_name); - } - this->Internal->Path = name; - closedir(dir); - return 1; -} - -unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name) -{ - DIR* dir = opendir(name.c_str()); - - if (!dir) { - return 0; - } - - unsigned long count = 0; - for (kwsys_dirent* d = readdir(dir); d; d = readdir(dir)) { - count++; - } - closedir(dir); - return count; -} - -} // namespace KWSYS_NAMESPACE - -#endif diff --git a/test/API/driver/kwsys/Directory.hxx.in b/test/API/driver/kwsys/Directory.hxx.in deleted file mode 100644 index ad8c51b..0000000 --- a/test/API/driver/kwsys/Directory.hxx.in +++ /dev/null @@ -1,72 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifndef @KWSYS_NAMESPACE@_Directory_hxx -#define @KWSYS_NAMESPACE@_Directory_hxx - -#include <@KWSYS_NAMESPACE@/Configure.h> - -#include - -namespace @KWSYS_NAMESPACE@ { - -class DirectoryInternals; - -/** \class Directory - * \brief Portable directory/filename traversal. - * - * Directory provides a portable way of finding the names of the files - * in a system directory. - * - * Directory currently works with Windows and Unix operating systems. - */ -class @KWSYS_NAMESPACE@_EXPORT Directory -{ -public: - Directory(); - ~Directory(); - - /** - * Load the specified directory and load the names of the files - * in that directory. 0 is returned if the directory can not be - * opened, 1 if it is opened. - */ - bool Load(const std::string&); - - /** - * Return the number of files in the current directory. - */ - unsigned long GetNumberOfFiles() const; - - /** - * Return the number of files in the specified directory. - * A higher performance static method. - */ - static unsigned long GetNumberOfFilesInDirectory(const std::string&); - - /** - * Return the file at the given index, the indexing is 0 based - */ - const char* GetFile(unsigned long) const; - - /** - * Return the path to Open'ed directory - */ - const char* GetPath() const; - - /** - * Clear the internal structure. Used internally at beginning of Load(...) - * to clear the cache. - */ - void Clear(); - -private: - // Private implementation details. - DirectoryInternals* Internal; - - Directory(const Directory&); // Not implemented. - void operator=(const Directory&); // Not implemented. -}; // End Class: Directory - -} // namespace @KWSYS_NAMESPACE@ - -#endif diff --git a/test/API/driver/kwsys/DynamicLoader.cxx b/test/API/driver/kwsys/DynamicLoader.cxx deleted file mode 100644 index a4b8641..0000000 --- a/test/API/driver/kwsys/DynamicLoader.cxx +++ /dev/null @@ -1,495 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#if defined(_WIN32) -# define NOMINMAX // hide min,max to not conflict with -#endif - -#include "kwsysPrivate.h" -#include KWSYS_HEADER(DynamicLoader.hxx) - -#include KWSYS_HEADER(Configure.hxx) -#include KWSYS_HEADER(Encoding.hxx) - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -# include "Configure.hxx.in" -# include "DynamicLoader.hxx.in" -#endif - -// This file actually contains several different implementations: -// * NOOP for environments without dynamic libs -// * HP machines which uses shl_load -// * Mac OS X 10.2.x and earlier which uses NSLinkModule -// * Windows which uses LoadLibrary -// * BeOS / Haiku -// * FreeMiNT for Atari -// * Default implementation for *NIX systems (including Mac OS X 10.3 and -// later) which use dlopen -// -// Each part of the ifdef contains a complete implementation for -// the static methods of DynamicLoader. - -#define CHECK_OPEN_FLAGS(var, supported, ret) \ - do { \ - /* Check for unknown flags. */ \ - if ((var & AllOpenFlags) != var) { \ - return ret; \ - } \ - \ - /* Check for unsupported flags. */ \ - if ((var & (supported)) != var) { \ - return ret; \ - } \ - } while (0) - -namespace KWSYS_NAMESPACE { - -DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( - const std::string& libname) -{ - return DynamicLoader::OpenLibrary(libname, 0); -} -} - -#if !KWSYS_SUPPORTS_SHARED_LIBS -// Implementation for environments without dynamic libs -# include // for strerror() - -namespace KWSYS_NAMESPACE { - -DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( - const std::string& libname, int flags) -{ - return 0; -} - -int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) -{ - if (!lib) { - return 0; - } - - return 1; -} - -DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( - DynamicLoader::LibraryHandle lib, const std::string& sym) -{ - return 0; -} - -const char* DynamicLoader::LastError() -{ - return "General error"; -} - -} // namespace KWSYS_NAMESPACE - -#elif defined(__hpux) -// Implementation for HPUX machines -# include -# include - -namespace KWSYS_NAMESPACE { - -DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( - const std::string& libname, int flags) -{ - CHECK_OPEN_FLAGS(flags, 0, 0); - - return shl_load(libname.c_str(), BIND_DEFERRED | DYNAMIC_PATH, 0L); -} - -int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) -{ - if (!lib) { - return 0; - } - return !shl_unload(lib); -} - -DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( - DynamicLoader::LibraryHandle lib, const std::string& sym) -{ - void* addr; - int status; - - /* TYPE_PROCEDURE Look for a function or procedure. (This used to be default) - * TYPE_DATA Look for a symbol in the data segment (for example, - * variables). - * TYPE_UNDEFINED Look for any symbol. - */ - status = shl_findsym(&lib, sym.c_str(), TYPE_UNDEFINED, &addr); - void* result = (status < 0) ? (void*)0 : addr; - - // Hack to cast pointer-to-data to pointer-to-function. - return *reinterpret_cast(&result); -} - -const char* DynamicLoader::LastError() -{ - // TODO: Need implementation with errno/strerror - /* If successful, shl_findsym returns an integer (int) value zero. If - * shl_findsym cannot find sym, it returns -1 and sets errno to zero. - * If any other errors occur, shl_findsym returns -1 and sets errno to one - * of these values (defined in ): - * ENOEXEC - * A format error was detected in the specified library. - * ENOSYM - * A symbol on which sym depends could not be found. - * EINVAL - * The specified handle is invalid. - */ - - if (errno == ENOEXEC || errno == ENOSYM || errno == EINVAL) { - return strerror(errno); - } - // else - return 0; -} - -} // namespace KWSYS_NAMESPACE - -#elif defined(__APPLE__) && (MAC_OS_X_VERSION_MAX_ALLOWED < 1030) -// Implementation for Mac OS X 10.2.x and earlier -# include -# include // for strlen - -namespace KWSYS_NAMESPACE { - -DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( - const std::string& libname, int flags) -{ - CHECK_OPEN_FLAGS(flags, 0, 0); - - NSObjectFileImageReturnCode rc; - NSObjectFileImage image = 0; - - rc = NSCreateObjectFileImageFromFile(libname.c_str(), &image); - // rc == NSObjectFileImageInappropriateFile when trying to load a dylib file - if (rc != NSObjectFileImageSuccess) { - return 0; - } - NSModule handle = NSLinkModule(image, libname.c_str(), - NSLINKMODULE_OPTION_BINDNOW | - NSLINKMODULE_OPTION_RETURN_ON_ERROR); - NSDestroyObjectFileImage(image); - return handle; -} - -int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) -{ - // NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED - // With this option the memory for the module is not deallocated - // allowing pointers into the module to still be valid. - // You should use this option instead if your code experience some problems - // reported against Panther 10.3.9 (fixed in Tiger 10.4.2 and up) - bool success = NSUnLinkModule(lib, NSUNLINKMODULE_OPTION_NONE); - return success; -} - -DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( - DynamicLoader::LibraryHandle lib, const std::string& sym) -{ - void* result = 0; - // Need to prepend symbols with '_' on Apple-gcc compilers - std::string rsym = '_' + sym; - - NSSymbol symbol = NSLookupSymbolInModule(lib, rsym.c_str()); - if (symbol) { - result = NSAddressOfSymbol(symbol); - } - - // Hack to cast pointer-to-data to pointer-to-function. - return *reinterpret_cast(&result); -} - -const char* DynamicLoader::LastError() -{ - return 0; -} - -} // namespace KWSYS_NAMESPACE - -#elif defined(_WIN32) && !defined(__CYGWIN__) -// Implementation for Windows win32 code but not cygwin -# include - -# include - -namespace KWSYS_NAMESPACE { - -DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( - const std::string& libname, int flags) -{ - CHECK_OPEN_FLAGS(flags, SearchBesideLibrary, nullptr); - - DWORD llFlags = 0; - if (flags & SearchBesideLibrary) { - llFlags |= LOAD_WITH_ALTERED_SEARCH_PATH; - } - - return LoadLibraryExW(Encoding::ToWindowsExtendedPath(libname).c_str(), - nullptr, llFlags); -} - -int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) -{ - return (int)FreeLibrary(lib); -} - -DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( - DynamicLoader::LibraryHandle lib, const std::string& sym) -{ - // TODO: The calling convention affects the name of the symbol. We - // should have a tool to help get the symbol with the desired - // calling convention. Currently we assume cdecl. - // - // Borland: - // __cdecl = "_func" (default) - // __fastcall = "@_func" - // __stdcall = "func" - // - // Watcom: - // __cdecl = "_func" - // __fastcall = "@_func@X" - // __stdcall = "_func@X" - // __watcall = "func_" (default) - // - // MSVC: - // __cdecl = "func" (default) - // __fastcall = "@_func@X" - // __stdcall = "_func@X" - // - // Note that the "@X" part of the name above is the total size (in - // bytes) of the arguments on the stack. - void* result; -# if defined(__BORLANDC__) || defined(__WATCOMC__) - // Need to prepend symbols with '_' - std::string ssym = '_' + sym; - const char* rsym = ssym.c_str(); -# else - const char* rsym = sym.c_str(); -# endif - result = (void*)GetProcAddress(lib, rsym); -// Hack to cast pointer-to-data to pointer-to-function. -# ifdef __WATCOMC__ - return *(DynamicLoader::SymbolPointer*)(&result); -# else - return *reinterpret_cast(&result); -# endif -} - -# define DYNLOAD_ERROR_BUFFER_SIZE 1024 - -const char* DynamicLoader::LastError() -{ - wchar_t lpMsgBuf[DYNLOAD_ERROR_BUFFER_SIZE + 1]; - - DWORD error = GetLastError(); - DWORD length = FormatMessageW( - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, error, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - lpMsgBuf, DYNLOAD_ERROR_BUFFER_SIZE, nullptr); - - static char str[DYNLOAD_ERROR_BUFFER_SIZE + 1]; - - if (length < 1) { - /* FormatMessage failed. Use a default message. */ - _snprintf(str, DYNLOAD_ERROR_BUFFER_SIZE, - "DynamicLoader encountered error 0x%X. " - "FormatMessage failed with error 0x%X", - error, GetLastError()); - return str; - } - - if (!WideCharToMultiByte(CP_UTF8, 0, lpMsgBuf, -1, str, - DYNLOAD_ERROR_BUFFER_SIZE, nullptr, nullptr)) { - /* WideCharToMultiByte failed. Use a default message. */ - _snprintf(str, DYNLOAD_ERROR_BUFFER_SIZE, - "DynamicLoader encountered error 0x%X. " - "WideCharToMultiByte failed with error 0x%X", - error, GetLastError()); - } - - return str; -} - -} // namespace KWSYS_NAMESPACE - -#elif defined(__BEOS__) -// Implementation for BeOS / Haiku -# include // for strerror() - -# include -# include - -namespace KWSYS_NAMESPACE { - -static image_id last_dynamic_err = B_OK; - -DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( - const std::string& libname, int flags) -{ - CHECK_OPEN_FLAGS(flags, 0, 0); - - // image_id's are integers, errors are negative. Add one just in case we - // get a valid image_id of zero (is that even possible?). - image_id rc = load_add_on(libname.c_str()); - if (rc < 0) { - last_dynamic_err = rc; - return 0; - } - - return rc + 1; -} - -int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) -{ - if (!lib) { - last_dynamic_err = B_BAD_VALUE; - return 0; - } else { - // The function dlclose() returns 0 on success, and non-zero on error. - status_t rc = unload_add_on(lib - 1); - if (rc != B_OK) { - last_dynamic_err = rc; - return 0; - } - } - - return 1; -} - -DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( - DynamicLoader::LibraryHandle lib, const std::string& sym) -{ - // Hack to cast pointer-to-data to pointer-to-function. - union - { - void* pvoid; - DynamicLoader::SymbolPointer psym; - } result; - - result.psym = nullptr; - - if (!lib) { - last_dynamic_err = B_BAD_VALUE; - } else { - // !!! FIXME: BeOS can do function-only lookups...does this ever - // !!! FIXME: actually _want_ a data symbol lookup, or was this union - // !!! FIXME: a leftover of dlsym()? (s/ANY/TEXT for functions only). - status_t rc = - get_image_symbol(lib - 1, sym.c_str(), B_SYMBOL_TYPE_ANY, &result.pvoid); - if (rc != B_OK) { - last_dynamic_err = rc; - result.psym = nullptr; - } - } - return result.psym; -} - -const char* DynamicLoader::LastError() -{ - const char* retval = strerror(last_dynamic_err); - last_dynamic_err = B_OK; - return retval; -} - -} // namespace KWSYS_NAMESPACE - -#elif defined(__MINT__) -// Implementation for FreeMiNT on Atari -# define _GNU_SOURCE /* for program_invocation_name */ -# include -# include -# include -# include - -namespace KWSYS_NAMESPACE { - -DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( - const std::string& libname, int flags) -{ - CHECK_OPEN_FLAGS(flags, 0, nullptr); - - char* name = (char*)calloc(1, libname.size() + 1); - dld_init(program_invocation_name); - strncpy(name, libname.c_str(), libname.size()); - dld_link(libname.c_str()); - return (void*)name; -} - -int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) -{ - dld_unlink_by_file((char*)lib, 0); - free(lib); - return 0; -} - -DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( - DynamicLoader::LibraryHandle lib, const std::string& sym) -{ - // Hack to cast pointer-to-data to pointer-to-function. - union - { - void* pvoid; - DynamicLoader::SymbolPointer psym; - } result; - result.pvoid = dld_get_symbol(sym.c_str()); - return result.psym; -} - -const char* DynamicLoader::LastError() -{ - return dld_strerror(dld_errno); -} - -} // namespace KWSYS_NAMESPACE - -#else -// Default implementation for *NIX systems (including Mac OS X 10.3 and -// later) which use dlopen -# include - -namespace KWSYS_NAMESPACE { - -DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( - const std::string& libname, int flags) -{ - CHECK_OPEN_FLAGS(flags, 0, nullptr); - - return dlopen(libname.c_str(), RTLD_LAZY); -} - -int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) -{ - if (lib) { - // The function dlclose() returns 0 on success, and non-zero on error. - return !dlclose(lib); - } - // else - return 0; -} - -DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( - DynamicLoader::LibraryHandle lib, const std::string& sym) -{ - // Hack to cast pointer-to-data to pointer-to-function. - union - { - void* pvoid; - DynamicLoader::SymbolPointer psym; - } result; - result.pvoid = dlsym(lib, sym.c_str()); - return result.psym; -} - -const char* DynamicLoader::LastError() -{ - return dlerror(); -} - -} // namespace KWSYS_NAMESPACE -#endif diff --git a/test/API/driver/kwsys/DynamicLoader.hxx.in b/test/API/driver/kwsys/DynamicLoader.hxx.in deleted file mode 100644 index 539c742..0000000 --- a/test/API/driver/kwsys/DynamicLoader.hxx.in +++ /dev/null @@ -1,106 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifndef @KWSYS_NAMESPACE@_DynamicLoader_hxx -#define @KWSYS_NAMESPACE@_DynamicLoader_hxx - -#include <@KWSYS_NAMESPACE@/Configure.hxx> - -#include - -#if defined(__hpux) -# include -#elif defined(_WIN32) && !defined(__CYGWIN__) -# include -#elif defined(__APPLE__) -# include -# if MAC_OS_X_VERSION_MAX_ALLOWED < 1030 -# include -# endif -#elif defined(__BEOS__) -# include -#endif - -namespace @KWSYS_NAMESPACE@ { -/** \class DynamicLoader - * \brief Portable loading of dynamic libraries or dll's. - * - * DynamicLoader provides a portable interface to loading dynamic - * libraries or dll's into a process. - * - * Directory currently works with Windows, Apple, HP-UX and Unix (POSIX) - * operating systems - * - * \warning dlopen on *nix system works the following way: - * If filename contains a slash ("/"), then it is interpreted as a (relative - * or absolute) pathname. Otherwise, the dynamic linker searches for the - * library as follows : see ld.so(8) for further details): - * Whereas this distinction does not exist on Win32. Therefore ideally you - * should be doing full path to guarantee to have a consistent way of dealing - * with dynamic loading of shared library. - * - * \warning the Cygwin implementation do not use the Win32 HMODULE. Put extra - * condition so that we can include the correct declaration (POSIX) - */ - -class @KWSYS_NAMESPACE@_EXPORT DynamicLoader -{ -public: -// Ugly stuff for library handles -// They are different on several different OS's -#if defined(__hpux) - typedef shl_t LibraryHandle; -#elif defined(_WIN32) && !defined(__CYGWIN__) - typedef HMODULE LibraryHandle; -#elif defined(__APPLE__) -# if MAC_OS_X_VERSION_MAX_ALLOWED < 1030 - typedef NSModule LibraryHandle; -# else - typedef void* LibraryHandle; -# endif -#elif defined(__BEOS__) - typedef image_id LibraryHandle; -#else // POSIX - typedef void* LibraryHandle; -#endif - - // Return type from DynamicLoader::GetSymbolAddress. - typedef void (*SymbolPointer)(); - - enum OpenFlags - { - // Search for dependent libraries beside the library being loaded. - // - // This is currently only supported on Windows. - SearchBesideLibrary = 0x00000001, - - AllOpenFlags = SearchBesideLibrary - }; - - /** Load a dynamic library into the current process. - * The returned LibraryHandle can be used to access the symbols in the - * library. The optional second argument is a set of flags to use when - * opening the library. If unrecognized or unsupported flags are specified, - * the library is not opened. */ - static LibraryHandle OpenLibrary(const std::string&); - static LibraryHandle OpenLibrary(const std::string&, int); - - /** Attempt to detach a dynamic library from the - * process. A value of true is returned if it is successful. */ - static int CloseLibrary(LibraryHandle); - - /** Find the address of the symbol in the given library. */ - static SymbolPointer GetSymbolAddress(LibraryHandle, const std::string&); - - /** Return the default module prefix for the current platform. */ - static const char* LibPrefix() { return "@KWSYS_DynamicLoader_PREFIX@"; } - - /** Return the default module suffix for the current platform. */ - static const char* LibExtension() { return "@KWSYS_DynamicLoader_SUFFIX@"; } - - /** Return the last error produced from a calls made on this class. */ - static const char* LastError(); -}; // End Class: DynamicLoader - -} // namespace @KWSYS_NAMESPACE@ - -#endif diff --git a/test/API/driver/kwsys/Encoding.h.in b/test/API/driver/kwsys/Encoding.h.in deleted file mode 100644 index 86a2669..0000000 --- a/test/API/driver/kwsys/Encoding.h.in +++ /dev/null @@ -1,69 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifndef @KWSYS_NAMESPACE@_Encoding_h -#define @KWSYS_NAMESPACE@_Encoding_h - -#include <@KWSYS_NAMESPACE@/Configure.h> - -#include - -/* Redefine all public interface symbol names to be in the proper - namespace. These macros are used internally to kwsys only, and are - not visible to user code. Use kwsysHeaderDump.pl to reproduce - these macros after making changes to the interface. */ -#if !defined(KWSYS_NAMESPACE) -# define kwsys_ns(x) @KWSYS_NAMESPACE@##x -# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT -#endif -#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS -# define kwsysEncoding kwsys_ns(Encoding) -# define kwsysEncoding_mbstowcs kwsys_ns(Encoding_mbstowcs) -# define kwsysEncoding_DupToWide kwsys_ns(Encoding_DupToWide) -# define kwsysEncoding_wcstombs kwsys_ns(Encoding_wcstombs) -# define kwsysEncoding_DupToNarrow kwsys_ns(Encoding_DupToNarrow) -#endif - -#if defined(__cplusplus) -extern "C" { -#endif - -/* Convert a narrow string to a wide string. - On Windows, UTF-8 is assumed, and on other platforms, - the current locale is assumed. - */ -kwsysEXPORT size_t kwsysEncoding_mbstowcs(wchar_t* dest, const char* src, - size_t n); - -/* Convert a narrow string to a wide string. - This can return NULL if the conversion fails. */ -kwsysEXPORT wchar_t* kwsysEncoding_DupToWide(const char* src); - -/* Convert a wide string to a narrow string. - On Windows, UTF-8 is assumed, and on other platforms, - the current locale is assumed. */ -kwsysEXPORT size_t kwsysEncoding_wcstombs(char* dest, const wchar_t* src, - size_t n); - -/* Convert a wide string to a narrow string. - This can return NULL if the conversion fails. */ -kwsysEXPORT char* kwsysEncoding_DupToNarrow(const wchar_t* str); - -#if defined(__cplusplus) -} /* extern "C" */ -#endif - -/* If we are building a kwsys .c or .cxx file, let it use these macros. - Otherwise, undefine them to keep the namespace clean. */ -#if !defined(KWSYS_NAMESPACE) -# undef kwsys_ns -# undef kwsysEXPORT -# if !defined(KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS -# undef kwsysEncoding -# undef kwsysEncoding_mbstowcs -# undef kwsysEncoding_DupToWide -# undef kwsysEncoding_wcstombs -# undef kwsysEncoding_DupToNarrow -# endif -#endif - -#endif diff --git a/test/API/driver/kwsys/Encoding.hxx.in b/test/API/driver/kwsys/Encoding.hxx.in deleted file mode 100644 index 75a2d4d..0000000 --- a/test/API/driver/kwsys/Encoding.hxx.in +++ /dev/null @@ -1,80 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifndef @KWSYS_NAMESPACE@_Encoding_hxx -#define @KWSYS_NAMESPACE@_Encoding_hxx - -#include <@KWSYS_NAMESPACE@/Configure.hxx> - -#include -#include - -namespace @KWSYS_NAMESPACE@ { -class @KWSYS_NAMESPACE@_EXPORT Encoding -{ -public: - // Container class for argc/argv. - class @KWSYS_NAMESPACE@_EXPORT CommandLineArguments - { - public: - // On Windows, get the program command line arguments - // in this Encoding module's 8 bit encoding. - // On other platforms the given argc/argv is used, and - // to be consistent, should be the argc/argv from main(). - static CommandLineArguments Main(int argc, char const* const* argv); - - // Construct CommandLineArguments with the given - // argc/argv. It is assumed that the string is already - // in the encoding used by this module. - CommandLineArguments(int argc, char const* const* argv); - - // Construct CommandLineArguments with the given - // argc and wide argv. This is useful if wmain() is used. - CommandLineArguments(int argc, wchar_t const* const* argv); - ~CommandLineArguments(); - CommandLineArguments(const CommandLineArguments&); - CommandLineArguments& operator=(const CommandLineArguments&); - - int argc() const; - char const* const* argv() const; - - protected: - std::vector argv_; - }; - - /** - * Convert between char and wchar_t - */ - -#if @KWSYS_NAMESPACE@_STL_HAS_WSTRING - - // Convert a narrow string to a wide string. - // On Windows, UTF-8 is assumed, and on other platforms, - // the current locale is assumed. - static std::wstring ToWide(const std::string& str); - static std::wstring ToWide(const char* str); - - // Convert a wide string to a narrow string. - // On Windows, UTF-8 is assumed, and on other platforms, - // the current locale is assumed. - static std::string ToNarrow(const std::wstring& str); - static std::string ToNarrow(const wchar_t* str); - -# if defined(_WIN32) - /** - * Convert the path to an extended length path to avoid MAX_PATH length - * limitations on Windows. If the input is a local path the result will be - * prefixed with \\?\; if the input is instead a network path, the result - * will be prefixed with \\?\UNC\. All output will also be converted to - * absolute paths with Windows-style backslashes. - **/ - static std::wstring ToWindowsExtendedPath(std::string const&); - static std::wstring ToWindowsExtendedPath(const char* source); - static std::wstring ToWindowsExtendedPath(std::wstring const& wsource); -# endif - -#endif // @KWSYS_NAMESPACE@_STL_HAS_WSTRING - -}; // class Encoding -} // namespace @KWSYS_NAMESPACE@ - -#endif diff --git a/test/API/driver/kwsys/EncodingC.c b/test/API/driver/kwsys/EncodingC.c deleted file mode 100644 index e12236a..0000000 --- a/test/API/driver/kwsys/EncodingC.c +++ /dev/null @@ -1,72 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include "kwsysPrivate.h" -#include KWSYS_HEADER(Encoding.h) - -/* Work-around CMake dependency scanning limitation. This must - duplicate the above list of headers. */ -#if 0 -# include "Encoding.h.in" -#endif - -#include - -#ifdef _WIN32 -# include -#endif - -size_t kwsysEncoding_mbstowcs(wchar_t* dest, const char* str, size_t n) -{ - if (str == 0) { - return (size_t)-1; - } -#ifdef _WIN32 - return MultiByteToWideChar(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str, -1, dest, - (int)n) - - 1; -#else - return mbstowcs(dest, str, n); -#endif -} - -wchar_t* kwsysEncoding_DupToWide(const char* str) -{ - wchar_t* ret = NULL; - size_t length = kwsysEncoding_mbstowcs(NULL, str, 0) + 1; - if (length > 0) { - ret = (wchar_t*)malloc((length) * sizeof(wchar_t)); - if (ret) { - ret[0] = 0; - kwsysEncoding_mbstowcs(ret, str, length); - } - } - return ret; -} - -size_t kwsysEncoding_wcstombs(char* dest, const wchar_t* str, size_t n) -{ - if (str == 0) { - return (size_t)-1; - } -#ifdef _WIN32 - return WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str, -1, dest, - (int)n, NULL, NULL) - - 1; -#else - return wcstombs(dest, str, n); -#endif -} - -char* kwsysEncoding_DupToNarrow(const wchar_t* str) -{ - char* ret = NULL; - size_t length = kwsysEncoding_wcstombs(0, str, 0) + 1; - if (length > 0) { - ret = (char*)malloc(length); - if (ret) { - ret[0] = 0; - kwsysEncoding_wcstombs(ret, str, length); - } - } - return ret; -} diff --git a/test/API/driver/kwsys/EncodingCXX.cxx b/test/API/driver/kwsys/EncodingCXX.cxx deleted file mode 100644 index 5cad934..0000000 --- a/test/API/driver/kwsys/EncodingCXX.cxx +++ /dev/null @@ -1,288 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifdef __osf__ -# define _OSF_SOURCE -# define _POSIX_C_SOURCE 199506L -# define _XOPEN_SOURCE_EXTENDED -#endif - -#include "kwsysPrivate.h" -#include KWSYS_HEADER(Encoding.hxx) -#include KWSYS_HEADER(Encoding.h) - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -# include "Encoding.h.in" -# include "Encoding.hxx.in" -#endif - -#include -#include -#include - -#ifdef _MSC_VER -# pragma warning(disable : 4786) -#endif - -// Windows API. -#if defined(_WIN32) -# include - -# include -# include -#endif - -namespace KWSYS_NAMESPACE { - -Encoding::CommandLineArguments Encoding::CommandLineArguments::Main( - int argc, char const* const* argv) -{ -#ifdef _WIN32 - (void)argc; - (void)argv; - - int ac; - LPWSTR* w_av = CommandLineToArgvW(GetCommandLineW(), &ac); - - std::vector av1(ac); - std::vector av2(ac); - for (int i = 0; i < ac; i++) { - av1[i] = ToNarrow(w_av[i]); - av2[i] = av1[i].c_str(); - } - LocalFree(w_av); - return CommandLineArguments(ac, &av2[0]); -#else - return CommandLineArguments(argc, argv); -#endif -} - -Encoding::CommandLineArguments::CommandLineArguments(int ac, - char const* const* av) -{ - this->argv_.resize(ac + 1); - for (int i = 0; i < ac; i++) { - this->argv_[i] = strdup(av[i]); - } - this->argv_[ac] = nullptr; -} - -Encoding::CommandLineArguments::CommandLineArguments(int ac, - wchar_t const* const* av) -{ - this->argv_.resize(ac + 1); - for (int i = 0; i < ac; i++) { - this->argv_[i] = kwsysEncoding_DupToNarrow(av[i]); - } - this->argv_[ac] = nullptr; -} - -Encoding::CommandLineArguments::~CommandLineArguments() -{ - for (size_t i = 0; i < this->argv_.size(); i++) { - free(argv_[i]); - } -} - -Encoding::CommandLineArguments::CommandLineArguments( - const CommandLineArguments& other) -{ - this->argv_.resize(other.argv_.size()); - for (size_t i = 0; i < this->argv_.size(); i++) { - this->argv_[i] = other.argv_[i] ? strdup(other.argv_[i]) : nullptr; - } -} - -Encoding::CommandLineArguments& Encoding::CommandLineArguments::operator=( - const CommandLineArguments& other) -{ - if (this != &other) { - size_t i; - for (i = 0; i < this->argv_.size(); i++) { - free(this->argv_[i]); - } - - this->argv_.resize(other.argv_.size()); - for (i = 0; i < this->argv_.size(); i++) { - this->argv_[i] = other.argv_[i] ? strdup(other.argv_[i]) : nullptr; - } - } - - return *this; -} - -int Encoding::CommandLineArguments::argc() const -{ - return static_cast(this->argv_.size() - 1); -} - -char const* const* Encoding::CommandLineArguments::argv() const -{ - return &this->argv_[0]; -} - -#if KWSYS_STL_HAS_WSTRING - -std::wstring Encoding::ToWide(const std::string& str) -{ - std::wstring wstr; -# if defined(_WIN32) - const int wlength = - MultiByteToWideChar(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.data(), - int(str.size()), nullptr, 0); - if (wlength > 0) { - wchar_t* wdata = new wchar_t[wlength]; - int r = MultiByteToWideChar(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.data(), - int(str.size()), wdata, wlength); - if (r > 0) { - wstr = std::wstring(wdata, wlength); - } - delete[] wdata; - } -# else - size_t pos = 0; - size_t nullPos = 0; - do { - if (pos < str.size() && str.at(pos) != '\0') { - wstr += ToWide(str.c_str() + pos); - } - nullPos = str.find('\0', pos); - if (nullPos != std::string::npos) { - pos = nullPos + 1; - wstr += wchar_t('\0'); - } - } while (nullPos != std::string::npos); -# endif - return wstr; -} - -std::string Encoding::ToNarrow(const std::wstring& str) -{ - std::string nstr; -# if defined(_WIN32) - int length = - WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.c_str(), - int(str.size()), nullptr, 0, nullptr, nullptr); - if (length > 0) { - char* data = new char[length]; - int r = - WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.c_str(), - int(str.size()), data, length, nullptr, nullptr); - if (r > 0) { - nstr = std::string(data, length); - } - delete[] data; - } -# else - size_t pos = 0; - size_t nullPos = 0; - do { - if (pos < str.size() && str.at(pos) != '\0') { - nstr += ToNarrow(str.c_str() + pos); - } - nullPos = str.find(wchar_t('\0'), pos); - if (nullPos != std::string::npos) { - pos = nullPos + 1; - nstr += '\0'; - } - } while (nullPos != std::string::npos); -# endif - return nstr; -} - -std::wstring Encoding::ToWide(const char* cstr) -{ - std::wstring wstr; - size_t length = kwsysEncoding_mbstowcs(nullptr, cstr, 0) + 1; - if (length > 0) { - std::vector wchars(length); - if (kwsysEncoding_mbstowcs(&wchars[0], cstr, length) > 0) { - wstr = &wchars[0]; - } - } - return wstr; -} - -std::string Encoding::ToNarrow(const wchar_t* wcstr) -{ - std::string str; - size_t length = kwsysEncoding_wcstombs(nullptr, wcstr, 0) + 1; - if (length > 0) { - std::vector chars(length); - if (kwsysEncoding_wcstombs(&chars[0], wcstr, length) > 0) { - str = &chars[0]; - } - } - return str; -} - -# if defined(_WIN32) -// Convert local paths to UNC style paths -std::wstring Encoding::ToWindowsExtendedPath(std::string const& source) -{ - return ToWindowsExtendedPath(ToWide(source)); -} - -// Convert local paths to UNC style paths -std::wstring Encoding::ToWindowsExtendedPath(const char* source) -{ - return ToWindowsExtendedPath(ToWide(source)); -} - -// Convert local paths to UNC style paths -std::wstring Encoding::ToWindowsExtendedPath(std::wstring const& wsource) -{ - // Resolve any relative paths - DWORD wfull_len; - - /* The +3 is a workaround for a bug in some versions of GetFullPathNameW that - * won't return a large enough buffer size if the input is too small */ - wfull_len = GetFullPathNameW(wsource.c_str(), 0, nullptr, nullptr) + 3; - std::vector wfull(wfull_len); - GetFullPathNameW(wsource.c_str(), wfull_len, &wfull[0], nullptr); - - /* This should get the correct size without any extra padding from the - * previous size workaround. */ - wfull_len = static_cast(wcslen(&wfull[0])); - - if (wfull_len >= 2 && isalpha(wfull[0]) && - wfull[1] == L':') { /* C:\Foo\bar\FooBar.txt */ - return L"\\\\?\\" + std::wstring(&wfull[0]); - } else if (wfull_len >= 2 && wfull[0] == L'\\' && - wfull[1] == L'\\') { /* Starts with \\ */ - if (wfull_len >= 4 && wfull[2] == L'?' && - wfull[3] == L'\\') { /* Starts with \\?\ */ - if (wfull_len >= 8 && wfull[4] == L'U' && wfull[5] == L'N' && - wfull[6] == L'C' && - wfull[7] == L'\\') { /* \\?\UNC\Foo\bar\FooBar.txt */ - return std::wstring(&wfull[0]); - } else if (wfull_len >= 6 && isalpha(wfull[4]) && - wfull[5] == L':') { /* \\?\C:\Foo\bar\FooBar.txt */ - return std::wstring(&wfull[0]); - } else if (wfull_len >= 5) { /* \\?\Foo\bar\FooBar.txt */ - return L"\\\\?\\UNC\\" + std::wstring(&wfull[4]); - } - } else if (wfull_len >= 4 && wfull[2] == L'.' && - wfull[3] == L'\\') { /* Starts with \\.\ a device name */ - if (wfull_len >= 6 && isalpha(wfull[4]) && - wfull[5] == L':') { /* \\.\C:\Foo\bar\FooBar.txt */ - return L"\\\\?\\" + std::wstring(&wfull[4]); - } else if (wfull_len >= - 5) { /* \\.\Foo\bar\ Device name is left unchanged */ - return std::wstring(&wfull[0]); - } - } else if (wfull_len >= 3) { /* \\Foo\bar\FooBar.txt */ - return L"\\\\?\\UNC\\" + std::wstring(&wfull[2]); - } - } - - // If this case has been reached, then the path is invalid. Leave it - // unchanged - return wsource; -} -# endif - -#endif // KWSYS_STL_HAS_WSTRING - -} // namespace KWSYS_NAMESPACE diff --git a/test/API/driver/kwsys/ExtraTest.cmake.in b/test/API/driver/kwsys/ExtraTest.cmake.in deleted file mode 100644 index e8c0a1c..0000000 --- a/test/API/driver/kwsys/ExtraTest.cmake.in +++ /dev/null @@ -1 +0,0 @@ -MESSAGE("*** This message is generated by message inside a file that is included in DartTestfile.txt ***") diff --git a/test/API/driver/kwsys/FStream.cxx b/test/API/driver/kwsys/FStream.cxx deleted file mode 100644 index 5e4133a..0000000 --- a/test/API/driver/kwsys/FStream.cxx +++ /dev/null @@ -1,55 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include "kwsysPrivate.h" -#include KWSYS_HEADER(FStream.hxx) - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -# include "FStream.hxx.in" -#endif - -namespace KWSYS_NAMESPACE { -namespace FStream { - -BOM ReadBOM(std::istream& in) -{ - if (!in.good()) { - return BOM_None; - } - unsigned long orig = in.tellg(); - unsigned char bom[4]; - in.read(reinterpret_cast(bom), 2); - if (!in.good()) { - in.clear(); - in.seekg(orig); - return BOM_None; - } - if (bom[0] == 0xEF && bom[1] == 0xBB) { - in.read(reinterpret_cast(bom + 2), 1); - if (in.good() && bom[2] == 0xBF) { - return BOM_UTF8; - } - } else if (bom[0] == 0xFE && bom[1] == 0xFF) { - return BOM_UTF16BE; - } else if (bom[0] == 0x00 && bom[1] == 0x00) { - in.read(reinterpret_cast(bom + 2), 2); - if (in.good() && bom[2] == 0xFE && bom[3] == 0xFF) { - return BOM_UTF32BE; - } - } else if (bom[0] == 0xFF && bom[1] == 0xFE) { - unsigned long p = in.tellg(); - in.read(reinterpret_cast(bom + 2), 2); - if (in.good() && bom[2] == 0x00 && bom[3] == 0x00) { - return BOM_UTF32LE; - } - in.seekg(p); - return BOM_UTF16LE; - } - in.clear(); - in.seekg(orig); - return BOM_None; -} - -} // FStream namespace -} // KWSYS_NAMESPACE diff --git a/test/API/driver/kwsys/FStream.hxx.in b/test/API/driver/kwsys/FStream.hxx.in deleted file mode 100644 index d79bbdf..0000000 --- a/test/API/driver/kwsys/FStream.hxx.in +++ /dev/null @@ -1,278 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifndef @KWSYS_NAMESPACE@_FStream_hxx -#define @KWSYS_NAMESPACE@_FStream_hxx - -#include <@KWSYS_NAMESPACE@/Configure.hxx> - -#include <@KWSYS_NAMESPACE@/Encoding.hxx> - -#include -#if defined(_WIN32) -# if !defined(_MSC_VER) && @KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H -# include -# endif -#endif - -namespace @KWSYS_NAMESPACE@ { -#if defined(_WIN32) && \ - (defined(_MSC_VER) || @KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H) -# if defined(_NOEXCEPT) -# define @KWSYS_NAMESPACE@_FStream_NOEXCEPT _NOEXCEPT -# else -# define @KWSYS_NAMESPACE@_FStream_NOEXCEPT -# endif - -# if defined(_MSC_VER) - -template -class basic_filebuf : public std::basic_filebuf -{ -# if _MSC_VER >= 1400 -public: - typedef std::basic_filebuf my_base_type; - basic_filebuf* open(char const* s, std::ios_base::openmode mode) - { - const std::wstring wstr = Encoding::ToWindowsExtendedPath(s); - return static_cast(my_base_type::open(wstr.c_str(), mode)); - } -# endif -}; - -# else - -inline std::wstring getcmode(const std::ios_base::openmode mode) -{ - std::wstring cmode; - bool plus = false; - if (mode & std::ios_base::app) { - cmode += L"a"; - plus = mode & std::ios_base::in ? true : false; - } else if (mode & std::ios_base::trunc || - (mode & std::ios_base::out && (mode & std::ios_base::in) == 0)) { - cmode += L"w"; - plus = mode & std::ios_base::in ? true : false; - } else { - cmode += L"r"; - plus = mode & std::ios_base::out ? true : false; - } - if (plus) { - cmode += L"+"; - } - if (mode & std::ios_base::binary) { - cmode += L"b"; - } else { - cmode += L"t"; - } - return cmode; -}; - -# endif - -template > -class basic_efilebuf -{ -public: -# if defined(_MSC_VER) - typedef basic_filebuf internal_buffer_type; -# else - typedef __gnu_cxx::stdio_filebuf internal_buffer_type; -# endif - - basic_efilebuf() - : file_(0) - { - buf_ = 0; - } - - bool _open(char const* file_name, std::ios_base::openmode mode) - { - if (is_open() || file_) { - return false; - } -# if defined(_MSC_VER) - const bool success = buf_->open(file_name, mode) != 0; -# else - const std::wstring wstr = Encoding::ToWindowsExtendedPath(file_name); - bool success = false; - std::wstring cmode = getcmode(mode); - file_ = _wfopen(wstr.c_str(), cmode.c_str()); - if (file_) { - if (buf_) { - delete buf_; - } - buf_ = new internal_buffer_type(file_, mode); - success = true; - } -# endif - return success; - } - - bool is_open() - { - if (!buf_) { - return false; - } - return buf_->is_open(); - } - - bool is_open() const - { - if (!buf_) { - return false; - } - return buf_->is_open(); - } - - bool _close() - { - bool success = false; - if (buf_) { - success = buf_->close() != 0; -# if !defined(_MSC_VER) - if (file_) { - success = fclose(file_) == 0 ? success : false; - file_ = 0; - } -# endif - } - return success; - } - - static void _set_state(bool success, std::basic_ios* ios, - basic_efilebuf* efilebuf) - { -# if !defined(_MSC_VER) - ios->rdbuf(efilebuf->buf_); -# else - static_cast(efilebuf); -# endif - if (!success) { - ios->setstate(std::ios_base::failbit); - } else { - ios->clear(); - } - } - - ~basic_efilebuf() - { - if (buf_) { - delete buf_; - } - } - -protected: - internal_buffer_type* buf_; - FILE* file_; -}; - -template > -class basic_ifstream - : public std::basic_istream - , public basic_efilebuf -{ -public: - typedef typename basic_efilebuf::internal_buffer_type - internal_buffer_type; - typedef std::basic_istream internal_stream_type; - - basic_ifstream() - : internal_stream_type(new internal_buffer_type()) - { - this->buf_ = - static_cast(internal_stream_type::rdbuf()); - } - explicit basic_ifstream(char const* file_name, - std::ios_base::openmode mode = std::ios_base::in) - : internal_stream_type(new internal_buffer_type()) - { - this->buf_ = - static_cast(internal_stream_type::rdbuf()); - open(file_name, mode); - } - - void open(char const* file_name, - std::ios_base::openmode mode = std::ios_base::in) - { - mode = mode | std::ios_base::in; - this->_set_state(this->_open(file_name, mode), this, this); - } - - void close() { this->_set_state(this->_close(), this, this); } - - using basic_efilebuf::is_open; - - internal_buffer_type* rdbuf() const { return this->buf_; } - - ~basic_ifstream() @KWSYS_NAMESPACE@_FStream_NOEXCEPT { close(); } -}; - -template > -class basic_ofstream - : public std::basic_ostream - , public basic_efilebuf -{ - using basic_efilebuf::is_open; - -public: - typedef typename basic_efilebuf::internal_buffer_type - internal_buffer_type; - typedef std::basic_ostream internal_stream_type; - - basic_ofstream() - : internal_stream_type(new internal_buffer_type()) - { - this->buf_ = - static_cast(internal_stream_type::rdbuf()); - } - explicit basic_ofstream(char const* file_name, - std::ios_base::openmode mode = std::ios_base::out) - : internal_stream_type(new internal_buffer_type()) - { - this->buf_ = - static_cast(internal_stream_type::rdbuf()); - open(file_name, mode); - } - void open(char const* file_name, - std::ios_base::openmode mode = std::ios_base::out) - { - mode = mode | std::ios_base::out; - this->_set_state(this->_open(file_name, mode), this, this); - } - - void close() { this->_set_state(this->_close(), this, this); } - - internal_buffer_type* rdbuf() const { return this->buf_; } - - ~basic_ofstream() @KWSYS_NAMESPACE@_FStream_NOEXCEPT { close(); } -}; - -typedef basic_ifstream ifstream; -typedef basic_ofstream ofstream; - -# undef @KWSYS_NAMESPACE@_FStream_NOEXCEPT -#else -using std::ofstream; -using std::ifstream; -#endif - -namespace FStream { -enum BOM -{ - BOM_None, - BOM_UTF8, - BOM_UTF16BE, - BOM_UTF16LE, - BOM_UTF32BE, - BOM_UTF32LE -}; - -// Read a BOM, if one exists. -// If a BOM exists, the stream is advanced to after the BOM. -// This function requires a seekable stream (but not a relative -// seekable stream). -@KWSYS_NAMESPACE@_EXPORT BOM ReadBOM(std::istream& in); -} -} - -#endif diff --git a/test/API/driver/kwsys/GitSetup/.gitattributes b/test/API/driver/kwsys/GitSetup/.gitattributes deleted file mode 100644 index e96d1f8..0000000 --- a/test/API/driver/kwsys/GitSetup/.gitattributes +++ /dev/null @@ -1,6 +0,0 @@ -.git* export-ignore - -config* eol=lf whitespace=indent-with-non-tab -git-* eol=lf whitespace=indent-with-non-tab -tips eol=lf whitespace=indent-with-non-tab -setup-* eol=lf whitespace=indent-with-non-tab diff --git a/test/API/driver/kwsys/GitSetup/LICENSE b/test/API/driver/kwsys/GitSetup/LICENSE deleted file mode 100644 index d645695..0000000 --- a/test/API/driver/kwsys/GitSetup/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/test/API/driver/kwsys/GitSetup/NOTICE b/test/API/driver/kwsys/GitSetup/NOTICE deleted file mode 100644 index 0d32c02..0000000 --- a/test/API/driver/kwsys/GitSetup/NOTICE +++ /dev/null @@ -1,5 +0,0 @@ -Kitware Local Git Setup Scripts -Copyright 2010-2012 Kitware, Inc. - -This product includes software developed at Kitware, Inc. -(http://www.kitware.com/). diff --git a/test/API/driver/kwsys/GitSetup/README b/test/API/driver/kwsys/GitSetup/README deleted file mode 100644 index 2f9f1ec..0000000 --- a/test/API/driver/kwsys/GitSetup/README +++ /dev/null @@ -1,87 +0,0 @@ -Kitware Local Git Setup Scripts - - -Introduction ------------- - -This is a collection of local Git development setup scripts meant for -inclusion in project source trees to aid their development workflow. -Project-specific information needed by the scripts may be configured -in a "config" file added next to them in the project. - - -Import ------- - -A project may import these scripts into their source tree by -initializing a subtree merge. Bring up a Git prompt and set the -current working directory inside a clone of the target project. -Fetch the "setup" branch from the GitSetup repository: - - $ git fetch ../GitSetup setup:setup - -Prepare to merge the branch but place the content in a subdirectory. -Any prefix (with trailing '/') may be chosen so long as it is used -consistently within a project through the rest of these instructions: - - $ git merge -s ours --no-commit setup - $ git read-tree -u --prefix=Utilities/GitSetup/ setup - -Commit the merge with an informative message: - - $ git commit - ------------------------------------------------------------------------ - Merge branch 'setup' - - Add Utilities/GitSetup/ directory using subtree merge from - the general GitSetup repository "setup" branch. - ------------------------------------------------------------------------ - -Optionally add to the project ".gitattributes" file the line - - /Utilities/GitSetup export-ignore - -to exclude the GitSetup directory from inclusion by "git archive" -since it does not make sense in source tarballs. - - -Configuration -------------- - -Read the "Project configuration instructions" comment in each script. -Add a "config" file next to the scripts with desired configuration -(optionally copy and modify "config.sample"). For example, to -configure the "setup-hooks" script: - - $ git config -f Utilities/GitSetup/config hooks.url "$url" - -where "$url" is the project repository publishing the "hooks" branch. -When finished, add and commit the configuration file: - - $ git add Utilities/GitSetup/config - $ git commit - - -Update ------- - -A project may update these scripts from the GitSetup repository. -Bring up a Git prompt and set the current working directory inside a -clone of the target project. Fetch the "setup" branch from the -GitSetup repository: - - $ git fetch ../GitSetup setup:setup - -Merge the "setup" branch into the subtree: - - $ git merge -X subtree=Utilities/GitSetup setup - -where "Utilities/GitSetup" is the same prefix used during the import -setup, but without a trailing '/'. - - -License -------- - -Distributed under the Apache License 2.0. -See LICENSE and NOTICE for details. diff --git a/test/API/driver/kwsys/GitSetup/config b/test/API/driver/kwsys/GitSetup/config deleted file mode 100644 index cba4c14..0000000 --- a/test/API/driver/kwsys/GitSetup/config +++ /dev/null @@ -1,4 +0,0 @@ -[hooks] - url = https://gitlab.kitware.com/utils/gitsetup.git -[upstream] - url = https://gitlab.kitware.com/utils/kwsys.git diff --git a/test/API/driver/kwsys/GitSetup/config.sample b/test/API/driver/kwsys/GitSetup/config.sample deleted file mode 100644 index eeb468b..0000000 --- a/test/API/driver/kwsys/GitSetup/config.sample +++ /dev/null @@ -1,32 +0,0 @@ -# Kitware Local Git Setup Scripts - Sample Project Configuration -# -# Copy to "config" and edit as necessary. - -[hooks] - url = http://public.kitware.com/GitSetup.git - #branch = hooks - -[ssh] - host = public.kitware.com - key = id_git_public - request-url = https://www.kitware.com/Admin/SendPassword.cgi - -[stage] - #url = git://public.kitware.com/stage/Project.git - #pushurl = git@public.kitware.com:stage/Project.git - -[gerrit] - #project = Project - site = http://review.source.kitware.com - # pushurl placeholder "$username" is literal - pushurl = $username@review.source.kitware.com:Project - -[upstream] - url = git://public.kitware.com/Project.git - -[gitlab] - host = gitlab.kitware.com - group-path = group - group-name = Group - project-path = project - project-name = Project diff --git a/test/API/driver/kwsys/GitSetup/git-gerrit-push b/test/API/driver/kwsys/GitSetup/git-gerrit-push deleted file mode 100644 index b46f753..0000000 --- a/test/API/driver/kwsys/GitSetup/git-gerrit-push +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env bash -#============================================================================= -# Copyright 2010-2015 Kitware, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#============================================================================= - -USAGE="[] [--no-topic] [--dry-run] [--]" -OPTIONS_SPEC= -SUBDIRECTORY_OK=Yes -. "$(git --exec-path)/git-sh-setup" - -#----------------------------------------------------------------------------- - -remote='' -refspecs='' -no_topic='' -dry_run='' - -# Parse the command line options. -while test $# != 0; do - case "$1" in - --no-topic) no_topic=1 ;; - --dry-run) dry_run=--dry-run ;; - --) shift; break ;; - -*) usage ;; - *) test -z "$remote" || usage ; remote="$1" ;; - esac - shift -done -test $# = 0 || usage - -# Default remote. -test -n "$remote" || remote="gerrit" - -if test -z "$no_topic"; then - # Identify and validate the topic branch name. - head="$(git symbolic-ref HEAD)" && topic="${head#refs/heads/}" || topic='' - if test -z "$topic" -o "$topic" = "master"; then - die 'Please name your topic: - git checkout -b descriptive-name' - fi - # The topic branch will be pushed by name. - refspecs="HEAD:refs/for/master/$topic $refspecs" -fi - -# Fetch the current upstream master branch head. -# This helps computation of a minimal pack to push. -echo "Fetching $remote master" -fetch_out=$(git fetch "$remote" master 2>&1) || die "$fetch_out" - -# Exit early if we have nothing to push. -if test -z "$refspecs"; then - echo 'Nothing to push!' - exit 0 -fi - -# Push. Save output and exit code. -echo "Pushing to $remote" -push_stdout=$(git push --porcelain $dry_run "$remote" $refspecs); push_exit=$? -echo "$push_stdout" - -# Reproduce the push exit code. -exit $push_exit diff --git a/test/API/driver/kwsys/GitSetup/git-gitlab-push b/test/API/driver/kwsys/GitSetup/git-gitlab-push deleted file mode 100644 index 768f853..0000000 --- a/test/API/driver/kwsys/GitSetup/git-gitlab-push +++ /dev/null @@ -1,177 +0,0 @@ -#!/usr/bin/env bash -#============================================================================= -# Copyright 2010-2015 Kitware, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#============================================================================= - -USAGE='[] [...] [--] - -OPTIONS - ---dry-run - Show what would be pushed without actually updating the destination - --f,--force - Force-push the topic HEAD to rewrite the destination branch - ---no-default - Do not push the default branch (e.g. master) - ---no-topic - Do not push the topic HEAD. -' -OPTIONS_SPEC= -SUBDIRECTORY_OK=Yes -. "$(git --exec-path)/git-sh-setup" - -egrep-q() { - egrep "$@" >/dev/null 2>/dev/null -} - -# Load the project configuration. -gitlab_upstream='' && -gitlab_configured='' && -config="${BASH_SOURCE%/*}/config" && -protocol=$(git config -f "$config" --get gitlab.protocol || - echo "https") && -host=$(git config -f "$config" --get gitlab.host) && -site=$(git config -f "$config" --get gitlab.site || - echo "$protocol://$host") && -group_path=$(git config -f "$config" --get gitlab.group-path) && -project_path=$(git config -f "$config" --get gitlab.project-path) && -gitlab_upstream="$site/$group_path/$project_path.git" && -gitlab_pushurl=$(git config --get remote.gitlab.pushurl || - git config --get remote.gitlab.url) && -gitlab_configured=1 - -#----------------------------------------------------------------------------- - -remote='' -refspecs='' -force='' -lease=false -lease_flag='' -no_topic='' -no_default='' -dry_run='' - -# Parse the command line options. -while test $# != 0; do - case "$1" in - -f|--force) force='+'; lease=true ;; - --no-topic) no_topic=1 ;; - --dry-run) dry_run=--dry-run ;; - --no-default) no_default=1 ;; - --) shift; break ;; - -*) usage ;; - *) test -z "$remote" || usage ; remote="$1" ;; - esac - shift -done -test $# = 0 || usage - -# Default remote. -test -n "$remote" || remote="gitlab" - -if test -z "$no_topic"; then - # Identify and validate the topic branch name. - head="$(git symbolic-ref HEAD)" && topic="${head#refs/heads/}" || topic='' - if test -z "$topic" -o "$topic" = "master"; then - die 'Please name your topic: - git checkout -b descriptive-name' - fi - - if $lease; then - have_ref=false - remoteref="refs/remotes/$remote/$topic" - if git rev-parse --verify -q "$remoteref"; then - have_ref=true - else - die "It seems that a local ref for the branch is -missing; forcing a push is dangerous and may overwrite -previous work. Fetch from the $remote remote first or -push without '-f' or '--force'." - fi - - have_lease_flag=false - if git push -h | egrep-q -e '--force-with-lease'; then - have_lease_flag=true - fi - - if $have_lease_flag && $have_ref; then - # Set the lease flag. - lease_flag="--force-with-lease=$topic:$remoteref" - # Clear the force string. - force='' - fi - fi - - # The topic branch will be pushed by name. - refspecs="${force}HEAD:refs/heads/$topic $refspecs" -fi - -# Fetch the current remote master branch head. -# This helps computation of a minimal pack to push. -echo "Fetching $remote master" -fetch_out=$(git fetch "$remote" master 2>&1) || die "$fetch_out" -gitlab_head=$(git rev-parse FETCH_HEAD) || exit - -# Fetch the current upstream master branch head. -if origin_fetchurl=$(git config --get remote.origin.url) && - test "$origin_fetchurl" = "$gitlab_upstream"; then - upstream_remote='origin' -else - upstream_remote="$gitlab_upstream" -fi -echo "Fetching $upstream_remote master" -fetch_out=$(git fetch "$upstream_remote" master 2>&1) || die "$fetch_out" -upstream_head=$(git rev-parse FETCH_HEAD) || exit - -# Add a refspec to keep the remote master up to date if possible. -if test -z "$no_default" && - base=$(git merge-base "$gitlab_head" "$upstream_head") && - test "$base" = "$gitlab_head"; then - refspecs="$upstream_head:refs/heads/master $refspecs" -fi - -# Exit early if we have nothing to push. -if test -z "$refspecs"; then - echo 'Nothing to push!' - exit 0 -fi - -# Push. Save output and exit code. -echo "Pushing to $remote" -push_config='-c advice.pushUpdateRejected=false' -push_stdout=$(git $push_config push $lease_flag --porcelain $dry_run "$remote" $refspecs); push_exit=$? -echo "$push_stdout" - -if test "$push_exit" -ne 0 && test -z "$force"; then - # Advise the user to fetch if needed. - if echo "$push_stdout" | egrep-q 'stale info'; then - echo " -You have pushed to your branch from another machine; you may be overwriting -commits unintentionally. Fetch from the $remote remote and check that you are -not pushing an outdated branch." - fi - - # Advise the user to force-push if needed. - if echo "$push_stdout" | egrep-q 'non-fast-forward'; then - echo ' -Add "-f" or "--force" to push a rewritten topic.' - fi -fi - -# Reproduce the push exit code. -exit $push_exit diff --git a/test/API/driver/kwsys/GitSetup/pre-commit b/test/API/driver/kwsys/GitSetup/pre-commit deleted file mode 100644 index 1f1d3f5..0000000 --- a/test/API/driver/kwsys/GitSetup/pre-commit +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash - -egrep-q() { - egrep "$@" >/dev/null 2>/dev/null -} - -die() { - echo 'pre-commit hook failure' 1>&2 - echo '-----------------------' 1>&2 - echo '' 1>&2 - echo "$@" 1>&2 - exit 1 -} - -#----------------------------------------------------------------------------- - -# Check that developmer setup is up-to-date. -lastSetupForDevelopment=$(git config --get hooks.SetupForDevelopment || echo 0) -eval $(grep '^SetupForDevelopment_VERSION=' "${BASH_SOURCE%/*}/../SetupForDevelopment.sh") -test -n "$SetupForDevelopment_VERSION" || SetupForDevelopment_VERSION=0 -if test $lastSetupForDevelopment -lt $SetupForDevelopment_VERSION; then - die 'Developer setup in this work tree is out of date. Please re-run - - ./SetupForDevelopment.sh -' -fi diff --git a/test/API/driver/kwsys/GitSetup/setup-aliases b/test/API/driver/kwsys/GitSetup/setup-aliases deleted file mode 100644 index 98810ad..0000000 --- a/test/API/driver/kwsys/GitSetup/setup-aliases +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash -echo "Adding 'git prepush' alias" && -git config alias.prepush 'log --graph --stat origin/master..' && -gerrit_disabled="KWSys no longer uses Gerrit. Please use GitLab." && -git config alias.gerrit-push '!sh -c "echo '"${gerrit_disabled}"'"' && -true diff --git a/test/API/driver/kwsys/GitSetup/setup-gerrit b/test/API/driver/kwsys/GitSetup/setup-gerrit deleted file mode 100644 index 6d46e3c..0000000 --- a/test/API/driver/kwsys/GitSetup/setup-gerrit +++ /dev/null @@ -1,147 +0,0 @@ -#!/usr/bin/env bash -#============================================================================= -# Copyright 2010-2012 Kitware, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#============================================================================= - -# Run this script to set up the local Git repository to push to -# a Gerrit Code Review instance for this project. - -# Project configuration instructions: -# -# - Run a Gerrit Code Review server -# -# - Populate adjacent "config" file with: -# gerrit.site = Top Gerrit URL (not project-specific) -# gerrit.project = Name of project in Gerrit -# gerrit.pushurl = Review site push URL with "$username" placeholder -# gerrit.remote = Gerrit remote name, if not "gerrit" -# gerrit.url = Gerrit project URL, if not "$site/p/$project" -# optionally with "$username" placeholder - -die() { - echo 1>&2 "$@" ; exit 1 -} - -# Make sure we are inside the repository. -cd "${BASH_SOURCE%/*}" && - -# Load the project configuration. -site=$(git config -f config --get gerrit.site) && -project=$(git config -f config --get gerrit.project) && -remote=$(git config -f config --get gerrit.remote || - echo "gerrit") && -fetchurl_=$(git config -f config --get gerrit.url || - echo "$site/p/$project") && -pushurl_=$(git config -f config --get gerrit.pushurl || - git config -f config --get gerrit.url) || -die 'This project is not configured to use Gerrit.' - -# Get current gerrit push URL. -pushurl=$(git config --get remote."$remote".pushurl || - git config --get remote."$remote".url || echo '') && - -# Tell user about current configuration. -if test -n "$pushurl"; then - echo 'Remote "'"$remote"'" is currently configured to push to - - '"$pushurl"' -' && - read -ep 'Reconfigure Gerrit? [y/N]: ' ans && - if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then - setup=1 - else - setup='' - fi -else - echo 'Remote "'"$remote"'" is not yet configured. - -'"$project"' changes must be pushed to our Gerrit Code Review site: - - '"$site/p/$project"' - -Register a Gerrit account and select a username (used below). -You will need an OpenID: - - http://openid.net/get-an-openid/ -' && - read -ep 'Configure Gerrit? [Y/n]: ' ans && - if [ "$ans" == "n" ] || [ "$ans" == "N" ]; then - exit 0 - else - setup=1 - fi -fi && - -# Perform setup if necessary. -if test -n "$setup"; then - echo 'Sign-in to Gerrit to get/set your username at - - '"$site"'/#/settings - -Add your SSH public keys at - - '"$site"'/#/settings/ssh-keys -' && - read -ep "Gerrit username? [$USER]: " gu && - if test -z "$gu"; then - gu="$USER" - fi && - fetchurl="${fetchurl_/\$username/$gu}" && - if test -z "$pushurl"; then - git remote add "$remote" "$fetchurl" - else - git config remote."$remote".url "$fetchurl" - fi && - pushurl="${pushurl_/\$username/$gu}" && - if test "$pushurl" != "$fetchurl"; then - git config remote."$remote".pushurl "$pushurl" - fi && - echo 'Remote "'"$remote"'" is now configured to push to - - '"$pushurl"' -' -fi && - -# Optionally test Gerrit access. -if test -n "$pushurl"; then - read -ep 'Test access to Gerrit (SSH)? [y/N]: ' ans && - if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then - echo -n 'Testing Gerrit access by SSH...' - if git ls-remote --heads "$pushurl" >/dev/null; then - echo 'passed.' - else - echo 'failed.' && - die 'Could not access Gerrit. Add your SSH public keys at - - '"$site"'/#/settings/ssh-keys -' - fi - fi -fi && - -# Set up GerritId hook. -hook=$(git config --get hooks.GerritId || echo '') && -if test -z "$hook"; then - echo ' -Enabling GerritId hook to add a "Change-Id" footer to commit -messages for interaction with Gerrit. Run - - git config hooks.GerritId false - -to disable this feature (but you will be on your own).' && - git config hooks.GerritId true -else - echo 'GerritId hook already configured to "'"$hook"'".' -fi diff --git a/test/API/driver/kwsys/GitSetup/setup-gitlab b/test/API/driver/kwsys/GitSetup/setup-gitlab deleted file mode 100644 index 9c7574d..0000000 --- a/test/API/driver/kwsys/GitSetup/setup-gitlab +++ /dev/null @@ -1,140 +0,0 @@ -#!/usr/bin/env bash -#============================================================================= -# Copyright 2010-2015 Kitware, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#============================================================================= - -# Run this script to set up the local Git repository to push to -# a personal fork for this project in GitLab. - -# Project configuration instructions: -# -# - Run a GitLab server -# -# - Populate adjacent "config" file with: -# gitlab.protocol = Top GitLab protocol, if not 'https' -# gitlab.host = Top GitLab fully qualified host name -# gitlab.site = Top GitLab URL, if not "://" -# gitlab.group-name = Name of group containing project in GitLab -# gitlab.group-path = Path of group containing project in GitLab -# gitlab.project-name = Name of project within GitLab group -# gitlab.project-path = Path of project within GitLab group -# gitlab.url = GitLab push URL with "$username" placeholder, -# if not "/$username/.git" -# gitlab.pushurl = GitLab push URL with "$username" placeholder, -# if not "git@:$username/.git" -# gitlab.remote = GitLab remote name, if not "gitlab" - -die() { - echo 1>&2 "$@" ; exit 1 -} - -# Make sure we are inside the repository. -cd "${BASH_SOURCE%/*}" && - -# Load the project configuration. -protocol=$(git config -f config --get gitlab.protocol || - echo "https") && -host=$(git config -f config --get gitlab.host) && -site=$(git config -f config --get gitlab.site || - echo "$protocol://$host") && -group_path=$(git config -f config --get gitlab.group-path) && -group_name=$(git config -f config --get gitlab.group-name) && -project_name=$(git config -f config --get gitlab.project-name) && -project_path=$(git config -f config --get gitlab.project-path) && -pushurl_=$(git config -f config --get gitlab.pushurl || - echo "git@$host:\$username/$project_path.git") && -remote=$(git config -f config --get gitlab.remote || - echo "gitlab") && -fetchurl_=$(git config -f config --get gitlab.url || - echo "$site/\$username/$project_path.git") || -die 'This project is not configured to use GitLab.' - -# Get current gitlab push URL. -pushurl=$(git config --get remote."$remote".pushurl || - git config --get remote."$remote".url || echo '') && - -# Tell user about current configuration. -if test -n "$pushurl"; then - echo 'Remote "'"$remote"'" is currently configured to push to - - '"$pushurl"' -' && - read -ep 'Reconfigure GitLab? [y/N]: ' ans && - if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then - setup=1 - else - setup='' - fi -else - echo 'Remote "'"$remote"'" is not yet configured. -' && - read -ep 'Configure GitLab to contribute to '"$project_name"'? [Y/n]: ' ans && - if [ "$ans" == "n" ] || [ "$ans" == "N" ]; then - exit 0 - else - setup=1 - fi -fi && - -setup_instructions='Add your SSH public keys at - - '"$site"'/profile/keys - -Then visit the main repository at: - - '"$site/$group_path/$project_path"' - -and use the Fork button in the upper right. -' - -# Perform setup if necessary. -if test -n "$setup"; then - echo 'Sign-in to GitLab to get/set your username at - - '"$site/profile/account"' - -'"$setup_instructions" && - read -ep "GitLab username? [$USER]: " gu && - if test -z "$gu"; then - gu="$USER" - fi && - fetchurl="${fetchurl_/\$username/$gu}" && - if test -z "$pushurl"; then - git remote add "$remote" "$fetchurl" - else - git config remote."$remote".url "$fetchurl" - fi && - pushurl="${pushurl_/\$username/$gu}" && - git config remote."$remote".pushurl "$pushurl" && - echo 'Remote "'"$remote"'" is now configured to push to - - '"$pushurl"' -' -fi && - -# Optionally test GitLab access. -if test -n "$pushurl"; then - read -ep 'Test access to GitLab (SSH)? [y/N]: ' ans && - if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then - echo -n 'Testing GitLab access by SSH...' - if git ls-remote --heads "$pushurl" >/dev/null; then - echo 'passed.' - else - echo 'failed.' && - die 'Could not access your GitLab fork of this project. -'"$setup_instructions" - fi - fi -fi diff --git a/test/API/driver/kwsys/GitSetup/setup-hooks b/test/API/driver/kwsys/GitSetup/setup-hooks deleted file mode 100644 index ca07712..0000000 --- a/test/API/driver/kwsys/GitSetup/setup-hooks +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env bash -#============================================================================= -# Copyright 2010-2012 Kitware, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#============================================================================= - -# Run this script to set up local Git hooks for this project. - -# Project configuration instructions: -# -# - Publish a "hooks" branch in the project repository such that -# clones will have "refs/remotes/origin/hooks". -# -# - Populate adjacent "config" file with: -# hooks.url = Repository URL publishing "hooks" branch -# hooks.branch = Repository branch instead of "hooks" - -egrep-q() { - egrep "$@" >/dev/null 2>/dev/null -} - -die() { - echo 1>&2 "$@" ; exit 1 -} - -# Make sure we are inside the repository. -cd "${BASH_SOURCE%/*}" && - -# Select a hooks branch. -if url=$(git config --get hooks.url); then - # Fetch hooks from locally configured repository. - branch=$(git config hooks.branch || echo hooks) -elif git for-each-ref refs/remotes/origin/hooks 2>/dev/null | - egrep-q 'refs/remotes/origin/hooks$'; then - # Use hooks cloned from origin. - url=.. && branch=remotes/origin/hooks -elif url=$(git config -f config --get hooks.url); then - # Fetch hooks from project-configured repository. - branch=$(git config -f config hooks.branch || echo hooks) -else - die 'This project is not configured to install local hooks.' -fi && - -# Populate ".git/hooks". -echo 'Setting up git hooks...' && -git_dir=$(git rev-parse --git-dir) && -mkdir -p "$git_dir/hooks" && -cd "$git_dir/hooks" && -if ! test -e .git; then - git init -q || die 'Could not run git init for hooks.' -fi && -git fetch -q "$url" "$branch" && -git reset -q --hard FETCH_HEAD || die 'Failed to install hooks' diff --git a/test/API/driver/kwsys/GitSetup/setup-ssh b/test/API/driver/kwsys/GitSetup/setup-ssh deleted file mode 100644 index 8920a5b..0000000 --- a/test/API/driver/kwsys/GitSetup/setup-ssh +++ /dev/null @@ -1,111 +0,0 @@ -#!/usr/bin/env bash -#============================================================================= -# Copyright 2010-2012 Kitware, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#============================================================================= - -# Run this script to set up ssh push access to the repository host. - -# Project configuration instructions: -# -# - Populate adjacent "config" file with: -# ssh.host = Repository host name -# ssh.user = Username on host, if not "git" -# ssh.key = Local ssh key name -# ssh.request-url = Web page URL to request ssh access - -egrep-q() { - egrep "$@" >/dev/null 2>/dev/null -} - -die() { - echo 1>&2 "$@" ; exit 1 -} - -# Make sure we are inside the repository. -cd "${BASH_SOURCE%/*}" && - -# Load the project configuration. -host=$(git config -f config --get ssh.host) && -user=$(git config -f config --get ssh.user || echo git) && -key=$(git config -f config --get ssh.key) && -request_url=$(git config -f config --get ssh.request-url) || -die 'This project is not configured for ssh push access.' - -# Check for existing configuration. -if test -r ~/.ssh/config && - egrep-q 'Host[= ]'"${host//\./\\.}" ~/.ssh/config; then - echo 'Host "'"$host"'" is already in ~/.ssh/config' && - setup= && - question='Test' -else - echo 'Host "'"$host"'" not found in ~/.ssh/config' && - setup=1 && - question='Setup and test' -fi && - -# Ask the user whether to make changes. -echo '' && -read -ep "${question} push access by ssh to $user@$host? [y/N]: " access && -if test "$access" != "y" -a "$access" != "Y"; then - exit 0 -fi && - -# Setup host configuration if necessary. -if test -n "$setup"; then - if ! test -d ~/.ssh; then - mkdir -p ~/.ssh && - chmod 700 ~/.ssh - fi && - if ! test -f ~/.ssh/config; then - touch ~/.ssh/config && - chmod 600 ~/.ssh/config - fi && - ssh_config='Host='"$host"' - IdentityFile ~/.ssh/'"$key" && - echo "Adding to ~/.ssh/config: - -$ssh_config -" && - echo "$ssh_config" >> ~/.ssh/config && - if ! test -e ~/.ssh/"$key"; then - if test -f ~/.ssh/id_rsa; then - # Take care of the common case. - ln -s id_rsa ~/.ssh/"$key" - echo ' -Assuming ~/.ssh/id_rsa is the private key corresponding to the public key for - - '"$user@$host"' - -If this is incorrect place private key at "~/.ssh/'"$key"'".' - else - echo ' -Place the private key corresponding to the public key registered for - - '"$user@$host"' - -at "~/.ssh/'"$key"'".' - fi - read -e -n 1 -p 'Press any key to continue...' - fi -fi || exit 1 - -# Test access configuration. -echo 'Testing ssh push access to "'"$user@$host"'"...' && -if ! ssh "$user@$host" info; then - die 'No ssh push access to "'"$user@$host"'". You may need to request access at - - '"$request_url"' -' -fi diff --git a/test/API/driver/kwsys/GitSetup/setup-stage b/test/API/driver/kwsys/GitSetup/setup-stage deleted file mode 100644 index ce6ec45..0000000 --- a/test/API/driver/kwsys/GitSetup/setup-stage +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env bash -#============================================================================= -# Copyright 2010-2012 Kitware, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#============================================================================= - -# Run this script to set up the topic stage for pushing changes. - -# Project configuration instructions: -# -# - Run a Topic Stage repository next to the main project repository. -# -# - Populate adjacent "config" file with: -# stage.url = Topic Stage repository URL -# stage.pushurl = Topic Stage push URL if not "$url" - -egrep-q() { - egrep "$@" >/dev/null 2>/dev/null -} - -die() { - echo 1>&2 "$@" ; exit 1 -} - -# Make sure we are inside the repository. -cd "${BASH_SOURCE%/*}" && - -# Load the project configuration. -fetchurl_=$(git config -f config --get stage.url) && -pushurl_=$(git config -f config --get stage.pushurl || echo "$fetchurl_") && -remote=$(git config -f config --get stage.remote || echo 'stage') || -die 'This project is not configured to use a topic stage.' - -# Get current stage push URL. -pushurl=$(git config --get remote."$remote".pushurl || - git config --get remote."$remote".url || echo '') && - -# Tell user about current configuration. -if test -n "$pushurl"; then - echo 'Remote "'"$remote"'" is currently configured to push to - - '"$pushurl"' -' && - read -ep 'Reconfigure Topic Stage? [y/N]: ' ans && - if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then - setup=1 - else - setup='' - fi -else - setup=1 -fi - -# Perform setup if necessary. -if test -n "$setup"; then - echo 'Setting up the topic stage...' && - fetchurl="${fetchurl_}" && - if test -z "$pushurl"; then - git remote add "$remote" "$fetchurl" - else - git config remote."$remote".url "$fetchurl" - fi && - pushurl="${pushurl_}" && - if test "$pushurl" != "$fetchurl"; then - git config remote."$remote".pushurl "$pushurl" - fi && - echo 'Remote "'"$remote"'" is now configured to push to - - '"$pushurl"' -' -fi || die 'Could not configure the topic stage remote.' diff --git a/test/API/driver/kwsys/GitSetup/setup-upstream b/test/API/driver/kwsys/GitSetup/setup-upstream deleted file mode 100644 index 92ce1da..0000000 --- a/test/API/driver/kwsys/GitSetup/setup-upstream +++ /dev/null @@ -1,104 +0,0 @@ -#!/usr/bin/env bash -#============================================================================= -# Copyright 2010-2015 Kitware, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#============================================================================= - -# Run this script to set up the local Git repository to use the -# preferred upstream repository URLs. - -# Project configuration instructions: -# -# - Populate adjacent "config" file with: -# upstream.url = Preferred fetch url for upstream remote -# upstream.remote = Preferred name for upstream remote, if not "origin" - -die() { - echo 1>&2 "$@" ; exit 1 -} - -# Make sure we are inside the repository. -cd "${BASH_SOURCE%/*}" && - -# Load the project configuration. -url=$(git config -f config --get upstream.url) && -remote=$(git config -f config --get upstream.remote || - echo 'origin') || -die 'This project is not configured to use a preferred upstream repository.' - -# Get current upstream URLs. -fetchurl=$(git config --get remote."$remote".url || echo '') && -pushurl=$(git config --get remote."$remote".pushurl || echo '') && - -if test "$fetchurl" = "$url"; then - echo 'Remote "'"$remote"'" already uses recommended upstream repository.' - exit 0 -fi - -upstream_recommend=' -We recommended configuring the "'"$remote"'" remote to fetch from upstream at - - '"$url"' -' - -# Tell user about current configuration. -if test -n "$fetchurl"; then - echo 'Remote "'"$remote"'" is currently configured to fetch from - - '"$fetchurl"' -' && - if test -n "$pushurl"; then - echo 'and push to - - '"$pushurl" - fi && - echo "$upstream_recommend" && - if test -n "$pushurl"; then - echo 'and to never push to it directly. -' - fi && - - read -ep 'Reconfigure "'"$remote"'" remote as recommended? [y/N]: ' ans && - if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then - setup=1 - else - setup='' - fi -else - echo 'Remote "'"$remote"'" is not yet configured.' && - echo "$upstream_recommend" && - read -ep 'Configure "'"$remote"'" remote as recommended? [Y/n]: ' ans && - if [ "$ans" == "n" ] || [ "$ans" == "N" ]; then - exit 0 - else - setup=1 - fi -fi && - -# Perform setup if necessary. -if test -n "$setup"; then - if test -z "$fetchurl"; then - git remote add "$remote" "$url" - else - git config remote."$remote".url "$url" && - if old=$(git config --get remote."$remote".pushurl); then - git config --unset remote."$remote".pushurl || - echo 'Warning: failed to unset remote.'"$remote"'.pushurl' - fi - fi && - echo 'Remote "'"$remote"'" is now configured to fetch from - - '"$url"' -' -fi diff --git a/test/API/driver/kwsys/GitSetup/setup-user b/test/API/driver/kwsys/GitSetup/setup-user deleted file mode 100644 index 1af439c..0000000 --- a/test/API/driver/kwsys/GitSetup/setup-user +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env bash -#============================================================================= -# Copyright 2010-2012 Kitware, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#============================================================================= - -# Run this script to configure Git user info in this repository. - -# Project configuration instructions: NONE - -for (( ; ; )); do - user_name=$(git config user.name || echo '') && - user_email=$(git config user.email || echo '') && - if test -n "$user_name" -a -n "$user_email"; then - echo 'Your commits will record as Author: - - '"$user_name <$user_email>"' -' && - read -ep 'Is the author name and email address above correct? [Y/n] ' correct && - if test "$correct" != "n" -a "$correct" != "N"; then - break - fi - fi && - read -ep 'Enter your full name e.g. "John Doe": ' name && - read -ep 'Enter your email address e.g. "john@gmail.com": ' email && - git config user.name "$name" && - git config user.email "$email" -done diff --git a/test/API/driver/kwsys/GitSetup/tips b/test/API/driver/kwsys/GitSetup/tips deleted file mode 100644 index 784e1ed..0000000 --- a/test/API/driver/kwsys/GitSetup/tips +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env bash -#============================================================================= -# Copyright 2010-2012 Kitware, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#============================================================================= - -# This script makes optional suggestions for working with Git. - -# Project configuration instructions: NONE - -egrep-q() { - egrep "$@" >/dev/null 2>/dev/null -} - -# Suggest color configuration. -if test -z "$(git config --get color.ui)"; then - echo ' -One may enable color output from Git commands with - - git config --global color.ui auto -' -fi - -# Suggest bash completion. -if ! bash -i -c 'echo $PS1' | egrep-q '__git_ps1'; then - echo ' -A dynamic, informative Git shell prompt can be obtained by sourcing -the git bash-completion script in your "~/.bashrc". Set the PS1 -environmental variable as suggested in the comments at the top of the -bash-completion script. You may need to install the bash-completion -package from your distribution to obtain it. -' -fi - -# Suggest merge tool. -if test -z "$(git config --get merge.tool)"; then - echo ' -One may configure Git to load a merge tool with - - git config merge.tool - -See "git help mergetool" for more information. -' -fi diff --git a/test/API/driver/kwsys/Glob.cxx b/test/API/driver/kwsys/Glob.cxx deleted file mode 100644 index 34bb0d0..0000000 --- a/test/API/driver/kwsys/Glob.cxx +++ /dev/null @@ -1,448 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include "kwsysPrivate.h" -#include KWSYS_HEADER(Glob.hxx) - -#include KWSYS_HEADER(Configure.hxx) - -#include KWSYS_HEADER(RegularExpression.hxx) -#include KWSYS_HEADER(SystemTools.hxx) -#include KWSYS_HEADER(Directory.hxx) - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -# include "Configure.hxx.in" -# include "Directory.hxx.in" -# include "Glob.hxx.in" -# include "RegularExpression.hxx.in" -# include "SystemTools.hxx.in" -#endif - -#include -#include -#include - -#include -#include -#include -namespace KWSYS_NAMESPACE { -#if defined(_WIN32) || defined(__APPLE__) || defined(__CYGWIN__) -// On Windows and Apple, no difference between lower and upper case -# define KWSYS_GLOB_CASE_INDEPENDENT -#endif - -#if defined(_WIN32) || defined(__CYGWIN__) -// Handle network paths -# define KWSYS_GLOB_SUPPORT_NETWORK_PATHS -#endif - -class GlobInternals -{ -public: - std::vector Files; - std::vector Expressions; -}; - -Glob::Glob() -{ - this->Internals = new GlobInternals; - this->Recurse = false; - this->Relative = ""; - - this->RecurseThroughSymlinks = true; - // RecurseThroughSymlinks is true by default for backwards compatibility, - // not because it's a good idea... - this->FollowedSymlinkCount = 0; - - // Keep separate variables for directory listing for back compatibility - this->ListDirs = true; - this->RecurseListDirs = false; -} - -Glob::~Glob() -{ - delete this->Internals; -} - -std::vector& Glob::GetFiles() -{ - return this->Internals->Files; -} - -std::string Glob::PatternToRegex(const std::string& pattern, - bool require_whole_string, bool preserve_case) -{ - // Incrementally build the regular expression from the pattern. - std::string regex = require_whole_string ? "^" : ""; - std::string::const_iterator pattern_first = pattern.begin(); - std::string::const_iterator pattern_last = pattern.end(); - for (std::string::const_iterator i = pattern_first; i != pattern_last; ++i) { - int c = *i; - if (c == '*') { - // A '*' (not between brackets) matches any string. - // We modify this to not match slashes since the original glob - // pattern documentation was meant for matching file name - // components separated by slashes. - regex += "[^/]*"; - } else if (c == '?') { - // A '?' (not between brackets) matches any single character. - // We modify this to not match slashes since the original glob - // pattern documentation was meant for matching file name - // components separated by slashes. - regex += "[^/]"; - } else if (c == '[') { - // Parse out the bracket expression. It begins just after the - // opening character. - std::string::const_iterator bracket_first = i + 1; - std::string::const_iterator bracket_last = bracket_first; - - // The first character may be complementation '!' or '^'. - if (bracket_last != pattern_last && - (*bracket_last == '!' || *bracket_last == '^')) { - ++bracket_last; - } - - // If the next character is a ']' it is included in the brackets - // because the bracket string may not be empty. - if (bracket_last != pattern_last && *bracket_last == ']') { - ++bracket_last; - } - - // Search for the closing ']'. - while (bracket_last != pattern_last && *bracket_last != ']') { - ++bracket_last; - } - - // Check whether we have a complete bracket string. - if (bracket_last == pattern_last) { - // The bracket string did not end, so it was opened simply by - // a '[' that is supposed to be matched literally. - regex += "\\["; - } else { - // Convert the bracket string to its regex equivalent. - std::string::const_iterator k = bracket_first; - - // Open the regex block. - regex += "["; - - // A regex range complement uses '^' instead of '!'. - if (k != bracket_last && *k == '!') { - regex += "^"; - ++k; - } - - // Convert the remaining characters. - for (; k != bracket_last; ++k) { - // Backslashes must be escaped. - if (*k == '\\') { - regex += "\\"; - } - - // Store this character. - regex += *k; - } - - // Close the regex block. - regex += "]"; - - // Jump to the end of the bracket string. - i = bracket_last; - } - } else { - // A single character matches itself. - int ch = c; - if (!(('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || - ('0' <= ch && ch <= '9'))) { - // Escape the non-alphanumeric character. - regex += "\\"; - } -#if defined(KWSYS_GLOB_CASE_INDEPENDENT) - else { - // On case-insensitive systems file names are converted to lower - // case before matching. - if (!preserve_case) { - ch = tolower(ch); - } - } -#endif - (void)preserve_case; - // Store the character. - regex.append(1, static_cast(ch)); - } - } - - if (require_whole_string) { - regex += "$"; - } - return regex; -} - -bool Glob::RecurseDirectory(std::string::size_type start, - const std::string& dir, GlobMessages* messages) -{ - kwsys::Directory d; - if (!d.Load(dir)) { - return true; - } - unsigned long cc; - std::string realname; - std::string fname; - for (cc = 0; cc < d.GetNumberOfFiles(); cc++) { - fname = d.GetFile(cc); - if (fname == "." || fname == "..") { - continue; - } - - if (start == 0) { - realname = dir + fname; - } else { - realname = dir + "/" + fname; - } - -#if defined(KWSYS_GLOB_CASE_INDEPENDENT) - // On Windows and Apple, no difference between lower and upper case - fname = kwsys::SystemTools::LowerCase(fname); -#endif - - bool isDir = kwsys::SystemTools::FileIsDirectory(realname); - bool isSymLink = kwsys::SystemTools::FileIsSymlink(realname); - - if (isDir && (!isSymLink || this->RecurseThroughSymlinks)) { - if (isSymLink) { - ++this->FollowedSymlinkCount; - std::string realPathErrorMessage; - std::string canonicalPath( - SystemTools::GetRealPath(dir, &realPathErrorMessage)); - - if (!realPathErrorMessage.empty()) { - if (messages) { - messages->push_back( - Message(Glob::error, - "Canonical path generation from path '" + dir + - "' failed! Reason: '" + realPathErrorMessage + "'")); - } - return false; - } - - if (std::find(this->VisitedSymlinks.begin(), - this->VisitedSymlinks.end(), - canonicalPath) == this->VisitedSymlinks.end()) { - if (this->RecurseListDirs) { - // symlinks are treated as directories - this->AddFile(this->Internals->Files, realname); - } - - this->VisitedSymlinks.push_back(canonicalPath); - if (!this->RecurseDirectory(start + 1, realname, messages)) { - this->VisitedSymlinks.pop_back(); - - return false; - } - this->VisitedSymlinks.pop_back(); - } - // else we have already visited this symlink - prevent cyclic recursion - else if (messages) { - std::string message; - for (std::vector::const_iterator pathIt = - std::find(this->VisitedSymlinks.begin(), - this->VisitedSymlinks.end(), canonicalPath); - pathIt != this->VisitedSymlinks.end(); ++pathIt) { - message += *pathIt + "\n"; - } - message += canonicalPath + "/" + fname; - messages->push_back(Message(Glob::cyclicRecursion, message)); - } - } else { - if (this->RecurseListDirs) { - this->AddFile(this->Internals->Files, realname); - } - if (!this->RecurseDirectory(start + 1, realname, messages)) { - return false; - } - } - } else { - if (!this->Internals->Expressions.empty() && - this->Internals->Expressions.back().find(fname)) { - this->AddFile(this->Internals->Files, realname); - } - } - } - - return true; -} - -void Glob::ProcessDirectory(std::string::size_type start, - const std::string& dir, GlobMessages* messages) -{ - // std::cout << "ProcessDirectory: " << dir << std::endl; - bool last = (start == this->Internals->Expressions.size() - 1); - if (last && this->Recurse) { - this->RecurseDirectory(start, dir, messages); - return; - } - - if (start >= this->Internals->Expressions.size()) { - return; - } - - kwsys::Directory d; - if (!d.Load(dir)) { - return; - } - unsigned long cc; - std::string realname; - std::string fname; - for (cc = 0; cc < d.GetNumberOfFiles(); cc++) { - fname = d.GetFile(cc); - if (fname == "." || fname == "..") { - continue; - } - - if (start == 0) { - realname = dir + fname; - } else { - realname = dir + "/" + fname; - } - -#if defined(KWSYS_GLOB_CASE_INDEPENDENT) - // On case-insensitive file systems convert to lower case for matching. - fname = kwsys::SystemTools::LowerCase(fname); -#endif - - // std::cout << "Look at file: " << fname << std::endl; - // std::cout << "Match: " - // << this->Internals->TextExpressions[start].c_str() << std::endl; - // std::cout << "Real name: " << realname << std::endl; - - if ((!last && !kwsys::SystemTools::FileIsDirectory(realname)) || - (!this->ListDirs && last && - kwsys::SystemTools::FileIsDirectory(realname))) { - continue; - } - - if (this->Internals->Expressions[start].find(fname)) { - if (last) { - this->AddFile(this->Internals->Files, realname); - } else { - this->ProcessDirectory(start + 1, realname, messages); - } - } - } -} - -bool Glob::FindFiles(const std::string& inexpr, GlobMessages* messages) -{ - std::string cexpr; - std::string::size_type cc; - std::string expr = inexpr; - - this->Internals->Expressions.clear(); - this->Internals->Files.clear(); - - if (!kwsys::SystemTools::FileIsFullPath(expr)) { - expr = kwsys::SystemTools::GetCurrentWorkingDirectory(); - expr += "/" + inexpr; - } - std::string fexpr = expr; - - std::string::size_type skip = 0; - std::string::size_type last_slash = 0; - for (cc = 0; cc < expr.size(); cc++) { - if (cc > 0 && expr[cc] == '/' && expr[cc - 1] != '\\') { - last_slash = cc; - } - if (cc > 0 && (expr[cc] == '[' || expr[cc] == '?' || expr[cc] == '*') && - expr[cc - 1] != '\\') { - break; - } - } - if (last_slash > 0) { - // std::cout << "I can skip: " << fexpr.substr(0, last_slash) - // << std::endl; - skip = last_slash; - } - if (skip == 0) { -#if defined(KWSYS_GLOB_SUPPORT_NETWORK_PATHS) - // Handle network paths - if (expr[0] == '/' && expr[1] == '/') { - int cnt = 0; - for (cc = 2; cc < expr.size(); cc++) { - if (expr[cc] == '/') { - cnt++; - if (cnt == 2) { - break; - } - } - } - skip = int(cc + 1); - } else -#endif - // Handle drive letters on Windows - if (expr[1] == ':' && expr[0] != '/') { - skip = 2; - } - } - - if (skip > 0) { - expr = expr.substr(skip); - } - - cexpr = ""; - for (cc = 0; cc < expr.size(); cc++) { - int ch = expr[cc]; - if (ch == '/') { - if (!cexpr.empty()) { - this->AddExpression(cexpr); - } - cexpr = ""; - } else { - cexpr.append(1, static_cast(ch)); - } - } - if (!cexpr.empty()) { - this->AddExpression(cexpr); - } - - // Handle network paths - if (skip > 0) { - this->ProcessDirectory(0, fexpr.substr(0, skip) + "/", messages); - } else { - this->ProcessDirectory(0, "/", messages); - } - return true; -} - -void Glob::AddExpression(const std::string& expr) -{ - this->Internals->Expressions.push_back( - kwsys::RegularExpression(this->PatternToRegex(expr))); -} - -void Glob::SetRelative(const char* dir) -{ - if (!dir) { - this->Relative = ""; - return; - } - this->Relative = dir; -} - -const char* Glob::GetRelative() -{ - if (this->Relative.empty()) { - return nullptr; - } - return this->Relative.c_str(); -} - -void Glob::AddFile(std::vector& files, const std::string& file) -{ - if (!this->Relative.empty()) { - files.push_back(kwsys::SystemTools::RelativePath(this->Relative, file)); - } else { - files.push_back(file); - } -} - -} // namespace KWSYS_NAMESPACE diff --git a/test/API/driver/kwsys/Glob.hxx.in b/test/API/driver/kwsys/Glob.hxx.in deleted file mode 100644 index 170766f..0000000 --- a/test/API/driver/kwsys/Glob.hxx.in +++ /dev/null @@ -1,134 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifndef @KWSYS_NAMESPACE@_Glob_hxx -#define @KWSYS_NAMESPACE@_Glob_hxx - -#include <@KWSYS_NAMESPACE@/Configure.h> -#include <@KWSYS_NAMESPACE@/Configure.hxx> - -#include -#include - -namespace @KWSYS_NAMESPACE@ { - -class GlobInternals; - -/** \class Glob - * \brief Portable globbing searches. - * - * Globbing expressions are much simpler than regular - * expressions. This class will search for files using - * globbing expressions. - * - * Finds all files that match a given globbing expression. - */ -class @KWSYS_NAMESPACE@_EXPORT Glob -{ -public: - enum MessageType - { - error, - cyclicRecursion - }; - - struct Message - { - MessageType type; - std::string content; - - Message(MessageType t, const std::string& c) - : type(t) - , content(c) - { - } - ~Message() = default; - Message(const Message& msg) = default; - Message& operator=(Message const& msg) = default; - }; - - typedef std::vector GlobMessages; - typedef std::vector::iterator GlobMessagesIterator; - -public: - Glob(); - ~Glob(); - - //! Find all files that match the pattern. - bool FindFiles(const std::string& inexpr, GlobMessages* messages = nullptr); - - //! Return the list of files that matched. - std::vector& GetFiles(); - - //! Set recurse to true to match subdirectories. - void RecurseOn() { this->SetRecurse(true); } - void RecurseOff() { this->SetRecurse(false); } - void SetRecurse(bool i) { this->Recurse = i; } - bool GetRecurse() { return this->Recurse; } - - //! Set recurse through symlinks to true if recursion should traverse the - // linked-to directories - void RecurseThroughSymlinksOn() { this->SetRecurseThroughSymlinks(true); } - void RecurseThroughSymlinksOff() { this->SetRecurseThroughSymlinks(false); } - void SetRecurseThroughSymlinks(bool i) { this->RecurseThroughSymlinks = i; } - bool GetRecurseThroughSymlinks() { return this->RecurseThroughSymlinks; } - - //! Get the number of symlinks followed through recursion - unsigned int GetFollowedSymlinkCount() { return this->FollowedSymlinkCount; } - - //! Set relative to true to only show relative path to files. - void SetRelative(const char* dir); - const char* GetRelative(); - - /** Convert the given globbing pattern to a regular expression. - There is no way to quote meta-characters. The - require_whole_string argument specifies whether the regex is - automatically surrounded by "^" and "$" to match the whole - string. This is on by default because patterns always match - whole strings, but may be disabled to support concatenating - expressions more easily (regex1|regex2|etc). */ - static std::string PatternToRegex(const std::string& pattern, - bool require_whole_string = true, - bool preserve_case = false); - - /** Getters and setters for enabling and disabling directory - listing in recursive and non recursive globbing mode. - If listing is enabled in recursive mode it also lists - directory symbolic links even if follow symlinks is enabled. */ - void SetListDirs(bool list) { this->ListDirs = list; } - bool GetListDirs() const { return this->ListDirs; } - void SetRecurseListDirs(bool list) { this->RecurseListDirs = list; } - bool GetRecurseListDirs() const { return this->RecurseListDirs; } - -protected: - //! Process directory - void ProcessDirectory(std::string::size_type start, const std::string& dir, - GlobMessages* messages); - - //! Process last directory, but only when recurse flags is on. That is - // effectively like saying: /path/to/file/**/file - bool RecurseDirectory(std::string::size_type start, const std::string& dir, - GlobMessages* messages); - - //! Add regular expression - void AddExpression(const std::string& expr); - - //! Add a file to the list - void AddFile(std::vector& files, const std::string& file); - - GlobInternals* Internals; - bool Recurse; - std::string Relative; - bool RecurseThroughSymlinks; - unsigned int FollowedSymlinkCount; - std::vector VisitedSymlinks; - bool ListDirs; - bool RecurseListDirs; - -private: - Glob(const Glob&); // Not implemented. - void operator=(const Glob&); // Not implemented. -}; - -} // namespace @KWSYS_NAMESPACE@ - -#endif diff --git a/test/API/driver/kwsys/IOStream.cxx b/test/API/driver/kwsys/IOStream.cxx deleted file mode 100644 index e21f87d..0000000 --- a/test/API/driver/kwsys/IOStream.cxx +++ /dev/null @@ -1,255 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include "kwsysPrivate.h" -#include KWSYS_HEADER(Configure.hxx) - -// Include the streams library. -#include -#include KWSYS_HEADER(IOStream.hxx) - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -# include "Configure.hxx.in" -# include "IOStream.hxx.in" -#endif - -// Implement the rest of this file only if it is needed. -#if KWSYS_IOS_NEED_OPERATORS_LL - -# include // sscanf, sprintf -# include // memchr - -# if defined(_MAX_INT_DIG) -# define KWSYS_IOS_INT64_MAX_DIG _MAX_INT_DIG -# else -# define KWSYS_IOS_INT64_MAX_DIG 32 -# endif - -namespace KWSYS_NAMESPACE { - -// Scan an input stream for an integer value. -static int IOStreamScanStream(std::istream& is, char* buffer) -{ - // Prepare to write to buffer. - char* out = buffer; - char* end = buffer + KWSYS_IOS_INT64_MAX_DIG - 1; - - // Look for leading sign. - if (is.peek() == '+') { - *out++ = '+'; - is.ignore(); - } else if (is.peek() == '-') { - *out++ = '-'; - is.ignore(); - } - - // Determine the base. If not specified in the stream, try to - // detect it from the input. A leading 0x means hex, and a leading - // 0 alone means octal. - int base = 0; - int flags = is.flags() & std::ios_base::basefield; - if (flags == std::ios_base::oct) { - base = 8; - } else if (flags == std::ios_base::dec) { - base = 10; - } else if (flags == std::ios_base::hex) { - base = 16; - } - bool foundDigit = false; - bool foundNonZero = false; - if (is.peek() == '0') { - foundDigit = true; - is.ignore(); - if ((is.peek() == 'x' || is.peek() == 'X') && (base == 0 || base == 16)) { - base = 16; - foundDigit = false; - is.ignore(); - } else if (base == 0) { - base = 8; - } - } - - // Determine the range of digits allowed for this number. - const char* digits = "0123456789abcdefABCDEF"; - int maxDigitIndex = 10; - if (base == 8) { - maxDigitIndex = 8; - } else if (base == 16) { - maxDigitIndex = 10 + 6 + 6; - } - - // Scan until an invalid digit is found. - for (; is.peek() != EOF; is.ignore()) { - if (memchr(digits, *out = (char)is.peek(), maxDigitIndex) != 0) { - if ((foundNonZero || *out != '0') && out < end) { - ++out; - foundNonZero = true; - } - foundDigit = true; - } else { - break; - } - } - - // Correct the buffer contents for degenerate cases. - if (foundDigit && !foundNonZero) { - *out++ = '0'; - } else if (!foundDigit) { - out = buffer; - } - - // Terminate the string in the buffer. - *out = '\0'; - - return base; -} - -// Read an integer value from an input stream. -template -std::istream& IOStreamScanTemplate(std::istream& is, T& value, char type) -{ - int state = std::ios_base::goodbit; - - // Skip leading whitespace. - std::istream::sentry okay(is); - - if (okay) { - try { - // Copy the string to a buffer and construct the format string. - char buffer[KWSYS_IOS_INT64_MAX_DIG]; -# if defined(_MSC_VER) - char format[] = "%I64_"; - const int typeIndex = 4; -# else - char format[] = "%ll_"; - const int typeIndex = 3; -# endif - switch (IOStreamScanStream(is, buffer)) { - case 8: - format[typeIndex] = 'o'; - break; - case 0: // Default to decimal if not told otherwise. - case 10: - format[typeIndex] = type; - break; - case 16: - format[typeIndex] = 'x'; - break; - }; - - // Use sscanf to parse the number from the buffer. - T result; - int success = (sscanf(buffer, format, &result) == 1) ? 1 : 0; - - // Set flags for resulting state. - if (is.peek() == EOF) { - state |= std::ios_base::eofbit; - } - if (!success) { - state |= std::ios_base::failbit; - } else { - value = result; - } - } catch (...) { - state |= std::ios_base::badbit; - } - } - - is.setstate(std::ios_base::iostate(state)); - return is; -} - -// Print an integer value to an output stream. -template -std::ostream& IOStreamPrintTemplate(std::ostream& os, T value, char type) -{ - std::ostream::sentry okay(os); - if (okay) { - try { - // Construct the format string. - char format[8]; - char* f = format; - *f++ = '%'; - if (os.flags() & std::ios_base::showpos) { - *f++ = '+'; - } - if (os.flags() & std::ios_base::showbase) { - *f++ = '#'; - } -# if defined(_MSC_VER) - *f++ = 'I'; - *f++ = '6'; - *f++ = '4'; -# else - *f++ = 'l'; - *f++ = 'l'; -# endif - long bflags = os.flags() & std::ios_base::basefield; - if (bflags == std::ios_base::oct) { - *f++ = 'o'; - } else if (bflags != std::ios_base::hex) { - *f++ = type; - } else if (os.flags() & std::ios_base::uppercase) { - *f++ = 'X'; - } else { - *f++ = 'x'; - } - *f = '\0'; - - // Use sprintf to print to a buffer and then write the - // buffer to the stream. - char buffer[2 * KWSYS_IOS_INT64_MAX_DIG]; - sprintf(buffer, format, value); - os << buffer; - } catch (...) { - os.clear(os.rdstate() | std::ios_base::badbit); - } - } - return os; -} - -# if !KWSYS_IOS_HAS_ISTREAM_LONG_LONG -// Implement input stream operator for IOStreamSLL. -std::istream& IOStreamScan(std::istream& is, IOStreamSLL& value) -{ - return IOStreamScanTemplate(is, value, 'd'); -} - -// Implement input stream operator for IOStreamULL. -std::istream& IOStreamScan(std::istream& is, IOStreamULL& value) -{ - return IOStreamScanTemplate(is, value, 'u'); -} -# endif - -# if !KWSYS_IOS_HAS_OSTREAM_LONG_LONG -// Implement output stream operator for IOStreamSLL. -std::ostream& IOStreamPrint(std::ostream& os, IOStreamSLL value) -{ - return IOStreamPrintTemplate(os, value, 'd'); -} - -// Implement output stream operator for IOStreamULL. -std::ostream& IOStreamPrint(std::ostream& os, IOStreamULL value) -{ - return IOStreamPrintTemplate(os, value, 'u'); -} -# endif - -} // namespace KWSYS_NAMESPACE - -#else - -namespace KWSYS_NAMESPACE { - -// Create one public symbol in this object file to avoid warnings from -// archivers. -void IOStreamSymbolToAvoidWarning(); -void IOStreamSymbolToAvoidWarning() -{ -} - -} // namespace KWSYS_NAMESPACE - -#endif // KWSYS_IOS_NEED_OPERATORS_LL diff --git a/test/API/driver/kwsys/IOStream.hxx.in b/test/API/driver/kwsys/IOStream.hxx.in deleted file mode 100644 index db8a23e..0000000 --- a/test/API/driver/kwsys/IOStream.hxx.in +++ /dev/null @@ -1,126 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifndef @KWSYS_NAMESPACE@_IOStream_hxx -#define @KWSYS_NAMESPACE@_IOStream_hxx - -#include - -/* Define these macros temporarily to keep the code readable. */ -#if !defined(KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS -# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT -#endif - -/* Whether istream supports long long. */ -#define @KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG \ - @KWSYS_IOS_HAS_ISTREAM_LONG_LONG@ - -/* Whether ostream supports long long. */ -#define @KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG \ - @KWSYS_IOS_HAS_OSTREAM_LONG_LONG@ - -/* Determine whether we need to define the streaming operators for - long long or __int64. */ -#if @KWSYS_USE_LONG_LONG@ -# if !@KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG || \ - !@KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG -# define @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL 1 -namespace @KWSYS_NAMESPACE@ { -typedef long long IOStreamSLL; -typedef unsigned long long IOStreamULL; -} -# endif -#elif defined(_MSC_VER) && _MSC_VER < 1300 -# define @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL 1 -namespace @KWSYS_NAMESPACE@ { -typedef __int64 IOStreamSLL; -typedef unsigned __int64 IOStreamULL; -} -#endif -#if !defined(@KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL) -# define @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL 0 -#endif - -#if @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL -# if !@KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG - -/* Input stream operator implementation functions. */ -namespace @KWSYS_NAMESPACE@ { -kwsysEXPORT std::istream& IOStreamScan(std::istream&, IOStreamSLL&); -kwsysEXPORT std::istream& IOStreamScan(std::istream&, IOStreamULL&); -} - -/* Provide input stream operator for long long. */ -# if !defined(@KWSYS_NAMESPACE@_IOS_NO_ISTREAM_LONG_LONG) && \ - !defined(KWSYS_IOS_ISTREAM_LONG_LONG_DEFINED) -# define KWSYS_IOS_ISTREAM_LONG_LONG_DEFINED -# define @KWSYS_NAMESPACE@_IOS_ISTREAM_LONG_LONG_DEFINED -inline std::istream& operator>>(std::istream& is, - @KWSYS_NAMESPACE@::IOStreamSLL& value) -{ - return @KWSYS_NAMESPACE@::IOStreamScan(is, value); -} -# endif - -/* Provide input stream operator for unsigned long long. */ -# if !defined(@KWSYS_NAMESPACE@_IOS_NO_ISTREAM_UNSIGNED_LONG_LONG) && \ - !defined(KWSYS_IOS_ISTREAM_UNSIGNED_LONG_LONG_DEFINED) -# define KWSYS_IOS_ISTREAM_UNSIGNED_LONG_LONG_DEFINED -# define @KWSYS_NAMESPACE@_IOS_ISTREAM_UNSIGNED_LONG_LONG_DEFINED -inline std::istream& operator>>(std::istream& is, - @KWSYS_NAMESPACE@::IOStreamULL& value) -{ - return @KWSYS_NAMESPACE@::IOStreamScan(is, value); -} -# endif -# endif /* !@KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG */ - -# if !@KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG - -/* Output stream operator implementation functions. */ -namespace @KWSYS_NAMESPACE@ { -kwsysEXPORT std::ostream& IOStreamPrint(std::ostream&, IOStreamSLL); -kwsysEXPORT std::ostream& IOStreamPrint(std::ostream&, IOStreamULL); -} - -/* Provide output stream operator for long long. */ -# if !defined(@KWSYS_NAMESPACE@_IOS_NO_OSTREAM_LONG_LONG) && \ - !defined(KWSYS_IOS_OSTREAM_LONG_LONG_DEFINED) -# define KWSYS_IOS_OSTREAM_LONG_LONG_DEFINED -# define @KWSYS_NAMESPACE@_IOS_OSTREAM_LONG_LONG_DEFINED -inline std::ostream& operator<<(std::ostream& os, - @KWSYS_NAMESPACE@::IOStreamSLL value) -{ - return @KWSYS_NAMESPACE@::IOStreamPrint(os, value); -} -# endif - -/* Provide output stream operator for unsigned long long. */ -# if !defined(@KWSYS_NAMESPACE@_IOS_NO_OSTREAM_UNSIGNED_LONG_LONG) && \ - !defined(KWSYS_IOS_OSTREAM_UNSIGNED_LONG_LONG_DEFINED) -# define KWSYS_IOS_OSTREAM_UNSIGNED_LONG_LONG_DEFINED -# define @KWSYS_NAMESPACE@_IOS_OSTREAM_UNSIGNED_LONG_LONG_DEFINED -inline std::ostream& operator<<(std::ostream& os, - @KWSYS_NAMESPACE@::IOStreamULL value) -{ - return @KWSYS_NAMESPACE@::IOStreamPrint(os, value); -} -# endif -# endif /* !@KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG */ -#endif /* @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL */ - -/* Undefine temporary macros. */ -#if !defined(KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS -# undef kwsysEXPORT -#endif - -/* If building a C++ file in kwsys itself, give the source file - access to the macros without a configured namespace. */ -#if defined(KWSYS_NAMESPACE) -# define KWSYS_IOS_HAS_ISTREAM_LONG_LONG \ - @KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG -# define KWSYS_IOS_HAS_OSTREAM_LONG_LONG \ - @KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG -# define KWSYS_IOS_NEED_OPERATORS_LL @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL -#endif - -#endif diff --git a/test/API/driver/kwsys/MD5.c b/test/API/driver/kwsys/MD5.c deleted file mode 100644 index 97cf9ba..0000000 --- a/test/API/driver/kwsys/MD5.c +++ /dev/null @@ -1,494 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include "kwsysPrivate.h" -#include KWSYS_HEADER(MD5.h) - -/* Work-around CMake dependency scanning limitation. This must - duplicate the above list of headers. */ -#if 0 -# include "MD5.h.in" -#endif - -#include /* size_t */ -#include /* malloc, free */ -#include /* memcpy, strlen */ - -/* This MD5 implementation has been taken from a third party. Slight - modifications to the arrangement of the code have been made to put - it in a single source file instead of a separate header and - implementation file. */ - -#if defined(__clang__) && !defined(__INTEL_COMPILER) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wcast-align" -#endif - -/* - Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - L. Peter Deutsch - ghost@aladdin.com - - */ -/* - Independent implementation of MD5 (RFC 1321). - - This code implements the MD5 Algorithm defined in RFC 1321, whose - text is available at - http://www.ietf.org/rfc/rfc1321.txt - The code is derived from the text of the RFC, including the test suite - (section A.5) but excluding the rest of Appendix A. It does not include - any code or documentation that is identified in the RFC as being - copyrighted. - - The original and principal author of md5.c is L. Peter Deutsch - . Other authors are noted in the change history - that follows (in reverse chronological order): - - 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order - either statically or dynamically; added missing #include - in library. - 2002-03-11 lpd Corrected argument list for main(), and added int return - type, in test program and T value program. - 2002-02-21 lpd Added missing #include in test program. - 2000-07-03 lpd Patched to eliminate warnings about "constant is - unsigned in ANSI C, signed in traditional"; made test program - self-checking. - 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. - 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). - 1999-05-03 lpd Original version. - */ - -/* - * This package supports both compile-time and run-time determination of CPU - * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be - * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is - * defined as non-zero, the code will be compiled to run only on big-endian - * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to - * run on either big- or little-endian CPUs, but will run slightly less - * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. - */ - -typedef unsigned char md5_byte_t; /* 8-bit byte */ -typedef unsigned int md5_word_t; /* 32-bit word */ - -/* Define the state of the MD5 Algorithm. */ -typedef struct md5_state_s -{ - md5_word_t count[2]; /* message length in bits, lsw first */ - md5_word_t abcd[4]; /* digest buffer */ - md5_byte_t buf[64]; /* accumulate block */ -} md5_state_t; - -#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ -#ifdef ARCH_IS_BIG_ENDIAN -# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) -#else -# define BYTE_ORDER 0 -#endif - -#define T_MASK ((md5_word_t)~0) -#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) -#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) -#define T3 0x242070db -#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) -#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) -#define T6 0x4787c62a -#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) -#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) -#define T9 0x698098d8 -#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) -#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) -#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) -#define T13 0x6b901122 -#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) -#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) -#define T16 0x49b40821 -#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) -#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) -#define T19 0x265e5a51 -#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) -#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) -#define T22 0x02441453 -#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) -#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) -#define T25 0x21e1cde6 -#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) -#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) -#define T28 0x455a14ed -#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) -#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) -#define T31 0x676f02d9 -#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) -#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) -#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) -#define T35 0x6d9d6122 -#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) -#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) -#define T38 0x4bdecfa9 -#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) -#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) -#define T41 0x289b7ec6 -#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) -#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) -#define T44 0x04881d05 -#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) -#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) -#define T47 0x1fa27cf8 -#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) -#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) -#define T50 0x432aff97 -#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) -#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) -#define T53 0x655b59c3 -#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) -#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) -#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) -#define T57 0x6fa87e4f -#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) -#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) -#define T60 0x4e0811a1 -#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) -#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) -#define T63 0x2ad7d2bb -#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) - -static void md5_process(md5_state_t* pms, const md5_byte_t* data /*[64]*/) -{ - md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], - d = pms->abcd[3]; - md5_word_t t; -#if BYTE_ORDER > 0 - /* Define storage only for big-endian CPUs. */ - md5_word_t X[16]; -#else - /* Define storage for little-endian or both types of CPUs. */ - md5_word_t xbuf[16]; - const md5_word_t* X; -#endif - - { -#if BYTE_ORDER == 0 - /* - * Determine dynamically whether this is a big-endian or - * little-endian machine, since we can use a more efficient - * algorithm on the latter. - */ - static const int w = 1; - - if (*((const md5_byte_t*)&w)) /* dynamic little-endian */ -#endif -#if BYTE_ORDER <= 0 /* little-endian */ - { - /* - * On little-endian machines, we can process properly aligned - * data without copying it. - */ - if (!((data - (const md5_byte_t*)0) & 3)) { - /* data are properly aligned */ - X = (const md5_word_t*)data; - } else { - /* not aligned */ - memcpy(xbuf, data, 64); - X = xbuf; - } - } -#endif -#if BYTE_ORDER == 0 - else /* dynamic big-endian */ -#endif -#if BYTE_ORDER >= 0 /* big-endian */ - { - /* - * On big-endian machines, we must arrange the bytes in the - * right order. - */ - const md5_byte_t* xp = data; - int i; - -# if BYTE_ORDER == 0 - X = xbuf; /* (dynamic only) */ -# else -# define xbuf X /* (static only) */ -# endif - for (i = 0; i < 16; ++i, xp += 4) - xbuf[i] = - (md5_word_t)(xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24)); - } -#endif - } - -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) - -/* Round 1. */ -/* Let [abcd k s i] denote the operation - a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ -#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) -#define SET(a, b, c, d, k, s, Ti) \ - t = a + F(b, c, d) + X[k] + (Ti); \ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 7, T1); - SET(d, a, b, c, 1, 12, T2); - SET(c, d, a, b, 2, 17, T3); - SET(b, c, d, a, 3, 22, T4); - SET(a, b, c, d, 4, 7, T5); - SET(d, a, b, c, 5, 12, T6); - SET(c, d, a, b, 6, 17, T7); - SET(b, c, d, a, 7, 22, T8); - SET(a, b, c, d, 8, 7, T9); - SET(d, a, b, c, 9, 12, T10); - SET(c, d, a, b, 10, 17, T11); - SET(b, c, d, a, 11, 22, T12); - SET(a, b, c, d, 12, 7, T13); - SET(d, a, b, c, 13, 12, T14); - SET(c, d, a, b, 14, 17, T15); - SET(b, c, d, a, 15, 22, T16); -#undef SET - -/* Round 2. */ -/* Let [abcd k s i] denote the operation - a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ -#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) -#define SET(a, b, c, d, k, s, Ti) \ - t = a + G(b, c, d) + X[k] + (Ti); \ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 1, 5, T17); - SET(d, a, b, c, 6, 9, T18); - SET(c, d, a, b, 11, 14, T19); - SET(b, c, d, a, 0, 20, T20); - SET(a, b, c, d, 5, 5, T21); - SET(d, a, b, c, 10, 9, T22); - SET(c, d, a, b, 15, 14, T23); - SET(b, c, d, a, 4, 20, T24); - SET(a, b, c, d, 9, 5, T25); - SET(d, a, b, c, 14, 9, T26); - SET(c, d, a, b, 3, 14, T27); - SET(b, c, d, a, 8, 20, T28); - SET(a, b, c, d, 13, 5, T29); - SET(d, a, b, c, 2, 9, T30); - SET(c, d, a, b, 7, 14, T31); - SET(b, c, d, a, 12, 20, T32); -#undef SET - -/* Round 3. */ -/* Let [abcd k s t] denote the operation - a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define SET(a, b, c, d, k, s, Ti) \ - t = a + H(b, c, d) + X[k] + (Ti); \ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 5, 4, T33); - SET(d, a, b, c, 8, 11, T34); - SET(c, d, a, b, 11, 16, T35); - SET(b, c, d, a, 14, 23, T36); - SET(a, b, c, d, 1, 4, T37); - SET(d, a, b, c, 4, 11, T38); - SET(c, d, a, b, 7, 16, T39); - SET(b, c, d, a, 10, 23, T40); - SET(a, b, c, d, 13, 4, T41); - SET(d, a, b, c, 0, 11, T42); - SET(c, d, a, b, 3, 16, T43); - SET(b, c, d, a, 6, 23, T44); - SET(a, b, c, d, 9, 4, T45); - SET(d, a, b, c, 12, 11, T46); - SET(c, d, a, b, 15, 16, T47); - SET(b, c, d, a, 2, 23, T48); -#undef SET - -/* Round 4. */ -/* Let [abcd k s t] denote the operation - a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ -#define I(x, y, z) ((y) ^ ((x) | ~(z))) -#define SET(a, b, c, d, k, s, Ti) \ - t = a + I(b, c, d) + X[k] + (Ti); \ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 6, T49); - SET(d, a, b, c, 7, 10, T50); - SET(c, d, a, b, 14, 15, T51); - SET(b, c, d, a, 5, 21, T52); - SET(a, b, c, d, 12, 6, T53); - SET(d, a, b, c, 3, 10, T54); - SET(c, d, a, b, 10, 15, T55); - SET(b, c, d, a, 1, 21, T56); - SET(a, b, c, d, 8, 6, T57); - SET(d, a, b, c, 15, 10, T58); - SET(c, d, a, b, 6, 15, T59); - SET(b, c, d, a, 13, 21, T60); - SET(a, b, c, d, 4, 6, T61); - SET(d, a, b, c, 11, 10, T62); - SET(c, d, a, b, 2, 15, T63); - SET(b, c, d, a, 9, 21, T64); -#undef SET - - /* Then perform the following additions. (That is increment each - of the four registers by the value it had before this block - was started.) */ - pms->abcd[0] += a; - pms->abcd[1] += b; - pms->abcd[2] += c; - pms->abcd[3] += d; -} - -/* Initialize the algorithm. */ -static void md5_init(md5_state_t* pms) -{ - pms->count[0] = pms->count[1] = 0; - pms->abcd[0] = 0x67452301; - pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; - pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; - pms->abcd[3] = 0x10325476; -} - -/* Append a string to the message. */ -static void md5_append(md5_state_t* pms, const md5_byte_t* data, size_t nbytes) -{ - const md5_byte_t* p = data; - size_t left = nbytes; - size_t offset = (pms->count[0] >> 3) & 63; - md5_word_t nbits = (md5_word_t)(nbytes << 3); - - if (nbytes <= 0) - return; - - /* Update the message length. */ - pms->count[1] += (md5_word_t)(nbytes >> 29); - pms->count[0] += nbits; - if (pms->count[0] < nbits) - pms->count[1]++; - - /* Process an initial partial block. */ - if (offset) { - size_t copy = (offset + nbytes > 64 ? 64 - offset : nbytes); - - memcpy(pms->buf + offset, p, copy); - if (offset + copy < 64) - return; - p += copy; - left -= copy; - md5_process(pms, pms->buf); - } - - /* Process full blocks. */ - for (; left >= 64; p += 64, left -= 64) - md5_process(pms, p); - - /* Process a final partial block. */ - if (left) - memcpy(pms->buf, p, left); -} - -/* Finish the message and return the digest. */ -static void md5_finish(md5_state_t* pms, md5_byte_t digest[16]) -{ - static const md5_byte_t pad[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - md5_byte_t data[8]; - int i; - - /* Save the length before padding. */ - for (i = 0; i < 8; ++i) - data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); - /* Pad to 56 bytes mod 64. */ - md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); - /* Append the length. */ - md5_append(pms, data, 8); - for (i = 0; i < 16; ++i) - digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); -} - -#if defined(__clang__) && !defined(__INTEL_COMPILER) -# pragma clang diagnostic pop -#endif - -/* Wrap up the MD5 state in our opaque structure. */ -struct kwsysMD5_s -{ - md5_state_t md5_state; -}; - -kwsysMD5* kwsysMD5_New(void) -{ - /* Allocate a process control structure. */ - kwsysMD5* md5 = (kwsysMD5*)malloc(sizeof(kwsysMD5)); - if (!md5) { - return 0; - } - return md5; -} - -void kwsysMD5_Delete(kwsysMD5* md5) -{ - /* Make sure we have an instance. */ - if (!md5) { - return; - } - - /* Free memory. */ - free(md5); -} - -void kwsysMD5_Initialize(kwsysMD5* md5) -{ - md5_init(&md5->md5_state); -} - -void kwsysMD5_Append(kwsysMD5* md5, unsigned char const* data, int length) -{ - size_t dlen; - if (length < 0) { - dlen = strlen((char const*)data); - } else { - dlen = (size_t)length; - } - md5_append(&md5->md5_state, (md5_byte_t const*)data, dlen); -} - -void kwsysMD5_Finalize(kwsysMD5* md5, unsigned char digest[16]) -{ - md5_finish(&md5->md5_state, (md5_byte_t*)digest); -} - -void kwsysMD5_FinalizeHex(kwsysMD5* md5, char buffer[32]) -{ - unsigned char digest[16]; - kwsysMD5_Finalize(md5, digest); - kwsysMD5_DigestToHex(digest, buffer); -} - -void kwsysMD5_DigestToHex(unsigned char const digest[16], char buffer[32]) -{ - /* Map from 4-bit index to hexadecimal representation. */ - static char const hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; - - /* Map each 4-bit block separately. */ - char* out = buffer; - int i; - for (i = 0; i < 16; ++i) { - *out++ = hex[digest[i] >> 4]; - *out++ = hex[digest[i] & 0xF]; - } -} diff --git a/test/API/driver/kwsys/MD5.h.in b/test/API/driver/kwsys/MD5.h.in deleted file mode 100644 index 7646f12..0000000 --- a/test/API/driver/kwsys/MD5.h.in +++ /dev/null @@ -1,97 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifndef @KWSYS_NAMESPACE@_MD5_h -#define @KWSYS_NAMESPACE@_MD5_h - -#include <@KWSYS_NAMESPACE@/Configure.h> - -/* Redefine all public interface symbol names to be in the proper - namespace. These macros are used internally to kwsys only, and are - not visible to user code. Use kwsysHeaderDump.pl to reproduce - these macros after making changes to the interface. */ -#if !defined(KWSYS_NAMESPACE) -# define kwsys_ns(x) @KWSYS_NAMESPACE@##x -# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT -#endif -#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS -# define kwsysMD5 kwsys_ns(MD5) -# define kwsysMD5_s kwsys_ns(MD5_s) -# define kwsysMD5_New kwsys_ns(MD5_New) -# define kwsysMD5_Delete kwsys_ns(MD5_Delete) -# define kwsysMD5_Initialize kwsys_ns(MD5_Initialize) -# define kwsysMD5_Append kwsys_ns(MD5_Append) -# define kwsysMD5_Finalize kwsys_ns(MD5_Finalize) -# define kwsysMD5_FinalizeHex kwsys_ns(MD5_FinalizeHex) -# define kwsysMD5_DigestToHex kwsys_ns(MD5_DigestToHex) -#endif - -#if defined(__cplusplus) -extern "C" { -#endif - -/** - * MD5 state data structure. - */ -typedef struct kwsysMD5_s kwsysMD5; - -/** - * Create a new MD5 instance. The returned instance is not initialized. - */ -kwsysEXPORT kwsysMD5* kwsysMD5_New(void); - -/** - * Delete an old MD5 instance. - */ -kwsysEXPORT void kwsysMD5_Delete(kwsysMD5* md5); - -/** - * Initialize a new MD5 digest. - */ -kwsysEXPORT void kwsysMD5_Initialize(kwsysMD5* md5); - -/** - * Append data to an MD5 digest. If the given length is negative, - * data will be read up to but not including a terminating null. - */ -kwsysEXPORT void kwsysMD5_Append(kwsysMD5* md5, unsigned char const* data, - int length); - -/** - * Finalize a MD5 digest and get the 16-byte hash value. - */ -kwsysEXPORT void kwsysMD5_Finalize(kwsysMD5* md5, unsigned char digest[16]); - -/** - * Finalize a MD5 digest and get the 32-bit hexadecimal representation. - */ -kwsysEXPORT void kwsysMD5_FinalizeHex(kwsysMD5* md5, char buffer[32]); - -/** - * Convert a MD5 digest 16-byte value to a 32-byte hexadecimal representation. - */ -kwsysEXPORT void kwsysMD5_DigestToHex(unsigned char const digest[16], - char buffer[32]); - -#if defined(__cplusplus) -} /* extern "C" */ -#endif - -/* If we are building a kwsys .c or .cxx file, let it use these macros. - Otherwise, undefine them to keep the namespace clean. */ -#if !defined(KWSYS_NAMESPACE) -# undef kwsys_ns -# undef kwsysEXPORT -# if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS -# undef kwsysMD5 -# undef kwsysMD5_s -# undef kwsysMD5_New -# undef kwsysMD5_Delete -# undef kwsysMD5_Initialize -# undef kwsysMD5_Append -# undef kwsysMD5_Finalize -# undef kwsysMD5_FinalizeHex -# undef kwsysMD5_DigestToHex -# endif -#endif - -#endif diff --git a/test/API/driver/kwsys/Process.h.in b/test/API/driver/kwsys/Process.h.in deleted file mode 100644 index 73ea9db..0000000 --- a/test/API/driver/kwsys/Process.h.in +++ /dev/null @@ -1,544 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifndef @KWSYS_NAMESPACE@_Process_h -#define @KWSYS_NAMESPACE@_Process_h - -#include <@KWSYS_NAMESPACE@/Configure.h> - -/* Redefine all public interface symbol names to be in the proper - namespace. These macros are used internally to kwsys only, and are - not visible to user code. Use kwsysHeaderDump.pl to reproduce - these macros after making changes to the interface. */ -#if !defined(KWSYS_NAMESPACE) -# define kwsys_ns(x) @KWSYS_NAMESPACE@##x -# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT -#endif -#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS -# define kwsysProcess kwsys_ns(Process) -# define kwsysProcess_s kwsys_ns(Process_s) -# define kwsysProcess_New kwsys_ns(Process_New) -# define kwsysProcess_Delete kwsys_ns(Process_Delete) -# define kwsysProcess_SetCommand kwsys_ns(Process_SetCommand) -# define kwsysProcess_AddCommand kwsys_ns(Process_AddCommand) -# define kwsysProcess_SetTimeout kwsys_ns(Process_SetTimeout) -# define kwsysProcess_SetWorkingDirectory \ - kwsys_ns(Process_SetWorkingDirectory) -# define kwsysProcess_SetPipeFile kwsys_ns(Process_SetPipeFile) -# define kwsysProcess_SetPipeNative kwsys_ns(Process_SetPipeNative) -# define kwsysProcess_SetPipeShared kwsys_ns(Process_SetPipeShared) -# define kwsysProcess_Option_Detach kwsys_ns(Process_Option_Detach) -# define kwsysProcess_Option_HideWindow kwsys_ns(Process_Option_HideWindow) -# define kwsysProcess_Option_MergeOutput kwsys_ns(Process_Option_MergeOutput) -# define kwsysProcess_Option_Verbatim kwsys_ns(Process_Option_Verbatim) -# define kwsysProcess_Option_CreateProcessGroup \ - kwsys_ns(Process_Option_CreateProcessGroup) -# define kwsysProcess_GetOption kwsys_ns(Process_GetOption) -# define kwsysProcess_SetOption kwsys_ns(Process_SetOption) -# define kwsysProcess_Option_e kwsys_ns(Process_Option_e) -# define kwsysProcess_State_Starting kwsys_ns(Process_State_Starting) -# define kwsysProcess_State_Error kwsys_ns(Process_State_Error) -# define kwsysProcess_State_Exception kwsys_ns(Process_State_Exception) -# define kwsysProcess_State_Executing kwsys_ns(Process_State_Executing) -# define kwsysProcess_State_Exited kwsys_ns(Process_State_Exited) -# define kwsysProcess_State_Expired kwsys_ns(Process_State_Expired) -# define kwsysProcess_State_Killed kwsys_ns(Process_State_Killed) -# define kwsysProcess_State_Disowned kwsys_ns(Process_State_Disowned) -# define kwsysProcess_State_e kwsys_ns(Process_State_e) -# define kwsysProcess_Exception_None kwsys_ns(Process_Exception_None) -# define kwsysProcess_Exception_Fault kwsys_ns(Process_Exception_Fault) -# define kwsysProcess_Exception_Illegal kwsys_ns(Process_Exception_Illegal) -# define kwsysProcess_Exception_Interrupt \ - kwsys_ns(Process_Exception_Interrupt) -# define kwsysProcess_Exception_Numerical \ - kwsys_ns(Process_Exception_Numerical) -# define kwsysProcess_Exception_Other kwsys_ns(Process_Exception_Other) -# define kwsysProcess_Exception_e kwsys_ns(Process_Exception_e) -# define kwsysProcess_GetState kwsys_ns(Process_GetState) -# define kwsysProcess_GetExitException kwsys_ns(Process_GetExitException) -# define kwsysProcess_GetExitCode kwsys_ns(Process_GetExitCode) -# define kwsysProcess_GetExitValue kwsys_ns(Process_GetExitValue) -# define kwsysProcess_GetErrorString kwsys_ns(Process_GetErrorString) -# define kwsysProcess_GetExceptionString kwsys_ns(Process_GetExceptionString) -# define kwsysProcess_GetStateByIndex kwsys_ns(Process_GetStateByIndex) -# define kwsysProcess_GetExitExceptionByIndex \ - kwsys_ns(Process_GetExitExceptionByIndex) -# define kwsysProcess_GetExitCodeByIndex kwsys_ns(Process_GetExitCodeByIndex) -# define kwsysProcess_GetExitValueByIndex \ - kwsys_ns(Process_GetExitValueByIndex) -# define kwsysProcess_GetExceptionStringByIndex \ - kwsys_ns(Process_GetExceptionStringByIndex) -# define kwsysProcess_GetExitCodeByIndex kwsys_ns(Process_GetExitCodeByIndex) -# define kwsysProcess_Execute kwsys_ns(Process_Execute) -# define kwsysProcess_Disown kwsys_ns(Process_Disown) -# define kwsysProcess_WaitForData kwsys_ns(Process_WaitForData) -# define kwsysProcess_Pipes_e kwsys_ns(Process_Pipes_e) -# define kwsysProcess_Pipe_None kwsys_ns(Process_Pipe_None) -# define kwsysProcess_Pipe_STDIN kwsys_ns(Process_Pipe_STDIN) -# define kwsysProcess_Pipe_STDOUT kwsys_ns(Process_Pipe_STDOUT) -# define kwsysProcess_Pipe_STDERR kwsys_ns(Process_Pipe_STDERR) -# define kwsysProcess_Pipe_Timeout kwsys_ns(Process_Pipe_Timeout) -# define kwsysProcess_Pipe_Handle kwsys_ns(Process_Pipe_Handle) -# define kwsysProcess_WaitForExit kwsys_ns(Process_WaitForExit) -# define kwsysProcess_Interrupt kwsys_ns(Process_Interrupt) -# define kwsysProcess_Kill kwsys_ns(Process_Kill) -# define kwsysProcess_KillPID kwsys_ns(Process_KillPID) -# define kwsysProcess_ResetStartTime kwsys_ns(Process_ResetStartTime) -#endif - -#if defined(__cplusplus) -extern "C" { -#endif - -/** - * Process control data structure. - */ -typedef struct kwsysProcess_s kwsysProcess; - -/* Platform-specific pipe handle type. */ -#if defined(_WIN32) && !defined(__CYGWIN__) -typedef void* kwsysProcess_Pipe_Handle; -#else -typedef int kwsysProcess_Pipe_Handle; -#endif - -/** - * Create a new Process instance. - */ -kwsysEXPORT kwsysProcess* kwsysProcess_New(void); - -/** - * Delete an existing Process instance. If the instance is currently - * executing a process, this blocks until the process terminates. - */ -kwsysEXPORT void kwsysProcess_Delete(kwsysProcess* cp); - -/** - * Set the command line to be executed. Argument is an array of - * pointers to the command and each argument. The array must end with - * a NULL pointer. Any previous command lines are removed. Returns - * 1 for success and 0 otherwise. - */ -kwsysEXPORT int kwsysProcess_SetCommand(kwsysProcess* cp, - char const* const* command); - -/** - * Add a command line to be executed. Argument is an array of - * pointers to the command and each argument. The array must end with - * a NULL pointer. If this is not the first command added, its - * standard input will be connected to the standard output of the - * previous command. Returns 1 for success and 0 otherwise. - */ -kwsysEXPORT int kwsysProcess_AddCommand(kwsysProcess* cp, - char const* const* command); - -/** - * Set the timeout in seconds for the child process. The timeout - * period begins when the child is executed. If the child has not - * terminated when the timeout expires, it will be killed. A - * non-positive (<= 0) value will disable the timeout. - */ -kwsysEXPORT void kwsysProcess_SetTimeout(kwsysProcess* cp, double timeout); - -/** - * Set the working directory for the child process. The working - * directory can be absolute or relative to the current directory. - * Returns 1 for success and 0 for failure. - */ -kwsysEXPORT int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, - const char* dir); - -/** - * Set the name of a file to be attached to the given pipe. Returns 1 - * for success and 0 for failure. - */ -kwsysEXPORT int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe, - const char* file); - -/** - * Set whether the given pipe in the child is shared with the parent - * process. The default is no for Pipe_STDOUT and Pipe_STDERR and yes - * for Pipe_STDIN. - */ -kwsysEXPORT void kwsysProcess_SetPipeShared(kwsysProcess* cp, int pipe, - int shared); - -/** - * Specify a platform-specific native pipe for use as one of the child - * interface pipes. The native pipe is specified by an array of two - * descriptors or handles. The first entry in the array (index 0) - * should be the read end of the pipe. The second entry in the array - * (index 1) should be the write end of the pipe. If a null pointer - * is given the option will be disabled. - * - * For Pipe_STDIN the native pipe is connected to the first child in - * the pipeline as its stdin. After the children are created the - * write end of the pipe will be closed in the child process and the - * read end will be closed in the parent process. - * - * For Pipe_STDOUT and Pipe_STDERR the pipe is connected to the last - * child as its stdout or stderr. After the children are created the - * write end of the pipe will be closed in the parent process and the - * read end will be closed in the child process. - */ -kwsysEXPORT void kwsysProcess_SetPipeNative(kwsysProcess* cp, int pipe, - kwsysProcess_Pipe_Handle p[2]); - -/** - * Get/Set a possibly platform-specific option. Possible options are: - * - * kwsysProcess_Option_Detach = Whether to detach the process. - * 0 = No (default) - * 1 = Yes - * - * kwsysProcess_Option_HideWindow = Whether to hide window on Windows. - * 0 = No (default) - * 1 = Yes - * - * kwsysProcess_Option_MergeOutput = Whether to merge stdout/stderr. - * No content will be returned as stderr. - * Any actual stderr will be on stdout. - * 0 = No (default) - * 1 = Yes - * - * kwsysProcess_Option_Verbatim = Whether SetCommand and AddCommand - * should treat the first argument - * as a verbatim command line - * and ignore the rest of the arguments. - * 0 = No (default) - * 1 = Yes - * - * kwsysProcess_Option_CreateProcessGroup = Whether to place the process in a - * new process group. This is - * useful if you want to send Ctrl+C - * to the process. On UNIX, also - * places the process in a new - * session. - * 0 = No (default) - * 1 = Yes - */ -kwsysEXPORT int kwsysProcess_GetOption(kwsysProcess* cp, int optionId); -kwsysEXPORT void kwsysProcess_SetOption(kwsysProcess* cp, int optionId, - int value); -enum kwsysProcess_Option_e -{ - kwsysProcess_Option_HideWindow, - kwsysProcess_Option_Detach, - kwsysProcess_Option_MergeOutput, - kwsysProcess_Option_Verbatim, - kwsysProcess_Option_CreateProcessGroup -}; - -/** - * Get the current state of the Process instance. Possible states are: - * - * kwsysProcess_State_Starting = Execute has not yet been called. - * kwsysProcess_State_Error = Error administrating the child process. - * kwsysProcess_State_Exception = Child process exited abnormally. - * kwsysProcess_State_Executing = Child process is currently running. - * kwsysProcess_State_Exited = Child process exited normally. - * kwsysProcess_State_Expired = Child process's timeout expired. - * kwsysProcess_State_Killed = Child process terminated by Kill method. - * kwsysProcess_State_Disowned = Child is no longer managed by this object. - */ -kwsysEXPORT int kwsysProcess_GetState(kwsysProcess* cp); -enum kwsysProcess_State_e -{ - kwsysProcess_State_Starting, - kwsysProcess_State_Error, - kwsysProcess_State_Exception, - kwsysProcess_State_Executing, - kwsysProcess_State_Exited, - kwsysProcess_State_Expired, - kwsysProcess_State_Killed, - kwsysProcess_State_Disowned -}; - -/** - * When GetState returns "Exception", this method returns a - * platform-independent description of the exceptional behavior that - * caused the child to terminate abnormally. Possible exceptions are: - * - * kwsysProcess_Exception_None = No exceptional behavior occurred. - * kwsysProcess_Exception_Fault = Child crashed with a memory fault. - * kwsysProcess_Exception_Illegal = Child crashed with an illegal - * instruction. - * kwsysProcess_Exception_Interrupt = Child was interrupted by user - * (Cntl-C/Break). - * kwsysProcess_Exception_Numerical = Child crashed with a numerical - * exception. - * kwsysProcess_Exception_Other = Child terminated for another reason. - */ -kwsysEXPORT int kwsysProcess_GetExitException(kwsysProcess* cp); -enum kwsysProcess_Exception_e -{ - kwsysProcess_Exception_None, - kwsysProcess_Exception_Fault, - kwsysProcess_Exception_Illegal, - kwsysProcess_Exception_Interrupt, - kwsysProcess_Exception_Numerical, - kwsysProcess_Exception_Other -}; - -/** - * When GetState returns "Exited" or "Exception", this method returns - * the platform-specific raw exit code of the process. UNIX platforms - * should use WIFEXITED/WEXITSTATUS and WIFSIGNALED/WTERMSIG to access - * this value. Windows users should compare the value to the various - * EXCEPTION_* values. - * - * If GetState returns "Exited", use GetExitValue to get the - * platform-independent child return value. - */ -kwsysEXPORT int kwsysProcess_GetExitCode(kwsysProcess* cp); - -/** - * When GetState returns "Exited", this method returns the child's - * platform-independent exit code (such as the value returned by the - * child's main). - */ -kwsysEXPORT int kwsysProcess_GetExitValue(kwsysProcess* cp); - -/** - * When GetState returns "Error", this method returns a string - * describing the problem. Otherwise, it returns NULL. - */ -kwsysEXPORT const char* kwsysProcess_GetErrorString(kwsysProcess* cp); - -/** - * When GetState returns "Exception", this method returns a string - * describing the problem. Otherwise, it returns NULL. - */ -kwsysEXPORT const char* kwsysProcess_GetExceptionString(kwsysProcess* cp); - -/** - * Get the current state of the Process instance. Possible states are: - * - * kwsysProcess_StateByIndex_Starting = Execute has not yet been called. - * kwsysProcess_StateByIndex_Exception = Child process exited abnormally. - * kwsysProcess_StateByIndex_Exited = Child process exited normally. - * kwsysProcess_StateByIndex_Error = Error getting the child return code. - */ -kwsysEXPORT int kwsysProcess_GetStateByIndex(kwsysProcess* cp, int idx); -enum kwsysProcess_StateByIndex_e -{ - kwsysProcess_StateByIndex_Starting = kwsysProcess_State_Starting, - kwsysProcess_StateByIndex_Exception = kwsysProcess_State_Exception, - kwsysProcess_StateByIndex_Exited = kwsysProcess_State_Exited, - kwsysProcess_StateByIndex_Error = kwsysProcess_State_Error -}; - -/** - * When GetState returns "Exception", this method returns a - * platform-independent description of the exceptional behavior that - * caused the child to terminate abnormally. Possible exceptions are: - * - * kwsysProcess_Exception_None = No exceptional behavior occurred. - * kwsysProcess_Exception_Fault = Child crashed with a memory fault. - * kwsysProcess_Exception_Illegal = Child crashed with an illegal - * instruction. - * kwsysProcess_Exception_Interrupt = Child was interrupted by user - * (Cntl-C/Break). - * kwsysProcess_Exception_Numerical = Child crashed with a numerical - * exception. - * kwsysProcess_Exception_Other = Child terminated for another reason. - */ -kwsysEXPORT int kwsysProcess_GetExitExceptionByIndex(kwsysProcess* cp, - int idx); - -/** - * When GetState returns "Exited" or "Exception", this method returns - * the platform-specific raw exit code of the process. UNIX platforms - * should use WIFEXITED/WEXITSTATUS and WIFSIGNALED/WTERMSIG to access - * this value. Windows users should compare the value to the various - * EXCEPTION_* values. - * - * If GetState returns "Exited", use GetExitValue to get the - * platform-independent child return value. - */ -kwsysEXPORT int kwsysProcess_GetExitCodeByIndex(kwsysProcess* cp, int idx); - -/** - * When GetState returns "Exited", this method returns the child's - * platform-independent exit code (such as the value returned by the - * child's main). - */ -kwsysEXPORT int kwsysProcess_GetExitValueByIndex(kwsysProcess* cp, int idx); - -/** - * When GetState returns "Exception", this method returns a string - * describing the problem. Otherwise, it returns NULL. - */ -kwsysEXPORT const char* kwsysProcess_GetExceptionStringByIndex( - kwsysProcess* cp, int idx); - -/** - * Start executing the child process. - */ -kwsysEXPORT void kwsysProcess_Execute(kwsysProcess* cp); - -/** - * Stop management of a detached child process. This closes any pipes - * being read. If the child was not created with the - * kwsysProcess_Option_Detach option, this method does nothing. This - * is because disowning a non-detached process will cause the child - * exit signal to be left unhandled until this process exits. - */ -kwsysEXPORT void kwsysProcess_Disown(kwsysProcess* cp); - -/** - * Block until data are available on a pipe, a timeout expires, or the - * child process terminates. Arguments are as follows: - * - * data = If data are read, the pointer to which this points is - * set to point to the data. - * length = If data are read, the integer to which this points is - * set to the length of the data read. - * timeout = Specifies the maximum time this call may block. Upon - * return after reading data, the time elapsed is subtracted - * from the timeout value. If this timeout expires, the - * value is set to 0. A NULL pointer passed for this argument - * indicates no timeout for the call. A negative or zero - * value passed for this argument may be used for polling - * and will always return immediately. - * - * Return value will be one of: - * - * Pipe_None = No more data will be available from the child process, - * ( == 0) or no process has been executed. WaitForExit should - * be called to wait for the process to terminate. - * Pipe_STDOUT = Data have been read from the child's stdout pipe. - * Pipe_STDERR = Data have been read from the child's stderr pipe. - * Pipe_Timeout = No data available within timeout specified for the - * call. Time elapsed has been subtracted from timeout - * argument. - */ -kwsysEXPORT int kwsysProcess_WaitForData(kwsysProcess* cp, char** data, - int* length, double* timeout); -enum kwsysProcess_Pipes_e -{ - kwsysProcess_Pipe_None, - kwsysProcess_Pipe_STDIN, - kwsysProcess_Pipe_STDOUT, - kwsysProcess_Pipe_STDERR, - kwsysProcess_Pipe_Timeout = 255 -}; - -/** - * Block until the child process terminates or the given timeout - * expires. If no process is running, returns immediately. The - * argument is: - * - * timeout = Specifies the maximum time this call may block. Upon - * returning due to child termination, the elapsed time - * is subtracted from the given value. A NULL pointer - * passed for this argument indicates no timeout for the - * call. - * - * Return value will be one of: - * - * 0 = Child did not terminate within timeout specified for - * the call. Time elapsed has been subtracted from timeout - * argument. - * 1 = Child has terminated or was not running. - */ -kwsysEXPORT int kwsysProcess_WaitForExit(kwsysProcess* cp, double* timeout); - -/** - * Interrupt the process group for the child process that is currently - * running by sending it the appropriate operating-system specific signal. - * The caller should call WaitForExit after this returns to wait for the - * child to terminate. - * - * WARNING: If you didn't specify kwsysProcess_Option_CreateProcessGroup, - * you will interrupt your own process group. - */ -kwsysEXPORT void kwsysProcess_Interrupt(kwsysProcess* cp); - -/** - * Forcefully terminate the child process that is currently running. - * The caller should call WaitForExit after this returns to wait for - * the child to terminate. - */ -kwsysEXPORT void kwsysProcess_Kill(kwsysProcess* cp); - -/** - * Same as kwsysProcess_Kill using process ID to locate process to - * terminate. - * @see kwsysProcess_Kill(kwsysProcess* cp) - */ -kwsysEXPORT void kwsysProcess_KillPID(unsigned long); - -/** - * Reset the start time of the child process to the current time. - */ -kwsysEXPORT void kwsysProcess_ResetStartTime(kwsysProcess* cp); - -#if defined(__cplusplus) -} /* extern "C" */ -#endif - -/* If we are building a kwsys .c or .cxx file, let it use these macros. - Otherwise, undefine them to keep the namespace clean. */ -#if !defined(KWSYS_NAMESPACE) -# undef kwsys_ns -# undef kwsysEXPORT -# if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS -# undef kwsysProcess -# undef kwsysProcess_s -# undef kwsysProcess_New -# undef kwsysProcess_Delete -# undef kwsysProcess_SetCommand -# undef kwsysProcess_AddCommand -# undef kwsysProcess_SetTimeout -# undef kwsysProcess_SetWorkingDirectory -# undef kwsysProcess_SetPipeFile -# undef kwsysProcess_SetPipeNative -# undef kwsysProcess_SetPipeShared -# undef kwsysProcess_Option_Detach -# undef kwsysProcess_Option_HideWindow -# undef kwsysProcess_Option_MergeOutput -# undef kwsysProcess_Option_Verbatim -# undef kwsysProcess_Option_CreateProcessGroup -# undef kwsysProcess_GetOption -# undef kwsysProcess_SetOption -# undef kwsysProcess_Option_e -# undef kwsysProcess_State_Starting -# undef kwsysProcess_State_Error -# undef kwsysProcess_State_Exception -# undef kwsysProcess_State_Executing -# undef kwsysProcess_State_Exited -# undef kwsysProcess_State_Expired -# undef kwsysProcess_State_Killed -# undef kwsysProcess_State_Disowned -# undef kwsysProcess_GetState -# undef kwsysProcess_State_e -# undef kwsysProcess_Exception_None -# undef kwsysProcess_Exception_Fault -# undef kwsysProcess_Exception_Illegal -# undef kwsysProcess_Exception_Interrupt -# undef kwsysProcess_Exception_Numerical -# undef kwsysProcess_Exception_Other -# undef kwsysProcess_GetExitException -# undef kwsysProcess_Exception_e -# undef kwsysProcess_GetExitCode -# undef kwsysProcess_GetExitValue -# undef kwsysProcess_GetErrorString -# undef kwsysProcess_GetExceptionString -# undef kwsysProcess_Execute -# undef kwsysProcess_Disown -# undef kwsysProcess_WaitForData -# undef kwsysProcess_Pipes_e -# undef kwsysProcess_Pipe_None -# undef kwsysProcess_Pipe_STDIN -# undef kwsysProcess_Pipe_STDOUT -# undef kwsysProcess_Pipe_STDERR -# undef kwsysProcess_Pipe_Timeout -# undef kwsysProcess_Pipe_Handle -# undef kwsysProcess_WaitForExit -# undef kwsysProcess_Interrupt -# undef kwsysProcess_Kill -# undef kwsysProcess_ResetStartTime -# endif -#endif - -#endif diff --git a/test/API/driver/kwsys/ProcessUNIX.c b/test/API/driver/kwsys/ProcessUNIX.c deleted file mode 100644 index 100eddc..0000000 --- a/test/API/driver/kwsys/ProcessUNIX.c +++ /dev/null @@ -1,2920 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include "kwsysPrivate.h" -#include KWSYS_HEADER(Process.h) -#include KWSYS_HEADER(System.h) - -/* Work-around CMake dependency scanning limitation. This must - duplicate the above list of headers. */ -#if 0 -# include "Process.h.in" -# include "System.h.in" -#endif - -/* - -Implementation for UNIX - -On UNIX, a child process is forked to exec the program. Three output -pipes are read by the parent process using a select call to block -until data are ready. Two of the pipes are stdout and stderr for the -child. The third is a special pipe populated by a signal handler to -indicate that a child has terminated. This is used in conjunction -with the timeout on the select call to implement a timeout for program -even when it closes stdout and stderr and at the same time avoiding -races. - -*/ - -/* - -TODO: - -We cannot create the pipeline of processes in suspended states. How -do we cleanup processes already started when one fails to load? Right -now we are just killing them, which is probably not the right thing to -do. - -*/ - -#if defined(__CYGWIN__) -/* Increase the file descriptor limit for select() before including - related system headers. (Default: 64) */ -# define FD_SETSIZE 16384 -#endif - -#include /* assert */ -#include /* isspace */ -#include /* DIR, dirent */ -#include /* errno */ -#include /* fcntl */ -#include /* sigaction */ -#include /* ptrdiff_t */ -#include /* snprintf */ -#include /* malloc, free */ -#include /* strdup, strerror, memset */ -#include /* open mode */ -#include /* struct timeval */ -#include /* pid_t, fd_set */ -#include /* waitpid */ -#include /* gettimeofday */ -#include /* pipe, close, fork, execvp, select, _exit */ - -#if defined(__VMS) -# define KWSYSPE_VMS_NONBLOCK , O_NONBLOCK -#else -# define KWSYSPE_VMS_NONBLOCK -#endif - -#if defined(KWSYS_C_HAS_PTRDIFF_T) && KWSYS_C_HAS_PTRDIFF_T -typedef ptrdiff_t kwsysProcess_ptrdiff_t; -#else -typedef int kwsysProcess_ptrdiff_t; -#endif - -#if defined(KWSYS_C_HAS_SSIZE_T) && KWSYS_C_HAS_SSIZE_T -typedef ssize_t kwsysProcess_ssize_t; -#else -typedef int kwsysProcess_ssize_t; -#endif - -#if defined(__BEOS__) && !defined(__ZETA__) -/* BeOS 5 doesn't have usleep(), but it has snooze(), which is identical. */ -# include -static inline void kwsysProcess_usleep(unsigned int msec) -{ - snooze(msec); -} -#else -# define kwsysProcess_usleep usleep -#endif - -/* - * BeOS's select() works like WinSock: it's for networking only, and - * doesn't work with Unix file handles...socket and file handles are - * different namespaces (the same descriptor means different things in - * each context!) - * - * So on Unix-like systems where select() is flakey, we'll set the - * pipes' file handles to be non-blocking and just poll them directly - * without select(). - */ -#if !defined(__BEOS__) && !defined(__VMS) && !defined(__MINT__) && \ - !defined(KWSYSPE_USE_SELECT) -# define KWSYSPE_USE_SELECT 1 -#endif - -/* Some platforms do not have siginfo on their signal handlers. */ -#if defined(SA_SIGINFO) && !defined(__BEOS__) -# define KWSYSPE_USE_SIGINFO 1 -#endif - -/* The number of pipes for the child's output. The standard stdout - and stderr pipes are the first two. One more pipe is used to - detect when the child process has terminated. The third pipe is - not given to the child process, so it cannot close it until it - terminates. */ -#define KWSYSPE_PIPE_COUNT 3 -#define KWSYSPE_PIPE_STDOUT 0 -#define KWSYSPE_PIPE_STDERR 1 -#define KWSYSPE_PIPE_SIGNAL 2 - -/* The maximum amount to read from a pipe at a time. */ -#define KWSYSPE_PIPE_BUFFER_SIZE 1024 - -/* Keep track of times using a signed representation. Switch to the - native (possibly unsigned) representation only when calling native - functions. */ -typedef struct timeval kwsysProcessTimeNative; -typedef struct kwsysProcessTime_s kwsysProcessTime; -struct kwsysProcessTime_s -{ - long tv_sec; - long tv_usec; -}; - -typedef struct kwsysProcessCreateInformation_s -{ - int StdIn; - int StdOut; - int StdErr; - int ErrorPipe[2]; -} kwsysProcessCreateInformation; - -static void kwsysProcessVolatileFree(volatile void* p); -static int kwsysProcessInitialize(kwsysProcess* cp); -static void kwsysProcessCleanup(kwsysProcess* cp, int error); -static void kwsysProcessCleanupDescriptor(int* pfd); -static void kwsysProcessClosePipes(kwsysProcess* cp); -static int kwsysProcessSetNonBlocking(int fd); -static int kwsysProcessCreate(kwsysProcess* cp, int prIndex, - kwsysProcessCreateInformation* si); -static void kwsysProcessDestroy(kwsysProcess* cp); -static int kwsysProcessSetupOutputPipeFile(int* p, const char* name); -static int kwsysProcessSetupOutputPipeNative(int* p, int des[2]); -static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout, - kwsysProcessTime* timeoutTime); -static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime, - double* userTimeout, - kwsysProcessTimeNative* timeoutLength, - int zeroIsExpired); -static kwsysProcessTime kwsysProcessTimeGetCurrent(void); -static double kwsysProcessTimeToDouble(kwsysProcessTime t); -static kwsysProcessTime kwsysProcessTimeFromDouble(double d); -static int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2); -static kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1, - kwsysProcessTime in2); -static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, - kwsysProcessTime in2); -static void kwsysProcessSetExitExceptionByIndex(kwsysProcess* cp, int sig, - int idx); -static void kwsysProcessChildErrorExit(int errorPipe); -static void kwsysProcessRestoreDefaultSignalHandlers(void); -static pid_t kwsysProcessFork(kwsysProcess* cp, - kwsysProcessCreateInformation* si); -static void kwsysProcessKill(pid_t process_id); -#if defined(__VMS) -static int kwsysProcessSetVMSFeature(const char* name, int value); -#endif -static int kwsysProcessesAdd(kwsysProcess* cp); -static void kwsysProcessesRemove(kwsysProcess* cp); -#if KWSYSPE_USE_SIGINFO -static void kwsysProcessesSignalHandler(int signum, siginfo_t* info, - void* ucontext); -#else -static void kwsysProcessesSignalHandler(int signum); -#endif - -/* A structure containing results data for each process. */ -typedef struct kwsysProcessResults_s kwsysProcessResults; -struct kwsysProcessResults_s -{ - /* The status of the child process. */ - int State; - - /* The exceptional behavior that terminated the process, if any. */ - int ExitException; - - /* The process exit code. */ - int ExitCode; - - /* The process return code, if any. */ - int ExitValue; - - /* Description for the ExitException. */ - char ExitExceptionString[KWSYSPE_PIPE_BUFFER_SIZE + 1]; -}; - -/* Structure containing data used to implement the child's execution. */ -struct kwsysProcess_s -{ - /* The command lines to execute. */ - char*** Commands; - volatile int NumberOfCommands; - - /* Descriptors for the read ends of the child's output pipes and - the signal pipe. */ - int PipeReadEnds[KWSYSPE_PIPE_COUNT]; - - /* Descriptors for the child's ends of the pipes. - Used temporarily during process creation. */ - int PipeChildStd[3]; - - /* Write descriptor for child termination signal pipe. */ - int SignalPipe; - - /* Buffer for pipe data. */ - char PipeBuffer[KWSYSPE_PIPE_BUFFER_SIZE]; - - /* Process IDs returned by the calls to fork. Everything is volatile - because the signal handler accesses them. You must be very careful - when reaping PIDs or modifying this array to avoid race conditions. */ - volatile pid_t* volatile ForkPIDs; - - /* Flag for whether the children were terminated by a failed select. */ - int SelectError; - - /* The timeout length. */ - double Timeout; - - /* The working directory for the process. */ - char* WorkingDirectory; - - /* Whether to create the child as a detached process. */ - int OptionDetach; - - /* Whether the child was created as a detached process. */ - int Detached; - - /* Whether to treat command lines as verbatim. */ - int Verbatim; - - /* Whether to merge stdout/stderr of the child. */ - int MergeOutput; - - /* Whether to create the process in a new process group. */ - volatile sig_atomic_t CreateProcessGroup; - - /* Time at which the child started. Negative for no timeout. */ - kwsysProcessTime StartTime; - - /* Time at which the child will timeout. Negative for no timeout. */ - kwsysProcessTime TimeoutTime; - - /* Flag for whether the timeout expired. */ - int TimeoutExpired; - - /* The number of pipes left open during execution. */ - int PipesLeft; - -#if KWSYSPE_USE_SELECT - /* File descriptor set for call to select. */ - fd_set PipeSet; -#endif - - /* The number of children still executing. */ - int CommandsLeft; - - /* The status of the process structure. Must be atomic because - the signal handler checks this to avoid a race. */ - volatile sig_atomic_t State; - - /* Whether the process was killed. */ - volatile sig_atomic_t Killed; - - /* Buffer for error message in case of failure. */ - char ErrorMessage[KWSYSPE_PIPE_BUFFER_SIZE + 1]; - - /* process results. */ - kwsysProcessResults* ProcessResults; - - /* The exit codes of each child process in the pipeline. */ - int* CommandExitCodes; - - /* Name of files to which stdin and stdout pipes are attached. */ - char* PipeFileSTDIN; - char* PipeFileSTDOUT; - char* PipeFileSTDERR; - - /* Whether each pipe is shared with the parent process. */ - int PipeSharedSTDIN; - int PipeSharedSTDOUT; - int PipeSharedSTDERR; - - /* Native pipes provided by the user. */ - int PipeNativeSTDIN[2]; - int PipeNativeSTDOUT[2]; - int PipeNativeSTDERR[2]; - - /* The real working directory of this process. */ - int RealWorkingDirectoryLength; - char* RealWorkingDirectory; -}; - -kwsysProcess* kwsysProcess_New(void) -{ - /* Allocate a process control structure. */ - kwsysProcess* cp = (kwsysProcess*)malloc(sizeof(kwsysProcess)); - if (!cp) { - return 0; - } - memset(cp, 0, sizeof(kwsysProcess)); - - /* Share stdin with the parent process by default. */ - cp->PipeSharedSTDIN = 1; - - /* No native pipes by default. */ - cp->PipeNativeSTDIN[0] = -1; - cp->PipeNativeSTDIN[1] = -1; - cp->PipeNativeSTDOUT[0] = -1; - cp->PipeNativeSTDOUT[1] = -1; - cp->PipeNativeSTDERR[0] = -1; - cp->PipeNativeSTDERR[1] = -1; - - /* Set initial status. */ - cp->State = kwsysProcess_State_Starting; - - return cp; -} - -void kwsysProcess_Delete(kwsysProcess* cp) -{ - /* Make sure we have an instance. */ - if (!cp) { - return; - } - - /* If the process is executing, wait for it to finish. */ - if (cp->State == kwsysProcess_State_Executing) { - if (cp->Detached) { - kwsysProcess_Disown(cp); - } else { - kwsysProcess_WaitForExit(cp, 0); - } - } - - /* Free memory. */ - kwsysProcess_SetCommand(cp, 0); - kwsysProcess_SetWorkingDirectory(cp, 0); - kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDIN, 0); - kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDOUT, 0); - kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDERR, 0); - free(cp->CommandExitCodes); - free(cp->ProcessResults); - free(cp); -} - -int kwsysProcess_SetCommand(kwsysProcess* cp, char const* const* command) -{ - int i; - if (!cp) { - return 0; - } - for (i = 0; i < cp->NumberOfCommands; ++i) { - char** c = cp->Commands[i]; - while (*c) { - free(*c++); - } - free(cp->Commands[i]); - } - cp->NumberOfCommands = 0; - if (cp->Commands) { - free(cp->Commands); - cp->Commands = 0; - } - if (command) { - return kwsysProcess_AddCommand(cp, command); - } - return 1; -} - -int kwsysProcess_AddCommand(kwsysProcess* cp, char const* const* command) -{ - int newNumberOfCommands; - char*** newCommands; - - /* Make sure we have a command to add. */ - if (!cp || !command || !*command) { - return 0; - } - - /* Allocate a new array for command pointers. */ - newNumberOfCommands = cp->NumberOfCommands + 1; - if (!(newCommands = - (char***)malloc(sizeof(char**) * (size_t)(newNumberOfCommands)))) { - /* Out of memory. */ - return 0; - } - - /* Copy any existing commands into the new array. */ - { - int i; - for (i = 0; i < cp->NumberOfCommands; ++i) { - newCommands[i] = cp->Commands[i]; - } - } - - /* Add the new command. */ - if (cp->Verbatim) { - /* In order to run the given command line verbatim we need to - parse it. */ - newCommands[cp->NumberOfCommands] = - kwsysSystem_Parse_CommandForUnix(*command, 0); - if (!newCommands[cp->NumberOfCommands] || - !newCommands[cp->NumberOfCommands][0]) { - /* Out of memory or no command parsed. */ - free(newCommands); - return 0; - } - } else { - /* Copy each argument string individually. */ - char const* const* c = command; - kwsysProcess_ptrdiff_t n = 0; - kwsysProcess_ptrdiff_t i = 0; - while (*c++) - ; - n = c - command - 1; - newCommands[cp->NumberOfCommands] = - (char**)malloc((size_t)(n + 1) * sizeof(char*)); - if (!newCommands[cp->NumberOfCommands]) { - /* Out of memory. */ - free(newCommands); - return 0; - } - for (i = 0; i < n; ++i) { - assert(command[i]); /* Quiet Clang scan-build. */ - newCommands[cp->NumberOfCommands][i] = strdup(command[i]); - if (!newCommands[cp->NumberOfCommands][i]) { - break; - } - } - if (i < n) { - /* Out of memory. */ - for (; i > 0; --i) { - free(newCommands[cp->NumberOfCommands][i - 1]); - } - free(newCommands); - return 0; - } - newCommands[cp->NumberOfCommands][n] = 0; - } - - /* Successfully allocated new command array. Free the old array. */ - free(cp->Commands); - cp->Commands = newCommands; - cp->NumberOfCommands = newNumberOfCommands; - - return 1; -} - -void kwsysProcess_SetTimeout(kwsysProcess* cp, double timeout) -{ - if (!cp) { - return; - } - cp->Timeout = timeout; - if (cp->Timeout < 0) { - cp->Timeout = 0; - } - // Force recomputation of TimeoutTime. - cp->TimeoutTime.tv_sec = -1; -} - -int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, const char* dir) -{ - if (!cp) { - return 0; - } - if (cp->WorkingDirectory == dir) { - return 1; - } - if (cp->WorkingDirectory && dir && strcmp(cp->WorkingDirectory, dir) == 0) { - return 1; - } - if (cp->WorkingDirectory) { - free(cp->WorkingDirectory); - cp->WorkingDirectory = 0; - } - if (dir) { - cp->WorkingDirectory = strdup(dir); - if (!cp->WorkingDirectory) { - return 0; - } - } - return 1; -} - -int kwsysProcess_SetPipeFile(kwsysProcess* cp, int prPipe, const char* file) -{ - char** pfile; - if (!cp) { - return 0; - } - switch (prPipe) { - case kwsysProcess_Pipe_STDIN: - pfile = &cp->PipeFileSTDIN; - break; - case kwsysProcess_Pipe_STDOUT: - pfile = &cp->PipeFileSTDOUT; - break; - case kwsysProcess_Pipe_STDERR: - pfile = &cp->PipeFileSTDERR; - break; - default: - return 0; - } - if (*pfile) { - free(*pfile); - *pfile = 0; - } - if (file) { - *pfile = strdup(file); - if (!*pfile) { - return 0; - } - } - - /* If we are redirecting the pipe, do not share it or use a native - pipe. */ - if (*pfile) { - kwsysProcess_SetPipeNative(cp, prPipe, 0); - kwsysProcess_SetPipeShared(cp, prPipe, 0); - } - return 1; -} - -void kwsysProcess_SetPipeShared(kwsysProcess* cp, int prPipe, int shared) -{ - if (!cp) { - return; - } - - switch (prPipe) { - case kwsysProcess_Pipe_STDIN: - cp->PipeSharedSTDIN = shared ? 1 : 0; - break; - case kwsysProcess_Pipe_STDOUT: - cp->PipeSharedSTDOUT = shared ? 1 : 0; - break; - case kwsysProcess_Pipe_STDERR: - cp->PipeSharedSTDERR = shared ? 1 : 0; - break; - default: - return; - } - - /* If we are sharing the pipe, do not redirect it to a file or use a - native pipe. */ - if (shared) { - kwsysProcess_SetPipeFile(cp, prPipe, 0); - kwsysProcess_SetPipeNative(cp, prPipe, 0); - } -} - -void kwsysProcess_SetPipeNative(kwsysProcess* cp, int prPipe, int p[2]) -{ - int* pPipeNative = 0; - - if (!cp) { - return; - } - - switch (prPipe) { - case kwsysProcess_Pipe_STDIN: - pPipeNative = cp->PipeNativeSTDIN; - break; - case kwsysProcess_Pipe_STDOUT: - pPipeNative = cp->PipeNativeSTDOUT; - break; - case kwsysProcess_Pipe_STDERR: - pPipeNative = cp->PipeNativeSTDERR; - break; - default: - return; - } - - /* Copy the native pipe descriptors provided. */ - if (p) { - pPipeNative[0] = p[0]; - pPipeNative[1] = p[1]; - } else { - pPipeNative[0] = -1; - pPipeNative[1] = -1; - } - - /* If we are using a native pipe, do not share it or redirect it to - a file. */ - if (p) { - kwsysProcess_SetPipeFile(cp, prPipe, 0); - kwsysProcess_SetPipeShared(cp, prPipe, 0); - } -} - -int kwsysProcess_GetOption(kwsysProcess* cp, int optionId) -{ - if (!cp) { - return 0; - } - - switch (optionId) { - case kwsysProcess_Option_Detach: - return cp->OptionDetach; - case kwsysProcess_Option_MergeOutput: - return cp->MergeOutput; - case kwsysProcess_Option_Verbatim: - return cp->Verbatim; - case kwsysProcess_Option_CreateProcessGroup: - return cp->CreateProcessGroup; - default: - return 0; - } -} - -void kwsysProcess_SetOption(kwsysProcess* cp, int optionId, int value) -{ - if (!cp) { - return; - } - - switch (optionId) { - case kwsysProcess_Option_Detach: - cp->OptionDetach = value; - break; - case kwsysProcess_Option_MergeOutput: - cp->MergeOutput = value; - break; - case kwsysProcess_Option_Verbatim: - cp->Verbatim = value; - break; - case kwsysProcess_Option_CreateProcessGroup: - cp->CreateProcessGroup = value; - break; - default: - break; - } -} - -int kwsysProcess_GetState(kwsysProcess* cp) -{ - return cp ? cp->State : kwsysProcess_State_Error; -} - -int kwsysProcess_GetExitException(kwsysProcess* cp) -{ - return (cp && cp->ProcessResults && (cp->NumberOfCommands > 0)) - ? cp->ProcessResults[cp->NumberOfCommands - 1].ExitException - : kwsysProcess_Exception_Other; -} - -int kwsysProcess_GetExitCode(kwsysProcess* cp) -{ - return (cp && cp->ProcessResults && (cp->NumberOfCommands > 0)) - ? cp->ProcessResults[cp->NumberOfCommands - 1].ExitCode - : 0; -} - -int kwsysProcess_GetExitValue(kwsysProcess* cp) -{ - return (cp && cp->ProcessResults && (cp->NumberOfCommands > 0)) - ? cp->ProcessResults[cp->NumberOfCommands - 1].ExitValue - : -1; -} - -const char* kwsysProcess_GetErrorString(kwsysProcess* cp) -{ - if (!cp) { - return "Process management structure could not be allocated"; - } else if (cp->State == kwsysProcess_State_Error) { - return cp->ErrorMessage; - } - return "Success"; -} - -const char* kwsysProcess_GetExceptionString(kwsysProcess* cp) -{ - if (!(cp && cp->ProcessResults && (cp->NumberOfCommands > 0))) { - return "GetExceptionString called with NULL process management structure"; - } else if (cp->State == kwsysProcess_State_Exception) { - return cp->ProcessResults[cp->NumberOfCommands - 1].ExitExceptionString; - } - return "No exception"; -} - -/* the index should be in array bound. */ -#define KWSYSPE_IDX_CHK(RET) \ - if (!cp || idx >= cp->NumberOfCommands || idx < 0) { \ - return RET; \ - } - -int kwsysProcess_GetStateByIndex(kwsysProcess* cp, int idx) -{ - KWSYSPE_IDX_CHK(kwsysProcess_State_Error) - return cp->ProcessResults[idx].State; -} - -int kwsysProcess_GetExitExceptionByIndex(kwsysProcess* cp, int idx) -{ - KWSYSPE_IDX_CHK(kwsysProcess_Exception_Other) - return cp->ProcessResults[idx].ExitException; -} - -int kwsysProcess_GetExitValueByIndex(kwsysProcess* cp, int idx) -{ - KWSYSPE_IDX_CHK(-1) - return cp->ProcessResults[idx].ExitValue; -} - -int kwsysProcess_GetExitCodeByIndex(kwsysProcess* cp, int idx) -{ - KWSYSPE_IDX_CHK(-1) - return cp->CommandExitCodes[idx]; -} - -const char* kwsysProcess_GetExceptionStringByIndex(kwsysProcess* cp, int idx) -{ - KWSYSPE_IDX_CHK("GetExceptionString called with NULL process management " - "structure or index out of bound") - if (cp->ProcessResults[idx].State == kwsysProcess_StateByIndex_Exception) { - return cp->ProcessResults[idx].ExitExceptionString; - } - return "No exception"; -} - -#undef KWSYSPE_IDX_CHK - -void kwsysProcess_Execute(kwsysProcess* cp) -{ - int i; - - /* Do not execute a second copy simultaneously. */ - if (!cp || cp->State == kwsysProcess_State_Executing) { - return; - } - - /* Make sure we have something to run. */ - if (cp->NumberOfCommands < 1) { - strcpy(cp->ErrorMessage, "No command"); - cp->State = kwsysProcess_State_Error; - return; - } - - /* Initialize the control structure for a new process. */ - if (!kwsysProcessInitialize(cp)) { - strcpy(cp->ErrorMessage, "Out of memory"); - cp->State = kwsysProcess_State_Error; - return; - } - -#if defined(__VMS) - /* Make sure pipes behave like streams on VMS. */ - if (!kwsysProcessSetVMSFeature("DECC$STREAM_PIPE", 1)) { - kwsysProcessCleanup(cp, 1); - return; - } -#endif - - /* Save the real working directory of this process and change to - the working directory for the child processes. This is needed - to make pipe file paths evaluate correctly. */ - if (cp->WorkingDirectory) { - int r; - if (!getcwd(cp->RealWorkingDirectory, - (size_t)(cp->RealWorkingDirectoryLength))) { - kwsysProcessCleanup(cp, 1); - return; - } - - /* Some platforms specify that the chdir call may be - interrupted. Repeat the call until it finishes. */ - while (((r = chdir(cp->WorkingDirectory)) < 0) && (errno == EINTR)) - ; - if (r < 0) { - kwsysProcessCleanup(cp, 1); - return; - } - } - - /* If not running a detached child, add this object to the global - set of process objects that wish to be notified when a child - exits. */ - if (!cp->OptionDetach) { - if (!kwsysProcessesAdd(cp)) { - kwsysProcessCleanup(cp, 1); - return; - } - } - - /* Setup the stdin pipe for the first process. */ - if (cp->PipeFileSTDIN) { - /* Open a file for the child's stdin to read. */ - cp->PipeChildStd[0] = open(cp->PipeFileSTDIN, O_RDONLY); - if (cp->PipeChildStd[0] < 0) { - kwsysProcessCleanup(cp, 1); - return; - } - - /* Set close-on-exec flag on the pipe's end. */ - if (fcntl(cp->PipeChildStd[0], F_SETFD, FD_CLOEXEC) < 0) { - kwsysProcessCleanup(cp, 1); - return; - } - } else if (cp->PipeSharedSTDIN) { - cp->PipeChildStd[0] = 0; - } else if (cp->PipeNativeSTDIN[0] >= 0) { - cp->PipeChildStd[0] = cp->PipeNativeSTDIN[0]; - - /* Set close-on-exec flag on the pipe's ends. The read end will - be dup2-ed into the stdin descriptor after the fork but before - the exec. */ - if ((fcntl(cp->PipeNativeSTDIN[0], F_SETFD, FD_CLOEXEC) < 0) || - (fcntl(cp->PipeNativeSTDIN[1], F_SETFD, FD_CLOEXEC) < 0)) { - kwsysProcessCleanup(cp, 1); - return; - } - } else { - cp->PipeChildStd[0] = -1; - } - - /* Create the output pipe for the last process. - We always create this so the pipe can be passed to select even if - it will report closed immediately. */ - { - /* Create the pipe. */ - int p[2]; - if (pipe(p KWSYSPE_VMS_NONBLOCK) < 0) { - kwsysProcessCleanup(cp, 1); - return; - } - - /* Store the pipe. */ - cp->PipeReadEnds[KWSYSPE_PIPE_STDOUT] = p[0]; - cp->PipeChildStd[1] = p[1]; - - /* Set close-on-exec flag on the pipe's ends. */ - if ((fcntl(p[0], F_SETFD, FD_CLOEXEC) < 0) || - (fcntl(p[1], F_SETFD, FD_CLOEXEC) < 0)) { - kwsysProcessCleanup(cp, 1); - return; - } - - /* Set to non-blocking in case select lies, or for the polling - implementation. */ - if (!kwsysProcessSetNonBlocking(p[0])) { - kwsysProcessCleanup(cp, 1); - return; - } - } - - if (cp->PipeFileSTDOUT) { - /* Use a file for stdout. */ - if (!kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[1], - cp->PipeFileSTDOUT)) { - kwsysProcessCleanup(cp, 1); - return; - } - } else if (cp->PipeSharedSTDOUT) { - /* Use the parent stdout. */ - kwsysProcessCleanupDescriptor(&cp->PipeChildStd[1]); - cp->PipeChildStd[1] = 1; - } else if (cp->PipeNativeSTDOUT[1] >= 0) { - /* Use the given descriptor for stdout. */ - if (!kwsysProcessSetupOutputPipeNative(&cp->PipeChildStd[1], - cp->PipeNativeSTDOUT)) { - kwsysProcessCleanup(cp, 1); - return; - } - } - - /* Create stderr pipe to be shared by all processes in the pipeline. - We always create this so the pipe can be passed to select even if - it will report closed immediately. */ - { - /* Create the pipe. */ - int p[2]; - if (pipe(p KWSYSPE_VMS_NONBLOCK) < 0) { - kwsysProcessCleanup(cp, 1); - return; - } - - /* Store the pipe. */ - cp->PipeReadEnds[KWSYSPE_PIPE_STDERR] = p[0]; - cp->PipeChildStd[2] = p[1]; - - /* Set close-on-exec flag on the pipe's ends. */ - if ((fcntl(p[0], F_SETFD, FD_CLOEXEC) < 0) || - (fcntl(p[1], F_SETFD, FD_CLOEXEC) < 0)) { - kwsysProcessCleanup(cp, 1); - return; - } - - /* Set to non-blocking in case select lies, or for the polling - implementation. */ - if (!kwsysProcessSetNonBlocking(p[0])) { - kwsysProcessCleanup(cp, 1); - return; - } - } - - if (cp->PipeFileSTDERR) { - /* Use a file for stderr. */ - if (!kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[2], - cp->PipeFileSTDERR)) { - kwsysProcessCleanup(cp, 1); - return; - } - } else if (cp->PipeSharedSTDERR) { - /* Use the parent stderr. */ - kwsysProcessCleanupDescriptor(&cp->PipeChildStd[2]); - cp->PipeChildStd[2] = 2; - } else if (cp->PipeNativeSTDERR[1] >= 0) { - /* Use the given handle for stderr. */ - if (!kwsysProcessSetupOutputPipeNative(&cp->PipeChildStd[2], - cp->PipeNativeSTDERR)) { - kwsysProcessCleanup(cp, 1); - return; - } - } - - /* The timeout period starts now. */ - cp->StartTime = kwsysProcessTimeGetCurrent(); - cp->TimeoutTime.tv_sec = -1; - cp->TimeoutTime.tv_usec = -1; - - /* Create the pipeline of processes. */ - { - kwsysProcessCreateInformation si = { -1, -1, -1, { -1, -1 } }; - int nextStdIn = cp->PipeChildStd[0]; - for (i = 0; i < cp->NumberOfCommands; ++i) { - /* Setup the process's pipes. */ - si.StdIn = nextStdIn; - if (i == cp->NumberOfCommands - 1) { - nextStdIn = -1; - si.StdOut = cp->PipeChildStd[1]; - } else { - /* Create a pipe to sit between the children. */ - int p[2] = { -1, -1 }; - if (pipe(p KWSYSPE_VMS_NONBLOCK) < 0) { - if (nextStdIn != cp->PipeChildStd[0]) { - kwsysProcessCleanupDescriptor(&nextStdIn); - } - kwsysProcessCleanup(cp, 1); - return; - } - - /* Set close-on-exec flag on the pipe's ends. */ - if ((fcntl(p[0], F_SETFD, FD_CLOEXEC) < 0) || - (fcntl(p[1], F_SETFD, FD_CLOEXEC) < 0)) { - close(p[0]); - close(p[1]); - if (nextStdIn != cp->PipeChildStd[0]) { - kwsysProcessCleanupDescriptor(&nextStdIn); - } - kwsysProcessCleanup(cp, 1); - return; - } - nextStdIn = p[0]; - si.StdOut = p[1]; - } - si.StdErr = cp->MergeOutput ? cp->PipeChildStd[1] : cp->PipeChildStd[2]; - - { - int res = kwsysProcessCreate(cp, i, &si); - - /* Close our copies of pipes used between children. */ - if (si.StdIn != cp->PipeChildStd[0]) { - kwsysProcessCleanupDescriptor(&si.StdIn); - } - if (si.StdOut != cp->PipeChildStd[1]) { - kwsysProcessCleanupDescriptor(&si.StdOut); - } - if (si.StdErr != cp->PipeChildStd[2] && !cp->MergeOutput) { - kwsysProcessCleanupDescriptor(&si.StdErr); - } - - if (!res) { - kwsysProcessCleanupDescriptor(&si.ErrorPipe[0]); - kwsysProcessCleanupDescriptor(&si.ErrorPipe[1]); - if (nextStdIn != cp->PipeChildStd[0]) { - kwsysProcessCleanupDescriptor(&nextStdIn); - } - kwsysProcessCleanup(cp, 1); - return; - } - } - } - } - - /* The parent process does not need the child's pipe ends. */ - for (i = 0; i < 3; ++i) { - kwsysProcessCleanupDescriptor(&cp->PipeChildStd[i]); - } - - /* Restore the working directory. */ - if (cp->RealWorkingDirectory) { - /* Some platforms specify that the chdir call may be - interrupted. Repeat the call until it finishes. */ - while ((chdir(cp->RealWorkingDirectory) < 0) && (errno == EINTR)) - ; - free(cp->RealWorkingDirectory); - cp->RealWorkingDirectory = 0; - } - - /* All the pipes are now open. */ - cp->PipesLeft = KWSYSPE_PIPE_COUNT; - - /* The process has now started. */ - cp->State = kwsysProcess_State_Executing; - cp->Detached = cp->OptionDetach; -} - -kwsysEXPORT void kwsysProcess_Disown(kwsysProcess* cp) -{ - /* Make sure a detached child process is running. */ - if (!cp || !cp->Detached || cp->State != kwsysProcess_State_Executing || - cp->TimeoutExpired || cp->Killed) { - return; - } - - /* Close all the pipes safely. */ - kwsysProcessClosePipes(cp); - - /* We will not wait for exit, so cleanup now. */ - kwsysProcessCleanup(cp, 0); - - /* The process has been disowned. */ - cp->State = kwsysProcess_State_Disowned; -} - -typedef struct kwsysProcessWaitData_s -{ - int Expired; - int PipeId; - int User; - double* UserTimeout; - kwsysProcessTime TimeoutTime; -} kwsysProcessWaitData; -static int kwsysProcessWaitForPipe(kwsysProcess* cp, char** data, int* length, - kwsysProcessWaitData* wd); - -int kwsysProcess_WaitForData(kwsysProcess* cp, char** data, int* length, - double* userTimeout) -{ - kwsysProcessTime userStartTime = { 0, 0 }; - kwsysProcessWaitData wd = { 0, kwsysProcess_Pipe_None, 0, 0, { 0, 0 } }; - wd.UserTimeout = userTimeout; - /* Make sure we are executing a process. */ - if (!cp || cp->State != kwsysProcess_State_Executing || cp->Killed || - cp->TimeoutExpired) { - return kwsysProcess_Pipe_None; - } - - /* Record the time at which user timeout period starts. */ - if (userTimeout) { - userStartTime = kwsysProcessTimeGetCurrent(); - } - - /* Calculate the time at which a timeout will expire, and whether it - is the user or process timeout. */ - wd.User = kwsysProcessGetTimeoutTime(cp, userTimeout, &wd.TimeoutTime); - - /* Data can only be available when pipes are open. If the process - is not running, cp->PipesLeft will be 0. */ - while (cp->PipesLeft > 0 && - !kwsysProcessWaitForPipe(cp, data, length, &wd)) { - } - - /* Update the user timeout. */ - if (userTimeout) { - kwsysProcessTime userEndTime = kwsysProcessTimeGetCurrent(); - kwsysProcessTime difference = - kwsysProcessTimeSubtract(userEndTime, userStartTime); - double d = kwsysProcessTimeToDouble(difference); - *userTimeout -= d; - if (*userTimeout < 0) { - *userTimeout = 0; - } - } - - /* Check what happened. */ - if (wd.PipeId) { - /* Data are ready on a pipe. */ - return wd.PipeId; - } else if (wd.Expired) { - /* A timeout has expired. */ - if (wd.User) { - /* The user timeout has expired. It has no time left. */ - return kwsysProcess_Pipe_Timeout; - } else { - /* The process timeout has expired. Kill the children now. */ - kwsysProcess_Kill(cp); - cp->Killed = 0; - cp->TimeoutExpired = 1; - return kwsysProcess_Pipe_None; - } - } else { - /* No pipes are left open. */ - return kwsysProcess_Pipe_None; - } -} - -static int kwsysProcessWaitForPipe(kwsysProcess* cp, char** data, int* length, - kwsysProcessWaitData* wd) -{ - int i; - kwsysProcessTimeNative timeoutLength; - -#if KWSYSPE_USE_SELECT - int numReady = 0; - int max = -1; - kwsysProcessTimeNative* timeout = 0; - - /* Check for any open pipes with data reported ready by the last - call to select. According to "man select_tut" we must deal - with all descriptors reported by a call to select before - passing them to another select call. */ - for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { - if (cp->PipeReadEnds[i] >= 0 && - FD_ISSET(cp->PipeReadEnds[i], &cp->PipeSet)) { - kwsysProcess_ssize_t n; - - /* We are handling this pipe now. Remove it from the set. */ - FD_CLR(cp->PipeReadEnds[i], &cp->PipeSet); - - /* The pipe is ready to read without blocking. Keep trying to - read until the operation is not interrupted. */ - while (((n = read(cp->PipeReadEnds[i], cp->PipeBuffer, - KWSYSPE_PIPE_BUFFER_SIZE)) < 0) && - (errno == EINTR)) - ; - if (n > 0) { - /* We have data on this pipe. */ - if (i == KWSYSPE_PIPE_SIGNAL) { - /* A child process has terminated. */ - kwsysProcessDestroy(cp); - } else if (data && length) { - /* Report this data. */ - *data = cp->PipeBuffer; - *length = (int)(n); - switch (i) { - case KWSYSPE_PIPE_STDOUT: - wd->PipeId = kwsysProcess_Pipe_STDOUT; - break; - case KWSYSPE_PIPE_STDERR: - wd->PipeId = kwsysProcess_Pipe_STDERR; - break; - } - return 1; - } - } else if (n < 0 && errno == EAGAIN) { - /* No data are really ready. The select call lied. See the - "man select" page on Linux for cases when this occurs. */ - } else { - /* We are done reading from this pipe. */ - kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]); - --cp->PipesLeft; - } - } - } - - /* If we have data, break early. */ - if (wd->PipeId) { - return 1; - } - - /* Make sure the set is empty (it should always be empty here - anyway). */ - FD_ZERO(&cp->PipeSet); - - /* Setup a timeout if required. */ - if (wd->TimeoutTime.tv_sec < 0) { - timeout = 0; - } else { - timeout = &timeoutLength; - } - if (kwsysProcessGetTimeoutLeft( - &wd->TimeoutTime, wd->User ? wd->UserTimeout : 0, &timeoutLength, 0)) { - /* Timeout has already expired. */ - wd->Expired = 1; - return 1; - } - - /* Add the pipe reading ends that are still open. */ - max = -1; - for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { - if (cp->PipeReadEnds[i] >= 0) { - FD_SET(cp->PipeReadEnds[i], &cp->PipeSet); - if (cp->PipeReadEnds[i] > max) { - max = cp->PipeReadEnds[i]; - } - } - } - - /* Make sure we have a non-empty set. */ - if (max < 0) { - /* All pipes have closed. Child has terminated. */ - return 1; - } - - /* Run select to block until data are available. Repeat call - until it is not interrupted. */ - while (((numReady = select(max + 1, &cp->PipeSet, 0, 0, timeout)) < 0) && - (errno == EINTR)) - ; - - /* Check result of select. */ - if (numReady == 0) { - /* Select's timeout expired. */ - wd->Expired = 1; - return 1; - } else if (numReady < 0) { - /* Select returned an error. Leave the error description in the - pipe buffer. */ - strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE); - - /* Kill the children now. */ - kwsysProcess_Kill(cp); - cp->Killed = 0; - cp->SelectError = 1; - } - - return 0; -#else - /* Poll pipes for data since we do not have select. */ - for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { - if (cp->PipeReadEnds[i] >= 0) { - const int fd = cp->PipeReadEnds[i]; - int n = read(fd, cp->PipeBuffer, KWSYSPE_PIPE_BUFFER_SIZE); - if (n > 0) { - /* We have data on this pipe. */ - if (i == KWSYSPE_PIPE_SIGNAL) { - /* A child process has terminated. */ - kwsysProcessDestroy(cp); - } else if (data && length) { - /* Report this data. */ - *data = cp->PipeBuffer; - *length = n; - switch (i) { - case KWSYSPE_PIPE_STDOUT: - wd->PipeId = kwsysProcess_Pipe_STDOUT; - break; - case KWSYSPE_PIPE_STDERR: - wd->PipeId = kwsysProcess_Pipe_STDERR; - break; - }; - } - return 1; - } else if (n == 0) /* EOF */ - { -/* We are done reading from this pipe. */ -# if defined(__VMS) - if (!cp->CommandsLeft) -# endif - { - kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]); - --cp->PipesLeft; - } - } else if (n < 0) /* error */ - { -# if defined(__VMS) - if (!cp->CommandsLeft) { - kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]); - --cp->PipesLeft; - } else -# endif - if ((errno != EINTR) && (errno != EAGAIN)) { - strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE); - /* Kill the children now. */ - kwsysProcess_Kill(cp); - cp->Killed = 0; - cp->SelectError = 1; - return 1; - } - } - } - } - - /* If we have data, break early. */ - if (wd->PipeId) { - return 1; - } - - if (kwsysProcessGetTimeoutLeft( - &wd->TimeoutTime, wd->User ? wd->UserTimeout : 0, &timeoutLength, 1)) { - /* Timeout has already expired. */ - wd->Expired = 1; - return 1; - } - - /* Sleep a little, try again. */ - { - unsigned int msec = - ((timeoutLength.tv_sec * 1000) + (timeoutLength.tv_usec / 1000)); - if (msec > 100000) { - msec = 100000; /* do not sleep more than 100 milliseconds at a time */ - } - kwsysProcess_usleep(msec); - } - return 0; -#endif -} - -int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout) -{ - int prPipe = 0; - - /* Make sure we are executing a process. */ - if (!cp || cp->State != kwsysProcess_State_Executing) { - return 1; - } - - /* Wait for all the pipes to close. Ignore all data. */ - while ((prPipe = kwsysProcess_WaitForData(cp, 0, 0, userTimeout)) > 0) { - if (prPipe == kwsysProcess_Pipe_Timeout) { - return 0; - } - } - - /* Check if there was an error in one of the waitpid calls. */ - if (cp->State == kwsysProcess_State_Error) { - /* The error message is already in its buffer. Tell - kwsysProcessCleanup to not create it. */ - kwsysProcessCleanup(cp, 0); - return 1; - } - - /* Check whether the child reported an error invoking the process. */ - if (cp->SelectError) { - /* The error message is already in its buffer. Tell - kwsysProcessCleanup to not create it. */ - kwsysProcessCleanup(cp, 0); - cp->State = kwsysProcess_State_Error; - return 1; - } - /* Determine the outcome. */ - if (cp->Killed) { - /* We killed the child. */ - cp->State = kwsysProcess_State_Killed; - } else if (cp->TimeoutExpired) { - /* The timeout expired. */ - cp->State = kwsysProcess_State_Expired; - } else { - /* The children exited. Report the outcome of the child processes. */ - for (prPipe = 0; prPipe < cp->NumberOfCommands; ++prPipe) { - cp->ProcessResults[prPipe].ExitCode = cp->CommandExitCodes[prPipe]; - if (WIFEXITED(cp->ProcessResults[prPipe].ExitCode)) { - /* The child exited normally. */ - cp->ProcessResults[prPipe].State = kwsysProcess_StateByIndex_Exited; - cp->ProcessResults[prPipe].ExitException = kwsysProcess_Exception_None; - cp->ProcessResults[prPipe].ExitValue = - (int)WEXITSTATUS(cp->ProcessResults[prPipe].ExitCode); - } else if (WIFSIGNALED(cp->ProcessResults[prPipe].ExitCode)) { - /* The child received an unhandled signal. */ - cp->ProcessResults[prPipe].State = kwsysProcess_State_Exception; - kwsysProcessSetExitExceptionByIndex( - cp, (int)WTERMSIG(cp->ProcessResults[prPipe].ExitCode), prPipe); - } else { - /* Error getting the child return code. */ - strcpy(cp->ProcessResults[prPipe].ExitExceptionString, - "Error getting child return code."); - cp->ProcessResults[prPipe].State = kwsysProcess_StateByIndex_Error; - } - } - /* support legacy state status value */ - cp->State = cp->ProcessResults[cp->NumberOfCommands - 1].State; - } - /* Normal cleanup. */ - kwsysProcessCleanup(cp, 0); - return 1; -} - -void kwsysProcess_Interrupt(kwsysProcess* cp) -{ - int i; - /* Make sure we are executing a process. */ - if (!cp || cp->State != kwsysProcess_State_Executing || cp->TimeoutExpired || - cp->Killed) { - return; - } - - /* Interrupt the children. */ - if (cp->CreateProcessGroup) { - if (cp->ForkPIDs) { - for (i = 0; i < cp->NumberOfCommands; ++i) { - /* Make sure the PID is still valid. */ - if (cp->ForkPIDs[i]) { - /* The user created a process group for this process. The group ID - is the process ID for the original process in the group. */ - kill(-cp->ForkPIDs[i], SIGINT); - } - } - } - } else { - /* No process group was created. Kill our own process group. - NOTE: While one could argue that we could call kill(cp->ForkPIDs[i], - SIGINT) as a way to still interrupt the process even though it's not in - a special group, this is not an option on Windows. Therefore, we kill - the current process group for consistency with Windows. */ - kill(0, SIGINT); - } -} - -void kwsysProcess_Kill(kwsysProcess* cp) -{ - int i; - - /* Make sure we are executing a process. */ - if (!cp || cp->State != kwsysProcess_State_Executing) { - return; - } - - /* First close the child exit report pipe write end to avoid causing a - SIGPIPE when the child terminates and our signal handler tries to - report it after we have already closed the read end. */ - kwsysProcessCleanupDescriptor(&cp->SignalPipe); - -#if !defined(__APPLE__) - /* Close all the pipe read ends. Do this before killing the - children because Cygwin has problems killing processes that are - blocking to wait for writing to their output pipes. */ - kwsysProcessClosePipes(cp); -#endif - - /* Kill the children. */ - cp->Killed = 1; - for (i = 0; i < cp->NumberOfCommands; ++i) { - int status; - if (cp->ForkPIDs[i]) { - /* Kill the child. */ - kwsysProcessKill(cp->ForkPIDs[i]); - - /* Reap the child. Keep trying until the call is not - interrupted. */ - while ((waitpid(cp->ForkPIDs[i], &status, 0) < 0) && (errno == EINTR)) - ; - } - } - -#if defined(__APPLE__) - /* Close all the pipe read ends. Do this after killing the - children because OS X has problems closing pipe read ends whose - pipes are full and still have an open write end. */ - kwsysProcessClosePipes(cp); -#endif - - cp->CommandsLeft = 0; -} - -/* Call the free() function with a pointer to volatile without causing - compiler warnings. */ -static void kwsysProcessVolatileFree(volatile void* p) -{ -/* clang has made it impossible to free memory that points to volatile - without first using special pragmas to disable a warning... */ -#if defined(__clang__) && !defined(__INTEL_COMPILER) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wcast-qual" -#endif - free((void*)p); /* The cast will silence most compilers, but not clang. */ -#if defined(__clang__) && !defined(__INTEL_COMPILER) -# pragma clang diagnostic pop -#endif -} - -/* Initialize a process control structure for kwsysProcess_Execute. */ -static int kwsysProcessInitialize(kwsysProcess* cp) -{ - int i; - volatile pid_t* oldForkPIDs; - for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { - cp->PipeReadEnds[i] = -1; - } - for (i = 0; i < 3; ++i) { - cp->PipeChildStd[i] = -1; - } - cp->SignalPipe = -1; - cp->SelectError = 0; - cp->StartTime.tv_sec = -1; - cp->StartTime.tv_usec = -1; - cp->TimeoutTime.tv_sec = -1; - cp->TimeoutTime.tv_usec = -1; - cp->TimeoutExpired = 0; - cp->PipesLeft = 0; - cp->CommandsLeft = 0; -#if KWSYSPE_USE_SELECT - FD_ZERO(&cp->PipeSet); -#endif - cp->State = kwsysProcess_State_Starting; - cp->Killed = 0; - cp->ErrorMessage[0] = 0; - - oldForkPIDs = cp->ForkPIDs; - cp->ForkPIDs = (volatile pid_t*)malloc(sizeof(volatile pid_t) * - (size_t)(cp->NumberOfCommands)); - kwsysProcessVolatileFree(oldForkPIDs); - if (!cp->ForkPIDs) { - return 0; - } - for (i = 0; i < cp->NumberOfCommands; ++i) { - cp->ForkPIDs[i] = 0; /* can't use memset due to volatile */ - } - - free(cp->CommandExitCodes); - cp->CommandExitCodes = - (int*)malloc(sizeof(int) * (size_t)(cp->NumberOfCommands)); - if (!cp->CommandExitCodes) { - return 0; - } - memset(cp->CommandExitCodes, 0, - sizeof(int) * (size_t)(cp->NumberOfCommands)); - - /* Allocate process result information for each process. */ - free(cp->ProcessResults); - cp->ProcessResults = (kwsysProcessResults*)malloc( - sizeof(kwsysProcessResults) * (size_t)(cp->NumberOfCommands)); - if (!cp->ProcessResults) { - return 0; - } - memset(cp->ProcessResults, 0, - sizeof(kwsysProcessResults) * (size_t)(cp->NumberOfCommands)); - for (i = 0; i < cp->NumberOfCommands; i++) { - cp->ProcessResults[i].ExitException = kwsysProcess_Exception_None; - cp->ProcessResults[i].State = kwsysProcess_StateByIndex_Starting; - cp->ProcessResults[i].ExitCode = 1; - cp->ProcessResults[i].ExitValue = 1; - strcpy(cp->ProcessResults[i].ExitExceptionString, "No exception"); - } - - /* Allocate memory to save the real working directory. */ - if (cp->WorkingDirectory) { -#if defined(MAXPATHLEN) - cp->RealWorkingDirectoryLength = MAXPATHLEN; -#elif defined(PATH_MAX) - cp->RealWorkingDirectoryLength = PATH_MAX; -#else - cp->RealWorkingDirectoryLength = 4096; -#endif - cp->RealWorkingDirectory = - (char*)malloc((size_t)(cp->RealWorkingDirectoryLength)); - if (!cp->RealWorkingDirectory) { - return 0; - } - } - - return 1; -} - -/* Free all resources used by the given kwsysProcess instance that were - allocated by kwsysProcess_Execute. */ -static void kwsysProcessCleanup(kwsysProcess* cp, int error) -{ - int i; - - if (error) { - /* We are cleaning up due to an error. Report the error message - if one has not been provided already. */ - if (cp->ErrorMessage[0] == 0) { - strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE); - } - - /* Set the error state. */ - cp->State = kwsysProcess_State_Error; - - /* Kill any children already started. */ - if (cp->ForkPIDs) { - int status; - for (i = 0; i < cp->NumberOfCommands; ++i) { - if (cp->ForkPIDs[i]) { - /* Kill the child. */ - kwsysProcessKill(cp->ForkPIDs[i]); - - /* Reap the child. Keep trying until the call is not - interrupted. */ - while ((waitpid(cp->ForkPIDs[i], &status, 0) < 0) && - (errno == EINTR)) - ; - } - } - } - - /* Restore the working directory. */ - if (cp->RealWorkingDirectory) { - while ((chdir(cp->RealWorkingDirectory) < 0) && (errno == EINTR)) - ; - } - } - - /* If not creating a detached child, remove this object from the - global set of process objects that wish to be notified when a - child exits. */ - if (!cp->OptionDetach) { - kwsysProcessesRemove(cp); - } - - /* Free memory. */ - if (cp->ForkPIDs) { - kwsysProcessVolatileFree(cp->ForkPIDs); - cp->ForkPIDs = 0; - } - if (cp->RealWorkingDirectory) { - free(cp->RealWorkingDirectory); - cp->RealWorkingDirectory = 0; - } - - /* Close pipe handles. */ - for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { - kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]); - } - for (i = 0; i < 3; ++i) { - kwsysProcessCleanupDescriptor(&cp->PipeChildStd[i]); - } -} - -/* Close the given file descriptor if it is open. Reset its value to -1. */ -static void kwsysProcessCleanupDescriptor(int* pfd) -{ - if (pfd && *pfd > 2) { - /* Keep trying to close until it is not interrupted by a - * signal. */ - while ((close(*pfd) < 0) && (errno == EINTR)) - ; - *pfd = -1; - } -} - -static void kwsysProcessClosePipes(kwsysProcess* cp) -{ - int i; - - /* Close any pipes that are still open. */ - for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { - if (cp->PipeReadEnds[i] >= 0) { -#if KWSYSPE_USE_SELECT - /* If the pipe was reported by the last call to select, we must - read from it. This is needed to satisfy the suggestions from - "man select_tut" and is not needed for the polling - implementation. Ignore the data. */ - if (FD_ISSET(cp->PipeReadEnds[i], &cp->PipeSet)) { - /* We are handling this pipe now. Remove it from the set. */ - FD_CLR(cp->PipeReadEnds[i], &cp->PipeSet); - - /* The pipe is ready to read without blocking. Keep trying to - read until the operation is not interrupted. */ - while ((read(cp->PipeReadEnds[i], cp->PipeBuffer, - KWSYSPE_PIPE_BUFFER_SIZE) < 0) && - (errno == EINTR)) - ; - } -#endif - - /* We are done reading from this pipe. */ - kwsysProcessCleanupDescriptor(&cp->PipeReadEnds[i]); - --cp->PipesLeft; - } - } -} - -static int kwsysProcessSetNonBlocking(int fd) -{ - int flags = fcntl(fd, F_GETFL); - if (flags >= 0) { - flags = fcntl(fd, F_SETFL, flags | O_NONBLOCK); - } - return flags >= 0; -} - -#if defined(__VMS) -int decc$set_child_standard_streams(int fd1, int fd2, int fd3); -#endif - -static int kwsysProcessCreate(kwsysProcess* cp, int prIndex, - kwsysProcessCreateInformation* si) -{ - sigset_t mask, old_mask; - int pgidPipe[2]; - char tmp; - ssize_t readRes; - - /* Create the error reporting pipe. */ - if (pipe(si->ErrorPipe) < 0) { - return 0; - } - - /* Create a pipe for detecting that the child process has created a process - group and session. */ - if (pipe(pgidPipe) < 0) { - kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]); - kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]); - return 0; - } - - /* Set close-on-exec flag on the pipe's write end. */ - if (fcntl(si->ErrorPipe[1], F_SETFD, FD_CLOEXEC) < 0 || - fcntl(pgidPipe[1], F_SETFD, FD_CLOEXEC) < 0) { - kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]); - kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]); - kwsysProcessCleanupDescriptor(&pgidPipe[0]); - kwsysProcessCleanupDescriptor(&pgidPipe[1]); - return 0; - } - - /* Block SIGINT / SIGTERM while we start. The purpose is so that our signal - handler doesn't get called from the child process after the fork and - before the exec, and subsequently start kill()'ing PIDs from ForkPIDs. */ - sigemptyset(&mask); - sigaddset(&mask, SIGINT); - sigaddset(&mask, SIGTERM); - if (sigprocmask(SIG_BLOCK, &mask, &old_mask) < 0) { - kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]); - kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]); - kwsysProcessCleanupDescriptor(&pgidPipe[0]); - kwsysProcessCleanupDescriptor(&pgidPipe[1]); - return 0; - } - -/* Fork off a child process. */ -#if defined(__VMS) - /* VMS needs vfork and execvp to be in the same function because - they use setjmp/longjmp to run the child startup code in the - parent! TODO: OptionDetach. Also - TODO: CreateProcessGroup. */ - cp->ForkPIDs[prIndex] = vfork(); -#else - cp->ForkPIDs[prIndex] = kwsysProcessFork(cp, si); -#endif - if (cp->ForkPIDs[prIndex] < 0) { - sigprocmask(SIG_SETMASK, &old_mask, 0); - kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]); - kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]); - kwsysProcessCleanupDescriptor(&pgidPipe[0]); - kwsysProcessCleanupDescriptor(&pgidPipe[1]); - return 0; - } - - if (cp->ForkPIDs[prIndex] == 0) { -#if defined(__VMS) - /* Specify standard pipes for child process. */ - decc$set_child_standard_streams(si->StdIn, si->StdOut, si->StdErr); -#else - /* Close the read end of the error reporting / process group - setup pipe. */ - close(si->ErrorPipe[0]); - close(pgidPipe[0]); - - /* Setup the stdin, stdout, and stderr pipes. */ - if (si->StdIn > 0) { - dup2(si->StdIn, 0); - } else if (si->StdIn < 0) { - close(0); - } - if (si->StdOut != 1) { - dup2(si->StdOut, 1); - } - if (si->StdErr != 2) { - dup2(si->StdErr, 2); - } - - /* Clear the close-on-exec flag for stdin, stdout, and stderr. - All other pipe handles will be closed when exec succeeds. */ - fcntl(0, F_SETFD, 0); - fcntl(1, F_SETFD, 0); - fcntl(2, F_SETFD, 0); - - /* Restore all default signal handlers. */ - kwsysProcessRestoreDefaultSignalHandlers(); - - /* Now that we have restored default signal handling and created the - process group, restore mask. */ - sigprocmask(SIG_SETMASK, &old_mask, 0); - - /* Create new process group. We use setsid instead of setpgid to avoid - the child getting hung up on signals like SIGTTOU. (In the real world, - this has been observed where "git svn" ends up calling the "resize" - program which opens /dev/tty. */ - if (cp->CreateProcessGroup && setsid() < 0) { - kwsysProcessChildErrorExit(si->ErrorPipe[1]); - } -#endif - - /* Execute the real process. If successful, this does not return. */ - execvp(cp->Commands[prIndex][0], cp->Commands[prIndex]); - /* TODO: What does VMS do if the child fails to start? */ - /* TODO: On VMS, how do we put the process in a new group? */ - - /* Failure. Report error to parent and terminate. */ - kwsysProcessChildErrorExit(si->ErrorPipe[1]); - } - -#if defined(__VMS) - /* Restore the standard pipes of this process. */ - decc$set_child_standard_streams(0, 1, 2); -#endif - - /* We are done with the error reporting pipe and process group setup pipe - write end. */ - kwsysProcessCleanupDescriptor(&si->ErrorPipe[1]); - kwsysProcessCleanupDescriptor(&pgidPipe[1]); - - /* Make sure the child is in the process group before we proceed. This - avoids race conditions with calls to the kill function that we make for - signalling process groups. */ - while ((readRes = read(pgidPipe[0], &tmp, 1)) > 0) - ; - if (readRes < 0) { - sigprocmask(SIG_SETMASK, &old_mask, 0); - kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]); - kwsysProcessCleanupDescriptor(&pgidPipe[0]); - return 0; - } - kwsysProcessCleanupDescriptor(&pgidPipe[0]); - - /* Unmask signals. */ - if (sigprocmask(SIG_SETMASK, &old_mask, 0) < 0) { - kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]); - return 0; - } - - /* A child has been created. */ - ++cp->CommandsLeft; - - /* Block until the child's exec call succeeds and closes the error - pipe or writes data to the pipe to report an error. */ - { - kwsysProcess_ssize_t total = 0; - kwsysProcess_ssize_t n = 1; - /* Read the entire error message up to the length of our buffer. */ - while (total < KWSYSPE_PIPE_BUFFER_SIZE && n > 0) { - /* Keep trying to read until the operation is not interrupted. */ - while (((n = read(si->ErrorPipe[0], cp->ErrorMessage + total, - (size_t)(KWSYSPE_PIPE_BUFFER_SIZE - total))) < 0) && - (errno == EINTR)) - ; - if (n > 0) { - total += n; - } - } - - /* We are done with the error reporting pipe read end. */ - kwsysProcessCleanupDescriptor(&si->ErrorPipe[0]); - - if (total > 0) { - /* The child failed to execute the process. */ - return 0; - } - } - - return 1; -} - -static void kwsysProcessDestroy(kwsysProcess* cp) -{ - /* A child process has terminated. Reap it if it is one handled by - this object. */ - int i; - /* Temporarily disable signals that access ForkPIDs. We don't want them to - read a reaped PID, and writes to ForkPIDs are not atomic. */ - sigset_t mask, old_mask; - sigemptyset(&mask); - sigaddset(&mask, SIGINT); - sigaddset(&mask, SIGTERM); - if (sigprocmask(SIG_BLOCK, &mask, &old_mask) < 0) { - return; - } - - for (i = 0; i < cp->NumberOfCommands; ++i) { - if (cp->ForkPIDs[i]) { - int result; - while (((result = waitpid(cp->ForkPIDs[i], &cp->CommandExitCodes[i], - WNOHANG)) < 0) && - (errno == EINTR)) - ; - if (result > 0) { - /* This child has terminated. */ - cp->ForkPIDs[i] = 0; - if (--cp->CommandsLeft == 0) { - /* All children have terminated. Close the signal pipe - write end so that no more notifications are sent to this - object. */ - kwsysProcessCleanupDescriptor(&cp->SignalPipe); - - /* TODO: Once the children have terminated, switch - WaitForData to use a non-blocking read to get the - rest of the data from the pipe. This is needed when - grandchildren keep the output pipes open. */ - } - } else if (result < 0 && cp->State != kwsysProcess_State_Error) { - /* Unexpected error. Report the first time this happens. */ - strncpy(cp->ErrorMessage, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE); - cp->State = kwsysProcess_State_Error; - } - } - } - - /* Re-enable signals. */ - sigprocmask(SIG_SETMASK, &old_mask, 0); -} - -static int kwsysProcessSetupOutputPipeFile(int* p, const char* name) -{ - int fout; - if (!name) { - return 1; - } - - /* Close the existing descriptor. */ - kwsysProcessCleanupDescriptor(p); - - /* Open a file for the pipe to write. */ - if ((fout = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) { - return 0; - } - - /* Set close-on-exec flag on the pipe's end. */ - if (fcntl(fout, F_SETFD, FD_CLOEXEC) < 0) { - close(fout); - return 0; - } - - /* Assign the replacement descriptor. */ - *p = fout; - return 1; -} - -static int kwsysProcessSetupOutputPipeNative(int* p, int des[2]) -{ - /* Close the existing descriptor. */ - kwsysProcessCleanupDescriptor(p); - - /* Set close-on-exec flag on the pipe's ends. The proper end will - be dup2-ed into the standard descriptor number after fork but - before exec. */ - if ((fcntl(des[0], F_SETFD, FD_CLOEXEC) < 0) || - (fcntl(des[1], F_SETFD, FD_CLOEXEC) < 0)) { - return 0; - } - - /* Assign the replacement descriptor. */ - *p = des[1]; - return 1; -} - -/* Get the time at which either the process or user timeout will - expire. Returns 1 if the user timeout is first, and 0 otherwise. */ -static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout, - kwsysProcessTime* timeoutTime) -{ - /* The first time this is called, we need to calculate the time at - which the child will timeout. */ - if (cp->Timeout > 0 && cp->TimeoutTime.tv_sec < 0) { - kwsysProcessTime length = kwsysProcessTimeFromDouble(cp->Timeout); - cp->TimeoutTime = kwsysProcessTimeAdd(cp->StartTime, length); - } - - /* Start with process timeout. */ - *timeoutTime = cp->TimeoutTime; - - /* Check if the user timeout is earlier. */ - if (userTimeout) { - kwsysProcessTime currentTime = kwsysProcessTimeGetCurrent(); - kwsysProcessTime userTimeoutLength = - kwsysProcessTimeFromDouble(*userTimeout); - kwsysProcessTime userTimeoutTime = - kwsysProcessTimeAdd(currentTime, userTimeoutLength); - if (timeoutTime->tv_sec < 0 || - kwsysProcessTimeLess(userTimeoutTime, *timeoutTime)) { - *timeoutTime = userTimeoutTime; - return 1; - } - } - return 0; -} - -/* Get the length of time before the given timeout time arrives. - Returns 1 if the time has already arrived, and 0 otherwise. */ -static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime, - double* userTimeout, - kwsysProcessTimeNative* timeoutLength, - int zeroIsExpired) -{ - if (timeoutTime->tv_sec < 0) { - /* No timeout time has been requested. */ - return 0; - } else { - /* Calculate the remaining time. */ - kwsysProcessTime currentTime = kwsysProcessTimeGetCurrent(); - kwsysProcessTime timeLeft = - kwsysProcessTimeSubtract(*timeoutTime, currentTime); - if (timeLeft.tv_sec < 0 && userTimeout && *userTimeout <= 0) { - /* Caller has explicitly requested a zero timeout. */ - timeLeft.tv_sec = 0; - timeLeft.tv_usec = 0; - } - - if (timeLeft.tv_sec < 0 || - (timeLeft.tv_sec == 0 && timeLeft.tv_usec == 0 && zeroIsExpired)) { - /* Timeout has already expired. */ - return 1; - } else { - /* There is some time left. */ - timeoutLength->tv_sec = timeLeft.tv_sec; - timeoutLength->tv_usec = timeLeft.tv_usec; - return 0; - } - } -} - -static kwsysProcessTime kwsysProcessTimeGetCurrent(void) -{ - kwsysProcessTime current; - kwsysProcessTimeNative current_native; -#if KWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC - struct timespec current_timespec; - clock_gettime(CLOCK_MONOTONIC, ¤t_timespec); - - current_native.tv_sec = current_timespec.tv_sec; - current_native.tv_usec = current_timespec.tv_nsec / 1000; -#else - gettimeofday(¤t_native, 0); -#endif - current.tv_sec = (long)current_native.tv_sec; - current.tv_usec = (long)current_native.tv_usec; - return current; -} - -static double kwsysProcessTimeToDouble(kwsysProcessTime t) -{ - return (double)t.tv_sec + (double)(t.tv_usec) * 0.000001; -} - -static kwsysProcessTime kwsysProcessTimeFromDouble(double d) -{ - kwsysProcessTime t; - t.tv_sec = (long)d; - t.tv_usec = (long)((d - (double)(t.tv_sec)) * 1000000); - return t; -} - -static int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2) -{ - return ((in1.tv_sec < in2.tv_sec) || - ((in1.tv_sec == in2.tv_sec) && (in1.tv_usec < in2.tv_usec))); -} - -static kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1, - kwsysProcessTime in2) -{ - kwsysProcessTime out; - out.tv_sec = in1.tv_sec + in2.tv_sec; - out.tv_usec = in1.tv_usec + in2.tv_usec; - if (out.tv_usec >= 1000000) { - out.tv_usec -= 1000000; - out.tv_sec += 1; - } - return out; -} - -static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, - kwsysProcessTime in2) -{ - kwsysProcessTime out; - out.tv_sec = in1.tv_sec - in2.tv_sec; - out.tv_usec = in1.tv_usec - in2.tv_usec; - if (out.tv_usec < 0) { - out.tv_usec += 1000000; - out.tv_sec -= 1; - } - return out; -} - -#define KWSYSPE_CASE(type, str) \ - cp->ProcessResults[idx].ExitException = kwsysProcess_Exception_##type; \ - strcpy(cp->ProcessResults[idx].ExitExceptionString, str) -static void kwsysProcessSetExitExceptionByIndex(kwsysProcess* cp, int sig, - int idx) -{ - switch (sig) { -#ifdef SIGSEGV - case SIGSEGV: - KWSYSPE_CASE(Fault, "Segmentation fault"); - break; -#endif -#ifdef SIGBUS -# if !defined(SIGSEGV) || SIGBUS != SIGSEGV - case SIGBUS: - KWSYSPE_CASE(Fault, "Bus error"); - break; -# endif -#endif -#ifdef SIGFPE - case SIGFPE: - KWSYSPE_CASE(Numerical, "Floating-point exception"); - break; -#endif -#ifdef SIGILL - case SIGILL: - KWSYSPE_CASE(Illegal, "Illegal instruction"); - break; -#endif -#ifdef SIGINT - case SIGINT: - KWSYSPE_CASE(Interrupt, "User interrupt"); - break; -#endif -#ifdef SIGABRT - case SIGABRT: - KWSYSPE_CASE(Other, "Child aborted"); - break; -#endif -#ifdef SIGKILL - case SIGKILL: - KWSYSPE_CASE(Other, "Child killed"); - break; -#endif -#ifdef SIGTERM - case SIGTERM: - KWSYSPE_CASE(Other, "Child terminated"); - break; -#endif -#ifdef SIGHUP - case SIGHUP: - KWSYSPE_CASE(Other, "SIGHUP"); - break; -#endif -#ifdef SIGQUIT - case SIGQUIT: - KWSYSPE_CASE(Other, "SIGQUIT"); - break; -#endif -#ifdef SIGTRAP - case SIGTRAP: - KWSYSPE_CASE(Other, "SIGTRAP"); - break; -#endif -#ifdef SIGIOT -# if !defined(SIGABRT) || SIGIOT != SIGABRT - case SIGIOT: - KWSYSPE_CASE(Other, "SIGIOT"); - break; -# endif -#endif -#ifdef SIGUSR1 - case SIGUSR1: - KWSYSPE_CASE(Other, "SIGUSR1"); - break; -#endif -#ifdef SIGUSR2 - case SIGUSR2: - KWSYSPE_CASE(Other, "SIGUSR2"); - break; -#endif -#ifdef SIGPIPE - case SIGPIPE: - KWSYSPE_CASE(Other, "SIGPIPE"); - break; -#endif -#ifdef SIGALRM - case SIGALRM: - KWSYSPE_CASE(Other, "SIGALRM"); - break; -#endif -#ifdef SIGSTKFLT - case SIGSTKFLT: - KWSYSPE_CASE(Other, "SIGSTKFLT"); - break; -#endif -#ifdef SIGCHLD - case SIGCHLD: - KWSYSPE_CASE(Other, "SIGCHLD"); - break; -#elif defined(SIGCLD) - case SIGCLD: - KWSYSPE_CASE(Other, "SIGCLD"); - break; -#endif -#ifdef SIGCONT - case SIGCONT: - KWSYSPE_CASE(Other, "SIGCONT"); - break; -#endif -#ifdef SIGSTOP - case SIGSTOP: - KWSYSPE_CASE(Other, "SIGSTOP"); - break; -#endif -#ifdef SIGTSTP - case SIGTSTP: - KWSYSPE_CASE(Other, "SIGTSTP"); - break; -#endif -#ifdef SIGTTIN - case SIGTTIN: - KWSYSPE_CASE(Other, "SIGTTIN"); - break; -#endif -#ifdef SIGTTOU - case SIGTTOU: - KWSYSPE_CASE(Other, "SIGTTOU"); - break; -#endif -#ifdef SIGURG - case SIGURG: - KWSYSPE_CASE(Other, "SIGURG"); - break; -#endif -#ifdef SIGXCPU - case SIGXCPU: - KWSYSPE_CASE(Other, "SIGXCPU"); - break; -#endif -#ifdef SIGXFSZ - case SIGXFSZ: - KWSYSPE_CASE(Other, "SIGXFSZ"); - break; -#endif -#ifdef SIGVTALRM - case SIGVTALRM: - KWSYSPE_CASE(Other, "SIGVTALRM"); - break; -#endif -#ifdef SIGPROF - case SIGPROF: - KWSYSPE_CASE(Other, "SIGPROF"); - break; -#endif -#ifdef SIGWINCH - case SIGWINCH: - KWSYSPE_CASE(Other, "SIGWINCH"); - break; -#endif -#ifdef SIGPOLL - case SIGPOLL: - KWSYSPE_CASE(Other, "SIGPOLL"); - break; -#endif -#ifdef SIGIO -# if !defined(SIGPOLL) || SIGIO != SIGPOLL - case SIGIO: - KWSYSPE_CASE(Other, "SIGIO"); - break; -# endif -#endif -#ifdef SIGPWR - case SIGPWR: - KWSYSPE_CASE(Other, "SIGPWR"); - break; -#endif -#ifdef SIGSYS - case SIGSYS: - KWSYSPE_CASE(Other, "SIGSYS"); - break; -#endif -#ifdef SIGUNUSED -# if !defined(SIGSYS) || SIGUNUSED != SIGSYS - case SIGUNUSED: - KWSYSPE_CASE(Other, "SIGUNUSED"); - break; -# endif -#endif - default: - cp->ProcessResults[idx].ExitException = kwsysProcess_Exception_Other; - sprintf(cp->ProcessResults[idx].ExitExceptionString, "Signal %d", sig); - break; - } -} -#undef KWSYSPE_CASE - -/* When the child process encounters an error before its program is - invoked, this is called to report the error to the parent and - exit. */ -static void kwsysProcessChildErrorExit(int errorPipe) -{ - /* Construct the error message. */ - char buffer[KWSYSPE_PIPE_BUFFER_SIZE]; - kwsysProcess_ssize_t result; - strncpy(buffer, strerror(errno), KWSYSPE_PIPE_BUFFER_SIZE); - buffer[KWSYSPE_PIPE_BUFFER_SIZE - 1] = '\0'; - - /* Report the error to the parent through the special pipe. */ - result = write(errorPipe, buffer, strlen(buffer)); - (void)result; - - /* Terminate without cleanup. */ - _exit(1); -} - -/* Restores all signal handlers to their default values. */ -static void kwsysProcessRestoreDefaultSignalHandlers(void) -{ - struct sigaction act; - memset(&act, 0, sizeof(struct sigaction)); - act.sa_handler = SIG_DFL; -#ifdef SIGHUP - sigaction(SIGHUP, &act, 0); -#endif -#ifdef SIGINT - sigaction(SIGINT, &act, 0); -#endif -#ifdef SIGQUIT - sigaction(SIGQUIT, &act, 0); -#endif -#ifdef SIGILL - sigaction(SIGILL, &act, 0); -#endif -#ifdef SIGTRAP - sigaction(SIGTRAP, &act, 0); -#endif -#ifdef SIGABRT - sigaction(SIGABRT, &act, 0); -#endif -#ifdef SIGIOT - sigaction(SIGIOT, &act, 0); -#endif -#ifdef SIGBUS - sigaction(SIGBUS, &act, 0); -#endif -#ifdef SIGFPE - sigaction(SIGFPE, &act, 0); -#endif -#ifdef SIGUSR1 - sigaction(SIGUSR1, &act, 0); -#endif -#ifdef SIGSEGV - sigaction(SIGSEGV, &act, 0); -#endif -#ifdef SIGUSR2 - sigaction(SIGUSR2, &act, 0); -#endif -#ifdef SIGPIPE - sigaction(SIGPIPE, &act, 0); -#endif -#ifdef SIGALRM - sigaction(SIGALRM, &act, 0); -#endif -#ifdef SIGTERM - sigaction(SIGTERM, &act, 0); -#endif -#ifdef SIGSTKFLT - sigaction(SIGSTKFLT, &act, 0); -#endif -#ifdef SIGCLD - sigaction(SIGCLD, &act, 0); -#endif -#ifdef SIGCHLD - sigaction(SIGCHLD, &act, 0); -#endif -#ifdef SIGCONT - sigaction(SIGCONT, &act, 0); -#endif -#ifdef SIGTSTP - sigaction(SIGTSTP, &act, 0); -#endif -#ifdef SIGTTIN - sigaction(SIGTTIN, &act, 0); -#endif -#ifdef SIGTTOU - sigaction(SIGTTOU, &act, 0); -#endif -#ifdef SIGURG - sigaction(SIGURG, &act, 0); -#endif -#ifdef SIGXCPU - sigaction(SIGXCPU, &act, 0); -#endif -#ifdef SIGXFSZ - sigaction(SIGXFSZ, &act, 0); -#endif -#ifdef SIGVTALRM - sigaction(SIGVTALRM, &act, 0); -#endif -#ifdef SIGPROF - sigaction(SIGPROF, &act, 0); -#endif -#ifdef SIGWINCH - sigaction(SIGWINCH, &act, 0); -#endif -#ifdef SIGPOLL - sigaction(SIGPOLL, &act, 0); -#endif -#ifdef SIGIO - sigaction(SIGIO, &act, 0); -#endif -#ifdef SIGPWR - sigaction(SIGPWR, &act, 0); -#endif -#ifdef SIGSYS - sigaction(SIGSYS, &act, 0); -#endif -#ifdef SIGUNUSED - sigaction(SIGUNUSED, &act, 0); -#endif -} - -static void kwsysProcessExit(void) -{ - _exit(0); -} - -#if !defined(__VMS) -static pid_t kwsysProcessFork(kwsysProcess* cp, - kwsysProcessCreateInformation* si) -{ - /* Create a detached process if requested. */ - if (cp->OptionDetach) { - /* Create an intermediate process. */ - pid_t middle_pid = fork(); - if (middle_pid < 0) { - /* Fork failed. Return as if we were not detaching. */ - return middle_pid; - } else if (middle_pid == 0) { - /* This is the intermediate process. Create the real child. */ - pid_t child_pid = fork(); - if (child_pid == 0) { - /* This is the real child process. There is nothing to do here. */ - return 0; - } else { - /* Use the error pipe to report the pid to the real parent. */ - while ((write(si->ErrorPipe[1], &child_pid, sizeof(child_pid)) < 0) && - (errno == EINTR)) - ; - - /* Exit without cleanup. The parent holds all resources. */ - kwsysProcessExit(); - return 0; /* Never reached, but avoids SunCC warning. */ - } - } else { - /* This is the original parent process. The intermediate - process will use the error pipe to report the pid of the - detached child. */ - pid_t child_pid; - int status; - while ((read(si->ErrorPipe[0], &child_pid, sizeof(child_pid)) < 0) && - (errno == EINTR)) - ; - - /* Wait for the intermediate process to exit and clean it up. */ - while ((waitpid(middle_pid, &status, 0) < 0) && (errno == EINTR)) - ; - return child_pid; - } - } else { - /* Not creating a detached process. Use normal fork. */ - return fork(); - } -} -#endif - -/* We try to obtain process information by invoking the ps command. - Here we define the command to call on each platform and the - corresponding parsing format string. The parsing format should - have two integers to store: the pid and then the ppid. */ -#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \ - defined(__OpenBSD__) || defined(__GLIBC__) || defined(__GNU__) -# define KWSYSPE_PS_COMMAND "ps axo pid,ppid" -# define KWSYSPE_PS_FORMAT "%d %d\n" -#elif defined(__sun) && (defined(__SVR4) || defined(__svr4__)) /* Solaris */ -# define KWSYSPE_PS_COMMAND "ps -e -o pid,ppid" -# define KWSYSPE_PS_FORMAT "%d %d\n" -#elif defined(__hpux) || defined(__sun__) || defined(__sgi) || \ - defined(_AIX) || defined(__sparc) -# define KWSYSPE_PS_COMMAND "ps -ef" -# define KWSYSPE_PS_FORMAT "%*s %d %d %*[^\n]\n" -#elif defined(__QNX__) -# define KWSYSPE_PS_COMMAND "ps -Af" -# define KWSYSPE_PS_FORMAT "%*d %d %d %*[^\n]\n" -#elif defined(__CYGWIN__) -# define KWSYSPE_PS_COMMAND "ps aux" -# define KWSYSPE_PS_FORMAT "%d %d %*[^\n]\n" -#endif - -void kwsysProcess_KillPID(unsigned long process_id) -{ - kwsysProcessKill((pid_t)process_id); -} - -static void kwsysProcessKill(pid_t process_id) -{ -#if defined(__linux__) || defined(__CYGWIN__) - DIR* procdir; -#endif - - /* Suspend the process to be sure it will not create more children. */ - kill(process_id, SIGSTOP); - -#if defined(__CYGWIN__) - /* Some Cygwin versions seem to need help here. Give up our time slice - so that the child can process SIGSTOP before we send SIGKILL. */ - usleep(1); -#endif - -/* Kill all children if we can find them. */ -#if defined(__linux__) || defined(__CYGWIN__) - /* First try using the /proc filesystem. */ - if ((procdir = opendir("/proc")) != NULL) { -# if defined(MAXPATHLEN) - char fname[MAXPATHLEN]; -# elif defined(PATH_MAX) - char fname[PATH_MAX]; -# else - char fname[4096]; -# endif - char buffer[KWSYSPE_PIPE_BUFFER_SIZE + 1]; - struct dirent* d; - - /* Each process has a directory in /proc whose name is the pid. - Within this directory is a file called stat that has the - following format: - - pid (command line) status ppid ... - - We want to get the ppid for all processes. Those that have - process_id as their parent should be recursively killed. */ - for (d = readdir(procdir); d; d = readdir(procdir)) { - int pid; - if (sscanf(d->d_name, "%d", &pid) == 1 && pid != 0) { - struct stat finfo; - sprintf(fname, "/proc/%d/stat", pid); - if (stat(fname, &finfo) == 0) { - FILE* f = fopen(fname, "r"); - if (f) { - size_t nread = fread(buffer, 1, KWSYSPE_PIPE_BUFFER_SIZE, f); - fclose(f); - buffer[nread] = '\0'; - if (nread > 0) { - const char* rparen = strrchr(buffer, ')'); - int ppid; - if (rparen && (sscanf(rparen + 1, "%*s %d", &ppid) == 1)) { - if (ppid == process_id) { - /* Recursively kill this child and its children. */ - kwsysProcessKill(pid); - } - } - } - } - } - } - } - closedir(procdir); - } else -#endif - { -#if defined(KWSYSPE_PS_COMMAND) - /* Try running "ps" to get the process information. */ - FILE* ps = popen(KWSYSPE_PS_COMMAND, "r"); - - /* Make sure the process started and provided a valid header. */ - if (ps && fscanf(ps, "%*[^\n]\n") != EOF) { - /* Look for processes whose parent is the process being killed. */ - int pid, ppid; - while (fscanf(ps, KWSYSPE_PS_FORMAT, &pid, &ppid) == 2) { - if (ppid == process_id) { - /* Recursively kill this child and its children. */ - kwsysProcessKill(pid); - } - } - } - - /* We are done with the ps process. */ - if (ps) { - pclose(ps); - } -#endif - } - - /* Kill the process. */ - kill(process_id, SIGKILL); - -#if defined(__APPLE__) - /* On OS X 10.3 the above SIGSTOP occasionally prevents the SIGKILL - from working. Just in case, we resume the child and kill it - again. There is a small race condition in this obscure case. If - the child manages to fork again between these two signals, we - will not catch its children. */ - kill(process_id, SIGCONT); - kill(process_id, SIGKILL); -#endif -} - -#if defined(__VMS) -int decc$feature_get_index(const char* name); -int decc$feature_set_value(int index, int mode, int value); -static int kwsysProcessSetVMSFeature(const char* name, int value) -{ - int i; - errno = 0; - i = decc$feature_get_index(name); - return i >= 0 && (decc$feature_set_value(i, 1, value) >= 0 || errno == 0); -} -#endif - -/* Global set of executing processes for use by the signal handler. - This global instance will be zero-initialized by the compiler. */ -typedef struct kwsysProcessInstances_s -{ - int Count; - int Size; - kwsysProcess** Processes; -} kwsysProcessInstances; -static kwsysProcessInstances kwsysProcesses; - -/* The old SIGCHLD / SIGINT / SIGTERM handlers. */ -static struct sigaction kwsysProcessesOldSigChldAction; -static struct sigaction kwsysProcessesOldSigIntAction; -static struct sigaction kwsysProcessesOldSigTermAction; - -static void kwsysProcessesUpdate(kwsysProcessInstances* newProcesses) -{ - /* Block signals while we update the set of pipes to check. - TODO: sigprocmask is undefined for threaded apps. See - pthread_sigmask. */ - sigset_t newset; - sigset_t oldset; - sigemptyset(&newset); - sigaddset(&newset, SIGCHLD); - sigaddset(&newset, SIGINT); - sigaddset(&newset, SIGTERM); - sigprocmask(SIG_BLOCK, &newset, &oldset); - - /* Store the new set in that seen by the signal handler. */ - kwsysProcesses = *newProcesses; - - /* Restore the signal mask to the previous setting. */ - sigprocmask(SIG_SETMASK, &oldset, 0); -} - -static int kwsysProcessesAdd(kwsysProcess* cp) -{ - /* Create a pipe through which the signal handler can notify the - given process object that a child has exited. */ - { - /* Create the pipe. */ - int p[2]; - if (pipe(p KWSYSPE_VMS_NONBLOCK) < 0) { - return 0; - } - - /* Store the pipes now to be sure they are cleaned up later. */ - cp->PipeReadEnds[KWSYSPE_PIPE_SIGNAL] = p[0]; - cp->SignalPipe = p[1]; - - /* Switch the pipe to non-blocking mode so that reading a byte can - be an atomic test-and-set. */ - if (!kwsysProcessSetNonBlocking(p[0]) || - !kwsysProcessSetNonBlocking(p[1])) { - return 0; - } - - /* The children do not need this pipe. Set close-on-exec flag on - the pipe's ends. */ - if ((fcntl(p[0], F_SETFD, FD_CLOEXEC) < 0) || - (fcntl(p[1], F_SETFD, FD_CLOEXEC) < 0)) { - return 0; - } - } - - /* Attempt to add the given signal pipe to the signal handler set. */ - { - - /* Make sure there is enough space for the new signal pipe. */ - kwsysProcessInstances oldProcesses = kwsysProcesses; - kwsysProcessInstances newProcesses = oldProcesses; - if (oldProcesses.Count == oldProcesses.Size) { - /* Start with enough space for a small number of process instances - and double the size each time more is needed. */ - newProcesses.Size = oldProcesses.Size ? oldProcesses.Size * 2 : 4; - - /* Try allocating the new block of memory. */ - if ((newProcesses.Processes = ((kwsysProcess**)malloc( - (size_t)(newProcesses.Size) * sizeof(kwsysProcess*))))) { - /* Copy the old pipe set to the new memory. */ - if (oldProcesses.Count > 0) { - memcpy(newProcesses.Processes, oldProcesses.Processes, - ((size_t)(oldProcesses.Count) * sizeof(kwsysProcess*))); - } - } else { - /* Failed to allocate memory for the new signal pipe set. */ - return 0; - } - } - - /* Append the new signal pipe to the set. */ - newProcesses.Processes[newProcesses.Count++] = cp; - - /* Store the new set in that seen by the signal handler. */ - kwsysProcessesUpdate(&newProcesses); - - /* Free the original pipes if new ones were allocated. */ - if (newProcesses.Processes != oldProcesses.Processes) { - free(oldProcesses.Processes); - } - - /* If this is the first process, enable the signal handler. */ - if (newProcesses.Count == 1) { - /* Install our handler for SIGCHLD. Repeat call until it is not - interrupted. */ - struct sigaction newSigAction; - memset(&newSigAction, 0, sizeof(struct sigaction)); -#if KWSYSPE_USE_SIGINFO - newSigAction.sa_sigaction = kwsysProcessesSignalHandler; - newSigAction.sa_flags = SA_NOCLDSTOP | SA_SIGINFO; -# ifdef SA_RESTART - newSigAction.sa_flags |= SA_RESTART; -# endif -#else - newSigAction.sa_handler = kwsysProcessesSignalHandler; - newSigAction.sa_flags = SA_NOCLDSTOP; -#endif - sigemptyset(&newSigAction.sa_mask); - while ((sigaction(SIGCHLD, &newSigAction, - &kwsysProcessesOldSigChldAction) < 0) && - (errno == EINTR)) - ; - - /* Install our handler for SIGINT / SIGTERM. Repeat call until - it is not interrupted. */ - sigemptyset(&newSigAction.sa_mask); - sigaddset(&newSigAction.sa_mask, SIGTERM); - while ((sigaction(SIGINT, &newSigAction, - &kwsysProcessesOldSigIntAction) < 0) && - (errno == EINTR)) - ; - - sigemptyset(&newSigAction.sa_mask); - sigaddset(&newSigAction.sa_mask, SIGINT); - while ((sigaction(SIGTERM, &newSigAction, - &kwsysProcessesOldSigIntAction) < 0) && - (errno == EINTR)) - ; - } - } - - return 1; -} - -static void kwsysProcessesRemove(kwsysProcess* cp) -{ - /* Attempt to remove the given signal pipe from the signal handler set. */ - { - /* Find the given process in the set. */ - kwsysProcessInstances newProcesses = kwsysProcesses; - int i; - for (i = 0; i < newProcesses.Count; ++i) { - if (newProcesses.Processes[i] == cp) { - break; - } - } - if (i < newProcesses.Count) { - /* Remove the process from the set. */ - --newProcesses.Count; - for (; i < newProcesses.Count; ++i) { - newProcesses.Processes[i] = newProcesses.Processes[i + 1]; - } - - /* If this was the last process, disable the signal handler. */ - if (newProcesses.Count == 0) { - /* Restore the signal handlers. Repeat call until it is not - interrupted. */ - while ((sigaction(SIGCHLD, &kwsysProcessesOldSigChldAction, 0) < 0) && - (errno == EINTR)) - ; - while ((sigaction(SIGINT, &kwsysProcessesOldSigIntAction, 0) < 0) && - (errno == EINTR)) - ; - while ((sigaction(SIGTERM, &kwsysProcessesOldSigTermAction, 0) < 0) && - (errno == EINTR)) - ; - - /* Free the table of process pointers since it is now empty. - This is safe because the signal handler has been removed. */ - newProcesses.Size = 0; - free(newProcesses.Processes); - newProcesses.Processes = 0; - } - - /* Store the new set in that seen by the signal handler. */ - kwsysProcessesUpdate(&newProcesses); - } - } - - /* Close the pipe through which the signal handler may have notified - the given process object that a child has exited. */ - kwsysProcessCleanupDescriptor(&cp->SignalPipe); -} - -static void kwsysProcessesSignalHandler(int signum -#if KWSYSPE_USE_SIGINFO - , - siginfo_t* info, void* ucontext -#endif -) -{ - int i, j, procStatus, old_errno = errno; -#if KWSYSPE_USE_SIGINFO - (void)info; - (void)ucontext; -#endif - - /* Signal all process objects that a child has terminated. */ - switch (signum) { - case SIGCHLD: - for (i = 0; i < kwsysProcesses.Count; ++i) { - /* Set the pipe in a signalled state. */ - char buf = 1; - kwsysProcess* cp = kwsysProcesses.Processes[i]; - kwsysProcess_ssize_t pipeStatus = - read(cp->PipeReadEnds[KWSYSPE_PIPE_SIGNAL], &buf, 1); - (void)pipeStatus; - pipeStatus = write(cp->SignalPipe, &buf, 1); - (void)pipeStatus; - } - break; - case SIGINT: - case SIGTERM: - /* Signal child processes that are running in new process groups. */ - for (i = 0; i < kwsysProcesses.Count; ++i) { - kwsysProcess* cp = kwsysProcesses.Processes[i]; - /* Check Killed to avoid data race condition when killing. - Check State to avoid data race condition in kwsysProcessCleanup - when there is an error (it leaves a reaped PID). */ - if (cp->CreateProcessGroup && !cp->Killed && - cp->State != kwsysProcess_State_Error && cp->ForkPIDs) { - for (j = 0; j < cp->NumberOfCommands; ++j) { - /* Make sure the PID is still valid. */ - if (cp->ForkPIDs[j]) { - /* The user created a process group for this process. The group - ID - is the process ID for the original process in the group. */ - kill(-cp->ForkPIDs[j], SIGINT); - } - } - } - } - - /* Wait for all processes to terminate. */ - while (wait(&procStatus) >= 0 || errno != ECHILD) { - } - - /* Terminate the process, which is now in an inconsistent state - because we reaped all the PIDs that it may have been reaping - or may have reaped in the future. Reraise the signal so that - the proper exit code is returned. */ - { - /* Install default signal handler. */ - struct sigaction defSigAction; - sigset_t unblockSet; - memset(&defSigAction, 0, sizeof(defSigAction)); - defSigAction.sa_handler = SIG_DFL; - sigemptyset(&defSigAction.sa_mask); - while ((sigaction(signum, &defSigAction, 0) < 0) && (errno == EINTR)) - ; - /* Unmask the signal. */ - sigemptyset(&unblockSet); - sigaddset(&unblockSet, signum); - sigprocmask(SIG_UNBLOCK, &unblockSet, 0); - /* Raise the signal again. */ - raise(signum); - /* We shouldn't get here... but if we do... */ - _exit(1); - } - /* break omitted to silence unreachable code clang compiler warning. */ - } - -#if !KWSYSPE_USE_SIGINFO - /* Re-Install our handler. Repeat call until it is not interrupted. */ - { - struct sigaction newSigAction; - struct sigaction& oldSigAction; - memset(&newSigAction, 0, sizeof(struct sigaction)); - newSigChldAction.sa_handler = kwsysProcessesSignalHandler; - newSigChldAction.sa_flags = SA_NOCLDSTOP; - sigemptyset(&newSigAction.sa_mask); - switch (signum) { - case SIGCHLD: - oldSigAction = &kwsysProcessesOldSigChldAction; - break; - case SIGINT: - sigaddset(&newSigAction.sa_mask, SIGTERM); - oldSigAction = &kwsysProcessesOldSigIntAction; - break; - case SIGTERM: - sigaddset(&newSigAction.sa_mask, SIGINT); - oldSigAction = &kwsysProcessesOldSigTermAction; - break; - default: - return 0; - } - while ((sigaction(signum, &newSigAction, oldSigAction) < 0) && - (errno == EINTR)) - ; - } -#endif - - errno = old_errno; -} - -void kwsysProcess_ResetStartTime(kwsysProcess* cp) -{ - if (!cp) { - return; - } - /* Reset start time. */ - cp->StartTime = kwsysProcessTimeGetCurrent(); -} diff --git a/test/API/driver/kwsys/ProcessWin32.c b/test/API/driver/kwsys/ProcessWin32.c deleted file mode 100644 index a963862..0000000 --- a/test/API/driver/kwsys/ProcessWin32.c +++ /dev/null @@ -1,2786 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include "kwsysPrivate.h" -#include KWSYS_HEADER(Process.h) -#include KWSYS_HEADER(Encoding.h) - -/* Work-around CMake dependency scanning limitation. This must - duplicate the above list of headers. */ -#if 0 -# include "Encoding.h.in" -# include "Process.h.in" -#endif - -/* - -Implementation for Windows - -On windows, a thread is created to wait for data on each pipe. The -threads are synchronized with the main thread to simulate the use of -a UNIX-style select system call. - -*/ - -#ifdef _MSC_VER -# pragma warning(push, 1) -#endif -#include /* Windows API */ -#if defined(_MSC_VER) && _MSC_VER >= 1800 -# define KWSYS_WINDOWS_DEPRECATED_GetVersionEx -#endif -#include /* _unlink */ -#include /* sprintf */ -#include /* strlen, strdup */ -#ifdef __WATCOMC__ -# define _unlink unlink -#endif - -#ifndef _MAX_FNAME -# define _MAX_FNAME 4096 -#endif -#ifndef _MAX_PATH -# define _MAX_PATH 4096 -#endif - -#ifdef _MSC_VER -# pragma warning(pop) -# pragma warning(disable : 4514) -# pragma warning(disable : 4706) -#endif - -#if defined(__BORLANDC__) -# pragma warn - 8004 /* assigned a value that is never used */ -# pragma warn - 8060 /* Assignment inside if() condition. */ -#endif - -/* There are pipes for the process pipeline's stdout and stderr. */ -#define KWSYSPE_PIPE_COUNT 2 -#define KWSYSPE_PIPE_STDOUT 0 -#define KWSYSPE_PIPE_STDERR 1 - -/* The maximum amount to read from a pipe at a time. */ -#define KWSYSPE_PIPE_BUFFER_SIZE 1024 - -/* Debug output macro. */ -#if 0 -# define KWSYSPE_DEBUG(x) \ - ((void*)cp == (void*)0x00226DE0 \ - ? (fprintf(stderr, "%d/%p/%d ", (int)GetCurrentProcessId(), cp, \ - __LINE__), \ - fprintf x, fflush(stderr), 1) \ - : (1)) -#else -# define KWSYSPE_DEBUG(x) (void)1 -#endif - -typedef LARGE_INTEGER kwsysProcessTime; - -typedef struct kwsysProcessCreateInformation_s -{ - /* Windows child startup control data. */ - STARTUPINFOW StartupInfo; - - /* Original handles before making inherited duplicates. */ - HANDLE hStdInput; - HANDLE hStdOutput; - HANDLE hStdError; -} kwsysProcessCreateInformation; - -typedef struct kwsysProcessPipeData_s kwsysProcessPipeData; -static DWORD WINAPI kwsysProcessPipeThreadRead(LPVOID ptd); -static void kwsysProcessPipeThreadReadPipe(kwsysProcess* cp, - kwsysProcessPipeData* td); -static DWORD WINAPI kwsysProcessPipeThreadWake(LPVOID ptd); -static void kwsysProcessPipeThreadWakePipe(kwsysProcess* cp, - kwsysProcessPipeData* td); -static int kwsysProcessInitialize(kwsysProcess* cp); -static DWORD kwsysProcessCreate(kwsysProcess* cp, int index, - kwsysProcessCreateInformation* si); -static void kwsysProcessDestroy(kwsysProcess* cp, int event); -static DWORD kwsysProcessSetupOutputPipeFile(PHANDLE handle, const char* name); -static void kwsysProcessSetupSharedPipe(DWORD nStdHandle, PHANDLE handle); -static void kwsysProcessSetupPipeNative(HANDLE native, PHANDLE handle); -static void kwsysProcessCleanupHandle(PHANDLE h); -static void kwsysProcessCleanup(kwsysProcess* cp, DWORD error); -static void kwsysProcessCleanErrorMessage(kwsysProcess* cp); -static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout, - kwsysProcessTime* timeoutTime); -static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime, - double* userTimeout, - kwsysProcessTime* timeoutLength); -static kwsysProcessTime kwsysProcessTimeGetCurrent(void); -static DWORD kwsysProcessTimeToDWORD(kwsysProcessTime t); -static double kwsysProcessTimeToDouble(kwsysProcessTime t); -static kwsysProcessTime kwsysProcessTimeFromDouble(double d); -static int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2); -static kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1, - kwsysProcessTime in2); -static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, - kwsysProcessTime in2); -static void kwsysProcessSetExitExceptionByIndex(kwsysProcess* cp, int code, - int idx); -static void kwsysProcessKillTree(int pid); -static void kwsysProcessDisablePipeThreads(kwsysProcess* cp); -static int kwsysProcessesInitialize(void); -static int kwsysTryEnterCreateProcessSection(void); -static void kwsysLeaveCreateProcessSection(void); -static int kwsysProcessesAdd(HANDLE hProcess, DWORD dwProcessId, - int newProcessGroup); -static void kwsysProcessesRemove(HANDLE hProcess); -static BOOL WINAPI kwsysCtrlHandler(DWORD dwCtrlType); - -/* A structure containing synchronization data for each thread. */ -typedef struct kwsysProcessPipeSync_s kwsysProcessPipeSync; -struct kwsysProcessPipeSync_s -{ - /* Handle to the thread. */ - HANDLE Thread; - - /* Semaphore indicating to the thread that a process has started. */ - HANDLE Ready; - - /* Semaphore indicating to the thread that it should begin work. */ - HANDLE Go; - - /* Semaphore indicating thread has reset for another process. */ - HANDLE Reset; -}; - -/* A structure containing data for each pipe's threads. */ -struct kwsysProcessPipeData_s -{ - /* ------------- Data managed per instance of kwsysProcess ------------- */ - - /* Synchronization data for reading thread. */ - kwsysProcessPipeSync Reader; - - /* Synchronization data for waking thread. */ - kwsysProcessPipeSync Waker; - - /* Index of this pipe. */ - int Index; - - /* The kwsysProcess instance owning this pipe. */ - kwsysProcess* Process; - - /* ------------- Data managed per call to Execute ------------- */ - - /* Buffer for data read in this pipe's thread. */ - char DataBuffer[KWSYSPE_PIPE_BUFFER_SIZE]; - - /* The length of the data stored in the buffer. */ - DWORD DataLength; - - /* Whether the pipe has been closed. */ - int Closed; - - /* Handle for the read end of this pipe. */ - HANDLE Read; - - /* Handle for the write end of this pipe. */ - HANDLE Write; -}; - -/* A structure containing results data for each process. */ -typedef struct kwsysProcessResults_s kwsysProcessResults; -struct kwsysProcessResults_s -{ - /* The status of the process. */ - int State; - - /* The exceptional behavior that terminated the process, if any. */ - int ExitException; - - /* The process exit code. */ - DWORD ExitCode; - - /* The process return code, if any. */ - int ExitValue; - - /* Description for the ExitException. */ - char ExitExceptionString[KWSYSPE_PIPE_BUFFER_SIZE + 1]; -}; - -/* Structure containing data used to implement the child's execution. */ -struct kwsysProcess_s -{ - /* ------------- Data managed per instance of kwsysProcess ------------- */ - - /* The status of the process structure. */ - int State; - - /* The command lines to execute. */ - wchar_t** Commands; - int NumberOfCommands; - - /* The exit code of each command. */ - DWORD* CommandExitCodes; - - /* The working directory for the child process. */ - wchar_t* WorkingDirectory; - - /* Whether to create the child as a detached process. */ - int OptionDetach; - - /* Whether the child was created as a detached process. */ - int Detached; - - /* Whether to hide the child process's window. */ - int HideWindow; - - /* Whether to treat command lines as verbatim. */ - int Verbatim; - - /* Whether to merge stdout/stderr of the child. */ - int MergeOutput; - - /* Whether to create the process in a new process group. */ - int CreateProcessGroup; - - /* Mutex to protect the shared index used by threads to report data. */ - HANDLE SharedIndexMutex; - - /* Semaphore used by threads to signal data ready. */ - HANDLE Full; - - /* Whether we are currently deleting this kwsysProcess instance. */ - int Deleting; - - /* Data specific to each pipe and its thread. */ - kwsysProcessPipeData Pipe[KWSYSPE_PIPE_COUNT]; - - /* Name of files to which stdin and stdout pipes are attached. */ - char* PipeFileSTDIN; - char* PipeFileSTDOUT; - char* PipeFileSTDERR; - - /* Whether each pipe is shared with the parent process. */ - int PipeSharedSTDIN; - int PipeSharedSTDOUT; - int PipeSharedSTDERR; - - /* Native pipes provided by the user. */ - HANDLE PipeNativeSTDIN[2]; - HANDLE PipeNativeSTDOUT[2]; - HANDLE PipeNativeSTDERR[2]; - - /* ------------- Data managed per call to Execute ------------- */ - - /* Index of last pipe to report data, if any. */ - int CurrentIndex; - - /* Index shared by threads to report data. */ - int SharedIndex; - - /* The timeout length. */ - double Timeout; - - /* Time at which the child started. */ - kwsysProcessTime StartTime; - - /* Time at which the child will timeout. Negative for no timeout. */ - kwsysProcessTime TimeoutTime; - - /* Flag for whether the process was killed. */ - int Killed; - - /* Flag for whether the timeout expired. */ - int TimeoutExpired; - - /* Flag for whether the process has terminated. */ - int Terminated; - - /* The number of pipes still open during execution and while waiting - for pipes to close after process termination. */ - int PipesLeft; - - /* Buffer for error messages. */ - char ErrorMessage[KWSYSPE_PIPE_BUFFER_SIZE + 1]; - - /* process results. */ - kwsysProcessResults* ProcessResults; - - /* Windows process information data. */ - PROCESS_INFORMATION* ProcessInformation; - - /* Data and process termination events for which to wait. */ - PHANDLE ProcessEvents; - int ProcessEventsLength; - - /* Real working directory of our own process. */ - DWORD RealWorkingDirectoryLength; - wchar_t* RealWorkingDirectory; - - /* Own handles for the child's ends of the pipes in the parent process. - Used temporarily during process creation. */ - HANDLE PipeChildStd[3]; -}; - -kwsysProcess* kwsysProcess_New(void) -{ - int i; - - /* Process control structure. */ - kwsysProcess* cp; - - /* Windows version number data. */ - OSVERSIONINFO osv; - - /* Initialize list of processes before we get any farther. It's especially - important that the console Ctrl handler be added BEFORE starting the - first process. This prevents the risk of an orphaned process being - started by the main thread while the default Ctrl handler is in - progress. */ - if (!kwsysProcessesInitialize()) { - return 0; - } - - /* Allocate a process control structure. */ - cp = (kwsysProcess*)malloc(sizeof(kwsysProcess)); - if (!cp) { - /* Could not allocate memory for the control structure. */ - return 0; - } - ZeroMemory(cp, sizeof(*cp)); - - /* Share stdin with the parent process by default. */ - cp->PipeSharedSTDIN = 1; - - /* Set initial status. */ - cp->State = kwsysProcess_State_Starting; - - /* Choose a method of running the child based on version of - windows. */ - ZeroMemory(&osv, sizeof(osv)); - osv.dwOSVersionInfoSize = sizeof(osv); -#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx -# pragma warning(push) -# ifdef __INTEL_COMPILER -# pragma warning(disable : 1478) -# elif defined __clang__ -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated-declarations" -# else -# pragma warning(disable : 4996) -# endif -#endif - GetVersionEx(&osv); -#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx -# ifdef __clang__ -# pragma clang diagnostic pop -# else -# pragma warning(pop) -# endif -#endif - if (osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { - /* Win9x no longer supported. */ - kwsysProcess_Delete(cp); - return 0; - } - - /* Initially no thread owns the mutex. Initialize semaphore to 1. */ - if (!(cp->SharedIndexMutex = CreateSemaphore(0, 1, 1, 0))) { - kwsysProcess_Delete(cp); - return 0; - } - - /* Initially no data are available. Initialize semaphore to 0. */ - if (!(cp->Full = CreateSemaphore(0, 0, 1, 0))) { - kwsysProcess_Delete(cp); - return 0; - } - - /* Create the thread to read each pipe. */ - for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { - DWORD dummy = 0; - - /* Assign the thread its index. */ - cp->Pipe[i].Index = i; - - /* Give the thread a pointer back to the kwsysProcess instance. */ - cp->Pipe[i].Process = cp; - - /* No process is yet running. Initialize semaphore to 0. */ - if (!(cp->Pipe[i].Reader.Ready = CreateSemaphore(0, 0, 1, 0))) { - kwsysProcess_Delete(cp); - return 0; - } - - /* The pipe is not yet reset. Initialize semaphore to 0. */ - if (!(cp->Pipe[i].Reader.Reset = CreateSemaphore(0, 0, 1, 0))) { - kwsysProcess_Delete(cp); - return 0; - } - - /* The thread's buffer is initially empty. Initialize semaphore to 1. */ - if (!(cp->Pipe[i].Reader.Go = CreateSemaphore(0, 1, 1, 0))) { - kwsysProcess_Delete(cp); - return 0; - } - - /* Create the reading thread. It will block immediately. The - thread will not make deeply nested calls, so we need only a - small stack. */ - if (!(cp->Pipe[i].Reader.Thread = CreateThread( - 0, 1024, kwsysProcessPipeThreadRead, &cp->Pipe[i], 0, &dummy))) { - kwsysProcess_Delete(cp); - return 0; - } - - /* No process is yet running. Initialize semaphore to 0. */ - if (!(cp->Pipe[i].Waker.Ready = CreateSemaphore(0, 0, 1, 0))) { - kwsysProcess_Delete(cp); - return 0; - } - - /* The pipe is not yet reset. Initialize semaphore to 0. */ - if (!(cp->Pipe[i].Waker.Reset = CreateSemaphore(0, 0, 1, 0))) { - kwsysProcess_Delete(cp); - return 0; - } - - /* The waker should not wake immediately. Initialize semaphore to 0. */ - if (!(cp->Pipe[i].Waker.Go = CreateSemaphore(0, 0, 1, 0))) { - kwsysProcess_Delete(cp); - return 0; - } - - /* Create the waking thread. It will block immediately. The - thread will not make deeply nested calls, so we need only a - small stack. */ - if (!(cp->Pipe[i].Waker.Thread = CreateThread( - 0, 1024, kwsysProcessPipeThreadWake, &cp->Pipe[i], 0, &dummy))) { - kwsysProcess_Delete(cp); - return 0; - } - } - for (i = 0; i < 3; ++i) { - cp->PipeChildStd[i] = INVALID_HANDLE_VALUE; - } - - return cp; -} - -void kwsysProcess_Delete(kwsysProcess* cp) -{ - int i; - - /* Make sure we have an instance. */ - if (!cp) { - return; - } - - /* If the process is executing, wait for it to finish. */ - if (cp->State == kwsysProcess_State_Executing) { - if (cp->Detached) { - kwsysProcess_Disown(cp); - } else { - kwsysProcess_WaitForExit(cp, 0); - } - } - - /* We are deleting the kwsysProcess instance. */ - cp->Deleting = 1; - - /* Terminate each of the threads. */ - for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { - /* Terminate this reading thread. */ - if (cp->Pipe[i].Reader.Thread) { - /* Signal the thread we are ready for it. It will terminate - immediately since Deleting is set. */ - ReleaseSemaphore(cp->Pipe[i].Reader.Ready, 1, 0); - - /* Wait for the thread to exit. */ - WaitForSingleObject(cp->Pipe[i].Reader.Thread, INFINITE); - - /* Close the handle to the thread. */ - kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Thread); - } - - /* Terminate this waking thread. */ - if (cp->Pipe[i].Waker.Thread) { - /* Signal the thread we are ready for it. It will terminate - immediately since Deleting is set. */ - ReleaseSemaphore(cp->Pipe[i].Waker.Ready, 1, 0); - - /* Wait for the thread to exit. */ - WaitForSingleObject(cp->Pipe[i].Waker.Thread, INFINITE); - - /* Close the handle to the thread. */ - kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Thread); - } - - /* Cleanup the pipe's semaphores. */ - kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Ready); - kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Go); - kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Reset); - kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Ready); - kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Go); - kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Reset); - } - - /* Close the shared semaphores. */ - kwsysProcessCleanupHandle(&cp->SharedIndexMutex); - kwsysProcessCleanupHandle(&cp->Full); - - /* Free memory. */ - kwsysProcess_SetCommand(cp, 0); - kwsysProcess_SetWorkingDirectory(cp, 0); - kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDIN, 0); - kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDOUT, 0); - kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDERR, 0); - free(cp->CommandExitCodes); - free(cp->ProcessResults); - free(cp); -} - -int kwsysProcess_SetCommand(kwsysProcess* cp, char const* const* command) -{ - int i; - if (!cp) { - return 0; - } - for (i = 0; i < cp->NumberOfCommands; ++i) { - free(cp->Commands[i]); - } - cp->NumberOfCommands = 0; - if (cp->Commands) { - free(cp->Commands); - cp->Commands = 0; - } - if (command) { - return kwsysProcess_AddCommand(cp, command); - } - return 1; -} - -int kwsysProcess_AddCommand(kwsysProcess* cp, char const* const* command) -{ - int newNumberOfCommands; - wchar_t** newCommands; - - /* Make sure we have a command to add. */ - if (!cp || !command || !*command) { - return 0; - } - - /* Allocate a new array for command pointers. */ - newNumberOfCommands = cp->NumberOfCommands + 1; - if (!(newCommands = - (wchar_t**)malloc(sizeof(wchar_t*) * newNumberOfCommands))) { - /* Out of memory. */ - return 0; - } - - /* Copy any existing commands into the new array. */ - { - int i; - for (i = 0; i < cp->NumberOfCommands; ++i) { - newCommands[i] = cp->Commands[i]; - } - } - - if (cp->Verbatim) { - /* Copy the verbatim command line into the buffer. */ - newCommands[cp->NumberOfCommands] = kwsysEncoding_DupToWide(*command); - } else { - /* Encode the arguments so CommandLineToArgvW can decode - them from the command line string in the child. */ - char buffer[32768]; /* CreateProcess max command-line length. */ - char* end = buffer + sizeof(buffer); - char* out = buffer; - char const* const* a; - for (a = command; *a; ++a) { - int quote = !**a; /* Quote the empty string. */ - int slashes = 0; - char const* c; - if (a != command && out != end) { - *out++ = ' '; - } - for (c = *a; !quote && *c; ++c) { - quote = (*c == ' ' || *c == '\t'); - } - if (quote && out != end) { - *out++ = '"'; - } - for (c = *a; *c; ++c) { - if (*c == '\\') { - ++slashes; - } else { - if (*c == '"') { - // Add n+1 backslashes to total 2n+1 before internal '"'. - while (slashes-- >= 0 && out != end) { - *out++ = '\\'; - } - } - slashes = 0; - } - if (out != end) { - *out++ = *c; - } - } - if (quote) { - // Add n backslashes to total 2n before ending '"'. - while (slashes-- > 0 && out != end) { - *out++ = '\\'; - } - if (out != end) { - *out++ = '"'; - } - } - } - if (out != end) { - *out = '\0'; - newCommands[cp->NumberOfCommands] = kwsysEncoding_DupToWide(buffer); - } else { - newCommands[cp->NumberOfCommands] = 0; - } - } - if (!newCommands[cp->NumberOfCommands]) { - /* Out of memory or command line too long. */ - free(newCommands); - return 0; - } - - /* Save the new array of commands. */ - free(cp->Commands); - cp->Commands = newCommands; - cp->NumberOfCommands = newNumberOfCommands; - return 1; -} - -void kwsysProcess_SetTimeout(kwsysProcess* cp, double timeout) -{ - if (!cp) { - return; - } - cp->Timeout = timeout; - if (cp->Timeout < 0) { - cp->Timeout = 0; - } - // Force recomputation of TimeoutTime. - cp->TimeoutTime.QuadPart = -1; -} - -int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, const char* dir) -{ - if (!cp) { - return 0; - } - if (cp->WorkingDirectory) { - free(cp->WorkingDirectory); - cp->WorkingDirectory = 0; - } - if (dir && dir[0]) { - wchar_t* wdir = kwsysEncoding_DupToWide(dir); - /* We must convert the working directory to a full path. */ - DWORD length = GetFullPathNameW(wdir, 0, 0, 0); - if (length > 0) { - wchar_t* work_dir = malloc(length * sizeof(wchar_t)); - if (!work_dir) { - free(wdir); - return 0; - } - if (!GetFullPathNameW(wdir, length, work_dir, 0)) { - free(work_dir); - free(wdir); - return 0; - } - cp->WorkingDirectory = work_dir; - } - free(wdir); - } - return 1; -} - -int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe, const char* file) -{ - char** pfile; - if (!cp) { - return 0; - } - switch (pipe) { - case kwsysProcess_Pipe_STDIN: - pfile = &cp->PipeFileSTDIN; - break; - case kwsysProcess_Pipe_STDOUT: - pfile = &cp->PipeFileSTDOUT; - break; - case kwsysProcess_Pipe_STDERR: - pfile = &cp->PipeFileSTDERR; - break; - default: - return 0; - } - if (*pfile) { - free(*pfile); - *pfile = 0; - } - if (file) { - *pfile = strdup(file); - if (!*pfile) { - return 0; - } - } - - /* If we are redirecting the pipe, do not share it or use a native - pipe. */ - if (*pfile) { - kwsysProcess_SetPipeNative(cp, pipe, 0); - kwsysProcess_SetPipeShared(cp, pipe, 0); - } - - return 1; -} - -void kwsysProcess_SetPipeShared(kwsysProcess* cp, int pipe, int shared) -{ - if (!cp) { - return; - } - - switch (pipe) { - case kwsysProcess_Pipe_STDIN: - cp->PipeSharedSTDIN = shared ? 1 : 0; - break; - case kwsysProcess_Pipe_STDOUT: - cp->PipeSharedSTDOUT = shared ? 1 : 0; - break; - case kwsysProcess_Pipe_STDERR: - cp->PipeSharedSTDERR = shared ? 1 : 0; - break; - default: - return; - } - - /* If we are sharing the pipe, do not redirect it to a file or use a - native pipe. */ - if (shared) { - kwsysProcess_SetPipeFile(cp, pipe, 0); - kwsysProcess_SetPipeNative(cp, pipe, 0); - } -} - -void kwsysProcess_SetPipeNative(kwsysProcess* cp, int pipe, HANDLE p[2]) -{ - HANDLE* pPipeNative = 0; - - if (!cp) { - return; - } - - switch (pipe) { - case kwsysProcess_Pipe_STDIN: - pPipeNative = cp->PipeNativeSTDIN; - break; - case kwsysProcess_Pipe_STDOUT: - pPipeNative = cp->PipeNativeSTDOUT; - break; - case kwsysProcess_Pipe_STDERR: - pPipeNative = cp->PipeNativeSTDERR; - break; - default: - return; - } - - /* Copy the native pipe handles provided. */ - if (p) { - pPipeNative[0] = p[0]; - pPipeNative[1] = p[1]; - } else { - pPipeNative[0] = 0; - pPipeNative[1] = 0; - } - - /* If we are using a native pipe, do not share it or redirect it to - a file. */ - if (p) { - kwsysProcess_SetPipeFile(cp, pipe, 0); - kwsysProcess_SetPipeShared(cp, pipe, 0); - } -} - -int kwsysProcess_GetOption(kwsysProcess* cp, int optionId) -{ - if (!cp) { - return 0; - } - - switch (optionId) { - case kwsysProcess_Option_Detach: - return cp->OptionDetach; - case kwsysProcess_Option_HideWindow: - return cp->HideWindow; - case kwsysProcess_Option_MergeOutput: - return cp->MergeOutput; - case kwsysProcess_Option_Verbatim: - return cp->Verbatim; - case kwsysProcess_Option_CreateProcessGroup: - return cp->CreateProcessGroup; - default: - return 0; - } -} - -void kwsysProcess_SetOption(kwsysProcess* cp, int optionId, int value) -{ - if (!cp) { - return; - } - - switch (optionId) { - case kwsysProcess_Option_Detach: - cp->OptionDetach = value; - break; - case kwsysProcess_Option_HideWindow: - cp->HideWindow = value; - break; - case kwsysProcess_Option_MergeOutput: - cp->MergeOutput = value; - break; - case kwsysProcess_Option_Verbatim: - cp->Verbatim = value; - break; - case kwsysProcess_Option_CreateProcessGroup: - cp->CreateProcessGroup = value; - break; - default: - break; - } -} - -int kwsysProcess_GetState(kwsysProcess* cp) -{ - return cp ? cp->State : kwsysProcess_State_Error; -} - -int kwsysProcess_GetExitException(kwsysProcess* cp) -{ - return (cp && cp->ProcessResults && (cp->NumberOfCommands > 0)) - ? cp->ProcessResults[cp->NumberOfCommands - 1].ExitException - : kwsysProcess_Exception_Other; -} - -int kwsysProcess_GetExitValue(kwsysProcess* cp) -{ - return (cp && cp->ProcessResults && (cp->NumberOfCommands > 0)) - ? cp->ProcessResults[cp->NumberOfCommands - 1].ExitValue - : -1; -} - -int kwsysProcess_GetExitCode(kwsysProcess* cp) -{ - return (cp && cp->ProcessResults && (cp->NumberOfCommands > 0)) - ? cp->ProcessResults[cp->NumberOfCommands - 1].ExitCode - : 0; -} - -const char* kwsysProcess_GetErrorString(kwsysProcess* cp) -{ - if (!cp) { - return "Process management structure could not be allocated"; - } else if (cp->State == kwsysProcess_State_Error) { - return cp->ErrorMessage; - } - return "Success"; -} - -const char* kwsysProcess_GetExceptionString(kwsysProcess* cp) -{ - if (!(cp && cp->ProcessResults && (cp->NumberOfCommands > 0))) { - return "GetExceptionString called with NULL process management structure"; - } else if (cp->State == kwsysProcess_State_Exception) { - return cp->ProcessResults[cp->NumberOfCommands - 1].ExitExceptionString; - } - return "No exception"; -} - -/* the index should be in array bound. */ -#define KWSYSPE_IDX_CHK(RET) \ - if (!cp || idx >= cp->NumberOfCommands || idx < 0) { \ - KWSYSPE_DEBUG((stderr, "array index out of bound\n")); \ - return RET; \ - } - -int kwsysProcess_GetStateByIndex(kwsysProcess* cp, int idx) -{ - KWSYSPE_IDX_CHK(kwsysProcess_State_Error) - return cp->ProcessResults[idx].State; -} - -int kwsysProcess_GetExitExceptionByIndex(kwsysProcess* cp, int idx) -{ - KWSYSPE_IDX_CHK(kwsysProcess_Exception_Other) - return cp->ProcessResults[idx].ExitException; -} - -int kwsysProcess_GetExitValueByIndex(kwsysProcess* cp, int idx) -{ - KWSYSPE_IDX_CHK(-1) - return cp->ProcessResults[idx].ExitValue; -} - -int kwsysProcess_GetExitCodeByIndex(kwsysProcess* cp, int idx) -{ - KWSYSPE_IDX_CHK(-1) - return cp->CommandExitCodes[idx]; -} - -const char* kwsysProcess_GetExceptionStringByIndex(kwsysProcess* cp, int idx) -{ - KWSYSPE_IDX_CHK("GetExceptionString called with NULL process management " - "structure or index out of bound") - if (cp->ProcessResults[idx].State == kwsysProcess_StateByIndex_Exception) { - return cp->ProcessResults[idx].ExitExceptionString; - } - return "No exception"; -} - -#undef KWSYSPE_IDX_CHK - -void kwsysProcess_Execute(kwsysProcess* cp) -{ - int i; - - /* Do not execute a second time. */ - if (!cp || cp->State == kwsysProcess_State_Executing) { - return; - } - - /* Make sure we have something to run. */ - if (cp->NumberOfCommands < 1) { - strcpy(cp->ErrorMessage, "No command"); - cp->State = kwsysProcess_State_Error; - return; - } - - /* Initialize the control structure for a new process. */ - if (!kwsysProcessInitialize(cp)) { - strcpy(cp->ErrorMessage, "Out of memory"); - cp->State = kwsysProcess_State_Error; - return; - } - - /* Save the real working directory of this process and change to - the working directory for the child processes. This is needed - to make pipe file paths evaluate correctly. */ - if (cp->WorkingDirectory) { - if (!GetCurrentDirectoryW(cp->RealWorkingDirectoryLength, - cp->RealWorkingDirectory)) { - kwsysProcessCleanup(cp, GetLastError()); - return; - } - SetCurrentDirectoryW(cp->WorkingDirectory); - } - - /* Setup the stdin pipe for the first process. */ - if (cp->PipeFileSTDIN) { - /* Create a handle to read a file for stdin. */ - wchar_t* wstdin = kwsysEncoding_DupToWide(cp->PipeFileSTDIN); - DWORD error; - cp->PipeChildStd[0] = - CreateFileW(wstdin, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, - OPEN_EXISTING, 0, 0); - error = GetLastError(); /* Check now in case free changes this. */ - free(wstdin); - if (cp->PipeChildStd[0] == INVALID_HANDLE_VALUE) { - kwsysProcessCleanup(cp, error); - return; - } - } else if (cp->PipeSharedSTDIN) { - /* Share this process's stdin with the child. */ - kwsysProcessSetupSharedPipe(STD_INPUT_HANDLE, &cp->PipeChildStd[0]); - } else if (cp->PipeNativeSTDIN[0]) { - /* Use the provided native pipe. */ - kwsysProcessSetupPipeNative(cp->PipeNativeSTDIN[0], &cp->PipeChildStd[0]); - } else { - /* Explicitly give the child no stdin. */ - cp->PipeChildStd[0] = INVALID_HANDLE_VALUE; - } - - /* Create the output pipe for the last process. - We always create this so the pipe thread can run even if we - do not end up giving the write end to the child below. */ - if (!CreatePipe(&cp->Pipe[KWSYSPE_PIPE_STDOUT].Read, - &cp->Pipe[KWSYSPE_PIPE_STDOUT].Write, 0, 0)) { - kwsysProcessCleanup(cp, GetLastError()); - return; - } - - if (cp->PipeFileSTDOUT) { - /* Use a file for stdout. */ - DWORD error = kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[1], - cp->PipeFileSTDOUT); - if (error) { - kwsysProcessCleanup(cp, error); - return; - } - } else if (cp->PipeSharedSTDOUT) { - /* Use the parent stdout. */ - kwsysProcessSetupSharedPipe(STD_OUTPUT_HANDLE, &cp->PipeChildStd[1]); - } else if (cp->PipeNativeSTDOUT[1]) { - /* Use the given handle for stdout. */ - kwsysProcessSetupPipeNative(cp->PipeNativeSTDOUT[1], &cp->PipeChildStd[1]); - } else { - /* Use our pipe for stdout. Duplicate the handle since our waker - thread will use the original. Do not make it inherited yet. */ - if (!DuplicateHandle(GetCurrentProcess(), - cp->Pipe[KWSYSPE_PIPE_STDOUT].Write, - GetCurrentProcess(), &cp->PipeChildStd[1], 0, FALSE, - DUPLICATE_SAME_ACCESS)) { - kwsysProcessCleanup(cp, GetLastError()); - return; - } - } - - /* Create stderr pipe to be shared by all processes in the pipeline. - We always create this so the pipe thread can run even if we do not - end up giving the write end to the child below. */ - if (!CreatePipe(&cp->Pipe[KWSYSPE_PIPE_STDERR].Read, - &cp->Pipe[KWSYSPE_PIPE_STDERR].Write, 0, 0)) { - kwsysProcessCleanup(cp, GetLastError()); - return; - } - - if (cp->PipeFileSTDERR) { - /* Use a file for stderr. */ - DWORD error = kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[2], - cp->PipeFileSTDERR); - if (error) { - kwsysProcessCleanup(cp, error); - return; - } - } else if (cp->PipeSharedSTDERR) { - /* Use the parent stderr. */ - kwsysProcessSetupSharedPipe(STD_ERROR_HANDLE, &cp->PipeChildStd[2]); - } else if (cp->PipeNativeSTDERR[1]) { - /* Use the given handle for stderr. */ - kwsysProcessSetupPipeNative(cp->PipeNativeSTDERR[1], &cp->PipeChildStd[2]); - } else { - /* Use our pipe for stderr. Duplicate the handle since our waker - thread will use the original. Do not make it inherited yet. */ - if (!DuplicateHandle(GetCurrentProcess(), - cp->Pipe[KWSYSPE_PIPE_STDERR].Write, - GetCurrentProcess(), &cp->PipeChildStd[2], 0, FALSE, - DUPLICATE_SAME_ACCESS)) { - kwsysProcessCleanup(cp, GetLastError()); - return; - } - } - - /* Create the pipeline of processes. */ - { - /* Child startup control data. */ - kwsysProcessCreateInformation si; - HANDLE nextStdInput = cp->PipeChildStd[0]; - - /* Initialize startup info data. */ - ZeroMemory(&si, sizeof(si)); - si.StartupInfo.cb = sizeof(si.StartupInfo); - - /* Decide whether a child window should be shown. */ - si.StartupInfo.dwFlags |= STARTF_USESHOWWINDOW; - si.StartupInfo.wShowWindow = - (unsigned short)(cp->HideWindow ? SW_HIDE : SW_SHOWDEFAULT); - - /* Connect the child's output pipes to the threads. */ - si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES; - - for (i = 0; i < cp->NumberOfCommands; ++i) { - /* Setup the process's pipes. */ - si.hStdInput = nextStdInput; - if (i == cp->NumberOfCommands - 1) { - /* The last child gets the overall stdout. */ - nextStdInput = INVALID_HANDLE_VALUE; - si.hStdOutput = cp->PipeChildStd[1]; - } else { - /* Create a pipe to sit between the children. */ - HANDLE p[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE }; - if (!CreatePipe(&p[0], &p[1], 0, 0)) { - DWORD error = GetLastError(); - if (nextStdInput != cp->PipeChildStd[0]) { - kwsysProcessCleanupHandle(&nextStdInput); - } - kwsysProcessCleanup(cp, error); - return; - } - nextStdInput = p[0]; - si.hStdOutput = p[1]; - } - si.hStdError = - cp->MergeOutput ? cp->PipeChildStd[1] : cp->PipeChildStd[2]; - - { - DWORD error = kwsysProcessCreate(cp, i, &si); - - /* Close our copies of pipes used between children. */ - if (si.hStdInput != cp->PipeChildStd[0]) { - kwsysProcessCleanupHandle(&si.hStdInput); - } - if (si.hStdOutput != cp->PipeChildStd[1]) { - kwsysProcessCleanupHandle(&si.hStdOutput); - } - if (si.hStdError != cp->PipeChildStd[2] && !cp->MergeOutput) { - kwsysProcessCleanupHandle(&si.hStdError); - } - if (!error) { - cp->ProcessEvents[i + 1] = cp->ProcessInformation[i].hProcess; - } else { - if (nextStdInput != cp->PipeChildStd[0]) { - kwsysProcessCleanupHandle(&nextStdInput); - } - kwsysProcessCleanup(cp, error); - return; - } - } - } - } - - /* The parent process does not need the child's pipe ends. */ - for (i = 0; i < 3; ++i) { - kwsysProcessCleanupHandle(&cp->PipeChildStd[i]); - } - - /* Restore the working directory. */ - if (cp->RealWorkingDirectory) { - SetCurrentDirectoryW(cp->RealWorkingDirectory); - free(cp->RealWorkingDirectory); - cp->RealWorkingDirectory = 0; - } - - /* The timeout period starts now. */ - cp->StartTime = kwsysProcessTimeGetCurrent(); - cp->TimeoutTime = kwsysProcessTimeFromDouble(-1); - - /* All processes in the pipeline have been started in suspended - mode. Resume them all now. */ - for (i = 0; i < cp->NumberOfCommands; ++i) { - ResumeThread(cp->ProcessInformation[i].hThread); - } - - /* ---- It is no longer safe to call kwsysProcessCleanup. ----- */ - /* Tell the pipe threads that a process has started. */ - for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { - ReleaseSemaphore(cp->Pipe[i].Reader.Ready, 1, 0); - ReleaseSemaphore(cp->Pipe[i].Waker.Ready, 1, 0); - } - - /* We don't care about the children's main threads. */ - for (i = 0; i < cp->NumberOfCommands; ++i) { - kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread); - } - - /* No pipe has reported data. */ - cp->CurrentIndex = KWSYSPE_PIPE_COUNT; - cp->PipesLeft = KWSYSPE_PIPE_COUNT; - - /* The process has now started. */ - cp->State = kwsysProcess_State_Executing; - cp->Detached = cp->OptionDetach; -} - -void kwsysProcess_Disown(kwsysProcess* cp) -{ - int i; - - /* Make sure we are executing a detached process. */ - if (!cp || !cp->Detached || cp->State != kwsysProcess_State_Executing || - cp->TimeoutExpired || cp->Killed || cp->Terminated) { - return; - } - - /* Disable the reading threads. */ - kwsysProcessDisablePipeThreads(cp); - - /* Wait for all pipe threads to reset. */ - for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { - WaitForSingleObject(cp->Pipe[i].Reader.Reset, INFINITE); - WaitForSingleObject(cp->Pipe[i].Waker.Reset, INFINITE); - } - - /* We will not wait for exit, so cleanup now. */ - kwsysProcessCleanup(cp, 0); - - /* The process has been disowned. */ - cp->State = kwsysProcess_State_Disowned; -} - -int kwsysProcess_WaitForData(kwsysProcess* cp, char** data, int* length, - double* userTimeout) -{ - kwsysProcessTime userStartTime; - kwsysProcessTime timeoutLength; - kwsysProcessTime timeoutTime; - DWORD timeout; - int user; - int done = 0; - int expired = 0; - int pipeId = kwsysProcess_Pipe_None; - DWORD w; - - /* Make sure we are executing a process. */ - if (!cp || cp->State != kwsysProcess_State_Executing || cp->Killed || - cp->TimeoutExpired) { - return kwsysProcess_Pipe_None; - } - - /* Record the time at which user timeout period starts. */ - userStartTime = kwsysProcessTimeGetCurrent(); - - /* Calculate the time at which a timeout will expire, and whether it - is the user or process timeout. */ - user = kwsysProcessGetTimeoutTime(cp, userTimeout, &timeoutTime); - - /* Loop until we have a reason to return. */ - while (!done && cp->PipesLeft > 0) { - /* If we previously got data from a thread, let it know we are - done with the data. */ - if (cp->CurrentIndex < KWSYSPE_PIPE_COUNT) { - KWSYSPE_DEBUG((stderr, "releasing reader %d\n", cp->CurrentIndex)); - ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0); - cp->CurrentIndex = KWSYSPE_PIPE_COUNT; - } - - /* Setup a timeout if required. */ - if (kwsysProcessGetTimeoutLeft(&timeoutTime, user ? userTimeout : 0, - &timeoutLength)) { - /* Timeout has already expired. */ - expired = 1; - break; - } - if (timeoutTime.QuadPart < 0) { - timeout = INFINITE; - } else { - timeout = kwsysProcessTimeToDWORD(timeoutLength); - } - - /* Wait for a pipe's thread to signal or a process to terminate. */ - w = WaitForMultipleObjects(cp->ProcessEventsLength, cp->ProcessEvents, 0, - timeout); - if (w == WAIT_TIMEOUT) { - /* Timeout has expired. */ - expired = 1; - done = 1; - } else if (w == WAIT_OBJECT_0) { - /* Save the index of the reporting thread and release the mutex. - The thread will block until we signal its Empty mutex. */ - cp->CurrentIndex = cp->SharedIndex; - ReleaseSemaphore(cp->SharedIndexMutex, 1, 0); - - /* Data are available or a pipe closed. */ - if (cp->Pipe[cp->CurrentIndex].Closed) { - /* The pipe closed at the write end. Close the read end and - inform the wakeup thread it is done with this process. */ - kwsysProcessCleanupHandle(&cp->Pipe[cp->CurrentIndex].Read); - ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Waker.Go, 1, 0); - KWSYSPE_DEBUG((stderr, "wakeup %d\n", cp->CurrentIndex)); - --cp->PipesLeft; - } else if (data && length) { - /* Report this data. */ - *data = cp->Pipe[cp->CurrentIndex].DataBuffer; - *length = cp->Pipe[cp->CurrentIndex].DataLength; - switch (cp->CurrentIndex) { - case KWSYSPE_PIPE_STDOUT: - pipeId = kwsysProcess_Pipe_STDOUT; - break; - case KWSYSPE_PIPE_STDERR: - pipeId = kwsysProcess_Pipe_STDERR; - break; - } - done = 1; - } - } else { - /* A process has terminated. */ - kwsysProcessDestroy(cp, w - WAIT_OBJECT_0); - } - } - - /* Update the user timeout. */ - if (userTimeout) { - kwsysProcessTime userEndTime = kwsysProcessTimeGetCurrent(); - kwsysProcessTime difference = - kwsysProcessTimeSubtract(userEndTime, userStartTime); - double d = kwsysProcessTimeToDouble(difference); - *userTimeout -= d; - if (*userTimeout < 0) { - *userTimeout = 0; - } - } - - /* Check what happened. */ - if (pipeId) { - /* Data are ready on a pipe. */ - return pipeId; - } else if (expired) { - /* A timeout has expired. */ - if (user) { - /* The user timeout has expired. It has no time left. */ - return kwsysProcess_Pipe_Timeout; - } else { - /* The process timeout has expired. Kill the child now. */ - KWSYSPE_DEBUG((stderr, "killing child because timeout expired\n")); - kwsysProcess_Kill(cp); - cp->TimeoutExpired = 1; - cp->Killed = 0; - return kwsysProcess_Pipe_None; - } - } else { - /* The children have terminated and no more data are available. */ - return kwsysProcess_Pipe_None; - } -} - -int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout) -{ - int i; - int pipe; - - /* Make sure we are executing a process. */ - if (!cp || cp->State != kwsysProcess_State_Executing) { - return 1; - } - - /* Wait for the process to terminate. Ignore all data. */ - while ((pipe = kwsysProcess_WaitForData(cp, 0, 0, userTimeout)) > 0) { - if (pipe == kwsysProcess_Pipe_Timeout) { - /* The user timeout has expired. */ - return 0; - } - } - - KWSYSPE_DEBUG((stderr, "no more data\n")); - - /* When the last pipe closes in WaitForData, the loop terminates - without releasing the pipe's thread. Release it now. */ - if (cp->CurrentIndex < KWSYSPE_PIPE_COUNT) { - KWSYSPE_DEBUG((stderr, "releasing reader %d\n", cp->CurrentIndex)); - ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0); - cp->CurrentIndex = KWSYSPE_PIPE_COUNT; - } - - /* Wait for all pipe threads to reset. */ - for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { - KWSYSPE_DEBUG((stderr, "waiting reader reset %d\n", i)); - WaitForSingleObject(cp->Pipe[i].Reader.Reset, INFINITE); - KWSYSPE_DEBUG((stderr, "waiting waker reset %d\n", i)); - WaitForSingleObject(cp->Pipe[i].Waker.Reset, INFINITE); - } - - /* ---- It is now safe again to call kwsysProcessCleanup. ----- */ - /* Close all the pipes. */ - kwsysProcessCleanup(cp, 0); - - /* Determine the outcome. */ - if (cp->Killed) { - /* We killed the child. */ - cp->State = kwsysProcess_State_Killed; - } else if (cp->TimeoutExpired) { - /* The timeout expired. */ - cp->State = kwsysProcess_State_Expired; - } else { - /* The children exited. Report the outcome of the child processes. */ - for (i = 0; i < cp->NumberOfCommands; ++i) { - cp->ProcessResults[i].ExitCode = cp->CommandExitCodes[i]; - if ((cp->ProcessResults[i].ExitCode & 0xF0000000) == 0xC0000000) { - /* Child terminated due to exceptional behavior. */ - cp->ProcessResults[i].State = kwsysProcess_StateByIndex_Exception; - cp->ProcessResults[i].ExitValue = 1; - kwsysProcessSetExitExceptionByIndex(cp, cp->ProcessResults[i].ExitCode, - i); - } else { - /* Child exited without exception. */ - cp->ProcessResults[i].State = kwsysProcess_StateByIndex_Exited; - cp->ProcessResults[i].ExitException = kwsysProcess_Exception_None; - cp->ProcessResults[i].ExitValue = cp->ProcessResults[i].ExitCode; - } - } - /* support legacy state status value */ - cp->State = cp->ProcessResults[cp->NumberOfCommands - 1].State; - } - - return 1; -} - -void kwsysProcess_Interrupt(kwsysProcess* cp) -{ - int i; - /* Make sure we are executing a process. */ - if (!cp || cp->State != kwsysProcess_State_Executing || cp->TimeoutExpired || - cp->Killed) { - KWSYSPE_DEBUG((stderr, "interrupt: child not executing\n")); - return; - } - - /* Skip actually interrupting the child if it has already terminated. */ - if (cp->Terminated) { - KWSYSPE_DEBUG((stderr, "interrupt: child already terminated\n")); - return; - } - - /* Interrupt the children. */ - if (cp->CreateProcessGroup) { - if (cp->ProcessInformation) { - for (i = 0; i < cp->NumberOfCommands; ++i) { - /* Make sure the process handle isn't closed (e.g. from disowning). */ - if (cp->ProcessInformation[i].hProcess) { - /* The user created a process group for this process. The group ID - is the process ID for the original process in the group. Note - that we have to use Ctrl+Break: Ctrl+C is not allowed for process - groups. */ - GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, - cp->ProcessInformation[i].dwProcessId); - } - } - } - } else { - /* No process group was created. Kill our own process group... */ - GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0); - } -} - -void kwsysProcess_Kill(kwsysProcess* cp) -{ - int i; - /* Make sure we are executing a process. */ - if (!cp || cp->State != kwsysProcess_State_Executing || cp->TimeoutExpired || - cp->Killed) { - KWSYSPE_DEBUG((stderr, "kill: child not executing\n")); - return; - } - - /* Disable the reading threads. */ - KWSYSPE_DEBUG((stderr, "kill: disabling pipe threads\n")); - kwsysProcessDisablePipeThreads(cp); - - /* Skip actually killing the child if it has already terminated. */ - if (cp->Terminated) { - KWSYSPE_DEBUG((stderr, "kill: child already terminated\n")); - return; - } - - /* Kill the children. */ - cp->Killed = 1; - for (i = 0; i < cp->NumberOfCommands; ++i) { - kwsysProcessKillTree(cp->ProcessInformation[i].dwProcessId); - /* Remove from global list of processes and close handles. */ - kwsysProcessesRemove(cp->ProcessInformation[i].hProcess); - kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread); - kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hProcess); - } - - /* We are killing the children and ignoring all data. Do not wait - for them to exit. */ -} - -void kwsysProcess_KillPID(unsigned long process_id) -{ - kwsysProcessKillTree((DWORD)process_id); -} - -/* - Function executed for each pipe's thread. Argument is a pointer to - the kwsysProcessPipeData instance for this thread. -*/ -DWORD WINAPI kwsysProcessPipeThreadRead(LPVOID ptd) -{ - kwsysProcessPipeData* td = (kwsysProcessPipeData*)ptd; - kwsysProcess* cp = td->Process; - - /* Wait for a process to be ready. */ - while ((WaitForSingleObject(td->Reader.Ready, INFINITE), !cp->Deleting)) { - /* Read output from the process for this thread's pipe. */ - kwsysProcessPipeThreadReadPipe(cp, td); - - /* Signal the main thread we have reset for a new process. */ - ReleaseSemaphore(td->Reader.Reset, 1, 0); - } - return 0; -} - -/* - Function called in each pipe's thread to handle data for one - execution of a subprocess. -*/ -void kwsysProcessPipeThreadReadPipe(kwsysProcess* cp, kwsysProcessPipeData* td) -{ - /* Wait for space in the thread's buffer. */ - while ((KWSYSPE_DEBUG((stderr, "wait for read %d\n", td->Index)), - WaitForSingleObject(td->Reader.Go, INFINITE), !td->Closed)) { - KWSYSPE_DEBUG((stderr, "reading %d\n", td->Index)); - - /* Read data from the pipe. This may block until data are available. */ - if (!ReadFile(td->Read, td->DataBuffer, KWSYSPE_PIPE_BUFFER_SIZE, - &td->DataLength, 0)) { - if (GetLastError() != ERROR_BROKEN_PIPE) { - /* UNEXPECTED failure to read the pipe. */ - } - - /* The pipe closed. There are no more data to read. */ - td->Closed = 1; - KWSYSPE_DEBUG((stderr, "read closed %d\n", td->Index)); - } - - KWSYSPE_DEBUG((stderr, "read %d\n", td->Index)); - - /* Wait for our turn to be handled by the main thread. */ - WaitForSingleObject(cp->SharedIndexMutex, INFINITE); - - KWSYSPE_DEBUG((stderr, "reporting read %d\n", td->Index)); - - /* Tell the main thread we have something to report. */ - cp->SharedIndex = td->Index; - ReleaseSemaphore(cp->Full, 1, 0); - } - - /* We were signalled to exit with our buffer empty. Reset the - mutex for a new process. */ - KWSYSPE_DEBUG((stderr, "self releasing reader %d\n", td->Index)); - ReleaseSemaphore(td->Reader.Go, 1, 0); -} - -/* - Function executed for each pipe's thread. Argument is a pointer to - the kwsysProcessPipeData instance for this thread. -*/ -DWORD WINAPI kwsysProcessPipeThreadWake(LPVOID ptd) -{ - kwsysProcessPipeData* td = (kwsysProcessPipeData*)ptd; - kwsysProcess* cp = td->Process; - - /* Wait for a process to be ready. */ - while ((WaitForSingleObject(td->Waker.Ready, INFINITE), !cp->Deleting)) { - /* Wait for a possible wakeup. */ - kwsysProcessPipeThreadWakePipe(cp, td); - - /* Signal the main thread we have reset for a new process. */ - ReleaseSemaphore(td->Waker.Reset, 1, 0); - } - return 0; -} - -/* - Function called in each pipe's thread to handle reading thread - wakeup for one execution of a subprocess. -*/ -void kwsysProcessPipeThreadWakePipe(kwsysProcess* cp, kwsysProcessPipeData* td) -{ - (void)cp; - - /* Wait for a possible wake command. */ - KWSYSPE_DEBUG((stderr, "wait for wake %d\n", td->Index)); - WaitForSingleObject(td->Waker.Go, INFINITE); - KWSYSPE_DEBUG((stderr, "waking %d\n", td->Index)); - - /* If the pipe is not closed, we need to wake up the reading thread. */ - if (!td->Closed) { - DWORD dummy; - KWSYSPE_DEBUG((stderr, "waker %d writing byte\n", td->Index)); - WriteFile(td->Write, "", 1, &dummy, 0); - KWSYSPE_DEBUG((stderr, "waker %d wrote byte\n", td->Index)); - } -} - -/* Initialize a process control structure for kwsysProcess_Execute. */ -int kwsysProcessInitialize(kwsysProcess* cp) -{ - int i; - /* Reset internal status flags. */ - cp->TimeoutExpired = 0; - cp->Terminated = 0; - cp->Killed = 0; - - free(cp->ProcessResults); - /* Allocate process result information for each process. */ - cp->ProcessResults = (kwsysProcessResults*)malloc( - sizeof(kwsysProcessResults) * (cp->NumberOfCommands)); - if (!cp->ProcessResults) { - return 0; - } - ZeroMemory(cp->ProcessResults, - sizeof(kwsysProcessResults) * cp->NumberOfCommands); - for (i = 0; i < cp->NumberOfCommands; i++) { - cp->ProcessResults[i].ExitException = kwsysProcess_Exception_None; - cp->ProcessResults[i].State = kwsysProcess_StateByIndex_Starting; - cp->ProcessResults[i].ExitCode = 1; - cp->ProcessResults[i].ExitValue = 1; - strcpy(cp->ProcessResults[i].ExitExceptionString, "No exception"); - } - - /* Allocate process information for each process. */ - free(cp->ProcessInformation); - cp->ProcessInformation = (PROCESS_INFORMATION*)malloc( - sizeof(PROCESS_INFORMATION) * cp->NumberOfCommands); - if (!cp->ProcessInformation) { - return 0; - } - ZeroMemory(cp->ProcessInformation, - sizeof(PROCESS_INFORMATION) * cp->NumberOfCommands); - free(cp->CommandExitCodes); - cp->CommandExitCodes = (DWORD*)malloc(sizeof(DWORD) * cp->NumberOfCommands); - if (!cp->CommandExitCodes) { - return 0; - } - ZeroMemory(cp->CommandExitCodes, sizeof(DWORD) * cp->NumberOfCommands); - - /* Allocate event wait array. The first event is cp->Full, the rest - are the process termination events. */ - cp->ProcessEvents = - (PHANDLE)malloc(sizeof(HANDLE) * (cp->NumberOfCommands + 1)); - if (!cp->ProcessEvents) { - return 0; - } - ZeroMemory(cp->ProcessEvents, sizeof(HANDLE) * (cp->NumberOfCommands + 1)); - cp->ProcessEvents[0] = cp->Full; - cp->ProcessEventsLength = cp->NumberOfCommands + 1; - - /* Allocate space to save the real working directory of this process. */ - if (cp->WorkingDirectory) { - cp->RealWorkingDirectoryLength = GetCurrentDirectoryW(0, 0); - if (cp->RealWorkingDirectoryLength > 0) { - cp->RealWorkingDirectory = - malloc(cp->RealWorkingDirectoryLength * sizeof(wchar_t)); - if (!cp->RealWorkingDirectory) { - return 0; - } - } - } - { - for (i = 0; i < 3; ++i) { - cp->PipeChildStd[i] = INVALID_HANDLE_VALUE; - } - } - - return 1; -} - -static DWORD kwsysProcessCreateChildHandle(PHANDLE out, HANDLE in, int isStdIn) -{ - DWORD flags; - - /* Check whether the handle is valid for this process. */ - if (in != INVALID_HANDLE_VALUE && GetHandleInformation(in, &flags)) { - /* Use the handle as-is if it is already inherited. */ - if (flags & HANDLE_FLAG_INHERIT) { - *out = in; - return ERROR_SUCCESS; - } - - /* Create an inherited copy of this handle. */ - if (DuplicateHandle(GetCurrentProcess(), in, GetCurrentProcess(), out, 0, - TRUE, DUPLICATE_SAME_ACCESS)) { - return ERROR_SUCCESS; - } else { - return GetLastError(); - } - } else { - /* The given handle is not valid for this process. Some child - processes may break if they do not have a valid standard handle, - so open NUL to give to the child. */ - SECURITY_ATTRIBUTES sa; - ZeroMemory(&sa, sizeof(sa)); - sa.nLength = (DWORD)sizeof(sa); - sa.bInheritHandle = 1; - *out = CreateFileW( - L"NUL", - (isStdIn ? GENERIC_READ : (GENERIC_WRITE | FILE_READ_ATTRIBUTES)), - FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, OPEN_EXISTING, 0, 0); - return (*out != INVALID_HANDLE_VALUE) ? ERROR_SUCCESS : GetLastError(); - } -} - -DWORD kwsysProcessCreate(kwsysProcess* cp, int index, - kwsysProcessCreateInformation* si) -{ - DWORD creationFlags; - DWORD error = ERROR_SUCCESS; - - /* Check if we are currently exiting. */ - if (!kwsysTryEnterCreateProcessSection()) { - /* The Ctrl handler is currently working on exiting our process. Rather - than return an error code, which could cause incorrect conclusions to be - reached by the caller, we simply hang. (For example, a CMake try_run - configure step might cause the project to configure wrong.) */ - Sleep(INFINITE); - } - - /* Create the child in a suspended state so we can wait until all - children have been created before running any one. */ - creationFlags = CREATE_SUSPENDED; - if (cp->CreateProcessGroup) { - creationFlags |= CREATE_NEW_PROCESS_GROUP; - } - - /* Create inherited copies of the handles. */ - (error = kwsysProcessCreateChildHandle(&si->StartupInfo.hStdInput, - si->hStdInput, 1)) || - (error = kwsysProcessCreateChildHandle(&si->StartupInfo.hStdOutput, - si->hStdOutput, 0)) || - (error = kwsysProcessCreateChildHandle(&si->StartupInfo.hStdError, - si->hStdError, 0)) || - /* Create the process. */ - (!CreateProcessW(0, cp->Commands[index], 0, 0, TRUE, creationFlags, 0, 0, - &si->StartupInfo, &cp->ProcessInformation[index]) && - (error = GetLastError())); - - /* Close the inherited copies of the handles. */ - if (si->StartupInfo.hStdInput != si->hStdInput) { - kwsysProcessCleanupHandle(&si->StartupInfo.hStdInput); - } - if (si->StartupInfo.hStdOutput != si->hStdOutput) { - kwsysProcessCleanupHandle(&si->StartupInfo.hStdOutput); - } - if (si->StartupInfo.hStdError != si->hStdError) { - kwsysProcessCleanupHandle(&si->StartupInfo.hStdError); - } - - /* Add the process to the global list of processes. */ - if (!error && - !kwsysProcessesAdd(cp->ProcessInformation[index].hProcess, - cp->ProcessInformation[index].dwProcessId, - cp->CreateProcessGroup)) { - /* This failed for some reason. Kill the suspended process. */ - TerminateProcess(cp->ProcessInformation[index].hProcess, 1); - /* And clean up... */ - kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hProcess); - kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hThread); - strcpy(cp->ErrorMessage, "kwsysProcessesAdd function failed"); - error = ERROR_NOT_ENOUGH_MEMORY; /* Most likely reason. */ - } - - /* If the console Ctrl handler is waiting for us, this will release it... */ - kwsysLeaveCreateProcessSection(); - return error; -} - -void kwsysProcessDestroy(kwsysProcess* cp, int event) -{ - int i; - int index; - - /* Find the process index for the termination event. */ - for (index = 0; index < cp->NumberOfCommands; ++index) { - if (cp->ProcessInformation[index].hProcess == cp->ProcessEvents[event]) { - break; - } - } - - /* Check the exit code of the process. */ - GetExitCodeProcess(cp->ProcessInformation[index].hProcess, - &cp->CommandExitCodes[index]); - - /* Remove from global list of processes. */ - kwsysProcessesRemove(cp->ProcessInformation[index].hProcess); - - /* Close the process handle for the terminated process. */ - kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hProcess); - - /* Remove the process from the available events. */ - cp->ProcessEventsLength -= 1; - for (i = event; i < cp->ProcessEventsLength; ++i) { - cp->ProcessEvents[i] = cp->ProcessEvents[i + 1]; - } - - /* Check if all processes have terminated. */ - if (cp->ProcessEventsLength == 1) { - cp->Terminated = 1; - - /* Close our copies of the pipe write handles so the pipe threads - can detect end-of-data. */ - for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { - /* TODO: If the child created its own child (our grandchild) - which inherited a copy of the pipe write-end then the pipe - may not close and we will still need the waker write pipe. - However we still want to be able to detect end-of-data in the - normal case. The reader thread will have to switch to using - PeekNamedPipe to read the last bit of data from the pipe - without blocking. This is equivalent to using a non-blocking - read on posix. */ - KWSYSPE_DEBUG((stderr, "closing wakeup write %d\n", i)); - kwsysProcessCleanupHandle(&cp->Pipe[i].Write); - } - } -} - -DWORD kwsysProcessSetupOutputPipeFile(PHANDLE phandle, const char* name) -{ - HANDLE fout; - wchar_t* wname; - DWORD error; - if (!name) { - return ERROR_INVALID_PARAMETER; - } - - /* Close the existing handle. */ - kwsysProcessCleanupHandle(phandle); - - /* Create a handle to write a file for the pipe. */ - wname = kwsysEncoding_DupToWide(name); - fout = - CreateFileW(wname, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0); - error = GetLastError(); - free(wname); - if (fout == INVALID_HANDLE_VALUE) { - return error; - } - - /* Assign the replacement handle. */ - *phandle = fout; - return ERROR_SUCCESS; -} - -void kwsysProcessSetupSharedPipe(DWORD nStdHandle, PHANDLE handle) -{ - /* Close the existing handle. */ - kwsysProcessCleanupHandle(handle); - /* Store the new standard handle. */ - *handle = GetStdHandle(nStdHandle); -} - -void kwsysProcessSetupPipeNative(HANDLE native, PHANDLE handle) -{ - /* Close the existing handle. */ - kwsysProcessCleanupHandle(handle); - /* Store the new given handle. */ - *handle = native; -} - -/* Close the given handle if it is open. Reset its value to 0. */ -void kwsysProcessCleanupHandle(PHANDLE h) -{ - if (h && *h && *h != INVALID_HANDLE_VALUE && - *h != GetStdHandle(STD_INPUT_HANDLE) && - *h != GetStdHandle(STD_OUTPUT_HANDLE) && - *h != GetStdHandle(STD_ERROR_HANDLE)) { - CloseHandle(*h); - *h = INVALID_HANDLE_VALUE; - } -} - -/* Close all handles created by kwsysProcess_Execute. */ -void kwsysProcessCleanup(kwsysProcess* cp, DWORD error) -{ - int i; - /* If this is an error case, report the error. */ - if (error) { - /* Construct an error message if one has not been provided already. */ - if (cp->ErrorMessage[0] == 0) { - /* Format the error message. */ - wchar_t err_msg[KWSYSPE_PIPE_BUFFER_SIZE]; - DWORD length = FormatMessageW( - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, error, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err_msg, - KWSYSPE_PIPE_BUFFER_SIZE, 0); - if (length < 1) { - /* FormatMessage failed. Use a default message. */ - _snprintf(cp->ErrorMessage, KWSYSPE_PIPE_BUFFER_SIZE, - "Process execution failed with error 0x%X. " - "FormatMessage failed with error 0x%X", - error, GetLastError()); - } - if (!WideCharToMultiByte(CP_UTF8, 0, err_msg, -1, cp->ErrorMessage, - KWSYSPE_PIPE_BUFFER_SIZE, NULL, NULL)) { - /* WideCharToMultiByte failed. Use a default message. */ - _snprintf(cp->ErrorMessage, KWSYSPE_PIPE_BUFFER_SIZE, - "Process execution failed with error 0x%X. " - "WideCharToMultiByte failed with error 0x%X", - error, GetLastError()); - } - } - - /* Remove trailing period and newline, if any. */ - kwsysProcessCleanErrorMessage(cp); - - /* Set the error state. */ - cp->State = kwsysProcess_State_Error; - - /* Cleanup any processes already started in a suspended state. */ - if (cp->ProcessInformation) { - for (i = 0; i < cp->NumberOfCommands; ++i) { - if (cp->ProcessInformation[i].hProcess) { - TerminateProcess(cp->ProcessInformation[i].hProcess, 255); - WaitForSingleObject(cp->ProcessInformation[i].hProcess, INFINITE); - } - } - for (i = 0; i < cp->NumberOfCommands; ++i) { - /* Remove from global list of processes and close handles. */ - kwsysProcessesRemove(cp->ProcessInformation[i].hProcess); - kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread); - kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hProcess); - } - } - - /* Restore the working directory. */ - if (cp->RealWorkingDirectory) { - SetCurrentDirectoryW(cp->RealWorkingDirectory); - } - } - - /* Free memory. */ - if (cp->ProcessInformation) { - free(cp->ProcessInformation); - cp->ProcessInformation = 0; - } - if (cp->ProcessEvents) { - free(cp->ProcessEvents); - cp->ProcessEvents = 0; - } - if (cp->RealWorkingDirectory) { - free(cp->RealWorkingDirectory); - cp->RealWorkingDirectory = 0; - } - - /* Close each pipe. */ - for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { - kwsysProcessCleanupHandle(&cp->Pipe[i].Write); - kwsysProcessCleanupHandle(&cp->Pipe[i].Read); - cp->Pipe[i].Closed = 0; - } - for (i = 0; i < 3; ++i) { - kwsysProcessCleanupHandle(&cp->PipeChildStd[i]); - } -} - -void kwsysProcessCleanErrorMessage(kwsysProcess* cp) -{ - /* Remove trailing period and newline, if any. */ - size_t length = strlen(cp->ErrorMessage); - if (cp->ErrorMessage[length - 1] == '\n') { - cp->ErrorMessage[length - 1] = 0; - --length; - if (length > 0 && cp->ErrorMessage[length - 1] == '\r') { - cp->ErrorMessage[length - 1] = 0; - --length; - } - } - if (length > 0 && cp->ErrorMessage[length - 1] == '.') { - cp->ErrorMessage[length - 1] = 0; - } -} - -/* Get the time at which either the process or user timeout will - expire. Returns 1 if the user timeout is first, and 0 otherwise. */ -int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout, - kwsysProcessTime* timeoutTime) -{ - /* The first time this is called, we need to calculate the time at - which the child will timeout. */ - if (cp->Timeout && cp->TimeoutTime.QuadPart < 0) { - kwsysProcessTime length = kwsysProcessTimeFromDouble(cp->Timeout); - cp->TimeoutTime = kwsysProcessTimeAdd(cp->StartTime, length); - } - - /* Start with process timeout. */ - *timeoutTime = cp->TimeoutTime; - - /* Check if the user timeout is earlier. */ - if (userTimeout) { - kwsysProcessTime currentTime = kwsysProcessTimeGetCurrent(); - kwsysProcessTime userTimeoutLength = - kwsysProcessTimeFromDouble(*userTimeout); - kwsysProcessTime userTimeoutTime = - kwsysProcessTimeAdd(currentTime, userTimeoutLength); - if (timeoutTime->QuadPart < 0 || - kwsysProcessTimeLess(userTimeoutTime, *timeoutTime)) { - *timeoutTime = userTimeoutTime; - return 1; - } - } - return 0; -} - -/* Get the length of time before the given timeout time arrives. - Returns 1 if the time has already arrived, and 0 otherwise. */ -int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime, - double* userTimeout, - kwsysProcessTime* timeoutLength) -{ - if (timeoutTime->QuadPart < 0) { - /* No timeout time has been requested. */ - return 0; - } else { - /* Calculate the remaining time. */ - kwsysProcessTime currentTime = kwsysProcessTimeGetCurrent(); - *timeoutLength = kwsysProcessTimeSubtract(*timeoutTime, currentTime); - - if (timeoutLength->QuadPart < 0 && userTimeout && *userTimeout <= 0) { - /* Caller has explicitly requested a zero timeout. */ - timeoutLength->QuadPart = 0; - } - - if (timeoutLength->QuadPart < 0) { - /* Timeout has already expired. */ - return 1; - } else { - /* There is some time left. */ - return 0; - } - } -} - -kwsysProcessTime kwsysProcessTimeGetCurrent() -{ - kwsysProcessTime current; - FILETIME ft; - GetSystemTimeAsFileTime(&ft); - current.LowPart = ft.dwLowDateTime; - current.HighPart = ft.dwHighDateTime; - return current; -} - -DWORD kwsysProcessTimeToDWORD(kwsysProcessTime t) -{ - return (DWORD)(t.QuadPart * 0.0001); -} - -double kwsysProcessTimeToDouble(kwsysProcessTime t) -{ - return t.QuadPart * 0.0000001; -} - -kwsysProcessTime kwsysProcessTimeFromDouble(double d) -{ - kwsysProcessTime t; - t.QuadPart = (LONGLONG)(d * 10000000); - return t; -} - -int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2) -{ - return in1.QuadPart < in2.QuadPart; -} - -kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1, - kwsysProcessTime in2) -{ - kwsysProcessTime out; - out.QuadPart = in1.QuadPart + in2.QuadPart; - return out; -} - -kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, - kwsysProcessTime in2) -{ - kwsysProcessTime out; - out.QuadPart = in1.QuadPart - in2.QuadPart; - return out; -} - -#define KWSYSPE_CASE(type, str) \ - cp->ProcessResults[idx].ExitException = kwsysProcess_Exception_##type; \ - strcpy(cp->ProcessResults[idx].ExitExceptionString, str) -static void kwsysProcessSetExitExceptionByIndex(kwsysProcess* cp, int code, - int idx) -{ - switch (code) { - case STATUS_CONTROL_C_EXIT: - KWSYSPE_CASE(Interrupt, "User interrupt"); - break; - - case STATUS_FLOAT_DENORMAL_OPERAND: - KWSYSPE_CASE(Numerical, "Floating-point exception (denormal operand)"); - break; - case STATUS_FLOAT_DIVIDE_BY_ZERO: - KWSYSPE_CASE(Numerical, "Divide-by-zero"); - break; - case STATUS_FLOAT_INEXACT_RESULT: - KWSYSPE_CASE(Numerical, "Floating-point exception (inexact result)"); - break; - case STATUS_FLOAT_INVALID_OPERATION: - KWSYSPE_CASE(Numerical, "Invalid floating-point operation"); - break; - case STATUS_FLOAT_OVERFLOW: - KWSYSPE_CASE(Numerical, "Floating-point overflow"); - break; - case STATUS_FLOAT_STACK_CHECK: - KWSYSPE_CASE(Numerical, "Floating-point stack check failed"); - break; - case STATUS_FLOAT_UNDERFLOW: - KWSYSPE_CASE(Numerical, "Floating-point underflow"); - break; -#ifdef STATUS_FLOAT_MULTIPLE_FAULTS - case STATUS_FLOAT_MULTIPLE_FAULTS: - KWSYSPE_CASE(Numerical, "Floating-point exception (multiple faults)"); - break; -#endif -#ifdef STATUS_FLOAT_MULTIPLE_TRAPS - case STATUS_FLOAT_MULTIPLE_TRAPS: - KWSYSPE_CASE(Numerical, "Floating-point exception (multiple traps)"); - break; -#endif - case STATUS_INTEGER_DIVIDE_BY_ZERO: - KWSYSPE_CASE(Numerical, "Integer divide-by-zero"); - break; - case STATUS_INTEGER_OVERFLOW: - KWSYSPE_CASE(Numerical, "Integer overflow"); - break; - - case STATUS_DATATYPE_MISALIGNMENT: - KWSYSPE_CASE(Fault, "Datatype misalignment"); - break; - case STATUS_ACCESS_VIOLATION: - KWSYSPE_CASE(Fault, "Access violation"); - break; - case STATUS_IN_PAGE_ERROR: - KWSYSPE_CASE(Fault, "In-page error"); - break; - case STATUS_INVALID_HANDLE: - KWSYSPE_CASE(Fault, "Invalid hanlde"); - break; - case STATUS_NONCONTINUABLE_EXCEPTION: - KWSYSPE_CASE(Fault, "Noncontinuable exception"); - break; - case STATUS_INVALID_DISPOSITION: - KWSYSPE_CASE(Fault, "Invalid disposition"); - break; - case STATUS_ARRAY_BOUNDS_EXCEEDED: - KWSYSPE_CASE(Fault, "Array bounds exceeded"); - break; - case STATUS_STACK_OVERFLOW: - KWSYSPE_CASE(Fault, "Stack overflow"); - break; - - case STATUS_ILLEGAL_INSTRUCTION: - KWSYSPE_CASE(Illegal, "Illegal instruction"); - break; - case STATUS_PRIVILEGED_INSTRUCTION: - KWSYSPE_CASE(Illegal, "Privileged instruction"); - break; - - case STATUS_NO_MEMORY: - default: - cp->ProcessResults[idx].ExitException = kwsysProcess_Exception_Other; - _snprintf(cp->ProcessResults[idx].ExitExceptionString, - KWSYSPE_PIPE_BUFFER_SIZE, "Exit code 0x%x\n", code); - break; - } -} -#undef KWSYSPE_CASE - -typedef struct kwsysProcess_List_s kwsysProcess_List; -static kwsysProcess_List* kwsysProcess_List_New(void); -static void kwsysProcess_List_Delete(kwsysProcess_List* self); -static int kwsysProcess_List_Update(kwsysProcess_List* self); -static int kwsysProcess_List_NextProcess(kwsysProcess_List* self); -static int kwsysProcess_List_GetCurrentProcessId(kwsysProcess_List* self); -static int kwsysProcess_List_GetCurrentParentId(kwsysProcess_List* self); - -/* Windows NT 4 API definitions. */ -#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) -typedef LONG NTSTATUS; -typedef LONG KPRIORITY; -typedef struct _UNICODE_STRING UNICODE_STRING; -struct _UNICODE_STRING -{ - USHORT Length; - USHORT MaximumLength; - PWSTR Buffer; -}; - -/* The process information structure. Declare only enough to get - process identifiers. The rest may be ignored because we use the - NextEntryDelta to move through an array of instances. */ -typedef struct _SYSTEM_PROCESS_INFORMATION SYSTEM_PROCESS_INFORMATION; -typedef SYSTEM_PROCESS_INFORMATION* PSYSTEM_PROCESS_INFORMATION; -struct _SYSTEM_PROCESS_INFORMATION -{ - ULONG NextEntryDelta; - ULONG ThreadCount; - ULONG Reserved1[6]; - LARGE_INTEGER CreateTime; - LARGE_INTEGER UserTime; - LARGE_INTEGER KernelTime; - UNICODE_STRING ProcessName; - KPRIORITY BasePriority; - ULONG ProcessId; - ULONG InheritedFromProcessId; -}; - -/* Toolhelp32 API definitions. */ -#define TH32CS_SNAPPROCESS 0x00000002 -#if defined(_WIN64) -typedef unsigned __int64 ProcessULONG_PTR; -#else -typedef unsigned long ProcessULONG_PTR; -#endif -typedef struct tagPROCESSENTRY32 PROCESSENTRY32; -typedef PROCESSENTRY32* LPPROCESSENTRY32; -struct tagPROCESSENTRY32 -{ - DWORD dwSize; - DWORD cntUsage; - DWORD th32ProcessID; - ProcessULONG_PTR th32DefaultHeapID; - DWORD th32ModuleID; - DWORD cntThreads; - DWORD th32ParentProcessID; - LONG pcPriClassBase; - DWORD dwFlags; - char szExeFile[MAX_PATH]; -}; - -/* Windows API function types. */ -typedef HANDLE(WINAPI* CreateToolhelp32SnapshotType)(DWORD, DWORD); -typedef BOOL(WINAPI* Process32FirstType)(HANDLE, LPPROCESSENTRY32); -typedef BOOL(WINAPI* Process32NextType)(HANDLE, LPPROCESSENTRY32); -typedef NTSTATUS(WINAPI* ZwQuerySystemInformationType)(ULONG, PVOID, ULONG, - PULONG); - -static int kwsysProcess_List__New_NT4(kwsysProcess_List* self); -static int kwsysProcess_List__New_Snapshot(kwsysProcess_List* self); -static void kwsysProcess_List__Delete_NT4(kwsysProcess_List* self); -static void kwsysProcess_List__Delete_Snapshot(kwsysProcess_List* self); -static int kwsysProcess_List__Update_NT4(kwsysProcess_List* self); -static int kwsysProcess_List__Update_Snapshot(kwsysProcess_List* self); -static int kwsysProcess_List__Next_NT4(kwsysProcess_List* self); -static int kwsysProcess_List__Next_Snapshot(kwsysProcess_List* self); -static int kwsysProcess_List__GetProcessId_NT4(kwsysProcess_List* self); -static int kwsysProcess_List__GetProcessId_Snapshot(kwsysProcess_List* self); -static int kwsysProcess_List__GetParentId_NT4(kwsysProcess_List* self); -static int kwsysProcess_List__GetParentId_Snapshot(kwsysProcess_List* self); - -struct kwsysProcess_List_s -{ - /* Implementation switches at runtime based on version of Windows. */ - int NT4; - - /* Implementation functions and data for NT 4. */ - ZwQuerySystemInformationType P_ZwQuerySystemInformation; - char* Buffer; - int BufferSize; - PSYSTEM_PROCESS_INFORMATION CurrentInfo; - - /* Implementation functions and data for other Windows versions. */ - CreateToolhelp32SnapshotType P_CreateToolhelp32Snapshot; - Process32FirstType P_Process32First; - Process32NextType P_Process32Next; - HANDLE Snapshot; - PROCESSENTRY32 CurrentEntry; -}; - -static kwsysProcess_List* kwsysProcess_List_New(void) -{ - OSVERSIONINFO osv; - kwsysProcess_List* self; - - /* Allocate and initialize the list object. */ - if (!(self = (kwsysProcess_List*)malloc(sizeof(kwsysProcess_List)))) { - return 0; - } - memset(self, 0, sizeof(*self)); - - /* Select an implementation. */ - ZeroMemory(&osv, sizeof(osv)); - osv.dwOSVersionInfoSize = sizeof(osv); -#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx -# pragma warning(push) -# ifdef __INTEL_COMPILER -# pragma warning(disable : 1478) -# elif defined __clang__ -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated-declarations" -# else -# pragma warning(disable : 4996) -# endif -#endif - GetVersionEx(&osv); -#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx -# ifdef __clang__ -# pragma clang diagnostic pop -# else -# pragma warning(pop) -# endif -#endif - self->NT4 = - (osv.dwPlatformId == VER_PLATFORM_WIN32_NT && osv.dwMajorVersion < 5) ? 1 - : 0; - - /* Initialize the selected implementation. */ - if (!(self->NT4 ? kwsysProcess_List__New_NT4(self) - : kwsysProcess_List__New_Snapshot(self))) { - kwsysProcess_List_Delete(self); - return 0; - } - - /* Update to the current set of processes. */ - if (!kwsysProcess_List_Update(self)) { - kwsysProcess_List_Delete(self); - return 0; - } - return self; -} - -static void kwsysProcess_List_Delete(kwsysProcess_List* self) -{ - if (self) { - if (self->NT4) { - kwsysProcess_List__Delete_NT4(self); - } else { - kwsysProcess_List__Delete_Snapshot(self); - } - free(self); - } -} - -static int kwsysProcess_List_Update(kwsysProcess_List* self) -{ - return self ? (self->NT4 ? kwsysProcess_List__Update_NT4(self) - : kwsysProcess_List__Update_Snapshot(self)) - : 0; -} - -static int kwsysProcess_List_GetCurrentProcessId(kwsysProcess_List* self) -{ - return self ? (self->NT4 ? kwsysProcess_List__GetProcessId_NT4(self) - : kwsysProcess_List__GetProcessId_Snapshot(self)) - : -1; -} - -static int kwsysProcess_List_GetCurrentParentId(kwsysProcess_List* self) -{ - return self ? (self->NT4 ? kwsysProcess_List__GetParentId_NT4(self) - : kwsysProcess_List__GetParentId_Snapshot(self)) - : -1; -} - -static int kwsysProcess_List_NextProcess(kwsysProcess_List* self) -{ - return (self ? (self->NT4 ? kwsysProcess_List__Next_NT4(self) - : kwsysProcess_List__Next_Snapshot(self)) - : 0); -} - -static int kwsysProcess_List__New_NT4(kwsysProcess_List* self) -{ - /* Get a handle to the NT runtime module that should already be - loaded in this program. This does not actually increment the - reference count to the module so we do not need to close the - handle. */ - HMODULE hNT = GetModuleHandleW(L"ntdll.dll"); - if (hNT) { - /* Get pointers to the needed API functions. */ - self->P_ZwQuerySystemInformation = - ((ZwQuerySystemInformationType)GetProcAddress( - hNT, "ZwQuerySystemInformation")); - } - if (!self->P_ZwQuerySystemInformation) { - return 0; - } - - /* Allocate an initial process information buffer. */ - self->BufferSize = 32768; - self->Buffer = (char*)malloc(self->BufferSize); - return self->Buffer ? 1 : 0; -} - -static void kwsysProcess_List__Delete_NT4(kwsysProcess_List* self) -{ - /* Free the process information buffer. */ - free(self->Buffer); -} - -static int kwsysProcess_List__Update_NT4(kwsysProcess_List* self) -{ - self->CurrentInfo = 0; - for (;;) { - /* Query number 5 is for system process list. */ - NTSTATUS status = - self->P_ZwQuerySystemInformation(5, self->Buffer, self->BufferSize, 0); - if (status == STATUS_INFO_LENGTH_MISMATCH) { - /* The query requires a bigger buffer. */ - int newBufferSize = self->BufferSize * 2; - char* newBuffer = (char*)malloc(newBufferSize); - if (newBuffer) { - free(self->Buffer); - self->Buffer = newBuffer; - self->BufferSize = newBufferSize; - } else { - return 0; - } - } else if (status >= 0) { - /* The query succeeded. Initialize traversal of the process list. */ - self->CurrentInfo = (PSYSTEM_PROCESS_INFORMATION)self->Buffer; - return 1; - } else { - /* The query failed. */ - return 0; - } - } -} - -static int kwsysProcess_List__Next_NT4(kwsysProcess_List* self) -{ - if (self->CurrentInfo) { - if (self->CurrentInfo->NextEntryDelta > 0) { - self->CurrentInfo = - ((PSYSTEM_PROCESS_INFORMATION)((char*)self->CurrentInfo + - self->CurrentInfo->NextEntryDelta)); - return 1; - } - self->CurrentInfo = 0; - } - return 0; -} - -static int kwsysProcess_List__GetProcessId_NT4(kwsysProcess_List* self) -{ - return self->CurrentInfo ? self->CurrentInfo->ProcessId : -1; -} - -static int kwsysProcess_List__GetParentId_NT4(kwsysProcess_List* self) -{ - return self->CurrentInfo ? self->CurrentInfo->InheritedFromProcessId : -1; -} - -static int kwsysProcess_List__New_Snapshot(kwsysProcess_List* self) -{ - /* Get a handle to the Windows runtime module that should already be - loaded in this program. This does not actually increment the - reference count to the module so we do not need to close the - handle. */ - HMODULE hKernel = GetModuleHandleW(L"kernel32.dll"); - if (hKernel) { - self->P_CreateToolhelp32Snapshot = - ((CreateToolhelp32SnapshotType)GetProcAddress( - hKernel, "CreateToolhelp32Snapshot")); - self->P_Process32First = - ((Process32FirstType)GetProcAddress(hKernel, "Process32First")); - self->P_Process32Next = - ((Process32NextType)GetProcAddress(hKernel, "Process32Next")); - } - return (self->P_CreateToolhelp32Snapshot && self->P_Process32First && - self->P_Process32Next) - ? 1 - : 0; -} - -static void kwsysProcess_List__Delete_Snapshot(kwsysProcess_List* self) -{ - if (self->Snapshot) { - CloseHandle(self->Snapshot); - } -} - -static int kwsysProcess_List__Update_Snapshot(kwsysProcess_List* self) -{ - if (self->Snapshot) { - CloseHandle(self->Snapshot); - } - if (!(self->Snapshot = - self->P_CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0))) { - return 0; - } - ZeroMemory(&self->CurrentEntry, sizeof(self->CurrentEntry)); - self->CurrentEntry.dwSize = sizeof(self->CurrentEntry); - if (!self->P_Process32First(self->Snapshot, &self->CurrentEntry)) { - CloseHandle(self->Snapshot); - self->Snapshot = 0; - return 0; - } - return 1; -} - -static int kwsysProcess_List__Next_Snapshot(kwsysProcess_List* self) -{ - if (self->Snapshot) { - if (self->P_Process32Next(self->Snapshot, &self->CurrentEntry)) { - return 1; - } - CloseHandle(self->Snapshot); - self->Snapshot = 0; - } - return 0; -} - -static int kwsysProcess_List__GetProcessId_Snapshot(kwsysProcess_List* self) -{ - return self->Snapshot ? self->CurrentEntry.th32ProcessID : -1; -} - -static int kwsysProcess_List__GetParentId_Snapshot(kwsysProcess_List* self) -{ - return self->Snapshot ? self->CurrentEntry.th32ParentProcessID : -1; -} - -static void kwsysProcessKill(DWORD pid) -{ - HANDLE h = OpenProcess(PROCESS_TERMINATE, 0, pid); - if (h) { - TerminateProcess(h, 255); - WaitForSingleObject(h, INFINITE); - CloseHandle(h); - } -} - -static void kwsysProcessKillTree(int pid) -{ - kwsysProcess_List* plist = kwsysProcess_List_New(); - kwsysProcessKill(pid); - if (plist) { - do { - if (kwsysProcess_List_GetCurrentParentId(plist) == pid) { - int ppid = kwsysProcess_List_GetCurrentProcessId(plist); - kwsysProcessKillTree(ppid); - } - } while (kwsysProcess_List_NextProcess(plist)); - kwsysProcess_List_Delete(plist); - } -} - -static void kwsysProcessDisablePipeThreads(kwsysProcess* cp) -{ - int i; - - /* If data were just reported data, release the pipe's thread. */ - if (cp->CurrentIndex < KWSYSPE_PIPE_COUNT) { - KWSYSPE_DEBUG((stderr, "releasing reader %d\n", cp->CurrentIndex)); - ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0); - cp->CurrentIndex = KWSYSPE_PIPE_COUNT; - } - - /* Wakeup all reading threads that are not on closed pipes. */ - for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { - /* The wakeup threads will write one byte to the pipe write ends. - If there are no data in the pipe then this is enough to wakeup - the reading threads. If there are already data in the pipe - this may block. We cannot use PeekNamedPipe to check whether - there are data because an outside process might still be - writing data if we are disowning it. Also, PeekNamedPipe will - block if checking a pipe on which the reading thread is - currently calling ReadPipe. Therefore we need a separate - thread to call WriteFile. If it blocks, that is okay because - it will unblock when we close the read end and break the pipe - below. */ - if (cp->Pipe[i].Read) { - KWSYSPE_DEBUG((stderr, "releasing waker %d\n", i)); - ReleaseSemaphore(cp->Pipe[i].Waker.Go, 1, 0); - } - } - - /* Tell pipe threads to reset until we run another process. */ - while (cp->PipesLeft > 0) { - /* The waking threads will cause all reading threads to report. - Wait for the next one and save its index. */ - KWSYSPE_DEBUG((stderr, "waiting for reader\n")); - WaitForSingleObject(cp->Full, INFINITE); - cp->CurrentIndex = cp->SharedIndex; - ReleaseSemaphore(cp->SharedIndexMutex, 1, 0); - KWSYSPE_DEBUG((stderr, "got reader %d\n", cp->CurrentIndex)); - - /* We are done reading this pipe. Close its read handle. */ - cp->Pipe[cp->CurrentIndex].Closed = 1; - kwsysProcessCleanupHandle(&cp->Pipe[cp->CurrentIndex].Read); - --cp->PipesLeft; - - /* Tell the reading thread we are done with the data. It will - reset immediately because the pipe is closed. */ - ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0); - } -} - -/* Global set of executing processes for use by the Ctrl handler. - This global instance will be zero-initialized by the compiler. - - Note that the console Ctrl handler runs on a background thread and so - everything it does must be thread safe. Here, we track the hProcess - HANDLEs directly instead of kwsysProcess instances, so that we don't have - to make kwsysProcess thread safe. */ -typedef struct kwsysProcessInstance_s -{ - HANDLE hProcess; - DWORD dwProcessId; - int NewProcessGroup; /* Whether the process was created in a new group. */ -} kwsysProcessInstance; - -typedef struct kwsysProcessInstances_s -{ - /* Whether we have initialized key fields below, like critical sections. */ - int Initialized; - - /* Ctrl handler runs on a different thread, so we must sync access. */ - CRITICAL_SECTION Lock; - - int Exiting; - size_t Count; - size_t Size; - kwsysProcessInstance* Processes; -} kwsysProcessInstances; -static kwsysProcessInstances kwsysProcesses; - -/* Initialize critial section and set up console Ctrl handler. You MUST call - this before using any other kwsysProcesses* functions below. */ -static int kwsysProcessesInitialize(void) -{ - /* Initialize everything if not done already. */ - if (!kwsysProcesses.Initialized) { - InitializeCriticalSection(&kwsysProcesses.Lock); - - /* Set up console ctrl handler. */ - if (!SetConsoleCtrlHandler(kwsysCtrlHandler, TRUE)) { - return 0; - } - - kwsysProcesses.Initialized = 1; - } - return 1; -} - -/* The Ctrl handler waits on the global list of processes. To prevent an - orphaned process, do not create a new process if the Ctrl handler is - already running. Do so by using this function to check if it is ok to - create a process. */ -static int kwsysTryEnterCreateProcessSection(void) -{ - /* Enter main critical section; this means creating a process and the Ctrl - handler are mutually exclusive. */ - EnterCriticalSection(&kwsysProcesses.Lock); - /* Indicate to the caller if they can create a process. */ - if (kwsysProcesses.Exiting) { - LeaveCriticalSection(&kwsysProcesses.Lock); - return 0; - } else { - return 1; - } -} - -/* Matching function on successful kwsysTryEnterCreateProcessSection return. - Make sure you called kwsysProcessesAdd if applicable before calling this.*/ -static void kwsysLeaveCreateProcessSection(void) -{ - LeaveCriticalSection(&kwsysProcesses.Lock); -} - -/* Add new process to global process list. The Ctrl handler will wait for - the process to exit before it returns. Do not close the process handle - until after calling kwsysProcessesRemove. The newProcessGroup parameter - must be set if the process was created with CREATE_NEW_PROCESS_GROUP. */ -static int kwsysProcessesAdd(HANDLE hProcess, DWORD dwProcessid, - int newProcessGroup) -{ - if (!kwsysProcessesInitialize() || !hProcess || - hProcess == INVALID_HANDLE_VALUE) { - return 0; - } - - /* Enter the critical section. */ - EnterCriticalSection(&kwsysProcesses.Lock); - - /* Make sure there is enough space for the new process handle. */ - if (kwsysProcesses.Count == kwsysProcesses.Size) { - size_t newSize; - kwsysProcessInstance* newArray; - /* Start with enough space for a small number of process handles - and double the size each time more is needed. */ - newSize = kwsysProcesses.Size ? kwsysProcesses.Size * 2 : 4; - - /* Try allocating the new block of memory. */ - if ((newArray = (kwsysProcessInstance*)malloc( - newSize * sizeof(kwsysProcessInstance)))) { - /* Copy the old process handles to the new memory. */ - if (kwsysProcesses.Count > 0) { - memcpy(newArray, kwsysProcesses.Processes, - kwsysProcesses.Count * sizeof(kwsysProcessInstance)); - } - } else { - /* Failed to allocate memory for the new process handle set. */ - LeaveCriticalSection(&kwsysProcesses.Lock); - return 0; - } - - /* Free original array. */ - free(kwsysProcesses.Processes); - - /* Update original structure with new allocation. */ - kwsysProcesses.Size = newSize; - kwsysProcesses.Processes = newArray; - } - - /* Append the new process information to the set. */ - kwsysProcesses.Processes[kwsysProcesses.Count].hProcess = hProcess; - kwsysProcesses.Processes[kwsysProcesses.Count].dwProcessId = dwProcessid; - kwsysProcesses.Processes[kwsysProcesses.Count++].NewProcessGroup = - newProcessGroup; - - /* Leave critical section and return success. */ - LeaveCriticalSection(&kwsysProcesses.Lock); - - return 1; -} - -/* Removes process to global process list. */ -static void kwsysProcessesRemove(HANDLE hProcess) -{ - size_t i; - - if (!hProcess || hProcess == INVALID_HANDLE_VALUE) { - return; - } - - EnterCriticalSection(&kwsysProcesses.Lock); - - /* Find the given process in the set. */ - for (i = 0; i < kwsysProcesses.Count; ++i) { - if (kwsysProcesses.Processes[i].hProcess == hProcess) { - break; - } - } - if (i < kwsysProcesses.Count) { - /* Found it! Remove the process from the set. */ - --kwsysProcesses.Count; - for (; i < kwsysProcesses.Count; ++i) { - kwsysProcesses.Processes[i] = kwsysProcesses.Processes[i + 1]; - } - - /* If this was the last process, free the array. */ - if (kwsysProcesses.Count == 0) { - kwsysProcesses.Size = 0; - free(kwsysProcesses.Processes); - kwsysProcesses.Processes = 0; - } - } - - LeaveCriticalSection(&kwsysProcesses.Lock); -} - -static BOOL WINAPI kwsysCtrlHandler(DWORD dwCtrlType) -{ - size_t i; - (void)dwCtrlType; - /* Enter critical section. */ - EnterCriticalSection(&kwsysProcesses.Lock); - - /* Set flag indicating that we are exiting. */ - kwsysProcesses.Exiting = 1; - - /* If some of our processes were created in a new process group, we must - manually interrupt them. They won't otherwise receive a Ctrl+C/Break. */ - for (i = 0; i < kwsysProcesses.Count; ++i) { - if (kwsysProcesses.Processes[i].NewProcessGroup) { - DWORD groupId = kwsysProcesses.Processes[i].dwProcessId; - if (groupId) { - GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, groupId); - } - } - } - - /* Wait for each child process to exit. This is the key step that prevents - us from leaving several orphaned children processes running in the - background when the user presses Ctrl+C. */ - for (i = 0; i < kwsysProcesses.Count; ++i) { - WaitForSingleObject(kwsysProcesses.Processes[i].hProcess, INFINITE); - } - - /* Leave critical section. */ - LeaveCriticalSection(&kwsysProcesses.Lock); - - /* Continue on to default Ctrl handler (which calls ExitProcess). */ - return FALSE; -} - -void kwsysProcess_ResetStartTime(kwsysProcess* cp) -{ - if (!cp) { - return; - } - /* Reset start time. */ - cp->StartTime = kwsysProcessTimeGetCurrent(); -} diff --git a/test/API/driver/kwsys/README.rst b/test/API/driver/kwsys/README.rst deleted file mode 100644 index fc6b590..0000000 --- a/test/API/driver/kwsys/README.rst +++ /dev/null @@ -1,37 +0,0 @@ -KWSys -***** - -Introduction -============ - -KWSys is the Kitware System Library. It provides platform-independent -APIs to many common system features that are implemented differently on -every platform. This library is intended to be shared among many -projects at the source level, so it has a configurable namespace. -Each project should configure KWSys to use a namespace unique to itself. -See comments in `CMakeLists.txt`_ for details. - -.. _`CMakeLists.txt`: CMakeLists.txt - -License -======= - -KWSys is distributed under the OSI-approved BSD 3-clause License. -See `Copyright.txt`_ for details. - -.. _`Copyright.txt`: Copyright.txt - -Reporting Bugs -============== - -KWSys has no independent issue tracker. After encountering an issue -(bug) please submit a patch using the instructions for `Contributing`_. -Otherwise please report the issue to the tracker for the project that -hosts the copy of KWSys in which the problem was found. - -Contributing -============ - -See `CONTRIBUTING.rst`_ for instructions to contribute. - -.. _`CONTRIBUTING.rst`: CONTRIBUTING.rst diff --git a/test/API/driver/kwsys/RegularExpression.cxx b/test/API/driver/kwsys/RegularExpression.cxx deleted file mode 100644 index 5e6f8da..0000000 --- a/test/API/driver/kwsys/RegularExpression.cxx +++ /dev/null @@ -1,1218 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -// -// Copyright (C) 1991 Texas Instruments Incorporated. -// -// Permission is granted to any individual or institution to use, copy, modify -// and distribute this software, provided that this complete copyright and -// permission notice is maintained, intact, in all copies and supporting -// documentation. -// -// Texas Instruments Incorporated provides this software "as is" without -// express or implied warranty. -// -// -// Created: MNF 06/13/89 Initial Design and Implementation -// Updated: LGO 08/09/89 Inherit from Generic -// Updated: MBN 09/07/89 Added conditional exception handling -// Updated: MBN 12/15/89 Sprinkled "const" qualifiers all over the place! -// Updated: DLS 03/22/91 New lite version -// - -#include "kwsysPrivate.h" -#include KWSYS_HEADER(RegularExpression.hxx) - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -# include "RegularExpression.hxx.in" -#endif - -#include -#include - -namespace KWSYS_NAMESPACE { - -// RegularExpression -- Copies the given regular expression. -RegularExpression::RegularExpression(const RegularExpression& rxp) -{ - if (!rxp.program) { - this->program = nullptr; - return; - } - int ind; - this->progsize = rxp.progsize; // Copy regular expression size - this->program = new char[this->progsize]; // Allocate storage - for (ind = this->progsize; ind-- != 0;) // Copy regular expression - this->program[ind] = rxp.program[ind]; - // Copy pointers into last successful "find" operation - this->regmatch = rxp.regmatch; - this->regmust = rxp.regmust; // Copy field - if (rxp.regmust != nullptr) { - char* dum = rxp.program; - ind = 0; - while (dum != rxp.regmust) { - ++dum; - ++ind; - } - this->regmust = this->program + ind; - } - this->regstart = rxp.regstart; // Copy starting index - this->reganch = rxp.reganch; // Copy remaining private data - this->regmlen = rxp.regmlen; // Copy remaining private data -} - -// operator= -- Copies the given regular expression. -RegularExpression& RegularExpression::operator=(const RegularExpression& rxp) -{ - if (this == &rxp) { - return *this; - } - if (!rxp.program) { - this->program = nullptr; - return *this; - } - int ind; - this->progsize = rxp.progsize; // Copy regular expression size - delete[] this->program; - this->program = new char[this->progsize]; // Allocate storage - for (ind = this->progsize; ind-- != 0;) // Copy regular expression - this->program[ind] = rxp.program[ind]; - // Copy pointers into last successful "find" operation - this->regmatch = rxp.regmatch; - this->regmust = rxp.regmust; // Copy field - if (rxp.regmust != nullptr) { - char* dum = rxp.program; - ind = 0; - while (dum != rxp.regmust) { - ++dum; - ++ind; - } - this->regmust = this->program + ind; - } - this->regstart = rxp.regstart; // Copy starting index - this->reganch = rxp.reganch; // Copy remaining private data - this->regmlen = rxp.regmlen; // Copy remaining private data - - return *this; -} - -// operator== -- Returns true if two regular expressions have the same -// compiled program for pattern matching. -bool RegularExpression::operator==(const RegularExpression& rxp) const -{ - if (this != &rxp) { // Same address? - int ind = this->progsize; // Get regular expression size - if (ind != rxp.progsize) // If different size regexp - return false; // Return failure - while (ind-- != 0) // Else while still characters - if (this->program[ind] != rxp.program[ind]) // If regexp are different - return false; // Return failure - } - return true; // Else same, return success -} - -// deep_equal -- Returns true if have the same compiled regular expressions -// and the same start and end pointers. - -bool RegularExpression::deep_equal(const RegularExpression& rxp) const -{ - int ind = this->progsize; // Get regular expression size - if (ind != rxp.progsize) // If different size regexp - return false; // Return failure - while (ind-- != 0) // Else while still characters - if (this->program[ind] != rxp.program[ind]) // If regexp are different - return false; // Return failure - // Else if same start/end ptrs, return true - return (this->regmatch.start() == rxp.regmatch.start() && - this->regmatch.end() == rxp.regmatch.end()); -} - -// The remaining code in this file is derived from the regular expression code -// whose copyright statement appears below. It has been changed to work -// with the class concepts of C++ and COOL. - -/* - * compile and find - * - * Copyright (c) 1986 by University of Toronto. - * Written by Henry Spencer. Not derived from licensed software. - * - * Permission is granted to anyone to use this software for any - * purpose on any computer system, and to redistribute it freely, - * subject to the following restrictions: - * - * 1. The author is not responsible for the consequences of use of - * this software, no matter how awful, even if they arise - * from defects in it. - * - * 2. The origin of this software must not be misrepresented, either - * by explicit claim or by omission. - * - * 3. Altered versions must be plainly marked as such, and must not - * be misrepresented as being the original software. - * - * Beware that some of this code is subtly aware of the way operator - * precedence is structured in regular expressions. Serious changes in - * regular-expression syntax might require a total rethink. - */ - -/* - * The "internal use only" fields in regexp.h are present to pass info from - * compile to execute that permits the execute phase to run lots faster on - * simple cases. They are: - * - * regstart char that must begin a match; '\0' if none obvious - * reganch is the match anchored (at beginning-of-line only)? - * regmust string (pointer into program) that match must include, or - * nullptr regmlen length of regmust string - * - * Regstart and reganch permit very fast decisions on suitable starting points - * for a match, cutting down the work a lot. Regmust permits fast rejection - * of lines that cannot possibly match. The regmust tests are costly enough - * that compile() supplies a regmust only if the r.e. contains something - * potentially expensive (at present, the only such thing detected is * or + - * at the start of the r.e., which can involve a lot of backup). Regmlen is - * supplied because the test in find() needs it and compile() is computing - * it anyway. - */ - -/* - * Structure for regexp "program". This is essentially a linear encoding - * of a nondeterministic finite-state machine (aka syntax charts or - * "railroad normal form" in parsing technology). Each node is an opcode - * plus a "next" pointer, possibly plus an operand. "Next" pointers of - * all nodes except BRANCH implement concatenation; a "next" pointer with - * a BRANCH on both ends of it is connecting two alternatives. (Here we - * have one of the subtle syntax dependencies: an individual BRANCH (as - * opposed to a collection of them) is never concatenated with anything - * because of operator precedence.) The operand of some types of node is - * a literal string; for others, it is a node leading into a sub-FSM. In - * particular, the operand of a BRANCH node is the first node of the branch. - * (NB this is *not* a tree structure: the tail of the branch connects - * to the thing following the set of BRANCHes.) The opcodes are: - */ - -// definition number opnd? meaning -#define END 0 // no End of program. -#define BOL 1 // no Match "" at beginning of line. -#define EOL 2 // no Match "" at end of line. -#define ANY 3 // no Match any one character. -#define ANYOF 4 // str Match any character in this string. -#define ANYBUT \ - 5 // str Match any character not in this - // string. -#define BRANCH \ - 6 // node Match this alternative, or the - // next... -#define BACK 7 // no Match "", "next" ptr points backward. -#define EXACTLY 8 // str Match this string. -#define NOTHING 9 // no Match empty string. -#define STAR \ - 10 // node Match this (simple) thing 0 or more - // times. -#define PLUS \ - 11 // node Match this (simple) thing 1 or more - // times. -#define OPEN \ - 20 // no Mark this point in input as start of - // #n. -// OPEN+1 is number 1, etc. -#define CLOSE 30 // no Analogous to OPEN. - -/* - * Opcode notes: - * - * BRANCH The set of branches constituting a single choice are hooked - * together with their "next" pointers, since precedence prevents - * anything being concatenated to any individual branch. The - * "next" pointer of the last BRANCH in a choice points to the - * thing following the whole choice. This is also where the - * final "next" pointer of each individual branch points; each - * branch starts with the operand node of a BRANCH node. - * - * BACK Normal "next" pointers all implicitly point forward; BACK - * exists to make loop structures possible. - * - * STAR,PLUS '?', and complex '*' and '+', are implemented as circular - * BRANCH structures using BACK. Simple cases (one character - * per match) are implemented with STAR and PLUS for speed - * and to minimize recursive plunges. - * - * OPEN,CLOSE ...are numbered at compile time. - */ - -/* - * A node is one char of opcode followed by two chars of "next" pointer. - * "Next" pointers are stored as two 8-bit pieces, high order first. The - * value is a positive offset from the opcode of the node containing it. - * An operand, if any, simply follows the node. (Note that much of the - * code generation knows about this implicit relationship.) - * - * Using two bytes for the "next" pointer is vast overkill for most things, - * but allows patterns to get big without disasters. - */ - -#define OP(p) (*(p)) -#define NEXT(p) (((*((p) + 1) & 0377) << 8) + (*((p) + 2) & 0377)) -#define OPERAND(p) ((p) + 3) - -const unsigned char MAGIC = 0234; -/* - * Utility definitions. - */ - -#define UCHARAT(p) (reinterpret_cast(p))[0] - -#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?') -#define META "^$.[()|?+*\\" - -/* - * Flags to be passed up and down. - */ -#define HASWIDTH 01 // Known never to match null string. -#define SIMPLE 02 // Simple enough to be STAR/PLUS operand. -#define SPSTART 04 // Starts with * or +. -#define WORST 0 // Worst case. - -///////////////////////////////////////////////////////////////////////// -// -// COMPILE AND ASSOCIATED FUNCTIONS -// -///////////////////////////////////////////////////////////////////////// - -/* - * Read only utility variables. - */ -static char regdummy; -static char* const regdummyptr = ®dummy; - -/* - * Utility class for RegularExpression::compile(). - */ -class RegExpCompile -{ -public: - const char* regparse; // Input-scan pointer. - int regnpar; // () count. - char* regcode; // Code-emit pointer; regdummyptr = don't. - long regsize; // Code size. - - char* reg(int, int*); - char* regbranch(int*); - char* regpiece(int*); - char* regatom(int*); - char* regnode(char); - void regc(char); - void reginsert(char, char*); - static void regtail(char*, const char*); - static void regoptail(char*, const char*); -}; - -static const char* regnext(const char*); -static char* regnext(char*); - -#ifdef STRCSPN -static int strcspn(); -#endif - -/* - * We can't allocate space until we know how big the compiled form will be, - * but we can't compile it (and thus know how big it is) until we've got a - * place to put the code. So we cheat: we compile it twice, once with code - * generation turned off and size counting turned on, and once "for real". - * This also means that we don't allocate space until we are sure that the - * thing really will compile successfully, and we never have to move the - * code and thus invalidate pointers into it. (Note that it has to be in - * one piece because free() must be able to free it all.) - * - * Beware that the optimization-preparation code in here knows about some - * of the structure of the compiled regexp. - */ - -// compile -- compile a regular expression into internal code -// for later pattern matching. - -bool RegularExpression::compile(const char* exp) -{ - const char* scan; - const char* longest; - int flags; - - if (exp == nullptr) { - // RAISE Error, SYM(RegularExpression), SYM(No_Expr), - printf("RegularExpression::compile(): No expression supplied.\n"); - return false; - } - - // First pass: determine size, legality. - RegExpCompile comp; - comp.regparse = exp; - comp.regnpar = 1; - comp.regsize = 0L; - comp.regcode = regdummyptr; - comp.regc(static_cast(MAGIC)); - if (!comp.reg(0, &flags)) { - printf("RegularExpression::compile(): Error in compile.\n"); - return false; - } - this->regmatch.clear(); - - // Small enough for pointer-storage convention? - if (comp.regsize >= 32767L) { // Probably could be 65535L. - // RAISE Error, SYM(RegularExpression), SYM(Expr_Too_Big), - printf("RegularExpression::compile(): Expression too big.\n"); - return false; - } - - // Allocate space. - //#ifndef _WIN32 - if (this->program != nullptr) - delete[] this->program; - //#endif - this->program = new char[comp.regsize]; - this->progsize = static_cast(comp.regsize); - - if (this->program == nullptr) { - // RAISE Error, SYM(RegularExpression), SYM(Out_Of_Memory), - printf("RegularExpression::compile(): Out of memory.\n"); - return false; - } - - // Second pass: emit code. - comp.regparse = exp; - comp.regnpar = 1; - comp.regcode = this->program; - comp.regc(static_cast(MAGIC)); - comp.reg(0, &flags); - - // Dig out information for optimizations. - this->regstart = '\0'; // Worst-case defaults. - this->reganch = 0; - this->regmust = nullptr; - this->regmlen = 0; - scan = this->program + 1; // First BRANCH. - if (OP(regnext(scan)) == END) { // Only one top-level choice. - scan = OPERAND(scan); - - // Starting-point info. - if (OP(scan) == EXACTLY) - this->regstart = *OPERAND(scan); - else if (OP(scan) == BOL) - this->reganch++; - - // - // If there's something expensive in the r.e., find the longest - // literal string that must appear and make it the regmust. Resolve - // ties in favor of later strings, since the regstart check works - // with the beginning of the r.e. and avoiding duplication - // strengthens checking. Not a strong reason, but sufficient in the - // absence of others. - // - if (flags & SPSTART) { - longest = nullptr; - size_t len = 0; - for (; scan != nullptr; scan = regnext(scan)) - if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) { - longest = OPERAND(scan); - len = strlen(OPERAND(scan)); - } - this->regmust = longest; - this->regmlen = len; - } - } - return true; -} - -/* - - reg - regular expression, i.e. main body or parenthesized thing - * - * Caller must absorb opening parenthesis. - * - * Combining parenthesis handling with the base level of regular expression - * is a trifle forced, but the need to tie the tails of the branches to what - * follows makes it hard to avoid. - */ -char* RegExpCompile::reg(int paren, int* flagp) -{ - char* ret; - char* br; - char* ender; - int parno = 0; - int flags; - - *flagp = HASWIDTH; // Tentatively. - - // Make an OPEN node, if parenthesized. - if (paren) { - if (regnpar >= RegularExpressionMatch::NSUBEXP) { - // RAISE Error, SYM(RegularExpression), SYM(Too_Many_Parens), - printf("RegularExpression::compile(): Too many parentheses.\n"); - return nullptr; - } - parno = regnpar; - regnpar++; - ret = regnode(static_cast(OPEN + parno)); - } else - ret = nullptr; - - // Pick up the branches, linking them together. - br = regbranch(&flags); - if (br == nullptr) - return (nullptr); - if (ret != nullptr) - regtail(ret, br); // OPEN -> first. - else - ret = br; - if (!(flags & HASWIDTH)) - *flagp &= ~HASWIDTH; - *flagp |= flags & SPSTART; - while (*regparse == '|') { - regparse++; - br = regbranch(&flags); - if (br == nullptr) - return (nullptr); - regtail(ret, br); // BRANCH -> BRANCH. - if (!(flags & HASWIDTH)) - *flagp &= ~HASWIDTH; - *flagp |= flags & SPSTART; - } - - // Make a closing node, and hook it on the end. - ender = regnode(static_cast((paren) ? CLOSE + parno : END)); - regtail(ret, ender); - - // Hook the tails of the branches to the closing node. - for (br = ret; br != nullptr; br = regnext(br)) - regoptail(br, ender); - - // Check for proper termination. - if (paren && *regparse++ != ')') { - // RAISE Error, SYM(RegularExpression), SYM(Unmatched_Parens), - printf("RegularExpression::compile(): Unmatched parentheses.\n"); - return nullptr; - } else if (!paren && *regparse != '\0') { - if (*regparse == ')') { - // RAISE Error, SYM(RegularExpression), SYM(Unmatched_Parens), - printf("RegularExpression::compile(): Unmatched parentheses.\n"); - return nullptr; - } else { - // RAISE Error, SYM(RegularExpression), SYM(Internal_Error), - printf("RegularExpression::compile(): Internal error.\n"); - return nullptr; - } - // NOTREACHED - } - return (ret); -} - -/* - - regbranch - one alternative of an | operator - * - * Implements the concatenation operator. - */ -char* RegExpCompile::regbranch(int* flagp) -{ - char* ret; - char* chain; - char* latest; - int flags; - - *flagp = WORST; // Tentatively. - - ret = regnode(BRANCH); - chain = nullptr; - while (*regparse != '\0' && *regparse != '|' && *regparse != ')') { - latest = regpiece(&flags); - if (latest == nullptr) - return (nullptr); - *flagp |= flags & HASWIDTH; - if (chain == nullptr) // First piece. - *flagp |= flags & SPSTART; - else - regtail(chain, latest); - chain = latest; - } - if (chain == nullptr) // Loop ran zero times. - regnode(NOTHING); - - return (ret); -} - -/* - - regpiece - something followed by possible [*+?] - * - * Note that the branching code sequences used for ? and the general cases - * of * and + are somewhat optimized: they use the same NOTHING node as - * both the endmarker for their branch list and the body of the last branch. - * It might seem that this node could be dispensed with entirely, but the - * endmarker role is not redundant. - */ -char* RegExpCompile::regpiece(int* flagp) -{ - char* ret; - char op; - char* next; - int flags; - - ret = regatom(&flags); - if (ret == nullptr) - return (nullptr); - - op = *regparse; - if (!ISMULT(op)) { - *flagp = flags; - return (ret); - } - - if (!(flags & HASWIDTH) && op != '?') { - // RAISE Error, SYM(RegularExpression), SYM(Empty_Operand), - printf("RegularExpression::compile() : *+ operand could be empty.\n"); - return nullptr; - } - *flagp = (op != '+') ? (WORST | SPSTART) : (WORST | HASWIDTH); - - if (op == '*' && (flags & SIMPLE)) - reginsert(STAR, ret); - else if (op == '*') { - // Emit x* as (x&|), where & means "self". - reginsert(BRANCH, ret); // Either x - regoptail(ret, regnode(BACK)); // and loop - regoptail(ret, ret); // back - regtail(ret, regnode(BRANCH)); // or - regtail(ret, regnode(NOTHING)); // null. - } else if (op == '+' && (flags & SIMPLE)) - reginsert(PLUS, ret); - else if (op == '+') { - // Emit x+ as x(&|), where & means "self". - next = regnode(BRANCH); // Either - regtail(ret, next); - regtail(regnode(BACK), ret); // loop back - regtail(next, regnode(BRANCH)); // or - regtail(ret, regnode(NOTHING)); // null. - } else if (op == '?') { - // Emit x? as (x|) - reginsert(BRANCH, ret); // Either x - regtail(ret, regnode(BRANCH)); // or - next = regnode(NOTHING); // null. - regtail(ret, next); - regoptail(ret, next); - } - regparse++; - if (ISMULT(*regparse)) { - // RAISE Error, SYM(RegularExpression), SYM(Nested_Operand), - printf("RegularExpression::compile(): Nested *?+.\n"); - return nullptr; - } - return (ret); -} - -/* - - regatom - the lowest level - * - * Optimization: gobbles an entire sequence of ordinary characters so that - * it can turn them into a single node, which is smaller to store and - * faster to run. Backslashed characters are exceptions, each becoming a - * separate node; the code is simpler that way and it's not worth fixing. - */ -char* RegExpCompile::regatom(int* flagp) -{ - char* ret; - int flags; - - *flagp = WORST; // Tentatively. - - switch (*regparse++) { - case '^': - ret = regnode(BOL); - break; - case '$': - ret = regnode(EOL); - break; - case '.': - ret = regnode(ANY); - *flagp |= HASWIDTH | SIMPLE; - break; - case '[': { - int rxpclass; - int rxpclassend; - - if (*regparse == '^') { // Complement of range. - ret = regnode(ANYBUT); - regparse++; - } else - ret = regnode(ANYOF); - if (*regparse == ']' || *regparse == '-') - regc(*regparse++); - while (*regparse != '\0' && *regparse != ']') { - if (*regparse == '-') { - regparse++; - if (*regparse == ']' || *regparse == '\0') - regc('-'); - else { - rxpclass = UCHARAT(regparse - 2) + 1; - rxpclassend = UCHARAT(regparse); - if (rxpclass > rxpclassend + 1) { - // RAISE Error, SYM(RegularExpression), SYM(Invalid_Range), - printf("RegularExpression::compile(): Invalid range in [].\n"); - return nullptr; - } - for (; rxpclass <= rxpclassend; rxpclass++) - regc(static_cast(rxpclass)); - regparse++; - } - } else - regc(*regparse++); - } - regc('\0'); - if (*regparse != ']') { - // RAISE Error, SYM(RegularExpression), SYM(Unmatched_Bracket), - printf("RegularExpression::compile(): Unmatched [].\n"); - return nullptr; - } - regparse++; - *flagp |= HASWIDTH | SIMPLE; - } break; - case '(': - ret = reg(1, &flags); - if (ret == nullptr) - return (nullptr); - *flagp |= flags & (HASWIDTH | SPSTART); - break; - case '\0': - case '|': - case ')': - // RAISE Error, SYM(RegularExpression), SYM(Internal_Error), - printf("RegularExpression::compile(): Internal error.\n"); // Never here - return nullptr; - case '?': - case '+': - case '*': - // RAISE Error, SYM(RegularExpression), SYM(No_Operand), - printf("RegularExpression::compile(): ?+* follows nothing.\n"); - return nullptr; - case '\\': - if (*regparse == '\0') { - // RAISE Error, SYM(RegularExpression), SYM(Trailing_Backslash), - printf("RegularExpression::compile(): Trailing backslash.\n"); - return nullptr; - } - ret = regnode(EXACTLY); - regc(*regparse++); - regc('\0'); - *flagp |= HASWIDTH | SIMPLE; - break; - default: { - int len; - char ender; - - regparse--; - len = int(strcspn(regparse, META)); - if (len <= 0) { - // RAISE Error, SYM(RegularExpression), SYM(Internal_Error), - printf("RegularExpression::compile(): Internal error.\n"); - return nullptr; - } - ender = *(regparse + len); - if (len > 1 && ISMULT(ender)) - len--; // Back off clear of ?+* operand. - *flagp |= HASWIDTH; - if (len == 1) - *flagp |= SIMPLE; - ret = regnode(EXACTLY); - while (len > 0) { - regc(*regparse++); - len--; - } - regc('\0'); - } break; - } - return (ret); -} - -/* - - regnode - emit a node - Location. - */ -char* RegExpCompile::regnode(char op) -{ - char* ret; - char* ptr; - - ret = regcode; - if (ret == regdummyptr) { - regsize += 3; - return (ret); - } - - ptr = ret; - *ptr++ = op; - *ptr++ = '\0'; // Null "next" pointer. - *ptr++ = '\0'; - regcode = ptr; - - return (ret); -} - -/* - - regc - emit (if appropriate) a byte of code - */ -void RegExpCompile::regc(char b) -{ - if (regcode != regdummyptr) - *regcode++ = b; - else - regsize++; -} - -/* - - reginsert - insert an operator in front of already-emitted operand - * - * Means relocating the operand. - */ -void RegExpCompile::reginsert(char op, char* opnd) -{ - char* src; - char* dst; - char* place; - - if (regcode == regdummyptr) { - regsize += 3; - return; - } - - src = regcode; - regcode += 3; - dst = regcode; - while (src > opnd) - *--dst = *--src; - - place = opnd; // Op node, where operand used to be. - *place++ = op; - *place++ = '\0'; - *place = '\0'; -} - -/* - - regtail - set the next-pointer at the end of a node chain - */ -void RegExpCompile::regtail(char* p, const char* val) -{ - char* scan; - char* temp; - int offset; - - if (p == regdummyptr) - return; - - // Find last node. - scan = p; - for (;;) { - temp = regnext(scan); - if (temp == nullptr) - break; - scan = temp; - } - - if (OP(scan) == BACK) - offset = int(scan - val); - else - offset = int(val - scan); - *(scan + 1) = static_cast((offset >> 8) & 0377); - *(scan + 2) = static_cast(offset & 0377); -} - -/* - - regoptail - regtail on operand of first argument; nop if operandless - */ -void RegExpCompile::regoptail(char* p, const char* val) -{ - // "Operandless" and "op != BRANCH" are synonymous in practice. - if (p == nullptr || p == regdummyptr || OP(p) != BRANCH) - return; - regtail(OPERAND(p), val); -} - -//////////////////////////////////////////////////////////////////////// -// -// find and friends -// -//////////////////////////////////////////////////////////////////////// - -/* - * Utility class for RegularExpression::find(). - */ -class RegExpFind -{ -public: - const char* reginput; // String-input pointer. - const char* regbol; // Beginning of input, for ^ check. - const char** regstartp; // Pointer to startp array. - const char** regendp; // Ditto for endp. - - int regtry(const char*, const char**, const char**, const char*); - int regmatch(const char*); - int regrepeat(const char*); -}; - -// find -- Matches the regular expression to the given string. -// Returns true if found, and sets start and end indexes accordingly. -bool RegularExpression::find(char const* string, - RegularExpressionMatch& rmatch) const -{ - const char* s; - - rmatch.clear(); - rmatch.searchstring = string; - - if (!this->program) { - return false; - } - - // Check validity of program. - if (UCHARAT(this->program) != MAGIC) { - // RAISE Error, SYM(RegularExpression), SYM(Internal_Error), - printf( - "RegularExpression::find(): Compiled regular expression corrupted.\n"); - return false; - } - - // If there is a "must appear" string, look for it. - if (this->regmust != nullptr) { - s = string; - while ((s = strchr(s, this->regmust[0])) != nullptr) { - if (strncmp(s, this->regmust, this->regmlen) == 0) - break; // Found it. - s++; - } - if (s == nullptr) // Not present. - return false; - } - - RegExpFind regFind; - - // Mark beginning of line for ^ . - regFind.regbol = string; - - // Simplest case: anchored match need be tried only once. - if (this->reganch) - return ( - regFind.regtry(string, rmatch.startp, rmatch.endp, this->program) != 0); - - // Messy cases: unanchored match. - s = string; - if (this->regstart != '\0') - // We know what char it must start with. - while ((s = strchr(s, this->regstart)) != nullptr) { - if (regFind.regtry(s, rmatch.startp, rmatch.endp, this->program)) - return true; - s++; - } - else - // We don't -- general case. - do { - if (regFind.regtry(s, rmatch.startp, rmatch.endp, this->program)) - return true; - } while (*s++ != '\0'); - - // Failure. - return false; -} - -/* - - regtry - try match at specific point - 0 failure, 1 success - */ -int RegExpFind::regtry(const char* string, const char** start, - const char** end, const char* prog) -{ - int i; - const char** sp1; - const char** ep; - - reginput = string; - regstartp = start; - regendp = end; - - sp1 = start; - ep = end; - for (i = RegularExpressionMatch::NSUBEXP; i > 0; i--) { - *sp1++ = nullptr; - *ep++ = nullptr; - } - if (regmatch(prog + 1)) { - start[0] = string; - end[0] = reginput; - return (1); - } else - return (0); -} - -/* - - regmatch - main matching routine - * - * Conceptually the strategy is simple: check to see whether the current - * node matches, call self recursively to see whether the rest matches, - * and then act accordingly. In practice we make some effort to avoid - * recursion, in particular by going through "ordinary" nodes (that don't - * need to know whether the rest of the match failed) by a loop instead of - * by recursion. - * 0 failure, 1 success - */ -int RegExpFind::regmatch(const char* prog) -{ - const char* scan; // Current node. - const char* next; // Next node. - - scan = prog; - - while (scan != nullptr) { - - next = regnext(scan); - - switch (OP(scan)) { - case BOL: - if (reginput != regbol) - return (0); - break; - case EOL: - if (*reginput != '\0') - return (0); - break; - case ANY: - if (*reginput == '\0') - return (0); - reginput++; - break; - case EXACTLY: { - size_t len; - const char* opnd; - - opnd = OPERAND(scan); - // Inline the first character, for speed. - if (*opnd != *reginput) - return (0); - len = strlen(opnd); - if (len > 1 && strncmp(opnd, reginput, len) != 0) - return (0); - reginput += len; - } break; - case ANYOF: - if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == nullptr) - return (0); - reginput++; - break; - case ANYBUT: - if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != nullptr) - return (0); - reginput++; - break; - case NOTHING: - break; - case BACK: - break; - case OPEN + 1: - case OPEN + 2: - case OPEN + 3: - case OPEN + 4: - case OPEN + 5: - case OPEN + 6: - case OPEN + 7: - case OPEN + 8: - case OPEN + 9: { - int no; - const char* save; - - no = OP(scan) - OPEN; - save = reginput; - - if (regmatch(next)) { - - // - // Don't set startp if some later invocation of the - // same parentheses already has. - // - if (regstartp[no] == nullptr) - regstartp[no] = save; - return (1); - } else - return (0); - } - // break; - case CLOSE + 1: - case CLOSE + 2: - case CLOSE + 3: - case CLOSE + 4: - case CLOSE + 5: - case CLOSE + 6: - case CLOSE + 7: - case CLOSE + 8: - case CLOSE + 9: { - int no; - const char* save; - - no = OP(scan) - CLOSE; - save = reginput; - - if (regmatch(next)) { - - // - // Don't set endp if some later invocation of the - // same parentheses already has. - // - if (regendp[no] == nullptr) - regendp[no] = save; - return (1); - } else - return (0); - } - // break; - case BRANCH: { - - const char* save; - - if (OP(next) != BRANCH) // No choice. - next = OPERAND(scan); // Avoid recursion. - else { - do { - save = reginput; - if (regmatch(OPERAND(scan))) - return (1); - reginput = save; - scan = regnext(scan); - } while (scan != nullptr && OP(scan) == BRANCH); - return (0); - // NOTREACHED - } - } break; - case STAR: - case PLUS: { - char nextch; - int no; - const char* save; - int min_no; - - // - // Lookahead to avoid useless match attempts when we know - // what character comes next. - // - nextch = '\0'; - if (OP(next) == EXACTLY) - nextch = *OPERAND(next); - min_no = (OP(scan) == STAR) ? 0 : 1; - save = reginput; - no = regrepeat(OPERAND(scan)); - while (no >= min_no) { - // If it could work, try it. - if (nextch == '\0' || *reginput == nextch) - if (regmatch(next)) - return (1); - // Couldn't or didn't -- back up. - no--; - reginput = save + no; - } - return (0); - } - // break; - case END: - return (1); // Success! - - default: - // RAISE Error, SYM(RegularExpression), SYM(Internal_Error), - printf( - "RegularExpression::find(): Internal error -- memory corrupted.\n"); - return 0; - } - scan = next; - } - - // - // We get here only if there's trouble -- normally "case END" is the - // terminating point. - // - // RAISE Error, SYM(RegularExpression), SYM(Internal_Error), - printf("RegularExpression::find(): Internal error -- corrupted pointers.\n"); - return (0); -} - -/* - - regrepeat - repeatedly match something simple, report how many - */ -int RegExpFind::regrepeat(const char* p) -{ - int count = 0; - const char* scan; - const char* opnd; - - scan = reginput; - opnd = OPERAND(p); - switch (OP(p)) { - case ANY: - count = int(strlen(scan)); - scan += count; - break; - case EXACTLY: - while (*opnd == *scan) { - count++; - scan++; - } - break; - case ANYOF: - while (*scan != '\0' && strchr(opnd, *scan) != nullptr) { - count++; - scan++; - } - break; - case ANYBUT: - while (*scan != '\0' && strchr(opnd, *scan) == nullptr) { - count++; - scan++; - } - break; - default: // Oh dear. Called inappropriately. - // RAISE Error, SYM(RegularExpression), SYM(Internal_Error), - printf("cm RegularExpression::find(): Internal error.\n"); - return 0; - } - reginput = scan; - return (count); -} - -/* - - regnext - dig the "next" pointer out of a node - */ -static const char* regnext(const char* p) -{ - int offset; - - if (p == regdummyptr) - return (nullptr); - - offset = NEXT(p); - if (offset == 0) - return (nullptr); - - if (OP(p) == BACK) - return (p - offset); - else - return (p + offset); -} - -static char* regnext(char* p) -{ - int offset; - - if (p == regdummyptr) - return (nullptr); - - offset = NEXT(p); - if (offset == 0) - return (nullptr); - - if (OP(p) == BACK) - return (p - offset); - else - return (p + offset); -} - -} // namespace KWSYS_NAMESPACE diff --git a/test/API/driver/kwsys/RegularExpression.hxx.in b/test/API/driver/kwsys/RegularExpression.hxx.in deleted file mode 100644 index 0c2366b..0000000 --- a/test/API/driver/kwsys/RegularExpression.hxx.in +++ /dev/null @@ -1,562 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -// Original Copyright notice: -// Copyright (C) 1991 Texas Instruments Incorporated. -// -// Permission is granted to any individual or institution to use, copy, modify, -// and distribute this software, provided that this complete copyright and -// permission notice is maintained, intact, in all copies and supporting -// documentation. -// -// Texas Instruments Incorporated provides this software "as is" without -// express or implied warranty. -// -// Created: MNF 06/13/89 Initial Design and Implementation -// Updated: LGO 08/09/89 Inherit from Generic -// Updated: MBN 09/07/89 Added conditional exception handling -// Updated: MBN 12/15/89 Sprinkled "const" qualifiers all over the place! -// Updated: DLS 03/22/91 New lite version -// - -#ifndef @KWSYS_NAMESPACE@_RegularExpression_hxx -#define @KWSYS_NAMESPACE@_RegularExpression_hxx - -#include <@KWSYS_NAMESPACE@/Configure.h> -#include <@KWSYS_NAMESPACE@/Configure.hxx> - -#include - -/* Disable useless Borland warnings. KWSys tries not to force things - on its includers, but there is no choice here. */ -#if defined(__BORLANDC__) -# pragma warn - 8027 /* function not inlined. */ -#endif - -namespace @KWSYS_NAMESPACE@ { - -// Forward declaration -class RegularExpression; - -/** \class RegularExpressionMatch - * \brief Stores the pattern matches of a RegularExpression - */ -class @KWSYS_NAMESPACE@_EXPORT RegularExpressionMatch -{ -public: - RegularExpressionMatch(); - - bool isValid() const; - void clear(); - - std::string::size_type start() const; - std::string::size_type end() const; - std::string::size_type start(int n) const; - std::string::size_type end(int n) const; - std::string match(int n) const; - - enum - { - NSUBEXP = 10 - }; - -private: - friend class RegularExpression; - const char* startp[NSUBEXP]; - const char* endp[NSUBEXP]; - const char* searchstring; -}; - -/** - * \brief Creates an invalid match object - */ -inline RegularExpressionMatch::RegularExpressionMatch() - : startp{} - , endp{} - , searchstring{} -{ -} - -/** - * \brief Returns true if the match pointers are valid - */ -inline bool RegularExpressionMatch::isValid() const -{ - return (this->startp[0] != nullptr); -} - -/** - * \brief Resets to the (invalid) construction state. - */ -inline void RegularExpressionMatch::clear() -{ - startp[0] = nullptr; - endp[0] = nullptr; - searchstring = nullptr; -} - -/** - * \brief Returns the start index of the full match. - */ -inline std::string::size_type RegularExpressionMatch::start() const -{ - return static_cast(this->startp[0] - searchstring); -} - -/** - * \brief Returns the end index of the full match. - */ -inline std::string::size_type RegularExpressionMatch::end() const -{ - return static_cast(this->endp[0] - searchstring); -} - -/** - * \brief Returns the start index of nth submatch. - * start(0) is the start of the full match. - */ -inline std::string::size_type RegularExpressionMatch::start(int n) const -{ - return static_cast(this->startp[n] - - this->searchstring); -} - -/** - * \brief Returns the end index of nth submatch. - * end(0) is the end of the full match. - */ -inline std::string::size_type RegularExpressionMatch::end(int n) const -{ - return static_cast(this->endp[n] - - this->searchstring); -} - -/** - * \brief Returns the nth submatch as a string. - */ -inline std::string RegularExpressionMatch::match(int n) const -{ - if (this->startp[n] == nullptr) { - return std::string(); - } else { - return std::string( - this->startp[n], - static_cast(this->endp[n] - this->startp[n])); - } -} - -/** \class RegularExpression - * \brief Implements pattern matching with regular expressions. - * - * This is the header file for the regular expression class. An object of - * this class contains a regular expression, in a special "compiled" format. - * This compiled format consists of several slots all kept as the objects - * private data. The RegularExpression class provides a convenient way to - * represent regular expressions. It makes it easy to search for the same - * regular expression in many different strings without having to compile a - * string to regular expression format more than necessary. - * - * This class implements pattern matching via regular expressions. - * A regular expression allows a programmer to specify complex - * patterns that can be searched for and matched against the - * character string of a string object. In its simplest form, a - * regular expression is a sequence of characters used to - * search for exact character matches. However, many times the - * exact sequence to be found is not known, or only a match at - * the beginning or end of a string is desired. The RegularExpression regu- - * lar expression class implements regular expression pattern - * matching as is found and implemented in many UNIX commands - * and utilities. - * - * Example: The perl code - * - * $filename =~ m"([a-z]+)\.cc"; - * print $1; - * - * Is written as follows in C++ - * - * RegularExpression re("([a-z]+)\\.cc"); - * re.find(filename); - * cerr << re.match(1); - * - * - * The regular expression class provides a convenient mechanism - * for specifying and manipulating regular expressions. The - * regular expression object allows specification of such pat- - * terns by using the following regular expression metacharac- - * ters: - * - * ^ Matches at beginning of a line - * - * $ Matches at end of a line - * - * . Matches any single character - * - * [ ] Matches any character(s) inside the brackets - * - * [^ ] Matches any character(s) not inside the brackets - * - * - Matches any character in range on either side of a dash - * - * * Matches preceding pattern zero or more times - * - * + Matches preceding pattern one or more times - * - * ? Matches preceding pattern zero or once only - * - * () Saves a matched expression and uses it in a later match - * - * Note that more than one of these metacharacters can be used - * in a single regular expression in order to create complex - * search patterns. For example, the pattern [^ab1-9] says to - * match any character sequence that does not begin with the - * characters "ab" followed by numbers in the series one - * through nine. - * - * There are three constructors for RegularExpression. One just creates an - * empty RegularExpression object. Another creates a RegularExpression - * object and initializes it with a regular expression that is given in the - * form of a char*. The third takes a reference to a RegularExpression - * object as an argument and creates an object initialized with the - * information from the given RegularExpression object. - * - * The find member function finds the first occurrence of the regular - * expression of that object in the string given to find as an argument. Find - * returns a boolean, and if true, mutates the private data appropriately. - * Find sets pointers to the beginning and end of the thing last found, they - * are pointers into the actual string that was searched. The start and end - * member functions return indices into the searched string that correspond - * to the beginning and end pointers respectively. The compile member - * function takes a char* and puts the compiled version of the char* argument - * into the object's private data fields. The == and != operators only check - * the to see if the compiled regular expression is the same, and the - * deep_equal functions also checks to see if the start and end pointers are - * the same. The is_valid function returns false if program is set to - * nullptr, (i.e. there is no valid compiled expression). The set_invalid - * function sets the program to nullptr (Warning: this deletes the compiled - * expression). The following examples may help clarify regular expression - * usage: - * - * * The regular expression "^hello" matches a "hello" only at the - * beginning of a line. It would match "hello there" but not "hi, - * hello there". - * - * * The regular expression "long$" matches a "long" only at the end - * of a line. It would match "so long\0", but not "long ago". - * - * * The regular expression "t..t..g" will match anything that has a - * "t" then any two characters, another "t", any two characters and - * then a "g". It will match "testing", or "test again" but would - * not match "toasting" - * - * * The regular expression "[1-9ab]" matches any number one through - * nine, and the characters "a" and "b". It would match "hello 1" - * or "begin", but would not match "no-match". - * - * * The regular expression "[^1-9ab]" matches any character that is - * not a number one through nine, or an "a" or "b". It would NOT - * match "hello 1" or "begin", but would match "no-match". - * - * * The regular expression "br* " matches something that begins with - * a "b", is followed by zero or more "r"s, and ends in a space. It - * would match "brrrrr ", and "b ", but would not match "brrh ". - * - * * The regular expression "br+ " matches something that begins with - * a "b", is followed by one or more "r"s, and ends in a space. It - * would match "brrrrr ", and "br ", but would not match "b " or - * "brrh ". - * - * * The regular expression "br? " matches something that begins with - * a "b", is followed by zero or one "r"s, and ends in a space. It - * would match "br ", and "b ", but would not match "brrrr " or - * "brrh ". - * - * * The regular expression "(..p)b" matches something ending with pb - * and beginning with whatever the two characters before the first p - * encountered in the line were. It would find "repb" in "rep drepa - * qrepb". The regular expression "(..p)a" would find "repa qrepb" - * in "rep drepa qrepb" - * - * * The regular expression "d(..p)" matches something ending with p, - * beginning with d, and having two characters in between that are - * the same as the two characters before the first p encountered in - * the line. It would match "drepa qrepb" in "rep drepa qrepb". - * - * All methods of RegularExpression can be called simultaneously from - * different threads but only if each invocation uses an own instance of - * RegularExpression. - */ -class @KWSYS_NAMESPACE@_EXPORT RegularExpression -{ -public: - /** - * Instantiate RegularExpression with program=nullptr. - */ - inline RegularExpression(); - - /** - * Instantiate RegularExpression with compiled char*. - */ - inline RegularExpression(char const*); - - /** - * Instantiate RegularExpression as a copy of another regular expression. - */ - RegularExpression(RegularExpression const&); - - /** - * Instantiate RegularExpression with compiled string. - */ - inline RegularExpression(std::string const&); - - /** - * Destructor. - */ - inline ~RegularExpression(); - - /** - * Compile a regular expression into internal code - * for later pattern matching. - */ - bool compile(char const*); - - /** - * Compile a regular expression into internal code - * for later pattern matching. - */ - inline bool compile(std::string const&); - - /** - * Matches the regular expression to the given string. - * Returns true if found, and sets start and end indexes - * in the RegularExpressionMatch instance accordingly. - * - * This method is thread safe when called with different - * RegularExpressionMatch instances. - */ - bool find(char const*, RegularExpressionMatch&) const; - - /** - * Matches the regular expression to the given string. - * Returns true if found, and sets start and end indexes accordingly. - */ - inline bool find(char const*); - - /** - * Matches the regular expression to the given std string. - * Returns true if found, and sets start and end indexes accordingly. - */ - inline bool find(std::string const&); - - /** - * Match indices - */ - inline RegularExpressionMatch const& regMatch() const; - inline std::string::size_type start() const; - inline std::string::size_type end() const; - inline std::string::size_type start(int n) const; - inline std::string::size_type end(int n) const; - - /** - * Match strings - */ - inline std::string match(int n) const; - - /** - * Copy the given regular expression. - */ - RegularExpression& operator=(const RegularExpression& rxp); - - /** - * Returns true if two regular expressions have the same - * compiled program for pattern matching. - */ - bool operator==(RegularExpression const&) const; - - /** - * Returns true if two regular expressions have different - * compiled program for pattern matching. - */ - inline bool operator!=(RegularExpression const&) const; - - /** - * Returns true if have the same compiled regular expressions - * and the same start and end pointers. - */ - bool deep_equal(RegularExpression const&) const; - - /** - * True if the compiled regexp is valid. - */ - inline bool is_valid() const; - - /** - * Marks the regular expression as invalid. - */ - inline void set_invalid(); - -private: - RegularExpressionMatch regmatch; - char regstart; // Internal use only - char reganch; // Internal use only - const char* regmust; // Internal use only - std::string::size_type regmlen; // Internal use only - char* program; - int progsize; -}; - -/** - * Create an empty regular expression. - */ -inline RegularExpression::RegularExpression() - : regstart{} - , reganch{} - , regmust{} - , program{ nullptr } - , progsize{} -{ -} - -/** - * Creates a regular expression from string s, and - * compiles s. - */ -inline RegularExpression::RegularExpression(const char* s) - : regstart{} - , reganch{} - , regmust{} - , program{ nullptr } - , progsize{} -{ - if (s) { - this->compile(s); - } -} - -/** - * Creates a regular expression from string s, and - * compiles s. - */ -inline RegularExpression::RegularExpression(const std::string& s) - : regstart{} - , reganch{} - , regmust{} - , program{ nullptr } - , progsize{} -{ - this->compile(s); -} - -/** - * Destroys and frees space allocated for the regular expression. - */ -inline RegularExpression::~RegularExpression() -{ - //#ifndef _WIN32 - delete[] this->program; - //#endif -} - -/** - * Compile a regular expression into internal code - * for later pattern matching. - */ -inline bool RegularExpression::compile(std::string const& s) -{ - return this->compile(s.c_str()); -} - -/** - * Matches the regular expression to the given std string. - * Returns true if found, and sets start and end indexes accordingly. - */ -inline bool RegularExpression::find(const char* s) -{ - return this->find(s, this->regmatch); -} - -/** - * Matches the regular expression to the given std string. - * Returns true if found, and sets start and end indexes accordingly. - */ -inline bool RegularExpression::find(std::string const& s) -{ - return this->find(s.c_str()); -} - -/** - * Returns the internal match object - */ -inline RegularExpressionMatch const& RegularExpression::regMatch() const -{ - return this->regmatch; -} - -/** - * Returns the start index of the full match. - */ -inline std::string::size_type RegularExpression::start() const -{ - return regmatch.start(); -} - -/** - * Returns the end index of the full match. - */ -inline std::string::size_type RegularExpression::end() const -{ - return regmatch.end(); -} - -/** - * Return start index of nth submatch. start(0) is the start of the full match. - */ -inline std::string::size_type RegularExpression::start(int n) const -{ - return regmatch.start(n); -} - -/** - * Return end index of nth submatch. end(0) is the end of the full match. - */ -inline std::string::size_type RegularExpression::end(int n) const -{ - return regmatch.end(n); -} - -/** - * Return nth submatch as a string. - */ -inline std::string RegularExpression::match(int n) const -{ - return regmatch.match(n); -} - -/** - * Returns true if two regular expressions have different - * compiled program for pattern matching. - */ -inline bool RegularExpression::operator!=(const RegularExpression& r) const -{ - return (!(*this == r)); -} - -/** - * Returns true if a valid regular expression is compiled - * and ready for pattern matching. - */ -inline bool RegularExpression::is_valid() const -{ - return (this->program != nullptr); -} - -inline void RegularExpression::set_invalid() -{ - //#ifndef _WIN32 - delete[] this->program; - //#endif - this->program = nullptr; -} - -} // namespace @KWSYS_NAMESPACE@ - -#endif diff --git a/test/API/driver/kwsys/SetupForDevelopment.sh b/test/API/driver/kwsys/SetupForDevelopment.sh deleted file mode 100644 index c3a2b16..0000000 --- a/test/API/driver/kwsys/SetupForDevelopment.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash - -cd "${BASH_SOURCE%/*}" && -GitSetup/setup-user && echo && -GitSetup/setup-hooks && echo && -GitSetup/setup-aliases && echo && -GitSetup/setup-upstream && echo && -GitSetup/tips - -# Rebase master by default -git config rebase.stat true -git config branch.master.rebase true - -# Disable Gerrit hook explicitly so the commit-msg hook will -# not complain even if some gerrit remotes are still configured. -git config hooks.GerritId false - -# Record the version of this setup so Scripts/pre-commit can check it. -SetupForDevelopment_VERSION=2 -git config hooks.SetupForDevelopment ${SetupForDevelopment_VERSION} diff --git a/test/API/driver/kwsys/SharedForward.h.in b/test/API/driver/kwsys/SharedForward.h.in deleted file mode 100644 index 5716cd4..0000000 --- a/test/API/driver/kwsys/SharedForward.h.in +++ /dev/null @@ -1,879 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifndef @KWSYS_NAMESPACE@_SharedForward_h -# define @KWSYS_NAMESPACE@_SharedForward_h - -/* - This header is used to create a forwarding executable sets up the - shared library search path and replaces itself with a real - executable. This is useful when creating installations on UNIX with - shared libraries that will run from any install directory. Typical - usage: - - #if defined(CMAKE_INTDIR) - # define CONFIG_DIR_PRE CMAKE_INTDIR "/" - # define CONFIG_DIR_POST "/" CMAKE_INTDIR - #else - # define CONFIG_DIR_PRE "" - # define CONFIG_DIR_POST "" - #endif - #define @KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD "/path/to/foo-build/bin" - #define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD "." CONFIG_DIR_POST - #define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL "../lib/foo-1.2" - #define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD CONFIG_DIR_PRE "foo-real" - #define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL - "../lib/foo-1.2/foo-real" - #define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_COMMAND "--command" - #define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_PRINT "--print" - #define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_LDD "--ldd" - #if defined(CMAKE_INTDIR) - # define @KWSYS_NAMESPACE@_SHARED_FORWARD_CONFIG_NAME CMAKE_INTDIR - #endif - #include <@KWSYS_NAMESPACE@/SharedForward.h> - int main(int argc, char** argv) - { - return @KWSYS_NAMESPACE@_shared_forward_to_real(argc, argv); - } - - Specify search and executable paths relative to the forwarding - executable location or as full paths. Include no trailing slash. - In the case of a multi-configuration build, when CMAKE_INTDIR is - defined, the DIR_BUILD setting should point at the directory above - the executable (the one containing the per-configuration - subdirectory specified by CMAKE_INTDIR). Then PATH_BUILD entries - and EXE_BUILD should be specified relative to this location and use - CMAKE_INTDIR as necessary. In the above example imagine appending - the PATH_BUILD or EXE_BUILD setting to the DIR_BUILD setting. The - result should form a valid path with per-configuration subdirectory. - - Additional paths may be specified in the PATH_BUILD and PATH_INSTALL - variables by using comma-separated strings. For example: - - #define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD \ - "." CONFIG_DIR_POST, "/path/to/bar-build" CONFIG_DIR_POST - #define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL \ - "../lib/foo-1.2", "../lib/bar-4.5" - - See the comments below for specific explanations of each macro. -*/ - -/* Disable -Wcast-qual warnings since they are too hard to fix in a - cross-platform way. */ -# if defined(__clang__) && defined(__has_warning) -# if __has_warning("-Wcast-qual") -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wcast-qual" -# endif -# endif - -# if defined(__BORLANDC__) && !defined(__cplusplus) -/* Code has no effect; raised by winnt.h in C (not C++) when ignoring an - unused parameter using "(param)" syntax (i.e. no cast to void). */ -# pragma warn - 8019 -# endif - -/* Full path to the directory in which this executable is built. Do - not include a trailing slash. */ -# if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD) -# error "Must define @KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD" -# endif -# if !defined(KWSYS_SHARED_FORWARD_DIR_BUILD) -# define KWSYS_SHARED_FORWARD_DIR_BUILD \ - @KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD -# endif - -/* Library search path for build tree. */ -# if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD) -# error "Must define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD" -# endif -# if !defined(KWSYS_SHARED_FORWARD_PATH_BUILD) -# define KWSYS_SHARED_FORWARD_PATH_BUILD \ - @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD -# endif - -/* Library search path for install tree. */ -# if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL) -# error "Must define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL" -# endif -# if !defined(KWSYS_SHARED_FORWARD_PATH_INSTALL) -# define KWSYS_SHARED_FORWARD_PATH_INSTALL \ - @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL -# endif - -/* The real executable to which to forward in the build tree. */ -# if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD) -# error "Must define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD" -# endif -# if !defined(KWSYS_SHARED_FORWARD_EXE_BUILD) -# define KWSYS_SHARED_FORWARD_EXE_BUILD \ - @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD -# endif - -/* The real executable to which to forward in the install tree. */ -# if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL) -# error "Must define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL" -# endif -# if !defined(KWSYS_SHARED_FORWARD_EXE_INSTALL) -# define KWSYS_SHARED_FORWARD_EXE_INSTALL \ - @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL -# endif - -/* The configuration name with which this executable was built (Debug/Release). - */ -# if defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_CONFIG_NAME) -# define KWSYS_SHARED_FORWARD_CONFIG_NAME \ - @KWSYS_NAMESPACE@_SHARED_FORWARD_CONFIG_NAME -# else -# undef KWSYS_SHARED_FORWARD_CONFIG_NAME -# endif - -/* Create command line option to replace executable. */ -# if defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_COMMAND) -# if !defined(KWSYS_SHARED_FORWARD_OPTION_COMMAND) -# define KWSYS_SHARED_FORWARD_OPTION_COMMAND \ - @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_COMMAND -# endif -# else -# undef KWSYS_SHARED_FORWARD_OPTION_COMMAND -# endif - -/* Create command line option to print environment setting and exit. */ -# if defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_PRINT) -# if !defined(KWSYS_SHARED_FORWARD_OPTION_PRINT) -# define KWSYS_SHARED_FORWARD_OPTION_PRINT \ - @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_PRINT -# endif -# else -# undef KWSYS_SHARED_FORWARD_OPTION_PRINT -# endif - -/* Create command line option to run ldd or equivalent. */ -# if defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_LDD) -# if !defined(KWSYS_SHARED_FORWARD_OPTION_LDD) -# define KWSYS_SHARED_FORWARD_OPTION_LDD \ - @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_LDD -# endif -# else -# undef KWSYS_SHARED_FORWARD_OPTION_LDD -# endif - -/* Include needed system headers. */ - -# include -# include -# include /* size_t */ -# include -# include -# include - -# if defined(_WIN32) && !defined(__CYGWIN__) -# include - -# include -# include -# define KWSYS_SHARED_FORWARD_ESCAPE_ARGV /* re-escape argv for execvp */ -# else -# include -# include -# endif - -/* Configuration for this platform. */ - -/* The path separator for this platform. */ -# if defined(_WIN32) && !defined(__CYGWIN__) -# define KWSYS_SHARED_FORWARD_PATH_SEP ';' -# define KWSYS_SHARED_FORWARD_PATH_SLASH '\\' -# else -# define KWSYS_SHARED_FORWARD_PATH_SEP ':' -# define KWSYS_SHARED_FORWARD_PATH_SLASH '/' -# endif -static const char kwsys_shared_forward_path_sep[2] = { - KWSYS_SHARED_FORWARD_PATH_SEP, 0 -}; -static const char kwsys_shared_forward_path_slash[2] = { - KWSYS_SHARED_FORWARD_PATH_SLASH, 0 -}; - -/* The maximum length of a file name. */ -# if defined(PATH_MAX) -# define KWSYS_SHARED_FORWARD_MAXPATH PATH_MAX -# elif defined(MAXPATHLEN) -# define KWSYS_SHARED_FORWARD_MAXPATH MAXPATHLEN -# else -# define KWSYS_SHARED_FORWARD_MAXPATH 16384 -# endif - -/* Select the environment variable holding the shared library runtime - search path for this platform and build configuration. Also select - ldd command equivalent. */ - -/* Linux */ -# if defined(__linux) -# define KWSYS_SHARED_FORWARD_LDD "ldd" -# define KWSYS_SHARED_FORWARD_LDD_N 1 -# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" - -/* FreeBSD */ -# elif defined(__FreeBSD__) -# define KWSYS_SHARED_FORWARD_LDD "ldd" -# define KWSYS_SHARED_FORWARD_LDD_N 1 -# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" - -/* OpenBSD */ -# elif defined(__OpenBSD__) -# define KWSYS_SHARED_FORWARD_LDD "ldd" -# define KWSYS_SHARED_FORWARD_LDD_N 1 -# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" - -/* OS X */ -# elif defined(__APPLE__) -# define KWSYS_SHARED_FORWARD_LDD "otool", "-L" -# define KWSYS_SHARED_FORWARD_LDD_N 2 -# define KWSYS_SHARED_FORWARD_LDPATH "DYLD_LIBRARY_PATH" - -/* AIX */ -# elif defined(_AIX) -# define KWSYS_SHARED_FORWARD_LDD "dump", "-H" -# define KWSYS_SHARED_FORWARD_LDD_N 2 -# define KWSYS_SHARED_FORWARD_LDPATH "LIBPATH" - -/* SUN */ -# elif defined(__sun) -# define KWSYS_SHARED_FORWARD_LDD "ldd" -# define KWSYS_SHARED_FORWARD_LDD_N 1 -# include -# if defined(_ILP32) -# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" -# elif defined(_LP64) -# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH_64" -# endif - -/* HP-UX */ -# elif defined(__hpux) -# define KWSYS_SHARED_FORWARD_LDD "chatr" -# define KWSYS_SHARED_FORWARD_LDD_N 1 -# if defined(__LP64__) -# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" -# else -# define KWSYS_SHARED_FORWARD_LDPATH "SHLIB_PATH" -# endif - -/* SGI MIPS */ -# elif defined(__sgi) && defined(_MIPS_SIM) -# define KWSYS_SHARED_FORWARD_LDD "ldd" -# define KWSYS_SHARED_FORWARD_LDD_N 1 -# if _MIPS_SIM == _ABIO32 -# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" -# elif _MIPS_SIM == _ABIN32 -# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARYN32_PATH" -# elif _MIPS_SIM == _ABI64 -# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY64_PATH" -# endif - -/* Cygwin */ -# elif defined(__CYGWIN__) -# define KWSYS_SHARED_FORWARD_LDD \ - "cygcheck" /* TODO: cygwin 1.7 has ldd \ - */ -# define KWSYS_SHARED_FORWARD_LDD_N 1 -# define KWSYS_SHARED_FORWARD_LDPATH "PATH" - -/* Windows */ -# elif defined(_WIN32) -# define KWSYS_SHARED_FORWARD_LDPATH "PATH" - -/* Guess on this unknown system. */ -# else -# define KWSYS_SHARED_FORWARD_LDD "ldd" -# define KWSYS_SHARED_FORWARD_LDD_N 1 -# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" -# endif - -# ifdef KWSYS_SHARED_FORWARD_ESCAPE_ARGV -typedef struct kwsys_sf_arg_info_s -{ - const char* arg; - int size; - int quote; -} kwsys_sf_arg_info; - -static kwsys_sf_arg_info kwsys_sf_get_arg_info(const char* in) -{ - /* Initialize information. */ - kwsys_sf_arg_info info; - - /* String iterator. */ - const char* c; - - /* Keep track of how many backslashes have been encountered in a row. */ - int windows_backslashes = 0; - - /* Start with the length of the original argument, plus one for - either a terminating null or a separating space. */ - info.arg = in; - info.size = (int)strlen(in) + 1; - info.quote = 0; - - /* Scan the string for characters that require escaping or quoting. */ - for (c = in; *c; ++c) { - /* Check whether this character needs quotes. */ - if (strchr(" \t?'#&<>|^", *c)) { - info.quote = 1; - } - - /* On Windows only backslashes and double-quotes need escaping. */ - if (*c == '\\') { - /* Found a backslash. It may need to be escaped later. */ - ++windows_backslashes; - } else if (*c == '"') { - /* Found a double-quote. We need to escape it and all - immediately preceding backslashes. */ - info.size += windows_backslashes + 1; - windows_backslashes = 0; - } else { - /* Found another character. This eliminates the possibility - that any immediately preceding backslashes will be - escaped. */ - windows_backslashes = 0; - } - } - - /* Check whether the argument needs surrounding quotes. */ - if (info.quote) { - /* Surrounding quotes are needed. Allocate space for them. */ - info.size += 2; - - /* We must escape all ending backslashes when quoting on windows. */ - info.size += windows_backslashes; - } - - return info; -} - -static char* kwsys_sf_get_arg(kwsys_sf_arg_info info, char* out) -{ - /* String iterator. */ - const char* c; - - /* Keep track of how many backslashes have been encountered in a row. */ - int windows_backslashes = 0; - - /* Whether the argument must be quoted. */ - if (info.quote) { - /* Add the opening quote for this argument. */ - *out++ = '"'; - } - - /* Scan the string for characters that require escaping or quoting. */ - for (c = info.arg; *c; ++c) { - /* On Windows only backslashes and double-quotes need escaping. */ - if (*c == '\\') { - /* Found a backslash. It may need to be escaped later. */ - ++windows_backslashes; - } else if (*c == '"') { - /* Found a double-quote. Escape all immediately preceding - backslashes. */ - while (windows_backslashes > 0) { - --windows_backslashes; - *out++ = '\\'; - } - - /* Add the backslash to escape the double-quote. */ - *out++ = '\\'; - } else { - /* We encountered a normal character. This eliminates any - escaping needed for preceding backslashes. */ - windows_backslashes = 0; - } - - /* Store this character. */ - *out++ = *c; - } - - if (info.quote) { - /* Add enough backslashes to escape any trailing ones. */ - while (windows_backslashes > 0) { - --windows_backslashes; - *out++ = '\\'; - } - - /* Add the closing quote for this argument. */ - *out++ = '"'; - } - - /* Store a terminating null without incrementing. */ - *out = 0; - - return out; -} -# endif - -/* Function to convert a logical or relative path to a physical full path. */ -static int kwsys_shared_forward_realpath(const char* in_path, char* out_path) -{ -# if defined(_WIN32) && !defined(__CYGWIN__) - /* Implementation for Windows. */ - DWORD n = - GetFullPathNameA(in_path, KWSYS_SHARED_FORWARD_MAXPATH, out_path, 0); - return n > 0 && n <= KWSYS_SHARED_FORWARD_MAXPATH; -# else - /* Implementation for UNIX. */ - return realpath(in_path, out_path) != 0; -# endif -} - -static int kwsys_shared_forward_samepath(const char* file1, const char* file2) -{ -# if defined(_WIN32) - int result = 0; - HANDLE h1 = CreateFileA(file1, GENERIC_READ, FILE_SHARE_READ, NULL, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - HANDLE h2 = CreateFileA(file2, GENERIC_READ, FILE_SHARE_READ, NULL, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (h1 != INVALID_HANDLE_VALUE && h2 != INVALID_HANDLE_VALUE) { - BY_HANDLE_FILE_INFORMATION fi1; - BY_HANDLE_FILE_INFORMATION fi2; - GetFileInformationByHandle(h1, &fi1); - GetFileInformationByHandle(h2, &fi2); - result = (fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber && - fi1.nFileIndexHigh == fi2.nFileIndexHigh && - fi1.nFileIndexLow == fi2.nFileIndexLow); - } - CloseHandle(h1); - CloseHandle(h2); - return result; -# else - struct stat fs1, fs2; - return (stat(file1, &fs1) == 0 && stat(file2, &fs2) == 0 && - memcmp(&fs2.st_dev, &fs1.st_dev, sizeof(fs1.st_dev)) == 0 && - memcmp(&fs2.st_ino, &fs1.st_ino, sizeof(fs1.st_ino)) == 0 && - fs2.st_size == fs1.st_size); -# endif -} - -/* Function to report a system error message. */ -static void kwsys_shared_forward_strerror(char* message) -{ -# if defined(_WIN32) && !defined(__CYGWIN__) - /* Implementation for Windows. */ - DWORD original = GetLastError(); - DWORD length = - FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - 0, original, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - message, KWSYS_SHARED_FORWARD_MAXPATH, 0); - if (length < 1 || length > KWSYS_SHARED_FORWARD_MAXPATH) { - /* FormatMessage failed. Use a default message. */ - _snprintf(message, KWSYS_SHARED_FORWARD_MAXPATH, - "Error 0x%X (FormatMessage failed with error 0x%X)", original, - GetLastError()); - } -# else - /* Implementation for UNIX. */ - strcpy(message, strerror(errno)); -# endif -} - -/* Functions to execute a child process. */ -static void kwsys_shared_forward_execvp(const char* cmd, - char const* const* argv) -{ -# ifdef KWSYS_SHARED_FORWARD_ESCAPE_ARGV - /* Count the number of arguments. */ - int argc = 0; - { - char const* const* argvc; - for (argvc = argv; *argvc; ++argvc, ++argc) { - } - } - - /* Create the escaped arguments. */ - { - char** nargv = (char**)malloc((argc + 1) * sizeof(char*)); - int i; - for (i = 0; i < argc; ++i) { - kwsys_sf_arg_info info = kwsys_sf_get_arg_info(argv[i]); - nargv[i] = (char*)malloc(info.size); - kwsys_sf_get_arg(info, nargv[i]); - } - nargv[argc] = 0; - - /* Replace the command line to be used. */ - argv = (char const* const*)nargv; - } -# endif - -/* Invoke the child process. */ -# if defined(_MSC_VER) - _execvp(cmd, argv); -# elif defined(__MINGW32__) && !defined(__MINGW64__) - execvp(cmd, argv); -# else - execvp(cmd, (char* const*)argv); -# endif -} - -/* Function to get the directory containing the given file or directory. */ -static void kwsys_shared_forward_dirname(const char* begin, char* result) -{ - /* Find the location of the last slash. */ - int last_slash_index = -1; - const char* end = begin + strlen(begin); - for (; begin <= end && last_slash_index < 0; --end) { - if (*end == '/' || *end == '\\') { - last_slash_index = (int)(end - begin); - } - } - - /* Handle each case of the index of the last slash. */ - if (last_slash_index < 0) { - /* No slashes. */ - strcpy(result, "."); - } else if (last_slash_index == 0) { - /* Only one leading slash. */ - strcpy(result, kwsys_shared_forward_path_slash); - } -# if defined(_WIN32) - else if (last_slash_index == 2 && begin[1] == ':') { - /* Only one leading drive letter and slash. */ - strncpy(result, begin, (size_t)last_slash_index); - result[last_slash_index] = KWSYS_SHARED_FORWARD_PATH_SLASH; - result[last_slash_index + 1] = 0; - } -# endif - else { - /* A non-leading slash. */ - strncpy(result, begin, (size_t)last_slash_index); - result[last_slash_index] = 0; - } -} - -/* Function to check if a file exists and is executable. */ -static int kwsys_shared_forward_is_executable(const char* f) -{ -# if defined(_MSC_VER) -# define KWSYS_SHARED_FORWARD_ACCESS _access -# else -# define KWSYS_SHARED_FORWARD_ACCESS access -# endif -# if defined(X_OK) -# define KWSYS_SHARED_FORWARD_ACCESS_OK X_OK -# else -# define KWSYS_SHARED_FORWARD_ACCESS_OK 04 -# endif - if (KWSYS_SHARED_FORWARD_ACCESS(f, KWSYS_SHARED_FORWARD_ACCESS_OK) == 0) { - return 1; - } else { - return 0; - } -} - -/* Function to locate the executable currently running. */ -static int kwsys_shared_forward_self_path(const char* argv0, char* result) -{ - /* Check whether argv0 has a slash. */ - int has_slash = 0; - const char* p = argv0; - for (; *p && !has_slash; ++p) { - if (*p == '/' || *p == '\\') { - has_slash = 1; - } - } - - if (has_slash) { - /* There is a slash. Use the dirname of the given location. */ - kwsys_shared_forward_dirname(argv0, result); - return 1; - } else { - /* There is no slash. Search the PATH for the executable. */ - const char* path = getenv("PATH"); - const char* begin = path; - const char* end = begin + (begin ? strlen(begin) : 0); - const char* first = begin; - while (first != end) { - /* Store the end of this path entry. */ - const char* last; - - /* Skip all path separators. */ - for (; *first && *first == KWSYS_SHARED_FORWARD_PATH_SEP; ++first) - ; - - /* Find the next separator. */ - for (last = first; *last && *last != KWSYS_SHARED_FORWARD_PATH_SEP; - ++last) - ; - - /* If we got a non-empty directory, look for the executable there. */ - if (first < last) { - /* Determine the length without trailing slash. */ - size_t length = (size_t)(last - first); - if (*(last - 1) == '/' || *(last - 1) == '\\') { - --length; - } - - /* Construct the name of the executable in this location. */ - strncpy(result, first, length); - result[length] = KWSYS_SHARED_FORWARD_PATH_SLASH; - strcpy(result + (length) + 1, argv0); - - /* Check if it exists and is executable. */ - if (kwsys_shared_forward_is_executable(result)) { - /* Found it. */ - result[length] = 0; - return 1; - } - } - - /* Move to the next directory in the path. */ - first = last; - } - } - - /* We could not find the executable. */ - return 0; -} - -/* Function to convert a specified path to a full path. If it is not - already full, it is taken relative to the self path. */ -static int kwsys_shared_forward_fullpath(const char* self_path, - const char* in_path, char* result, - const char* desc) -{ - /* Check the specified path type. */ - if (in_path[0] == '/') { - /* Already a full path. */ - strcpy(result, in_path); - } -# if defined(_WIN32) - else if (in_path[0] && in_path[1] == ':') { - /* Already a full path. */ - strcpy(result, in_path); - } -# endif - else { - /* Relative to self path. */ - char temp_path[KWSYS_SHARED_FORWARD_MAXPATH]; - strcpy(temp_path, self_path); - strcat(temp_path, kwsys_shared_forward_path_slash); - strcat(temp_path, in_path); - if (!kwsys_shared_forward_realpath(temp_path, result)) { - if (desc) { - char msgbuf[KWSYS_SHARED_FORWARD_MAXPATH]; - kwsys_shared_forward_strerror(msgbuf); - fprintf(stderr, "Error converting %s \"%s\" to real path: %s\n", desc, - temp_path, msgbuf); - } - return 0; - } - } - return 1; -} - -/* Function to compute the library search path and executable name - based on the self path. */ -static int kwsys_shared_forward_get_settings(const char* self_path, - char* ldpath, char* exe) -{ - /* Possible search paths. */ - static const char* search_path_build[] = { KWSYS_SHARED_FORWARD_PATH_BUILD, - 0 }; - static const char* search_path_install[] = { - KWSYS_SHARED_FORWARD_PATH_INSTALL, 0 - }; - - /* Chosen paths. */ - const char** search_path; - const char* exe_path; - -/* Get the real name of the build and self paths. */ -# if defined(KWSYS_SHARED_FORWARD_CONFIG_NAME) - char build_path[] = - KWSYS_SHARED_FORWARD_DIR_BUILD "/" KWSYS_SHARED_FORWARD_CONFIG_NAME; - char self_path_logical[KWSYS_SHARED_FORWARD_MAXPATH]; -# else - char build_path[] = KWSYS_SHARED_FORWARD_DIR_BUILD; - const char* self_path_logical = self_path; -# endif - char build_path_real[KWSYS_SHARED_FORWARD_MAXPATH]; - char self_path_real[KWSYS_SHARED_FORWARD_MAXPATH]; - if (!kwsys_shared_forward_realpath(self_path, self_path_real)) { - char msgbuf[KWSYS_SHARED_FORWARD_MAXPATH]; - kwsys_shared_forward_strerror(msgbuf); - fprintf(stderr, "Error converting self path \"%s\" to real path: %s\n", - self_path, msgbuf); - return 0; - } - - /* Check whether we are running in the build tree or an install tree. */ - if (kwsys_shared_forward_realpath(build_path, build_path_real) && - kwsys_shared_forward_samepath(self_path_real, build_path_real)) { - /* Running in build tree. Use the build path and exe. */ - search_path = search_path_build; -# if defined(_WIN32) - exe_path = KWSYS_SHARED_FORWARD_EXE_BUILD ".exe"; -# else - exe_path = KWSYS_SHARED_FORWARD_EXE_BUILD; -# endif - -# if defined(KWSYS_SHARED_FORWARD_CONFIG_NAME) - /* Remove the configuration directory from self_path. */ - kwsys_shared_forward_dirname(self_path, self_path_logical); -# endif - } else { - /* Running in install tree. Use the install path and exe. */ - search_path = search_path_install; -# if defined(_WIN32) - exe_path = KWSYS_SHARED_FORWARD_EXE_INSTALL ".exe"; -# else - exe_path = KWSYS_SHARED_FORWARD_EXE_INSTALL; -# endif - -# if defined(KWSYS_SHARED_FORWARD_CONFIG_NAME) - /* Use the original self path directory. */ - strcpy(self_path_logical, self_path); -# endif - } - - /* Construct the runtime search path. */ - { - const char** dir; - for (dir = search_path; *dir; ++dir) { - /* Add separator between path components. */ - if (dir != search_path) { - strcat(ldpath, kwsys_shared_forward_path_sep); - } - - /* Add this path component. */ - if (!kwsys_shared_forward_fullpath(self_path_logical, *dir, - ldpath + strlen(ldpath), - "runtime path entry")) { - return 0; - } - } - } - - /* Construct the executable location. */ - if (!kwsys_shared_forward_fullpath(self_path_logical, exe_path, exe, - "executable file")) { - return 0; - } - return 1; -} - -/* Function to print why execution of a command line failed. */ -static void kwsys_shared_forward_print_failure(char const* const* argv) -{ - char msg[KWSYS_SHARED_FORWARD_MAXPATH]; - char const* const* arg = argv; - kwsys_shared_forward_strerror(msg); - fprintf(stderr, "Error running"); - for (; *arg; ++arg) { - fprintf(stderr, " \"%s\"", *arg); - } - fprintf(stderr, ": %s\n", msg); -} - -/* Static storage space to store the updated environment variable. */ -static char kwsys_shared_forward_ldpath[65535] = - KWSYS_SHARED_FORWARD_LDPATH "="; - -/* Main driver function to be called from main. */ -static int @KWSYS_NAMESPACE@_shared_forward_to_real(int argc, char** argv_in) -{ - char const** argv = (char const**)argv_in; - /* Get the directory containing this executable. */ - char self_path[KWSYS_SHARED_FORWARD_MAXPATH]; - if (kwsys_shared_forward_self_path(argv[0], self_path)) { - /* Found this executable. Use it to get the library directory. */ - char exe[KWSYS_SHARED_FORWARD_MAXPATH]; - if (kwsys_shared_forward_get_settings(self_path, - kwsys_shared_forward_ldpath, exe)) { - /* Append the old runtime search path. */ - const char* old_ldpath = getenv(KWSYS_SHARED_FORWARD_LDPATH); - if (old_ldpath) { - strcat(kwsys_shared_forward_ldpath, kwsys_shared_forward_path_sep); - strcat(kwsys_shared_forward_ldpath, old_ldpath); - } - - /* Store the environment variable. */ - putenv(kwsys_shared_forward_ldpath); - -# if defined(KWSYS_SHARED_FORWARD_OPTION_COMMAND) - /* Look for the command line replacement option. */ - if (argc > 1 && - strcmp(argv[1], KWSYS_SHARED_FORWARD_OPTION_COMMAND) == 0) { - if (argc > 2) { - /* Use the command line given. */ - strcpy(exe, argv[2]); - argv += 2; - argc -= 2; - } else { - /* The option was not given an executable. */ - fprintf(stderr, - "Option " KWSYS_SHARED_FORWARD_OPTION_COMMAND - " must be followed by a command line.\n"); - return 1; - } - } -# endif - -# if defined(KWSYS_SHARED_FORWARD_OPTION_PRINT) - /* Look for the print command line option. */ - if (argc > 1 && - strcmp(argv[1], KWSYS_SHARED_FORWARD_OPTION_PRINT) == 0) { - fprintf(stdout, "%s\n", kwsys_shared_forward_ldpath); - fprintf(stdout, "%s\n", exe); - return 0; - } -# endif - -# if defined(KWSYS_SHARED_FORWARD_OPTION_LDD) - /* Look for the ldd command line option. */ - if (argc > 1 && strcmp(argv[1], KWSYS_SHARED_FORWARD_OPTION_LDD) == 0) { -# if defined(KWSYS_SHARED_FORWARD_LDD) - /* Use the named ldd-like executable and arguments. */ - char const* ldd_argv[] = { KWSYS_SHARED_FORWARD_LDD, 0, 0 }; - ldd_argv[KWSYS_SHARED_FORWARD_LDD_N] = exe; - kwsys_shared_forward_execvp(ldd_argv[0], ldd_argv); - - /* Report why execution failed. */ - kwsys_shared_forward_print_failure(ldd_argv); - return 1; -# else - /* We have no ldd-like executable available on this platform. */ - fprintf(stderr, "No ldd-like tool is known to this executable.\n"); - return 1; -# endif - } -# endif - - /* Replace this process with the real executable. */ - argv[0] = exe; - kwsys_shared_forward_execvp(argv[0], argv); - - /* Report why execution failed. */ - kwsys_shared_forward_print_failure(argv); - } else { - /* Could not convert self path to the library directory. */ - } - } else { - /* Could not find this executable. */ - fprintf(stderr, "Error locating executable \"%s\".\n", argv[0]); - } - - /* Avoid unused argument warning. */ - (void)argc; - - /* Exit with failure. */ - return 1; -} - -/* Restore warning stack. */ -# if defined(__clang__) && defined(__has_warning) -# if __has_warning("-Wcast-qual") -# pragma clang diagnostic pop -# endif -# endif - -#else -# error "@KWSYS_NAMESPACE@/SharedForward.h should be included only once." -#endif diff --git a/test/API/driver/kwsys/String.c b/test/API/driver/kwsys/String.c deleted file mode 100644 index daf7ad1..0000000 --- a/test/API/driver/kwsys/String.c +++ /dev/null @@ -1,100 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifdef KWSYS_STRING_C -/* -All code in this source file is conditionally compiled to work-around -template definition auto-search on VMS. Other source files in this -directory that use the stl string cause the compiler to load this -source to try to get the definition of the string template. This -condition blocks the compiler from seeing the symbols defined here. -*/ -# include "kwsysPrivate.h" -# include KWSYS_HEADER(String.h) - -/* Work-around CMake dependency scanning limitation. This must - duplicate the above list of headers. */ -# if 0 -# include "String.h.in" -# endif - -/* Select an implementation for strcasecmp. */ -# if defined(_MSC_VER) -# define KWSYS_STRING_USE_STRICMP -# include -# elif defined(__GNUC__) -# define KWSYS_STRING_USE_STRCASECMP -# include -# else -/* Table to convert upper case letters to lower case and leave all - other characters alone. */ -static char kwsysString_strcasecmp_tolower[] = { - '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', '\010', - '\011', '\012', '\013', '\014', '\015', '\016', '\017', '\020', '\021', - '\022', '\023', '\024', '\025', '\026', '\027', '\030', '\031', '\032', - '\033', '\034', '\035', '\036', '\037', '\040', '\041', '\042', '\043', - '\044', '\045', '\046', '\047', '\050', '\051', '\052', '\053', '\054', - '\055', '\056', '\057', '\060', '\061', '\062', '\063', '\064', '\065', - '\066', '\067', '\070', '\071', '\072', '\073', '\074', '\075', '\076', - '\077', '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147', - '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', '\160', - '\161', '\162', '\163', '\164', '\165', '\166', '\167', '\170', '\171', - '\172', '\133', '\134', '\135', '\136', '\137', '\140', '\141', '\142', - '\143', '\144', '\145', '\146', '\147', '\150', '\151', '\152', '\153', - '\154', '\155', '\156', '\157', '\160', '\161', '\162', '\163', '\164', - '\165', '\166', '\167', '\170', '\171', '\172', '\173', '\174', '\175', - '\176', '\177', '\200', '\201', '\202', '\203', '\204', '\205', '\206', - '\207', '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217', - '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', '\230', - '\231', '\232', '\233', '\234', '\235', '\236', '\237', '\240', '\241', - '\242', '\243', '\244', '\245', '\246', '\247', '\250', '\251', '\252', - '\253', '\254', '\255', '\256', '\257', '\260', '\261', '\262', '\263', - '\264', '\265', '\266', '\267', '\270', '\271', '\272', '\273', '\274', - '\275', '\276', '\277', '\300', '\301', '\302', '\303', '\304', '\305', - '\306', '\307', '\310', '\311', '\312', '\313', '\314', '\315', '\316', - '\317', '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327', - '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337', '\340', - '\341', '\342', '\343', '\344', '\345', '\346', '\347', '\350', '\351', - '\352', '\353', '\354', '\355', '\356', '\357', '\360', '\361', '\362', - '\363', '\364', '\365', '\366', '\367', '\370', '\371', '\372', '\373', - '\374', '\375', '\376', '\377' -}; -# endif - -/*--------------------------------------------------------------------------*/ -int kwsysString_strcasecmp(const char* lhs, const char* rhs) -{ -# if defined(KWSYS_STRING_USE_STRICMP) - return _stricmp(lhs, rhs); -# elif defined(KWSYS_STRING_USE_STRCASECMP) - return strcasecmp(lhs, rhs); -# else - const char* const lower = kwsysString_strcasecmp_tolower; - unsigned char const* us1 = (unsigned char const*)lhs; - unsigned char const* us2 = (unsigned char const*)rhs; - int result; - while ((result = lower[*us1] - lower[*us2++], result == 0) && *us1++) { - } - return result; -# endif -} - -/*--------------------------------------------------------------------------*/ -int kwsysString_strncasecmp(const char* lhs, const char* rhs, size_t n) -{ -# if defined(KWSYS_STRING_USE_STRICMP) - return _strnicmp(lhs, rhs, n); -# elif defined(KWSYS_STRING_USE_STRCASECMP) - return strncasecmp(lhs, rhs, n); -# else - const char* const lower = kwsysString_strcasecmp_tolower; - unsigned char const* us1 = (unsigned char const*)lhs; - unsigned char const* us2 = (unsigned char const*)rhs; - int result = 0; - while (n && (result = lower[*us1] - lower[*us2++], result == 0) && *us1++) { - --n; - } - return result; -# endif -} - -#endif /* KWSYS_STRING_C */ diff --git a/test/API/driver/kwsys/String.h.in b/test/API/driver/kwsys/String.h.in deleted file mode 100644 index 7c9348a..0000000 --- a/test/API/driver/kwsys/String.h.in +++ /dev/null @@ -1,57 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifndef @KWSYS_NAMESPACE@_String_h -#define @KWSYS_NAMESPACE@_String_h - -#include <@KWSYS_NAMESPACE@/Configure.h> - -#include /* size_t */ - -/* Redefine all public interface symbol names to be in the proper - namespace. These macros are used internally to kwsys only, and are - not visible to user code. Use kwsysHeaderDump.pl to reproduce - these macros after making changes to the interface. */ -#if !defined(KWSYS_NAMESPACE) -# define kwsys_ns(x) @KWSYS_NAMESPACE@##x -# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT -#endif -#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS -# define kwsysString_strcasecmp kwsys_ns(String_strcasecmp) -# define kwsysString_strncasecmp kwsys_ns(String_strncasecmp) -#endif - -#if defined(__cplusplus) -extern "C" { -#endif - -/** - * Compare two strings ignoring the case of the characters. The - * integer returned is negative, zero, or positive if the first string - * is found to be less than, equal to, or greater than the second - * string, respectively. - */ -kwsysEXPORT int kwsysString_strcasecmp(const char* lhs, const char* rhs); - -/** - * Identical to String_strcasecmp except that only the first n - * characters are considered. - */ -kwsysEXPORT int kwsysString_strncasecmp(const char* lhs, const char* rhs, - size_t n); - -#if defined(__cplusplus) -} /* extern "C" */ -#endif - -/* If we are building a kwsys .c or .cxx file, let it use these macros. - Otherwise, undefine them to keep the namespace clean. */ -#if !defined(KWSYS_NAMESPACE) -# undef kwsys_ns -# undef kwsysEXPORT -# if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS -# undef kwsysString_strcasecmp -# undef kwsysString_strncasecmp -# endif -#endif - -#endif diff --git a/test/API/driver/kwsys/String.hxx.in b/test/API/driver/kwsys/String.hxx.in deleted file mode 100644 index db1cf22..0000000 --- a/test/API/driver/kwsys/String.hxx.in +++ /dev/null @@ -1,65 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifndef @KWSYS_NAMESPACE@_String_hxx -#define @KWSYS_NAMESPACE@_String_hxx - -#include - -namespace @KWSYS_NAMESPACE@ { - -/** \class String - * \brief Short-name version of the STL basic_string class template. - * - * The standard library "string" type is actually a typedef for - * "basic_string<..long argument list..>". This string class is - * simply a subclass of this type with the same interface so that the - * name is shorter in debugging symbols and error messages. - */ -class String : public std::string -{ - /** The original string type. */ - typedef std::string stl_string; - -public: - /** String member types. */ - typedef stl_string::value_type value_type; - typedef stl_string::pointer pointer; - typedef stl_string::reference reference; - typedef stl_string::const_reference const_reference; - typedef stl_string::size_type size_type; - typedef stl_string::difference_type difference_type; - typedef stl_string::iterator iterator; - typedef stl_string::const_iterator const_iterator; - typedef stl_string::reverse_iterator reverse_iterator; - typedef stl_string::const_reverse_iterator const_reverse_iterator; - - /** String constructors. */ - String() - : stl_string() - { - } - String(const value_type* s) - : stl_string(s) - { - } - String(const value_type* s, size_type n) - : stl_string(s, n) - { - } - String(const stl_string& s, size_type pos = 0, size_type n = npos) - : stl_string(s, pos, n) - { - } -}; // End Class: String - -#if defined(__WATCOMC__) -inline bool operator<(String const& l, String const& r) -{ - return (static_cast(l) < - static_cast(r)); -} -#endif - -} // namespace @KWSYS_NAMESPACE@ - -#endif diff --git a/test/API/driver/kwsys/System.c b/test/API/driver/kwsys/System.c deleted file mode 100644 index d43cc6f..0000000 --- a/test/API/driver/kwsys/System.c +++ /dev/null @@ -1,236 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include "kwsysPrivate.h" -#include KWSYS_HEADER(System.h) - -/* Work-around CMake dependency scanning limitation. This must - duplicate the above list of headers. */ -#if 0 -# include "System.h.in" -#endif - -#include /* isspace */ -#include /* ptrdiff_t */ -#include /* malloc, free */ -#include /* memcpy */ - -#include - -#if defined(KWSYS_C_HAS_PTRDIFF_T) && KWSYS_C_HAS_PTRDIFF_T -typedef ptrdiff_t kwsysSystem_ptrdiff_t; -#else -typedef int kwsysSystem_ptrdiff_t; -#endif - -static int kwsysSystem__AppendByte(char* local, char** begin, char** end, - int* size, char c) -{ - /* Allocate space for the character. */ - if ((*end - *begin) >= *size) { - kwsysSystem_ptrdiff_t length = *end - *begin; - char* newBuffer = (char*)malloc((size_t)(*size * 2)); - if (!newBuffer) { - return 0; - } - memcpy(newBuffer, *begin, (size_t)(length) * sizeof(char)); - if (*begin != local) { - free(*begin); - } - *begin = newBuffer; - *end = *begin + length; - *size *= 2; - } - - /* Store the character. */ - *(*end)++ = c; - return 1; -} - -static int kwsysSystem__AppendArgument(char** local, char*** begin, - char*** end, int* size, char* arg_local, - char** arg_begin, char** arg_end, - int* arg_size) -{ - /* Append a null-terminator to the argument string. */ - if (!kwsysSystem__AppendByte(arg_local, arg_begin, arg_end, arg_size, - '\0')) { - return 0; - } - - /* Allocate space for the argument pointer. */ - if ((*end - *begin) >= *size) { - kwsysSystem_ptrdiff_t length = *end - *begin; - char** newPointers = (char**)malloc((size_t)(*size) * 2 * sizeof(char*)); - if (!newPointers) { - return 0; - } - memcpy(newPointers, *begin, (size_t)(length) * sizeof(char*)); - if (*begin != local) { - free(*begin); - } - *begin = newPointers; - *end = *begin + length; - *size *= 2; - } - - /* Allocate space for the argument string. */ - **end = (char*)malloc((size_t)(*arg_end - *arg_begin)); - if (!**end) { - return 0; - } - - /* Store the argument in the command array. */ - memcpy(**end, *arg_begin, (size_t)(*arg_end - *arg_begin)); - ++(*end); - - /* Reset the argument to be empty. */ - *arg_end = *arg_begin; - - return 1; -} - -#define KWSYSPE_LOCAL_BYTE_COUNT 1024 -#define KWSYSPE_LOCAL_ARGS_COUNT 32 -static char** kwsysSystem__ParseUnixCommand(const char* command, int flags) -{ - /* Create a buffer for argument pointers during parsing. */ - char* local_pointers[KWSYSPE_LOCAL_ARGS_COUNT]; - int pointers_size = KWSYSPE_LOCAL_ARGS_COUNT; - char** pointer_begin = local_pointers; - char** pointer_end = pointer_begin; - - /* Create a buffer for argument strings during parsing. */ - char local_buffer[KWSYSPE_LOCAL_BYTE_COUNT]; - int buffer_size = KWSYSPE_LOCAL_BYTE_COUNT; - char* buffer_begin = local_buffer; - char* buffer_end = buffer_begin; - - /* Parse the command string. Try to behave like a UNIX shell. */ - char** newCommand = 0; - const char* c = command; - int in_argument = 0; - int in_escape = 0; - int in_single = 0; - int in_double = 0; - int failed = 0; - for (; *c; ++c) { - if (in_escape) { - /* This character is escaped so do no special handling. */ - if (!in_argument) { - in_argument = 1; - } - if (!kwsysSystem__AppendByte(local_buffer, &buffer_begin, &buffer_end, - &buffer_size, *c)) { - failed = 1; - break; - } - in_escape = 0; - } else if (*c == '\\') { - /* The next character should be escaped. */ - in_escape = 1; - } else if (*c == '\'' && !in_double) { - /* Enter or exit single-quote state. */ - if (in_single) { - in_single = 0; - } else { - in_single = 1; - if (!in_argument) { - in_argument = 1; - } - } - } else if (*c == '"' && !in_single) { - /* Enter or exit double-quote state. */ - if (in_double) { - in_double = 0; - } else { - in_double = 1; - if (!in_argument) { - in_argument = 1; - } - } - } else if (isspace((unsigned char)*c)) { - if (in_argument) { - if (in_single || in_double) { - /* This space belongs to a quoted argument. */ - if (!kwsysSystem__AppendByte(local_buffer, &buffer_begin, - &buffer_end, &buffer_size, *c)) { - failed = 1; - break; - } - } else { - /* This argument has been terminated by whitespace. */ - if (!kwsysSystem__AppendArgument( - local_pointers, &pointer_begin, &pointer_end, &pointers_size, - local_buffer, &buffer_begin, &buffer_end, &buffer_size)) { - failed = 1; - break; - } - in_argument = 0; - } - } - } else { - /* This character belong to an argument. */ - if (!in_argument) { - in_argument = 1; - } - if (!kwsysSystem__AppendByte(local_buffer, &buffer_begin, &buffer_end, - &buffer_size, *c)) { - failed = 1; - break; - } - } - } - - /* Finish the last argument. */ - if (in_argument) { - if (!kwsysSystem__AppendArgument( - local_pointers, &pointer_begin, &pointer_end, &pointers_size, - local_buffer, &buffer_begin, &buffer_end, &buffer_size)) { - failed = 1; - } - } - - /* If we still have memory allocate space for the new command - buffer. */ - if (!failed) { - kwsysSystem_ptrdiff_t n = pointer_end - pointer_begin; - newCommand = (char**)malloc((size_t)(n + 1) * sizeof(char*)); - } - - if (newCommand) { - /* Copy the arguments into the new command buffer. */ - kwsysSystem_ptrdiff_t n = pointer_end - pointer_begin; - memcpy(newCommand, pointer_begin, sizeof(char*) * (size_t)(n)); - newCommand[n] = 0; - } else { - /* Free arguments already allocated. */ - while (pointer_end != pointer_begin) { - free(*(--pointer_end)); - } - } - - /* Free temporary buffers. */ - if (pointer_begin != local_pointers) { - free(pointer_begin); - } - if (buffer_begin != local_buffer) { - free(buffer_begin); - } - - /* The flags argument is currently unused. */ - (void)flags; - - /* Return the final command buffer. */ - return newCommand; -} - -char** kwsysSystem_Parse_CommandForUnix(const char* command, int flags) -{ - /* Validate the flags. */ - if (flags != 0) { - return 0; - } - - /* Forward to our internal implementation. */ - return kwsysSystem__ParseUnixCommand(command, flags); -} diff --git a/test/API/driver/kwsys/System.h.in b/test/API/driver/kwsys/System.h.in deleted file mode 100644 index a9d4f5e..0000000 --- a/test/API/driver/kwsys/System.h.in +++ /dev/null @@ -1,60 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifndef @KWSYS_NAMESPACE@_System_h -#define @KWSYS_NAMESPACE@_System_h - -#include <@KWSYS_NAMESPACE@/Configure.h> - -/* Redefine all public interface symbol names to be in the proper - namespace. These macros are used internally to kwsys only, and are - not visible to user code. Use kwsysHeaderDump.pl to reproduce - these macros after making changes to the interface. */ -#if !defined(KWSYS_NAMESPACE) -# define kwsys_ns(x) @KWSYS_NAMESPACE@##x -# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT -#endif -#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS -# define kwsysSystem_Parse_CommandForUnix \ - kwsys_ns(System_Parse_CommandForUnix) -#endif - -#if defined(__cplusplus) -extern "C" { -#endif - -/** - * Parse a unix-style command line string into separate arguments. - * - * On success, returns a pointer to an array of pointers to individual - * argument strings. Each string is null-terminated and the last - * entry in the array is a NULL pointer (just like argv). It is the - * caller's responsibility to free() the strings and the array of - * pointers to them. - * - * On failure, returns NULL. Failure occurs only on invalid flags or - * when memory cannot be allocated; never due to content of the input - * string. Missing close-quotes are treated as if the necessary - * closing quote appears. - * - * By default single- and double-quoted arguments are supported, and - * any character may be escaped by a backslash. The flags argument is - * reserved for future use, and must be zero (or the call will fail). - */ -kwsysEXPORT char** kwsysSystem_Parse_CommandForUnix(const char* command, - int flags); - -#if defined(__cplusplus) -} /* extern "C" */ -#endif - -/* If we are building a kwsys .c or .cxx file, let it use these macros. - Otherwise, undefine them to keep the namespace clean. */ -#if !defined(KWSYS_NAMESPACE) -# undef kwsys_ns -# undef kwsysEXPORT -# if !defined(KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS -# undef kwsysSystem_Parse_CommandForUnix -# endif -#endif - -#endif diff --git a/test/API/driver/kwsys/SystemInformation.cxx b/test/API/driver/kwsys/SystemInformation.cxx deleted file mode 100644 index 6ec6e48..0000000 --- a/test/API/driver/kwsys/SystemInformation.cxx +++ /dev/null @@ -1,5466 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#if defined(_WIN32) -# define NOMINMAX // use our min,max -# if !defined(_WIN32_WINNT) && defined(_MSC_VER) && _MSC_VER >= 1800 -# define _WIN32_WINNT 0x0600 // vista -# endif -# if !defined(_WIN32_WINNT) && !(defined(_MSC_VER) && _MSC_VER < 1300) -# define _WIN32_WINNT 0x0501 -# endif -# include // WSADATA, include before sys/types.h -#endif - -#if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE) -# define _GNU_SOURCE -#endif - -// TODO: -// We need an alternative implementation for many functions in this file -// when USE_ASM_INSTRUCTIONS gets defined as 0. -// -// Consider using these on Win32/Win64 for some of them: -// -// IsProcessorFeaturePresent -// http://msdn.microsoft.com/en-us/library/ms724482(VS.85).aspx -// -// GetProcessMemoryInfo -// http://msdn.microsoft.com/en-us/library/ms683219(VS.85).aspx - -#include "kwsysPrivate.h" -#include KWSYS_HEADER(SystemInformation.hxx) -#include KWSYS_HEADER(Process.h) - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -# include "Process.h.in" -# include "SystemInformation.hxx.in" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(_WIN32) -# include -# if defined(_MSC_VER) && _MSC_VER >= 1800 -# define KWSYS_WINDOWS_DEPRECATED_GetVersionEx -# endif -# include -# if defined(KWSYS_SYS_HAS_PSAPI) -# include -# endif -# if !defined(siginfo_t) -typedef int siginfo_t; -# endif -#else -# include - -# include // extern int errno; -# include -# include -# include // getrlimit -# include -# include // int uname(struct utsname *buf); -# include -#endif - -#if defined(__CYGWIN__) && !defined(_WIN32) -# include -# undef _WIN32 -#endif - -#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__DragonFly__) -# include -# include -# include -# include -# include -# if defined(KWSYS_SYS_HAS_IFADDRS_H) -# include -# include -# define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN -# endif -#endif - -#if defined(KWSYS_SYS_HAS_MACHINE_CPU_H) -# include -#endif - -#ifdef __APPLE__ -# include -# include -# include -# include -# include -# include -# include -# include -# if defined(KWSYS_SYS_HAS_IFADDRS_H) -# include -# include -# define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN -# endif -# if !(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ - 0 >= 1050) -# undef KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE -# endif -#endif - -#if defined(__linux) || defined(__sun) || defined(_SCO_DS) || \ - defined(__GLIBC__) || defined(__GNU__) -# include -# include -# include -# if defined(KWSYS_SYS_HAS_IFADDRS_H) -# include -# include -# if defined(__LSB_VERSION__) -/* LSB has no getifaddrs */ -# elif defined(__ANDROID_API__) && __ANDROID_API__ < 24 -/* Android has no getifaddrs prior to API 24. */ -# else -# define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN -# endif -# endif -# if defined(KWSYS_CXX_HAS_RLIMIT64) -typedef struct rlimit64 ResourceLimitType; -# define GetResourceLimit getrlimit64 -# else -typedef struct rlimit ResourceLimitType; -# define GetResourceLimit getrlimit -# endif -#elif defined(__hpux) -# include -# include -# if defined(KWSYS_SYS_HAS_MPCTL_H) -# include -# endif -#endif - -#ifdef __HAIKU__ -# include -#endif - -#if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) -# include -# if defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE) -# include -# endif -# if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP) -# include -# endif -#else -# undef KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE -# undef KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP -#endif - -#include // int isdigit(int c); -#include -#include -#include -#include - -#if defined(KWSYS_USE_LONG_LONG) -# if defined(KWSYS_IOS_HAS_OSTREAM_LONG_LONG) -# define iostreamLongLong(x) (x) -# else -# define iostreamLongLong(x) ((long)(x)) -# endif -#elif defined(KWSYS_USE___INT64) -# if defined(KWSYS_IOS_HAS_OSTREAM___INT64) -# define iostreamLongLong(x) (x) -# else -# define iostreamLongLong(x) ((long)(x)) -# endif -#else -# error "No Long Long" -#endif - -#if defined(KWSYS_CXX_HAS_ATOLL) -# define atoLongLong atoll -#else -# if defined(KWSYS_CXX_HAS__ATOI64) -# define atoLongLong _atoi64 -# elif defined(KWSYS_CXX_HAS_ATOL) -# define atoLongLong atol -# else -# define atoLongLong atoi -# endif -#endif - -#if defined(_MSC_VER) && (_MSC_VER >= 1300) && !defined(_WIN64) && \ - !defined(__clang__) -# define USE_ASM_INSTRUCTIONS 1 -#else -# define USE_ASM_INSTRUCTIONS 0 -#endif - -#if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__clang__) -# include -# define USE_CPUID_INTRINSICS 1 -#else -# define USE_CPUID_INTRINSICS 0 -#endif - -#if USE_ASM_INSTRUCTIONS || USE_CPUID_INTRINSICS || \ - defined(KWSYS_CXX_HAS_BORLAND_ASM_CPUID) -# define USE_CPUID 1 -#else -# define USE_CPUID 0 -#endif - -#if USE_CPUID - -# define CPUID_AWARE_COMPILER - -/** - * call CPUID instruction - * - * Will return false if the instruction failed. - */ -static bool call_cpuid(int select, int result[4]) -{ -# if USE_CPUID_INTRINSICS - __cpuid(result, select); - return true; -# else - int tmp[4]; -# if defined(_MSC_VER) - // Use SEH to determine CPUID presence - __try { - _asm { -# ifdef CPUID_AWARE_COMPILER - ; we must push/pop the registers <> writes to, as the - ; optimiser does not know about <>, and so does not expect - ; these registers to change. - push eax - push ebx - push ecx - push edx -# endif - ; <> - mov eax, select -# ifdef CPUID_AWARE_COMPILER - cpuid -# else - _asm _emit 0x0f - _asm _emit 0xa2 -# endif - mov tmp[0 * TYPE int], eax - mov tmp[1 * TYPE int], ebx - mov tmp[2 * TYPE int], ecx - mov tmp[3 * TYPE int], edx - -# ifdef CPUID_AWARE_COMPILER - pop edx - pop ecx - pop ebx - pop eax -# endif - } - } __except (1) { - return false; - } - - memcpy(result, tmp, sizeof(tmp)); -# elif defined(KWSYS_CXX_HAS_BORLAND_ASM_CPUID) - unsigned int a, b, c, d; - __asm { - mov EAX, select; - cpuid - mov a, EAX; - mov b, EBX; - mov c, ECX; - mov d, EDX; - } - - result[0] = a; - result[1] = b; - result[2] = c; - result[3] = d; -# endif - - // The cpuid instruction succeeded. - return true; -# endif -} -#endif - -namespace KWSYS_NAMESPACE { -template -T min(T a, T b) -{ - return a < b ? a : b; -} - -extern "C" { -typedef void (*SigAction)(int, siginfo_t*, void*); -} - -// Define SystemInformationImplementation class -typedef void (*DELAY_FUNC)(unsigned int uiMS); - -class SystemInformationImplementation -{ -public: - typedef SystemInformation::LongLong LongLong; - SystemInformationImplementation(); - ~SystemInformationImplementation(); - - const char* GetVendorString(); - const char* GetVendorID(); - std::string GetTypeID(); - std::string GetFamilyID(); - std::string GetModelID(); - std::string GetModelName(); - std::string GetSteppingCode(); - const char* GetExtendedProcessorName(); - const char* GetProcessorSerialNumber(); - int GetProcessorCacheSize(); - unsigned int GetLogicalProcessorsPerPhysical(); - float GetProcessorClockFrequency(); - int GetProcessorAPICID(); - int GetProcessorCacheXSize(long int); - bool DoesCPUSupportFeature(long int); - - const char* GetOSName(); - const char* GetHostname(); - int GetFullyQualifiedDomainName(std::string& fqdn); - const char* GetOSRelease(); - const char* GetOSVersion(); - const char* GetOSPlatform(); - - bool Is64Bits(); - - unsigned int GetNumberOfLogicalCPU(); // per physical cpu - unsigned int GetNumberOfPhysicalCPU(); - - bool DoesCPUSupportCPUID(); - - // Retrieve memory information in MiB. - size_t GetTotalVirtualMemory(); - size_t GetAvailableVirtualMemory(); - size_t GetTotalPhysicalMemory(); - size_t GetAvailablePhysicalMemory(); - - LongLong GetProcessId(); - - // Retrieve memory information in KiB. - LongLong GetHostMemoryTotal(); - LongLong GetHostMemoryAvailable(const char* envVarName); - LongLong GetHostMemoryUsed(); - - LongLong GetProcMemoryAvailable(const char* hostLimitEnvVarName, - const char* procLimitEnvVarName); - LongLong GetProcMemoryUsed(); - - double GetLoadAverage(); - - // enable/disable stack trace signal handler. - static void SetStackTraceOnError(int enable); - - // get current stack - static std::string GetProgramStack(int firstFrame, int wholePath); - - /** Run the different checks */ - void RunCPUCheck(); - void RunOSCheck(); - void RunMemoryCheck(); - -public: - typedef struct tagID - { - int Type; - int Family; - int Model; - int Revision; - int ExtendedFamily; - int ExtendedModel; - std::string ProcessorName; - std::string Vendor; - std::string SerialNumber; - std::string ModelName; - } ID; - - typedef struct tagCPUPowerManagement - { - bool HasVoltageID; - bool HasFrequencyID; - bool HasTempSenseDiode; - } CPUPowerManagement; - - typedef struct tagCPUExtendedFeatures - { - bool Has3DNow; - bool Has3DNowPlus; - bool SupportsMP; - bool HasMMXPlus; - bool HasSSEMMX; - unsigned int LogicalProcessorsPerPhysical; - int APIC_ID; - CPUPowerManagement PowerManagement; - } CPUExtendedFeatures; - - typedef struct CPUtagFeatures - { - bool HasFPU; - bool HasTSC; - bool HasMMX; - bool HasSSE; - bool HasSSEFP; - bool HasSSE2; - bool HasIA64; - bool HasAPIC; - bool HasCMOV; - bool HasMTRR; - bool HasACPI; - bool HasSerial; - bool HasThermal; - int CPUSpeed; - int L1CacheSize; - int L2CacheSize; - int L3CacheSize; - CPUExtendedFeatures ExtendedFeatures; - } CPUFeatures; - - enum Manufacturer - { - AMD, - Intel, - NSC, - UMC, - Cyrix, - NexGen, - IDT, - Rise, - Transmeta, - Sun, - IBM, - Motorola, - HP, - Hygon, - UnknownManufacturer - }; - -protected: - // For windows - bool RetrieveCPUFeatures(); - bool RetrieveCPUIdentity(); - bool RetrieveCPUCacheDetails(); - bool RetrieveClassicalCPUCacheDetails(); - bool RetrieveCPUClockSpeed(); - bool RetrieveClassicalCPUClockSpeed(); - bool RetrieveCPUExtendedLevelSupport(int); - bool RetrieveExtendedCPUFeatures(); - bool RetrieveProcessorSerialNumber(); - bool RetrieveCPUPowerManagement(); - bool RetrieveClassicalCPUIdentity(); - bool RetrieveExtendedCPUIdentity(); - - // Processor information - Manufacturer ChipManufacturer; - CPUFeatures Features; - ID ChipID; - float CPUSpeedInMHz; - unsigned int NumberOfLogicalCPU; - unsigned int NumberOfPhysicalCPU; - - void CPUCountWindows(); // For windows - unsigned char GetAPICId(); // For windows - bool IsSMTSupported(); - static LongLong GetCyclesDifference(DELAY_FUNC, unsigned int); // For windows - - // For Linux and Cygwin, /proc/cpuinfo formats are slightly different - bool RetreiveInformationFromCpuInfoFile(); - std::string ExtractValueFromCpuInfoFile(std::string buffer, const char* word, - size_t init = 0); - - bool QueryLinuxMemory(); - bool QueryCygwinMemory(); - - static void Delay(unsigned int); - static void DelayOverhead(unsigned int); - - void FindManufacturer(const std::string& family = ""); - - // For Mac - bool ParseSysCtl(); - int CallSwVers(const char* arg, std::string& ver); - void TrimNewline(std::string&); - std::string ExtractValueFromSysCtl(const char* word); - std::string SysCtlBuffer; - - // For Solaris - bool QuerySolarisMemory(); - bool QuerySolarisProcessor(); - std::string ParseValueFromKStat(const char* arguments); - std::string RunProcess(std::vector args); - - // For Haiku OS - bool QueryHaikuInfo(); - - // For QNX - bool QueryQNXMemory(); - bool QueryQNXProcessor(); - - // For OpenBSD, FreeBSD, NetBSD, DragonFly - bool QueryBSDMemory(); - bool QueryBSDProcessor(); - - // For HP-UX - bool QueryHPUXMemory(); - bool QueryHPUXProcessor(); - - // For Microsoft Windows - bool QueryWindowsMemory(); - - // For AIX - bool QueryAIXMemory(); - - bool QueryProcessorBySysconf(); - bool QueryProcessor(); - - // Evaluate the memory information. - bool QueryMemoryBySysconf(); - bool QueryMemory(); - size_t TotalVirtualMemory; - size_t AvailableVirtualMemory; - size_t TotalPhysicalMemory; - size_t AvailablePhysicalMemory; - - size_t CurrentPositionInFile; - - // Operating System information - bool QueryOSInformation(); - std::string OSName; - std::string Hostname; - std::string OSRelease; - std::string OSVersion; - std::string OSPlatform; - bool OSIs64Bit; -}; - -SystemInformation::SystemInformation() -{ - this->Implementation = new SystemInformationImplementation; -} - -SystemInformation::~SystemInformation() -{ - delete this->Implementation; -} - -const char* SystemInformation::GetVendorString() -{ - return this->Implementation->GetVendorString(); -} - -const char* SystemInformation::GetVendorID() -{ - return this->Implementation->GetVendorID(); -} - -std::string SystemInformation::GetTypeID() -{ - return this->Implementation->GetTypeID(); -} - -std::string SystemInformation::GetFamilyID() -{ - return this->Implementation->GetFamilyID(); -} - -std::string SystemInformation::GetModelID() -{ - return this->Implementation->GetModelID(); -} - -std::string SystemInformation::GetModelName() -{ - return this->Implementation->GetModelName(); -} - -std::string SystemInformation::GetSteppingCode() -{ - return this->Implementation->GetSteppingCode(); -} - -const char* SystemInformation::GetExtendedProcessorName() -{ - return this->Implementation->GetExtendedProcessorName(); -} - -const char* SystemInformation::GetProcessorSerialNumber() -{ - return this->Implementation->GetProcessorSerialNumber(); -} - -int SystemInformation::GetProcessorCacheSize() -{ - return this->Implementation->GetProcessorCacheSize(); -} - -unsigned int SystemInformation::GetLogicalProcessorsPerPhysical() -{ - return this->Implementation->GetLogicalProcessorsPerPhysical(); -} - -float SystemInformation::GetProcessorClockFrequency() -{ - return this->Implementation->GetProcessorClockFrequency(); -} - -int SystemInformation::GetProcessorAPICID() -{ - return this->Implementation->GetProcessorAPICID(); -} - -int SystemInformation::GetProcessorCacheXSize(long int l) -{ - return this->Implementation->GetProcessorCacheXSize(l); -} - -bool SystemInformation::DoesCPUSupportFeature(long int i) -{ - return this->Implementation->DoesCPUSupportFeature(i); -} - -std::string SystemInformation::GetCPUDescription() -{ - std::ostringstream oss; - oss << this->GetNumberOfPhysicalCPU() << " core "; - if (this->GetModelName().empty()) { - oss << this->GetProcessorClockFrequency() << " MHz " - << this->GetVendorString() << " " << this->GetExtendedProcessorName(); - } else { - oss << this->GetModelName(); - } - - // remove extra spaces - std::string tmp = oss.str(); - size_t pos; - while ((pos = tmp.find(" ")) != std::string::npos) { - tmp.replace(pos, 2, " "); - } - - return tmp; -} - -const char* SystemInformation::GetOSName() -{ - return this->Implementation->GetOSName(); -} - -const char* SystemInformation::GetHostname() -{ - return this->Implementation->GetHostname(); -} - -std::string SystemInformation::GetFullyQualifiedDomainName() -{ - std::string fqdn; - this->Implementation->GetFullyQualifiedDomainName(fqdn); - return fqdn; -} - -const char* SystemInformation::GetOSRelease() -{ - return this->Implementation->GetOSRelease(); -} - -const char* SystemInformation::GetOSVersion() -{ - return this->Implementation->GetOSVersion(); -} - -const char* SystemInformation::GetOSPlatform() -{ - return this->Implementation->GetOSPlatform(); -} - -int SystemInformation::GetOSIsWindows() -{ -#if defined(_WIN32) - return 1; -#else - return 0; -#endif -} - -int SystemInformation::GetOSIsLinux() -{ -#if defined(__linux) - return 1; -#else - return 0; -#endif -} - -int SystemInformation::GetOSIsApple() -{ -#if defined(__APPLE__) - return 1; -#else - return 0; -#endif -} - -std::string SystemInformation::GetOSDescription() -{ - std::ostringstream oss; - oss << this->GetOSName() << " " << this->GetOSRelease() << " " - << this->GetOSVersion(); - - return oss.str(); -} - -bool SystemInformation::Is64Bits() -{ - return this->Implementation->Is64Bits(); -} - -unsigned int SystemInformation::GetNumberOfLogicalCPU() // per physical cpu -{ - return this->Implementation->GetNumberOfLogicalCPU(); -} - -unsigned int SystemInformation::GetNumberOfPhysicalCPU() -{ - return this->Implementation->GetNumberOfPhysicalCPU(); -} - -bool SystemInformation::DoesCPUSupportCPUID() -{ - return this->Implementation->DoesCPUSupportCPUID(); -} - -// Retrieve memory information in MiB. -size_t SystemInformation::GetTotalVirtualMemory() -{ - return this->Implementation->GetTotalVirtualMemory(); -} - -size_t SystemInformation::GetAvailableVirtualMemory() -{ - return this->Implementation->GetAvailableVirtualMemory(); -} - -size_t SystemInformation::GetTotalPhysicalMemory() -{ - return this->Implementation->GetTotalPhysicalMemory(); -} - -size_t SystemInformation::GetAvailablePhysicalMemory() -{ - return this->Implementation->GetAvailablePhysicalMemory(); -} - -std::string SystemInformation::GetMemoryDescription( - const char* hostLimitEnvVarName, const char* procLimitEnvVarName) -{ - std::ostringstream oss; - oss << "Host Total: " << iostreamLongLong(this->GetHostMemoryTotal()) - << " KiB, Host Available: " - << iostreamLongLong(this->GetHostMemoryAvailable(hostLimitEnvVarName)) - << " KiB, Process Available: " - << iostreamLongLong(this->GetProcMemoryAvailable(hostLimitEnvVarName, - procLimitEnvVarName)) - << " KiB"; - return oss.str(); -} - -// host memory info in units of KiB. -SystemInformation::LongLong SystemInformation::GetHostMemoryTotal() -{ - return this->Implementation->GetHostMemoryTotal(); -} - -SystemInformation::LongLong SystemInformation::GetHostMemoryAvailable( - const char* hostLimitEnvVarName) -{ - return this->Implementation->GetHostMemoryAvailable(hostLimitEnvVarName); -} - -SystemInformation::LongLong SystemInformation::GetHostMemoryUsed() -{ - return this->Implementation->GetHostMemoryUsed(); -} - -// process memory info in units of KiB. -SystemInformation::LongLong SystemInformation::GetProcMemoryAvailable( - const char* hostLimitEnvVarName, const char* procLimitEnvVarName) -{ - return this->Implementation->GetProcMemoryAvailable(hostLimitEnvVarName, - procLimitEnvVarName); -} - -SystemInformation::LongLong SystemInformation::GetProcMemoryUsed() -{ - return this->Implementation->GetProcMemoryUsed(); -} - -double SystemInformation::GetLoadAverage() -{ - return this->Implementation->GetLoadAverage(); -} - -SystemInformation::LongLong SystemInformation::GetProcessId() -{ - return this->Implementation->GetProcessId(); -} - -void SystemInformation::SetStackTraceOnError(int enable) -{ - SystemInformationImplementation::SetStackTraceOnError(enable); -} - -std::string SystemInformation::GetProgramStack(int firstFrame, int wholePath) -{ - return SystemInformationImplementation::GetProgramStack(firstFrame, - wholePath); -} - -/** Run the different checks */ -void SystemInformation::RunCPUCheck() -{ - this->Implementation->RunCPUCheck(); -} - -void SystemInformation::RunOSCheck() -{ - this->Implementation->RunOSCheck(); -} - -void SystemInformation::RunMemoryCheck() -{ - this->Implementation->RunMemoryCheck(); -} - -// SystemInformationImplementation starts here - -#if USE_CPUID -# define STORE_TLBCACHE_INFO(x, y) x = (x < (y)) ? (y) : x -# define TLBCACHE_INFO_UNITS (15) -#endif - -#if USE_ASM_INSTRUCTIONS -# define CLASSICAL_CPU_FREQ_LOOP 10000000 -# define RDTSC_INSTRUCTION _asm _emit 0x0f _asm _emit 0x31 -#endif - -#define INITIAL_APIC_ID_BITS 0xFF000000 -// initial APIC ID for the processor this code is running on. -// Default value = 0xff if HT is not supported - -// Hide implementation details in an anonymous namespace. -namespace { -// ***************************************************************************** -#if defined(__linux) || defined(__APPLE__) -int LoadLines(FILE* file, std::vector& lines) -{ - // Load each line in the given file into a the vector. - int nRead = 0; - const int bufSize = 1024; - char buf[bufSize] = { '\0' }; - while (!feof(file) && !ferror(file)) { - errno = 0; - if (fgets(buf, bufSize, file) == nullptr) { - if (ferror(file) && (errno == EINTR)) { - clearerr(file); - } - continue; - } - char* pBuf = buf; - while (*pBuf) { - if (*pBuf == '\n') - *pBuf = '\0'; - pBuf += 1; - } - lines.push_back(buf); - ++nRead; - } - if (ferror(file)) { - return 0; - } - return nRead; -} - -# if defined(__linux) -// ***************************************************************************** -int LoadLines(const char* fileName, std::vector& lines) -{ - FILE* file = fopen(fileName, "r"); - if (file == 0) { - return 0; - } - int nRead = LoadLines(file, lines); - fclose(file); - return nRead; -} -# endif - -// **************************************************************************** -template -int NameValue(std::vector const& lines, std::string const& name, - T& value) -{ - size_t nLines = lines.size(); - for (size_t i = 0; i < nLines; ++i) { - size_t at = lines[i].find(name); - if (at == std::string::npos) { - continue; - } - std::istringstream is(lines[i].substr(at + name.size())); - is >> value; - return 0; - } - return -1; -} -#endif - -#if defined(__linux) -// **************************************************************************** -template -int GetFieldsFromFile(const char* fileName, const char** fieldNames, T* values) -{ - std::vector fields; - if (!LoadLines(fileName, fields)) { - return -1; - } - int i = 0; - while (fieldNames[i] != nullptr) { - int ierr = NameValue(fields, fieldNames[i], values[i]); - if (ierr) { - return -(i + 2); - } - i += 1; - } - return 0; -} - -// **************************************************************************** -template -int GetFieldFromFile(const char* fileName, const char* fieldName, T& value) -{ - const char* fieldNames[2] = { fieldName, nullptr }; - T values[1] = { T(0) }; - int ierr = GetFieldsFromFile(fileName, fieldNames, values); - if (ierr) { - return ierr; - } - value = values[0]; - return 0; -} -#endif - -// **************************************************************************** -#if defined(__APPLE__) -template -int GetFieldsFromCommand(const char* command, const char** fieldNames, - T* values) -{ - FILE* file = popen(command, "r"); - if (file == nullptr) { - return -1; - } - std::vector fields; - int nl = LoadLines(file, fields); - pclose(file); - if (nl == 0) { - return -1; - } - int i = 0; - while (fieldNames[i] != nullptr) { - int ierr = NameValue(fields, fieldNames[i], values[i]); - if (ierr) { - return -(i + 2); - } - i += 1; - } - return 0; -} -#endif - -// **************************************************************************** -#if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) -void StacktraceSignalHandler(int sigNo, siginfo_t* sigInfo, - void* /*sigContext*/) -{ -# if defined(__linux) || defined(__APPLE__) - std::ostringstream oss; - oss << std::endl - << "=========================================================" - << std::endl - << "Process id " << getpid() << " "; - switch (sigNo) { - case SIGINT: - oss << "Caught SIGINT"; - break; - - case SIGTERM: - oss << "Caught SIGTERM"; - break; - - case SIGABRT: - oss << "Caught SIGABRT"; - break; - - case SIGFPE: - oss << "Caught SIGFPE at " << (sigInfo->si_addr == nullptr ? "0x" : "") - << sigInfo->si_addr << " "; - switch (sigInfo->si_code) { -# if defined(FPE_INTDIV) - case FPE_INTDIV: - oss << "integer division by zero"; - break; -# endif - -# if defined(FPE_INTOVF) - case FPE_INTOVF: - oss << "integer overflow"; - break; -# endif - - case FPE_FLTDIV: - oss << "floating point divide by zero"; - break; - - case FPE_FLTOVF: - oss << "floating point overflow"; - break; - - case FPE_FLTUND: - oss << "floating point underflow"; - break; - - case FPE_FLTRES: - oss << "floating point inexact result"; - break; - - case FPE_FLTINV: - oss << "floating point invalid operation"; - break; - -# if defined(FPE_FLTSUB) - case FPE_FLTSUB: - oss << "floating point subscript out of range"; - break; -# endif - - default: - oss << "code " << sigInfo->si_code; - break; - } - break; - - case SIGSEGV: - oss << "Caught SIGSEGV at " << (sigInfo->si_addr == nullptr ? "0x" : "") - << sigInfo->si_addr << " "; - switch (sigInfo->si_code) { - case SEGV_MAPERR: - oss << "address not mapped to object"; - break; - - case SEGV_ACCERR: - oss << "invalid permission for mapped object"; - break; - - default: - oss << "code " << sigInfo->si_code; - break; - } - break; - - case SIGBUS: - oss << "Caught SIGBUS at " << (sigInfo->si_addr == nullptr ? "0x" : "") - << sigInfo->si_addr << " "; - switch (sigInfo->si_code) { - case BUS_ADRALN: - oss << "invalid address alignment"; - break; - -# if defined(BUS_ADRERR) - case BUS_ADRERR: - oss << "nonexistent physical address"; - break; -# endif - -# if defined(BUS_OBJERR) - case BUS_OBJERR: - oss << "object-specific hardware error"; - break; -# endif - -# if defined(BUS_MCEERR_AR) - case BUS_MCEERR_AR: - oss << "Hardware memory error consumed on a machine check; action " - "required."; - break; -# endif - -# if defined(BUS_MCEERR_AO) - case BUS_MCEERR_AO: - oss << "Hardware memory error detected in process but not consumed; " - "action optional."; - break; -# endif - - default: - oss << "code " << sigInfo->si_code; - break; - } - break; - - case SIGILL: - oss << "Caught SIGILL at " << (sigInfo->si_addr == nullptr ? "0x" : "") - << sigInfo->si_addr << " "; - switch (sigInfo->si_code) { - case ILL_ILLOPC: - oss << "illegal opcode"; - break; - -# if defined(ILL_ILLOPN) - case ILL_ILLOPN: - oss << "illegal operand"; - break; -# endif - -# if defined(ILL_ILLADR) - case ILL_ILLADR: - oss << "illegal addressing mode."; - break; -# endif - - case ILL_ILLTRP: - oss << "illegal trap"; - break; - - case ILL_PRVOPC: - oss << "privileged opcode"; - break; - -# if defined(ILL_PRVREG) - case ILL_PRVREG: - oss << "privileged register"; - break; -# endif - -# if defined(ILL_COPROC) - case ILL_COPROC: - oss << "co-processor error"; - break; -# endif - -# if defined(ILL_BADSTK) - case ILL_BADSTK: - oss << "internal stack error"; - break; -# endif - - default: - oss << "code " << sigInfo->si_code; - break; - } - break; - - default: - oss << "Caught " << sigNo << " code " << sigInfo->si_code; - break; - } - oss << std::endl - << "Program Stack:" << std::endl - << SystemInformationImplementation::GetProgramStack(2, 0) - << "=========================================================" - << std::endl; - std::cerr << oss.str() << std::endl; - - // restore the previously registered handlers - // and abort - SystemInformationImplementation::SetStackTraceOnError(0); - abort(); -# else - // avoid warning C4100 - (void)sigNo; - (void)sigInfo; -# endif -} -#endif - -#if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) -# define safes(_arg) ((_arg) ? (_arg) : "???") - -// Description: -// A container for symbol properties. Each instance -// must be Initialized. -class SymbolProperties -{ -public: - SymbolProperties(); - - // Description: - // The SymbolProperties instance must be initialized by - // passing a stack address. - void Initialize(void* address); - - // Description: - // Get the symbol's stack address. - void* GetAddress() const { return this->Address; } - - // Description: - // If not set paths will be removed. eg, from a binary - // or source file. - void SetReportPath(int rp) { this->ReportPath = rp; } - - // Description: - // Set/Get the name of the binary file that the symbol - // is found in. - void SetBinary(const char* binary) { this->Binary = safes(binary); } - - std::string GetBinary() const; - - // Description: - // Set the name of the function that the symbol is found in. - // If c++ demangling is supported it will be demangled. - void SetFunction(const char* function) - { - this->Function = this->Demangle(function); - } - - std::string GetFunction() const { return this->Function; } - - // Description: - // Set/Get the name of the source file where the symbol - // is defined. - void SetSourceFile(const char* sourcefile) - { - this->SourceFile = safes(sourcefile); - } - - std::string GetSourceFile() const - { - return this->GetFileName(this->SourceFile); - } - - // Description: - // Set/Get the line number where the symbol is defined - void SetLineNumber(long linenumber) { this->LineNumber = linenumber; } - long GetLineNumber() const { return this->LineNumber; } - - // Description: - // Set the address where the binary image is mapped - // into memory. - void SetBinaryBaseAddress(void* address) - { - this->BinaryBaseAddress = address; - } - -private: - void* GetRealAddress() const - { - return (void*)((char*)this->Address - (char*)this->BinaryBaseAddress); - } - - std::string GetFileName(const std::string& path) const; - std::string Demangle(const char* symbol) const; - -private: - std::string Binary; - void* BinaryBaseAddress; - void* Address; - std::string SourceFile; - std::string Function; - long LineNumber; - int ReportPath; -}; - -std::ostream& operator<<(std::ostream& os, const SymbolProperties& sp) -{ -# if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP) - os << std::hex << sp.GetAddress() << " : " << sp.GetFunction() << " [(" - << sp.GetBinary() << ") " << sp.GetSourceFile() << ":" << std::dec - << sp.GetLineNumber() << "]"; -# elif defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) - void* addr = sp.GetAddress(); - char** syminfo = backtrace_symbols(&addr, 1); - os << safes(syminfo[0]); - free(syminfo); -# else - (void)os; - (void)sp; -# endif - return os; -} - -SymbolProperties::SymbolProperties() -{ - // not using an initializer list - // to avoid some PGI compiler warnings - this->SetBinary("???"); - this->SetBinaryBaseAddress(nullptr); - this->Address = nullptr; - this->SetSourceFile("???"); - this->SetFunction("???"); - this->SetLineNumber(-1); - this->SetReportPath(0); - // avoid PGI compiler warnings - this->GetRealAddress(); - this->GetFunction(); - this->GetSourceFile(); - this->GetLineNumber(); -} - -std::string SymbolProperties::GetFileName(const std::string& path) const -{ - std::string file(path); - if (!this->ReportPath) { - size_t at = file.rfind("/"); - if (at != std::string::npos) { - file = file.substr(at + 1); - } - } - return file; -} - -std::string SymbolProperties::GetBinary() const -{ -// only linux has proc fs -# if defined(__linux__) - if (this->Binary == "/proc/self/exe") { - std::string binary; - char buf[1024] = { '\0' }; - ssize_t ll = 0; - if ((ll = readlink("/proc/self/exe", buf, 1024)) > 0 && ll < 1024) { - buf[ll] = '\0'; - binary = buf; - } else { - binary = "/proc/self/exe"; - } - return this->GetFileName(binary); - } -# endif - return this->GetFileName(this->Binary); -} - -std::string SymbolProperties::Demangle(const char* symbol) const -{ - std::string result = safes(symbol); -# if defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE) - int status = 0; - size_t bufferLen = 1024; - char* buffer = (char*)malloc(1024); - char* demangledSymbol = - abi::__cxa_demangle(symbol, buffer, &bufferLen, &status); - if (!status) { - result = demangledSymbol; - } - free(buffer); -# else - (void)symbol; -# endif - return result; -} - -void SymbolProperties::Initialize(void* address) -{ - this->Address = address; -# if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP) - // first fallback option can demangle c++ functions - Dl_info info; - int ierr = dladdr(this->Address, &info); - if (ierr && info.dli_sname && info.dli_saddr) { - this->SetBinary(info.dli_fname); - this->SetFunction(info.dli_sname); - } -# else -// second fallback use builtin backtrace_symbols -// to decode the bactrace. -# endif -} -#endif // don't define this class if we're not using it - -#if defined(_WIN32) || defined(__CYGWIN__) -# define KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes -#endif -#if defined(_MSC_VER) && _MSC_VER < 1310 -# undef KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes -#endif -#if defined(KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes) -double calculateCPULoad(unsigned __int64 idleTicks, - unsigned __int64 totalTicks) -{ - static double previousLoad = -0.0; - static unsigned __int64 previousIdleTicks = 0; - static unsigned __int64 previousTotalTicks = 0; - - unsigned __int64 const idleTicksSinceLastTime = - idleTicks - previousIdleTicks; - unsigned __int64 const totalTicksSinceLastTime = - totalTicks - previousTotalTicks; - - double load; - if (previousTotalTicks == 0 || totalTicksSinceLastTime == 0) { - // No new information. Use previous result. - load = previousLoad; - } else { - // Calculate load since last time. - load = 1.0 - double(idleTicksSinceLastTime) / totalTicksSinceLastTime; - - // Smooth if possible. - if (previousLoad > 0) { - load = 0.25 * load + 0.75 * previousLoad; - } - } - - previousLoad = load; - previousIdleTicks = idleTicks; - previousTotalTicks = totalTicks; - - return load; -} - -unsigned __int64 fileTimeToUInt64(FILETIME const& ft) -{ - LARGE_INTEGER out; - out.HighPart = ft.dwHighDateTime; - out.LowPart = ft.dwLowDateTime; - return out.QuadPart; -} -#endif - -} // anonymous namespace - -SystemInformationImplementation::SystemInformationImplementation() -{ - this->TotalVirtualMemory = 0; - this->AvailableVirtualMemory = 0; - this->TotalPhysicalMemory = 0; - this->AvailablePhysicalMemory = 0; - this->CurrentPositionInFile = 0; - this->ChipManufacturer = UnknownManufacturer; - memset(&this->Features, 0, sizeof(CPUFeatures)); - this->ChipID.Type = 0; - this->ChipID.Family = 0; - this->ChipID.Model = 0; - this->ChipID.Revision = 0; - this->ChipID.ExtendedFamily = 0; - this->ChipID.ExtendedModel = 0; - this->CPUSpeedInMHz = 0; - this->NumberOfLogicalCPU = 0; - this->NumberOfPhysicalCPU = 0; - this->OSName = ""; - this->Hostname = ""; - this->OSRelease = ""; - this->OSVersion = ""; - this->OSPlatform = ""; - this->OSIs64Bit = (sizeof(void*) == 8); -} - -SystemInformationImplementation::~SystemInformationImplementation() -{ -} - -void SystemInformationImplementation::RunCPUCheck() -{ -#ifdef _WIN32 - // Check to see if this processor supports CPUID. - bool supportsCPUID = DoesCPUSupportCPUID(); - - if (supportsCPUID) { - // Retrieve the CPU details. - RetrieveCPUIdentity(); - this->FindManufacturer(); - RetrieveCPUFeatures(); - } - - // These two may be called without support for the CPUID instruction. - // (But if the instruction is there, they should be called *after* - // the above call to RetrieveCPUIdentity... that's why the two if - // blocks exist with the same "if (supportsCPUID)" logic... - // - if (!RetrieveCPUClockSpeed()) { - RetrieveClassicalCPUClockSpeed(); - } - - if (supportsCPUID) { - // Retrieve cache information. - if (!RetrieveCPUCacheDetails()) { - RetrieveClassicalCPUCacheDetails(); - } - - // Retrieve the extended CPU details. - if (!RetrieveExtendedCPUIdentity()) { - RetrieveClassicalCPUIdentity(); - } - - RetrieveExtendedCPUFeatures(); - RetrieveCPUPowerManagement(); - - // Now attempt to retrieve the serial number (if possible). - RetrieveProcessorSerialNumber(); - } - - this->CPUCountWindows(); - -#elif defined(__APPLE__) - this->ParseSysCtl(); -#elif defined(__SVR4) && defined(__sun) - this->QuerySolarisProcessor(); -#elif defined(__HAIKU__) - this->QueryHaikuInfo(); -#elif defined(__QNX__) - this->QueryQNXProcessor(); -#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__DragonFly__) - this->QueryBSDProcessor(); -#elif defined(__hpux) - this->QueryHPUXProcessor(); -#elif defined(__linux) || defined(__CYGWIN__) - this->RetreiveInformationFromCpuInfoFile(); -#else - this->QueryProcessor(); -#endif -} - -void SystemInformationImplementation::RunOSCheck() -{ - this->QueryOSInformation(); -} - -void SystemInformationImplementation::RunMemoryCheck() -{ -#if defined(__APPLE__) - this->ParseSysCtl(); -#elif defined(__SVR4) && defined(__sun) - this->QuerySolarisMemory(); -#elif defined(__HAIKU__) - this->QueryHaikuInfo(); -#elif defined(__QNX__) - this->QueryQNXMemory(); -#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__DragonFly__) - this->QueryBSDMemory(); -#elif defined(__CYGWIN__) - this->QueryCygwinMemory(); -#elif defined(_WIN32) - this->QueryWindowsMemory(); -#elif defined(__hpux) - this->QueryHPUXMemory(); -#elif defined(__linux) - this->QueryLinuxMemory(); -#elif defined(_AIX) - this->QueryAIXMemory(); -#else - this->QueryMemory(); -#endif -} - -/** Get the vendor string */ -const char* SystemInformationImplementation::GetVendorString() -{ - return this->ChipID.Vendor.c_str(); -} - -/** Get the OS Name */ -const char* SystemInformationImplementation::GetOSName() -{ - return this->OSName.c_str(); -} - -/** Get the hostname */ -const char* SystemInformationImplementation::GetHostname() -{ - if (this->Hostname.empty()) { - this->Hostname = "localhost"; -#if defined(_WIN32) - WORD wVersionRequested; - WSADATA wsaData; - char name[255]; - wVersionRequested = MAKEWORD(2, 0); - if (WSAStartup(wVersionRequested, &wsaData) == 0) { - gethostname(name, sizeof(name)); - WSACleanup(); - } - this->Hostname = name; -#else - struct utsname unameInfo; - int errorFlag = uname(&unameInfo); - if (errorFlag == 0) { - this->Hostname = unameInfo.nodename; - } -#endif - } - return this->Hostname.c_str(); -} - -/** Get the FQDN */ -int SystemInformationImplementation::GetFullyQualifiedDomainName( - std::string& fqdn) -{ - // in the event of absolute failure return localhost. - fqdn = "localhost"; - -#if defined(_WIN32) - int ierr; - // TODO - a more robust implementation for windows, see comments - // in unix implementation. - WSADATA wsaData; - WORD ver = MAKEWORD(2, 0); - ierr = WSAStartup(ver, &wsaData); - if (ierr) { - return -1; - } - - char base[256] = { '\0' }; - ierr = gethostname(base, 256); - if (ierr) { - WSACleanup(); - return -2; - } - fqdn = base; - - HOSTENT* hent = gethostbyname(base); - if (hent) { - fqdn = hent->h_name; - } - - WSACleanup(); - return 0; - -#elif defined(KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN) - // gethostname typical returns an alias for loopback interface - // we want the fully qualified domain name. Because there are - // any number of interfaces on this system we look for the - // first of these that contains the name returned by gethostname - // and is longer. failing that we return gethostname and indicate - // with a failure code. Return of a failure code is not necessarily - // an indication of an error. for instance gethostname may return - // the fully qualified domain name, or there may not be one if the - // system lives on a private network such as in the case of a cluster - // node. - - int ierr = 0; - char base[NI_MAXHOST]; - ierr = gethostname(base, NI_MAXHOST); - if (ierr) { - return -1; - } - size_t baseSize = strlen(base); - fqdn = base; - - struct ifaddrs* ifas; - struct ifaddrs* ifa; - ierr = getifaddrs(&ifas); - if (ierr) { - return -2; - } - - for (ifa = ifas; ifa != nullptr; ifa = ifa->ifa_next) { - int fam = ifa->ifa_addr ? ifa->ifa_addr->sa_family : -1; - // Skip Loopback interfaces - if (((fam == AF_INET) || (fam == AF_INET6)) && - !(ifa->ifa_flags & IFF_LOOPBACK)) { - char host[NI_MAXHOST] = { '\0' }; - - const size_t addrlen = (fam == AF_INET ? sizeof(struct sockaddr_in) - : sizeof(struct sockaddr_in6)); - - ierr = getnameinfo(ifa->ifa_addr, static_cast(addrlen), host, - NI_MAXHOST, nullptr, 0, NI_NAMEREQD); - if (ierr) { - // don't report the failure now since we may succeed on another - // interface. If all attempts fail then return the failure code. - ierr = -3; - continue; - } - - std::string candidate = host; - if ((candidate.find(base) != std::string::npos) && - baseSize < candidate.size()) { - // success, stop now. - ierr = 0; - fqdn = candidate; - break; - } - } - } - freeifaddrs(ifas); - - return ierr; -#else - /* TODO: Implement on more platforms. */ - fqdn = this->GetHostname(); - return -1; -#endif -} - -/** Get the OS release */ -const char* SystemInformationImplementation::GetOSRelease() -{ - return this->OSRelease.c_str(); -} - -/** Get the OS version */ -const char* SystemInformationImplementation::GetOSVersion() -{ - return this->OSVersion.c_str(); -} - -/** Get the OS platform */ -const char* SystemInformationImplementation::GetOSPlatform() -{ - return this->OSPlatform.c_str(); -} - -/** Get the vendor ID */ -const char* SystemInformationImplementation::GetVendorID() -{ - // Return the vendor ID. - switch (this->ChipManufacturer) { - case Intel: - return "Intel Corporation"; - case AMD: - return "Advanced Micro Devices"; - case NSC: - return "National Semiconductor"; - case Cyrix: - return "Cyrix Corp., VIA Inc."; - case NexGen: - return "NexGen Inc., Advanced Micro Devices"; - case IDT: - return "IDT\\Centaur, Via Inc."; - case UMC: - return "United Microelectronics Corp."; - case Rise: - return "Rise"; - case Transmeta: - return "Transmeta"; - case Sun: - return "Sun Microelectronics"; - case IBM: - return "IBM"; - case Motorola: - return "Motorola"; - case HP: - return "Hewlett-Packard"; - case Hygon: - return "Chengdu Haiguang IC Design Co., Ltd."; - case UnknownManufacturer: - default: - return "Unknown Manufacturer"; - } -} - -/** Return the type ID of the CPU */ -std::string SystemInformationImplementation::GetTypeID() -{ - std::ostringstream str; - str << this->ChipID.Type; - return str.str(); -} - -/** Return the family of the CPU present */ -std::string SystemInformationImplementation::GetFamilyID() -{ - std::ostringstream str; - str << this->ChipID.Family; - return str.str(); -} - -// Return the model of CPU present */ -std::string SystemInformationImplementation::GetModelID() -{ - std::ostringstream str; - str << this->ChipID.Model; - return str.str(); -} - -// Return the model name of CPU present */ -std::string SystemInformationImplementation::GetModelName() -{ - return this->ChipID.ModelName; -} - -/** Return the stepping code of the CPU present. */ -std::string SystemInformationImplementation::GetSteppingCode() -{ - std::ostringstream str; - str << this->ChipID.Revision; - return str.str(); -} - -/** Return the stepping code of the CPU present. */ -const char* SystemInformationImplementation::GetExtendedProcessorName() -{ - return this->ChipID.ProcessorName.c_str(); -} - -/** Return the serial number of the processor - * in hexadecimal: xxxx-xxxx-xxxx-xxxx-xxxx-xxxx. */ -const char* SystemInformationImplementation::GetProcessorSerialNumber() -{ - return this->ChipID.SerialNumber.c_str(); -} - -/** Return the logical processors per physical */ -unsigned int SystemInformationImplementation::GetLogicalProcessorsPerPhysical() -{ - return this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical; -} - -/** Return the processor clock frequency. */ -float SystemInformationImplementation::GetProcessorClockFrequency() -{ - return this->CPUSpeedInMHz; -} - -/** Return the APIC ID. */ -int SystemInformationImplementation::GetProcessorAPICID() -{ - return this->Features.ExtendedFeatures.APIC_ID; -} - -/** Return the L1 cache size. */ -int SystemInformationImplementation::GetProcessorCacheSize() -{ - return this->Features.L1CacheSize; -} - -/** Return the chosen cache size. */ -int SystemInformationImplementation::GetProcessorCacheXSize(long int dwCacheID) -{ - switch (dwCacheID) { - case SystemInformation::CPU_FEATURE_L1CACHE: - return this->Features.L1CacheSize; - case SystemInformation::CPU_FEATURE_L2CACHE: - return this->Features.L2CacheSize; - case SystemInformation::CPU_FEATURE_L3CACHE: - return this->Features.L3CacheSize; - } - return -1; -} - -bool SystemInformationImplementation::DoesCPUSupportFeature(long int dwFeature) -{ - bool bHasFeature = false; - - // Check for MMX instructions. - if (((dwFeature & SystemInformation::CPU_FEATURE_MMX) != 0) && - this->Features.HasMMX) - bHasFeature = true; - - // Check for MMX+ instructions. - if (((dwFeature & SystemInformation::CPU_FEATURE_MMX_PLUS) != 0) && - this->Features.ExtendedFeatures.HasMMXPlus) - bHasFeature = true; - - // Check for SSE FP instructions. - if (((dwFeature & SystemInformation::CPU_FEATURE_SSE) != 0) && - this->Features.HasSSE) - bHasFeature = true; - - // Check for SSE FP instructions. - if (((dwFeature & SystemInformation::CPU_FEATURE_SSE_FP) != 0) && - this->Features.HasSSEFP) - bHasFeature = true; - - // Check for SSE MMX instructions. - if (((dwFeature & SystemInformation::CPU_FEATURE_SSE_MMX) != 0) && - this->Features.ExtendedFeatures.HasSSEMMX) - bHasFeature = true; - - // Check for SSE2 instructions. - if (((dwFeature & SystemInformation::CPU_FEATURE_SSE2) != 0) && - this->Features.HasSSE2) - bHasFeature = true; - - // Check for 3DNow! instructions. - if (((dwFeature & SystemInformation::CPU_FEATURE_AMD_3DNOW) != 0) && - this->Features.ExtendedFeatures.Has3DNow) - bHasFeature = true; - - // Check for 3DNow+ instructions. - if (((dwFeature & SystemInformation::CPU_FEATURE_AMD_3DNOW_PLUS) != 0) && - this->Features.ExtendedFeatures.Has3DNowPlus) - bHasFeature = true; - - // Check for IA64 instructions. - if (((dwFeature & SystemInformation::CPU_FEATURE_IA64) != 0) && - this->Features.HasIA64) - bHasFeature = true; - - // Check for MP capable. - if (((dwFeature & SystemInformation::CPU_FEATURE_MP_CAPABLE) != 0) && - this->Features.ExtendedFeatures.SupportsMP) - bHasFeature = true; - - // Check for a serial number for the processor. - if (((dwFeature & SystemInformation::CPU_FEATURE_SERIALNUMBER) != 0) && - this->Features.HasSerial) - bHasFeature = true; - - // Check for a local APIC in the processor. - if (((dwFeature & SystemInformation::CPU_FEATURE_APIC) != 0) && - this->Features.HasAPIC) - bHasFeature = true; - - // Check for CMOV instructions. - if (((dwFeature & SystemInformation::CPU_FEATURE_CMOV) != 0) && - this->Features.HasCMOV) - bHasFeature = true; - - // Check for MTRR instructions. - if (((dwFeature & SystemInformation::CPU_FEATURE_MTRR) != 0) && - this->Features.HasMTRR) - bHasFeature = true; - - // Check for L1 cache size. - if (((dwFeature & SystemInformation::CPU_FEATURE_L1CACHE) != 0) && - (this->Features.L1CacheSize != -1)) - bHasFeature = true; - - // Check for L2 cache size. - if (((dwFeature & SystemInformation::CPU_FEATURE_L2CACHE) != 0) && - (this->Features.L2CacheSize != -1)) - bHasFeature = true; - - // Check for L3 cache size. - if (((dwFeature & SystemInformation::CPU_FEATURE_L3CACHE) != 0) && - (this->Features.L3CacheSize != -1)) - bHasFeature = true; - - // Check for ACPI capability. - if (((dwFeature & SystemInformation::CPU_FEATURE_ACPI) != 0) && - this->Features.HasACPI) - bHasFeature = true; - - // Check for thermal monitor support. - if (((dwFeature & SystemInformation::CPU_FEATURE_THERMALMONITOR) != 0) && - this->Features.HasThermal) - bHasFeature = true; - - // Check for temperature sensing diode support. - if (((dwFeature & SystemInformation::CPU_FEATURE_TEMPSENSEDIODE) != 0) && - this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode) - bHasFeature = true; - - // Check for frequency ID support. - if (((dwFeature & SystemInformation::CPU_FEATURE_FREQUENCYID) != 0) && - this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID) - bHasFeature = true; - - // Check for voltage ID support. - if (((dwFeature & SystemInformation::CPU_FEATURE_VOLTAGEID_FREQUENCY) != - 0) && - this->Features.ExtendedFeatures.PowerManagement.HasVoltageID) - bHasFeature = true; - - // Check for FPU support. - if (((dwFeature & SystemInformation::CPU_FEATURE_FPU) != 0) && - this->Features.HasFPU) - bHasFeature = true; - - return bHasFeature; -} - -void SystemInformationImplementation::Delay(unsigned int uiMS) -{ -#ifdef _WIN32 - LARGE_INTEGER Frequency, StartCounter, EndCounter; - __int64 x; - - // Get the frequency of the high performance counter. - if (!QueryPerformanceFrequency(&Frequency)) - return; - x = Frequency.QuadPart / 1000 * uiMS; - - // Get the starting position of the counter. - QueryPerformanceCounter(&StartCounter); - - do { - // Get the ending position of the counter. - QueryPerformanceCounter(&EndCounter); - } while (EndCounter.QuadPart - StartCounter.QuadPart < x); -#endif - (void)uiMS; -} - -bool SystemInformationImplementation::DoesCPUSupportCPUID() -{ -#if USE_CPUID - int dummy[4] = { 0, 0, 0, 0 }; - -# if USE_ASM_INSTRUCTIONS - return call_cpuid(0, dummy); -# else - call_cpuid(0, dummy); - return dummy[0] || dummy[1] || dummy[2] || dummy[3]; -# endif -#else - // Assume no cpuid instruction. - return false; -#endif -} - -bool SystemInformationImplementation::RetrieveCPUFeatures() -{ -#if USE_CPUID - int cpuinfo[4] = { 0, 0, 0, 0 }; - - if (!call_cpuid(1, cpuinfo)) { - return false; - } - - // Retrieve the features of CPU present. - this->Features.HasFPU = - ((cpuinfo[3] & 0x00000001) != 0); // FPU Present --> Bit 0 - this->Features.HasTSC = - ((cpuinfo[3] & 0x00000010) != 0); // TSC Present --> Bit 4 - this->Features.HasAPIC = - ((cpuinfo[3] & 0x00000200) != 0); // APIC Present --> Bit 9 - this->Features.HasMTRR = - ((cpuinfo[3] & 0x00001000) != 0); // MTRR Present --> Bit 12 - this->Features.HasCMOV = - ((cpuinfo[3] & 0x00008000) != 0); // CMOV Present --> Bit 15 - this->Features.HasSerial = - ((cpuinfo[3] & 0x00040000) != 0); // Serial Present --> Bit 18 - this->Features.HasACPI = - ((cpuinfo[3] & 0x00400000) != 0); // ACPI Capable --> Bit 22 - this->Features.HasMMX = - ((cpuinfo[3] & 0x00800000) != 0); // MMX Present --> Bit 23 - this->Features.HasSSE = - ((cpuinfo[3] & 0x02000000) != 0); // SSE Present --> Bit 25 - this->Features.HasSSE2 = - ((cpuinfo[3] & 0x04000000) != 0); // SSE2 Present --> Bit 26 - this->Features.HasThermal = - ((cpuinfo[3] & 0x20000000) != 0); // Thermal Monitor Present --> Bit 29 - this->Features.HasIA64 = - ((cpuinfo[3] & 0x40000000) != 0); // IA64 Present --> Bit 30 - -# if USE_ASM_INSTRUCTIONS - // Retrieve extended SSE capabilities if SSE is available. - if (this->Features.HasSSE) { - - // Attempt to __try some SSE FP instructions. - __try { - // Perform: orps xmm0, xmm0 - _asm - { - _emit 0x0f - _emit 0x56 - _emit 0xc0 - } - - // SSE FP capable processor. - this->Features.HasSSEFP = true; - } __except (1) { - // bad instruction - processor or OS cannot handle SSE FP. - this->Features.HasSSEFP = false; - } - } else { - // Set the advanced SSE capabilities to not available. - this->Features.HasSSEFP = false; - } -# else - this->Features.HasSSEFP = false; -# endif - - // Retrieve Intel specific extended features. - if (this->ChipManufacturer == Intel) { - bool SupportsSMT = - ((cpuinfo[3] & 0x10000000) != 0); // Intel specific: SMT --> Bit 28 - - if ((SupportsSMT) && (this->Features.HasAPIC)) { - // Retrieve APIC information if there is one present. - this->Features.ExtendedFeatures.APIC_ID = - ((cpuinfo[1] & 0xFF000000) >> 24); - } - } - - return true; - -#else - return false; -#endif -} - -/** Find the manufacturer given the vendor id */ -void SystemInformationImplementation::FindManufacturer( - const std::string& family) -{ - if (this->ChipID.Vendor == "GenuineIntel") - this->ChipManufacturer = Intel; // Intel Corp. - else if (this->ChipID.Vendor == "UMC UMC UMC ") - this->ChipManufacturer = UMC; // United Microelectronics Corp. - else if (this->ChipID.Vendor == "AuthenticAMD") - this->ChipManufacturer = AMD; // Advanced Micro Devices - else if (this->ChipID.Vendor == "AMD ISBETTER") - this->ChipManufacturer = AMD; // Advanced Micro Devices (1994) - else if (this->ChipID.Vendor == "HygonGenuine") - this->ChipManufacturer = Hygon; // Chengdu Haiguang IC Design Co., Ltd. - else if (this->ChipID.Vendor == "CyrixInstead") - this->ChipManufacturer = Cyrix; // Cyrix Corp., VIA Inc. - else if (this->ChipID.Vendor == "NexGenDriven") - this->ChipManufacturer = NexGen; // NexGen Inc. (now AMD) - else if (this->ChipID.Vendor == "CentaurHauls") - this->ChipManufacturer = IDT; // IDT/Centaur (now VIA) - else if (this->ChipID.Vendor == "RiseRiseRise") - this->ChipManufacturer = Rise; // Rise - else if (this->ChipID.Vendor == "GenuineTMx86") - this->ChipManufacturer = Transmeta; // Transmeta - else if (this->ChipID.Vendor == "TransmetaCPU") - this->ChipManufacturer = Transmeta; // Transmeta - else if (this->ChipID.Vendor == "Geode By NSC") - this->ChipManufacturer = NSC; // National Semiconductor - else if (this->ChipID.Vendor == "Sun") - this->ChipManufacturer = Sun; // Sun Microelectronics - else if (this->ChipID.Vendor == "IBM") - this->ChipManufacturer = IBM; // IBM Microelectronics - else if (this->ChipID.Vendor == "Hewlett-Packard") - this->ChipManufacturer = HP; // Hewlett-Packard - else if (this->ChipID.Vendor == "Motorola") - this->ChipManufacturer = Motorola; // Motorola Microelectronics - else if (family.substr(0, 7) == "PA-RISC") - this->ChipManufacturer = HP; // Hewlett-Packard - else - this->ChipManufacturer = UnknownManufacturer; // Unknown manufacturer -} - -/** */ -bool SystemInformationImplementation::RetrieveCPUIdentity() -{ -#if USE_CPUID - int localCPUVendor[4]; - int localCPUSignature[4]; - - if (!call_cpuid(0, localCPUVendor)) { - return false; - } - if (!call_cpuid(1, localCPUSignature)) { - return false; - } - - // Process the returned information. - // ; eax = 0 --> eax: maximum value of CPUID instruction. - // ; ebx: part 1 of 3; CPU signature. - // ; edx: part 2 of 3; CPU signature. - // ; ecx: part 3 of 3; CPU signature. - char vbuf[13]; - memcpy(&(vbuf[0]), &(localCPUVendor[1]), sizeof(int)); - memcpy(&(vbuf[4]), &(localCPUVendor[3]), sizeof(int)); - memcpy(&(vbuf[8]), &(localCPUVendor[2]), sizeof(int)); - vbuf[12] = '\0'; - this->ChipID.Vendor = vbuf; - - // Retrieve the family of CPU present. - // ; eax = 1 --> eax: CPU ID - bits 31..16 - unused, bits 15..12 - type, - // bits 11..8 - family, bits 7..4 - model, bits 3..0 - mask revision - // ; ebx: 31..24 - default APIC ID, 23..16 - logical processor ID, - // 15..8 - CFLUSH chunk size , 7..0 - brand ID - // ; edx: CPU feature flags - this->ChipID.ExtendedFamily = - ((localCPUSignature[0] & 0x0FF00000) >> 20); // Bits 27..20 Used - this->ChipID.ExtendedModel = - ((localCPUSignature[0] & 0x000F0000) >> 16); // Bits 19..16 Used - this->ChipID.Type = - ((localCPUSignature[0] & 0x0000F000) >> 12); // Bits 15..12 Used - this->ChipID.Family = - ((localCPUSignature[0] & 0x00000F00) >> 8); // Bits 11..8 Used - this->ChipID.Model = - ((localCPUSignature[0] & 0x000000F0) >> 4); // Bits 7..4 Used - this->ChipID.Revision = - ((localCPUSignature[0] & 0x0000000F) >> 0); // Bits 3..0 Used - - return true; - -#else - return false; -#endif -} - -/** */ -bool SystemInformationImplementation::RetrieveCPUCacheDetails() -{ -#if USE_CPUID - int L1Cache[4] = { 0, 0, 0, 0 }; - int L2Cache[4] = { 0, 0, 0, 0 }; - - // Check to see if what we are about to do is supported... - if (RetrieveCPUExtendedLevelSupport(0x80000005)) { - if (!call_cpuid(0x80000005, L1Cache)) { - return false; - } - // Save the L1 data cache size (in KB) from ecx: bits 31..24 as well as - // data cache size from edx: bits 31..24. - this->Features.L1CacheSize = ((L1Cache[2] & 0xFF000000) >> 24); - this->Features.L1CacheSize += ((L1Cache[3] & 0xFF000000) >> 24); - } else { - // Store -1 to indicate the cache could not be queried. - this->Features.L1CacheSize = -1; - } - - // Check to see if what we are about to do is supported... - if (RetrieveCPUExtendedLevelSupport(0x80000006)) { - if (!call_cpuid(0x80000006, L2Cache)) { - return false; - } - // Save the L2 unified cache size (in KB) from ecx: bits 31..16. - this->Features.L2CacheSize = ((L2Cache[2] & 0xFFFF0000) >> 16); - } else { - // Store -1 to indicate the cache could not be queried. - this->Features.L2CacheSize = -1; - } - - // Define L3 as being not present as we cannot test for it. - this->Features.L3CacheSize = -1; - -#endif - - // Return failure if we cannot detect either cache with this method. - return ((this->Features.L1CacheSize == -1) && - (this->Features.L2CacheSize == -1)) - ? false - : true; -} - -/** */ -bool SystemInformationImplementation::RetrieveClassicalCPUCacheDetails() -{ -#if USE_CPUID - int TLBCode = -1, TLBData = -1, L1Code = -1, L1Data = -1, L1Trace = -1, - L2Unified = -1, L3Unified = -1; - int TLBCacheData[4] = { 0, 0, 0, 0 }; - int TLBPassCounter = 0; - int TLBCacheUnit = 0; - - do { - if (!call_cpuid(2, TLBCacheData)) { - return false; - } - - int bob = ((TLBCacheData[0] & 0x00FF0000) >> 16); - (void)bob; - // Process the returned TLB and cache information. - for (int nCounter = 0; nCounter < TLBCACHE_INFO_UNITS; nCounter++) { - // First of all - decide which unit we are dealing with. - switch (nCounter) { - // eax: bits 8..15 : bits 16..23 : bits 24..31 - case 0: - TLBCacheUnit = ((TLBCacheData[0] & 0x0000FF00) >> 8); - break; - case 1: - TLBCacheUnit = ((TLBCacheData[0] & 0x00FF0000) >> 16); - break; - case 2: - TLBCacheUnit = ((TLBCacheData[0] & 0xFF000000) >> 24); - break; - - // ebx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31 - case 3: - TLBCacheUnit = ((TLBCacheData[1] & 0x000000FF) >> 0); - break; - case 4: - TLBCacheUnit = ((TLBCacheData[1] & 0x0000FF00) >> 8); - break; - case 5: - TLBCacheUnit = ((TLBCacheData[1] & 0x00FF0000) >> 16); - break; - case 6: - TLBCacheUnit = ((TLBCacheData[1] & 0xFF000000) >> 24); - break; - - // ecx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31 - case 7: - TLBCacheUnit = ((TLBCacheData[2] & 0x000000FF) >> 0); - break; - case 8: - TLBCacheUnit = ((TLBCacheData[2] & 0x0000FF00) >> 8); - break; - case 9: - TLBCacheUnit = ((TLBCacheData[2] & 0x00FF0000) >> 16); - break; - case 10: - TLBCacheUnit = ((TLBCacheData[2] & 0xFF000000) >> 24); - break; - - // edx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31 - case 11: - TLBCacheUnit = ((TLBCacheData[3] & 0x000000FF) >> 0); - break; - case 12: - TLBCacheUnit = ((TLBCacheData[3] & 0x0000FF00) >> 8); - break; - case 13: - TLBCacheUnit = ((TLBCacheData[3] & 0x00FF0000) >> 16); - break; - case 14: - TLBCacheUnit = ((TLBCacheData[3] & 0xFF000000) >> 24); - break; - - // Default case - an error has occurred. - default: - return false; - } - - // Now process the resulting unit to see what it means.... - switch (TLBCacheUnit) { - case 0x00: - break; - case 0x01: - STORE_TLBCACHE_INFO(TLBCode, 4); - break; - case 0x02: - STORE_TLBCACHE_INFO(TLBCode, 4096); - break; - case 0x03: - STORE_TLBCACHE_INFO(TLBData, 4); - break; - case 0x04: - STORE_TLBCACHE_INFO(TLBData, 4096); - break; - case 0x06: - STORE_TLBCACHE_INFO(L1Code, 8); - break; - case 0x08: - STORE_TLBCACHE_INFO(L1Code, 16); - break; - case 0x0a: - STORE_TLBCACHE_INFO(L1Data, 8); - break; - case 0x0c: - STORE_TLBCACHE_INFO(L1Data, 16); - break; - case 0x10: - STORE_TLBCACHE_INFO(L1Data, 16); - break; // <-- FIXME: IA-64 Only - case 0x15: - STORE_TLBCACHE_INFO(L1Code, 16); - break; // <-- FIXME: IA-64 Only - case 0x1a: - STORE_TLBCACHE_INFO(L2Unified, 96); - break; // <-- FIXME: IA-64 Only - case 0x22: - STORE_TLBCACHE_INFO(L3Unified, 512); - break; - case 0x23: - STORE_TLBCACHE_INFO(L3Unified, 1024); - break; - case 0x25: - STORE_TLBCACHE_INFO(L3Unified, 2048); - break; - case 0x29: - STORE_TLBCACHE_INFO(L3Unified, 4096); - break; - case 0x39: - STORE_TLBCACHE_INFO(L2Unified, 128); - break; - case 0x3c: - STORE_TLBCACHE_INFO(L2Unified, 256); - break; - case 0x40: - STORE_TLBCACHE_INFO(L2Unified, 0); - break; // <-- FIXME: No integrated L2 cache (P6 core) or L3 cache (P4 - // core). - case 0x41: - STORE_TLBCACHE_INFO(L2Unified, 128); - break; - case 0x42: - STORE_TLBCACHE_INFO(L2Unified, 256); - break; - case 0x43: - STORE_TLBCACHE_INFO(L2Unified, 512); - break; - case 0x44: - STORE_TLBCACHE_INFO(L2Unified, 1024); - break; - case 0x45: - STORE_TLBCACHE_INFO(L2Unified, 2048); - break; - case 0x50: - STORE_TLBCACHE_INFO(TLBCode, 4096); - break; - case 0x51: - STORE_TLBCACHE_INFO(TLBCode, 4096); - break; - case 0x52: - STORE_TLBCACHE_INFO(TLBCode, 4096); - break; - case 0x5b: - STORE_TLBCACHE_INFO(TLBData, 4096); - break; - case 0x5c: - STORE_TLBCACHE_INFO(TLBData, 4096); - break; - case 0x5d: - STORE_TLBCACHE_INFO(TLBData, 4096); - break; - case 0x66: - STORE_TLBCACHE_INFO(L1Data, 8); - break; - case 0x67: - STORE_TLBCACHE_INFO(L1Data, 16); - break; - case 0x68: - STORE_TLBCACHE_INFO(L1Data, 32); - break; - case 0x70: - STORE_TLBCACHE_INFO(L1Trace, 12); - break; - case 0x71: - STORE_TLBCACHE_INFO(L1Trace, 16); - break; - case 0x72: - STORE_TLBCACHE_INFO(L1Trace, 32); - break; - case 0x77: - STORE_TLBCACHE_INFO(L1Code, 16); - break; // <-- FIXME: IA-64 Only - case 0x79: - STORE_TLBCACHE_INFO(L2Unified, 128); - break; - case 0x7a: - STORE_TLBCACHE_INFO(L2Unified, 256); - break; - case 0x7b: - STORE_TLBCACHE_INFO(L2Unified, 512); - break; - case 0x7c: - STORE_TLBCACHE_INFO(L2Unified, 1024); - break; - case 0x7e: - STORE_TLBCACHE_INFO(L2Unified, 256); - break; - case 0x81: - STORE_TLBCACHE_INFO(L2Unified, 128); - break; - case 0x82: - STORE_TLBCACHE_INFO(L2Unified, 256); - break; - case 0x83: - STORE_TLBCACHE_INFO(L2Unified, 512); - break; - case 0x84: - STORE_TLBCACHE_INFO(L2Unified, 1024); - break; - case 0x85: - STORE_TLBCACHE_INFO(L2Unified, 2048); - break; - case 0x88: - STORE_TLBCACHE_INFO(L3Unified, 2048); - break; // <-- FIXME: IA-64 Only - case 0x89: - STORE_TLBCACHE_INFO(L3Unified, 4096); - break; // <-- FIXME: IA-64 Only - case 0x8a: - STORE_TLBCACHE_INFO(L3Unified, 8192); - break; // <-- FIXME: IA-64 Only - case 0x8d: - STORE_TLBCACHE_INFO(L3Unified, 3096); - break; // <-- FIXME: IA-64 Only - case 0x90: - STORE_TLBCACHE_INFO(TLBCode, 262144); - break; // <-- FIXME: IA-64 Only - case 0x96: - STORE_TLBCACHE_INFO(TLBCode, 262144); - break; // <-- FIXME: IA-64 Only - case 0x9b: - STORE_TLBCACHE_INFO(TLBCode, 262144); - break; // <-- FIXME: IA-64 Only - - // Default case - an error has occurred. - default: - return false; - } - } - - // Increment the TLB pass counter. - TLBPassCounter++; - } while ((TLBCacheData[0] & 0x000000FF) > TLBPassCounter); - - // Ok - we now have the maximum TLB, L1, L2, and L3 sizes... - if ((L1Code == -1) && (L1Data == -1) && (L1Trace == -1)) { - this->Features.L1CacheSize = -1; - } else if ((L1Code == -1) && (L1Data == -1) && (L1Trace != -1)) { - this->Features.L1CacheSize = L1Trace; - } else if ((L1Code != -1) && (L1Data == -1)) { - this->Features.L1CacheSize = L1Code; - } else if ((L1Code == -1) && (L1Data != -1)) { - this->Features.L1CacheSize = L1Data; - } else if ((L1Code != -1) && (L1Data != -1)) { - this->Features.L1CacheSize = L1Code + L1Data; - } else { - this->Features.L1CacheSize = -1; - } - - // Ok - we now have the maximum TLB, L1, L2, and L3 sizes... - if (L2Unified == -1) { - this->Features.L2CacheSize = -1; - } else { - this->Features.L2CacheSize = L2Unified; - } - - // Ok - we now have the maximum TLB, L1, L2, and L3 sizes... - if (L3Unified == -1) { - this->Features.L3CacheSize = -1; - } else { - this->Features.L3CacheSize = L3Unified; - } - - return true; - -#else - return false; -#endif -} - -/** */ -bool SystemInformationImplementation::RetrieveCPUClockSpeed() -{ - bool retrieved = false; - -#if defined(_WIN32) - unsigned int uiRepetitions = 1; - unsigned int uiMSecPerRepetition = 50; - __int64 i64Total = 0; - __int64 i64Overhead = 0; - - // Check if the TSC implementation works at all - if (this->Features.HasTSC && - GetCyclesDifference(SystemInformationImplementation::Delay, - uiMSecPerRepetition) > 0) { - for (unsigned int nCounter = 0; nCounter < uiRepetitions; nCounter++) { - i64Total += GetCyclesDifference(SystemInformationImplementation::Delay, - uiMSecPerRepetition); - i64Overhead += GetCyclesDifference( - SystemInformationImplementation::DelayOverhead, uiMSecPerRepetition); - } - - // Calculate the MHz speed. - i64Total -= i64Overhead; - i64Total /= uiRepetitions; - i64Total /= uiMSecPerRepetition; - i64Total /= 1000; - - // Save the CPU speed. - this->CPUSpeedInMHz = (float)i64Total; - - retrieved = true; - } - - // If RDTSC is not supported, we fallback to trying to read this value - // from the registry: - if (!retrieved) { - HKEY hKey = nullptr; - LONG err = - RegOpenKeyExW(HKEY_LOCAL_MACHINE, - L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, - KEY_READ, &hKey); - - if (ERROR_SUCCESS == err) { - DWORD dwType = 0; - DWORD data = 0; - DWORD dwSize = sizeof(DWORD); - - err = - RegQueryValueExW(hKey, L"~MHz", 0, &dwType, (LPBYTE)&data, &dwSize); - - if (ERROR_SUCCESS == err) { - this->CPUSpeedInMHz = (float)data; - retrieved = true; - } - - RegCloseKey(hKey); - hKey = nullptr; - } - } -#endif - - return retrieved; -} - -/** */ -bool SystemInformationImplementation::RetrieveClassicalCPUClockSpeed() -{ -#if USE_ASM_INSTRUCTIONS - LARGE_INTEGER liStart, liEnd, liCountsPerSecond; - double dFrequency, dDifference; - - // Attempt to get a starting tick count. - QueryPerformanceCounter(&liStart); - - __try { - _asm { - mov eax, 0x80000000 - mov ebx, CLASSICAL_CPU_FREQ_LOOP - Timer_Loop: - bsf ecx,eax - dec ebx - jnz Timer_Loop - } - } __except (1) { - return false; - } - - // Attempt to get a starting tick count. - QueryPerformanceCounter(&liEnd); - - // Get the difference... NB: This is in seconds.... - QueryPerformanceFrequency(&liCountsPerSecond); - dDifference = (((double)liEnd.QuadPart - (double)liStart.QuadPart) / - (double)liCountsPerSecond.QuadPart); - - // Calculate the clock speed. - if (this->ChipID.Family == 3) { - // 80386 processors.... Loop time is 115 cycles! - dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 115) / dDifference) / 1000000); - } else if (this->ChipID.Family == 4) { - // 80486 processors.... Loop time is 47 cycles! - dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 47) / dDifference) / 1000000); - } else if (this->ChipID.Family == 5) { - // Pentium processors.... Loop time is 43 cycles! - dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 43) / dDifference) / 1000000); - } - - // Save the clock speed. - this->Features.CPUSpeed = (int)dFrequency; - - return true; - -#else - return false; -#endif -} - -/** */ -bool SystemInformationImplementation::RetrieveCPUExtendedLevelSupport( - int CPULevelToCheck) -{ - int cpuinfo[4] = { 0, 0, 0, 0 }; - - // The extended CPUID is supported by various vendors starting with the - // following CPU models: - // - // Manufacturer & Chip Name | Family Model Revision - // - // AMD K6, K6-2 | 5 6 x - // Cyrix GXm, Cyrix III "Joshua" | 5 4 x - // IDT C6-2 | 5 8 x - // VIA Cyrix III | 6 5 x - // Transmeta Crusoe | 5 x x - // Intel Pentium 4 | f x x - // - - // We check to see if a supported processor is present... - if (this->ChipManufacturer == AMD) { - if (this->ChipID.Family < 5) - return false; - if ((this->ChipID.Family == 5) && (this->ChipID.Model < 6)) - return false; - } else if (this->ChipManufacturer == Cyrix) { - if (this->ChipID.Family < 5) - return false; - if ((this->ChipID.Family == 5) && (this->ChipID.Model < 4)) - return false; - if ((this->ChipID.Family == 6) && (this->ChipID.Model < 5)) - return false; - } else if (this->ChipManufacturer == IDT) { - if (this->ChipID.Family < 5) - return false; - if ((this->ChipID.Family == 5) && (this->ChipID.Model < 8)) - return false; - } else if (this->ChipManufacturer == Transmeta) { - if (this->ChipID.Family < 5) - return false; - } else if (this->ChipManufacturer == Intel) { - if (this->ChipID.Family < 0xf) { - return false; - } - } - -#if USE_CPUID - if (!call_cpuid(0x80000000, cpuinfo)) { - return false; - } -#endif - - // Now we have to check the level wanted vs level returned... - int nLevelWanted = (CPULevelToCheck & 0x7FFFFFFF); - int nLevelReturn = (cpuinfo[0] & 0x7FFFFFFF); - - // Check to see if the level provided is supported... - if (nLevelWanted > nLevelReturn) { - return false; - } - - return true; -} - -/** */ -bool SystemInformationImplementation::RetrieveExtendedCPUFeatures() -{ - - // Check that we are not using an Intel processor as it does not support - // this. - if (this->ChipManufacturer == Intel) { - return false; - } - - // Check to see if what we are about to do is supported... - if (!RetrieveCPUExtendedLevelSupport(static_cast(0x80000001))) { - return false; - } - -#if USE_CPUID - int localCPUExtendedFeatures[4] = { 0, 0, 0, 0 }; - - if (!call_cpuid(0x80000001, localCPUExtendedFeatures)) { - return false; - } - - // Retrieve the extended features of CPU present. - this->Features.ExtendedFeatures.Has3DNow = - ((localCPUExtendedFeatures[3] & 0x80000000) != - 0); // 3DNow Present --> Bit 31. - this->Features.ExtendedFeatures.Has3DNowPlus = - ((localCPUExtendedFeatures[3] & 0x40000000) != - 0); // 3DNow+ Present -- > Bit 30. - this->Features.ExtendedFeatures.HasSSEMMX = - ((localCPUExtendedFeatures[3] & 0x00400000) != - 0); // SSE MMX Present --> Bit 22. - this->Features.ExtendedFeatures.SupportsMP = - ((localCPUExtendedFeatures[3] & 0x00080000) != - 0); // MP Capable -- > Bit 19. - - // Retrieve AMD specific extended features. - if (this->ChipManufacturer == AMD || this->ChipManufacturer == Hygon) { - this->Features.ExtendedFeatures.HasMMXPlus = - ((localCPUExtendedFeatures[3] & 0x00400000) != - 0); // AMD specific: MMX-SSE --> Bit 22 - } - - // Retrieve Cyrix specific extended features. - if (this->ChipManufacturer == Cyrix) { - this->Features.ExtendedFeatures.HasMMXPlus = - ((localCPUExtendedFeatures[3] & 0x01000000) != - 0); // Cyrix specific: Extended MMX --> Bit 24 - } - - return true; - -#else - return false; -#endif -} - -/** */ -bool SystemInformationImplementation::RetrieveProcessorSerialNumber() -{ - // Check to see if the processor supports the processor serial number. - if (!this->Features.HasSerial) { - return false; - } - -#if USE_CPUID - int SerialNumber[4]; - - if (!call_cpuid(3, SerialNumber)) { - return false; - } - - // Process the returned information. - // ; eax = 3 --> ebx: top 32 bits are the processor signature bits --> NB: - // Transmeta only ?!? - // ; ecx: middle 32 bits are the processor signature bits - // ; edx: bottom 32 bits are the processor signature bits - char sn[128]; - sprintf(sn, "%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x", - ((SerialNumber[1] & 0xff000000) >> 24), - ((SerialNumber[1] & 0x00ff0000) >> 16), - ((SerialNumber[1] & 0x0000ff00) >> 8), - ((SerialNumber[1] & 0x000000ff) >> 0), - ((SerialNumber[2] & 0xff000000) >> 24), - ((SerialNumber[2] & 0x00ff0000) >> 16), - ((SerialNumber[2] & 0x0000ff00) >> 8), - ((SerialNumber[2] & 0x000000ff) >> 0), - ((SerialNumber[3] & 0xff000000) >> 24), - ((SerialNumber[3] & 0x00ff0000) >> 16), - ((SerialNumber[3] & 0x0000ff00) >> 8), - ((SerialNumber[3] & 0x000000ff) >> 0)); - this->ChipID.SerialNumber = sn; - return true; - -#else - return false; -#endif -} - -/** */ -bool SystemInformationImplementation::RetrieveCPUPowerManagement() -{ - // Check to see if what we are about to do is supported... - if (!RetrieveCPUExtendedLevelSupport(static_cast(0x80000007))) { - this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID = false; - this->Features.ExtendedFeatures.PowerManagement.HasVoltageID = false; - this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode = false; - return false; - } - -#if USE_CPUID - int localCPUPowerManagement[4] = { 0, 0, 0, 0 }; - - if (!call_cpuid(0x80000007, localCPUPowerManagement)) { - return false; - } - - // Check for the power management capabilities of the CPU. - this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode = - ((localCPUPowerManagement[3] & 0x00000001) != 0); - this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID = - ((localCPUPowerManagement[3] & 0x00000002) != 0); - this->Features.ExtendedFeatures.PowerManagement.HasVoltageID = - ((localCPUPowerManagement[3] & 0x00000004) != 0); - - return true; - -#else - return false; -#endif -} - -#if USE_CPUID -// Used only in USE_CPUID implementation below. -static void SystemInformationStripLeadingSpace(std::string& str) -{ - // Because some manufacturers have leading white space - we have to - // post-process the name. - std::string::size_type pos = str.find_first_not_of(" "); - if (pos != std::string::npos) { - str = str.substr(pos); - } -} -#endif - -/** */ -bool SystemInformationImplementation::RetrieveExtendedCPUIdentity() -{ - // Check to see if what we are about to do is supported... - if (!RetrieveCPUExtendedLevelSupport(static_cast(0x80000002))) - return false; - if (!RetrieveCPUExtendedLevelSupport(static_cast(0x80000003))) - return false; - if (!RetrieveCPUExtendedLevelSupport(static_cast(0x80000004))) - return false; - -#if USE_CPUID - int CPUExtendedIdentity[12]; - - if (!call_cpuid(0x80000002, CPUExtendedIdentity)) { - return false; - } - if (!call_cpuid(0x80000003, CPUExtendedIdentity + 4)) { - return false; - } - if (!call_cpuid(0x80000004, CPUExtendedIdentity + 8)) { - return false; - } - - // Process the returned information. - char nbuf[49]; - memcpy(&(nbuf[0]), &(CPUExtendedIdentity[0]), sizeof(int)); - memcpy(&(nbuf[4]), &(CPUExtendedIdentity[1]), sizeof(int)); - memcpy(&(nbuf[8]), &(CPUExtendedIdentity[2]), sizeof(int)); - memcpy(&(nbuf[12]), &(CPUExtendedIdentity[3]), sizeof(int)); - memcpy(&(nbuf[16]), &(CPUExtendedIdentity[4]), sizeof(int)); - memcpy(&(nbuf[20]), &(CPUExtendedIdentity[5]), sizeof(int)); - memcpy(&(nbuf[24]), &(CPUExtendedIdentity[6]), sizeof(int)); - memcpy(&(nbuf[28]), &(CPUExtendedIdentity[7]), sizeof(int)); - memcpy(&(nbuf[32]), &(CPUExtendedIdentity[8]), sizeof(int)); - memcpy(&(nbuf[36]), &(CPUExtendedIdentity[9]), sizeof(int)); - memcpy(&(nbuf[40]), &(CPUExtendedIdentity[10]), sizeof(int)); - memcpy(&(nbuf[44]), &(CPUExtendedIdentity[11]), sizeof(int)); - nbuf[48] = '\0'; - this->ChipID.ProcessorName = nbuf; - this->ChipID.ModelName = nbuf; - - // Because some manufacturers have leading white space - we have to - // post-process the name. - SystemInformationStripLeadingSpace(this->ChipID.ProcessorName); - return true; -#else - return false; -#endif -} - -/** */ -bool SystemInformationImplementation::RetrieveClassicalCPUIdentity() -{ - // Start by decided which manufacturer we are using.... - switch (this->ChipManufacturer) { - case Intel: - // Check the family / model / revision to determine the CPU ID. - switch (this->ChipID.Family) { - case 3: - this->ChipID.ProcessorName = "Newer i80386 family"; - break; - case 4: - switch (this->ChipID.Model) { - case 0: - this->ChipID.ProcessorName = "i80486DX-25/33"; - break; - case 1: - this->ChipID.ProcessorName = "i80486DX-50"; - break; - case 2: - this->ChipID.ProcessorName = "i80486SX"; - break; - case 3: - this->ChipID.ProcessorName = "i80486DX2"; - break; - case 4: - this->ChipID.ProcessorName = "i80486SL"; - break; - case 5: - this->ChipID.ProcessorName = "i80486SX2"; - break; - case 7: - this->ChipID.ProcessorName = "i80486DX2 WriteBack"; - break; - case 8: - this->ChipID.ProcessorName = "i80486DX4"; - break; - case 9: - this->ChipID.ProcessorName = "i80486DX4 WriteBack"; - break; - default: - this->ChipID.ProcessorName = "Unknown 80486 family"; - return false; - } - break; - case 5: - switch (this->ChipID.Model) { - case 0: - this->ChipID.ProcessorName = "P5 A-Step"; - break; - case 1: - this->ChipID.ProcessorName = "P5"; - break; - case 2: - this->ChipID.ProcessorName = "P54C"; - break; - case 3: - this->ChipID.ProcessorName = "P24T OverDrive"; - break; - case 4: - this->ChipID.ProcessorName = "P55C"; - break; - case 7: - this->ChipID.ProcessorName = "P54C"; - break; - case 8: - this->ChipID.ProcessorName = "P55C (0.25micron)"; - break; - default: - this->ChipID.ProcessorName = "Unknown Pentium family"; - return false; - } - break; - case 6: - switch (this->ChipID.Model) { - case 0: - this->ChipID.ProcessorName = "P6 A-Step"; - break; - case 1: - this->ChipID.ProcessorName = "P6"; - break; - case 3: - this->ChipID.ProcessorName = "Pentium II (0.28 micron)"; - break; - case 5: - this->ChipID.ProcessorName = "Pentium II (0.25 micron)"; - break; - case 6: - this->ChipID.ProcessorName = "Pentium II With On-Die L2 Cache"; - break; - case 7: - this->ChipID.ProcessorName = "Pentium III (0.25 micron)"; - break; - case 8: - this->ChipID.ProcessorName = - "Pentium III (0.18 micron) With 256 KB On-Die L2 Cache "; - break; - case 0xa: - this->ChipID.ProcessorName = - "Pentium III (0.18 micron) With 1 Or 2 MB On-Die L2 Cache "; - break; - case 0xb: - this->ChipID.ProcessorName = "Pentium III (0.13 micron) With " - "256 Or 512 KB On-Die L2 Cache "; - break; - case 23: - this->ChipID.ProcessorName = - "Intel(R) Core(TM)2 Duo CPU T9500 @ 2.60GHz"; - break; - default: - this->ChipID.ProcessorName = "Unknown P6 family"; - return false; - } - break; - case 7: - this->ChipID.ProcessorName = "Intel Merced (IA-64)"; - break; - case 0xf: - // Check the extended family bits... - switch (this->ChipID.ExtendedFamily) { - case 0: - switch (this->ChipID.Model) { - case 0: - this->ChipID.ProcessorName = "Pentium IV (0.18 micron)"; - break; - case 1: - this->ChipID.ProcessorName = "Pentium IV (0.18 micron)"; - break; - case 2: - this->ChipID.ProcessorName = "Pentium IV (0.13 micron)"; - break; - default: - this->ChipID.ProcessorName = "Unknown Pentium 4 family"; - return false; - } - break; - case 1: - this->ChipID.ProcessorName = "Intel McKinley (IA-64)"; - break; - default: - this->ChipID.ProcessorName = "Pentium"; - } - break; - default: - this->ChipID.ProcessorName = "Unknown Intel family"; - return false; - } - break; - - case AMD: - // Check the family / model / revision to determine the CPU ID. - switch (this->ChipID.Family) { - case 4: - switch (this->ChipID.Model) { - case 3: - this->ChipID.ProcessorName = "80486DX2"; - break; - case 7: - this->ChipID.ProcessorName = "80486DX2 WriteBack"; - break; - case 8: - this->ChipID.ProcessorName = "80486DX4"; - break; - case 9: - this->ChipID.ProcessorName = "80486DX4 WriteBack"; - break; - case 0xe: - this->ChipID.ProcessorName = "5x86"; - break; - case 0xf: - this->ChipID.ProcessorName = "5x86WB"; - break; - default: - this->ChipID.ProcessorName = "Unknown 80486 family"; - return false; - } - break; - case 5: - switch (this->ChipID.Model) { - case 0: - this->ChipID.ProcessorName = "SSA5 (PR75, PR90 = PR100)"; - break; - case 1: - this->ChipID.ProcessorName = "5k86 (PR120 = PR133)"; - break; - case 2: - this->ChipID.ProcessorName = "5k86 (PR166)"; - break; - case 3: - this->ChipID.ProcessorName = "5k86 (PR200)"; - break; - case 6: - this->ChipID.ProcessorName = "K6 (0.30 micron)"; - break; - case 7: - this->ChipID.ProcessorName = "K6 (0.25 micron)"; - break; - case 8: - this->ChipID.ProcessorName = "K6-2"; - break; - case 9: - this->ChipID.ProcessorName = "K6-III"; - break; - case 0xd: - this->ChipID.ProcessorName = "K6-2+ or K6-III+ (0.18 micron)"; - break; - default: - this->ChipID.ProcessorName = "Unknown 80586 family"; - return false; - } - break; - case 6: - switch (this->ChipID.Model) { - case 1: - this->ChipID.ProcessorName = "Athlon- (0.25 micron)"; - break; - case 2: - this->ChipID.ProcessorName = "Athlon- (0.18 micron)"; - break; - case 3: - this->ChipID.ProcessorName = "Duron- (SF core)"; - break; - case 4: - this->ChipID.ProcessorName = "Athlon- (Thunderbird core)"; - break; - case 6: - this->ChipID.ProcessorName = "Athlon- (Palomino core)"; - break; - case 7: - this->ChipID.ProcessorName = "Duron- (Morgan core)"; - break; - case 8: - if (this->Features.ExtendedFeatures.SupportsMP) - this->ChipID.ProcessorName = "Athlon - MP (Thoroughbred core)"; - else - this->ChipID.ProcessorName = "Athlon - XP (Thoroughbred core)"; - break; - default: - this->ChipID.ProcessorName = "Unknown K7 family"; - return false; - } - break; - default: - this->ChipID.ProcessorName = "Unknown AMD family"; - return false; - } - break; - - case Hygon: - this->ChipID.ProcessorName = "Unknown Hygon family"; - return false; - - case Transmeta: - switch (this->ChipID.Family) { - case 5: - switch (this->ChipID.Model) { - case 4: - this->ChipID.ProcessorName = "Crusoe TM3x00 and TM5x00"; - break; - default: - this->ChipID.ProcessorName = "Unknown Crusoe family"; - return false; - } - break; - default: - this->ChipID.ProcessorName = "Unknown Transmeta family"; - return false; - } - break; - - case Rise: - switch (this->ChipID.Family) { - case 5: - switch (this->ChipID.Model) { - case 0: - this->ChipID.ProcessorName = "mP6 (0.25 micron)"; - break; - case 2: - this->ChipID.ProcessorName = "mP6 (0.18 micron)"; - break; - default: - this->ChipID.ProcessorName = "Unknown Rise family"; - return false; - } - break; - default: - this->ChipID.ProcessorName = "Unknown Rise family"; - return false; - } - break; - - case UMC: - switch (this->ChipID.Family) { - case 4: - switch (this->ChipID.Model) { - case 1: - this->ChipID.ProcessorName = "U5D"; - break; - case 2: - this->ChipID.ProcessorName = "U5S"; - break; - default: - this->ChipID.ProcessorName = "Unknown UMC family"; - return false; - } - break; - default: - this->ChipID.ProcessorName = "Unknown UMC family"; - return false; - } - break; - - case IDT: - switch (this->ChipID.Family) { - case 5: - switch (this->ChipID.Model) { - case 4: - this->ChipID.ProcessorName = "C6"; - break; - case 8: - this->ChipID.ProcessorName = "C2"; - break; - case 9: - this->ChipID.ProcessorName = "C3"; - break; - default: - this->ChipID.ProcessorName = "Unknown IDT\\Centaur family"; - return false; - } - break; - case 6: - switch (this->ChipID.Model) { - case 6: - this->ChipID.ProcessorName = "VIA Cyrix III - Samuel"; - break; - default: - this->ChipID.ProcessorName = "Unknown IDT\\Centaur family"; - return false; - } - break; - default: - this->ChipID.ProcessorName = "Unknown IDT\\Centaur family"; - return false; - } - break; - - case Cyrix: - switch (this->ChipID.Family) { - case 4: - switch (this->ChipID.Model) { - case 4: - this->ChipID.ProcessorName = "MediaGX GX = GXm"; - break; - case 9: - this->ChipID.ProcessorName = "5x86"; - break; - default: - this->ChipID.ProcessorName = "Unknown Cx5x86 family"; - return false; - } - break; - case 5: - switch (this->ChipID.Model) { - case 2: - this->ChipID.ProcessorName = "Cx6x86"; - break; - case 4: - this->ChipID.ProcessorName = "MediaGX GXm"; - break; - default: - this->ChipID.ProcessorName = "Unknown Cx6x86 family"; - return false; - } - break; - case 6: - switch (this->ChipID.Model) { - case 0: - this->ChipID.ProcessorName = "6x86MX"; - break; - case 5: - this->ChipID.ProcessorName = "Cyrix M2 Core"; - break; - case 6: - this->ChipID.ProcessorName = "WinChip C5A Core"; - break; - case 7: - this->ChipID.ProcessorName = "WinChip C5B\\C5C Core"; - break; - case 8: - this->ChipID.ProcessorName = "WinChip C5C-T Core"; - break; - default: - this->ChipID.ProcessorName = "Unknown 6x86MX\\Cyrix III family"; - return false; - } - break; - default: - this->ChipID.ProcessorName = "Unknown Cyrix family"; - return false; - } - break; - - case NexGen: - switch (this->ChipID.Family) { - case 5: - switch (this->ChipID.Model) { - case 0: - this->ChipID.ProcessorName = "Nx586 or Nx586FPU"; - break; - default: - this->ChipID.ProcessorName = "Unknown NexGen family"; - return false; - } - break; - default: - this->ChipID.ProcessorName = "Unknown NexGen family"; - return false; - } - break; - - case NSC: - this->ChipID.ProcessorName = "Cx486SLC \\ DLC \\ Cx486S A-Step"; - break; - - case Sun: - case IBM: - case Motorola: - case HP: - case UnknownManufacturer: - default: - this->ChipID.ProcessorName = - "Unknown family"; // We cannot identify the processor. - return false; - } - - return true; -} - -/** Extract a value from the CPUInfo file */ -std::string SystemInformationImplementation::ExtractValueFromCpuInfoFile( - std::string buffer, const char* word, size_t init) -{ - size_t pos = buffer.find(word, init); - if (pos != std::string::npos) { - this->CurrentPositionInFile = pos; - pos = buffer.find(":", pos); - size_t pos2 = buffer.find("\n", pos); - if (pos != std::string::npos && pos2 != std::string::npos) { - // It may happen that the beginning matches, but this is still not the - // requested key. - // An example is looking for "cpu" when "cpu family" comes first. So we - // check that - // we have only spaces from here to pos, otherwise we search again. - for (size_t i = this->CurrentPositionInFile + strlen(word); i < pos; - ++i) { - if (buffer[i] != ' ' && buffer[i] != '\t') { - return this->ExtractValueFromCpuInfoFile(buffer, word, pos2); - } - } - return buffer.substr(pos + 2, pos2 - pos - 2); - } - } - this->CurrentPositionInFile = std::string::npos; - return ""; -} - -/** Query for the cpu status */ -bool SystemInformationImplementation::RetreiveInformationFromCpuInfoFile() -{ - this->NumberOfLogicalCPU = 0; - this->NumberOfPhysicalCPU = 0; - std::string buffer; - - FILE* fd = fopen("/proc/cpuinfo", "r"); - if (!fd) { - std::cout << "Problem opening /proc/cpuinfo" << std::endl; - return false; - } - - size_t fileSize = 0; - while (!feof(fd)) { - buffer += static_cast(fgetc(fd)); - fileSize++; - } - fclose(fd); - buffer.resize(fileSize - 2); - // Number of logical CPUs (combination of multiple processors, multi-core - // and SMT) - size_t pos = buffer.find("processor\t"); - while (pos != std::string::npos) { - this->NumberOfLogicalCPU++; - pos = buffer.find("processor\t", pos + 1); - } - -#ifdef __linux - // Count sockets. - std::set PhysicalIDs; - std::string idc = this->ExtractValueFromCpuInfoFile(buffer, "physical id"); - while (this->CurrentPositionInFile != std::string::npos) { - int id = atoi(idc.c_str()); - PhysicalIDs.insert(id); - idc = this->ExtractValueFromCpuInfoFile(buffer, "physical id", - this->CurrentPositionInFile + 1); - } - uint64_t NumberOfSockets = PhysicalIDs.size(); - NumberOfSockets = std::max(NumberOfSockets, (uint64_t)1); - // Physical ids returned by Linux don't distinguish cores. - // We want to record the total number of cores in this->NumberOfPhysicalCPU - // (checking only the first proc) - std::string Cores = this->ExtractValueFromCpuInfoFile(buffer, "cpu cores"); - unsigned int NumberOfCoresPerSocket = (unsigned int)atoi(Cores.c_str()); - NumberOfCoresPerSocket = std::max(NumberOfCoresPerSocket, 1u); - this->NumberOfPhysicalCPU = - NumberOfCoresPerSocket * (unsigned int)NumberOfSockets; - -#else // __CYGWIN__ - // does not have "physical id" entries, neither "cpu cores" - // this has to be fixed for hyper-threading. - std::string cpucount = - this->ExtractValueFromCpuInfoFile(buffer, "cpu count"); - this->NumberOfPhysicalCPU = this->NumberOfLogicalCPU = - atoi(cpucount.c_str()); -#endif - // gotta have one, and if this is 0 then we get a / by 0n - // better to have a bad answer than a crash - if (this->NumberOfPhysicalCPU <= 0) { - this->NumberOfPhysicalCPU = 1; - } - // LogicalProcessorsPerPhysical>1 => SMT. - this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = - this->NumberOfLogicalCPU / this->NumberOfPhysicalCPU; - - // CPU speed (checking only the first processor) - std::string CPUSpeed = this->ExtractValueFromCpuInfoFile(buffer, "cpu MHz"); - if (!CPUSpeed.empty()) { - this->CPUSpeedInMHz = static_cast(atof(CPUSpeed.c_str())); - } -#ifdef __linux - else { - // Linux Sparc: CPU speed is in Hz and encoded in hexadecimal - CPUSpeed = this->ExtractValueFromCpuInfoFile(buffer, "Cpu0ClkTck"); - this->CPUSpeedInMHz = - static_cast(strtoull(CPUSpeed.c_str(), 0, 16)) / 1000000.0f; - } -#endif - - // Chip family - std::string familyStr = - this->ExtractValueFromCpuInfoFile(buffer, "cpu family"); - if (familyStr.empty()) { - familyStr = this->ExtractValueFromCpuInfoFile(buffer, "CPU architecture"); - } - this->ChipID.Family = atoi(familyStr.c_str()); - - // Chip Vendor - this->ChipID.Vendor = this->ExtractValueFromCpuInfoFile(buffer, "vendor_id"); - this->FindManufacturer(familyStr); - - // second try for setting family - if (this->ChipID.Family == 0 && this->ChipManufacturer == HP) { - if (familyStr == "PA-RISC 1.1a") - this->ChipID.Family = 0x11a; - else if (familyStr == "PA-RISC 2.0") - this->ChipID.Family = 0x200; - // If you really get CMake to work on a machine not belonging to - // any of those families I owe you a dinner if you get it to - // contribute nightly builds regularly. - } - - // Chip Model - this->ChipID.Model = - atoi(this->ExtractValueFromCpuInfoFile(buffer, "model").c_str()); - if (!this->RetrieveClassicalCPUIdentity()) { - // Some platforms (e.g. PA-RISC) tell us their CPU name here. - // Note: x86 does not. - std::string cpuname = this->ExtractValueFromCpuInfoFile(buffer, "cpu"); - if (!cpuname.empty()) { - this->ChipID.ProcessorName = cpuname; - } - } - - // Chip revision - std::string cpurev = this->ExtractValueFromCpuInfoFile(buffer, "stepping"); - if (cpurev.empty()) { - cpurev = this->ExtractValueFromCpuInfoFile(buffer, "CPU revision"); - } - this->ChipID.Revision = atoi(cpurev.c_str()); - - // Chip Model Name - this->ChipID.ModelName = - this->ExtractValueFromCpuInfoFile(buffer, "model name"); - - // L1 Cache size - // Different architectures may show different names for the caches. - // Sum up everything we find. - std::vector cachename; - cachename.clear(); - - cachename.push_back("cache size"); // e.g. x86 - cachename.push_back("I-cache"); // e.g. PA-RISC - cachename.push_back("D-cache"); // e.g. PA-RISC - - this->Features.L1CacheSize = 0; - for (size_t index = 0; index < cachename.size(); index++) { - std::string cacheSize = - this->ExtractValueFromCpuInfoFile(buffer, cachename[index]); - if (!cacheSize.empty()) { - pos = cacheSize.find(" KB"); - if (pos != std::string::npos) { - cacheSize = cacheSize.substr(0, pos); - } - this->Features.L1CacheSize += atoi(cacheSize.c_str()); - } - } - - // processor feature flags (probably x86 specific) - std::string cpuflags = this->ExtractValueFromCpuInfoFile(buffer, "flags"); - if (!cpurev.empty()) { - // now we can match every flags as space + flag + space - cpuflags = " " + cpuflags + " "; - if ((cpuflags.find(" fpu ") != std::string::npos)) { - this->Features.HasFPU = true; - } - if ((cpuflags.find(" tsc ") != std::string::npos)) { - this->Features.HasTSC = true; - } - if ((cpuflags.find(" mmx ") != std::string::npos)) { - this->Features.HasMMX = true; - } - if ((cpuflags.find(" sse ") != std::string::npos)) { - this->Features.HasSSE = true; - } - if ((cpuflags.find(" sse2 ") != std::string::npos)) { - this->Features.HasSSE2 = true; - } - if ((cpuflags.find(" apic ") != std::string::npos)) { - this->Features.HasAPIC = true; - } - if ((cpuflags.find(" cmov ") != std::string::npos)) { - this->Features.HasCMOV = true; - } - if ((cpuflags.find(" mtrr ") != std::string::npos)) { - this->Features.HasMTRR = true; - } - if ((cpuflags.find(" acpi ") != std::string::npos)) { - this->Features.HasACPI = true; - } - if ((cpuflags.find(" 3dnow ") != std::string::npos)) { - this->Features.ExtendedFeatures.Has3DNow = true; - } - } - - return true; -} - -bool SystemInformationImplementation::QueryProcessorBySysconf() -{ -#if defined(_SC_NPROC_ONLN) && !defined(_SC_NPROCESSORS_ONLN) -// IRIX names this slightly different -# define _SC_NPROCESSORS_ONLN _SC_NPROC_ONLN -#endif - -#ifdef _SC_NPROCESSORS_ONLN - long c = sysconf(_SC_NPROCESSORS_ONLN); - if (c <= 0) { - return false; - } - - this->NumberOfPhysicalCPU = static_cast(c); - this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU; - - return true; -#else - return false; -#endif -} - -bool SystemInformationImplementation::QueryProcessor() -{ - return this->QueryProcessorBySysconf(); -} - -/** -Get total system RAM in units of KiB. -*/ -SystemInformation::LongLong -SystemInformationImplementation::GetHostMemoryTotal() -{ -#if defined(_WIN32) -# if defined(_MSC_VER) && _MSC_VER < 1300 - MEMORYSTATUS stat; - stat.dwLength = sizeof(stat); - GlobalMemoryStatus(&stat); - return stat.dwTotalPhys / 1024; -# else - MEMORYSTATUSEX statex; - statex.dwLength = sizeof(statex); - GlobalMemoryStatusEx(&statex); - return statex.ullTotalPhys / 1024; -# endif -#elif defined(__linux) - SystemInformation::LongLong memTotal = 0; - int ierr = GetFieldFromFile("/proc/meminfo", "MemTotal:", memTotal); - if (ierr) { - return -1; - } - return memTotal; -#elif defined(__APPLE__) - uint64_t mem; - size_t len = sizeof(mem); - int ierr = sysctlbyname("hw.memsize", &mem, &len, nullptr, 0); - if (ierr) { - return -1; - } - return mem / 1024; -#else - return 0; -#endif -} - -/** -Get total system RAM in units of KiB. This may differ from the -host total if a host-wide resource limit is applied. -*/ -SystemInformation::LongLong -SystemInformationImplementation::GetHostMemoryAvailable( - const char* hostLimitEnvVarName) -{ - SystemInformation::LongLong memTotal = this->GetHostMemoryTotal(); - - // the following mechanism is provided for systems that - // apply resource limits across groups of processes. - // this is of use on certain SMP systems (eg. SGI UV) - // where the host has a large amount of ram but a given user's - // access to it is severely restricted. The system will - // apply a limit across a set of processes. Units are in KiB. - if (hostLimitEnvVarName) { - const char* hostLimitEnvVarValue = getenv(hostLimitEnvVarName); - if (hostLimitEnvVarValue) { - SystemInformation::LongLong hostLimit = - atoLongLong(hostLimitEnvVarValue); - if (hostLimit > 0) { - memTotal = min(hostLimit, memTotal); - } - } - } - - return memTotal; -} - -/** -Get total system RAM in units of KiB. This may differ from the -host total if a per-process resource limit is applied. -*/ -SystemInformation::LongLong -SystemInformationImplementation::GetProcMemoryAvailable( - const char* hostLimitEnvVarName, const char* procLimitEnvVarName) -{ - SystemInformation::LongLong memAvail = - this->GetHostMemoryAvailable(hostLimitEnvVarName); - - // the following mechanism is provide for systems where rlimits - // are not employed. Units are in KiB. - if (procLimitEnvVarName) { - const char* procLimitEnvVarValue = getenv(procLimitEnvVarName); - if (procLimitEnvVarValue) { - SystemInformation::LongLong procLimit = - atoLongLong(procLimitEnvVarValue); - if (procLimit > 0) { - memAvail = min(procLimit, memAvail); - } - } - } - -#if defined(__linux) - int ierr; - ResourceLimitType rlim; - ierr = GetResourceLimit(RLIMIT_DATA, &rlim); - if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) { - memAvail = - min((SystemInformation::LongLong)rlim.rlim_cur / 1024, memAvail); - } - - ierr = GetResourceLimit(RLIMIT_AS, &rlim); - if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) { - memAvail = - min((SystemInformation::LongLong)rlim.rlim_cur / 1024, memAvail); - } -#elif defined(__APPLE__) - struct rlimit rlim; - int ierr; - ierr = getrlimit(RLIMIT_DATA, &rlim); - if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) { - memAvail = - min((SystemInformation::LongLong)rlim.rlim_cur / 1024, memAvail); - } - - ierr = getrlimit(RLIMIT_RSS, &rlim); - if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) { - memAvail = - min((SystemInformation::LongLong)rlim.rlim_cur / 1024, memAvail); - } -#endif - - return memAvail; -} - -/** -Get RAM used by all processes in the host, in units of KiB. -*/ -SystemInformation::LongLong -SystemInformationImplementation::GetHostMemoryUsed() -{ -#if defined(_WIN32) -# if defined(_MSC_VER) && _MSC_VER < 1300 - MEMORYSTATUS stat; - stat.dwLength = sizeof(stat); - GlobalMemoryStatus(&stat); - return (stat.dwTotalPhys - stat.dwAvailPhys) / 1024; -# else - MEMORYSTATUSEX statex; - statex.dwLength = sizeof(statex); - GlobalMemoryStatusEx(&statex); - return (statex.ullTotalPhys - statex.ullAvailPhys) / 1024; -# endif -#elif defined(__linux) - // First try to use MemAvailable, but it only works on newer kernels - const char* names2[3] = { "MemTotal:", "MemAvailable:", nullptr }; - SystemInformation::LongLong values2[2] = { SystemInformation::LongLong(0) }; - int ierr = GetFieldsFromFile("/proc/meminfo", names2, values2); - if (ierr) { - const char* names4[5] = { "MemTotal:", "MemFree:", "Buffers:", "Cached:", - nullptr }; - SystemInformation::LongLong values4[4] = { SystemInformation::LongLong( - 0) }; - ierr = GetFieldsFromFile("/proc/meminfo", names4, values4); - if (ierr) { - return ierr; - } - SystemInformation::LongLong& memTotal = values4[0]; - SystemInformation::LongLong& memFree = values4[1]; - SystemInformation::LongLong& memBuffers = values4[2]; - SystemInformation::LongLong& memCached = values4[3]; - return memTotal - memFree - memBuffers - memCached; - } - SystemInformation::LongLong& memTotal = values2[0]; - SystemInformation::LongLong& memAvail = values2[1]; - return memTotal - memAvail; -#elif defined(__APPLE__) - SystemInformation::LongLong psz = getpagesize(); - if (psz < 1) { - return -1; - } - const char* names[3] = { "Pages wired down:", "Pages active:", nullptr }; - SystemInformation::LongLong values[2] = { SystemInformation::LongLong(0) }; - int ierr = GetFieldsFromCommand("vm_stat", names, values); - if (ierr) { - return -1; - } - SystemInformation::LongLong& vmWired = values[0]; - SystemInformation::LongLong& vmActive = values[1]; - return ((vmActive + vmWired) * psz) / 1024; -#else - return 0; -#endif -} - -/** -Get system RAM used by the process associated with the given -process id in units of KiB. -*/ -SystemInformation::LongLong -SystemInformationImplementation::GetProcMemoryUsed() -{ -#if defined(_WIN32) && defined(KWSYS_SYS_HAS_PSAPI) - long pid = GetCurrentProcessId(); - HANDLE hProc; - hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid); - if (hProc == 0) { - return -1; - } - PROCESS_MEMORY_COUNTERS pmc; - int ok = GetProcessMemoryInfo(hProc, &pmc, sizeof(pmc)); - CloseHandle(hProc); - if (!ok) { - return -2; - } - return pmc.WorkingSetSize / 1024; -#elif defined(__linux) - SystemInformation::LongLong memUsed = 0; - int ierr = GetFieldFromFile("/proc/self/status", "VmRSS:", memUsed); - if (ierr) { - return -1; - } - return memUsed; -#elif defined(__APPLE__) - SystemInformation::LongLong memUsed = 0; - pid_t pid = getpid(); - std::ostringstream oss; - oss << "ps -o rss= -p " << pid; - FILE* file = popen(oss.str().c_str(), "r"); - if (file == nullptr) { - return -1; - } - oss.str(""); - while (!feof(file) && !ferror(file)) { - char buf[256] = { '\0' }; - errno = 0; - size_t nRead = fread(buf, 1, 256, file); - if (ferror(file) && (errno == EINTR)) { - clearerr(file); - } - if (nRead) - oss << buf; - } - int ierr = ferror(file); - pclose(file); - if (ierr) { - return -2; - } - std::istringstream iss(oss.str()); - iss >> memUsed; - return memUsed; -#else - return 0; -#endif -} - -double SystemInformationImplementation::GetLoadAverage() -{ -#if defined(KWSYS_CXX_HAS_GETLOADAVG) - double loadavg[3] = { 0.0, 0.0, 0.0 }; - if (getloadavg(loadavg, 3) > 0) { - return loadavg[0]; - } - return -0.0; -#elif defined(KWSYS_SYSTEMINFORMATION_USE_GetSystemTimes) - // Old windows.h headers do not provide GetSystemTimes. - typedef BOOL(WINAPI * GetSystemTimesType)(LPFILETIME, LPFILETIME, - LPFILETIME); - static GetSystemTimesType pGetSystemTimes = - (GetSystemTimesType)GetProcAddress(GetModuleHandleW(L"kernel32"), - "GetSystemTimes"); - FILETIME idleTime, kernelTime, userTime; - if (pGetSystemTimes && pGetSystemTimes(&idleTime, &kernelTime, &userTime)) { - unsigned __int64 const idleTicks = fileTimeToUInt64(idleTime); - unsigned __int64 const totalTicks = - fileTimeToUInt64(kernelTime) + fileTimeToUInt64(userTime); - return calculateCPULoad(idleTicks, totalTicks) * GetNumberOfPhysicalCPU(); - } - return -0.0; -#else - // Not implemented on this platform. - return -0.0; -#endif -} - -/** -Get the process id of the running process. -*/ -SystemInformation::LongLong SystemInformationImplementation::GetProcessId() -{ -#if defined(_WIN32) - return GetCurrentProcessId(); -#elif defined(__linux) || defined(__APPLE__) || defined(__OpenBSD__) || \ - defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) - return getpid(); -#else - return -1; -#endif -} - -/** - * Used in GetProgramStack(...) below - */ -#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600 && defined(_MSC_VER) && \ - _MSC_VER >= 1800 -# define KWSYS_SYSTEMINFORMATION_HAS_DBGHELP -# define TRACE_MAX_STACK_FRAMES 1024 -# define TRACE_MAX_FUNCTION_NAME_LENGTH 1024 -# pragma warning(push) -# pragma warning(disable : 4091) /* 'typedef ': ignored on left of '' */ -# include "dbghelp.h" -# pragma warning(pop) -#endif - -/** -return current program stack in a string -demangle cxx symbols if possible. -*/ -std::string SystemInformationImplementation::GetProgramStack(int firstFrame, - int wholePath) -{ - std::ostringstream oss; - std::string programStack = ""; - -#ifdef KWSYS_SYSTEMINFORMATION_HAS_DBGHELP - (void)wholePath; - - void* stack[TRACE_MAX_STACK_FRAMES]; - HANDLE process = GetCurrentProcess(); - SymInitialize(process, nullptr, TRUE); - WORD numberOfFrames = - CaptureStackBackTrace(firstFrame, TRACE_MAX_STACK_FRAMES, stack, nullptr); - SYMBOL_INFO* symbol = static_cast( - malloc(sizeof(SYMBOL_INFO) + - (TRACE_MAX_FUNCTION_NAME_LENGTH - 1) * sizeof(TCHAR))); - symbol->MaxNameLen = TRACE_MAX_FUNCTION_NAME_LENGTH; - symbol->SizeOfStruct = sizeof(SYMBOL_INFO); - DWORD displacement; - IMAGEHLP_LINE64 line; - line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); - for (int i = 0; i < numberOfFrames; i++) { - DWORD64 address = reinterpret_cast(stack[i]); - SymFromAddr(process, address, nullptr, symbol); - if (SymGetLineFromAddr64(process, address, &displacement, &line)) { - oss << " at " << symbol->Name << " in " << line.FileName << " line " - << line.LineNumber << std::endl; - } else { - oss << " at " << symbol->Name << std::endl; - } - } - free(symbol); - -#else - programStack += "" -# if !defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) - "WARNING: The stack could not be examined " - "because backtrace is not supported.\n" -# elif !defined(KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD) - "WARNING: The stack trace will not use advanced " - "capabilities because this is a release build.\n" -# else -# if !defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP) - "WARNING: Function names will not be demangled " - "because dladdr is not available.\n" -# endif -# if !defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE) - "WARNING: Function names will not be demangled " - "because cxxabi is not available.\n" -# endif -# endif - ; - -# if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE) - void* stackSymbols[256]; - int nFrames = backtrace(stackSymbols, 256); - for (int i = firstFrame; i < nFrames; ++i) { - SymbolProperties symProps; - symProps.SetReportPath(wholePath); - symProps.Initialize(stackSymbols[i]); - oss << symProps << std::endl; - } -# else - (void)firstFrame; - (void)wholePath; -# endif -#endif - - programStack += oss.str(); - - return programStack; -} - -/** -when set print stack trace in response to common signals. -*/ -void SystemInformationImplementation::SetStackTraceOnError(int enable) -{ -#if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) - static int saOrigValid = 0; - static struct sigaction saABRTOrig; - static struct sigaction saSEGVOrig; - static struct sigaction saTERMOrig; - static struct sigaction saINTOrig; - static struct sigaction saILLOrig; - static struct sigaction saBUSOrig; - static struct sigaction saFPEOrig; - - if (enable && !saOrigValid) { - // save the current actions - sigaction(SIGABRT, nullptr, &saABRTOrig); - sigaction(SIGSEGV, nullptr, &saSEGVOrig); - sigaction(SIGTERM, nullptr, &saTERMOrig); - sigaction(SIGINT, nullptr, &saINTOrig); - sigaction(SIGILL, nullptr, &saILLOrig); - sigaction(SIGBUS, nullptr, &saBUSOrig); - sigaction(SIGFPE, nullptr, &saFPEOrig); - - // enable read, disable write - saOrigValid = 1; - - // install ours - struct sigaction sa; - sa.sa_sigaction = (SigAction)StacktraceSignalHandler; - sa.sa_flags = SA_SIGINFO | SA_RESETHAND; -# ifdef SA_RESTART - sa.sa_flags |= SA_RESTART; -# endif - sigemptyset(&sa.sa_mask); - - sigaction(SIGABRT, &sa, nullptr); - sigaction(SIGSEGV, &sa, nullptr); - sigaction(SIGTERM, &sa, nullptr); - sigaction(SIGINT, &sa, nullptr); - sigaction(SIGILL, &sa, nullptr); - sigaction(SIGBUS, &sa, nullptr); - sigaction(SIGFPE, &sa, nullptr); - } else if (!enable && saOrigValid) { - // restore previous actions - sigaction(SIGABRT, &saABRTOrig, nullptr); - sigaction(SIGSEGV, &saSEGVOrig, nullptr); - sigaction(SIGTERM, &saTERMOrig, nullptr); - sigaction(SIGINT, &saINTOrig, nullptr); - sigaction(SIGILL, &saILLOrig, nullptr); - sigaction(SIGBUS, &saBUSOrig, nullptr); - sigaction(SIGFPE, &saFPEOrig, nullptr); - - // enable write, disable read - saOrigValid = 0; - } -#else - // avoid warning C4100 - (void)enable; -#endif -} - -bool SystemInformationImplementation::QueryWindowsMemory() -{ -#if defined(_WIN32) -# if defined(_MSC_VER) && _MSC_VER < 1300 - MEMORYSTATUS ms; - unsigned long tv, tp, av, ap; - ms.dwLength = sizeof(ms); - GlobalMemoryStatus(&ms); -# define MEM_VAL(value) dw##value -# else - MEMORYSTATUSEX ms; - DWORDLONG tv, tp, av, ap; - ms.dwLength = sizeof(ms); - if (0 == GlobalMemoryStatusEx(&ms)) { - return 0; - } -# define MEM_VAL(value) ull##value -# endif - tv = ms.MEM_VAL(TotalPageFile); - tp = ms.MEM_VAL(TotalPhys); - av = ms.MEM_VAL(AvailPageFile); - ap = ms.MEM_VAL(AvailPhys); - this->TotalVirtualMemory = tv >> 10 >> 10; - this->TotalPhysicalMemory = tp >> 10 >> 10; - this->AvailableVirtualMemory = av >> 10 >> 10; - this->AvailablePhysicalMemory = ap >> 10 >> 10; - return true; -#else - return false; -#endif -} - -bool SystemInformationImplementation::QueryLinuxMemory() -{ -#if defined(__linux) - unsigned long tv = 0; - unsigned long tp = 0; - unsigned long av = 0; - unsigned long ap = 0; - - char buffer[1024]; // for reading lines - - int linuxMajor = 0; - int linuxMinor = 0; - - // Find the Linux kernel version first - struct utsname unameInfo; - int errorFlag = uname(&unameInfo); - if (errorFlag != 0) { - std::cout << "Problem calling uname(): " << strerror(errno) << std::endl; - return false; - } - - if (strlen(unameInfo.release) >= 3) { - // release looks like "2.6.3-15mdk-i686-up-4GB" - char majorChar = unameInfo.release[0]; - char minorChar = unameInfo.release[2]; - - if (isdigit(majorChar)) { - linuxMajor = majorChar - '0'; - } - - if (isdigit(minorChar)) { - linuxMinor = minorChar - '0'; - } - } - - FILE* fd = fopen("/proc/meminfo", "r"); - if (!fd) { - std::cout << "Problem opening /proc/meminfo" << std::endl; - return false; - } - - if (linuxMajor >= 3 || ((linuxMajor >= 2) && (linuxMinor >= 6))) { - // new /proc/meminfo format since kernel 2.6.x - // Rigorously, this test should check from the developing version 2.5.x - // that introduced the new format... - - enum - { - mMemTotal, - mMemFree, - mBuffers, - mCached, - mSwapTotal, - mSwapFree - }; - const char* format[6] = { "MemTotal:%lu kB", "MemFree:%lu kB", - "Buffers:%lu kB", "Cached:%lu kB", - "SwapTotal:%lu kB", "SwapFree:%lu kB" }; - bool have[6] = { false, false, false, false, false, false }; - unsigned long value[6]; - int count = 0; - while (fgets(buffer, static_cast(sizeof(buffer)), fd)) { - for (int i = 0; i < 6; ++i) { - if (!have[i] && sscanf(buffer, format[i], &value[i]) == 1) { - have[i] = true; - ++count; - } - } - } - if (count == 6) { - this->TotalPhysicalMemory = value[mMemTotal] / 1024; - this->AvailablePhysicalMemory = - (value[mMemFree] + value[mBuffers] + value[mCached]) / 1024; - this->TotalVirtualMemory = value[mSwapTotal] / 1024; - this->AvailableVirtualMemory = value[mSwapFree] / 1024; - } else { - std::cout << "Problem parsing /proc/meminfo" << std::endl; - fclose(fd); - return false; - } - } else { - // /proc/meminfo format for kernel older than 2.6.x - - unsigned long temp; - unsigned long cachedMem; - unsigned long buffersMem; - // Skip "total: used:..." - char* r = fgets(buffer, static_cast(sizeof(buffer)), fd); - int status = 0; - if (r == buffer) { - status += fscanf(fd, "Mem: %lu %lu %lu %lu %lu %lu\n", &tp, &temp, &ap, - &temp, &buffersMem, &cachedMem); - } - if (status == 6) { - status += fscanf(fd, "Swap: %lu %lu %lu\n", &tv, &temp, &av); - } - if (status == 9) { - this->TotalVirtualMemory = tv >> 10 >> 10; - this->TotalPhysicalMemory = tp >> 10 >> 10; - this->AvailableVirtualMemory = av >> 10 >> 10; - this->AvailablePhysicalMemory = - (ap + buffersMem + cachedMem) >> 10 >> 10; - } else { - std::cout << "Problem parsing /proc/meminfo" << std::endl; - fclose(fd); - return false; - } - } - fclose(fd); - - return true; -#else - return false; -#endif -} - -bool SystemInformationImplementation::QueryCygwinMemory() -{ -#ifdef __CYGWIN__ - // _SC_PAGE_SIZE does return the mmap() granularity on Cygwin, - // see http://cygwin.com/ml/cygwin/2006-06/msg00350.html - // Therefore just use 4096 as the page size of Windows. - long m = sysconf(_SC_PHYS_PAGES); - if (m < 0) { - return false; - } - this->TotalPhysicalMemory = m >> 8; - return true; -#else - return false; -#endif -} - -bool SystemInformationImplementation::QueryAIXMemory() -{ -#if defined(_AIX) && defined(_SC_AIX_REALMEM) - long c = sysconf(_SC_AIX_REALMEM); - if (c <= 0) { - return false; - } - - this->TotalPhysicalMemory = c / 1024; - - return true; -#else - return false; -#endif -} - -bool SystemInformationImplementation::QueryMemoryBySysconf() -{ -#if defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE) - // Assume the mmap() granularity as returned by _SC_PAGESIZE is also - // the system page size. The only known system where this isn't true - // is Cygwin. - long p = sysconf(_SC_PHYS_PAGES); - long m = sysconf(_SC_PAGESIZE); - - if (p < 0 || m < 0) { - return false; - } - - // assume pagesize is a power of 2 and smaller 1 MiB - size_t pagediv = (1024 * 1024 / m); - - this->TotalPhysicalMemory = p; - this->TotalPhysicalMemory /= pagediv; - -# if defined(_SC_AVPHYS_PAGES) - p = sysconf(_SC_AVPHYS_PAGES); - if (p < 0) { - return false; - } - - this->AvailablePhysicalMemory = p; - this->AvailablePhysicalMemory /= pagediv; -# endif - - return true; -#else - return false; -#endif -} - -/** Query for the memory status */ -bool SystemInformationImplementation::QueryMemory() -{ - return this->QueryMemoryBySysconf(); -} - -/** */ -size_t SystemInformationImplementation::GetTotalVirtualMemory() -{ - return this->TotalVirtualMemory; -} - -/** */ -size_t SystemInformationImplementation::GetAvailableVirtualMemory() -{ - return this->AvailableVirtualMemory; -} - -size_t SystemInformationImplementation::GetTotalPhysicalMemory() -{ - return this->TotalPhysicalMemory; -} - -/** */ -size_t SystemInformationImplementation::GetAvailablePhysicalMemory() -{ - return this->AvailablePhysicalMemory; -} - -/** Get Cycle differences */ -SystemInformation::LongLong -SystemInformationImplementation::GetCyclesDifference(DELAY_FUNC DelayFunction, - unsigned int uiParameter) -{ -#if defined(_MSC_VER) && (_MSC_VER >= 1400) - unsigned __int64 stamp1, stamp2; - - stamp1 = __rdtsc(); - DelayFunction(uiParameter); - stamp2 = __rdtsc(); - - return stamp2 - stamp1; -#elif USE_ASM_INSTRUCTIONS - - unsigned int edx1, eax1; - unsigned int edx2, eax2; - - // Calculate the frequency of the CPU instructions. - __try { - _asm { - push uiParameter ; push parameter param - mov ebx, DelayFunction ; store func in ebx - - RDTSC_INSTRUCTION - - mov esi, eax ; esi = eax - mov edi, edx ; edi = edx - - call ebx ; call the delay functions - - RDTSC_INSTRUCTION - - pop ebx - - mov edx2, edx ; edx2 = edx - mov eax2, eax ; eax2 = eax - - mov edx1, edi ; edx2 = edi - mov eax1, esi ; eax2 = esi - } - } __except (1) { - return -1; - } - - return ((((__int64)edx2 << 32) + eax2) - (((__int64)edx1 << 32) + eax1)); - -#else - (void)DelayFunction; - (void)uiParameter; - return -1; -#endif -} - -/** Compute the delay overhead */ -void SystemInformationImplementation::DelayOverhead(unsigned int uiMS) -{ -#if defined(_WIN32) - LARGE_INTEGER Frequency, StartCounter, EndCounter; - __int64 x; - - // Get the frequency of the high performance counter. - if (!QueryPerformanceFrequency(&Frequency)) { - return; - } - x = Frequency.QuadPart / 1000 * uiMS; - - // Get the starting position of the counter. - QueryPerformanceCounter(&StartCounter); - - do { - // Get the ending position of the counter. - QueryPerformanceCounter(&EndCounter); - } while (EndCounter.QuadPart - StartCounter.QuadPart == x); -#endif - (void)uiMS; -} - -/** Works only for windows */ -bool SystemInformationImplementation::IsSMTSupported() -{ - return this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical > 1; -} - -/** Return the APIC Id. Works only for windows. */ -unsigned char SystemInformationImplementation::GetAPICId() -{ - int Regs[4] = { 0, 0, 0, 0 }; - -#if USE_CPUID - if (!this->IsSMTSupported()) { - return static_cast(-1); // HT not supported - } // Logical processor = 1 - call_cpuid(1, Regs); -#endif - - return static_cast((Regs[1] & INITIAL_APIC_ID_BITS) >> 24); -} - -/** Count the number of CPUs. Works only on windows. */ -void SystemInformationImplementation::CPUCountWindows() -{ -#if defined(_WIN32) - this->NumberOfPhysicalCPU = 0; - this->NumberOfLogicalCPU = 0; - - typedef BOOL(WINAPI * GetLogicalProcessorInformationType)( - PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD); - static GetLogicalProcessorInformationType pGetLogicalProcessorInformation = - (GetLogicalProcessorInformationType)GetProcAddress( - GetModuleHandleW(L"kernel32"), "GetLogicalProcessorInformation"); - - if (!pGetLogicalProcessorInformation) { - // Fallback to approximate implementation on ancient Windows versions. - SYSTEM_INFO info; - ZeroMemory(&info, sizeof(info)); - GetSystemInfo(&info); - this->NumberOfPhysicalCPU = - static_cast(info.dwNumberOfProcessors); - this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU; - return; - } - - std::vector ProcInfo; - { - DWORD Length = 0; - DWORD rc = pGetLogicalProcessorInformation(nullptr, &Length); - assert(FALSE == rc); - (void)rc; // Silence unused variable warning in Borland C++ 5.81 - assert(GetLastError() == ERROR_INSUFFICIENT_BUFFER); - ProcInfo.resize(Length / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION)); - rc = pGetLogicalProcessorInformation(&ProcInfo[0], &Length); - assert(rc != FALSE); - (void)rc; // Silence unused variable warning in Borland C++ 5.81 - } - - typedef std::vector::iterator - pinfoIt_t; - for (pinfoIt_t it = ProcInfo.begin(); it != ProcInfo.end(); ++it) { - SYSTEM_LOGICAL_PROCESSOR_INFORMATION PInfo = *it; - if (PInfo.Relationship != RelationProcessorCore) { - continue; - } - - std::bitset::digits> ProcMask( - (unsigned long long)PInfo.ProcessorMask); - unsigned int count = (unsigned int)ProcMask.count(); - if (count == 0) { // I think this should never happen, but just to be safe. - continue; - } - this->NumberOfPhysicalCPU++; - this->NumberOfLogicalCPU += (unsigned int)count; - this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = count; - } - this->NumberOfPhysicalCPU = std::max(1u, this->NumberOfPhysicalCPU); - this->NumberOfLogicalCPU = std::max(1u, this->NumberOfLogicalCPU); -#else -#endif -} - -/** Return the number of logical CPUs on the system */ -unsigned int SystemInformationImplementation::GetNumberOfLogicalCPU() -{ - return this->NumberOfLogicalCPU; -} - -/** Return the number of physical CPUs on the system */ -unsigned int SystemInformationImplementation::GetNumberOfPhysicalCPU() -{ - return this->NumberOfPhysicalCPU; -} - -/** For Mac use sysctlbyname calls to find system info */ -bool SystemInformationImplementation::ParseSysCtl() -{ -#if defined(__APPLE__) - char retBuf[128]; - int err = 0; - uint64_t value = 0; - size_t len = sizeof(value); - sysctlbyname("hw.memsize", &value, &len, nullptr, 0); - this->TotalPhysicalMemory = static_cast(value / 1048576); - - // Parse values for Mac - this->AvailablePhysicalMemory = 0; - vm_statistics_data_t vmstat; - mach_msg_type_number_t count = HOST_VM_INFO_COUNT; - if (host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vmstat, - &count) == KERN_SUCCESS) { - len = sizeof(value); - err = sysctlbyname("hw.pagesize", &value, &len, nullptr, 0); - int64_t available_memory = - (vmstat.free_count + vmstat.inactive_count) * value; - this->AvailablePhysicalMemory = - static_cast(available_memory / 1048576); - } - -# ifdef VM_SWAPUSAGE - // Virtual memory. - int mib[2] = { CTL_VM, VM_SWAPUSAGE }; - unsigned int miblen = - static_cast(sizeof(mib) / sizeof(mib[0])); - struct xsw_usage swap; - len = sizeof(swap); - err = sysctl(mib, miblen, &swap, &len, nullptr, 0); - if (err == 0) { - this->AvailableVirtualMemory = - static_cast(swap.xsu_avail / 1048576); - this->TotalVirtualMemory = static_cast(swap.xsu_total / 1048576); - } -# else - this->AvailableVirtualMemory = 0; - this->TotalVirtualMemory = 0; -# endif - - // CPU Info - len = sizeof(this->NumberOfPhysicalCPU); - sysctlbyname("hw.physicalcpu", &this->NumberOfPhysicalCPU, &len, nullptr, 0); - len = sizeof(this->NumberOfLogicalCPU); - sysctlbyname("hw.logicalcpu", &this->NumberOfLogicalCPU, &len, nullptr, 0); - - int cores_per_package = 0; - len = sizeof(cores_per_package); - err = sysctlbyname("machdep.cpu.cores_per_package", &cores_per_package, &len, - nullptr, 0); - // That name was not found, default to 1 - this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = - err != 0 ? 1 : static_cast(cores_per_package); - - len = sizeof(value); - sysctlbyname("hw.cpufrequency", &value, &len, nullptr, 0); - this->CPUSpeedInMHz = static_cast(value) / 1000000; - - // Chip family - len = sizeof(this->ChipID.Family); - // Seems only the intel chips will have this name so if this fails it is - // probably a PPC machine - err = - sysctlbyname("machdep.cpu.family", &this->ChipID.Family, &len, nullptr, 0); - if (err != 0) // Go back to names we know but are less descriptive - { - this->ChipID.Family = 0; - ::memset(retBuf, 0, 128); - len = 32; - err = sysctlbyname("hw.machine", &retBuf, &len, nullptr, 0); - std::string machineBuf(retBuf); - if (machineBuf.find_first_of("Power") != std::string::npos) { - this->ChipID.Vendor = "IBM"; - len = sizeof(this->ChipID.Family); - err = sysctlbyname("hw.cputype", &this->ChipID.Family, &len, nullptr, 0); - len = sizeof(this->ChipID.Model); - err = - sysctlbyname("hw.cpusubtype", &this->ChipID.Model, &len, nullptr, 0); - this->FindManufacturer(); - } - } else // Should be an Intel Chip. - { - len = sizeof(this->ChipID.Family); - err = sysctlbyname("machdep.cpu.family", &this->ChipID.Family, &len, - nullptr, 0); - - ::memset(retBuf, 0, 128); - len = 128; - err = sysctlbyname("machdep.cpu.vendor", retBuf, &len, nullptr, 0); - // Chip Vendor - this->ChipID.Vendor = retBuf; - this->FindManufacturer(); - - // Chip Model - len = sizeof(value); - err = sysctlbyname("machdep.cpu.model", &value, &len, nullptr, 0); - this->ChipID.Model = static_cast(value); - - // Chip Stepping - len = sizeof(value); - value = 0; - err = sysctlbyname("machdep.cpu.stepping", &value, &len, nullptr, 0); - if (!err) { - this->ChipID.Revision = static_cast(value); - } - - // feature string - char* buf = nullptr; - size_t allocSize = 128; - - err = 0; - len = 0; - - // sysctlbyname() will return with err==0 && len==0 if the buffer is too - // small - while (err == 0 && len == 0) { - delete[] buf; - allocSize *= 2; - buf = new char[allocSize]; - if (!buf) { - break; - } - buf[0] = ' '; - len = allocSize - 2; // keep space for leading and trailing space - err = sysctlbyname("machdep.cpu.features", buf + 1, &len, nullptr, 0); - } - if (!err && buf && len) { - // now we can match every flags as space + flag + space - buf[len + 1] = ' '; - std::string cpuflags(buf, len + 2); - - if ((cpuflags.find(" FPU ") != std::string::npos)) { - this->Features.HasFPU = true; - } - if ((cpuflags.find(" TSC ") != std::string::npos)) { - this->Features.HasTSC = true; - } - if ((cpuflags.find(" MMX ") != std::string::npos)) { - this->Features.HasMMX = true; - } - if ((cpuflags.find(" SSE ") != std::string::npos)) { - this->Features.HasSSE = true; - } - if ((cpuflags.find(" SSE2 ") != std::string::npos)) { - this->Features.HasSSE2 = true; - } - if ((cpuflags.find(" APIC ") != std::string::npos)) { - this->Features.HasAPIC = true; - } - if ((cpuflags.find(" CMOV ") != std::string::npos)) { - this->Features.HasCMOV = true; - } - if ((cpuflags.find(" MTRR ") != std::string::npos)) { - this->Features.HasMTRR = true; - } - if ((cpuflags.find(" ACPI ") != std::string::npos)) { - this->Features.HasACPI = true; - } - } - delete[] buf; - } - - // brand string - ::memset(retBuf, 0, sizeof(retBuf)); - len = sizeof(retBuf); - err = sysctlbyname("machdep.cpu.brand_string", retBuf, &len, nullptr, 0); - if (!err) { - this->ChipID.ProcessorName = retBuf; - this->ChipID.ModelName = retBuf; - } - - // Cache size - len = sizeof(value); - err = sysctlbyname("hw.l1icachesize", &value, &len, nullptr, 0); - this->Features.L1CacheSize = static_cast(value); - len = sizeof(value); - err = sysctlbyname("hw.l2cachesize", &value, &len, nullptr, 0); - this->Features.L2CacheSize = static_cast(value); - - return true; -#else - return false; -#endif -} - -/** Extract a value from sysctl command */ -std::string SystemInformationImplementation::ExtractValueFromSysCtl( - const char* word) -{ - size_t pos = this->SysCtlBuffer.find(word); - if (pos != std::string::npos) { - pos = this->SysCtlBuffer.find(": ", pos); - size_t pos2 = this->SysCtlBuffer.find("\n", pos); - if (pos != std::string::npos && pos2 != std::string::npos) { - return this->SysCtlBuffer.substr(pos + 2, pos2 - pos - 2); - } - } - return ""; -} - -/** Run a given process */ -std::string SystemInformationImplementation::RunProcess( - std::vector args) -{ - std::string buffer; - - // Run the application - kwsysProcess* gp = kwsysProcess_New(); - kwsysProcess_SetCommand(gp, args.data()); - kwsysProcess_SetOption(gp, kwsysProcess_Option_HideWindow, 1); - - kwsysProcess_Execute(gp); - - char* data = nullptr; - int length; - double timeout = 255; - int pipe; // pipe id as returned by kwsysProcess_WaitForData() - - while ((static_cast( - pipe = kwsysProcess_WaitForData(gp, &data, &length, &timeout)), - (pipe == kwsysProcess_Pipe_STDOUT || - pipe == kwsysProcess_Pipe_STDERR))) // wait for 1s - { - buffer.append(data, length); - } - kwsysProcess_WaitForExit(gp, nullptr); - - int result = 0; - switch (kwsysProcess_GetState(gp)) { - case kwsysProcess_State_Exited: { - result = kwsysProcess_GetExitValue(gp); - } break; - case kwsysProcess_State_Error: { - std::cerr << "Error: Could not run " << args[0] << ":\n"; - std::cerr << kwsysProcess_GetErrorString(gp) << "\n"; - } break; - case kwsysProcess_State_Exception: { - std::cerr << "Error: " << args[0] << " terminated with an exception: " - << kwsysProcess_GetExceptionString(gp) << "\n"; - } break; - case kwsysProcess_State_Starting: - case kwsysProcess_State_Executing: - case kwsysProcess_State_Expired: - case kwsysProcess_State_Killed: { - // Should not get here. - std::cerr << "Unexpected ending state after running " << args[0] - << std::endl; - } break; - } - kwsysProcess_Delete(gp); - if (result) { - std::cerr << "Error " << args[0] << " returned :" << result << "\n"; - } - return buffer; -} - -std::string SystemInformationImplementation::ParseValueFromKStat( - const char* arguments) -{ - std::vector args_string; - std::string command = arguments; - size_t start = std::string::npos; - size_t pos = command.find(' ', 0); - while (pos != std::string::npos) { - bool inQuotes = false; - // Check if we are between quotes - size_t b0 = command.find('"', 0); - size_t b1 = command.find('"', b0 + 1); - while (b0 != std::string::npos && b1 != std::string::npos && b1 > b0) { - if (pos > b0 && pos < b1) { - inQuotes = true; - break; - } - b0 = command.find('"', b1 + 1); - b1 = command.find('"', b0 + 1); - } - - if (!inQuotes) { - args_string.push_back(command.substr(start + 1, pos - start - 1)); - std::string& arg = args_string.back(); - - // Remove the quotes if any - arg.erase(std::remove(arg.begin(), arg.end(), '"'), arg.end()); - start = pos; - } - pos = command.find(' ', pos + 1); - } - args_string.push_back(command.substr(start + 1, command.size() - start - 1)); - - std::vector args; - args.reserve(3 + args_string.size()); - args.push_back("kstat"); - args.push_back("-p"); - for (size_t i = 0; i < args_string.size(); ++i) { - args.push_back(args_string[i].c_str()); - } - args.push_back(nullptr); - - std::string buffer = this->RunProcess(args); - - std::string value; - for (size_t i = buffer.size() - 1; i > 0; i--) { - if (buffer[i] == ' ' || buffer[i] == '\t') { - break; - } - if (buffer[i] != '\n' && buffer[i] != '\r') { - value.insert(0u, 1, buffer[i]); - } - } - return value; -} - -/** Querying for system information from Solaris */ -bool SystemInformationImplementation::QuerySolarisMemory() -{ -#if defined(__SVR4) && defined(__sun) -// Solaris allows querying this value by sysconf, but if this is -// a 32 bit process on a 64 bit host the returned memory will be -// limited to 4GiB. So if this is a 32 bit process or if the sysconf -// method fails use the kstat interface. -# if SIZEOF_VOID_P == 8 - if (this->QueryMemoryBySysconf()) { - return true; - } -# endif - - char* tail; - unsigned long totalMemory = - strtoul(this->ParseValueFromKStat("-s physmem").c_str(), &tail, 0); - this->TotalPhysicalMemory = totalMemory / 128; - - return true; -#else - return false; -#endif -} - -bool SystemInformationImplementation::QuerySolarisProcessor() -{ - if (!this->QueryProcessorBySysconf()) { - return false; - } - - // Parse values - this->CPUSpeedInMHz = static_cast( - atoi(this->ParseValueFromKStat("-s clock_MHz").c_str())); - - // Chip family - this->ChipID.Family = 0; - - // Chip Model - this->ChipID.ProcessorName = this->ParseValueFromKStat("-s cpu_type"); - this->ChipID.Model = 0; - - // Chip Vendor - if (this->ChipID.ProcessorName != "i386") { - this->ChipID.Vendor = "Sun"; - this->FindManufacturer(); - } - - return true; -} - -/** Querying for system information from Haiku OS */ -bool SystemInformationImplementation::QueryHaikuInfo() -{ -#if defined(__HAIKU__) - - // CPU count - system_info info; - get_system_info(&info); - this->NumberOfPhysicalCPU = info.cpu_count; - - // CPU speed - uint32 topologyNodeCount = 0; - cpu_topology_node_info* topology = 0; - get_cpu_topology_info(0, &topologyNodeCount); - if (topologyNodeCount != 0) - topology = new cpu_topology_node_info[topologyNodeCount]; - get_cpu_topology_info(topology, &topologyNodeCount); - - for (uint32 i = 0; i < topologyNodeCount; i++) { - if (topology[i].type == B_TOPOLOGY_CORE) { - this->CPUSpeedInMHz = - topology[i].data.core.default_frequency / 1000000.0f; - break; - } - } - - delete[] topology; - - // Physical Memory - this->TotalPhysicalMemory = (info.max_pages * B_PAGE_SIZE) / (1024 * 1024); - this->AvailablePhysicalMemory = this->TotalPhysicalMemory - - ((info.used_pages * B_PAGE_SIZE) / (1024 * 1024)); - - // NOTE: get_system_info_etc is currently a private call so just set to 0 - // until it becomes public - this->TotalVirtualMemory = 0; - this->AvailableVirtualMemory = 0; - - // Retrieve cpuid_info union for cpu 0 - cpuid_info cpu_info; - get_cpuid(&cpu_info, 0, 0); - - // Chip Vendor - // Use a temporary buffer so that we can add NULL termination to the string - char vbuf[13]; - strncpy(vbuf, cpu_info.eax_0.vendor_id, 12); - vbuf[12] = '\0'; - this->ChipID.Vendor = vbuf; - - this->FindManufacturer(); - - // Retrieve cpuid_info union for cpu 0 this time using a register value of 1 - get_cpuid(&cpu_info, 1, 0); - - this->NumberOfLogicalCPU = cpu_info.eax_1.logical_cpus; - - // Chip type - this->ChipID.Type = cpu_info.eax_1.type; - - // Chip family - this->ChipID.Family = cpu_info.eax_1.family; - - // Chip Model - this->ChipID.Model = cpu_info.eax_1.model; - - // Chip Revision - this->ChipID.Revision = cpu_info.eax_1.stepping; - - // Chip Extended Family - this->ChipID.ExtendedFamily = cpu_info.eax_1.extended_family; - - // Chip Extended Model - this->ChipID.ExtendedModel = cpu_info.eax_1.extended_model; - - // Get ChipID.ProcessorName from other information already gathered - this->RetrieveClassicalCPUIdentity(); - - // Cache size - this->Features.L1CacheSize = 0; - this->Features.L2CacheSize = 0; - - return true; - -#else - return false; -#endif -} - -bool SystemInformationImplementation::QueryQNXMemory() -{ -#if defined(__QNX__) - std::string buffer; - std::vector args; - args.clear(); - - args.push_back("showmem"); - args.push_back("-S"); - args.push_back(0); - buffer = this->RunProcess(args); - args.clear(); - - size_t pos = buffer.find("System RAM:"); - if (pos == std::string::npos) - return false; - pos = buffer.find(":", pos); - size_t pos2 = buffer.find("M (", pos); - if (pos2 == std::string::npos) - return false; - - pos++; - while (buffer[pos] == ' ') - pos++; - - this->TotalPhysicalMemory = atoi(buffer.substr(pos, pos2 - pos).c_str()); - return true; -#endif - return false; -} - -bool SystemInformationImplementation::QueryBSDMemory() -{ -#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__DragonFly__) - int ctrl[2] = { CTL_HW, HW_PHYSMEM }; -# if defined(HW_PHYSMEM64) - int64_t k; - ctrl[1] = HW_PHYSMEM64; -# else - int k; -# endif - size_t sz = sizeof(k); - - if (sysctl(ctrl, 2, &k, &sz, nullptr, 0) != 0) { - return false; - } - - this->TotalPhysicalMemory = k >> 10 >> 10; - - return true; -#else - return false; -#endif -} - -bool SystemInformationImplementation::QueryQNXProcessor() -{ -#if defined(__QNX__) - // the output on my QNX 6.4.1 looks like this: - // Processor1: 686 Pentium II Stepping 3 2175MHz FPU - std::string buffer; - std::vector args; - args.clear(); - - args.push_back("pidin"); - args.push_back("info"); - args.push_back(0); - buffer = this->RunProcess(args); - args.clear(); - - size_t pos = buffer.find("Processor1:"); - if (pos == std::string::npos) - return false; - - size_t pos2 = buffer.find("MHz", pos); - if (pos2 == std::string::npos) - return false; - - size_t pos3 = pos2; - while (buffer[pos3] != ' ') - --pos3; - - this->CPUSpeedInMHz = atoi(buffer.substr(pos3 + 1, pos2 - pos3 - 1).c_str()); - - pos2 = buffer.find(" Stepping", pos); - if (pos2 != std::string::npos) { - pos2 = buffer.find(" ", pos2 + 1); - if (pos2 != std::string::npos && pos2 < pos3) { - this->ChipID.Revision = - atoi(buffer.substr(pos2 + 1, pos3 - pos2).c_str()); - } - } - - this->NumberOfPhysicalCPU = 0; - do { - pos = buffer.find("\nProcessor", pos + 1); - ++this->NumberOfPhysicalCPU; - } while (pos != std::string::npos); - this->NumberOfLogicalCPU = 1; - - return true; -#else - return false; -#endif -} - -bool SystemInformationImplementation::QueryBSDProcessor() -{ -#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__DragonFly__) - int k; - size_t sz = sizeof(k); - int ctrl[2] = { CTL_HW, HW_NCPU }; - - if (sysctl(ctrl, 2, &k, &sz, nullptr, 0) != 0) { - return false; - } - - this->NumberOfPhysicalCPU = k; - this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU; - -# if defined(HW_CPUSPEED) - ctrl[1] = HW_CPUSPEED; - - if (sysctl(ctrl, 2, &k, &sz, nullptr, 0) != 0) { - return false; - } - - this->CPUSpeedInMHz = (float)k; -# endif - -# if defined(CPU_SSE) - ctrl[0] = CTL_MACHDEP; - ctrl[1] = CPU_SSE; - - if (sysctl(ctrl, 2, &k, &sz, nullptr, 0) != 0) { - return false; - } - - this->Features.HasSSE = (k > 0); -# endif - -# if defined(CPU_SSE2) - ctrl[0] = CTL_MACHDEP; - ctrl[1] = CPU_SSE2; - - if (sysctl(ctrl, 2, &k, &sz, nullptr, 0) != 0) { - return false; - } - - this->Features.HasSSE2 = (k > 0); -# endif - -# if defined(CPU_CPUVENDOR) - ctrl[0] = CTL_MACHDEP; - ctrl[1] = CPU_CPUVENDOR; - char vbuf[25]; - ::memset(vbuf, 0, sizeof(vbuf)); - sz = sizeof(vbuf) - 1; - if (sysctl(ctrl, 2, vbuf, &sz, nullptr, 0) != 0) { - return false; - } - - this->ChipID.Vendor = vbuf; - this->FindManufacturer(); -# endif - - return true; -#else - return false; -#endif -} - -bool SystemInformationImplementation::QueryHPUXMemory() -{ -#if defined(__hpux) - unsigned long tv = 0; - unsigned long tp = 0; - unsigned long av = 0; - unsigned long ap = 0; - struct pst_static pst; - struct pst_dynamic pdy; - - unsigned long ps = 0; - if (pstat_getstatic(&pst, sizeof(pst), (size_t)1, 0) == -1) { - return false; - } - - ps = pst.page_size; - tp = pst.physical_memory * ps; - tv = (pst.physical_memory + pst.pst_maxmem) * ps; - if (pstat_getdynamic(&pdy, sizeof(pdy), (size_t)1, 0) == -1) { - return false; - } - - ap = tp - pdy.psd_rm * ps; - av = tv - pdy.psd_vm; - this->TotalVirtualMemory = tv >> 10 >> 10; - this->TotalPhysicalMemory = tp >> 10 >> 10; - this->AvailableVirtualMemory = av >> 10 >> 10; - this->AvailablePhysicalMemory = ap >> 10 >> 10; - return true; -#else - return false; -#endif -} - -bool SystemInformationImplementation::QueryHPUXProcessor() -{ -#if defined(__hpux) -# if defined(KWSYS_SYS_HAS_MPCTL_H) - int c = mpctl(MPC_GETNUMSPUS_SYS, 0, 0); - if (c <= 0) { - return false; - } - - this->NumberOfPhysicalCPU = c; - this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU; - - long t = sysconf(_SC_CPU_VERSION); - - if (t == -1) { - return false; - } - - switch (t) { - case CPU_PA_RISC1_0: - this->ChipID.Vendor = "Hewlett-Packard"; - this->ChipID.Family = 0x100; - break; - case CPU_PA_RISC1_1: - this->ChipID.Vendor = "Hewlett-Packard"; - this->ChipID.Family = 0x110; - break; - case CPU_PA_RISC2_0: - this->ChipID.Vendor = "Hewlett-Packard"; - this->ChipID.Family = 0x200; - break; -# if defined(CPU_HP_INTEL_EM_1_0) || defined(CPU_IA64_ARCHREV_0) -# ifdef CPU_HP_INTEL_EM_1_0 - case CPU_HP_INTEL_EM_1_0: -# endif -# ifdef CPU_IA64_ARCHREV_0 - case CPU_IA64_ARCHREV_0: -# endif - this->ChipID.Vendor = "GenuineIntel"; - this->Features.HasIA64 = true; - break; -# endif - default: - return false; - } - - this->FindManufacturer(); - - return true; -# else - return false; -# endif -#else - return false; -#endif -} - -/** Query the operating system information */ -bool SystemInformationImplementation::QueryOSInformation() -{ -#if defined(_WIN32) - - this->OSName = "Windows"; - - OSVERSIONINFOEXW osvi; - BOOL bIsWindows64Bit; - BOOL bOsVersionInfoEx; - char operatingSystem[256]; - - // Try calling GetVersionEx using the OSVERSIONINFOEX structure. - ZeroMemory(&osvi, sizeof(OSVERSIONINFOEXW)); - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW); -# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx -# pragma warning(push) -# ifdef __INTEL_COMPILER -# pragma warning(disable : 1478) -# elif defined __clang__ -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated-declarations" -# else -# pragma warning(disable : 4996) -# endif -# endif - bOsVersionInfoEx = GetVersionExW((OSVERSIONINFOW*)&osvi); - if (!bOsVersionInfoEx) { - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW); - if (!GetVersionExW((OSVERSIONINFOW*)&osvi)) { - return false; - } - } -# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx -# ifdef __clang__ -# pragma clang diagnostic pop -# else -# pragma warning(pop) -# endif -# endif - - switch (osvi.dwPlatformId) { - case VER_PLATFORM_WIN32_NT: - // Test for the product. - if (osvi.dwMajorVersion <= 4) { - this->OSRelease = "NT"; - } - if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) { - this->OSRelease = "2000"; - } - if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) { - this->OSRelease = "XP"; - } - // XP Professional x64 - if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) { - this->OSRelease = "XP"; - } -# ifdef VER_NT_WORKSTATION - // Test for product type. - if (bOsVersionInfoEx) { - if (osvi.wProductType == VER_NT_WORKSTATION) { - if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0) { - this->OSRelease = "Vista"; - } - if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1) { - this->OSRelease = "7"; - } -// VER_SUITE_PERSONAL may not be defined -# ifdef VER_SUITE_PERSONAL - else { - if (osvi.wSuiteMask & VER_SUITE_PERSONAL) { - this->OSRelease += " Personal"; - } else { - this->OSRelease += " Professional"; - } - } -# endif - } else if (osvi.wProductType == VER_NT_SERVER) { - // Check for .NET Server instead of Windows XP. - if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) { - this->OSRelease = ".NET"; - } - - // Continue with the type detection. - if (osvi.wSuiteMask & VER_SUITE_DATACENTER) { - this->OSRelease += " DataCenter Server"; - } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) { - this->OSRelease += " Advanced Server"; - } else { - this->OSRelease += " Server"; - } - } - - sprintf(operatingSystem, "%ls (Build %ld)", osvi.szCSDVersion, - osvi.dwBuildNumber & 0xFFFF); - this->OSVersion = operatingSystem; - } else -# endif // VER_NT_WORKSTATION - { - HKEY hKey; - wchar_t szProductType[80]; - DWORD dwBufLen; - - // Query the registry to retrieve information. - RegOpenKeyExW(HKEY_LOCAL_MACHINE, - L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions", 0, - KEY_QUERY_VALUE, &hKey); - RegQueryValueExW(hKey, L"ProductType", nullptr, nullptr, - (LPBYTE)szProductType, &dwBufLen); - RegCloseKey(hKey); - - if (lstrcmpiW(L"WINNT", szProductType) == 0) { - this->OSRelease += " Professional"; - } - if (lstrcmpiW(L"LANMANNT", szProductType) == 0) { - // Decide between Windows 2000 Advanced Server and Windows .NET - // Enterprise Server. - if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) { - this->OSRelease += " Standard Server"; - } else { - this->OSRelease += " Server"; - } - } - if (lstrcmpiW(L"SERVERNT", szProductType) == 0) { - // Decide between Windows 2000 Advanced Server and Windows .NET - // Enterprise Server. - if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) { - this->OSRelease += " Enterprise Server"; - } else { - this->OSRelease += " Advanced Server"; - } - } - } - - // Display version, service pack (if any), and build number. - if (osvi.dwMajorVersion <= 4) { - // NB: NT 4.0 and earlier. - sprintf(operatingSystem, "version %ld.%ld %ls (Build %ld)", - osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.szCSDVersion, - osvi.dwBuildNumber & 0xFFFF); - this->OSVersion = operatingSystem; - } else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) { - // Windows XP and .NET server. - typedef BOOL(CALLBACK * LPFNPROC)(HANDLE, BOOL*); - HINSTANCE hKernelDLL; - LPFNPROC DLLProc; - - // Load the Kernel32 DLL. - hKernelDLL = LoadLibraryW(L"kernel32"); - if (hKernelDLL != nullptr) { - // Only XP and .NET Server support IsWOW64Process so... Load - // dynamically! - DLLProc = (LPFNPROC)GetProcAddress(hKernelDLL, "IsWow64Process"); - - // If the function address is valid, call the function. - if (DLLProc != nullptr) - (DLLProc)(GetCurrentProcess(), &bIsWindows64Bit); - else - bIsWindows64Bit = false; - - // Free the DLL module. - FreeLibrary(hKernelDLL); - } - } else { - // Windows 2000 and everything else. - sprintf(operatingSystem, "%ls (Build %ld)", osvi.szCSDVersion, - osvi.dwBuildNumber & 0xFFFF); - this->OSVersion = operatingSystem; - } - break; - - case VER_PLATFORM_WIN32_WINDOWS: - // Test for the product. - if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) { - this->OSRelease = "95"; - if (osvi.szCSDVersion[1] == 'C') { - this->OSRelease += "OSR 2.5"; - } else if (osvi.szCSDVersion[1] == 'B') { - this->OSRelease += "OSR 2"; - } - } - - if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10) { - this->OSRelease = "98"; - if (osvi.szCSDVersion[1] == 'A') { - this->OSRelease += "SE"; - } - } - - if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90) { - this->OSRelease = "Me"; - } - break; - - case VER_PLATFORM_WIN32s: - this->OSRelease = "Win32s"; - break; - - default: - this->OSRelease = "Unknown"; - break; - } - - // Get the hostname - WORD wVersionRequested; - WSADATA wsaData; - char name[255]; - wVersionRequested = MAKEWORD(2, 0); - - if (WSAStartup(wVersionRequested, &wsaData) == 0) { - gethostname(name, sizeof(name)); - WSACleanup(); - } - this->Hostname = name; - - const char* arch = getenv("PROCESSOR_ARCHITECTURE"); - const char* wow64 = getenv("PROCESSOR_ARCHITEW6432"); - if (arch) { - this->OSPlatform = arch; - } - - if (wow64) { - // the PROCESSOR_ARCHITEW6432 is only defined when running 32bit programs - // on 64bit OS - this->OSIs64Bit = true; - } else if (arch) { - // all values other than x86 map to 64bit architectures - this->OSIs64Bit = (strncmp(arch, "x86", 3) != 0); - } - -#else - - struct utsname unameInfo; - int errorFlag = uname(&unameInfo); - if (errorFlag == 0) { - this->OSName = unameInfo.sysname; - this->Hostname = unameInfo.nodename; - this->OSRelease = unameInfo.release; - this->OSVersion = unameInfo.version; - this->OSPlatform = unameInfo.machine; - - // This is still insufficient to capture 64bit architecture such - // powerpc and possible mips and sparc - if (this->OSPlatform.find_first_of("64") != std::string::npos) { - this->OSIs64Bit = true; - } - } - -# ifdef __APPLE__ - this->OSName = "Unknown Apple OS"; - this->OSRelease = "Unknown product version"; - this->OSVersion = "Unknown build version"; - - this->CallSwVers("-productName", this->OSName); - this->CallSwVers("-productVersion", this->OSRelease); - this->CallSwVers("-buildVersion", this->OSVersion); -# endif - -#endif - - return true; -} - -int SystemInformationImplementation::CallSwVers(const char* arg, - std::string& ver) -{ -#ifdef __APPLE__ - std::vector args; - args.push_back("sw_vers"); - args.push_back(arg); - args.push_back(nullptr); - ver = this->RunProcess(args); - this->TrimNewline(ver); -#else - // avoid C4100 - (void)arg; - (void)ver; -#endif - return 0; -} - -void SystemInformationImplementation::TrimNewline(std::string& output) -{ - // remove \r - std::string::size_type pos = 0; - while ((pos = output.find("\r", pos)) != std::string::npos) { - output.erase(pos); - } - - // remove \n - pos = 0; - while ((pos = output.find("\n", pos)) != std::string::npos) { - output.erase(pos); - } -} - -/** Return true if the machine is 64 bits */ -bool SystemInformationImplementation::Is64Bits() -{ - return this->OSIs64Bit; -} -} diff --git a/test/API/driver/kwsys/SystemInformation.hxx.in b/test/API/driver/kwsys/SystemInformation.hxx.in deleted file mode 100644 index fc42e9d..0000000 --- a/test/API/driver/kwsys/SystemInformation.hxx.in +++ /dev/null @@ -1,170 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifndef @KWSYS_NAMESPACE@_SystemInformation_h -#define @KWSYS_NAMESPACE@_SystemInformation_h - -#include <@KWSYS_NAMESPACE@/Configure.hxx> - -#include /* size_t */ -#include - -namespace @KWSYS_NAMESPACE@ { - -// forward declare the implementation class -class SystemInformationImplementation; - -class @KWSYS_NAMESPACE@_EXPORT SystemInformation -{ -#if @KWSYS_USE_LONG_LONG@ - typedef long long LongLong; -#elif @KWSYS_USE___INT64@ - typedef __int64 LongLong; -#else -# error "No Long Long" -#endif - friend class SystemInformationImplementation; - SystemInformationImplementation* Implementation; - -public: - // possible parameter values for DoesCPUSupportFeature() - static const long int CPU_FEATURE_MMX = 1 << 0; - static const long int CPU_FEATURE_MMX_PLUS = 1 << 1; - static const long int CPU_FEATURE_SSE = 1 << 2; - static const long int CPU_FEATURE_SSE2 = 1 << 3; - static const long int CPU_FEATURE_AMD_3DNOW = 1 << 4; - static const long int CPU_FEATURE_AMD_3DNOW_PLUS = 1 << 5; - static const long int CPU_FEATURE_IA64 = 1 << 6; - static const long int CPU_FEATURE_MP_CAPABLE = 1 << 7; - static const long int CPU_FEATURE_HYPERTHREAD = 1 << 8; - static const long int CPU_FEATURE_SERIALNUMBER = 1 << 9; - static const long int CPU_FEATURE_APIC = 1 << 10; - static const long int CPU_FEATURE_SSE_FP = 1 << 11; - static const long int CPU_FEATURE_SSE_MMX = 1 << 12; - static const long int CPU_FEATURE_CMOV = 1 << 13; - static const long int CPU_FEATURE_MTRR = 1 << 14; - static const long int CPU_FEATURE_L1CACHE = 1 << 15; - static const long int CPU_FEATURE_L2CACHE = 1 << 16; - static const long int CPU_FEATURE_L3CACHE = 1 << 17; - static const long int CPU_FEATURE_ACPI = 1 << 18; - static const long int CPU_FEATURE_THERMALMONITOR = 1 << 19; - static const long int CPU_FEATURE_TEMPSENSEDIODE = 1 << 20; - static const long int CPU_FEATURE_FREQUENCYID = 1 << 21; - static const long int CPU_FEATURE_VOLTAGEID_FREQUENCY = 1 << 22; - static const long int CPU_FEATURE_FPU = 1 << 23; - -public: - SystemInformation(); - ~SystemInformation(); - - SystemInformation(const SystemInformation&) = delete; - SystemInformation& operator=(const SystemInformation&) = delete; - - const char* GetVendorString(); - const char* GetVendorID(); - std::string GetTypeID(); - std::string GetFamilyID(); - std::string GetModelID(); - std::string GetModelName(); - std::string GetSteppingCode(); - const char* GetExtendedProcessorName(); - const char* GetProcessorSerialNumber(); - int GetProcessorCacheSize(); - unsigned int GetLogicalProcessorsPerPhysical(); - float GetProcessorClockFrequency(); - int GetProcessorAPICID(); - int GetProcessorCacheXSize(long int); - bool DoesCPUSupportFeature(long int); - - // returns an informative general description of the cpu - // on this system. - std::string GetCPUDescription(); - - const char* GetHostname(); - std::string GetFullyQualifiedDomainName(); - - const char* GetOSName(); - const char* GetOSRelease(); - const char* GetOSVersion(); - const char* GetOSPlatform(); - - int GetOSIsWindows(); - int GetOSIsLinux(); - int GetOSIsApple(); - - // returns an informative general description of the os - // on this system. - std::string GetOSDescription(); - - // returns if the operating system is 64bit or not. - bool Is64Bits(); - - unsigned int GetNumberOfLogicalCPU(); - unsigned int GetNumberOfPhysicalCPU(); - - bool DoesCPUSupportCPUID(); - - // Retrieve id of the current running process - LongLong GetProcessId(); - - // Retrieve memory information in MiB. - size_t GetTotalVirtualMemory(); - size_t GetAvailableVirtualMemory(); - size_t GetTotalPhysicalMemory(); - size_t GetAvailablePhysicalMemory(); - - // returns an informative general description if the installed and - // available ram on this system. See the GetHostMemoryTotal, and - // Get{Host,Proc}MemoryAvailable methods for more information. - std::string GetMemoryDescription(const char* hostLimitEnvVarName = nullptr, - const char* procLimitEnvVarName = nullptr); - - // Retrieve amount of physical memory installed on the system in KiB - // units. - LongLong GetHostMemoryTotal(); - - // Get total system RAM in units of KiB available colectivley to all - // processes in a process group. An example of a process group - // are the processes comprising an mpi program which is running in - // parallel. The amount of memory reported may differ from the host - // total if a host wide resource limit is applied. Such reource limits - // are reported to us via an application specified environment variable. - LongLong GetHostMemoryAvailable(const char* hostLimitEnvVarName = nullptr); - - // Get total system RAM in units of KiB available to this process. - // This may differ from the host available if a per-process resource - // limit is applied. per-process memory limits are applied on unix - // system via rlimit API. Resource limits that are not imposed via - // rlimit API may be reported to us via an application specified - // environment variable. - LongLong GetProcMemoryAvailable(const char* hostLimitEnvVarName = nullptr, - const char* procLimitEnvVarName = nullptr); - - // Get the system RAM used by all processes on the host, in units of KiB. - LongLong GetHostMemoryUsed(); - - // Get system RAM used by this process id in units of KiB. - LongLong GetProcMemoryUsed(); - - // Return the load average of the machine or -0.0 if it cannot - // be determined. - double GetLoadAverage(); - - // enable/disable stack trace signal handler. In order to - // produce an informative stack trace the application should - // be dynamically linked and compiled with debug symbols. - static void SetStackTraceOnError(int enable); - - // format and return the current program stack in a string. In - // order to produce an informative stack trace the application - // should be dynamically linked and compiled with debug symbols. - static std::string GetProgramStack(int firstFrame, int wholePath); - - /** Run the different checks */ - void RunCPUCheck(); - void RunOSCheck(); - void RunMemoryCheck(); -}; - -} // namespace @KWSYS_NAMESPACE@ - -#endif diff --git a/test/API/driver/kwsys/SystemTools.cxx b/test/API/driver/kwsys/SystemTools.cxx deleted file mode 100644 index ce4d6ef..0000000 --- a/test/API/driver/kwsys/SystemTools.cxx +++ /dev/null @@ -1,4703 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifdef __osf__ -# define _OSF_SOURCE -# define _POSIX_C_SOURCE 199506L -# define _XOPEN_SOURCE_EXTENDED -#endif - -#if defined(_WIN32) && \ - (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) || \ - defined(__MINGW32__)) -# define KWSYS_WINDOWS_DIRS -#else -# if defined(__SUNPRO_CC) -# include -# endif -#endif - -#include "kwsysPrivate.h" -#include KWSYS_HEADER(RegularExpression.hxx) -#include KWSYS_HEADER(SystemTools.hxx) -#include KWSYS_HEADER(Directory.hxx) -#include KWSYS_HEADER(FStream.hxx) -#include KWSYS_HEADER(Encoding.h) -#include KWSYS_HEADER(Encoding.hxx) - -#include -#include -#include -#include -#include -#include - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -# include "Directory.hxx.in" -# include "Encoding.hxx.in" -# include "FStream.hxx.in" -# include "RegularExpression.hxx.in" -# include "SystemTools.hxx.in" -#endif - -#ifdef _MSC_VER -# pragma warning(disable : 4786) -#endif - -#if defined(__sgi) && !defined(__GNUC__) -# pragma set woff 1375 /* base class destructor not virtual */ -#endif - -#include -#include -#ifdef __QNX__ -# include /* for malloc/free on QNX */ -#endif -#include -#include -#include -#include - -#if defined(_WIN32) && !defined(_MSC_VER) && defined(__GNUC__) -# include /* for strcasecmp */ -#endif - -#ifdef _MSC_VER -# define umask _umask // Note this is still umask on Borland -#endif - -// support for realpath call -#ifndef _WIN32 -# include -# include -# include -# include -# include -# include -# include -# ifndef __VMS -# include -# include -# endif -# include /* sigprocmask */ -#endif - -#ifdef __linux -# include -#endif - -// Windows API. -#if defined(_WIN32) -# include -# include -# ifndef INVALID_FILE_ATTRIBUTES -# define INVALID_FILE_ATTRIBUTES ((DWORD)-1) -# endif -# if defined(_MSC_VER) && _MSC_VER >= 1800 -# define KWSYS_WINDOWS_DEPRECATED_GetVersionEx -# endif -#elif defined(__CYGWIN__) -# include -# undef _WIN32 -#endif - -#if !KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H -extern char** environ; -#endif - -#ifdef __CYGWIN__ -# include -#endif - -// getpwnam doesn't exist on Windows and Cray Xt3/Catamount -// same for TIOCGWINSZ -#if defined(_WIN32) || defined(__LIBCATAMOUNT__) || \ - (defined(HAVE_GETPWNAM) && HAVE_GETPWNAM == 0) -# undef HAVE_GETPWNAM -# undef HAVE_TTY_INFO -#else -# define HAVE_GETPWNAM 1 -# define HAVE_TTY_INFO 1 -#endif - -#define VTK_URL_PROTOCOL_REGEX "([a-zA-Z0-9]*)://(.*)" -#define VTK_URL_REGEX \ - "([a-zA-Z0-9]*)://(([A-Za-z0-9]+)(:([^:@]+))?@)?([^:@/]+)(:([0-9]+))?/" \ - "(.+)?" - -#ifdef _MSC_VER -# include -#else -# include -#endif - -// This is a hack to prevent warnings about these functions being -// declared but not referenced. -#if defined(__sgi) && !defined(__GNUC__) -# include -namespace KWSYS_NAMESPACE { -class SystemToolsHack -{ -public: - enum - { - Ref1 = sizeof(cfgetospeed(0)), - Ref2 = sizeof(cfgetispeed(0)), - Ref3 = sizeof(tcgetattr(0, 0)), - Ref4 = sizeof(tcsetattr(0, 0, 0)), - Ref5 = sizeof(cfsetospeed(0, 0)), - Ref6 = sizeof(cfsetispeed(0, 0)) - }; -}; -} -#endif - -#if defined(_WIN32) && \ - (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) || \ - defined(__MINGW32__)) -# include -# include -# define _unlink unlink -#endif - -/* The maximum length of a file name. */ -#if defined(PATH_MAX) -# define KWSYS_SYSTEMTOOLS_MAXPATH PATH_MAX -#elif defined(MAXPATHLEN) -# define KWSYS_SYSTEMTOOLS_MAXPATH MAXPATHLEN -#else -# define KWSYS_SYSTEMTOOLS_MAXPATH 16384 -#endif -#if defined(__WATCOMC__) -# include -# define _mkdir mkdir -# define _rmdir rmdir -# define _getcwd getcwd -# define _chdir chdir -#endif - -#if defined(__BEOS__) && !defined(__ZETA__) -# include -# include - -// BeOS 5 doesn't have usleep(), but it has snooze(), which is identical. -static inline void usleep(unsigned int msec) -{ - ::snooze(msec); -} - -// BeOS 5 also doesn't have realpath(), but its C++ API offers something close. -static inline char* realpath(const char* path, char* resolved_path) -{ - const size_t maxlen = KWSYS_SYSTEMTOOLS_MAXPATH; - snprintf(resolved_path, maxlen, "%s", path); - BPath normalized(resolved_path, nullptr, true); - const char* resolved = normalized.Path(); - if (resolved != nullptr) // nullptr == No such file. - { - if (snprintf(resolved_path, maxlen, "%s", resolved) < maxlen) { - return resolved_path; - } - } - return nullptr; // something went wrong. -} -#endif - -#ifdef _WIN32 -static time_t windows_filetime_to_posix_time(const FILETIME& ft) -{ - LARGE_INTEGER date; - date.HighPart = ft.dwHighDateTime; - date.LowPart = ft.dwLowDateTime; - - // removes the diff between 1970 and 1601 - date.QuadPart -= ((LONGLONG)(369 * 365 + 89) * 24 * 3600 * 10000000); - - // converts back from 100-nanoseconds to seconds - return date.QuadPart / 10000000; -} -#endif - -#ifdef KWSYS_WINDOWS_DIRS -# include - -inline int Mkdir(const std::string& dir) -{ - return _wmkdir( - KWSYS_NAMESPACE::Encoding::ToWindowsExtendedPath(dir).c_str()); -} -inline int Rmdir(const std::string& dir) -{ - return _wrmdir( - KWSYS_NAMESPACE::Encoding::ToWindowsExtendedPath(dir).c_str()); -} -inline const char* Getcwd(char* buf, unsigned int len) -{ - std::vector w_buf(len); - if (_wgetcwd(&w_buf[0], len)) { - size_t nlen = kwsysEncoding_wcstombs(buf, &w_buf[0], len); - if (nlen == static_cast(-1)) { - return 0; - } - if (nlen < len) { - // make sure the drive letter is capital - if (nlen > 1 && buf[1] == ':') { - buf[0] = toupper(buf[0]); - } - return buf; - } - } - return 0; -} -inline int Chdir(const std::string& dir) -{ -# if defined(__BORLANDC__) - return chdir(dir.c_str()); -# else - return _wchdir(KWSYS_NAMESPACE::Encoding::ToWide(dir).c_str()); -# endif -} -inline void Realpath(const std::string& path, std::string& resolved_path, - std::string* errorMessage = 0) -{ - std::wstring tmp = KWSYS_NAMESPACE::Encoding::ToWide(path); - wchar_t* ptemp; - wchar_t fullpath[MAX_PATH]; - DWORD bufferLen = GetFullPathNameW( - tmp.c_str(), sizeof(fullpath) / sizeof(fullpath[0]), fullpath, &ptemp); - if (bufferLen < sizeof(fullpath) / sizeof(fullpath[0])) { - resolved_path = KWSYS_NAMESPACE::Encoding::ToNarrow(fullpath); - KWSYS_NAMESPACE::SystemTools::ConvertToUnixSlashes(resolved_path); - } else if (errorMessage) { - if (bufferLen) { - *errorMessage = "Destination path buffer size too small."; - } else if (unsigned int errorId = GetLastError()) { - LPSTR message = nullptr; - DWORD size = FormatMessageA( - FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - nullptr, errorId, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPSTR)&message, 0, nullptr); - *errorMessage = std::string(message, size); - LocalFree(message); - } else { - *errorMessage = "Unknown error."; - } - - resolved_path = ""; - } else { - resolved_path = path; - } -} -#else -# include - -# include -# include -inline int Mkdir(const std::string& dir) -{ - return mkdir(dir.c_str(), 00777); -} -inline int Rmdir(const std::string& dir) -{ - return rmdir(dir.c_str()); -} -inline const char* Getcwd(char* buf, unsigned int len) -{ - return getcwd(buf, len); -} - -inline int Chdir(const std::string& dir) -{ - return chdir(dir.c_str()); -} -inline void Realpath(const std::string& path, std::string& resolved_path, - std::string* errorMessage = nullptr) -{ - char resolved_name[KWSYS_SYSTEMTOOLS_MAXPATH]; - - errno = 0; - char* ret = realpath(path.c_str(), resolved_name); - if (ret) { - resolved_path = ret; - } else if (errorMessage) { - if (errno) { - *errorMessage = strerror(errno); - } else { - *errorMessage = "Unknown error."; - } - - resolved_path = ""; - } else { - // if path resolution fails, return what was passed in - resolved_path = path; - } -} -#endif - -#if !defined(_WIN32) && defined(__COMO__) -// Hack for como strict mode to avoid defining _SVID_SOURCE or _BSD_SOURCE. -extern "C" { -extern FILE* popen(__const char* __command, __const char* __modes) __THROW; -extern int pclose(FILE* __stream) __THROW; -extern char* realpath(__const char* __restrict __name, - char* __restrict __resolved) __THROW; -extern char* strdup(__const char* __s) __THROW; -extern int putenv(char* __string) __THROW; -} -#endif - -namespace KWSYS_NAMESPACE { - -double SystemTools::GetTime(void) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - FILETIME ft; - GetSystemTimeAsFileTime(&ft); - return (429.4967296 * ft.dwHighDateTime + 0.0000001 * ft.dwLowDateTime - - 11644473600.0); -#else - struct timeval t; - gettimeofday(&t, nullptr); - return 1.0 * double(t.tv_sec) + 0.000001 * double(t.tv_usec); -#endif -} - -/* Type of character storing the environment. */ -#if defined(_WIN32) -typedef wchar_t envchar; -#else -typedef char envchar; -#endif - -/* Order by environment key only (VAR from VAR=VALUE). */ -struct kwsysEnvCompare -{ - bool operator()(const envchar* l, const envchar* r) const - { -#if defined(_WIN32) - const wchar_t* leq = wcschr(l, L'='); - const wchar_t* req = wcschr(r, L'='); - size_t llen = leq ? (leq - l) : wcslen(l); - size_t rlen = req ? (req - r) : wcslen(r); - if (llen == rlen) { - return wcsncmp(l, r, llen) < 0; - } else { - return wcscmp(l, r) < 0; - } -#else - const char* leq = strchr(l, '='); - const char* req = strchr(r, '='); - size_t llen = leq ? static_cast(leq - l) : strlen(l); - size_t rlen = req ? static_cast(req - r) : strlen(r); - if (llen == rlen) { - return strncmp(l, r, llen) < 0; - } else { - return strcmp(l, r) < 0; - } -#endif - } -}; - -class kwsysEnvSet : public std::set -{ -public: - class Free - { - const envchar* Env; - - public: - Free(const envchar* env) - : Env(env) - { - } - ~Free() { free(const_cast(this->Env)); } - - Free(const Free&) = delete; - Free& operator=(const Free&) = delete; - }; - - const envchar* Release(const envchar* env) - { - const envchar* old = nullptr; - iterator i = this->find(env); - if (i != this->end()) { - old = *i; - this->erase(i); - } - return old; - } -}; - -#ifdef _WIN32 -struct SystemToolsPathCaseCmp -{ - bool operator()(std::string const& l, std::string const& r) const - { -# ifdef _MSC_VER - return _stricmp(l.c_str(), r.c_str()) < 0; -# elif defined(__GNUC__) - return strcasecmp(l.c_str(), r.c_str()) < 0; -# else - return SystemTools::Strucmp(l.c_str(), r.c_str()) < 0; -# endif - } -}; -#endif - -/** - * SystemTools static variables singleton class. - */ -class SystemToolsStatic -{ -public: - typedef std::map StringMap; -#if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP - /** - * Path translation table from dir to refdir - * Each time 'dir' will be found it will be replace by 'refdir' - */ - StringMap TranslationMap; -#endif -#ifdef _WIN32 - static std::string GetCasePathName(std::string const& pathIn); - static std::string GetActualCaseForPathCached(std::string const& path); - static const char* GetEnvBuffered(const char* key); - std::map PathCaseMap; - std::map EnvMap; -#endif -#ifdef __CYGWIN__ - StringMap Cyg2Win32Map; -#endif - - /** - * Actual implementation of ReplaceString. - */ - static void ReplaceString(std::string& source, const char* replace, - size_t replaceSize, const std::string& with); - - /** - * Actual implementation of FileIsFullPath. - */ - static bool FileIsFullPath(const char*, size_t); - - /** - * Find a filename (file or directory) in the system PATH, with - * optional extra paths. - */ - static std::string FindName( - const std::string& name, - const std::vector& path = std::vector(), - bool no_system_path = false); -}; - -#ifdef _WIN32 -std::string SystemToolsStatic::GetCasePathName(std::string const& pathIn) -{ - std::string casePath; - - // First check if the file is relative. We don't fix relative paths since the - // real case depends on the root directory and the given path fragment may - // have meaning elsewhere in the project. - if (!SystemTools::FileIsFullPath(pathIn)) { - // This looks unnecessary, but it allows for the return value optimization - // since all return paths return the same local variable. - casePath = pathIn; - return casePath; - } - - std::vector path_components; - SystemTools::SplitPath(pathIn, path_components); - - // Start with root component. - std::vector::size_type idx = 0; - casePath = path_components[idx++]; - // make sure drive letter is always upper case - if (casePath.size() > 1 && casePath[1] == ':') { - casePath[0] = toupper(casePath[0]); - } - const char* sep = ""; - - // If network path, fill casePath with server/share so FindFirstFile - // will work after that. Maybe someday call other APIs to get - // actual case of servers and shares. - if (path_components.size() > 2 && path_components[0] == "//") { - casePath += path_components[idx++]; - casePath += "/"; - casePath += path_components[idx++]; - sep = "/"; - } - - // Convert case of all components that exist. - bool converting = true; - for (; idx < path_components.size(); idx++) { - casePath += sep; - sep = "/"; - - if (converting) { - // If path component contains wildcards, we skip matching - // because these filenames are not allowed on windows, - // and we do not want to match a different file. - if (path_components[idx].find('*') != std::string::npos || - path_components[idx].find('?') != std::string::npos) { - converting = false; - } else { - std::string test_str = casePath; - test_str += path_components[idx]; - WIN32_FIND_DATAW findData; - HANDLE hFind = - ::FindFirstFileW(Encoding::ToWide(test_str).c_str(), &findData); - if (INVALID_HANDLE_VALUE != hFind) { - path_components[idx] = Encoding::ToNarrow(findData.cFileName); - ::FindClose(hFind); - } else { - converting = false; - } - } - } - - casePath += path_components[idx]; - } - return casePath; -} - -std::string SystemToolsStatic::GetActualCaseForPathCached(std::string const& p) -{ - // Check to see if actual case has already been called - // for this path, and the result is stored in the PathCaseMap - auto& pcm = SystemTools::Statics->PathCaseMap; - { - auto itr = pcm.find(p); - if (itr != pcm.end()) { - return itr->second; - } - } - std::string casePath = SystemToolsStatic::GetCasePathName(p); - if (casePath.size() <= MAX_PATH) { - pcm[p] = casePath; - } - return casePath; -} -#endif - -// adds the elements of the env variable path to the arg passed in -void SystemTools::GetPath(std::vector& path, const char* env) -{ - size_t const old_size = path.size(); -#if defined(_WIN32) && !defined(__CYGWIN__) - const char pathSep = ';'; -#else - const char pathSep = ':'; -#endif - if (!env) { - env = "PATH"; - } - std::string pathEnv; - if (!SystemTools::GetEnv(env, pathEnv)) { - return; - } - - // A hack to make the below algorithm work. - if (!pathEnv.empty() && pathEnv.back() != pathSep) { - pathEnv += pathSep; - } - std::string::size_type start = 0; - bool done = false; - while (!done) { - std::string::size_type endpos = pathEnv.find(pathSep, start); - if (endpos != std::string::npos) { - path.push_back(pathEnv.substr(start, endpos - start)); - start = endpos + 1; - } else { - done = true; - } - } - for (std::vector::iterator i = path.begin() + old_size; - i != path.end(); ++i) { - SystemTools::ConvertToUnixSlashes(*i); - } -} - -#if defined(_WIN32) -const char* SystemToolsStatic::GetEnvBuffered(const char* key) -{ - std::string env; - if (SystemTools::GetEnv(key, env)) { - std::string& menv = SystemTools::Statics->EnvMap[key]; - if (menv != env) { - menv = std::move(env); - } - return menv.c_str(); - } - return nullptr; -} -#endif - -const char* SystemTools::GetEnv(const char* key) -{ -#if defined(_WIN32) - return SystemToolsStatic::GetEnvBuffered(key); -#else - return getenv(key); -#endif -} - -const char* SystemTools::GetEnv(const std::string& key) -{ -#if defined(_WIN32) - return SystemToolsStatic::GetEnvBuffered(key.c_str()); -#else - return getenv(key.c_str()); -#endif -} - -bool SystemTools::GetEnv(const char* key, std::string& result) -{ -#if defined(_WIN32) - const std::wstring wkey = Encoding::ToWide(key); - const wchar_t* wv = _wgetenv(wkey.c_str()); - if (wv) { - result = Encoding::ToNarrow(wv); - return true; - } -#else - const char* v = getenv(key); - if (v) { - result = v; - return true; - } -#endif - return false; -} - -bool SystemTools::GetEnv(const std::string& key, std::string& result) -{ - return SystemTools::GetEnv(key.c_str(), result); -} - -bool SystemTools::HasEnv(const char* key) -{ -#if defined(_WIN32) - const std::wstring wkey = Encoding::ToWide(key); - const wchar_t* v = _wgetenv(wkey.c_str()); -#else - const char* v = getenv(key); -#endif - return v != nullptr; -} - -bool SystemTools::HasEnv(const std::string& key) -{ - return SystemTools::HasEnv(key.c_str()); -} - -#if KWSYS_CXX_HAS_UNSETENV -/* unsetenv("A") removes A from the environment. - On older platforms it returns void instead of int. */ -static int kwsysUnPutEnv(const std::string& env) -{ - size_t pos = env.find('='); - if (pos != std::string::npos) { - std::string name = env.substr(0, pos); - unsetenv(name.c_str()); - } else { - unsetenv(env.c_str()); - } - return 0; -} - -#elif defined(__CYGWIN__) || defined(__GLIBC__) -/* putenv("A") removes A from the environment. It must not put the - memory in the environment because it does not have any "=" syntax. */ -static int kwsysUnPutEnv(const std::string& env) -{ - int err = 0; - size_t pos = env.find('='); - size_t const len = pos == std::string::npos ? env.size() : pos; - size_t const sz = len + 1; - char local_buf[256]; - char* buf = sz > sizeof(local_buf) ? (char*)malloc(sz) : local_buf; - if (!buf) { - return -1; - } - strncpy(buf, env.c_str(), len); - buf[len] = 0; - if (putenv(buf) < 0 && errno != EINVAL) { - err = errno; - } - if (buf != local_buf) { - free(buf); - } - if (err) { - errno = err; - return -1; - } - return 0; -} - -#elif defined(_WIN32) -/* putenv("A=") places "A=" in the environment, which is as close to - removal as we can get with the putenv API. We have to leak the - most recent value placed in the environment for each variable name - on program exit in case exit routines access it. */ - -static kwsysEnvSet kwsysUnPutEnvSet; - -static int kwsysUnPutEnv(std::string const& env) -{ - std::wstring wEnv = Encoding::ToWide(env); - size_t const pos = wEnv.find('='); - size_t const len = pos == std::string::npos ? wEnv.size() : pos; - wEnv.resize(len + 1, L'='); - wchar_t* newEnv = _wcsdup(wEnv.c_str()); - if (!newEnv) { - return -1; - } - kwsysEnvSet::Free oldEnv(kwsysUnPutEnvSet.Release(newEnv)); - kwsysUnPutEnvSet.insert(newEnv); - return _wputenv(newEnv); -} - -#else -/* Manipulate the "environ" global directly. */ -static int kwsysUnPutEnv(const std::string& env) -{ - size_t pos = env.find('='); - size_t const len = pos == std::string::npos ? env.size() : pos; - int in = 0; - int out = 0; - while (environ[in]) { - if (strlen(environ[in]) > len && environ[in][len] == '=' && - strncmp(env.c_str(), environ[in], len) == 0) { - ++in; - } else { - environ[out++] = environ[in++]; - } - } - while (out < in) { - environ[out++] = 0; - } - return 0; -} -#endif - -#if KWSYS_CXX_HAS_SETENV - -/* setenv("A", "B", 1) will set A=B in the environment and makes its - own copies of the strings. */ -bool SystemTools::PutEnv(const std::string& env) -{ - size_t pos = env.find('='); - if (pos != std::string::npos) { - std::string name = env.substr(0, pos); - return setenv(name.c_str(), env.c_str() + pos + 1, 1) == 0; - } else { - return kwsysUnPutEnv(env) == 0; - } -} - -bool SystemTools::UnPutEnv(const std::string& env) -{ - return kwsysUnPutEnv(env) == 0; -} - -#else - -/* putenv("A=B") will set A=B in the environment. Most putenv implementations - put their argument directly in the environment. They never free the memory - on program exit. Keep an active set of pointers to memory we allocate and - pass to putenv, one per environment key. At program exit remove any - environment values that may still reference memory we allocated. Then free - the memory. This will not affect any environment values we never set. */ - -# ifdef __INTEL_COMPILER -# pragma warning disable 444 /* base has non-virtual destructor */ -# endif - -class kwsysEnv : public kwsysEnvSet -{ -public: - ~kwsysEnv() - { - for (iterator i = this->begin(); i != this->end(); ++i) { -# if defined(_WIN32) - const std::string s = Encoding::ToNarrow(*i); - kwsysUnPutEnv(s); -# else - kwsysUnPutEnv(*i); -# endif - free(const_cast(*i)); - } - } - bool Put(const char* env) - { -# if defined(_WIN32) - const std::wstring wEnv = Encoding::ToWide(env); - wchar_t* newEnv = _wcsdup(wEnv.c_str()); -# else - char* newEnv = strdup(env); -# endif - Free oldEnv(this->Release(newEnv)); - this->insert(newEnv); -# if defined(_WIN32) - return _wputenv(newEnv) == 0; -# else - return putenv(newEnv) == 0; -# endif - } - bool UnPut(const char* env) - { -# if defined(_WIN32) - const std::wstring wEnv = Encoding::ToWide(env); - Free oldEnv(this->Release(wEnv.c_str())); -# else - Free oldEnv(this->Release(env)); -# endif - return kwsysUnPutEnv(env) == 0; - } -}; - -static kwsysEnv kwsysEnvInstance; - -bool SystemTools::PutEnv(const std::string& env) -{ - return kwsysEnvInstance.Put(env.c_str()); -} - -bool SystemTools::UnPutEnv(const std::string& env) -{ - return kwsysEnvInstance.UnPut(env.c_str()); -} - -#endif - -const char* SystemTools::GetExecutableExtension() -{ -#if defined(_WIN32) || defined(__CYGWIN__) || defined(__VMS) - return ".exe"; -#else - return ""; -#endif -} - -FILE* SystemTools::Fopen(const std::string& file, const char* mode) -{ -#ifdef _WIN32 - return _wfopen(Encoding::ToWindowsExtendedPath(file).c_str(), - Encoding::ToWide(mode).c_str()); -#else - return fopen(file.c_str(), mode); -#endif -} - -bool SystemTools::MakeDirectory(const char* path, const mode_t* mode) -{ - if (!path) { - return false; - } - return SystemTools::MakeDirectory(std::string(path), mode); -} - -bool SystemTools::MakeDirectory(const std::string& path, const mode_t* mode) -{ - if (SystemTools::PathExists(path)) { - return SystemTools::FileIsDirectory(path); - } - if (path.empty()) { - return false; - } - std::string dir = path; - SystemTools::ConvertToUnixSlashes(dir); - - std::string::size_type pos = 0; - std::string topdir; - while ((pos = dir.find('/', pos)) != std::string::npos) { - topdir = dir.substr(0, pos); - - if (Mkdir(topdir) == 0 && mode != nullptr) { - SystemTools::SetPermissions(topdir, *mode); - } - - ++pos; - } - topdir = dir; - if (Mkdir(topdir) != 0) { - // There is a bug in the Borland Run time library which makes MKDIR - // return EACCES when it should return EEXISTS - // if it is some other error besides directory exists - // then return false - if ((errno != EEXIST) -#ifdef __BORLANDC__ - && (errno != EACCES) -#endif - ) { - return false; - } - } else if (mode != nullptr) { - SystemTools::SetPermissions(topdir, *mode); - } - - return true; -} - -// replace replace with with as many times as it shows up in source. -// write the result into source. -void SystemTools::ReplaceString(std::string& source, - const std::string& replace, - const std::string& with) -{ - // do while hangs if replaceSize is 0 - if (replace.empty()) { - return; - } - - SystemToolsStatic::ReplaceString(source, replace.c_str(), replace.size(), - with); -} - -void SystemTools::ReplaceString(std::string& source, const char* replace, - const char* with) -{ - // do while hangs if replaceSize is 0 - if (!*replace) { - return; - } - - SystemToolsStatic::ReplaceString(source, replace, strlen(replace), - with ? with : ""); -} - -void SystemToolsStatic::ReplaceString(std::string& source, const char* replace, - size_t replaceSize, - const std::string& with) -{ - const char* src = source.c_str(); - char* searchPos = const_cast(strstr(src, replace)); - - // get out quick if string is not found - if (!searchPos) { - return; - } - - // perform replacements until done - char* orig = strdup(src); - char* currentPos = orig; - searchPos = searchPos - src + orig; - - // initialize the result - source.erase(source.begin(), source.end()); - do { - *searchPos = '\0'; - source += currentPos; - currentPos = searchPos + replaceSize; - // replace - source += with; - searchPos = strstr(currentPos, replace); - } while (searchPos); - - // copy any trailing text - source += currentPos; - free(orig); -} - -#if defined(_WIN32) && !defined(__CYGWIN__) - -# if defined(KEY_WOW64_32KEY) && defined(KEY_WOW64_64KEY) -# define KWSYS_ST_KEY_WOW64_32KEY KEY_WOW64_32KEY -# define KWSYS_ST_KEY_WOW64_64KEY KEY_WOW64_64KEY -# else -# define KWSYS_ST_KEY_WOW64_32KEY 0x0200 -# define KWSYS_ST_KEY_WOW64_64KEY 0x0100 -# endif - -static bool SystemToolsParseRegistryKey(const std::string& key, - HKEY& primaryKey, std::string& second, - std::string& valuename) -{ - std::string primary = key; - - size_t start = primary.find('\\'); - if (start == std::string::npos) { - return false; - } - - size_t valuenamepos = primary.find(';'); - if (valuenamepos != std::string::npos) { - valuename = primary.substr(valuenamepos + 1); - } - - second = primary.substr(start + 1, valuenamepos - start - 1); - primary = primary.substr(0, start); - - if (primary == "HKEY_CURRENT_USER") { - primaryKey = HKEY_CURRENT_USER; - } - if (primary == "HKEY_CURRENT_CONFIG") { - primaryKey = HKEY_CURRENT_CONFIG; - } - if (primary == "HKEY_CLASSES_ROOT") { - primaryKey = HKEY_CLASSES_ROOT; - } - if (primary == "HKEY_LOCAL_MACHINE") { - primaryKey = HKEY_LOCAL_MACHINE; - } - if (primary == "HKEY_USERS") { - primaryKey = HKEY_USERS; - } - - return true; -} - -static DWORD SystemToolsMakeRegistryMode(DWORD mode, - SystemTools::KeyWOW64 view) -{ - // only add the modes when on a system that supports Wow64. - static FARPROC wow64p = - GetProcAddress(GetModuleHandleW(L"kernel32"), "IsWow64Process"); - if (wow64p == nullptr) { - return mode; - } - - if (view == SystemTools::KeyWOW64_32) { - return mode | KWSYS_ST_KEY_WOW64_32KEY; - } else if (view == SystemTools::KeyWOW64_64) { - return mode | KWSYS_ST_KEY_WOW64_64KEY; - } - return mode; -} -#endif - -#if defined(_WIN32) && !defined(__CYGWIN__) -bool SystemTools::GetRegistrySubKeys(const std::string& key, - std::vector& subkeys, - KeyWOW64 view) -{ - HKEY primaryKey = HKEY_CURRENT_USER; - std::string second; - std::string valuename; - if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) { - return false; - } - - HKEY hKey; - if (RegOpenKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0, - SystemToolsMakeRegistryMode(KEY_READ, view), - &hKey) != ERROR_SUCCESS) { - return false; - } else { - wchar_t name[1024]; - DWORD dwNameSize = sizeof(name) / sizeof(name[0]); - - DWORD i = 0; - while (RegEnumKeyW(hKey, i, name, dwNameSize) == ERROR_SUCCESS) { - subkeys.push_back(Encoding::ToNarrow(name)); - ++i; - } - - RegCloseKey(hKey); - } - - return true; -} -#else -bool SystemTools::GetRegistrySubKeys(const std::string&, - std::vector&, KeyWOW64) -{ - return false; -} -#endif - -// Read a registry value. -// Example : -// HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\2.1\InstallPath -// => will return the data of the "default" value of the key -// HKEY_LOCAL_MACHINE\SOFTWARE\Scriptics\Tcl\8.4;Root -// => will return the data of the "Root" value of the key - -#if defined(_WIN32) && !defined(__CYGWIN__) -bool SystemTools::ReadRegistryValue(const std::string& key, std::string& value, - KeyWOW64 view) -{ - bool valueset = false; - HKEY primaryKey = HKEY_CURRENT_USER; - std::string second; - std::string valuename; - if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) { - return false; - } - - HKEY hKey; - if (RegOpenKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0, - SystemToolsMakeRegistryMode(KEY_READ, view), - &hKey) != ERROR_SUCCESS) { - return false; - } else { - DWORD dwType, dwSize; - dwSize = 1023; - wchar_t data[1024]; - if (RegQueryValueExW(hKey, Encoding::ToWide(valuename).c_str(), nullptr, - &dwType, (BYTE*)data, &dwSize) == ERROR_SUCCESS) { - if (dwType == REG_SZ) { - value = Encoding::ToNarrow(data); - valueset = true; - } else if (dwType == REG_EXPAND_SZ) { - wchar_t expanded[1024]; - DWORD dwExpandedSize = sizeof(expanded) / sizeof(expanded[0]); - if (ExpandEnvironmentStringsW(data, expanded, dwExpandedSize)) { - value = Encoding::ToNarrow(expanded); - valueset = true; - } - } - } - - RegCloseKey(hKey); - } - - return valueset; -} -#else -bool SystemTools::ReadRegistryValue(const std::string&, std::string&, KeyWOW64) -{ - return false; -} -#endif - -// Write a registry value. -// Example : -// HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\2.1\InstallPath -// => will set the data of the "default" value of the key -// HKEY_LOCAL_MACHINE\SOFTWARE\Scriptics\Tcl\8.4;Root -// => will set the data of the "Root" value of the key - -#if defined(_WIN32) && !defined(__CYGWIN__) -bool SystemTools::WriteRegistryValue(const std::string& key, - const std::string& value, KeyWOW64 view) -{ - HKEY primaryKey = HKEY_CURRENT_USER; - std::string second; - std::string valuename; - if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) { - return false; - } - - HKEY hKey; - DWORD dwDummy; - wchar_t lpClass[] = L""; - if (RegCreateKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0, lpClass, - REG_OPTION_NON_VOLATILE, - SystemToolsMakeRegistryMode(KEY_WRITE, view), nullptr, - &hKey, &dwDummy) != ERROR_SUCCESS) { - return false; - } - - std::wstring wvalue = Encoding::ToWide(value); - if (RegSetValueExW(hKey, Encoding::ToWide(valuename).c_str(), 0, REG_SZ, - (CONST BYTE*)wvalue.c_str(), - (DWORD)(sizeof(wchar_t) * (wvalue.size() + 1))) == - ERROR_SUCCESS) { - return true; - } - return false; -} -#else -bool SystemTools::WriteRegistryValue(const std::string&, const std::string&, - KeyWOW64) -{ - return false; -} -#endif - -// Delete a registry value. -// Example : -// HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\2.1\InstallPath -// => will delete the data of the "default" value of the key -// HKEY_LOCAL_MACHINE\SOFTWARE\Scriptics\Tcl\8.4;Root -// => will delete the data of the "Root" value of the key - -#if defined(_WIN32) && !defined(__CYGWIN__) -bool SystemTools::DeleteRegistryValue(const std::string& key, KeyWOW64 view) -{ - HKEY primaryKey = HKEY_CURRENT_USER; - std::string second; - std::string valuename; - if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) { - return false; - } - - HKEY hKey; - if (RegOpenKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0, - SystemToolsMakeRegistryMode(KEY_WRITE, view), - &hKey) != ERROR_SUCCESS) { - return false; - } else { - if (RegDeleteValue(hKey, (LPTSTR)valuename.c_str()) == ERROR_SUCCESS) { - RegCloseKey(hKey); - return true; - } - } - return false; -} -#else -bool SystemTools::DeleteRegistryValue(const std::string&, KeyWOW64) -{ - return false; -} -#endif - -bool SystemTools::SameFile(const std::string& file1, const std::string& file2) -{ -#ifdef _WIN32 - HANDLE hFile1, hFile2; - - hFile1 = - CreateFileW(Encoding::ToWide(file1).c_str(), GENERIC_READ, FILE_SHARE_READ, - nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); - hFile2 = - CreateFileW(Encoding::ToWide(file2).c_str(), GENERIC_READ, FILE_SHARE_READ, - nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); - if (hFile1 == INVALID_HANDLE_VALUE || hFile2 == INVALID_HANDLE_VALUE) { - if (hFile1 != INVALID_HANDLE_VALUE) { - CloseHandle(hFile1); - } - if (hFile2 != INVALID_HANDLE_VALUE) { - CloseHandle(hFile2); - } - return false; - } - - BY_HANDLE_FILE_INFORMATION fiBuf1; - BY_HANDLE_FILE_INFORMATION fiBuf2; - GetFileInformationByHandle(hFile1, &fiBuf1); - GetFileInformationByHandle(hFile2, &fiBuf2); - CloseHandle(hFile1); - CloseHandle(hFile2); - return (fiBuf1.dwVolumeSerialNumber == fiBuf2.dwVolumeSerialNumber && - fiBuf1.nFileIndexHigh == fiBuf2.nFileIndexHigh && - fiBuf1.nFileIndexLow == fiBuf2.nFileIndexLow); -#else - struct stat fileStat1, fileStat2; - if (stat(file1.c_str(), &fileStat1) == 0 && - stat(file2.c_str(), &fileStat2) == 0) { - // see if the files are the same file - // check the device inode and size - if (memcmp(&fileStat2.st_dev, &fileStat1.st_dev, - sizeof(fileStat1.st_dev)) == 0 && - memcmp(&fileStat2.st_ino, &fileStat1.st_ino, - sizeof(fileStat1.st_ino)) == 0 && - fileStat2.st_size == fileStat1.st_size) { - return true; - } - } - return false; -#endif -} - -bool SystemTools::PathExists(const std::string& path) -{ - if (path.empty()) { - return false; - } -#if defined(__CYGWIN__) - // Convert path to native windows path if possible. - char winpath[MAX_PATH]; - if (SystemTools::PathCygwinToWin32(path.c_str(), winpath)) { - return (GetFileAttributesA(winpath) != INVALID_FILE_ATTRIBUTES); - } - struct stat st; - return lstat(path.c_str(), &st) == 0; -#elif defined(_WIN32) - return (GetFileAttributesW(Encoding::ToWindowsExtendedPath(path).c_str()) != - INVALID_FILE_ATTRIBUTES); -#else - struct stat st; - return lstat(path.c_str(), &st) == 0; -#endif -} - -bool SystemTools::FileExists(const char* filename) -{ - if (!filename) { - return false; - } - return SystemTools::FileExists(std::string(filename)); -} - -bool SystemTools::FileExists(const std::string& filename) -{ - if (filename.empty()) { - return false; - } -#if defined(__CYGWIN__) - // Convert filename to native windows path if possible. - char winpath[MAX_PATH]; - if (SystemTools::PathCygwinToWin32(filename.c_str(), winpath)) { - return (GetFileAttributesA(winpath) != INVALID_FILE_ATTRIBUTES); - } - return access(filename.c_str(), R_OK) == 0; -#elif defined(_WIN32) - DWORD attr = - GetFileAttributesW(Encoding::ToWindowsExtendedPath(filename).c_str()); - if (attr == INVALID_FILE_ATTRIBUTES) { - return false; - } - - if (attr & FILE_ATTRIBUTE_REPARSE_POINT) { - // Using 0 instead of GENERIC_READ as it allows reading of file attributes - // even if we do not have permission to read the file itself - HANDLE handle = - CreateFileW(Encoding::ToWindowsExtendedPath(filename).c_str(), 0, 0, - nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); - - if (handle == INVALID_HANDLE_VALUE) { - return false; - } - - CloseHandle(handle); - } - - return true; -#else -// SCO OpenServer 5.0.7/3.2's command has 711 permission. -# if defined(_SCO_DS) - return access(filename.c_str(), F_OK) == 0; -# else - return access(filename.c_str(), R_OK) == 0; -# endif -#endif -} - -bool SystemTools::FileExists(const char* filename, bool isFile) -{ - if (!filename) { - return false; - } - return SystemTools::FileExists(std::string(filename), isFile); -} - -bool SystemTools::FileExists(const std::string& filename, bool isFile) -{ - if (SystemTools::FileExists(filename)) { - // If isFile is set return not FileIsDirectory, - // so this will only be true if it is a file - return !isFile || !SystemTools::FileIsDirectory(filename); - } - return false; -} - -bool SystemTools::TestFileAccess(const char* filename, - TestFilePermissions permissions) -{ - if (!filename) { - return false; - } - return SystemTools::TestFileAccess(std::string(filename), permissions); -} - -bool SystemTools::TestFileAccess(const std::string& filename, - TestFilePermissions permissions) -{ - if (filename.empty()) { - return false; - } -#if defined(_WIN32) && !defined(__CYGWIN__) - // If execute set, change to read permission (all files on Windows - // are executable if they are readable). The CRT will always fail - // if you pass an execute bit. - if (permissions & TEST_FILE_EXECUTE) { - permissions &= ~TEST_FILE_EXECUTE; - permissions |= TEST_FILE_READ; - } - return _waccess(Encoding::ToWindowsExtendedPath(filename).c_str(), - permissions) == 0; -#else - return access(filename.c_str(), permissions) == 0; -#endif -} - -int SystemTools::Stat(const char* path, SystemTools::Stat_t* buf) -{ - if (!path) { - errno = EFAULT; - return -1; - } - return SystemTools::Stat(std::string(path), buf); -} - -int SystemTools::Stat(const std::string& path, SystemTools::Stat_t* buf) -{ - if (path.empty()) { - errno = ENOENT; - return -1; - } -#if defined(_WIN32) && !defined(__CYGWIN__) - // Ideally we should use Encoding::ToWindowsExtendedPath to support - // long paths, but _wstat64 rejects paths with '?' in them, thinking - // they are wildcards. - std::wstring const& wpath = Encoding::ToWide(path); -# if defined(__BORLANDC__) - return _wstati64(wpath.c_str(), buf); -# else - return _wstat64(wpath.c_str(), buf); -# endif -#else - return stat(path.c_str(), buf); -#endif -} - -#ifdef __CYGWIN__ -bool SystemTools::PathCygwinToWin32(const char* path, char* win32_path) -{ - auto itr = SystemTools::Statics->Cyg2Win32Map.find(path); - if (itr != SystemTools::Statics->Cyg2Win32Map.end()) { - strncpy(win32_path, itr->second.c_str(), MAX_PATH); - } else { - if (cygwin_conv_path(CCP_POSIX_TO_WIN_A, path, win32_path, MAX_PATH) != - 0) { - win32_path[0] = 0; - } - SystemTools::Statics->Cyg2Win32Map.insert( - SystemToolsStatic::StringMap::value_type(path, win32_path)); - } - return win32_path[0] != 0; -} -#endif - -bool SystemTools::Touch(const std::string& filename, bool create) -{ - if (!SystemTools::PathExists(filename)) { - if (create) { - FILE* file = Fopen(filename, "a+b"); - if (file) { - fclose(file); - return true; - } - return false; - } else { - return true; - } - } -#if defined(_WIN32) && !defined(__CYGWIN__) - HANDLE h = CreateFileW(Encoding::ToWindowsExtendedPath(filename).c_str(), - FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, 0, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); - if (!h) { - return false; - } - FILETIME mtime; - GetSystemTimeAsFileTime(&mtime); - if (!SetFileTime(h, 0, 0, &mtime)) { - CloseHandle(h); - return false; - } - CloseHandle(h); -#elif KWSYS_CXX_HAS_UTIMENSAT - // utimensat is only available on newer Unixes and macOS 10.13+ - if (utimensat(AT_FDCWD, filename.c_str(), nullptr, 0) < 0) { - return false; - } -#else - // fall back to utimes - if (utimes(filename.c_str(), nullptr) < 0) { - return false; - } -#endif - return true; -} - -bool SystemTools::FileTimeCompare(const std::string& f1, const std::string& f2, - int* result) -{ - // Default to same time. - *result = 0; -#if !defined(_WIN32) || defined(__CYGWIN__) - // POSIX version. Use stat function to get file modification time. - struct stat s1; - if (stat(f1.c_str(), &s1) != 0) { - return false; - } - struct stat s2; - if (stat(f2.c_str(), &s2) != 0) { - return false; - } -# if KWSYS_CXX_STAT_HAS_ST_MTIM - // Compare using nanosecond resolution. - if (s1.st_mtim.tv_sec < s2.st_mtim.tv_sec) { - *result = -1; - } else if (s1.st_mtim.tv_sec > s2.st_mtim.tv_sec) { - *result = 1; - } else if (s1.st_mtim.tv_nsec < s2.st_mtim.tv_nsec) { - *result = -1; - } else if (s1.st_mtim.tv_nsec > s2.st_mtim.tv_nsec) { - *result = 1; - } -# elif KWSYS_CXX_STAT_HAS_ST_MTIMESPEC - // Compare using nanosecond resolution. - if (s1.st_mtimespec.tv_sec < s2.st_mtimespec.tv_sec) { - *result = -1; - } else if (s1.st_mtimespec.tv_sec > s2.st_mtimespec.tv_sec) { - *result = 1; - } else if (s1.st_mtimespec.tv_nsec < s2.st_mtimespec.tv_nsec) { - *result = -1; - } else if (s1.st_mtimespec.tv_nsec > s2.st_mtimespec.tv_nsec) { - *result = 1; - } -# else - // Compare using 1 second resolution. - if (s1.st_mtime < s2.st_mtime) { - *result = -1; - } else if (s1.st_mtime > s2.st_mtime) { - *result = 1; - } -# endif -#else - // Windows version. Get the modification time from extended file attributes. - WIN32_FILE_ATTRIBUTE_DATA f1d; - WIN32_FILE_ATTRIBUTE_DATA f2d; - if (!GetFileAttributesExW(Encoding::ToWindowsExtendedPath(f1).c_str(), - GetFileExInfoStandard, &f1d)) { - return false; - } - if (!GetFileAttributesExW(Encoding::ToWindowsExtendedPath(f2).c_str(), - GetFileExInfoStandard, &f2d)) { - return false; - } - - // Compare the file times using resolution provided by system call. - *result = (int)CompareFileTime(&f1d.ftLastWriteTime, &f2d.ftLastWriteTime); -#endif - return true; -} - -// Return a capitalized string (i.e the first letter is uppercased, all other -// are lowercased) -std::string SystemTools::Capitalized(const std::string& s) -{ - std::string n; - if (s.empty()) { - return n; - } - n.resize(s.size()); - n[0] = static_cast(toupper(s[0])); - for (size_t i = 1; i < s.size(); i++) { - n[i] = static_cast(tolower(s[i])); - } - return n; -} - -// Return capitalized words -std::string SystemTools::CapitalizedWords(const std::string& s) -{ - std::string n(s); - for (size_t i = 0; i < s.size(); i++) { -#if defined(_MSC_VER) && defined(_MT) && defined(_DEBUG) - // MS has an assert that will fail if s[i] < 0; setting - // LC_CTYPE using setlocale() does *not* help. Painful. - if ((int)s[i] >= 0 && isalpha(s[i]) && - (i == 0 || ((int)s[i - 1] >= 0 && isspace(s[i - 1])))) -#else - if (isalpha(s[i]) && (i == 0 || isspace(s[i - 1]))) -#endif - { - n[i] = static_cast(toupper(s[i])); - } - } - return n; -} - -// Return uncapitalized words -std::string SystemTools::UnCapitalizedWords(const std::string& s) -{ - std::string n(s); - for (size_t i = 0; i < s.size(); i++) { -#if defined(_MSC_VER) && defined(_MT) && defined(_DEBUG) - // MS has an assert that will fail if s[i] < 0; setting - // LC_CTYPE using setlocale() does *not* help. Painful. - if ((int)s[i] >= 0 && isalpha(s[i]) && - (i == 0 || ((int)s[i - 1] >= 0 && isspace(s[i - 1])))) -#else - if (isalpha(s[i]) && (i == 0 || isspace(s[i - 1]))) -#endif - { - n[i] = static_cast(tolower(s[i])); - } - } - return n; -} - -// only works for words with at least two letters -std::string SystemTools::AddSpaceBetweenCapitalizedWords(const std::string& s) -{ - std::string n; - if (!s.empty()) { - n.reserve(s.size()); - n += s[0]; - for (size_t i = 1; i < s.size(); i++) { - if (isupper(s[i]) && !isspace(s[i - 1]) && !isupper(s[i - 1])) { - n += ' '; - } - n += s[i]; - } - } - return n; -} - -char* SystemTools::AppendStrings(const char* str1, const char* str2) -{ - if (!str1) { - return SystemTools::DuplicateString(str2); - } - if (!str2) { - return SystemTools::DuplicateString(str1); - } - size_t len1 = strlen(str1); - char* newstr = new char[len1 + strlen(str2) + 1]; - if (!newstr) { - return nullptr; - } - strcpy(newstr, str1); - strcat(newstr + len1, str2); - return newstr; -} - -char* SystemTools::AppendStrings(const char* str1, const char* str2, - const char* str3) -{ - if (!str1) { - return SystemTools::AppendStrings(str2, str3); - } - if (!str2) { - return SystemTools::AppendStrings(str1, str3); - } - if (!str3) { - return SystemTools::AppendStrings(str1, str2); - } - - size_t len1 = strlen(str1), len2 = strlen(str2); - char* newstr = new char[len1 + len2 + strlen(str3) + 1]; - if (!newstr) { - return nullptr; - } - strcpy(newstr, str1); - strcat(newstr + len1, str2); - strcat(newstr + len1 + len2, str3); - return newstr; -} - -// Return a lower case string -std::string SystemTools::LowerCase(const std::string& s) -{ - std::string n; - n.resize(s.size()); - for (size_t i = 0; i < s.size(); i++) { - n[i] = static_cast(tolower(s[i])); - } - return n; -} - -// Return a lower case string -std::string SystemTools::UpperCase(const std::string& s) -{ - std::string n; - n.resize(s.size()); - for (size_t i = 0; i < s.size(); i++) { - n[i] = static_cast(toupper(s[i])); - } - return n; -} - -// Count char in string -size_t SystemTools::CountChar(const char* str, char c) -{ - size_t count = 0; - - if (str) { - while (*str) { - if (*str == c) { - ++count; - } - ++str; - } - } - return count; -} - -// Remove chars in string -char* SystemTools::RemoveChars(const char* str, const char* toremove) -{ - if (!str) { - return nullptr; - } - char* clean_str = new char[strlen(str) + 1]; - char* ptr = clean_str; - while (*str) { - const char* str2 = toremove; - while (*str2 && *str != *str2) { - ++str2; - } - if (!*str2) { - *ptr++ = *str; - } - ++str; - } - *ptr = '\0'; - return clean_str; -} - -// Remove chars in string -char* SystemTools::RemoveCharsButUpperHex(const char* str) -{ - if (!str) { - return nullptr; - } - char* clean_str = new char[strlen(str) + 1]; - char* ptr = clean_str; - while (*str) { - if ((*str >= '0' && *str <= '9') || (*str >= 'A' && *str <= 'F')) { - *ptr++ = *str; - } - ++str; - } - *ptr = '\0'; - return clean_str; -} - -// Replace chars in string -char* SystemTools::ReplaceChars(char* str, const char* toreplace, - char replacement) -{ - if (str) { - char* ptr = str; - while (*ptr) { - const char* ptr2 = toreplace; - while (*ptr2) { - if (*ptr == *ptr2) { - *ptr = replacement; - } - ++ptr2; - } - ++ptr; - } - } - return str; -} - -// Returns if string starts with another string -bool SystemTools::StringStartsWith(const char* str1, const char* str2) -{ - if (!str1 || !str2) { - return false; - } - size_t len1 = strlen(str1), len2 = strlen(str2); - return len1 >= len2 && !strncmp(str1, str2, len2) ? true : false; -} - -// Returns if string starts with another string -bool SystemTools::StringStartsWith(const std::string& str1, const char* str2) -{ - if (!str2) { - return false; - } - size_t len1 = str1.size(), len2 = strlen(str2); - return len1 >= len2 && !strncmp(str1.c_str(), str2, len2) ? true : false; -} - -// Returns if string ends with another string -bool SystemTools::StringEndsWith(const char* str1, const char* str2) -{ - if (!str1 || !str2) { - return false; - } - size_t len1 = strlen(str1), len2 = strlen(str2); - return len1 >= len2 && !strncmp(str1 + (len1 - len2), str2, len2) ? true - : false; -} - -// Returns if string ends with another string -bool SystemTools::StringEndsWith(const std::string& str1, const char* str2) -{ - if (!str2) { - return false; - } - size_t len1 = str1.size(), len2 = strlen(str2); - return len1 >= len2 && !strncmp(str1.c_str() + (len1 - len2), str2, len2) - ? true - : false; -} - -// Returns a pointer to the last occurrence of str2 in str1 -const char* SystemTools::FindLastString(const char* str1, const char* str2) -{ - if (!str1 || !str2) { - return nullptr; - } - - size_t len1 = strlen(str1), len2 = strlen(str2); - if (len1 >= len2) { - const char* ptr = str1 + len1 - len2; - do { - if (!strncmp(ptr, str2, len2)) { - return ptr; - } - } while (ptr-- != str1); - } - - return nullptr; -} - -// Duplicate string -char* SystemTools::DuplicateString(const char* str) -{ - if (str) { - char* newstr = new char[strlen(str) + 1]; - return strcpy(newstr, str); - } - return nullptr; -} - -// Return a cropped string -std::string SystemTools::CropString(const std::string& s, size_t max_len) -{ - if (!s.size() || max_len == 0 || max_len >= s.size()) { - return s; - } - - std::string n; - n.reserve(max_len); - - size_t middle = max_len / 2; - - n += s.substr(0, middle); - n += s.substr(s.size() - (max_len - middle)); - - if (max_len > 2) { - n[middle] = '.'; - if (max_len > 3) { - n[middle - 1] = '.'; - if (max_len > 4) { - n[middle + 1] = '.'; - } - } - } - - return n; -} - -std::vector SystemTools::SplitString(const std::string& p, - char sep, bool isPath) -{ - std::string path = p; - std::vector paths; - if (path.empty()) { - return paths; - } - if (isPath && path[0] == '/') { - path.erase(path.begin()); - paths.push_back("/"); - } - std::string::size_type pos1 = 0; - std::string::size_type pos2 = path.find(sep, pos1 + 1); - while (pos2 != std::string::npos) { - paths.push_back(path.substr(pos1, pos2 - pos1)); - pos1 = pos2 + 1; - pos2 = path.find(sep, pos1 + 1); - } - paths.push_back(path.substr(pos1, pos2 - pos1)); - - return paths; -} - -int SystemTools::EstimateFormatLength(const char* format, va_list ap) -{ - if (!format) { - return 0; - } - - // Quick-hack attempt at estimating the length of the string. - // Should never under-estimate. - - // Start with the length of the format string itself. - - size_t length = strlen(format); - - // Increase the length for every argument in the format. - - const char* cur = format; - while (*cur) { - if (*cur++ == '%') { - // Skip "%%" since it doesn't correspond to a va_arg. - if (*cur != '%') { - while (!int(isalpha(*cur))) { - ++cur; - } - switch (*cur) { - case 's': { - // Check the length of the string. - char* s = va_arg(ap, char*); - if (s) { - length += strlen(s); - } - } break; - case 'e': - case 'f': - case 'g': { - // Assume the argument contributes no more than 64 characters. - length += 64; - - // Eat the argument. - static_cast(va_arg(ap, double)); - } break; - default: { - // Assume the argument contributes no more than 64 characters. - length += 64; - - // Eat the argument. - static_cast(va_arg(ap, int)); - } break; - } - } - - // Move past the characters just tested. - ++cur; - } - } - - return static_cast(length); -} - -std::string SystemTools::EscapeChars(const char* str, - const char* chars_to_escape, - char escape_char) -{ - std::string n; - if (str) { - if (!chars_to_escape || !*chars_to_escape) { - n.append(str); - } else { - n.reserve(strlen(str)); - while (*str) { - const char* ptr = chars_to_escape; - while (*ptr) { - if (*str == *ptr) { - n += escape_char; - break; - } - ++ptr; - } - n += *str; - ++str; - } - } - } - return n; -} - -#ifdef __VMS -static void ConvertVMSToUnix(std::string& path) -{ - std::string::size_type rootEnd = path.find(":["); - std::string::size_type pathEnd = path.find("]"); - if (rootEnd != std::string::npos) { - std::string root = path.substr(0, rootEnd); - std::string pathPart = path.substr(rootEnd + 2, pathEnd - rootEnd - 2); - const char* pathCString = pathPart.c_str(); - const char* pos0 = pathCString; - for (std::string::size_type pos = 0; *pos0; ++pos) { - if (*pos0 == '.') { - pathPart[pos] = '/'; - } - pos0++; - } - path = "/" + root + "/" + pathPart; - } -} -#endif - -// convert windows slashes to unix slashes -void SystemTools::ConvertToUnixSlashes(std::string& path) -{ - if (path.empty()) { - return; - } - - const char* pathCString = path.c_str(); - bool hasDoubleSlash = false; -#ifdef __VMS - ConvertVMSToUnix(path); -#else - const char* pos0 = pathCString; - for (std::string::size_type pos = 0; *pos0; ++pos) { - if (*pos0 == '\\') { - path[pos] = '/'; - } - - // Also, reuse the loop to check for slash followed by another slash - if (!hasDoubleSlash && *(pos0 + 1) == '/' && *(pos0 + 2) == '/') { -# ifdef _WIN32 - // However, on windows if the first characters are both slashes, - // then keep them that way, so that network paths can be handled. - if (pos > 0) { - hasDoubleSlash = true; - } -# else - hasDoubleSlash = true; -# endif - } - - pos0++; - } - - if (hasDoubleSlash) { - SystemTools::ReplaceString(path, "//", "/"); - } -#endif - - // remove any trailing slash - // if there is a tilda ~ then replace it with HOME - pathCString = path.c_str(); - if (pathCString[0] == '~' && - (pathCString[1] == '/' || pathCString[1] == '\0')) { - std::string homeEnv; - if (SystemTools::GetEnv("HOME", homeEnv)) { - path.replace(0, 1, homeEnv); - } - } -#ifdef HAVE_GETPWNAM - else if (pathCString[0] == '~') { - std::string::size_type idx = path.find_first_of("/\0"); - std::string user = path.substr(1, idx - 1); - passwd* pw = getpwnam(user.c_str()); - if (pw) { - path.replace(0, idx, pw->pw_dir); - } - } -#endif - // remove trailing slash if the path is more than - // a single / - pathCString = path.c_str(); - size_t size = path.size(); - if (size > 1 && path.back() == '/') { - // if it is c:/ then do not remove the trailing slash - if (!((size == 3 && pathCString[1] == ':'))) { - path.resize(size - 1); - } - } -} - -#ifdef _WIN32 -std::wstring SystemTools::ConvertToWindowsExtendedPath( - const std::string& source) -{ - return Encoding::ToWindowsExtendedPath(source); -} -#endif - -// change // to /, and escape any spaces in the path -std::string SystemTools::ConvertToUnixOutputPath(const std::string& path) -{ - std::string ret = path; - - // remove // except at the beginning might be a cygwin drive - std::string::size_type pos = 1; - while ((pos = ret.find("//", pos)) != std::string::npos) { - ret.erase(pos, 1); - } - // escape spaces and () in the path - if (ret.find_first_of(" ") != std::string::npos) { - std::string result; - char lastch = 1; - for (const char* ch = ret.c_str(); *ch != '\0'; ++ch) { - // if it is already escaped then don't try to escape it again - if ((*ch == ' ') && lastch != '\\') { - result += '\\'; - } - result += *ch; - lastch = *ch; - } - ret = result; - } - return ret; -} - -std::string SystemTools::ConvertToOutputPath(const std::string& path) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - return SystemTools::ConvertToWindowsOutputPath(path); -#else - return SystemTools::ConvertToUnixOutputPath(path); -#endif -} - -// remove double slashes not at the start -std::string SystemTools::ConvertToWindowsOutputPath(const std::string& path) -{ - std::string ret; - // make it big enough for all of path and double quotes - ret.reserve(path.size() + 3); - // put path into the string - ret = path; - std::string::size_type pos = 0; - // first convert all of the slashes - while ((pos = ret.find('/', pos)) != std::string::npos) { - ret[pos] = '\\'; - pos++; - } - // check for really small paths - if (ret.size() < 2) { - return ret; - } - // now clean up a bit and remove double slashes - // Only if it is not the first position in the path which is a network - // path on windows - pos = 1; // start at position 1 - if (ret[0] == '\"') { - pos = 2; // if the string is already quoted then start at 2 - if (ret.size() < 3) { - return ret; - } - } - while ((pos = ret.find("\\\\", pos)) != std::string::npos) { - ret.erase(pos, 1); - } - // now double quote the path if it has spaces in it - // and is not already double quoted - if (ret.find(' ') != std::string::npos && ret[0] != '\"') { - ret.insert(static_cast(0), - static_cast(1), '\"'); - ret.append(1, '\"'); - } - return ret; -} - -/** - * Append the filename from the path source to the directory name dir. - */ -static std::string FileInDir(const std::string& source, const std::string& dir) -{ - std::string new_destination = dir; - SystemTools::ConvertToUnixSlashes(new_destination); - return new_destination + '/' + SystemTools::GetFilenameName(source); -} - -bool SystemTools::CopyFileIfDifferent(const std::string& source, - const std::string& destination) -{ - // special check for a destination that is a directory - // FilesDiffer does not handle file to directory compare - if (SystemTools::FileIsDirectory(destination)) { - const std::string new_destination = FileInDir(source, destination); - return SystemTools::CopyFileIfDifferent(source, new_destination); - } - // source and destination are files so do a copy if they - // are different - if (SystemTools::FilesDiffer(source, destination)) { - return SystemTools::CopyFileAlways(source, destination); - } - // at this point the files must be the same so return true - return true; -} - -#define KWSYS_ST_BUFFER 4096 - -bool SystemTools::FilesDiffer(const std::string& source, - const std::string& destination) -{ - -#if defined(_WIN32) - WIN32_FILE_ATTRIBUTE_DATA statSource; - if (GetFileAttributesExW(Encoding::ToWindowsExtendedPath(source).c_str(), - GetFileExInfoStandard, &statSource) == 0) { - return true; - } - - WIN32_FILE_ATTRIBUTE_DATA statDestination; - if (GetFileAttributesExW( - Encoding::ToWindowsExtendedPath(destination).c_str(), - GetFileExInfoStandard, &statDestination) == 0) { - return true; - } - - if (statSource.nFileSizeHigh != statDestination.nFileSizeHigh || - statSource.nFileSizeLow != statDestination.nFileSizeLow) { - return true; - } - - if (statSource.nFileSizeHigh == 0 && statSource.nFileSizeLow == 0) { - return false; - } - off_t nleft = - ((__int64)statSource.nFileSizeHigh << 32) + statSource.nFileSizeLow; - -#else - - struct stat statSource; - if (stat(source.c_str(), &statSource) != 0) { - return true; - } - - struct stat statDestination; - if (stat(destination.c_str(), &statDestination) != 0) { - return true; - } - - if (statSource.st_size != statDestination.st_size) { - return true; - } - - if (statSource.st_size == 0) { - return false; - } - off_t nleft = statSource.st_size; -#endif - -#if defined(_WIN32) - kwsys::ifstream finSource(source.c_str(), (std::ios::binary | std::ios::in)); - kwsys::ifstream finDestination(destination.c_str(), - (std::ios::binary | std::ios::in)); -#else - kwsys::ifstream finSource(source.c_str()); - kwsys::ifstream finDestination(destination.c_str()); -#endif - if (!finSource || !finDestination) { - return true; - } - - // Compare the files a block at a time. - char source_buf[KWSYS_ST_BUFFER]; - char dest_buf[KWSYS_ST_BUFFER]; - while (nleft > 0) { - // Read a block from each file. - std::streamsize nnext = (nleft > KWSYS_ST_BUFFER) - ? KWSYS_ST_BUFFER - : static_cast(nleft); - finSource.read(source_buf, nnext); - finDestination.read(dest_buf, nnext); - - // If either failed to read assume they are different. - if (static_cast(finSource.gcount()) != nnext || - static_cast(finDestination.gcount()) != nnext) { - return true; - } - - // If this block differs the file differs. - if (memcmp(static_cast(source_buf), - static_cast(dest_buf), - static_cast(nnext)) != 0) { - return true; - } - - // Update the byte count remaining. - nleft -= nnext; - } - - // No differences found. - return false; -} - -bool SystemTools::TextFilesDiffer(const std::string& path1, - const std::string& path2) -{ - kwsys::ifstream if1(path1.c_str()); - kwsys::ifstream if2(path2.c_str()); - if (!if1 || !if2) { - return true; - } - - for (;;) { - std::string line1, line2; - bool hasData1 = GetLineFromStream(if1, line1); - bool hasData2 = GetLineFromStream(if2, line2); - if (hasData1 != hasData2) { - return true; - } - if (!hasData1) { - break; - } - if (line1 != line2) { - return true; - } - } - return false; -} - -/** - * Blockwise copy source to destination file - */ -static bool CopyFileContentBlockwise(const std::string& source, - const std::string& destination) -{ -// Open files -#if defined(_WIN32) - kwsys::ifstream fin( - Encoding::ToNarrow(Encoding::ToWindowsExtendedPath(source)).c_str(), - std::ios::in | std::ios::binary); -#else - kwsys::ifstream fin(source.c_str(), std::ios::in | std::ios::binary); -#endif - if (!fin) { - return false; - } - - // try and remove the destination file so that read only destination files - // can be written to. - // If the remove fails continue so that files in read only directories - // that do not allow file removal can be modified. - SystemTools::RemoveFile(destination); - -#if defined(_WIN32) - kwsys::ofstream fout( - Encoding::ToNarrow(Encoding::ToWindowsExtendedPath(destination)).c_str(), - std::ios::out | std::ios::trunc | std::ios::binary); -#else - kwsys::ofstream fout(destination.c_str(), - std::ios::out | std::ios::trunc | std::ios::binary); -#endif - if (!fout) { - return false; - } - - // This copy loop is very sensitive on certain platforms with - // slightly broken stream libraries (like HPUX). Normally, it is - // incorrect to not check the error condition on the fin.read() - // before using the data, but the fin.gcount() will be zero if an - // error occurred. Therefore, the loop should be safe everywhere. - while (fin) { - const int bufferSize = 4096; - char buffer[bufferSize]; - - fin.read(buffer, bufferSize); - if (fin.gcount()) { - fout.write(buffer, fin.gcount()); - } else { - break; - } - } - - // Make sure the operating system has finished writing the file - // before closing it. This will ensure the file is finished before - // the check below. - fout.flush(); - - fin.close(); - fout.close(); - - if (!fout) { - return false; - } - - return true; -} - -/** - * Clone the source file to the destination file - * - * If available, the Linux FICLONE ioctl is used to create a check - * copy-on-write clone of the source file. - * - * The method returns false for the following cases: - * - The code has not been compiled on Linux or the ioctl was unknown - * - The source and destination is on different file systems - * - The underlying filesystem does not support file cloning - * - An unspecified error occurred - */ -static bool CloneFileContent(const std::string& source, - const std::string& destination) -{ -#if defined(__linux) && defined(FICLONE) - int in = open(source.c_str(), O_RDONLY); - if (in < 0) { - return false; - } - - SystemTools::RemoveFile(destination); - - int out = - open(destination.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); - if (out < 0) { - close(in); - return false; - } - - int result = ioctl(out, FICLONE, in); - close(in); - close(out); - - if (result < 0) { - return false; - } - - return true; -#else - (void)source; - (void)destination; - return false; -#endif -} - -/** - * Copy a file named by "source" to the file named by "destination". - */ -bool SystemTools::CopyFileAlways(const std::string& source, - const std::string& destination) -{ - mode_t perm = 0; - bool perms = SystemTools::GetPermissions(source, perm); - std::string real_destination = destination; - - if (SystemTools::FileIsDirectory(source)) { - SystemTools::MakeDirectory(destination); - } else { - // If destination is a directory, try to create a file with the same - // name as the source in that directory. - - std::string destination_dir; - if (SystemTools::FileIsDirectory(destination)) { - destination_dir = real_destination; - SystemTools::ConvertToUnixSlashes(real_destination); - real_destination += '/'; - std::string source_name = source; - real_destination += SystemTools::GetFilenameName(source_name); - } else { - destination_dir = SystemTools::GetFilenamePath(destination); - } - // If files are the same do not copy - if (SystemTools::SameFile(source, real_destination)) { - return true; - } - - // Create destination directory - - SystemTools::MakeDirectory(destination_dir); - - if (!CloneFileContent(source, real_destination)) { - // if cloning did not succeed, fall back to blockwise copy - if (!CopyFileContentBlockwise(source, real_destination)) { - return false; - } - } - } - if (perms) { - if (!SystemTools::SetPermissions(real_destination, perm)) { - return false; - } - } - return true; -} - -bool SystemTools::CopyAFile(const std::string& source, - const std::string& destination, bool always) -{ - if (always) { - return SystemTools::CopyFileAlways(source, destination); - } else { - return SystemTools::CopyFileIfDifferent(source, destination); - } -} - -/** - * Copy a directory content from "source" directory to the directory named by - * "destination". - */ -bool SystemTools::CopyADirectory(const std::string& source, - const std::string& destination, bool always) -{ - Directory dir; - if (dir.Load(source) == 0) { - return false; - } - size_t fileNum; - if (!SystemTools::MakeDirectory(destination)) { - return false; - } - for (fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum) { - if (strcmp(dir.GetFile(static_cast(fileNum)), ".") && - strcmp(dir.GetFile(static_cast(fileNum)), "..")) { - std::string fullPath = source; - fullPath += "/"; - fullPath += dir.GetFile(static_cast(fileNum)); - if (SystemTools::FileIsDirectory(fullPath)) { - std::string fullDestPath = destination; - fullDestPath += "/"; - fullDestPath += dir.GetFile(static_cast(fileNum)); - if (!SystemTools::CopyADirectory(fullPath, fullDestPath, always)) { - return false; - } - } else { - if (!SystemTools::CopyAFile(fullPath, destination, always)) { - return false; - } - } - } - } - - return true; -} - -// return size of file; also returns zero if no file exists -unsigned long SystemTools::FileLength(const std::string& filename) -{ - unsigned long length = 0; -#ifdef _WIN32 - WIN32_FILE_ATTRIBUTE_DATA fs; - if (GetFileAttributesExW(Encoding::ToWindowsExtendedPath(filename).c_str(), - GetFileExInfoStandard, &fs) != 0) { - /* To support the full 64-bit file size, use fs.nFileSizeHigh - * and fs.nFileSizeLow to construct the 64 bit size - - length = ((__int64)fs.nFileSizeHigh << 32) + fs.nFileSizeLow; - */ - length = static_cast(fs.nFileSizeLow); - } -#else - struct stat fs; - if (stat(filename.c_str(), &fs) == 0) { - length = static_cast(fs.st_size); - } -#endif - return length; -} - -int SystemTools::Strucmp(const char* l, const char* r) -{ - int lc; - int rc; - do { - lc = tolower(*l++); - rc = tolower(*r++); - } while (lc == rc && lc); - return lc - rc; -} - -// return file's modified time -long int SystemTools::ModifiedTime(const std::string& filename) -{ - long int mt = 0; -#ifdef _WIN32 - WIN32_FILE_ATTRIBUTE_DATA fs; - if (GetFileAttributesExW(Encoding::ToWindowsExtendedPath(filename).c_str(), - GetFileExInfoStandard, &fs) != 0) { - mt = windows_filetime_to_posix_time(fs.ftLastWriteTime); - } -#else - struct stat fs; - if (stat(filename.c_str(), &fs) == 0) { - mt = static_cast(fs.st_mtime); - } -#endif - return mt; -} - -// return file's creation time -long int SystemTools::CreationTime(const std::string& filename) -{ - long int ct = 0; -#ifdef _WIN32 - WIN32_FILE_ATTRIBUTE_DATA fs; - if (GetFileAttributesExW(Encoding::ToWindowsExtendedPath(filename).c_str(), - GetFileExInfoStandard, &fs) != 0) { - ct = windows_filetime_to_posix_time(fs.ftCreationTime); - } -#else - struct stat fs; - if (stat(filename.c_str(), &fs) == 0) { - ct = fs.st_ctime >= 0 ? static_cast(fs.st_ctime) : 0; - } -#endif - return ct; -} - -std::string SystemTools::GetLastSystemError() -{ - int e = errno; - return strerror(e); -} - -bool SystemTools::RemoveFile(const std::string& source) -{ -#ifdef _WIN32 - std::wstring const& ws = Encoding::ToWindowsExtendedPath(source); - if (DeleteFileW(ws.c_str())) { - return true; - } - DWORD err = GetLastError(); - if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) { - return true; - } - if (err != ERROR_ACCESS_DENIED) { - return false; - } - /* The file may be read-only. Try adding write permission. */ - mode_t mode; - if (!SystemTools::GetPermissions(source, mode) || - !SystemTools::SetPermissions(source, S_IWRITE)) { - SetLastError(err); - return false; - } - - const DWORD DIRECTORY_SOFT_LINK_ATTRS = - FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT; - DWORD attrs = GetFileAttributesW(ws.c_str()); - if (attrs != INVALID_FILE_ATTRIBUTES && - (attrs & DIRECTORY_SOFT_LINK_ATTRS) == DIRECTORY_SOFT_LINK_ATTRS && - RemoveDirectoryW(ws.c_str())) { - return true; - } - if (DeleteFileW(ws.c_str()) || GetLastError() == ERROR_FILE_NOT_FOUND || - GetLastError() == ERROR_PATH_NOT_FOUND) { - return true; - } - /* Try to restore the original permissions. */ - SystemTools::SetPermissions(source, mode); - SetLastError(err); - return false; -#else - return unlink(source.c_str()) == 0 || errno == ENOENT; -#endif -} - -bool SystemTools::RemoveADirectory(const std::string& source) -{ - // Add write permission to the directory so we can modify its - // content to remove files and directories from it. - mode_t mode; - if (SystemTools::GetPermissions(source, mode)) { -#if defined(_WIN32) && !defined(__CYGWIN__) - mode |= S_IWRITE; -#else - mode |= S_IWUSR; -#endif - SystemTools::SetPermissions(source, mode); - } - - Directory dir; - dir.Load(source); - size_t fileNum; - for (fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum) { - if (strcmp(dir.GetFile(static_cast(fileNum)), ".") && - strcmp(dir.GetFile(static_cast(fileNum)), "..")) { - std::string fullPath = source; - fullPath += "/"; - fullPath += dir.GetFile(static_cast(fileNum)); - if (SystemTools::FileIsDirectory(fullPath) && - !SystemTools::FileIsSymlink(fullPath)) { - if (!SystemTools::RemoveADirectory(fullPath)) { - return false; - } - } else { - if (!SystemTools::RemoveFile(fullPath)) { - return false; - } - } - } - } - - return (Rmdir(source) == 0); -} - -/** - */ -size_t SystemTools::GetMaximumFilePathLength() -{ - return KWSYS_SYSTEMTOOLS_MAXPATH; -} - -/** - * Find the file the given name. Searches the given path and then - * the system search path. Returns the full path to the file if it is - * found. Otherwise, the empty string is returned. - */ -std::string SystemToolsStatic::FindName( - const std::string& name, const std::vector& userPaths, - bool no_system_path) -{ - // Add the system search path to our path first - std::vector path; - if (!no_system_path) { - SystemTools::GetPath(path, "CMAKE_FILE_PATH"); - SystemTools::GetPath(path); - } - // now add the additional paths - path.reserve(path.size() + userPaths.size()); - path.insert(path.end(), userPaths.begin(), userPaths.end()); - // now look for the file - std::string tryPath; - for (std::string const& p : path) { - tryPath = p; - if (tryPath.empty() || tryPath.back() != '/') { - tryPath += '/'; - } - tryPath += name; - if (SystemTools::FileExists(tryPath)) { - return tryPath; - } - } - // Couldn't find the file. - return ""; -} - -/** - * Find the file the given name. Searches the given path and then - * the system search path. Returns the full path to the file if it is - * found. Otherwise, the empty string is returned. - */ -std::string SystemTools::FindFile(const std::string& name, - const std::vector& userPaths, - bool no_system_path) -{ - std::string tryPath = - SystemToolsStatic::FindName(name, userPaths, no_system_path); - if (!tryPath.empty() && !SystemTools::FileIsDirectory(tryPath)) { - return SystemTools::CollapseFullPath(tryPath); - } - // Couldn't find the file. - return ""; -} - -/** - * Find the directory the given name. Searches the given path and then - * the system search path. Returns the full path to the directory if it is - * found. Otherwise, the empty string is returned. - */ -std::string SystemTools::FindDirectory( - const std::string& name, const std::vector& userPaths, - bool no_system_path) -{ - std::string tryPath = - SystemToolsStatic::FindName(name, userPaths, no_system_path); - if (!tryPath.empty() && SystemTools::FileIsDirectory(tryPath)) { - return SystemTools::CollapseFullPath(tryPath); - } - // Couldn't find the file. - return ""; -} - -/** - * Find the executable with the given name. Searches the given path and then - * the system search path. Returns the full path to the executable if it is - * found. Otherwise, the empty string is returned. - */ -std::string SystemTools::FindProgram(const char* nameIn, - const std::vector& userPaths, - bool no_system_path) -{ - if (!nameIn || !*nameIn) { - return ""; - } - return SystemTools::FindProgram(std::string(nameIn), userPaths, - no_system_path); -} - -std::string SystemTools::FindProgram(const std::string& name, - const std::vector& userPaths, - bool no_system_path) -{ - std::string tryPath; - -#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) - std::vector extensions; - // check to see if the name already has a .xxx at - // the end of it - // on windows try .com then .exe - if (name.size() <= 3 || name[name.size() - 4] != '.') { - extensions.emplace_back(".com"); - extensions.emplace_back(".exe"); - - // first try with extensions if the os supports them - for (std::string const& ext : extensions) { - tryPath = name; - tryPath += ext; - if (SystemTools::FileExists(tryPath, true)) { - return SystemTools::CollapseFullPath(tryPath); - } - } - } -#endif - - // now try just the name - if (SystemTools::FileExists(name, true)) { - return SystemTools::CollapseFullPath(name); - } - // now construct the path - std::vector path; - // Add the system search path to our path. - if (!no_system_path) { - SystemTools::GetPath(path); - } - // now add the additional paths - path.reserve(path.size() + userPaths.size()); - path.insert(path.end(), userPaths.begin(), userPaths.end()); - // Add a trailing slash to all paths to aid the search process. - for (std::string& p : path) { - if (p.empty() || p.back() != '/') { - p += '/'; - } - } - // Try each path - for (std::string& p : path) { -#ifdef _WIN32 - // Remove double quotes from the path on windows - SystemTools::ReplaceString(p, "\"", ""); -#endif -#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) - // first try with extensions - for (std::string const& ext : extensions) { - tryPath = p; - tryPath += name; - tryPath += ext; - if (SystemTools::FileExists(tryPath, true)) { - return SystemTools::CollapseFullPath(tryPath); - } - } -#endif - // now try it without them - tryPath = p; - tryPath += name; - if (SystemTools::FileExists(tryPath, true)) { - return SystemTools::CollapseFullPath(tryPath); - } - } - // Couldn't find the program. - return ""; -} - -std::string SystemTools::FindProgram(const std::vector& names, - const std::vector& path, - bool noSystemPath) -{ - for (std::string const& name : names) { - // Try to find the program. - std::string result = SystemTools::FindProgram(name, path, noSystemPath); - if (!result.empty()) { - return result; - } - } - return ""; -} - -/** - * Find the library with the given name. Searches the given path and then - * the system search path. Returns the full path to the library if it is - * found. Otherwise, the empty string is returned. - */ -std::string SystemTools::FindLibrary(const std::string& name, - const std::vector& userPaths) -{ - // See if the executable exists as written. - if (SystemTools::FileExists(name, true)) { - return SystemTools::CollapseFullPath(name); - } - - // Add the system search path to our path. - std::vector path; - SystemTools::GetPath(path); - // now add the additional paths - path.reserve(path.size() + userPaths.size()); - path.insert(path.end(), userPaths.begin(), userPaths.end()); - // Add a trailing slash to all paths to aid the search process. - for (std::string& p : path) { - if (p.empty() || p.back() != '/') { - p += '/'; - } - } - std::string tryPath; - for (std::string const& p : path) { -#if defined(__APPLE__) - tryPath = p; - tryPath += name; - tryPath += ".framework"; - if (SystemTools::FileIsDirectory(tryPath)) { - return SystemTools::CollapseFullPath(tryPath); - } -#endif -#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__) - tryPath = p; - tryPath += name; - tryPath += ".lib"; - if (SystemTools::FileExists(tryPath, true)) { - return SystemTools::CollapseFullPath(tryPath); - } -#else - tryPath = p; - tryPath += "lib"; - tryPath += name; - tryPath += ".so"; - if (SystemTools::FileExists(tryPath, true)) { - return SystemTools::CollapseFullPath(tryPath); - } - tryPath = p; - tryPath += "lib"; - tryPath += name; - tryPath += ".a"; - if (SystemTools::FileExists(tryPath, true)) { - return SystemTools::CollapseFullPath(tryPath); - } - tryPath = p; - tryPath += "lib"; - tryPath += name; - tryPath += ".sl"; - if (SystemTools::FileExists(tryPath, true)) { - return SystemTools::CollapseFullPath(tryPath); - } - tryPath = p; - tryPath += "lib"; - tryPath += name; - tryPath += ".dylib"; - if (SystemTools::FileExists(tryPath, true)) { - return SystemTools::CollapseFullPath(tryPath); - } - tryPath = p; - tryPath += "lib"; - tryPath += name; - tryPath += ".dll"; - if (SystemTools::FileExists(tryPath, true)) { - return SystemTools::CollapseFullPath(tryPath); - } -#endif - } - - // Couldn't find the library. - return ""; -} - -std::string SystemTools::GetRealPath(const std::string& path, - std::string* errorMessage) -{ - std::string ret; - Realpath(path, ret, errorMessage); - return ret; -} - -bool SystemTools::FileIsDirectory(const std::string& inName) -{ - if (inName.empty()) { - return false; - } - size_t length = inName.size(); - const char* name = inName.c_str(); - - // Remove any trailing slash from the name except in a root component. - char local_buffer[KWSYS_SYSTEMTOOLS_MAXPATH]; - std::string string_buffer; - size_t last = length - 1; - if (last > 0 && (name[last] == '/' || name[last] == '\\') && - strcmp(name, "/") != 0 && name[last - 1] != ':') { - if (last < sizeof(local_buffer)) { - memcpy(local_buffer, name, last); - local_buffer[last] = '\0'; - name = local_buffer; - } else { - string_buffer.append(name, last); - name = string_buffer.c_str(); - } - } - -// Now check the file node type. -#if defined(_WIN32) - DWORD attr = - GetFileAttributesW(Encoding::ToWindowsExtendedPath(name).c_str()); - if (attr != INVALID_FILE_ATTRIBUTES) { - return (attr & FILE_ATTRIBUTE_DIRECTORY) != 0; -#else - struct stat fs; - if (stat(name, &fs) == 0) { - return S_ISDIR(fs.st_mode); -#endif - } else { - return false; - } -} - -bool SystemTools::FileIsSymlink(const std::string& name) -{ -#if defined(_WIN32) - std::wstring path = Encoding::ToWindowsExtendedPath(name); - DWORD attr = GetFileAttributesW(path.c_str()); - if (attr != INVALID_FILE_ATTRIBUTES) { - if ((attr & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { - // FILE_ATTRIBUTE_REPARSE_POINT means: - // * a file or directory that has an associated reparse point, or - // * a file that is a symbolic link. - HANDLE hFile = CreateFileW( - path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, - FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, nullptr); - if (hFile == INVALID_HANDLE_VALUE) { - return false; - } - byte buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; - DWORD bytesReturned = 0; - if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, nullptr, 0, buffer, - MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bytesReturned, - nullptr)) { - CloseHandle(hFile); - // Since FILE_ATTRIBUTE_REPARSE_POINT is set this file must be - // a symbolic link if it is not a reparse point. - return GetLastError() == ERROR_NOT_A_REPARSE_POINT; - } - CloseHandle(hFile); - ULONG reparseTag = - reinterpret_cast(&buffer[0])->ReparseTag; - return (reparseTag == IO_REPARSE_TAG_SYMLINK) || - (reparseTag == IO_REPARSE_TAG_MOUNT_POINT); - } - return false; - } else { - return false; - } -#else - struct stat fs; - if (lstat(name.c_str(), &fs) == 0) { - return S_ISLNK(fs.st_mode); - } else { - return false; - } -#endif -} - -bool SystemTools::FileIsFIFO(const std::string& name) -{ -#if defined(_WIN32) - HANDLE hFile = - CreateFileW(Encoding::ToWide(name).c_str(), GENERIC_READ, FILE_SHARE_READ, - nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); - if (hFile == INVALID_HANDLE_VALUE) { - return false; - } - const DWORD type = GetFileType(hFile); - CloseHandle(hFile); - return type == FILE_TYPE_PIPE; -#else - struct stat fs; - if (lstat(name.c_str(), &fs) == 0) { - return S_ISFIFO(fs.st_mode); - } else { - return false; - } -#endif -} - -#if defined(_WIN32) && !defined(__CYGWIN__) -bool SystemTools::CreateSymlink(const std::string&, const std::string&) -{ - return false; -} -#else -bool SystemTools::CreateSymlink(const std::string& origName, - const std::string& newName) -{ - return symlink(origName.c_str(), newName.c_str()) >= 0; -} -#endif - -#if defined(_WIN32) && !defined(__CYGWIN__) -bool SystemTools::ReadSymlink(const std::string&, std::string&) -{ - return false; -} -#else -bool SystemTools::ReadSymlink(const std::string& newName, - std::string& origName) -{ - char buf[KWSYS_SYSTEMTOOLS_MAXPATH + 1]; - int count = static_cast( - readlink(newName.c_str(), buf, KWSYS_SYSTEMTOOLS_MAXPATH)); - if (count >= 0) { - // Add null-terminator. - buf[count] = 0; - origName = buf; - return true; - } else { - return false; - } -} -#endif - -int SystemTools::ChangeDirectory(const std::string& dir) -{ - return Chdir(dir); -} - -std::string SystemTools::GetCurrentWorkingDirectory(bool collapse) -{ - char buf[2048]; - const char* cwd = Getcwd(buf, 2048); - std::string path; - if (cwd) { - path = cwd; - } - if (collapse) { - return SystemTools::CollapseFullPath(path); - } - return path; -} - -std::string SystemTools::GetProgramPath(const std::string& in_name) -{ - std::string dir, file; - SystemTools::SplitProgramPath(in_name, dir, file); - return dir; -} - -bool SystemTools::SplitProgramPath(const std::string& in_name, - std::string& dir, std::string& file, bool) -{ - dir = in_name; - file = ""; - SystemTools::ConvertToUnixSlashes(dir); - - if (!SystemTools::FileIsDirectory(dir)) { - std::string::size_type slashPos = dir.rfind("/"); - if (slashPos != std::string::npos) { - file = dir.substr(slashPos + 1); - dir = dir.substr(0, slashPos); - } else { - file = dir; - dir = ""; - } - } - if (!(dir.empty()) && !SystemTools::FileIsDirectory(dir)) { - std::string oldDir = in_name; - SystemTools::ConvertToUnixSlashes(oldDir); - dir = in_name; - return false; - } - return true; -} - -bool SystemTools::FindProgramPath(const char* argv0, std::string& pathOut, - std::string& errorMsg, const char* exeName, - const char* buildDir, - const char* installPrefix) -{ - std::vector failures; - std::string self = argv0 ? argv0 : ""; - failures.push_back(self); - SystemTools::ConvertToUnixSlashes(self); - self = SystemTools::FindProgram(self); - if (!SystemTools::FileExists(self)) { - if (buildDir) { - std::string intdir = "."; -#ifdef CMAKE_INTDIR - intdir = CMAKE_INTDIR; -#endif - self = buildDir; - self += "/bin/"; - self += intdir; - self += "/"; - self += exeName; - self += SystemTools::GetExecutableExtension(); - } - } - if (installPrefix) { - if (!SystemTools::FileExists(self)) { - failures.push_back(self); - self = installPrefix; - self += "/bin/"; - self += exeName; - } - } - if (!SystemTools::FileExists(self)) { - failures.push_back(self); - std::ostringstream msg; - msg << "Can not find the command line program "; - if (exeName) { - msg << exeName; - } - msg << "\n"; - if (argv0) { - msg << " argv[0] = \"" << argv0 << "\"\n"; - } - msg << " Attempted paths:\n"; - for (std::string const& ff : failures) { - msg << " \"" << ff << "\"\n"; - } - errorMsg = msg.str(); - return false; - } - pathOut = self; - return true; -} - -std::string SystemTools::CollapseFullPath(const std::string& in_relative) -{ - return SystemTools::CollapseFullPath(in_relative, nullptr); -} - -#if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP -void SystemTools::AddTranslationPath(const std::string& a, - const std::string& b) -{ - std::string path_a = a; - std::string path_b = b; - SystemTools::ConvertToUnixSlashes(path_a); - SystemTools::ConvertToUnixSlashes(path_b); - // First check this is a directory path, since we don't want the table to - // grow too fat - if (SystemTools::FileIsDirectory(path_a)) { - // Make sure the path is a full path and does not contain no '..' - // Ken--the following code is incorrect. .. can be in a valid path - // for example /home/martink/MyHubba...Hubba/Src - if (SystemTools::FileIsFullPath(path_b) && - path_b.find("..") == std::string::npos) { - // Before inserting make sure path ends with '/' - if (!path_a.empty() && path_a.back() != '/') { - path_a += '/'; - } - if (!path_b.empty() && path_b.back() != '/') { - path_b += '/'; - } - if (!(path_a == path_b)) { - SystemTools::Statics->TranslationMap.insert( - SystemToolsStatic::StringMap::value_type(std::move(path_a), - std::move(path_b))); - } - } - } -} - -void SystemTools::AddKeepPath(const std::string& dir) -{ - std::string cdir; - Realpath(SystemTools::CollapseFullPath(dir), cdir); - SystemTools::AddTranslationPath(cdir, dir); -} - -void SystemTools::CheckTranslationPath(std::string& path) -{ - // Do not translate paths that are too short to have meaningful - // translations. - if (path.size() < 2) { - return; - } - - // Always add a trailing slash before translation. It does not - // matter if this adds an extra slash, but we do not want to - // translate part of a directory (like the foo part of foo-dir). - path += '/'; - - // In case a file was specified we still have to go through this: - // Now convert any path found in the table back to the one desired: - for (auto const& pair : SystemTools::Statics->TranslationMap) { - // We need to check of the path is a substring of the other path - if (path.find(pair.first) == 0) { - path = path.replace(0, pair.first.size(), pair.second); - } - } - - // Remove the trailing slash we added before. - path.pop_back(); -} -#endif - -static void SystemToolsAppendComponents( - std::vector& out_components, - std::vector::iterator first, - std::vector::iterator last) -{ - static const std::string up = ".."; - static const std::string cur = "."; - for (std::vector::const_iterator i = first; i != last; ++i) { - if (*i == up) { - // Remove the previous component if possible. Ignore ../ components - // that try to go above the root. Keep ../ components if they are - // at the beginning of a relative path (base path is relative). - if (out_components.size() > 1 && out_components.back() != up) { - out_components.resize(out_components.size() - 1); - } else if (!out_components.empty() && out_components[0].empty()) { - out_components.emplace_back(std::move(*i)); - } - } else if (!i->empty() && *i != cur) { - out_components.emplace_back(std::move(*i)); - } - } -} - -std::string SystemTools::CollapseFullPath(const std::string& in_path, - const char* in_base) -{ - // Use the current working directory as a base path. - char buf[2048]; - const char* res_in_base = in_base; - if (!res_in_base) { - if (const char* cwd = Getcwd(buf, 2048)) { - res_in_base = cwd; - } else { - res_in_base = ""; - } - } - - return SystemTools::CollapseFullPath(in_path, std::string(res_in_base)); -} - -std::string SystemTools::CollapseFullPath(const std::string& in_path, - const std::string& in_base) -{ - // Collect the output path components. - std::vector out_components; - - // Split the input path components. - std::vector path_components; - SystemTools::SplitPath(in_path, path_components); - out_components.reserve(path_components.size()); - - // If the input path is relative, start with a base path. - if (path_components[0].empty()) { - std::vector base_components; - // Use the given base path. - SystemTools::SplitPath(in_base, base_components); - - // Append base path components to the output path. - out_components.push_back(base_components[0]); - SystemToolsAppendComponents(out_components, base_components.begin() + 1, - base_components.end()); - } - - // Append input path components to the output path. - SystemToolsAppendComponents(out_components, path_components.begin(), - path_components.end()); - - // Transform the path back to a string. - std::string newPath = SystemTools::JoinPath(out_components); - -#if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP - // Update the translation table with this potentially new path. I am not - // sure why this line is here, it seems really questionable, but yet I - // would put good money that if I remove it something will break, basically - // from what I can see it created a mapping from the collapsed path, to be - // replaced by the input path, which almost completely does the opposite of - // this function, the only thing preventing this from happening a lot is - // that if the in_path has a .. in it, then it is not added to the - // translation table. So for most calls this either does nothing due to the - // .. or it adds a translation between identical paths as nothing was - // collapsed, so I am going to try to comment it out, and see what hits the - // fan, hopefully quickly. - // Commented out line below: - // SystemTools::AddTranslationPath(newPath, in_path); - - SystemTools::CheckTranslationPath(newPath); -#endif -#ifdef _WIN32 - newPath = SystemTools::Statics->GetActualCaseForPathCached(newPath); - SystemTools::ConvertToUnixSlashes(newPath); -#endif - // Return the reconstructed path. - return newPath; -} - -// compute the relative path from here to there -std::string SystemTools::RelativePath(const std::string& local, - const std::string& remote) -{ - if (!SystemTools::FileIsFullPath(local)) { - return ""; - } - if (!SystemTools::FileIsFullPath(remote)) { - return ""; - } - - std::string l = SystemTools::CollapseFullPath(local); - std::string r = SystemTools::CollapseFullPath(remote); - - // split up both paths into arrays of strings using / as a separator - std::vector localSplit = SystemTools::SplitString(l, '/', true); - std::vector remoteSplit = - SystemTools::SplitString(r, '/', true); - std::vector - commonPath; // store shared parts of path in this array - std::vector finalPath; // store the final relative path here - // count up how many matching directory names there are from the start - unsigned int sameCount = 0; - while (((sameCount <= (localSplit.size() - 1)) && - (sameCount <= (remoteSplit.size() - 1))) && -// for Windows and Apple do a case insensitive string compare -#if defined(_WIN32) || defined(__APPLE__) - SystemTools::Strucmp(localSplit[sameCount].c_str(), - remoteSplit[sameCount].c_str()) == 0 -#else - localSplit[sameCount] == remoteSplit[sameCount] -#endif - ) { - // put the common parts of the path into the commonPath array - commonPath.push_back(localSplit[sameCount]); - // erase the common parts of the path from the original path arrays - localSplit[sameCount] = ""; - remoteSplit[sameCount] = ""; - sameCount++; - } - - // If there is nothing in common at all then just return the full - // path. This is the case only on windows when the paths have - // different drive letters. On unix two full paths always at least - // have the root "/" in common so we will return a relative path - // that passes through the root directory. - if (sameCount == 0) { - return remote; - } - - // for each entry that is not common in the local path - // add a ../ to the finalpath array, this gets us out of the local - // path into the remote dir - for (std::string const& lp : localSplit) { - if (!lp.empty()) { - finalPath.emplace_back("../"); - } - } - // for each entry that is not common in the remote path add it - // to the final path. - for (std::string const& rp : remoteSplit) { - if (!rp.empty()) { - finalPath.push_back(rp); - } - } - std::string relativePath; // result string - // now turn the array of directories into a unix path by puttint / - // between each entry that does not already have one - for (std::string const& fp : finalPath) { - if (!relativePath.empty() && relativePath.back() != '/') { - relativePath += '/'; - } - relativePath += fp; - } - return relativePath; -} - -std::string SystemTools::GetActualCaseForPath(const std::string& p) -{ -#ifdef _WIN32 - return SystemToolsStatic::GetCasePathName(p); -#else - return p; -#endif -} - -const char* SystemTools::SplitPathRootComponent(const std::string& p, - std::string* root) -{ - // Identify the root component. - const char* c = p.c_str(); - if ((c[0] == '/' && c[1] == '/') || (c[0] == '\\' && c[1] == '\\')) { - // Network path. - if (root) { - *root = "//"; - } - c += 2; - } else if (c[0] == '/' || c[0] == '\\') { - // Unix path (or Windows path w/out drive letter). - if (root) { - *root = "/"; - } - c += 1; - } else if (c[0] && c[1] == ':' && (c[2] == '/' || c[2] == '\\')) { - // Windows path. - if (root) { - (*root) = "_:/"; - (*root)[0] = c[0]; - } - c += 3; - } else if (c[0] && c[1] == ':') { - // Path relative to a windows drive working directory. - if (root) { - (*root) = "_:"; - (*root)[0] = c[0]; - } - c += 2; - } else if (c[0] == '~') { - // Home directory. The returned root should always have a - // trailing slash so that appending components as - // c[0]c[1]/c[2]/... works. The remaining path returned should - // skip the first slash if it exists: - // - // "~" : root = "~/" , return "" - // "~/ : root = "~/" , return "" - // "~/x : root = "~/" , return "x" - // "~u" : root = "~u/", return "" - // "~u/" : root = "~u/", return "" - // "~u/x" : root = "~u/", return "x" - size_t n = 1; - while (c[n] && c[n] != '/') { - ++n; - } - if (root) { - root->assign(c, n); - *root += '/'; - } - if (c[n] == '/') { - ++n; - } - c += n; - } else { - // Relative path. - if (root) { - *root = ""; - } - } - - // Return the remaining path. - return c; -} - -void SystemTools::SplitPath(const std::string& p, - std::vector& components, - bool expand_home_dir) -{ - const char* c; - components.clear(); - - // Identify the root component. - { - std::string root; - c = SystemTools::SplitPathRootComponent(p, &root); - - // Expand home directory references if requested. - if (expand_home_dir && !root.empty() && root[0] == '~') { - std::string homedir; - root = root.substr(0, root.size() - 1); - if (root.size() == 1) { -#if defined(_WIN32) && !defined(__CYGWIN__) - if (!SystemTools::GetEnv("USERPROFILE", homedir)) -#endif - SystemTools::GetEnv("HOME", homedir); - } -#ifdef HAVE_GETPWNAM - else if (passwd* pw = getpwnam(root.c_str() + 1)) { - if (pw->pw_dir) { - homedir = pw->pw_dir; - } - } -#endif - if (!homedir.empty() && - (homedir.back() == '/' || homedir.back() == '\\')) { - homedir.resize(homedir.size() - 1); - } - SystemTools::SplitPath(homedir, components); - } else { - components.push_back(root); - } - } - - // Parse the remaining components. - const char* first = c; - const char* last = first; - for (; *last; ++last) { - if (*last == '/' || *last == '\\') { - // End of a component. Save it. - components.push_back(std::string(first, last)); - first = last + 1; - } - } - - // Save the last component unless there were no components. - if (last != c) { - components.push_back(std::string(first, last)); - } -} - -std::string SystemTools::JoinPath(const std::vector& components) -{ - return SystemTools::JoinPath(components.begin(), components.end()); -} - -std::string SystemTools::JoinPath( - std::vector::const_iterator first, - std::vector::const_iterator last) -{ - // Construct result in a single string. - std::string result; - size_t len = 0; - for (std::vector::const_iterator i = first; i != last; ++i) { - len += 1 + i->size(); - } - result.reserve(len); - - // The first two components do not add a slash. - if (first != last) { - result.append(*first++); - } - if (first != last) { - result.append(*first++); - } - - // All remaining components are always separated with a slash. - while (first != last) { - result.push_back('/'); - result.append((*first++)); - } - - // Return the concatenated result. - return result; -} - -bool SystemTools::ComparePath(const std::string& c1, const std::string& c2) -{ -#if defined(_WIN32) || defined(__APPLE__) -# ifdef _MSC_VER - return _stricmp(c1.c_str(), c2.c_str()) == 0; -# elif defined(__APPLE__) || defined(__GNUC__) - return strcasecmp(c1.c_str(), c2.c_str()) == 0; -# else - return SystemTools::Strucmp(c1.c_str(), c2.c_str()) == 0; -# endif -#else - return c1 == c2; -#endif -} - -bool SystemTools::Split(const std::string& str, - std::vector& lines, char separator) -{ - std::string data(str); - std::string::size_type lpos = 0; - while (lpos < data.length()) { - std::string::size_type rpos = data.find_first_of(separator, lpos); - if (rpos == std::string::npos) { - // String ends at end of string without a separator. - lines.push_back(data.substr(lpos)); - return false; - } else { - // String ends in a separator, remove the character. - lines.push_back(data.substr(lpos, rpos - lpos)); - } - lpos = rpos + 1; - } - return true; -} - -bool SystemTools::Split(const std::string& str, - std::vector& lines) -{ - std::string data(str); - std::string::size_type lpos = 0; - while (lpos < data.length()) { - std::string::size_type rpos = data.find_first_of('\n', lpos); - if (rpos == std::string::npos) { - // Line ends at end of string without a newline. - lines.push_back(data.substr(lpos)); - return false; - } - if ((rpos > lpos) && (data[rpos - 1] == '\r')) { - // Line ends in a "\r\n" pair, remove both characters. - lines.push_back(data.substr(lpos, (rpos - 1) - lpos)); - } else { - // Line ends in a "\n", remove the character. - lines.push_back(data.substr(lpos, rpos - lpos)); - } - lpos = rpos + 1; - } - return true; -} - -/** - * Return path of a full filename (no trailing slashes). - * Warning: returned path is converted to Unix slashes format. - */ -std::string SystemTools::GetFilenamePath(const std::string& filename) -{ - std::string fn = filename; - SystemTools::ConvertToUnixSlashes(fn); - - std::string::size_type slash_pos = fn.rfind("/"); - if (slash_pos != std::string::npos) { - std::string ret = fn.substr(0, slash_pos); - if (ret.size() == 2 && ret[1] == ':') { - return ret + '/'; - } - if (ret.empty()) { - return "/"; - } - return ret; - } else { - return ""; - } -} - -/** - * Return file name of a full filename (i.e. file name without path). - */ -std::string SystemTools::GetFilenameName(const std::string& filename) -{ -#if defined(_WIN32) || defined(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES) - const char* separators = "/\\"; -#else - char separators = '/'; -#endif - std::string::size_type slash_pos = filename.find_last_of(separators); - if (slash_pos != std::string::npos) { - return filename.substr(slash_pos + 1); - } else { - return filename; - } -} - -/** - * Return file extension of a full filename (dot included). - * Warning: this is the longest extension (for example: .tar.gz) - */ -std::string SystemTools::GetFilenameExtension(const std::string& filename) -{ - std::string name = SystemTools::GetFilenameName(filename); - std::string::size_type dot_pos = name.find('.'); - if (dot_pos != std::string::npos) { - return name.substr(dot_pos); - } else { - return ""; - } -} - -/** - * Return file extension of a full filename (dot included). - * Warning: this is the shortest extension (for example: .gz of .tar.gz) - */ -std::string SystemTools::GetFilenameLastExtension(const std::string& filename) -{ - std::string name = SystemTools::GetFilenameName(filename); - std::string::size_type dot_pos = name.rfind('.'); - if (dot_pos != std::string::npos) { - return name.substr(dot_pos); - } else { - return ""; - } -} - -/** - * Return file name without extension of a full filename (i.e. without path). - * Warning: it considers the longest extension (for example: .tar.gz) - */ -std::string SystemTools::GetFilenameWithoutExtension( - const std::string& filename) -{ - std::string name = SystemTools::GetFilenameName(filename); - std::string::size_type dot_pos = name.find('.'); - if (dot_pos != std::string::npos) { - return name.substr(0, dot_pos); - } else { - return name; - } -} - -/** - * Return file name without extension of a full filename (i.e. without path). - * Warning: it considers the last extension (for example: removes .gz - * from .tar.gz) - */ -std::string SystemTools::GetFilenameWithoutLastExtension( - const std::string& filename) -{ - std::string name = SystemTools::GetFilenameName(filename); - std::string::size_type dot_pos = name.rfind('.'); - if (dot_pos != std::string::npos) { - return name.substr(0, dot_pos); - } else { - return name; - } -} - -bool SystemTools::FileHasSignature(const char* filename, const char* signature, - long offset) -{ - if (!filename || !signature) { - return false; - } - - FILE* fp = Fopen(filename, "rb"); - if (!fp) { - return false; - } - - fseek(fp, offset, SEEK_SET); - - bool res = false; - size_t signature_len = strlen(signature); - char* buffer = new char[signature_len]; - - if (fread(buffer, 1, signature_len, fp) == signature_len) { - res = (!strncmp(buffer, signature, signature_len) ? true : false); - } - - delete[] buffer; - - fclose(fp); - return res; -} - -SystemTools::FileTypeEnum SystemTools::DetectFileType(const char* filename, - unsigned long length, - double percent_bin) -{ - if (!filename || percent_bin < 0) { - return SystemTools::FileTypeUnknown; - } - - if (SystemTools::FileIsDirectory(filename)) { - return SystemTools::FileTypeUnknown; - } - - FILE* fp = Fopen(filename, "rb"); - if (!fp) { - return SystemTools::FileTypeUnknown; - } - - // Allocate buffer and read bytes - - unsigned char* buffer = new unsigned char[length]; - size_t read_length = fread(buffer, 1, length, fp); - fclose(fp); - if (read_length == 0) { - delete[] buffer; - return SystemTools::FileTypeUnknown; - } - - // Loop over contents and count - - size_t text_count = 0; - - const unsigned char* ptr = buffer; - const unsigned char* buffer_end = buffer + read_length; - - while (ptr != buffer_end) { - if ((*ptr >= 0x20 && *ptr <= 0x7F) || *ptr == '\n' || *ptr == '\r' || - *ptr == '\t') { - text_count++; - } - ptr++; - } - - delete[] buffer; - - double current_percent_bin = (static_cast(read_length - text_count) / - static_cast(read_length)); - - if (current_percent_bin >= percent_bin) { - return SystemTools::FileTypeBinary; - } - - return SystemTools::FileTypeText; -} - -bool SystemTools::LocateFileInDir(const char* filename, const char* dir, - std::string& filename_found, - int try_filename_dirs) -{ - if (!filename || !dir) { - return false; - } - - // Get the basename of 'filename' - - std::string filename_base = SystemTools::GetFilenameName(filename); - - // Check if 'dir' is really a directory - // If win32 and matches something like C:, accept it as a dir - - std::string real_dir; - if (!SystemTools::FileIsDirectory(dir)) { -#if defined(_WIN32) - size_t dir_len = strlen(dir); - if (dir_len < 2 || dir[dir_len - 1] != ':') { -#endif - real_dir = SystemTools::GetFilenamePath(dir); - dir = real_dir.c_str(); -#if defined(_WIN32) - } -#endif - } - - // Try to find the file in 'dir' - - bool res = false; - if (!filename_base.empty() && dir) { - size_t dir_len = strlen(dir); - int need_slash = - (dir_len && dir[dir_len - 1] != '/' && dir[dir_len - 1] != '\\'); - - std::string temp = dir; - if (need_slash) { - temp += "/"; - } - temp += filename_base; - - if (SystemTools::FileExists(temp)) { - res = true; - filename_found = temp; - } - - // If not found, we can try harder by appending part of the file to - // to the directory to look inside. - // Example: if we were looking for /foo/bar/yo.txt in /d1/d2, then - // try to find yo.txt in /d1/d2/bar, then /d1/d2/foo/bar, etc. - - else if (try_filename_dirs) { - std::string filename_dir(filename); - std::string filename_dir_base; - std::string filename_dir_bases; - do { - filename_dir = SystemTools::GetFilenamePath(filename_dir); - filename_dir_base = SystemTools::GetFilenameName(filename_dir); -#if defined(_WIN32) - if (filename_dir_base.empty() || filename_dir_base.back() == ':') -#else - if (filename_dir_base.empty()) -#endif - { - break; - } - - filename_dir_bases = filename_dir_base + "/" + filename_dir_bases; - - temp = dir; - if (need_slash) { - temp += "/"; - } - temp += filename_dir_bases; - - res = SystemTools::LocateFileInDir(filename_base.c_str(), temp.c_str(), - filename_found, 0); - - } while (!res && !filename_dir_base.empty()); - } - } - - return res; -} - -bool SystemTools::FileIsFullPath(const std::string& in_name) -{ - return SystemToolsStatic::FileIsFullPath(in_name.c_str(), in_name.size()); -} - -bool SystemTools::FileIsFullPath(const char* in_name) -{ - return SystemToolsStatic::FileIsFullPath( - in_name, in_name[0] ? (in_name[1] ? 2 : 1) : 0); -} - -bool SystemToolsStatic::FileIsFullPath(const char* in_name, size_t len) -{ -#if defined(_WIN32) || defined(__CYGWIN__) - // On Windows, the name must be at least two characters long. - if (len < 2) { - return false; - } - if (in_name[1] == ':') { - return true; - } - if (in_name[0] == '\\') { - return true; - } -#else - // On UNIX, the name must be at least one character long. - if (len < 1) { - return false; - } -#endif -#if !defined(_WIN32) - if (in_name[0] == '~') { - return true; - } -#endif - // On UNIX, the name must begin in a '/'. - // On Windows, if the name begins in a '/', then it is a full - // network path. - if (in_name[0] == '/') { - return true; - } - return false; -} - -bool SystemTools::GetShortPath(const std::string& path, std::string& shortPath) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - std::string tempPath = path; // create a buffer - - // if the path passed in has quotes around it, first remove the quotes - if (!path.empty() && path[0] == '"' && path.back() == '"') { - tempPath = path.substr(1, path.length() - 2); - } - - std::wstring wtempPath = Encoding::ToWide(tempPath); - DWORD ret = GetShortPathNameW(wtempPath.c_str(), nullptr, 0); - std::vector buffer(ret); - if (ret != 0) { - ret = GetShortPathNameW(wtempPath.c_str(), &buffer[0], - static_cast(buffer.size())); - } - - if (ret == 0) { - return false; - } else { - shortPath = Encoding::ToNarrow(&buffer[0]); - return true; - } -#else - shortPath = path; - return true; -#endif -} - -std::string SystemTools::GetCurrentDateTime(const char* format) -{ - char buf[1024]; - time_t t; - time(&t); - strftime(buf, sizeof(buf), format, localtime(&t)); - return std::string(buf); -} - -std::string SystemTools::MakeCidentifier(const std::string& s) -{ - std::string str(s); - if (str.find_first_of("0123456789") == 0) { - str = "_" + str; - } - - std::string permited_chars("_" - "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "0123456789"); - std::string::size_type pos = 0; - while ((pos = str.find_first_not_of(permited_chars, pos)) != - std::string::npos) { - str[pos] = '_'; - } - return str; -} - -// Convenience function around std::getline which removes a trailing carriage -// return and can truncate the buffer as needed. Returns true -// if any data were read before the end-of-file was reached. -bool SystemTools::GetLineFromStream(std::istream& is, std::string& line, - bool* has_newline /* = 0 */, - long sizeLimit /* = -1 */) -{ - // Start with an empty line. - line = ""; - - // Early short circuit return if stream is no good. Just return - // false and the empty line. (Probably means caller tried to - // create a file stream with a non-existent file name...) - // - if (!is) { - if (has_newline) { - *has_newline = false; - } - return false; - } - - std::getline(is, line); - bool haveData = !line.empty() || !is.eof(); - if (!line.empty()) { - // Avoid storing a carriage return character. - if (line.back() == '\r') { - line.resize(line.size() - 1); - } - - // if we read too much then truncate the buffer - if (sizeLimit >= 0 && line.size() >= static_cast(sizeLimit)) { - line.resize(sizeLimit); - } - } - - // Return the results. - if (has_newline) { - *has_newline = !is.eof(); - } - return haveData; -} - -int SystemTools::GetTerminalWidth() -{ - int width = -1; -#ifdef HAVE_TTY_INFO - struct winsize ws; - std::string columns; /* Unix98 environment variable */ - if (ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col > 0 && ws.ws_row > 0) { - width = ws.ws_col; - } - if (!isatty(STDOUT_FILENO)) { - width = -1; - } - if (SystemTools::GetEnv("COLUMNS", columns) && !columns.empty()) { - long t; - char* endptr; - t = strtol(columns.c_str(), &endptr, 0); - if (endptr && !*endptr && (t > 0) && (t < 1000)) { - width = static_cast(t); - } - } - if (width < 9) { - width = -1; - } -#endif - return width; -} - -bool SystemTools::GetPermissions(const char* file, mode_t& mode) -{ - if (!file) { - return false; - } - return SystemTools::GetPermissions(std::string(file), mode); -} - -bool SystemTools::GetPermissions(const std::string& file, mode_t& mode) -{ -#if defined(_WIN32) - DWORD attr = - GetFileAttributesW(Encoding::ToWindowsExtendedPath(file).c_str()); - if (attr == INVALID_FILE_ATTRIBUTES) { - return false; - } - if ((attr & FILE_ATTRIBUTE_READONLY) != 0) { - mode = (_S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6)); - } else { - mode = (_S_IWRITE | (_S_IWRITE >> 3) | (_S_IWRITE >> 6)) | - (_S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6)); - } - if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { - mode |= S_IFDIR | (_S_IEXEC | (_S_IEXEC >> 3) | (_S_IEXEC >> 6)); - } else { - mode |= S_IFREG; - } - size_t dotPos = file.rfind('.'); - const char* ext = dotPos == std::string::npos ? 0 : (file.c_str() + dotPos); - if (ext && - (Strucmp(ext, ".exe") == 0 || Strucmp(ext, ".com") == 0 || - Strucmp(ext, ".cmd") == 0 || Strucmp(ext, ".bat") == 0)) { - mode |= (_S_IEXEC | (_S_IEXEC >> 3) | (_S_IEXEC >> 6)); - } -#else - struct stat st; - if (stat(file.c_str(), &st) < 0) { - return false; - } - mode = st.st_mode; -#endif - return true; -} - -bool SystemTools::SetPermissions(const char* file, mode_t mode, - bool honor_umask) -{ - if (!file) { - return false; - } - return SystemTools::SetPermissions(std::string(file), mode, honor_umask); -} - -bool SystemTools::SetPermissions(const std::string& file, mode_t mode, - bool honor_umask) -{ - if (!SystemTools::PathExists(file)) { - return false; - } - if (honor_umask) { - mode_t currentMask = umask(0); - umask(currentMask); - mode &= ~currentMask; - } -#ifdef _WIN32 - if (_wchmod(Encoding::ToWindowsExtendedPath(file).c_str(), mode) < 0) -#else - if (chmod(file.c_str(), mode) < 0) -#endif - { - return false; - } - - return true; -} - -std::string SystemTools::GetParentDirectory(const std::string& fileOrDir) -{ - return SystemTools::GetFilenamePath(fileOrDir); -} - -bool SystemTools::IsSubDirectory(const std::string& cSubdir, - const std::string& cDir) -{ - if (cDir.empty()) { - return false; - } - std::string subdir = cSubdir; - std::string dir = cDir; - SystemTools::ConvertToUnixSlashes(subdir); - SystemTools::ConvertToUnixSlashes(dir); - if (subdir.size() <= dir.size() || dir.empty()) { - return false; - } - bool isRootPath = dir.back() == '/'; // like "/" or "C:/" - size_t expectedSlashPosition = isRootPath ? dir.size() - 1u : dir.size(); - if (subdir[expectedSlashPosition] != '/') { - return false; - } - std::string s = subdir.substr(0, dir.size()); - return SystemTools::ComparePath(s, dir); -} - -void SystemTools::Delay(unsigned int msec) -{ -#ifdef _WIN32 - Sleep(msec); -#else - // The sleep function gives 1 second resolution and the usleep - // function gives 1e-6 second resolution but on some platforms has a - // maximum sleep time of 1 second. This could be re-implemented to - // use select with masked signals or pselect to mask signals - // atomically. If select is given empty sets and zero as the max - // file descriptor but a non-zero timeout it can be used to block - // for a precise amount of time. - if (msec >= 1000) { - sleep(msec / 1000); - usleep((msec % 1000) * 1000); - } else { - usleep(msec * 1000); - } -#endif -} - -std::string SystemTools::GetOperatingSystemNameAndVersion() -{ - std::string res; - -#ifdef _WIN32 - char buffer[256]; - - OSVERSIONINFOEXA osvi; - BOOL bOsVersionInfoEx; - - ZeroMemory(&osvi, sizeof(osvi)); - osvi.dwOSVersionInfoSize = sizeof(osvi); - -# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx -# pragma warning(push) -# ifdef __INTEL_COMPILER -# pragma warning(disable : 1478) -# elif defined __clang__ -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated-declarations" -# else -# pragma warning(disable : 4996) -# endif -# endif - bOsVersionInfoEx = GetVersionExA((OSVERSIONINFOA*)&osvi); - if (!bOsVersionInfoEx) { - return 0; - } -# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx -# ifdef __clang__ -# pragma clang diagnostic pop -# else -# pragma warning(pop) -# endif -# endif - - switch (osvi.dwPlatformId) { - // Test for the Windows NT product family. - - case VER_PLATFORM_WIN32_NT: - - // Test for the specific product family. - if (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0) { - if (osvi.wProductType == VER_NT_WORKSTATION) { - res += "Microsoft Windows 10"; - } else { - res += "Microsoft Windows Server 2016 family"; - } - } - - if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 3) { - if (osvi.wProductType == VER_NT_WORKSTATION) { - res += "Microsoft Windows 8.1"; - } else { - res += "Microsoft Windows Server 2012 R2 family"; - } - } - - if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 2) { - if (osvi.wProductType == VER_NT_WORKSTATION) { - res += "Microsoft Windows 8"; - } else { - res += "Microsoft Windows Server 2012 family"; - } - } - - if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1) { - if (osvi.wProductType == VER_NT_WORKSTATION) { - res += "Microsoft Windows 7"; - } else { - res += "Microsoft Windows Server 2008 R2 family"; - } - } - - if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0) { - if (osvi.wProductType == VER_NT_WORKSTATION) { - res += "Microsoft Windows Vista"; - } else { - res += "Microsoft Windows Server 2008 family"; - } - } - - if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) { - res += "Microsoft Windows Server 2003 family"; - } - - if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) { - res += "Microsoft Windows XP"; - } - - if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) { - res += "Microsoft Windows 2000"; - } - - if (osvi.dwMajorVersion <= 4) { - res += "Microsoft Windows NT"; - } - - // Test for specific product on Windows NT 4.0 SP6 and later. - - if (bOsVersionInfoEx) { - // Test for the workstation type. - - if (osvi.wProductType == VER_NT_WORKSTATION) { - if (osvi.dwMajorVersion == 4) { - res += " Workstation 4.0"; - } else if (osvi.dwMajorVersion == 5) { - if (osvi.wSuiteMask & VER_SUITE_PERSONAL) { - res += " Home Edition"; - } else { - res += " Professional"; - } - } - } - - // Test for the server type. - - else if (osvi.wProductType == VER_NT_SERVER) { - if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) { - if (osvi.wSuiteMask & VER_SUITE_DATACENTER) { - res += " Datacenter Edition"; - } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) { - res += " Enterprise Edition"; - } else if (osvi.wSuiteMask == VER_SUITE_BLADE) { - res += " Web Edition"; - } else { - res += " Standard Edition"; - } - } - - else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) { - if (osvi.wSuiteMask & VER_SUITE_DATACENTER) { - res += " Datacenter Server"; - } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) { - res += " Advanced Server"; - } else { - res += " Server"; - } - } - - else if (osvi.dwMajorVersion <= 4) // Windows NT 4.0 - { - if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) { - res += " Server 4.0, Enterprise Edition"; - } else { - res += " Server 4.0"; - } - } - } - } - - // Test for specific product on Windows NT 4.0 SP5 and earlier - - else { - HKEY hKey; -# define BUFSIZE 80 - wchar_t szProductType[BUFSIZE]; - DWORD dwBufLen = BUFSIZE; - LONG lRet; - - lRet = - RegOpenKeyExW(HKEY_LOCAL_MACHINE, - L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions", - 0, KEY_QUERY_VALUE, &hKey); - if (lRet != ERROR_SUCCESS) { - return 0; - } - - lRet = RegQueryValueExW(hKey, L"ProductType", nullptr, nullptr, - (LPBYTE)szProductType, &dwBufLen); - - if ((lRet != ERROR_SUCCESS) || (dwBufLen > BUFSIZE)) { - return 0; - } - - RegCloseKey(hKey); - - if (lstrcmpiW(L"WINNT", szProductType) == 0) { - res += " Workstation"; - } - if (lstrcmpiW(L"LANMANNT", szProductType) == 0) { - res += " Server"; - } - if (lstrcmpiW(L"SERVERNT", szProductType) == 0) { - res += " Advanced Server"; - } - - res += " "; - sprintf(buffer, "%ld", osvi.dwMajorVersion); - res += buffer; - res += "."; - sprintf(buffer, "%ld", osvi.dwMinorVersion); - res += buffer; - } - - // Display service pack (if any) and build number. - - if (osvi.dwMajorVersion == 4 && - lstrcmpiA(osvi.szCSDVersion, "Service Pack 6") == 0) { - HKEY hKey; - LONG lRet; - - // Test for SP6 versus SP6a. - - lRet = RegOpenKeyExW( - HKEY_LOCAL_MACHINE, - L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q246009", - 0, KEY_QUERY_VALUE, &hKey); - - if (lRet == ERROR_SUCCESS) { - res += " Service Pack 6a (Build "; - sprintf(buffer, "%ld", osvi.dwBuildNumber & 0xFFFF); - res += buffer; - res += ")"; - } else // Windows NT 4.0 prior to SP6a - { - res += " "; - res += osvi.szCSDVersion; - res += " (Build "; - sprintf(buffer, "%ld", osvi.dwBuildNumber & 0xFFFF); - res += buffer; - res += ")"; - } - - RegCloseKey(hKey); - } else // Windows NT 3.51 and earlier or Windows 2000 and later - { - res += " "; - res += osvi.szCSDVersion; - res += " (Build "; - sprintf(buffer, "%ld", osvi.dwBuildNumber & 0xFFFF); - res += buffer; - res += ")"; - } - - break; - - // Test for the Windows 95 product family. - - case VER_PLATFORM_WIN32_WINDOWS: - - if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) { - res += "Microsoft Windows 95"; - if (osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B') { - res += " OSR2"; - } - } - - if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10) { - res += "Microsoft Windows 98"; - if (osvi.szCSDVersion[1] == 'A') { - res += " SE"; - } - } - - if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90) { - res += "Microsoft Windows Millennium Edition"; - } - break; - - case VER_PLATFORM_WIN32s: - - res += "Microsoft Win32s"; - break; - } -#endif - - return res; -} - -bool SystemTools::ParseURLProtocol(const std::string& URL, - std::string& protocol, - std::string& dataglom) -{ - // match 0 entire url - // match 1 protocol - // match 2 dataglom following protocol:// - kwsys::RegularExpression urlRe(VTK_URL_PROTOCOL_REGEX); - - if (!urlRe.find(URL)) - return false; - - protocol = urlRe.match(1); - dataglom = urlRe.match(2); - - return true; -} - -bool SystemTools::ParseURL(const std::string& URL, std::string& protocol, - std::string& username, std::string& password, - std::string& hostname, std::string& dataport, - std::string& database) -{ - kwsys::RegularExpression urlRe(VTK_URL_REGEX); - if (!urlRe.find(URL)) - return false; - - // match 0 URL - // match 1 protocol - // match 2 mangled user - // match 3 username - // match 4 mangled password - // match 5 password - // match 6 hostname - // match 7 mangled port - // match 8 dataport - // match 9 database name - - protocol = urlRe.match(1); - username = urlRe.match(3); - password = urlRe.match(5); - hostname = urlRe.match(6); - dataport = urlRe.match(8); - database = urlRe.match(9); - - return true; -} - -// These must NOT be initialized. Default initialization to zero is -// necessary. -static unsigned int SystemToolsManagerCount; -SystemToolsStatic* SystemTools::Statics; - -// SystemToolsManager manages the SystemTools singleton. -// SystemToolsManager should be included in any translation unit -// that will use SystemTools or that implements the singleton -// pattern. It makes sure that the SystemTools singleton is created -// before and destroyed after all other singletons in CMake. - -SystemToolsManager::SystemToolsManager() -{ - if (++SystemToolsManagerCount == 1) { - SystemTools::ClassInitialize(); - } -} - -SystemToolsManager::~SystemToolsManager() -{ - if (--SystemToolsManagerCount == 0) { - SystemTools::ClassFinalize(); - } -} - -#if defined(__VMS) -// On VMS we configure the run time C library to be more UNIX like. -// http://h71000.www7.hp.com/doc/732final/5763/5763pro_004.html -extern "C" int decc$feature_get_index(char* name); -extern "C" int decc$feature_set_value(int index, int mode, int value); -static int SetVMSFeature(char* name, int value) -{ - int i; - errno = 0; - i = decc$feature_get_index(name); - return i >= 0 && (decc$feature_set_value(i, 1, value) >= 0 || errno == 0); -} -#endif - -void SystemTools::ClassInitialize() -{ -#ifdef __VMS - SetVMSFeature("DECC$FILENAME_UNIX_ONLY", 1); -#endif - - // Create statics singleton instance - SystemTools::Statics = new SystemToolsStatic; - -#if KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP -// Add some special translation paths for unix. These are not added -// for windows because drive letters need to be maintained. Also, -// there are not sym-links and mount points on windows anyway. -# if !defined(_WIN32) || defined(__CYGWIN__) - // The tmp path is frequently a logical path so always keep it: - SystemTools::AddKeepPath("/tmp/"); - - // If the current working directory is a logical path then keep the - // logical name. - std::string pwd_str; - if (SystemTools::GetEnv("PWD", pwd_str)) { - char buf[2048]; - if (const char* cwd = Getcwd(buf, 2048)) { - // The current working directory may be a logical path. Find - // the shortest logical path that still produces the correct - // physical path. - std::string cwd_changed; - std::string pwd_changed; - - // Test progressively shorter logical-to-physical mappings. - std::string cwd_str = cwd; - std::string pwd_path; - Realpath(pwd_str, pwd_path); - while (cwd_str == pwd_path && cwd_str != pwd_str) { - // The current pair of paths is a working logical mapping. - cwd_changed = cwd_str; - pwd_changed = pwd_str; - - // Strip off one directory level and see if the logical - // mapping still works. - pwd_str = SystemTools::GetFilenamePath(pwd_str); - cwd_str = SystemTools::GetFilenamePath(cwd_str); - Realpath(pwd_str, pwd_path); - } - - // Add the translation to keep the logical path name. - if (!cwd_changed.empty() && !pwd_changed.empty()) { - SystemTools::AddTranslationPath(cwd_changed, pwd_changed); - } - } - } -# endif -#endif -} - -void SystemTools::ClassFinalize() -{ - delete SystemTools::Statics; -} - -} // namespace KWSYS_NAMESPACE - -#if defined(_MSC_VER) && defined(_DEBUG) -# include -# include -# include -namespace KWSYS_NAMESPACE { - -static int SystemToolsDebugReport(int, char* message, int*) -{ - fprintf(stderr, "%s", message); - fflush(stderr); - return 1; // no further reporting required -} - -void SystemTools::EnableMSVCDebugHook() -{ - if (SystemTools::HasEnv("DART_TEST_FROM_DART") || - SystemTools::HasEnv("DASHBOARD_TEST_FROM_CTEST")) { - _CrtSetReportHook(SystemToolsDebugReport); - } -} - -} // namespace KWSYS_NAMESPACE -#else -namespace KWSYS_NAMESPACE { -void SystemTools::EnableMSVCDebugHook() -{ -} -} // namespace KWSYS_NAMESPACE -#endif diff --git a/test/API/driver/kwsys/SystemTools.hxx.in b/test/API/driver/kwsys/SystemTools.hxx.in deleted file mode 100644 index c4ab9d4..0000000 --- a/test/API/driver/kwsys/SystemTools.hxx.in +++ /dev/null @@ -1,981 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifndef @KWSYS_NAMESPACE@_SystemTools_hxx -#define @KWSYS_NAMESPACE@_SystemTools_hxx - -#include <@KWSYS_NAMESPACE@/Configure.hxx> - -#include -#include -#include -#include - -#include -// include sys/stat.h after sys/types.h -#include - -#if !defined(_WIN32) || defined(__CYGWIN__) -# include // For access permissions for use with access() -#endif - -// Required for va_list -#include -// Required for FILE* -#include -#if !defined(va_list) -// Some compilers move va_list into the std namespace and there is no way to -// tell that this has been done. Playing with things being included before or -// after stdarg.h does not solve things because we do not have control over -// what the user does. This hack solves this problem by moving va_list to our -// own namespace that is local for kwsys. -namespace std { -} // Required for platforms that do not have std namespace -namespace @KWSYS_NAMESPACE@_VA_LIST { -using namespace std; -typedef va_list hack_va_list; -} -namespace @KWSYS_NAMESPACE@ { -typedef @KWSYS_NAMESPACE@_VA_LIST::hack_va_list va_list; -} -#endif // va_list - -namespace @KWSYS_NAMESPACE@ { - -class SystemToolsStatic; - -/** \class SystemToolsManager - * \brief Use to make sure SystemTools is initialized before it is used - * and is the last static object destroyed - */ -class @KWSYS_NAMESPACE@_EXPORT SystemToolsManager -{ -public: - SystemToolsManager(); - ~SystemToolsManager(); - - SystemToolsManager(const SystemToolsManager&) = delete; - SystemToolsManager& operator=(const SystemToolsManager&) = delete; -}; - -// This instance will show up in any translation unit that uses -// SystemTools. It will make sure SystemTools is initialized -// before it is used and is the last static object destroyed. -static SystemToolsManager SystemToolsManagerInstance; - -// Flags for use with TestFileAccess. Use a typedef in case any operating -// system in the future needs a special type. These are flags that may be -// combined using the | operator. -typedef int TestFilePermissions; -#if defined(_WIN32) && !defined(__CYGWIN__) -// On Windows (VC and Borland), no system header defines these constants... -static const TestFilePermissions TEST_FILE_OK = 0; -static const TestFilePermissions TEST_FILE_READ = 4; -static const TestFilePermissions TEST_FILE_WRITE = 2; -static const TestFilePermissions TEST_FILE_EXECUTE = 1; -#else -// Standard POSIX constants -static const TestFilePermissions TEST_FILE_OK = F_OK; -static const TestFilePermissions TEST_FILE_READ = R_OK; -static const TestFilePermissions TEST_FILE_WRITE = W_OK; -static const TestFilePermissions TEST_FILE_EXECUTE = X_OK; -#endif - -/** \class SystemTools - * \brief A collection of useful platform-independent system functions. - */ -class @KWSYS_NAMESPACE@_EXPORT SystemTools -{ -public: - /** ----------------------------------------------------------------- - * String Manipulation Routines - * ----------------------------------------------------------------- - */ - - /** - * Replace symbols in str that are not valid in C identifiers as - * defined by the 1999 standard, ie. anything except [A-Za-z0-9_]. - * They are replaced with `_' and if the first character is a digit - * then an underscore is prepended. Note that this can produce - * identifiers that the standard reserves (_[A-Z].* and __.*). - */ - static std::string MakeCidentifier(const std::string& s); - - static std::string MakeCindentifier(const std::string& s) - { - return MakeCidentifier(s); - } - - /** - * Replace replace all occurrences of the string in the source string. - */ - static void ReplaceString(std::string& source, const char* replace, - const char* with); - static void ReplaceString(std::string& source, const std::string& replace, - const std::string& with); - - /** - * Return a capitalized string (i.e the first letter is uppercased, - * all other are lowercased). - */ - static std::string Capitalized(const std::string&); - - /** - * Return a 'capitalized words' string (i.e the first letter of each word - * is uppercased all other are left untouched though). - */ - static std::string CapitalizedWords(const std::string&); - - /** - * Return a 'uncapitalized words' string (i.e the first letter of each word - * is lowercased all other are left untouched though). - */ - static std::string UnCapitalizedWords(const std::string&); - - /** - * Return a lower case string - */ - static std::string LowerCase(const std::string&); - - /** - * Return a lower case string - */ - static std::string UpperCase(const std::string&); - - /** - * Count char in string - */ - static size_t CountChar(const char* str, char c); - - /** - * Remove some characters from a string. - * Return a pointer to the new resulting string (allocated with 'new') - */ - static char* RemoveChars(const char* str, const char* toremove); - - /** - * Remove remove all but 0->9, A->F characters from a string. - * Return a pointer to the new resulting string (allocated with 'new') - */ - static char* RemoveCharsButUpperHex(const char* str); - - /** - * Replace some characters by another character in a string (in-place) - * Return a pointer to string - */ - static char* ReplaceChars(char* str, const char* toreplace, - char replacement); - - /** - * Returns true if str1 starts (respectively ends) with str2 - */ - static bool StringStartsWith(const char* str1, const char* str2); - static bool StringStartsWith(const std::string& str1, const char* str2); - static bool StringEndsWith(const char* str1, const char* str2); - static bool StringEndsWith(const std::string& str1, const char* str2); - - /** - * Returns a pointer to the last occurrence of str2 in str1 - */ - static const char* FindLastString(const char* str1, const char* str2); - - /** - * Make a duplicate of the string similar to the strdup C function - * but use new to create the 'new' string, so one can use - * 'delete' to remove it. Returns 0 if the input is empty. - */ - static char* DuplicateString(const char* str); - - /** - * Return the string cropped to a given length by removing chars in the - * center of the string and replacing them with an ellipsis (...) - */ - static std::string CropString(const std::string&, size_t max_len); - - /** split a path by separator into an array of strings, default is /. - If isPath is true then the string is treated like a path and if - s starts with a / then the first element of the returned array will - be /, so /foo/bar will be [/, foo, bar] - */ - static std::vector SplitString(const std::string& s, - char separator = '/', - bool isPath = false); - /** - * Perform a case-independent string comparison - */ - static int Strucmp(const char* s1, const char* s2); - - /** - * Split a string on its newlines into multiple lines - * Return false only if the last line stored had no newline - */ - static bool Split(const std::string& s, std::vector& l); - static bool Split(const std::string& s, std::vector& l, - char separator); - - /** - * Return string with space added between capitalized words - * (i.e. EatMyShorts becomes Eat My Shorts ) - * (note that IEatShorts becomes IEat Shorts) - */ - static std::string AddSpaceBetweenCapitalizedWords(const std::string&); - - /** - * Append two or more strings and produce new one. - * Programmer must 'delete []' the resulting string, which was allocated - * with 'new'. - * Return 0 if inputs are empty or there was an error - */ - static char* AppendStrings(const char* str1, const char* str2); - static char* AppendStrings(const char* str1, const char* str2, - const char* str3); - - /** - * Estimate the length of the string that will be produced - * from printing the given format string and arguments. The - * returned length will always be at least as large as the string - * that will result from printing. - * WARNING: since va_arg is called to iterate of the argument list, - * you will not be able to use this 'ap' anymore from the beginning. - * It's up to you to call va_end though. - */ - static int EstimateFormatLength(const char* format, va_list ap); - - /** - * Escape specific characters in 'str'. - */ - static std::string EscapeChars(const char* str, const char* chars_to_escape, - char escape_char = '\\'); - - /** ----------------------------------------------------------------- - * Filename Manipulation Routines - * ----------------------------------------------------------------- - */ - - /** - * Replace Windows file system slashes with Unix-style slashes. - */ - static void ConvertToUnixSlashes(std::string& path); - -#ifdef _WIN32 - /** Calls Encoding::ToWindowsExtendedPath. */ - static std::wstring ConvertToWindowsExtendedPath(const std::string&); -#endif - - /** - * For windows this calls ConvertToWindowsOutputPath and for unix - * it calls ConvertToUnixOutputPath - */ - static std::string ConvertToOutputPath(const std::string&); - - /** - * Convert the path to a string that can be used in a unix makefile. - * double slashes are removed, and spaces are escaped. - */ - static std::string ConvertToUnixOutputPath(const std::string&); - - /** - * Convert the path to string that can be used in a windows project or - * makefile. Double slashes are removed if they are not at the start of - * the string, the slashes are converted to windows style backslashes, and - * if there are spaces in the string it is double quoted. - */ - static std::string ConvertToWindowsOutputPath(const std::string&); - - /** - * Return true if a path with the given name exists in the current directory. - */ - static bool PathExists(const std::string& path); - - /** - * Return true if a file exists in the current directory. - * If isFile = true, then make sure the file is a file and - * not a directory. If isFile = false, then return true - * if it is a file or a directory. Note that the file will - * also be checked for read access. (Currently, this check - * for read access is only done on POSIX systems.) - */ - static bool FileExists(const char* filename, bool isFile); - static bool FileExists(const std::string& filename, bool isFile); - static bool FileExists(const char* filename); - static bool FileExists(const std::string& filename); - - /** - * Test if a file exists and can be accessed with the requested - * permissions. Symbolic links are followed. Returns true if - * the access test was successful. - * - * On POSIX systems (including Cygwin), this maps to the access - * function. On Windows systems, all existing files are - * considered readable, and writable files are considered to - * have the read-only file attribute cleared. - */ - static bool TestFileAccess(const char* filename, - TestFilePermissions permissions); - static bool TestFileAccess(const std::string& filename, - TestFilePermissions permissions); -/** - * Cross platform wrapper for stat struct - */ -#if defined(_WIN32) && !defined(__CYGWIN__) -# if defined(__BORLANDC__) - typedef struct stati64 Stat_t; -# else - typedef struct _stat64 Stat_t; -# endif -#else - typedef struct stat Stat_t; -#endif - - /** - * Cross platform wrapper for stat system call - * - * On Windows this may not work for paths longer than 250 characters - * due to limitations of the underlying '_wstat64' call. - */ - static int Stat(const char* path, Stat_t* buf); - static int Stat(const std::string& path, Stat_t* buf); - -/** - * Converts Cygwin path to Win32 path. Uses dictionary container for - * caching and calls to cygwin_conv_to_win32_path from Cygwin dll - * for actual translation. Returns true on success, else false. - */ -#ifdef __CYGWIN__ - static bool PathCygwinToWin32(const char* path, char* win32_path); -#endif - - /** - * Return file length - */ - static unsigned long FileLength(const std::string& filename); - - /** - Change the modification time or create a file - */ - static bool Touch(const std::string& filename, bool create); - - /** - * Compare file modification times. - * Return true for successful comparison and false for error. - * When true is returned, result has -1, 0, +1 for - * f1 older, same, or newer than f2. - */ - static bool FileTimeCompare(const std::string& f1, const std::string& f2, - int* result); - - /** - * Get the file extension (including ".") needed for an executable - * on the current platform ("" for unix, ".exe" for Windows). - */ - static const char* GetExecutableExtension(); - - /** - * Given a path on a Windows machine, return the actual case of - * the path as it exists on disk. Path components that do not - * exist on disk are returned unchanged. Relative paths are always - * returned unchanged. Drive letters are always made upper case. - * This does nothing on non-Windows systems but return the path. - */ - static std::string GetActualCaseForPath(const std::string& path); - - /** - * Given the path to a program executable, get the directory part of - * the path with the file stripped off. If there is no directory - * part, the empty string is returned. - */ - static std::string GetProgramPath(const std::string&); - static bool SplitProgramPath(const std::string& in_name, std::string& dir, - std::string& file, bool errorReport = true); - - /** - * Given argv[0] for a unix program find the full path to a running - * executable. argv0 can be null for windows WinMain programs - * in this case GetModuleFileName will be used to find the path - * to the running executable. If argv0 is not a full path, - * then this will try to find the full path. If the path is not - * found false is returned, if found true is returned. An error - * message of the attempted paths is stored in errorMsg. - * exeName is the name of the executable. - * buildDir is a possibly null path to the build directory. - * installPrefix is a possibly null pointer to the install directory. - */ - static bool FindProgramPath(const char* argv0, std::string& pathOut, - std::string& errorMsg, - const char* exeName = nullptr, - const char* buildDir = nullptr, - const char* installPrefix = nullptr); - - /** - * Given a path to a file or directory, convert it to a full path. - * This collapses away relative paths relative to the cwd argument - * (which defaults to the current working directory). The full path - * is returned. - */ - static std::string CollapseFullPath(const std::string& in_relative); - static std::string CollapseFullPath(const std::string& in_relative, - const char* in_base); - static std::string CollapseFullPath(const std::string& in_relative, - const std::string& in_base); - - /** - * Get the real path for a given path, removing all symlinks. In - * the event of an error (non-existent path, permissions issue, - * etc.) the original path is returned if errorMessage pointer is - * nullptr. Otherwise empty string is returned and errorMessage - * contains error description. - */ - static std::string GetRealPath(const std::string& path, - std::string* errorMessage = nullptr); - - /** - * Split a path name into its root component and the rest of the - * path. The root component is one of the following: - * "/" = UNIX full path - * "c:/" = Windows full path (can be any drive letter) - * "c:" = Windows drive-letter relative path (can be any drive letter) - * "//" = Network path - * "~/" = Home path for current user - * "~u/" = Home path for user 'u' - * "" = Relative path - * - * A pointer to the rest of the path after the root component is - * returned. The root component is stored in the "root" string if - * given. - */ - static const char* SplitPathRootComponent(const std::string& p, - std::string* root = nullptr); - - /** - * Split a path name into its basic components. The first component - * always exists and is the root returned by SplitPathRootComponent. - * The remaining components form the path. If there is a trailing - * slash then the last component is the empty string. The - * components can be recombined as "c[0]c[1]/c[2]/.../c[n]" to - * produce the original path. Home directory references are - * automatically expanded if expand_home_dir is true and this - * platform supports them. - * - * This does *not* normalize the input path. All components are - * preserved, including empty ones. Typically callers should use - * this only on paths that have already been normalized. - */ - static void SplitPath(const std::string& p, - std::vector& components, - bool expand_home_dir = true); - - /** - * Join components of a path name into a single string. See - * SplitPath for the format of the components. - * - * This does *not* normalize the input path. All components are - * preserved, including empty ones. Typically callers should use - * this only on paths that have already been normalized. - */ - static std::string JoinPath(const std::vector& components); - static std::string JoinPath(std::vector::const_iterator first, - std::vector::const_iterator last); - - /** - * Compare a path or components of a path. - */ - static bool ComparePath(const std::string& c1, const std::string& c2); - - /** - * Return path of a full filename (no trailing slashes) - */ - static std::string GetFilenamePath(const std::string&); - - /** - * Return file name of a full filename (i.e. file name without path) - */ - static std::string GetFilenameName(const std::string&); - - /** - * Return longest file extension of a full filename (dot included) - */ - static std::string GetFilenameExtension(const std::string&); - - /** - * Return shortest file extension of a full filename (dot included) - */ - static std::string GetFilenameLastExtension(const std::string& filename); - - /** - * Return file name without extension of a full filename - */ - static std::string GetFilenameWithoutExtension(const std::string&); - - /** - * Return file name without its last (shortest) extension - */ - static std::string GetFilenameWithoutLastExtension(const std::string&); - - /** - * Return whether the path represents a full path (not relative) - */ - static bool FileIsFullPath(const std::string&); - static bool FileIsFullPath(const char*); - - /** - * For windows return the short path for the given path, - * Unix just a pass through - */ - static bool GetShortPath(const std::string& path, std::string& result); - - /** - * Read line from file. Make sure to read a full line and truncates it if - * requested via sizeLimit. Returns true if any data were read before the - * end-of-file was reached. If the has_newline argument is specified, it will - * be true when the line read had a newline character. - */ - static bool GetLineFromStream(std::istream& istr, std::string& line, - bool* has_newline = nullptr, - long sizeLimit = -1); - - /** - * Get the parent directory of the directory or file - */ - static std::string GetParentDirectory(const std::string& fileOrDir); - - /** - * Check if the given file or directory is in subdirectory of dir - */ - static bool IsSubDirectory(const std::string& fileOrDir, - const std::string& dir); - - /** ----------------------------------------------------------------- - * File Manipulation Routines - * ----------------------------------------------------------------- - */ - - /** - * Open a file considering unicode. - */ - static FILE* Fopen(const std::string& file, const char* mode); - -/** - * Visual C++ does not define mode_t (note that Borland does, however). - */ -#if defined(_MSC_VER) - typedef unsigned short mode_t; -#endif - - /** - * Make a new directory if it is not there. This function - * can make a full path even if none of the directories existed - * prior to calling this function. - */ - static bool MakeDirectory(const char* path, const mode_t* mode = nullptr); - static bool MakeDirectory(const std::string& path, - const mode_t* mode = nullptr); - - /** - * Copy the source file to the destination file only - * if the two files differ. - */ - static bool CopyFileIfDifferent(const std::string& source, - const std::string& destination); - - /** - * Compare the contents of two files. Return true if different - */ - static bool FilesDiffer(const std::string& source, - const std::string& destination); - - /** - * Compare the contents of two files, ignoring line ending differences. - * Return true if different - */ - static bool TextFilesDiffer(const std::string& path1, - const std::string& path2); - - /** - * Return true if the two files are the same file - */ - static bool SameFile(const std::string& file1, const std::string& file2); - - /** - * Copy a file. - */ - static bool CopyFileAlways(const std::string& source, - const std::string& destination); - - /** - * Copy a file. If the "always" argument is true the file is always - * copied. If it is false, the file is copied only if it is new or - * has changed. - */ - static bool CopyAFile(const std::string& source, - const std::string& destination, bool always = true); - - /** - * Copy content directory to another directory with all files and - * subdirectories. If the "always" argument is true all files are - * always copied. If it is false, only files that have changed or - * are new are copied. - */ - static bool CopyADirectory(const std::string& source, - const std::string& destination, - bool always = true); - - /** - * Remove a file - */ - static bool RemoveFile(const std::string& source); - - /** - * Remove a directory - */ - static bool RemoveADirectory(const std::string& source); - - /** - * Get the maximum full file path length - */ - static size_t GetMaximumFilePathLength(); - - /** - * Find a file in the system PATH, with optional extra paths - */ - static std::string FindFile( - const std::string& name, - const std::vector& path = std::vector(), - bool no_system_path = false); - - /** - * Find a directory in the system PATH, with optional extra paths - */ - static std::string FindDirectory( - const std::string& name, - const std::vector& path = std::vector(), - bool no_system_path = false); - - /** - * Find an executable in the system PATH, with optional extra paths - */ - static std::string FindProgram( - const char* name, - const std::vector& path = std::vector(), - bool no_system_path = false); - static std::string FindProgram( - const std::string& name, - const std::vector& path = std::vector(), - bool no_system_path = false); - static std::string FindProgram( - const std::vector& names, - const std::vector& path = std::vector(), - bool no_system_path = false); - - /** - * Find a library in the system PATH, with optional extra paths - */ - static std::string FindLibrary(const std::string& name, - const std::vector& path); - - /** - * Return true if the file is a directory - */ - static bool FileIsDirectory(const std::string& name); - - /** - * Return true if the file is a symlink - */ - static bool FileIsSymlink(const std::string& name); - - /** - * Return true if the file is a FIFO - */ - static bool FileIsFIFO(const std::string& name); - - /** - * Return true if the file has a given signature (first set of bytes) - */ - static bool FileHasSignature(const char* filename, const char* signature, - long offset = 0); - - /** - * Attempt to detect and return the type of a file. - * Up to 'length' bytes are read from the file, if more than 'percent_bin' % - * of the bytes are non-textual elements, the file is considered binary, - * otherwise textual. Textual elements are bytes in the ASCII [0x20, 0x7E] - * range, but also \\n, \\r, \\t. - * The algorithm is simplistic, and should probably check for usual file - * extensions, 'magic' signature, unicode, etc. - */ - enum FileTypeEnum - { - FileTypeUnknown, - FileTypeBinary, - FileTypeText - }; - static SystemTools::FileTypeEnum DetectFileType(const char* filename, - unsigned long length = 256, - double percent_bin = 0.05); - - /** - * Create a symbolic link if the platform supports it. Returns whether - * creation succeeded. - */ - static bool CreateSymlink(const std::string& origName, - const std::string& newName); - - /** - * Read the contents of a symbolic link. Returns whether reading - * succeeded. - */ - static bool ReadSymlink(const std::string& newName, std::string& origName); - - /** - * Try to locate the file 'filename' in the directory 'dir'. - * If 'filename' is a fully qualified filename, the basename of the file is - * used to check for its existence in 'dir'. - * If 'dir' is not a directory, GetFilenamePath() is called on 'dir' to - * get its directory first (thus, you can pass a filename as 'dir', as - * a convenience). - * 'filename_found' is assigned the fully qualified name/path of the file - * if it is found (not touched otherwise). - * If 'try_filename_dirs' is true, try to find the file using the - * components of its path, i.e. if we are looking for c:/foo/bar/bill.txt, - * first look for bill.txt in 'dir', then in 'dir'/bar, then in 'dir'/foo/bar - * etc. - * Return true if the file was found, false otherwise. - */ - static bool LocateFileInDir(const char* filename, const char* dir, - std::string& filename_found, - int try_filename_dirs = 0); - - /** compute the relative path from local to remote. local must - be a directory. remote can be a file or a directory. - Both remote and local must be full paths. Basically, if - you are in directory local and you want to access the file in remote - what is the relative path to do that. For example: - /a/b/c/d to /a/b/c1/d1 -> ../../c1/d1 - from /usr/src to /usr/src/test/blah/foo.cpp -> test/blah/foo.cpp - */ - static std::string RelativePath(const std::string& local, - const std::string& remote); - - /** - * Return file's modified time - */ - static long int ModifiedTime(const std::string& filename); - - /** - * Return file's creation time (Win32: works only for NTFS, not FAT) - */ - static long int CreationTime(const std::string& filename); - - /** - * Get and set permissions of the file. If honor_umask is set, the umask - * is queried and applied to the given permissions. Returns false if - * failure. - * - * WARNING: A non-thread-safe method is currently used to get the umask - * if a honor_umask parameter is set to true. - */ - static bool GetPermissions(const char* file, mode_t& mode); - static bool GetPermissions(const std::string& file, mode_t& mode); - static bool SetPermissions(const char* file, mode_t mode, - bool honor_umask = false); - static bool SetPermissions(const std::string& file, mode_t mode, - bool honor_umask = false); - - /** ----------------------------------------------------------------- - * Time Manipulation Routines - * ----------------------------------------------------------------- - */ - - /** Get current time in seconds since Posix Epoch (Jan 1, 1970). */ - static double GetTime(); - - /** - * Get current date/time - */ - static std::string GetCurrentDateTime(const char* format); - - /** ----------------------------------------------------------------- - * Registry Manipulation Routines - * ----------------------------------------------------------------- - */ - - /** - * Specify access to the 32-bit or 64-bit application view of - * registry values. The default is to match the currently running - * binary type. - */ - enum KeyWOW64 - { - KeyWOW64_Default, - KeyWOW64_32, - KeyWOW64_64 - }; - - /** - * Get a list of subkeys. - */ - static bool GetRegistrySubKeys(const std::string& key, - std::vector& subkeys, - KeyWOW64 view = KeyWOW64_Default); - - /** - * Read a registry value - */ - static bool ReadRegistryValue(const std::string& key, std::string& value, - KeyWOW64 view = KeyWOW64_Default); - - /** - * Write a registry value - */ - static bool WriteRegistryValue(const std::string& key, - const std::string& value, - KeyWOW64 view = KeyWOW64_Default); - - /** - * Delete a registry value - */ - static bool DeleteRegistryValue(const std::string& key, - KeyWOW64 view = KeyWOW64_Default); - - /** ----------------------------------------------------------------- - * Environment Manipulation Routines - * ----------------------------------------------------------------- - */ - - /** - * Add the paths from the environment variable PATH to the - * string vector passed in. If env is set then the value - * of env will be used instead of PATH. - */ - static void GetPath(std::vector& path, - const char* env = nullptr); - - /** - * Read an environment variable - */ - static const char* GetEnv(const char* key); - static const char* GetEnv(const std::string& key); - static bool GetEnv(const char* key, std::string& result); - static bool GetEnv(const std::string& key, std::string& result); - static bool HasEnv(const char* key); - static bool HasEnv(const std::string& key); - - /** Put a string into the environment - of the form var=value */ - static bool PutEnv(const std::string& env); - - /** Remove a string from the environment. - Input is of the form "var" or "var=value" (value is ignored). */ - static bool UnPutEnv(const std::string& env); - - /** - * Get current working directory CWD - */ - static std::string GetCurrentWorkingDirectory(bool collapse = true); - - /** - * Change directory to the directory specified - */ - static int ChangeDirectory(const std::string& dir); - - /** - * Get the result of strerror(errno) - */ - static std::string GetLastSystemError(); - - /** - * When building DEBUG with MSVC, this enables a hook that prevents - * error dialogs from popping up if the program is being run from - * DART. - */ - static void EnableMSVCDebugHook(); - - /** - * Get the width of the terminal window. The code may or may not work, so - * make sure you have some reasonable defaults prepared if the code returns - * some bogus size. - */ - static int GetTerminalWidth(); - -#if @KWSYS_NAMESPACE@_SYSTEMTOOLS_USE_TRANSLATION_MAP - /** - * Add an entry in the path translation table. - */ - static void AddTranslationPath(const std::string& dir, - const std::string& refdir); - - /** - * If dir is different after CollapseFullPath is called, - * Then insert it into the path translation table - */ - static void AddKeepPath(const std::string& dir); - - /** - * Update path by going through the Path Translation table; - */ - static void CheckTranslationPath(std::string& path); -#endif - - /** - * Delay the execution for a specified amount of time specified - * in milliseconds - */ - static void Delay(unsigned int msec); - - /** - * Get the operating system name and version - * This is implemented for Win32 only for the moment - */ - static std::string GetOperatingSystemNameAndVersion(); - - /** ----------------------------------------------------------------- - * URL Manipulation Routines - * ----------------------------------------------------------------- - */ - - /** - * Parse a character string : - * protocol://dataglom - * and fill protocol as appropriate. - * Return false if the URL does not have the required form, true otherwise. - */ - static bool ParseURLProtocol(const std::string& URL, std::string& protocol, - std::string& dataglom); - - /** - * Parse a string (a URL without protocol prefix) with the form: - * protocol://[[username[':'password]'@']hostname[':'dataport]]'/'[datapath] - * and fill protocol, username, password, hostname, dataport, and datapath - * when values are found. - * Return true if the string matches the format; false otherwise. - */ - static bool ParseURL(const std::string& URL, std::string& protocol, - std::string& username, std::string& password, - std::string& hostname, std::string& dataport, - std::string& datapath); - -private: - /** - * Allocate the stl map that serve as the Path Translation table. - */ - static void ClassInitialize(); - - /** - * Deallocate the stl map that serve as the Path Translation table. - */ - static void ClassFinalize(); - - /** - * This method prevents warning on SGI - */ - SystemToolsManager* GetSystemToolsManager() - { - return &SystemToolsManagerInstance; - } - - static SystemToolsStatic* Statics; - friend class SystemToolsStatic; - friend class SystemToolsManager; -}; - -} // namespace @KWSYS_NAMESPACE@ - -#endif diff --git a/test/API/driver/kwsys/Terminal.c b/test/API/driver/kwsys/Terminal.c deleted file mode 100644 index 4dd2461..0000000 --- a/test/API/driver/kwsys/Terminal.c +++ /dev/null @@ -1,414 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include "kwsysPrivate.h" -#include KWSYS_HEADER(Terminal.h) - -/* Work-around CMake dependency scanning limitation. This must - duplicate the above list of headers. */ -#if 0 -# include "Terminal.h.in" -#endif - -/* Configure support for this platform. */ -#if defined(_WIN32) || defined(__CYGWIN__) -# define KWSYS_TERMINAL_SUPPORT_CONSOLE -#endif -#if !defined(_WIN32) -# define KWSYS_TERMINAL_ISATTY_WORKS -#endif - -/* Include needed system APIs. */ - -#include /* va_list */ -#include /* getenv */ -#include /* strcmp */ - -#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE) -# include /* _get_osfhandle */ -# include /* SetConsoleTextAttribute */ -#endif - -#if defined(KWSYS_TERMINAL_ISATTY_WORKS) -# include /* isatty */ -#else -# include /* fstat */ -#endif - -static int kwsysTerminalStreamIsVT100(FILE* stream, int default_vt100, - int default_tty); -static void kwsysTerminalSetVT100Color(FILE* stream, int color); -#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE) -static HANDLE kwsysTerminalGetStreamHandle(FILE* stream); -static void kwsysTerminalSetConsoleColor(HANDLE hOut, - CONSOLE_SCREEN_BUFFER_INFO* hOutInfo, - FILE* stream, int color); -#endif - -void kwsysTerminal_cfprintf(int color, FILE* stream, const char* format, ...) -{ - /* Setup the stream with the given color if possible. */ - int pipeIsConsole = 0; - int pipeIsVT100 = 0; - int default_vt100 = color & kwsysTerminal_Color_AssumeVT100; - int default_tty = color & kwsysTerminal_Color_AssumeTTY; -#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE) - CONSOLE_SCREEN_BUFFER_INFO hOutInfo; - HANDLE hOut = kwsysTerminalGetStreamHandle(stream); - if (GetConsoleScreenBufferInfo(hOut, &hOutInfo)) { - pipeIsConsole = 1; - kwsysTerminalSetConsoleColor(hOut, &hOutInfo, stream, color); - } -#endif - if (!pipeIsConsole && - kwsysTerminalStreamIsVT100(stream, default_vt100, default_tty)) { - pipeIsVT100 = 1; - kwsysTerminalSetVT100Color(stream, color); - } - - /* Format the text into the stream. */ - { - va_list var_args; - va_start(var_args, format); - vfprintf(stream, format, var_args); - va_end(var_args); - } - -/* Restore the normal color state for the stream. */ -#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE) - if (pipeIsConsole) { - kwsysTerminalSetConsoleColor(hOut, &hOutInfo, stream, - kwsysTerminal_Color_Normal); - } -#endif - if (pipeIsVT100) { - kwsysTerminalSetVT100Color(stream, kwsysTerminal_Color_Normal); - } -} - -/* Detect cases when a stream is definitely not interactive. */ -#if !defined(KWSYS_TERMINAL_ISATTY_WORKS) -static int kwsysTerminalStreamIsNotInteractive(FILE* stream) -{ - /* The given stream is definitely not interactive if it is a regular - file. */ - struct stat stream_stat; - if (fstat(fileno(stream), &stream_stat) == 0) { - if (stream_stat.st_mode & S_IFREG) { - return 1; - } - } - return 0; -} -#endif - -/* List of terminal names known to support VT100 color escape sequences. */ -static const char* kwsysTerminalVT100Names[] = { "Eterm", - "alacritty", - "alacritty-direct", - "ansi", - "color-xterm", - "con132x25", - "con132x30", - "con132x43", - "con132x60", - "con80x25", - "con80x28", - "con80x30", - "con80x43", - "con80x50", - "con80x60", - "cons25", - "console", - "cygwin", - "dtterm", - "eterm-color", - "gnome", - "gnome-256color", - "konsole", - "konsole-256color", - "kterm", - "linux", - "msys", - "linux-c", - "mach-color", - "mlterm", - "putty", - "putty-256color", - "rxvt", - "rxvt-256color", - "rxvt-cygwin", - "rxvt-cygwin-native", - "rxvt-unicode", - "rxvt-unicode-256color", - "screen", - "screen-256color", - "screen-256color-bce", - "screen-bce", - "screen-w", - "screen.linux", - "tmux", - "tmux-256color", - "vt100", - "xterm", - "xterm-16color", - "xterm-256color", - "xterm-88color", - "xterm-color", - "xterm-debian", - "xterm-kitty", - "xterm-termite", - 0 }; - -/* Detect whether a stream is displayed in a VT100-compatible terminal. */ -static int kwsysTerminalStreamIsVT100(FILE* stream, int default_vt100, - int default_tty) -{ - /* Force color according to http://bixense.com/clicolors/ convention. */ - { - const char* clicolor_force = getenv("CLICOLOR_FORCE"); - if (clicolor_force && *clicolor_force && - strcmp(clicolor_force, "0") != 0) { - return 1; - } - } - - /* If running inside emacs the terminal is not VT100. Some emacs - seem to claim the TERM is xterm even though they do not support - VT100 escapes. */ - { - const char* emacs = getenv("EMACS"); - if (emacs && *emacs == 't') { - return 0; - } - } - - /* Check for a valid terminal. */ - if (!default_vt100) { - const char** t = 0; - const char* term = getenv("TERM"); - if (term) { - for (t = kwsysTerminalVT100Names; *t && strcmp(term, *t) != 0; ++t) { - } - } - if (!(t && *t)) { - return 0; - } - } - -#if defined(KWSYS_TERMINAL_ISATTY_WORKS) - /* Make sure the stream is a tty. */ - (void)default_tty; - return isatty(fileno(stream)) ? 1 : 0; -#else - /* Check for cases in which the stream is definitely not a tty. */ - if (kwsysTerminalStreamIsNotInteractive(stream)) { - return 0; - } - - /* Use the provided default for whether this is a tty. */ - return default_tty; -#endif -} - -/* VT100 escape sequence strings. */ -#if defined(__MVS__) -/* if building on z/OS (aka MVS), assume we are using EBCDIC */ -# define ESCAPE_CHAR "\47" -#else -# define ESCAPE_CHAR "\33" -#endif - -#define KWSYS_TERMINAL_VT100_NORMAL ESCAPE_CHAR "[0m" -#define KWSYS_TERMINAL_VT100_BOLD ESCAPE_CHAR "[1m" -#define KWSYS_TERMINAL_VT100_UNDERLINE ESCAPE_CHAR "[4m" -#define KWSYS_TERMINAL_VT100_BLINK ESCAPE_CHAR "[5m" -#define KWSYS_TERMINAL_VT100_INVERSE ESCAPE_CHAR "[7m" -#define KWSYS_TERMINAL_VT100_FOREGROUND_BLACK ESCAPE_CHAR "[30m" -#define KWSYS_TERMINAL_VT100_FOREGROUND_RED ESCAPE_CHAR "[31m" -#define KWSYS_TERMINAL_VT100_FOREGROUND_GREEN ESCAPE_CHAR "[32m" -#define KWSYS_TERMINAL_VT100_FOREGROUND_YELLOW ESCAPE_CHAR "[33m" -#define KWSYS_TERMINAL_VT100_FOREGROUND_BLUE ESCAPE_CHAR "[34m" -#define KWSYS_TERMINAL_VT100_FOREGROUND_MAGENTA ESCAPE_CHAR "[35m" -#define KWSYS_TERMINAL_VT100_FOREGROUND_CYAN ESCAPE_CHAR "[36m" -#define KWSYS_TERMINAL_VT100_FOREGROUND_WHITE ESCAPE_CHAR "[37m" -#define KWSYS_TERMINAL_VT100_BACKGROUND_BLACK ESCAPE_CHAR "[40m" -#define KWSYS_TERMINAL_VT100_BACKGROUND_RED ESCAPE_CHAR "[41m" -#define KWSYS_TERMINAL_VT100_BACKGROUND_GREEN ESCAPE_CHAR "[42m" -#define KWSYS_TERMINAL_VT100_BACKGROUND_YELLOW ESCAPE_CHAR "[43m" -#define KWSYS_TERMINAL_VT100_BACKGROUND_BLUE ESCAPE_CHAR "[44m" -#define KWSYS_TERMINAL_VT100_BACKGROUND_MAGENTA ESCAPE_CHAR "[45m" -#define KWSYS_TERMINAL_VT100_BACKGROUND_CYAN ESCAPE_CHAR "[46m" -#define KWSYS_TERMINAL_VT100_BACKGROUND_WHITE ESCAPE_CHAR "[47m" - -/* Write VT100 escape sequences to the stream for the given color. */ -static void kwsysTerminalSetVT100Color(FILE* stream, int color) -{ - if (color == kwsysTerminal_Color_Normal) { - fprintf(stream, KWSYS_TERMINAL_VT100_NORMAL); - return; - } - - switch (color & kwsysTerminal_Color_ForegroundMask) { - case kwsysTerminal_Color_Normal: - fprintf(stream, KWSYS_TERMINAL_VT100_NORMAL); - break; - case kwsysTerminal_Color_ForegroundBlack: - fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_BLACK); - break; - case kwsysTerminal_Color_ForegroundRed: - fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_RED); - break; - case kwsysTerminal_Color_ForegroundGreen: - fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_GREEN); - break; - case kwsysTerminal_Color_ForegroundYellow: - fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_YELLOW); - break; - case kwsysTerminal_Color_ForegroundBlue: - fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_BLUE); - break; - case kwsysTerminal_Color_ForegroundMagenta: - fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_MAGENTA); - break; - case kwsysTerminal_Color_ForegroundCyan: - fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_CYAN); - break; - case kwsysTerminal_Color_ForegroundWhite: - fprintf(stream, KWSYS_TERMINAL_VT100_FOREGROUND_WHITE); - break; - } - switch (color & kwsysTerminal_Color_BackgroundMask) { - case kwsysTerminal_Color_BackgroundBlack: - fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_BLACK); - break; - case kwsysTerminal_Color_BackgroundRed: - fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_RED); - break; - case kwsysTerminal_Color_BackgroundGreen: - fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_GREEN); - break; - case kwsysTerminal_Color_BackgroundYellow: - fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_YELLOW); - break; - case kwsysTerminal_Color_BackgroundBlue: - fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_BLUE); - break; - case kwsysTerminal_Color_BackgroundMagenta: - fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_MAGENTA); - break; - case kwsysTerminal_Color_BackgroundCyan: - fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_CYAN); - break; - case kwsysTerminal_Color_BackgroundWhite: - fprintf(stream, KWSYS_TERMINAL_VT100_BACKGROUND_WHITE); - break; - } - if (color & kwsysTerminal_Color_ForegroundBold) { - fprintf(stream, KWSYS_TERMINAL_VT100_BOLD); - } -} - -#if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE) - -# define KWSYS_TERMINAL_MASK_FOREGROUND \ - (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | \ - FOREGROUND_INTENSITY) -# define KWSYS_TERMINAL_MASK_BACKGROUND \ - (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | \ - BACKGROUND_INTENSITY) - -/* Get the Windows handle for a FILE stream. */ -static HANDLE kwsysTerminalGetStreamHandle(FILE* stream) -{ - /* Get the C-library file descriptor from the stream. */ - int fd = fileno(stream); - -# if defined(__CYGWIN__) - /* Cygwin seems to have an extra pipe level. If the file descriptor - corresponds to stdout or stderr then obtain the matching windows - handle directly. */ - if (fd == fileno(stdout)) { - return GetStdHandle(STD_OUTPUT_HANDLE); - } else if (fd == fileno(stderr)) { - return GetStdHandle(STD_ERROR_HANDLE); - } -# endif - - /* Get the underlying Windows handle for the descriptor. */ - return (HANDLE)_get_osfhandle(fd); -} - -/* Set color attributes in a Windows console. */ -static void kwsysTerminalSetConsoleColor(HANDLE hOut, - CONSOLE_SCREEN_BUFFER_INFO* hOutInfo, - FILE* stream, int color) -{ - WORD attributes = 0; - switch (color & kwsysTerminal_Color_ForegroundMask) { - case kwsysTerminal_Color_Normal: - attributes |= hOutInfo->wAttributes & KWSYS_TERMINAL_MASK_FOREGROUND; - break; - case kwsysTerminal_Color_ForegroundBlack: - attributes |= 0; - break; - case kwsysTerminal_Color_ForegroundRed: - attributes |= FOREGROUND_RED; - break; - case kwsysTerminal_Color_ForegroundGreen: - attributes |= FOREGROUND_GREEN; - break; - case kwsysTerminal_Color_ForegroundYellow: - attributes |= FOREGROUND_RED | FOREGROUND_GREEN; - break; - case kwsysTerminal_Color_ForegroundBlue: - attributes |= FOREGROUND_BLUE; - break; - case kwsysTerminal_Color_ForegroundMagenta: - attributes |= FOREGROUND_RED | FOREGROUND_BLUE; - break; - case kwsysTerminal_Color_ForegroundCyan: - attributes |= FOREGROUND_BLUE | FOREGROUND_GREEN; - break; - case kwsysTerminal_Color_ForegroundWhite: - attributes |= FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; - break; - } - switch (color & kwsysTerminal_Color_BackgroundMask) { - case kwsysTerminal_Color_Normal: - attributes |= hOutInfo->wAttributes & KWSYS_TERMINAL_MASK_BACKGROUND; - break; - case kwsysTerminal_Color_BackgroundBlack: - attributes |= 0; - break; - case kwsysTerminal_Color_BackgroundRed: - attributes |= BACKGROUND_RED; - break; - case kwsysTerminal_Color_BackgroundGreen: - attributes |= BACKGROUND_GREEN; - break; - case kwsysTerminal_Color_BackgroundYellow: - attributes |= BACKGROUND_RED | BACKGROUND_GREEN; - break; - case kwsysTerminal_Color_BackgroundBlue: - attributes |= BACKGROUND_BLUE; - break; - case kwsysTerminal_Color_BackgroundMagenta: - attributes |= BACKGROUND_RED | BACKGROUND_BLUE; - break; - case kwsysTerminal_Color_BackgroundCyan: - attributes |= BACKGROUND_BLUE | BACKGROUND_GREEN; - break; - case kwsysTerminal_Color_BackgroundWhite: - attributes |= BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED; - break; - } - if (color & kwsysTerminal_Color_ForegroundBold) { - attributes |= FOREGROUND_INTENSITY; - } - if (color & kwsysTerminal_Color_BackgroundBold) { - attributes |= BACKGROUND_INTENSITY; - } - fflush(stream); - SetConsoleTextAttribute(hOut, attributes); -} -#endif diff --git a/test/API/driver/kwsys/Terminal.h.in b/test/API/driver/kwsys/Terminal.h.in deleted file mode 100644 index 1a2c745..0000000 --- a/test/API/driver/kwsys/Terminal.h.in +++ /dev/null @@ -1,170 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifndef @KWSYS_NAMESPACE@_Terminal_h -#define @KWSYS_NAMESPACE@_Terminal_h - -#include <@KWSYS_NAMESPACE@/Configure.h> - -#include /* For file stream type FILE. */ - -/* Redefine all public interface symbol names to be in the proper - namespace. These macros are used internally to kwsys only, and are - not visible to user code. Use kwsysHeaderDump.pl to reproduce - these macros after making changes to the interface. */ -#if !defined(KWSYS_NAMESPACE) -# define kwsys_ns(x) @KWSYS_NAMESPACE@##x -# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT -#endif -#if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS -# define kwsysTerminal_cfprintf kwsys_ns(Terminal_cfprintf) -# define kwsysTerminal_Color_e kwsys_ns(Terminal_Color_e) -# define kwsysTerminal_Color_Normal kwsys_ns(Terminal_Color_Normal) -# define kwsysTerminal_Color_ForegroundBlack \ - kwsys_ns(Terminal_Color_ForegroundBlack) -# define kwsysTerminal_Color_ForegroundRed \ - kwsys_ns(Terminal_Color_ForegroundRed) -# define kwsysTerminal_Color_ForegroundGreen \ - kwsys_ns(Terminal_Color_ForegroundGreen) -# define kwsysTerminal_Color_ForegroundYellow \ - kwsys_ns(Terminal_Color_ForegroundYellow) -# define kwsysTerminal_Color_ForegroundBlue \ - kwsys_ns(Terminal_Color_ForegroundBlue) -# define kwsysTerminal_Color_ForegroundMagenta \ - kwsys_ns(Terminal_Color_ForegroundMagenta) -# define kwsysTerminal_Color_ForegroundCyan \ - kwsys_ns(Terminal_Color_ForegroundCyan) -# define kwsysTerminal_Color_ForegroundWhite \ - kwsys_ns(Terminal_Color_ForegroundWhite) -# define kwsysTerminal_Color_ForegroundMask \ - kwsys_ns(Terminal_Color_ForegroundMask) -# define kwsysTerminal_Color_BackgroundBlack \ - kwsys_ns(Terminal_Color_BackgroundBlack) -# define kwsysTerminal_Color_BackgroundRed \ - kwsys_ns(Terminal_Color_BackgroundRed) -# define kwsysTerminal_Color_BackgroundGreen \ - kwsys_ns(Terminal_Color_BackgroundGreen) -# define kwsysTerminal_Color_BackgroundYellow \ - kwsys_ns(Terminal_Color_BackgroundYellow) -# define kwsysTerminal_Color_BackgroundBlue \ - kwsys_ns(Terminal_Color_BackgroundBlue) -# define kwsysTerminal_Color_BackgroundMagenta \ - kwsys_ns(Terminal_Color_BackgroundMagenta) -# define kwsysTerminal_Color_BackgroundCyan \ - kwsys_ns(Terminal_Color_BackgroundCyan) -# define kwsysTerminal_Color_BackgroundWhite \ - kwsys_ns(Terminal_Color_BackgroundWhite) -# define kwsysTerminal_Color_BackgroundMask \ - kwsys_ns(Terminal_Color_BackgroundMask) -# define kwsysTerminal_Color_ForegroundBold \ - kwsys_ns(Terminal_Color_ForegroundBold) -# define kwsysTerminal_Color_BackgroundBold \ - kwsys_ns(Terminal_Color_BackgroundBold) -# define kwsysTerminal_Color_AssumeTTY kwsys_ns(Terminal_Color_AssumeTTY) -# define kwsysTerminal_Color_AssumeVT100 kwsys_ns(Terminal_Color_AssumeVT100) -# define kwsysTerminal_Color_AttributeMask \ - kwsys_ns(Terminal_Color_AttributeMask) -#endif - -#if defined(__cplusplus) -extern "C" { -#endif - -/** - * Write colored and formatted text to a stream. Color is used only - * for streams supporting it. The color specification is constructed - * by bitwise-OR-ing enumeration values. At most one foreground and - * one background value may be given. - * - * Whether the a stream supports color is usually automatically - * detected, but with two exceptions: - * - * - When the stream is displayed in a terminal supporting VT100 - * color but using an intermediate pipe for communication the - * detection of a tty fails. (This typically occurs for a shell - * running in an rxvt terminal in MSYS.) If the caller knows this - * to be the case, the attribute Color_AssumeTTY may be included in - * the color specification. - * - * - When the stream is displayed in a terminal whose TERM - * environment variable is not set or is set to a value that is not - * known to support VT100 colors. If the caller knows this to be - * the case, the attribute Color_AssumeVT100 may be included in the - * color specification. - */ -kwsysEXPORT void kwsysTerminal_cfprintf(int color, FILE* stream, - const char* format, ...); -enum kwsysTerminal_Color_e -{ - /* Normal Text */ - kwsysTerminal_Color_Normal = 0, - - /* Foreground Color */ - kwsysTerminal_Color_ForegroundBlack = 0x1, - kwsysTerminal_Color_ForegroundRed = 0x2, - kwsysTerminal_Color_ForegroundGreen = 0x3, - kwsysTerminal_Color_ForegroundYellow = 0x4, - kwsysTerminal_Color_ForegroundBlue = 0x5, - kwsysTerminal_Color_ForegroundMagenta = 0x6, - kwsysTerminal_Color_ForegroundCyan = 0x7, - kwsysTerminal_Color_ForegroundWhite = 0x8, - kwsysTerminal_Color_ForegroundMask = 0xF, - - /* Background Color */ - kwsysTerminal_Color_BackgroundBlack = 0x10, - kwsysTerminal_Color_BackgroundRed = 0x20, - kwsysTerminal_Color_BackgroundGreen = 0x30, - kwsysTerminal_Color_BackgroundYellow = 0x40, - kwsysTerminal_Color_BackgroundBlue = 0x50, - kwsysTerminal_Color_BackgroundMagenta = 0x60, - kwsysTerminal_Color_BackgroundCyan = 0x70, - kwsysTerminal_Color_BackgroundWhite = 0x80, - kwsysTerminal_Color_BackgroundMask = 0xF0, - - /* Attributes */ - kwsysTerminal_Color_ForegroundBold = 0x100, - kwsysTerminal_Color_BackgroundBold = 0x200, - kwsysTerminal_Color_AssumeTTY = 0x400, - kwsysTerminal_Color_AssumeVT100 = 0x800, - kwsysTerminal_Color_AttributeMask = 0xF00 -}; - -#if defined(__cplusplus) -} /* extern "C" */ -#endif - -/* If we are building a kwsys .c or .cxx file, let it use these macros. - Otherwise, undefine them to keep the namespace clean. */ -#if !defined(KWSYS_NAMESPACE) -# undef kwsys_ns -# undef kwsysEXPORT -# if !@KWSYS_NAMESPACE@_NAME_IS_KWSYS -# undef kwsysTerminal_cfprintf -# undef kwsysTerminal_Color_e -# undef kwsysTerminal_Color_Normal -# undef kwsysTerminal_Color_ForegroundBlack -# undef kwsysTerminal_Color_ForegroundRed -# undef kwsysTerminal_Color_ForegroundGreen -# undef kwsysTerminal_Color_ForegroundYellow -# undef kwsysTerminal_Color_ForegroundBlue -# undef kwsysTerminal_Color_ForegroundMagenta -# undef kwsysTerminal_Color_ForegroundCyan -# undef kwsysTerminal_Color_ForegroundWhite -# undef kwsysTerminal_Color_ForegroundMask -# undef kwsysTerminal_Color_BackgroundBlack -# undef kwsysTerminal_Color_BackgroundRed -# undef kwsysTerminal_Color_BackgroundGreen -# undef kwsysTerminal_Color_BackgroundYellow -# undef kwsysTerminal_Color_BackgroundBlue -# undef kwsysTerminal_Color_BackgroundMagenta -# undef kwsysTerminal_Color_BackgroundCyan -# undef kwsysTerminal_Color_BackgroundWhite -# undef kwsysTerminal_Color_BackgroundMask -# undef kwsysTerminal_Color_ForegroundBold -# undef kwsysTerminal_Color_BackgroundBold -# undef kwsysTerminal_Color_AssumeTTY -# undef kwsysTerminal_Color_AssumeVT100 -# undef kwsysTerminal_Color_AttributeMask -# endif -#endif - -#endif diff --git a/test/API/driver/kwsys/clang-format.bash b/test/API/driver/kwsys/clang-format.bash deleted file mode 100644 index b0282ab..0000000 --- a/test/API/driver/kwsys/clang-format.bash +++ /dev/null @@ -1,128 +0,0 @@ -#!/usr/bin/env bash -#============================================================================= -# Copyright 2015-2017 Kitware, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#============================================================================= - -usage='usage: clang-format.bash [] [--] - - --help Print usage plus more detailed help. - - --clang-format Use given clang-format tool. - - --amend Filter files changed by HEAD. - --cached Filter files locally staged for commit. - --modified Filter files locally modified from HEAD. - --tracked Filter files tracked by Git. -' - -help="$usage"' -Example to format locally modified files: - - ./clang-format.bash --modified - -Example to format locally modified files staged for commit: - - ./clang-format.bash --cached - -Example to format files modified by the most recent commit: - - ./clang-format.bash --amend - -Example to format all files: - - ./clang-format.bash --tracked - -Example to format the current topic: - - git filter-branch \ - --tree-filter "./clang-format.bash --tracked" \ - master.. -' - -die() { - echo "$@" 1>&2; exit 1 -} - -#----------------------------------------------------------------------------- - -# Parse command-line arguments. -clang_format='' -mode='' -while test "$#" != 0; do - case "$1" in - --amend) mode="amend" ;; - --cached) mode="cached" ;; - --clang-format) shift; clang_format="$1" ;; - --help) echo "$help"; exit 0 ;; - --modified) mode="modified" ;; - --tracked) mode="tracked" ;; - --) shift ; break ;; - -*) die "$usage" ;; - *) break ;; - esac - shift -done -test "$#" = 0 || die "$usage" - -# Find a default tool. -tools=' - clang-format-6.0 - clang-format -' -if test "x$clang_format" = "x"; then - for tool in $tools; do - if type -p "$tool" >/dev/null; then - clang_format="$tool" - break - fi - done -fi - -# Verify that we have a tool. -if ! type -p "$clang_format" >/dev/null; then - echo "Unable to locate a 'clang-format' tool." - exit 1 -fi - -if ! "$clang_format" --version | grep 'clang-format version 6\.0' >/dev/null 2>/dev/null; then - echo "clang-format version 6.0 is required (exactly)" - exit 1 -fi - -# Select listing mode. -case "$mode" in - '') echo "$usage"; exit 0 ;; - amend) git_ls='git diff-tree --diff-filter=AM --name-only HEAD -r --no-commit-id' ;; - cached) git_ls='git diff-index --diff-filter=AM --name-only HEAD --cached' ;; - modified) git_ls='git diff-index --diff-filter=AM --name-only HEAD' ;; - tracked) git_ls='git ls-files' ;; - *) die "invalid mode: $mode" ;; -esac - -# List files as selected above. -list_files() { - $git_ls | - - # Select sources with our attribute. - git check-attr --stdin format.clang-format | - sed -n '/: format\.clang-format: set$/ {s/:[^:]*:[^:]*$//p}' -} - -# Transform configured sources to protect @SYMBOLS@. -list_files | xargs -d '\n' sed -i 's/@\(KWSYS_[A-Z0-9_]\+\)@/x\1x/g' -# Update sources in-place. -list_files | xargs -d '\n' "$clang_format" -i -# Transform configured sources to restore @SYMBOLS@. -list_files | xargs -d '\n' sed -i 's/x\(KWSYS_[A-Z0-9_]\+\)x/@\1@/g' diff --git a/test/API/driver/kwsys/hash_fun.hxx.in b/test/API/driver/kwsys/hash_fun.hxx.in deleted file mode 100644 index 8626c2a..0000000 --- a/test/API/driver/kwsys/hash_fun.hxx.in +++ /dev/null @@ -1,166 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -/* - * Copyright (c) 1996 - * Silicon Graphics Computer Systems, Inc. - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Silicon Graphics makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - * - * Copyright (c) 1994 - * Hewlett-Packard Company - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Hewlett-Packard Company makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - */ -#ifndef @KWSYS_NAMESPACE@_hash_fun_hxx -#define @KWSYS_NAMESPACE@_hash_fun_hxx - -#include <@KWSYS_NAMESPACE@/Configure.hxx> - -#include // size_t -#include - -namespace @KWSYS_NAMESPACE@ { - -template -struct hash -{ -}; - -inline size_t _stl_hash_string(const char* __s) -{ - unsigned long __h = 0; - for (; *__s; ++__s) - __h = 5 * __h + *__s; - - return size_t(__h); -} - -template <> -struct hash -{ - size_t operator()(const char* __s) const { return _stl_hash_string(__s); } -}; - -template <> -struct hash -{ - size_t operator()(const char* __s) const { return _stl_hash_string(__s); } -}; - -template <> -struct hash -{ - size_t operator()(const std::string& __s) const - { - return _stl_hash_string(__s.c_str()); - } -}; - -#if !defined(__BORLANDC__) -template <> -struct hash -{ - size_t operator()(const std::string& __s) const - { - return _stl_hash_string(__s.c_str()); - } -}; -#endif - -template <> -struct hash -{ - size_t operator()(char __x) const { return __x; } -}; - -template <> -struct hash -{ - size_t operator()(unsigned char __x) const { return __x; } -}; - -template <> -struct hash -{ - size_t operator()(unsigned char __x) const { return __x; } -}; - -template <> -struct hash -{ - size_t operator()(short __x) const { return __x; } -}; - -template <> -struct hash -{ - size_t operator()(unsigned short __x) const { return __x; } -}; - -template <> -struct hash -{ - size_t operator()(int __x) const { return __x; } -}; - -template <> -struct hash -{ - size_t operator()(unsigned int __x) const { return __x; } -}; - -template <> -struct hash -{ - size_t operator()(long __x) const { return __x; } -}; - -template <> -struct hash -{ - size_t operator()(unsigned long __x) const { return __x; } -}; - -// use long long or __int64 -#if @KWSYS_USE_LONG_LONG@ -template <> -struct hash -{ - size_t operator()(long long __x) const { return __x; } -}; - -template <> -struct hash -{ - size_t operator()(unsigned long long __x) const { return __x; } -}; -#elif @KWSYS_USE___INT64@ -template <> -struct hash<__int64> -{ - size_t operator()(__int64 __x) const { return __x; } -}; -template <> -struct hash -{ - size_t operator()(unsigned __int64 __x) const { return __x; } -}; -#endif // use long long or __int64 - -} // namespace @KWSYS_NAMESPACE@ - -#endif diff --git a/test/API/driver/kwsys/hash_map.hxx.in b/test/API/driver/kwsys/hash_map.hxx.in deleted file mode 100644 index 5f04e9c..0000000 --- a/test/API/driver/kwsys/hash_map.hxx.in +++ /dev/null @@ -1,423 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -/* - * Copyright (c) 1996 - * Silicon Graphics Computer Systems, Inc. - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Silicon Graphics makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - * - * Copyright (c) 1994 - * Hewlett-Packard Company - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Hewlett-Packard Company makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - */ -#ifndef @KWSYS_NAMESPACE@_hash_map_hxx -#define @KWSYS_NAMESPACE@_hash_map_hxx - -#include <@KWSYS_NAMESPACE@/hashtable.hxx> - -#include <@KWSYS_NAMESPACE@/hash_fun.hxx> - -#include // equal_to - -#if defined(_MSC_VER) -# pragma warning(push) -# pragma warning(disable : 4284) -# pragma warning(disable : 4786) -#endif - -#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32) -# pragma set woff 1174 -# pragma set woff 1375 -#endif - -namespace @KWSYS_NAMESPACE@ { - -// select1st is an extension: it is not part of the standard. -template -struct hash_select1st -{ - const T1& operator()(const std::pair& __x) const - { - return __x.first; - } -}; - -// Forward declaration of equality operator; needed for friend declaration. - -template , - class _EqualKey = std::equal_to<_Key>, - class _Alloc = std::allocator > -class hash_map; - -template -bool operator==(const hash_map<_Key, _Tp, _HashFn, _EqKey, _Alloc>&, - const hash_map<_Key, _Tp, _HashFn, _EqKey, _Alloc>&); - -template -class hash_map -{ -private: - typedef hashtable, _Key, _HashFcn, - hash_select1st, _EqualKey, _Alloc> - _Ht; - _Ht _M_ht; - -public: - typedef typename _Ht::key_type key_type; - typedef _Tp data_type; - typedef _Tp mapped_type; - typedef typename _Ht::value_type value_type; - typedef typename _Ht::hasher hasher; - typedef typename _Ht::key_equal key_equal; - - typedef typename _Ht::size_type size_type; - typedef typename _Ht::difference_type difference_type; - typedef typename _Ht::pointer pointer; - typedef typename _Ht::const_pointer const_pointer; - typedef typename _Ht::reference reference; - typedef typename _Ht::const_reference const_reference; - - typedef typename _Ht::iterator iterator; - typedef typename _Ht::const_iterator const_iterator; - - typedef typename _Ht::allocator_type allocator_type; - - hasher hash_funct() const { return _M_ht.hash_funct(); } - key_equal key_eq() const { return _M_ht.key_eq(); } - allocator_type get_allocator() const { return _M_ht.get_allocator(); } - -public: - hash_map() - : _M_ht(100, hasher(), key_equal(), allocator_type()) - { - } - explicit hash_map(size_type __n) - : _M_ht(__n, hasher(), key_equal(), allocator_type()) - { - } - hash_map(size_type __n, const hasher& __hf) - : _M_ht(__n, __hf, key_equal(), allocator_type()) - { - } - hash_map(size_type __n, const hasher& __hf, const key_equal& __eql, - const allocator_type& __a = allocator_type()) - : _M_ht(__n, __hf, __eql, __a) - { - } - - template - hash_map(_InputIterator __f, _InputIterator __l) - : _M_ht(100, hasher(), key_equal(), allocator_type()) - { - _M_ht.insert_unique(__f, __l); - } - template - hash_map(_InputIterator __f, _InputIterator __l, size_type __n) - : _M_ht(__n, hasher(), key_equal(), allocator_type()) - { - _M_ht.insert_unique(__f, __l); - } - template - hash_map(_InputIterator __f, _InputIterator __l, size_type __n, - const hasher& __hf) - : _M_ht(__n, __hf, key_equal(), allocator_type()) - { - _M_ht.insert_unique(__f, __l); - } - template - hash_map(_InputIterator __f, _InputIterator __l, size_type __n, - const hasher& __hf, const key_equal& __eql, - const allocator_type& __a = allocator_type()) - : _M_ht(__n, __hf, __eql, __a) - { - _M_ht.insert_unique(__f, __l); - } - -public: - size_type size() const { return _M_ht.size(); } - size_type max_size() const { return _M_ht.max_size(); } - bool empty() const { return _M_ht.empty(); } - void swap(hash_map& __hs) { _M_ht.swap(__hs._M_ht); } - - friend bool operator==<>(const hash_map&, const hash_map&); - - iterator begin() { return _M_ht.begin(); } - iterator end() { return _M_ht.end(); } - const_iterator begin() const { return _M_ht.begin(); } - const_iterator end() const { return _M_ht.end(); } - -public: - std::pair insert(const value_type& __obj) - { - return _M_ht.insert_unique(__obj); - } - template - void insert(_InputIterator __f, _InputIterator __l) - { - _M_ht.insert_unique(__f, __l); - } - std::pair insert_noresize(const value_type& __obj) - { - return _M_ht.insert_unique_noresize(__obj); - } - - iterator find(const key_type& __key) { return _M_ht.find(__key); } - const_iterator find(const key_type& __key) const - { - return _M_ht.find(__key); - } - - _Tp& operator[](const key_type& __key) - { - return _M_ht.find_or_insert(value_type(__key, _Tp())).second; - } - - size_type count(const key_type& __key) const { return _M_ht.count(__key); } - - std::pair equal_range(const key_type& __key) - { - return _M_ht.equal_range(__key); - } - std::pair equal_range( - const key_type& __key) const - { - return _M_ht.equal_range(__key); - } - - size_type erase(const key_type& __key) { return _M_ht.erase(__key); } - void erase(iterator __it) { _M_ht.erase(__it); } - void erase(iterator __f, iterator __l) { _M_ht.erase(__f, __l); } - void clear() { _M_ht.clear(); } - - void resize(size_type __hint) { _M_ht.resize(__hint); } - size_type bucket_count() const { return _M_ht.bucket_count(); } - size_type max_bucket_count() const { return _M_ht.max_bucket_count(); } - size_type elems_in_bucket(size_type __n) const - { - return _M_ht.elems_in_bucket(__n); - } -}; - -template -bool operator==(const hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm1, - const hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm2) -{ - return __hm1._M_ht == __hm2._M_ht; -} - -template -inline bool operator!=( - const hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm1, - const hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm2) -{ - return !(__hm1 == __hm2); -} - -template -inline void swap(hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm1, - hash_map<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm2) -{ - __hm1.swap(__hm2); -} - -// Forward declaration of equality operator; needed for friend declaration. - -template , - class _EqualKey = std::equal_to<_Key>, - class _Alloc = std::allocator > -class hash_multimap; - -template -bool operator==(const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm1, - const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm2); - -template -class hash_multimap -{ -private: - typedef hashtable, _Key, _HashFcn, - hash_select1st, _EqualKey, _Alloc> - _Ht; - _Ht _M_ht; - -public: - typedef typename _Ht::key_type key_type; - typedef _Tp data_type; - typedef _Tp mapped_type; - typedef typename _Ht::value_type value_type; - typedef typename _Ht::hasher hasher; - typedef typename _Ht::key_equal key_equal; - - typedef typename _Ht::size_type size_type; - typedef typename _Ht::difference_type difference_type; - typedef typename _Ht::pointer pointer; - typedef typename _Ht::const_pointer const_pointer; - typedef typename _Ht::reference reference; - typedef typename _Ht::const_reference const_reference; - - typedef typename _Ht::iterator iterator; - typedef typename _Ht::const_iterator const_iterator; - - typedef typename _Ht::allocator_type allocator_type; - - hasher hash_funct() const { return _M_ht.hash_funct(); } - key_equal key_eq() const { return _M_ht.key_eq(); } - allocator_type get_allocator() const { return _M_ht.get_allocator(); } - -public: - hash_multimap() - : _M_ht(100, hasher(), key_equal(), allocator_type()) - { - } - explicit hash_multimap(size_type __n) - : _M_ht(__n, hasher(), key_equal(), allocator_type()) - { - } - hash_multimap(size_type __n, const hasher& __hf) - : _M_ht(__n, __hf, key_equal(), allocator_type()) - { - } - hash_multimap(size_type __n, const hasher& __hf, const key_equal& __eql, - const allocator_type& __a = allocator_type()) - : _M_ht(__n, __hf, __eql, __a) - { - } - - template - hash_multimap(_InputIterator __f, _InputIterator __l) - : _M_ht(100, hasher(), key_equal(), allocator_type()) - { - _M_ht.insert_equal(__f, __l); - } - template - hash_multimap(_InputIterator __f, _InputIterator __l, size_type __n) - : _M_ht(__n, hasher(), key_equal(), allocator_type()) - { - _M_ht.insert_equal(__f, __l); - } - template - hash_multimap(_InputIterator __f, _InputIterator __l, size_type __n, - const hasher& __hf) - : _M_ht(__n, __hf, key_equal(), allocator_type()) - { - _M_ht.insert_equal(__f, __l); - } - template - hash_multimap(_InputIterator __f, _InputIterator __l, size_type __n, - const hasher& __hf, const key_equal& __eql, - const allocator_type& __a = allocator_type()) - : _M_ht(__n, __hf, __eql, __a) - { - _M_ht.insert_equal(__f, __l); - } - -public: - size_type size() const { return _M_ht.size(); } - size_type max_size() const { return _M_ht.max_size(); } - bool empty() const { return _M_ht.empty(); } - void swap(hash_multimap& __hs) { _M_ht.swap(__hs._M_ht); } - - friend bool operator==<>(const hash_multimap&, const hash_multimap&); - - iterator begin() { return _M_ht.begin(); } - iterator end() { return _M_ht.end(); } - const_iterator begin() const { return _M_ht.begin(); } - const_iterator end() const { return _M_ht.end(); } - -public: - iterator insert(const value_type& __obj) - { - return _M_ht.insert_equal(__obj); - } - template - void insert(_InputIterator __f, _InputIterator __l) - { - _M_ht.insert_equal(__f, __l); - } - iterator insert_noresize(const value_type& __obj) - { - return _M_ht.insert_equal_noresize(__obj); - } - - iterator find(const key_type& __key) { return _M_ht.find(__key); } - const_iterator find(const key_type& __key) const - { - return _M_ht.find(__key); - } - - size_type count(const key_type& __key) const { return _M_ht.count(__key); } - - std::pair equal_range(const key_type& __key) - { - return _M_ht.equal_range(__key); - } - std::pair equal_range( - const key_type& __key) const - { - return _M_ht.equal_range(__key); - } - - size_type erase(const key_type& __key) { return _M_ht.erase(__key); } - void erase(iterator __it) { _M_ht.erase(__it); } - void erase(iterator __f, iterator __l) { _M_ht.erase(__f, __l); } - void clear() { _M_ht.clear(); } - -public: - void resize(size_type __hint) { _M_ht.resize(__hint); } - size_type bucket_count() const { return _M_ht.bucket_count(); } - size_type max_bucket_count() const { return _M_ht.max_bucket_count(); } - size_type elems_in_bucket(size_type __n) const - { - return _M_ht.elems_in_bucket(__n); - } -}; - -template -bool operator==(const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm1, - const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm2) -{ - return __hm1._M_ht == __hm2._M_ht; -} - -template -inline bool operator!=( - const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm1, - const hash_multimap<_Key, _Tp, _HF, _EqKey, _Alloc>& __hm2) -{ - return !(__hm1 == __hm2); -} - -template -inline void swap(hash_multimap<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm1, - hash_multimap<_Key, _Tp, _HashFcn, _EqlKey, _Alloc>& __hm2) -{ - __hm1.swap(__hm2); -} - -} // namespace @KWSYS_NAMESPACE@ - -#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32) -# pragma reset woff 1174 -# pragma reset woff 1375 -#endif - -#if defined(_MSC_VER) -# pragma warning(pop) -#endif - -#endif diff --git a/test/API/driver/kwsys/hash_set.hxx.in b/test/API/driver/kwsys/hash_set.hxx.in deleted file mode 100644 index f4a37ee..0000000 --- a/test/API/driver/kwsys/hash_set.hxx.in +++ /dev/null @@ -1,392 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -/* - * Copyright (c) 1996 - * Silicon Graphics Computer Systems, Inc. - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Silicon Graphics makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - * - * Copyright (c) 1994 - * Hewlett-Packard Company - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Hewlett-Packard Company makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - */ -#ifndef @KWSYS_NAMESPACE@_hash_set_hxx -#define @KWSYS_NAMESPACE@_hash_set_hxx - -#include <@KWSYS_NAMESPACE@/hashtable.hxx> - -#include <@KWSYS_NAMESPACE@/hash_fun.hxx> - -#include // equal_to - -#if defined(_MSC_VER) -# pragma warning(push) -# pragma warning(disable : 4284) -# pragma warning(disable : 4786) -#endif - -#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32) -# pragma set woff 1174 -# pragma set woff 1375 -#endif - -namespace @KWSYS_NAMESPACE@ { - -// identity is an extension: it is not part of the standard. -template -struct _Identity -{ - const _Tp& operator()(const _Tp& __x) const { return __x; } -}; - -// Forward declaration of equality operator; needed for friend declaration. - -template , - class _EqualKey = std::equal_to<_Value>, - class _Alloc = std::allocator > -class hash_set; - -template -bool operator==(const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs1, - const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs2); - -template -class hash_set -{ -private: - typedef hashtable<_Value, _Value, _HashFcn, _Identity<_Value>, _EqualKey, - _Alloc> - _Ht; - _Ht _M_ht; - -public: - typedef typename _Ht::key_type key_type; - typedef typename _Ht::value_type value_type; - typedef typename _Ht::hasher hasher; - typedef typename _Ht::key_equal key_equal; - - typedef typename _Ht::size_type size_type; - typedef typename _Ht::difference_type difference_type; - typedef typename _Ht::const_pointer pointer; - typedef typename _Ht::const_pointer const_pointer; - typedef typename _Ht::const_reference reference; - typedef typename _Ht::const_reference const_reference; - - typedef typename _Ht::const_iterator iterator; - typedef typename _Ht::const_iterator const_iterator; - - typedef typename _Ht::allocator_type allocator_type; - - hasher hash_funct() const { return _M_ht.hash_funct(); } - key_equal key_eq() const { return _M_ht.key_eq(); } - allocator_type get_allocator() const { return _M_ht.get_allocator(); } - -public: - hash_set() - : _M_ht(100, hasher(), key_equal(), allocator_type()) - { - } - explicit hash_set(size_type __n) - : _M_ht(__n, hasher(), key_equal(), allocator_type()) - { - } - hash_set(size_type __n, const hasher& __hf) - : _M_ht(__n, __hf, key_equal(), allocator_type()) - { - } - hash_set(size_type __n, const hasher& __hf, const key_equal& __eql, - const allocator_type& __a = allocator_type()) - : _M_ht(__n, __hf, __eql, __a) - { - } - - template - hash_set(_InputIterator __f, _InputIterator __l) - : _M_ht(100, hasher(), key_equal(), allocator_type()) - { - _M_ht.insert_unique(__f, __l); - } - template - hash_set(_InputIterator __f, _InputIterator __l, size_type __n) - : _M_ht(__n, hasher(), key_equal(), allocator_type()) - { - _M_ht.insert_unique(__f, __l); - } - template - hash_set(_InputIterator __f, _InputIterator __l, size_type __n, - const hasher& __hf) - : _M_ht(__n, __hf, key_equal(), allocator_type()) - { - _M_ht.insert_unique(__f, __l); - } - template - hash_set(_InputIterator __f, _InputIterator __l, size_type __n, - const hasher& __hf, const key_equal& __eql, - const allocator_type& __a = allocator_type()) - : _M_ht(__n, __hf, __eql, __a) - { - _M_ht.insert_unique(__f, __l); - } - -public: - size_type size() const { return _M_ht.size(); } - size_type max_size() const { return _M_ht.max_size(); } - bool empty() const { return _M_ht.empty(); } - void swap(hash_set& __hs) { _M_ht.swap(__hs._M_ht); } - - friend bool operator==<>(const hash_set&, const hash_set&); - - iterator begin() const { return _M_ht.begin(); } - iterator end() const { return _M_ht.end(); } - -public: - std::pair insert(const value_type& __obj) - { - typedef typename _Ht::iterator _Ht_iterator; - std::pair<_Ht_iterator, bool> __p = _M_ht.insert_unique(__obj); - return std::pair(__p.first, __p.second); - } - template - void insert(_InputIterator __f, _InputIterator __l) - { - _M_ht.insert_unique(__f, __l); - } - std::pair insert_noresize(const value_type& __obj) - { - typedef typename _Ht::iterator _Ht_iterator; - std::pair<_Ht_iterator, bool> __p = _M_ht.insert_unique_noresize(__obj); - return std::pair(__p.first, __p.second); - } - - iterator find(const key_type& __key) const { return _M_ht.find(__key); } - - size_type count(const key_type& __key) const { return _M_ht.count(__key); } - - std::pair equal_range(const key_type& __key) const - { - return _M_ht.equal_range(__key); - } - - size_type erase(const key_type& __key) { return _M_ht.erase(__key); } - void erase(iterator __it) { _M_ht.erase(__it); } - void erase(iterator __f, iterator __l) { _M_ht.erase(__f, __l); } - void clear() { _M_ht.clear(); } - -public: - void resize(size_type __hint) { _M_ht.resize(__hint); } - size_type bucket_count() const { return _M_ht.bucket_count(); } - size_type max_bucket_count() const { return _M_ht.max_bucket_count(); } - size_type elems_in_bucket(size_type __n) const - { - return _M_ht.elems_in_bucket(__n); - } -}; - -template -bool operator==(const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs1, - const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs2) -{ - return __hs1._M_ht == __hs2._M_ht; -} - -template -inline bool operator!=( - const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs1, - const hash_set<_Value, _HashFcn, _EqualKey, _Alloc>& __hs2) -{ - return !(__hs1 == __hs2); -} - -template -inline void swap(hash_set<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1, - hash_set<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2) -{ - __hs1.swap(__hs2); -} - -template , - class _EqualKey = std::equal_to<_Value>, - class _Alloc = std::allocator > -class hash_multiset; - -template -bool operator==(const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1, - const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2); - -template -class hash_multiset -{ -private: - typedef hashtable<_Value, _Value, _HashFcn, _Identity<_Value>, _EqualKey, - _Alloc> - _Ht; - _Ht _M_ht; - -public: - typedef typename _Ht::key_type key_type; - typedef typename _Ht::value_type value_type; - typedef typename _Ht::hasher hasher; - typedef typename _Ht::key_equal key_equal; - - typedef typename _Ht::size_type size_type; - typedef typename _Ht::difference_type difference_type; - typedef typename _Ht::const_pointer pointer; - typedef typename _Ht::const_pointer const_pointer; - typedef typename _Ht::const_reference reference; - typedef typename _Ht::const_reference const_reference; - - typedef typename _Ht::const_iterator iterator; - typedef typename _Ht::const_iterator const_iterator; - - typedef typename _Ht::allocator_type allocator_type; - - hasher hash_funct() const { return _M_ht.hash_funct(); } - key_equal key_eq() const { return _M_ht.key_eq(); } - allocator_type get_allocator() const { return _M_ht.get_allocator(); } - -public: - hash_multiset() - : _M_ht(100, hasher(), key_equal(), allocator_type()) - { - } - explicit hash_multiset(size_type __n) - : _M_ht(__n, hasher(), key_equal(), allocator_type()) - { - } - hash_multiset(size_type __n, const hasher& __hf) - : _M_ht(__n, __hf, key_equal(), allocator_type()) - { - } - hash_multiset(size_type __n, const hasher& __hf, const key_equal& __eql, - const allocator_type& __a = allocator_type()) - : _M_ht(__n, __hf, __eql, __a) - { - } - - template - hash_multiset(_InputIterator __f, _InputIterator __l) - : _M_ht(100, hasher(), key_equal(), allocator_type()) - { - _M_ht.insert_equal(__f, __l); - } - template - hash_multiset(_InputIterator __f, _InputIterator __l, size_type __n) - : _M_ht(__n, hasher(), key_equal(), allocator_type()) - { - _M_ht.insert_equal(__f, __l); - } - template - hash_multiset(_InputIterator __f, _InputIterator __l, size_type __n, - const hasher& __hf) - : _M_ht(__n, __hf, key_equal(), allocator_type()) - { - _M_ht.insert_equal(__f, __l); - } - template - hash_multiset(_InputIterator __f, _InputIterator __l, size_type __n, - const hasher& __hf, const key_equal& __eql, - const allocator_type& __a = allocator_type()) - : _M_ht(__n, __hf, __eql, __a) - { - _M_ht.insert_equal(__f, __l); - } - -public: - size_type size() const { return _M_ht.size(); } - size_type max_size() const { return _M_ht.max_size(); } - bool empty() const { return _M_ht.empty(); } - void swap(hash_multiset& hs) { _M_ht.swap(hs._M_ht); } - - friend bool operator==<>(const hash_multiset&, const hash_multiset&); - - iterator begin() const { return _M_ht.begin(); } - iterator end() const { return _M_ht.end(); } - -public: - iterator insert(const value_type& __obj) - { - return _M_ht.insert_equal(__obj); - } - template - void insert(_InputIterator __f, _InputIterator __l) - { - _M_ht.insert_equal(__f, __l); - } - iterator insert_noresize(const value_type& __obj) - { - return _M_ht.insert_equal_noresize(__obj); - } - - iterator find(const key_type& __key) const { return _M_ht.find(__key); } - - size_type count(const key_type& __key) const { return _M_ht.count(__key); } - - std::pair equal_range(const key_type& __key) const - { - return _M_ht.equal_range(__key); - } - - size_type erase(const key_type& __key) { return _M_ht.erase(__key); } - void erase(iterator __it) { _M_ht.erase(__it); } - void erase(iterator __f, iterator __l) { _M_ht.erase(__f, __l); } - void clear() { _M_ht.clear(); } - -public: - void resize(size_type __hint) { _M_ht.resize(__hint); } - size_type bucket_count() const { return _M_ht.bucket_count(); } - size_type max_bucket_count() const { return _M_ht.max_bucket_count(); } - size_type elems_in_bucket(size_type __n) const - { - return _M_ht.elems_in_bucket(__n); - } -}; - -template -bool operator==(const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1, - const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2) -{ - return __hs1._M_ht == __hs2._M_ht; -} - -template -inline bool operator!=( - const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1, - const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2) -{ - return !(__hs1 == __hs2); -} - -template -inline void swap(hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1, - hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2) -{ - __hs1.swap(__hs2); -} - -} // namespace @KWSYS_NAMESPACE@ - -#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32) -# pragma reset woff 1174 -# pragma reset woff 1375 -#endif - -#if defined(_MSC_VER) -# pragma warning(pop) -#endif - -#endif diff --git a/test/API/driver/kwsys/hashtable.hxx.in b/test/API/driver/kwsys/hashtable.hxx.in deleted file mode 100644 index 8c4b002..0000000 --- a/test/API/driver/kwsys/hashtable.hxx.in +++ /dev/null @@ -1,995 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -/* - * Copyright (c) 1996 - * Silicon Graphics Computer Systems, Inc. - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Silicon Graphics makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - * - * Copyright (c) 1994 - * Hewlett-Packard Company - * - * Permission to use, copy, modify, distribute and sell this software - * and its documentation for any purpose is hereby granted without fee, - * provided that the above copyright notice appear in all copies and - * that both that copyright notice and this permission notice appear - * in supporting documentation. Hewlett-Packard Company makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - */ -#ifdef __BORLANDC__ -# pragma warn - 8027 /* 'for' not inlined. */ -# pragma warn - 8026 /* 'exception' not inlined. */ -#endif - -#ifndef @KWSYS_NAMESPACE@_hashtable_hxx -# define @KWSYS_NAMESPACE@_hashtable_hxx - -# include <@KWSYS_NAMESPACE@/Configure.hxx> - -# include // lower_bound -# include // iterator_traits -# include // allocator -# include // size_t -# include // pair -# include // vector - -# if defined(_MSC_VER) -# pragma warning(push) -# pragma warning(disable : 4284) -# pragma warning(disable : 4786) -# pragma warning(disable : 4512) /* no assignment operator for class */ -# endif -# if defined(__sgi) && !defined(__GNUC__) -# pragma set woff 3970 /* pointer to int conversion */ 3321 3968 -# endif - -// In C++11, clang will warn about using dynamic exception specifications -// as they are deprecated. But as this class is trying to faithfully -// mimic unordered_set and unordered_map, we want to keep the 'throw()' -// decorations below. So we suppress the warning. -# if defined(__clang__) && defined(__has_warning) -# if __has_warning("-Wdeprecated") -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated" -# endif -# endif - -namespace @KWSYS_NAMESPACE@ { - -template -struct _Hashtable_node -{ - _Hashtable_node* _M_next; - _Val _M_val; - void public_method_to_quiet_warning_about_all_methods_private(); - -private: - void operator=(_Hashtable_node<_Val> const&) = delete; -}; - -template > -class hashtable; - -template -struct _Hashtable_iterator; - -template -struct _Hashtable_const_iterator; - -template -struct _Hashtable_iterator -{ - typedef hashtable<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc> - _Hashtable; - typedef _Hashtable_iterator<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, - _Alloc> - iterator; - typedef _Hashtable_const_iterator<_Val, _Key, _HashFcn, _ExtractKey, - _EqualKey, _Alloc> - const_iterator; - typedef _Hashtable_node<_Val> _Node; - - typedef std::forward_iterator_tag iterator_category; - typedef _Val value_type; - typedef ptrdiff_t difference_type; - typedef size_t size_type; - typedef _Val& reference; - typedef _Val* pointer; - - _Node* _M_cur; - _Hashtable* _M_ht; - - _Hashtable_iterator(_Node* __n, _Hashtable* __tab) - : _M_cur(__n) - , _M_ht(__tab) - { - } - _Hashtable_iterator() {} - reference operator*() const { return _M_cur->_M_val; } - pointer operator->() const { return &(operator*()); } - iterator& operator++(); - iterator operator++(int); - bool operator==(const iterator& __it) const { return _M_cur == __it._M_cur; } - bool operator!=(const iterator& __it) const { return _M_cur != __it._M_cur; } -}; - -template -struct _Hashtable_const_iterator -{ - typedef hashtable<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc> - _Hashtable; - typedef _Hashtable_iterator<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, - _Alloc> - iterator; - typedef _Hashtable_const_iterator<_Val, _Key, _HashFcn, _ExtractKey, - _EqualKey, _Alloc> - const_iterator; - typedef _Hashtable_node<_Val> _Node; - - typedef std::forward_iterator_tag iterator_category; - typedef _Val value_type; - typedef ptrdiff_t difference_type; - typedef size_t size_type; - typedef const _Val& reference; - typedef const _Val* pointer; - - const _Node* _M_cur; - const _Hashtable* _M_ht; - - _Hashtable_const_iterator(const _Node* __n, const _Hashtable* __tab) - : _M_cur(__n) - , _M_ht(__tab) - { - } - _Hashtable_const_iterator() {} - _Hashtable_const_iterator(const iterator& __it) - : _M_cur(__it._M_cur) - , _M_ht(__it._M_ht) - { - } - reference operator*() const { return _M_cur->_M_val; } - pointer operator->() const { return &(operator*()); } - const_iterator& operator++(); - const_iterator operator++(int); - bool operator==(const const_iterator& __it) const - { - return _M_cur == __it._M_cur; - } - bool operator!=(const const_iterator& __it) const - { - return _M_cur != __it._M_cur; - } -}; - -// Note: assumes long is at least 32 bits. -enum -{ - _stl_num_primes = 31 -}; - -// create a function with a static local to that function that returns -// the static -static inline const unsigned long* get_stl_prime_list() -{ - - static const unsigned long _stl_prime_list[_stl_num_primes] = { - 5ul, 11ul, 23ul, 53ul, 97ul, - 193ul, 389ul, 769ul, 1543ul, 3079ul, - 6151ul, 12289ul, 24593ul, 49157ul, 98317ul, - 196613ul, 393241ul, 786433ul, 1572869ul, 3145739ul, - 6291469ul, 12582917ul, 25165843ul, 50331653ul, 100663319ul, - 201326611ul, 402653189ul, 805306457ul, 1610612741ul, 3221225473ul, - 4294967291ul - }; - - return &_stl_prime_list[0]; -} - -static inline size_t _stl_next_prime(size_t __n) -{ - const unsigned long* __first = get_stl_prime_list(); - const unsigned long* __last = get_stl_prime_list() + (int)_stl_num_primes; - const unsigned long* pos = std::lower_bound(__first, __last, __n); - return pos == __last ? *(__last - 1) : *pos; -} - -// Forward declaration of operator==. - -template -class hashtable; - -template -bool operator==(const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht1, - const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht2); - -// Hashtables handle allocators a bit differently than other containers -// do. If we're using standard-conforming allocators, then a hashtable -// unconditionally has a member variable to hold its allocator, even if -// it so happens that all instances of the allocator type are identical. -// This is because, for hashtables, this extra storage is negligible. -// Additionally, a base class wouldn't serve any other purposes; it -// wouldn't, for example, simplify the exception-handling code. - -template -class hashtable -{ -public: - typedef _Key key_type; - typedef _Val value_type; - typedef _HashFcn hasher; - typedef _EqualKey key_equal; - - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef value_type* pointer; - typedef const value_type* const_pointer; - typedef value_type& reference; - typedef const value_type& const_reference; - - hasher hash_funct() const { return _M_hash; } - key_equal key_eq() const { return _M_equals; } - -private: - typedef _Hashtable_node<_Val> _Node; - -public: - typedef typename _Alloc::template rebind<_Val>::other allocator_type; - allocator_type get_allocator() const { return _M_node_allocator; } - -private: - typedef - typename _Alloc::template rebind<_Node>::other _M_node_allocator_type; - typedef - typename _Alloc::template rebind<_Node*>::other _M_node_ptr_allocator_type; - typedef std::vector<_Node*, _M_node_ptr_allocator_type> _M_buckets_type; - -private: - _M_node_allocator_type _M_node_allocator; - hasher _M_hash; - key_equal _M_equals; - _ExtractKey _M_get_key; - _M_buckets_type _M_buckets; - size_type _M_num_elements; - - _Node* _M_get_node() { return _M_node_allocator.allocate(1); } - void _M_put_node(_Node* __p) { _M_node_allocator.deallocate(__p, 1); } - -public: - typedef _Hashtable_iterator<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, - _Alloc> - iterator; - typedef _Hashtable_const_iterator<_Val, _Key, _HashFcn, _ExtractKey, - _EqualKey, _Alloc> - const_iterator; - - friend struct _Hashtable_iterator<_Val, _Key, _HashFcn, _ExtractKey, - _EqualKey, _Alloc>; - friend struct _Hashtable_const_iterator<_Val, _Key, _HashFcn, _ExtractKey, - _EqualKey, _Alloc>; - -public: - hashtable(size_type __n, const _HashFcn& __hf, const _EqualKey& __eql, - const _ExtractKey& __ext, - const allocator_type& __a = allocator_type()) - : _M_node_allocator(__a) - , _M_hash(__hf) - , _M_equals(__eql) - , _M_get_key(__ext) - , _M_buckets(__a) - , _M_num_elements(0) - { - _M_initialize_buckets(__n); - } - - hashtable(size_type __n, const _HashFcn& __hf, const _EqualKey& __eql, - const allocator_type& __a = allocator_type()) - : _M_node_allocator(__a) - , _M_hash(__hf) - , _M_equals(__eql) - , _M_get_key(_ExtractKey()) - , _M_buckets(__a) - , _M_num_elements(0) - { - _M_initialize_buckets(__n); - } - - hashtable(const hashtable& __ht) - : _M_node_allocator(__ht.get_allocator()) - , _M_hash(__ht._M_hash) - , _M_equals(__ht._M_equals) - , _M_get_key(__ht._M_get_key) - , _M_buckets(__ht.get_allocator()) - , _M_num_elements(0) - { - _M_copy_from(__ht); - } - - hashtable& operator=(const hashtable& __ht) - { - if (&__ht != this) { - clear(); - _M_hash = __ht._M_hash; - _M_equals = __ht._M_equals; - _M_get_key = __ht._M_get_key; - _M_copy_from(__ht); - } - return *this; - } - - ~hashtable() { clear(); } - - size_type size() const { return _M_num_elements; } - size_type max_size() const { return size_type(-1); } - bool empty() const { return size() == 0; } - - void swap(hashtable& __ht) - { - std::swap(_M_hash, __ht._M_hash); - std::swap(_M_equals, __ht._M_equals); - std::swap(_M_get_key, __ht._M_get_key); - _M_buckets.swap(__ht._M_buckets); - std::swap(_M_num_elements, __ht._M_num_elements); - } - - iterator begin() - { - for (size_type __n = 0; __n < _M_buckets.size(); ++__n) - if (_M_buckets[__n]) - return iterator(_M_buckets[__n], this); - return end(); - } - - iterator end() { return iterator(nullptr, this); } - - const_iterator begin() const - { - for (size_type __n = 0; __n < _M_buckets.size(); ++__n) - if (_M_buckets[__n]) - return const_iterator(_M_buckets[__n], this); - return end(); - } - - const_iterator end() const { return const_iterator(nullptr, this); } - - friend bool operator==<>(const hashtable&, const hashtable&); - -public: - size_type bucket_count() const { return _M_buckets.size(); } - - size_type max_bucket_count() const - { - return get_stl_prime_list()[(int)_stl_num_primes - 1]; - } - - size_type elems_in_bucket(size_type __bucket) const - { - size_type __result = 0; - for (_Node* __cur = _M_buckets[__bucket]; __cur; __cur = __cur->_M_next) - __result += 1; - return __result; - } - - std::pair insert_unique(const value_type& __obj) - { - resize(_M_num_elements + 1); - return insert_unique_noresize(__obj); - } - - iterator insert_equal(const value_type& __obj) - { - resize(_M_num_elements + 1); - return insert_equal_noresize(__obj); - } - - std::pair insert_unique_noresize(const value_type& __obj); - iterator insert_equal_noresize(const value_type& __obj); - - template - void insert_unique(_InputIterator __f, _InputIterator __l) - { - insert_unique( - __f, __l, - typename std::iterator_traits<_InputIterator>::iterator_category()); - } - - template - void insert_equal(_InputIterator __f, _InputIterator __l) - { - insert_equal( - __f, __l, - typename std::iterator_traits<_InputIterator>::iterator_category()); - } - - template - void insert_unique(_InputIterator __f, _InputIterator __l, - std::input_iterator_tag) - { - for (; __f != __l; ++__f) - insert_unique(*__f); - } - - template - void insert_equal(_InputIterator __f, _InputIterator __l, - std::input_iterator_tag) - { - for (; __f != __l; ++__f) - insert_equal(*__f); - } - - template - void insert_unique(_ForwardIterator __f, _ForwardIterator __l, - std::forward_iterator_tag) - { - size_type __n = 0; - std::distance(__f, __l, __n); - resize(_M_num_elements + __n); - for (; __n > 0; --__n, ++__f) - insert_unique_noresize(*__f); - } - - template - void insert_equal(_ForwardIterator __f, _ForwardIterator __l, - std::forward_iterator_tag) - { - size_type __n = 0; - std::distance(__f, __l, __n); - resize(_M_num_elements + __n); - for (; __n > 0; --__n, ++__f) - insert_equal_noresize(*__f); - } - - reference find_or_insert(const value_type& __obj); - - iterator find(const key_type& __key) - { - size_type __n = _M_bkt_num_key(__key); - _Node* __first; - for (__first = _M_buckets[__n]; - __first && !_M_equals(_M_get_key(__first->_M_val), __key); - __first = __first->_M_next) { - } - return iterator(__first, this); - } - - const_iterator find(const key_type& __key) const - { - size_type __n = _M_bkt_num_key(__key); - const _Node* __first; - for (__first = _M_buckets[__n]; - __first && !_M_equals(_M_get_key(__first->_M_val), __key); - __first = __first->_M_next) { - } - return const_iterator(__first, this); - } - - size_type count(const key_type& __key) const - { - const size_type __n = _M_bkt_num_key(__key); - size_type __result = 0; - - for (const _Node* __cur = _M_buckets[__n]; __cur; __cur = __cur->_M_next) - if (_M_equals(_M_get_key(__cur->_M_val), __key)) - ++__result; - return __result; - } - - std::pair equal_range(const key_type& __key); - - std::pair equal_range( - const key_type& __key) const; - - size_type erase(const key_type& __key); - void erase(const iterator& __it); - void erase(iterator __first, iterator __last); - - void erase(const const_iterator& __it); - void erase(const_iterator __first, const_iterator __last); - - void resize(size_type __num_elements_hint); - void clear(); - -private: - size_type _M_next_size(size_type __n) const { return _stl_next_prime(__n); } - - void _M_initialize_buckets(size_type __n) - { - const size_type __n_buckets = _M_next_size(__n); - _M_buckets.reserve(__n_buckets); - _M_buckets.insert(_M_buckets.end(), __n_buckets, (_Node*)nullptr); - _M_num_elements = 0; - } - - size_type _M_bkt_num_key(const key_type& __key) const - { - return _M_bkt_num_key(__key, _M_buckets.size()); - } - - size_type _M_bkt_num(const value_type& __obj) const - { - return _M_bkt_num_key(_M_get_key(__obj)); - } - - size_type _M_bkt_num_key(const key_type& __key, size_t __n) const - { - return _M_hash(__key) % __n; - } - - size_type _M_bkt_num(const value_type& __obj, size_t __n) const - { - return _M_bkt_num_key(_M_get_key(__obj), __n); - } - - void construct(_Val* p, const _Val& v) { new (p) _Val(v); } - void destroy(_Val* p) - { - (void)p; - p->~_Val(); - } - - _Node* _M_new_node(const value_type& __obj) - { - _Node* __n = _M_get_node(); - __n->_M_next = nullptr; - try { - construct(&__n->_M_val, __obj); - return __n; - } catch (...) { - _M_put_node(__n); - throw; - } - } - - void _M_delete_node(_Node* __n) - { - destroy(&__n->_M_val); - _M_put_node(__n); - } - - void _M_erase_bucket(const size_type __n, _Node* __first, _Node* __last); - void _M_erase_bucket(const size_type __n, _Node* __last); - - void _M_copy_from(const hashtable& __ht); -}; - -template -_Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>& -_Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>::operator++() -{ - const _Node* __old = _M_cur; - _M_cur = _M_cur->_M_next; - if (!_M_cur) { - size_type __bucket = _M_ht->_M_bkt_num(__old->_M_val); - while (!_M_cur && ++__bucket < _M_ht->_M_buckets.size()) - _M_cur = _M_ht->_M_buckets[__bucket]; - } - return *this; -} - -template -inline _Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All> -_Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>::operator++(int) -{ - iterator __tmp = *this; - ++*this; - return __tmp; -} - -template -_Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>& -_Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>::operator++() -{ - const _Node* __old = _M_cur; - _M_cur = _M_cur->_M_next; - if (!_M_cur) { - size_type __bucket = _M_ht->_M_bkt_num(__old->_M_val); - while (!_M_cur && ++__bucket < _M_ht->_M_buckets.size()) - _M_cur = _M_ht->_M_buckets[__bucket]; - } - return *this; -} - -template -inline _Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All> -_Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>::operator++(int) -{ - const_iterator __tmp = *this; - ++*this; - return __tmp; -} - -template -bool operator==(const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht1, - const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht2) -{ - typedef typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::_Node _Node; - if (__ht1._M_buckets.size() != __ht2._M_buckets.size()) - return false; - for (int __n = 0; __n < __ht1._M_buckets.size(); ++__n) { - _Node* __cur1 = __ht1._M_buckets[__n]; - _Node* __cur2 = __ht2._M_buckets[__n]; - for (; __cur1 && __cur2 && __cur1->_M_val == __cur2->_M_val; - __cur1 = __cur1->_M_next, __cur2 = __cur2->_M_next) { - } - if (__cur1 || __cur2) - return false; - } - return true; -} - -template -inline bool operator!=(const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht1, - const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht2) -{ - return !(__ht1 == __ht2); -} - -template -inline void swap(hashtable<_Val, _Key, _HF, _Extract, _EqKey, _All>& __ht1, - hashtable<_Val, _Key, _HF, _Extract, _EqKey, _All>& __ht2) -{ - __ht1.swap(__ht2); -} - -template -std::pair::iterator, bool> -hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::insert_unique_noresize( - const value_type& __obj) -{ - const size_type __n = _M_bkt_num(__obj); - _Node* __first = _M_buckets[__n]; - - for (_Node* __cur = __first; __cur; __cur = __cur->_M_next) - if (_M_equals(_M_get_key(__cur->_M_val), _M_get_key(__obj))) - return std::pair(iterator(__cur, this), false); - - _Node* __tmp = _M_new_node(__obj); - __tmp->_M_next = __first; - _M_buckets[__n] = __tmp; - ++_M_num_elements; - return std::pair(iterator(__tmp, this), true); -} - -template -typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::iterator -hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::insert_equal_noresize( - const value_type& __obj) -{ - const size_type __n = _M_bkt_num(__obj); - _Node* __first = _M_buckets[__n]; - - for (_Node* __cur = __first; __cur; __cur = __cur->_M_next) - if (_M_equals(_M_get_key(__cur->_M_val), _M_get_key(__obj))) { - _Node* __tmp = _M_new_node(__obj); - __tmp->_M_next = __cur->_M_next; - __cur->_M_next = __tmp; - ++_M_num_elements; - return iterator(__tmp, this); - } - - _Node* __tmp = _M_new_node(__obj); - __tmp->_M_next = __first; - _M_buckets[__n] = __tmp; - ++_M_num_elements; - return iterator(__tmp, this); -} - -template -typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::reference -hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::find_or_insert( - const value_type& __obj) -{ - resize(_M_num_elements + 1); - - size_type __n = _M_bkt_num(__obj); - _Node* __first = _M_buckets[__n]; - - for (_Node* __cur = __first; __cur; __cur = __cur->_M_next) - if (_M_equals(_M_get_key(__cur->_M_val), _M_get_key(__obj))) - return __cur->_M_val; - - _Node* __tmp = _M_new_node(__obj); - __tmp->_M_next = __first; - _M_buckets[__n] = __tmp; - ++_M_num_elements; - return __tmp->_M_val; -} - -template -std::pair::iterator, - typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::iterator> -hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::equal_range(const key_type& __key) -{ - typedef std::pair _Pii; - const size_type __n = _M_bkt_num_key(__key); - - for (_Node* __first = _M_buckets[__n]; __first; __first = __first->_M_next) - if (_M_equals(_M_get_key(__first->_M_val), __key)) { - for (_Node* __cur = __first->_M_next; __cur; __cur = __cur->_M_next) - if (!_M_equals(_M_get_key(__cur->_M_val), __key)) - return _Pii(iterator(__first, this), iterator(__cur, this)); - for (size_type __m = __n + 1; __m < _M_buckets.size(); ++__m) - if (_M_buckets[__m]) - return _Pii(iterator(__first, this), - iterator(_M_buckets[__m], this)); - return _Pii(iterator(__first, this), end()); - } - return _Pii(end(), end()); -} - -template -std::pair::const_iterator, - typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::const_iterator> -hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::equal_range( - const key_type& __key) const -{ - typedef std::pair _Pii; - const size_type __n = _M_bkt_num_key(__key); - - for (const _Node* __first = _M_buckets[__n]; __first; - __first = __first->_M_next) { - if (_M_equals(_M_get_key(__first->_M_val), __key)) { - for (const _Node* __cur = __first->_M_next; __cur; - __cur = __cur->_M_next) - if (!_M_equals(_M_get_key(__cur->_M_val), __key)) - return _Pii(const_iterator(__first, this), - const_iterator(__cur, this)); - for (size_type __m = __n + 1; __m < _M_buckets.size(); ++__m) - if (_M_buckets[__m]) - return _Pii(const_iterator(__first, this), - const_iterator(_M_buckets[__m], this)); - return _Pii(const_iterator(__first, this), end()); - } - } - return _Pii(end(), end()); -} - -template -typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::size_type -hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::erase(const key_type& __key) -{ - const size_type __n = _M_bkt_num_key(__key); - _Node* __first = _M_buckets[__n]; - size_type __erased = 0; - - if (__first) { - _Node* __cur = __first; - _Node* __next = __cur->_M_next; - while (__next) { - if (_M_equals(_M_get_key(__next->_M_val), __key)) { - __cur->_M_next = __next->_M_next; - _M_delete_node(__next); - __next = __cur->_M_next; - ++__erased; - --_M_num_elements; - } else { - __cur = __next; - __next = __cur->_M_next; - } - } - if (_M_equals(_M_get_key(__first->_M_val), __key)) { - _M_buckets[__n] = __first->_M_next; - _M_delete_node(__first); - ++__erased; - --_M_num_elements; - } - } - return __erased; -} - -template -void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::erase(const iterator& __it) -{ - _Node* __p = __it._M_cur; - if (__p) { - const size_type __n = _M_bkt_num(__p->_M_val); - _Node* __cur = _M_buckets[__n]; - - if (__cur == __p) { - _M_buckets[__n] = __cur->_M_next; - _M_delete_node(__cur); - --_M_num_elements; - } else { - _Node* __next = __cur->_M_next; - while (__next) { - if (__next == __p) { - __cur->_M_next = __next->_M_next; - _M_delete_node(__next); - --_M_num_elements; - break; - } else { - __cur = __next; - __next = __cur->_M_next; - } - } - } - } -} - -template -void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::erase(iterator __first, - iterator __last) -{ - size_type __f_bucket = - __first._M_cur ? _M_bkt_num(__first._M_cur->_M_val) : _M_buckets.size(); - size_type __l_bucket = - __last._M_cur ? _M_bkt_num(__last._M_cur->_M_val) : _M_buckets.size(); - - if (__first._M_cur == __last._M_cur) - return; - else if (__f_bucket == __l_bucket) - _M_erase_bucket(__f_bucket, __first._M_cur, __last._M_cur); - else { - _M_erase_bucket(__f_bucket, __first._M_cur, nullptr); - for (size_type __n = __f_bucket + 1; __n < __l_bucket; ++__n) - _M_erase_bucket(__n, nullptr); - if (__l_bucket != _M_buckets.size()) - _M_erase_bucket(__l_bucket, __last._M_cur); - } -} - -template -inline void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::erase( - const_iterator __first, const_iterator __last) -{ - erase(iterator(const_cast<_Node*>(__first._M_cur), - const_cast(__first._M_ht)), - iterator(const_cast<_Node*>(__last._M_cur), - const_cast(__last._M_ht))); -} - -template -inline void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::erase( - const const_iterator& __it) -{ - erase(iterator(const_cast<_Node*>(__it._M_cur), - const_cast(__it._M_ht))); -} - -template -void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::resize( - size_type __num_elements_hint) -{ - const size_type __old_n = _M_buckets.size(); - if (__num_elements_hint > __old_n) { - const size_type __n = _M_next_size(__num_elements_hint); - if (__n > __old_n) { - _M_buckets_type __tmp(__n, (_Node*)(nullptr), - _M_buckets.get_allocator()); - try { - for (size_type __bucket = 0; __bucket < __old_n; ++__bucket) { - _Node* __first = _M_buckets[__bucket]; - while (__first) { - size_type __new_bucket = _M_bkt_num(__first->_M_val, __n); - _M_buckets[__bucket] = __first->_M_next; - __first->_M_next = __tmp[__new_bucket]; - __tmp[__new_bucket] = __first; - __first = _M_buckets[__bucket]; - } - } - _M_buckets.swap(__tmp); - } catch (...) { - for (size_type __bucket = 0; __bucket < __tmp.size(); ++__bucket) { - while (__tmp[__bucket]) { - _Node* __next = __tmp[__bucket]->_M_next; - _M_delete_node(__tmp[__bucket]); - __tmp[__bucket] = __next; - } - } - throw; - } - } - } -} - -template -void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::_M_erase_bucket( - const size_type __n, _Node* __first, _Node* __last) -{ - _Node* __cur = _M_buckets[__n]; - if (__cur == __first) - _M_erase_bucket(__n, __last); - else { - _Node* __next; - for (__next = __cur->_M_next; __next != __first; - __cur = __next, __next = __cur->_M_next) - ; - while (__next != __last) { - __cur->_M_next = __next->_M_next; - _M_delete_node(__next); - __next = __cur->_M_next; - --_M_num_elements; - } - } -} - -template -void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::_M_erase_bucket( - const size_type __n, _Node* __last) -{ - _Node* __cur = _M_buckets[__n]; - while (__cur != __last) { - _Node* __next = __cur->_M_next; - _M_delete_node(__cur); - __cur = __next; - _M_buckets[__n] = __cur; - --_M_num_elements; - } -} - -template -void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::clear() -{ - for (size_type __i = 0; __i < _M_buckets.size(); ++__i) { - _Node* __cur = _M_buckets[__i]; - while (__cur != nullptr) { - _Node* __next = __cur->_M_next; - _M_delete_node(__cur); - __cur = __next; - } - _M_buckets[__i] = nullptr; - } - _M_num_elements = 0; -} - -template -void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::_M_copy_from( - const hashtable& __ht) -{ - _M_buckets.clear(); - _M_buckets.reserve(__ht._M_buckets.size()); - _M_buckets.insert(_M_buckets.end(), __ht._M_buckets.size(), (_Node*)nullptr); - try { - for (size_type __i = 0; __i < __ht._M_buckets.size(); ++__i) { - const _Node* __cur = __ht._M_buckets[__i]; - if (__cur) { - _Node* __copy = _M_new_node(__cur->_M_val); - _M_buckets[__i] = __copy; - - for (_Node* __next = __cur->_M_next; __next; - __cur = __next, __next = __cur->_M_next) { - __copy->_M_next = _M_new_node(__next->_M_val); - __copy = __copy->_M_next; - } - } - } - _M_num_elements = __ht._M_num_elements; - } catch (...) { - clear(); - throw; - } -} - -} // namespace @KWSYS_NAMESPACE@ - -// Undo warning suppression. -# if defined(__clang__) && defined(__has_warning) -# if __has_warning("-Wdeprecated") -# pragma clang diagnostic pop -# endif -# endif - -# if defined(_MSC_VER) -# pragma warning(pop) -# endif - -#endif diff --git a/test/API/driver/kwsys/kwsysHeaderDump.pl b/test/API/driver/kwsys/kwsysHeaderDump.pl deleted file mode 100644 index e3391e7..0000000 --- a/test/API/driver/kwsys/kwsysHeaderDump.pl +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/perl -# Distributed under the OSI-approved BSD 3-Clause License. See accompanying -# file Copyright.txt or https://cmake.org/licensing#kwsys for details. - -if ( $#ARGV+1 < 2 ) -{ - print "Usage: ./kwsysHeaderDump.pl
\n"; - exit(1); -} - -$name = $ARGV[0]; -$max = 0; -open(INFILE, $ARGV[1]); -while (chomp ($line = )) -{ - if (($line !~ /^\#/) && - ($line =~ s/.*kwsys${name}_([A-Za-z0-9_]*).*/\1/) && - ($i{$line}++ < 1)) - { - push(@lines, "$line"); - if (length($line) > $max) - { - $max = length($line); - } - } -} -close(INFILE); - -$width = $max + 13; -print sprintf("#define %-${width}s kwsys_ns(${name})\n", "kwsys${name}"); -foreach $l (@lines) -{ - print sprintf("#define %-${width}s kwsys_ns(${name}_$l)\n", - "kwsys${name}_$l"); -} -print "\n"; -print sprintf("# undef kwsys${name}\n"); -foreach $l (@lines) -{ - print sprintf("# undef kwsys${name}_$l\n"); -} diff --git a/test/API/driver/kwsys/kwsysPlatformTests.cmake b/test/API/driver/kwsys/kwsysPlatformTests.cmake deleted file mode 100644 index 28d3f68..0000000 --- a/test/API/driver/kwsys/kwsysPlatformTests.cmake +++ /dev/null @@ -1,216 +0,0 @@ -# Distributed under the OSI-approved BSD 3-Clause License. See accompanying -# file Copyright.txt or https://cmake.org/licensing#kwsys for details. - -SET(KWSYS_PLATFORM_TEST_FILE_C kwsysPlatformTestsC.c) -SET(KWSYS_PLATFORM_TEST_FILE_CXX kwsysPlatformTestsCXX.cxx) - -MACRO(KWSYS_PLATFORM_TEST lang var description invert) - IF(NOT DEFINED ${var}_COMPILED) - MESSAGE(STATUS "${description}") - set(maybe_cxx_standard "") - if(CMAKE_VERSION VERSION_LESS 3.8 AND CMAKE_CXX_STANDARD) - set(maybe_cxx_standard "-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}") - endif() - TRY_COMPILE(${var}_COMPILED - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/${KWSYS_PLATFORM_TEST_FILE_${lang}} - COMPILE_DEFINITIONS -DTEST_${var} ${KWSYS_PLATFORM_TEST_DEFINES} ${KWSYS_PLATFORM_TEST_EXTRA_FLAGS} - CMAKE_FLAGS "-DLINK_LIBRARIES:STRING=${KWSYS_PLATFORM_TEST_LINK_LIBRARIES}" - ${maybe_cxx_standard} - OUTPUT_VARIABLE OUTPUT) - IF(${var}_COMPILED) - FILE(APPEND - ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log - "${description} compiled with the following output:\n${OUTPUT}\n\n") - ELSE() - FILE(APPEND - ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log - "${description} failed to compile with the following output:\n${OUTPUT}\n\n") - ENDIF() - IF(${invert} MATCHES INVERT) - IF(${var}_COMPILED) - MESSAGE(STATUS "${description} - no") - ELSE() - MESSAGE(STATUS "${description} - yes") - ENDIF() - ELSE() - IF(${var}_COMPILED) - MESSAGE(STATUS "${description} - yes") - ELSE() - MESSAGE(STATUS "${description} - no") - ENDIF() - ENDIF() - ENDIF() - IF(${invert} MATCHES INVERT) - IF(${var}_COMPILED) - SET(${var} 0) - ELSE() - SET(${var} 1) - ENDIF() - ELSE() - IF(${var}_COMPILED) - SET(${var} 1) - ELSE() - SET(${var} 0) - ENDIF() - ENDIF() -ENDMACRO() - -MACRO(KWSYS_PLATFORM_TEST_RUN lang var description invert) - IF(NOT DEFINED ${var}) - MESSAGE(STATUS "${description}") - TRY_RUN(${var} ${var}_COMPILED - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/${KWSYS_PLATFORM_TEST_FILE_${lang}} - COMPILE_DEFINITIONS -DTEST_${var} ${KWSYS_PLATFORM_TEST_DEFINES} ${KWSYS_PLATFORM_TEST_EXTRA_FLAGS} - OUTPUT_VARIABLE OUTPUT) - - # Note that ${var} will be a 0 return value on success. - IF(${var}_COMPILED) - IF(${var}) - FILE(APPEND - ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log - "${description} compiled but failed to run with the following output:\n${OUTPUT}\n\n") - ELSE() - FILE(APPEND - ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log - "${description} compiled and ran with the following output:\n${OUTPUT}\n\n") - ENDIF() - ELSE() - FILE(APPEND - ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log - "${description} failed to compile with the following output:\n${OUTPUT}\n\n") - SET(${var} -1 CACHE INTERNAL "${description} failed to compile.") - ENDIF() - - IF(${invert} MATCHES INVERT) - IF(${var}_COMPILED) - IF(${var}) - MESSAGE(STATUS "${description} - yes") - ELSE() - MESSAGE(STATUS "${description} - no") - ENDIF() - ELSE() - MESSAGE(STATUS "${description} - failed to compile") - ENDIF() - ELSE() - IF(${var}_COMPILED) - IF(${var}) - MESSAGE(STATUS "${description} - no") - ELSE() - MESSAGE(STATUS "${description} - yes") - ENDIF() - ELSE() - MESSAGE(STATUS "${description} - failed to compile") - ENDIF() - ENDIF() - ENDIF() - - IF(${invert} MATCHES INVERT) - IF(${var}_COMPILED) - IF(${var}) - SET(${var} 1) - ELSE() - SET(${var} 0) - ENDIF() - ELSE() - SET(${var} 1) - ENDIF() - ELSE() - IF(${var}_COMPILED) - IF(${var}) - SET(${var} 0) - ELSE() - SET(${var} 1) - ENDIF() - ELSE() - SET(${var} 0) - ENDIF() - ENDIF() -ENDMACRO() - -MACRO(KWSYS_PLATFORM_C_TEST var description invert) - SET(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_C_TEST_DEFINES}) - SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_C_TEST_EXTRA_FLAGS}) - KWSYS_PLATFORM_TEST(C "${var}" "${description}" "${invert}") - SET(KWSYS_PLATFORM_TEST_DEFINES) - SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS) -ENDMACRO() - -MACRO(KWSYS_PLATFORM_C_TEST_RUN var description invert) - SET(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_C_TEST_DEFINES}) - SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_C_TEST_EXTRA_FLAGS}) - KWSYS_PLATFORM_TEST_RUN(C "${var}" "${description}" "${invert}") - SET(KWSYS_PLATFORM_TEST_DEFINES) - SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS) -ENDMACRO() - -MACRO(KWSYS_PLATFORM_CXX_TEST var description invert) - SET(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_CXX_TEST_DEFINES}) - SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_CXX_TEST_EXTRA_FLAGS}) - SET(KWSYS_PLATFORM_TEST_LINK_LIBRARIES ${KWSYS_PLATFORM_CXX_TEST_LINK_LIBRARIES}) - KWSYS_PLATFORM_TEST(CXX "${var}" "${description}" "${invert}") - SET(KWSYS_PLATFORM_TEST_DEFINES) - SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS) - SET(KWSYS_PLATFORM_TEST_LINK_LIBRARIES) -ENDMACRO() - -MACRO(KWSYS_PLATFORM_CXX_TEST_RUN var description invert) - SET(KWSYS_PLATFORM_TEST_DEFINES ${KWSYS_PLATFORM_CXX_TEST_DEFINES}) - SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS ${KWSYS_PLATFORM_CXX_TEST_EXTRA_FLAGS}) - KWSYS_PLATFORM_TEST_RUN(CXX "${var}" "${description}" "${invert}") - SET(KWSYS_PLATFORM_TEST_DEFINES) - SET(KWSYS_PLATFORM_TEST_EXTRA_FLAGS) -ENDMACRO() - -#----------------------------------------------------------------------------- -# KWSYS_PLATFORM_INFO_TEST(lang var description) -# -# Compile test named by ${var} and store INFO strings extracted from binary. -MACRO(KWSYS_PLATFORM_INFO_TEST lang var description) - # We can implement this macro on CMake 2.6 and above. - IF("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.6) - SET(${var} "") - ELSE() - # Choose a location for the result binary. - SET(KWSYS_PLATFORM_INFO_FILE - ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/${var}.bin) - - # Compile the test binary. - IF(NOT EXISTS ${KWSYS_PLATFORM_INFO_FILE}) - MESSAGE(STATUS "${description}") - TRY_COMPILE(${var}_COMPILED - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/${KWSYS_PLATFORM_TEST_FILE_${lang}} - COMPILE_DEFINITIONS -DTEST_${var} - ${KWSYS_PLATFORM_${lang}_TEST_DEFINES} - ${KWSYS_PLATFORM_${lang}_TEST_EXTRA_FLAGS} - OUTPUT_VARIABLE OUTPUT - COPY_FILE ${KWSYS_PLATFORM_INFO_FILE} - ) - IF(${var}_COMPILED) - FILE(APPEND - ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log - "${description} compiled with the following output:\n${OUTPUT}\n\n") - ELSE() - FILE(APPEND - ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log - "${description} failed to compile with the following output:\n${OUTPUT}\n\n") - ENDIF() - IF(${var}_COMPILED) - MESSAGE(STATUS "${description} - compiled") - ELSE() - MESSAGE(STATUS "${description} - failed") - ENDIF() - ENDIF() - - # Parse info strings out of the compiled binary. - IF(${var}_COMPILED) - FILE(STRINGS ${KWSYS_PLATFORM_INFO_FILE} ${var} REGEX "INFO:[A-Za-z0-9]+\\[[^]]*\\]") - ELSE() - SET(${var} "") - ENDIF() - - SET(KWSYS_PLATFORM_INFO_FILE) - ENDIF() -ENDMACRO() diff --git a/test/API/driver/kwsys/kwsysPlatformTestsC.c b/test/API/driver/kwsys/kwsysPlatformTestsC.c deleted file mode 100644 index b0cf7ad..0000000 --- a/test/API/driver/kwsys/kwsysPlatformTestsC.c +++ /dev/null @@ -1,108 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -/* - Macros to define main() in a cross-platform way. - - Usage: - - int KWSYS_PLATFORM_TEST_C_MAIN() - { - return 0; - } - - int KWSYS_PLATFORM_TEST_C_MAIN_ARGS(argc, argv) - { - (void)argc; (void)argv; - return 0; - } -*/ -#if defined(__CLASSIC_C__) -# define KWSYS_PLATFORM_TEST_C_MAIN() main() -# define KWSYS_PLATFORM_TEST_C_MAIN_ARGS(argc, argv) \ - main(argc, argv) int argc; \ - char* argv[]; -#else -# define KWSYS_PLATFORM_TEST_C_MAIN() main(void) -# define KWSYS_PLATFORM_TEST_C_MAIN_ARGS(argc, argv) \ - main(int argc, char* argv[]) -#endif - -#ifdef TEST_KWSYS_C_HAS_PTRDIFF_T -# include -int f(ptrdiff_t n) -{ - return n > 0; -} -int KWSYS_PLATFORM_TEST_C_MAIN() -{ - char* p = 0; - ptrdiff_t d = p - p; - (void)d; - return f(p - p); -} -#endif - -#ifdef TEST_KWSYS_C_HAS_SSIZE_T -# include -int f(ssize_t n) -{ - return (int)n; -} -int KWSYS_PLATFORM_TEST_C_MAIN() -{ - ssize_t n = 0; - return f(n); -} -#endif - -#ifdef TEST_KWSYS_C_HAS_CLOCK_GETTIME_MONOTONIC -# if defined(__APPLE__) -# include -# if MAC_OS_X_VERSION_MIN_REQUIRED < 101200 -# error "clock_gettime not available on macOS < 10.12" -# endif -# endif -# include -int KWSYS_PLATFORM_TEST_C_MAIN() -{ - struct timespec ts; - return clock_gettime(CLOCK_MONOTONIC, &ts); -} -#endif - -#ifdef TEST_KWSYS_C_TYPE_MACROS -char* info_macros = -# if defined(__SIZEOF_SHORT__) - "INFO:macro[__SIZEOF_SHORT__]\n" -# endif -# if defined(__SIZEOF_INT__) - "INFO:macro[__SIZEOF_INT__]\n" -# endif -# if defined(__SIZEOF_LONG__) - "INFO:macro[__SIZEOF_LONG__]\n" -# endif -# if defined(__SIZEOF_LONG_LONG__) - "INFO:macro[__SIZEOF_LONG_LONG__]\n" -# endif -# if defined(__SHORT_MAX__) - "INFO:macro[__SHORT_MAX__]\n" -# endif -# if defined(__INT_MAX__) - "INFO:macro[__INT_MAX__]\n" -# endif -# if defined(__LONG_MAX__) - "INFO:macro[__LONG_MAX__]\n" -# endif -# if defined(__LONG_LONG_MAX__) - "INFO:macro[__LONG_LONG_MAX__]\n" -# endif - ""; - -int KWSYS_PLATFORM_TEST_C_MAIN_ARGS(argc, argv) -{ - int require = 0; - require += info_macros[argc]; - (void)argv; - return require; -} -#endif diff --git a/test/API/driver/kwsys/kwsysPlatformTestsCXX.cxx b/test/API/driver/kwsys/kwsysPlatformTestsCXX.cxx deleted file mode 100644 index cfd5666..0000000 --- a/test/API/driver/kwsys/kwsysPlatformTestsCXX.cxx +++ /dev/null @@ -1,335 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifdef TEST_KWSYS_CXX_HAS_CSTDIO -# include -int main() -{ - return 0; -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS_LONG_LONG -long long f(long long n) -{ - return n; -} -int main() -{ - long long n = 0; - return static_cast(f(n)); -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS___INT64 -__int64 f(__int64 n) -{ - return n; -} -int main() -{ - __int64 n = 0; - return static_cast(f(n)); -} -#endif - -#ifdef TEST_KWSYS_CXX_STAT_HAS_ST_MTIM -# include - -# include -# include -int main() -{ - struct stat stat1; - (void)stat1.st_mtim.tv_sec; - (void)stat1.st_mtim.tv_nsec; - return 0; -} -#endif - -#ifdef TEST_KWSYS_CXX_STAT_HAS_ST_MTIMESPEC -# include - -# include -# include -int main() -{ - struct stat stat1; - (void)stat1.st_mtimespec.tv_sec; - (void)stat1.st_mtimespec.tv_nsec; - return 0; -} -#endif - -#ifdef TEST_KWSYS_CXX_SAME_LONG_AND___INT64 -void function(long**) -{ -} -int main() -{ - __int64** p = 0; - function(p); - return 0; -} -#endif - -#ifdef TEST_KWSYS_CXX_SAME_LONG_LONG_AND___INT64 -void function(long long**) -{ -} -int main() -{ - __int64** p = 0; - function(p); - return 0; -} -#endif - -#ifdef TEST_KWSYS_IOS_HAS_ISTREAM_LONG_LONG -# include -int test_istream(std::istream& is, long long& x) -{ - return (is >> x) ? 1 : 0; -} -int main() -{ - long long x = 0; - return test_istream(std::cin, x); -} -#endif - -#ifdef TEST_KWSYS_IOS_HAS_OSTREAM_LONG_LONG -# include -int test_ostream(std::ostream& os, long long x) -{ - return (os << x) ? 1 : 0; -} -int main() -{ - long long x = 0; - return test_ostream(std::cout, x); -} -#endif - -#ifdef TEST_KWSYS_IOS_HAS_ISTREAM___INT64 -# include -int test_istream(std::istream& is, __int64& x) -{ - return (is >> x) ? 1 : 0; -} -int main() -{ - __int64 x = 0; - return test_istream(std::cin, x); -} -#endif - -#ifdef TEST_KWSYS_IOS_HAS_OSTREAM___INT64 -# include -int test_ostream(std::ostream& os, __int64 x) -{ - return (os << x) ? 1 : 0; -} -int main() -{ - __int64 x = 0; - return test_ostream(std::cout, x); -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS_SETENV -# include -int main() -{ - return setenv("A", "B", 1); -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS_UNSETENV -# include -int main() -{ - unsetenv("A"); - return 0; -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H -# include -int main() -{ - char* e = environ[0]; - return e ? 0 : 1; -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS_GETLOADAVG -// Match feature definitions from SystemInformation.cxx -# if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE) -# define _GNU_SOURCE -# endif -# include -int main() -{ - double loadavg[3] = { 0.0, 0.0, 0.0 }; - return getloadavg(loadavg, 3); -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS_RLIMIT64 -# include -int main() -{ - struct rlimit64 rlim; - return getrlimit64(0, &rlim); -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS_ATOLL -# include -int main() -{ - const char* str = "1024"; - return static_cast(atoll(str)); -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS_ATOL -# include -int main() -{ - const char* str = "1024"; - return static_cast(atol(str)); -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS__ATOI64 -# include -int main() -{ - const char* str = "1024"; - return static_cast(_atoi64(str)); -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS_UTIMES -# include -int main() -{ - struct timeval* current_time = 0; - return utimes("/example", current_time); -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS_UTIMENSAT -# include -# include -# if defined(__APPLE__) -# include -# if MAC_OS_X_VERSION_MIN_REQUIRED < 101300 -# error "utimensat not available on macOS < 10.13" -# endif -# endif -int main() -{ - struct timespec times[2] = { { 0, UTIME_OMIT }, { 0, UTIME_NOW } }; - return utimensat(AT_FDCWD, "/example", times, AT_SYMLINK_NOFOLLOW); -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS_BACKTRACE -# if defined(__PATHSCALE__) || defined(__PATHCC__) || \ - (defined(__LSB_VERSION__) && (__LSB_VERSION__ < 41)) -backtrace does not work with this compiler or os -# endif -# if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE) -# define _GNU_SOURCE -# endif -# include -int main() -{ - void* stackSymbols[256]; - backtrace(stackSymbols, 256); - backtrace_symbols(&stackSymbols[0], 1); - return 0; -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS_DLADDR -# if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE) -# define _GNU_SOURCE -# endif -# include -int main() -{ - Dl_info info; - int ierr = dladdr((void*)main, &info); - return 0; -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS_CXXABI -# if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE) -# define _GNU_SOURCE -# endif -# if defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5130 && __linux && \ - __SUNPRO_CC_COMPAT == 'G' -# include -# endif -# include -int main() -{ - int status = 0; - size_t bufferLen = 512; - char buffer[512] = { '\0' }; - const char* function = "_ZN5kwsys17SystemInformation15GetProgramStackEii"; - char* demangledFunction = - abi::__cxa_demangle(function, buffer, &bufferLen, &status); - return status; -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS_BORLAND_ASM -int main() -{ - int a = 1; - __asm { - xor EBX, EBX; - mov a, EBX; - } - - return a; -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS_BORLAND_ASM_CPUID -int main() -{ - int a = 0; - __asm { - xor EAX, EAX; - cpuid; - mov a, EAX; - } - - return a; -} -#endif - -#ifdef TEST_KWSYS_STL_HAS_WSTRING -# include -void f(std::wstring*) -{ -} -int main() -{ - return 0; -} -#endif - -#ifdef TEST_KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H -# include -int main() -{ - return 0; -} -#endif diff --git a/test/API/driver/kwsys/kwsysPrivate.h b/test/API/driver/kwsys/kwsysPrivate.h deleted file mode 100644 index dd9c127..0000000 --- a/test/API/driver/kwsys/kwsysPrivate.h +++ /dev/null @@ -1,34 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifndef KWSYS_NAMESPACE -# error "Do not include kwsysPrivate.h outside of kwsys c and cxx files." -#endif - -#ifndef _kwsysPrivate_h -# define _kwsysPrivate_h - -/* - Define KWSYS_HEADER macro to help the c and cxx files include kwsys - headers from the configured namespace directory. The macro can be - used like this: - - #include KWSYS_HEADER(Directory.hxx) - #include KWSYS_HEADER(std/vector) -*/ -/* clang-format off */ -#define KWSYS_HEADER(x) KWSYS_HEADER0(KWSYS_NAMESPACE/x) -/* clang-format on */ -# define KWSYS_HEADER0(x) KWSYS_HEADER1(x) -# define KWSYS_HEADER1(x) - -/* - Define KWSYS_NAMESPACE_STRING to be a string constant containing the - name configured for this instance of the kwsys library. -*/ -# define KWSYS_NAMESPACE_STRING KWSYS_NAMESPACE_STRING0(KWSYS_NAMESPACE) -# define KWSYS_NAMESPACE_STRING0(x) KWSYS_NAMESPACE_STRING1(x) -# define KWSYS_NAMESPACE_STRING1(x) # x - -#else -# error "kwsysPrivate.h included multiple times." -#endif diff --git a/test/API/driver/kwsys/testCommandLineArguments.cxx b/test/API/driver/kwsys/testCommandLineArguments.cxx deleted file mode 100644 index 1778a9b..0000000 --- a/test/API/driver/kwsys/testCommandLineArguments.cxx +++ /dev/null @@ -1,209 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include "kwsysPrivate.h" -#include KWSYS_HEADER(CommandLineArguments.hxx) - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -# include "CommandLineArguments.hxx.in" -#endif - -#include -#include - -#include /* size_t */ -#include /* strcmp */ - -static void* random_ptr = reinterpret_cast(0x123); - -static int argument(const char* arg, const char* value, void* call_data) -{ - std::cout << "Got argument: \"" << arg << "\" value: \"" - << (value ? value : "(null)") << "\"" << std::endl; - if (call_data != random_ptr) { - std::cerr << "Problem processing call_data" << std::endl; - return 0; - } - return 1; -} - -static int unknown_argument(const char* argument, void* call_data) -{ - std::cout << "Got unknown argument: \"" << argument << "\"" << std::endl; - if (call_data != random_ptr) { - std::cerr << "Problem processing call_data" << std::endl; - return 0; - } - return 1; -} - -static bool CompareTwoItemsOnList(bool i1, bool i2) -{ - return i1 == i2; -} -static bool CompareTwoItemsOnList(int i1, int i2) -{ - return i1 == i2; -} -static bool CompareTwoItemsOnList(double i1, double i2) -{ - return i1 == i2; -} -static bool CompareTwoItemsOnList(const char* i1, const char* i2) -{ - return strcmp(i1, i2) == 0; -} -static bool CompareTwoItemsOnList(const std::string& i1, const std::string& i2) -{ - return i1 == i2; -} - -int testCommandLineArguments(int argc, char* argv[]) -{ - // Example run: ./testCommandLineArguments --some-int-variable 4 - // --another-bool-variable --some-bool-variable=yes - // --some-stl-string-variable=foobar --set-bool-arg1 --set-bool-arg2 - // --some-string-variable=hello - - int res = 0; - kwsys::CommandLineArguments arg; - arg.Initialize(argc, argv); - - // For error handling - arg.SetClientData(random_ptr); - arg.SetUnknownArgumentCallback(unknown_argument); - - int some_int_variable = 10; - double some_double_variable = 10.10; - char* some_string_variable = nullptr; - std::string some_stl_string_variable; - bool some_bool_variable = false; - bool some_bool_variable1 = false; - bool bool_arg1 = false; - int bool_arg2 = 0; - - std::vector numbers_argument; - int valid_numbers[] = { 5, 1, 8, 3, 7, 1, 3, 9, 7, 1 }; - - std::vector doubles_argument; - double valid_doubles[] = { 12.5, 1.31, 22 }; - - std::vector bools_argument; - bool valid_bools[] = { true, true, false }; - - std::vector strings_argument; - const char* valid_strings[] = { "andy", "bill", "brad", "ken" }; - - std::vector stl_strings_argument; - std::string valid_stl_strings[] = { "ken", "brad", "bill", "andy" }; - - typedef kwsys::CommandLineArguments argT; - - arg.AddArgument("--some-int-variable", argT::SPACE_ARGUMENT, - &some_int_variable, "Set some random int variable"); - arg.AddArgument("--some-double-variable", argT::CONCAT_ARGUMENT, - &some_double_variable, "Set some random double variable"); - arg.AddArgument("--some-string-variable", argT::EQUAL_ARGUMENT, - &some_string_variable, "Set some random string variable"); - arg.AddArgument("--some-stl-string-variable", argT::EQUAL_ARGUMENT, - &some_stl_string_variable, - "Set some random stl string variable"); - arg.AddArgument("--some-bool-variable", argT::EQUAL_ARGUMENT, - &some_bool_variable, "Set some random bool variable"); - arg.AddArgument("--another-bool-variable", argT::NO_ARGUMENT, - &some_bool_variable1, "Set some random bool variable 1"); - arg.AddBooleanArgument("--set-bool-arg1", &bool_arg1, - "Test AddBooleanArgument 1"); - arg.AddBooleanArgument("--set-bool-arg2", &bool_arg2, - "Test AddBooleanArgument 2"); - arg.AddArgument("--some-multi-argument", argT::MULTI_ARGUMENT, - &numbers_argument, "Some multiple values variable"); - arg.AddArgument("-N", argT::SPACE_ARGUMENT, &doubles_argument, - "Some explicit multiple values variable"); - arg.AddArgument("-BB", argT::CONCAT_ARGUMENT, &bools_argument, - "Some explicit multiple values variable"); - arg.AddArgument("-SS", argT::EQUAL_ARGUMENT, &strings_argument, - "Some explicit multiple values variable"); - arg.AddArgument("-SSS", argT::MULTI_ARGUMENT, &stl_strings_argument, - "Some explicit multiple values variable"); - - arg.AddCallback("-A", argT::NO_ARGUMENT, argument, random_ptr, - "Some option -A. This option has a multiline comment. It " - "should demonstrate how the code splits lines."); - arg.AddCallback("-B", argT::SPACE_ARGUMENT, argument, random_ptr, - "Option -B takes argument with space"); - arg.AddCallback("-C", argT::EQUAL_ARGUMENT, argument, random_ptr, - "Option -C takes argument after ="); - arg.AddCallback("-D", argT::CONCAT_ARGUMENT, argument, random_ptr, - "This option takes concatenated argument"); - arg.AddCallback("--long1", argT::NO_ARGUMENT, argument, random_ptr, "-A"); - arg.AddCallback("--long2", argT::SPACE_ARGUMENT, argument, random_ptr, "-B"); - arg.AddCallback("--long3", argT::EQUAL_ARGUMENT, argument, random_ptr, - "Same as -C but a bit different"); - arg.AddCallback("--long4", argT::CONCAT_ARGUMENT, argument, random_ptr, - "-C"); - - if (!arg.Parse()) { - std::cerr << "Problem parsing arguments" << std::endl; - res = 1; - } - std::cout << "Help: " << arg.GetHelp() << std::endl; - - std::cout << "Some int variable was set to: " << some_int_variable - << std::endl; - std::cout << "Some double variable was set to: " << some_double_variable - << std::endl; - if (some_string_variable && - strcmp(some_string_variable, "test string with space") == 0) { - std::cout << "Some string variable was set to: " << some_string_variable - << std::endl; - delete[] some_string_variable; - } else { - std::cerr << "Problem setting string variable" << std::endl; - res = 1; - } - size_t cc; -#define CompareTwoLists(list1, list_valid, lsize) \ - do { \ - if (list1.size() != lsize) { \ - std::cerr << "Problem setting " #list1 ". Size is: " << list1.size() \ - << " should be: " << lsize << std::endl; \ - res = 1; \ - } else { \ - std::cout << #list1 " argument set:"; \ - for (cc = 0; cc < lsize; ++cc) { \ - std::cout << " " << list1[cc]; \ - if (!CompareTwoItemsOnList(list1[cc], list_valid[cc])) { \ - std::cerr << "Problem setting " #list1 ". Value of " << cc \ - << " is: [" << list1[cc] << "] <> [" << list_valid[cc] \ - << "]" << std::endl; \ - res = 1; \ - break; \ - } \ - } \ - std::cout << std::endl; \ - } \ - } while (0) - CompareTwoLists(numbers_argument, valid_numbers, 10); - CompareTwoLists(doubles_argument, valid_doubles, 3); - CompareTwoLists(bools_argument, valid_bools, 3); - CompareTwoLists(strings_argument, valid_strings, 4); - CompareTwoLists(stl_strings_argument, valid_stl_strings, 4); - - std::cout << "Some STL String variable was set to: " - << some_stl_string_variable << std::endl; - std::cout << "Some bool variable was set to: " << some_bool_variable - << std::endl; - std::cout << "Some bool variable was set to: " << some_bool_variable1 - << std::endl; - std::cout << "bool_arg1 variable was set to: " << bool_arg1 << std::endl; - std::cout << "bool_arg2 variable was set to: " << bool_arg2 << std::endl; - std::cout << std::endl; - - for (cc = 0; cc < strings_argument.size(); ++cc) { - delete[] strings_argument[cc]; - strings_argument[cc] = nullptr; - } - return res; -} diff --git a/test/API/driver/kwsys/testCommandLineArguments1.cxx b/test/API/driver/kwsys/testCommandLineArguments1.cxx deleted file mode 100644 index 64561b1..0000000 --- a/test/API/driver/kwsys/testCommandLineArguments1.cxx +++ /dev/null @@ -1,93 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include "kwsysPrivate.h" -#include KWSYS_HEADER(CommandLineArguments.hxx) - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -# include "CommandLineArguments.hxx.in" -#endif - -#include -#include - -#include /* assert */ -#include /* strcmp */ - -int testCommandLineArguments1(int argc, char* argv[]) -{ - kwsys::CommandLineArguments arg; - arg.Initialize(argc, argv); - - int n = 0; - char* m = nullptr; - std::string p; - int res = 0; - - typedef kwsys::CommandLineArguments argT; - arg.AddArgument("-n", argT::SPACE_ARGUMENT, &n, "Argument N"); - arg.AddArgument("-m", argT::EQUAL_ARGUMENT, &m, "Argument M"); - arg.AddBooleanArgument("-p", &p, "Argument P"); - - arg.StoreUnusedArguments(true); - - if (!arg.Parse()) { - std::cerr << "Problem parsing arguments" << std::endl; - res = 1; - } - if (n != 24) { - std::cout << "Problem setting N. Value of N: " << n << std::endl; - res = 1; - } - if (!m || strcmp(m, "test value") != 0) { - std::cout << "Problem setting M. Value of M: " << m << std::endl; - res = 1; - } - if (p != "1") { - std::cout << "Problem setting P. Value of P: " << p << std::endl; - res = 1; - } - std::cout << "Value of N: " << n << std::endl; - std::cout << "Value of M: " << m << std::endl; - std::cout << "Value of P: " << p << std::endl; - if (m) { - delete[] m; - } - - char** newArgv = nullptr; - int newArgc = 0; - arg.GetUnusedArguments(&newArgc, &newArgv); - int cc; - const char* valid_unused_args[9] = { nullptr, - "--ignored", - "--second-ignored", - "third-ignored", - "some", - "junk", - "at", - "the", - "end" }; - if (newArgc != 9) { - std::cerr << "Bad number of unused arguments: " << newArgc << std::endl; - res = 1; - } - for (cc = 0; cc < newArgc; ++cc) { - assert(newArgv[cc]); /* Quiet Clang scan-build. */ - std::cout << "Unused argument[" << cc << "] = [" << newArgv[cc] << "]" - << std::endl; - if (cc >= 9) { - std::cerr << "Too many unused arguments: " << cc << std::endl; - res = 1; - } else if (valid_unused_args[cc] && - strcmp(valid_unused_args[cc], newArgv[cc]) != 0) { - std::cerr << "Bad unused argument [" << cc << "] \"" << newArgv[cc] - << "\" should be: \"" << valid_unused_args[cc] << "\"" - << std::endl; - res = 1; - } - } - arg.DeleteRemainingArguments(newArgc, &newArgv); - - return res; -} diff --git a/test/API/driver/kwsys/testConfigure.cxx b/test/API/driver/kwsys/testConfigure.cxx deleted file mode 100644 index a3c2ed3..0000000 --- a/test/API/driver/kwsys/testConfigure.cxx +++ /dev/null @@ -1,30 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying -file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include "kwsysPrivate.h" -#include KWSYS_HEADER(Configure.hxx) - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -# include "Configure.hxx.in" -#endif - -static bool testFallthrough(int n) -{ - int r = 0; - switch (n) { - case 1: - ++r; - KWSYS_FALLTHROUGH; - default: - ++r; - } - return r == 2; -} - -int testConfigure(int, char* []) -{ - bool res = true; - res = testFallthrough(1) && res; - return res ? 0 : 1; -} diff --git a/test/API/driver/kwsys/testConsoleBuf.cxx b/test/API/driver/kwsys/testConsoleBuf.cxx deleted file mode 100644 index 4b7ddf0..0000000 --- a/test/API/driver/kwsys/testConsoleBuf.cxx +++ /dev/null @@ -1,782 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include "kwsysPrivate.h" - -// Ignore Windows version levels defined by command-line flags. This -// source needs access to all APIs available on the host in order for -// the test to run properly. The test binary is not installed anyway. -#undef _WIN32_WINNT -#undef NTDDI_VERSION - -#include KWSYS_HEADER(Encoding.hxx) - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -# include "Encoding.hxx.in" -#endif - -#if defined(_WIN32) - -# include -# include -# include -# include -# include -# include -# include - -# include "testConsoleBuf.hxx" - -# if defined(_MSC_VER) && _MSC_VER >= 1800 -# define KWSYS_WINDOWS_DEPRECATED_GetVersion -# endif -// يونيكود -static const WCHAR UnicodeInputTestString[] = - L"\u064A\u0648\u0646\u064A\u0643\u0648\u062F!"; -static UINT TestCodepage = KWSYS_ENCODING_DEFAULT_CODEPAGE; - -static const DWORD waitTimeout = 10 * 1000; -static STARTUPINFO startupInfo; -static PROCESS_INFORMATION processInfo; -static HANDLE beforeInputEvent; -static HANDLE afterOutputEvent; -static std::string encodedInputTestString; -static std::string encodedTestString; - -static void displayError(DWORD errorCode) -{ - std::cerr.setf(std::ios::hex, std::ios::basefield); - std::cerr << "Failed with error: 0x" << errorCode << "!" << std::endl; - LPWSTR message; - if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM, - nullptr, errorCode, 0, (LPWSTR)&message, 0, nullptr)) { - std::cerr << "Error message: " << kwsys::Encoding::ToNarrow(message) - << std::endl; - HeapFree(GetProcessHeap(), 0, message); - } else { - std::cerr << "FormatMessage() failed with error: 0x" << GetLastError() - << "!" << std::endl; - } - std::cerr.unsetf(std::ios::hex); -} - -std::basic_streambuf* errstream(const char* unused) -{ - static_cast(unused); - return std::cerr.rdbuf(); -} - -std::basic_streambuf* errstream(const wchar_t* unused) -{ - static_cast(unused); - return std::wcerr.rdbuf(); -} - -template -static void dumpBuffers(const T* expected, const T* received, size_t size) -{ - std::basic_ostream err(errstream(expected)); - err << "Expected output: '" << std::basic_string(expected, size) << "'" - << std::endl; - if (err.fail()) { - err.clear(); - err << "--- Error while outputting ---" << std::endl; - } - err << "Received output: '" << std::basic_string(received, size) << "'" - << std::endl; - if (err.fail()) { - err.clear(); - err << "--- Error while outputting ---" << std::endl; - } - std::cerr << "Expected output | Received output" << std::endl; - for (size_t i = 0; i < size; i++) { - std::cerr << std::setbase(16) << std::setfill('0') << " " - << "0x" << std::setw(8) << static_cast(expected[i]) - << " | " - << "0x" << std::setw(8) - << static_cast(received[i]); - if (static_cast(expected[i]) != - static_cast(received[i])) { - std::cerr << " MISMATCH!"; - } - std::cerr << std::endl; - } - std::cerr << std::endl; -} - -static bool createProcess(HANDLE hIn, HANDLE hOut, HANDLE hErr) -{ - BOOL bInheritHandles = FALSE; - DWORD dwCreationFlags = 0; - memset(&processInfo, 0, sizeof(processInfo)); - memset(&startupInfo, 0, sizeof(startupInfo)); - startupInfo.cb = sizeof(startupInfo); - startupInfo.dwFlags = STARTF_USESHOWWINDOW; - startupInfo.wShowWindow = SW_HIDE; - if (hIn || hOut || hErr) { - startupInfo.dwFlags |= STARTF_USESTDHANDLES; - startupInfo.hStdInput = hIn; - startupInfo.hStdOutput = hOut; - startupInfo.hStdError = hErr; - bInheritHandles = TRUE; - } - - WCHAR cmd[MAX_PATH]; - if (GetModuleFileNameW(nullptr, cmd, MAX_PATH) == 0) { - std::cerr << "GetModuleFileName failed!" << std::endl; - return false; - } - WCHAR* p = cmd + wcslen(cmd); - while (p > cmd && *p != L'\\') - p--; - *(p + 1) = 0; - wcscat(cmd, cmdConsoleBufChild); - wcscat(cmd, L".exe"); - - bool success = - CreateProcessW(nullptr, // No module name (use command line) - cmd, // Command line - nullptr, // Process handle not inheritable - nullptr, // Thread handle not inheritable - bInheritHandles, // Set handle inheritance - dwCreationFlags, - nullptr, // Use parent's environment block - nullptr, // Use parent's starting directory - &startupInfo, // Pointer to STARTUPINFO structure - &processInfo) != - 0; // Pointer to PROCESS_INFORMATION structure - if (!success) { - DWORD lastError = GetLastError(); - std::cerr << "CreateProcess(" << kwsys::Encoding::ToNarrow(cmd) << ")" - << std::endl; - displayError(lastError); - } - return success; -} - -static void finishProcess(bool success) -{ - if (success) { - success = - WaitForSingleObject(processInfo.hProcess, waitTimeout) == WAIT_OBJECT_0; - }; - if (!success) { - TerminateProcess(processInfo.hProcess, 1); - } - CloseHandle(processInfo.hProcess); - CloseHandle(processInfo.hThread); -} - -static bool createPipe(PHANDLE readPipe, PHANDLE writePipe) -{ - SECURITY_ATTRIBUTES securityAttributes; - securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); - securityAttributes.bInheritHandle = TRUE; - securityAttributes.lpSecurityDescriptor = nullptr; - return CreatePipe(readPipe, writePipe, &securityAttributes, 0) == 0 ? false - : true; -} - -static void finishPipe(HANDLE readPipe, HANDLE writePipe) -{ - if (readPipe != INVALID_HANDLE_VALUE) { - CloseHandle(readPipe); - } - if (writePipe != INVALID_HANDLE_VALUE) { - CloseHandle(writePipe); - } -} - -static HANDLE createFile(LPCWSTR fileName) -{ - SECURITY_ATTRIBUTES securityAttributes; - securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); - securityAttributes.bInheritHandle = TRUE; - securityAttributes.lpSecurityDescriptor = nullptr; - - HANDLE file = - CreateFileW(fileName, GENERIC_READ | GENERIC_WRITE, - 0, // do not share - &securityAttributes, - CREATE_ALWAYS, // overwrite existing - FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, - nullptr); // no template - if (file == INVALID_HANDLE_VALUE) { - DWORD lastError = GetLastError(); - std::cerr << "CreateFile(" << kwsys::Encoding::ToNarrow(fileName) << ")" - << std::endl; - displayError(lastError); - } - return file; -} - -static void finishFile(HANDLE file) -{ - if (file != INVALID_HANDLE_VALUE) { - CloseHandle(file); - } -} - -# ifndef MAPVK_VK_TO_VSC -# define MAPVK_VK_TO_VSC (0) -# endif - -static void writeInputKeyEvent(INPUT_RECORD inputBuffer[], WCHAR chr) -{ - inputBuffer[0].EventType = KEY_EVENT; - inputBuffer[0].Event.KeyEvent.bKeyDown = TRUE; - inputBuffer[0].Event.KeyEvent.wRepeatCount = 1; - SHORT keyCode = VkKeyScanW(chr); - if (keyCode == -1) { - // Character can't be entered with current keyboard layout - // Just set any, it doesn't really matter - keyCode = 'K'; - } - inputBuffer[0].Event.KeyEvent.wVirtualKeyCode = LOBYTE(keyCode); - inputBuffer[0].Event.KeyEvent.wVirtualScanCode = MapVirtualKey( - inputBuffer[0].Event.KeyEvent.wVirtualKeyCode, MAPVK_VK_TO_VSC); - inputBuffer[0].Event.KeyEvent.uChar.UnicodeChar = chr; - inputBuffer[0].Event.KeyEvent.dwControlKeyState = 0; - if ((HIBYTE(keyCode) & 1) == 1) { - inputBuffer[0].Event.KeyEvent.dwControlKeyState |= SHIFT_PRESSED; - } - if ((HIBYTE(keyCode) & 2) == 2) { - inputBuffer[0].Event.KeyEvent.dwControlKeyState |= RIGHT_CTRL_PRESSED; - } - if ((HIBYTE(keyCode) & 4) == 4) { - inputBuffer[0].Event.KeyEvent.dwControlKeyState |= RIGHT_ALT_PRESSED; - } - inputBuffer[1].EventType = inputBuffer[0].EventType; - inputBuffer[1].Event.KeyEvent.bKeyDown = FALSE; - inputBuffer[1].Event.KeyEvent.wRepeatCount = 1; - inputBuffer[1].Event.KeyEvent.wVirtualKeyCode = - inputBuffer[0].Event.KeyEvent.wVirtualKeyCode; - inputBuffer[1].Event.KeyEvent.wVirtualScanCode = - inputBuffer[0].Event.KeyEvent.wVirtualScanCode; - inputBuffer[1].Event.KeyEvent.uChar.UnicodeChar = - inputBuffer[0].Event.KeyEvent.uChar.UnicodeChar; - inputBuffer[1].Event.KeyEvent.dwControlKeyState = 0; -} - -static int testPipe() -{ - int didFail = 1; - HANDLE inPipeRead = INVALID_HANDLE_VALUE; - HANDLE inPipeWrite = INVALID_HANDLE_VALUE; - HANDLE outPipeRead = INVALID_HANDLE_VALUE; - HANDLE outPipeWrite = INVALID_HANDLE_VALUE; - HANDLE errPipeRead = INVALID_HANDLE_VALUE; - HANDLE errPipeWrite = INVALID_HANDLE_VALUE; - UINT currentCodepage = GetConsoleCP(); - char buffer[200]; - char buffer2[200]; - try { - if (!createPipe(&inPipeRead, &inPipeWrite) || - !createPipe(&outPipeRead, &outPipeWrite) || - !createPipe(&errPipeRead, &errPipeWrite)) { - throw std::runtime_error("createFile failed!"); - } - if (TestCodepage == CP_ACP) { - TestCodepage = GetACP(); - } - if (!SetConsoleCP(TestCodepage)) { - throw std::runtime_error("SetConsoleCP failed!"); - } - - DWORD bytesWritten = 0; - if (!WriteFile(inPipeWrite, encodedInputTestString.c_str(), - (DWORD)encodedInputTestString.size(), &bytesWritten, - nullptr) || - bytesWritten == 0) { - throw std::runtime_error("WriteFile failed!"); - } - - if (createProcess(inPipeRead, outPipeWrite, errPipeWrite)) { - try { - DWORD status; - if ((status = WaitForSingleObject(afterOutputEvent, waitTimeout)) != - WAIT_OBJECT_0) { - std::cerr.setf(std::ios::hex, std::ios::basefield); - std::cerr << "WaitForSingleObject returned unexpected status 0x" - << status << std::endl; - std::cerr.unsetf(std::ios::hex); - throw std::runtime_error("WaitForSingleObject failed!"); - } - DWORD bytesRead = 0; - if (!ReadFile(outPipeRead, buffer, sizeof(buffer), &bytesRead, - nullptr) || - bytesRead == 0) { - throw std::runtime_error("ReadFile#1 failed!"); - } - buffer[bytesRead] = 0; - if ((bytesRead < - encodedTestString.size() + 1 + encodedInputTestString.size() && - !ReadFile(outPipeRead, buffer + bytesRead, - sizeof(buffer) - bytesRead, &bytesRead, nullptr)) || - bytesRead == 0) { - throw std::runtime_error("ReadFile#2 failed!"); - } - if (memcmp(buffer, encodedTestString.c_str(), - encodedTestString.size()) == 0 && - memcmp(buffer + encodedTestString.size() + 1, - encodedInputTestString.c_str(), - encodedInputTestString.size()) == 0) { - bytesRead = 0; - if (!ReadFile(errPipeRead, buffer2, sizeof(buffer2), &bytesRead, - nullptr) || - bytesRead == 0) { - throw std::runtime_error("ReadFile#3 failed!"); - } - buffer2[bytesRead] = 0; - didFail = encodedTestString.compare(0, std::string::npos, buffer2, - encodedTestString.size()) == 0 - ? 0 - : 1; - } - if (didFail != 0) { - std::cerr << "Pipe's output didn't match expected output!" - << std::endl; - dumpBuffers(encodedTestString.c_str(), buffer, - encodedTestString.size()); - dumpBuffers(encodedInputTestString.c_str(), - buffer + encodedTestString.size() + 1, - encodedInputTestString.size()); - dumpBuffers(encodedTestString.c_str(), buffer2, - encodedTestString.size()); - } - } catch (const std::runtime_error& ex) { - DWORD lastError = GetLastError(); - std::cerr << "In function testPipe, line " << __LINE__ << ": " - << ex.what() << std::endl; - displayError(lastError); - } - finishProcess(didFail == 0); - } - } catch (const std::runtime_error& ex) { - DWORD lastError = GetLastError(); - std::cerr << "In function testPipe, line " << __LINE__ << ": " << ex.what() - << std::endl; - displayError(lastError); - } - finishPipe(inPipeRead, inPipeWrite); - finishPipe(outPipeRead, outPipeWrite); - finishPipe(errPipeRead, errPipeWrite); - SetConsoleCP(currentCodepage); - return didFail; -} - -static int testFile() -{ - int didFail = 1; - HANDLE inFile = INVALID_HANDLE_VALUE; - HANDLE outFile = INVALID_HANDLE_VALUE; - HANDLE errFile = INVALID_HANDLE_VALUE; - try { - if ((inFile = createFile(L"stdinFile.txt")) == INVALID_HANDLE_VALUE || - (outFile = createFile(L"stdoutFile.txt")) == INVALID_HANDLE_VALUE || - (errFile = createFile(L"stderrFile.txt")) == INVALID_HANDLE_VALUE) { - throw std::runtime_error("createFile failed!"); - } - DWORD bytesWritten = 0; - char buffer[200]; - char buffer2[200]; - - int length; - if ((length = WideCharToMultiByte(TestCodepage, 0, UnicodeInputTestString, - -1, buffer, sizeof(buffer), nullptr, - nullptr)) == 0) { - throw std::runtime_error("WideCharToMultiByte failed!"); - } - buffer[length - 1] = '\n'; - if (!WriteFile(inFile, buffer, length, &bytesWritten, nullptr) || - bytesWritten == 0) { - throw std::runtime_error("WriteFile failed!"); - } - if (SetFilePointer(inFile, 0, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { - throw std::runtime_error("SetFilePointer failed!"); - } - - if (createProcess(inFile, outFile, errFile)) { - DWORD bytesRead = 0; - try { - DWORD status; - if ((status = WaitForSingleObject(afterOutputEvent, waitTimeout)) != - WAIT_OBJECT_0) { - std::cerr.setf(std::ios::hex, std::ios::basefield); - std::cerr << "WaitForSingleObject returned unexpected status 0x" - << status << std::endl; - std::cerr.unsetf(std::ios::hex); - throw std::runtime_error("WaitForSingleObject failed!"); - } - if (SetFilePointer(outFile, 0, 0, FILE_BEGIN) == - INVALID_SET_FILE_POINTER) { - throw std::runtime_error("SetFilePointer#1 failed!"); - } - if (!ReadFile(outFile, buffer, sizeof(buffer), &bytesRead, nullptr) || - bytesRead == 0) { - throw std::runtime_error("ReadFile#1 failed!"); - } - buffer[bytesRead] = 0; - if (memcmp(buffer, encodedTestString.c_str(), - encodedTestString.size()) == 0 && - memcmp(buffer + encodedTestString.size() + 1, - encodedInputTestString.c_str(), - encodedInputTestString.size()) == 0) { - bytesRead = 0; - if (SetFilePointer(errFile, 0, 0, FILE_BEGIN) == - INVALID_SET_FILE_POINTER) { - throw std::runtime_error("SetFilePointer#2 failed!"); - } - - if (!ReadFile(errFile, buffer2, sizeof(buffer2), &bytesRead, - nullptr) || - bytesRead == 0) { - throw std::runtime_error("ReadFile#2 failed!"); - } - buffer2[bytesRead] = 0; - didFail = encodedTestString.compare(0, std::string::npos, buffer2, - encodedTestString.size()) == 0 - ? 0 - : 1; - } - if (didFail != 0) { - std::cerr << "File's output didn't match expected output!" - << std::endl; - dumpBuffers(encodedTestString.c_str(), buffer, - encodedTestString.size()); - dumpBuffers(encodedInputTestString.c_str(), - buffer + encodedTestString.size() + 1, - encodedInputTestString.size()); - dumpBuffers(encodedTestString.c_str(), buffer2, - encodedTestString.size()); - } - } catch (const std::runtime_error& ex) { - DWORD lastError = GetLastError(); - std::cerr << "In function testFile, line " << __LINE__ << ": " - << ex.what() << std::endl; - displayError(lastError); - } - finishProcess(didFail == 0); - } - } catch (const std::runtime_error& ex) { - DWORD lastError = GetLastError(); - std::cerr << "In function testFile, line " << __LINE__ << ": " << ex.what() - << std::endl; - displayError(lastError); - } - finishFile(inFile); - finishFile(outFile); - finishFile(errFile); - return didFail; -} - -# ifndef _WIN32_WINNT_VISTA -# define _WIN32_WINNT_VISTA 0x0600 -# endif - -static int testConsole() -{ - int didFail = 1; - HANDLE parentIn = GetStdHandle(STD_INPUT_HANDLE); - HANDLE parentOut = GetStdHandle(STD_OUTPUT_HANDLE); - HANDLE parentErr = GetStdHandle(STD_ERROR_HANDLE); - HANDLE hIn = parentIn; - HANDLE hOut = parentOut; - DWORD consoleMode; - bool newConsole = false; - bool forceNewConsole = false; - bool restoreConsole = false; - LPCWSTR TestFaceName = L"Lucida Console"; - const DWORD TestFontFamily = 0x00000036; - const DWORD TestFontSize = 0x000c0000; - HKEY hConsoleKey; - WCHAR FaceName[200]; - FaceName[0] = 0; - DWORD FaceNameSize = sizeof(FaceName); - DWORD FontFamily = TestFontFamily; - DWORD FontSize = TestFontSize; -# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersion -# pragma warning(push) -# ifdef __INTEL_COMPILER -# pragma warning(disable : 1478) -# elif defined __clang__ -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated-declarations" -# else -# pragma warning(disable : 4996) -# endif -# endif - const bool isVistaOrGreater = - LOBYTE(LOWORD(GetVersion())) >= HIBYTE(_WIN32_WINNT_VISTA); -# ifdef KWSYS_WINDOWS_DEPRECATED_GetVersion -# ifdef __clang__ -# pragma clang diagnostic pop -# else -# pragma warning(pop) -# endif -# endif - if (!isVistaOrGreater) { - if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Console", 0, KEY_READ | KEY_WRITE, - &hConsoleKey) == ERROR_SUCCESS) { - DWORD dwordSize = sizeof(DWORD); - if (RegQueryValueExW(hConsoleKey, L"FontFamily", nullptr, nullptr, - (LPBYTE)&FontFamily, &dwordSize) == ERROR_SUCCESS) { - if (FontFamily != TestFontFamily) { - RegQueryValueExW(hConsoleKey, L"FaceName", nullptr, nullptr, - (LPBYTE)FaceName, &FaceNameSize); - RegQueryValueExW(hConsoleKey, L"FontSize", nullptr, nullptr, - (LPBYTE)&FontSize, &dwordSize); - - RegSetValueExW(hConsoleKey, L"FontFamily", 0, REG_DWORD, - (BYTE*)&TestFontFamily, sizeof(TestFontFamily)); - RegSetValueExW(hConsoleKey, L"FaceName", 0, REG_SZ, - (BYTE*)TestFaceName, - (DWORD)((wcslen(TestFaceName) + 1) * sizeof(WCHAR))); - RegSetValueExW(hConsoleKey, L"FontSize", 0, REG_DWORD, - (BYTE*)&TestFontSize, sizeof(TestFontSize)); - - restoreConsole = true; - forceNewConsole = true; - } - } else { - std::cerr << "RegGetValueW(FontFamily) failed!" << std::endl; - } - RegCloseKey(hConsoleKey); - } else { - std::cerr << "RegOpenKeyExW(HKEY_CURRENT_USER\\Console) failed!" - << std::endl; - } - } - if (forceNewConsole || GetConsoleMode(parentOut, &consoleMode) == 0) { - // Not a real console, let's create new one. - FreeConsole(); - if (!AllocConsole()) { - std::cerr << "AllocConsole failed!" << std::endl; - return didFail; - } - SECURITY_ATTRIBUTES securityAttributes; - securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); - securityAttributes.bInheritHandle = TRUE; - securityAttributes.lpSecurityDescriptor = nullptr; - hIn = CreateFileW(L"CONIN$", GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, &securityAttributes, - OPEN_EXISTING, 0, nullptr); - if (hIn == INVALID_HANDLE_VALUE) { - DWORD lastError = GetLastError(); - std::cerr << "CreateFile(CONIN$)" << std::endl; - displayError(lastError); - } - hOut = CreateFileW(L"CONOUT$", GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, &securityAttributes, - OPEN_EXISTING, 0, nullptr); - if (hOut == INVALID_HANDLE_VALUE) { - DWORD lastError = GetLastError(); - std::cerr << "CreateFile(CONOUT$)" << std::endl; - displayError(lastError); - } - SetStdHandle(STD_INPUT_HANDLE, hIn); - SetStdHandle(STD_OUTPUT_HANDLE, hOut); - SetStdHandle(STD_ERROR_HANDLE, hOut); - newConsole = true; - } - -# if _WIN32_WINNT >= _WIN32_WINNT_VISTA - if (isVistaOrGreater) { - CONSOLE_FONT_INFOEX consoleFont; - memset(&consoleFont, 0, sizeof(consoleFont)); - consoleFont.cbSize = sizeof(consoleFont); - HMODULE kernel32 = LoadLibraryW(L"kernel32.dll"); - typedef BOOL(WINAPI * GetCurrentConsoleFontExFunc)( - HANDLE hConsoleOutput, BOOL bMaximumWindow, - PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx); - typedef BOOL(WINAPI * SetCurrentConsoleFontExFunc)( - HANDLE hConsoleOutput, BOOL bMaximumWindow, - PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx); - GetCurrentConsoleFontExFunc getConsoleFont = - (GetCurrentConsoleFontExFunc)GetProcAddress(kernel32, - "GetCurrentConsoleFontEx"); - SetCurrentConsoleFontExFunc setConsoleFont = - (SetCurrentConsoleFontExFunc)GetProcAddress(kernel32, - "SetCurrentConsoleFontEx"); - if (getConsoleFont(hOut, FALSE, &consoleFont)) { - if (consoleFont.FontFamily != TestFontFamily) { - consoleFont.FontFamily = TestFontFamily; - wcscpy(consoleFont.FaceName, TestFaceName); - if (!setConsoleFont(hOut, FALSE, &consoleFont)) { - std::cerr << "SetCurrentConsoleFontEx failed!" << std::endl; - } - } - } else { - std::cerr << "GetCurrentConsoleFontEx failed!" << std::endl; - } - } else { -# endif - if (restoreConsole && - RegOpenKeyExW(HKEY_CURRENT_USER, L"Console", 0, KEY_WRITE, - &hConsoleKey) == ERROR_SUCCESS) { - RegSetValueExW(hConsoleKey, L"FontFamily", 0, REG_DWORD, - (BYTE*)&FontFamily, sizeof(FontFamily)); - if (FaceName[0] != 0) { - RegSetValueExW(hConsoleKey, L"FaceName", 0, REG_SZ, (BYTE*)FaceName, - FaceNameSize); - } else { - RegDeleteValueW(hConsoleKey, L"FaceName"); - } - RegSetValueExW(hConsoleKey, L"FontSize", 0, REG_DWORD, (BYTE*)&FontSize, - sizeof(FontSize)); - RegCloseKey(hConsoleKey); - } -# if _WIN32_WINNT >= _WIN32_WINNT_VISTA - } -# endif - - if (createProcess(nullptr, nullptr, nullptr)) { - try { - DWORD status; - if ((status = WaitForSingleObject(beforeInputEvent, waitTimeout)) != - WAIT_OBJECT_0) { - std::cerr.setf(std::ios::hex, std::ios::basefield); - std::cerr << "WaitForSingleObject returned unexpected status 0x" - << status << std::endl; - std::cerr.unsetf(std::ios::hex); - throw std::runtime_error("WaitForSingleObject#1 failed!"); - } - INPUT_RECORD inputBuffer[(sizeof(UnicodeInputTestString) / - sizeof(UnicodeInputTestString[0])) * - 2]; - memset(&inputBuffer, 0, sizeof(inputBuffer)); - unsigned int i; - for (i = 0; i < (sizeof(UnicodeInputTestString) / - sizeof(UnicodeInputTestString[0]) - - 1); - i++) { - writeInputKeyEvent(&inputBuffer[i * 2], UnicodeInputTestString[i]); - } - writeInputKeyEvent(&inputBuffer[i * 2], VK_RETURN); - DWORD eventsWritten = 0; - // We need to wait a bit before writing to console so child process have - // started waiting for input on stdin. - Sleep(300); - if (!WriteConsoleInputW(hIn, inputBuffer, - sizeof(inputBuffer) / sizeof(inputBuffer[0]), - &eventsWritten) || - eventsWritten == 0) { - throw std::runtime_error("WriteConsoleInput failed!"); - } - if ((status = WaitForSingleObject(afterOutputEvent, waitTimeout)) != - WAIT_OBJECT_0) { - std::cerr.setf(std::ios::hex, std::ios::basefield); - std::cerr << "WaitForSingleObject returned unexpected status 0x" - << status << std::endl; - std::cerr.unsetf(std::ios::hex); - throw std::runtime_error("WaitForSingleObject#2 failed!"); - } - CONSOLE_SCREEN_BUFFER_INFO screenBufferInfo; - if (!GetConsoleScreenBufferInfo(hOut, &screenBufferInfo)) { - throw std::runtime_error("GetConsoleScreenBufferInfo failed!"); - } - - COORD coord; - DWORD charsRead = 0; - coord.X = 0; - coord.Y = screenBufferInfo.dwCursorPosition.Y - 4; - WCHAR* outputBuffer = new WCHAR[screenBufferInfo.dwSize.X * 4]; - if (!ReadConsoleOutputCharacterW(hOut, outputBuffer, - screenBufferInfo.dwSize.X * 4, coord, - &charsRead) || - charsRead == 0) { - delete[] outputBuffer; - throw std::runtime_error("ReadConsoleOutputCharacter failed!"); - } - std::wstring wideTestString = kwsys::Encoding::ToWide(encodedTestString); - std::replace(wideTestString.begin(), wideTestString.end(), '\0', ' '); - std::wstring wideInputTestString = - kwsys::Encoding::ToWide(encodedInputTestString); - if (memcmp(outputBuffer, wideTestString.c_str(), - wideTestString.size() * sizeof(wchar_t)) == 0 && - memcmp(outputBuffer + screenBufferInfo.dwSize.X * 1, - wideTestString.c_str(), - wideTestString.size() * sizeof(wchar_t)) == 0 && - memcmp(outputBuffer + screenBufferInfo.dwSize.X * 2, - UnicodeInputTestString, - sizeof(UnicodeInputTestString) - sizeof(WCHAR)) == 0 && - memcmp(outputBuffer + screenBufferInfo.dwSize.X * 3, - wideInputTestString.c_str(), - (wideInputTestString.size() - 1) * sizeof(wchar_t)) == 0) { - didFail = 0; - } else { - std::cerr << "Console's output didn't match expected output!" - << std::endl; - dumpBuffers(wideTestString.c_str(), outputBuffer, - wideTestString.size()); - dumpBuffers(wideTestString.c_str(), - outputBuffer + screenBufferInfo.dwSize.X * 1, - wideTestString.size()); - dumpBuffers( - UnicodeInputTestString, outputBuffer + screenBufferInfo.dwSize.X * 2, - (sizeof(UnicodeInputTestString) - 1) / sizeof(WCHAR)); - dumpBuffers(wideInputTestString.c_str(), - outputBuffer + screenBufferInfo.dwSize.X * 3, - wideInputTestString.size() - 1); - } - delete[] outputBuffer; - } catch (const std::runtime_error& ex) { - DWORD lastError = GetLastError(); - std::cerr << "In function testConsole, line " << __LINE__ << ": " - << ex.what() << std::endl; - displayError(lastError); - } - finishProcess(didFail == 0); - } - if (newConsole) { - SetStdHandle(STD_INPUT_HANDLE, parentIn); - SetStdHandle(STD_OUTPUT_HANDLE, parentOut); - SetStdHandle(STD_ERROR_HANDLE, parentErr); - CloseHandle(hIn); - CloseHandle(hOut); - FreeConsole(); - } - return didFail; -} - -#endif - -int testConsoleBuf(int, char* []) -{ - int ret = 0; - -#if defined(_WIN32) - beforeInputEvent = CreateEventW(nullptr, - FALSE, // auto-reset event - FALSE, // initial state is nonsignaled - BeforeInputEventName); // object name - if (!beforeInputEvent) { - std::cerr << "CreateEvent#1 failed " << GetLastError() << std::endl; - return 1; - } - - afterOutputEvent = CreateEventW(nullptr, FALSE, FALSE, AfterOutputEventName); - if (!afterOutputEvent) { - std::cerr << "CreateEvent#2 failed " << GetLastError() << std::endl; - return 1; - } - - encodedTestString = kwsys::Encoding::ToNarrow(std::wstring( - UnicodeTestString, sizeof(UnicodeTestString) / sizeof(wchar_t) - 1)); - encodedInputTestString = kwsys::Encoding::ToNarrow( - std::wstring(UnicodeInputTestString, - sizeof(UnicodeInputTestString) / sizeof(wchar_t) - 1)); - encodedInputTestString += "\n"; - - ret |= testPipe(); - ret |= testFile(); - ret |= testConsole(); - - CloseHandle(beforeInputEvent); - CloseHandle(afterOutputEvent); -#endif - - return ret; -} diff --git a/test/API/driver/kwsys/testConsoleBuf.hxx b/test/API/driver/kwsys/testConsoleBuf.hxx deleted file mode 100644 index e93cb4f..0000000 --- a/test/API/driver/kwsys/testConsoleBuf.hxx +++ /dev/null @@ -1,17 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifndef testConsoleBuf_hxx -#define testConsoleBuf_hxx - -static const wchar_t cmdConsoleBufChild[] = L"testConsoleBufChild"; - -static const wchar_t BeforeInputEventName[] = L"BeforeInputEvent"; -static const wchar_t AfterOutputEventName[] = L"AfterOutputEvent"; - -// यूनिकोड είναι здорово! -static const wchar_t UnicodeTestString[] = - L"\u092F\u0942\u0928\u093F\u0915\u094B\u0921 " - L"\u03B5\u03AF\u03BD\0\u03B1\u03B9 " - L"\u0437\u0434\u043E\u0440\u043E\u0432\u043E!"; - -#endif diff --git a/test/API/driver/kwsys/testConsoleBufChild.cxx b/test/API/driver/kwsys/testConsoleBufChild.cxx deleted file mode 100644 index 3c8fdc2..0000000 --- a/test/API/driver/kwsys/testConsoleBufChild.cxx +++ /dev/null @@ -1,55 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include "kwsysPrivate.h" - -#include KWSYS_HEADER(ConsoleBuf.hxx) -#include KWSYS_HEADER(Encoding.hxx) - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -# include "ConsoleBuf.hxx.in" -# include "Encoding.hxx.in" -#endif - -#include - -#include "testConsoleBuf.hxx" - -int main(int argc, const char* argv[]) -{ -#if defined(_WIN32) - kwsys::ConsoleBuf::Manager out(std::cout); - kwsys::ConsoleBuf::Manager err(std::cerr, true); - kwsys::ConsoleBuf::Manager in(std::cin); - - if (argc > 1) { - std::cout << argv[1] << std::endl; - std::cerr << argv[1] << std::endl; - } else { - std::string str = kwsys::Encoding::ToNarrow(std::wstring( - UnicodeTestString, sizeof(UnicodeTestString) / sizeof(wchar_t) - 1)); - std::cout << str << std::endl; - std::cerr << str << std::endl; - } - - std::string input; - HANDLE event = OpenEventW(EVENT_MODIFY_STATE, FALSE, BeforeInputEventName); - if (event) { - SetEvent(event); - CloseHandle(event); - } - - std::cin >> input; - std::cout << input << std::endl; - event = OpenEventW(EVENT_MODIFY_STATE, FALSE, AfterOutputEventName); - if (event) { - SetEvent(event); - CloseHandle(event); - } -#else - static_cast(argc); - static_cast(argv); -#endif - return 0; -} diff --git a/test/API/driver/kwsys/testDirectory.cxx b/test/API/driver/kwsys/testDirectory.cxx deleted file mode 100644 index b1ab0c8..0000000 --- a/test/API/driver/kwsys/testDirectory.cxx +++ /dev/null @@ -1,110 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying -file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include "kwsysPrivate.h" -#include KWSYS_HEADER(Directory.hxx) -#include KWSYS_HEADER(Encoding.hxx) -#include KWSYS_HEADER(SystemTools.hxx) - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -# include "Directory.hxx.in" -# include "Encoding.hxx.in" -# include "SystemTools.hxx.in" -#endif - -#include -#include -#include - -#include - -int _doLongPathTest() -{ - using namespace kwsys; - static const int LONG_PATH_THRESHOLD = 512; - int res = 0; - std::string topdir(TEST_SYSTEMTOOLS_BINARY_DIR "/directory_testing/"); - std::stringstream testpathstrm; - std::string testdirpath; - std::string extendedtestdirpath; - - testpathstrm << topdir; - size_t pathlen = testpathstrm.str().length(); - testpathstrm.seekp(0, std::ios_base::end); - while (pathlen < LONG_PATH_THRESHOLD) { - testpathstrm << "0123456789/"; - pathlen = testpathstrm.str().length(); - } - - testdirpath = testpathstrm.str(); -#ifdef _WIN32 - extendedtestdirpath = - Encoding::ToNarrow(SystemTools::ConvertToWindowsExtendedPath(testdirpath)); -#else - extendedtestdirpath = testdirpath; -#endif - - if (SystemTools::MakeDirectory(extendedtestdirpath)) { - std::ofstream testfile1( - (extendedtestdirpath + "longfilepathtest1.txt").c_str()); - std::ofstream testfile2( - (extendedtestdirpath + "longfilepathtest2.txt").c_str()); - testfile1 << "foo"; - testfile2 << "bar"; - testfile1.close(); - testfile2.close(); - - Directory testdir; - // Set res to failure if the directory doesn't load - res += !testdir.Load(testdirpath); - // Increment res failure if the directory appears empty - res += testdir.GetNumberOfFiles() == 0; - // Increment res failures if the path has changed from - // what was provided. - res += testdirpath != testdir.GetPath(); - - SystemTools::RemoveADirectory(topdir); - } else { - std::cerr << "Failed to create directory with long path: " - << extendedtestdirpath << std::endl; - res += 1; - } - return res; -} - -int _copyDirectoryTest() -{ - using namespace kwsys; - const std::string source(TEST_SYSTEMTOOLS_BINARY_DIR - "/directory_testing/copyDirectoryTestSrc"); - if (SystemTools::PathExists(source)) { - std::cerr << source << " shouldn't exist before test" << std::endl; - return 1; - } - const std::string destination(TEST_SYSTEMTOOLS_BINARY_DIR - "/directory_testing/copyDirectoryTestDst"); - if (SystemTools::PathExists(destination)) { - std::cerr << destination << " shouldn't exist before test" << std::endl; - return 2; - } - const bool copysuccess = SystemTools::CopyADirectory(source, destination); - const bool destinationexists = SystemTools::PathExists(destination); - if (copysuccess) { - std::cerr << "CopyADirectory should have returned false" << std::endl; - SystemTools::RemoveADirectory(destination); - return 3; - } - if (destinationexists) { - std::cerr << "CopyADirectory returned false, but destination directory" - << " has been created" << std::endl; - SystemTools::RemoveADirectory(destination); - return 4; - } - return 0; -} - -int testDirectory(int, char* []) -{ - return _doLongPathTest() + _copyDirectoryTest(); -} diff --git a/test/API/driver/kwsys/testDynamicLoader.cxx b/test/API/driver/kwsys/testDynamicLoader.cxx deleted file mode 100644 index 2421ac0..0000000 --- a/test/API/driver/kwsys/testDynamicLoader.cxx +++ /dev/null @@ -1,133 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include "kwsysPrivate.h" - -#include KWSYS_HEADER(DynamicLoader.hxx) - -#if defined(__BEOS__) || defined(__HAIKU__) -# include /* disable_debugger() API. */ -#endif - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -# include "DynamicLoader.hxx.in" -#endif - -#include -#include - -// Include with <> instead of "" to avoid getting any in-source copy -// left on disk. -#include - -static std::string GetLibName(const char* lname, const char* subdir = nullptr) -{ - // Construct proper name of lib - std::string slname; - slname = EXECUTABLE_OUTPUT_PATH; - if (subdir) { - slname += "/"; - slname += subdir; - } -#ifdef CMAKE_INTDIR - slname += "/"; - slname += CMAKE_INTDIR; -#endif - slname += "/"; - slname += kwsys::DynamicLoader::LibPrefix(); - slname += lname; - slname += kwsys::DynamicLoader::LibExtension(); - - return slname; -} - -/* libname = Library name (proper prefix, proper extension) - * System = symbol to lookup in libname - * r1: should OpenLibrary succeed ? - * r2: should GetSymbolAddress succeed ? - * r3: should CloseLibrary succeed ? - */ -static int TestDynamicLoader(const char* libname, const char* symbol, int r1, - int r2, int r3, int flags = 0) -{ - std::cerr << "Testing: " << libname << std::endl; - kwsys::DynamicLoader::LibraryHandle l = - kwsys::DynamicLoader::OpenLibrary(libname, flags); - // If result is incompatible with expectation just fails (xor): - if ((r1 && !l) || (!r1 && l)) { - std::cerr << "OpenLibrary: " << kwsys::DynamicLoader::LastError() - << std::endl; - return 1; - } - kwsys::DynamicLoader::SymbolPointer f = - kwsys::DynamicLoader::GetSymbolAddress(l, symbol); - if ((r2 && !f) || (!r2 && f)) { - std::cerr << "GetSymbolAddress: " << kwsys::DynamicLoader::LastError() - << std::endl; - return 1; - } -#ifndef __APPLE__ - int s = kwsys::DynamicLoader::CloseLibrary(l); - if ((r3 && !s) || (!r3 && s)) { - std::cerr << "CloseLibrary: " << kwsys::DynamicLoader::LastError() - << std::endl; - return 1; - } -#else - (void)r3; -#endif - return 0; -} - -int testDynamicLoader(int argc, char* argv[]) -{ -#if defined(_WIN32) - SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); -#elif defined(__BEOS__) || defined(__HAIKU__) - disable_debugger(1); -#endif - int res = 0; - if (argc == 3) { - // User specify a libname and symbol to check. - res = TestDynamicLoader(argv[1], argv[2], 1, 1, 1); - return res; - } - -// dlopen() on Syllable before 11/22/2007 doesn't return 0 on error -#ifndef __SYLLABLE__ - // Make sure that inexistent lib is giving correct result - res += TestDynamicLoader("azerty_", "foo_bar", 0, 0, 0); - // Make sure that random binary file cannot be assimilated as dylib - res += TestDynamicLoader(TEST_SYSTEMTOOLS_SOURCE_DIR "/testSystemTools.bin", - "wp", 0, 0, 0); -#endif - -#ifdef __linux__ - // This one is actually fun to test, since dlopen is by default - // loaded...wonder why :) - res += TestDynamicLoader("foobar.lib", "dlopen", 0, 1, 0); - res += TestDynamicLoader("libdl.so", "dlopen", 1, 1, 1); - res += TestDynamicLoader("libdl.so", "TestDynamicLoader", 1, 0, 1); -#endif - // Now try on the generated library - std::string libname = GetLibName(KWSYS_NAMESPACE_STRING "TestDynload"); - res += TestDynamicLoader(libname.c_str(), "dummy", 1, 0, 1); - res += TestDynamicLoader(libname.c_str(), "TestDynamicLoaderSymbolPointer", - 1, 1, 1); - res += TestDynamicLoader(libname.c_str(), "_TestDynamicLoaderSymbolPointer", - 1, 0, 1); - res += TestDynamicLoader(libname.c_str(), "TestDynamicLoaderData", 1, 1, 1); - res += TestDynamicLoader(libname.c_str(), "_TestDynamicLoaderData", 1, 0, 1); - -#ifdef _WIN32 - libname = GetLibName(KWSYS_NAMESPACE_STRING "TestDynloadUse", "dynloaddir"); - res += TestDynamicLoader(libname.c_str(), "dummy", 0, 0, 0); - res += TestDynamicLoader(libname.c_str(), "TestLoad", 1, 1, 1, - kwsys::DynamicLoader::SearchBesideLibrary); - res += TestDynamicLoader(libname.c_str(), "_TestLoad", 1, 0, 1, - kwsys::DynamicLoader::SearchBesideLibrary); -#endif - - return res; -} diff --git a/test/API/driver/kwsys/testDynload.c b/test/API/driver/kwsys/testDynload.c deleted file mode 100644 index c49f747..0000000 --- a/test/API/driver/kwsys/testDynload.c +++ /dev/null @@ -1,13 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifdef _WIN32 -# define DL_EXPORT __declspec(dllexport) -#else -# define DL_EXPORT -#endif - -DL_EXPORT int TestDynamicLoaderData = 0; - -DL_EXPORT void TestDynamicLoaderSymbolPointer() -{ -} diff --git a/test/API/driver/kwsys/testDynloadImpl.c b/test/API/driver/kwsys/testDynloadImpl.c deleted file mode 100644 index 2b9069b..0000000 --- a/test/API/driver/kwsys/testDynloadImpl.c +++ /dev/null @@ -1,10 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ - -#include "testDynloadImpl.h" - -int TestDynamicLoaderImplData = 0; - -void TestDynamicLoaderImplSymbolPointer() -{ -} diff --git a/test/API/driver/kwsys/testDynloadImpl.h b/test/API/driver/kwsys/testDynloadImpl.h deleted file mode 100644 index d0c9dfb..0000000 --- a/test/API/driver/kwsys/testDynloadImpl.h +++ /dev/null @@ -1,15 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifdef _WIN32 -# ifdef BUILDING_TestDynloadImpl -# define DLIMPL_EXPORT __declspec(dllexport) -# else -# define DLIMPL_EXPORT __declspec(dllimport) -# endif -#else -# define DLIMPL_EXPORT -#endif - -DLIMPL_EXPORT int TestDynamicLoaderImplData; - -DLIMPL_EXPORT void TestDynamicLoaderImplSymbolPointer(); diff --git a/test/API/driver/kwsys/testDynloadUse.c b/test/API/driver/kwsys/testDynloadUse.c deleted file mode 100644 index 5402add..0000000 --- a/test/API/driver/kwsys/testDynloadUse.c +++ /dev/null @@ -1,15 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include "testDynloadImpl.h" - -#ifdef _WIN32 -# define DL_EXPORT __declspec(dllexport) -#else -# define DL_EXPORT -#endif - -DL_EXPORT int TestLoad() -{ - TestDynamicLoaderImplSymbolPointer(); - return TestDynamicLoaderImplData; -} diff --git a/test/API/driver/kwsys/testEncode.c b/test/API/driver/kwsys/testEncode.c deleted file mode 100644 index b7b6dd8..0000000 --- a/test/API/driver/kwsys/testEncode.c +++ /dev/null @@ -1,67 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include "kwsysPrivate.h" -#include KWSYS_HEADER(MD5.h) - -/* Work-around CMake dependency scanning limitation. This must - duplicate the above list of headers. */ -#if 0 -# include "MD5.h.in" -#endif - -#include -#include - -static const unsigned char testMD5input1[] = - " A quick brown fox jumps over the lazy dog.\n" - " This is sample text for MD5 sum input.\n"; -static const char testMD5output1[] = "8f146af46ed4f267921bb937d4d3500c"; - -static const int testMD5input2len = 28; -static const unsigned char testMD5input2[] = "the cow jumped over the moon"; -static const char testMD5output2[] = "a2ad137b746138fae4e5adca9c85d3ae"; - -static int testMD5_1(kwsysMD5* md5) -{ - char md5out[33]; - kwsysMD5_Initialize(md5); - kwsysMD5_Append(md5, testMD5input1, -1); - kwsysMD5_FinalizeHex(md5, md5out); - md5out[32] = 0; - printf("md5sum 1: expected [%s]\n" - " got [%s]\n", - testMD5output1, md5out); - return (strcmp(md5out, testMD5output1) != 0) ? 1 : 0; -} - -static int testMD5_2(kwsysMD5* md5) -{ - unsigned char digest[16]; - char md5out[33]; - kwsysMD5_Initialize(md5); - kwsysMD5_Append(md5, testMD5input2, testMD5input2len); - kwsysMD5_Finalize(md5, digest); - kwsysMD5_DigestToHex(digest, md5out); - md5out[32] = 0; - printf("md5sum 2: expected [%s]\n" - " got [%s]\n", - testMD5output2, md5out); - return (strcmp(md5out, testMD5output2) != 0) ? 1 : 0; -} - -int testEncode(int argc, char* argv[]) -{ - int result = 0; - (void)argc; - (void)argv; - - /* Test MD5 digest. */ - { - kwsysMD5* md5 = kwsysMD5_New(); - result |= testMD5_1(md5); - result |= testMD5_2(md5); - kwsysMD5_Delete(md5); - } - - return result; -} diff --git a/test/API/driver/kwsys/testEncoding.cxx b/test/API/driver/kwsys/testEncoding.cxx deleted file mode 100644 index 988697b..0000000 --- a/test/API/driver/kwsys/testEncoding.cxx +++ /dev/null @@ -1,286 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include "kwsysPrivate.h" - -#if defined(_MSC_VER) -# pragma warning(disable : 4786) -#endif - -#include KWSYS_HEADER(Encoding.hxx) -#include KWSYS_HEADER(Encoding.h) - -#include -#include -#include -#include -#include - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -# include "Encoding.h.in" -# include "Encoding.hxx.in" -#endif - -static const unsigned char helloWorldStrings[][32] = { - // English - { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', 0 }, - // Japanese - { 0xE3, 0x81, 0x93, 0xE3, 0x82, 0x93, 0xE3, 0x81, 0xAB, 0xE3, 0x81, - 0xA1, 0xE3, 0x81, 0xAF, 0xE4, 0xB8, 0x96, 0xE7, 0x95, 0x8C, 0 }, - // Arabic - { 0xD9, 0x85, 0xD8, 0xB1, 0xD8, 0xAD, 0xD8, 0xA8, 0xD8, 0xA7, 0x20, 0xD8, - 0xA7, 0xD9, 0x84, 0xD8, 0xB9, 0xD8, 0xA7, 0xD9, 0x84, 0xD9, 0x85, 0 }, - // Yiddish - { 0xD7, 0x94, 0xD7, 0xA2, 0xD7, 0x9C, 0xD7, 0x90, 0x20, 0xD7, - 0x95, 0xD7, 0x95, 0xD7, 0xA2, 0xD7, 0x9C, 0xD7, 0x98, 0 }, - // Russian - { 0xD0, 0xBF, 0xD1, 0x80, 0xD0, 0xB8, 0xD0, 0xB2, 0xD0, 0xB5, - 0xD1, 0x82, 0x20, 0xD0, 0xBC, 0xD0, 0xB8, 0xD1, 0x80, 0 }, - // Latin - { 0x4D, 0x75, 0x6E, 0x64, 0x75, 0x73, 0x20, 0x73, 0x61, 0x6C, 0x76, 0x65, - 0 }, - // Swahili - { 0x68, 0x75, 0x6A, 0x61, 0x6D, 0x62, 0x6F, 0x20, 0x44, 0x75, 0x6E, 0x69, - 0x61, 0 }, - // Icelandic - { 0x48, 0x61, 0x6C, 0x6C, 0xC3, 0xB3, 0x20, 0x68, 0x65, 0x69, 0x6D, 0x75, - 0x72, 0 }, - { 0 } -}; - -static int testHelloWorldEncoding() -{ - int ret = 0; - for (int i = 0; helloWorldStrings[i][0] != 0; i++) { - std::string str = reinterpret_cast(helloWorldStrings[i]); - std::cout << str << std::endl; - std::wstring wstr = kwsys::Encoding::ToWide(str); - std::string str2 = kwsys::Encoding::ToNarrow(wstr); - wchar_t* c_wstr = kwsysEncoding_DupToWide(str.c_str()); - char* c_str2 = kwsysEncoding_DupToNarrow(c_wstr); - if (!wstr.empty() && (str != str2 || strcmp(c_str2, str.c_str()))) { - std::cout << "converted string was different: " << str2 << std::endl; - std::cout << "converted string was different: " << c_str2 << std::endl; - ret++; - } - free(c_wstr); - free(c_str2); - } - return ret; -} - -static int testRobustEncoding() -{ - // test that the conversion functions handle invalid - // unicode correctly/gracefully - - // we manipulate the format flags of stdout, remember - // the original state here to restore before return - std::ios::fmtflags const& flags = std::cout.flags(); - - int ret = 0; - char cstr[] = { (char)-1, 0 }; - // this conversion could fail - std::wstring wstr = kwsys::Encoding::ToWide(cstr); - - wstr = kwsys::Encoding::ToWide(nullptr); - if (wstr != L"") { - const wchar_t* wcstr = wstr.c_str(); - std::cout << "ToWide(NULL) returned"; - for (size_t i = 0; i < wstr.size(); i++) { - std::cout << " " << std::hex << (int)wcstr[i]; - } - std::cout << std::endl; - ret++; - } - wstr = kwsys::Encoding::ToWide(""); - if (wstr != L"") { - const wchar_t* wcstr = wstr.c_str(); - std::cout << "ToWide(\"\") returned"; - for (size_t i = 0; i < wstr.size(); i++) { - std::cout << " " << std::hex << (int)wcstr[i]; - } - std::cout << std::endl; - ret++; - } - -#ifdef _WIN32 - // 16 bit wchar_t - we make an invalid surrogate pair - wchar_t cwstr[] = { 0xD801, 0xDA00, 0 }; - // this conversion could fail - std::string win_str = kwsys::Encoding::ToNarrow(cwstr); -#endif - - std::string str = kwsys::Encoding::ToNarrow(nullptr); - if (str != "") { - std::cout << "ToNarrow(NULL) returned " << str << std::endl; - ret++; - } - - str = kwsys::Encoding::ToNarrow(L""); - if (wstr != L"") { - std::cout << "ToNarrow(\"\") returned " << str << std::endl; - ret++; - } - - std::cout.flags(flags); - return ret; -} - -static int testWithNulls() -{ - int ret = 0; - std::vector strings; - strings.push_back(std::string("ab") + '\0' + 'c'); - strings.push_back(std::string("d") + '\0' + '\0' + 'e'); - strings.push_back(std::string() + '\0' + 'f'); - strings.push_back(std::string() + '\0' + '\0' + "gh"); - strings.push_back(std::string("ij") + '\0'); - strings.push_back(std::string("k") + '\0' + '\0'); - strings.push_back(std::string("\0\0\0\0", 4) + "lmn" + - std::string("\0\0\0\0", 4)); - for (std::vector::iterator it = strings.begin(); - it != strings.end(); ++it) { - std::wstring wstr = kwsys::Encoding::ToWide(*it); - std::string str = kwsys::Encoding::ToNarrow(wstr); - std::string s(*it); - std::replace(s.begin(), s.end(), '\0', ' '); - std::cout << "'" << s << "' (" << it->size() << ")" << std::endl; - if (str != *it) { - std::replace(str.begin(), str.end(), '\0', ' '); - std::cout << "string with null was different: '" << str << "' (" - << str.size() << ")" << std::endl; - ret++; - } - } - return ret; -} - -static int testCommandLineArguments() -{ - int status = 0; - - char const* argv[2] = { "./app.exe", (char const*)helloWorldStrings[1] }; - - kwsys::Encoding::CommandLineArguments args(2, argv); - kwsys::Encoding::CommandLineArguments arg2 = - kwsys::Encoding::CommandLineArguments(args); - - char const* const* u8_argv = args.argv(); - for (int i = 0; i < args.argc(); i++) { - char const* u8_arg = u8_argv[i]; - if (strcmp(argv[i], u8_arg) != 0) { - std::cout << "argv[" << i << "] " << argv[i] << " != " << u8_arg - << std::endl; - status++; - } - } - - kwsys::Encoding::CommandLineArguments args3 = - kwsys::Encoding::CommandLineArguments::Main(2, argv); - - return status; -} - -static int testToWindowsExtendedPath() -{ -#ifdef _WIN32 - int ret = 0; - if (kwsys::Encoding::ToWindowsExtendedPath( - "L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") != - L"\\\\?\\L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") { - std::cout << "Problem with ToWindowsExtendedPath " - << "\"L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\"" - << std::endl; - ++ret; - } - - if (kwsys::Encoding::ToWindowsExtendedPath( - "L:/Local Mojo/Hex Power Pack/Iffy Voodoo") != - L"\\\\?\\L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") { - std::cout << "Problem with ToWindowsExtendedPath " - << "\"L:/Local Mojo/Hex Power Pack/Iffy Voodoo\"" << std::endl; - ++ret; - } - - if (kwsys::Encoding::ToWindowsExtendedPath( - "\\\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") != - L"\\\\?\\UNC\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") { - std::cout << "Problem with ToWindowsExtendedPath " - << "\"\\\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\"" - << std::endl; - ++ret; - } - - if (kwsys::Encoding::ToWindowsExtendedPath( - "//Foo/Local Mojo/Hex Power Pack/Iffy Voodoo") != - L"\\\\?\\UNC\\Foo\\Local Mojo\\Hex Power Pack\\Iffy Voodoo") { - std::cout << "Problem with ToWindowsExtendedPath " - << "\"//Foo/Local Mojo/Hex Power Pack/Iffy Voodoo\"" - << std::endl; - ++ret; - } - - if (kwsys::Encoding::ToWindowsExtendedPath("//") != L"//") { - std::cout << "Problem with ToWindowsExtendedPath " - << "\"//\"" << std::endl; - ++ret; - } - - if (kwsys::Encoding::ToWindowsExtendedPath("\\\\.\\") != L"\\\\.\\") { - std::cout << "Problem with ToWindowsExtendedPath " - << "\"\\\\.\\\"" << std::endl; - ++ret; - } - - if (kwsys::Encoding::ToWindowsExtendedPath("\\\\.\\X") != L"\\\\.\\X") { - std::cout << "Problem with ToWindowsExtendedPath " - << "\"\\\\.\\X\"" << std::endl; - ++ret; - } - - if (kwsys::Encoding::ToWindowsExtendedPath("\\\\.\\X:") != L"\\\\?\\X:") { - std::cout << "Problem with ToWindowsExtendedPath " - << "\"\\\\.\\X:\"" << std::endl; - ++ret; - } - - if (kwsys::Encoding::ToWindowsExtendedPath("\\\\.\\X:\\") != - L"\\\\?\\X:\\") { - std::cout << "Problem with ToWindowsExtendedPath " - << "\"\\\\.\\X:\\\"" << std::endl; - ++ret; - } - - if (kwsys::Encoding::ToWindowsExtendedPath("NUL") != L"\\\\.\\NUL") { - std::cout << "Problem with ToWindowsExtendedPath " - << "\"NUL\"" << std::endl; - ++ret; - } - - return ret; -#else - return 0; -#endif -} - -int testEncoding(int, char* []) -{ - const char* loc = setlocale(LC_ALL, ""); - if (loc) { - std::cout << "Locale: " << loc << std::endl; - } else { - std::cout << "Locale: None" << std::endl; - } - - int ret = 0; - - ret |= testHelloWorldEncoding(); - ret |= testRobustEncoding(); - ret |= testCommandLineArguments(); - ret |= testWithNulls(); - ret |= testToWindowsExtendedPath(); - - return ret; -} diff --git a/test/API/driver/kwsys/testFStream.cxx b/test/API/driver/kwsys/testFStream.cxx deleted file mode 100644 index 5009e98..0000000 --- a/test/API/driver/kwsys/testFStream.cxx +++ /dev/null @@ -1,113 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include "kwsysPrivate.h" - -#if defined(_MSC_VER) -# pragma warning(disable : 4786) -#endif - -#include KWSYS_HEADER(FStream.hxx) -#include -#ifdef __BORLANDC__ -# include /* memcmp */ -#endif - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -# include "FStream.hxx.in" -#endif - -#include - -static int testNoFile() -{ - kwsys::ifstream in_file("NoSuchFile.txt"); - if (in_file) { - return 1; - } - - return 0; -} - -static const int num_test_files = 7; -static const int max_test_file_size = 45; - -static kwsys::FStream::BOM expected_bom[num_test_files] = { - kwsys::FStream::BOM_None, kwsys::FStream::BOM_None, - kwsys::FStream::BOM_UTF8, kwsys::FStream::BOM_UTF16LE, - kwsys::FStream::BOM_UTF16BE, kwsys::FStream::BOM_UTF32LE, - kwsys::FStream::BOM_UTF32BE -}; - -static unsigned char expected_bom_data[num_test_files][5] = { - { 0 }, - { 0 }, - { 3, 0xEF, 0xBB, 0xBF }, - { 2, 0xFF, 0xFE }, - { 2, 0xFE, 0xFF }, - { 4, 0xFF, 0xFE, 0x00, 0x00 }, - { 4, 0x00, 0x00, 0xFE, 0xFF }, -}; - -static unsigned char file_data[num_test_files][max_test_file_size] = { - { 1, 'H' }, - { 11, 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd' }, - { 11, 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd' }, - { 22, 0x48, 0x00, 0x65, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6F, 0x00, 0x20, - 0x00, 0x57, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x6C, 0x00, 0x64, 0x00 }, - { 22, 0x00, 0x48, 0x00, 0x65, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6F, 0x00, - 0x20, 0x00, 0x57, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x6C, 0x00, 0x64 }, - { 44, 0x48, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, - 0x00, 0x6C, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, - 0x00, 0x57, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, - 0x00, 0x6C, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00 }, - { 44, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, - 0x6C, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, - 0x72, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x64 }, -}; - -static int testBOM() -{ - // test various encodings in binary mode - for (int i = 0; i < num_test_files; i++) { - { - kwsys::ofstream out("bom.txt", kwsys::ofstream::binary); - out.write(reinterpret_cast(expected_bom_data[i] + 1), - *expected_bom_data[i]); - out.write(reinterpret_cast(file_data[i] + 1), - file_data[i][0]); - } - - kwsys::ifstream in("bom.txt", kwsys::ofstream::binary); - kwsys::FStream::BOM bom = kwsys::FStream::ReadBOM(in); - if (bom != expected_bom[i]) { - std::cout << "Unexpected BOM " << i << std::endl; - return 1; - } - char data[max_test_file_size]; - in.read(data, file_data[i][0]); - if (!in.good()) { - std::cout << "Unable to read data " << i << std::endl; - return 1; - } - - if (memcmp(data, file_data[i] + 1, file_data[i][0]) != 0) { - std::cout << "Incorrect read data " << i << std::endl; - return 1; - } - } - - return 0; -} - -int testFStream(int, char* []) -{ - int ret = 0; - - ret |= testNoFile(); - ret |= testBOM(); - - return ret; -} diff --git a/test/API/driver/kwsys/testFail.c b/test/API/driver/kwsys/testFail.c deleted file mode 100644 index 82caeac..0000000 --- a/test/API/driver/kwsys/testFail.c +++ /dev/null @@ -1,24 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include -#include -#include - -int testFail(int argc, char* argv[]) -{ - char* env = getenv("DASHBOARD_TEST_FROM_CTEST"); - int oldCtest = 0; - if (env) { - if (strcmp(env, "1") == 0) { - oldCtest = 1; - } - printf("DASHBOARD_TEST_FROM_CTEST = %s\n", env); - } - printf("%s: This test intentionally fails\n", argv[0]); - if (oldCtest) { - printf("The version of ctest is not able to handle intentionally failing " - "tests, so pass.\n"); - return 0; - } - return argc; -} diff --git a/test/API/driver/kwsys/testHashSTL.cxx b/test/API/driver/kwsys/testHashSTL.cxx deleted file mode 100644 index 4ed2f89..0000000 --- a/test/API/driver/kwsys/testHashSTL.cxx +++ /dev/null @@ -1,64 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include "kwsysPrivate.h" -#include KWSYS_HEADER(hash_map.hxx) -#include KWSYS_HEADER(hash_set.hxx) - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -# include "hash_map.hxx.in" -# include "hash_set.hxx.in" -#endif - -#include - -#if defined(_MSC_VER) -# pragma warning(disable : 4786) -#endif - -#if defined(__sgi) && !defined(__GNUC__) -# pragma set woff 1468 /* inline function cannot be explicitly instantiated \ - */ -#endif - -template class kwsys::hash_map; -template class kwsys::hash_set; - -static bool test_hash_map() -{ - typedef kwsys::hash_map mtype; - mtype m; - const char* keys[] = { "hello", "world" }; - m[keys[0]] = 1; - m.insert(mtype::value_type(keys[1], 2)); - int sum = 0; - for (mtype::iterator mi = m.begin(); mi != m.end(); ++mi) { - std::cout << "Found entry [" << mi->first << "," << mi->second << "]" - << std::endl; - sum += mi->second; - } - return sum == 3; -} - -static bool test_hash_set() -{ - typedef kwsys::hash_set stype; - stype s; - s.insert(1); - s.insert(2); - int sum = 0; - for (stype::iterator si = s.begin(); si != s.end(); ++si) { - std::cout << "Found entry [" << *si << "]" << std::endl; - sum += *si; - } - return sum == 3; -} - -int testHashSTL(int, char* []) -{ - bool result = true; - result = test_hash_map() && result; - result = test_hash_set() && result; - return result ? 0 : 1; -} diff --git a/test/API/driver/kwsys/testProcess.c b/test/API/driver/kwsys/testProcess.c deleted file mode 100644 index 39aaa23..0000000 --- a/test/API/driver/kwsys/testProcess.c +++ /dev/null @@ -1,728 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include "kwsysPrivate.h" -#include KWSYS_HEADER(Process.h) -#include KWSYS_HEADER(Encoding.h) - -/* Work-around CMake dependency scanning limitation. This must - duplicate the above list of headers. */ -#if 0 -# include "Encoding.h.in" -# include "Process.h.in" -#endif - -#include -#include -#include -#include -#include - -#if defined(_WIN32) -# include -#else -# include -# include -#endif - -#if defined(__BORLANDC__) -# pragma warn - 8060 /* possibly incorrect assignment */ -#endif - -/* Platform-specific sleep functions. */ - -#if defined(__BEOS__) && !defined(__ZETA__) -/* BeOS 5 doesn't have usleep(), but it has snooze(), which is identical. */ -# include -static inline void testProcess_usleep(unsigned int usec) -{ - snooze(usec); -} -#elif defined(_WIN32) -/* Windows can only sleep in millisecond intervals. */ -static void testProcess_usleep(unsigned int usec) -{ - Sleep(usec / 1000); -} -#else -# define testProcess_usleep usleep -#endif - -#if defined(_WIN32) -static void testProcess_sleep(unsigned int sec) -{ - Sleep(sec * 1000); -} -#else -static void testProcess_sleep(unsigned int sec) -{ - sleep(sec); -} -#endif - -int runChild(const char* cmd[], int state, int exception, int value, int share, - int output, int delay, double timeout, int poll, int repeat, - int disown, int createNewGroup, unsigned int interruptDelay); - -static int test1(int argc, const char* argv[]) -{ - /* This is a very basic functional test of kwsysProcess. It is repeated - numerous times to verify that there are no resource leaks in kwsysProcess - that eventually lead to an error. Many versions of OS X will fail after - 256 leaked file handles, so 257 iterations seems to be a good test. On - the other hand, too many iterations will cause the test to time out - - especially if the test is instrumented with e.g. valgrind. - - If you have problems with this test timing out on your system, or want to - run more than 257 iterations, you can change the number of iterations by - setting the KWSYS_TEST_PROCESS_1_COUNT environment variable. */ - (void)argc; - (void)argv; - fprintf(stdout, "Output on stdout from test returning 0.\n"); - fprintf(stderr, "Output on stderr from test returning 0.\n"); - return 0; -} - -static int test2(int argc, const char* argv[]) -{ - (void)argc; - (void)argv; - fprintf(stdout, "Output on stdout from test returning 123.\n"); - fprintf(stderr, "Output on stderr from test returning 123.\n"); - return 123; -} - -static int test3(int argc, const char* argv[]) -{ - (void)argc; - (void)argv; - fprintf(stdout, "Output before sleep on stdout from timeout test.\n"); - fprintf(stderr, "Output before sleep on stderr from timeout test.\n"); - fflush(stdout); - fflush(stderr); - testProcess_sleep(15); - fprintf(stdout, "Output after sleep on stdout from timeout test.\n"); - fprintf(stderr, "Output after sleep on stderr from timeout test.\n"); - return 0; -} - -static int test4(int argc, const char* argv[]) -{ -#ifndef CRASH_USING_ABORT - /* Prepare a pointer to an invalid address. Don't use null, because - dereferencing null is undefined behaviour and compilers are free to - do whatever they want. ex: Clang will warn at compile time, or even - optimize away the write. We hope to 'outsmart' them by using - 'volatile' and a slightly larger address, based on a runtime value. */ - volatile int* invalidAddress = 0; - invalidAddress += argc ? 1 : 2; -#endif - -#if defined(_WIN32) - /* Avoid error diagnostic popups since we are crashing on purpose. */ - SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); -#elif defined(__BEOS__) || defined(__HAIKU__) - /* Avoid error diagnostic popups since we are crashing on purpose. */ - disable_debugger(1); -#endif - (void)argc; - (void)argv; - fprintf(stdout, "Output before crash on stdout from crash test.\n"); - fprintf(stderr, "Output before crash on stderr from crash test.\n"); - fflush(stdout); - fflush(stderr); -#ifdef CRASH_USING_ABORT - abort(); -#else - assert(invalidAddress); /* Quiet Clang scan-build. */ - /* Provoke deliberate crash by writing to the invalid address. */ - *invalidAddress = 0; -#endif - fprintf(stdout, "Output after crash on stdout from crash test.\n"); - fprintf(stderr, "Output after crash on stderr from crash test.\n"); - return 0; -} - -static int test5(int argc, const char* argv[]) -{ - int r; - const char* cmd[4]; - (void)argc; - cmd[0] = argv[0]; - cmd[1] = "run"; - cmd[2] = "4"; - cmd[3] = 0; - fprintf(stdout, "Output on stdout before recursive test.\n"); - fprintf(stderr, "Output on stderr before recursive test.\n"); - fflush(stdout); - fflush(stderr); - r = runChild(cmd, kwsysProcess_State_Exception, -#ifdef CRASH_USING_ABORT - kwsysProcess_Exception_Other, -#else - kwsysProcess_Exception_Fault, -#endif - 1, 1, 1, 0, 15, 0, 1, 0, 0, 0); - fprintf(stdout, "Output on stdout after recursive test.\n"); - fprintf(stderr, "Output on stderr after recursive test.\n"); - fflush(stdout); - fflush(stderr); - return r; -} - -#define TEST6_SIZE (4096 * 2) -static void test6(int argc, const char* argv[]) -{ - int i; - char runaway[TEST6_SIZE + 1]; - (void)argc; - (void)argv; - for (i = 0; i < TEST6_SIZE; ++i) { - runaway[i] = '.'; - } - runaway[TEST6_SIZE] = '\n'; - - /* Generate huge amounts of output to test killing. */ - for (;;) { - fwrite(runaway, 1, TEST6_SIZE + 1, stdout); - fflush(stdout); - } -} - -/* Define MINPOLL to be one more than the number of times output is - written. Define MAXPOLL to be the largest number of times a loop - delaying 1/10th of a second should ever have to poll. */ -#define MINPOLL 5 -#define MAXPOLL 20 -static int test7(int argc, const char* argv[]) -{ - (void)argc; - (void)argv; - fprintf(stdout, "Output on stdout before sleep.\n"); - fprintf(stderr, "Output on stderr before sleep.\n"); - fflush(stdout); - fflush(stderr); - /* Sleep for 1 second. */ - testProcess_sleep(1); - fprintf(stdout, "Output on stdout after sleep.\n"); - fprintf(stderr, "Output on stderr after sleep.\n"); - fflush(stdout); - fflush(stderr); - return 0; -} - -static int test8(int argc, const char* argv[]) -{ - /* Create a disowned grandchild to test handling of processes - that exit before their children. */ - int r; - const char* cmd[4]; - (void)argc; - cmd[0] = argv[0]; - cmd[1] = "run"; - cmd[2] = "108"; - cmd[3] = 0; - fprintf(stdout, "Output on stdout before grandchild test.\n"); - fprintf(stderr, "Output on stderr before grandchild test.\n"); - fflush(stdout); - fflush(stderr); - r = runChild(cmd, kwsysProcess_State_Disowned, kwsysProcess_Exception_None, - 1, 1, 1, 0, 10, 0, 1, 1, 0, 0); - fprintf(stdout, "Output on stdout after grandchild test.\n"); - fprintf(stderr, "Output on stderr after grandchild test.\n"); - fflush(stdout); - fflush(stderr); - return r; -} - -static int test8_grandchild(int argc, const char* argv[]) -{ - (void)argc; - (void)argv; - fprintf(stdout, "Output on stdout from grandchild before sleep.\n"); - fprintf(stderr, "Output on stderr from grandchild before sleep.\n"); - fflush(stdout); - fflush(stderr); - /* TODO: Instead of closing pipes here leave them open to make sure - the grandparent can stop listening when the parent exits. This - part of the test cannot be enabled until the feature is - implemented. */ - fclose(stdout); - fclose(stderr); - testProcess_sleep(15); - return 0; -} - -static int test9(int argc, const char* argv[]) -{ - /* Test Ctrl+C behavior: the root test program will send a Ctrl+C to this - process. Here, we start a child process that sleeps for a long time - while ignoring signals. The test is successful if this process waits - for the child to return before exiting from the Ctrl+C handler. - - WARNING: This test will falsely pass if the share parameter of runChild - was set to 0 when invoking the test9 process. */ - int r; - const char* cmd[4]; - (void)argc; - cmd[0] = argv[0]; - cmd[1] = "run"; - cmd[2] = "109"; - cmd[3] = 0; - fprintf(stdout, "Output on stdout before grandchild test.\n"); - fprintf(stderr, "Output on stderr before grandchild test.\n"); - fflush(stdout); - fflush(stderr); - r = runChild(cmd, kwsysProcess_State_Exited, kwsysProcess_Exception_None, 0, - 1, 1, 0, 30, 0, 1, 0, 0, 0); - /* This sleep will avoid a race condition between this function exiting - normally and our Ctrl+C handler exiting abnormally after the process - exits. */ - testProcess_sleep(1); - fprintf(stdout, "Output on stdout after grandchild test.\n"); - fprintf(stderr, "Output on stderr after grandchild test.\n"); - fflush(stdout); - fflush(stderr); - return r; -} - -#if defined(_WIN32) -static BOOL WINAPI test9_grandchild_handler(DWORD dwCtrlType) -{ - /* Ignore all Ctrl+C/Break signals. We must use an actual handler function - instead of using SetConsoleCtrlHandler(NULL, TRUE) so that we can also - ignore Ctrl+Break in addition to Ctrl+C. */ - (void)dwCtrlType; - return TRUE; -} -#endif - -static int test9_grandchild(int argc, const char* argv[]) -{ - /* The grandchild just sleeps for a few seconds while ignoring signals. */ - (void)argc; - (void)argv; -#if defined(_WIN32) - if (!SetConsoleCtrlHandler(test9_grandchild_handler, TRUE)) { - return 1; - } -#else - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = SIG_IGN; - sigemptyset(&sa.sa_mask); - if (sigaction(SIGINT, &sa, 0) < 0) { - return 1; - } -#endif - fprintf(stdout, "Output on stdout from grandchild before sleep.\n"); - fprintf(stderr, "Output on stderr from grandchild before sleep.\n"); - fflush(stdout); - fflush(stderr); - /* Sleep for 9 seconds. */ - testProcess_sleep(9); - fprintf(stdout, "Output on stdout from grandchild after sleep.\n"); - fprintf(stderr, "Output on stderr from grandchild after sleep.\n"); - fflush(stdout); - fflush(stderr); - return 0; -} - -static int test10(int argc, const char* argv[]) -{ - /* Test Ctrl+C behavior: the root test program will send a Ctrl+C to this - process. Here, we start a child process that sleeps for a long time and - processes signals normally. However, this grandchild is created in a new - process group - ensuring that Ctrl+C we receive is sent to our process - groups. We make sure it exits anyway. */ - int r; - const char* cmd[4]; - (void)argc; - cmd[0] = argv[0]; - cmd[1] = "run"; - cmd[2] = "110"; - cmd[3] = 0; - fprintf(stdout, "Output on stdout before grandchild test.\n"); - fprintf(stderr, "Output on stderr before grandchild test.\n"); - fflush(stdout); - fflush(stderr); - r = - runChild(cmd, kwsysProcess_State_Exception, - kwsysProcess_Exception_Interrupt, 0, 1, 1, 0, 30, 0, 1, 0, 1, 0); - fprintf(stdout, "Output on stdout after grandchild test.\n"); - fprintf(stderr, "Output on stderr after grandchild test.\n"); - fflush(stdout); - fflush(stderr); - return r; -} - -static int test10_grandchild(int argc, const char* argv[]) -{ - /* The grandchild just sleeps for a few seconds and handles signals. */ - (void)argc; - (void)argv; - fprintf(stdout, "Output on stdout from grandchild before sleep.\n"); - fprintf(stderr, "Output on stderr from grandchild before sleep.\n"); - fflush(stdout); - fflush(stderr); - /* Sleep for 6 seconds. */ - testProcess_sleep(6); - fprintf(stdout, "Output on stdout from grandchild after sleep.\n"); - fprintf(stderr, "Output on stderr from grandchild after sleep.\n"); - fflush(stdout); - fflush(stderr); - return 0; -} - -static int runChild2(kwsysProcess* kp, const char* cmd[], int state, - int exception, int value, int share, int output, - int delay, double timeout, int poll, int disown, - int createNewGroup, unsigned int interruptDelay) -{ - int result = 0; - char* data = 0; - int length = 0; - double userTimeout = 0; - double* pUserTimeout = 0; - kwsysProcess_SetCommand(kp, cmd); - if (timeout >= 0) { - kwsysProcess_SetTimeout(kp, timeout); - } - if (share) { - kwsysProcess_SetPipeShared(kp, kwsysProcess_Pipe_STDOUT, 1); - kwsysProcess_SetPipeShared(kp, kwsysProcess_Pipe_STDERR, 1); - } - if (disown) { - kwsysProcess_SetOption(kp, kwsysProcess_Option_Detach, 1); - } - if (createNewGroup) { - kwsysProcess_SetOption(kp, kwsysProcess_Option_CreateProcessGroup, 1); - } - kwsysProcess_Execute(kp); - - if (poll) { - pUserTimeout = &userTimeout; - } - - if (interruptDelay) { - testProcess_sleep(interruptDelay); - kwsysProcess_Interrupt(kp); - } - - if (!share && !disown) { - int p; - while ((p = kwsysProcess_WaitForData(kp, &data, &length, pUserTimeout))) { - if (output) { - if (poll && p == kwsysProcess_Pipe_Timeout) { - fprintf(stdout, "WaitForData timeout reached.\n"); - fflush(stdout); - - /* Count the number of times we polled without getting data. - If it is excessive then kill the child and fail. */ - if (++poll >= MAXPOLL) { - fprintf(stdout, "Poll count reached limit %d.\n", MAXPOLL); - kwsysProcess_Kill(kp); - } - } else { - fwrite(data, 1, (size_t)length, stdout); - fflush(stdout); - } - } - if (poll) { - /* Delay to avoid busy loop during polling. */ - testProcess_usleep(100000); - } - if (delay) { -/* Purposely sleeping only on Win32 to let pipe fill up. */ -#if defined(_WIN32) - testProcess_usleep(100000); -#endif - } - } - } - - if (disown) { - kwsysProcess_Disown(kp); - } else { - kwsysProcess_WaitForExit(kp, 0); - } - - switch (kwsysProcess_GetState(kp)) { - case kwsysProcess_State_Starting: - printf("No process has been executed.\n"); - break; - case kwsysProcess_State_Executing: - printf("The process is still executing.\n"); - break; - case kwsysProcess_State_Expired: - printf("Child was killed when timeout expired.\n"); - break; - case kwsysProcess_State_Exited: - printf("Child exited with value = %d\n", kwsysProcess_GetExitValue(kp)); - result = ((exception != kwsysProcess_GetExitException(kp)) || - (value != kwsysProcess_GetExitValue(kp))); - break; - case kwsysProcess_State_Killed: - printf("Child was killed by parent.\n"); - break; - case kwsysProcess_State_Exception: - printf("Child terminated abnormally: %s\n", - kwsysProcess_GetExceptionString(kp)); - result = ((exception != kwsysProcess_GetExitException(kp)) || - (value != kwsysProcess_GetExitValue(kp))); - break; - case kwsysProcess_State_Disowned: - printf("Child was disowned.\n"); - break; - case kwsysProcess_State_Error: - printf("Error in administrating child process: [%s]\n", - kwsysProcess_GetErrorString(kp)); - break; - } - - if (result) { - if (exception != kwsysProcess_GetExitException(kp)) { - fprintf(stderr, - "Mismatch in exit exception. " - "Should have been %d, was %d.\n", - exception, kwsysProcess_GetExitException(kp)); - } - if (value != kwsysProcess_GetExitValue(kp)) { - fprintf(stderr, - "Mismatch in exit value. " - "Should have been %d, was %d.\n", - value, kwsysProcess_GetExitValue(kp)); - } - } - - if (kwsysProcess_GetState(kp) != state) { - fprintf(stderr, - "Mismatch in state. " - "Should have been %d, was %d.\n", - state, kwsysProcess_GetState(kp)); - result = 1; - } - - /* We should have polled more times than there were data if polling - was enabled. */ - if (poll && poll < MINPOLL) { - fprintf(stderr, "Poll count is %d, which is less than %d.\n", poll, - MINPOLL); - result = 1; - } - - return result; -} - -/** - * Runs a child process and blocks until it returns. Arguments as follows: - * - * cmd = Command line to run. - * state = Expected return value of kwsysProcess_GetState after exit. - * exception = Expected return value of kwsysProcess_GetExitException. - * value = Expected return value of kwsysProcess_GetExitValue. - * share = Whether to share stdout/stderr child pipes with our pipes - * by way of kwsysProcess_SetPipeShared. If false, new pipes - * are created. - * output = If !share && !disown, whether to write the child's stdout - * and stderr output to our stdout. - * delay = If !share && !disown, adds an additional short delay to - * the pipe loop to allow the pipes to fill up; Windows only. - * timeout = Non-zero to sets a timeout in seconds via - * kwsysProcess_SetTimeout. - * poll = If !share && !disown, we count the number of 0.1 second - * intervals where the child pipes had no new data. We fail - * if not in the bounds of MINPOLL/MAXPOLL. - * repeat = Number of times to run the process. - * disown = If set, the process is disowned. - * createNewGroup = If set, the process is created in a new process group. - * interruptDelay = If non-zero, number of seconds to delay before - * interrupting the process. Note that this delay will occur - * BEFORE any reading/polling of pipes occurs and before any - * detachment occurs. - */ -int runChild(const char* cmd[], int state, int exception, int value, int share, - int output, int delay, double timeout, int poll, int repeat, - int disown, int createNewGroup, unsigned int interruptDelay) -{ - int result = 1; - kwsysProcess* kp = kwsysProcess_New(); - if (!kp) { - fprintf(stderr, "kwsysProcess_New returned NULL!\n"); - return 1; - } - while (repeat-- > 0) { - result = runChild2(kp, cmd, state, exception, value, share, output, delay, - timeout, poll, disown, createNewGroup, interruptDelay); - if (result) { - break; - } - } - kwsysProcess_Delete(kp); - return result; -} - -int main(int argc, const char* argv[]) -{ - int n = 0; - -#ifdef _WIN32 - int i; - char new_args[10][_MAX_PATH]; - LPWSTR* w_av = CommandLineToArgvW(GetCommandLineW(), &argc); - for (i = 0; i < argc; i++) { - kwsysEncoding_wcstombs(new_args[i], w_av[i], _MAX_PATH); - argv[i] = new_args[i]; - } - LocalFree(w_av); -#endif - -#if 0 - { - HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE); - DuplicateHandle(GetCurrentProcess(), out, - GetCurrentProcess(), &out, 0, FALSE, - DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); - SetStdHandle(STD_OUTPUT_HANDLE, out); - } - { - HANDLE out = GetStdHandle(STD_ERROR_HANDLE); - DuplicateHandle(GetCurrentProcess(), out, - GetCurrentProcess(), &out, 0, FALSE, - DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); - SetStdHandle(STD_ERROR_HANDLE, out); - } -#endif - if (argc == 2) { - n = atoi(argv[1]); - } else if (argc == 3 && strcmp(argv[1], "run") == 0) { - n = atoi(argv[2]); - } - /* Check arguments. */ - if (((n >= 1 && n <= 10) || n == 108 || n == 109 || n == 110) && argc == 3) { - /* This is the child process for a requested test number. */ - switch (n) { - case 1: - return test1(argc, argv); - case 2: - return test2(argc, argv); - case 3: - return test3(argc, argv); - case 4: - return test4(argc, argv); - case 5: - return test5(argc, argv); - case 6: - test6(argc, argv); - return 0; - case 7: - return test7(argc, argv); - case 8: - return test8(argc, argv); - case 9: - return test9(argc, argv); - case 10: - return test10(argc, argv); - case 108: - return test8_grandchild(argc, argv); - case 109: - return test9_grandchild(argc, argv); - case 110: - return test10_grandchild(argc, argv); - } - fprintf(stderr, "Invalid test number %d.\n", n); - return 1; - } else if (n >= 1 && n <= 10) { - /* This is the parent process for a requested test number. */ - int states[10] = { - kwsysProcess_State_Exited, kwsysProcess_State_Exited, - kwsysProcess_State_Expired, kwsysProcess_State_Exception, - kwsysProcess_State_Exited, kwsysProcess_State_Expired, - kwsysProcess_State_Exited, kwsysProcess_State_Exited, - kwsysProcess_State_Expired, /* Ctrl+C handler test */ - kwsysProcess_State_Exception /* Process group test */ - }; - int exceptions[10] = { - kwsysProcess_Exception_None, kwsysProcess_Exception_None, - kwsysProcess_Exception_None, -#ifdef CRASH_USING_ABORT - kwsysProcess_Exception_Other, -#else - kwsysProcess_Exception_Fault, -#endif - kwsysProcess_Exception_None, kwsysProcess_Exception_None, - kwsysProcess_Exception_None, kwsysProcess_Exception_None, - kwsysProcess_Exception_None, kwsysProcess_Exception_Interrupt - }; - int values[10] = { 0, 123, 1, 1, 0, 0, 0, 0, 1, 1 }; - int shares[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 }; - int outputs[10] = { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1 }; - int delays[10] = { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 }; - double timeouts[10] = { 10, 10, 10, 30, 30, 10, -1, 10, 6, 4 }; - int polls[10] = { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }; - int repeat[10] = { 257, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; - int createNewGroups[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 }; - unsigned int interruptDelays[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 3, 2 }; - int r; - const char* cmd[4]; -#ifdef _WIN32 - char* argv0 = 0; -#endif - char* test1IterationsStr = getenv("KWSYS_TEST_PROCESS_1_COUNT"); - if (test1IterationsStr) { - long int test1Iterations = strtol(test1IterationsStr, 0, 10); - if (test1Iterations > 10 && test1Iterations != LONG_MAX) { - repeat[0] = (int)test1Iterations; - } - } -#ifdef _WIN32 - if (n == 0 && (argv0 = strdup(argv[0]))) { - /* Try converting to forward slashes to see if it works. */ - char* c; - for (c = argv0; *c; ++c) { - if (*c == '\\') { - *c = '/'; - } - } - cmd[0] = argv0; - } else { - cmd[0] = argv[0]; - } -#else - cmd[0] = argv[0]; -#endif - cmd[1] = "run"; - cmd[2] = argv[1]; - cmd[3] = 0; - fprintf(stdout, "Output on stdout before test %d.\n", n); - fprintf(stderr, "Output on stderr before test %d.\n", n); - fflush(stdout); - fflush(stderr); - r = runChild(cmd, states[n - 1], exceptions[n - 1], values[n - 1], - shares[n - 1], outputs[n - 1], delays[n - 1], timeouts[n - 1], - polls[n - 1], repeat[n - 1], 0, createNewGroups[n - 1], - interruptDelays[n - 1]); - fprintf(stdout, "Output on stdout after test %d.\n", n); - fprintf(stderr, "Output on stderr after test %d.\n", n); - fflush(stdout); - fflush(stderr); -#if defined(_WIN32) - free(argv0); -#endif - return r; - } else if (argc > 2 && strcmp(argv[1], "0") == 0) { - /* This is the special debugging test to run a given command - line. */ - const char** cmd = argv + 2; - int state = kwsysProcess_State_Exited; - int exception = kwsysProcess_Exception_None; - int value = 0; - double timeout = 0; - int r = - runChild(cmd, state, exception, value, 0, 1, 0, timeout, 0, 1, 0, 0, 0); - return r; - } else { - /* Improper usage. */ - fprintf(stdout, "Usage: %s \n", argv[0]); - return 1; - } -} diff --git a/test/API/driver/kwsys/testSharedForward.c.in b/test/API/driver/kwsys/testSharedForward.c.in deleted file mode 100644 index b3eb413..0000000 --- a/test/API/driver/kwsys/testSharedForward.c.in +++ /dev/null @@ -1,27 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#if defined(CMAKE_INTDIR) -# define CONFIG_DIR_PRE CMAKE_INTDIR "/" -# define CONFIG_DIR_POST "/" CMAKE_INTDIR -#else -# define CONFIG_DIR_PRE "" -# define CONFIG_DIR_POST "" -#endif -#define @KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD "@EXEC_DIR@" -#define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD "." CONFIG_DIR_POST -#define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL 0 -#define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD \ - CONFIG_DIR_PRE "@KWSYS_NAMESPACE@TestProcess" -#define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL \ - "@KWSYS_NAMESPACE@TestProcess" -#define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_COMMAND "--command" -#define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_PRINT "--print" -#define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_LDD "--ldd" -#if defined(CMAKE_INTDIR) -# define @KWSYS_NAMESPACE@_SHARED_FORWARD_CONFIG_NAME CMAKE_INTDIR -#endif -#include <@KWSYS_NAMESPACE@/SharedForward.h> -int main(int argc, char** argv) -{ - return @KWSYS_NAMESPACE@_shared_forward_to_real(argc, argv); -} diff --git a/test/API/driver/kwsys/testSystemInformation.cxx b/test/API/driver/kwsys/testSystemInformation.cxx deleted file mode 100644 index 154517e..0000000 --- a/test/API/driver/kwsys/testSystemInformation.cxx +++ /dev/null @@ -1,106 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include "kwsysPrivate.h" -#include KWSYS_HEADER(SystemInformation.hxx) - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -# include "SystemInformation.hxx.in" -#endif - -#include - -#if defined(KWSYS_USE_LONG_LONG) -# if defined(KWSYS_IOS_HAS_OSTREAM_LONG_LONG) -# define iostreamLongLong(x) (x) -# else -# define iostreamLongLong(x) ((long)x) -# endif -#elif defined(KWSYS_USE___INT64) -# if defined(KWSYS_IOS_HAS_OSTREAM___INT64) -# define iostreamLongLong(x) (x) -# else -# define iostreamLongLong(x) ((long)x) -# endif -#else -# error "No Long Long" -#endif - -#define printMethod(info, m) std::cout << #m << ": " << info.m() << "\n" - -#define printMethod2(info, m, unit) \ - std::cout << #m << ": " << info.m() << " " << unit << "\n" - -#define printMethod3(info, m, unit) \ - std::cout << #m << ": " << iostreamLongLong(info.m) << " " << unit << "\n" - -int testSystemInformation(int, char* []) -{ - std::cout << "CTEST_FULL_OUTPUT\n"; // avoid truncation - - kwsys::SystemInformation info; - info.RunCPUCheck(); - info.RunOSCheck(); - info.RunMemoryCheck(); - printMethod(info, GetOSName); - printMethod(info, GetOSIsLinux); - printMethod(info, GetOSIsApple); - printMethod(info, GetOSIsWindows); - printMethod(info, GetHostname); - printMethod(info, GetFullyQualifiedDomainName); - printMethod(info, GetOSRelease); - printMethod(info, GetOSVersion); - printMethod(info, GetOSPlatform); - printMethod(info, Is64Bits); - printMethod(info, GetVendorString); - printMethod(info, GetVendorID); - printMethod(info, GetTypeID); - printMethod(info, GetFamilyID); - printMethod(info, GetModelID); - printMethod(info, GetExtendedProcessorName); - printMethod(info, GetSteppingCode); - printMethod(info, GetProcessorSerialNumber); - printMethod2(info, GetProcessorCacheSize, "KB"); - printMethod(info, GetLogicalProcessorsPerPhysical); - printMethod2(info, GetProcessorClockFrequency, "MHz"); - printMethod(info, GetNumberOfLogicalCPU); - printMethod(info, GetNumberOfPhysicalCPU); - printMethod(info, DoesCPUSupportCPUID); - printMethod(info, GetProcessorAPICID); - printMethod2(info, GetTotalVirtualMemory, "MB"); - printMethod2(info, GetAvailableVirtualMemory, "MB"); - printMethod2(info, GetTotalPhysicalMemory, "MB"); - printMethod2(info, GetAvailablePhysicalMemory, "MB"); - printMethod3(info, GetHostMemoryTotal(), "KiB"); - printMethod3(info, GetHostMemoryAvailable("KWSHL"), "KiB"); - printMethod3(info, GetProcMemoryAvailable("KWSHL", "KWSPL"), "KiB"); - printMethod3(info, GetHostMemoryUsed(), "KiB"); - printMethod3(info, GetProcMemoryUsed(), "KiB"); - printMethod(info, GetLoadAverage); - - for (long int i = 0; i <= 31; i++) { - if (info.DoesCPUSupportFeature(static_cast(1) << i)) { - std::cout << "CPU feature " << i << "\n"; - } - } - - /* test stack trace - */ - std::cout << "Program Stack:" << std::endl - << kwsys::SystemInformation::GetProgramStack(0, 0) << std::endl - << std::endl; - - /* test segv handler - info.SetStackTraceOnError(1); - double *d = (double*)100; - *d=0; - */ - - /* test abort handler - info.SetStackTraceOnError(1); - abort(); - */ - - return 0; -} diff --git a/test/API/driver/kwsys/testSystemTools.bin b/test/API/driver/kwsys/testSystemTools.bin deleted file mode 100644 index 961a404..0000000 Binary files a/test/API/driver/kwsys/testSystemTools.bin and /dev/null differ diff --git a/test/API/driver/kwsys/testSystemTools.cxx b/test/API/driver/kwsys/testSystemTools.cxx deleted file mode 100644 index 1f3a15b..0000000 --- a/test/API/driver/kwsys/testSystemTools.cxx +++ /dev/null @@ -1,1128 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include "kwsysPrivate.h" - -#if defined(_MSC_VER) -# pragma warning(disable : 4786) -#endif - -#include KWSYS_HEADER(FStream.hxx) -#include KWSYS_HEADER(SystemTools.hxx) - -// Work-around CMake dependency scanning limitation. This must -// duplicate the above list of headers. -#if 0 -# include "FStream.hxx.in" -# include "SystemTools.hxx.in" -#endif - -// Include with <> instead of "" to avoid getting any in-source copy -// left on disk. -#include - -#include -#include -#include /* free */ -#include /* strcmp */ -#if defined(_WIN32) && !defined(__CYGWIN__) -# include /* _umask (MSVC) / umask (Borland) */ -# ifdef _MSC_VER -# define umask _umask // Note this is still umask on Borland -# endif -#endif -#include /* umask (POSIX), _S_I* constants (Windows) */ -// Visual C++ does not define mode_t (note that Borland does, however). -#if defined(_MSC_VER) -typedef unsigned short mode_t; -#endif - -static const char* toUnixPaths[][2] = { - { "/usr/local/bin/passwd", "/usr/local/bin/passwd" }, - { "/usr/lo cal/bin/pa sswd", "/usr/lo cal/bin/pa sswd" }, - { "/usr/lo\\ cal/bin/pa\\ sswd", "/usr/lo/ cal/bin/pa/ sswd" }, - { "c:/usr/local/bin/passwd", "c:/usr/local/bin/passwd" }, - { "c:/usr/lo cal/bin/pa sswd", "c:/usr/lo cal/bin/pa sswd" }, - { "c:/usr/lo\\ cal/bin/pa\\ sswd", "c:/usr/lo/ cal/bin/pa/ sswd" }, - { "\\usr\\local\\bin\\passwd", "/usr/local/bin/passwd" }, - { "\\usr\\lo cal\\bin\\pa sswd", "/usr/lo cal/bin/pa sswd" }, - { "\\usr\\lo\\ cal\\bin\\pa\\ sswd", "/usr/lo/ cal/bin/pa/ sswd" }, - { "c:\\usr\\local\\bin\\passwd", "c:/usr/local/bin/passwd" }, - { "c:\\usr\\lo cal\\bin\\pa sswd", "c:/usr/lo cal/bin/pa sswd" }, - { "c:\\usr\\lo\\ cal\\bin\\pa\\ sswd", "c:/usr/lo/ cal/bin/pa/ sswd" }, - { "\\\\usr\\local\\bin\\passwd", "//usr/local/bin/passwd" }, - { "\\\\usr\\lo cal\\bin\\pa sswd", "//usr/lo cal/bin/pa sswd" }, - { "\\\\usr\\lo\\ cal\\bin\\pa\\ sswd", "//usr/lo/ cal/bin/pa/ sswd" }, - { nullptr, nullptr } -}; - -static bool CheckConvertToUnixSlashes(std::string const& input, - std::string const& output) -{ - std::string result = input; - kwsys::SystemTools::ConvertToUnixSlashes(result); - if (result != output) { - std::cerr << "Problem with ConvertToUnixSlashes - input: " << input - << " output: " << result << " expected: " << output << std::endl; - return false; - } - return true; -} - -static const char* checkEscapeChars[][4] = { - { "1 foo 2 bar 2", "12", "\\", "\\1 foo \\2 bar \\2" }, - { " {} ", "{}", "#", " #{#} " }, - { nullptr, nullptr, nullptr, nullptr } -}; - -static bool CheckEscapeChars(std::string const& input, - const char* chars_to_escape, char escape_char, - std::string const& output) -{ - std::string result = kwsys::SystemTools::EscapeChars( - input.c_str(), chars_to_escape, escape_char); - if (result != output) { - std::cerr << "Problem with CheckEscapeChars - input: " << input - << " output: " << result << " expected: " << output << std::endl; - return false; - } - return true; -} - -static bool CheckFileOperations() -{ - bool res = true; - const std::string testNonExistingFile(TEST_SYSTEMTOOLS_SOURCE_DIR - "/testSystemToolsNonExistingFile"); - const std::string testDotFile(TEST_SYSTEMTOOLS_SOURCE_DIR "/."); - const std::string testBinFile(TEST_SYSTEMTOOLS_SOURCE_DIR - "/testSystemTools.bin"); - const std::string testTxtFile(TEST_SYSTEMTOOLS_SOURCE_DIR - "/testSystemTools.cxx"); - const std::string testNewDir(TEST_SYSTEMTOOLS_BINARY_DIR - "/testSystemToolsNewDir"); - const std::string testNewFile(testNewDir + "/testNewFile.txt"); - - if (kwsys::SystemTools::DetectFileType(testNonExistingFile.c_str()) != - kwsys::SystemTools::FileTypeUnknown) { - std::cerr << "Problem with DetectFileType - failed to detect type of: " - << testNonExistingFile << std::endl; - res = false; - } - - if (kwsys::SystemTools::DetectFileType(testDotFile.c_str()) != - kwsys::SystemTools::FileTypeUnknown) { - std::cerr << "Problem with DetectFileType - failed to detect type of: " - << testDotFile << std::endl; - res = false; - } - - if (kwsys::SystemTools::DetectFileType(testBinFile.c_str()) != - kwsys::SystemTools::FileTypeBinary) { - std::cerr << "Problem with DetectFileType - failed to detect type of: " - << testBinFile << std::endl; - res = false; - } - - if (kwsys::SystemTools::DetectFileType(testTxtFile.c_str()) != - kwsys::SystemTools::FileTypeText) { - std::cerr << "Problem with DetectFileType - failed to detect type of: " - << testTxtFile << std::endl; - res = false; - } - - if (kwsys::SystemTools::FileLength(testBinFile) != 766) { - std::cerr << "Problem with FileLength - incorrect length for: " - << testBinFile << std::endl; - res = false; - } - - kwsys::SystemTools::Stat_t buf; - if (kwsys::SystemTools::Stat(testTxtFile.c_str(), &buf) != 0) { - std::cerr << "Problem with Stat - unable to stat text file: " - << testTxtFile << std::endl; - res = false; - } - - if (kwsys::SystemTools::Stat(testBinFile, &buf) != 0) { - std::cerr << "Problem with Stat - unable to stat bin file: " << testBinFile - << std::endl; - res = false; - } - - if (!kwsys::SystemTools::MakeDirectory(testNewDir)) { - std::cerr << "Problem with MakeDirectory for: " << testNewDir << std::endl; - res = false; - } - // calling it again should just return true - if (!kwsys::SystemTools::MakeDirectory(testNewDir)) { - std::cerr << "Problem with second call to MakeDirectory for: " - << testNewDir << std::endl; - res = false; - } - // calling with 0 pointer should return false - if (kwsys::SystemTools::MakeDirectory(nullptr)) { - std::cerr << "Problem with MakeDirectory(0)" << std::endl; - res = false; - } - // calling with an empty string should return false - if (kwsys::SystemTools::MakeDirectory(std::string())) { - std::cerr << "Problem with MakeDirectory(std::string())" << std::endl; - res = false; - } - // check existence - if (!kwsys::SystemTools::FileExists(testNewDir.c_str(), false)) { - std::cerr << "Problem with FileExists as C string and not file for: " - << testNewDir << std::endl; - res = false; - } - // check existence - if (!kwsys::SystemTools::PathExists(testNewDir)) { - std::cerr << "Problem with PathExists for: " << testNewDir << std::endl; - res = false; - } - // remove it - if (!kwsys::SystemTools::RemoveADirectory(testNewDir)) { - std::cerr << "Problem with RemoveADirectory for: " << testNewDir - << std::endl; - res = false; - } - // check existence - if (kwsys::SystemTools::FileExists(testNewDir.c_str(), false)) { - std::cerr << "After RemoveADirectory: " - << "Problem with FileExists as C string and not file for: " - << testNewDir << std::endl; - res = false; - } - // check existence - if (kwsys::SystemTools::PathExists(testNewDir)) { - std::cerr << "After RemoveADirectory: " - << "Problem with PathExists for: " << testNewDir << std::endl; - res = false; - } - // create it using the char* version - if (!kwsys::SystemTools::MakeDirectory(testNewDir.c_str())) { - std::cerr << "Problem with second call to MakeDirectory as C string for: " - << testNewDir << std::endl; - res = false; - } - - if (!kwsys::SystemTools::Touch(testNewFile, true)) { - std::cerr << "Problem with Touch for: " << testNewFile << std::endl; - res = false; - } - // calling MakeDirectory with something that is no file should fail - if (kwsys::SystemTools::MakeDirectory(testNewFile)) { - std::cerr << "Problem with to MakeDirectory for: " << testNewFile - << std::endl; - res = false; - } - - // calling with 0 pointer should return false - if (kwsys::SystemTools::FileExists(nullptr)) { - std::cerr << "Problem with FileExists(0)" << std::endl; - res = false; - } - if (kwsys::SystemTools::FileExists(nullptr, true)) { - std::cerr << "Problem with FileExists(0) as file" << std::endl; - res = false; - } - // calling with an empty string should return false - if (kwsys::SystemTools::FileExists(std::string())) { - std::cerr << "Problem with FileExists(std::string())" << std::endl; - res = false; - } - // FileExists(x, true) should return false on a directory - if (kwsys::SystemTools::FileExists(testNewDir, true)) { - std::cerr << "Problem with FileExists as file for: " << testNewDir - << std::endl; - res = false; - } - if (kwsys::SystemTools::FileExists(testNewDir.c_str(), true)) { - std::cerr << "Problem with FileExists as C string and file for: " - << testNewDir << std::endl; - res = false; - } - // FileExists(x, false) should return true even on a directory - if (!kwsys::SystemTools::FileExists(testNewDir, false)) { - std::cerr << "Problem with FileExists as not file for: " << testNewDir - << std::endl; - res = false; - } - if (!kwsys::SystemTools::FileExists(testNewDir.c_str(), false)) { - std::cerr << "Problem with FileExists as C string and not file for: " - << testNewDir << std::endl; - res = false; - } - // should work, was created as new file before - if (!kwsys::SystemTools::FileExists(testNewFile)) { - std::cerr << "Problem with FileExists for: " << testNewFile << std::endl; - res = false; - } - if (!kwsys::SystemTools::FileExists(testNewFile.c_str())) { - std::cerr << "Problem with FileExists as C string for: " << testNewFile - << std::endl; - res = false; - } - if (!kwsys::SystemTools::FileExists(testNewFile, true)) { - std::cerr << "Problem with FileExists as file for: " << testNewFile - << std::endl; - res = false; - } - if (!kwsys::SystemTools::FileExists(testNewFile.c_str(), true)) { - std::cerr << "Problem with FileExists as C string and file for: " - << testNewFile << std::endl; - res = false; - } - - // calling with an empty string should return false - if (kwsys::SystemTools::PathExists(std::string())) { - std::cerr << "Problem with PathExists(std::string())" << std::endl; - res = false; - } - // PathExists(x) should return true on a directory - if (!kwsys::SystemTools::PathExists(testNewDir)) { - std::cerr << "Problem with PathExists for: " << testNewDir << std::endl; - res = false; - } - // should work, was created as new file before - if (!kwsys::SystemTools::PathExists(testNewFile)) { - std::cerr << "Problem with PathExists for: " << testNewFile << std::endl; - res = false; - } - -// Reset umask -#if defined(_WIN32) && !defined(__CYGWIN__) - // NOTE: Windows doesn't support toggling _S_IREAD. - mode_t fullMask = _S_IWRITE; -#else - // On a normal POSIX platform, we can toggle all permissions. - mode_t fullMask = S_IRWXU | S_IRWXG | S_IRWXO; -#endif - mode_t orig_umask = umask(fullMask); - - // Test file permissions without umask - mode_t origPerm, thisPerm; - if (!kwsys::SystemTools::GetPermissions(testNewFile, origPerm)) { - std::cerr << "Problem with GetPermissions (1) for: " << testNewFile - << std::endl; - res = false; - } - - if (!kwsys::SystemTools::SetPermissions(testNewFile, 0)) { - std::cerr << "Problem with SetPermissions (1) for: " << testNewFile - << std::endl; - res = false; - } - - if (!kwsys::SystemTools::GetPermissions(testNewFile, thisPerm)) { - std::cerr << "Problem with GetPermissions (2) for: " << testNewFile - << std::endl; - res = false; - } - - if ((thisPerm & fullMask) != 0) { - std::cerr << "SetPermissions failed to set permissions (1) for: " - << testNewFile << ": actual = " << thisPerm - << "; expected = " << 0 << std::endl; - res = false; - } - - // While we're at it, check proper TestFileAccess functionality. - if (kwsys::SystemTools::TestFileAccess(testNewFile, - kwsys::TEST_FILE_WRITE)) { - std::cerr - << "TestFileAccess incorrectly indicated that this is a writable file:" - << testNewFile << std::endl; - res = false; - } - - if (!kwsys::SystemTools::TestFileAccess(testNewFile, kwsys::TEST_FILE_OK)) { - std::cerr - << "TestFileAccess incorrectly indicated that this file does not exist:" - << testNewFile << std::endl; - res = false; - } - - // Test restoring/setting full permissions. - if (!kwsys::SystemTools::SetPermissions(testNewFile, fullMask)) { - std::cerr << "Problem with SetPermissions (2) for: " << testNewFile - << std::endl; - res = false; - } - - if (!kwsys::SystemTools::GetPermissions(testNewFile, thisPerm)) { - std::cerr << "Problem with GetPermissions (3) for: " << testNewFile - << std::endl; - res = false; - } - - if ((thisPerm & fullMask) != fullMask) { - std::cerr << "SetPermissions failed to set permissions (2) for: " - << testNewFile << ": actual = " << thisPerm - << "; expected = " << fullMask << std::endl; - res = false; - } - - // Test setting file permissions while honoring umask - if (!kwsys::SystemTools::SetPermissions(testNewFile, fullMask, true)) { - std::cerr << "Problem with SetPermissions (3) for: " << testNewFile - << std::endl; - res = false; - } - - if (!kwsys::SystemTools::GetPermissions(testNewFile, thisPerm)) { - std::cerr << "Problem with GetPermissions (4) for: " << testNewFile - << std::endl; - res = false; - } - - if ((thisPerm & fullMask) != 0) { - std::cerr << "SetPermissions failed to honor umask for: " << testNewFile - << ": actual = " << thisPerm << "; expected = " << 0 - << std::endl; - res = false; - } - - // Restore umask - umask(orig_umask); - - // Restore file permissions - if (!kwsys::SystemTools::SetPermissions(testNewFile, origPerm)) { - std::cerr << "Problem with SetPermissions (4) for: " << testNewFile - << std::endl; - res = false; - } - - // Remove the test file - if (!kwsys::SystemTools::RemoveFile(testNewFile)) { - std::cerr << "Problem with RemoveFile: " << testNewFile << std::endl; - res = false; - } - - std::string const testFileMissing(testNewDir + "/testMissingFile.txt"); - if (!kwsys::SystemTools::RemoveFile(testFileMissing)) { - std::string const& msg = kwsys::SystemTools::GetLastSystemError(); - std::cerr << "RemoveFile(\"" << testFileMissing << "\") failed: " << msg - << "\n"; - res = false; - } - - std::string const testFileMissingDir(testNewDir + "/missing/file.txt"); - if (!kwsys::SystemTools::RemoveFile(testFileMissingDir)) { - std::string const& msg = kwsys::SystemTools::GetLastSystemError(); - std::cerr << "RemoveFile(\"" << testFileMissingDir << "\") failed: " << msg - << "\n"; - res = false; - } - - kwsys::SystemTools::Touch(testNewFile, true); - if (!kwsys::SystemTools::RemoveADirectory(testNewDir)) { - std::cerr << "Problem with RemoveADirectory for: " << testNewDir - << std::endl; - res = false; - } - -#ifdef KWSYS_TEST_SYSTEMTOOLS_LONG_PATHS - // Perform the same file and directory creation and deletion tests but - // with paths > 256 characters in length. - - const std::string testNewLongDir( - TEST_SYSTEMTOOLS_BINARY_DIR - "/" - "012345678901234567890123456789012345678901234567890123456789" - "012345678901234567890123456789012345678901234567890123456789" - "012345678901234567890123456789012345678901234567890123456789" - "012345678901234567890123456789012345678901234567890123456789" - "01234567890123"); - const std::string testNewLongFile( - testNewLongDir + - "/" - "012345678901234567890123456789012345678901234567890123456789" - "012345678901234567890123456789012345678901234567890123456789" - "012345678901234567890123456789012345678901234567890123456789" - "012345678901234567890123456789012345678901234567890123456789" - "0123456789.txt"); - - if (!kwsys::SystemTools::MakeDirectory(testNewLongDir)) { - std::cerr << "Problem with MakeDirectory for: " << testNewLongDir - << std::endl; - res = false; - } - - if (!kwsys::SystemTools::Touch(testNewLongFile.c_str(), true)) { - std::cerr << "Problem with Touch for: " << testNewLongFile << std::endl; - res = false; - } - - if (!kwsys::SystemTools::RemoveFile(testNewLongFile)) { - std::cerr << "Problem with RemoveFile: " << testNewLongFile << std::endl; - res = false; - } - - kwsys::SystemTools::Touch(testNewLongFile.c_str(), true); - if (!kwsys::SystemTools::RemoveADirectory(testNewLongDir)) { - std::cerr << "Problem with RemoveADirectory for: " << testNewLongDir - << std::endl; - res = false; - } -#endif - - return res; -} - -static bool CheckStringOperations() -{ - bool res = true; - - std::string test = "mary had a little lamb."; - if (kwsys::SystemTools::CapitalizedWords(test) != - "Mary Had A Little Lamb.") { - std::cerr << "Problem with CapitalizedWords " << '"' << test << '"' - << std::endl; - res = false; - } - - test = "Mary Had A Little Lamb."; - if (kwsys::SystemTools::UnCapitalizedWords(test) != - "mary had a little lamb.") { - std::cerr << "Problem with UnCapitalizedWords " << '"' << test << '"' - << std::endl; - res = false; - } - - test = "MaryHadTheLittleLamb."; - if (kwsys::SystemTools::AddSpaceBetweenCapitalizedWords(test) != - "Mary Had The Little Lamb.") { - std::cerr << "Problem with AddSpaceBetweenCapitalizedWords " << '"' << test - << '"' << std::endl; - res = false; - } - - char* cres = - kwsys::SystemTools::AppendStrings("Mary Had A", " Little Lamb."); - if (strcmp(cres, "Mary Had A Little Lamb.")) { - std::cerr << "Problem with AppendStrings " - << "\"Mary Had A\" \" Little Lamb.\"" << std::endl; - res = false; - } - delete[] cres; - - cres = kwsys::SystemTools::AppendStrings("Mary Had", " A ", "Little Lamb."); - if (strcmp(cres, "Mary Had A Little Lamb.")) { - std::cerr << "Problem with AppendStrings " - << "\"Mary Had\" \" A \" \"Little Lamb.\"" << std::endl; - res = false; - } - delete[] cres; - - if (kwsys::SystemTools::CountChar("Mary Had A Little Lamb.", 'a') != 3) { - std::cerr << "Problem with CountChar " - << "\"Mary Had A Little Lamb.\"" << std::endl; - res = false; - } - - cres = kwsys::SystemTools::RemoveChars("Mary Had A Little Lamb.", "aeiou"); - if (strcmp(cres, "Mry Hd A Lttl Lmb.")) { - std::cerr << "Problem with RemoveChars " - << "\"Mary Had A Little Lamb.\"" << std::endl; - res = false; - } - delete[] cres; - - cres = kwsys::SystemTools::RemoveCharsButUpperHex("Mary Had A Little Lamb."); - if (strcmp(cres, "A")) { - std::cerr << "Problem with RemoveCharsButUpperHex " - << "\"Mary Had A Little Lamb.\"" << std::endl; - res = false; - } - delete[] cres; - - char* cres2 = strdup("Mary Had A Little Lamb."); - kwsys::SystemTools::ReplaceChars(cres2, "aeiou", 'X'); - if (strcmp(cres2, "MXry HXd A LXttlX LXmb.")) { - std::cerr << "Problem with ReplaceChars " - << "\"Mary Had A Little Lamb.\"" << std::endl; - res = false; - } - free(cres2); - - if (!kwsys::SystemTools::StringStartsWith("Mary Had A Little Lamb.", - "Mary ")) { - std::cerr << "Problem with StringStartsWith " - << "\"Mary Had A Little Lamb.\"" << std::endl; - res = false; - } - - if (!kwsys::SystemTools::StringEndsWith("Mary Had A Little Lamb.", - " Lamb.")) { - std::cerr << "Problem with StringEndsWith " - << "\"Mary Had A Little Lamb.\"" << std::endl; - res = false; - } - - cres = kwsys::SystemTools::DuplicateString("Mary Had A Little Lamb."); - if (strcmp(cres, "Mary Had A Little Lamb.")) { - std::cerr << "Problem with DuplicateString " - << "\"Mary Had A Little Lamb.\"" << std::endl; - res = false; - } - delete[] cres; - - test = "Mary Had A Little Lamb."; - if (kwsys::SystemTools::CropString(test, 13) != "Mary ...Lamb.") { - std::cerr << "Problem with CropString " - << "\"Mary Had A Little Lamb.\"" << std::endl; - res = false; - } - - std::vector lines; - kwsys::SystemTools::Split("Mary Had A Little Lamb.", lines, ' '); - if (lines[0] != "Mary" || lines[1] != "Had" || lines[2] != "A" || - lines[3] != "Little" || lines[4] != "Lamb.") { - std::cerr << "Problem with Split " - << "\"Mary Had A Little Lamb.\"" << std::endl; - res = false; - } - - if (kwsys::SystemTools::ConvertToWindowsOutputPath( - "L://Local Mojo/Hex Power Pack/Iffy Voodoo") != - "\"L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\"") { - std::cerr << "Problem with ConvertToWindowsOutputPath " - << "\"L://Local Mojo/Hex Power Pack/Iffy Voodoo\"" << std::endl; - res = false; - } - - if (kwsys::SystemTools::ConvertToWindowsOutputPath( - "//grayson/Local Mojo/Hex Power Pack/Iffy Voodoo") != - "\"\\\\grayson\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\"") { - std::cerr << "Problem with ConvertToWindowsOutputPath " - << "\"//grayson/Local Mojo/Hex Power Pack/Iffy Voodoo\"" - << std::endl; - res = false; - } - - if (kwsys::SystemTools::ConvertToUnixOutputPath( - "//Local Mojo/Hex Power Pack/Iffy Voodoo") != - "//Local\\ Mojo/Hex\\ Power\\ Pack/Iffy\\ Voodoo") { - std::cerr << "Problem with ConvertToUnixOutputPath " - << "\"//Local Mojo/Hex Power Pack/Iffy Voodoo\"" << std::endl; - res = false; - } - - return res; -} - -static bool CheckPutEnv(const std::string& env, const char* name, - const char* value) -{ - if (!kwsys::SystemTools::PutEnv(env)) { - std::cerr << "PutEnv(\"" << env << "\") failed!" << std::endl; - return false; - } - std::string v = "(null)"; - kwsys::SystemTools::GetEnv(name, v); - if (v != value) { - std::cerr << "GetEnv(\"" << name << "\") returned \"" << v << "\", not \"" - << value << "\"!" << std::endl; - return false; - } - return true; -} - -static bool CheckUnPutEnv(const char* env, const char* name) -{ - if (!kwsys::SystemTools::UnPutEnv(env)) { - std::cerr << "UnPutEnv(\"" << env << "\") failed!" << std::endl; - return false; - } - std::string v; - if (kwsys::SystemTools::GetEnv(name, v)) { - std::cerr << "GetEnv(\"" << name << "\") returned \"" << v - << "\", not (null)!" << std::endl; - return false; - } - return true; -} - -static bool CheckEnvironmentOperations() -{ - bool res = true; - res &= CheckPutEnv("A=B", "A", "B"); - res &= CheckPutEnv("B=C", "B", "C"); - res &= CheckPutEnv("C=D", "C", "D"); - res &= CheckPutEnv("D=E", "D", "E"); - res &= CheckUnPutEnv("A", "A"); - res &= CheckUnPutEnv("B=", "B"); - res &= CheckUnPutEnv("C=D", "C"); - /* Leave "D=E" in environment so a memory checker can test for leaks. */ - return res; -} - -static bool CheckRelativePath(const std::string& local, - const std::string& remote, - const std::string& expected) -{ - std::string result = kwsys::SystemTools::RelativePath(local, remote); - if (!kwsys::SystemTools::ComparePath(expected, result)) { - std::cerr << "RelativePath(" << local << ", " << remote << ") yielded " - << result << " instead of " << expected << std::endl; - return false; - } - return true; -} - -static bool CheckRelativePaths() -{ - bool res = true; - res &= CheckRelativePath("/usr/share", "/bin/bash", "../../bin/bash"); - res &= CheckRelativePath("/usr/./share/", "/bin/bash", "../../bin/bash"); - res &= CheckRelativePath("/usr//share/", "/bin/bash", "../../bin/bash"); - res &= - CheckRelativePath("/usr/share/../bin/", "/bin/bash", "../../bin/bash"); - res &= CheckRelativePath("/usr/share", "/usr/share//bin", "bin"); - return res; -} - -static bool CheckCollapsePath(const std::string& path, - const std::string& expected, - const char* base = nullptr) -{ - std::string result = kwsys::SystemTools::CollapseFullPath(path, base); - if (!kwsys::SystemTools::ComparePath(expected, result)) { - std::cerr << "CollapseFullPath(" << path << ") yielded " << result - << " instead of " << expected << std::endl; - return false; - } - return true; -} - -static bool CheckCollapsePath() -{ - bool res = true; - res &= CheckCollapsePath("/usr/share/*", "/usr/share/*"); - res &= CheckCollapsePath("C:/Windows/*", "C:/Windows/*"); - res &= CheckCollapsePath("/usr/share/../lib", "/usr/lib"); - res &= CheckCollapsePath("/usr/share/./lib", "/usr/share/lib"); - res &= CheckCollapsePath("/usr/share/../../lib", "/lib"); - res &= CheckCollapsePath("/usr/share/.././../lib", "/lib"); - res &= CheckCollapsePath("/../lib", "/lib"); - res &= CheckCollapsePath("/../lib/", "/lib"); - res &= CheckCollapsePath("/", "/"); - res &= CheckCollapsePath("C:/", "C:/"); - res &= CheckCollapsePath("C:/../", "C:/"); - res &= CheckCollapsePath("C:/../../", "C:/"); - res &= CheckCollapsePath("../b", "../../b", "../"); - res &= CheckCollapsePath("../a/../b", "../b", "../rel"); - res &= CheckCollapsePath("a/../b", "../rel/b", "../rel"); - return res; -} - -static std::string StringVectorToString(const std::vector& vec) -{ - std::stringstream ss; - ss << "vector("; - for (std::vector::const_iterator i = vec.begin(); - i != vec.end(); ++i) { - if (i != vec.begin()) { - ss << ", "; - } - ss << *i; - } - ss << ")"; - return ss.str(); -} - -static bool CheckGetPath() -{ - const char* envName = "S"; -#ifdef _WIN32 - const char* envValue = "C:\\Somewhere\\something;D:\\Temp"; -#else - const char* envValue = "/Somewhere/something:/tmp"; -#endif - const char* registryPath = "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MyApp; MyKey]"; - - std::vector originalPaths; - originalPaths.push_back(registryPath); - - std::vector expectedPaths; - expectedPaths.push_back(registryPath); -#ifdef _WIN32 - expectedPaths.push_back("C:/Somewhere/something"); - expectedPaths.push_back("D:/Temp"); -#else - expectedPaths.push_back("/Somewhere/something"); - expectedPaths.push_back("/tmp"); -#endif - - bool res = true; - res &= CheckPutEnv(std::string(envName) + "=" + envValue, envName, envValue); - - std::vector paths = originalPaths; - kwsys::SystemTools::GetPath(paths, envName); - - if (paths != expectedPaths) { - std::cerr << "GetPath(" << StringVectorToString(originalPaths) << ", " - << envName << ") yielded " << StringVectorToString(paths) - << " instead of " << StringVectorToString(expectedPaths) - << std::endl; - res = false; - } - - res &= CheckUnPutEnv(envName, envName); - return res; -} - -static bool CheckGetFilenameName() -{ - const char* windowsFilepath = "C:\\somewhere\\something"; - const char* unixFilepath = "/somewhere/something"; - -#if defined(_WIN32) || defined(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES) - std::string expectedWindowsFilename = "something"; -#else - std::string expectedWindowsFilename = "C:\\somewhere\\something"; -#endif - std::string expectedUnixFilename = "something"; - - bool res = true; - std::string filename = kwsys::SystemTools::GetFilenameName(windowsFilepath); - if (filename != expectedWindowsFilename) { - std::cerr << "GetFilenameName(" << windowsFilepath << ") yielded " - << filename << " instead of " << expectedWindowsFilename - << std::endl; - res = false; - } - - filename = kwsys::SystemTools::GetFilenameName(unixFilepath); - if (filename != expectedUnixFilename) { - std::cerr << "GetFilenameName(" << unixFilepath << ") yielded " << filename - << " instead of " << expectedUnixFilename << std::endl; - res = false; - } - return res; -} - -static bool CheckFind() -{ - bool res = true; - const std::string testFindFileName("testFindFile.txt"); - const std::string testFindFile(TEST_SYSTEMTOOLS_BINARY_DIR "/" + - testFindFileName); - - if (!kwsys::SystemTools::Touch(testFindFile, true)) { - std::cerr << "Problem with Touch for: " << testFindFile << std::endl; - // abort here as the existence of the file only makes the test meaningful - return false; - } - - std::vector searchPaths; - searchPaths.push_back(TEST_SYSTEMTOOLS_BINARY_DIR); - if (kwsys::SystemTools::FindFile(testFindFileName, searchPaths, true) - .empty()) { - std::cerr << "Problem with FindFile without system paths for: " - << testFindFileName << std::endl; - res = false; - } - if (kwsys::SystemTools::FindFile(testFindFileName, searchPaths, false) - .empty()) { - std::cerr << "Problem with FindFile with system paths for: " - << testFindFileName << std::endl; - res = false; - } - - return res; -} - -static bool CheckIsSubDirectory() -{ - bool res = true; - - if (kwsys::SystemTools::IsSubDirectory("/foo", "/") == false) { - std::cerr << "Problem with IsSubDirectory (root - unix): " << std::endl; - res = false; - } - if (kwsys::SystemTools::IsSubDirectory("c:/foo", "c:/") == false) { - std::cerr << "Problem with IsSubDirectory (root - dos): " << std::endl; - res = false; - } - if (kwsys::SystemTools::IsSubDirectory("/foo/bar", "/foo") == false) { - std::cerr << "Problem with IsSubDirectory (deep): " << std::endl; - res = false; - } - if (kwsys::SystemTools::IsSubDirectory("/foo", "/foo") == true) { - std::cerr << "Problem with IsSubDirectory (identity): " << std::endl; - res = false; - } - if (kwsys::SystemTools::IsSubDirectory("/fooo", "/foo") == true) { - std::cerr << "Problem with IsSubDirectory (substring): " << std::endl; - res = false; - } - if (kwsys::SystemTools::IsSubDirectory("/foo/", "/foo") == true) { - std::cerr << "Problem with IsSubDirectory (prepended slash): " - << std::endl; - res = false; - } - - return res; -} - -static bool CheckGetLineFromStream() -{ - const std::string fileWithFiveCharsOnFirstLine(TEST_SYSTEMTOOLS_SOURCE_DIR - "/README.rst"); - - kwsys::ifstream file(fileWithFiveCharsOnFirstLine.c_str(), std::ios::in); - - if (!file) { - std::cerr << "Problem opening: " << fileWithFiveCharsOnFirstLine - << std::endl; - return false; - } - - std::string line; - bool has_newline = false; - bool result; - - file.seekg(0, std::ios::beg); - result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, -1); - if (!result || line.size() != 5) { - std::cerr << "First line does not have five characters: " << line.size() - << std::endl; - return false; - } - - file.seekg(0, std::ios::beg); - result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, -1); - if (!result || line.size() != 5) { - std::cerr << "First line does not have five characters after rewind: " - << line.size() << std::endl; - return false; - } - - bool ret = true; - - for (size_t size = 1; size <= 5; ++size) { - file.seekg(0, std::ios::beg); - result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, - static_cast(size)); - if (!result || line.size() != size) { - std::cerr << "Should have read " << size << " characters but got " - << line.size() << std::endl; - ret = false; - } - } - - return ret; -} - -static bool CheckGetLineFromStreamLongLine() -{ - const std::string fileWithLongLine("longlines.txt"); - std::string firstLine, secondLine; - // First line: large buffer, containing a carriage return for some reason. - firstLine.assign(2050, ' '); - firstLine += "\rfirst"; - secondLine.assign(2050, 'y'); - secondLine += "second"; - - // Create file with long lines. - { - kwsys::ofstream out(fileWithLongLine.c_str(), std::ios::binary); - if (!out) { - std::cerr << "Problem opening for write: " << fileWithLongLine - << std::endl; - return false; - } - out << firstLine << "\r\n\n" << secondLine << "\n"; - } - - kwsys::ifstream file(fileWithLongLine.c_str(), std::ios::binary); - if (!file) { - std::cerr << "Problem opening: " << fileWithLongLine << std::endl; - return false; - } - - std::string line; - bool has_newline = false; - bool result; - - // Read first line. - result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, -1); - if (!result || line != firstLine) { - std::cerr << "First line does not match, expected " << firstLine.size() - << " characters, got " << line.size() << std::endl; - return false; - } - if (!has_newline) { - std::cerr << "Expected new line to be read from first line" << std::endl; - return false; - } - - // Read empty line. - has_newline = false; - result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, -1); - if (!result || !line.empty()) { - std::cerr << "Expected successful read with an empty line, got " - << line.size() << " characters" << std::endl; - return false; - } - if (!has_newline) { - std::cerr << "Expected new line to be read for an empty line" << std::endl; - return false; - } - - // Read second line. - has_newline = false; - result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, -1); - if (!result || line != secondLine) { - std::cerr << "Second line does not match, expected " << secondLine.size() - << " characters, got " << line.size() << std::endl; - return false; - } - if (!has_newline) { - std::cerr << "Expected new line to be read from second line" << std::endl; - return false; - } - - return true; -} - -static bool writeFile(const char* fileName, const char* data) -{ - kwsys::ofstream out(fileName, std::ios::binary); - out << data; - if (!out) { - std::cerr << "Failed to write file: " << fileName << std::endl; - return false; - } - return true; -} - -static std::string readFile(const char* fileName) -{ - kwsys::ifstream in(fileName, std::ios::binary); - std::stringstream sstr; - sstr << in.rdbuf(); - std::string data = sstr.str(); - if (!in) { - std::cerr << "Failed to read file: " << fileName << std::endl; - return std::string(); - } - return data; -} - -struct -{ - const char* a; - const char* b; - bool differ; -} diff_test_cases[] = { { "one", "one", false }, - { "one", "two", true }, - { "", "", false }, - { "\n", "\r\n", false }, - { "one\n", "one\n", false }, - { "one\r\n", "one\n", false }, - { "one\n", "one", false }, - { "one\ntwo", "one\ntwo", false }, - { "one\ntwo", "one\r\ntwo", false } }; - -static bool CheckTextFilesDiffer() -{ - const int num_test_cases = - sizeof(diff_test_cases) / sizeof(diff_test_cases[0]); - for (int i = 0; i < num_test_cases; ++i) { - if (!writeFile("file_a", diff_test_cases[i].a) || - !writeFile("file_b", diff_test_cases[i].b)) { - return false; - } - if (kwsys::SystemTools::TextFilesDiffer("file_a", "file_b") != - diff_test_cases[i].differ) { - std::cerr << "Incorrect TextFilesDiffer result for test case " << i + 1 - << "." << std::endl; - return false; - } - } - - return true; -} - -static bool CheckCopyFileIfDifferent() -{ - bool ret = true; - const int num_test_cases = - sizeof(diff_test_cases) / sizeof(diff_test_cases[0]); - for (int i = 0; i < num_test_cases; ++i) { - if (!writeFile("file_a", diff_test_cases[i].a) || - !writeFile("file_b", diff_test_cases[i].b)) { - return false; - } - const char* cptarget = - i < 4 ? TEST_SYSTEMTOOLS_BINARY_DIR "/file_b" : "file_b"; - if (!kwsys::SystemTools::CopyFileIfDifferent("file_a", cptarget)) { - std::cerr << "CopyFileIfDifferent() returned false for test case " - << i + 1 << "." << std::endl; - ret = false; - continue; - } - std::string bdata = readFile("file_b"); - if (diff_test_cases[i].a != bdata) { - std::cerr << "Incorrect CopyFileIfDifferent file contents in test case " - << i + 1 << "." << std::endl; - ret = false; - continue; - } - } - - return ret; -} - -int testSystemTools(int, char* []) -{ - bool res = true; - - int cc; - for (cc = 0; toUnixPaths[cc][0]; cc++) { - res &= CheckConvertToUnixSlashes(toUnixPaths[cc][0], toUnixPaths[cc][1]); - } - - // Special check for ~ - std::string output; - if (kwsys::SystemTools::GetEnv("HOME", output)) { - output += "/foo bar/lala"; - res &= CheckConvertToUnixSlashes("~/foo bar/lala", output); - } - - for (cc = 0; checkEscapeChars[cc][0]; cc++) { - res &= CheckEscapeChars(checkEscapeChars[cc][0], checkEscapeChars[cc][1], - *checkEscapeChars[cc][2], checkEscapeChars[cc][3]); - } - - res &= CheckFileOperations(); - - res &= CheckStringOperations(); - - res &= CheckEnvironmentOperations(); - - res &= CheckRelativePaths(); - - res &= CheckCollapsePath(); - - res &= CheckGetPath(); - - res &= CheckFind(); - - res &= CheckIsSubDirectory(); - - res &= CheckGetLineFromStream(); - - res &= CheckGetLineFromStreamLongLine(); - - res &= CheckGetFilenameName(); - - res &= CheckTextFilesDiffer(); - - res &= CheckCopyFileIfDifferent(); - - return res ? 0 : 1; -} diff --git a/test/API/driver/kwsys/testSystemTools.h.in b/test/API/driver/kwsys/testSystemTools.h.in deleted file mode 100644 index 022e36e..0000000 --- a/test/API/driver/kwsys/testSystemTools.h.in +++ /dev/null @@ -1,12 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#ifndef @KWSYS_NAMESPACE@_testSystemtools_h -#define @KWSYS_NAMESPACE@_testSystemtools_h - -#define EXECUTABLE_OUTPUT_PATH "@CMAKE_CURRENT_BINARY_DIR@" - -#define TEST_SYSTEMTOOLS_SOURCE_DIR "@TEST_SYSTEMTOOLS_SOURCE_DIR@" -#define TEST_SYSTEMTOOLS_BINARY_DIR "@TEST_SYSTEMTOOLS_BINARY_DIR@" -#cmakedefine KWSYS_TEST_SYSTEMTOOLS_LONG_PATHS - -#endif diff --git a/test/API/driver/kwsys/testTerminal.c b/test/API/driver/kwsys/testTerminal.c deleted file mode 100644 index 652830c..0000000 --- a/test/API/driver/kwsys/testTerminal.c +++ /dev/null @@ -1,22 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ -#include "kwsysPrivate.h" -#include KWSYS_HEADER(Terminal.h) - -/* Work-around CMake dependency scanning limitation. This must - duplicate the above list of headers. */ -#if 0 -# include "Terminal.h.in" -#endif - -int testTerminal(int argc, char* argv[]) -{ - (void)argc; - (void)argv; - kwsysTerminal_cfprintf(kwsysTerminal_Color_ForegroundYellow | - kwsysTerminal_Color_BackgroundBlue | - kwsysTerminal_Color_AssumeTTY, - stdout, "Hello %s!", "World"); - fprintf(stdout, "\n"); - return 0; -} diff --git a/test/API/driver/kwsys/update-gitsetup.bash b/test/API/driver/kwsys/update-gitsetup.bash deleted file mode 100644 index aa83cb8..0000000 --- a/test/API/driver/kwsys/update-gitsetup.bash +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -x -shopt -s dotglob - -readonly name="GitSetup" -readonly ownership="GitSetup Upstream " -readonly subtree="GitSetup" -readonly repo="https://gitlab.kitware.com/utils/gitsetup.git" -readonly tag="setup" -readonly shortlog=false -readonly paths=" -" - -extract_source () { - git_archive -} - -. "${BASH_SOURCE%/*}/update-third-party.bash" diff --git a/test/API/driver/kwsys/update-third-party.bash b/test/API/driver/kwsys/update-third-party.bash deleted file mode 100644 index 3b8358e..0000000 --- a/test/API/driver/kwsys/update-third-party.bash +++ /dev/null @@ -1,169 +0,0 @@ -#============================================================================= -# Copyright 2015-2016 Kitware, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#============================================================================= - -######################################################################## -# Script for updating third party packages. -# -# This script should be sourced in a project-specific script which sets -# the following variables: -# -# name -# The name of the project. -# ownership -# A git author name/email for the commits. -# subtree -# The location of the thirdparty package within the main source -# tree. -# repo -# The git repository to use as upstream. -# tag -# The tag, branch or commit hash to use for upstream. -# shortlog -# Optional. Set to 'true' to get a shortlog in the commit message. -# -# Additionally, an "extract_source" function must be defined. It will be -# run within the checkout of the project on the requested tag. It should -# should place the desired tree into $extractdir/$name-reduced. This -# directory will be used as the newest commit for the project. -# -# 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. -######################################################################## - -######################################################################## -# Utility functions -######################################################################## -git_archive () { - git archive --worktree-attributes --prefix="$name-reduced/" HEAD -- $paths | \ - tar -C "$extractdir" -x -} - -die () { - echo >&2 "$@" - exit 1 -} - -warn () { - echo >&2 "warning: $@" -} - -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 basehash="$( git rev-list --author="$ownership" --grep="$basehash_regex" -n 1 HEAD )" -readonly upstream_old_short="$( git cat-file commit "$basehash" | sed -n '/'"$basehash_regex"'/ {s/.*(//;s/)//;p}' | egrep '^[0-9a-f]+$' )" - -######################################################################## -# Sanity checking -######################################################################## -[ -n "$name" ] || \ - die "'name' is empty" -[ -n "$ownership" ] || \ - die "'ownership' is empty" -[ -n "$subtree" ] || \ - die "'subtree' is empty" -[ -n "$repo" ] || \ - die "'repo' is empty" -[ -n "$tag" ] || \ - die "'tag' is empty" -[ -n "$basehash" ] || \ - warn "'basehash' is empty; performing initial import" -readonly do_shortlog="${shortlog-false}" - -readonly workdir="$PWD/work" -readonly upstreamdir="$workdir/upstream" -readonly extractdir="$workdir/extract" - -[ -d "$workdir" ] && \ - die "error: workdir '$workdir' already exists" - -trap "rm -rf '$workdir'" EXIT - -# Get upstream -git clone "$repo" "$upstreamdir" - -if [ -n "$basehash" ]; then - # Use the existing package's history - git worktree add "$extractdir" "$basehash" - # Clear out the working tree - pushd "$extractdir" - git ls-files | xargs rm -v - find . -type d -empty -delete - popd -else - # Create a repo to hold this package's history - mkdir -p "$extractdir" - git -C "$extractdir" init -fi - -# Extract the subset of upstream we care about -pushd "$upstreamdir" -git checkout "$tag" -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" )" -readonly upstream_date="$( echo "$upstream_datetime" | grep -o -e "$regex_date" )" -if $do_shortlog && [ -n "$basehash" ]; then - readonly commit_shortlog=" - -Upstream Shortlog ------------------ - -$( git shortlog --no-merges --abbrev=8 --format='%h %s' "$upstream_old_short".."$upstream_hash" )" -else - readonly commit_shortlog="" -fi -extract_source || \ - die "failed to extract source" -popd - -[ -d "$extractdir/$name-reduced" ] || \ - die "expected directory to extract does not exist" -readonly commit_summary="$name $upstream_date ($upstream_hash_short)" - -# Commit the subset -pushd "$extractdir" -mv -v "$name-reduced/"* . -rmdir "$name-reduced/" -git add -A . -git commit -n --author="$ownership" --date="$upstream_datetime" -F - <<-EOF -$commit_summary - -Code extracted from: - - $repo - -at commit $upstream_hash ($tag).$commit_shortlog -EOF -git branch -f "upstream-$name" -popd - -# Merge the subset into this repository -if [ -n "$basehash" ]; then - git merge --log -s recursive "-Xsubtree=$subtree/" --no-commit "upstream-$name" -else - unrelated_histories_flag="" - if git merge --help | grep -q -e allow-unrelated-histories; then - unrelated_histories_flag="--allow-unrelated-histories " - fi - readonly unrelated_histories_flag - - git fetch "$extractdir" "upstream-$name:upstream-$name" - git merge --log -s ours --no-commit $unrelated_histories_flag "upstream-$name" - git read-tree -u --prefix="$subtree/" "upstream-$name" -fi -git commit --no-edit -git branch -d "upstream-$name" diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d52beb0..fe52cd3 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -395,24 +395,6 @@ if (HDF5_BUILD_UTILS) set (H5_TESTS ${H5_TESTS} mirror_vfd) endif () -set (HDF5_API_TESTS - attribute - dataset - datatype - file - group - link - misc - object -) - -if (HDF5_TEST_API_ENABLE_ASYNC) - set (HDF5_API_TESTS - ${HDF5_API_TESTS} - async - ) -endif () - macro (ADD_H5_EXE file) add_executable (${file} ${HDF5_TEST_SOURCE_DIR}/${file}.c) target_include_directories (${file} PRIVATE "${HDF5_SRC_INCLUDE_DIRS};${HDF5_SRC_BINARY_DIR};${HDF5_TEST_BINARY_DIR};$<$:${MPI_C_INCLUDE_DIRS}>") @@ -897,8 +879,10 @@ if (HDF5_ENABLE_FORMATTERS) clang_format (HDF5_TEST_use_disable_mdc_flushes_FORMAT use_disable_mdc_flushes) endif () -add_subdirectory (API) - if (HDF5_TEST_SERIAL) include (CMakeTests.cmake) endif () + +if (HDF5_TEST_API) + add_subdirectory (API) +endif () diff --git a/testpar/API/CMakeLists.txt b/testpar/API/CMakeLists.txt index 5eb69c4..e907078 100644 --- a/testpar/API/CMakeLists.txt +++ b/testpar/API/CMakeLists.txt @@ -9,16 +9,31 @@ # help@hdfgroup.org. # -#------------------------------------------------------------------------------ -# Set module path -#------------------------------------------------------------------------------ -set(HDF5_TEST_API_CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake") -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${HDF5_TEST_API_CMAKE_MODULE_PATH}) +cmake_minimum_required (VERSION 3.18) +project (HDF5_TEST_PAR_API C) #------------------------------------------------------------------------------ -# Setup for API tests +# Define for API tests #------------------------------------------------------------------------------ +set (HDF5_API_TESTS + attribute + dataset + datatype + file + group + link + misc + object +) + +if (HDF5_TEST_API_ENABLE_ASYNC) + set (HDF5_API_TESTS + ${HDF5_API_TESTS} + async + ) +endif () + # Ported HDF5 tests set (HDF5_API_PAR_TESTS_EXTRA t_bigio diff --git a/testpar/CMakeLists.txt b/testpar/CMakeLists.txt index d34b800..6bb5fa6 100644 --- a/testpar/CMakeLists.txt +++ b/testpar/CMakeLists.txt @@ -104,30 +104,14 @@ set (H5P_TESTS t_vfd ) -set (HDF5_API_TESTS - attribute - dataset - datatype - file - group - link - misc - object -) - -if (HDF5_TEST_API_ENABLE_ASYNC) - set (HDF5_API_TESTS - ${HDF5_API_TESTS} - async - ) -endif () - foreach (h5_testp ${H5P_TESTS}) ADD_H5P_EXE(${h5_testp}) endforeach () -add_subdirectory (API) - if (HDF5_TEST_PARALLEL) include (CMakeTests.cmake) endif () + +if (HDF5_TEST_API) + add_subdirectory (API) +endif () -- cgit v0.12 From cc1157b7a3c739c03ff1d300f0efe5552ed3f23a Mon Sep 17 00:00:00 2001 From: jhendersonHDF Date: Wed, 3 May 2023 11:46:31 -0500 Subject: Minor tidying of API tests files (#2878) * Minor tidying of API tests files * Remove old API test configuration setting --- test/API/CMakeLists.txt | 1 + test/API/README.md | 15 ++++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/test/API/CMakeLists.txt b/test/API/CMakeLists.txt index c2f95bd..dd2bca2 100644 --- a/test/API/CMakeLists.txt +++ b/test/API/CMakeLists.txt @@ -9,6 +9,7 @@ # help@hdfgroup.org. # + cmake_minimum_required (VERSION 3.18) project (HDF5_TEST_API C) diff --git a/test/API/README.md b/test/API/README.md index d57472d..aec6eaa 100644 --- a/test/API/README.md +++ b/test/API/README.md @@ -1,12 +1,13 @@ # HDF5 API Tests -This directory contains several test applications that exercise [HDF5](https://github.com/HDFGroup/hdf5)'s +This directory contains several test applications that exercise HDF5's public API and serve as regression tests for HDF5 [VOL Connectors](https://portal.hdfgroup.org/display/HDF5/Virtual+Object+Layer). ## Build Process and options -These HDF5 API tests are enabled and built by default, but can be disabled if desired. -The following build options are available to influence how the API tests get built: +These HDF5 API tests are disabled by default, but can be enabled by passing the +`-DHDF5_TEST_API=ON` option to CMake. The following build options are available +to influence how the API tests get built: ### CMake @@ -39,9 +40,9 @@ Currently unsupported ### Usage -These API tests currently only support usage with HDF5 VOL connectors that can be loaded dynamically -as a plugin. For information on how to build a VOL connector in this manner, refer to section 2.3 of -the [HDF5 VOL Connector Author Guide](https://portal.hdfgroup.org/display/HDF5/HDF5+VOL+Connector+Authors+Guide?preview=/53610813/59903039/vol_connector_author_guide.pdf). +These API tests currently only support usage with the native HDF5 VOL connector and HDF5 VOL +connectors that can be loaded dynamically as a plugin. For information on how to build a VOL +connector in this manner, refer to section 2.3 of the [HDF5 VOL Connector Author Guide](https://portal.hdfgroup.org/display/HDF5/HDF5+VOL+Connector+Authors+Guide?preview=/53610813/59903039/vol_connector_author_guide.pdf). TODO: section on building VOL connectors alongside HDF5 for use with tests @@ -64,7 +65,7 @@ and use it when running tests. If HDF5 is unable to locate or load the VOL conne will fall back to running the tests with the native HDF5 VOL connector and an error similar to the following will appear in the test output: - HDF5-DIAG: Error detected in HDF5 (1.13.0) MPI-process 0: + HDF5-DIAG: Error detected in HDF5 (X.XX.X) MPI-process 0: #000: /home/user/git/hdf5/src/H5.c line 1010 in H5open(): library initialization failed major: Function entry/exit minor: Unable to initialize object -- cgit v0.12 From 7bcbf16abc3aa23b6709199c8c1f0120312aca6a Mon Sep 17 00:00:00 2001 From: Scot Breitenfeld Date: Wed, 3 May 2023 11:46:59 -0500 Subject: fixed args in execvp for h5fuse (#2885) --- testpar/t_subfiling_vfd.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/testpar/t_subfiling_vfd.c b/testpar/t_subfiling_vfd.c index f827aa5..0841923 100644 --- a/testpar/t_subfiling_vfd.c +++ b/testpar/t_subfiling_vfd.c @@ -1888,7 +1888,7 @@ test_subfiling_h5fuse(void) if (pid == 0) { char *tmp_filename; - char *args[6]; + char *args[7]; tmp_filename = HDmalloc(PATH_MAX); VRFY(tmp_filename, "HDmalloc succeeded"); @@ -1900,9 +1900,10 @@ test_subfiling_h5fuse(void) args[0] = HDstrdup("env"); args[1] = HDstrdup("sh"); args[2] = HDstrdup("h5fuse.sh"); - args[3] = HDstrdup("-q -f"); - args[4] = tmp_filename; - args[5] = NULL; + args[3] = HDstrdup("-q"); + args[4] = HDstrdup("-f"); + args[5] = tmp_filename; + args[6] = NULL; /* Call h5fuse script from MPI rank 0 */ HDexecvp("env", args); -- cgit v0.12 From 0a4181c0be023a3899321c57771458daf60ee9c7 Mon Sep 17 00:00:00 2001 From: jhendersonHDF Date: Wed, 3 May 2023 11:47:17 -0500 Subject: Fix Autotools internal-debug=all builds (#2886) --- src/H5Ocache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/H5Ocache.c b/src/H5Ocache.c index 72261fa..66b092a 100644 --- a/src/H5Ocache.c +++ b/src/H5Ocache.c @@ -534,7 +534,7 @@ H5O__cache_notify(H5AC_notify_action_t action, void *_thing) for (u = 0; u < oh->nmesgs; u++) if (oh->mesg[u].chunkno == 0) oh->mesg[u].dirty = FALSE; -#ifdef H5O_DEBUG +#ifndef NDEBUG /* Reset the number of messages dirtied by decoding */ oh->ndecode_dirtied = 0; #endif -- cgit v0.12 From 6b7c0449b29880f8412d468e96b30321052ce9ae Mon Sep 17 00:00:00 2001 From: jhendersonHDF Date: Wed, 3 May 2023 15:24:14 -0500 Subject: Remove references to old MANIFEST file (#2890) --- CONTRIBUTING.md | 1 - fortran/src/README | 1 - 2 files changed, 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 687e981..a16e845 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -125,7 +125,6 @@ Please make sure that you check the items applicable to your pull request: * [ ] Does the new feature require a change to an existing API? See "API Compatibility Macros" document (https://portal.hdfgroup.org/display/HDF5/API+Compatibility+Macros) * Documentation * [ ] Was the change described in the release_docs/RELEASE.txt file? - * [ ] Was MANIFEST updated if new files had been added to the source? * [ ] Was the new function documented in the corresponding public header file using [Doxygen](https://docs.hdfgroup.org/hdf5/develop/_r_m_t.html)? * [ ] Was new functionality documented for the HDF5 community (the level of documentation depends on the feature; ask us what would be appropriate) * Testing diff --git a/fortran/src/README b/fortran/src/README index f9316b5..f73a59a 100644 --- a/fortran/src/README +++ b/fortran/src/README @@ -130,5 +130,4 @@ Procedure for adding a new file to the repository Add the name of the file to the: (1) Makefile.am located in the same directory as the newfile (2) CMakeLists.txt located in the same directory as the newfile - (3) MANIFEST located in the top level directory -- cgit v0.12 From 3fbdd700cb68b4a7f6f9ac44eebcf677bb71fd0a Mon Sep 17 00:00:00 2001 From: jhendersonHDF Date: Wed, 3 May 2023 16:11:38 -0500 Subject: Add RELEASE.txt entry for API tests (#2889) --- release_docs/RELEASE.txt | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/release_docs/RELEASE.txt b/release_docs/RELEASE.txt index 01e1235..ec82272 100644 --- a/release_docs/RELEASE.txt +++ b/release_docs/RELEASE.txt @@ -47,6 +47,48 @@ New Features Configuration: ------------- + - Added new CMake options for building and running HDF5 API tests + (Experimental) + + HDF5 API tests are an experimental feature, primarily targeted + toward HDF5 VOL connector authors, that is currently being developed. + These tests exercise the HDF5 API and are being integrated back + into the HDF5 library from the HDF5 VOL tests repository + (https://github.com/HDFGroup/vol-tests). To support this feature, + the following new options have been added to CMake: + + * HDF5_TEST_API: ON/OFF (Default: OFF) + + Controls whether the HDF5 API tests will be built. These tests + will only be run during testing of HDF5 if the HDF5_TEST_SERIAL + (for serial tests) and HDF5_TEST_PARALLEL (for parallel tests) + options are enabled. + + * HDF5_TEST_API_INSTALL: ON/OFF (Default: OFF) + + Controls whether the HDF5 API test executables will be installed + on the system alongside the HDF5 library. This option is currently + not functional. + + * HDF5_TEST_API_ENABLE_ASYNC: ON/OFF (Default: OFF) + + Controls whether the HDF5 Async API tests will be built. These + tests will only be run if the VOL connector used supports Async + operations. + + * HDF5_TEST_API_ENABLE_DRIVER: ON/OFF (Default: OFF) + + Controls whether to build the HDF5 API test driver program. This + test driver program is useful for VOL connectors that use a + client/server model where the server needs to be up and running + before the VOL connector can function. This option is currently + not functional. + + * HDF5_TEST_API_SERVER: String (Default: "") + + Used to specify a path to the server executable that the test + driver program should execute. + - Added support for CMake presets file. CMake supports two main files, CMakePresets.json and CMakeUserPresets.json, -- cgit v0.12