Re: How to do a seek (nonadvancing read) on a stream file?
(This is an attempt to reply to a Mon Feb 3 19:09:38 GMT 2025 message by Steve Kargl.) > I believe that you are misreading C1223. The file is > opened with form='unformatted'. Hm, okay. I guess it comes down to whether you "diagram" the sentence in the spec as "An ADVANCE= specifier shall appear only in a formatted (sequential or stream) data transfer statement" or "An ADVANCE= specifier shall appear only in a (formatted sequential) or (stream data transfer) statement". If you interpret it the first way the gfortran behavior is correct (although the error message could be improved…), if you interpret it the second way gfortran is incorrect. > PS: You're looking for the INQUIRE statement. In the context of the program I was trying to write, INQUIRE can be used to get the byte length of the file. That is not something I was trying to do. The data was structured, and needed to be parsed to determine the allocation size. In other words INQUIRE is the equivalent of C ftell() and I am looking for the equivalent of C fseek(). (Which the standard appears to only offer through nonadvancing reads… which gfortran appears to disallow for an unformatted stream file. Unless you do the "silly" thing I eventually did, which is to bundle your seek together with the next advancing read.) Thanks for the information. On Mon, Feb 3, 2025 at 1:34 PM Andi McClure wrote: > Last week, as an exercise in learning FORTRAN, I did a programming puzzle > ( https://adventofcode.com/2024/day/4 ) with gfortran. I targeted the > 2023 standard (*not* GNU). I saw two oddities. The first I posted about in > this mailing list already (and it turns out there is a relevant bugzilla > bug). The other I *think* is a bug (and I am not finding an existing > bugzilla bug on my own), but I am less sure, so wanted to check here first > before filing. > > For my solution, I needed to read in a file in stream mode, character by > character(1). I needed to do this twice, once to find out what size array > to load the data into and once to load the data into my newly-allocated > array. It initially appeared stream mode would allow me to do this without > closing and reopening the file, by "seeking" back to the beginning of the > file using the pos= argument to READ. But when I tried to do this, > something odd happened. > > Details: I open the file with > > ``` > > open(10,file=path,access='stream',form='unformatted',action='read',iostat=file_error) > ``` > > This works; scanning to determine the input size works. Now I need to > seek. I find this old stackoverflow answer: > https://stackoverflow.com/a/11785795 > > Claiming that the following code works (and implying they tested it in " > ifort"): > > ``` > READ (iu,"()", ADVANCE='NO', POS=file_pos) ! iu is file unit > ``` > > I created a test program implementing this: > > > https://github.com/mcclure/aoc2024/blob/38875a77fd48d8208ebcadfb3ec9c53fb722ef8b/04-01-wordsearch/src/puzzle.f90#L4 > > And using a test input such as: > > > https://github.com/mcclure/aoc2024/blob/38875a77fd48d8208ebcadfb3ec9c53fb722ef8b/04-01-wordsearch/data/sample-2.18.txt > > I can run it with `gfortran src/puzzle.f90 -std=f2023 -o program && > ./program data/sample-2.18.txt`. When I do this, I get a failure: > > ``` > At line 88 of file src/puzzle.f90 (unit = 10, file = > 'data/sample-2.18.txt') > Fortran runtime error: Format present for UNFORMATTED data transfer > ``` > > It appears it does not like the "()" format. However, imagine I edit line > 88 to change `read(10, "()", advance='no', pos=1)` to `read(10, > advance='no', pos=1)`, removing the format. Now I get a different error: > > ``` > ./program data/sample-2.18.txt > src/puzzle.f90:88:21: > >88 | read(10, advance='no', pos=1) > | 1 > Error: the ADVANCE= specifier at (1) must appear with an explicit format > expression > ``` > > So if I have a (null) format specifier the error message tells me to > remove the format expression, and if I remove the format specifier the > error message tells me to add a format expression. There appears to be *no > way* of using advance='no' that will not cause gfortran to emit an error; > even putting in a (spurious/useless) read, such as with `read(10, "(a)", > advance='no', pos=1) char_in`, produces "Fortran runtime error: Format > present for UNFORMATTED data transfer". > > I do not have a specific need for this to be fixed; I eventually got my > program to work via a workaround I would consider "silly" ( see lin
How to do a seek (nonadvancing read) on a stream file?
Last week, as an exercise in learning FORTRAN, I did a programming puzzle ( https://adventofcode.com/2024/day/4 ) with gfortran. I targeted the 2023 standard (*not* GNU). I saw two oddities. The first I posted about in this mailing list already (and it turns out there is a relevant bugzilla bug). The other I *think* is a bug (and I am not finding an existing bugzilla bug on my own), but I am less sure, so wanted to check here first before filing. For my solution, I needed to read in a file in stream mode, character by character(1). I needed to do this twice, once to find out what size array to load the data into and once to load the data into my newly-allocated array. It initially appeared stream mode would allow me to do this without closing and reopening the file, by "seeking" back to the beginning of the file using the pos= argument to READ. But when I tried to do this, something odd happened. Details: I open the file with ``` open(10,file=path,access='stream',form='unformatted',action='read',iostat=file_error) ``` This works; scanning to determine the input size works. Now I need to seek. I find this old stackoverflow answer: https://stackoverflow.com/a/11785795 Claiming that the following code works (and implying they tested it in " ifort"): ``` READ (iu,"()", ADVANCE='NO', POS=file_pos) ! iu is file unit ``` I created a test program implementing this: https://github.com/mcclure/aoc2024/blob/38875a77fd48d8208ebcadfb3ec9c53fb722ef8b/04-01-wordsearch/src/puzzle.f90#L4 And using a test input such as: https://github.com/mcclure/aoc2024/blob/38875a77fd48d8208ebcadfb3ec9c53fb722ef8b/04-01-wordsearch/data/sample-2.18.txt I can run it with `gfortran src/puzzle.f90 -std=f2023 -o program && ./program data/sample-2.18.txt`. When I do this, I get a failure: ``` At line 88 of file src/puzzle.f90 (unit = 10, file = 'data/sample-2.18.txt') Fortran runtime error: Format present for UNFORMATTED data transfer ``` It appears it does not like the "()" format. However, imagine I edit line 88 to change `read(10, "()", advance='no', pos=1)` to `read(10, advance='no', pos=1)`, removing the format. Now I get a different error: ``` ./program data/sample-2.18.txt src/puzzle.f90:88:21: 88 | read(10, advance='no', pos=1) | 1 Error: the ADVANCE= specifier at (1) must appear with an explicit format expression ``` So if I have a (null) format specifier the error message tells me to remove the format expression, and if I remove the format specifier the error message tells me to add a format expression. There appears to be *no way* of using advance='no' that will not cause gfortran to emit an error; even putting in a (spurious/useless) read, such as with `read(10, "(a)", advance='no', pos=1) char_in`, produces "Fortran runtime error: Format present for UNFORMATTED data transfer". I do not have a specific need for this to be fixed; I eventually got my program to work via a workaround I would consider "silly" ( see line 102: https://github.com/mcclure/aoc2024/blob/ca77f141f33ab494dc1bb43f3d6f13e775a36303/04-01-wordsearch/src/puzzle.f90#L102 ). However it seems like there is a bug here, for three reasons: because having some method of seeking the file without simultaneously doing a read is fundamentally desirable; because the error messages seem to give misleading directions; and because I *think* this is a standard nonconformance. If I look at the current standard ( 2023 draft document: https://j3-fortran.org/doc/year/23/23-007r1.pdf ) under the definition of io-control-spec I see; > C1223 (R1213) An ADVANCE= specifier shall appear only in a formatted sequential or stream data transfer25 > statement with explicit format specification (13.2) whose io-control-spec-list does not contain an internal-26 > file-variable as the io-unit. This implies an io-control-spec-list with *no* "io-unit" should be allowed. I find this same text (with different numbering) in drafts of the 2008 and 2003 standards, so it appears this has been part of FORTRAN as long as stream mode itself. Does anyone know of an impediment to filing this (am I doing something wrong, is there an existing bug I was not able to find(2))? --- (1) I understand use of stream mode is considered unusual. The problem I was solving here was a rare case it was actually appropriate: the input file, linked above as "test input", was a grid of ASCII art. (2) I think I have the hang of using the mailing list now, so I expect I will actually see the reply this time *_*
gfortran not following deferred initialization rules for get_command_argument
This last week, as an exercise in learning FORTRAN, I attempted to complete a programming puzzle ( https://adventofcode.com/2024/day/4 ) with gfortran. I made a specific decision to target the 2023 standard and *not* the GNU standard. I believe I have found a nonconformance with gfortran 14.2.0 targeting the 2023 standard(1). Details: I wanted my program to input data from a file, and intended it to take the filename from the command line. I found the standard way to do this is: https://gcc.gnu.org/onlinedocs/gfortran/GET_005fCOMMAND_005fARGUMENT.html Normal usage of this function involves knowing the length of the argument you are going to input ahead of time(2). However, I had been reading standards documents, and found this section in this 2023 "informal" publication of the Fortran working group, "The new features of Fortran 2023" https://wg5-fortran.org/N2201-N2250/N2212.pdf , emphasis mine: > 2.2 US 14. Automatic allocation of lengths of character variables > When a deferred-length allocatable variable is defined by intrinsic assignment, as in the example > > character(:), allocatable :: quotation > : > quotation = ’Now is the winter of our discontent.’ > > it is allocated by the processor to the correct length. This behaviour is extended to messages > returned through iomsg and errmsg specifiers, writing to a scalar character variable as an > internal file, and intent out and inout scalar character arguments of intrinsic procedures, **such > as in call `get_command(command)`**. This is an informal publication but I believe this should be taken to apply to the "value" argument of GET_COMMAND_ARGUMENT, for three reasons: Because the "new features" document explicitly calls out GET_COMMAND, and GET_COMMAND_ARGUMENT is so similar; because the 2023 draft standard I find https://j3-fortran.org/doc/year/23/23-007r1.pdf seems to confirm the behavior, in 16.9.1: "When an allocatable deferred-length character scalar corresponding to an INTENT (INOUT) or INTENT (OUT) argument is assigned a value, the value is assigned as if by intrinsic assignment."; and because the same draft spec states in GET_COMMAND_ARGUMENT that "value" is indeed INTENT(OUT). However, I do *not* see automatic allocation of the GET_COMMAND_ARGUMENT out value in gfortran. Here is a test program: https://github.com/mcclure/aoc2024/blob/822e460f81b944c21ca675303b868c45b22a4c2b/04-01-wordsearch/src/puzzle.f90 I run this with `gfortran src/puzzle.f90 -std=f2023 -o program && ./program data/puzzle.txt`. This program defines a character string as in the FORTRAN 2023 "new features" document (the source says "len=:" rather than ":", but changing this to ":" does not change the output), passes the unallocated string to GET_COMMAND_ARGUMENT, prints the string, then attempts to open a file by that name. When print, the string appears to be empty; a blank line is printed, and then > At line 20 of file src/puzzle.f90 (unit = 10) > Fortran runtime error: Cannot open file '': No such file or directory Here's a longer test program, with a long comment, which passes the string to GET_COMMAND_ARGUMENT but also a variable for the "length" out parameter. It then allocates a string of that length and passes it to GET_COMMAND_ARGUMENT. This works (and you can confirm it is opening the file by passing the name of a non-existent file as argument, which the program will then create(3)): https://github.com/mcclure/aoc2024/blob/b31be91adb5a0721f97e2ba8f145da4f36129753/04-01-wordsearch/src/puzzle.f90 Summary: It is my opinion from the FORTRAN 2023 spec that the first test program above should have worked and the additional steps in the second test program should not have been necessary. Have I misread the spec, is there something wrong with my code, or have I identified a bug in gfortran? Should I file at the GCC Bugzilla? --- (1) If I'm not mistaken 14.2.0 dates from August 2024, so I would expect it to be up to date. I installed gfortran via Debian Trixie and here is the output of gfortran -v: https://gist.githubusercontent.com/mcclure/9ccf6010b2db4b19adbed3127192c9da/raw/9fb74f44124a727a5d88730f2d69ffb4b2bca6f2/gfortran.txt (2) The sample code in the GNU doc recommends allocating a string longer than needed, in which excess space will be filled with blanks. This solution was in practice adequate for my needs, but because my goal in writing the program was to learn modern FORTRAN, I decided to try to "do it right" if possible. (3) The sample is minimal, so `action='read'` is not specified in the open() call.