I have a file I'm parsing that contains lines such as:
ind_var_index 3 # independent variable for table lookups ()
num_eng 7 #maximum number of engines allowable
eng_ena 0 0 1 1 1 1 0 0 0 0 #engine enable flags[]
I would (ideally) like to read the id in the line (first string) then compare it against a search id before deciding whether to read the rest of the line. But if I try to use list directed I/O I can't use: ADVANCE='NO'. So I ended up with the following solution:
read( unit=fp, fmt="(a)", iostat=stat2 ) line
read( unit=line, fmt=*, iostat=stat2 ) word, (var(i), i = 1, array_length)
The question I have is what if, after the id, there is junk, what does:
(var(i), i = 1, array_length)
evaluate to?
I checked the iostat with junk and it was 0 - no help.
> I would (ideally) like to read the id in the line (first string) then compare it against a search id before deciding whether to read the rest of the line. But if I try to use list directed I/O I can't use: ADVANCE='NO'. So I ended up with the following solution:
> read( unit=fp, fmt="(a)", iostat=stat2 ) line
> read( unit=line, fmt=*, iostat=stat2 ) word, (var(i), i = 1, array_length)
> The question I have is what if, after the id, there is junk, what does:
> (var(i), i = 1, array_length)
> evaluate to?
> I checked the iostat with junk and it was 0 - no help.
Apparently everything from and including # is comment?
If so, then remove the comment.
Then count the blank fields between the various items.
(It's 1 less than the number of blank fields.)
Finally do your internal read of line, as above.
if there are enough data items, the list-directed READ is satisfied. Anything
else in the string is simply ignored.
Therefore: if you remove the comment (including the comment character), you
can be sure that the READ will fail with an error code if there are too few data. If there are more data, these are silently ignored.
> > I would (ideally) like to read the id in the line (first string) then compare it against a search id before deciding whether to read the rest of the line. But if I try to use list directed I/O I can't use: ADVANCE='NO'. So I ended up with the following solution:
> > read( unit=fp, fmt="(a)", iostat=stat2 ) line
> > read( unit=line, fmt=*, iostat=stat2 ) word, (var(i), i = 1, array_length)
> > The question I have is what if, after the id, there is junk, what does:
> > (var(i), i = 1, array_length)
> > evaluate to?
> > I checked the iostat with junk and it was 0 - no help.
> Apparently everything from and including # is comment?
> If so, then remove the comment.
> Then count the blank fields between the various items.
> (It's 1 less than the number of blank fields.)
> Finally do your internal read of line, as above.
I converted the '#' to char(0). Didn't really effect anything
though. It works either way - I get to the 3rd line, it recognizes
the id and reads 7 of the following 0's and 1's.
When I check the values of var(:) for the case of junk after the id, I
get junk values - not surprisingly. I thought there would be some
indication that there was nothing meaningful to read but evidently
not?
Interestingly, the second line doesn't even have 7 items to try to
convert to REALs?
I also tried:
read( unit=fp, fmt=*, iostat=stat ) word, (w(i), i = 1,
array_length)
where:
character(30) :: w(array_length)
to check out its behavior.
Of course, this simplely ploughs right thru newlines and eats up
whatever it needs to complete: (w(i), i = 1, array_length), including
the next id on the next line.
On Nov 3, 9:42 am, Arjen Markus <arjen.markus...@gmail.com> wrote:
> In addition to Robin's answer:
> if there are enough data items, the list-directed READ is satisfied. Anything
> else in the string is simply ignored.
> Therefore: if you remove the comment (including the comment character), you
> can be sure that the READ will fail with an error code if there are too few
> data. If there are more data, these are silently ignored.
> Regards,
> Arjen
It appears to have no ill effects if there are less than array_length
(=7) items in the line? No problems? Am I getting away with
something I shouldn't be doing to begin with?
> I would (ideally) like to read the id in the line (first string) then
> compare it against a search id before deciding whether to read the
> rest of the line. But if I try to use list directed I/O I can't
> use: ADVANCE='NO'. So I ended up with the following solution:
> read( unit=fp, fmt="(a)", iostat=stat2 ) line
> read( unit=line, fmt=*, iostat=stat2 ) word, (var(i), i = 1, array_length)
> The question I have is what if, after the id, there is junk, what does:
> (var(i), i = 1, array_length)
> evaluate to?
> I checked the iostat with junk and it was 0 - no help.
What is value of array_length?
If it is the size of the dimension of array var (in which case you might as well write read(...) word, var as the implied do does nothing useful) then I would certainly expect an i/o error if there aren't sufficient entries on the record and there is a non-numeric field.
But, back to your case, there really should be a format conversion error and if the compiler doesn't complain I'd think that would be a bug if not documented as a feature/extension, anyway (and I think a detailed reading would show it to be nonconforming though I didn't go searching for a citation).
Anyway, the "real" answer here is to parse the line to remove the trailing comment before scanning.
PS. CVF will return the values but I don't believe it is guaranteed behavior; I think it is "processor dependent" as to what happens to the i/o list when the error occurs.
program test
implicit none
character(len=80) :: s
character(len=20) :: v
integer :: idx(2)
integer :: ios
s='ind_var_index 3 # independent variable'
idx=-1
read(s,*,iostat=ios) v,idx
write(*,*) v,idx
write(*,*) 'ios ', ios
end program test
> > I would (ideally) like to read the id in the line (first string) then
> > compare it against a search id before deciding whether to read the
> > rest of the line. But if I try to use list directed I/O I can't
> > use: ADVANCE='NO'. So I ended up with the following solution:
> > read( unit=fp, fmt="(a)", iostat=stat2 ) line
> > read( unit=line, fmt=*, iostat=stat2 ) word, (var(i), i = 1, array_length)
> > The question I have is what if, after the id, there is junk, what does:
> > (var(i), i = 1, array_length)
> > evaluate to?
> > I checked the iostat with junk and it was 0 - no help.
> What is value of array_length?
> If it is the size of the dimension of array var (in which case you might
> as well write read(...) word, var as the implied do does nothing useful)
> then I would certainly expect an i/o error if there aren't sufficient
> entries on the record and there is a non-numeric field.
> But, back to your case, there really should be a format conversion error
> and if the compiler doesn't complain I'd think that would be a bug if
> not documented as a feature/extension, anyway (and I think a detailed
> reading would show it to be nonconforming though I didn't go searching
> for a citation).
> Anyway, the "real" answer here is to parse the line to remove the
> trailing comment before scanning.
> PS. CVF will return the values but I don't believe it is guaranteed
> behavior; I think it is "processor dependent" as to what happens to the
> i/o list when the error occurs.
> program test
> implicit none
> character(len=80) :: s
> character(len=20) :: v
> integer :: idx(2)
> integer :: ios
> write(*,*) v,idx
> write(*,*) 'ios ', ios
> end program test
> C:\Temp> df /nologo jski.f90
> jski.f90
> C:\Temp> jski
> ind_var_index 3 -1
> ios 59
> C:\Temp>
> --
Doesn't matter if there are less than array_length (=7) items in the
line. iostat=5010 in the case of a bad read BUT it continues along.
No ill effects. I would say this is fine but is there a better way?
>> But, back to your case, there really should be a format conversion error
>> and if the compiler doesn't complain I'd think that would be a bug if
>> not documented as a feature/extension, anyway (and I think a detailed
>> reading would show it to be nonconforming though I didn't go searching
>> for a citation).
>> Anyway, the "real" answer here is to parse the line to remove the
>> trailing comment before scanning.
...
> Doesn't matter if there are less than array_length (=7) items in the
> line. iostat=5010 in the case of a bad read BUT it continues along.
> No ill effects. I would say this is fine but is there a better way?
> BTW, I'm using gfortran.
I don't understand what you mean above at all, precisely. :)
Returning an iostat will prevent the i/o rtl from aborting if that is what you mean by "it continues along. No ill effects."
OTOH, as noted above, I do _not_ believe it is guaranteed Standard behavior that it is required for the i/o list items to be returned correctly if there is a conversion error on the READ.
As for the better way, as noted earlier, only parse the record to the comment character. Sotoo, (caution, aircode)
> > > I would (ideally) like to read the id in the line (first string) then
> > > compare it against a search id before deciding whether to read the
> > > rest of the line. But if I try to use list directed I/O I can't
> > > use: ADVANCE='NO'. So I ended up with the following solution:
> > > read( unit=fp, fmt="(a)", iostat=stat2 ) line
> > > read( unit=line, fmt=*, iostat=stat2 ) word, (var(i), i = 1, array_length)
> > > The question I have is what if, after the id, there is junk, what does:
> > > (var(i), i = 1, array_length)
> > > evaluate to?
> > > I checked the iostat with junk and it was 0 - no help.
> > What is value of array_length?
> > If it is the size of the dimension of array var (in which case you might
> > as well write read(...) word, var as the implied do does nothing useful)
> > then I would certainly expect an i/o error if there aren't sufficient
> > entries on the record and there is a non-numeric field.
> > But, back to your case, there really should be a format conversion error
> > and if the compiler doesn't complain I'd think that would be a bug if
> > not documented as a feature/extension, anyway (and I think a detailed
> > reading would show it to be nonconforming though I didn't go searching
> > for a citation).
> > Anyway, the "real" answer here is to parse the line to remove the
> > trailing comment before scanning.
> > PS. CVF will return the values but I don't believe it is guaranteed
> > behavior; I think it is "processor dependent" as to what happens to the
> > i/o list when the error occurs.
> > program test
> > implicit none
> > character(len=80) :: s
> > character(len=20) :: v
> > integer :: idx(2)
> > integer :: ios
> Doesn't matter if there are less than array_length (=7) items in the
> line. iostat=5010 in the case of a bad read BUT it continues along.
> No ill effects. I would say this is fine but is there a better way?
> BTW, I'm using gfortran.
> ---John
If I use:
read( unit=line, fmt=*, iostat=stat2 ) word, w
where:
character(30) :: w(array_length)
and there are lees that array_length (=7) items, I get iostat=-1.
>>> I would (ideally) like to read the id in the line (first string) then >>> compare it against a search id before deciding whether to read the rest >>> of the line. But if I try to use list directed I/O I can't use: >>> ADVANCE='NO'. So I ended up with the following solution:
>>> read( unit=fp, fmt="(a)", iostat=stat2 ) line
>>> read( unit=line, fmt=*, iostat=stat2 ) word, (var(i), i = 1, array_length)
>>> The question I have is what if, after the id, there is junk, what does:
>>> (var(i), i = 1, array_length)
>>> evaluate to?
>>> I checked the iostat with junk and it was 0 - no help.
>> Apparently everything from and including # is comment?
>> If so, then remove the comment.
>> Then count the blank fields between the various items.
>> (It's 1 less than the number of blank fields.)
>> Finally do your internal read of line, as above.
> I converted the '#' to char(0).
You complain that folks think you are resitant to using your intelligence
to finally notice that Fortran is not not C and then you go out of your way
to prove it it in spades. Any observer would think you are either a troll
or an idiot. Or is it the old story that you have lots and lots of time
to do it repeatedly wrong but not enough time to do it correctly at an
early stage. That biases the vote towards idiot.
The null charaacter is a Cism as a sentinal to follow the last meaningful
element in a C array of characters. Only half or the C string library uses
the convention as the other half uses explicit lengths. So it is at best
a rather weak convention even in C. Fortran strings are arrays of characters
that do not use a sentinal convention. Many string related things are easier
in Fortran but there is a problem with knowing how many trailing blanks are in
a string that has first been read and then blank padded as the trailing read
blanks and the padded blanks are very hard to tell apart.
When you were told to remove the comment they meant to overwrite it with
blanks. The null character has no special meaning in Fortran and is not even
listed in the Fortran character set with the possible exception of in a character
context.
> Didn't really effect anything
> though. It works either way - I get to the 3rd line, it recognizes
> the id and reads 7 of the following 0's and 1's.
> When I check the values of var(:) for the case of junk after the id, I
> get junk values - not surprisingly. I thought there would be some
> indication that there was nothing meaningful to read but evidently
> not?
> Interestingly, the second line doesn't even have 7 items to try to
> convert to REALs?
> I also tried:
> read( unit=fp, fmt=*, iostat=stat ) word, (w(i), i = 1,
> array_length)
> where:
> character(30) :: w(array_length)
> to check out its behavior.
> Of course, this simplely ploughs right thru newlines and eats up
> whatever it needs to complete: (w(i), i = 1, array_length), including
> the next id on the next line.
> On 11/3/2012 9:31 AM, jski wrote:> On Nov 3, 10:09 am, dpb<n...@non.net> wrote:
> ...
> >> But, back to your case, there really should be a format conversion error
> >> and if the compiler doesn't complain I'd think that would be a bug if
> >> not documented as a feature/extension, anyway (and I think a detailed
> >> reading would show it to be nonconforming though I didn't go searching
> >> for a citation).
> >> Anyway, the "real" answer here is to parse the line to remove the
> >> trailing comment before scanning.
> ...
> > Doesn't matter if there are less than array_length (=7) items in the
> > line. iostat=5010 in the case of a bad read BUT it continues along.
> > No ill effects. I would say this is fine but is there a better way?
> > BTW, I'm using gfortran.
> I don't understand what you mean above at all, precisely. :)
> Returning an iostat will prevent the i/o rtl from aborting if that is
> what you mean by "it continues along. No ill effects."
> OTOH, as noted above, I do _not_ believe it is guaranteed Standard
> behavior that it is required for the i/o list items to be returned
> correctly if there is a conversion error on the READ.
> As for the better way, as noted earlier, only parse the record to the
> comment character. Sotoo, (caution, aircode)
> >>> I would (ideally) like to read the id in the line (first string) then
> >>> compare it against a search id before deciding whether to read the rest
> >>> of the line. But if I try to use list directed I/O I can't use:
> >>> ADVANCE='NO'. So I ended up with the following solution:
> >>> read( unit=fp, fmt="(a)", iostat=stat2 ) line
> >>> read( unit=line, fmt=*, iostat=stat2 ) word, (var(i), i = 1, array_length)
> >>> The question I have is what if, after the id, there is junk, what does:
> >>> (var(i), i = 1, array_length)
> >>> evaluate to?
> >>> I checked the iostat with junk and it was 0 - no help.
> >> Apparently everything from and including # is comment?
> >> If so, then remove the comment.
> >> Then count the blank fields between the various items.
> >> (It's 1 less than the number of blank fields.)
> >> Finally do your internal read of line, as above.
> > I converted the '#' to char(0).
> You complain that folks think you are resitant to using your intelligence
> to finally notice that Fortran is not not C and then you go out of your way
> to prove it it in spades. Any observer would think you are either a troll
> or an idiot. Or is it the old story that you have lots and lots of time
> to do it repeatedly wrong but not enough time to do it correctly at an
> early stage. That biases the vote towards idiot.
> The null charaacter is a Cism as a sentinal to follow the last meaningful
> element in a C array of characters. Only half or the C string library uses
> the convention as the other half uses explicit lengths. So it is at best
> a rather weak convention even in C. Fortran strings are arrays of characters
> that do not use a sentinal convention. Many string related things are easier
> in Fortran but there is a problem with knowing how many trailing blanks are in
> a string that has first been read and then blank padded as the trailing read
> blanks and the padded blanks are very hard to tell apart.
> When you were told to remove the comment they meant to overwrite it with
> blanks. The null character has no special meaning in Fortran and is not even
> listed in the Fortran character set with the possible exception of in a
> character
> context.
> > Didn't really effect anything
> > though. It works either way - I get to the 3rd line, it recognizes
> > the id and reads 7 of the following 0's and 1's.
> > When I check the values of var(:) for the case of junk after the id, I
> > get junk values - not surprisingly. I thought there would be some
> > indication that there was nothing meaningful to read but evidently
> > not?
> > Interestingly, the second line doesn't even have 7 items to try to
> > convert to REALs?
> > I also tried:
> > read( unit=fp, fmt=*, iostat=stat ) word, (w(i), i = 1,
> > array_length)
> > where:
> > character(30) :: w(array_length)
> > to check out its behavior.
> > Of course, this simplely ploughs right thru newlines and eats up
> > whatever it needs to complete: (w(i), i = 1, array_length), including
> > the next id on the next line.
> > ---John
Gordon, thanks for the small minded, buffoonish remarks. They add a
lot to the the dialog.
>>>>> I would (ideally) like to read the id in the line (first string) then
>>>>> compare it against a search id before deciding whether to read the rest
>>>>> of the line. But if I try to use list directed I/O I can't use:
>>>>> ADVANCE='NO'. So I ended up with the following solution:
>>>>> read( unit=fp, fmt="(a)", iostat=stat2 ) line
>>>>> read( unit=line, fmt=*, iostat=stat2 ) word, (var(i), i = 1, array_length)
>>>>> The question I have is what if, after the id, there is junk, what does:
>>>>> (var(i), i = 1, array_length)
>>>>> evaluate to?
>>>>> I checked the iostat with junk and it was 0 - no help.
>>>> Apparently everything from and including # is comment?
>>>> If so, then remove the comment.
>>>> Then count the blank fields between the various items.
>>>> (It's 1 less than the number of blank fields.)
>>>> Finally do your internal read of line, as above.
>>> I converted the '#' to char(0).
>> You complain that folks think you are resitant to using your intelligence
>> to finally notice that Fortran is not not C and then you go out of your way
>> to prove it it in spades. Any observer would think you are either a troll
>> or an idiot. Or is it the old story that you have lots and lots of time
>> to do it repeatedly wrong but not enough time to do it correctly at an
>> early stage. That biases the vote towards idiot.
>> The null charaacter is a Cism as a sentinal to follow the last meaningful
>> element in a C array of characters. Only half or the C string library uses
>> the convention as the other half uses explicit lengths. So it is at best
>> a rather weak convention even in C. Fortran strings are arrays of characters
>> that do not use a sentinal convention. Many string related things are easier
>> in Fortran but there is a problem with knowing how many trailing blanks are in
>> a string that has first been read and then blank padded as the trailing read
>> blanks and the padded blanks are very hard to tell apart.
>> When you were told to remove the comment they meant to overwrite it with
>> blanks. The null character has no special meaning in Fortran and is not even
>> listed in the Fortran character set with the possible exception of in a
>> character
>> context.
>>> Didn't really effect anything
>>> though. It works either way - I get to the 3rd line, it recognizes
>>> the id and reads 7 of the following 0's and 1's.
>>> When I check the values of var(:) for the case of junk after the id, I
>>> get junk values - not surprisingly. I thought there would be some
>>> indication that there was nothing meaningful to read but evidently
>>> not?
>>> Interestingly, the second line doesn't even have 7 items to try to
>>> convert to REALs?
>>> I also tried:
>>> read( unit=fp, fmt=*, iostat=stat ) word, (w(i), i = 1,
>>> array_length)
>>> where:
>>> character(30) :: w(array_length)
>>> to check out its behavior.
>>> Of course, this simplely ploughs right thru newlines and eats up
>>> whatever it needs to complete: (w(i), i = 1, array_length), including
>>> the next id on the next line.
>>> ---John
> Gordon, thanks for the small minded, buffoonish remarks. They add a
> lot to the the dialog.
I must admire the intelligence, skill and diligence with which you go about emulating
a complete fool. Keep it up. You will be able to waste both your time and the time of
those who bother to try to help you inspite of your studious ignoring of the advice.
By the way, did you do anything about the null characters or are you just insisting
the Fortran must follow your notion of a Cism? You forgot to address the content of
you inability to get your conversion to work.
> But, again, there is no guarantee that:
> s(1:max(index(s,'#')-1,len_trim(s)) contains SIZE(values) number of
> items. So there may be an I/O error.
The above of course was intended to be min() instead of max() except it isn't robust to there not being a comment...so be sure to protect against index() returning zero...
Which is what I was telling you...
But, there is a way...replace the '#' comment indicator w/ the '/' record terminator (or if there isn't a comment add a trailing slash. This has the effect of terminating the input record for list-directed input and of supplying null values for any remaining values in the i/o list. See p. 10.10.3 in the Standard I've given you links to previously (or look up the section on list-directed input in the reference texts, I'm sure it has the information in more nearly plain English).
Or, as Robin says, parse the line and count the input fields and adjust the i/o list count accordingly...
> > s(1:max(index(s,'#')-1,len_trim(s)) contains SIZE(values) number of
> > items. So there may be an I/O error.
> The above of course was intended to be min() instead of max() except it
> isn't robust to there not being a comment...so be sure to protect
> against index() returning zero...
> Which is what I was telling you...
> But, there is a way...replace the '#' comment indicator w/ the '/'
> record terminator (or if there isn't a comment add a trailing slash.
> This has the effect of terminating the input record for list-directed
> input and of supplying null values for any remaining values in the i/o
> list. See p. 10.10.3 in the Standard I've given you links to previously
> (or look up the section on list-directed input in the reference texts,
> I'm sure it has the information in more nearly plain English).
> Or, as Robin says, parse the line and count the input fields and adjust
> the i/o list count accordingly...
> --
"But, there is a way...replace the '#' comment indicator w/ the '/'
record terminator (or if there isn't a comment add a trailing slash.
This has the effect of terminating the input record for list-directed
input and of supplying null values for any remaining values in the i/o
list."
> The null charaacter is a Cism as a sentinal to follow the last meaningful
> element in a C array of characters. Only half or the C string library uses
> the convention as the other half uses explicit lengths. So it is at best
> a rather weak convention even in C. Fortran strings are arrays of characters
> that do not use a sentinal convention. Many string related things are easier
> in Fortran but there is a problem with knowing how many trailing blanks are in
> a string that has first been read and then blank padded as the trailing read
> blanks and the padded blanks are very hard to tell apart.
This is true, but doesn't mean that you won't have problems using
strings that have CHAR(0) in them.
For one, some of the underlying library routines in many Fortran
libraries are written in C, often using the C I/O routines along
the way. If you use CHAR(0) in I/O operations, you might be surprised. Other than that, though, I would not expect problems,
but you never know.
"9.2.2 Formatted record
A formatted record consists of a sequence of characters that are
representable in the processor; however, a processor may prohibit some control characters (3.1.1) from appearing in a formatted record. The length of a formatted record is measured in characters and depends primarily on the number of characters put into the record when it is written. However, it may depend on the processor and the external medium. The length may be zero. Formatted records
shall be read or written only by formatted input/output statements."
I believe this also applies to internal I/O, though I am not so
sure about that.
>> The null charaacter is a Cism as a sentinal to follow the last meaningful
>> element in a C array of characters. Only half or the C string library uses
>> the convention as the other half uses explicit lengths. So it is at best
>> a rather weak convention even in C. Fortran strings are arrays of characters
>> that do not use a sentinal convention. Many string related things are easier
>> in Fortran but there is a problem with knowing how many trailing blanks are in
>> a string that has first been read and then blank padded as the trailing read
>> blanks and the padded blanks are very hard to tell apart.
> This is true, but doesn't mean that you won't have problems using
> strings that have CHAR(0) in them.
> For one, some of the underlying library routines in many Fortran
> libraries are written in C, often using the C I/O routines along
> the way. If you use CHAR(0) in I/O operations, you might be
> surprised. Other than that, though, I would not expect problems,
> but you never know.
> "9.2.2 Formatted record
> A formatted record consists of a sequence of characters that are
> representable in the processor; however, a processor may prohibit
> some control characters (3.1.1) from appearing in a formatted
> record. The length of a formatted record is measured in characters
> and depends primarily on the number of characters put into the
> record when it is written. However, it may depend on the processor
> and the external medium. The length may be zero. Formatted records
> shall be read or written only by formatted input/output statements."
> I believe this also applies to internal I/O, though I am not so
> sure about that.
I'm sure you can be sure (although I haven't looked). One of the beauties of Fortran is that it really tries to be consistent. A formatted record is a formatted record; regardless of where it came from or how it is used. Internal I/O is the same as external I/O unless there is some obvious reason for a restriction.
>> > This is true, but doesn't mean that you won't have problems using
>> > strings that have CHAR(0) in them.
(snip, quote from Fortran 2008)
>> > "9.2.2 Formatted record
>> > A formatted record consists of a sequence of characters that are
>> > representable in the processor; however, a processor may prohibit
>> > some control characters (3.1.1) from appearing in a formatted
>> > record. The length of a formatted record is measured in characters
>> > and depends primarily on the number of characters put into the
>> > record when it is written. However, it may depend on the processor
>> > and the external medium. The length may be zero. Formatted records
>> > shall be read or written only by formatted input/output statements."
>> > I believe this also applies to internal I/O, though I am not so
>> > sure about that.
(snip)
> Hopefully, no one will call me "idiot" for asking but what > defines "end of record" in fortran? I too use gfortran.
For external files, it pretty much has to be whatever the host
system uses. For unix and unix-like system, that is CHAR(10), (X'0A', the ASCII linefeed character). For MS-DOS and Windows
systems, CRLF, CHAR(13) followed by CHAR(10), with it left
undefined what happens if you have one an not the other.
I believe that there is still a gcc, with gfortran included,
that runs on MVS descendants, using either IBM fixed length
records or VB (variable length, blocked, with a record length
in the record and block headers.)
For internal I/O, it should be the length of the CHARACTER
variable (or array element).
>>>> The null charaacter is a Cism as a sentinal to follow the last meaningful
>>>> element in a C array of characters. Only half or the C string library uses
>>>> the convention as the other half uses explicit lengths. So it is at best
>>>> a rather weak convention even in C. Fortran strings are arrays of characters
>>>> that do not use a sentinal convention. Many string related things are easier
>>>> in Fortran but there is a problem with knowing how many trailing blanks are in
>>>> a string that has first been read and then blank padded as the trailing read
>>>> blanks and the padded blanks are very hard to tell apart.
>>> This is true, but doesn't mean that you won't have problems using
>>> strings that have CHAR(0) in them.
>>> For one, some of the underlying library routines in many Fortran
>>> libraries are written in C, often using the C I/O routines along
>>> the way. If you use CHAR(0) in I/O operations, you might be
>>> surprised. Other than that, though, I would not expect problems,
>>> but you never know.
>>> "9.2.2 Formatted record
>>> A formatted record consists of a sequence of characters that are
>>> representable in the processor; however, a processor may prohibit
>>> some control characters (3.1.1) from appearing in a formatted
>>> record. The length of a formatted record is measured in characters
>>> and depends primarily on the number of characters put into the
>>> record when it is written. However, it may depend on the processor
>>> and the external medium. The length may be zero. Formatted records
>>> shall be read or written only by formatted input/output statements."
>>> I believe this also applies to internal I/O, though I am not so
>>> sure about that.
>> I'm sure you can be sure (although I haven't looked). One of the
>> beauties of Fortran is that it really tries to be consistent. A
>> formatted record is a formatted record; regardless of where it came from
>> or how it is used. Internal I/O is the same as external I/O unless
>> there is some obvious reason for a restriction.
>> Dick Hendrickson
>>> -- glen
> Hopefully, no one will call me "idiot" for asking but what defines "end of record" in fortran? I too use gfortran.
> <Ella>
There isn't a specific definition of "end of record"; that is, there isn't specified character. To understand historic Fortran I/O you mostly have to think about card readers and line printers. When Fortran reads a "record" it reads one card-the entire card goes through the card reader. When it outputs a record, it prints one line and the printer moves the paper forward one notch. Of course, things are different now. Punch cards and line printers don't exist. But the idea is the same. Historically, a Fortran output statement would produce at least one record; you could get more by using a FORMAT statement with either long lists or special format things. Similarly, a read statement would read one (or more) input records.
So, the simple answer is that an output statement produces one (or more) records; each separated from the other by a processor dependent end-of-record thing and a read statement reads one (or more) records; it reads the entire record, up to the end-of-record thing. The standard doesn't specify what the end-of-record thing is; but, Fortran exists in a computing system and usually uses whatever the other languages use.
It's a little harder to understand with the later versions of Fortran. Non-advancing I/O allows you to read or write part of a record (sort of like reading the first half of a card). Stream I/O allows you to use the C model of I/O; I/O just produces a stream of characters and the OS doesn't impose a particular structure on the characters. Although other programs might require or expect some sort of structure. If you send a stream output file to a screen something has to happen when the cursor comes to the right hand edge of the screen.
>>>> The null charaacter is a Cism as a sentinal to follow the last meaningful
>>>> element in a C array of characters. Only half or the C string library uses
>>>> the convention as the other half uses explicit lengths. So it is at best
>>>> a rather weak convention even in C. Fortran strings are arrays of characters
>>>> that do not use a sentinal convention. Many string related things are easier
>>>> in Fortran but there is a problem with knowing how many trailing blanks are in
>>>> a string that has first been read and then blank padded as the trailing read
>>>> blanks and the padded blanks are very hard to tell apart.
>>> This is true, but doesn't mean that you won't have problems using
>>> strings that have CHAR(0) in them.
>>> For one, some of the underlying library routines in many Fortran
>>> libraries are written in C, often using the C I/O routines along
>>> the way. If you use CHAR(0) in I/O operations, you might be
>>> surprised. Other than that, though, I would not expect problems,
>>> but you never know.
>>> "9.2.2 Formatted record
>>> A formatted record consists of a sequence of characters that are
>>> representable in the processor; however, a processor may prohibit
>>> some control characters (3.1.1) from appearing in a formatted
>>> record. The length of a formatted record is measured in characters
>>> and depends primarily on the number of characters put into the
>>> record when it is written. However, it may depend on the processor
>>> and the external medium. The length may be zero. Formatted records
>>> shall be read or written only by formatted input/output statements."
>>> I believe this also applies to internal I/O, though I am not so
>>> sure about that.
>> I'm sure you can be sure (although I haven't looked). One of the
>> beauties of Fortran is that it really tries to be consistent. A
>> formatted record is a formatted record; regardless of where it came from
>> or how it is used. Internal I/O is the same as external I/O unless
>> there is some obvious reason for a restriction.
>> Dick Hendrickson
>>> -- glen
> Hopefully, no one will call me "idiot" for asking but what defines "end > of record" in fortran? I too use gfortran.
> <Ella>
The notion of "end of record" is outside Fortran. It depends on whatever the file
system used by Fortran uses. Sometimes it is a character embedded within the stream of
characters. For Unix that is usually <LF>, for MacOs it is <CR>, for Windows it is
the pair <CR><LF> with sometimes the <LF> becoming a <FF>. ASCII would suggest using a <RS>
and some systems have taken the suggestion. When cards were common "all" records were
80 characters and the end was defined by the count (and it was possable for 80 to be other
lengths) in blocked files on IBM's OS. Others used a count stored external to the stream.
So the short answer is "it depends". gfortran is available on several systems so it has
several answers. Since you did not specify a system the details are left as an exercise
for the reader.
> >> > This is true, but doesn't mean that you won't have problems using
> >> > strings that have CHAR(0) in them.
> (snip, quote from Fortran 2008)
> >> > "9.2.2 Formatted record
> >> > A formatted record consists of a sequence of characters that are
> >> > representable in the processor; however, a processor may prohibit
> >> > some control characters (3.1.1) from appearing in a formatted
> >> > record. The length of a formatted record is measured in characters
> >> > and depends primarily on the number of characters put into the
> >> > record when it is written. However, it may depend on the processor
> >> > and the external medium. The length may be zero. Formatted records
> >> > shall be read or written only by formatted input/output statements."
> >> > I believe this also applies to internal I/O, though I am not so
> >> > sure about that.
> (snip)
> > Hopefully, no one will call me "idiot" for asking but what
> > defines "end of record" in fortran? I too use gfortran.
> For external files, it pretty much has to be whatever the host
> system uses. For unix and unix-like system, that is CHAR(10),
> (X'0A', the ASCII linefeed character). For MS-DOS and Windows
> systems, CRLF, CHAR(13) followed by CHAR(10), with it left
> undefined what happens if you have one an not the other.
> I believe that there is still a gcc, with gfortran included,
> that runs on MVS descendants, using either IBM fixed length
> records or VB (variable length, blocked, with a record length
> in the record and block headers.)
> For internal I/O, it should be the length of the CHARACTER
> variable (or array element).
> -- glen
If I do: read(unit=file, fmt="(a)", iostat=ios) string
then system looks for char(10) in Linux? So system reads up to
char(10) for string?
>> Hopefully, no one will call me "idiot" for asking but what >> defines "end of record" in fortran? I too use gfortran.
then Dick Hendrickson <dick.hendrick...@att.net> wrote:
> There isn't a specific definition of "end of record"; that is, there > isn't specified character. To understand historic Fortran I/O you > mostly have to think about card readers and line printers. When Fortran > reads a "record" it reads one card-the entire card goes through the card > reader. When it outputs a record, it prints one line and the printer > moves the paper forward one notch. Of course, things are different now. > Punch cards and line printers don't exist. But the idea is the same. > Historically, a Fortran output statement would produce at least one > record; you could get more by using a FORMAT statement with either long > lists or special format things. Similarly, a read statement would read > one (or more) input records.
It is interesting. The IBM 704, where Fortran started, read each row
of holes into two 36 bit words. Software had to rearrange that to
72 characters. The last 8 card columns weren't read at all.
> So, the simple answer is that an output statement produces one (or more) > records; each separated from the other by a processor dependent > end-of-record thing and a read statement reads one (or more) records; it > reads the entire record, up to the end-of-record thing. The standard > doesn't specify what the end-of-record thing is; but, Fortran exists in > a computing system and usually uses whatever the other languages use.
> It's a little harder to understand with the later versions of Fortran. > Non-advancing I/O allows you to read or write part of a record (sort of > like reading the first half of a card). Stream I/O allows you to use the > C model of I/O; I/O just produces a stream of characters and the OS > doesn't impose a particular structure on the characters. Although other > programs might require or expect some sort of structure. If you send a > stream output file to a screen something has to happen when the cursor > comes to the right hand edge of the screen.
I started learning PL/I, not so long after Fortran. Even though designed
around IBM's record oriented file system, PL/I uses STREAM I/O for
what Fortran calls FORMATTED. It is still record buffered, but the
program can write parts of records at a time.
I don't know so well the systems where C originated, but at least in
the ANSI standard, and I believe even in K&R the idea that the system
will buffer the I/O is there.
The usual implementation of getc() and putc() uses C macros to load
and store from/to a buffer, only doing an actual function call when
the buffer is empty/full.
The early Fortran systems might have directly used the I/O buffer
that the system used for actual I/O operations.
Many systems now put another level of buffering between the program
and the I/O devices. Unix uses that as a disk cache, to speed up
I/O by prefetching and delaying writing full buffers.
So, or a long time now, there is not necessarily a connection between records as seen by the program and those actually seen
by the I/O device.