-/* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008
+/* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
Free Software Foundation, Inc.
Contributed by Andy Vaught
Namelist transfer functions contributed by Paul Thomas
Libgfortran is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
any later version.
-In addition to the permissions in the GNU General Public License, the
-Free Software Foundation gives you unlimited permission to link the
-compiled version of this file into combinations with other programs,
-and to distribute those combinations without any restriction coming
-from the use of this file. (The General Public License restrictions
-do apply in other respects; for example, they cover modification of
-the file, and distribution when not linked into a combine
-executable.)
-
Libgfortran is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-You should have received a copy of the GNU General Public License
-along with Libgfortran; see the file COPYING. If not, write to
-the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA. */
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
/* transfer.c -- Top level handling of data transfer statements. */
#include "io.h"
+#include "fbuf.h"
+#include "format.h"
+#include "unix.h"
#include <string.h>
#include <assert.h>
#include <stdlib.h>
{NULL, 0}
};
+static const st_option round_opt[] = {
+ {"up", ROUND_UP},
+ {"down", ROUND_DOWN},
+ {"zero", ROUND_ZERO},
+ {"nearest", ROUND_NEAREST},
+ {"compatible", ROUND_COMPATIBLE},
+ {"processor_defined", ROUND_PROCDEFINED},
+ {NULL, 0}
+};
+
static const st_option sign_opt[] = {
{"plus", SIGN_SP},
}
-/* Mid level data transfer statements. These subroutines do reading
- and writing in the style of salloc_r()/salloc_w() within the
- current record. */
+/* Mid level data transfer statements. */
/* When reading sequential formatted records we have a problem. We
don't know how long the line is until we read the trailing newline,
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. */
+
+/* Read sequential file - internal unit */
-char *
-read_sf (st_parameter_dt *dtp, int * length, int no_error)
+static char *
+read_sf_internal (st_parameter_dt *dtp, int * length)
{
static char *empty_string[0];
- char *base, *p, q;
- int n, lorig, memread, seen_comma;
+ char *base;
+ int lorig;
- /* If we hit EOF previously with the no_error flag set (i.e. X, T,
- TR edit descriptors), and we now try to read again, this time
- without setting no_error. */
- if (!no_error && dtp->u.p.at_eof)
+ /* Zero size array gives internal unit len of 0. Nothing to read. */
+ if (dtp->internal_unit_len == 0
+ && dtp->u.p.current_unit->pad_status == PAD_NO)
+ hit_eof (dtp);
+
+ /* If we have seen an eor previously, return a length of 0. The
+ caller is responsible for correctly padding the input field. */
+ if (dtp->u.p.sf_seen_eor)
{
*length = 0;
+ /* Just return something that isn't a NULL pointer, otherwise the
+ caller thinks an error occured. */
+ return (char*) empty_string;
+ }
+
+ lorig = *length;
+ base = mem_alloc_r (dtp->u.p.current_unit->s, length);
+ if (unlikely (lorig > *length))
+ {
hit_eof (dtp);
return NULL;
}
+ dtp->u.p.current_unit->bytes_left -= *length;
+
+ if ((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0)
+ dtp->u.p.size_used += (GFC_IO_INT) *length;
+
+ return base;
+
+}
+
+/* Read sequential file - external unit */
+
+static char *
+read_sf (st_parameter_dt *dtp, int * length)
+{
+ static char *empty_string[0];
+ char *base, *p, q;
+ int n, lorig, seen_comma;
+
/* If we have seen an eor previously, return a length of 0. The
caller is responsible for correctly padding the input field. */
if (dtp->u.p.sf_seen_eor)
return (char*) empty_string;
}
- if (is_internal_unit (dtp))
- {
- memread = *length;
- base = mem_alloc_r (dtp->u.p.current_unit->s, length);
- if (unlikely (memread > *length))
- {
- hit_eof (dtp);
- return NULL;
- }
- n = *length;
- goto done;
- }
-
n = seen_comma = 0;
/* Read data into format buffer and scan through it. */
if (q == '\n' || q == '\r')
{
- /* Unexpected end of line. */
+ /* Unexpected end of line. Set the position. */
+ fbuf_seek (dtp->u.p.current_unit, n + 1 ,SEEK_CUR);
+ dtp->u.p.sf_seen_eor = 1;
/* If we see an EOR during non-advancing I/O, we need to skip
the rest of the I/O statement. Set the corresponding flag. */
if (dtp->u.p.advance_status == ADVANCE_NO || dtp->u.p.seen_dollar)
dtp->u.p.eor_condition = 1;
-
+
/* If we encounter a CR, it might be a CRLF. */
if (q == '\r') /* Probably a CRLF */
{
- if (n < *length && *(p + 1) == '\n')
- dtp->u.p.sf_seen_eor = 2;
+ /* See if there is an LF. Use fbuf_read rather then fbuf_getc so
+ the position is not advanced unless it really is an LF. */
+ int readlen = 1;
+ p = fbuf_read (dtp->u.p.current_unit, &readlen);
+ if (*p == '\n' && readlen == 1)
+ {
+ dtp->u.p.sf_seen_eor = 2;
+ fbuf_seek (dtp->u.p.current_unit, 1 ,SEEK_CUR);
+ }
}
- else
- dtp->u.p.sf_seen_eor = 1;
/* Without padding, terminate the I/O statement without assigning
the value. With padding, the value still needs to be assigned,
so we can just continue with a short read. */
if (dtp->u.p.current_unit->pad_status == PAD_NO)
{
- if (likely (no_error))
- break;
generate_error (&dtp->common, LIBERROR_EOR, NULL);
return NULL;
}
*length = n;
- break;
+ goto done;
}
/* Short circuit the read if a comma is found during numeric input.
The flag is set to zero during character reads so that commas in
*length = n;
break;
}
-
n++;
p++;
}
- fbuf_seek (dtp->u.p.current_unit, n + dtp->u.p.sf_seen_eor + seen_comma,
- SEEK_CUR);
+ fbuf_seek (dtp->u.p.current_unit, n + seen_comma, SEEK_CUR);
/* A short read implies we hit EOF, unless we hit EOR, a comma, or
some other stuff. Set the relevant flags. */
if (lorig > *length && !dtp->u.p.sf_seen_eor && !seen_comma)
{
- if (no_error)
- dtp->u.p.at_eof = 1;
- else
+ if (n > 0)
{
- hit_eof (dtp);
- return NULL;
- }
+ if (dtp->u.p.advance_status == ADVANCE_NO)
+ {
+ if (dtp->u.p.current_unit->pad_status == PAD_NO)
+ {
+ hit_eof (dtp);
+ return NULL;
+ }
+ else
+ dtp->u.p.eor_condition = 1;
+ }
+ else
+ dtp->u.p.at_eof = 1;
+ }
+ else if (dtp->u.p.advance_status == ADVANCE_NO
+ || dtp->u.p.current_unit->pad_status == PAD_NO
+ || dtp->u.p.current_unit->bytes_left
+ == dtp->u.p.current_unit->recl)
+ {
+ hit_eof (dtp);
+ return NULL;
+ }
}
done:
dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
else
{
- if (unlikely (dtp->u.p.current_unit->pad_status == PAD_NO))
+ if (unlikely (dtp->u.p.current_unit->pad_status == PAD_NO)
+ && !is_internal_unit (dtp))
{
/* Not enough data left. */
generate_error (&dtp->common, LIBERROR_EOR, NULL);
}
}
- if (unlikely (dtp->u.p.current_unit->bytes_left == 0))
+ if (unlikely (dtp->u.p.current_unit->bytes_left == 0
+ && !is_internal_unit(dtp)))
{
- hit_eof (dtp);
+ hit_eof (dtp);
return NULL;
}
(dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL ||
dtp->u.p.current_unit->flags.access == ACCESS_STREAM))
{
- source = read_sf (dtp, nbytes, 0);
+ if (is_internal_unit (dtp))
+ source = read_sf_internal (dtp, nbytes);
+ else
+ source = read_sf (dtp, nbytes);
+
dtp->u.p.current_unit->strm_pos +=
(gfc_offset) (*nbytes + dtp->u.p.sf_seen_eor);
return source;
unformatted files. */
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)
{
ssize_t to_read_record;
ssize_t have_read_record;
if (is_stream_io (dtp))
{
- to_read_record = *nbytes;
have_read_record = sread (dtp->u.p.current_unit->s, buf,
- to_read_record);
+ nbytes);
if (unlikely (have_read_record < 0))
{
generate_error (&dtp->common, LIBERROR_OS, NULL);
dtp->u.p.current_unit->strm_pos += (gfc_offset) have_read_record;
- if (unlikely (to_read_record != have_read_record))
+ if (unlikely ((ssize_t) nbytes != have_read_record))
{
/* Short read, e.g. if we hit EOF. For stream files,
we have to set the end-of-file condition. */
hit_eof (dtp);
- return;
}
return;
}
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)
{
short_record = 1;
- to_read_record = (size_t) dtp->u.p.current_unit->bytes_left;
- *nbytes = to_read_record;
+ to_read_record = dtp->u.p.current_unit->bytes_left;
+ nbytes = to_read_record;
}
-
else
{
short_record = 0;
- to_read_record = *nbytes;
+ to_read_record = nbytes;
}
dtp->u.p.current_unit->bytes_left -= to_read_record;
return;
}
- if (to_read_record != (ssize_t) *nbytes)
+ if (to_read_record != (ssize_t) nbytes)
{
/* Short read, e.g. if we hit EOF. Apparently, we read
more than was written to the last record. */
- *nbytes = to_read_record;
return;
}
if (unlikely (short_record))
{
generate_error (&dtp->common, LIBERROR_SHORT_RECORD, NULL);
- return;
}
return;
}
/* Check whether we exceed the total record length. */
if (dtp->u.p.current_unit->flags.has_recl
- && (*nbytes > (size_t) dtp->u.p.current_unit->bytes_left))
+ && ((gfc_offset) nbytes > dtp->u.p.current_unit->bytes_left))
{
- to_read_record = (ssize_t) dtp->u.p.current_unit->bytes_left;
+ to_read_record = dtp->u.p.current_unit->bytes_left;
short_record = 1;
}
else
{
- to_read_record = *nbytes;
+ to_read_record = nbytes;
short_record = 0;
}
have_read_record = 0;
if (dtp->u.p.current_unit->bytes_left_subrecord
< (gfc_offset) to_read_record)
{
- to_read_subrecord = (ssize_t) dtp->u.p.current_unit->bytes_left_subrecord;
+ to_read_subrecord = dtp->u.p.current_unit->bytes_left_subrecord;
to_read_record -= to_read_subrecord;
}
else
structure has been corrupted, or the trailing record
marker would still be present. */
- *nbytes = have_read_record;
generate_error (&dtp->common, LIBERROR_CORRUPT_FILE, NULL);
return;
}
unformatted_read (st_parameter_dt *dtp, bt type,
void *dest, int kind, size_t size, size_t nelems)
{
- size_t i, sz;
-
if (likely (dtp->u.p.current_unit->flags.convert == GFC_CONVERT_NATIVE)
|| kind == 1)
{
- sz = size * nelems;
if (type == BT_CHARACTER)
- sz *= GFC_SIZE_OF_CHAR_KIND(kind);
- read_block_direct (dtp, dest, &sz);
+ size *= GFC_SIZE_OF_CHAR_KIND(kind);
+ read_block_direct (dtp, dest, size * nelems);
}
else
{
char buffer[16];
char *p;
+ size_t i;
p = dest;
for (i = 0; i < nelems; i++)
{
- read_block_direct (dtp, buffer, &size);
+ read_block_direct (dtp, buffer, size);
reverse_memcpy (p, buffer, size);
p += size;
}
/* Return a pointer to the name of a type. */
-const char *
-type_name (bt type)
-{
- const char *p;
+const char *
+type_name (bt type)
+{
+ const char *p;
+
+ switch (type)
+ {
+ case BT_INTEGER:
+ p = "INTEGER";
+ break;
+ case BT_LOGICAL:
+ p = "LOGICAL";
+ break;
+ case BT_CHARACTER:
+ p = "CHARACTER";
+ break;
+ case BT_REAL:
+ p = "REAL";
+ break;
+ case BT_COMPLEX:
+ p = "COMPLEX";
+ break;
+ default:
+ internal_error (NULL, "type_name(): Bad type");
+ }
+
+ return p;
+}
+
+
+/* Write a constant string to the output.
+ This is complicated because the string can have doubled delimiters
+ in it. The length in the format node is the true length. */
+
+static void
+write_constant_string (st_parameter_dt *dtp, const fnode *f)
+{
+ char c, delimiter, *p, *q;
+ int length;
+
+ length = f->u.string.length;
+ if (length == 0)
+ return;
+
+ p = write_block (dtp, length);
+ if (p == NULL)
+ return;
+
+ q = f->u.string.p;
+ delimiter = q[-1];
+
+ for (; length > 0; length--)
+ {
+ c = *p++ = *q++;
+ if (c == delimiter && c != 'H' && c != 'h')
+ q++; /* Skip the doubled delimiter. */
+ }
+}
+
+
+/* Given actual and expected types in a formatted data transfer, make
+ sure they agree. If not, an error message is generated. Returns
+ nonzero if something went wrong. */
+
+static int
+require_type (st_parameter_dt *dtp, bt expected, bt actual, const fnode *f)
+{
+ char buffer[100];
+
+ if (actual == expected)
+ return 0;
+
+ /* Adjust item_count before emitting error message. */
+ sprintf (buffer, "Expected %s for item %d in formatted transfer, got %s",
+ type_name (expected), dtp->u.p.item_count - 1, type_name (actual));
+
+ format_error (dtp, f, buffer);
+ return 1;
+}
+
+
+/* This function is in 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,
+ 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 function that supplies the address and type
+ of the next element, then comes back here to process it. */
+
+static void
+formatted_transfer_scalar_read (st_parameter_dt *dtp, bt type, void *p, int kind,
+ size_t size)
+{
+ int pos, bytes_used;
+ const fnode *f;
+ format_token t;
+ int n;
+ int consume_data_flag;
+
+ /* Change a complex data item into a pair of reals. */
+
+ n = (p == NULL) ? 0 : ((type != BT_COMPLEX) ? 1 : 2);
+ if (type == BT_COMPLEX)
+ {
+ type = BT_REAL;
+ size /= 2;
+ }
+
+ /* If there's an EOR condition, we simulate finalizing the transfer
+ by doing nothing. */
+ if (dtp->u.p.eor_condition)
+ return;
+
+ /* Set this flag so that commas in reads cause the read to complete before
+ the entire field has been read. The next read field will start right after
+ the comma in the stream. (Set to 0 for character reads). */
+ dtp->u.p.sf_read_comma =
+ dtp->u.p.current_unit->decimal_status == DECIMAL_COMMA ? 0 : 1;
+
+ for (;;)
+ {
+ /* If reversion has occurred and there is another real data item,
+ then we have to move to the next record. */
+ if (dtp->u.p.reversion_flag && n > 0)
+ {
+ dtp->u.p.reversion_flag = 0;
+ next_record (dtp, 0);
+ }
+
+ consume_data_flag = 1;
+ if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
+ break;
+
+ f = next_format (dtp);
+ if (f == NULL)
+ {
+ /* No data descriptors left. */
+ if (unlikely (n > 0))
+ generate_error (&dtp->common, LIBERROR_FORMAT,
+ "Insufficient data descriptors in format after reversion");
+ return;
+ }
+
+ t = f->format;
+
+ bytes_used = (int)(dtp->u.p.current_unit->recl
+ - dtp->u.p.current_unit->bytes_left);
+
+ if (is_stream_io(dtp))
+ bytes_used = 0;
+
+ switch (t)
+ {
+ case FMT_I:
+ if (n == 0)
+ goto need_read_data;
+ if (require_type (dtp, BT_INTEGER, type, f))
+ return;
+ read_decimal (dtp, f, p, kind);
+ break;
+
+ case FMT_B:
+ if (n == 0)
+ goto need_read_data;
+ if (compile_options.allow_std < GFC_STD_GNU
+ && require_type (dtp, BT_INTEGER, type, f))
+ return;
+ read_radix (dtp, f, p, kind, 2);
+ break;
+
+ case FMT_O:
+ if (n == 0)
+ goto need_read_data;
+ if (compile_options.allow_std < GFC_STD_GNU
+ && require_type (dtp, BT_INTEGER, type, f))
+ return;
+ read_radix (dtp, f, p, kind, 8);
+ break;
+
+ case FMT_Z:
+ if (n == 0)
+ goto need_read_data;
+ if (compile_options.allow_std < GFC_STD_GNU
+ && require_type (dtp, BT_INTEGER, type, f))
+ return;
+ read_radix (dtp, f, p, kind, 16);
+ break;
+
+ case FMT_A:
+ if (n == 0)
+ goto need_read_data;
+
+ /* It is possible to have FMT_A with something not BT_CHARACTER such
+ as when writing out hollerith strings, so check both type
+ and kind before calling wide character routines. */
+ if (type == BT_CHARACTER && kind == 4)
+ read_a_char4 (dtp, f, p, size);
+ else
+ read_a (dtp, f, p, size);
+ break;
+
+ case FMT_L:
+ if (n == 0)
+ goto need_read_data;
+ read_l (dtp, f, p, kind);
+ break;
+
+ case FMT_D:
+ if (n == 0)
+ goto need_read_data;
+ if (require_type (dtp, BT_REAL, type, f))
+ return;
+ read_f (dtp, f, p, kind);
+ break;
+
+ case FMT_E:
+ if (n == 0)
+ goto need_read_data;
+ if (require_type (dtp, BT_REAL, type, f))
+ return;
+ read_f (dtp, f, p, kind);
+ break;
+
+ case FMT_EN:
+ if (n == 0)
+ goto need_read_data;
+ if (require_type (dtp, BT_REAL, type, f))
+ return;
+ read_f (dtp, f, p, kind);
+ break;
+
+ case FMT_ES:
+ if (n == 0)
+ goto need_read_data;
+ if (require_type (dtp, BT_REAL, type, f))
+ return;
+ read_f (dtp, f, p, kind);
+ break;
+
+ case FMT_F:
+ if (n == 0)
+ goto need_read_data;
+ if (require_type (dtp, BT_REAL, type, f))
+ return;
+ read_f (dtp, f, p, kind);
+ break;
+
+ case FMT_G:
+ if (n == 0)
+ goto need_read_data;
+ switch (type)
+ {
+ case BT_INTEGER:
+ read_decimal (dtp, f, p, kind);
+ break;
+ case BT_LOGICAL:
+ read_l (dtp, f, p, kind);
+ break;
+ case BT_CHARACTER:
+ if (kind == 4)
+ read_a_char4 (dtp, f, p, size);
+ else
+ read_a (dtp, f, p, size);
+ break;
+ case BT_REAL:
+ read_f (dtp, f, p, kind);
+ break;
+ default:
+ internal_error (&dtp->common, "formatted_transfer(): Bad type");
+ }
+ break;
+
+ case FMT_STRING:
+ consume_data_flag = 0;
+ format_error (dtp, f, "Constant string in input format");
+ return;
+
+ /* Format codes that don't transfer data. */
+ case FMT_X:
+ case FMT_TR:
+ consume_data_flag = 0;
+ dtp->u.p.skips += f->u.n;
+ pos = bytes_used + dtp->u.p.skips - 1;
+ dtp->u.p.pending_spaces = pos - dtp->u.p.max_pos + 1;
+ read_x (dtp, f->u.n);
+ break;
+
+ case FMT_TL:
+ case FMT_T:
+ consume_data_flag = 0;
+
+ if (f->format == FMT_TL)
+ {
+ /* Handle the special case when no bytes have been used yet.
+ Cannot go below zero. */
+ if (bytes_used == 0)
+ {
+ dtp->u.p.pending_spaces -= f->u.n;
+ dtp->u.p.skips -= f->u.n;
+ dtp->u.p.skips = dtp->u.p.skips < 0 ? 0 : dtp->u.p.skips;
+ }
+
+ pos = bytes_used - f->u.n;
+ }
+ else /* FMT_T */
+ pos = f->u.n - 1;
+
+ /* Standard 10.6.1.1: excessive left tabbing is reset to the
+ left tab limit. We do not check if the position has gone
+ beyond the end of record because a subsequent tab could
+ bring us back again. */
+ pos = pos < 0 ? 0 : pos;
+
+ dtp->u.p.skips = dtp->u.p.skips + pos - bytes_used;
+ dtp->u.p.pending_spaces = dtp->u.p.pending_spaces
+ + pos - dtp->u.p.max_pos;
+ dtp->u.p.pending_spaces = dtp->u.p.pending_spaces < 0
+ ? 0 : dtp->u.p.pending_spaces;
+ if (dtp->u.p.skips == 0)
+ break;
+
+ /* Adjust everything for end-of-record condition */
+ if (dtp->u.p.sf_seen_eor && !is_internal_unit (dtp))
+ {
+ dtp->u.p.current_unit->bytes_left -= dtp->u.p.sf_seen_eor;
+ dtp->u.p.skips -= dtp->u.p.sf_seen_eor;
+ bytes_used = pos;
+ dtp->u.p.sf_seen_eor = 0;
+ }
+ if (dtp->u.p.skips < 0)
+ {
+ if (is_internal_unit (dtp))
+ sseek (dtp->u.p.current_unit->s, dtp->u.p.skips, SEEK_CUR);
+ else
+ fbuf_seek (dtp->u.p.current_unit, dtp->u.p.skips, SEEK_CUR);
+ dtp->u.p.current_unit->bytes_left -= (gfc_offset) dtp->u.p.skips;
+ dtp->u.p.skips = dtp->u.p.pending_spaces = 0;
+ }
+ else
+ read_x (dtp, dtp->u.p.skips);
+ break;
+
+ case FMT_S:
+ consume_data_flag = 0;
+ dtp->u.p.sign_status = SIGN_S;
+ break;
+
+ case FMT_SS:
+ consume_data_flag = 0;
+ dtp->u.p.sign_status = SIGN_SS;
+ break;
+
+ case FMT_SP:
+ consume_data_flag = 0;
+ dtp->u.p.sign_status = SIGN_SP;
+ break;
+
+ case FMT_BN:
+ consume_data_flag = 0 ;
+ dtp->u.p.blank_status = BLANK_NULL;
+ break;
+
+ case FMT_BZ:
+ consume_data_flag = 0;
+ dtp->u.p.blank_status = BLANK_ZERO;
+ break;
+
+ case FMT_DC:
+ consume_data_flag = 0;
+ dtp->u.p.current_unit->decimal_status = DECIMAL_COMMA;
+ break;
+
+ case FMT_DP:
+ consume_data_flag = 0;
+ dtp->u.p.current_unit->decimal_status = DECIMAL_POINT;
+ break;
+
+ case FMT_RC:
+ consume_data_flag = 0;
+ dtp->u.p.current_unit->round_status = ROUND_COMPATIBLE;
+ break;
+
+ case FMT_RD:
+ consume_data_flag = 0;
+ dtp->u.p.current_unit->round_status = ROUND_DOWN;
+ break;
+
+ case FMT_RN:
+ consume_data_flag = 0;
+ dtp->u.p.current_unit->round_status = ROUND_NEAREST;
+ break;
- switch (type)
- {
- case BT_INTEGER:
- p = "INTEGER";
- break;
- case BT_LOGICAL:
- p = "LOGICAL";
- break;
- case BT_CHARACTER:
- p = "CHARACTER";
- break;
- case BT_REAL:
- p = "REAL";
- break;
- case BT_COMPLEX:
- p = "COMPLEX";
- break;
- default:
- internal_error (NULL, "type_name(): Bad type");
- }
+ case FMT_RP:
+ consume_data_flag = 0;
+ dtp->u.p.current_unit->round_status = ROUND_PROCDEFINED;
+ break;
- return p;
-}
+ case FMT_RU:
+ consume_data_flag = 0;
+ dtp->u.p.current_unit->round_status = ROUND_UP;
+ break;
+ case FMT_RZ:
+ consume_data_flag = 0;
+ dtp->u.p.current_unit->round_status = ROUND_ZERO;
+ break;
-/* Write a constant string to the output.
- This is complicated because the string can have doubled delimiters
- in it. The length in the format node is the true length. */
+ case FMT_P:
+ consume_data_flag = 0;
+ dtp->u.p.scale_factor = f->u.k;
+ break;
-static void
-write_constant_string (st_parameter_dt *dtp, const fnode *f)
-{
- char c, delimiter, *p, *q;
- int length;
+ case FMT_DOLLAR:
+ consume_data_flag = 0;
+ dtp->u.p.seen_dollar = 1;
+ break;
- length = f->u.string.length;
- if (length == 0)
- return;
+ case FMT_SLASH:
+ consume_data_flag = 0;
+ dtp->u.p.skips = dtp->u.p.pending_spaces = 0;
+ next_record (dtp, 0);
+ break;
- p = write_block (dtp, length);
- if (p == NULL)
- return;
-
- q = f->u.string.p;
- delimiter = q[-1];
+ case FMT_COLON:
+ /* A colon descriptor causes us to exit this loop (in
+ particular preventing another / descriptor from being
+ processed) unless there is another data item to be
+ transferred. */
+ consume_data_flag = 0;
+ if (n == 0)
+ return;
+ break;
- for (; length > 0; length--)
- {
- c = *p++ = *q++;
- if (c == delimiter && c != 'H' && c != 'h')
- q++; /* Skip the doubled delimiter. */
- }
-}
+ default:
+ internal_error (&dtp->common, "Bad format node");
+ }
+ /* Adjust the item count and data pointer. */
-/* Given actual and expected types in a formatted data transfer, make
- sure they agree. If not, an error message is generated. Returns
- nonzero if something went wrong. */
+ if ((consume_data_flag > 0) && (n > 0))
+ {
+ n--;
+ p = ((char *) p) + size;
+ }
-static int
-require_type (st_parameter_dt *dtp, bt expected, bt actual, const fnode *f)
-{
- char buffer[100];
+ dtp->u.p.skips = 0;
- if (actual == expected)
- return 0;
+ pos = (int)(dtp->u.p.current_unit->recl - dtp->u.p.current_unit->bytes_left);
+ dtp->u.p.max_pos = (dtp->u.p.max_pos > pos) ? dtp->u.p.max_pos : pos;
+ }
- sprintf (buffer, "Expected %s for item %d in formatted transfer, got %s",
- type_name (expected), dtp->u.p.item_count, type_name (actual));
+ return;
- format_error (dtp, f, buffer);
- return 1;
+ /* Come here when we need a data descriptor but don't have one. We
+ push the current format node back onto the input, then return and
+ let the user program call us back with the data. */
+ need_read_data:
+ unget_format (dtp, f);
}
-/* 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,
- 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. */
-
static void
-formatted_transfer_scalar (st_parameter_dt *dtp, bt type, void *p, int kind,
- size_t size)
+formatted_transfer_scalar_write (st_parameter_dt *dtp, bt type, void *p, int kind,
+ size_t size)
{
int pos, bytes_used;
const fnode *f;
if (dtp->u.p.skips < 0)
{
if (is_internal_unit (dtp))
- move_pos_offset (dtp->u.p.current_unit->s, dtp->u.p.skips);
+ sseek (dtp->u.p.current_unit->s, dtp->u.p.skips, SEEK_CUR);
else
fbuf_seek (dtp->u.p.current_unit, dtp->u.p.skips, SEEK_CUR);
dtp->u.p.current_unit->bytes_left -= (gfc_offset) dtp->u.p.skips;
goto need_data;
if (require_type (dtp, BT_INTEGER, type, f))
return;
-
- if (dtp->u.p.mode == READING)
- read_decimal (dtp, f, p, kind);
- else
- write_i (dtp, f, p, kind);
-
+ write_i (dtp, f, p, kind);
break;
case FMT_B:
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, kind, 2);
- else
- write_b (dtp, f, p, kind);
-
+ write_b (dtp, f, p, kind);
break;
case FMT_O:
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, kind, 8);
- else
- write_o (dtp, f, p, kind);
-
+ write_o (dtp, f, p, kind);
break;
case FMT_Z:
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, kind, 16);
- else
- write_z (dtp, f, p, kind);
-
+ write_z (dtp, f, p, kind);
break;
case FMT_A:
/* It is possible to have FMT_A with something not BT_CHARACTER such
as when writing out hollerith strings, so check both type
and kind before calling wide character routines. */
- if (dtp->u.p.mode == READING)
- {
- if (type == BT_CHARACTER && kind == 4)
- read_a_char4 (dtp, f, p, size);
- else
- read_a (dtp, f, p, size);
- }
+ if (type == BT_CHARACTER && kind == 4)
+ write_a_char4 (dtp, f, p, size);
else
- {
- if (type == BT_CHARACTER && kind == 4)
- write_a_char4 (dtp, f, p, size);
- else
- write_a (dtp, f, p, size);
- }
+ write_a (dtp, f, p, size);
break;
case FMT_L:
if (n == 0)
goto need_data;
-
- if (dtp->u.p.mode == READING)
- read_l (dtp, f, p, kind);
- else
- write_l (dtp, f, p, kind);
-
+ write_l (dtp, f, p, kind);
break;
case FMT_D:
goto need_data;
if (require_type (dtp, BT_REAL, type, f))
return;
-
- if (dtp->u.p.mode == READING)
- read_f (dtp, f, p, kind);
- else
- write_d (dtp, f, p, kind);
-
+ write_d (dtp, f, p, kind);
break;
case FMT_E:
goto need_data;
if (require_type (dtp, BT_REAL, type, f))
return;
-
- if (dtp->u.p.mode == READING)
- read_f (dtp, f, p, kind);
- else
- write_e (dtp, f, p, kind);
+ write_e (dtp, f, p, kind);
break;
case FMT_EN:
goto need_data;
if (require_type (dtp, BT_REAL, type, f))
return;
-
- if (dtp->u.p.mode == READING)
- read_f (dtp, f, p, kind);
- else
- write_en (dtp, f, p, kind);
-
+ write_en (dtp, f, p, kind);
break;
case FMT_ES:
goto need_data;
if (require_type (dtp, BT_REAL, type, f))
return;
-
- if (dtp->u.p.mode == READING)
- read_f (dtp, f, p, kind);
- else
- write_es (dtp, f, p, kind);
-
+ write_es (dtp, f, p, kind);
break;
case FMT_F:
goto need_data;
if (require_type (dtp, BT_REAL, type, f))
return;
-
- if (dtp->u.p.mode == READING)
- read_f (dtp, f, p, kind);
- else
- write_f (dtp, f, p, kind);
-
+ write_f (dtp, f, p, kind);
break;
case FMT_G:
if (n == 0)
goto need_data;
- if (dtp->u.p.mode == READING)
- switch (type)
- {
- case BT_INTEGER:
- read_decimal (dtp, f, p, kind);
- break;
- case BT_LOGICAL:
- read_l (dtp, f, p, kind);
- break;
- case BT_CHARACTER:
- if (kind == 4)
- read_a_char4 (dtp, f, p, size);
- else
- read_a (dtp, f, p, size);
- break;
- case BT_REAL:
- read_f (dtp, f, p, kind);
- break;
- default:
- goto bad_type;
- }
- else
- switch (type)
- {
+ switch (type)
+ {
case BT_INTEGER:
write_i (dtp, f, p, kind);
break;
write_d (dtp, f, p, kind);
break;
default:
- bad_type:
internal_error (&dtp->common,
"formatted_transfer(): Bad type");
- }
-
+ }
break;
case FMT_STRING:
consume_data_flag = 0;
- if (dtp->u.p.mode == READING)
- {
- format_error (dtp, f, "Constant string in input format");
- return;
- }
write_constant_string (dtp, f);
break;
that trailing blanks are suppressed, unless we are doing a
non-advancing write in which case we want to output the blanks
now. */
- if (dtp->u.p.mode == WRITING
- && dtp->u.p.advance_status == ADVANCE_NO)
+ if (dtp->u.p.advance_status == ADVANCE_NO)
{
write_x (dtp, dtp->u.p.skips, dtp->u.p.pending_spaces);
dtp->u.p.skips = dtp->u.p.pending_spaces = 0;
}
-
- if (dtp->u.p.mode == READING)
- read_x (dtp, f->u.n);
-
break;
case FMT_TL:
pos = bytes_used - f->u.n;
}
else /* FMT_T */
- {
- if (dtp->u.p.mode == READING)
- pos = f->u.n - 1;
- else
- pos = f->u.n - dtp->u.p.pending_spaces - 1;
- }
+ pos = f->u.n - dtp->u.p.pending_spaces - 1;
/* Standard 10.6.1.1: excessive left tabbing is reset to the
left tab limit. We do not check if the position has gone
+ pos - dtp->u.p.max_pos;
dtp->u.p.pending_spaces = dtp->u.p.pending_spaces < 0
? 0 : dtp->u.p.pending_spaces;
-
- if (dtp->u.p.skips == 0)
- break;
-
- /* Writes occur just before the switch on f->format, above, so that
- trailing blanks are suppressed. */
- if (dtp->u.p.mode == READING)
- {
- /* Adjust everything for end-of-record condition */
- if (dtp->u.p.sf_seen_eor && !is_internal_unit (dtp))
- {
- dtp->u.p.current_unit->bytes_left -= dtp->u.p.sf_seen_eor;
- dtp->u.p.skips -= dtp->u.p.sf_seen_eor;
- bytes_used = pos;
- dtp->u.p.sf_seen_eor = 0;
- }
- if (dtp->u.p.skips < 0)
- {
- if (is_internal_unit (dtp))
- move_pos_offset (dtp->u.p.current_unit->s, dtp->u.p.skips);
- else
- fbuf_seek (dtp->u.p.current_unit, dtp->u.p.skips, SEEK_CUR);
- dtp->u.p.current_unit->bytes_left
- -= (gfc_offset) dtp->u.p.skips;
- dtp->u.p.skips = dtp->u.p.pending_spaces = 0;
- }
- else
- read_x (dtp, dtp->u.p.skips);
- }
-
break;
case FMT_S:
dtp->u.p.current_unit->decimal_status = DECIMAL_POINT;
break;
+ case FMT_RC:
+ consume_data_flag = 0;
+ dtp->u.p.current_unit->round_status = ROUND_COMPATIBLE;
+ break;
+
+ case FMT_RD:
+ consume_data_flag = 0;
+ dtp->u.p.current_unit->round_status = ROUND_DOWN;
+ break;
+
+ case FMT_RN:
+ consume_data_flag = 0;
+ dtp->u.p.current_unit->round_status = ROUND_NEAREST;
+ break;
+
+ case FMT_RP:
+ consume_data_flag = 0;
+ dtp->u.p.current_unit->round_status = ROUND_PROCDEFINED;
+ break;
+
+ case FMT_RU:
+ consume_data_flag = 0;
+ dtp->u.p.current_unit->round_status = ROUND_UP;
+ break;
+
+ case FMT_RZ:
+ consume_data_flag = 0;
+ dtp->u.p.current_unit->round_status = ROUND_ZERO;
+ break;
+
case FMT_P:
consume_data_flag = 0;
dtp->u.p.scale_factor = f->u.k;
/* Adjust the item count and data pointer. */
if ((consume_data_flag > 0) && (n > 0))
- {
- n--;
- p = ((char *) p) + size;
- }
-
- if (dtp->u.p.mode == READING)
- dtp->u.p.skips = 0;
+ {
+ n--;
+ p = ((char *) p) + size;
+ }
pos = (int)(dtp->u.p.current_unit->recl - dtp->u.p.current_unit->bytes_left);
dtp->u.p.max_pos = (dtp->u.p.max_pos > pos) ? dtp->u.p.max_pos : pos;
-
}
return;
unget_format (dtp, f);
}
+ /* This function is first called from data_init_transfer to initiate the loop
+ over each item in the format, transferring data as required. Subsequent
+ calls to this function occur for each data item foound in the READ/WRITE
+ statement. The item_count is incremented for each call. Since the first
+ call is from data_transfer_init, the item_count is always one greater than
+ the actual count number of the item being transferred. */
+
static void
formatted_transfer (st_parameter_dt *dtp, bt type, void *p, int kind,
size_t size, size_t nelems)
tmp = (char *) p;
size_t stride = type == BT_CHARACTER ?
size * GFC_SIZE_OF_CHAR_KIND(kind) : size;
- /* Big loop over all the elements. */
- for (elem = 0; elem < nelems; elem++)
+ if (dtp->u.p.mode == READING)
+ {
+ /* Big loop over all the elements. */
+ for (elem = 0; elem < nelems; elem++)
+ {
+ dtp->u.p.item_count++;
+ formatted_transfer_scalar_read (dtp, type, tmp + stride*elem, kind, size);
+ }
+ }
+ else
{
- dtp->u.p.item_count++;
- formatted_transfer_scalar (dtp, type, tmp + stride*elem, kind, size);
+ /* Big loop over all the elements. */
+ for (elem = 0; elem < nelems; elem++)
+ {
+ dtp->u.p.item_count++;
+ formatted_transfer_scalar_write (dtp, type, tmp + stride*elem, kind, size);
+ }
}
}
-
/* Data transfer entry points. The type of the data entity is
implicit in the subroutine call. This prevents us from having to
share a common enum with the compiler. */
for (n = 0; n < rank; n++)
{
count[n] = 0;
- stride[n] = iotype == BT_CHARACTER ?
- desc->dim[n].stride * GFC_SIZE_OF_CHAR_KIND(kind) :
- desc->dim[n].stride;
- extent[n] = desc->dim[n].ubound + 1 - desc->dim[n].lbound;
+ stride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(desc,n);
+ extent[n] = GFC_DESCRIPTOR_EXTENT(desc,n);
/* If the extent of even one dimension is zero, then the entire
array section contains zero elements, so we return after writing
stride0 = stride[0];
- /* If the innermost dimension has stride 1, we can do the transfer
+ /* If the innermost dimension has a stride of 1, we can do the transfer
in contiguous chunks. */
- if (stride0 == 1)
+ if (stride0 == size)
tsize = extent[0];
else
tsize = 1;
while (data)
{
dtp->u.p.transfer (dtp, iotype, data, kind, size, tsize);
- data += stride0 * size * tsize;
+ data += stride0 * tsize;
count[0] += tsize;
n = 0;
while (count[n] == extent[n])
{
count[n] = 0;
- data -= stride[n] * extent[n] * size;
+ data -= stride[n] * extent[n];
n++;
if (n == rank)
{
else
{
count[n]++;
- data += stride[n] * size;
+ data += stride[n];
}
}
}
close_unit (dtp->u.p.current_unit);
dtp->u.p.current_unit = NULL;
generate_error (&dtp->common, LIBERROR_BAD_OPTION,
- "Bad unit number in OPEN statement");
+ "Bad unit number in statement");
return;
}
memset (&u_flags, '\0', sizeof (u_flags));
return;
}
- if (dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL
- && (cf & IOPARM_DT_HAS_REC) != 0)
+ if (dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL)
{
- generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
- "Record number not allowed for sequential access "
- "data transfer");
- return;
- }
+ if ((cf & IOPARM_DT_HAS_REC) != 0)
+ {
+ generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
+ "Record number not allowed for sequential access "
+ "data transfer");
+ return;
+ }
+
+ if (dtp->u.p.current_unit->endfile == AFTER_ENDFILE)
+ {
+ generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
+ "Sequential READ or WRITE not allowed after "
+ "EOF marker, possibly use REWIND or BACKSPACE");
+ return;
+ }
+ }
/* Process the ADVANCE option. */
dtp->u.p.advance_status
if (dtp->u.p.current_unit->decimal_status == DECIMAL_UNSPECIFIED)
dtp->u.p.current_unit->decimal_status = dtp->u.p.current_unit->flags.decimal;
+ /* Check the round mode. */
+ dtp->u.p.current_unit->round_status
+ = !(cf & IOPARM_DT_HAS_ROUND) ? ROUND_UNSPECIFIED :
+ find_option (&dtp->common, dtp->round, dtp->round_len,
+ round_opt, "Bad ROUND parameter in data transfer "
+ "statement");
+
+ if (dtp->u.p.current_unit->round_status == ROUND_UNSPECIFIED)
+ dtp->u.p.current_unit->round_status = dtp->u.p.current_unit->flags.round;
+
/* Check the sign mode. */
dtp->u.p.sign_status
= !(cf & IOPARM_DT_HAS_SIGN) ? SIGN_UNSPECIFIED :
if (dtp->pos != dtp->u.p.current_unit->strm_pos)
{
fbuf_flush (dtp->u.p.current_unit, dtp->u.p.mode);
- sflush (dtp->u.p.current_unit->s);
if (sseek (dtp->u.p.current_unit->s, dtp->pos - 1, SEEK_SET) < 0)
{
generate_error (&dtp->common, LIBERROR_OS, NULL);
for (i=0; i<rank; i++)
{
- ls[i].idx = desc->dim[i].lbound;
- ls[i].start = desc->dim[i].lbound;
- ls[i].end = desc->dim[i].ubound;
- ls[i].step = desc->dim[i].stride;
- empty = empty || (desc->dim[i].ubound < desc->dim[i].lbound);
+ ls[i].idx = GFC_DESCRIPTOR_LBOUND(desc,i);
+ ls[i].start = GFC_DESCRIPTOR_LBOUND(desc,i);
+ ls[i].end = GFC_DESCRIPTOR_UBOUND(desc,i);
+ ls[i].step = GFC_DESCRIPTOR_STRIDE(desc,i);
+ empty = empty || (GFC_DESCRIPTOR_UBOUND(desc,i)
+ < GFC_DESCRIPTOR_LBOUND(desc,i));
- if (desc->dim[i].stride > 0)
+ if (GFC_DESCRIPTOR_STRIDE(desc,i) > 0)
{
- index += (desc->dim[i].ubound - desc->dim[i].lbound)
- * desc->dim[i].stride;
+ index += (GFC_DESCRIPTOR_EXTENT(desc,i) - 1)
+ * GFC_DESCRIPTOR_STRIDE(desc,i);
}
else
{
- index -= (desc->dim[i].ubound - desc->dim[i].lbound)
- * desc->dim[i].stride;
- *start_record -= (desc->dim[i].ubound - desc->dim[i].lbound)
- * desc->dim[i].stride;
+ index -= (GFC_DESCRIPTOR_EXTENT(desc,i) - 1)
+ * GFC_DESCRIPTOR_STRIDE(desc,i);
+ *start_record -= (GFC_DESCRIPTOR_EXTENT(desc,i) - 1)
+ * GFC_DESCRIPTOR_STRIDE(desc,i);
}
}
position. */
static void
-skip_record (st_parameter_dt *dtp, size_t bytes)
+skip_record (st_parameter_dt *dtp, ssize_t bytes)
{
- size_t rlength;
- ssize_t readb;
- static const size_t MAX_READ = 4096;
+ ssize_t rlength, readb;
+ static const ssize_t MAX_READ = 4096;
char p[MAX_READ];
dtp->u.p.current_unit->bytes_left_subrecord += bytes;
if (sseek (dtp->u.p.current_unit->s,
dtp->u.p.current_unit->bytes_left_subrecord, SEEK_CUR) < 0)
generate_error (&dtp->common, LIBERROR_OS, NULL);
+
+ dtp->u.p.current_unit->bytes_left_subrecord = 0;
}
else
{ /* Seek by reading data. */
while (dtp->u.p.current_unit->bytes_left_subrecord > 0)
{
rlength =
- (MAX_READ < (size_t) dtp->u.p.current_unit->bytes_left_subrecord) ?
- MAX_READ : (size_t) dtp->u.p.current_unit->bytes_left_subrecord;
+ (MAX_READ < dtp->u.p.current_unit->bytes_left_subrecord) ?
+ MAX_READ : dtp->u.p.current_unit->bytes_left_subrecord;
readb = sread (dtp->u.p.current_unit->s, p, rlength);
if (readb < 0)
/* Space to the next record for read mode. */
static void
-next_record_r (st_parameter_dt *dtp)
+next_record_r (st_parameter_dt *dtp, int done)
{
gfc_offset record;
int bytes_left;
case FORMATTED_DIRECT:
case UNFORMATTED_DIRECT:
- skip_record (dtp, 0);
+ skip_record (dtp, dtp->u.p.current_unit->bytes_left);
break;
case FORMATTED_STREAM:
case FORMATTED_SEQUENTIAL:
/* read_sf has already terminated input because of an '\n', or
we have hit EOF. */
- if (dtp->u.p.sf_seen_eor || dtp->u.p.at_eof)
+ if (dtp->u.p.sf_seen_eor)
{
dtp->u.p.sf_seen_eor = 0;
- dtp->u.p.at_eof = 0;
break;
}
record = next_array_record (dtp, dtp->u.p.current_unit->ls,
&finished);
+ if (!done && finished)
+ hit_eof (dtp);
/* Now seek to this record. */
record = record * dtp->u.p.current_unit->recl;
{
if (errno != 0)
generate_error (&dtp->common, LIBERROR_OS, NULL);
- else
- hit_eof (dtp);
+ else
+ {
+ if (is_stream_io (dtp)
+ || dtp->u.p.current_unit->pad_status == PAD_NO
+ || dtp->u.p.current_unit->bytes_left
+ == dtp->u.p.current_unit->recl)
+ hit_eof (dtp);
+ }
break;
}
static void
next_record_w_unf (st_parameter_dt *dtp, int next_subrecord)
{
- gfc_offset c, m, m_write;
- size_t record_marker;
+ gfc_offset m, m_write, record_marker;
/* Bytes written. */
m = dtp->u.p.current_unit->recl_subrecord
- dtp->u.p.current_unit->bytes_left_subrecord;
- c = stell (dtp->u.p.current_unit->s);
/* Write the length tail. If we finish a record containing
subrecords, we write out the negative length. */
/* Seek to the head and overwrite the bogus length with the real
length. */
- if (unlikely (sseek (dtp->u.p.current_unit->s, c - m - record_marker,
- SEEK_SET) < 0))
+ if (unlikely (sseek (dtp->u.p.current_unit->s, - m - 2 * record_marker,
+ SEEK_CUR) < 0))
goto io_error;
if (next_subrecord)
/* Seek past the end of the current record. */
- if (unlikely (sseek (dtp->u.p.current_unit->s, c + record_marker,
- SEEK_SET) < 0))
+ if (unlikely (sseek (dtp->u.p.current_unit->s, m + record_marker,
+ SEEK_CUR) < 0))
goto io_error;
return;
{
trans = (bytes_left < WRITE_CHUNK) ? bytes_left : WRITE_CHUNK;
trans = swrite (s, p, trans);
- if (trans < 0)
+ if (trans <= 0)
return trans;
bytes_left -= trans;
}
dtp->u.p.current_unit->read_bad = 0;
if (dtp->u.p.mode == READING)
- next_record_r (dtp);
+ next_record_r (dtp, done);
else
next_record_w (dtp, done);
}
if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
- return;
+ {
+ if (dtp->u.p.current_unit && current_mode (dtp) == UNFORMATTED_SEQUENTIAL)
+ dtp->u.p.current_unit->current_record = 0;
+ return;
+ }
if ((dtp->u.p.ionml != NULL)
&& (cf & IOPARM_DT_HAS_NAMELIST_NAME) != 0)
&& dtp->u.p.advance_status != ADVANCE_NO)
next_record (dtp, 1);
- if (dtp->u.p.current_unit->flags.form == FORM_UNFORMATTED
- && stell (dtp->u.p.current_unit->s) >= dtp->rec)
- {
- sflush (dtp->u.p.current_unit->s);
- }
return;
}
dtp->u.p.current_unit->saved_pos =
dtp->u.p.max_pos > 0 ? dtp->u.p.max_pos - bytes_written : 0;
fbuf_flush (dtp->u.p.current_unit, dtp->u.p.mode);
- sflush (dtp->u.p.current_unit->s);
return;
}
else if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED
size_t size, size_t nelems)
{
if ((dtp->common.flags & IOPARM_DT_HAS_IOLENGTH) != 0)
- *dtp->iolength += (GFC_IO_INT) size * nelems;
+ *dtp->iolength += (GFC_IO_INT) (size * nelems);
}
st_read_done (st_parameter_dt *dtp)
{
finalize_transfer (dtp);
- free_format_data (dtp);
+ if (is_internal_unit (dtp) || dtp->u.p.format_not_saved)
+ free_format_data (dtp->u.p.fmt);
free_ionml (dtp);
if (dtp->u.p.current_unit != NULL)
unlock_unit (dtp->u.p.current_unit);
break;
}
- free_format_data (dtp);
+ if (is_internal_unit (dtp) || dtp->u.p.format_not_saved)
+ free_format_data (dtp->u.p.fmt);
free_ionml (dtp);
if (dtp->u.p.current_unit != NULL)
unlock_unit (dtp->u.p.current_unit);
for (nml = dtp->u.p.ionml; nml->next; nml = nml->next);
- nml->dim[n].stride = stride;
- nml->dim[n].lbound = lbound;
- nml->dim[n].ubound = ubound;
+ GFC_DIMENSION_SET(nml->dim[n],lbound,ubound,stride);
}
/* Reverse memcpy - used for byte swapping. */