# Extracting a set of numbers from a file

I do most of my programming in C/C++ and Perl, but I currently learning Fortran. I began by coding up a simple program, something that took me < 5 minutes in Perl (see this thread from BioStar). After working for several hours on a solution in Fortran 95 (teaching myself as I go), I came to this solution.

implicit none

! Variable definitions
integer                 :: argc
integer                 :: num_digits
integer                 :: i, j
integer                 :: iocode
integer                 :: line_length
integer                 :: value
character ( len=256 )   :: infile
character ( len=16 )    :: int_format
character ( len=16 )    :: int_string
character ( len=2048 )  :: line

! Verify and parse command line arguments
argc = iargc()
if( argc < 1 ) then
write(*, '(A, I0, A)') "Error: please provide file name (argc=", argc, ")"
stop
endif
call getarg(1, infile)

! Open input file, croak if there is an issue
open( unit=1, file=infile, action='read', iostat=iocode )
if( iocode > 0 ) then
write(*, '(A, A, A)') "Error: unable to open input file '", trim(infile), "'"
stop
endif

! Process the file, print in CSV format
do while(1 == 1)
! Read the line, skip if it is empty
100 read( unit=1, fmt='(A)', end=200 ) line
line_length = len_trim(line)
if( line_length == 0 ) then
goto 100
endif

! The first value in the line is a string
! Find string boundaries and print it out
i = 0
do while( line(i:i) == ' ' )
i = i+1
end do
j = i
do while( line(j:j) /= ' ' )
j = j+1
end do

! Now grab the rest of the integer values
! on the line, multiply them by 3, and print
i = j
j = 0
do while( i < line_length)
do while( line(i:i) == ' ' )
i = i+1
end do
j = i
do while( j < line_length .and. line(j:j) /= ' ' )
j = j+1
end do
int_string = line(i:j-1)
value = value*3
write(*, '(A, I0)', advance="no") ",", value
i = j
j = 0
end do

print *
end do
200 close( 1 )

end program


There is a lot that I don't like about how I've written this program, but it's hard to separate my inexperience with the new syntax from bad practice. One thing in particular that I don't like is my use of labels and the infamous goto statement. I'm interested in any feedback whatsoever, but I'm particularly interested in better ways to handle the control structure of the program (without using the goto statement and end parameter in the read function if possible).

You could get rid of the GOTO statements by using labelled loops with EXIT and CYCLE statements. These allow you to do the sort of flow control that you've used the GOTOs for, but don't permit the less desirable features, such as computed GOTOs. Using these newer Fortran features also gives you a clearer idea of the flow control at the point at which the branching occurs. E.g., CYCLE or EXIT statements send you respectively further up or down the source code, and a well chosen label may indicate what the branching is trying to achieve.

Another suggestion, although this is more of a personal preference, is to avoid the potentially endless DO WHILE(1 == 1) loop by using a normal DO loop with a large upper limit and adding warning message if that limit is reached before the end of file is encountered. Plenty of people might find that overly fussy though.

Example code showing these two points:

PROGRAM so_goto

IMPLICIT NONE

INTEGER,PARAMETER :: line_max = 100000

INTEGER :: i, ios, line_length
CHARACTER( len=2048 ) :: line

IF( ios < 0 ) EXIT fread
line_length = LEN_TRIM(line)
IF( line_length == 0 ) CYCLE fread

IF( i == line_max ) THEN
print*,"BTW, you've hit your read limit before the end of the file."
ENDIF

• +1 I much prefer the EXIT/CYCLE syntax to the GOTO statements. It makes the intent of the statements much more explicit. – Daniel Standage Jan 27 '11 at 14:25
• Either use a normal do or if an endless loop, than just do is enough. The while part is superfluous and should be only used when a real condition is needed. – Vladimir F Sep 29 '12 at 20:38