! { dg-do run }
!
! Tests dtio transfer of arrays of derived types and classes
!
MODULE p
  TYPE :: person
    CHARACTER (LEN=20) :: name
    INTEGER(4) :: age
    CONTAINS
      procedure :: pwf
      procedure :: prf
      GENERIC :: WRITE(FORMATTED) => pwf
      GENERIC :: READ(FORMATTED) => prf
  END TYPE person
  type, extends(person) :: employee
    character(20) :: job_title
  end type
  type, extends(person) :: officer
    character(20) :: position
  end type
  type, extends(person) :: member
    integer :: membership_number
  end type
  type :: club
    type(employee), allocatable :: staff(:)
    class(person), allocatable :: committee(:)
    class(person), allocatable :: membership(:)
  end type
CONTAINS
  SUBROUTINE pwf (dtv,unit,iotype,vlist,iostat,iomsg)
    CLASS(person), INTENT(IN) :: dtv
    INTEGER, INTENT(IN) :: unit
    CHARACTER (LEN=*), INTENT(IN) :: iotype
    INTEGER, INTENT(IN) :: vlist(:)
    INTEGER, INTENT(OUT) :: iostat
    CHARACTER (LEN=*), INTENT(INOUT) :: iomsg
    select type (dtv)
      type is (employee)
        WRITE(unit, FMT = "(A/)", IOSTAT=iostat) "Employee"
        WRITE(unit, FMT = "(A20,I4,A20/)", IOSTAT=iostat) dtv%name, dtv%age, dtv%job_title
      type is (officer)
        WRITE(unit, FMT = "(A/)", IOSTAT=iostat) "Officer"
        WRITE(unit, FMT = "(A20,I4,A20/)", IOSTAT=iostat) dtv%name, dtv%age, dtv%position
      type is (member)
        WRITE(unit, FMT = "(A/)", IOSTAT=iostat) "Member"
        WRITE(unit, FMT = "(A20,I4,I4/)", IOSTAT=iostat) dtv%name, dtv%age, dtv%membership_number
      class default
        WRITE(unit, FMT = "(A/)", IOSTAT=iostat) "Ugggh!"
        WRITE(unit, FMT = "(A20,I4,' '/)", IOSTAT=iostat) dtv%name, dtv%age
    end select
  END SUBROUTINE pwf

  SUBROUTINE prf (dtv,unit,iotype,vlist,iostat,iomsg)
    CLASS(person), INTENT(INOUT) :: dtv
    INTEGER, INTENT(IN) :: unit
    CHARACTER (LEN=*), INTENT(IN) :: iotype
    INTEGER, INTENT(IN) :: vlist(:)
    INTEGER, INTENT(OUT) :: iostat
    CHARACTER (LEN=*), INTENT(INOUT) :: iomsg
    character (20) :: header, rname, jtitle, oposition
    integer :: i
    integer :: no
    integer :: age
    iostat = 0
    select type (dtv)

      type is (employee)
        read (unit = unit, fmt = *) header
        READ (UNIT = UNIT, FMT = "(A20,I4,A20)") rname, age, jtitle
        if (trim (rname) .ne. dtv%name) iostat = 1
        if (age .ne. dtv%age) iostat = 2
        if (trim (jtitle) .ne. dtv%job_title) iostat = 3
        if (iotype .ne. "DTstaff") iostat = 4

      type is (officer)
        read (unit = unit, fmt = *) header
        READ (UNIT = UNIT, FMT = "(A20,I4,A20)") rname, age, oposition
        if (trim (rname) .ne. dtv%name) iostat = 1
        if (age .ne. dtv%age) iostat = 2
        if (trim (oposition) .ne. dtv%position) iostat = 3
        if (iotype .ne. "DTofficers") iostat = 4

      type is (member)
        read (unit = unit, fmt = *) header
        READ (UNIT = UNIT, FMT = "(A20,I4,I4)") rname, age, no
        if (trim (rname) .ne. dtv%name) iostat = 1
        if (age .ne. dtv%age) iostat = 2
        if (no .ne. dtv%membership_number) iostat = 3
        if (iotype .ne. "DTmembers") iostat = 4

      class default
        STOP 1
    end select
  end subroutine
END MODULE p

PROGRAM test
  USE p

  type (club) :: social_club
  TYPE (person) :: chairman
  CLASS (person), allocatable :: president(:)
  character (40) :: line
  integer :: i, j

  allocate (social_club%staff, source = [employee ("Bert",25,"Barman"), &
                                         employee ("Joy",16,"Auditor")])

  allocate (social_club%committee, source = [officer ("Hank",32, "Chair"), &
                                             officer ("Ann", 29, "Secretary")])

  allocate (social_club%membership, source = [member ("Dan",52,1), &
                                              member ("Sue",39,2)])

  chairman%name="Charlie"
  chairman%age=62

  open (7, status = "scratch")
  write (7,*) social_club%staff                ! Tests array of derived types
  write (7,*) social_club%committee            ! Tests class array
  do i = 1, size (social_club%membership, 1)
    write (7,*) social_club%membership(i)      ! Tests class array elements
  end do

  rewind (7)
  read (7, "(DT'staff')", iostat = i) social_club%staff
  if (i .ne. 0) STOP 2

  social_club%committee(2)%age = 33            ! Introduce an error

  read (7, "(DT'officers')", iostat = i) social_club%committee
  if (i .ne. 2) STOP 3! Pick up error

  do j = 1, size (social_club%membership, 1)
    read (7, "(DT'members')", iostat = i) social_club%membership(j)
    if (i .ne. 0) STOP 4
  end do
  close (7)
END PROGRAM test
