fortran

Fortran ftell returning to wrong position


Here is a snippet of simple code that reads line from file, then returns to previous position and re-reads same line:

program main
  implicit none
  integer         :: unit, pos, stat
  character(128)  :: buffer

  ! Open file as formatted stream
  open( NEWUNIT=unit, FILE="data.txt", ACCESS="stream", FORM="formatted", STATUS="old", ACTION="read", IOSTAT=stat )
  if ( stat /= 0 ) error stop

  ! Skip 2 lines
  read (unit,*) buffer
  read (unit,*) buffer

  ! Store position
  pos = ftell(unit)

  ! Read & write next line
  read (unit,*) buffer
  write (*,*) "buffer=", trim(buffer)

  ! Return to previous position
  call fseek(unit,pos,0)
  ! pos = ftell(unit)   ! <-- ?!

  ! Read & write next line (should be same output)
  read (unit,*) buffer
  write (*,*) "buffer=", trim(buffer)

  ! Close file stream
  close (UNIT=unit)

end program main

The "data.txt" is just a dummy file with 4 lines:

1
2
3
4

Now when I compile the snippet (gfortran 9.3.0) and run it, I get an answer:

 buffer=3
 buffer=4

which is wrong, as they should be same. More interestingly when I add an additional ftell (commented line in the snippet) after 'fseek' I get correct answer:

 buffer=3
 buffer=3

Any idea why it does that? or am I using ftell and fseek incorrectly?


Solution

  • gfortran's documentation for FTELL and FSEEK clearly states that these routines are provided for backwards compatibility with g77. As your code is using NEWUNIT, ERROR STOP, and STREAM access, you are not compiling old moldy code. You ought to use standard conforming methods as pointed out by @Vladimir.

    A quick debugging session shows that FTELL and FSEEK are using a 0-based reference for the file position while the inquire method of modern Fortran is 1 based. There could be an off-by-one type bug in gfortran, but as FTELL and FSEEK are for backwards compatibility with g77 (an unmaintained 15+ year old compiler), someone would need to do some code spelunking to determine the intended behavior. I suspect none of the current, active, gfortran developers care enough to explore the problem. So, to fix your problem

    program main
    
      implicit none
    
      integer pos, stat, unit
      character(128) buffer
    
      ! Open file as formatted stream
      open(NEWUNIT=unit, FILE="data.txt", ACCESS="stream", FORM="formatted", &
      &  STATUS="old", ACTION="read", IOSTAT=stat)
    
      if (stat /= 0) stop
    
      ! Skip 2 lines
      read (unit,*) buffer
      read (unit,*) buffer
    
      ! Store position
      inquire(unit, pos=pos)
    
      ! Read & write next line
      read (unit,*) buffer
      write (*,*) "buffer=", trim(buffer)
    
      ! Reread & write line (should be same output)
      read (unit,*,pos=pos) buffer
      write (*,*) "buffer=", trim(buffer)
    
      ! Close file stream
      close (UNIT=unit)
    
    end program main