summaryrefslogtreecommitdiffstats
path: root/HDF5Examples/FORTRAN/H5G/h5ex_g_traverse.F90
blob: 198d437003afd68ce66d60e290b00d90fa54ef0d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
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