hdf5/fortran/test/tH5E_F03.F90
Dana Robinson 7f1e49206d
Renamed COPYING to LICENSE (#4978)
This is where most people will expect to find license information. The
COPYING_LBNL_HDF5 file has also been renamed to LICENSE_LBNL_HDF5.
The licenses are unchanged.
2024-10-18 21:13:04 -07:00

498 lines
15 KiB
Fortran

!****h* root/fortran/test/tH5E_F03.f90
!
! NAME
! tH5E_F03.f90
!
! FUNCTION
! Test FORTRAN HDF5 H5E APIs which are dependent on FORTRAN 2003
! features.
!
! COPYRIGHT
! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
! 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 LICENSE 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. *
! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
!
! USES
! liter_cb_mod
!
! CONTAINS SUBROUTINES
! test_error
!
!*****
#include <H5config_f.inc>
! *****************************************
! *** H 5 E T E S T S
! *****************************************
MODULE test_my_hdf5_error_handler
USE HDF5
USE TH5_MISC
USE TH5_MISC_GEN
CONTAINS
!***************************************************************
!**
!** my_hdf5_error_handler: Custom error callback routine.
!**
!***************************************************************
INTEGER(C_INT) FUNCTION my_hdf5_error_handler(estack_id, data_inout) bind(C)
! This error function handle works with only version 2 error stack
IMPLICIT NONE
! estack_id is always passed from C as: H5E_DEFAULT
INTEGER(HID_T), VALUE :: estack_id
! data that was registered with H5Eset_auto_f
! INTEGER :: data_inout ! another option
! or
TYPE(C_PTR), VALUE :: data_inout
INTEGER, POINTER :: iunit
CALL C_F_POINTER(data_inout, iunit)
! iunit = data_inout
WRITE(iunit,'(A)') "H5Eset_auto_f_msg"
WRITE(iunit,'(I0)') iunit
iunit = 10*iunit
my_hdf5_error_handler = 1 ! this is not used by the C routine
END FUNCTION my_hdf5_error_handler
!-------------------------------------------------------------------------
! Function: custom_print_cb
!
! Purpose: Callback function to print error stack in customized way.
!
!-------------------------------------------------------------------------
!
INTEGER(C_INT) FUNCTION custom_print_cb(n, err_desc, op_data) BIND(C)
IMPLICIT NONE
INTEGER(SIZE_T), PARAMETER :: MSG_SIZE = 64
INTEGER(C_INT), VALUE :: n
TYPE(h5e_error_t) :: err_desc
TYPE(C_PTR) :: op_data
CHARACTER(LEN=MSG_SIZE) :: maj
CHARACTER(LEN=MSG_SIZE) :: minn
CHARACTER(LEN=MSG_SIZE) :: cls
INTEGER(SIZE_T) :: size
INTEGER :: msg_type
INTEGER :: error
IF(n.NE.0_C_INT)THEN
custom_print_cb = -1
RETURN
ENDIF
CALL H5Eget_class_name_f(err_desc%cls_id, cls, error)
IF(error .LT.0)THEN
custom_print_cb = -1
RETURN
ENDIF
IF(TRIM(cls).NE."Custom error class")THEN
custom_print_cb = -1
RETURN
ENDIF
size = 3
CALL H5Eget_class_name_f(err_desc%cls_id, cls, error, size)
IF(error .LT.0)THEN
custom_print_cb = -1
RETURN
ENDIF
IF(TRIM(cls).NE."Cus")THEN
custom_print_cb = -1
RETURN
ENDIF
size = 0
CALL H5Eget_class_name_f(err_desc%cls_id, "", error, size)
IF(error .LT.0)THEN
custom_print_cb = -1
RETURN
ENDIF
IF(size.NE.18)THEN
custom_print_cb = -1
RETURN
ENDIF
size = MSG_SIZE
CALL H5Eget_msg_f(err_desc%maj_num, msg_type, maj, error, size)
IF(error .LT.0)THEN
custom_print_cb = -1
RETURN
ENDIF
CALL h5eget_major_f(err_desc%maj_num, maj, size, error)
IF("MAJOR MSG".NE.TRIM(maj))THEN
custom_print_cb = -1
RETURN
ENDIF
IF(error .LT. 0)THEN
custom_print_cb = -1
RETURN
ENDIF
CALL h5eget_minor_f(err_desc%min_num, minn, error)
IF(error .LT. 0)THEN
custom_print_cb = -1
RETURN
ENDIF
IF("MIN MSG".NE.TRIM(minn))THEN
custom_print_cb = -1
RETURN
ENDIF
custom_print_cb = 0
END FUNCTION custom_print_cb
END MODULE test_my_hdf5_error_handler
MODULE TH5E_F03
USE ISO_C_BINDING
USE test_my_hdf5_error_handler
CONTAINS
SUBROUTINE test_error(total_error)
IMPLICIT NONE
INTEGER :: total_error
INTEGER(hid_t) :: file
INTEGER :: error
INTEGER, TARGET :: my_hdf5_error_handler_data
INTEGER, TARGET :: iunit
TYPE(C_PTR) :: f_ptr
TYPE(C_FUNPTR) :: func
CHARACTER(LEN=180) :: chr180
INTEGER :: idx
INTEGER(HID_T) :: fapl
LOGICAL :: status
! set the error stack to the customized routine
iunit = 12
OPEN(iunit, FILE="stderr.txt")
my_hdf5_error_handler_data = iunit
! ** SET THE CUSTOMIZED PRINTING OF ERROR STACK **
! set the customized error handling routine
func = C_FUNLOC(my_hdf5_error_handler)
! set the data sent to the customized routine
f_ptr = C_LOC(my_hdf5_error_handler_data)
CALL H5Eset_auto_f(1, error, H5E_DEFAULT_F, func, f_ptr)
CALL check("H5Eset_auto_f", error, total_error)
! If a fapl is not created, then the test will fail when using
! check-passthrough-vol because the callback function is called twice, gh #4137.
CALL h5pcreate_f(H5P_DATASET_ACCESS_F, fapl, error)
CALL check("h5pcreate_f", error, total_error)
CALL h5fopen_f("DOESNOTEXIST", H5F_ACC_RDONLY_F, file, error, fapl)
CALL VERIFY("h5fopen_f", error, -1, total_error)
CALL h5pclose_f(fapl,error)
CALL check("h5pclose_f", error, total_error)
CLOSE(iunit)
OPEN(iunit, FILE="stderr.txt")
READ(iunit,'(A)') chr180
idx = INDEX(string=chr180,substring="H5Eset_auto_f_msg")
IF(idx.EQ.0) CALL check("H5Eset_auto_f", -1, total_error)
READ(iunit, *) idx
CALL VERIFY("H5Eset_auto_f", idx, iunit, total_error)
CALL VERIFY("H5Eset_auto_f", my_hdf5_error_handler_data, 10*iunit, total_error)
CLOSE(iunit, STATUS='delete')
CALL H5Eset_auto_f(0, error)
CALL check("H5Eset_auto_f", error, total_error)
CALL h5fopen_f("DOESNOTEXIST", H5F_ACC_RDONLY_F, file, error)
CALL VERIFY("h5fopen_f", error, -1, total_error)
INQUIRE(file="H5Etest.txt", EXIST=status)
IF(status)THEN
CALL VERIFY("H5Eset_auto_f", error, -1, total_error)
ENDIF
END SUBROUTINE test_error
SUBROUTINE test_error_stack(total_error)
IMPLICIT NONE
INTEGER :: total_error
INTEGER :: error
INTEGER(HID_T) :: cls_id, major, minor, estack_id, estack_id1, estack_id2
CHARACTER(LEN=18) :: file
CHARACTER(LEN=18) :: func
INTEGER :: line
TYPE(C_PTR) :: ptr1
INTEGER :: msg_type
CHARACTER(LEN=9) :: maj_mesg = "MAJOR MSG"
CHARACTER(LEN=7) :: min_mesg = "MIN MSG"
!file status
LOGICAL :: status
CHARACTER(LEN=180) :: chr180
INTEGER :: idx
INTEGER(SIZE_T) :: count
CHARACTER(LEN=64), TARGET :: stderr
TYPE(C_FUNPTR) :: func_ptr
#ifdef H5_FORTRAN_HAVE_CHAR_ALLOC
CHARACTER(:), ALLOCATABLE :: msg_alloc
#endif
CHARACTER(LEN=9) :: chr9
INTEGER(SIZE_T) :: msg_size
CALL h5eregister_class_f("Custom error class", "H5E_F03", "0.1", cls_id, error)
CALL check("H5Eregister_class_f", error, total_error)
CALL H5Ecreate_msg_f(cls_id, H5E_MAJOR_F, maj_mesg, major, error)
CALL check("H5Ecreate_msg_f", error, total_error)
CALL H5Ecreate_msg_f(cls_id, H5E_MINOR_F, min_mesg, minor, error)
CALL check("H5Ecreate_msg_f", error, total_error)
file = "FILE"
func = "FUNC"
line = 99
CALL h5ecreate_stack_f(estack_id, error)
CALL check("h5ecreate_stack_f", error, total_error)
! push a custom error message onto the stack
CALL H5Epush_f(estack_id, file, func, line, &
cls_id, major, minor, "%s ERROR TEXT %s %s %s", error, &
arg1=ACHAR(27)//"[31m"//C_NULL_CHAR, arg2=ACHAR(27)//"[0m"//C_NULL_CHAR, &
arg3=ACHAR(0)//C_NULL_CHAR, arg4=ACHAR(10)//C_NULL_CHAR )
CALL check("H5Epush_f", error, total_error)
CALL h5eget_num_f(estack_id, count, error)
CALL check("h5eget_num_f", error, total_error)
CALL VERIFY("h5eget_num_f", count, 1_SIZE_T, total_error)
msg_size = 0
CALL H5Eget_msg_f(major, msg_type, chr9, error, msg_size)
CALL check("H5Eget_msg_f", error, total_error)
CALL VERIFY("H5Eget_msg_f", msg_type, H5E_MAJOR_F, total_error)
CALL VERIFY("H5Eget_msg_f", msg_size, 9_SIZE_T, total_error)
! Check when a shorter buffer length is passed as the msg_size
msg_size = 3
CALL H5Eget_msg_f(major, msg_type, chr9, error, msg_size)
CALL check("H5Eget_msg_f", error, total_error)
CALL VERIFY("H5Eget_msg_f", msg_type, H5E_MAJOR_F, total_error)
CALL VERIFY("H5Eget_msg_f", msg_size, 9_SIZE_T, total_error)
CALL VERIFY("H5Eget_msg_f", TRIM(chr9), maj_mesg(1:3), total_error)
! Check when a exact size buffer length is passed as the msg_size
msg_size = 9
CALL H5Eget_msg_f(major, msg_type, chr9, error, msg_size)
CALL check("H5Eget_msg_f", error, total_error)
CALL VERIFY("H5Eget_msg_f", msg_type, H5E_MAJOR_F, total_error)
CALL VERIFY("H5Eget_msg_f", msg_size, 9_SIZE_T, total_error)
CALL VERIFY("H5Eget_msg_f", TRIM(chr9), maj_mesg(1:9), total_error)
msg_size = 0
CALL H5Eget_msg_f(minor, msg_type, chr9, error, msg_size)
CALL check("H5Eget_msg_f", error, total_error)
CALL VERIFY("H5Eget_msg_f", msg_type, H5E_MINOR_F, total_error)
CALL VERIFY("H5Eget_msg_f", msg_size, 7_SIZE_T, total_error)
! Check when a shorter buffer length is passed as the msg_size
msg_size = 3
CALL H5Eget_msg_f(minor, msg_type, chr9, error, msg_size)
CALL check("H5Eget_msg_f", error, total_error)
CALL VERIFY("H5Eget_msg_f", msg_type, H5E_MINOR_F, total_error)
CALL VERIFY("H5Eget_msg_f", msg_size, 7_SIZE_T, total_error)
CALL VERIFY("H5Eget_msg_f", TRIM(chr9), min_mesg(1:3), total_error)
! Check when a larger buffer length is passed as the msg_size
msg_size = 9
CALL H5Eget_msg_f(minor, msg_type, chr9, error, msg_size)
CALL check("H5Eget_msg_f", error, total_error)
CALL VERIFY("H5Eget_msg_f", msg_type, H5E_MINOR_F, total_error)
CALL VERIFY("H5Eget_msg_f", msg_size, 7_SIZE_T, total_error)
CALL VERIFY("H5Eget_msg_f", TRIM(chr9), min_mesg(1:7), total_error)
! Check with an allocatable character of the exact size
#ifdef H5_FORTRAN_HAVE_CHAR_ALLOC
msg_size = 0
CALL H5Eget_msg_f(minor, msg_type, "", error, msg_size)
CALL check("H5Eget_msg_f", error, total_error)
CALL VERIFY("H5Eget_msg_f", msg_type, H5E_MINOR_F, total_error)
CALL VERIFY("H5Eget_msg_f", msg_size, 7_SIZE_T, total_error)
ALLOCATE(CHARACTER(LEN=msg_size) :: msg_alloc)
CALL H5Eget_msg_f(minor, msg_type, msg_alloc, error)
CALL check("H5Eget_msg_f", error, total_error)
CALL VERIFY("H5Eget_msg_f", msg_type, H5E_MINOR_F, total_error)
CALL VERIFY("H5Eget_msg_f", msg_alloc, min_mesg, total_error)
#endif
CALL h5eprint_f(H5E_DEFAULT_F, error)
CALL check("h5eprint_f", error, total_error)
CALL h5eprint_f(error)
CALL check("h5eprint_f", error, total_error)
INQUIRE(file="H5Etest.txt", EXIST=status)
IF(status)THEN
OPEN(UNIT=12, FILE="H5Etest.txt", status='old')
CLOSE(12, STATUS='delete')
ENDIF
CALL h5eprint_f(estack_id, error, "H5Etest.txt")
CALL check("h5eprint_f", error, total_error)
INQUIRE(file="H5Etest.txt", EXIST=status)
IF(.NOT.status)THEN
CALL check("h5eprint_f", -1, total_error)
ELSE
! The contents of the file should be:
! Custom error class-DIAG: Error detected in H5E_F03 (0.1) thread 0:
! #000: FILE line 99 in FUNC(): ERROR TEXT
!
! major: MAJOR MSG
! minor: MIN MSG
OPEN(UNIT=12, FILE="H5Etest.txt", status='old')
READ(12,'(A)') chr180
idx = INDEX(string=chr180,substring="Custom error class")
IF(idx.EQ.0) CALL check("h5eprint_f1", -1, total_error)
idx = INDEX(string=chr180,substring="H5E_F03")
IF(idx.EQ.0) CALL check("h5eprint_f2", -1, total_error)
idx = INDEX(string=chr180,substring="0.1")
IF(idx.EQ.0) CALL check("h5eprint_f3", -1, total_error)
READ(12,'(A)') chr180
idx = INDEX(string=chr180,substring="FILE")
IF(idx.EQ.0) CALL check("h5eprint_f4", -1, total_error)
idx = INDEX(string=chr180,substring="99")
IF(idx.EQ.0) CALL check("h5eprint_f5", -1, total_error)
idx = INDEX(string=chr180,substring="FUNC")
IF(idx.EQ.0) CALL check("h5eprint_f6", -1, total_error)
idx = INDEX(string=chr180,substring="ERROR TEXT")
IF(idx.EQ.0) CALL check("h5eprint_f7", -1, total_error)
READ(12,'()')
READ(12,"(A)") chr180
idx = INDEX(string=chr180,substring=maj_mesg)
IF(idx.EQ.0) CALL check("h5eprint_f", -1, total_error)
READ(12,"(A)") chr180
idx = INDEX(string=chr180,substring=min_mesg)
IF(idx.EQ.0) CALL check("h5eprint_f", -1, total_error)
CLOSE(12, STATUS='delete')
ENDIF
stderr = "** Print error stack in customized way **"//C_NULL_CHAR
ptr1 = C_LOC(stderr(1:1))
func_ptr = C_FUNLOC(custom_print_cb)
CALL h5ewalk_f(estack_id, H5E_WALK_UPWARD_F, func_ptr, ptr1, error)
CALL check("h5ewalk_f", error, total_error)
CALL h5eget_num_f(estack_id, count, error)
CALL check("h5eget_num_f", error, total_error)
CALL VERIFY("h5eget_num_f", count, 1_SIZE_T, total_error)
CALL H5Ecreate_stack_f(estack_id2, error)
CALL check("H5Ecreate_stack_f", error, total_error)
CALL H5Eappend_stack_f(estack_id2, estack_id, .FALSE., error)
CALL check("H5Eappend_stack_f", error, total_error)
CALL h5eget_num_f(estack_id2, count, error)
CALL check("h5eget_num_f", error, total_error)
CALL VERIFY("h5eget_num_f", count, 1_SIZE_T, total_error)
! Copy error stack, which clears the original
CALL H5Eget_current_stack_f(estack_id1, error)
CALL check("H5Eget_current_stack_f", error, total_error)
CALL h5eget_num_f(estack_id1, count, error)
CALL check("h5eget_num_f", error, total_error)
CALL VERIFY("h5eget_num_f", count, 0_SIZE_T, total_error)
CALL H5Eclose_stack_f(estack_id2, error)
CALL check(" H5Eclose_stack_f", error, total_error)
CALL H5Eclose_stack_f(estack_id, error)
CALL check("H5Eclose_stack_f", error, total_error)
CALL H5Eclose_stack_f(estack_id1, error)
CALL check("H5Eclose_stack_f", error, total_error)
CALL h5ecreate_stack_f(estack_id1, error)
CALL check("h5ecreate_stack_f", error, total_error)
! push a custom error message onto the stack
CALL H5Epush_f(estack_id1, file, func, line, &
cls_id, major, minor, "%s ERROR TEXT %s %s", error, &
arg1=ACHAR(27)//"[31m", arg2=ACHAR(27)//"[0m", arg3=ACHAR(10) )
CALL check("H5Epush_f", error, total_error)
CALL H5Eset_current_stack_f(estack_id1, error) ! API will also close estack_id1
CALL check("H5Eset_current_stack_f", error, total_error)
CALL h5eget_num_f(H5E_DEFAULT_F, count, error)
CALL check("h5eget_num_f", error, total_error)
CALL VERIFY("h5eget_num_f", count, 1_SIZE_T, total_error)
CALL h5epop_f(H5E_DEFAULT_F, 1_size_t, error)
CALL check("h5epop_f", error, total_error)
CALL h5eget_num_f(H5E_DEFAULT_F, count, error)
CALL check("h5eget_num_f", error, total_error)
CALL VERIFY("h5eget_num_f", count, 0_SIZE_T, total_error)
CALL H5Eclose_msg_f(major, error)
CALL check("H5Eclose_msg_f", error, total_error)
CALL H5Eclose_msg_f(minor, error)
CALL check("H5Eclose_msg_f", error, total_error)
CALL h5eunregister_class_f(cls_id, error)
CALL check("H5Eunregister_class_f", error, total_error)
END SUBROUTINE test_error_stack
END MODULE TH5E_F03