diff options
-rw-r--r-- | gcc/fortran/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/fortran/check.c | 38 | ||||
-rw-r--r-- | gcc/fortran/intrinsic.c | 8 | ||||
-rw-r--r-- | gcc/fortran/intrinsic.h | 2 | ||||
-rw-r--r-- | gcc/fortran/intrinsic.texi | 64 | ||||
-rw-r--r-- | gcc/fortran/iresolve.c | 44 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/gfortran.dg/fseek.f90 | 43 | ||||
-rw-r--r-- | libgfortran/ChangeLog | 8 | ||||
-rw-r--r-- | libgfortran/gfortran.map | 1 | ||||
-rw-r--r-- | libgfortran/io/intrinsics.c | 28 | ||||
-rw-r--r-- | libgfortran/io/unix.c | 10 |
12 files changed, 250 insertions, 10 deletions
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index b3b17fd8630..84b90231bfd 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -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 diff --git a/gcc/fortran/check.c b/gcc/fortran/check.c index 9806ebdf79a..73192e9fa67 100644 --- a/gcc/fortran/check.c +++ b/gcc/fortran/check.c @@ -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) diff --git a/gcc/fortran/intrinsic.c b/gcc/fortran/intrinsic.c index de74678d268..927fcc13dcd 100644 --- a/gcc/fortran/intrinsic.c +++ b/gcc/fortran/intrinsic.c @@ -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); diff --git a/gcc/fortran/intrinsic.h b/gcc/fortran/intrinsic.h index 46d49f7e744..8f07c05ca5c 100644 --- a/gcc/fortran/intrinsic.h +++ b/gcc/fortran/intrinsic.h @@ -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 *); diff --git a/gcc/fortran/intrinsic.texi b/gcc/fortran/intrinsic.texi index b71609b4dd4..4e6b26a21d9 100644 --- a/gcc/fortran/intrinsic.texi +++ b/gcc/fortran/intrinsic.texi @@ -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 diff --git a/gcc/fortran/iresolve.c b/gcc/fortran/iresolve.c index 14ed3e32e8d..b0a1c37dda6 100644 --- a/gcc/fortran/iresolve.c +++ b/gcc/fortran/iresolve.c @@ -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) { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index dca1dc33070..d6ca0dab86c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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 index 00000000000..a42575c2c05 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/fseek.f90 @@ -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 + diff --git a/libgfortran/ChangeLog b/libgfortran/ChangeLog index 52f15066293..806b17d1d95 100644 --- a/libgfortran/ChangeLog +++ b/libgfortran/ChangeLog @@ -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 diff --git a/libgfortran/gfortran.map b/libgfortran/gfortran.map index 830651f87eb..19b458b7b64 100644 --- a/libgfortran/gfortran.map +++ b/libgfortran/gfortran.map @@ -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; diff --git a/libgfortran/io/intrinsics.c b/libgfortran/io/intrinsics.c index ab99b25e5a5..2402f486926 100644 --- a/libgfortran/io/intrinsics.c +++ b/libgfortran/io/intrinsics.c @@ -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 */ diff --git a/libgfortran/io/unix.c b/libgfortran/io/unix.c index 458983c4595..cdac0d7dfdd 100644 --- a/libgfortran/io/unix.c +++ b/libgfortran/io/unix.c @@ -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; } |