This is the mail archive of the fortran@gcc.gnu.org mailing list for the GNU Fortran project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Patch, libfortran, 3/3] Update file position lazily


Hi,

libgfortran maintains a position flag which is used by the
INQUIRE(POSITION=...) statement. Currently we update this flag after
every IO statement. For unbuffered IO this is somewhat tedious, as
figuring out whether we're at the beginning of a file or the end
requires at least two syscalls. The attached patch moves this checking
to the inquire implementation, which is certainly less frequently
invoked than READ or WRITE.

Also, I think I've found a small standards conformance bug. From F2008
(N1830) 9.10.2.23 (page 256): "... ASIS if the connection was opened
without changing its position." and "If the ïle has been repositioned
since the connection, the scalar-default-char-variable
is assigned a processor-dependent value, which shall not be REWIND
unless the ïle is positioned at its initial
point and shall not be APPEND unless the ïle is positioned so that its
endïle record is the next record or at its
terminal point if it has no endïle record.
"

If my understanding of the above is correct, returning ASIS is
incorrent unless the position is unchanged since the OPEN statement.
Currently we return ASIS by default if it's neither REWIND nor APPEND.
So the patch changes the implementation to return the
processor-dependent value UNSPECIFIED in this case.

Regtested on x86_64-unknown-linux-gnu, Ok for trunk?

2011-10-18  Janne Blomqvist  <jb@gcc.gnu.org>

	* io/inquire.c (inquire_via_unit): Check whether we're at the
	beginning or end if the position is unspecified. If the position
	is not one of the 3 standard ones, return unspecified.
	* io/io.h (update_position): Remove prototype.
	* io/transfer.c (next_record): Set the position to unspecified,
	letting inquire figure it out more exactly when needed.
	* io/unit.c (update_position): Remove function.


testsuite ChangeLog:

2011-10-18  Janne Blomqvist  <jb@gcc.gnu.org>

	* gfortran.dg/inquire_5.f90: Update testcase to match the standard
	and current implementation.


-- 
Janne Blomqvist
diff --git a/gcc/testsuite/gfortran.dg/inquire_5.f90 b/gcc/testsuite/gfortran.dg/inquire_5.f90
index fe107a1..064f96d 100644
--- a/gcc/testsuite/gfortran.dg/inquire_5.f90
+++ b/gcc/testsuite/gfortran.dg/inquire_5.f90
@@ -1,11 +1,10 @@
 ! { dg-do run { target fd_truncate } }
-! { dg-options "-std=legacy" }
 !
 ! pr19314 inquire(..position=..) segfaults
 ! test by Thomas.Koenig@online.de
 !         bdavis9659@comcast.net
       implicit none
-      character*20 chr
+      character(len=20) chr
       open(7,STATUS='SCRATCH')
       inquire(7,position=chr)
       if (chr.NE.'ASIS') CALL ABORT
@@ -31,7 +30,8 @@
       write(7,*)'this is another record'
       backspace(7)
       inquire(7,position=chr)
-      if (chr.NE.'ASIS') CALL ABORT
+      if (chr.eq.'ASIS' .or. chr .eq. 'REWIND' &
+           .or. chr .eq. 'APPEND') CALL ABORT
       rewind(7)
       inquire(7,position=chr)
       if (chr.NE.'REWIND') CALL ABORT
diff --git a/libgfortran/io/inquire.c b/libgfortran/io/inquire.c
index 252f29f..fb525ca 100644
--- a/libgfortran/io/inquire.c
+++ b/libgfortran/io/inquire.c
@@ -418,24 +418,36 @@ inquire_via_unit (st_parameter_inquire *iqp, gfc_unit * u)
       if (u == NULL || u->flags.access == ACCESS_DIRECT)
         p = undefined;
       else
-        switch (u->flags.position)
-          {
-             case POSITION_REWIND:
-               p = "REWIND";
-               break;
-             case POSITION_APPEND:
-               p = "APPEND";
-               break;
-             case POSITION_ASIS:
-               p = "ASIS";
-               break;
-             default:
-               /* if not direct access, it must be
-                  either REWIND, APPEND, or ASIS.
-                  ASIS seems to be the best default */
-               p = "ASIS";
-               break;
-          }
+	{
+	  /* If the position is unspecified, check if we can figure
+	     out whether it's at the beginning or end.  */
+	  if (u->flags.position == POSITION_UNSPECIFIED)
+	    {
+	      gfc_offset cur = stell (u->s);
+	      if (cur == 0)
+		u->flags.position = POSITION_REWIND;
+	      else if (cur != -1 && (ssize (u->s) == cur))
+		u->flags.position = POSITION_APPEND;
+	    }
+	  switch (u->flags.position)
+	    {
+	    case POSITION_REWIND:
+	      p = "REWIND";
+	      break;
+	    case POSITION_APPEND:
+	      p = "APPEND";
+	      break;
+	    case POSITION_ASIS:
+	      p = "ASIS";
+	      break;
+	    default:
+	      /* If the position has changed and is not rewind or
+		 append, it must be set to a processor-dependent
+		 value.  */
+	      p = "UNSPECIFIED";
+	      break;
+	    }
+	}
       cf_strcpy (iqp->position, iqp->position_len, p);
     }
 
diff --git a/libgfortran/io/io.h b/libgfortran/io/io.h
index 37353d7..23f07ca 100644
--- a/libgfortran/io/io.h
+++ b/libgfortran/io/io.h
@@ -608,9 +608,6 @@ internal_proto(get_unit);
 extern void unlock_unit (gfc_unit *);
 internal_proto(unlock_unit);
 
-extern void update_position (gfc_unit *);
-internal_proto(update_position);
-
 extern void finish_last_advance_record (gfc_unit *u);
 internal_proto (finish_last_advance_record);
 
diff --git a/libgfortran/io/transfer.c b/libgfortran/io/transfer.c
index 26263ae..062f80e 100644
--- a/libgfortran/io/transfer.c
+++ b/libgfortran/io/transfer.c
@@ -3343,9 +3343,10 @@ next_record (st_parameter_dt *dtp, int done)
 
   if (!is_stream_io (dtp))
     {
-      /* Keep position up to date for INQUIRE */
+      /* Since we have changed the position, set it to unspecified so
+	 that INQUIRE(POSITION=) knows it needs to look into it.  */
       if (done)
-	update_position (dtp->u.p.current_unit);
+	dtp->u.p.current_unit->flags.position = POSITION_UNSPECIFIED;
 
       dtp->u.p.current_unit->current_record = 0;
       if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT)
diff --git a/libgfortran/io/unit.c b/libgfortran/io/unit.c
index 1d36214..b4d10cd 100644
--- a/libgfortran/io/unit.c
+++ b/libgfortran/io/unit.c
@@ -706,26 +706,6 @@ close_units (void)
 }
 
 
-/* update_position()-- Update the flags position for later use by inquire.  */
-
-void
-update_position (gfc_unit *u)
-{
-  /* If unit is not seekable, this makes no sense (and the standard is
-     silent on this matter), and thus we don't change the position for
-     a non-seekable file.  */
-  gfc_offset cur = stell (u->s);
-  if (cur == -1)
-    return;
-  else if (cur == 0)
-    u->flags.position = POSITION_REWIND;
-  else if (ssize (u->s) == cur)
-    u->flags.position = POSITION_APPEND;
-  else
-    u->flags.position = POSITION_ASIS;
-}
-
-
 /* High level interface to truncate a file, i.e. flush format buffers,
    and generate an error or set some flags.  Just like POSIX
    ftruncate, returns 0 on success, -1 on failure.  */

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]