Reputation: 332
I want to implement the user-defined I/O procedures for the derived types in my Fortran code. However, write
statements within those procedures cannot produce new lines between two sequential write
statements. The derived type and procedures are defined as below.
The module:
module station_module
implicit none
character(8), parameter :: FmtFloat = '(5E15.7)'
type :: station
integer, private :: ns = 0
real, public, allocatable :: xloc(:), yloc(:), zloc(:)
contains
procedure, public :: import_station
procedure, public :: export_station
procedure, private :: read_station
generic, public :: read (formatted) => read_station
procedure, private :: write_station
generic, public :: write (formatted) => write_station
final :: destruct_station
end type station
interface station
module procedure new_station
end interface station
contains
function new_station(n) result(t)
implicit none
integer, intent(in) :: n
type(station) :: t
if (n > 0) then
allocate (t%zloc(n))
allocate (t%yloc(n))
allocate (t%xloc(n))
t%ns = n
end if
end function new_station
subroutine read_station(dtv, unit, iotype, vlist, iostat, iomsg)
implicit none
class(station), intent(inout) :: dtv
integer, intent(in) :: unit
character(*), intent(in) :: iotype
integer, intent(in) :: vlist(:)
integer, intent(out) :: iostat
character(*), intent(inout) :: iomsg
call dtv%import_station(unit)
iostat = 0
end subroutine read_station
subroutine import_station(this, unit)
implicit none
class(station), intent(inout) :: this
integer, intent(in) :: unit
character(256) :: header, footer
integer ns
read (unit, '(A)') header !> Header
read (unit, *) ns
if (ns > 0) then
if (allocated(this%zloc)) then
deallocate (this%zloc)
end if
allocate (this%zloc(ns))
read (unit, *) this%zloc
if (allocated(this%yloc)) then
deallocate (this%yloc)
end if
allocate (this%yloc(ns))
read (unit, *) this%yloc
if (allocated(this%xloc)) then
deallocate (this%xloc)
end if
allocate (this%xloc(ns))
read (unit, *) this%xloc
this%ns = ns
end if
read (unit, '(A)') footer !> Footer
end subroutine import_station
subroutine export_station(this, unit)
implicit none
class(station), intent(in) :: this
integer, intent(in) :: unit
write (unit, '(A)') ">STATION INFO"
write (unit, '(I6)') this%ns
write (unit, *) "Z:"
write (unit, FmtFloat) this%zloc
write (unit, *) "Y:"
write (unit, FmtFloat) this%yloc
write (unit, *) "X:"
write (unit, FmtFloat) this%xloc
write (unit, '(A)') ">END STATION"
end subroutine export_station
subroutine write_station(dtv, unit, iotype, vlist, iostat, iomsg)
implicit none
class(station), intent(in) :: dtv
integer, intent(in) :: unit
character(*), intent(in) :: iotype
integer, intent(in) :: vlist(:)
integer, intent(out) :: iostat
character(*), intent(inout) :: iomsg
call dtv%export_station(unit)
iostat = 0
end subroutine write_station
subroutine destruct_station(this)
implicit none
type(station), intent(inout) :: this
if (allocated(this%xloc)) then
deallocate (this%xloc)
end if
if (allocated(this%yloc)) then
deallocate (this%yloc)
end if
if (allocated(this%zloc)) then
deallocate (this%zloc)
end if
this%ns = 0
end subroutine destruct_station
end module station_module
We can see that the user-defined formatted write statement just call a regular subroutine named export_station
, by which I expect the same result in both ways.
Here is my test program:
program Test
use station_module
implicit none
type(station) :: pt, pt1, pt2
pt = station(4)
write(*, *) pt
call pt%export_station(6)
end program Test
The output:
>STATION INFO 4Z: 0.0000000E+00 0.0000000E+00 0.0000000E+00 0.0000000E+00
Y: 0.0000000E+00 0.0000000E+00 0.0000000E+00 0.0000000E+00X: 0.0000000E+00 0.0000000E+00 0.0000000E+00 0.0000000E+00>END STATION
>STATION INFO
4
Z:
0.0000000E+00 0.0000000E+00 0.0000000E+00 0.0000000E+00
Y:
0.0000000E+00 0.0000000E+00 0.0000000E+00 0.0000000E+00
X:
0.0000000E+00 0.0000000E+00 0.0000000E+00 0.0000000E+00
>END STATION
The regular subroutine export_station
produces what I expect. New lines are produced between two write
statements, while write
statement of the derived type does not.
Upvotes: 4
Views: 125
Reputation: 7267
This was also asked on the Intel forum. I replied there."User-defined derived-type I/O is all non-advancing (and you can't change this). If you want newlines you have to write them explicitly (using a / format, for example.)"
Upvotes: 6
Reputation: 32366
There are two classes of output statements here: a parent and a child. The parent output statement in the first case is the write (*,*) pt
.
When this first is the parent, then the call to export_station
through write_station
leads to the write statements there being child output statements. When export_station
is called directly by the user those write statements are themselves parent output statements.
One significant difference between a child data transfer statement and a parent data transfer statement is that a parent statement positions the file prior to and after data transfer. That is, when the write (unit,*) "Z:"
completes the file is positioned after the record just written only when the transfer statement is a parent.
Thus, you see the new lines: this is simply placing after the written record.
A child data transfer statement, not positioning the file on completion, does not effect a new line.
I don't have access to a test machine at the moment, so this part is speculative. You can explicitly write a new line character returned from new_line('')
as part of your output for the child transfer statement. As advance='no'
will be ignored in a child statement you could use that for both cases, explicitly controlling where new lines are written, rather than relying on the split record approach as currently exists.
Upvotes: 2