J3/98-134r1
To: X3J3
From: JOR (R. Bleikamp)
Subject: Edits for derived type I/O
Date: Feb. 18, 1998
Edits are based on the functional description in paper 97-217r1.
Changes since 98-134 are marked with "|" in the left margin.
The text strings and delimit text to be italicized.
Many quoted names (i.e. "w", "d") are to be italicized or bold also.
"*"s in the left margin are used to highlight really important concepts.
Two minor functional changes from 97-217r1. The processor no longer resets
the state of BN/BZ/SP/SS/P to the unit default. They are still pushed/popped
around the call to the user defined derived type I/O routine. Second,
these routines are now callable by the user (it was too hard to avoid).
Edits are based on 98-007 (Jan 13, 1998).
Section 9.2.2.1 [143:38], list item (7),
change "data transfer" to
"data transfer, except for child data transfer I/O statements (9.4.4.4.3)"
Section 9.4.2 [156:11]
Section 9.4.2 [156:17]
Section 9.4.2 [156:20]
In all three lines, change the "." to
", except when the object is processed by a user defined derived type
I/O routine, as described in section 9.4.4.4.3."
Section 9.4.2 [156:28]
Change the "." to
", except when the list item is processed by a user defined derived
type I/O routine, as described in section 9.4.4.4.3."
Section 9.4.4.4.2 [161:3],
Change "objects." to
"objects, except when the derived type object is processed by a user
defined derived type I/O routine, as described in section 9.4.4.4.3."
Section 9.4.4 [157:41], in the first list,
In list item (5),
change "(9.2.1.3.2)."
to "(9.2.1.3.2), except when executing a child data transfer statement
(9.4.4.4.3)."
Section 9.4.4 [158:1], in the first list,
In list item (8),
change "(9.2.1.3.3)." to
"(9.2.1.3.3), except when executing a child data transfer statement
(9.4.4.4.3)."
If we decide to support ASYNC I/O in a user defined derived type
I/O routine, then the second list in this section needs a similar edit.
No edits for now.
Add a new section, 9.4.4.4.3 [161:26+]:
"9.4.4.4.3 User Defined Derived Type I/O Routines
User defined derived type I/O routines allow a program to alter the
default handling of derived type objects and values in data transfer
I/O statements as described in section 9.4.2.
A user defined derived type I/O routine is any routine whose interface
matches one of the interfaces described in this section.
A particular user defined derived type I/O routine is selected based
on the direction of the data transfer (input or output), the type of
data transfer statement (formatted or unformatted), and the particular
derived type.
When an interface for a matching user defined derived type I/O
routine is visible in a scoping unit, and other requirements are met,
the processor will not process those derived types list items as
described in 9.4.2. Instead, it will call the matching user defined
derived type I/O routine, for any data transfer I/O statements executed
in that scoping unit. The user defined derived type routine
controls the actual data transfer operations for the derived type
list item.
* An I/O statement which includes a derived type list item, that
* causes a user defined derived type I/O routine to be invoked, is
* called a parent data transfer I/O statement. Any other I/O data
* transfer statement executed specifying the unit passed into a
* user defined derived type I/O routine while the parent data
* transfer I/O statement is being processed is called a child data
* transfer I/O statement.
Note: A user defined derived type I/O routine will usually contain
child data transfer I/O statements, that read values from,
or write values to, the current record. The effect of executing the
user defined derived type I/O routine is similar to substituting the
list items from any child data transfer statements into the parent
data transfer I/O statement's list item list, along with similar
substitutions in the format specification.
Note: A particular execution of a READ, WRITE or PRINT statement can
be both a parent and a child data transfer I/O statement. A user
defined derived type I/O routine can indirectly call itself or another
user defined derived type I/O routine by executing a child data
transfer I/O statement containing a list item of derived type,
where a matching interface is visible for that derived type.
If a user defined derived type I/O routine calls itself indirectly
in this manner, it must be declared RECURSIVE.
* A child data transfer I/O statement is processed differently than
* a non-child data transfer I/O statement in the following ways:
* - Executing a child data transfer statement does not position
* the file prior to data transfer.
* - An unformatted child data transfer I/O statement does not
* position the file after data transfer is complete.
For a particular derived type, there are four possible user defined
derived type I/O routines; one each for formatted input, formatted
output, unformatted input, and unformatted output. The user need not
supply all four routines for a particular type.
The four allowable interfaces for user defined derived type
I/O routines are:
INTERFACE READ ( FORMATTED )
SUBROUTINE my_read_routine_formatted &
(unit, &
dtv, &
iotype, w, d, m, &
eof, err, eor, errmsg)
INTEGER, INTENT(IN) :: unit ! unit number
! the derived type value/variable
TYPE (whateveritis), INTENT(OUT) :: dtv
! the edit descriptor string
CHARACTER, (LEN=*), INTENT(IN) :: iotype
INTEGER, OPTIONAL, INTENT(IN) :: w,d,m
LOGICAL, INTENT(OUT) :: eof, err, eor
CHARACTER, (LEN=*), INTENT(OUT) :: errmsg
END
END INTERFACE
INTERFACE READ ( UNFORMATTED )
SUBROUTINE my_read_routine_unformatted &
(unit, &
dtv, &
eof, err, eor, errmsg)
INTEGER, INTENT(IN) :: unit
! the derived type value/variable
TYPE (whateveritis) INTENT(OUT) :: dtv
LOGICAL, INTENT(OUT) :: eof, err, eor
CHARACTER, (LEN=*), INTENT(OUT) :: errmsg
END
END INTERFACE
INTERFACE WRITE ( FORMATTED )
SUBROUTINE my_write_routine_formatted &
(unit, &
dtv, &
iotype, w, d, m, &
err, errmsg)
INTEGER, INTENT(IN) :: unit
! the derived type value/variable
TYPE (whateveritis), INTENT(IN) :: dtv
! the edit descriptor string
CHARACTER, (LEN=*), INTENT(IN) :: iotype
INTEGER, OPTIONAL, INTENT(IN) :: w,d,m
LOGICAL, INTENT(OUT) :: err
CHARACTER, (LEN=*), INTENT(OUT) :: errmsg
END
END INTERFACE
INTERFACE WRITE ( UNFORMATTED )
SUBROUTINE my_write_routine_unformatted &
(unit, &
dtv, &
err, errmsg)
INTEGER, INTENT(IN) :: unit
! the derived type value/variable
TYPE (whateveritis), INTENT(IN) :: dtv
LOGICAL, INTENT(OUT) :: err
CHARACTER, (LEN=*), INTENT(OUT) :: errmsg
END
END INTERFACE
The actual specific routine names (the my_..._routine_...
| routine names above) and the dummy argument names are not significant.
| (134r1: deleted text about these routines not being directly callable)
| The dummy arguments shall have the type, type parameters, and
| rank as described above. No other attributes may be specified
| for a dummy argument, except that the "dtv" dummy
| argument may also be given the TARGET attribute.
The user defined derived type I/O routines are invoked during the
processing of I/O data transfer statements when the I/O data
transfer statement is processing a derived type list item and:
- for unformatted, list directed, and namelist i/o, a
matching interface for the derived type of that list item
is visible
- for I/O statements with a ,
a matching interface for the derived type of that list
item is visible, and the list item matches up with a DT
edit descriptor,
The "unit" dummy argument will have the same unit value as
specified by the user in the originating I/O statement
for all external units except "*". When an internal unit or
the "*" external unit was specified in the originating I/O
statement, the "unit" dummy argument will have a processor
dependent negative value.
Note: Since the "unit" dummy argument value will be negative when
the parent I/O statement specified an internal file or "*" unit,
a user defined derived type I/O routine should not execute an
INQUIRE without checking for a positive value of the unit dummy
argument.
The "iotype" argument will have the value:
- "LISTDIRECTED" if the originating I/O statement specified
list directed I/O,
- "NAMELIST" if the original I/O statement contained an
NML= specifier, or
- "DT[letters]" if the originating I/O statement contained a
format specification and the list item matched up with a
DT edit descriptor.
The "DT" in "iotype" and the letters after the "DT"
will be converted to upper case.
If the original I/O statement is a READ statement, a value assigned
to the "dtv" dummy arg (or some portion thereof) by the user defined
derived type I/O read routine will assign those values into the
input list item.
If the original I/O statement is a WRITE or PRINT, the "dtv"
dummy arg contains the value of the list item from the
original I/O statement.
The "w", "d", and "m" arguments contain the user specified
values from the FORMAT (i.e. FORMAT(DT12.5.2 ) ). If the
user did not specify "w", "d", and/or "m", those dummy
arguments will not be present. They will not be present if
the original I/O statement was a list directed, or namelist
I/O statement.
The user defined derived type I/O routines for reads shall
assign a value of .FALSE. or .TRUE. to the "err", "eof", and
"eor" dummy args. The value assigned to these dummy arguments
determine whether or not the corresponding condition will
be triggered by the processor in the parent I/O statement when
the user defined derived type I/O routine returns.
If the value .TRUE. is assigned to the "err" dummy argument,
the "errmsg" dummy argument shall be defined also, before the
user defined derived type I/O routine returns.
When "err" is set to true, and the parent I/O statement did
contained neither an ERR= nor an IOSTAT= specifier, the
processor shall attempt to output the "errmsg" value and stop
execution of the program.
Note to the reader: If we add an ERRMSG= specifier to all read/write
statements, this value would be returned thereto.
When a DT edit descriptor is matched with a list item that is
not a derived type an error will occur.
When a DT edit descriptor is matched with a list item that is
a derived type, but no matching interface for a
user defined derived type I/O routine was visible, an error will
occur.
Note: The users routine may chose to interpret the "w" argument as a
field width, but this is not required. If it does, it would be
appropriate to fill an output field with "*"s if "w" is too small.
When a parent READ statement is active, I/O statements
shall not READ from any other external unit other than the one
passed in via the dummy arg "unit", nor perform output to any
external unit.
When a parent WRITE or PRINT statement is active, I/O statements
shall not perform output to any other external unit other than the
one passed in via the dummy arg "unit, nor perform input from any
external unit.
When a parent I/O statement is active, data transfer I/O
statements that specify an internal file are permitted.
OPEN, CLOSE, BACKSPACE, ENDFILE, and REWIND statements shall not
be executed while a user defined derived type I/O routine
is active.
The user defined derived type I/O routines may
use a FORMAT with a DT edit descriptor, for handling components
of the derived type which are themselves a derived type.
A child I/O statement that is a list directed or namelist I/O
statement may contain a list item of derived type.
Child WRITE and PRINT statements will write
into the record started by the parent output statement,
starting at the position in the record where the last edit descriptor
left off. Record boundaries may be created by output statements
in the user defined derived type I/O routines for formatted I/O.
A child formatted WRITE or PRINT statement will not position the file
to the next record before the list items are processed, but it
will end the current record when the child output statement
completes, unless the child output statement is non-advancing.
Child READ statements start reading from the postion in the current
record where the last edit descriptor from the parent
I/O statement left off. Multiple records may be read from a
formatted file. A child formatted READ statement will position
the file at the next record when the child READ statement completes,
unless the child READ statement is non-advancing.
Record positioning edit descriptors, such as TL and TR,
used on "unit" by a child I/O statement, shall not cause the
record position to be positioned before the record position at
the time the user defined derived type I/O routine was invoked.
Note: A robust user defined derived type I/O routine may wish to
use INQUIRE to determine what BLANK=, PAD= and DELIM= are for
an external unit.
Edit descriptors which affect subsequent edit descriptors
behavior, such as BN, SP, P, etc., are permitted in FORMATs in
child I/O statements. The processor will save the state of BN,
BZ, S, SP, SS, and P before calling a user defined derived type
I/O routine, call the user defined derived type I/O routine, and
reset the processor's state of BN, BZ, S, SP, SS, and P to the saved
state when the user defined derived type I/O routine returns.
A child I/O statement is free to use these state changing edit
descriptors without having any effect on the formatting of list
items in the parent I/O list.
Note to the reader: If directed rounding mode edit descriptors are added,
these will be added to the list of "saved" states.
READ and WRITE statements executed in a user defined derived
type I/O routine, or executed in a routine invoked (directly
or indirectly) from a user defined derived type I/O routine
shall not contain an ASYNCHRONOUS="YES" specifier, nor shall
the parent READ or WRITE statement contain an ASYNCHRONOUS="YES"
specifier.
A user defined derived type I/O routine, and any routines invoked
therefrom, shall not define, or cause to become undefined, any
storage location referenced by any I/O list item, the
corresponding format, or any specifer in any active parent input/output
statement, except through the "dtv" dummy argument.
In section 10.2.1 [173:1+], add
"or DT [letter] ... [w[.d[.m]]] "
In section 10.2.1 [173:11+] add
"Constraint: The string of letters following a DT edit descriptor
shall not contain more than 253 characters."
Add a new section 10.5.5 [181:28+]:
"10.5.5 User defined derived type editing
The DT edit descriptor allows a user provided routine to be used
for processing a list item of derived type instead of the processor
supplied I/O formatting routines.
The DT characters may be followed by up to 253 letters
(additional interspersed blanks are permitted) (ex. "DT LNK LST").
The text of the edit descriptor, including the initial "DT" and
the string of letters, up to but not including w,
will be converted to uppercase and have all blanks removed.
The resulting character value will be passed to the user defined
derived type I/O routine as the "iotype" argument.
Note: The letters after "DT" could be used to request different
formatting rules for various components in the derived type.
When a derived type variable or value matchs up with a DT
edit descriptor, the user shall provide the corresponding
read/write procedure for that derived type, with
a visible interface that matches the definition in
section 9.4.4.4.3.
In section 12.3.2.1, in R1207 [204:14+] add,
"or READ (FORMATTED)
or READ (UNFORMATTED)
or WRITE (FORMATTED)
or WRITE (UNFORMATTED)"
| In section 12.3.2.1 [206:5+] add a new paragraph:
| "An interface-stmt containing the keywords READ or WRITE,
| followed by "(FORMATTED)" or "(UNFORMATTED)", is an interface
| for a user defined derived type I/O routine (9.4.4.4.3).
|
| Add sections as follows:
| "12.3.2.1.3 User defined derived type I/O routine interfaces
| All of the procedures specified in an interface block for
| a user defined derived type I/O routine shall be subroutines
| that have an interface as described in section
| 9.4.4.4.3.
|
| For any derived type, there shall be at most one routine for
| that type in all "READ (FORMATTED)" interface blocks,
| at most one routine for that type in all "READ (UNFORMATTED)"
| interface blocks,
| at most one routine for that type in all "WRITE (FORMATTED)"
| interface blocks, and
| at most one routine for that type in all "WRITE (UNFORMATTED)"
| interface blocks.
OPTIONAL edits for Richard Maine, for the F2000 Introduction, summary of
new features.
User control of derived type I/O
F2000 provides a portable mechanism for the implementor of opaque
data types to also implement the I/O conversion routines for
the opaque data type, in Fortran, directly accessible from Fortran's
READ and WRITE statements, for both formatted and unformatted I/O.