Search code examples
fortranhdf5

Get length of HDF5 filename in Fortran?


I'm trying to get the filename of an HDF5 object in Fortran, for which I do not know the length of the filename in advance. The HDF5 documentation says this can be accomplished by passing NULL to h5fget_name:

If the length of the name, which determines the required value of size, is unknown, a preliminary H5Fget_name call can be made by setting name to NULL.

However, it is unclear how to accomplish this from Fortran code. Per the above language in the documentation, something like this should work:

  function get_hdf5_filename(obj_id) result(filename)

    use hdf5
    use iso_c_binding, ONLY: c_null_ptr

    ! Arguments
    integer(HID_T), intent(in)::obj_id
        !! Handle of HDF5 object

    ! Result
    character(:), allocatable::filename

    integer(SIZE_T)::size = 0
        !! Length of filename

    integer::hdferr
        !! HDF5 error code

    call h5fget_name_f(obj_id, c_null_ptr, size, hdferr)

    allocate (character(size)::filename)

    call h5fget_name_f(obj_id, filename, size, hdferr)

  end function get_hdf5_filename

However, gfortran won't compile the above and gives a type mismatch error:

Error: Type mismatch in argument 'buf' at (1); passed TYPE(c_ptr) to CHARACTER(1)

Solution

  • A possible solution is to create a C function that returns the filename length for a given HDF5 object:

    #include "hdf5.h"
    #include "H5f90i.h"
    
    int_f get_hdf5_filename_length(hid_t_f *obj_id){
      return H5Fget_name((hid_t)*obj_id, NULL, 0);
    }
    

    which can be called from Fortran in the following way:

      function get_hdf5_filename(obj_id) result(filename)
    
        use hdf5
        use iso_c_binding, ONLY: c_null_ptr
    
        interface
           function get_hdf5_filename_length(obj_id) bind(c) result(length)
             use hdf5
             integer(HID_T)::obj_id
             integer(SIZE_T)::length
           end function get_hdf5_filename_length
        end interface
    
        ! Arguments
        integer(HID_T), intent(in)::obj_id
            !! Handle of HDF5 object
    
        ! Result
        character(:), pointer::filename
    
        integer(SIZE_T)::size = 50
            !! Length of filename
    
        integer::hdferr
            !! HDF5 error code
    
        integer::i
            !! Loop counter
    
        size = get_hdf5_filename_length(obj_id)
    
        ! filename has to be allocated to size+1 to allow for the terminating null
        ! of the filename string in C
        allocate (character(size+1)::filename)
    
        ! h5fget_name_f uses len_trim to determine the buffer length,
        ! which requires the buffer be filled with non-whitespace characters
        ! in order to work correctly
        do i = 1, size + 1
          filename(i:i) = 'a'
        end do
    
        ! Get the filename
        call h5fget_name_f(obj_id, filename, size, hdferr)
    
        ! Remove the null character from the end of the string
        filename => filename(1:size)
    
      end function get_hdf5_filename
    

    Note that it is not enough to allocate the string buffer to the correct size; it also needs to be populated with non-whitespace characters before being passed to h5fget_name_f, because h5fget_name_f calls len_trim on the passed buffer and uses the result to determine the maximum permissible filename length.