First: thanks to Malcolm Cohen and Andy Vaught, (and also Craig Dedo)
for helping me to understand stream I/O a bit better.
I had not appreciated the substantial differences between formatted and
unformatted stream I/O, and had only looked properly at the sections of
the Standard describing the former. These make it clear what happens
before (9.2.3.2) and after (9.2.3.3) a WRITE or READ, but not during.
I now see that section 9.5.3.4.1 says that for formatted transfers:
"After each value is transferred, the current file position is moved to
a point immediately after the last file storage unit of the value."
However there does not seem to be any corresponding statement in
9.5.3.4.2 describing formatted data transfer. To me this looks like an
unfortunate omission from the Standard.
My confusion was compounded by the fact that for *formatted* stream
output only, the POS= value can only be 1 or a value from an earlier
INQUIRE by position. I took this to mean that one could only append, or
re-write from the start of the file. Malcolm has pointed out that the
last sentence of 9.5.1.10 clearly says "previously returned by a POS=
specifier in an INQUIRE". This was meant as a hint that one can
"bookmark" a file's position at any number of earlier points using any
number of INQUIRE statements, and reposition the file to any of them. I
had not realised this; others may miss the implication also.
Actually, I still don't quite see why the restriction is needed: what
harm can come from being able to re-write a section of a file starting
at any arbitrary byte-offset, since one can do this with an unformatted
file? I suppose it must be something to do with the penchant that some
systems have for inserting arbitrary CR and/or LF characters in
formatted output, which would make the resulting character-count hard to
determine.
Malcolm Cohen further informed me that this restriction derives from
that in the C99 Standard. Indeed it does, now that I've looked it up.
Section 7.19.9.2 says
"For a text stream, either offset shall be zero or offset shall be a
value
returned by an earlier successful call to the ftell function ..."
I have to say that I really enjoyed the next bit, which showed me some
unexpected pleasures of the C-side:
"After determining the new position, a successful call to the fseek
function undoes any effects of the ungetc function on the stream..."
The ungetc function in C was new to me: apparently it pushes one or more
value back on the *input* stream. Isn't that wonderful? I'm surprised
that Fortran2003 does not provide similar functionality, presumably by
giving us an UNREAD statement. Actually I think there are times when an
UNWRITE statement would be even more useful; this is obviously necessary
in the interests of symmetry.
At times like these, I usually turn to the gospel according to Messrs
Metcalf, Reid, and Cohen. However the only mention of stream I/O in
"Fortran95/2003 Explained" is in section 19.6 (p327). This, I'm afraid,
did little to dispel my confusion by showing me only how to re-write a
file by using two WRITE statements and one INQUIRE.
I can't help feeling that the description of stream I/O in the F2003
Standard is somewhat less than clear. I think the basic mistake is for
it to be interspersed with the complexities of record-handling. The
whole point of stream I/O, I thought, was that for the first time it
frees the Fortran programmer from the shackles of record-based I/O. If
only IBM had been using punched tape instead of cards at the time
Fortran was invented, maybe this whole elaborate edifice would never
have been constructed?
Now that I think I understand things better, what I'll try to do is to
write a short idiots' guide to steam I/O in Fortran, and post it on the
web.
--
Clive Page
|