Commit 07b3bbf2 by Thomas Koenig Committed by Thomas Koenig

re PR libfortran/29568 (implement unformatted files with subrecords (Intel style))

2006-12-01  Thomas Koenig  <Thomas.Koenig@online.de>

	PR libfortran/29568
	* gfortran.dg/convert_implied_open.f90:  Change to
	new default record length.
	* gfortran.dg/unf_short_record_1.f90:  Adapt to
	new error message.
	* gfortran.dg/unformatted_subrecords_1.f90:  New test.

2006-12-01  Thomas Koenig  <Thomas.Koenig@online.de>

	PR libfortran/29568
	* gfortran.h (gfc_option_t):  Add max_subrecord_length.
	(top level): Define MAX_SUBRECORD_LENGTH.
	* lang.opt:  Add option -fmax-subrecord-length=.
	* trans-decl.c:  Add new function set_max_subrecord_length.
	(gfc_generate_function_code): If we are within the main
	program and max_subrecord_length has been set, call
	set_max_subrecord_length.
	* options.c (gfc_init_options):  Add defaults for
	max_subrecord_lenght, convert and record_marker.
	(gfc_handle_option):  Add handling for
	-fmax_subrecord_length.
	* invoke.texi:  Document the new default for
	-frecord-marker=<n>.

2006-12-01  Thomas Koenig  <Thomas.Koenig@online.de>

	PR libfortran/29568
	* libgfortran/libgfortran.h (compile_options_t):  Add
	record_marker. (top level):  Define GFC_MAX_SUBRECORD_LENGTH.
	* runtime/compile_options.c (set_record_marker):  Change
	default to four-byte record marker.
	(set_max_subrecord_length):  New function.
	* runtime/error.c (translate_error):  Change error message
	for short record on unformatted read.
	* io/io.h (gfc_unit):  Add recl_subrecord, bytes_left_subrecord
	and continued.
	* io/file_pos.c (unformatted_backspace):  Change default of record
	marker size to four bytes.  Loop over subrecords.
	* io/open.c:  Default recl is max_offset.  If
	compile_options.max_subrecord_length has been set, set set
	u->recl_subrecord to its value, to the maximum value otherwise.
	* io/transfer.c (top level):  Add prototypes for us_read, us_write,
	next_record_r_unf and next_record_w_unf.
	(read_block_direct):  Separate codepaths for unformatted direct
	and unformatted sequential.  If a recl has been set by the
	user, use the number of bytes left for the record if it is smaller
	than the read request.  Loop over subrecords.  Set an error if the
	user has set a recl and the read was short.
	(write_buf):  Separate codepaths for unformatted direct and
	unformatted sequential. If a recl has been set by the
	user, use the number of bytes left for the record if it is smaller
	than the read request.  Loop over subrecords.  Set an error if the
	user has set a recl and the read was short.
	(us_read):  Add parameter continued (to indicate that bytes_left
	should not be intialized).  Change default of record marker size
	to four bytes. Use subrecord.  If the subrecord length is smaller than
	zero, this indicates a continuation.
	(us_write):  Add parameter continued (to indicate that the continued
	flag should be set).  Use subrecord.
	(pre_position):  Use 0 for continued on us_write and us_read calls.
	(skip_record):  New function.
	(next_record_r_unf):  New function.
	(next_record_r):  Use next_record_r_unf.
	(write_us_marker):  Default size for record markers is four bytes.
	(next_record_w_unf):  New function.
	(next_record_w):  Use next_record_w_unf.

From-SVN: r119412
parent 7c6a62dd
2006-12-01 Thomas Koenig <Thomas.Koenig@online.de>
PR libfortran/29568
* gfortran.h (gfc_option_t): Add max_subrecord_length.
(top level): Define MAX_SUBRECORD_LENGTH.
* lang.opt: Add option -fmax-subrecord-length=.
* trans-decl.c: Add new function set_max_subrecord_length.
(gfc_generate_function_code): If we are within the main
program and max_subrecord_length has been set, call
set_max_subrecord_length.
* options.c (gfc_init_options): Add defaults for
max_subrecord_lenght, convert and record_marker.
(gfc_handle_option): Add handling for
-fmax_subrecord_length.
* invoke.texi: Document the new default for
-frecord-marker=<n>.
2006-11-28 Paul Thomas <pault@gcc.gnu.org> 2006-11-28 Paul Thomas <pault@gcc.gnu.org>
PR fortran/29976 PR fortran/29976
......
...@@ -59,6 +59,9 @@ char *alloca (); ...@@ -59,6 +59,9 @@ char *alloca ();
#define GFC_MAX_DIMENSIONS 7 /* Maximum dimensions in an array. */ #define GFC_MAX_DIMENSIONS 7 /* Maximum dimensions in an array. */
#define GFC_LETTERS 26 /* Number of letters in the alphabet. */ #define GFC_LETTERS 26 /* Number of letters in the alphabet. */
#define MAX_SUBRECORD_LENGTH 2147483639 /* 2**31-9 */
#define free(x) Use_gfc_free_instead_of_free() #define free(x) Use_gfc_free_instead_of_free()
#define gfc_is_whitespace(c) ((c==' ') || (c=='\t')) #define gfc_is_whitespace(c) ((c==' ') || (c=='\t'))
...@@ -1661,12 +1664,12 @@ typedef struct ...@@ -1661,12 +1664,12 @@ typedef struct
int fshort_enums; int fshort_enums;
int convert; int convert;
int record_marker; int record_marker;
int max_subrecord_length;
} }
gfc_option_t; gfc_option_t;
extern gfc_option_t gfc_option; extern gfc_option_t gfc_option;
/* Constructor nodes for array and structure constructors. */ /* Constructor nodes for array and structure constructors. */
typedef struct gfc_constructor typedef struct gfc_constructor
{ {
......
...@@ -650,13 +650,17 @@ variable override the default specified by -fconvert.} ...@@ -650,13 +650,17 @@ variable override the default specified by -fconvert.}
@cindex -frecord-marker=@var{length} @cindex -frecord-marker=@var{length}
@item -frecord-marker=@var{length} @item -frecord-marker=@var{length}
Specify the length of record markers for unformatted files. Specify the length of record markers for unformatted files.
Valid values for @var{length} are 4 and 8. Default is whatever Valid values for @var{length} are 4 and 8. Default is 4.
@code{off_t} is specified to be on that particular system. @emph{This is different from previous versions of gfortran},
Note that specifying @var{length} as 4 limits the record which specified a default record marker length of 8 on most
length of unformatted files to 2 GB. This option does not systems. If you want to read or write files compatible
extend the maximum possible record length on systems where with earlier versions of gfortran, use @samp{-frecord-marker=8}.
@code{off_t} is a four_byte quantity.
@cindex -fmax-subrecord-length=@var{length}
@item -fmax-subrecord-length=@var{length}
Specify the maximum length for a subrecord. The maximum permitted
value for length is 2147483639, which is also the default. Only
really useful for use by the gfortran testsuite.
@end table @end table
@node Code Gen Options @node Code Gen Options
......
...@@ -189,6 +189,10 @@ fmax-identifier-length= ...@@ -189,6 +189,10 @@ fmax-identifier-length=
Fortran RejectNegative Joined UInteger Fortran RejectNegative Joined UInteger
-fmax-identifier-length=<n> Maximum identifier length -fmax-identifier-length=<n> Maximum identifier length
fmax-subrecord-length=
Fortran RejectNegative Joined UInteger
-fmax-subrecord-length=<n> Maximum length for subrecords
fmax-stack-var-size= fmax-stack-var-size=
Fortran RejectNegative Joined UInteger Fortran RejectNegative Joined UInteger
-fmax-stack-var-size=<n> Size in bytes of the largest array that will be put on the stack -fmax-stack-var-size=<n> Size in bytes of the largest array that will be put on the stack
......
...@@ -51,6 +51,9 @@ gfc_init_options (unsigned int argc ATTRIBUTE_UNUSED, ...@@ -51,6 +51,9 @@ gfc_init_options (unsigned int argc ATTRIBUTE_UNUSED,
gfc_option.max_continue_fixed = 19; gfc_option.max_continue_fixed = 19;
gfc_option.max_continue_free = 39; gfc_option.max_continue_free = 39;
gfc_option.max_identifier_length = GFC_MAX_SYMBOL_LEN; gfc_option.max_identifier_length = GFC_MAX_SYMBOL_LEN;
gfc_option.max_subrecord_length = 0;
gfc_option.convert = CONVERT_NATIVE;
gfc_option.record_marker = 0;
gfc_option.verbose = 0; gfc_option.verbose = 0;
gfc_option.warn_aliasing = 0; gfc_option.warn_aliasing = 0;
...@@ -636,6 +639,12 @@ gfc_handle_option (size_t scode, const char *arg, int value) ...@@ -636,6 +639,12 @@ gfc_handle_option (size_t scode, const char *arg, int value)
case OPT_frecord_marker_8: case OPT_frecord_marker_8:
gfc_option.record_marker = 8; gfc_option.record_marker = 8;
break; break;
case OPT_fmax_subrecord_length_:
if (value > MAX_SUBRECORD_LENGTH)
gfc_fatal_error ("Maximum subrecord length cannot exceed %d", MAX_SUBRECORD_LENGTH);
gfc_option.max_subrecord_length = value;
} }
return result; return result;
......
...@@ -94,6 +94,7 @@ tree gfor_fndecl_set_fpe; ...@@ -94,6 +94,7 @@ tree gfor_fndecl_set_fpe;
tree gfor_fndecl_set_std; tree gfor_fndecl_set_std;
tree gfor_fndecl_set_convert; tree gfor_fndecl_set_convert;
tree gfor_fndecl_set_record_marker; tree gfor_fndecl_set_record_marker;
tree gfor_fndecl_set_max_subrecord_length;
tree gfor_fndecl_ctime; tree gfor_fndecl_ctime;
tree gfor_fndecl_fdate; tree gfor_fndecl_fdate;
tree gfor_fndecl_ttynam; tree gfor_fndecl_ttynam;
...@@ -2379,6 +2380,10 @@ gfc_build_builtin_function_decls (void) ...@@ -2379,6 +2380,10 @@ gfc_build_builtin_function_decls (void)
gfc_build_library_function_decl (get_identifier (PREFIX("set_record_marker")), gfc_build_library_function_decl (get_identifier (PREFIX("set_record_marker")),
void_type_node, 1, gfc_c_int_type_node); void_type_node, 1, gfc_c_int_type_node);
gfor_fndecl_set_max_subrecord_length =
gfc_build_library_function_decl (get_identifier (PREFIX("set_max_subrecord_length")),
void_type_node, 1, gfc_c_int_type_node);
gfor_fndecl_in_pack = gfc_build_library_function_decl ( gfor_fndecl_in_pack = gfc_build_library_function_decl (
get_identifier (PREFIX("internal_pack")), get_identifier (PREFIX("internal_pack")),
pvoid_type_node, 1, pvoid_type_node); pvoid_type_node, 1, pvoid_type_node);
...@@ -3187,6 +3192,18 @@ gfc_generate_function_code (gfc_namespace * ns) ...@@ -3187,6 +3192,18 @@ gfc_generate_function_code (gfc_namespace * ns)
} }
if (sym->attr.is_main_program && gfc_option.max_subrecord_length != 0)
{
tree arglist, gfc_c_int_type_node;
gfc_c_int_type_node = gfc_get_int_type (gfc_c_int_kind);
arglist = gfc_chainon_list (NULL_TREE,
build_int_cst (gfc_c_int_type_node,
gfc_option.max_subrecord_length));
tmp = build_function_call_expr (gfor_fndecl_set_max_subrecord_length, arglist);
gfc_add_expr_to_block (&body, tmp);
}
if (TREE_TYPE (DECL_RESULT (fndecl)) != void_type_node if (TREE_TYPE (DECL_RESULT (fndecl)) != void_type_node
&& sym->attr.subroutine) && sym->attr.subroutine)
{ {
......
2006-12-01 Thomas Koenig <Thomas.Koenig@online.de>
PR libfortran/29568
* gfortran.dg/convert_implied_open.f90: Change to
new default record length.
* gfortran.dg/unf_short_record_1.f90: Adapt to
new error message.
* gfortran.dg/unformatted_subrecords_1.f90: New test.
2006-12-01 Andrew MacLeod <amacleod@redhat.com> 2006-12-01 Andrew MacLeod <amacleod@redhat.com>
* gcc.dg/max-1.c: Remove reference to -fno-tree-lrs option. * gcc.dg/max-1.c: Remove reference to -fno-tree-lrs option.
...@@ -3,13 +3,13 @@ ...@@ -3,13 +3,13 @@
! PR 26735 - implied open didn't use to honor -fconvert ! PR 26735 - implied open didn't use to honor -fconvert
program main program main
implicit none implicit none
integer (kind=8) :: i1, i2, i3 integer (kind=4) :: i1, i2, i3
write (10) 1_8 write (10) 1_4
close (10) close (10)
open (10, form="unformatted", access="direct", recl=8) open (10, form="unformatted", access="direct", recl=4)
read (10,rec=1) i1 read (10,rec=1) i1
read (10,rec=2) i2 read (10,rec=2) i2
read (10,rec=3) i3 read (10,rec=3) i3
if (i1 /= 8 .or. i2 /= 1 .or. i3 /= 8) call abort if (i1 /= 4 .or. i2 /= 1 .or. i3 /= 4) call abort
close (10,status="delete") close (10,status="delete")
end program main end program main
...@@ -11,7 +11,7 @@ program main ...@@ -11,7 +11,7 @@ program main
read (10, err=20, iomsg=msg) a read (10, err=20, iomsg=msg) a
call abort call abort
20 continue 20 continue
if (msg .ne. "Short record on unformatted read") call abort if (msg .ne. "I/O past end of record on unformatted file") call abort
if (a(1) .ne. 'a' .or. a(2) .ne. 'b' .or. a(3) .ne. 'b') call abort if (a(1) .ne. 'a' .or. a(2) .ne. 'b' .or. a(3) .ne. 'b') call abort
close (10, status="delete") close (10, status="delete")
end program main end program main
! { dg-do run }
! { dg-options "-fmax-subrecord-length=16" }
! Test Intel record markers with 16-byte subrecord sizes.
program main
implicit none
integer, dimension(20) :: n
integer, dimension(30) :: m
integer :: i
real :: r
integer :: k
! Maximum subrecord length is 16 here, or the test will fail.
open (10, file="f10.dat", &
form="unformatted", access="sequential")
n = (/ (i**2, i=1, 20) /)
write (10) n
close (10)
! Read back the file, including record markers.
open (10, file="f10.dat", form="unformatted", access="stream")
read (10) m
if (any(m .ne. (/ -16, 1, 4, 9, 16, 16, -16, 25, 36, 49, 64, &
-16, -16, 81, 100, 121, 144, -16, -16, 169, 196, 225, &
256, -16, 16, 289, 324, 361, 400, -16 /))) call abort
close (10)
open (10, file="f10.dat", form="unformatted", &
access="sequential")
m = 42
read (10) m(1:5)
if (any(m(1:5) .ne. (/ 1, 4, 9, 16, 25 /))) call abort
if (any(m(6:30) .ne. 42)) call abort
backspace 10
n = 0
read (10) n(1:5)
if (any(n(1:5) .ne. (/ 1, 4, 9, 16, 25 /))) call abort
if (any(n(6:20) .ne. 0)) call abort
! Append to the end of the file
write (10) 3.14
! Test multiple backspace statements
backspace 10
backspace 10
read (10) k
if (k .ne. 1) call abort
read (10) r
if (abs(r-3.14) .gt. 1e-7) call abort
close (10, status="delete")
end program main
2006-12-01 Thomas Koenig <Thomas.Koenig@online.de>
PR libfortran/29568
* libgfortran/libgfortran.h (compile_options_t): Add
record_marker. (top level): Define GFC_MAX_SUBRECORD_LENGTH.
* runtime/compile_options.c (set_record_marker): Change
default to four-byte record marker.
(set_max_subrecord_length): New function.
* runtime/error.c (translate_error): Change error message
for short record on unformatted read.
* io/io.h (gfc_unit): Add recl_subrecord, bytes_left_subrecord
and continued.
* io/file_pos.c (unformatted_backspace): Change default of record
marker size to four bytes. Loop over subrecords.
* io/open.c: Default recl is max_offset. If
compile_options.max_subrecord_length has been set, set set
u->recl_subrecord to its value, to the maximum value otherwise.
* io/transfer.c (top level): Add prototypes for us_read, us_write,
next_record_r_unf and next_record_w_unf.
(read_block_direct): Separate codepaths for unformatted direct
and unformatted sequential. If a recl has been set by the
user, use the number of bytes left for the record if it is smaller
than the read request. Loop over subrecords. Set an error if the
user has set a recl and the read was short.
(write_buf): Separate codepaths for unformatted direct and
unformatted sequential. If a recl has been set by the
user, use the number of bytes left for the record if it is smaller
than the read request. Loop over subrecords. Set an error if the
user has set a recl and the read was short.
(us_read): Add parameter continued (to indicate that bytes_left
should not be intialized). Change default of record marker size
to four bytes. Use subrecord. If the subrecord length is smaller than
zero, this indicates a continuation.
(us_write): Add parameter continued (to indicate that the continued
flag should be set). Use subrecord.
(pre_position): Use 0 for continued on us_write and us_read calls.
(skip_record): New function.
(next_record_r_unf): New function.
(next_record_r): Use next_record_r_unf.
(write_us_marker): Default size for record markers is four bytes.
(next_record_w_unf): New function.
(next_record_w): Use next_record_w_unf.
2006-11-25 Francois-Xavier Coudert <coudert@clipper.ens.fr> 2006-11-25 Francois-Xavier Coudert <coudert@clipper.ens.fr>
* Makefile.am: Remove intrinsics/erf.c and intrinsics/bessel.c. * Makefile.am: Remove intrinsics/erf.c and intrinsics/bessel.c.
......
...@@ -98,7 +98,7 @@ formatted_backspace (st_parameter_filepos *fpp, gfc_unit *u) ...@@ -98,7 +98,7 @@ formatted_backspace (st_parameter_filepos *fpp, gfc_unit *u)
/* unformatted_backspace(fpp) -- Move the file backwards for an unformatted /* unformatted_backspace(fpp) -- Move the file backwards for an unformatted
sequential file. We are guaranteed to be between records on entry and sequential file. We are guaranteed to be between records on entry and
we have to shift to the previous record. */ we have to shift to the previous record. Loop over subrecords. */
static void static void
unformatted_backspace (st_parameter_filepos *fpp, gfc_unit *u) unformatted_backspace (st_parameter_filepos *fpp, gfc_unit *u)
...@@ -107,74 +107,74 @@ unformatted_backspace (st_parameter_filepos *fpp, gfc_unit *u) ...@@ -107,74 +107,74 @@ unformatted_backspace (st_parameter_filepos *fpp, gfc_unit *u)
GFC_INTEGER_4 m4; GFC_INTEGER_4 m4;
GFC_INTEGER_8 m8; GFC_INTEGER_8 m8;
int length, length_read; int length, length_read;
int continued;
char *p; char *p;
if (compile_options.record_marker == 0) if (compile_options.record_marker == 0)
length = sizeof (gfc_offset); length = sizeof (GFC_INTEGER_4);
else else
length = compile_options.record_marker; length = compile_options.record_marker;
length_read = length; do
{
length_read = length;
p = salloc_r_at (u->s, &length_read, p = salloc_r_at (u->s, &length_read,
file_position (u->s) - length); file_position (u->s) - length);
if (p == NULL || length_read != length) if (p == NULL || length_read != length)
goto io_error; goto io_error;
/* Only CONVERT_NATIVE and CONVERT_SWAP are valid here. */ /* Only CONVERT_NATIVE and CONVERT_SWAP are valid here. */
if (u->flags.convert == CONVERT_NATIVE) if (u->flags.convert == CONVERT_NATIVE)
{
switch (compile_options.record_marker)
{ {
case 0: switch (length)
memcpy (&m, p, sizeof(gfc_offset)); {
break; case sizeof(GFC_INTEGER_4):
memcpy (&m4, p, sizeof (m4));
case sizeof(GFC_INTEGER_4): m = m4;
memcpy (&m4, p, sizeof (m4)); break;
m = m4;
break; case sizeof(GFC_INTEGER_8):
memcpy (&m8, p, sizeof (m8));
case sizeof(GFC_INTEGER_8): m = m8;
memcpy (&m8, p, sizeof (m8)); break;
m = m8;
break; default:
runtime_error ("Illegal value for record marker");
default: break;
runtime_error ("Illegal value for record marker"); }
break;
} }
} else
else
{
switch (compile_options.record_marker)
{ {
case 0: switch (length)
reverse_memcpy (&m, p, sizeof(gfc_offset)); {
break; case sizeof(GFC_INTEGER_4):
reverse_memcpy (&m4, p, sizeof (m4));
case sizeof(GFC_INTEGER_4): m = m4;
reverse_memcpy (&m4, p, sizeof (m4)); break;
m = m4;
break; case sizeof(GFC_INTEGER_8):
reverse_memcpy (&m8, p, sizeof (m8));
case sizeof(GFC_INTEGER_8): m = m8;
reverse_memcpy (&m8, p, sizeof (m8)); break;
m = m8;
break; default:
runtime_error ("Illegal value for record marker");
default: break;
runtime_error ("Illegal value for record marker"); }
break;
} }
} continued = m < 0;
if (continued)
m = -m;
if ((new = file_position (u->s) - m - 2*length) < 0) if ((new = file_position (u->s) - m - 2*length) < 0)
new = 0; new = 0;
if (sseek (u->s, new) == FAILURE) if (sseek (u->s, new) == FAILURE)
goto io_error; goto io_error;
} while (continued);
u->last_record--; u->last_record--;
return; return;
......
...@@ -499,12 +499,19 @@ typedef struct gfc_unit ...@@ -499,12 +499,19 @@ typedef struct gfc_unit
unit_mode mode; unit_mode mode;
unit_flags flags; unit_flags flags;
/* recl -- Record length of the file. /* recl -- Record length of the file.
last_record -- Last record number read or written last_record -- Last record number read or written
maxrec -- Maximum record number in a direct access file maxrec -- Maximum record number in a direct access file
bytes_left -- Bytes left in current record. bytes_left -- Bytes left in current record.
strm_pos -- Current position in file for STREAM I/O. */ strm_pos -- Current position in file for STREAM I/O.
gfc_offset recl, last_record, maxrec, bytes_left, strm_pos; recl_subrecord -- Maximum length for subrecord.
bytes_left_subrecord -- Bytes left in current subrecord. */
gfc_offset recl, last_record, maxrec, bytes_left, strm_pos,
recl_subrecord, bytes_left_subrecord;
/* Set to 1 if we have read a subrecord. */
int continued;
__gthread_mutex_t lock; __gthread_mutex_t lock;
/* Number of threads waiting to acquire this unit's lock. /* Number of threads waiting to acquire this unit's lock.
......
...@@ -413,23 +413,29 @@ new_unit (st_parameter_open *opp, gfc_unit *u, unit_flags * flags) ...@@ -413,23 +413,29 @@ new_unit (st_parameter_open *opp, gfc_unit *u, unit_flags * flags)
else else
{ {
u->flags.has_recl = 0; u->flags.has_recl = 0;
switch (compile_options.record_marker) u->recl = max_offset;
if (compile_options.max_subrecord_length)
{ {
case 0: u->recl_subrecord = compile_options.max_subrecord_length;
u->recl = max_offset; }
break; else
{
case sizeof (GFC_INTEGER_4): switch (compile_options.record_marker)
u->recl = GFC_INTEGER_4_HUGE; {
break; case 0:
/* Fall through */
case sizeof (GFC_INTEGER_8): case sizeof (GFC_INTEGER_4):
u->recl = max_offset; u->recl_subrecord = GFC_MAX_SUBRECORD_LENGTH;
break; break;
default: case sizeof (GFC_INTEGER_8):
runtime_error ("Illegal value for record marker"); u->recl_subrecord = max_offset - 16;
break; break;
default:
runtime_error ("Illegal value for record marker");
break;
}
} }
} }
......
...@@ -82,6 +82,11 @@ extern void transfer_array (st_parameter_dt *, gfc_array_char *, int, ...@@ -82,6 +82,11 @@ extern void transfer_array (st_parameter_dt *, gfc_array_char *, int,
gfc_charlen_type); gfc_charlen_type);
export_proto(transfer_array); export_proto(transfer_array);
static void us_read (st_parameter_dt *, int);
static void us_write (st_parameter_dt *, int);
static void next_record_r_unf (st_parameter_dt *, int);
static void next_record_w_unf (st_parameter_dt *, int);
static const st_option advance_opt[] = { static const st_option advance_opt[] = {
{"yes", ADVANCE_YES}, {"yes", ADVANCE_YES},
{"no", ADVANCE_NO}, {"no", ADVANCE_NO},
...@@ -336,12 +341,16 @@ read_block (st_parameter_dt *dtp, int *length) ...@@ -336,12 +341,16 @@ read_block (st_parameter_dt *dtp, int *length)
} }
/* Reads a block directly into application data space. */ /* Reads a block directly into application data space. This is for
unformatted files. */
static void static void
read_block_direct (st_parameter_dt *dtp, void *buf, size_t *nbytes) read_block_direct (st_parameter_dt *dtp, void *buf, size_t *nbytes)
{ {
size_t nread; size_t to_read_record;
size_t have_read_record;
size_t to_read_subrecord;
size_t have_read_subrecord;
int short_record; int short_record;
if (is_stream_io (dtp)) if (is_stream_io (dtp))
...@@ -353,62 +362,169 @@ read_block_direct (st_parameter_dt *dtp, void *buf, size_t *nbytes) ...@@ -353,62 +362,169 @@ read_block_direct (st_parameter_dt *dtp, void *buf, size_t *nbytes)
return; return;
} }
nread = *nbytes; to_read_record = *nbytes;
if (sread (dtp->u.p.current_unit->s, buf, &nread) != 0) have_read_record = to_read_record;
if (sread (dtp->u.p.current_unit->s, buf, &have_read_record) != 0)
{ {
generate_error (&dtp->common, ERROR_OS, NULL); generate_error (&dtp->common, ERROR_OS, NULL);
return; return;
} }
dtp->u.p.current_unit->strm_pos += (gfc_offset) nread; dtp->u.p.current_unit->strm_pos += (gfc_offset) have_read_record;
if (nread != *nbytes) /* Short read, e.g. if we hit EOF. */
generate_error (&dtp->common, ERROR_END, NULL);
if (to_read_record != have_read_record)
{
/* Short read, e.g. if we hit EOF. */
generate_error (&dtp->common, ERROR_END, NULL);
return;
}
return; return;
} }
/* Unformatted file with records */ if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT)
if (dtp->u.p.current_unit->bytes_left < (gfc_offset) *nbytes)
{ {
short_record = 1; if (dtp->u.p.current_unit->bytes_left < (gfc_offset) *nbytes)
nread = (size_t) dtp->u.p.current_unit->bytes_left; {
*nbytes = nread; short_record = 1;
to_read_record = (size_t) dtp->u.p.current_unit->bytes_left;
*nbytes = to_read_record;
if (dtp->u.p.current_unit->bytes_left == 0) if (dtp->u.p.current_unit->bytes_left == 0)
{
dtp->u.p.current_unit->endfile = AT_ENDFILE;
generate_error (&dtp->common, ERROR_END, NULL);
return;
}
}
else
{
short_record = 0;
to_read_record = *nbytes;
}
dtp->u.p.current_unit->bytes_left -= to_read_record;
if (sread (dtp->u.p.current_unit->s, buf, &to_read_record) != 0)
{
generate_error (&dtp->common, ERROR_OS, NULL);
return;
}
if (to_read_record != *nbytes) /* Short read, e.g. if we hit EOF. */
{ {
dtp->u.p.current_unit->endfile = AT_ENDFILE; *nbytes = to_read_record;
generate_error (&dtp->common, ERROR_END, NULL); generate_error (&dtp->common, ERROR_END, NULL);
return; return;
} }
if (short_record)
{
generate_error (&dtp->common, ERROR_SHORT_RECORD, NULL);
return;
}
return;
} }
/* Unformatted sequential. We loop over the subrecords, reading
until the request has been fulfilled or the record has run out
of continuation subrecords. */
/* Check whether we exceed the total record length. */
if (dtp->u.p.current_unit->flags.has_recl)
{
to_read_record =
*nbytes > (size_t) dtp->u.p.current_unit->bytes_left ?
*nbytes : (size_t) dtp->u.p.current_unit->bytes_left;
short_record = 1;
}
else else
{ {
to_read_record = *nbytes;
short_record = 0; short_record = 0;
nread = *nbytes;
} }
have_read_record = 0;
dtp->u.p.current_unit->bytes_left -= nread; while(1)
if (sread (dtp->u.p.current_unit->s, buf, &nread) != 0)
{ {
generate_error (&dtp->common, ERROR_OS, NULL); if (dtp->u.p.current_unit->bytes_left_subrecord
return; < (gfc_offset) to_read_record)
} {
to_read_subrecord = (size_t) dtp->u.p.current_unit->bytes_left_subrecord;
to_read_record -= to_read_subrecord;
if (nread != *nbytes) /* Short read, e.g. if we hit EOF. */ if (dtp->u.p.current_unit->bytes_left_subrecord == 0)
{ {
*nbytes = nread; if (dtp->u.p.current_unit->continued)
generate_error (&dtp->common, ERROR_END, NULL); {
return; /* Skip to the next subrecord */
next_record_r_unf (dtp, 0);
us_read (dtp, 1);
continue;
}
else
{
dtp->u.p.current_unit->endfile = AT_ENDFILE;
generate_error (&dtp->common, ERROR_END, NULL);
return;
}
}
}
else
{
to_read_subrecord = to_read_record;
to_read_record = 0;
}
dtp->u.p.current_unit->bytes_left_subrecord -= to_read_subrecord;
have_read_subrecord = to_read_subrecord;
if (sread (dtp->u.p.current_unit->s, buf + have_read_record,
&have_read_subrecord) != 0)
{
generate_error (&dtp->common, ERROR_OS, NULL);
return;
}
have_read_record += have_read_subrecord;
if (to_read_subrecord != have_read_subrecord) /* Short read,
e.g. if we hit EOF. */
{
*nbytes = have_read_record;
generate_error (&dtp->common, ERROR_END, NULL);
return;
}
if (to_read_record > 0)
{
if (dtp->u.p.current_unit->continued)
{
next_record_r_unf (dtp, 0);
us_read (dtp, 1);
}
else
{
generate_error (&dtp->common, ERROR_SHORT_RECORD, NULL);
return;
}
}
else
{
/* Normal exit, the read request has been fulfilled. */
break;
}
} }
dtp->u.p.current_unit->bytes_left -= have_read_record;
if (short_record) if (short_record)
{ {
generate_error (&dtp->common, ERROR_SHORT_RECORD, NULL); generate_error (&dtp->common, ERROR_SHORT_RECORD, NULL);
return; return;
} }
return;
} }
...@@ -471,11 +587,20 @@ write_block (st_parameter_dt *dtp, int length) ...@@ -471,11 +587,20 @@ write_block (st_parameter_dt *dtp, int length)
} }
/* High level interface to swrite(), taking care of errors. */ /* High level interface to swrite(), taking care of errors. This is only
called for unformatted files. There are three cases to consider:
Stream I/O, unformatted direct, unformatted sequential. */
static try static try
write_buf (st_parameter_dt *dtp, void *buf, size_t nbytes) write_buf (st_parameter_dt *dtp, void *buf, size_t nbytes)
{ {
size_t have_written, to_write_subrecord;
int short_record;
/* Stream I/O. */
if (is_stream_io (dtp)) if (is_stream_io (dtp))
{ {
if (sseek (dtp->u.p.current_unit->s, if (sseek (dtp->u.p.current_unit->s,
...@@ -484,42 +609,88 @@ write_buf (st_parameter_dt *dtp, void *buf, size_t nbytes) ...@@ -484,42 +609,88 @@ write_buf (st_parameter_dt *dtp, void *buf, size_t nbytes)
generate_error (&dtp->common, ERROR_OS, NULL); generate_error (&dtp->common, ERROR_OS, NULL);
return FAILURE; return FAILURE;
} }
if (swrite (dtp->u.p.current_unit->s, buf, &nbytes) != 0)
{
generate_error (&dtp->common, ERROR_OS, NULL);
return FAILURE;
}
dtp->u.p.current_unit->strm_pos += (gfc_offset) nbytes;
return SUCCESS;
} }
else
/* Unformatted direct access. */
if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT)
{ {
if (dtp->u.p.current_unit->bytes_left < (gfc_offset) nbytes) if (dtp->u.p.current_unit->bytes_left < (gfc_offset) nbytes)
{ {
/* For preconnected units with default record length, set generate_error (&dtp->common, ERROR_DIRECT_EOR, NULL);
bytes left to unit record length and proceed, otherwise return FAILURE;
error. */ }
if ((dtp->u.p.current_unit->unit_number == options.stdout_unit
|| dtp->u.p.current_unit->unit_number == options.stderr_unit) if (swrite (dtp->u.p.current_unit->s, buf, &nbytes) != 0)
&& dtp->u.p.current_unit->recl == DEFAULT_RECL) {
dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl; generate_error (&dtp->common, ERROR_OS, NULL);
else return FAILURE;
{
if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT)
generate_error (&dtp->common, ERROR_DIRECT_EOR, NULL);
else
generate_error (&dtp->common, ERROR_EOR, NULL);
return FAILURE;
}
} }
dtp->u.p.current_unit->bytes_left -= (gfc_offset) nbytes; dtp->u.p.current_unit->strm_pos += (gfc_offset) nbytes;
return SUCCESS;
} }
if (swrite (dtp->u.p.current_unit->s, buf, &nbytes) != 0) /* Unformatted sequential. */
have_written = 0;
if (dtp->u.p.current_unit->flags.has_recl
&& (gfc_offset) nbytes > dtp->u.p.current_unit->bytes_left)
{ {
generate_error (&dtp->common, ERROR_OS, NULL); nbytes = dtp->u.p.current_unit->bytes_left;
return FAILURE; short_record = 1;
}
else
{
short_record = 0;
} }
if ((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0) while (1)
dtp->u.p.size_used += (gfc_offset) nbytes; {
to_write_subrecord =
(size_t) dtp->u.p.current_unit->bytes_left_subrecord < nbytes ?
(size_t) dtp->u.p.current_unit->bytes_left_subrecord : nbytes;
dtp->u.p.current_unit->bytes_left_subrecord -=
(gfc_offset) to_write_subrecord;
dtp->u.p.current_unit->strm_pos += (gfc_offset) nbytes; if (swrite (dtp->u.p.current_unit->s, buf + have_written,
&to_write_subrecord) != 0)
{
generate_error (&dtp->common, ERROR_OS, NULL);
return FAILURE;
}
dtp->u.p.current_unit->strm_pos += (gfc_offset) to_write_subrecord;
nbytes -= to_write_subrecord;
have_written += to_write_subrecord;
if (nbytes == 0)
break;
next_record_w_unf (dtp, 1);
us_write (dtp, 1);
}
dtp->u.p.current_unit->bytes_left -= have_written;
if (short_record)
{
generate_error (&dtp->common, ERROR_SHORT_RECORD, NULL);
return FAILURE;
}
return SUCCESS; return SUCCESS;
} }
...@@ -1357,7 +1528,7 @@ transfer_array (st_parameter_dt *dtp, gfc_array_char *desc, int kind, ...@@ -1357,7 +1528,7 @@ transfer_array (st_parameter_dt *dtp, gfc_array_char *desc, int kind,
/* Preposition a sequential unformatted file while reading. */ /* Preposition a sequential unformatted file while reading. */
static void static void
us_read (st_parameter_dt *dtp) us_read (st_parameter_dt *dtp, int continued)
{ {
char *p; char *p;
int n; int n;
...@@ -1370,7 +1541,7 @@ us_read (st_parameter_dt *dtp) ...@@ -1370,7 +1541,7 @@ us_read (st_parameter_dt *dtp)
return; return;
if (compile_options.record_marker == 0) if (compile_options.record_marker == 0)
n = sizeof (gfc_offset); n = sizeof (GFC_INTEGER_4);
else else
n = compile_options.record_marker; n = compile_options.record_marker;
...@@ -1393,12 +1564,8 @@ us_read (st_parameter_dt *dtp) ...@@ -1393,12 +1564,8 @@ us_read (st_parameter_dt *dtp)
/* Only CONVERT_NATIVE and CONVERT_SWAP are valid here. */ /* Only CONVERT_NATIVE and CONVERT_SWAP are valid here. */
if (dtp->u.p.current_unit->flags.convert == CONVERT_NATIVE) if (dtp->u.p.current_unit->flags.convert == CONVERT_NATIVE)
{ {
switch (compile_options.record_marker) switch (nr)
{ {
case 0:
memcpy (&i, p, sizeof(gfc_offset));
break;
case sizeof(GFC_INTEGER_4): case sizeof(GFC_INTEGER_4):
memcpy (&i4, p, sizeof (i4)); memcpy (&i4, p, sizeof (i4));
i = i4; i = i4;
...@@ -1415,12 +1582,8 @@ us_read (st_parameter_dt *dtp) ...@@ -1415,12 +1582,8 @@ us_read (st_parameter_dt *dtp)
} }
} }
else else
switch (compile_options.record_marker) switch (nr)
{ {
case 0:
reverse_memcpy (&i, p, sizeof(gfc_offset));
break;
case sizeof(GFC_INTEGER_4): case sizeof(GFC_INTEGER_4):
reverse_memcpy (&i4, p, sizeof (i4)); reverse_memcpy (&i4, p, sizeof (i4));
i = i4; i = i4;
...@@ -1436,7 +1599,19 @@ us_read (st_parameter_dt *dtp) ...@@ -1436,7 +1599,19 @@ us_read (st_parameter_dt *dtp)
break; break;
} }
dtp->u.p.current_unit->bytes_left = i; if (i >= 0)
{
dtp->u.p.current_unit->bytes_left_subrecord = i;
dtp->u.p.current_unit->continued = 0;
}
else
{
dtp->u.p.current_unit->bytes_left_subrecord = -i;
dtp->u.p.current_unit->continued = 1;
}
if (! continued)
dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
} }
...@@ -1444,7 +1619,7 @@ us_read (st_parameter_dt *dtp) ...@@ -1444,7 +1619,7 @@ us_read (st_parameter_dt *dtp)
amount to writing a bogus length that will be filled in later. */ amount to writing a bogus length that will be filled in later. */
static void static void
us_write (st_parameter_dt *dtp) us_write (st_parameter_dt *dtp, int continued)
{ {
size_t nbytes; size_t nbytes;
gfc_offset dummy; gfc_offset dummy;
...@@ -1452,7 +1627,7 @@ us_write (st_parameter_dt *dtp) ...@@ -1452,7 +1627,7 @@ us_write (st_parameter_dt *dtp)
dummy = 0; dummy = 0;
if (compile_options.record_marker == 0) if (compile_options.record_marker == 0)
nbytes = sizeof (gfc_offset); nbytes = sizeof (GFC_INTEGER_4);
else else
nbytes = compile_options.record_marker ; nbytes = compile_options.record_marker ;
...@@ -1460,12 +1635,12 @@ us_write (st_parameter_dt *dtp) ...@@ -1460,12 +1635,12 @@ us_write (st_parameter_dt *dtp)
generate_error (&dtp->common, ERROR_OS, NULL); generate_error (&dtp->common, ERROR_OS, NULL);
/* For sequential unformatted, if RECL= was not specified in the OPEN /* For sequential unformatted, if RECL= was not specified in the OPEN
we write until we have more bytes than can fit in the record markers. we write until we have more bytes than can fit in the subrecord
If disk space runs out first, it will error on the write. */ markers, then we write a new subrecord. */
if (dtp->u.p.current_unit->flags.has_recl == 0)
dtp->u.p.current_unit->recl = max_offset;
dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl; dtp->u.p.current_unit->bytes_left_subrecord =
dtp->u.p.current_unit->recl_subrecord;
dtp->u.p.current_unit->continued = continued;
} }
...@@ -1491,9 +1666,9 @@ pre_position (st_parameter_dt *dtp) ...@@ -1491,9 +1666,9 @@ pre_position (st_parameter_dt *dtp)
case UNFORMATTED_SEQUENTIAL: case UNFORMATTED_SEQUENTIAL:
if (dtp->u.p.mode == READING) if (dtp->u.p.mode == READING)
us_read (dtp); us_read (dtp, 0);
else else
us_write (dtp); us_write (dtp, 0);
break; break;
...@@ -1886,17 +2061,92 @@ next_array_record (st_parameter_dt *dtp, array_loop_spec *ls) ...@@ -1886,17 +2061,92 @@ next_array_record (st_parameter_dt *dtp, array_loop_spec *ls)
return index; return index;
} }
/* Space to the next record for read mode. If the file is not
seekable, we read MAX_READ chunks until we get to the right
/* Skip to the end of the current record, taking care of an optional
record marker of size bytes. If the file is not seekable, we
read chunks of size MAX_READ until we get to the right
position. */ position. */
#define MAX_READ 4096 #define MAX_READ 4096
static void static void
skip_record (st_parameter_dt *dtp, size_t bytes)
{
gfc_offset new;
int rlength, length;
char *p;
dtp->u.p.current_unit->bytes_left_subrecord += bytes;
if (dtp->u.p.current_unit->bytes_left_subrecord == 0)
return;
if (is_seekable (dtp->u.p.current_unit->s))
{
new = file_position (dtp->u.p.current_unit->s)
+ dtp->u.p.current_unit->bytes_left_subrecord;
/* Direct access files do not generate END conditions,
only I/O errors. */
if (sseek (dtp->u.p.current_unit->s, new) == FAILURE)
generate_error (&dtp->common, ERROR_OS, NULL);
}
else
{ /* Seek by reading data. */
while (dtp->u.p.current_unit->bytes_left_subrecord > 0)
{
rlength = length =
(MAX_READ > dtp->u.p.current_unit->bytes_left_subrecord) ?
MAX_READ : dtp->u.p.current_unit->bytes_left_subrecord;
p = salloc_r (dtp->u.p.current_unit->s, &rlength);
if (p == NULL)
{
generate_error (&dtp->common, ERROR_OS, NULL);
return;
}
dtp->u.p.current_unit->bytes_left_subrecord -= length;
}
}
}
#undef MAX_READ
/* Advance to the next record reading unformatted files, taking
care of subrecords. If complete_record is nonzero, we loop
until all subrecords are cleared. */
static void
next_record_r_unf (st_parameter_dt *dtp, int complete_record)
{
size_t bytes;
bytes = compile_options.record_marker == 0 ?
sizeof (GFC_INTEGER_4) : compile_options.record_marker;
while(1)
{
/* Skip over tail */
skip_record (dtp, bytes);
if ( ! (complete_record && dtp->u.p.current_unit->continued))
return;
us_read (dtp, 1);
}
}
/* Space to the next record for read mode. */
static void
next_record_r (st_parameter_dt *dtp) next_record_r (st_parameter_dt *dtp)
{ {
gfc_offset new, record; gfc_offset record;
int bytes_left, rlength, length; int length, bytes_left;
char *p; char *p;
switch (current_mode (dtp)) switch (current_mode (dtp))
...@@ -1906,47 +2156,12 @@ next_record_r (st_parameter_dt *dtp) ...@@ -1906,47 +2156,12 @@ next_record_r (st_parameter_dt *dtp)
return; return;
case UNFORMATTED_SEQUENTIAL: case UNFORMATTED_SEQUENTIAL:
next_record_r_unf (dtp, 1);
/* Skip over tail */ break;
dtp->u.p.current_unit->bytes_left +=
compile_options.record_marker == 0 ?
sizeof (gfc_offset) : compile_options.record_marker;
/* Fall through... */
case FORMATTED_DIRECT: case FORMATTED_DIRECT:
case UNFORMATTED_DIRECT: case UNFORMATTED_DIRECT:
if (dtp->u.p.current_unit->bytes_left == 0) skip_record (dtp, 0);
break;
if (is_seekable (dtp->u.p.current_unit->s))
{
new = file_position (dtp->u.p.current_unit->s)
+ dtp->u.p.current_unit->bytes_left;
/* Direct access files do not generate END conditions,
only I/O errors. */
if (sseek (dtp->u.p.current_unit->s, new) == FAILURE)
generate_error (&dtp->common, ERROR_OS, NULL);
}
else
{ /* Seek by reading data. */
while (dtp->u.p.current_unit->bytes_left > 0)
{
rlength = length = (MAX_READ > dtp->u.p.current_unit->bytes_left) ?
MAX_READ : dtp->u.p.current_unit->bytes_left;
p = salloc_r (dtp->u.p.current_unit->s, &rlength);
if (p == NULL)
{
generate_error (&dtp->common, ERROR_OS, NULL);
break;
}
dtp->u.p.current_unit->bytes_left -= length;
}
}
break; break;
case FORMATTED_STREAM: case FORMATTED_STREAM:
...@@ -2025,19 +2240,15 @@ write_us_marker (st_parameter_dt *dtp, const gfc_offset buf) ...@@ -2025,19 +2240,15 @@ write_us_marker (st_parameter_dt *dtp, const gfc_offset buf)
char p[sizeof (GFC_INTEGER_8)]; char p[sizeof (GFC_INTEGER_8)];
if (compile_options.record_marker == 0) if (compile_options.record_marker == 0)
len = sizeof (gfc_offset); len = sizeof (GFC_INTEGER_4);
else else
len = compile_options.record_marker; len = compile_options.record_marker;
/* Only CONVERT_NATIVE and CONVERT_SWAP are valid here. */ /* Only CONVERT_NATIVE and CONVERT_SWAP are valid here. */
if (dtp->u.p.current_unit->flags.convert == CONVERT_NATIVE) if (dtp->u.p.current_unit->flags.convert == CONVERT_NATIVE)
{ {
switch (compile_options.record_marker) switch (len)
{ {
case 0:
return swrite (dtp->u.p.current_unit->s, &buf, &len);
break;
case sizeof (GFC_INTEGER_4): case sizeof (GFC_INTEGER_4):
buf4 = buf; buf4 = buf;
return swrite (dtp->u.p.current_unit->s, &buf4, &len); return swrite (dtp->u.p.current_unit->s, &buf4, &len);
...@@ -2055,13 +2266,8 @@ write_us_marker (st_parameter_dt *dtp, const gfc_offset buf) ...@@ -2055,13 +2266,8 @@ write_us_marker (st_parameter_dt *dtp, const gfc_offset buf)
} }
else else
{ {
switch (compile_options.record_marker) switch (len)
{ {
case 0:
reverse_memcpy (p, &buf, sizeof (gfc_offset));
return swrite (dtp->u.p.current_unit->s, p, &len);
break;
case sizeof (GFC_INTEGER_4): case sizeof (GFC_INTEGER_4):
buf4 = buf; buf4 = buf;
reverse_memcpy (p, &buf4, sizeof (GFC_INTEGER_4)); reverse_memcpy (p, &buf4, sizeof (GFC_INTEGER_4));
...@@ -2070,7 +2276,7 @@ write_us_marker (st_parameter_dt *dtp, const gfc_offset buf) ...@@ -2070,7 +2276,7 @@ write_us_marker (st_parameter_dt *dtp, const gfc_offset buf)
case sizeof (GFC_INTEGER_8): case sizeof (GFC_INTEGER_8):
buf8 = buf; buf8 = buf;
reverse_memcpy (p, &buf8, sizeof (GFC_INTEGER_4)); reverse_memcpy (p, &buf8, sizeof (GFC_INTEGER_8));
return swrite (dtp->u.p.current_unit->s, p, &len); return swrite (dtp->u.p.current_unit->s, p, &len);
break; break;
...@@ -2082,16 +2288,72 @@ write_us_marker (st_parameter_dt *dtp, const gfc_offset buf) ...@@ -2082,16 +2288,72 @@ write_us_marker (st_parameter_dt *dtp, const gfc_offset buf)
} }
/* Position to the next (sub)record in write mode for
unformatted sequential files. */
static void
next_record_w_unf (st_parameter_dt *dtp, int next_subrecord)
{
gfc_offset c, m, m_write;
size_t record_marker;
/* Bytes written. */
m = dtp->u.p.current_unit->recl_subrecord
- dtp->u.p.current_unit->bytes_left_subrecord;
c = file_position (dtp->u.p.current_unit->s);
/* Write the length tail. If we finish a record containing
subrecords, we write out the negative length. */
if (dtp->u.p.current_unit->continued)
m_write = -m;
else
m_write = m;
if (write_us_marker (dtp, m_write) != 0)
goto io_error;
if (compile_options.record_marker == 0)
record_marker = sizeof (GFC_INTEGER_4);
else
record_marker = compile_options.record_marker;
/* Seek to the head and overwrite the bogus length with the real
length. */
if (sseek (dtp->u.p.current_unit->s, c - m - record_marker)
== FAILURE)
goto io_error;
if (next_subrecord)
m_write = -m;
else
m_write = m;
if (write_us_marker (dtp, m_write) != 0)
goto io_error;
/* Seek past the end of the current record. */
if (sseek (dtp->u.p.current_unit->s, c + record_marker) == FAILURE)
goto io_error;
return;
io_error:
generate_error (&dtp->common, ERROR_OS, NULL);
return;
}
/* Position to the next record in write mode. */ /* Position to the next record in write mode. */
static void static void
next_record_w (st_parameter_dt *dtp, int done) next_record_w (st_parameter_dt *dtp, int done)
{ {
gfc_offset c, m, record, max_pos; gfc_offset m, record, max_pos;
int length; int length;
char *p; char *p;
size_t record_marker;
/* Zero counters for X- and T-editing. */ /* Zero counters for X- and T-editing. */
max_pos = dtp->u.p.max_pos; max_pos = dtp->u.p.max_pos;
...@@ -2119,35 +2381,7 @@ next_record_w (st_parameter_dt *dtp, int done) ...@@ -2119,35 +2381,7 @@ next_record_w (st_parameter_dt *dtp, int done)
break; break;
case UNFORMATTED_SEQUENTIAL: case UNFORMATTED_SEQUENTIAL:
/* Bytes written. */ next_record_w_unf (dtp, 0);
m = dtp->u.p.current_unit->recl - dtp->u.p.current_unit->bytes_left;
c = file_position (dtp->u.p.current_unit->s);
/* Write the length tail. */
if (write_us_marker (dtp, m) != 0)
goto io_error;
if (compile_options.record_marker == 4)
record_marker = sizeof(GFC_INTEGER_4);
else
record_marker = sizeof (gfc_offset);
/* Seek to the head and overwrite the bogus length with the real
length. */
if (sseek (dtp->u.p.current_unit->s, c - m - record_marker)
== FAILURE)
goto io_error;
if (write_us_marker (dtp, m) != 0)
goto io_error;
/* Seek past the end of the current record. */
if (sseek (dtp->u.p.current_unit->s, c + record_marker) == FAILURE)
goto io_error;
break; break;
case FORMATTED_STREAM: case FORMATTED_STREAM:
......
...@@ -370,6 +370,7 @@ typedef struct ...@@ -370,6 +370,7 @@ typedef struct
int pedantic; int pedantic;
int convert; int convert;
size_t record_marker; size_t record_marker;
int max_subrecord_length;
} }
compile_options_t; compile_options_t;
...@@ -379,6 +380,7 @@ internal_proto(compile_options); ...@@ -379,6 +380,7 @@ internal_proto(compile_options);
extern void init_compile_options (void); extern void init_compile_options (void);
internal_proto(init_compile_options); internal_proto(init_compile_options);
#define GFC_MAX_SUBRECORD_LENGTH 2147483639 /* 2**31 - 9 */
/* Structure for statement options. */ /* Structure for statement options. */
......
...@@ -86,13 +86,11 @@ set_record_marker (int val) ...@@ -86,13 +86,11 @@ set_record_marker (int val)
switch(val) switch(val)
{ {
case 4: case 4:
if (sizeof (GFC_INTEGER_4) != sizeof (gfc_offset)) compile_options.record_marker = sizeof (GFC_INTEGER_4);
compile_options.record_marker = sizeof (GFC_INTEGER_4);
break; break;
case 8: case 8:
if (sizeof (GFC_INTEGER_8) != sizeof (gfc_offset)) compile_options.record_marker = sizeof (GFC_INTEGER_8);
compile_options.record_marker = sizeof (GFC_INTEGER_8);
break; break;
default: default:
...@@ -100,3 +98,17 @@ set_record_marker (int val) ...@@ -100,3 +98,17 @@ set_record_marker (int val)
break; break;
} }
} }
extern void set_max_subrecord_length (int);
export_proto (set_max_subrecord_length);
void set_max_subrecord_length(int val)
{
if (val > GFC_MAX_SUBRECORD_LENGTH || val < 1)
{
runtime_error ("Invalid value for maximum subrecord length");
return;
}
compile_options.max_subrecord_length = val;
}
...@@ -437,7 +437,7 @@ translate_error (int code) ...@@ -437,7 +437,7 @@ translate_error (int code)
break; break;
case ERROR_SHORT_RECORD: case ERROR_SHORT_RECORD:
p = "Short record on unformatted read"; p = "I/O past end of record on unformatted file";
break; break;
default: default:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment