[gfortran] patch for pr15472 and sequential unformatted I/O

Bud Davis bdavis@gcc.gnu.org
Fri Jul 2 04:58:00 GMT 2004


this patch fixes the PR and about 3 other problems that were keeping
unformatted sequential I/O from working.

it uses 32 bit record length markers on systems with offset_t == 32 bits
and 64 bit record length markers on systems with offset_t == 64. same as
before, it just now works.

i couldn't test these limits because none of the systems i use have
enough memory to create a 2GB or 2GB+ array, but it worked until i ran
out of memory.

tested on i686/gnu/linux FC1 and i686/FreeBSD 5.2 with no additional
test suite failures.


--bud


2004-07-02  Bud Davis  <bdavis9659@comcast.net>

	PR gfortran/15472
	* io/transfer.c(us_write): set recl for seq unform writes to max size.
	* io/transfer.c(data_transfer_init): handle un-opened seq unform unit.
	* io/unix.c(fd_alloc_w_at): deal with writes in the middle of the
	buffer.
	* io/unix.c(is_seekable): set based upon the file/device, not the 
	method being used to access it (fd or mmap).

New test suite file:


! pr 15472
! sequential access files
!
!  this test verifies the most basic sequential unformatted I/O
!      write 3 records of various sizes
!      then read them back
!      and compare with what was written
!
       implicit none
       integer size
       parameter(size=100)
       logical debug 
       data debug /.FALSE./
! set debug to true for help in debugging failures.
       integer m(2)
       integer n
       real*4 r(size)
       integer i
       m(1) = Z'11111111'
       m(2) = Z'22222222'
       n    = Z'33333333'
       do i = 1,size
         r(i) = i
       end do
       write(9)m  ! an array of 2
       write(9)n  ! an integer
       write(9)r  ! an array of reals
! zero all the results so we can compare after they are read back
       do i = 1,size
          r(i) = 0
       end do
       m(1) = 0
       m(2) = 0
       n = 0

       rewind(9)
       read(9)m
       read(9)n
       read(9)r
!
! check results
       if (m(1).ne.Z'11111111') then
         if (debug) then
            print '(A,Z8)','m(1) incorrect.  m(1) = ',m(1)
         else
            call abort
         endif
       endif

       if (m(2).ne.Z'22222222') then
         if (debug) then
            print '(A,Z8)','m(2) incorrect.  m(2) = ',m(2)
         else
            call abort
         endif
       endif

       if (n.ne.Z'33333333') then
         if (debug) then
            print '(A,Z8)','n incorrect.  n = ',n
         else
            call abort
         endif
       endif

       do i = 1,size
          if (int(r(i)).ne.i) then
            if (debug) then
              print*,'element ',i,' was ',r(i),' should be ',i
            else
              call abort
            endif
          endif
       end do
! use hexdump to look at the file "fort.9"
       if (debug) then
         close(9)
       else
         close(9,status='DELETE')
       endif
       end



Index: gcc/libgfortran/io/transfer.c
===================================================================
RCS file: /cvs/gcc/gcc/libgfortran/io/transfer.c,v
retrieving revision 1.7
diff -c -3 -p -r1.7 transfer.c
*** gcc/libgfortran/io/transfer.c	22 Jun 2004 00:43:55 -0000	1.7
--- gcc/libgfortran/io/transfer.c	2 Jul 2004 04:11:23 -0000
*************** us_write (void)
*** 835,840 ****
--- 835,845 ----
    if (sfree (current_unit->s) == FAILURE)
      generate_error (ERROR_OS, NULL);
  
+   /* for sequential unformatted, we write until we have more bytes than
+       can fit in the record markers. if disk space runs out first it will
+       error on the write */
+   current_unit->recl = g.max_offset;
+ 
    current_unit->bytes_left = current_unit->recl;
  }
  
*************** data_transfer_init (int read_flag)
*** 890,896 ****
       memset (&u_flags, '\0', sizeof (u_flags));
       u_flags.access = ACCESS_SEQUENTIAL;
       u_flags.action = ACTION_READWRITE;
!      u_flags.form = FORM_UNSPECIFIED;
       u_flags.delim = DELIM_UNSPECIFIED;
       u_flags.blank = BLANK_UNSPECIFIED;
       u_flags.pad = PAD_UNSPECIFIED;
--- 895,905 ----
       memset (&u_flags, '\0', sizeof (u_flags));
       u_flags.access = ACCESS_SEQUENTIAL;
       u_flags.action = ACTION_READWRITE;
!      /* is it unformatted ?*/
!      if (ioparm.format == NULL && !ioparm.list_format)
!        u_flags.form = FORM_UNFORMATTED;
!      else
!        u_flags.form = FORM_UNSPECIFIED;
       u_flags.delim = DELIM_UNSPECIFIED;
       u_flags.blank = BLANK_UNSPECIFIED;
       u_flags.pad = PAD_UNSPECIFIED;
Index: gcc/libgfortran/io/unix.c
===================================================================
RCS file: /cvs/gcc/gcc/libgfortran/io/unix.c,v
retrieving revision 1.6
diff -c -3 -p -r1.6 unix.c
*** gcc/libgfortran/io/unix.c	26 Jun 2004 11:49:06 -0000	1.6
--- gcc/libgfortran/io/unix.c	2 Jul 2004 04:11:32 -0000
*************** typedef struct
*** 90,96 ****
    gfc_offset physical_offset;	/* Current physical file offset */
    gfc_offset logical_offset;	/* Current logical file offset */
    gfc_offset dirty_offset;	/* Start of modified bytes in buffer */
!   gfc_offset file_length;		/* Length of the file, -1 if not seekable. */
  
    char *buffer;
    int len;			/* Physical length of the current buffer */
--- 90,96 ----
    gfc_offset physical_offset;	/* Current physical file offset */
    gfc_offset logical_offset;	/* Current logical file offset */
    gfc_offset dirty_offset;	/* Start of modified bytes in buffer */
!   gfc_offset file_length;	/* Length of the file, -1 if not seekable. */
  
    char *buffer;
    int len;			/* Physical length of the current buffer */
*************** fd_alloc_w_at (unix_stream * s, int *len
*** 416,423 ****
      {
        if (s->dirty_offset + s->ndirty == where)
  	s->ndirty += *len;
        else
! 	fd_flush (s);		/* Can't combine two dirty blocks */
      }
  
    s->logical_offset = where + *len;
--- 416,431 ----
      {
        if (s->dirty_offset + s->ndirty == where)
  	s->ndirty += *len;
+       else if (where <= s->dirty_offset && where >= s->buffer_offset)
+         {
+           s->dirty_offset = where;
+           s->ndirty = s->ndirty ;
+         }
+       else if (where > s->dirty_offset && where < s->ndirty + s->dirty_offset)
+         ; /*  right in the middle, do nothing */
        else
!         fd_flush (s);           /* Can't combine two dirty blocks */
! 
      }
  
    s->logical_offset = where + *len;
*************** file_position (stream * s)
*** 1390,1397 ****
  int
  is_seekable (stream * s)
  {
! 
!   return ((unix_stream *) s)->mmaped;
  }
  
  try
--- 1398,1407 ----
  int
  is_seekable (stream * s)
  {
!   /* by convention, if file_length == -1, the file is not seekable
!      note that a mmapped file is always seekable, an fd_ file may
!      or may not be. */
!   return ((unix_stream *) s)->file_length!=-1;
  }
  
  try




More information about the Fortran mailing list