[J3] Interaction between user-defined input and list-directed input

Malcolm Cohen malcolm at nag-j.co.jp
Mon Apr 25 05:49:44 UTC 2022


Hi Thomas,

This is quite tricky.

The "actual i/o" parts are all done by the invoked procedure. The parent list-directed i/o does not handle the "2*1.0" because the procedure is invoked instead. There is no way the parent can do this as it cannot know beforehand what the child is going to do.

In the example, the procedure gets invoked twice. The first time, it issues a list-directed READ of a single REAL item; the input stream at that point is "2*1.0", so the list-directed READ swallows all of that (and probably the separating blank or eor).

However, repeat factors only have effect until the end of the i/o statement - if you read "1000000*1.0" into a single REAL, the rest of the million copies of 1.0 just don't happen. After that READ, there is nothing left - the repetition will be thrown away.

Then the procedure is invoked for the second time. Again, it issues a list-directed READ, but now the input stream is at the end of file. So it gets an end-of-file return.

Child i/o statements are just like parent ones except that there is no "file positioning before data transfer" and no file positioning after data transfer". For formatted i/o, this is almost exactly the same as ADVANCE='NO' ... except that one is not permitted to do ADVANCE='NO' in a list-directed i/o statement.

That is, the expected effect, expressed using ADVANCE='NO' as if it were allowed here, is something like
    READ(unit,*,ADVANCE='NO') a%r
    READ(unit,*) b%r

One would expect the first READ to swallow the whole "2*1.0"; even though there is no advancing, there is nothing left for the second read to read.

At least two compilers do that (a third does that but has another bug in that an error passed back from the child to a parent without IOSTAT= does not trigger error termination).

Cheers,
-- 
..............Malcolm Cohen, NAG Oxford/Tokyo.

-----Original Message-----
From: J3 <j3-bounces at mailman.j3-fortran.org> On Behalf Of Thomas Konig via J3
Sent: Sunday, April 24, 2022 7:08 PM
To: General J3 interest list <j3 at mailman.j3-fortran.org>
Cc: Thomas König <tk at tkoenig.net>
Subject: [J3] Interaction between user-defined input and list-directed input

Hello,

I have been having some trouble understanding the interaction between the particular features of list-directed input and user-defined input.

One point: Input of the form r*c.  I see no mention in the standard of this being restricted in the case of user-defined I/O, so I would expect the test program

module x
   implicit none
   type foo
      real :: r
   end type foo
   interface read(formatted)
      module procedure read_formatted
   end interface read(formatted)
contains
   subroutine read_formatted (dtv, unit, iotype, vlist, iostat, iomsg)
     class (foo), 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
     read (unit,*,iostat=iostat,iomsg=iomsg) dtv%r
   end subroutine read_formatted
end module x

program main
   use x
   implicit none
   type(foo) :: a, b
   open (10,status="scratch")
   write (10,'(A)') '2*1.0'
   rewind (10)
   read (10,*) a%r, b%r
   print *,a,b
   rewind (10)
   a%r = -42.
   b%r = -42.
   read (10,*) a, b
   print *,a,b
end program main

to succeed and to print something like

    1.00000000       1.00000000
    1.00000000       1.00000000

Another point is the handling of when an item has been read.
Is the child I/O responsible for reading records? Looking at

module x
   implicit none
   type, public:: foo
      character(len=2) :: c
   end type foo
   interface read(formatted)
      module procedure read_formatted
   end interface read(formatted)
contains
   subroutine read_formatted (dtv, unit, iotype, vlist, iostat, iomsg)
     class (foo), 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
     read (unit,'(A)',iostat=iostat,iomsg=iomsg) dtv%c
   end subroutine read_formatted
end module x

program main
   use x
   implicit none
   type(foo) :: a, b
   open (10,file="testfile.dat",status="replace")
   write (10,'(A)') '','aa bb'
   rewind (10)
   read (10,*) a%c, b%c
   write (*,'(10(A))') "Component read   : a = '",a,"' , b = '", b, "'"
   rewind (10)
   a%c = "x"
   b%c = "y"
   read (10,*) a, b
   write (*,'(10(A))') "User-defined read: a = '",a,"' , b = '", b, "'"
end program main

I get output of

Component read   : a = 'aa' , b = 'bb'
User-defined read: a = 'aa' , b = 'bb'

or

Component read   : a = 'aa' , b = 'bb'
User-defined read: a = '  ' , b = '  '

depending on which compiler I use.

Finally, the question of when a value is actually read is a bit unclear.  Is the child I/O responsible for reading until end of record or a space?  Test case is

module x
   implicit none
   type, public:: foo
      character :: c
   end type foo
   interface read(formatted)
      module procedure read_formatted
   end interface read(formatted)
contains
   subroutine read_formatted (dtv, unit, iotype, vlist, iostat, iomsg)
     class (foo), 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
     read (unit,'(A)',iostat=iostat,iomsg=iomsg) dtv%c
   end subroutine read_formatted
end module x

program main
   use x
   implicit none
   type(foo) :: a, b
   open (10,file="testfile.dat",status="replace")
   write (10,'(A)') 'aa bb'
   rewind (10)
   read (10,*) a%c, b%c
   write (*,'(10(A))') "Component read   : a = '",a,"' , b = '", b, "'"
   rewind (10)
   a%c = "x"
   b%c = "y"
   read (10,*) a, b
   write (*,'(10(A))') "User-defined read: a = '",a,"' , b = '", b, "'"
end program main

where at least there is agreement between compilers, i.e.

Component read   : a = 'a' , b = 'b'
User-defined read: a = 'a' , b = 'a'

Best regards

	Thomas



More information about the J3 mailing list