Skip to content

Commit 9ff67b2

Browse files
committed
dataset:write:character:scalar: trim to avoid empty junk
for now we leave empty character arrays as-is, the user would need to check for junk test:attr:empty string: seeing if GCC 11.3 needs auxiliary test variable doc: character write auxiliary variable recommended
1 parent 574bb40 commit 9ff67b2

File tree

4 files changed

+59
-7
lines changed

4 files changed

+59
-7
lines changed

API.md

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
This document provides a listing of h5fortran `public` scoped user-facing procedures and methods with a summary of their parameters.
44

5+
Reading or writing {real64,real32,int32,int64} from scalar to 7d is supported.
6+
57
All examples assume:
68

79
```fortran
@@ -18,6 +20,40 @@ use h5fortran, only : hdf5version
1820
print *, hdf5version()
1921
```
2022

23+
## Character variables
24+
25+
Character variables are also supported for datasets and attributes.
26+
On some compilers (e.g. oneAPI), it's more stable to use an auxiliary variable when writing character data to avoid "junk" in the string.
27+
28+
For example:
29+
30+
```fortran
31+
character(5) :: aux
32+
33+
aux = "hello"
34+
35+
h%write("/mystr", aux)
36+
```
37+
38+
rather than simply
39+
40+
```fortran
41+
h%write("/mystr", "hello")
42+
```
43+
44+
This is ESPECIALLY true if writing empty character to a dataset or attribute:
45+
46+
```fortran
47+
48+
h%write("/mystr", "") !< DON'T: may have junk characters in file
49+
50+
51+
!! instead do like:
52+
character(123) :: aux !< arbitrary length
53+
aux = ""
54+
h%write("/mystr", aux)
55+
```
56+
2157
## Open HDF5 file reference
2258

2359
More than one HDF5 file can be open in a program, by declaring unique file handle (variable) like:
@@ -48,7 +84,7 @@ call h%close(close_hdf5_interface)
4884
logical, intent(in), optional :: close_hdf5_interface
4985
```
5086

51-
To avoid memory leaks or corrupted files, always "close" files before STOPping the Fortran program.
87+
To avoid memory leaks or corrupted files, always "close" files before Stopping the Fortran program.
5288

5389
## Flush data to disk while file is open
5490

src/write_scalar.f90

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
dtype = H5T_STD_I64LE
2727
type is (character(*))
2828
dtype = H5T_NATIVE_CHARACTER
29-
charlen = len(A) !< workaround for GCC 8.3.0 bug
29+
charlen = len_trim(A) !< workaround for GCC 8.3.0 bug
3030
if(charlen == 0) charlen = 1 !< empty string is OK but charlen is strictly positive.
3131
class default
3232
error stop "ERROR:h5fortran:write: unknown variable type for " // dname
@@ -48,7 +48,7 @@
4848
type is (integer(int64))
4949
call H5Dwrite_f(dset_id, dtype, A, dset_dims, ier, file_space_id=file_space_id, xfer_prp=xfer_id)
5050
type is (character(*))
51-
call H5Dwrite_f(dset_id, dtype_id, A, dset_dims, ier, file_space_id=file_space_id, xfer_prp=xfer_id)
51+
call H5Dwrite_f(dset_id, dtype_id, trim(A), dset_dims, ier, file_space_id=file_space_id, xfer_prp=xfer_id)
5252
class default
5353
error stop "ERROR:h5fortran:write: unsupported type for " // dname
5454
end select

test/test_attributes.f90

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
program test_attributes
22

33
use, intrinsic:: iso_fortran_env, only: int32, real32, real64, stderr=>error_unit
4-
use, intrinsic:: iso_c_binding
4+
use, intrinsic:: iso_c_binding, only: C_NULL_CHAR
55

66
use h5fortran, only: hdf5_file, h5write_attr, h5read_attr, HSIZE_T
77

@@ -34,6 +34,8 @@ subroutine test_write_attributes(path)
3434
type(hdf5_file) :: h
3535
character(*), intent(in) :: path
3636

37+
character(123) :: buf
38+
3739
integer :: i2(1,1), i3(1,1,1), i4(1,1,1,1), i5(1,1,1,1,1), i6(1,1,1,1,1,1), i7(1,1,1,1,1,1,1)
3840

3941
call h%open(path, action='w', debug=.true.)
@@ -54,10 +56,16 @@ subroutine test_write_attributes(path)
5456
call h%writeattr('/x', 'i6', i6)
5557
call h%writeattr('/x', 'i7', i7)
5658

57-
call h%writeattr("/x", "1d_emptyp", [character(1) :: "", ""])
59+
buf = ""
60+
!! This auxiliary buffer fixes GCC 11.3.0 and oneAPI.
61+
!! It wasn't necessary on GCC 11.4.1 and newer.
62+
!! with h5dump, what's seen on disk file is "\001" value instead of "\000" or space.
63+
call h%writeattr("/x", "empty_char", buf)
64+
65+
call h%writeattr("/x", "1d_empty", [character(1) :: "", ""])
5866
call h%writeattr("/x", "c1d", [character(5) :: 'one', 'two', 'three'])
5967
call h%writeattr("/x", "c2d", reshape([character(5) :: 'one', 'two', 'three', 'four', 'five', 'six'], [2,3]))
60-
call h%writeattr("/x", "empty_char", "")
68+
6169

6270
call h%close()
6371

test/test_string.f90

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
program test_string
22

33
use, intrinsic:: iso_fortran_env, only: stderr=>error_unit
4+
use, intrinsic:: iso_c_binding, only : C_NULL_CHAR
45

56
use hdf5, only: H5T_STR_SPACEPAD_F, HSIZE_T
67
use h5fortran, only: hdf5_file
@@ -29,9 +30,14 @@ subroutine test_write(fn)
2930

3031
type(hdf5_file) :: h
3132

33+
character(123) :: aux
34+
3235
call h%open(fn, action='w', debug=.true.)
3336

34-
call h%write("/empty", "")
37+
aux = ""
38+
!! compillers like oneAPI need an auxiliary variable not a raw constant
39+
call h%write("/empty", aux)
40+
3541
call h%write('/little', '42')
3642
call h%write('/MySentence', 'this is a little sentence.')
3743
call h%write('/vector_scalar', ['vector scalar'])
@@ -58,7 +64,9 @@ subroutine test_read(fn)
5864

5965
call h%open(fn, action='r')
6066

67+
value = ""
6168
call h%read('/empty', value)
69+
print '(L1,1x,i0,1x,a)', trim(value) == C_NULL_CHAR, len_trim(value), trim(value)
6270
if(len_trim(value) /= 0) error stop 'test_string: empty string failure: len_trim /= 0'
6371
if (value /= '') error stop 'test_string: empty string failure: value = ' // trim(value)
6472

0 commit comments

Comments
 (0)