OSDN Git Service

gcc/fortran:
authordfranke <dfranke@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 4 May 2007 18:02:18 +0000 (18:02 +0000)
committerdfranke <dfranke@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 4 May 2007 18:02:18 +0000 (18:02 +0000)
2007-05-04  Daniel Franke  <franke.daniel@gmail.com>

PR fortran/22539
* intrinsic.c (add_subroutines): Added FSEEK.
* intrinsic.h (gfc_resolve_fseek_sub, gfc_check_fseek_sub): New.
* iresolve.c (gfc_resolve_fseek_sub): New.
* check.c (gfc_check_fseek_sub): New.
* intrinsic.texi (FSEEK): Updated.

gcc/testsuite:
2007-05-01  Daniel Franke  <franke.daniel@gmail.com>

PR fortran/22539
* gfortran.dg/fseek.f90: New test.

libgfortran:
2007-05-04  Daniel Franke  <franke.daniel@gmail.com>

PR fortran/22539
* io/intrinsics.c (fseek_sub): New.
* io/unix.c (fd_fseek): Change logical and physical offsets only
if seek succeeds.
* gfortran.map (fseek_sub): New.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@124437 138bc75d-0d04-0410-961f-82ee72b054a4

12 files changed:
gcc/fortran/ChangeLog
gcc/fortran/check.c
gcc/fortran/intrinsic.c
gcc/fortran/intrinsic.h
gcc/fortran/intrinsic.texi
gcc/fortran/iresolve.c
gcc/testsuite/ChangeLog
gcc/testsuite/gfortran.dg/fseek.f90 [new file with mode: 0644]
libgfortran/ChangeLog
libgfortran/gfortran.map
libgfortran/io/intrinsics.c
libgfortran/io/unix.c

index b3b17fd..84b9023 100644 (file)
@@ -1,3 +1,12 @@
+2007-05-04  Daniel Franke  <franke.daniel@gmail.com>
+
+       PR fortran/22539
+       * intrinsic.c (add_subroutines): Added FSEEK.
+       * intrinsic.h (gfc_resolve_fseek_sub, gfc_check_fseek_sub): New.
+       * iresolve.c (gfc_resolve_fseek_sub): New.
+       * check.c (gfc_check_fseek_sub): New.
+       * intrinsic.texi (FSEEK): Updated.
+
 2007-05-04  Tobias Burnus  <burnus@net-b.de>
 
        PR fortran/31803
index 9806ebd..73192e9 100644 (file)
@@ -2461,6 +2461,44 @@ gfc_check_fgetput (gfc_expr *c)
 
 
 try
+gfc_check_fseek_sub (gfc_expr *unit, gfc_expr *offset, gfc_expr *whence, gfc_expr *status)
+{
+  if (type_check (unit, 0, BT_INTEGER) == FAILURE)
+    return FAILURE;
+
+  if (scalar_check (unit, 0) == FAILURE)
+    return FAILURE;
+
+  if (type_check (offset, 1, BT_INTEGER) == FAILURE)
+    return FAILURE;
+
+  if (scalar_check (offset, 1) == FAILURE)
+    return FAILURE;
+
+  if (type_check (whence, 2, BT_INTEGER) == FAILURE)
+    return FAILURE;
+
+  if (scalar_check (whence, 2) == FAILURE)
+    return FAILURE;
+
+  if (status == NULL)
+    return SUCCESS;
+
+  if (type_check (status, 3, BT_INTEGER) == FAILURE)
+    return FAILURE;
+
+  if (kind_value_check (status, 3, 4) == FAILURE)
+    return FAILURE
+
+  if (scalar_check (status, 3) == FAILURE)
+    return FAILURE;
+
+  return SUCCESS;
+}
+
+
+
+try
 gfc_check_fstat (gfc_expr *unit, gfc_expr *array)
 {
   if (type_check (unit, 0, BT_INTEGER) == FAILURE)
index de74678..927fcc1 100644 (file)
@@ -2313,7 +2313,8 @@ add_subroutines (void)
     *com = "command", *length = "length", *st = "status",
     *val = "value", *num = "number", *name = "name",
     *trim_name = "trim_name", *ut = "unit", *han = "handler",
-    *sec = "seconds", *res = "result", *of = "offset", *md = "mode";
+    *sec = "seconds", *res = "result", *of = "offset", *md = "mode",
+    *whence = "whence";
 
   int di, dr, dc, dl, ii;
 
@@ -2489,6 +2490,11 @@ add_subroutines (void)
   add_sym_1s ("free", NOT_ELEMENTAL,  BT_UNKNOWN, 0, GFC_STD_GNU, gfc_check_free,
              NULL, gfc_resolve_free, c, BT_INTEGER, ii, REQUIRED);
 
+  add_sym_4s ("fseek", NOT_ELEMENTAL, BT_UNKNOWN, 0, GFC_STD_GNU,
+              gfc_check_fseek_sub, NULL, gfc_resolve_fseek_sub,
+              ut, BT_INTEGER, di, REQUIRED, of, BT_INTEGER, di, REQUIRED,
+              whence, BT_INTEGER, di, REQUIRED, st, BT_INTEGER, di, OPTIONAL);
+
   add_sym_2s ("ftell", NOT_ELEMENTAL,  BT_UNKNOWN, 0, GFC_STD_GNU,
              gfc_check_ftell_sub, NULL, gfc_resolve_ftell_sub,
              ut, BT_INTEGER, di, REQUIRED, of, BT_INTEGER, ii, REQUIRED);
index 46d49f7..8f07c05 100644 (file)
@@ -162,6 +162,7 @@ try gfc_check_random_seed (gfc_expr *, gfc_expr *, gfc_expr *);
 try gfc_check_etime_sub (gfc_expr *, gfc_expr *);
 try gfc_check_fgetputc_sub (gfc_expr *, gfc_expr *, gfc_expr *);
 try gfc_check_fgetput_sub (gfc_expr *, gfc_expr *);
+try gfc_check_fseek_sub (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *);
 try gfc_check_ftell_sub (gfc_expr *, gfc_expr *);
 try gfc_check_getcwd_sub (gfc_expr *, gfc_expr *);
 try gfc_check_hostnm_sub (gfc_expr *, gfc_expr *);
@@ -456,6 +457,7 @@ void gfc_resolve_exit (gfc_code *);
 void gfc_resolve_fdate_sub (gfc_code *);
 void gfc_resolve_flush (gfc_code *);
 void gfc_resolve_free (gfc_code *);
+void gfc_resolve_fseek_sub (gfc_code *);
 void gfc_resolve_fstat_sub (gfc_code *);
 void gfc_resolve_ftell_sub (gfc_code *);
 void gfc_resolve_fgetc_sub (gfc_code *);
index b71609b..4e6b26a 100644 (file)
@@ -3966,10 +3966,31 @@ See @code{MALLOC} for an example.
 @cindex file operation, seek
 @cindex file operation, position
 
-Not yet implemented in GNU Fortran.
-
 @table @asis
 @item @emph{Description}:
+Moves @var{UNIT} to the specified @var{OFFSET}. If @var{WHENCE} 
+is set to 0, the @var{OFFSET} is taken as an absolute value @code{SEEK_SET},
+if set to 1, @var{OFFSET} is taken to be relative to the current position 
+@code{SEEK_CUR}, and if set to 2 relative to the end of the file @code{SEEK_END}.
+On error, @var{STATUS} is set to a non-zero value. If @var{STATUS} the seek 
+fails silently.
+
+This intrinsic routine is not fully backwards compatible with @command{g77}. 
+In @command{g77}, the @code{FSEEK} takes a statement label instead of a 
+@var{STATUS} variable. If FSEEK is used in old code, change
+@smallexample
+  CALL FSEEK(UNIT, OFFSET, WHENCE, *label)
+@end smallexample 
+to
+@smallexample
+  INTEGER :: status
+  CALL FSEEK(UNIT, OFFSET, WHENCE, status)
+  IF (status /= 0) GOTO label
+@end smallexample 
+
+Please note that GNU Fortran provides the Fortran 2003 Stream facility.
+Programmers should consider the use of new stream IO feature in new code 
+for future portability. See also @ref{Fortran 2003 status}.
 
 @item @emph{Standard}:
 GNU extension
@@ -3978,13 +3999,44 @@ GNU extension
 Subroutine
 
 @item @emph{Syntax}:
+@code{CALL FSEEK(UNIT, OFFSET, WHENCE[, STATUS])}
+
 @item @emph{Arguments}:
-@item @emph{Return value}:
+@multitable @columnfractions .15 .70
+@item @var{UNIT}   @tab Shall be a scalar of type @code{INTEGER}.
+@item @var{OFFSET} @tab Shall be a scalar of type @code{INTEGER}.
+@item @var{WHENCE} @tab Shall be a scalar of type @code{INTEGER}.
+Its value shall be either 0, 1 or 2.
+@item @var{STATUS} @tab (Optional) shall be a scalar of type 
+@code{INTEGER(4)}.
+@end multitable
+
 @item @emph{Example}:
-@item @emph{Specific names}:
-@item @emph{See also}:
-@uref{http://gcc.gnu.org/bugzilla/show_bug.cgi?id=19292, g77 features lacking in gfortran}
+@smallexample
+PROGRAM test_fseek
+  INTEGER, PARAMETER :: SEEK_SET = 0, SEEK_CUR = 1, SEEK_END = 2
+  INTEGER :: fd, offset, ierr
+
+  ierr   = 0
+  offset = 5
+  fd     = 10
+
+  OPEN(UNIT=fd, FILE="fseek.test")
+  CALL FSEEK(fd, offset, SEEK_SET, ierr)  ! move to OFFSET
+  print *, FTELL(fd), ierr
+
+  CALL FSEEK(fd, 0, SEEK_END, ierr)       ! move to end
+  print *, FTELL(fd), ierr
 
+  CALL FSEEK(fd, 0, SEEK_SET, ierr)       ! move to beginning
+  print *, FTELL(fd), ierr
+
+  CLOSE(UNIT=fd)
+END PROGRAM
+@end smallexample
+
+@item @emph{See also}:
+@ref{FTELL}
 @end table
 
 
index 14ed3e3..b0a1c37 100644 (file)
@@ -2965,6 +2965,50 @@ gfc_resolve_fput_sub (gfc_code *c)
 }
 
 
+void 
+gfc_resolve_fseek_sub (gfc_code *c)
+{
+  gfc_expr *unit;
+  gfc_expr *offset;
+  gfc_expr *whence;
+  gfc_expr *status;
+  gfc_typespec ts;
+
+  unit   = c->ext.actual->expr;
+  offset = c->ext.actual->next->expr;
+  whence = c->ext.actual->next->next->expr;
+  status = c->ext.actual->next->next->next->expr;
+
+  if (unit->ts.kind != gfc_c_int_kind)
+    {
+      ts.type = BT_INTEGER;
+      ts.kind = gfc_c_int_kind;
+      ts.derived = NULL;
+      ts.cl = NULL;
+      gfc_convert_type (unit, &ts, 2);
+    }
+
+  if (offset->ts.kind != gfc_intio_kind)
+    {
+      ts.type = BT_INTEGER;
+      ts.kind = gfc_intio_kind;
+      ts.derived = NULL;
+      ts.cl = NULL;
+      gfc_convert_type (offset, &ts, 2);
+    }
+
+  if (whence->ts.kind != gfc_c_int_kind)
+    {
+      ts.type = BT_INTEGER;
+      ts.kind = gfc_c_int_kind;
+      ts.derived = NULL;
+      ts.cl = NULL;
+      gfc_convert_type (whence, &ts, 2);
+    }
+
+  c->resolved_sym = gfc_get_intrinsic_sub_symbol (PREFIX ("fseek_sub"));
+}
+
 void
 gfc_resolve_ftell_sub (gfc_code *c)
 {
index dca1dc3..d6ca0da 100644 (file)
@@ -1,3 +1,8 @@
+2007-05-04  Daniel Franke  <franke.daniel@gmail.com>
+
+       PR fortran/22539
+       * gfortran.dg/fseek.f90: New test.
+
 2007-05-04  Bob Wilson  <bob.wilson@acm.org>
        
        * g++.old-deja/g++.pt/static11.C: Remove xtensa-*-elf* xfail.
diff --git a/gcc/testsuite/gfortran.dg/fseek.f90 b/gcc/testsuite/gfortran.dg/fseek.f90
new file mode 100644 (file)
index 0000000..a42575c
--- /dev/null
@@ -0,0 +1,43 @@
+! { dg-do run }
+
+PROGRAM test_fseek
+  INTEGER, PARAMETER :: SEEK_SET = 0, SEEK_CUR = 1, SEEK_END = 2, fd=10
+  INTEGER :: ierr = 0
+
+  ! expected position: 12, one leading blank + 10 + newline
+  WRITE(fd, *) "1234567890"
+  IF (FTELL(fd) /= 12) CALL abort()
+
+  ! move backward from current position
+  CALL FSEEK(fd, -12, SEEK_CUR, ierr)
+  IF (ierr /= 0 .OR. FTELL(fd) /= 0) CALL abort()
+
+  ! move to negative position (error)
+  CALL FSEEK(fd, -1, SEEK_SET, ierr)
+  IF (ierr == 0 .OR. FTELL(fd) /= 0) CALL abort()
+
+  ! move forward from end (12 + 10)
+  CALL FSEEK(fd, 10, SEEK_END, ierr)
+  IF (ierr /= 0 .OR. FTELL(fd) /= 22) CALL abort()
+
+  ! set position (0)
+  CALL FSEEK(fd, 0, SEEK_SET, ierr)
+  IF (ierr /= 0 .OR. FTELL(fd) /= 0) CALL abort()
+
+  ! move forward from current position
+  CALL FSEEK(fd, 5, SEEK_CUR, ierr)
+  IF (ierr /= 0 .OR. FTELL(fd) /= 5) CALL abort()
+
+  CALL FSEEK(fd, HUGE(0_1), SEEK_SET, ierr)
+  IF (ierr /= 0 .OR. FTELL(fd) /= HUGE(0_1)) CALL abort()
+
+  CALL FSEEK(fd, HUGE(0_2), SEEK_SET, ierr)
+  IF (ierr /= 0 .OR. FTELL(fd) /= HUGE(0_2)) CALL abort()
+
+  CALL FSEEK(fd, HUGE(0_4), SEEK_SET, ierr)
+  IF (ierr /= 0 .OR. FTELL(fd) /= HUGE(0_4)) CALL abort()
+  
+  CALL FSEEK(fd, -HUGE(0_4), SEEK_CUR, ierr)
+  IF (ierr /= 0 .OR. FTELL(fd) /= 0) CALL abort()
+END PROGRAM
+
index 52f1506..806b17d 100644 (file)
@@ -1,3 +1,11 @@
+2007-05-04  Daniel Franke  <franke.daniel@gmail.com>
+
+       PR fortran/22539
+       * io/intrinsics.c (fseek_sub): New.
+       * io/unix.c (fd_fseek): Change logical and physical offsets only
+       if seek succeeds.
+       * gfortran.map (fseek_sub): New.
+
 2007-05-04  Francois-Xavier Coudert  <fxcoudert@gcc.gnu.org>
 
        PR libfortran/31210
index 830651f..19b458b 100644 (file)
@@ -128,6 +128,7 @@ GFORTRAN_1.0 {
     _gfortran_fraction_r4;
     _gfortran_fraction_r8;
     _gfortran_free;
+    _gfortran_fseek_sub;
     _gfortran_fstat_i4;
     _gfortran_fstat_i4_sub;
     _gfortran_fstat_i8;
index ab99b25..2402f48 100644 (file)
@@ -228,6 +228,34 @@ flush_i8 (GFC_INTEGER_8 *unit)
     }
 }
 
+/* FSEEK intrinsic */
+
+extern void fseek_sub (int *, GFC_IO_INT *, int *, int *);
+export_proto(fseek_sub);
+
+void
+fseek_sub (int * unit, GFC_IO_INT * offset, int * whence, int * status)
+{
+  gfc_unit * u = find_unit (*unit);
+  try result = FAILURE;
+
+  if (u != NULL && is_seekable(u->s))
+    {
+      if (*whence == 0)
+        result = sseek(u->s, *offset);                       /* SEEK_SET */
+      else if (*whence == 1)
+        result = sseek(u->s, file_position(u->s) + *offset); /* SEEK_CUR */
+      else if (*whence == 2)
+        result = sseek(u->s, file_length(u->s) + *offset);   /* SEEK_END */
+
+      unlock_unit (u);
+    }
+
+  if (status)
+    *status = (result == FAILURE ? -1 : 0);
+}
+
+
 
 /* FTELL intrinsic */
 
index 458983c..cdac0d7 100644 (file)
@@ -601,10 +601,14 @@ fd_seek (unix_stream * s, gfc_offset offset)
       return SUCCESS;
     }
 
-  s->physical_offset = s->logical_offset = offset;
-  s->active = 0;
+  if (lseek (s->fd, offset, SEEK_SET) >= 0)
+    {
+      s->physical_offset = s->logical_offset = offset;
+      s->active = 0;
+      return SUCCESS;
+    }
 
-  return (lseek (s->fd, offset, SEEK_SET) < 0) ? FAILURE : SUCCESS;
+  return FAILURE;
 }