gfc_charlen_type);
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[] = {
{"yes", ADVANCE_YES},
{"no", ADVANCE_NO},
typedef enum
{ FORMATTED_SEQUENTIAL, UNFORMATTED_SEQUENTIAL,
- FORMATTED_DIRECT, UNFORMATTED_DIRECT
+ FORMATTED_DIRECT, UNFORMATTED_DIRECT, FORMATTED_STREAM, UNFORMATTED_STREAM
}
file_mode;
{
file_mode m;
+ m = FORM_UNSPECIFIED;
+
if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT)
{
m = dtp->u.p.current_unit->flags.form == FORM_FORMATTED ?
FORMATTED_DIRECT : UNFORMATTED_DIRECT;
}
- else
+ else if (dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL)
{
m = dtp->u.p.current_unit->flags.form == FORM_FORMATTED ?
FORMATTED_SEQUENTIAL : UNFORMATTED_SEQUENTIAL;
}
+ else if (dtp->u.p.current_unit->flags.access == ACCESS_STREAM)
+ {
+ m = dtp->u.p.current_unit->flags.form == FORM_FORMATTED ?
+ FORMATTED_STREAM : UNFORMATTED_STREAM;
+ }
return m;
}
an I/O error.
Given this, the solution is to read a byte at a time, stopping if
- we hit the newline. For small locations, we use a static buffer.
+ we hit the newline. For small allocations, we use a static buffer.
For larger allocations, we are forced to allocate memory on the
heap. Hopefully this won't happen very often. */
if (*q == ',')
if (dtp->u.p.sf_read_comma == 1)
{
- notify_std (GFC_STD_GNU, "Comma in formatted numeric read.");
+ notify_std (&dtp->common, GFC_STD_GNU,
+ "Comma in formatted numeric read.");
*length = n;
break;
}
char *source;
int nread;
- if (dtp->u.p.current_unit->bytes_left < *length)
+ if (is_stream_io (dtp))
{
- /* For preconnected units with default record length, set bytes left
- to unit record length and proceed, otherwise error. */
- if (dtp->u.p.current_unit->unit_number == options.stdin_unit
- && dtp->u.p.current_unit->recl == DEFAULT_RECL)
- dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
- else
+ if (sseek (dtp->u.p.current_unit->s,
+ dtp->u.p.current_unit->strm_pos - 1) == FAILURE)
{
- if (dtp->u.p.current_unit->flags.pad == PAD_NO)
+ generate_error (&dtp->common, ERROR_END, NULL);
+ return NULL;
+ }
+ }
+ else
+ {
+ if (dtp->u.p.current_unit->bytes_left < (gfc_offset) *length)
+ {
+ /* For preconnected units with default record length, set bytes left
+ to unit record length and proceed, otherwise error. */
+ if (dtp->u.p.current_unit->unit_number == options.stdin_unit
+ && dtp->u.p.current_unit->recl == DEFAULT_RECL)
+ dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
+ else
{
- /* Not enough data left. */
- generate_error (&dtp->common, ERROR_EOR, NULL);
+ if (dtp->u.p.current_unit->flags.pad == PAD_NO)
+ {
+ /* Not enough data left. */
+ generate_error (&dtp->common, ERROR_EOR, NULL);
+ return NULL;
+ }
+ }
+
+ 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 NULL;
}
- }
- *length = dtp->u.p.current_unit->bytes_left;
+ *length = dtp->u.p.current_unit->bytes_left;
+ }
}
if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED &&
- dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL)
- return read_sf (dtp, length, 0); /* Special case. */
-
- dtp->u.p.current_unit->bytes_left -= *length;
+ (dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL ||
+ dtp->u.p.current_unit->flags.access == ACCESS_STREAM))
+ {
+ source = read_sf (dtp, length, 0);
+ dtp->u.p.current_unit->strm_pos +=
+ (gfc_offset) (*length + dtp->u.p.sf_seen_eor);
+ return source;
+ }
+ dtp->u.p.current_unit->bytes_left -= (gfc_offset) *length;
nread = *length;
source = salloc_r (dtp->u.p.current_unit->s, &nread);
}
}
+ dtp->u.p.current_unit->strm_pos += (gfc_offset) nread;
+
return source;
}
-/* Reads a block directly into application data space. */
+/* Reads a block directly into application data space. This is for
+ unformatted files. */
static void
read_block_direct (st_parameter_dt *dtp, void *buf, size_t *nbytes)
{
- int *length;
- void *data;
- 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;
- if (dtp->u.p.current_unit->bytes_left < *nbytes)
+ if (is_stream_io (dtp))
{
- /* For preconnected units with default record length, set bytes left
- to unit record length and proceed, otherwise error. */
- if (dtp->u.p.current_unit->unit_number == options.stdin_unit
- && dtp->u.p.current_unit->recl == DEFAULT_RECL)
- dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
- else
+ if (sseek (dtp->u.p.current_unit->s,
+ dtp->u.p.current_unit->strm_pos - 1) == FAILURE)
{
- if (dtp->u.p.current_unit->flags.pad == PAD_NO)
- {
- /* Not enough data left. */
- generate_error (&dtp->common, ERROR_EOR, NULL);
- return;
- }
+ generate_error (&dtp->common, ERROR_END, NULL);
+ return;
}
- *nbytes = dtp->u.p.current_unit->bytes_left;
+ to_read_record = *nbytes;
+ 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);
+ return;
+ }
+
+ dtp->u.p.current_unit->strm_pos += (gfc_offset) have_read_record;
+
+ if (to_read_record != have_read_record)
+ {
+ /* Short read, e.g. if we hit EOF. For stream files,
+ we have to set the end-of-file condition. */
+ generate_error (&dtp->common, ERROR_END, NULL);
+ return;
+ }
+ return;
}
- if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED &&
- dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL)
+ if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT)
{
- length = (int *) nbytes;
- data = read_sf (dtp, length, 0); /* Special case. */
- memcpy (buf, data, (size_t) *length);
+ if (dtp->u.p.current_unit->bytes_left < (gfc_offset) *nbytes)
+ {
+ short_record = 1;
+ to_read_record = (size_t) dtp->u.p.current_unit->bytes_left;
+ *nbytes = to_read_record;
+ }
+
+ 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. Apparently, we read
+ more than was written to the last record. */
+ *nbytes = to_read_record;
+ generate_error (&dtp->common, ERROR_SHORT_RECORD, NULL);
+ return;
+ }
+
+ if (short_record)
+ {
+ generate_error (&dtp->common, ERROR_SHORT_RECORD, NULL);
+ return;
+ }
return;
}
- dtp->u.p.current_unit->bytes_left -= *nbytes;
+ /* Unformatted sequential. We loop over the subrecords, reading
+ until the request has been fulfilled or the record has run out
+ of continuation subrecords. */
- nread = *nbytes;
- if (sread (dtp->u.p.current_unit->s, buf, &nread) != 0)
+ if (dtp->u.p.current_unit->endfile == AT_ENDFILE)
{
- generate_error (&dtp->common, ERROR_OS, NULL);
+ generate_error (&dtp->common, ERROR_END, NULL);
return;
}
- if ((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0)
- dtp->u.p.size_used += (gfc_offset) nread;
+ /* Check whether we exceed the total record length. */
- if (nread != *nbytes)
- { /* Short read, e.g. if we hit EOF. */
- if (dtp->u.p.current_unit->flags.pad == PAD_YES)
+ 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
+ {
+ to_read_record = *nbytes;
+ short_record = 0;
+ }
+ have_read_record = 0;
+
+ while(1)
+ {
+ if (dtp->u.p.current_unit->bytes_left_subrecord
+ < (gfc_offset) to_read_record)
+ {
+ to_read_subrecord = (size_t) dtp->u.p.current_unit->bytes_left_subrecord;
+ to_read_record -= to_read_subrecord;
+ }
+ 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)
{
- memset (((char *) buf) + nread, ' ', *nbytes - nread);
- *nbytes = nread;
+ 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. This means the record
+ structure has been corrupted, or the trailing record
+ marker would still be present. */
+
+ *nbytes = have_read_record;
+ generate_error (&dtp->common, ERROR_CORRUPT_FILE, 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
+ {
+ /* Let's make sure the file position is correctly set for the
+ next read statement. */
+
+ next_record_r_unf (dtp, 0);
+ us_read (dtp, 0);
+ generate_error (&dtp->common, ERROR_SHORT_RECORD, NULL);
+ return;
+ }
}
else
- generate_error (&dtp->common, ERROR_EOR, NULL);
+ {
+ /* Normal exit, the read request has been fulfilled. */
+ break;
+ }
}
+
+ dtp->u.p.current_unit->bytes_left -= have_read_record;
+ if (short_record)
+ {
+ generate_error (&dtp->common, ERROR_SHORT_RECORD, NULL);
+ return;
+ }
+ return;
}
{
char *dest;
- if (dtp->u.p.current_unit->bytes_left < length)
+ if (is_stream_io (dtp))
{
- /* For preconnected units with default record length, set bytes left
- to unit record length and proceed, otherwise error. */
- if ((dtp->u.p.current_unit->unit_number == options.stdout_unit
- || dtp->u.p.current_unit->unit_number == options.stderr_unit)
- && dtp->u.p.current_unit->recl == DEFAULT_RECL)
- dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
- else
+ if (sseek (dtp->u.p.current_unit->s,
+ dtp->u.p.current_unit->strm_pos - 1) == FAILURE)
{
- generate_error (&dtp->common, ERROR_EOR, NULL);
+ generate_error (&dtp->common, ERROR_OS, NULL);
return NULL;
}
}
+ else
+ {
+ if (dtp->u.p.current_unit->bytes_left < (gfc_offset) length)
+ {
+ /* For preconnected units with default record length, set bytes left
+ to unit record length and proceed, otherwise error. */
+ if ((dtp->u.p.current_unit->unit_number == options.stdout_unit
+ || dtp->u.p.current_unit->unit_number == options.stderr_unit)
+ && dtp->u.p.current_unit->recl == DEFAULT_RECL)
+ dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
+ else
+ {
+ generate_error (&dtp->common, ERROR_EOR, NULL);
+ return NULL;
+ }
+ }
+
+ dtp->u.p.current_unit->bytes_left -= (gfc_offset) length;
+ }
- dtp->u.p.current_unit->bytes_left -= (gfc_offset) length;
dest = salloc_w (dtp->u.p.current_unit->s, &length);
-
+
if (dest == NULL)
{
generate_error (&dtp->common, ERROR_END, NULL);
return NULL;
}
+ if (is_internal_unit (dtp) && dtp->u.p.current_unit->endfile == AT_ENDFILE)
+ generate_error (&dtp->common, ERROR_END, NULL);
+
if ((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0)
dtp->u.p.size_used += (gfc_offset) length;
+ dtp->u.p.current_unit->strm_pos += (gfc_offset) length;
+
return dest;
}
-/* 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
write_buf (st_parameter_dt *dtp, void *buf, size_t nbytes)
{
- if (dtp->u.p.current_unit->bytes_left < nbytes)
- {
- /* For preconnected units with default record length, set bytes left
- to unit record length and proceed, otherwise error. */
- if ((dtp->u.p.current_unit->unit_number == options.stdout_unit
- || dtp->u.p.current_unit->unit_number == options.stderr_unit)
- && dtp->u.p.current_unit->recl == DEFAULT_RECL)
- dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
- else
+
+ size_t have_written, to_write_subrecord;
+ int short_record;
+
+
+ /* Stream I/O. */
+
+ if (is_stream_io (dtp))
+ {
+ if (sseek (dtp->u.p.current_unit->s,
+ dtp->u.p.current_unit->strm_pos - 1) == 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);
+ generate_error (&dtp->common, ERROR_OS, NULL);
+ 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;
}
- dtp->u.p.current_unit->bytes_left -= (gfc_offset) nbytes;
+ /* Unformatted direct access. */
- if (swrite (dtp->u.p.current_unit->s, buf, &nbytes) != 0)
+ if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT)
{
- generate_error (&dtp->common, ERROR_OS, NULL);
- return FAILURE;
+ if (dtp->u.p.current_unit->bytes_left < (gfc_offset) nbytes)
+ {
+ generate_error (&dtp->common, ERROR_DIRECT_EOR, NULL);
+ 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;
+ dtp->u.p.current_unit->bytes_left -= (gfc_offset) nbytes;
+
+ return SUCCESS;
+
}
- if ((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0)
- dtp->u.p.size_used += (gfc_offset) nbytes;
+ /* Unformatted sequential. */
+
+ have_written = 0;
+
+ if (dtp->u.p.current_unit->flags.has_recl
+ && (gfc_offset) nbytes > dtp->u.p.current_unit->bytes_left)
+ {
+ nbytes = dtp->u.p.current_unit->bytes_left;
+ short_record = 1;
+ }
+ else
+ {
+ short_record = 0;
+ }
+
+ while (1)
+ {
+
+ 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;
+
+ 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;
}
void *dest, int kind,
size_t size, size_t nelems)
{
+ size_t i, sz;
+
/* Currently, character implies size=1. */
if (dtp->u.p.current_unit->flags.convert == CONVERT_NATIVE
|| size == 1 || type == BT_CHARACTER)
{
- size *= nelems;
- read_block_direct (dtp, dest, &size);
+ sz = size * nelems;
+ read_block_direct (dtp, dest, &sz);
}
else
{
char buffer[16];
char *p;
- size_t i, sz;
/* Break up complex into its constituent reals. */
if (type == BT_COMPLEX)
/* By now, all complex variables have been split into their
constituent reals. For types with padding, we only need to
read kind bytes. We don't care about the contents
- of the padding. */
+ of the padding. If we hit a short record, then sz is
+ adjusted accordingly, making later reads no-ops. */
sz = kind;
for (i=0; i<nelems; i++)
/* This subroutine is the main loop for a formatted data transfer
statement. It would be natural to implement this as a coroutine
with the user program, but C makes that awkward. We loop,
- processesing format elements. When we actually have to transfer
+ processing format elements. When we actually have to transfer
data instead of just setting flags, we return control to the user
program which calls a subroutine that supplies the address and type
of the next element, then comes back here to process it. */
dtp->u.p.skips = dtp->u.p.pending_spaces = 0;
}
- bytes_used = (int)(dtp->u.p.current_unit->recl - dtp->u.p.current_unit->bytes_left);
+ bytes_used = (int)(dtp->u.p.current_unit->recl
+ - dtp->u.p.current_unit->bytes_left);
switch (t)
{
case FMT_B:
if (n == 0)
goto need_data;
- if (require_type (dtp, BT_INTEGER, type, f))
+
+ if (compile_options.allow_std < GFC_STD_GNU
+ && require_type (dtp, BT_INTEGER, type, f))
return;
if (dtp->u.p.mode == READING)
case FMT_O:
if (n == 0)
- goto need_data;
+ goto need_data;
+
+ if (compile_options.allow_std < GFC_STD_GNU
+ && require_type (dtp, BT_INTEGER, type, f))
+ return;
if (dtp->u.p.mode == READING)
read_radix (dtp, f, p, len, 8);
if (n == 0)
goto need_data;
+ if (compile_options.allow_std < GFC_STD_GNU
+ && require_type (dtp, BT_INTEGER, type, f))
+ return;
+
if (dtp->u.p.mode == READING)
read_radix (dtp, f, p, len, 16);
else
internal_error (&dtp->common, "transfer_array(): Bad type");
}
- if (desc->dim[0].stride == 0)
- desc->dim[0].stride = 1;
-
rank = GFC_DESCRIPTOR_RANK (desc);
for (n = 0; n < rank; n++)
{
/* Preposition a sequential unformatted file while reading. */
static void
-us_read (st_parameter_dt *dtp)
+us_read (st_parameter_dt *dtp, int continued)
{
char *p;
int n;
return;
if (compile_options.record_marker == 0)
- n = sizeof (gfc_offset);
+ n = sizeof (GFC_INTEGER_4);
else
n = compile_options.record_marker;
/* Only CONVERT_NATIVE and CONVERT_SWAP are valid here. */
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):
memcpy (&i4, p, sizeof (i4));
i = i4;
}
}
else
- switch (compile_options.record_marker)
+ switch (nr)
{
- case 0:
- reverse_memcpy (&i, p, sizeof(gfc_offset));
- break;
-
case sizeof(GFC_INTEGER_4):
reverse_memcpy (&i4, p, sizeof (i4));
i = i4;
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;
}
amount to writing a bogus length that will be filled in later. */
static void
-us_write (st_parameter_dt *dtp)
+us_write (st_parameter_dt *dtp, int continued)
{
size_t nbytes;
gfc_offset dummy;
dummy = 0;
if (compile_options.record_marker == 0)
- nbytes = sizeof (gfc_offset);
+ nbytes = sizeof (GFC_INTEGER_4);
else
nbytes = compile_options.record_marker ;
if (swrite (dtp->u.p.current_unit->s, &dummy, &nbytes) != 0)
generate_error (&dtp->common, 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. */
- dtp->u.p.current_unit->recl = max_offset;
+ /* For sequential unformatted, if RECL= was not specified in the OPEN
+ we write until we have more bytes than can fit in the subrecord
+ markers, then we write a new subrecord. */
- 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;
}
switch (current_mode (dtp))
{
+ case FORMATTED_STREAM:
+ case UNFORMATTED_STREAM:
+ /* There are no records with stream I/O. Set the default position
+ to the beginning of the file if no position was specified. */
+ if ((dtp->common.flags & IOPARM_DT_HAS_REC) == 0)
+ dtp->u.p.current_unit->strm_pos = 1;
+ break;
+
case UNFORMATTED_SEQUENTIAL:
if (dtp->u.p.mode == READING)
- us_read (dtp);
+ us_read (dtp, 0);
else
- us_write (dtp);
+ us_write (dtp, 0);
break;
generate_error (&dtp->common, ERROR_OPTION_CONFLICT,
"Missing format for FORMATTED data transfer");
-
if (is_internal_unit (dtp)
&& dtp->u.p.current_unit->flags.form == FORM_UNFORMATTED)
generate_error (&dtp->common, ERROR_OPTION_CONFLICT,
"Internal file cannot be accessed by UNFORMATTED data transfer");
- /* Check the record number. */
+ /* Check the record or position number. */
if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT
&& (cf & IOPARM_DT_HAS_REC) == 0)
return;
/* Sanity checks on the record number. */
-
if ((cf & IOPARM_DT_HAS_REC) != 0)
{
if (dtp->rec <= 0)
}
/* Position the file. */
- if (sseek (dtp->u.p.current_unit->s,
- (dtp->rec - 1) * dtp->u.p.current_unit->recl) == FAILURE)
+ if (!is_stream_io (dtp))
{
- generate_error (&dtp->common, ERROR_OS, NULL);
- return;
+ if (sseek (dtp->u.p.current_unit->s, (gfc_offset) (dtp->rec - 1)
+ * dtp->u.p.current_unit->recl) == FAILURE)
+ {
+ generate_error (&dtp->common, ERROR_OS, NULL);
+ return;
+ }
}
+ else
+ dtp->u.p.current_unit->strm_pos = dtp->rec;
+
}
/* Overwriting an existing sequential file ?
if (read_flag)
{
- if (dtp->u.p.current_unit->read_bad)
+ if (dtp->u.p.current_unit->read_bad && !is_stream_io (dtp))
{
generate_error (&dtp->common, ERROR_BAD_OPTION,
"Cannot READ after a nonadvancing WRITE");
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. */
#define MAX_READ 4096
static void
-next_record_r (st_parameter_dt *dtp)
+skip_record (st_parameter_dt *dtp, size_t bytes)
{
- gfc_offset new, record;
- int bytes_left, rlength, length;
+ gfc_offset new;
+ int rlength, length;
char *p;
- switch (current_mode (dtp))
+ 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)
{
- case UNFORMATTED_SEQUENTIAL:
/* Skip over tail */
- 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 UNFORMATTED_DIRECT:
- if (dtp->u.p.current_unit->bytes_left == 0)
- break;
+ skip_record (dtp, bytes);
- 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;
+ if ( ! (complete_record && dtp->u.p.current_unit->continued))
+ return;
- /* 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);
+ us_read (dtp, 1);
+ }
+}
- }
- 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;
+/* Space to the next record for read mode. */
- p = salloc_r (dtp->u.p.current_unit->s, &rlength);
- if (p == NULL)
- {
- generate_error (&dtp->common, ERROR_OS, NULL);
- break;
- }
+static void
+next_record_r (st_parameter_dt *dtp)
+{
+ gfc_offset record;
+ int length, bytes_left;
+ char *p;
- dtp->u.p.current_unit->bytes_left -= length;
- }
- }
+ switch (current_mode (dtp))
+ {
+ /* No records in unformatted STREAM I/O. */
+ case UNFORMATTED_STREAM:
+ return;
+
+ case UNFORMATTED_SEQUENTIAL:
+ next_record_r_unf (dtp, 1);
+ break;
+
+ case FORMATTED_DIRECT:
+ case UNFORMATTED_DIRECT:
+ skip_record (dtp, 0);
break;
+ case FORMATTED_STREAM:
case FORMATTED_SEQUENTIAL:
length = 1;
/* sf_read has already terminated input because of an '\n' */
dtp->u.p.current_unit->endfile = AT_ENDFILE;
break;
}
+
+ if (is_stream_io (dtp))
+ dtp->u.p.current_unit->strm_pos++;
}
while (*p != '\n');
char p[sizeof (GFC_INTEGER_8)];
if (compile_options.record_marker == 0)
- len = sizeof (gfc_offset);
+ len = sizeof (GFC_INTEGER_4);
else
len = compile_options.record_marker;
/* Only CONVERT_NATIVE and CONVERT_SWAP are valid here. */
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):
buf4 = buf;
return swrite (dtp->u.p.current_unit->s, &buf4, &len);
}
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):
buf4 = buf;
reverse_memcpy (p, &buf4, sizeof (GFC_INTEGER_4));
case sizeof (GFC_INTEGER_8):
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);
break;
}
+/* 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. */
static void
next_record_w (st_parameter_dt *dtp, int done)
{
- gfc_offset c, m, record, max_pos;
+ gfc_offset m, record, max_pos;
int length;
char *p;
- size_t record_marker;
/* Zero counters for X- and T-editing. */
max_pos = dtp->u.p.max_pos;
switch (current_mode (dtp))
{
+ /* No records in unformatted STREAM I/O. */
+ case UNFORMATTED_STREAM:
+ return;
+
case FORMATTED_DIRECT:
if (dtp->u.p.current_unit->bytes_left == 0)
break;
break;
case UNFORMATTED_SEQUENTIAL:
- /* Bytes written. */
- 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;
-
+ next_record_w_unf (dtp, 0);
break;
+ case FORMATTED_STREAM:
case FORMATTED_SEQUENTIAL:
- if (dtp->u.p.current_unit->bytes_left == 0)
- break;
-
if (is_internal_unit (dtp))
{
if (is_array_io (dtp))
/* Now that the current record has been padded out,
determine where the next record in the array is. */
record = next_array_record (dtp, dtp->u.p.current_unit->ls);
-
+ if (record == 0)
+ dtp->u.p.current_unit->endfile = AT_ENDFILE;
+
/* Now seek to this record */
record = record * dtp->u.p.current_unit->recl;
else
length = (int) dtp->u.p.current_unit->bytes_left;
}
+
if (sset (dtp->u.p.current_unit->s, ' ', length) == FAILURE)
{
generate_error (&dtp->common, ERROR_END, NULL);
}
else
{
+
/* If this is the last call to next_record move to the farthest
position reached in preparation for completing the record.
(for file unit) */
#endif
if (swrite (dtp->u.p.current_unit->s, &crlf[2-len], &len) != 0)
goto io_error;
+
+ if (is_stream_io (dtp))
+ dtp->u.p.current_unit->strm_pos += len;
}
break;
else
next_record_w (dtp, done);
- /* keep position up to date for INQUIRE */
- dtp->u.p.current_unit->flags.position = POSITION_ASIS;
-
- dtp->u.p.current_unit->current_record = 0;
- if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT)
- {
- fp = file_position (dtp->u.p.current_unit->s);
- /* Calculate next record, rounding up partial records. */
- dtp->u.p.current_unit->last_record = (fp + dtp->u.p.current_unit->recl - 1)
- / dtp->u.p.current_unit->recl;
- }
- else
- dtp->u.p.current_unit->last_record++;
+ if (!is_stream_io (dtp))
+ {
+ /* keep position up to date for INQUIRE */
+ dtp->u.p.current_unit->flags.position = POSITION_ASIS;
+ dtp->u.p.current_unit->current_record = 0;
+ if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT)
+ {
+ fp = file_position (dtp->u.p.current_unit->s);
+ /* Calculate next record, rounding up partial records. */
+ dtp->u.p.current_unit->last_record =
+ (fp + dtp->u.p.current_unit->recl - 1) /
+ dtp->u.p.current_unit->recl;
+ }
+ else
+ dtp->u.p.current_unit->last_record++;
+ }
if (!done)
pre_position (dtp);
}
if ((cf & IOPARM_DT_LIST_FORMAT) != 0 && dtp->u.p.mode == READING)
- finish_list_read (dtp);
- else
{
- dtp->u.p.current_unit->current_record = 0;
- if (dtp->u.p.advance_status == ADVANCE_NO || dtp->u.p.seen_dollar)
- {
- /* Most systems buffer lines, so force the partial record
- to be written out. */
- if (!is_internal_unit (dtp))
- flush (dtp->u.p.current_unit->s);
- dtp->u.p.seen_dollar = 0;
- return;
- }
+ finish_list_read (dtp);
+ sfree (dtp->u.p.current_unit->s);
+ return;
+ }
- next_record (dtp, 1);
+ if (is_stream_io (dtp))
+ {
+ if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED)
+ next_record (dtp, 1);
+ flush (dtp->u.p.current_unit->s);
+ sfree (dtp->u.p.current_unit->s);
+ return;
}
+ dtp->u.p.current_unit->current_record = 0;
+
+ if (!is_internal_unit (dtp) && dtp->u.p.seen_dollar)
+ {
+ dtp->u.p.seen_dollar = 0;
+ sfree (dtp->u.p.current_unit->s);
+ return;
+ }
+
+ if (dtp->u.p.advance_status == ADVANCE_NO)
+ {
+ flush (dtp->u.p.current_unit->s);
+ return;
+ }
+
+ next_record (dtp, 1);
sfree (dtp->u.p.current_unit->s);
}
void
st_read (st_parameter_dt *dtp)
{
-
library_start (&dtp->common);
data_transfer_init (dtp, 1);