summaryrefslogtreecommitdiffstats
path: root/HDF5Examples/FORTRAN/H5G/h5ex_g_traverse.F90
diff options
context:
space:
mode:
Diffstat (limited to 'HDF5Examples/FORTRAN/H5G/h5ex_g_traverse.F90')
-rw-r--r--HDF5Examples/FORTRAN/H5G/h5ex_g_traverse.F90249
1 files changed, 249 insertions, 0 deletions
diff --git a/HDF5Examples/FORTRAN/H5G/h5ex_g_traverse.F90 b/HDF5Examples/FORTRAN/H5G/h5ex_g_traverse.F90
new file mode 100644
index 0000000..198d437
--- /dev/null
+++ b/HDF5Examples/FORTRAN/H5G/h5ex_g_traverse.F90
@@ -0,0 +1,249 @@
+!************************************************************
+!
+! This example shows a way to recursively traverse the file
+! using h5literate and h5literate_by_name_f. The method shown
+! here guarantees that
+! the recursion will not enter an infinite loop, but does
+! not prevent objects from being visited more than once.
+! The program prints the directory structure of the file
+! specified in filename. The default file used by this example
+! implements the structure described in the User's Guide,
+! chapter 4, figure 26.
+!
+! ************************************************************
+
+! An optional include to determine the correct HDF5 version
+! for selecting the appropriate HDF5 API parameters. This is
+! not part of the HDF5 library and is generally unnecessary.
+#include "h5_version.h"
+
+MODULE g_traverse
+
+ USE HDF5
+ USE ISO_C_BINDING
+ IMPLICIT NONE
+
+ CHARACTER(LEN=18) :: filename = "h5ex_g_traverse.h5"
+
+ !
+ ! Define operator data structure type for H5Literate callback.
+ ! During recursive iteration, these structures will form a
+ ! linked list that can be searched for duplicate groups,
+ ! preventing infinite recursion.
+ !
+ TYPE :: opdata
+ INTEGER :: recurs ! Recursion level. 0=root
+ TYPE(opdata), POINTER :: prev ! Pointer to previous opdata
+#if H5_VERSION_GE(1, 12, 0)
+ TYPE(H5O_TOKEN_T_F) :: token ! Group token
+#else
+ INTEGER(haddr_t) :: token ! Group address
+#endif
+ END TYPE opdata
+
+CONTAINS
+
+ !
+ ! OPERATOR FUNCTION TO BE CALLED BY H5LITERATE_F
+ !
+ ! ************************************************************
+ !
+ ! Operator function. This function prints the name and type
+ ! of the object passed to it. If the object is a group, it
+ ! is first checked against other groups in its path using
+ ! the group_check function, then if it is not a duplicate,
+ ! H5Literate is called for that group. This guarantees that
+ ! the program will not enter infinite recursion due to a
+ ! circular path in the file.
+ !
+ ! ************************************************************
+
+ RECURSIVE INTEGER(KIND=C_INT) FUNCTION op_func(loc_id, name, info, operator_data) RESULT(ret_val) BIND(C)
+
+ USE HDF5
+ USE ISO_C_BINDING
+ IMPLICIT NONE
+
+ INTEGER(hid_t), VALUE :: loc_id
+ CHARACTER(LEN=1), DIMENSION(1:10) :: name ! Must have LEN=1 for bind(C) strings
+ TYPE(C_PTR), VALUE :: info
+ TYPE(C_PTR), VALUE :: operator_data
+
+ INTEGER :: status, return_val
+ TYPE(h5o_info_t), TARGET :: infobuf
+ TYPE(C_PTR) :: ptr
+ CHARACTER(LEN=10) :: name_string
+ INTEGER :: i
+ TYPE(opdata), POINTER :: od
+ TYPE(opdata), TARGET :: nextod
+ INTEGER(HSIZE_T) :: idx
+
+ TYPE(C_PTR) :: ptr2
+ TYPE(C_FUNPTR) :: funptr
+
+ CHARACTER(LEN=10) :: space
+ INTEGER :: spaces ! Number of whitespaces to prepend to output
+ INTEGER :: len
+
+ ret_val = 0
+
+ name_string(1:10) = " "
+ len = 0
+ DO
+ len = len + 1
+ IF(name(len)(1:1).EQ.C_NULL_CHAR) EXIT
+ name_string(len:len) = name(len)(1:1)
+ ENDDO
+ len = len - 1 ! subtract NULL character
+
+ space(1:10) = " "
+
+ CALL C_F_POINTER(operator_data, od)
+ !
+ ! Get type of the object and display its name and type.
+ ! The name of the object is passed to this function by
+ ! the Library.
+ !
+ CALL H5Oget_info_by_name_f(loc_id, name_string, infobuf, status)
+
+ spaces = 2*(od%recurs+1)
+
+ WRITE(*,'(A)', ADVANCE='NO') space(1:spaces) ! Format output
+
+
+ IF(infobuf%type.EQ.H5O_TYPE_GROUP_F)THEN
+
+ WRITE(*,'("Group: ",A," {")') name_string(1:len)
+
+!
+! Check group address/token against linked list of operator
+! data structures. We will always run the check, as the
+! reference count cannot be relied upon if there are
+! symbolic links, and H5Oget_info_by_name always follows
+! symbolic links. Alternatively we could use H5Lget_info
+! and never recurse on groups discovered by symbolic
+! links, however it could still fail if an object's
+! reference count was manually manipulated with
+! H5Odecr_refcount.
+!
+
+ i = group_check(loc_id, od, infobuf%token)
+
+ IF(i.EQ.1)THEN
+ WRITE(*,'(A)') space(1:spaces)//" Warning: Loop detected!"
+ ELSE
+
+ nextod%recurs = od%recurs + 1
+ nextod%prev => od
+ nextod%token = infobuf%token
+ idx = 0
+ ptr2 = C_LOC(nextod%recurs)
+ funptr = C_FUNLOC(op_func)
+ CALL h5literate_by_name_f(loc_id, name_string, H5_INDEX_NAME_F, H5_ITER_NATIVE_F, idx, &
+ funptr, ptr2, ret_val, status)
+
+ ENDIF
+ WRITE(*,'(A)') space(1:spaces)//"}"
+ RETURN
+ ELSE IF(infobuf%type.EQ.H5O_TYPE_DATASET_F)THEN
+ WRITE(*,'("Dataset: ",A)') name_string(1:len)
+ ELSE IF(infobuf%type.EQ.H5O_TYPE_NAMED_DATATYPE_F)THEN
+ WRITE(*,'("Datatype: ",A)') name_string(1:len)
+ ELSE
+ WRITE(*,'("Unknown: ",A)') name_string(1:len)
+ ENDIF
+
+END FUNCTION op_func
+
+!************************************************************
+!
+! This function recursively searches the linked list of
+! opdata structures for one whose address/token matches
+! target_token. Returns 1 if a match is found, and 0
+! otherwise.
+!
+! ************************************************************/
+
+ INTEGER RECURSIVE FUNCTION group_check(loc_id, od, target_token) result(g_c)
+
+ IMPLICIT NONE
+ INTEGER :: i
+ TYPE(opdata), POINTER :: od
+ INTEGER(HID_T) :: loc_id
+ INTEGER :: cmp_value
+#if H5_VERSION_GE(1, 14, 3)
+ TYPE(H5O_TOKEN_T_F) :: target_token
+ INTEGER :: status
+ CALL h5otoken_cmp_f(loc_id, od%token, target_token, cmp_value, status)
+#else
+#if H5_VERSION_GE(1, 12, 0)
+#error "example only supports HDF5 versions < 1.12.0 and > 1.14.2"
+#else
+ INTEGER(haddr_t) :: target_token
+ cmp_value = -1
+ IF(od%token .EQ. target_token) cmp_value = 0
+#endif
+#endif
+ IF (cmp_value.EQ.0)THEN
+ g_c = 1 ! Addresses/token match
+ ELSE IF (od%recurs.EQ.0)THEN
+ g_c = 0 ! Root group reached with no matches
+ ELSE
+ ! Recursively examine the next node
+ g_c = group_check(loc_id, od%prev, target_token)
+ END IF
+ END FUNCTION group_check
+
+END MODULE g_traverse
+
+PROGRAM main
+
+ USE HDF5
+ USE ISO_C_BINDING
+
+ USE g_traverse
+
+ IMPLICIT NONE
+
+ INTEGER(hid_t) :: file ! Handle
+ INTEGER :: status
+ TYPE(h5o_info_t) :: infobuf
+ TYPE(opdata), TARGET :: od
+ TYPE(C_PTR) :: ptr
+ INTEGER(hsize_t) :: idx
+ INTEGER :: ret_value
+ TYPE(C_FUNPTR) :: funptr
+ !
+ ! Initialize FORTRAN interface.
+ !
+ CALL h5open_f(status)
+ !
+ ! Open file and initialize the operator data structure.
+ !
+ CALL H5Fopen_f(filename, H5F_ACC_RDONLY_F, file, status)
+
+ CALL h5oget_info_by_name_f(file, "/", infobuf, status)
+
+ od%recurs = 0
+ od%prev => NULL()
+ od%token = infobuf%token
+ !
+ ! Print the root group and formatting, begin iteration.
+ !
+ idx = 0
+ funptr = C_FUNLOC(op_func)
+ ptr = C_LOC(od)
+
+ WRITE(*,'(A)') "/ {"
+ CALL H5Literate_f(file, H5_INDEX_NAME_F, H5_ITER_NATIVE_F, idx, funptr, ptr, ret_value, status)
+ WRITE(*,'(A)') "}"
+
+ !
+ ! Close and release resources.
+ !
+ CALL H5Fclose_f(file, status)
+
+END PROGRAM main
+
+
+