Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fortran read statement reading beyond an end of line

do you know if the following statement is guaranteed to be true by one of the fortran 90/95/2003 standards? "Suppose a read statement for a character variable is given a blank line (i.e., containing only white spaces and new line characters). If the format specifier is an asterisk (*), it continues to read the subsequent lines until a non-blank line is found. If the format specifier is '(A)', a blank string is substituted to the character variable."

For example, please look at the following minimal program and input file.

program code:

PROGRAM chk_read
  INTEGER,         PARAMETER :: MAXLEN=30
  CHARACTER(len=MAXLEN)      :: str1, str2

  str1='minomonta'
  read(*,*)     str1
  write(*,'(3A)')  'str1_start|', str1, '|str1_end'

  str2='minomonta'
  read(*,'(A)') str2
  write(*,'(3A)')  'str2_start|', str2, '|str2_end'

END PROGRAM chk_read

input file:

----'input.dat' content is below this line----

yamanakako

kawaguchiko    
----'input.dat' content is above this line----

Please note that there are four lines in 'input.dat' and the first and third lines are blank (contain only white spaces and new line characters). If I run the program as

$ ../chk_read < input.dat > output.dat 

I get the following output

----'output.dat' content is below this line----
str1_start|yamanakako                    |str1_end
str2_start|                              |str2_end
----'output.dat' content is above this line----

The first read statement for the variable 'str1' seems to look at the first line of 'input.dat', find a blank line, move on to the second line, find the character value 'yamanakako', and store it in 'str1'.

In contrast, the second read statement for the variable 'str2' seems to be given the third line, which is blank, and store the blank line in 'str2', without moving on to the fourth line.

I tried compiling the program by Intel Fortran (ifort 12.0.4) and GNU Fortran (gfortran 4.5.0) and got the same result.

A little bit about a background of asking this question: I am writing a subroutine to read a data file that uses a blank line as a separator of data blocks. I want to make sure that the blank line, and only the blank line, is thrown away while reading the data. I also need to make it standard conforming and portable.

Thanks for your help.

like image 851
norio Avatar asked Nov 28 '11 12:11

norio


1 Answers

From Fortran 2008 standard draft:

List-directed input/output allows data editing according to the type of the list item instead of by a format specification. It also allows data to be free-field, that is, separated by commas (or semicolons) or blanks.

Then:

The characters in one or more list-directed records constitute a sequence of values and value separators. The end of a record has the same effect as a blank character, unless it is within a character constant. Any sequence of two or more consecutive blanks is treated as a single blank, unless it is within a character constant.

This implicitly states that in list-directed input, blank lines are treated as blanks until the next non-blank value.

When using a fmt='(A)' format descriptor when reading, blank lines are read into str. On the other side, fmt=*, which implies list-directed I/O in free-form, skips blank lines until it finds a non-blank character string. To test this, do something like:

PROGRAM chk_read
INTEGER :: cnt
INTEGER,         PARAMETER :: MAXLEN=30
CHARACTER(len=MAXLEN)      :: str

cnt=1
do
  read(*,fmt='(A)',end=100)str
  write(*,'(I1,3A)')cnt,' str_start|', str, '|str_end'
  cnt=cnt+1
enddo
100 continue

END PROGRAM chk_read

$ cat input.dat



yamanakako

kawaguchiko

EOF

Running the program gives this output:

$ a.out < input.dat 
1 str_start|                              |str_end
2 str_start|                              |str_end
3 str_start|                              |str_end
4 str_start|yamanakako                    |str_end
5 str_start|                              |str_end
6 str_start|kawaguchiko                   |str_end

On the other hand, if you use default input:

read(*,fmt=*,end=100)str

You end up with this output:

$ a.out < input.dat 
1 str1_start|yamanakako                    |str1_end
2 str2_start|kawaguchiko                   |str2_end
like image 150
milancurcic Avatar answered Oct 10 '22 04:10

milancurcic