1*4c3eb207Smrg /* Copyright (C) 2002-2020 Free Software Foundation, Inc.
2627f7eb2Smrg Contributed by Andy Vaught
3627f7eb2Smrg Namelist transfer functions contributed by Paul Thomas
4627f7eb2Smrg F2003 I/O support contributed by Jerry DeLisle
5627f7eb2Smrg
6627f7eb2Smrg This file is part of the GNU Fortran runtime library (libgfortran).
7627f7eb2Smrg
8627f7eb2Smrg Libgfortran is free software; you can redistribute it and/or modify
9627f7eb2Smrg it under the terms of the GNU General Public License as published by
10627f7eb2Smrg the Free Software Foundation; either version 3, or (at your option)
11627f7eb2Smrg any later version.
12627f7eb2Smrg
13627f7eb2Smrg Libgfortran is distributed in the hope that it will be useful,
14627f7eb2Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
15627f7eb2Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16627f7eb2Smrg GNU General Public License for more details.
17627f7eb2Smrg
18627f7eb2Smrg Under Section 7 of GPL version 3, you are granted additional
19627f7eb2Smrg permissions described in the GCC Runtime Library Exception, version
20627f7eb2Smrg 3.1, as published by the Free Software Foundation.
21627f7eb2Smrg
22627f7eb2Smrg You should have received a copy of the GNU General Public License and
23627f7eb2Smrg a copy of the GCC Runtime Library Exception along with this program;
24627f7eb2Smrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25627f7eb2Smrg <http://www.gnu.org/licenses/>. */
26627f7eb2Smrg
27627f7eb2Smrg
28627f7eb2Smrg /* transfer.c -- Top level handling of data transfer statements. */
29627f7eb2Smrg
30627f7eb2Smrg #include "io.h"
31627f7eb2Smrg #include "fbuf.h"
32627f7eb2Smrg #include "format.h"
33627f7eb2Smrg #include "unix.h"
34627f7eb2Smrg #include "async.h"
35627f7eb2Smrg #include <string.h>
36627f7eb2Smrg #include <errno.h>
37627f7eb2Smrg
38627f7eb2Smrg
39627f7eb2Smrg /* Calling conventions: Data transfer statements are unlike other
40627f7eb2Smrg library calls in that they extend over several calls.
41627f7eb2Smrg
42627f7eb2Smrg The first call is always a call to st_read() or st_write(). These
43627f7eb2Smrg subroutines return no status unless a namelist read or write is
44627f7eb2Smrg being done, in which case there is the usual status. No further
45627f7eb2Smrg calls are necessary in this case.
46627f7eb2Smrg
47627f7eb2Smrg For other sorts of data transfer, there are zero or more data
48627f7eb2Smrg transfer statement that depend on the format of the data transfer
49627f7eb2Smrg statement. For READ (and for backwards compatibily: for WRITE), one has
50627f7eb2Smrg
51627f7eb2Smrg transfer_integer
52627f7eb2Smrg transfer_logical
53627f7eb2Smrg transfer_character
54627f7eb2Smrg transfer_character_wide
55627f7eb2Smrg transfer_real
56627f7eb2Smrg transfer_complex
57627f7eb2Smrg transfer_real128
58627f7eb2Smrg transfer_complex128
59627f7eb2Smrg
60627f7eb2Smrg and for WRITE
61627f7eb2Smrg
62627f7eb2Smrg transfer_integer_write
63627f7eb2Smrg transfer_logical_write
64627f7eb2Smrg transfer_character_write
65627f7eb2Smrg transfer_character_wide_write
66627f7eb2Smrg transfer_real_write
67627f7eb2Smrg transfer_complex_write
68627f7eb2Smrg transfer_real128_write
69627f7eb2Smrg transfer_complex128_write
70627f7eb2Smrg
71627f7eb2Smrg These subroutines do not return status. The *128 functions
72627f7eb2Smrg are in the file transfer128.c.
73627f7eb2Smrg
74627f7eb2Smrg The last call is a call to st_[read|write]_done(). While
75627f7eb2Smrg something can easily go wrong with the initial st_read() or
76627f7eb2Smrg st_write(), an error inhibits any data from actually being
77627f7eb2Smrg transferred. */
78627f7eb2Smrg
79627f7eb2Smrg extern void transfer_integer (st_parameter_dt *, void *, int);
80627f7eb2Smrg export_proto(transfer_integer);
81627f7eb2Smrg
82627f7eb2Smrg extern void transfer_integer_write (st_parameter_dt *, void *, int);
83627f7eb2Smrg export_proto(transfer_integer_write);
84627f7eb2Smrg
85627f7eb2Smrg extern void transfer_real (st_parameter_dt *, void *, int);
86627f7eb2Smrg export_proto(transfer_real);
87627f7eb2Smrg
88627f7eb2Smrg extern void transfer_real_write (st_parameter_dt *, void *, int);
89627f7eb2Smrg export_proto(transfer_real_write);
90627f7eb2Smrg
91627f7eb2Smrg extern void transfer_logical (st_parameter_dt *, void *, int);
92627f7eb2Smrg export_proto(transfer_logical);
93627f7eb2Smrg
94627f7eb2Smrg extern void transfer_logical_write (st_parameter_dt *, void *, int);
95627f7eb2Smrg export_proto(transfer_logical_write);
96627f7eb2Smrg
97627f7eb2Smrg extern void transfer_character (st_parameter_dt *, void *, gfc_charlen_type);
98627f7eb2Smrg export_proto(transfer_character);
99627f7eb2Smrg
100627f7eb2Smrg extern void transfer_character_write (st_parameter_dt *, void *, gfc_charlen_type);
101627f7eb2Smrg export_proto(transfer_character_write);
102627f7eb2Smrg
103627f7eb2Smrg extern void transfer_character_wide (st_parameter_dt *, void *, gfc_charlen_type, int);
104627f7eb2Smrg export_proto(transfer_character_wide);
105627f7eb2Smrg
106627f7eb2Smrg extern void transfer_character_wide_write (st_parameter_dt *,
107627f7eb2Smrg void *, gfc_charlen_type, int);
108627f7eb2Smrg export_proto(transfer_character_wide_write);
109627f7eb2Smrg
110627f7eb2Smrg extern void transfer_complex (st_parameter_dt *, void *, int);
111627f7eb2Smrg export_proto(transfer_complex);
112627f7eb2Smrg
113627f7eb2Smrg extern void transfer_complex_write (st_parameter_dt *, void *, int);
114627f7eb2Smrg export_proto(transfer_complex_write);
115627f7eb2Smrg
116627f7eb2Smrg extern void transfer_array (st_parameter_dt *, gfc_array_char *, int,
117627f7eb2Smrg gfc_charlen_type);
118627f7eb2Smrg export_proto(transfer_array);
119627f7eb2Smrg
120627f7eb2Smrg extern void transfer_array_write (st_parameter_dt *, gfc_array_char *, int,
121627f7eb2Smrg gfc_charlen_type);
122627f7eb2Smrg export_proto(transfer_array_write);
123627f7eb2Smrg
124627f7eb2Smrg /* User defined derived type input/output. */
125627f7eb2Smrg extern void
126627f7eb2Smrg transfer_derived (st_parameter_dt *dtp, void *dtio_source, void *dtio_proc);
127627f7eb2Smrg export_proto(transfer_derived);
128627f7eb2Smrg
129627f7eb2Smrg extern void
130627f7eb2Smrg transfer_derived_write (st_parameter_dt *dtp, void *dtio_source, void *dtio_proc);
131627f7eb2Smrg export_proto(transfer_derived_write);
132627f7eb2Smrg
133627f7eb2Smrg static void us_read (st_parameter_dt *, int);
134627f7eb2Smrg static void us_write (st_parameter_dt *, int);
135627f7eb2Smrg static void next_record_r_unf (st_parameter_dt *, int);
136627f7eb2Smrg static void next_record_w_unf (st_parameter_dt *, int);
137627f7eb2Smrg
138627f7eb2Smrg static const st_option advance_opt[] = {
139627f7eb2Smrg {"yes", ADVANCE_YES},
140627f7eb2Smrg {"no", ADVANCE_NO},
141627f7eb2Smrg {NULL, 0}
142627f7eb2Smrg };
143627f7eb2Smrg
144627f7eb2Smrg
145627f7eb2Smrg static const st_option decimal_opt[] = {
146627f7eb2Smrg {"point", DECIMAL_POINT},
147627f7eb2Smrg {"comma", DECIMAL_COMMA},
148627f7eb2Smrg {NULL, 0}
149627f7eb2Smrg };
150627f7eb2Smrg
151627f7eb2Smrg static const st_option round_opt[] = {
152627f7eb2Smrg {"up", ROUND_UP},
153627f7eb2Smrg {"down", ROUND_DOWN},
154627f7eb2Smrg {"zero", ROUND_ZERO},
155627f7eb2Smrg {"nearest", ROUND_NEAREST},
156627f7eb2Smrg {"compatible", ROUND_COMPATIBLE},
157627f7eb2Smrg {"processor_defined", ROUND_PROCDEFINED},
158627f7eb2Smrg {NULL, 0}
159627f7eb2Smrg };
160627f7eb2Smrg
161627f7eb2Smrg
162627f7eb2Smrg static const st_option sign_opt[] = {
163627f7eb2Smrg {"plus", SIGN_SP},
164627f7eb2Smrg {"suppress", SIGN_SS},
165627f7eb2Smrg {"processor_defined", SIGN_S},
166627f7eb2Smrg {NULL, 0}
167627f7eb2Smrg };
168627f7eb2Smrg
169627f7eb2Smrg static const st_option blank_opt[] = {
170627f7eb2Smrg {"null", BLANK_NULL},
171627f7eb2Smrg {"zero", BLANK_ZERO},
172627f7eb2Smrg {NULL, 0}
173627f7eb2Smrg };
174627f7eb2Smrg
175627f7eb2Smrg static const st_option delim_opt[] = {
176627f7eb2Smrg {"apostrophe", DELIM_APOSTROPHE},
177627f7eb2Smrg {"quote", DELIM_QUOTE},
178627f7eb2Smrg {"none", DELIM_NONE},
179627f7eb2Smrg {NULL, 0}
180627f7eb2Smrg };
181627f7eb2Smrg
182627f7eb2Smrg static const st_option pad_opt[] = {
183627f7eb2Smrg {"yes", PAD_YES},
184627f7eb2Smrg {"no", PAD_NO},
185627f7eb2Smrg {NULL, 0}
186627f7eb2Smrg };
187627f7eb2Smrg
188627f7eb2Smrg static const st_option async_opt[] = {
189627f7eb2Smrg {"yes", ASYNC_YES},
190627f7eb2Smrg {"no", ASYNC_NO},
191627f7eb2Smrg {NULL, 0}
192627f7eb2Smrg };
193627f7eb2Smrg
194627f7eb2Smrg typedef enum
195627f7eb2Smrg { FORMATTED_SEQUENTIAL, UNFORMATTED_SEQUENTIAL,
196*4c3eb207Smrg FORMATTED_DIRECT, UNFORMATTED_DIRECT, FORMATTED_STREAM,
197*4c3eb207Smrg UNFORMATTED_STREAM, FORMATTED_UNSPECIFIED
198627f7eb2Smrg }
199627f7eb2Smrg file_mode;
200627f7eb2Smrg
201627f7eb2Smrg
202627f7eb2Smrg static file_mode
current_mode(st_parameter_dt * dtp)203627f7eb2Smrg current_mode (st_parameter_dt *dtp)
204627f7eb2Smrg {
205627f7eb2Smrg file_mode m;
206627f7eb2Smrg
207*4c3eb207Smrg m = FORMATTED_UNSPECIFIED;
208627f7eb2Smrg
209627f7eb2Smrg if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT)
210627f7eb2Smrg {
211627f7eb2Smrg m = dtp->u.p.current_unit->flags.form == FORM_FORMATTED ?
212627f7eb2Smrg FORMATTED_DIRECT : UNFORMATTED_DIRECT;
213627f7eb2Smrg }
214627f7eb2Smrg else if (dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL)
215627f7eb2Smrg {
216627f7eb2Smrg m = dtp->u.p.current_unit->flags.form == FORM_FORMATTED ?
217627f7eb2Smrg FORMATTED_SEQUENTIAL : UNFORMATTED_SEQUENTIAL;
218627f7eb2Smrg }
219627f7eb2Smrg else if (dtp->u.p.current_unit->flags.access == ACCESS_STREAM)
220627f7eb2Smrg {
221627f7eb2Smrg m = dtp->u.p.current_unit->flags.form == FORM_FORMATTED ?
222627f7eb2Smrg FORMATTED_STREAM : UNFORMATTED_STREAM;
223627f7eb2Smrg }
224627f7eb2Smrg
225627f7eb2Smrg return m;
226627f7eb2Smrg }
227627f7eb2Smrg
228627f7eb2Smrg
229627f7eb2Smrg /* Mid level data transfer statements. */
230627f7eb2Smrg
231627f7eb2Smrg /* Read sequential file - internal unit */
232627f7eb2Smrg
233627f7eb2Smrg static char *
read_sf_internal(st_parameter_dt * dtp,size_t * length)234627f7eb2Smrg read_sf_internal (st_parameter_dt *dtp, size_t *length)
235627f7eb2Smrg {
236627f7eb2Smrg static char *empty_string[0];
237627f7eb2Smrg char *base = NULL;
238627f7eb2Smrg size_t lorig;
239627f7eb2Smrg
240627f7eb2Smrg /* Zero size array gives internal unit len of 0. Nothing to read. */
241627f7eb2Smrg if (dtp->internal_unit_len == 0
242627f7eb2Smrg && dtp->u.p.current_unit->pad_status == PAD_NO)
243627f7eb2Smrg hit_eof (dtp);
244627f7eb2Smrg
245627f7eb2Smrg /* There are some cases with mixed DTIO where we have read a character
246627f7eb2Smrg and saved it in the last character buffer, so we need to backup. */
247627f7eb2Smrg if (unlikely (dtp->u.p.current_unit->child_dtio > 0 &&
248627f7eb2Smrg dtp->u.p.current_unit->last_char != EOF - 1))
249627f7eb2Smrg {
250627f7eb2Smrg dtp->u.p.current_unit->last_char = EOF - 1;
251627f7eb2Smrg sseek (dtp->u.p.current_unit->s, -1, SEEK_CUR);
252627f7eb2Smrg }
253627f7eb2Smrg
254627f7eb2Smrg /* To support legacy code we have to scan the input string one byte
255627f7eb2Smrg at a time because we don't know where an early comma may be and the
256627f7eb2Smrg requested length could go past the end of a comma shortened
257627f7eb2Smrg string. We only do this if -std=legacy was given at compile
258627f7eb2Smrg time. We also do not support this on kind=4 strings. */
259627f7eb2Smrg if (unlikely(compile_options.warn_std == 0)) // the slow legacy way.
260627f7eb2Smrg {
261627f7eb2Smrg size_t n;
262627f7eb2Smrg size_t tmp = 1;
263627f7eb2Smrg char *q;
264627f7eb2Smrg
265627f7eb2Smrg /* If we have seen an eor previously, return a length of 0. The
266627f7eb2Smrg caller is responsible for correctly padding the input field. */
267627f7eb2Smrg if (dtp->u.p.sf_seen_eor)
268627f7eb2Smrg {
269627f7eb2Smrg *length = 0;
270627f7eb2Smrg /* Just return something that isn't a NULL pointer, otherwise the
271627f7eb2Smrg caller thinks an error occurred. */
272627f7eb2Smrg return (char*) empty_string;
273627f7eb2Smrg }
274627f7eb2Smrg
275627f7eb2Smrg /* Get the first character of the string to establish the base
276627f7eb2Smrg address and check for comma or end-of-record condition. */
277627f7eb2Smrg base = mem_alloc_r (dtp->u.p.current_unit->s, &tmp);
278627f7eb2Smrg if (tmp == 0)
279627f7eb2Smrg {
280627f7eb2Smrg dtp->u.p.sf_seen_eor = 1;
281627f7eb2Smrg *length = 0;
282627f7eb2Smrg return (char*) empty_string;
283627f7eb2Smrg }
284627f7eb2Smrg if (*base == ',')
285627f7eb2Smrg {
286627f7eb2Smrg dtp->u.p.current_unit->bytes_left--;
287627f7eb2Smrg *length = 0;
288627f7eb2Smrg return (char*) empty_string;
289627f7eb2Smrg }
290627f7eb2Smrg
291627f7eb2Smrg /* Now we scan the rest and deal with either an end-of-file
292627f7eb2Smrg condition or a comma, as needed. */
293627f7eb2Smrg for (n = 1; n < *length; n++)
294627f7eb2Smrg {
295627f7eb2Smrg q = mem_alloc_r (dtp->u.p.current_unit->s, &tmp);
296627f7eb2Smrg if (tmp == 0)
297627f7eb2Smrg {
298627f7eb2Smrg hit_eof (dtp);
299627f7eb2Smrg return NULL;
300627f7eb2Smrg }
301627f7eb2Smrg if (*q == ',')
302627f7eb2Smrg {
303627f7eb2Smrg dtp->u.p.current_unit->bytes_left -= n;
304627f7eb2Smrg *length = n;
305627f7eb2Smrg break;
306627f7eb2Smrg }
307627f7eb2Smrg }
308627f7eb2Smrg }
309627f7eb2Smrg else // the fast way
310627f7eb2Smrg {
311627f7eb2Smrg lorig = *length;
312627f7eb2Smrg if (is_char4_unit(dtp))
313627f7eb2Smrg {
314627f7eb2Smrg gfc_char4_t *p = (gfc_char4_t *) mem_alloc_r4 (dtp->u.p.current_unit->s,
315627f7eb2Smrg length);
316627f7eb2Smrg base = fbuf_alloc (dtp->u.p.current_unit, lorig);
317627f7eb2Smrg for (size_t i = 0; i < *length; i++, p++)
318627f7eb2Smrg base[i] = *p > 255 ? '?' : (unsigned char) *p;
319627f7eb2Smrg }
320627f7eb2Smrg else
321627f7eb2Smrg base = mem_alloc_r (dtp->u.p.current_unit->s, length);
322627f7eb2Smrg
323627f7eb2Smrg if (unlikely (lorig > *length))
324627f7eb2Smrg {
325627f7eb2Smrg hit_eof (dtp);
326627f7eb2Smrg return NULL;
327627f7eb2Smrg }
328627f7eb2Smrg }
329627f7eb2Smrg
330627f7eb2Smrg dtp->u.p.current_unit->bytes_left -= *length;
331627f7eb2Smrg
332627f7eb2Smrg if (((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0) ||
333627f7eb2Smrg dtp->u.p.current_unit->has_size)
334627f7eb2Smrg dtp->u.p.current_unit->size_used += (GFC_IO_INT) *length;
335627f7eb2Smrg
336627f7eb2Smrg return base;
337627f7eb2Smrg
338627f7eb2Smrg }
339627f7eb2Smrg
340627f7eb2Smrg /* When reading sequential formatted records we have a problem. We
341627f7eb2Smrg don't know how long the line is until we read the trailing newline,
342627f7eb2Smrg and we don't want to read too much. If we read too much, we might
343627f7eb2Smrg have to do a physical seek backwards depending on how much data is
344627f7eb2Smrg present, and devices like terminals aren't seekable and would cause
345627f7eb2Smrg an I/O error.
346627f7eb2Smrg
347627f7eb2Smrg Given this, the solution is to read a byte at a time, stopping if
348627f7eb2Smrg we hit the newline. For small allocations, we use a static buffer.
349627f7eb2Smrg For larger allocations, we are forced to allocate memory on the
350627f7eb2Smrg heap. Hopefully this won't happen very often. */
351627f7eb2Smrg
352627f7eb2Smrg /* Read sequential file - external unit */
353627f7eb2Smrg
354627f7eb2Smrg static char *
read_sf(st_parameter_dt * dtp,size_t * length)355627f7eb2Smrg read_sf (st_parameter_dt *dtp, size_t *length)
356627f7eb2Smrg {
357627f7eb2Smrg static char *empty_string[0];
358627f7eb2Smrg size_t lorig, n;
359627f7eb2Smrg int q, q2;
360627f7eb2Smrg int seen_comma;
361627f7eb2Smrg
362627f7eb2Smrg /* If we have seen an eor previously, return a length of 0. The
363627f7eb2Smrg caller is responsible for correctly padding the input field. */
364627f7eb2Smrg if (dtp->u.p.sf_seen_eor)
365627f7eb2Smrg {
366627f7eb2Smrg *length = 0;
367627f7eb2Smrg /* Just return something that isn't a NULL pointer, otherwise the
368627f7eb2Smrg caller thinks an error occurred. */
369627f7eb2Smrg return (char*) empty_string;
370627f7eb2Smrg }
371627f7eb2Smrg
372627f7eb2Smrg /* There are some cases with mixed DTIO where we have read a character
373627f7eb2Smrg and saved it in the last character buffer, so we need to backup. */
374627f7eb2Smrg if (unlikely (dtp->u.p.current_unit->child_dtio > 0 &&
375627f7eb2Smrg dtp->u.p.current_unit->last_char != EOF - 1))
376627f7eb2Smrg {
377627f7eb2Smrg dtp->u.p.current_unit->last_char = EOF - 1;
378627f7eb2Smrg fbuf_seek (dtp->u.p.current_unit, -1, SEEK_CUR);
379627f7eb2Smrg }
380627f7eb2Smrg
381627f7eb2Smrg n = seen_comma = 0;
382627f7eb2Smrg
383627f7eb2Smrg /* Read data into format buffer and scan through it. */
384627f7eb2Smrg lorig = *length;
385627f7eb2Smrg
386627f7eb2Smrg while (n < *length)
387627f7eb2Smrg {
388627f7eb2Smrg q = fbuf_getc (dtp->u.p.current_unit);
389627f7eb2Smrg if (q == EOF)
390627f7eb2Smrg break;
391627f7eb2Smrg else if (dtp->u.p.current_unit->flags.cc != CC_NONE
392627f7eb2Smrg && (q == '\n' || q == '\r'))
393627f7eb2Smrg {
394627f7eb2Smrg /* Unexpected end of line. Set the position. */
395627f7eb2Smrg dtp->u.p.sf_seen_eor = 1;
396627f7eb2Smrg
397627f7eb2Smrg /* If we see an EOR during non-advancing I/O, we need to skip
398627f7eb2Smrg the rest of the I/O statement. Set the corresponding flag. */
399627f7eb2Smrg if (dtp->u.p.advance_status == ADVANCE_NO || dtp->u.p.seen_dollar)
400627f7eb2Smrg dtp->u.p.eor_condition = 1;
401627f7eb2Smrg
402627f7eb2Smrg /* If we encounter a CR, it might be a CRLF. */
403627f7eb2Smrg if (q == '\r') /* Probably a CRLF */
404627f7eb2Smrg {
405627f7eb2Smrg /* See if there is an LF. */
406627f7eb2Smrg q2 = fbuf_getc (dtp->u.p.current_unit);
407627f7eb2Smrg if (q2 == '\n')
408627f7eb2Smrg dtp->u.p.sf_seen_eor = 2;
409627f7eb2Smrg else if (q2 != EOF) /* Oops, seek back. */
410627f7eb2Smrg fbuf_seek (dtp->u.p.current_unit, -1, SEEK_CUR);
411627f7eb2Smrg }
412627f7eb2Smrg
413627f7eb2Smrg /* Without padding, terminate the I/O statement without assigning
414627f7eb2Smrg the value. With padding, the value still needs to be assigned,
415627f7eb2Smrg so we can just continue with a short read. */
416627f7eb2Smrg if (dtp->u.p.current_unit->pad_status == PAD_NO)
417627f7eb2Smrg {
418627f7eb2Smrg generate_error (&dtp->common, LIBERROR_EOR, NULL);
419627f7eb2Smrg return NULL;
420627f7eb2Smrg }
421627f7eb2Smrg
422627f7eb2Smrg *length = n;
423627f7eb2Smrg goto done;
424627f7eb2Smrg }
425627f7eb2Smrg /* Short circuit the read if a comma is found during numeric input.
426627f7eb2Smrg The flag is set to zero during character reads so that commas in
427627f7eb2Smrg strings are not ignored */
428627f7eb2Smrg else if (q == ',')
429627f7eb2Smrg if (dtp->u.p.sf_read_comma == 1)
430627f7eb2Smrg {
431627f7eb2Smrg seen_comma = 1;
432627f7eb2Smrg notify_std (&dtp->common, GFC_STD_GNU,
433627f7eb2Smrg "Comma in formatted numeric read.");
434627f7eb2Smrg break;
435627f7eb2Smrg }
436627f7eb2Smrg n++;
437627f7eb2Smrg }
438627f7eb2Smrg
439627f7eb2Smrg *length = n;
440627f7eb2Smrg
441627f7eb2Smrg /* A short read implies we hit EOF, unless we hit EOR, a comma, or
442627f7eb2Smrg some other stuff. Set the relevant flags. */
443627f7eb2Smrg if (lorig > *length && !dtp->u.p.sf_seen_eor && !seen_comma)
444627f7eb2Smrg {
445627f7eb2Smrg if (n > 0)
446627f7eb2Smrg {
447627f7eb2Smrg if (dtp->u.p.advance_status == ADVANCE_NO)
448627f7eb2Smrg {
449627f7eb2Smrg if (dtp->u.p.current_unit->pad_status == PAD_NO)
450627f7eb2Smrg {
451627f7eb2Smrg hit_eof (dtp);
452627f7eb2Smrg return NULL;
453627f7eb2Smrg }
454627f7eb2Smrg else
455627f7eb2Smrg dtp->u.p.eor_condition = 1;
456627f7eb2Smrg }
457627f7eb2Smrg else
458627f7eb2Smrg dtp->u.p.at_eof = 1;
459627f7eb2Smrg }
460627f7eb2Smrg else if (dtp->u.p.advance_status == ADVANCE_NO
461627f7eb2Smrg || dtp->u.p.current_unit->pad_status == PAD_NO
462627f7eb2Smrg || dtp->u.p.current_unit->bytes_left
463627f7eb2Smrg == dtp->u.p.current_unit->recl)
464627f7eb2Smrg {
465627f7eb2Smrg hit_eof (dtp);
466627f7eb2Smrg return NULL;
467627f7eb2Smrg }
468627f7eb2Smrg }
469627f7eb2Smrg
470627f7eb2Smrg done:
471627f7eb2Smrg
472627f7eb2Smrg dtp->u.p.current_unit->bytes_left -= n;
473627f7eb2Smrg
474627f7eb2Smrg if (((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0) ||
475627f7eb2Smrg dtp->u.p.current_unit->has_size)
476627f7eb2Smrg dtp->u.p.current_unit->size_used += (GFC_IO_INT) n;
477627f7eb2Smrg
478627f7eb2Smrg /* We can't call fbuf_getptr before the loop doing fbuf_getc, because
479627f7eb2Smrg fbuf_getc might reallocate the buffer. So return current pointer
480627f7eb2Smrg minus all the advances, which is n plus up to two characters
481627f7eb2Smrg of newline or comma. */
482627f7eb2Smrg return fbuf_getptr (dtp->u.p.current_unit)
483627f7eb2Smrg - n - dtp->u.p.sf_seen_eor - seen_comma;
484627f7eb2Smrg }
485627f7eb2Smrg
486627f7eb2Smrg
487627f7eb2Smrg /* Function for reading the next couple of bytes from the current
488627f7eb2Smrg file, advancing the current position. We return NULL on end of record or
489627f7eb2Smrg end of file. This function is only for formatted I/O, unformatted uses
490627f7eb2Smrg read_block_direct.
491627f7eb2Smrg
492627f7eb2Smrg If the read is short, then it is because the current record does not
493627f7eb2Smrg have enough data to satisfy the read request and the file was
494627f7eb2Smrg opened with PAD=YES. The caller must assume tailing spaces for
495627f7eb2Smrg short reads. */
496627f7eb2Smrg
497627f7eb2Smrg void *
read_block_form(st_parameter_dt * dtp,size_t * nbytes)498627f7eb2Smrg read_block_form (st_parameter_dt *dtp, size_t *nbytes)
499627f7eb2Smrg {
500627f7eb2Smrg char *source;
501627f7eb2Smrg size_t norig;
502627f7eb2Smrg
503627f7eb2Smrg if (!is_stream_io (dtp))
504627f7eb2Smrg {
505627f7eb2Smrg if (dtp->u.p.current_unit->bytes_left < (gfc_offset) *nbytes)
506627f7eb2Smrg {
507627f7eb2Smrg /* For preconnected units with default record length, set bytes left
508627f7eb2Smrg to unit record length and proceed, otherwise error. */
509627f7eb2Smrg if (dtp->u.p.current_unit->unit_number == options.stdin_unit
510627f7eb2Smrg && dtp->u.p.current_unit->recl == default_recl)
511627f7eb2Smrg dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
512627f7eb2Smrg else
513627f7eb2Smrg {
514627f7eb2Smrg if (unlikely (dtp->u.p.current_unit->pad_status == PAD_NO)
515627f7eb2Smrg && !is_internal_unit (dtp))
516627f7eb2Smrg {
517627f7eb2Smrg /* Not enough data left. */
518627f7eb2Smrg generate_error (&dtp->common, LIBERROR_EOR, NULL);
519627f7eb2Smrg return NULL;
520627f7eb2Smrg }
521627f7eb2Smrg }
522627f7eb2Smrg
523627f7eb2Smrg if (is_internal_unit(dtp))
524627f7eb2Smrg {
525627f7eb2Smrg if (*nbytes > 0 && dtp->u.p.current_unit->bytes_left == 0)
526627f7eb2Smrg {
527627f7eb2Smrg if (dtp->u.p.advance_status == ADVANCE_NO)
528627f7eb2Smrg {
529627f7eb2Smrg generate_error (&dtp->common, LIBERROR_EOR, NULL);
530627f7eb2Smrg return NULL;
531627f7eb2Smrg }
532627f7eb2Smrg }
533627f7eb2Smrg }
534627f7eb2Smrg else
535627f7eb2Smrg {
536627f7eb2Smrg if (unlikely (dtp->u.p.current_unit->bytes_left == 0))
537627f7eb2Smrg {
538627f7eb2Smrg hit_eof (dtp);
539627f7eb2Smrg return NULL;
540627f7eb2Smrg }
541627f7eb2Smrg }
542627f7eb2Smrg
543627f7eb2Smrg *nbytes = dtp->u.p.current_unit->bytes_left;
544627f7eb2Smrg }
545627f7eb2Smrg }
546627f7eb2Smrg
547627f7eb2Smrg if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED &&
548627f7eb2Smrg (dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL ||
549627f7eb2Smrg dtp->u.p.current_unit->flags.access == ACCESS_STREAM))
550627f7eb2Smrg {
551627f7eb2Smrg if (is_internal_unit (dtp))
552627f7eb2Smrg source = read_sf_internal (dtp, nbytes);
553627f7eb2Smrg else
554627f7eb2Smrg source = read_sf (dtp, nbytes);
555627f7eb2Smrg
556627f7eb2Smrg dtp->u.p.current_unit->strm_pos +=
557627f7eb2Smrg (gfc_offset) (*nbytes + dtp->u.p.sf_seen_eor);
558627f7eb2Smrg return source;
559627f7eb2Smrg }
560627f7eb2Smrg
561627f7eb2Smrg /* If we reach here, we can assume it's direct access. */
562627f7eb2Smrg
563627f7eb2Smrg dtp->u.p.current_unit->bytes_left -= (gfc_offset) *nbytes;
564627f7eb2Smrg
565627f7eb2Smrg norig = *nbytes;
566627f7eb2Smrg source = fbuf_read (dtp->u.p.current_unit, nbytes);
567627f7eb2Smrg fbuf_seek (dtp->u.p.current_unit, *nbytes, SEEK_CUR);
568627f7eb2Smrg
569627f7eb2Smrg if (((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0) ||
570627f7eb2Smrg dtp->u.p.current_unit->has_size)
571627f7eb2Smrg dtp->u.p.current_unit->size_used += (GFC_IO_INT) *nbytes;
572627f7eb2Smrg
573627f7eb2Smrg if (norig != *nbytes)
574627f7eb2Smrg {
575627f7eb2Smrg /* Short read, this shouldn't happen. */
576627f7eb2Smrg if (dtp->u.p.current_unit->pad_status == PAD_NO)
577627f7eb2Smrg {
578627f7eb2Smrg generate_error (&dtp->common, LIBERROR_EOR, NULL);
579627f7eb2Smrg source = NULL;
580627f7eb2Smrg }
581627f7eb2Smrg }
582627f7eb2Smrg
583627f7eb2Smrg dtp->u.p.current_unit->strm_pos += (gfc_offset) *nbytes;
584627f7eb2Smrg
585627f7eb2Smrg return source;
586627f7eb2Smrg }
587627f7eb2Smrg
588627f7eb2Smrg
589627f7eb2Smrg /* Read a block from a character(kind=4) internal unit, to be transferred into
590627f7eb2Smrg a character(kind=4) variable. Note: Portions of this code borrowed from
591627f7eb2Smrg read_sf_internal. */
592627f7eb2Smrg void *
read_block_form4(st_parameter_dt * dtp,size_t * nbytes)593627f7eb2Smrg read_block_form4 (st_parameter_dt *dtp, size_t *nbytes)
594627f7eb2Smrg {
595627f7eb2Smrg static gfc_char4_t *empty_string[0];
596627f7eb2Smrg gfc_char4_t *source;
597627f7eb2Smrg size_t lorig;
598627f7eb2Smrg
599627f7eb2Smrg if (dtp->u.p.current_unit->bytes_left < (gfc_offset) *nbytes)
600627f7eb2Smrg *nbytes = dtp->u.p.current_unit->bytes_left;
601627f7eb2Smrg
602627f7eb2Smrg /* Zero size array gives internal unit len of 0. Nothing to read. */
603627f7eb2Smrg if (dtp->internal_unit_len == 0
604627f7eb2Smrg && dtp->u.p.current_unit->pad_status == PAD_NO)
605627f7eb2Smrg hit_eof (dtp);
606627f7eb2Smrg
607627f7eb2Smrg /* If we have seen an eor previously, return a length of 0. The
608627f7eb2Smrg caller is responsible for correctly padding the input field. */
609627f7eb2Smrg if (dtp->u.p.sf_seen_eor)
610627f7eb2Smrg {
611627f7eb2Smrg *nbytes = 0;
612627f7eb2Smrg /* Just return something that isn't a NULL pointer, otherwise the
613627f7eb2Smrg caller thinks an error occurred. */
614627f7eb2Smrg return empty_string;
615627f7eb2Smrg }
616627f7eb2Smrg
617627f7eb2Smrg lorig = *nbytes;
618627f7eb2Smrg source = (gfc_char4_t *) mem_alloc_r4 (dtp->u.p.current_unit->s, nbytes);
619627f7eb2Smrg
620627f7eb2Smrg if (unlikely (lorig > *nbytes))
621627f7eb2Smrg {
622627f7eb2Smrg hit_eof (dtp);
623627f7eb2Smrg return NULL;
624627f7eb2Smrg }
625627f7eb2Smrg
626627f7eb2Smrg dtp->u.p.current_unit->bytes_left -= *nbytes;
627627f7eb2Smrg
628627f7eb2Smrg if (((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0) ||
629627f7eb2Smrg dtp->u.p.current_unit->has_size)
630627f7eb2Smrg dtp->u.p.current_unit->size_used += (GFC_IO_INT) *nbytes;
631627f7eb2Smrg
632627f7eb2Smrg return source;
633627f7eb2Smrg }
634627f7eb2Smrg
635627f7eb2Smrg
636627f7eb2Smrg /* Reads a block directly into application data space. This is for
637627f7eb2Smrg unformatted files. */
638627f7eb2Smrg
639627f7eb2Smrg static void
read_block_direct(st_parameter_dt * dtp,void * buf,size_t nbytes)640627f7eb2Smrg read_block_direct (st_parameter_dt *dtp, void *buf, size_t nbytes)
641627f7eb2Smrg {
642627f7eb2Smrg ssize_t to_read_record;
643627f7eb2Smrg ssize_t have_read_record;
644627f7eb2Smrg ssize_t to_read_subrecord;
645627f7eb2Smrg ssize_t have_read_subrecord;
646627f7eb2Smrg int short_record;
647627f7eb2Smrg
648627f7eb2Smrg if (is_stream_io (dtp))
649627f7eb2Smrg {
650627f7eb2Smrg have_read_record = sread (dtp->u.p.current_unit->s, buf,
651627f7eb2Smrg nbytes);
652627f7eb2Smrg if (unlikely (have_read_record < 0))
653627f7eb2Smrg {
654627f7eb2Smrg generate_error (&dtp->common, LIBERROR_OS, NULL);
655627f7eb2Smrg return;
656627f7eb2Smrg }
657627f7eb2Smrg
658627f7eb2Smrg dtp->u.p.current_unit->strm_pos += (gfc_offset) have_read_record;
659627f7eb2Smrg
660627f7eb2Smrg if (unlikely ((ssize_t) nbytes != have_read_record))
661627f7eb2Smrg {
662627f7eb2Smrg /* Short read, e.g. if we hit EOF. For stream files,
663627f7eb2Smrg we have to set the end-of-file condition. */
664627f7eb2Smrg hit_eof (dtp);
665627f7eb2Smrg }
666627f7eb2Smrg return;
667627f7eb2Smrg }
668627f7eb2Smrg
669627f7eb2Smrg if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT)
670627f7eb2Smrg {
671627f7eb2Smrg if (dtp->u.p.current_unit->bytes_left < (gfc_offset) nbytes)
672627f7eb2Smrg {
673627f7eb2Smrg short_record = 1;
674627f7eb2Smrg to_read_record = dtp->u.p.current_unit->bytes_left;
675627f7eb2Smrg nbytes = to_read_record;
676627f7eb2Smrg }
677627f7eb2Smrg else
678627f7eb2Smrg {
679627f7eb2Smrg short_record = 0;
680627f7eb2Smrg to_read_record = nbytes;
681627f7eb2Smrg }
682627f7eb2Smrg
683627f7eb2Smrg dtp->u.p.current_unit->bytes_left -= to_read_record;
684627f7eb2Smrg
685627f7eb2Smrg to_read_record = sread (dtp->u.p.current_unit->s, buf, to_read_record);
686627f7eb2Smrg if (unlikely (to_read_record < 0))
687627f7eb2Smrg {
688627f7eb2Smrg generate_error (&dtp->common, LIBERROR_OS, NULL);
689627f7eb2Smrg return;
690627f7eb2Smrg }
691627f7eb2Smrg
692627f7eb2Smrg if (to_read_record != (ssize_t) nbytes)
693627f7eb2Smrg {
694627f7eb2Smrg /* Short read, e.g. if we hit EOF. Apparently, we read
695627f7eb2Smrg more than was written to the last record. */
696627f7eb2Smrg return;
697627f7eb2Smrg }
698627f7eb2Smrg
699627f7eb2Smrg if (unlikely (short_record))
700627f7eb2Smrg {
701627f7eb2Smrg generate_error (&dtp->common, LIBERROR_SHORT_RECORD, NULL);
702627f7eb2Smrg }
703627f7eb2Smrg return;
704627f7eb2Smrg }
705627f7eb2Smrg
706627f7eb2Smrg /* Unformatted sequential. We loop over the subrecords, reading
707627f7eb2Smrg until the request has been fulfilled or the record has run out
708627f7eb2Smrg of continuation subrecords. */
709627f7eb2Smrg
710627f7eb2Smrg /* Check whether we exceed the total record length. */
711627f7eb2Smrg
712627f7eb2Smrg if (dtp->u.p.current_unit->flags.has_recl
713627f7eb2Smrg && ((gfc_offset) nbytes > dtp->u.p.current_unit->bytes_left))
714627f7eb2Smrg {
715627f7eb2Smrg to_read_record = dtp->u.p.current_unit->bytes_left;
716627f7eb2Smrg short_record = 1;
717627f7eb2Smrg }
718627f7eb2Smrg else
719627f7eb2Smrg {
720627f7eb2Smrg to_read_record = nbytes;
721627f7eb2Smrg short_record = 0;
722627f7eb2Smrg }
723627f7eb2Smrg have_read_record = 0;
724627f7eb2Smrg
725627f7eb2Smrg while(1)
726627f7eb2Smrg {
727627f7eb2Smrg if (dtp->u.p.current_unit->bytes_left_subrecord
728627f7eb2Smrg < (gfc_offset) to_read_record)
729627f7eb2Smrg {
730627f7eb2Smrg to_read_subrecord = dtp->u.p.current_unit->bytes_left_subrecord;
731627f7eb2Smrg to_read_record -= to_read_subrecord;
732627f7eb2Smrg }
733627f7eb2Smrg else
734627f7eb2Smrg {
735627f7eb2Smrg to_read_subrecord = to_read_record;
736627f7eb2Smrg to_read_record = 0;
737627f7eb2Smrg }
738627f7eb2Smrg
739627f7eb2Smrg dtp->u.p.current_unit->bytes_left_subrecord -= to_read_subrecord;
740627f7eb2Smrg
741627f7eb2Smrg have_read_subrecord = sread (dtp->u.p.current_unit->s,
742627f7eb2Smrg buf + have_read_record, to_read_subrecord);
743627f7eb2Smrg if (unlikely (have_read_subrecord < 0))
744627f7eb2Smrg {
745627f7eb2Smrg generate_error (&dtp->common, LIBERROR_OS, NULL);
746627f7eb2Smrg return;
747627f7eb2Smrg }
748627f7eb2Smrg
749627f7eb2Smrg have_read_record += have_read_subrecord;
750627f7eb2Smrg
751627f7eb2Smrg if (unlikely (to_read_subrecord != have_read_subrecord))
752627f7eb2Smrg {
753627f7eb2Smrg /* Short read, e.g. if we hit EOF. This means the record
754627f7eb2Smrg structure has been corrupted, or the trailing record
755627f7eb2Smrg marker would still be present. */
756627f7eb2Smrg
757627f7eb2Smrg generate_error (&dtp->common, LIBERROR_CORRUPT_FILE, NULL);
758627f7eb2Smrg return;
759627f7eb2Smrg }
760627f7eb2Smrg
761627f7eb2Smrg if (to_read_record > 0)
762627f7eb2Smrg {
763627f7eb2Smrg if (likely (dtp->u.p.current_unit->continued))
764627f7eb2Smrg {
765627f7eb2Smrg next_record_r_unf (dtp, 0);
766627f7eb2Smrg us_read (dtp, 1);
767627f7eb2Smrg }
768627f7eb2Smrg else
769627f7eb2Smrg {
770627f7eb2Smrg /* Let's make sure the file position is correctly pre-positioned
771627f7eb2Smrg for the next read statement. */
772627f7eb2Smrg
773627f7eb2Smrg dtp->u.p.current_unit->current_record = 0;
774627f7eb2Smrg next_record_r_unf (dtp, 0);
775627f7eb2Smrg generate_error (&dtp->common, LIBERROR_SHORT_RECORD, NULL);
776627f7eb2Smrg return;
777627f7eb2Smrg }
778627f7eb2Smrg }
779627f7eb2Smrg else
780627f7eb2Smrg {
781627f7eb2Smrg /* Normal exit, the read request has been fulfilled. */
782627f7eb2Smrg break;
783627f7eb2Smrg }
784627f7eb2Smrg }
785627f7eb2Smrg
786627f7eb2Smrg dtp->u.p.current_unit->bytes_left -= have_read_record;
787627f7eb2Smrg if (unlikely (short_record))
788627f7eb2Smrg {
789627f7eb2Smrg generate_error (&dtp->common, LIBERROR_SHORT_RECORD, NULL);
790627f7eb2Smrg return;
791627f7eb2Smrg }
792627f7eb2Smrg return;
793627f7eb2Smrg }
794627f7eb2Smrg
795627f7eb2Smrg
796627f7eb2Smrg /* Function for writing a block of bytes to the current file at the
797627f7eb2Smrg current position, advancing the file pointer. We are given a length
798627f7eb2Smrg and return a pointer to a buffer that the caller must (completely)
799627f7eb2Smrg fill in. Returns NULL on error. */
800627f7eb2Smrg
801627f7eb2Smrg void *
write_block(st_parameter_dt * dtp,size_t length)802627f7eb2Smrg write_block (st_parameter_dt *dtp, size_t length)
803627f7eb2Smrg {
804627f7eb2Smrg char *dest;
805627f7eb2Smrg
806627f7eb2Smrg if (!is_stream_io (dtp))
807627f7eb2Smrg {
808627f7eb2Smrg if (dtp->u.p.current_unit->bytes_left < (gfc_offset) length)
809627f7eb2Smrg {
810627f7eb2Smrg /* For preconnected units with default record length, set bytes left
811627f7eb2Smrg to unit record length and proceed, otherwise error. */
812627f7eb2Smrg if (likely ((dtp->u.p.current_unit->unit_number
813627f7eb2Smrg == options.stdout_unit
814627f7eb2Smrg || dtp->u.p.current_unit->unit_number
815627f7eb2Smrg == options.stderr_unit)
816627f7eb2Smrg && dtp->u.p.current_unit->recl == default_recl))
817627f7eb2Smrg dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
818627f7eb2Smrg else
819627f7eb2Smrg {
820627f7eb2Smrg generate_error (&dtp->common, LIBERROR_EOR, NULL);
821627f7eb2Smrg return NULL;
822627f7eb2Smrg }
823627f7eb2Smrg }
824627f7eb2Smrg
825627f7eb2Smrg dtp->u.p.current_unit->bytes_left -= (gfc_offset) length;
826627f7eb2Smrg }
827627f7eb2Smrg
828627f7eb2Smrg if (is_internal_unit (dtp))
829627f7eb2Smrg {
830627f7eb2Smrg if (is_char4_unit(dtp)) /* char4 internel unit. */
831627f7eb2Smrg {
832627f7eb2Smrg gfc_char4_t *dest4;
833627f7eb2Smrg dest4 = mem_alloc_w4 (dtp->u.p.current_unit->s, &length);
834627f7eb2Smrg if (dest4 == NULL)
835627f7eb2Smrg {
836627f7eb2Smrg generate_error (&dtp->common, LIBERROR_END, NULL);
837627f7eb2Smrg return NULL;
838627f7eb2Smrg }
839627f7eb2Smrg return dest4;
840627f7eb2Smrg }
841627f7eb2Smrg else
842627f7eb2Smrg dest = mem_alloc_w (dtp->u.p.current_unit->s, &length);
843627f7eb2Smrg
844627f7eb2Smrg if (dest == NULL)
845627f7eb2Smrg {
846627f7eb2Smrg generate_error (&dtp->common, LIBERROR_END, NULL);
847627f7eb2Smrg return NULL;
848627f7eb2Smrg }
849627f7eb2Smrg
850627f7eb2Smrg if (unlikely (dtp->u.p.current_unit->endfile == AT_ENDFILE))
851627f7eb2Smrg generate_error (&dtp->common, LIBERROR_END, NULL);
852627f7eb2Smrg }
853627f7eb2Smrg else
854627f7eb2Smrg {
855627f7eb2Smrg dest = fbuf_alloc (dtp->u.p.current_unit, length);
856627f7eb2Smrg if (dest == NULL)
857627f7eb2Smrg {
858627f7eb2Smrg generate_error (&dtp->common, LIBERROR_OS, NULL);
859627f7eb2Smrg return NULL;
860627f7eb2Smrg }
861627f7eb2Smrg }
862627f7eb2Smrg
863627f7eb2Smrg if (((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0) ||
864627f7eb2Smrg dtp->u.p.current_unit->has_size)
865627f7eb2Smrg dtp->u.p.current_unit->size_used += (GFC_IO_INT) length;
866627f7eb2Smrg
867627f7eb2Smrg dtp->u.p.current_unit->strm_pos += (gfc_offset) length;
868627f7eb2Smrg
869627f7eb2Smrg return dest;
870627f7eb2Smrg }
871627f7eb2Smrg
872627f7eb2Smrg
873627f7eb2Smrg /* High level interface to swrite(), taking care of errors. This is only
874627f7eb2Smrg called for unformatted files. There are three cases to consider:
875627f7eb2Smrg Stream I/O, unformatted direct, unformatted sequential. */
876627f7eb2Smrg
877627f7eb2Smrg static bool
write_buf(st_parameter_dt * dtp,void * buf,size_t nbytes)878627f7eb2Smrg write_buf (st_parameter_dt *dtp, void *buf, size_t nbytes)
879627f7eb2Smrg {
880627f7eb2Smrg
881627f7eb2Smrg ssize_t have_written;
882627f7eb2Smrg ssize_t to_write_subrecord;
883627f7eb2Smrg int short_record;
884627f7eb2Smrg
885627f7eb2Smrg /* Stream I/O. */
886627f7eb2Smrg
887627f7eb2Smrg if (is_stream_io (dtp))
888627f7eb2Smrg {
889627f7eb2Smrg have_written = swrite (dtp->u.p.current_unit->s, buf, nbytes);
890627f7eb2Smrg if (unlikely (have_written < 0))
891627f7eb2Smrg {
892627f7eb2Smrg generate_error (&dtp->common, LIBERROR_OS, NULL);
893627f7eb2Smrg return false;
894627f7eb2Smrg }
895627f7eb2Smrg
896627f7eb2Smrg dtp->u.p.current_unit->strm_pos += (gfc_offset) have_written;
897627f7eb2Smrg
898627f7eb2Smrg return true;
899627f7eb2Smrg }
900627f7eb2Smrg
901627f7eb2Smrg /* Unformatted direct access. */
902627f7eb2Smrg
903627f7eb2Smrg if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT)
904627f7eb2Smrg {
905627f7eb2Smrg if (unlikely (dtp->u.p.current_unit->bytes_left < (gfc_offset) nbytes))
906627f7eb2Smrg {
907627f7eb2Smrg generate_error (&dtp->common, LIBERROR_DIRECT_EOR, NULL);
908627f7eb2Smrg return false;
909627f7eb2Smrg }
910627f7eb2Smrg
911627f7eb2Smrg if (buf == NULL && nbytes == 0)
912627f7eb2Smrg return true;
913627f7eb2Smrg
914627f7eb2Smrg have_written = swrite (dtp->u.p.current_unit->s, buf, nbytes);
915627f7eb2Smrg if (unlikely (have_written < 0))
916627f7eb2Smrg {
917627f7eb2Smrg generate_error (&dtp->common, LIBERROR_OS, NULL);
918627f7eb2Smrg return false;
919627f7eb2Smrg }
920627f7eb2Smrg
921627f7eb2Smrg dtp->u.p.current_unit->strm_pos += (gfc_offset) have_written;
922627f7eb2Smrg dtp->u.p.current_unit->bytes_left -= (gfc_offset) have_written;
923627f7eb2Smrg
924627f7eb2Smrg return true;
925627f7eb2Smrg }
926627f7eb2Smrg
927627f7eb2Smrg /* Unformatted sequential. */
928627f7eb2Smrg
929627f7eb2Smrg have_written = 0;
930627f7eb2Smrg
931627f7eb2Smrg if (dtp->u.p.current_unit->flags.has_recl
932627f7eb2Smrg && (gfc_offset) nbytes > dtp->u.p.current_unit->bytes_left)
933627f7eb2Smrg {
934627f7eb2Smrg nbytes = dtp->u.p.current_unit->bytes_left;
935627f7eb2Smrg short_record = 1;
936627f7eb2Smrg }
937627f7eb2Smrg else
938627f7eb2Smrg {
939627f7eb2Smrg short_record = 0;
940627f7eb2Smrg }
941627f7eb2Smrg
942627f7eb2Smrg while (1)
943627f7eb2Smrg {
944627f7eb2Smrg
945627f7eb2Smrg to_write_subrecord =
946627f7eb2Smrg (size_t) dtp->u.p.current_unit->bytes_left_subrecord < nbytes ?
947627f7eb2Smrg (size_t) dtp->u.p.current_unit->bytes_left_subrecord : nbytes;
948627f7eb2Smrg
949627f7eb2Smrg dtp->u.p.current_unit->bytes_left_subrecord -=
950627f7eb2Smrg (gfc_offset) to_write_subrecord;
951627f7eb2Smrg
952627f7eb2Smrg to_write_subrecord = swrite (dtp->u.p.current_unit->s,
953627f7eb2Smrg buf + have_written, to_write_subrecord);
954627f7eb2Smrg if (unlikely (to_write_subrecord < 0))
955627f7eb2Smrg {
956627f7eb2Smrg generate_error (&dtp->common, LIBERROR_OS, NULL);
957627f7eb2Smrg return false;
958627f7eb2Smrg }
959627f7eb2Smrg
960627f7eb2Smrg dtp->u.p.current_unit->strm_pos += (gfc_offset) to_write_subrecord;
961627f7eb2Smrg nbytes -= to_write_subrecord;
962627f7eb2Smrg have_written += to_write_subrecord;
963627f7eb2Smrg
964627f7eb2Smrg if (nbytes == 0)
965627f7eb2Smrg break;
966627f7eb2Smrg
967627f7eb2Smrg next_record_w_unf (dtp, 1);
968627f7eb2Smrg us_write (dtp, 1);
969627f7eb2Smrg }
970627f7eb2Smrg dtp->u.p.current_unit->bytes_left -= have_written;
971627f7eb2Smrg if (unlikely (short_record))
972627f7eb2Smrg {
973627f7eb2Smrg generate_error (&dtp->common, LIBERROR_SHORT_RECORD, NULL);
974627f7eb2Smrg return false;
975627f7eb2Smrg }
976627f7eb2Smrg return true;
977627f7eb2Smrg }
978627f7eb2Smrg
979627f7eb2Smrg
980627f7eb2Smrg /* Reverse memcpy - used for byte swapping. */
981627f7eb2Smrg
982627f7eb2Smrg static void
reverse_memcpy(void * dest,const void * src,size_t n)983627f7eb2Smrg reverse_memcpy (void *dest, const void *src, size_t n)
984627f7eb2Smrg {
985627f7eb2Smrg char *d, *s;
986627f7eb2Smrg size_t i;
987627f7eb2Smrg
988627f7eb2Smrg d = (char *) dest;
989627f7eb2Smrg s = (char *) src + n - 1;
990627f7eb2Smrg
991627f7eb2Smrg /* Write with ascending order - this is likely faster
992627f7eb2Smrg on modern architectures because of write combining. */
993627f7eb2Smrg for (i=0; i<n; i++)
994627f7eb2Smrg *(d++) = *(s--);
995627f7eb2Smrg }
996627f7eb2Smrg
997627f7eb2Smrg
998627f7eb2Smrg /* Utility function for byteswapping an array, using the bswap
999627f7eb2Smrg builtins if possible. dest and src can overlap completely, or then
1000627f7eb2Smrg they must point to separate objects; partial overlaps are not
1001627f7eb2Smrg allowed. */
1002627f7eb2Smrg
1003627f7eb2Smrg static void
bswap_array(void * dest,const void * src,size_t size,size_t nelems)1004627f7eb2Smrg bswap_array (void *dest, const void *src, size_t size, size_t nelems)
1005627f7eb2Smrg {
1006627f7eb2Smrg const char *ps;
1007627f7eb2Smrg char *pd;
1008627f7eb2Smrg
1009627f7eb2Smrg switch (size)
1010627f7eb2Smrg {
1011627f7eb2Smrg case 1:
1012627f7eb2Smrg break;
1013627f7eb2Smrg case 2:
1014627f7eb2Smrg for (size_t i = 0; i < nelems; i++)
1015627f7eb2Smrg ((uint16_t*)dest)[i] = __builtin_bswap16 (((uint16_t*)src)[i]);
1016627f7eb2Smrg break;
1017627f7eb2Smrg case 4:
1018627f7eb2Smrg for (size_t i = 0; i < nelems; i++)
1019627f7eb2Smrg ((uint32_t*)dest)[i] = __builtin_bswap32 (((uint32_t*)src)[i]);
1020627f7eb2Smrg break;
1021627f7eb2Smrg case 8:
1022627f7eb2Smrg for (size_t i = 0; i < nelems; i++)
1023627f7eb2Smrg ((uint64_t*)dest)[i] = __builtin_bswap64 (((uint64_t*)src)[i]);
1024627f7eb2Smrg break;
1025627f7eb2Smrg case 12:
1026627f7eb2Smrg ps = src;
1027627f7eb2Smrg pd = dest;
1028627f7eb2Smrg for (size_t i = 0; i < nelems; i++)
1029627f7eb2Smrg {
1030627f7eb2Smrg uint32_t tmp;
1031627f7eb2Smrg memcpy (&tmp, ps, 4);
1032627f7eb2Smrg *(uint32_t*)pd = __builtin_bswap32 (*(uint32_t*)(ps + 8));
1033627f7eb2Smrg *(uint32_t*)(pd + 4) = __builtin_bswap32 (*(uint32_t*)(ps + 4));
1034627f7eb2Smrg *(uint32_t*)(pd + 8) = __builtin_bswap32 (tmp);
1035627f7eb2Smrg ps += size;
1036627f7eb2Smrg pd += size;
1037627f7eb2Smrg }
1038627f7eb2Smrg break;
1039627f7eb2Smrg case 16:
1040627f7eb2Smrg ps = src;
1041627f7eb2Smrg pd = dest;
1042627f7eb2Smrg for (size_t i = 0; i < nelems; i++)
1043627f7eb2Smrg {
1044627f7eb2Smrg uint64_t tmp;
1045627f7eb2Smrg memcpy (&tmp, ps, 8);
1046627f7eb2Smrg *(uint64_t*)pd = __builtin_bswap64 (*(uint64_t*)(ps + 8));
1047627f7eb2Smrg *(uint64_t*)(pd + 8) = __builtin_bswap64 (tmp);
1048627f7eb2Smrg ps += size;
1049627f7eb2Smrg pd += size;
1050627f7eb2Smrg }
1051627f7eb2Smrg break;
1052627f7eb2Smrg default:
1053627f7eb2Smrg pd = dest;
1054627f7eb2Smrg if (dest != src)
1055627f7eb2Smrg {
1056627f7eb2Smrg ps = src;
1057627f7eb2Smrg for (size_t i = 0; i < nelems; i++)
1058627f7eb2Smrg {
1059627f7eb2Smrg reverse_memcpy (pd, ps, size);
1060627f7eb2Smrg ps += size;
1061627f7eb2Smrg pd += size;
1062627f7eb2Smrg }
1063627f7eb2Smrg }
1064627f7eb2Smrg else
1065627f7eb2Smrg {
1066627f7eb2Smrg /* In-place byte swap. */
1067627f7eb2Smrg for (size_t i = 0; i < nelems; i++)
1068627f7eb2Smrg {
1069627f7eb2Smrg char tmp, *low = pd, *high = pd + size - 1;
1070627f7eb2Smrg for (size_t j = 0; j < size/2; j++)
1071627f7eb2Smrg {
1072627f7eb2Smrg tmp = *low;
1073627f7eb2Smrg *low = *high;
1074627f7eb2Smrg *high = tmp;
1075627f7eb2Smrg low++;
1076627f7eb2Smrg high--;
1077627f7eb2Smrg }
1078627f7eb2Smrg pd += size;
1079627f7eb2Smrg }
1080627f7eb2Smrg }
1081627f7eb2Smrg }
1082627f7eb2Smrg }
1083627f7eb2Smrg
1084627f7eb2Smrg
1085627f7eb2Smrg /* Master function for unformatted reads. */
1086627f7eb2Smrg
1087627f7eb2Smrg static void
unformatted_read(st_parameter_dt * dtp,bt type,void * dest,int kind,size_t size,size_t nelems)1088627f7eb2Smrg unformatted_read (st_parameter_dt *dtp, bt type,
1089627f7eb2Smrg void *dest, int kind, size_t size, size_t nelems)
1090627f7eb2Smrg {
1091627f7eb2Smrg if (type == BT_CLASS)
1092627f7eb2Smrg {
1093627f7eb2Smrg int unit = dtp->u.p.current_unit->unit_number;
1094627f7eb2Smrg char tmp_iomsg[IOMSG_LEN] = "";
1095627f7eb2Smrg char *child_iomsg;
1096627f7eb2Smrg gfc_charlen_type child_iomsg_len;
1097627f7eb2Smrg int noiostat;
1098627f7eb2Smrg int *child_iostat = NULL;
1099627f7eb2Smrg
1100627f7eb2Smrg /* Set iostat, intent(out). */
1101627f7eb2Smrg noiostat = 0;
1102627f7eb2Smrg child_iostat = (dtp->common.flags & IOPARM_HAS_IOSTAT) ?
1103627f7eb2Smrg dtp->common.iostat : &noiostat;
1104627f7eb2Smrg
1105627f7eb2Smrg /* Set iomsg, intent(inout). */
1106627f7eb2Smrg if (dtp->common.flags & IOPARM_HAS_IOMSG)
1107627f7eb2Smrg {
1108627f7eb2Smrg child_iomsg = dtp->common.iomsg;
1109627f7eb2Smrg child_iomsg_len = dtp->common.iomsg_len;
1110627f7eb2Smrg }
1111627f7eb2Smrg else
1112627f7eb2Smrg {
1113627f7eb2Smrg child_iomsg = tmp_iomsg;
1114627f7eb2Smrg child_iomsg_len = IOMSG_LEN;
1115627f7eb2Smrg }
1116627f7eb2Smrg
1117627f7eb2Smrg /* Call the user defined unformatted READ procedure. */
1118627f7eb2Smrg dtp->u.p.current_unit->child_dtio++;
1119627f7eb2Smrg dtp->u.p.ufdtio_ptr (dest, &unit, child_iostat, child_iomsg,
1120627f7eb2Smrg child_iomsg_len);
1121627f7eb2Smrg dtp->u.p.current_unit->child_dtio--;
1122627f7eb2Smrg return;
1123627f7eb2Smrg }
1124627f7eb2Smrg
1125627f7eb2Smrg if (type == BT_CHARACTER)
1126627f7eb2Smrg size *= GFC_SIZE_OF_CHAR_KIND(kind);
1127627f7eb2Smrg read_block_direct (dtp, dest, size * nelems);
1128627f7eb2Smrg
1129627f7eb2Smrg if (unlikely (dtp->u.p.current_unit->flags.convert == GFC_CONVERT_SWAP)
1130627f7eb2Smrg && kind != 1)
1131627f7eb2Smrg {
1132627f7eb2Smrg /* Handle wide chracters. */
1133627f7eb2Smrg if (type == BT_CHARACTER)
1134627f7eb2Smrg {
1135627f7eb2Smrg nelems *= size;
1136627f7eb2Smrg size = kind;
1137627f7eb2Smrg }
1138627f7eb2Smrg
1139627f7eb2Smrg /* Break up complex into its constituent reals. */
1140627f7eb2Smrg else if (type == BT_COMPLEX)
1141627f7eb2Smrg {
1142627f7eb2Smrg nelems *= 2;
1143627f7eb2Smrg size /= 2;
1144627f7eb2Smrg }
1145627f7eb2Smrg bswap_array (dest, dest, size, nelems);
1146627f7eb2Smrg }
1147627f7eb2Smrg }
1148627f7eb2Smrg
1149627f7eb2Smrg
1150627f7eb2Smrg /* Master function for unformatted writes. NOTE: For kind=10 the size is 16
1151627f7eb2Smrg bytes on 64 bit machines. The unused bytes are not initialized and never
1152627f7eb2Smrg used, which can show an error with memory checking analyzers like
1153627f7eb2Smrg valgrind. We us BT_CLASS to denote a User Defined I/O call. */
1154627f7eb2Smrg
1155627f7eb2Smrg static void
unformatted_write(st_parameter_dt * dtp,bt type,void * source,int kind,size_t size,size_t nelems)1156627f7eb2Smrg unformatted_write (st_parameter_dt *dtp, bt type,
1157627f7eb2Smrg void *source, int kind, size_t size, size_t nelems)
1158627f7eb2Smrg {
1159627f7eb2Smrg if (type == BT_CLASS)
1160627f7eb2Smrg {
1161627f7eb2Smrg int unit = dtp->u.p.current_unit->unit_number;
1162627f7eb2Smrg char tmp_iomsg[IOMSG_LEN] = "";
1163627f7eb2Smrg char *child_iomsg;
1164627f7eb2Smrg gfc_charlen_type child_iomsg_len;
1165627f7eb2Smrg int noiostat;
1166627f7eb2Smrg int *child_iostat = NULL;
1167627f7eb2Smrg
1168627f7eb2Smrg /* Set iostat, intent(out). */
1169627f7eb2Smrg noiostat = 0;
1170627f7eb2Smrg child_iostat = (dtp->common.flags & IOPARM_HAS_IOSTAT) ?
1171627f7eb2Smrg dtp->common.iostat : &noiostat;
1172627f7eb2Smrg
1173627f7eb2Smrg /* Set iomsg, intent(inout). */
1174627f7eb2Smrg if (dtp->common.flags & IOPARM_HAS_IOMSG)
1175627f7eb2Smrg {
1176627f7eb2Smrg child_iomsg = dtp->common.iomsg;
1177627f7eb2Smrg child_iomsg_len = dtp->common.iomsg_len;
1178627f7eb2Smrg }
1179627f7eb2Smrg else
1180627f7eb2Smrg {
1181627f7eb2Smrg child_iomsg = tmp_iomsg;
1182627f7eb2Smrg child_iomsg_len = IOMSG_LEN;
1183627f7eb2Smrg }
1184627f7eb2Smrg
1185627f7eb2Smrg /* Call the user defined unformatted WRITE procedure. */
1186627f7eb2Smrg dtp->u.p.current_unit->child_dtio++;
1187627f7eb2Smrg dtp->u.p.ufdtio_ptr (source, &unit, child_iostat, child_iomsg,
1188627f7eb2Smrg child_iomsg_len);
1189627f7eb2Smrg dtp->u.p.current_unit->child_dtio--;
1190627f7eb2Smrg return;
1191627f7eb2Smrg }
1192627f7eb2Smrg
1193627f7eb2Smrg if (likely (dtp->u.p.current_unit->flags.convert == GFC_CONVERT_NATIVE)
1194627f7eb2Smrg || kind == 1)
1195627f7eb2Smrg {
1196627f7eb2Smrg size_t stride = type == BT_CHARACTER ?
1197627f7eb2Smrg size * GFC_SIZE_OF_CHAR_KIND(kind) : size;
1198627f7eb2Smrg
1199627f7eb2Smrg write_buf (dtp, source, stride * nelems);
1200627f7eb2Smrg }
1201627f7eb2Smrg else
1202627f7eb2Smrg {
1203627f7eb2Smrg #define BSWAP_BUFSZ 512
1204627f7eb2Smrg char buffer[BSWAP_BUFSZ];
1205627f7eb2Smrg char *p;
1206627f7eb2Smrg size_t nrem;
1207627f7eb2Smrg
1208627f7eb2Smrg p = source;
1209627f7eb2Smrg
1210627f7eb2Smrg /* Handle wide chracters. */
1211627f7eb2Smrg if (type == BT_CHARACTER && kind != 1)
1212627f7eb2Smrg {
1213627f7eb2Smrg nelems *= size;
1214627f7eb2Smrg size = kind;
1215627f7eb2Smrg }
1216627f7eb2Smrg
1217627f7eb2Smrg /* Break up complex into its constituent reals. */
1218627f7eb2Smrg if (type == BT_COMPLEX)
1219627f7eb2Smrg {
1220627f7eb2Smrg nelems *= 2;
1221627f7eb2Smrg size /= 2;
1222627f7eb2Smrg }
1223627f7eb2Smrg
1224627f7eb2Smrg /* By now, all complex variables have been split into their
1225627f7eb2Smrg constituent reals. */
1226627f7eb2Smrg
1227627f7eb2Smrg nrem = nelems;
1228627f7eb2Smrg do
1229627f7eb2Smrg {
1230627f7eb2Smrg size_t nc;
1231627f7eb2Smrg if (size * nrem > BSWAP_BUFSZ)
1232627f7eb2Smrg nc = BSWAP_BUFSZ / size;
1233627f7eb2Smrg else
1234627f7eb2Smrg nc = nrem;
1235627f7eb2Smrg
1236627f7eb2Smrg bswap_array (buffer, p, size, nc);
1237627f7eb2Smrg write_buf (dtp, buffer, size * nc);
1238627f7eb2Smrg p += size * nc;
1239627f7eb2Smrg nrem -= nc;
1240627f7eb2Smrg }
1241627f7eb2Smrg while (nrem > 0);
1242627f7eb2Smrg }
1243627f7eb2Smrg }
1244627f7eb2Smrg
1245627f7eb2Smrg
1246627f7eb2Smrg /* Return a pointer to the name of a type. */
1247627f7eb2Smrg
1248627f7eb2Smrg const char *
type_name(bt type)1249627f7eb2Smrg type_name (bt type)
1250627f7eb2Smrg {
1251627f7eb2Smrg const char *p;
1252627f7eb2Smrg
1253627f7eb2Smrg switch (type)
1254627f7eb2Smrg {
1255627f7eb2Smrg case BT_INTEGER:
1256627f7eb2Smrg p = "INTEGER";
1257627f7eb2Smrg break;
1258627f7eb2Smrg case BT_LOGICAL:
1259627f7eb2Smrg p = "LOGICAL";
1260627f7eb2Smrg break;
1261627f7eb2Smrg case BT_CHARACTER:
1262627f7eb2Smrg p = "CHARACTER";
1263627f7eb2Smrg break;
1264627f7eb2Smrg case BT_REAL:
1265627f7eb2Smrg p = "REAL";
1266627f7eb2Smrg break;
1267627f7eb2Smrg case BT_COMPLEX:
1268627f7eb2Smrg p = "COMPLEX";
1269627f7eb2Smrg break;
1270627f7eb2Smrg case BT_CLASS:
1271627f7eb2Smrg p = "CLASS or DERIVED";
1272627f7eb2Smrg break;
1273627f7eb2Smrg default:
1274627f7eb2Smrg internal_error (NULL, "type_name(): Bad type");
1275627f7eb2Smrg }
1276627f7eb2Smrg
1277627f7eb2Smrg return p;
1278627f7eb2Smrg }
1279627f7eb2Smrg
1280627f7eb2Smrg
1281627f7eb2Smrg /* Write a constant string to the output.
1282627f7eb2Smrg This is complicated because the string can have doubled delimiters
1283627f7eb2Smrg in it. The length in the format node is the true length. */
1284627f7eb2Smrg
1285627f7eb2Smrg static void
write_constant_string(st_parameter_dt * dtp,const fnode * f)1286627f7eb2Smrg write_constant_string (st_parameter_dt *dtp, const fnode *f)
1287627f7eb2Smrg {
1288627f7eb2Smrg char c, delimiter, *p, *q;
1289627f7eb2Smrg int length;
1290627f7eb2Smrg
1291627f7eb2Smrg length = f->u.string.length;
1292627f7eb2Smrg if (length == 0)
1293627f7eb2Smrg return;
1294627f7eb2Smrg
1295627f7eb2Smrg p = write_block (dtp, length);
1296627f7eb2Smrg if (p == NULL)
1297627f7eb2Smrg return;
1298627f7eb2Smrg
1299627f7eb2Smrg q = f->u.string.p;
1300627f7eb2Smrg delimiter = q[-1];
1301627f7eb2Smrg
1302627f7eb2Smrg for (; length > 0; length--)
1303627f7eb2Smrg {
1304627f7eb2Smrg c = *p++ = *q++;
1305627f7eb2Smrg if (c == delimiter && c != 'H' && c != 'h')
1306627f7eb2Smrg q++; /* Skip the doubled delimiter. */
1307627f7eb2Smrg }
1308627f7eb2Smrg }
1309627f7eb2Smrg
1310627f7eb2Smrg
1311627f7eb2Smrg /* Given actual and expected types in a formatted data transfer, make
1312627f7eb2Smrg sure they agree. If not, an error message is generated. Returns
1313627f7eb2Smrg nonzero if something went wrong. */
1314627f7eb2Smrg
1315627f7eb2Smrg static int
require_type(st_parameter_dt * dtp,bt expected,bt actual,const fnode * f)1316627f7eb2Smrg require_type (st_parameter_dt *dtp, bt expected, bt actual, const fnode *f)
1317627f7eb2Smrg {
1318627f7eb2Smrg #define BUFLEN 100
1319627f7eb2Smrg char buffer[BUFLEN];
1320627f7eb2Smrg
1321627f7eb2Smrg if (actual == expected)
1322627f7eb2Smrg return 0;
1323627f7eb2Smrg
1324627f7eb2Smrg /* Adjust item_count before emitting error message. */
1325627f7eb2Smrg snprintf (buffer, BUFLEN,
1326627f7eb2Smrg "Expected %s for item %d in formatted transfer, got %s",
1327627f7eb2Smrg type_name (expected), dtp->u.p.item_count - 1, type_name (actual));
1328627f7eb2Smrg
1329627f7eb2Smrg format_error (dtp, f, buffer);
1330627f7eb2Smrg return 1;
1331627f7eb2Smrg }
1332627f7eb2Smrg
1333627f7eb2Smrg
1334627f7eb2Smrg /* Check that the dtio procedure required for formatted IO is present. */
1335627f7eb2Smrg
1336627f7eb2Smrg static int
check_dtio_proc(st_parameter_dt * dtp,const fnode * f)1337627f7eb2Smrg check_dtio_proc (st_parameter_dt *dtp, const fnode *f)
1338627f7eb2Smrg {
1339627f7eb2Smrg char buffer[BUFLEN];
1340627f7eb2Smrg
1341627f7eb2Smrg if (dtp->u.p.fdtio_ptr != NULL)
1342627f7eb2Smrg return 0;
1343627f7eb2Smrg
1344627f7eb2Smrg snprintf (buffer, BUFLEN,
1345627f7eb2Smrg "Missing DTIO procedure or intrinsic type passed for item %d "
1346627f7eb2Smrg "in formatted transfer",
1347627f7eb2Smrg dtp->u.p.item_count - 1);
1348627f7eb2Smrg
1349627f7eb2Smrg format_error (dtp, f, buffer);
1350627f7eb2Smrg return 1;
1351627f7eb2Smrg }
1352627f7eb2Smrg
1353627f7eb2Smrg
1354627f7eb2Smrg static int
require_numeric_type(st_parameter_dt * dtp,bt actual,const fnode * f)1355627f7eb2Smrg require_numeric_type (st_parameter_dt *dtp, bt actual, const fnode *f)
1356627f7eb2Smrg {
1357627f7eb2Smrg #define BUFLEN 100
1358627f7eb2Smrg char buffer[BUFLEN];
1359627f7eb2Smrg
1360627f7eb2Smrg if (actual == BT_INTEGER || actual == BT_REAL || actual == BT_COMPLEX)
1361627f7eb2Smrg return 0;
1362627f7eb2Smrg
1363627f7eb2Smrg /* Adjust item_count before emitting error message. */
1364627f7eb2Smrg snprintf (buffer, BUFLEN,
1365627f7eb2Smrg "Expected numeric type for item %d in formatted transfer, got %s",
1366627f7eb2Smrg dtp->u.p.item_count - 1, type_name (actual));
1367627f7eb2Smrg
1368627f7eb2Smrg format_error (dtp, f, buffer);
1369627f7eb2Smrg return 1;
1370627f7eb2Smrg }
1371627f7eb2Smrg
1372627f7eb2Smrg static char *
get_dt_format(char * p,gfc_charlen_type * length)1373627f7eb2Smrg get_dt_format (char *p, gfc_charlen_type *length)
1374627f7eb2Smrg {
1375627f7eb2Smrg char delim = p[-1]; /* The delimiter is always the first character back. */
1376627f7eb2Smrg char c, *q, *res;
1377627f7eb2Smrg gfc_charlen_type len = *length; /* This length already correct, less 'DT'. */
1378627f7eb2Smrg
1379627f7eb2Smrg res = q = xmalloc (len + 2);
1380627f7eb2Smrg
1381627f7eb2Smrg /* Set the beginning of the string to 'DT', length adjusted below. */
1382627f7eb2Smrg *q++ = 'D';
1383627f7eb2Smrg *q++ = 'T';
1384627f7eb2Smrg
1385627f7eb2Smrg /* The string may contain doubled quotes so scan and skip as needed. */
1386627f7eb2Smrg for (; len > 0; len--)
1387627f7eb2Smrg {
1388627f7eb2Smrg c = *q++ = *p++;
1389627f7eb2Smrg if (c == delim)
1390627f7eb2Smrg p++; /* Skip the doubled delimiter. */
1391627f7eb2Smrg }
1392627f7eb2Smrg
1393627f7eb2Smrg /* Adjust the string length by two now that we are done. */
1394627f7eb2Smrg *length += 2;
1395627f7eb2Smrg
1396627f7eb2Smrg return res;
1397627f7eb2Smrg }
1398627f7eb2Smrg
1399627f7eb2Smrg
1400627f7eb2Smrg /* This function is in the main loop for a formatted data transfer
1401627f7eb2Smrg statement. It would be natural to implement this as a coroutine
1402627f7eb2Smrg with the user program, but C makes that awkward. We loop,
1403627f7eb2Smrg processing format elements. When we actually have to transfer
1404627f7eb2Smrg data instead of just setting flags, we return control to the user
1405627f7eb2Smrg program which calls a function that supplies the address and type
1406627f7eb2Smrg of the next element, then comes back here to process it. */
1407627f7eb2Smrg
1408627f7eb2Smrg static void
formatted_transfer_scalar_read(st_parameter_dt * dtp,bt type,void * p,int kind,size_t size)1409627f7eb2Smrg formatted_transfer_scalar_read (st_parameter_dt *dtp, bt type, void *p, int kind,
1410627f7eb2Smrg size_t size)
1411627f7eb2Smrg {
1412627f7eb2Smrg int pos, bytes_used;
1413627f7eb2Smrg const fnode *f;
1414627f7eb2Smrg format_token t;
1415627f7eb2Smrg int n;
1416627f7eb2Smrg int consume_data_flag;
1417627f7eb2Smrg
1418627f7eb2Smrg /* Change a complex data item into a pair of reals. */
1419627f7eb2Smrg
1420627f7eb2Smrg n = (p == NULL) ? 0 : ((type != BT_COMPLEX) ? 1 : 2);
1421627f7eb2Smrg if (type == BT_COMPLEX)
1422627f7eb2Smrg {
1423627f7eb2Smrg type = BT_REAL;
1424627f7eb2Smrg size /= 2;
1425627f7eb2Smrg }
1426627f7eb2Smrg
1427627f7eb2Smrg /* If there's an EOR condition, we simulate finalizing the transfer
1428627f7eb2Smrg by doing nothing. */
1429627f7eb2Smrg if (dtp->u.p.eor_condition)
1430627f7eb2Smrg return;
1431627f7eb2Smrg
1432627f7eb2Smrg /* Set this flag so that commas in reads cause the read to complete before
1433627f7eb2Smrg the entire field has been read. The next read field will start right after
1434627f7eb2Smrg the comma in the stream. (Set to 0 for character reads). */
1435627f7eb2Smrg dtp->u.p.sf_read_comma =
1436627f7eb2Smrg dtp->u.p.current_unit->decimal_status == DECIMAL_COMMA ? 0 : 1;
1437627f7eb2Smrg
1438627f7eb2Smrg for (;;)
1439627f7eb2Smrg {
1440627f7eb2Smrg /* If reversion has occurred and there is another real data item,
1441627f7eb2Smrg then we have to move to the next record. */
1442627f7eb2Smrg if (dtp->u.p.reversion_flag && n > 0)
1443627f7eb2Smrg {
1444627f7eb2Smrg dtp->u.p.reversion_flag = 0;
1445627f7eb2Smrg next_record (dtp, 0);
1446627f7eb2Smrg }
1447627f7eb2Smrg
1448627f7eb2Smrg consume_data_flag = 1;
1449627f7eb2Smrg if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
1450627f7eb2Smrg break;
1451627f7eb2Smrg
1452627f7eb2Smrg f = next_format (dtp);
1453627f7eb2Smrg if (f == NULL)
1454627f7eb2Smrg {
1455627f7eb2Smrg /* No data descriptors left. */
1456627f7eb2Smrg if (unlikely (n > 0))
1457627f7eb2Smrg generate_error (&dtp->common, LIBERROR_FORMAT,
1458627f7eb2Smrg "Insufficient data descriptors in format after reversion");
1459627f7eb2Smrg return;
1460627f7eb2Smrg }
1461627f7eb2Smrg
1462627f7eb2Smrg t = f->format;
1463627f7eb2Smrg
1464627f7eb2Smrg bytes_used = (int)(dtp->u.p.current_unit->recl
1465627f7eb2Smrg - dtp->u.p.current_unit->bytes_left);
1466627f7eb2Smrg
1467627f7eb2Smrg if (is_stream_io(dtp))
1468627f7eb2Smrg bytes_used = 0;
1469627f7eb2Smrg
1470627f7eb2Smrg switch (t)
1471627f7eb2Smrg {
1472627f7eb2Smrg case FMT_I:
1473627f7eb2Smrg if (n == 0)
1474627f7eb2Smrg goto need_read_data;
1475627f7eb2Smrg if (require_type (dtp, BT_INTEGER, type, f))
1476627f7eb2Smrg return;
1477627f7eb2Smrg read_decimal (dtp, f, p, kind);
1478627f7eb2Smrg break;
1479627f7eb2Smrg
1480627f7eb2Smrg case FMT_B:
1481627f7eb2Smrg if (n == 0)
1482627f7eb2Smrg goto need_read_data;
1483627f7eb2Smrg if (!(compile_options.allow_std & GFC_STD_GNU)
1484627f7eb2Smrg && require_numeric_type (dtp, type, f))
1485627f7eb2Smrg return;
1486627f7eb2Smrg if (!(compile_options.allow_std & GFC_STD_F2008)
1487627f7eb2Smrg && require_type (dtp, BT_INTEGER, type, f))
1488627f7eb2Smrg return;
1489627f7eb2Smrg read_radix (dtp, f, p, kind, 2);
1490627f7eb2Smrg break;
1491627f7eb2Smrg
1492627f7eb2Smrg case FMT_O:
1493627f7eb2Smrg if (n == 0)
1494627f7eb2Smrg goto need_read_data;
1495627f7eb2Smrg if (!(compile_options.allow_std & GFC_STD_GNU)
1496627f7eb2Smrg && require_numeric_type (dtp, type, f))
1497627f7eb2Smrg return;
1498627f7eb2Smrg if (!(compile_options.allow_std & GFC_STD_F2008)
1499627f7eb2Smrg && require_type (dtp, BT_INTEGER, type, f))
1500627f7eb2Smrg return;
1501627f7eb2Smrg read_radix (dtp, f, p, kind, 8);
1502627f7eb2Smrg break;
1503627f7eb2Smrg
1504627f7eb2Smrg case FMT_Z:
1505627f7eb2Smrg if (n == 0)
1506627f7eb2Smrg goto need_read_data;
1507627f7eb2Smrg if (!(compile_options.allow_std & GFC_STD_GNU)
1508627f7eb2Smrg && require_numeric_type (dtp, type, f))
1509627f7eb2Smrg return;
1510627f7eb2Smrg if (!(compile_options.allow_std & GFC_STD_F2008)
1511627f7eb2Smrg && require_type (dtp, BT_INTEGER, type, f))
1512627f7eb2Smrg return;
1513627f7eb2Smrg read_radix (dtp, f, p, kind, 16);
1514627f7eb2Smrg break;
1515627f7eb2Smrg
1516627f7eb2Smrg case FMT_A:
1517627f7eb2Smrg if (n == 0)
1518627f7eb2Smrg goto need_read_data;
1519627f7eb2Smrg
1520627f7eb2Smrg /* It is possible to have FMT_A with something not BT_CHARACTER such
1521627f7eb2Smrg as when writing out hollerith strings, so check both type
1522627f7eb2Smrg and kind before calling wide character routines. */
1523627f7eb2Smrg if (type == BT_CHARACTER && kind == 4)
1524627f7eb2Smrg read_a_char4 (dtp, f, p, size);
1525627f7eb2Smrg else
1526627f7eb2Smrg read_a (dtp, f, p, size);
1527627f7eb2Smrg break;
1528627f7eb2Smrg
1529627f7eb2Smrg case FMT_L:
1530627f7eb2Smrg if (n == 0)
1531627f7eb2Smrg goto need_read_data;
1532627f7eb2Smrg read_l (dtp, f, p, kind);
1533627f7eb2Smrg break;
1534627f7eb2Smrg
1535627f7eb2Smrg case FMT_D:
1536627f7eb2Smrg if (n == 0)
1537627f7eb2Smrg goto need_read_data;
1538627f7eb2Smrg if (require_type (dtp, BT_REAL, type, f))
1539627f7eb2Smrg return;
1540627f7eb2Smrg read_f (dtp, f, p, kind);
1541627f7eb2Smrg break;
1542627f7eb2Smrg
1543627f7eb2Smrg case FMT_DT:
1544627f7eb2Smrg if (n == 0)
1545627f7eb2Smrg goto need_read_data;
1546627f7eb2Smrg
1547627f7eb2Smrg if (check_dtio_proc (dtp, f))
1548627f7eb2Smrg return;
1549627f7eb2Smrg if (require_type (dtp, BT_CLASS, type, f))
1550627f7eb2Smrg return;
1551627f7eb2Smrg int unit = dtp->u.p.current_unit->unit_number;
1552627f7eb2Smrg char dt[] = "DT";
1553627f7eb2Smrg char tmp_iomsg[IOMSG_LEN] = "";
1554627f7eb2Smrg char *child_iomsg;
1555627f7eb2Smrg gfc_charlen_type child_iomsg_len;
1556627f7eb2Smrg int noiostat;
1557627f7eb2Smrg int *child_iostat = NULL;
1558627f7eb2Smrg char *iotype;
1559627f7eb2Smrg gfc_charlen_type iotype_len = f->u.udf.string_len;
1560627f7eb2Smrg
1561627f7eb2Smrg /* Build the iotype string. */
1562627f7eb2Smrg if (iotype_len == 0)
1563627f7eb2Smrg {
1564627f7eb2Smrg iotype_len = 2;
1565627f7eb2Smrg iotype = dt;
1566627f7eb2Smrg }
1567627f7eb2Smrg else
1568627f7eb2Smrg iotype = get_dt_format (f->u.udf.string, &iotype_len);
1569627f7eb2Smrg
1570627f7eb2Smrg /* Set iostat, intent(out). */
1571627f7eb2Smrg noiostat = 0;
1572627f7eb2Smrg child_iostat = (dtp->common.flags & IOPARM_HAS_IOSTAT) ?
1573627f7eb2Smrg dtp->common.iostat : &noiostat;
1574627f7eb2Smrg
1575627f7eb2Smrg /* Set iomsg, intent(inout). */
1576627f7eb2Smrg if (dtp->common.flags & IOPARM_HAS_IOMSG)
1577627f7eb2Smrg {
1578627f7eb2Smrg child_iomsg = dtp->common.iomsg;
1579627f7eb2Smrg child_iomsg_len = dtp->common.iomsg_len;
1580627f7eb2Smrg }
1581627f7eb2Smrg else
1582627f7eb2Smrg {
1583627f7eb2Smrg child_iomsg = tmp_iomsg;
1584627f7eb2Smrg child_iomsg_len = IOMSG_LEN;
1585627f7eb2Smrg }
1586627f7eb2Smrg
1587627f7eb2Smrg /* Call the user defined formatted READ procedure. */
1588627f7eb2Smrg dtp->u.p.current_unit->child_dtio++;
1589627f7eb2Smrg dtp->u.p.current_unit->last_char = EOF - 1;
1590627f7eb2Smrg dtp->u.p.fdtio_ptr (p, &unit, iotype, f->u.udf.vlist,
1591627f7eb2Smrg child_iostat, child_iomsg,
1592627f7eb2Smrg iotype_len, child_iomsg_len);
1593627f7eb2Smrg dtp->u.p.current_unit->child_dtio--;
1594627f7eb2Smrg
1595627f7eb2Smrg if (f->u.udf.string_len != 0)
1596627f7eb2Smrg free (iotype);
1597627f7eb2Smrg /* Note: vlist is freed in free_format_data. */
1598627f7eb2Smrg break;
1599627f7eb2Smrg
1600627f7eb2Smrg case FMT_E:
1601627f7eb2Smrg if (n == 0)
1602627f7eb2Smrg goto need_read_data;
1603627f7eb2Smrg if (require_type (dtp, BT_REAL, type, f))
1604627f7eb2Smrg return;
1605627f7eb2Smrg read_f (dtp, f, p, kind);
1606627f7eb2Smrg break;
1607627f7eb2Smrg
1608627f7eb2Smrg case FMT_EN:
1609627f7eb2Smrg if (n == 0)
1610627f7eb2Smrg goto need_read_data;
1611627f7eb2Smrg if (require_type (dtp, BT_REAL, type, f))
1612627f7eb2Smrg return;
1613627f7eb2Smrg read_f (dtp, f, p, kind);
1614627f7eb2Smrg break;
1615627f7eb2Smrg
1616627f7eb2Smrg case FMT_ES:
1617627f7eb2Smrg if (n == 0)
1618627f7eb2Smrg goto need_read_data;
1619627f7eb2Smrg if (require_type (dtp, BT_REAL, type, f))
1620627f7eb2Smrg return;
1621627f7eb2Smrg read_f (dtp, f, p, kind);
1622627f7eb2Smrg break;
1623627f7eb2Smrg
1624627f7eb2Smrg case FMT_F:
1625627f7eb2Smrg if (n == 0)
1626627f7eb2Smrg goto need_read_data;
1627627f7eb2Smrg if (require_type (dtp, BT_REAL, type, f))
1628627f7eb2Smrg return;
1629627f7eb2Smrg read_f (dtp, f, p, kind);
1630627f7eb2Smrg break;
1631627f7eb2Smrg
1632627f7eb2Smrg case FMT_G:
1633627f7eb2Smrg if (n == 0)
1634627f7eb2Smrg goto need_read_data;
1635627f7eb2Smrg switch (type)
1636627f7eb2Smrg {
1637627f7eb2Smrg case BT_INTEGER:
1638627f7eb2Smrg read_decimal (dtp, f, p, kind);
1639627f7eb2Smrg break;
1640627f7eb2Smrg case BT_LOGICAL:
1641627f7eb2Smrg read_l (dtp, f, p, kind);
1642627f7eb2Smrg break;
1643627f7eb2Smrg case BT_CHARACTER:
1644627f7eb2Smrg if (kind == 4)
1645627f7eb2Smrg read_a_char4 (dtp, f, p, size);
1646627f7eb2Smrg else
1647627f7eb2Smrg read_a (dtp, f, p, size);
1648627f7eb2Smrg break;
1649627f7eb2Smrg case BT_REAL:
1650627f7eb2Smrg read_f (dtp, f, p, kind);
1651627f7eb2Smrg break;
1652627f7eb2Smrg default:
1653627f7eb2Smrg internal_error (&dtp->common,
1654627f7eb2Smrg "formatted_transfer (): Bad type");
1655627f7eb2Smrg }
1656627f7eb2Smrg break;
1657627f7eb2Smrg
1658627f7eb2Smrg case FMT_STRING:
1659627f7eb2Smrg consume_data_flag = 0;
1660627f7eb2Smrg format_error (dtp, f, "Constant string in input format");
1661627f7eb2Smrg return;
1662627f7eb2Smrg
1663627f7eb2Smrg /* Format codes that don't transfer data. */
1664627f7eb2Smrg case FMT_X:
1665627f7eb2Smrg case FMT_TR:
1666627f7eb2Smrg consume_data_flag = 0;
1667627f7eb2Smrg dtp->u.p.skips += f->u.n;
1668627f7eb2Smrg pos = bytes_used + dtp->u.p.skips - 1;
1669627f7eb2Smrg dtp->u.p.pending_spaces = pos - dtp->u.p.max_pos + 1;
1670627f7eb2Smrg read_x (dtp, f->u.n);
1671627f7eb2Smrg break;
1672627f7eb2Smrg
1673627f7eb2Smrg case FMT_TL:
1674627f7eb2Smrg case FMT_T:
1675627f7eb2Smrg consume_data_flag = 0;
1676627f7eb2Smrg
1677627f7eb2Smrg if (f->format == FMT_TL)
1678627f7eb2Smrg {
1679627f7eb2Smrg /* Handle the special case when no bytes have been used yet.
1680627f7eb2Smrg Cannot go below zero. */
1681627f7eb2Smrg if (bytes_used == 0)
1682627f7eb2Smrg {
1683627f7eb2Smrg dtp->u.p.pending_spaces -= f->u.n;
1684627f7eb2Smrg dtp->u.p.skips -= f->u.n;
1685627f7eb2Smrg dtp->u.p.skips = dtp->u.p.skips < 0 ? 0 : dtp->u.p.skips;
1686627f7eb2Smrg }
1687627f7eb2Smrg
1688627f7eb2Smrg pos = bytes_used - f->u.n;
1689627f7eb2Smrg }
1690627f7eb2Smrg else /* FMT_T */
1691627f7eb2Smrg pos = f->u.n - 1;
1692627f7eb2Smrg
1693627f7eb2Smrg /* Standard 10.6.1.1: excessive left tabbing is reset to the
1694627f7eb2Smrg left tab limit. We do not check if the position has gone
1695627f7eb2Smrg beyond the end of record because a subsequent tab could
1696627f7eb2Smrg bring us back again. */
1697627f7eb2Smrg pos = pos < 0 ? 0 : pos;
1698627f7eb2Smrg
1699627f7eb2Smrg dtp->u.p.skips = dtp->u.p.skips + pos - bytes_used;
1700627f7eb2Smrg dtp->u.p.pending_spaces = dtp->u.p.pending_spaces
1701627f7eb2Smrg + pos - dtp->u.p.max_pos;
1702627f7eb2Smrg dtp->u.p.pending_spaces = dtp->u.p.pending_spaces < 0
1703627f7eb2Smrg ? 0 : dtp->u.p.pending_spaces;
1704627f7eb2Smrg if (dtp->u.p.skips == 0)
1705627f7eb2Smrg break;
1706627f7eb2Smrg
1707627f7eb2Smrg /* Adjust everything for end-of-record condition */
1708627f7eb2Smrg if (dtp->u.p.sf_seen_eor && !is_internal_unit (dtp))
1709627f7eb2Smrg {
1710627f7eb2Smrg dtp->u.p.current_unit->bytes_left -= dtp->u.p.sf_seen_eor;
1711627f7eb2Smrg dtp->u.p.skips -= dtp->u.p.sf_seen_eor;
1712627f7eb2Smrg bytes_used = pos;
1713627f7eb2Smrg if (dtp->u.p.pending_spaces == 0)
1714627f7eb2Smrg dtp->u.p.sf_seen_eor = 0;
1715627f7eb2Smrg }
1716627f7eb2Smrg if (dtp->u.p.skips < 0)
1717627f7eb2Smrg {
1718627f7eb2Smrg if (is_internal_unit (dtp))
1719627f7eb2Smrg sseek (dtp->u.p.current_unit->s, dtp->u.p.skips, SEEK_CUR);
1720627f7eb2Smrg else
1721627f7eb2Smrg fbuf_seek (dtp->u.p.current_unit, dtp->u.p.skips, SEEK_CUR);
1722627f7eb2Smrg dtp->u.p.current_unit->bytes_left -= (gfc_offset) dtp->u.p.skips;
1723627f7eb2Smrg dtp->u.p.skips = dtp->u.p.pending_spaces = 0;
1724627f7eb2Smrg }
1725627f7eb2Smrg else
1726627f7eb2Smrg read_x (dtp, dtp->u.p.skips);
1727627f7eb2Smrg break;
1728627f7eb2Smrg
1729627f7eb2Smrg case FMT_S:
1730627f7eb2Smrg consume_data_flag = 0;
1731*4c3eb207Smrg dtp->u.p.sign_status = SIGN_PROCDEFINED;
1732627f7eb2Smrg break;
1733627f7eb2Smrg
1734627f7eb2Smrg case FMT_SS:
1735627f7eb2Smrg consume_data_flag = 0;
1736*4c3eb207Smrg dtp->u.p.sign_status = SIGN_SUPPRESS;
1737627f7eb2Smrg break;
1738627f7eb2Smrg
1739627f7eb2Smrg case FMT_SP:
1740627f7eb2Smrg consume_data_flag = 0;
1741*4c3eb207Smrg dtp->u.p.sign_status = SIGN_PLUS;
1742627f7eb2Smrg break;
1743627f7eb2Smrg
1744627f7eb2Smrg case FMT_BN:
1745627f7eb2Smrg consume_data_flag = 0 ;
1746627f7eb2Smrg dtp->u.p.blank_status = BLANK_NULL;
1747627f7eb2Smrg break;
1748627f7eb2Smrg
1749627f7eb2Smrg case FMT_BZ:
1750627f7eb2Smrg consume_data_flag = 0;
1751627f7eb2Smrg dtp->u.p.blank_status = BLANK_ZERO;
1752627f7eb2Smrg break;
1753627f7eb2Smrg
1754627f7eb2Smrg case FMT_DC:
1755627f7eb2Smrg consume_data_flag = 0;
1756627f7eb2Smrg dtp->u.p.current_unit->decimal_status = DECIMAL_COMMA;
1757627f7eb2Smrg break;
1758627f7eb2Smrg
1759627f7eb2Smrg case FMT_DP:
1760627f7eb2Smrg consume_data_flag = 0;
1761627f7eb2Smrg dtp->u.p.current_unit->decimal_status = DECIMAL_POINT;
1762627f7eb2Smrg break;
1763627f7eb2Smrg
1764627f7eb2Smrg case FMT_RC:
1765627f7eb2Smrg consume_data_flag = 0;
1766627f7eb2Smrg dtp->u.p.current_unit->round_status = ROUND_COMPATIBLE;
1767627f7eb2Smrg break;
1768627f7eb2Smrg
1769627f7eb2Smrg case FMT_RD:
1770627f7eb2Smrg consume_data_flag = 0;
1771627f7eb2Smrg dtp->u.p.current_unit->round_status = ROUND_DOWN;
1772627f7eb2Smrg break;
1773627f7eb2Smrg
1774627f7eb2Smrg case FMT_RN:
1775627f7eb2Smrg consume_data_flag = 0;
1776627f7eb2Smrg dtp->u.p.current_unit->round_status = ROUND_NEAREST;
1777627f7eb2Smrg break;
1778627f7eb2Smrg
1779627f7eb2Smrg case FMT_RP:
1780627f7eb2Smrg consume_data_flag = 0;
1781627f7eb2Smrg dtp->u.p.current_unit->round_status = ROUND_PROCDEFINED;
1782627f7eb2Smrg break;
1783627f7eb2Smrg
1784627f7eb2Smrg case FMT_RU:
1785627f7eb2Smrg consume_data_flag = 0;
1786627f7eb2Smrg dtp->u.p.current_unit->round_status = ROUND_UP;
1787627f7eb2Smrg break;
1788627f7eb2Smrg
1789627f7eb2Smrg case FMT_RZ:
1790627f7eb2Smrg consume_data_flag = 0;
1791627f7eb2Smrg dtp->u.p.current_unit->round_status = ROUND_ZERO;
1792627f7eb2Smrg break;
1793627f7eb2Smrg
1794627f7eb2Smrg case FMT_P:
1795627f7eb2Smrg consume_data_flag = 0;
1796627f7eb2Smrg dtp->u.p.scale_factor = f->u.k;
1797627f7eb2Smrg break;
1798627f7eb2Smrg
1799627f7eb2Smrg case FMT_DOLLAR:
1800627f7eb2Smrg consume_data_flag = 0;
1801627f7eb2Smrg dtp->u.p.seen_dollar = 1;
1802627f7eb2Smrg break;
1803627f7eb2Smrg
1804627f7eb2Smrg case FMT_SLASH:
1805627f7eb2Smrg consume_data_flag = 0;
1806627f7eb2Smrg dtp->u.p.skips = dtp->u.p.pending_spaces = 0;
1807627f7eb2Smrg next_record (dtp, 0);
1808627f7eb2Smrg break;
1809627f7eb2Smrg
1810627f7eb2Smrg case FMT_COLON:
1811627f7eb2Smrg /* A colon descriptor causes us to exit this loop (in
1812627f7eb2Smrg particular preventing another / descriptor from being
1813627f7eb2Smrg processed) unless there is another data item to be
1814627f7eb2Smrg transferred. */
1815627f7eb2Smrg consume_data_flag = 0;
1816627f7eb2Smrg if (n == 0)
1817627f7eb2Smrg return;
1818627f7eb2Smrg break;
1819627f7eb2Smrg
1820627f7eb2Smrg default:
1821627f7eb2Smrg internal_error (&dtp->common, "Bad format node");
1822627f7eb2Smrg }
1823627f7eb2Smrg
1824627f7eb2Smrg /* Adjust the item count and data pointer. */
1825627f7eb2Smrg
1826627f7eb2Smrg if ((consume_data_flag > 0) && (n > 0))
1827627f7eb2Smrg {
1828627f7eb2Smrg n--;
1829627f7eb2Smrg p = ((char *) p) + size;
1830627f7eb2Smrg }
1831627f7eb2Smrg
1832627f7eb2Smrg dtp->u.p.skips = 0;
1833627f7eb2Smrg
1834627f7eb2Smrg pos = (int)(dtp->u.p.current_unit->recl - dtp->u.p.current_unit->bytes_left);
1835627f7eb2Smrg dtp->u.p.max_pos = (dtp->u.p.max_pos > pos) ? dtp->u.p.max_pos : pos;
1836627f7eb2Smrg }
1837627f7eb2Smrg
1838627f7eb2Smrg return;
1839627f7eb2Smrg
1840627f7eb2Smrg /* Come here when we need a data descriptor but don't have one. We
1841627f7eb2Smrg push the current format node back onto the input, then return and
1842627f7eb2Smrg let the user program call us back with the data. */
1843627f7eb2Smrg need_read_data:
1844627f7eb2Smrg unget_format (dtp, f);
1845627f7eb2Smrg }
1846627f7eb2Smrg
1847627f7eb2Smrg
1848627f7eb2Smrg static void
formatted_transfer_scalar_write(st_parameter_dt * dtp,bt type,void * p,int kind,size_t size)1849627f7eb2Smrg formatted_transfer_scalar_write (st_parameter_dt *dtp, bt type, void *p, int kind,
1850627f7eb2Smrg size_t size)
1851627f7eb2Smrg {
1852627f7eb2Smrg gfc_offset pos, bytes_used;
1853627f7eb2Smrg const fnode *f;
1854627f7eb2Smrg format_token t;
1855627f7eb2Smrg int n;
1856627f7eb2Smrg int consume_data_flag;
1857627f7eb2Smrg
1858627f7eb2Smrg /* Change a complex data item into a pair of reals. */
1859627f7eb2Smrg
1860627f7eb2Smrg n = (p == NULL) ? 0 : ((type != BT_COMPLEX) ? 1 : 2);
1861627f7eb2Smrg if (type == BT_COMPLEX)
1862627f7eb2Smrg {
1863627f7eb2Smrg type = BT_REAL;
1864627f7eb2Smrg size /= 2;
1865627f7eb2Smrg }
1866627f7eb2Smrg
1867627f7eb2Smrg /* If there's an EOR condition, we simulate finalizing the transfer
1868627f7eb2Smrg by doing nothing. */
1869627f7eb2Smrg if (dtp->u.p.eor_condition)
1870627f7eb2Smrg return;
1871627f7eb2Smrg
1872627f7eb2Smrg /* Set this flag so that commas in reads cause the read to complete before
1873627f7eb2Smrg the entire field has been read. The next read field will start right after
1874627f7eb2Smrg the comma in the stream. (Set to 0 for character reads). */
1875627f7eb2Smrg dtp->u.p.sf_read_comma =
1876627f7eb2Smrg dtp->u.p.current_unit->decimal_status == DECIMAL_COMMA ? 0 : 1;
1877627f7eb2Smrg
1878627f7eb2Smrg for (;;)
1879627f7eb2Smrg {
1880627f7eb2Smrg /* If reversion has occurred and there is another real data item,
1881627f7eb2Smrg then we have to move to the next record. */
1882627f7eb2Smrg if (dtp->u.p.reversion_flag && n > 0)
1883627f7eb2Smrg {
1884627f7eb2Smrg dtp->u.p.reversion_flag = 0;
1885627f7eb2Smrg next_record (dtp, 0);
1886627f7eb2Smrg }
1887627f7eb2Smrg
1888627f7eb2Smrg consume_data_flag = 1;
1889627f7eb2Smrg if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
1890627f7eb2Smrg break;
1891627f7eb2Smrg
1892627f7eb2Smrg f = next_format (dtp);
1893627f7eb2Smrg if (f == NULL)
1894627f7eb2Smrg {
1895627f7eb2Smrg /* No data descriptors left. */
1896627f7eb2Smrg if (unlikely (n > 0))
1897627f7eb2Smrg generate_error (&dtp->common, LIBERROR_FORMAT,
1898627f7eb2Smrg "Insufficient data descriptors in format after reversion");
1899627f7eb2Smrg return;
1900627f7eb2Smrg }
1901627f7eb2Smrg
1902627f7eb2Smrg /* Now discharge T, TR and X movements to the right. This is delayed
1903627f7eb2Smrg until a data producing format to suppress trailing spaces. */
1904627f7eb2Smrg
1905627f7eb2Smrg t = f->format;
1906627f7eb2Smrg if (dtp->u.p.mode == WRITING && dtp->u.p.skips != 0
1907627f7eb2Smrg && ((n>0 && ( t == FMT_I || t == FMT_B || t == FMT_O
1908627f7eb2Smrg || t == FMT_Z || t == FMT_F || t == FMT_E
1909627f7eb2Smrg || t == FMT_EN || t == FMT_ES || t == FMT_G
1910627f7eb2Smrg || t == FMT_L || t == FMT_A || t == FMT_D
1911627f7eb2Smrg || t == FMT_DT))
1912627f7eb2Smrg || t == FMT_STRING))
1913627f7eb2Smrg {
1914627f7eb2Smrg if (dtp->u.p.skips > 0)
1915627f7eb2Smrg {
1916627f7eb2Smrg gfc_offset tmp;
1917627f7eb2Smrg write_x (dtp, dtp->u.p.skips, dtp->u.p.pending_spaces);
1918627f7eb2Smrg tmp = dtp->u.p.current_unit->recl
1919627f7eb2Smrg - dtp->u.p.current_unit->bytes_left;
1920627f7eb2Smrg dtp->u.p.max_pos =
1921627f7eb2Smrg dtp->u.p.max_pos > tmp ? dtp->u.p.max_pos : tmp;
1922627f7eb2Smrg dtp->u.p.skips = 0;
1923627f7eb2Smrg }
1924627f7eb2Smrg if (dtp->u.p.skips < 0)
1925627f7eb2Smrg {
1926627f7eb2Smrg if (is_internal_unit (dtp))
1927627f7eb2Smrg sseek (dtp->u.p.current_unit->s, dtp->u.p.skips, SEEK_CUR);
1928627f7eb2Smrg else
1929627f7eb2Smrg fbuf_seek (dtp->u.p.current_unit, dtp->u.p.skips, SEEK_CUR);
1930627f7eb2Smrg dtp->u.p.current_unit->bytes_left -= (gfc_offset) dtp->u.p.skips;
1931627f7eb2Smrg }
1932627f7eb2Smrg dtp->u.p.skips = dtp->u.p.pending_spaces = 0;
1933627f7eb2Smrg }
1934627f7eb2Smrg
1935627f7eb2Smrg bytes_used = dtp->u.p.current_unit->recl
1936627f7eb2Smrg - dtp->u.p.current_unit->bytes_left;
1937627f7eb2Smrg
1938627f7eb2Smrg if (is_stream_io(dtp))
1939627f7eb2Smrg bytes_used = 0;
1940627f7eb2Smrg
1941627f7eb2Smrg switch (t)
1942627f7eb2Smrg {
1943627f7eb2Smrg case FMT_I:
1944627f7eb2Smrg if (n == 0)
1945627f7eb2Smrg goto need_data;
1946627f7eb2Smrg if (require_type (dtp, BT_INTEGER, type, f))
1947627f7eb2Smrg return;
1948627f7eb2Smrg write_i (dtp, f, p, kind);
1949627f7eb2Smrg break;
1950627f7eb2Smrg
1951627f7eb2Smrg case FMT_B:
1952627f7eb2Smrg if (n == 0)
1953627f7eb2Smrg goto need_data;
1954627f7eb2Smrg if (!(compile_options.allow_std & GFC_STD_GNU)
1955627f7eb2Smrg && require_numeric_type (dtp, type, f))
1956627f7eb2Smrg return;
1957627f7eb2Smrg if (!(compile_options.allow_std & GFC_STD_F2008)
1958627f7eb2Smrg && require_type (dtp, BT_INTEGER, type, f))
1959627f7eb2Smrg return;
1960627f7eb2Smrg write_b (dtp, f, p, kind);
1961627f7eb2Smrg break;
1962627f7eb2Smrg
1963627f7eb2Smrg case FMT_O:
1964627f7eb2Smrg if (n == 0)
1965627f7eb2Smrg goto need_data;
1966627f7eb2Smrg if (!(compile_options.allow_std & GFC_STD_GNU)
1967627f7eb2Smrg && require_numeric_type (dtp, type, f))
1968627f7eb2Smrg return;
1969627f7eb2Smrg if (!(compile_options.allow_std & GFC_STD_F2008)
1970627f7eb2Smrg && require_type (dtp, BT_INTEGER, type, f))
1971627f7eb2Smrg return;
1972627f7eb2Smrg write_o (dtp, f, p, kind);
1973627f7eb2Smrg break;
1974627f7eb2Smrg
1975627f7eb2Smrg case FMT_Z:
1976627f7eb2Smrg if (n == 0)
1977627f7eb2Smrg goto need_data;
1978627f7eb2Smrg if (!(compile_options.allow_std & GFC_STD_GNU)
1979627f7eb2Smrg && require_numeric_type (dtp, type, f))
1980627f7eb2Smrg return;
1981627f7eb2Smrg if (!(compile_options.allow_std & GFC_STD_F2008)
1982627f7eb2Smrg && require_type (dtp, BT_INTEGER, type, f))
1983627f7eb2Smrg return;
1984627f7eb2Smrg write_z (dtp, f, p, kind);
1985627f7eb2Smrg break;
1986627f7eb2Smrg
1987627f7eb2Smrg case FMT_A:
1988627f7eb2Smrg if (n == 0)
1989627f7eb2Smrg goto need_data;
1990627f7eb2Smrg
1991627f7eb2Smrg /* It is possible to have FMT_A with something not BT_CHARACTER such
1992627f7eb2Smrg as when writing out hollerith strings, so check both type
1993627f7eb2Smrg and kind before calling wide character routines. */
1994627f7eb2Smrg if (type == BT_CHARACTER && kind == 4)
1995627f7eb2Smrg write_a_char4 (dtp, f, p, size);
1996627f7eb2Smrg else
1997627f7eb2Smrg write_a (dtp, f, p, size);
1998627f7eb2Smrg break;
1999627f7eb2Smrg
2000627f7eb2Smrg case FMT_L:
2001627f7eb2Smrg if (n == 0)
2002627f7eb2Smrg goto need_data;
2003627f7eb2Smrg write_l (dtp, f, p, kind);
2004627f7eb2Smrg break;
2005627f7eb2Smrg
2006627f7eb2Smrg case FMT_D:
2007627f7eb2Smrg if (n == 0)
2008627f7eb2Smrg goto need_data;
2009627f7eb2Smrg if (require_type (dtp, BT_REAL, type, f))
2010627f7eb2Smrg return;
2011*4c3eb207Smrg if (f->u.real.w == 0)
2012*4c3eb207Smrg write_real_w0 (dtp, p, kind, f);
2013*4c3eb207Smrg else
2014627f7eb2Smrg write_d (dtp, f, p, kind);
2015627f7eb2Smrg break;
2016627f7eb2Smrg
2017627f7eb2Smrg case FMT_DT:
2018627f7eb2Smrg if (n == 0)
2019627f7eb2Smrg goto need_data;
2020627f7eb2Smrg int unit = dtp->u.p.current_unit->unit_number;
2021627f7eb2Smrg char dt[] = "DT";
2022627f7eb2Smrg char tmp_iomsg[IOMSG_LEN] = "";
2023627f7eb2Smrg char *child_iomsg;
2024627f7eb2Smrg gfc_charlen_type child_iomsg_len;
2025627f7eb2Smrg int noiostat;
2026627f7eb2Smrg int *child_iostat = NULL;
2027627f7eb2Smrg char *iotype;
2028627f7eb2Smrg gfc_charlen_type iotype_len = f->u.udf.string_len;
2029627f7eb2Smrg
2030627f7eb2Smrg /* Build the iotype string. */
2031627f7eb2Smrg if (iotype_len == 0)
2032627f7eb2Smrg {
2033627f7eb2Smrg iotype_len = 2;
2034627f7eb2Smrg iotype = dt;
2035627f7eb2Smrg }
2036627f7eb2Smrg else
2037627f7eb2Smrg iotype = get_dt_format (f->u.udf.string, &iotype_len);
2038627f7eb2Smrg
2039627f7eb2Smrg /* Set iostat, intent(out). */
2040627f7eb2Smrg noiostat = 0;
2041627f7eb2Smrg child_iostat = (dtp->common.flags & IOPARM_HAS_IOSTAT) ?
2042627f7eb2Smrg dtp->common.iostat : &noiostat;
2043627f7eb2Smrg
2044627f7eb2Smrg /* Set iomsg, intent(inout). */
2045627f7eb2Smrg if (dtp->common.flags & IOPARM_HAS_IOMSG)
2046627f7eb2Smrg {
2047627f7eb2Smrg child_iomsg = dtp->common.iomsg;
2048627f7eb2Smrg child_iomsg_len = dtp->common.iomsg_len;
2049627f7eb2Smrg }
2050627f7eb2Smrg else
2051627f7eb2Smrg {
2052627f7eb2Smrg child_iomsg = tmp_iomsg;
2053627f7eb2Smrg child_iomsg_len = IOMSG_LEN;
2054627f7eb2Smrg }
2055627f7eb2Smrg
2056627f7eb2Smrg if (check_dtio_proc (dtp, f))
2057627f7eb2Smrg return;
2058627f7eb2Smrg
2059627f7eb2Smrg /* Call the user defined formatted WRITE procedure. */
2060627f7eb2Smrg dtp->u.p.current_unit->child_dtio++;
2061627f7eb2Smrg
2062627f7eb2Smrg dtp->u.p.fdtio_ptr (p, &unit, iotype, f->u.udf.vlist,
2063627f7eb2Smrg child_iostat, child_iomsg,
2064627f7eb2Smrg iotype_len, child_iomsg_len);
2065627f7eb2Smrg dtp->u.p.current_unit->child_dtio--;
2066627f7eb2Smrg
2067627f7eb2Smrg if (f->u.udf.string_len != 0)
2068627f7eb2Smrg free (iotype);
2069627f7eb2Smrg /* Note: vlist is freed in free_format_data. */
2070627f7eb2Smrg break;
2071627f7eb2Smrg
2072627f7eb2Smrg case FMT_E:
2073627f7eb2Smrg if (n == 0)
2074627f7eb2Smrg goto need_data;
2075627f7eb2Smrg if (require_type (dtp, BT_REAL, type, f))
2076627f7eb2Smrg return;
2077*4c3eb207Smrg if (f->u.real.w == 0)
2078*4c3eb207Smrg write_real_w0 (dtp, p, kind, f);
2079*4c3eb207Smrg else
2080627f7eb2Smrg write_e (dtp, f, p, kind);
2081627f7eb2Smrg break;
2082627f7eb2Smrg
2083627f7eb2Smrg case FMT_EN:
2084627f7eb2Smrg if (n == 0)
2085627f7eb2Smrg goto need_data;
2086627f7eb2Smrg if (require_type (dtp, BT_REAL, type, f))
2087627f7eb2Smrg return;
2088*4c3eb207Smrg if (f->u.real.w == 0)
2089*4c3eb207Smrg write_real_w0 (dtp, p, kind, f);
2090*4c3eb207Smrg else
2091627f7eb2Smrg write_en (dtp, f, p, kind);
2092627f7eb2Smrg break;
2093627f7eb2Smrg
2094627f7eb2Smrg case FMT_ES:
2095627f7eb2Smrg if (n == 0)
2096627f7eb2Smrg goto need_data;
2097627f7eb2Smrg if (require_type (dtp, BT_REAL, type, f))
2098627f7eb2Smrg return;
2099*4c3eb207Smrg if (f->u.real.w == 0)
2100*4c3eb207Smrg write_real_w0 (dtp, p, kind, f);
2101*4c3eb207Smrg else
2102627f7eb2Smrg write_es (dtp, f, p, kind);
2103627f7eb2Smrg break;
2104627f7eb2Smrg
2105627f7eb2Smrg case FMT_F:
2106627f7eb2Smrg if (n == 0)
2107627f7eb2Smrg goto need_data;
2108627f7eb2Smrg if (require_type (dtp, BT_REAL, type, f))
2109627f7eb2Smrg return;
2110627f7eb2Smrg write_f (dtp, f, p, kind);
2111627f7eb2Smrg break;
2112627f7eb2Smrg
2113627f7eb2Smrg case FMT_G:
2114627f7eb2Smrg if (n == 0)
2115627f7eb2Smrg goto need_data;
2116627f7eb2Smrg switch (type)
2117627f7eb2Smrg {
2118627f7eb2Smrg case BT_INTEGER:
2119627f7eb2Smrg write_i (dtp, f, p, kind);
2120627f7eb2Smrg break;
2121627f7eb2Smrg case BT_LOGICAL:
2122627f7eb2Smrg write_l (dtp, f, p, kind);
2123627f7eb2Smrg break;
2124627f7eb2Smrg case BT_CHARACTER:
2125627f7eb2Smrg if (kind == 4)
2126627f7eb2Smrg write_a_char4 (dtp, f, p, size);
2127627f7eb2Smrg else
2128627f7eb2Smrg write_a (dtp, f, p, size);
2129627f7eb2Smrg break;
2130627f7eb2Smrg case BT_REAL:
2131627f7eb2Smrg if (f->u.real.w == 0)
2132*4c3eb207Smrg write_real_w0 (dtp, p, kind, f);
2133627f7eb2Smrg else
2134627f7eb2Smrg write_d (dtp, f, p, kind);
2135627f7eb2Smrg break;
2136627f7eb2Smrg default:
2137627f7eb2Smrg internal_error (&dtp->common,
2138627f7eb2Smrg "formatted_transfer (): Bad type");
2139627f7eb2Smrg }
2140627f7eb2Smrg break;
2141627f7eb2Smrg
2142627f7eb2Smrg case FMT_STRING:
2143627f7eb2Smrg consume_data_flag = 0;
2144627f7eb2Smrg write_constant_string (dtp, f);
2145627f7eb2Smrg break;
2146627f7eb2Smrg
2147627f7eb2Smrg /* Format codes that don't transfer data. */
2148627f7eb2Smrg case FMT_X:
2149627f7eb2Smrg case FMT_TR:
2150627f7eb2Smrg consume_data_flag = 0;
2151627f7eb2Smrg
2152627f7eb2Smrg dtp->u.p.skips += f->u.n;
2153627f7eb2Smrg pos = bytes_used + dtp->u.p.skips - 1;
2154627f7eb2Smrg dtp->u.p.pending_spaces = pos - dtp->u.p.max_pos + 1;
2155627f7eb2Smrg /* Writes occur just before the switch on f->format, above, so
2156627f7eb2Smrg that trailing blanks are suppressed, unless we are doing a
2157627f7eb2Smrg non-advancing write in which case we want to output the blanks
2158627f7eb2Smrg now. */
2159627f7eb2Smrg if (dtp->u.p.advance_status == ADVANCE_NO)
2160627f7eb2Smrg {
2161627f7eb2Smrg write_x (dtp, dtp->u.p.skips, dtp->u.p.pending_spaces);
2162627f7eb2Smrg dtp->u.p.skips = dtp->u.p.pending_spaces = 0;
2163627f7eb2Smrg }
2164627f7eb2Smrg break;
2165627f7eb2Smrg
2166627f7eb2Smrg case FMT_TL:
2167627f7eb2Smrg case FMT_T:
2168627f7eb2Smrg consume_data_flag = 0;
2169627f7eb2Smrg
2170627f7eb2Smrg if (f->format == FMT_TL)
2171627f7eb2Smrg {
2172627f7eb2Smrg
2173627f7eb2Smrg /* Handle the special case when no bytes have been used yet.
2174627f7eb2Smrg Cannot go below zero. */
2175627f7eb2Smrg if (bytes_used == 0)
2176627f7eb2Smrg {
2177627f7eb2Smrg dtp->u.p.pending_spaces -= f->u.n;
2178627f7eb2Smrg dtp->u.p.skips -= f->u.n;
2179627f7eb2Smrg dtp->u.p.skips = dtp->u.p.skips < 0 ? 0 : dtp->u.p.skips;
2180627f7eb2Smrg }
2181627f7eb2Smrg
2182627f7eb2Smrg pos = bytes_used - f->u.n;
2183627f7eb2Smrg }
2184627f7eb2Smrg else /* FMT_T */
2185627f7eb2Smrg pos = f->u.n - dtp->u.p.pending_spaces - 1;
2186627f7eb2Smrg
2187627f7eb2Smrg /* Standard 10.6.1.1: excessive left tabbing is reset to the
2188627f7eb2Smrg left tab limit. We do not check if the position has gone
2189627f7eb2Smrg beyond the end of record because a subsequent tab could
2190627f7eb2Smrg bring us back again. */
2191627f7eb2Smrg pos = pos < 0 ? 0 : pos;
2192627f7eb2Smrg
2193627f7eb2Smrg dtp->u.p.skips = dtp->u.p.skips + pos - bytes_used;
2194627f7eb2Smrg dtp->u.p.pending_spaces = dtp->u.p.pending_spaces
2195627f7eb2Smrg + pos - dtp->u.p.max_pos;
2196627f7eb2Smrg dtp->u.p.pending_spaces = dtp->u.p.pending_spaces < 0
2197627f7eb2Smrg ? 0 : dtp->u.p.pending_spaces;
2198627f7eb2Smrg break;
2199627f7eb2Smrg
2200627f7eb2Smrg case FMT_S:
2201627f7eb2Smrg consume_data_flag = 0;
2202*4c3eb207Smrg dtp->u.p.sign_status = SIGN_PROCDEFINED;
2203627f7eb2Smrg break;
2204627f7eb2Smrg
2205627f7eb2Smrg case FMT_SS:
2206627f7eb2Smrg consume_data_flag = 0;
2207*4c3eb207Smrg dtp->u.p.sign_status = SIGN_SUPPRESS;
2208627f7eb2Smrg break;
2209627f7eb2Smrg
2210627f7eb2Smrg case FMT_SP:
2211627f7eb2Smrg consume_data_flag = 0;
2212*4c3eb207Smrg dtp->u.p.sign_status = SIGN_PLUS;
2213627f7eb2Smrg break;
2214627f7eb2Smrg
2215627f7eb2Smrg case FMT_BN:
2216627f7eb2Smrg consume_data_flag = 0 ;
2217627f7eb2Smrg dtp->u.p.blank_status = BLANK_NULL;
2218627f7eb2Smrg break;
2219627f7eb2Smrg
2220627f7eb2Smrg case FMT_BZ:
2221627f7eb2Smrg consume_data_flag = 0;
2222627f7eb2Smrg dtp->u.p.blank_status = BLANK_ZERO;
2223627f7eb2Smrg break;
2224627f7eb2Smrg
2225627f7eb2Smrg case FMT_DC:
2226627f7eb2Smrg consume_data_flag = 0;
2227627f7eb2Smrg dtp->u.p.current_unit->decimal_status = DECIMAL_COMMA;
2228627f7eb2Smrg break;
2229627f7eb2Smrg
2230627f7eb2Smrg case FMT_DP:
2231627f7eb2Smrg consume_data_flag = 0;
2232627f7eb2Smrg dtp->u.p.current_unit->decimal_status = DECIMAL_POINT;
2233627f7eb2Smrg break;
2234627f7eb2Smrg
2235627f7eb2Smrg case FMT_RC:
2236627f7eb2Smrg consume_data_flag = 0;
2237627f7eb2Smrg dtp->u.p.current_unit->round_status = ROUND_COMPATIBLE;
2238627f7eb2Smrg break;
2239627f7eb2Smrg
2240627f7eb2Smrg case FMT_RD:
2241627f7eb2Smrg consume_data_flag = 0;
2242627f7eb2Smrg dtp->u.p.current_unit->round_status = ROUND_DOWN;
2243627f7eb2Smrg break;
2244627f7eb2Smrg
2245627f7eb2Smrg case FMT_RN:
2246627f7eb2Smrg consume_data_flag = 0;
2247627f7eb2Smrg dtp->u.p.current_unit->round_status = ROUND_NEAREST;
2248627f7eb2Smrg break;
2249627f7eb2Smrg
2250627f7eb2Smrg case FMT_RP:
2251627f7eb2Smrg consume_data_flag = 0;
2252627f7eb2Smrg dtp->u.p.current_unit->round_status = ROUND_PROCDEFINED;
2253627f7eb2Smrg break;
2254627f7eb2Smrg
2255627f7eb2Smrg case FMT_RU:
2256627f7eb2Smrg consume_data_flag = 0;
2257627f7eb2Smrg dtp->u.p.current_unit->round_status = ROUND_UP;
2258627f7eb2Smrg break;
2259627f7eb2Smrg
2260627f7eb2Smrg case FMT_RZ:
2261627f7eb2Smrg consume_data_flag = 0;
2262627f7eb2Smrg dtp->u.p.current_unit->round_status = ROUND_ZERO;
2263627f7eb2Smrg break;
2264627f7eb2Smrg
2265627f7eb2Smrg case FMT_P:
2266627f7eb2Smrg consume_data_flag = 0;
2267627f7eb2Smrg dtp->u.p.scale_factor = f->u.k;
2268627f7eb2Smrg break;
2269627f7eb2Smrg
2270627f7eb2Smrg case FMT_DOLLAR:
2271627f7eb2Smrg consume_data_flag = 0;
2272627f7eb2Smrg dtp->u.p.seen_dollar = 1;
2273627f7eb2Smrg break;
2274627f7eb2Smrg
2275627f7eb2Smrg case FMT_SLASH:
2276627f7eb2Smrg consume_data_flag = 0;
2277627f7eb2Smrg dtp->u.p.skips = dtp->u.p.pending_spaces = 0;
2278627f7eb2Smrg next_record (dtp, 0);
2279627f7eb2Smrg break;
2280627f7eb2Smrg
2281627f7eb2Smrg case FMT_COLON:
2282627f7eb2Smrg /* A colon descriptor causes us to exit this loop (in
2283627f7eb2Smrg particular preventing another / descriptor from being
2284627f7eb2Smrg processed) unless there is another data item to be
2285627f7eb2Smrg transferred. */
2286627f7eb2Smrg consume_data_flag = 0;
2287627f7eb2Smrg if (n == 0)
2288627f7eb2Smrg return;
2289627f7eb2Smrg break;
2290627f7eb2Smrg
2291627f7eb2Smrg default:
2292627f7eb2Smrg internal_error (&dtp->common, "Bad format node");
2293627f7eb2Smrg }
2294627f7eb2Smrg
2295627f7eb2Smrg /* Adjust the item count and data pointer. */
2296627f7eb2Smrg
2297627f7eb2Smrg if ((consume_data_flag > 0) && (n > 0))
2298627f7eb2Smrg {
2299627f7eb2Smrg n--;
2300627f7eb2Smrg p = ((char *) p) + size;
2301627f7eb2Smrg }
2302627f7eb2Smrg
2303627f7eb2Smrg pos = dtp->u.p.current_unit->recl - dtp->u.p.current_unit->bytes_left;
2304627f7eb2Smrg dtp->u.p.max_pos = (dtp->u.p.max_pos > pos) ? dtp->u.p.max_pos : pos;
2305627f7eb2Smrg }
2306627f7eb2Smrg
2307627f7eb2Smrg return;
2308627f7eb2Smrg
2309627f7eb2Smrg /* Come here when we need a data descriptor but don't have one. We
2310627f7eb2Smrg push the current format node back onto the input, then return and
2311627f7eb2Smrg let the user program call us back with the data. */
2312627f7eb2Smrg need_data:
2313627f7eb2Smrg unget_format (dtp, f);
2314627f7eb2Smrg }
2315627f7eb2Smrg
2316627f7eb2Smrg /* This function is first called from data_init_transfer to initiate the loop
2317627f7eb2Smrg over each item in the format, transferring data as required. Subsequent
2318627f7eb2Smrg calls to this function occur for each data item foound in the READ/WRITE
2319627f7eb2Smrg statement. The item_count is incremented for each call. Since the first
2320627f7eb2Smrg call is from data_transfer_init, the item_count is always one greater than
2321627f7eb2Smrg the actual count number of the item being transferred. */
2322627f7eb2Smrg
2323627f7eb2Smrg static void
formatted_transfer(st_parameter_dt * dtp,bt type,void * p,int kind,size_t size,size_t nelems)2324627f7eb2Smrg formatted_transfer (st_parameter_dt *dtp, bt type, void *p, int kind,
2325627f7eb2Smrg size_t size, size_t nelems)
2326627f7eb2Smrg {
2327627f7eb2Smrg size_t elem;
2328627f7eb2Smrg char *tmp;
2329627f7eb2Smrg
2330627f7eb2Smrg tmp = (char *) p;
2331627f7eb2Smrg size_t stride = type == BT_CHARACTER ?
2332627f7eb2Smrg size * GFC_SIZE_OF_CHAR_KIND(kind) : size;
2333627f7eb2Smrg if (dtp->u.p.mode == READING)
2334627f7eb2Smrg {
2335627f7eb2Smrg /* Big loop over all the elements. */
2336627f7eb2Smrg for (elem = 0; elem < nelems; elem++)
2337627f7eb2Smrg {
2338627f7eb2Smrg dtp->u.p.item_count++;
2339627f7eb2Smrg formatted_transfer_scalar_read (dtp, type, tmp + stride*elem, kind, size);
2340627f7eb2Smrg }
2341627f7eb2Smrg }
2342627f7eb2Smrg else
2343627f7eb2Smrg {
2344627f7eb2Smrg /* Big loop over all the elements. */
2345627f7eb2Smrg for (elem = 0; elem < nelems; elem++)
2346627f7eb2Smrg {
2347627f7eb2Smrg dtp->u.p.item_count++;
2348627f7eb2Smrg formatted_transfer_scalar_write (dtp, type, tmp + stride*elem, kind, size);
2349627f7eb2Smrg }
2350627f7eb2Smrg }
2351627f7eb2Smrg }
2352627f7eb2Smrg
2353627f7eb2Smrg /* Wrapper function for I/O of scalar types. If this should be an async I/O
2354627f7eb2Smrg request, queue it. For a synchronous write on an async unit, perform the
2355627f7eb2Smrg wait operation and return an error. For all synchronous writes, call the
2356627f7eb2Smrg right transfer function. */
2357627f7eb2Smrg
2358627f7eb2Smrg static void
wrap_scalar_transfer(st_parameter_dt * dtp,bt type,void * p,int kind,size_t size,size_t n_elem)2359627f7eb2Smrg wrap_scalar_transfer (st_parameter_dt *dtp, bt type, void *p, int kind,
2360627f7eb2Smrg size_t size, size_t n_elem)
2361627f7eb2Smrg {
2362627f7eb2Smrg if (dtp->u.p.current_unit && dtp->u.p.current_unit->au)
2363627f7eb2Smrg {
2364627f7eb2Smrg if (dtp->u.p.async)
2365627f7eb2Smrg {
2366627f7eb2Smrg transfer_args args;
2367627f7eb2Smrg args.scalar.transfer = dtp->u.p.transfer;
2368627f7eb2Smrg args.scalar.arg_bt = type;
2369627f7eb2Smrg args.scalar.data = p;
2370627f7eb2Smrg args.scalar.i = kind;
2371627f7eb2Smrg args.scalar.s1 = size;
2372627f7eb2Smrg args.scalar.s2 = n_elem;
2373627f7eb2Smrg enqueue_transfer (dtp->u.p.current_unit->au, &args,
2374627f7eb2Smrg AIO_TRANSFER_SCALAR);
2375627f7eb2Smrg return;
2376627f7eb2Smrg }
2377627f7eb2Smrg }
2378627f7eb2Smrg /* Come here if there was no asynchronous I/O to be scheduled. */
2379627f7eb2Smrg if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
2380627f7eb2Smrg return;
2381627f7eb2Smrg
2382627f7eb2Smrg dtp->u.p.transfer (dtp, type, p, kind, size, 1);
2383627f7eb2Smrg }
2384627f7eb2Smrg
2385627f7eb2Smrg
2386627f7eb2Smrg /* Data transfer entry points. The type of the data entity is
2387627f7eb2Smrg implicit in the subroutine call. This prevents us from having to
2388627f7eb2Smrg share a common enum with the compiler. */
2389627f7eb2Smrg
2390627f7eb2Smrg void
transfer_integer(st_parameter_dt * dtp,void * p,int kind)2391627f7eb2Smrg transfer_integer (st_parameter_dt *dtp, void *p, int kind)
2392627f7eb2Smrg {
2393627f7eb2Smrg wrap_scalar_transfer (dtp, BT_INTEGER, p, kind, kind, 1);
2394627f7eb2Smrg }
2395627f7eb2Smrg
2396627f7eb2Smrg void
transfer_integer_write(st_parameter_dt * dtp,void * p,int kind)2397627f7eb2Smrg transfer_integer_write (st_parameter_dt *dtp, void *p, int kind)
2398627f7eb2Smrg {
2399627f7eb2Smrg transfer_integer (dtp, p, kind);
2400627f7eb2Smrg }
2401627f7eb2Smrg
2402627f7eb2Smrg void
transfer_real(st_parameter_dt * dtp,void * p,int kind)2403627f7eb2Smrg transfer_real (st_parameter_dt *dtp, void *p, int kind)
2404627f7eb2Smrg {
2405627f7eb2Smrg size_t size;
2406627f7eb2Smrg if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
2407627f7eb2Smrg return;
2408627f7eb2Smrg size = size_from_real_kind (kind);
2409627f7eb2Smrg wrap_scalar_transfer (dtp, BT_REAL, p, kind, size, 1);
2410627f7eb2Smrg }
2411627f7eb2Smrg
2412627f7eb2Smrg void
transfer_real_write(st_parameter_dt * dtp,void * p,int kind)2413627f7eb2Smrg transfer_real_write (st_parameter_dt *dtp, void *p, int kind)
2414627f7eb2Smrg {
2415627f7eb2Smrg transfer_real (dtp, p, kind);
2416627f7eb2Smrg }
2417627f7eb2Smrg
2418627f7eb2Smrg void
transfer_logical(st_parameter_dt * dtp,void * p,int kind)2419627f7eb2Smrg transfer_logical (st_parameter_dt *dtp, void *p, int kind)
2420627f7eb2Smrg {
2421627f7eb2Smrg wrap_scalar_transfer (dtp, BT_LOGICAL, p, kind, kind, 1);
2422627f7eb2Smrg }
2423627f7eb2Smrg
2424627f7eb2Smrg void
transfer_logical_write(st_parameter_dt * dtp,void * p,int kind)2425627f7eb2Smrg transfer_logical_write (st_parameter_dt *dtp, void *p, int kind)
2426627f7eb2Smrg {
2427627f7eb2Smrg transfer_logical (dtp, p, kind);
2428627f7eb2Smrg }
2429627f7eb2Smrg
2430627f7eb2Smrg void
transfer_character(st_parameter_dt * dtp,void * p,gfc_charlen_type len)2431627f7eb2Smrg transfer_character (st_parameter_dt *dtp, void *p, gfc_charlen_type len)
2432627f7eb2Smrg {
2433627f7eb2Smrg static char *empty_string[0];
2434627f7eb2Smrg
2435627f7eb2Smrg if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
2436627f7eb2Smrg return;
2437627f7eb2Smrg
2438627f7eb2Smrg /* Strings of zero length can have p == NULL, which confuses the
2439627f7eb2Smrg transfer routines into thinking we need more data elements. To avoid
2440627f7eb2Smrg this, we give them a nice pointer. */
2441627f7eb2Smrg if (len == 0 && p == NULL)
2442627f7eb2Smrg p = empty_string;
2443627f7eb2Smrg
2444627f7eb2Smrg /* Set kind here to 1. */
2445627f7eb2Smrg wrap_scalar_transfer (dtp, BT_CHARACTER, p, 1, len, 1);
2446627f7eb2Smrg }
2447627f7eb2Smrg
2448627f7eb2Smrg void
transfer_character_write(st_parameter_dt * dtp,void * p,gfc_charlen_type len)2449627f7eb2Smrg transfer_character_write (st_parameter_dt *dtp, void *p, gfc_charlen_type len)
2450627f7eb2Smrg {
2451627f7eb2Smrg transfer_character (dtp, p, len);
2452627f7eb2Smrg }
2453627f7eb2Smrg
2454627f7eb2Smrg void
transfer_character_wide(st_parameter_dt * dtp,void * p,gfc_charlen_type len,int kind)2455627f7eb2Smrg transfer_character_wide (st_parameter_dt *dtp, void *p, gfc_charlen_type len, int kind)
2456627f7eb2Smrg {
2457627f7eb2Smrg static char *empty_string[0];
2458627f7eb2Smrg
2459627f7eb2Smrg if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
2460627f7eb2Smrg return;
2461627f7eb2Smrg
2462627f7eb2Smrg /* Strings of zero length can have p == NULL, which confuses the
2463627f7eb2Smrg transfer routines into thinking we need more data elements. To avoid
2464627f7eb2Smrg this, we give them a nice pointer. */
2465627f7eb2Smrg if (len == 0 && p == NULL)
2466627f7eb2Smrg p = empty_string;
2467627f7eb2Smrg
2468627f7eb2Smrg /* Here we pass the actual kind value. */
2469627f7eb2Smrg wrap_scalar_transfer (dtp, BT_CHARACTER, p, kind, len, 1);
2470627f7eb2Smrg }
2471627f7eb2Smrg
2472627f7eb2Smrg void
transfer_character_wide_write(st_parameter_dt * dtp,void * p,gfc_charlen_type len,int kind)2473627f7eb2Smrg transfer_character_wide_write (st_parameter_dt *dtp, void *p, gfc_charlen_type len, int kind)
2474627f7eb2Smrg {
2475627f7eb2Smrg transfer_character_wide (dtp, p, len, kind);
2476627f7eb2Smrg }
2477627f7eb2Smrg
2478627f7eb2Smrg void
transfer_complex(st_parameter_dt * dtp,void * p,int kind)2479627f7eb2Smrg transfer_complex (st_parameter_dt *dtp, void *p, int kind)
2480627f7eb2Smrg {
2481627f7eb2Smrg size_t size;
2482627f7eb2Smrg if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
2483627f7eb2Smrg return;
2484627f7eb2Smrg size = size_from_complex_kind (kind);
2485627f7eb2Smrg wrap_scalar_transfer (dtp, BT_COMPLEX, p, kind, size, 1);
2486627f7eb2Smrg }
2487627f7eb2Smrg
2488627f7eb2Smrg void
transfer_complex_write(st_parameter_dt * dtp,void * p,int kind)2489627f7eb2Smrg transfer_complex_write (st_parameter_dt *dtp, void *p, int kind)
2490627f7eb2Smrg {
2491627f7eb2Smrg transfer_complex (dtp, p, kind);
2492627f7eb2Smrg }
2493627f7eb2Smrg
2494627f7eb2Smrg void
transfer_array_inner(st_parameter_dt * dtp,gfc_array_char * desc,int kind,gfc_charlen_type charlen)2495627f7eb2Smrg transfer_array_inner (st_parameter_dt *dtp, gfc_array_char *desc, int kind,
2496627f7eb2Smrg gfc_charlen_type charlen)
2497627f7eb2Smrg {
2498627f7eb2Smrg index_type count[GFC_MAX_DIMENSIONS];
2499627f7eb2Smrg index_type extent[GFC_MAX_DIMENSIONS];
2500627f7eb2Smrg index_type stride[GFC_MAX_DIMENSIONS];
2501627f7eb2Smrg index_type stride0, rank, size, n;
2502627f7eb2Smrg size_t tsize;
2503627f7eb2Smrg char *data;
2504627f7eb2Smrg bt iotype;
2505627f7eb2Smrg
2506627f7eb2Smrg /* Adjust item_count before emitting error message. */
2507627f7eb2Smrg
2508627f7eb2Smrg if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
2509627f7eb2Smrg return;
2510627f7eb2Smrg
2511627f7eb2Smrg iotype = (bt) GFC_DESCRIPTOR_TYPE (desc);
2512627f7eb2Smrg size = iotype == BT_CHARACTER ? charlen : GFC_DESCRIPTOR_SIZE (desc);
2513627f7eb2Smrg
2514627f7eb2Smrg rank = GFC_DESCRIPTOR_RANK (desc);
2515627f7eb2Smrg
2516627f7eb2Smrg for (n = 0; n < rank; n++)
2517627f7eb2Smrg {
2518627f7eb2Smrg count[n] = 0;
2519627f7eb2Smrg stride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(desc,n);
2520627f7eb2Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(desc,n);
2521627f7eb2Smrg
2522627f7eb2Smrg /* If the extent of even one dimension is zero, then the entire
2523627f7eb2Smrg array section contains zero elements, so we return after writing
2524627f7eb2Smrg a zero array record. */
2525627f7eb2Smrg if (extent[n] <= 0)
2526627f7eb2Smrg {
2527627f7eb2Smrg data = NULL;
2528627f7eb2Smrg tsize = 0;
2529627f7eb2Smrg dtp->u.p.transfer (dtp, iotype, data, kind, size, tsize);
2530627f7eb2Smrg return;
2531627f7eb2Smrg }
2532627f7eb2Smrg }
2533627f7eb2Smrg
2534627f7eb2Smrg stride0 = stride[0];
2535627f7eb2Smrg
2536627f7eb2Smrg /* If the innermost dimension has a stride of 1, we can do the transfer
2537627f7eb2Smrg in contiguous chunks. */
2538627f7eb2Smrg if (stride0 == size)
2539627f7eb2Smrg tsize = extent[0];
2540627f7eb2Smrg else
2541627f7eb2Smrg tsize = 1;
2542627f7eb2Smrg
2543627f7eb2Smrg data = GFC_DESCRIPTOR_DATA (desc);
2544627f7eb2Smrg
2545627f7eb2Smrg /* When reading, we need to check endfile conditions so we do not miss
2546627f7eb2Smrg an END=label. Make this separate so we do not have an extra test
2547627f7eb2Smrg in a tight loop when it is not needed. */
2548627f7eb2Smrg
2549627f7eb2Smrg if (dtp->u.p.current_unit && dtp->u.p.mode == READING)
2550627f7eb2Smrg {
2551627f7eb2Smrg while (data)
2552627f7eb2Smrg {
2553627f7eb2Smrg if (unlikely (dtp->u.p.current_unit->endfile == AFTER_ENDFILE))
2554627f7eb2Smrg return;
2555627f7eb2Smrg
2556627f7eb2Smrg dtp->u.p.transfer (dtp, iotype, data, kind, size, tsize);
2557627f7eb2Smrg data += stride0 * tsize;
2558627f7eb2Smrg count[0] += tsize;
2559627f7eb2Smrg n = 0;
2560627f7eb2Smrg while (count[n] == extent[n])
2561627f7eb2Smrg {
2562627f7eb2Smrg count[n] = 0;
2563627f7eb2Smrg data -= stride[n] * extent[n];
2564627f7eb2Smrg n++;
2565627f7eb2Smrg if (n == rank)
2566627f7eb2Smrg {
2567627f7eb2Smrg data = NULL;
2568627f7eb2Smrg break;
2569627f7eb2Smrg }
2570627f7eb2Smrg else
2571627f7eb2Smrg {
2572627f7eb2Smrg count[n]++;
2573627f7eb2Smrg data += stride[n];
2574627f7eb2Smrg }
2575627f7eb2Smrg }
2576627f7eb2Smrg }
2577627f7eb2Smrg }
2578627f7eb2Smrg else
2579627f7eb2Smrg {
2580627f7eb2Smrg while (data)
2581627f7eb2Smrg {
2582627f7eb2Smrg dtp->u.p.transfer (dtp, iotype, data, kind, size, tsize);
2583627f7eb2Smrg data += stride0 * tsize;
2584627f7eb2Smrg count[0] += tsize;
2585627f7eb2Smrg n = 0;
2586627f7eb2Smrg while (count[n] == extent[n])
2587627f7eb2Smrg {
2588627f7eb2Smrg count[n] = 0;
2589627f7eb2Smrg data -= stride[n] * extent[n];
2590627f7eb2Smrg n++;
2591627f7eb2Smrg if (n == rank)
2592627f7eb2Smrg {
2593627f7eb2Smrg data = NULL;
2594627f7eb2Smrg break;
2595627f7eb2Smrg }
2596627f7eb2Smrg else
2597627f7eb2Smrg {
2598627f7eb2Smrg count[n]++;
2599627f7eb2Smrg data += stride[n];
2600627f7eb2Smrg }
2601627f7eb2Smrg }
2602627f7eb2Smrg }
2603627f7eb2Smrg }
2604627f7eb2Smrg }
2605627f7eb2Smrg
2606627f7eb2Smrg void
transfer_array(st_parameter_dt * dtp,gfc_array_char * desc,int kind,gfc_charlen_type charlen)2607627f7eb2Smrg transfer_array (st_parameter_dt *dtp, gfc_array_char *desc, int kind,
2608627f7eb2Smrg gfc_charlen_type charlen)
2609627f7eb2Smrg {
2610627f7eb2Smrg if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
2611627f7eb2Smrg return;
2612627f7eb2Smrg
2613627f7eb2Smrg if (dtp->u.p.current_unit && dtp->u.p.current_unit->au)
2614627f7eb2Smrg {
2615627f7eb2Smrg if (dtp->u.p.async)
2616627f7eb2Smrg {
2617627f7eb2Smrg transfer_args args;
2618627f7eb2Smrg size_t sz = sizeof (gfc_array_char)
2619627f7eb2Smrg + sizeof (descriptor_dimension)
2620627f7eb2Smrg * GFC_DESCRIPTOR_RANK (desc);
2621627f7eb2Smrg args.array.desc = xmalloc (sz);
2622627f7eb2Smrg NOTE ("desc = %p", (void *) args.array.desc);
2623627f7eb2Smrg memcpy (args.array.desc, desc, sz);
2624627f7eb2Smrg args.array.kind = kind;
2625627f7eb2Smrg args.array.charlen = charlen;
2626627f7eb2Smrg enqueue_transfer (dtp->u.p.current_unit->au, &args,
2627627f7eb2Smrg AIO_TRANSFER_ARRAY);
2628627f7eb2Smrg return;
2629627f7eb2Smrg }
2630627f7eb2Smrg }
2631627f7eb2Smrg /* Come here if there was no asynchronous I/O to be scheduled. */
2632627f7eb2Smrg transfer_array_inner (dtp, desc, kind, charlen);
2633627f7eb2Smrg }
2634627f7eb2Smrg
2635627f7eb2Smrg
2636627f7eb2Smrg void
transfer_array_write(st_parameter_dt * dtp,gfc_array_char * desc,int kind,gfc_charlen_type charlen)2637627f7eb2Smrg transfer_array_write (st_parameter_dt *dtp, gfc_array_char *desc, int kind,
2638627f7eb2Smrg gfc_charlen_type charlen)
2639627f7eb2Smrg {
2640627f7eb2Smrg transfer_array (dtp, desc, kind, charlen);
2641627f7eb2Smrg }
2642627f7eb2Smrg
2643627f7eb2Smrg
2644627f7eb2Smrg /* User defined input/output iomsg. */
2645627f7eb2Smrg
2646627f7eb2Smrg #define IOMSG_LEN 256
2647627f7eb2Smrg
2648627f7eb2Smrg void
transfer_derived(st_parameter_dt * parent,void * dtio_source,void * dtio_proc)2649627f7eb2Smrg transfer_derived (st_parameter_dt *parent, void *dtio_source, void *dtio_proc)
2650627f7eb2Smrg {
2651627f7eb2Smrg if (parent->u.p.current_unit)
2652627f7eb2Smrg {
2653627f7eb2Smrg if (parent->u.p.current_unit->flags.form == FORM_UNFORMATTED)
2654627f7eb2Smrg parent->u.p.ufdtio_ptr = (unformatted_dtio) dtio_proc;
2655627f7eb2Smrg else
2656627f7eb2Smrg parent->u.p.fdtio_ptr = (formatted_dtio) dtio_proc;
2657627f7eb2Smrg }
2658627f7eb2Smrg wrap_scalar_transfer (parent, BT_CLASS, dtio_source, 0, 0, 1);
2659627f7eb2Smrg }
2660627f7eb2Smrg
2661627f7eb2Smrg
2662627f7eb2Smrg /* Preposition a sequential unformatted file while reading. */
2663627f7eb2Smrg
2664627f7eb2Smrg static void
us_read(st_parameter_dt * dtp,int continued)2665627f7eb2Smrg us_read (st_parameter_dt *dtp, int continued)
2666627f7eb2Smrg {
2667627f7eb2Smrg ssize_t n, nr;
2668627f7eb2Smrg GFC_INTEGER_4 i4;
2669627f7eb2Smrg GFC_INTEGER_8 i8;
2670627f7eb2Smrg gfc_offset i;
2671627f7eb2Smrg
2672627f7eb2Smrg if (compile_options.record_marker == 0)
2673627f7eb2Smrg n = sizeof (GFC_INTEGER_4);
2674627f7eb2Smrg else
2675627f7eb2Smrg n = compile_options.record_marker;
2676627f7eb2Smrg
2677627f7eb2Smrg nr = sread (dtp->u.p.current_unit->s, &i, n);
2678627f7eb2Smrg if (unlikely (nr < 0))
2679627f7eb2Smrg {
2680627f7eb2Smrg generate_error (&dtp->common, LIBERROR_BAD_US, NULL);
2681627f7eb2Smrg return;
2682627f7eb2Smrg }
2683627f7eb2Smrg else if (nr == 0)
2684627f7eb2Smrg {
2685627f7eb2Smrg hit_eof (dtp);
2686627f7eb2Smrg return; /* end of file */
2687627f7eb2Smrg }
2688627f7eb2Smrg else if (unlikely (n != nr))
2689627f7eb2Smrg {
2690627f7eb2Smrg generate_error (&dtp->common, LIBERROR_BAD_US, NULL);
2691627f7eb2Smrg return;
2692627f7eb2Smrg }
2693627f7eb2Smrg
2694627f7eb2Smrg /* Only GFC_CONVERT_NATIVE and GFC_CONVERT_SWAP are valid here. */
2695627f7eb2Smrg if (likely (dtp->u.p.current_unit->flags.convert == GFC_CONVERT_NATIVE))
2696627f7eb2Smrg {
2697627f7eb2Smrg switch (nr)
2698627f7eb2Smrg {
2699627f7eb2Smrg case sizeof(GFC_INTEGER_4):
2700627f7eb2Smrg memcpy (&i4, &i, sizeof (i4));
2701627f7eb2Smrg i = i4;
2702627f7eb2Smrg break;
2703627f7eb2Smrg
2704627f7eb2Smrg case sizeof(GFC_INTEGER_8):
2705627f7eb2Smrg memcpy (&i8, &i, sizeof (i8));
2706627f7eb2Smrg i = i8;
2707627f7eb2Smrg break;
2708627f7eb2Smrg
2709627f7eb2Smrg default:
2710627f7eb2Smrg runtime_error ("Illegal value for record marker");
2711627f7eb2Smrg break;
2712627f7eb2Smrg }
2713627f7eb2Smrg }
2714627f7eb2Smrg else
2715627f7eb2Smrg {
2716627f7eb2Smrg uint32_t u32;
2717627f7eb2Smrg uint64_t u64;
2718627f7eb2Smrg switch (nr)
2719627f7eb2Smrg {
2720627f7eb2Smrg case sizeof(GFC_INTEGER_4):
2721627f7eb2Smrg memcpy (&u32, &i, sizeof (u32));
2722627f7eb2Smrg u32 = __builtin_bswap32 (u32);
2723627f7eb2Smrg memcpy (&i4, &u32, sizeof (i4));
2724627f7eb2Smrg i = i4;
2725627f7eb2Smrg break;
2726627f7eb2Smrg
2727627f7eb2Smrg case sizeof(GFC_INTEGER_8):
2728627f7eb2Smrg memcpy (&u64, &i, sizeof (u64));
2729627f7eb2Smrg u64 = __builtin_bswap64 (u64);
2730627f7eb2Smrg memcpy (&i8, &u64, sizeof (i8));
2731627f7eb2Smrg i = i8;
2732627f7eb2Smrg break;
2733627f7eb2Smrg
2734627f7eb2Smrg default:
2735627f7eb2Smrg runtime_error ("Illegal value for record marker");
2736627f7eb2Smrg break;
2737627f7eb2Smrg }
2738627f7eb2Smrg }
2739627f7eb2Smrg
2740627f7eb2Smrg if (i >= 0)
2741627f7eb2Smrg {
2742627f7eb2Smrg dtp->u.p.current_unit->bytes_left_subrecord = i;
2743627f7eb2Smrg dtp->u.p.current_unit->continued = 0;
2744627f7eb2Smrg }
2745627f7eb2Smrg else
2746627f7eb2Smrg {
2747627f7eb2Smrg dtp->u.p.current_unit->bytes_left_subrecord = -i;
2748627f7eb2Smrg dtp->u.p.current_unit->continued = 1;
2749627f7eb2Smrg }
2750627f7eb2Smrg
2751627f7eb2Smrg if (! continued)
2752627f7eb2Smrg dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
2753627f7eb2Smrg }
2754627f7eb2Smrg
2755627f7eb2Smrg
2756627f7eb2Smrg /* Preposition a sequential unformatted file while writing. This
2757627f7eb2Smrg amount to writing a bogus length that will be filled in later. */
2758627f7eb2Smrg
2759627f7eb2Smrg static void
us_write(st_parameter_dt * dtp,int continued)2760627f7eb2Smrg us_write (st_parameter_dt *dtp, int continued)
2761627f7eb2Smrg {
2762627f7eb2Smrg ssize_t nbytes;
2763627f7eb2Smrg gfc_offset dummy;
2764627f7eb2Smrg
2765627f7eb2Smrg dummy = 0;
2766627f7eb2Smrg
2767627f7eb2Smrg if (compile_options.record_marker == 0)
2768627f7eb2Smrg nbytes = sizeof (GFC_INTEGER_4);
2769627f7eb2Smrg else
2770627f7eb2Smrg nbytes = compile_options.record_marker ;
2771627f7eb2Smrg
2772627f7eb2Smrg if (swrite (dtp->u.p.current_unit->s, &dummy, nbytes) != nbytes)
2773627f7eb2Smrg generate_error (&dtp->common, LIBERROR_OS, NULL);
2774627f7eb2Smrg
2775627f7eb2Smrg /* For sequential unformatted, if RECL= was not specified in the OPEN
2776627f7eb2Smrg we write until we have more bytes than can fit in the subrecord
2777627f7eb2Smrg markers, then we write a new subrecord. */
2778627f7eb2Smrg
2779627f7eb2Smrg dtp->u.p.current_unit->bytes_left_subrecord =
2780627f7eb2Smrg dtp->u.p.current_unit->recl_subrecord;
2781627f7eb2Smrg dtp->u.p.current_unit->continued = continued;
2782627f7eb2Smrg }
2783627f7eb2Smrg
2784627f7eb2Smrg
2785627f7eb2Smrg /* Position to the next record prior to transfer. We are assumed to
2786627f7eb2Smrg be before the next record. We also calculate the bytes in the next
2787627f7eb2Smrg record. */
2788627f7eb2Smrg
2789627f7eb2Smrg static void
pre_position(st_parameter_dt * dtp)2790627f7eb2Smrg pre_position (st_parameter_dt *dtp)
2791627f7eb2Smrg {
2792627f7eb2Smrg if (dtp->u.p.current_unit->current_record)
2793627f7eb2Smrg return; /* Already positioned. */
2794627f7eb2Smrg
2795627f7eb2Smrg switch (current_mode (dtp))
2796627f7eb2Smrg {
2797627f7eb2Smrg case FORMATTED_STREAM:
2798627f7eb2Smrg case UNFORMATTED_STREAM:
2799627f7eb2Smrg /* There are no records with stream I/O. If the position was specified
2800627f7eb2Smrg data_transfer_init has already positioned the file. If no position
2801627f7eb2Smrg was specified, we continue from where we last left off. I.e.
2802627f7eb2Smrg there is nothing to do here. */
2803627f7eb2Smrg break;
2804627f7eb2Smrg
2805627f7eb2Smrg case UNFORMATTED_SEQUENTIAL:
2806627f7eb2Smrg if (dtp->u.p.mode == READING)
2807627f7eb2Smrg us_read (dtp, 0);
2808627f7eb2Smrg else
2809627f7eb2Smrg us_write (dtp, 0);
2810627f7eb2Smrg
2811627f7eb2Smrg break;
2812627f7eb2Smrg
2813627f7eb2Smrg case FORMATTED_SEQUENTIAL:
2814627f7eb2Smrg case FORMATTED_DIRECT:
2815627f7eb2Smrg case UNFORMATTED_DIRECT:
2816627f7eb2Smrg dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
2817627f7eb2Smrg break;
2818*4c3eb207Smrg case FORMATTED_UNSPECIFIED:
2819*4c3eb207Smrg gcc_unreachable ();
2820627f7eb2Smrg }
2821627f7eb2Smrg
2822627f7eb2Smrg dtp->u.p.current_unit->current_record = 1;
2823627f7eb2Smrg }
2824627f7eb2Smrg
2825627f7eb2Smrg
2826627f7eb2Smrg /* Initialize things for a data transfer. This code is common for
2827627f7eb2Smrg both reading and writing. */
2828627f7eb2Smrg
2829627f7eb2Smrg static void
data_transfer_init(st_parameter_dt * dtp,int read_flag)2830627f7eb2Smrg data_transfer_init (st_parameter_dt *dtp, int read_flag)
2831627f7eb2Smrg {
2832627f7eb2Smrg unit_flags u_flags; /* Used for creating a unit if needed. */
2833627f7eb2Smrg GFC_INTEGER_4 cf = dtp->common.flags;
2834627f7eb2Smrg namelist_info *ionml;
2835627f7eb2Smrg async_unit *au;
2836627f7eb2Smrg
2837627f7eb2Smrg NOTE ("data_transfer_init");
2838627f7eb2Smrg
2839627f7eb2Smrg ionml = ((cf & IOPARM_DT_IONML_SET) != 0) ? dtp->u.p.ionml : NULL;
2840627f7eb2Smrg
2841627f7eb2Smrg memset (&dtp->u.p, 0, sizeof (dtp->u.p));
2842627f7eb2Smrg
2843627f7eb2Smrg dtp->u.p.ionml = ionml;
2844627f7eb2Smrg dtp->u.p.mode = read_flag ? READING : WRITING;
2845627f7eb2Smrg dtp->u.p.namelist_mode = 0;
2846627f7eb2Smrg dtp->u.p.cc.len = 0;
2847627f7eb2Smrg
2848627f7eb2Smrg if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
2849627f7eb2Smrg return;
2850627f7eb2Smrg
2851627f7eb2Smrg dtp->u.p.current_unit = get_unit (dtp, 1);
2852627f7eb2Smrg
2853627f7eb2Smrg if (dtp->u.p.current_unit == NULL)
2854627f7eb2Smrg {
2855627f7eb2Smrg /* This means we tried to access an external unit < 0 without
2856627f7eb2Smrg having opened it first with NEWUNIT=. */
2857627f7eb2Smrg generate_error (&dtp->common, LIBERROR_BAD_OPTION,
2858627f7eb2Smrg "Unit number is negative and unit was not already "
2859627f7eb2Smrg "opened with OPEN(NEWUNIT=...)");
2860627f7eb2Smrg return;
2861627f7eb2Smrg }
2862627f7eb2Smrg else if (dtp->u.p.current_unit->s == NULL)
2863627f7eb2Smrg { /* Open the unit with some default flags. */
2864627f7eb2Smrg st_parameter_open opp;
2865627f7eb2Smrg unit_convert conv;
2866627f7eb2Smrg NOTE ("Open the unit with some default flags.");
2867627f7eb2Smrg memset (&u_flags, '\0', sizeof (u_flags));
2868627f7eb2Smrg u_flags.access = ACCESS_SEQUENTIAL;
2869627f7eb2Smrg u_flags.action = ACTION_READWRITE;
2870627f7eb2Smrg
2871627f7eb2Smrg /* Is it unformatted? */
2872627f7eb2Smrg if (!(cf & (IOPARM_DT_HAS_FORMAT | IOPARM_DT_LIST_FORMAT
2873627f7eb2Smrg | IOPARM_DT_IONML_SET)))
2874627f7eb2Smrg u_flags.form = FORM_UNFORMATTED;
2875627f7eb2Smrg else
2876627f7eb2Smrg u_flags.form = FORM_UNSPECIFIED;
2877627f7eb2Smrg
2878627f7eb2Smrg u_flags.delim = DELIM_UNSPECIFIED;
2879627f7eb2Smrg u_flags.blank = BLANK_UNSPECIFIED;
2880627f7eb2Smrg u_flags.pad = PAD_UNSPECIFIED;
2881627f7eb2Smrg u_flags.decimal = DECIMAL_UNSPECIFIED;
2882627f7eb2Smrg u_flags.encoding = ENCODING_UNSPECIFIED;
2883627f7eb2Smrg u_flags.async = ASYNC_UNSPECIFIED;
2884627f7eb2Smrg u_flags.round = ROUND_UNSPECIFIED;
2885627f7eb2Smrg u_flags.sign = SIGN_UNSPECIFIED;
2886627f7eb2Smrg u_flags.share = SHARE_UNSPECIFIED;
2887627f7eb2Smrg u_flags.cc = CC_UNSPECIFIED;
2888627f7eb2Smrg u_flags.readonly = 0;
2889627f7eb2Smrg
2890627f7eb2Smrg u_flags.status = STATUS_UNKNOWN;
2891627f7eb2Smrg
2892627f7eb2Smrg conv = get_unformatted_convert (dtp->common.unit);
2893627f7eb2Smrg
2894627f7eb2Smrg if (conv == GFC_CONVERT_NONE)
2895627f7eb2Smrg conv = compile_options.convert;
2896627f7eb2Smrg
2897627f7eb2Smrg switch (conv)
2898627f7eb2Smrg {
2899627f7eb2Smrg case GFC_CONVERT_NATIVE:
2900627f7eb2Smrg case GFC_CONVERT_SWAP:
2901627f7eb2Smrg break;
2902627f7eb2Smrg
2903627f7eb2Smrg case GFC_CONVERT_BIG:
2904627f7eb2Smrg conv = __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ? GFC_CONVERT_NATIVE : GFC_CONVERT_SWAP;
2905627f7eb2Smrg break;
2906627f7eb2Smrg
2907627f7eb2Smrg case GFC_CONVERT_LITTLE:
2908627f7eb2Smrg conv = __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ? GFC_CONVERT_SWAP : GFC_CONVERT_NATIVE;
2909627f7eb2Smrg break;
2910627f7eb2Smrg
2911627f7eb2Smrg default:
2912627f7eb2Smrg internal_error (&opp.common, "Illegal value for CONVERT");
2913627f7eb2Smrg break;
2914627f7eb2Smrg }
2915627f7eb2Smrg
2916627f7eb2Smrg u_flags.convert = conv;
2917627f7eb2Smrg
2918627f7eb2Smrg opp.common = dtp->common;
2919627f7eb2Smrg opp.common.flags &= IOPARM_COMMON_MASK;
2920627f7eb2Smrg dtp->u.p.current_unit = new_unit (&opp, dtp->u.p.current_unit, &u_flags);
2921627f7eb2Smrg dtp->common.flags &= ~IOPARM_COMMON_MASK;
2922627f7eb2Smrg dtp->common.flags |= (opp.common.flags & IOPARM_COMMON_MASK);
2923627f7eb2Smrg if (dtp->u.p.current_unit == NULL)
2924627f7eb2Smrg return;
2925627f7eb2Smrg }
2926627f7eb2Smrg
2927627f7eb2Smrg if (dtp->u.p.current_unit->child_dtio == 0)
2928627f7eb2Smrg {
2929627f7eb2Smrg if ((cf & IOPARM_DT_HAS_SIZE) != 0)
2930627f7eb2Smrg {
2931627f7eb2Smrg dtp->u.p.current_unit->has_size = true;
2932627f7eb2Smrg /* Initialize the count. */
2933627f7eb2Smrg dtp->u.p.current_unit->size_used = 0;
2934627f7eb2Smrg }
2935627f7eb2Smrg else
2936627f7eb2Smrg dtp->u.p.current_unit->has_size = false;
2937627f7eb2Smrg }
2938627f7eb2Smrg else if (dtp->u.p.current_unit->internal_unit_kind > 0)
2939627f7eb2Smrg dtp->u.p.unit_is_internal = 1;
2940627f7eb2Smrg
2941627f7eb2Smrg if ((cf & IOPARM_DT_HAS_ASYNCHRONOUS) != 0)
2942627f7eb2Smrg {
2943627f7eb2Smrg int f;
2944627f7eb2Smrg f = find_option (&dtp->common, dtp->asynchronous, dtp->asynchronous_len,
2945627f7eb2Smrg async_opt, "Bad ASYNCHRONOUS in data transfer "
2946627f7eb2Smrg "statement");
2947627f7eb2Smrg if (f == ASYNC_YES && dtp->u.p.current_unit->flags.async != ASYNC_YES)
2948627f7eb2Smrg {
2949627f7eb2Smrg generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
2950627f7eb2Smrg "ASYNCHRONOUS transfer without "
2951627f7eb2Smrg "ASYHCRONOUS='YES' in OPEN");
2952627f7eb2Smrg return;
2953627f7eb2Smrg }
2954627f7eb2Smrg dtp->u.p.async = f == ASYNC_YES;
2955627f7eb2Smrg }
2956627f7eb2Smrg
2957627f7eb2Smrg au = dtp->u.p.current_unit->au;
2958627f7eb2Smrg if (au)
2959627f7eb2Smrg {
2960627f7eb2Smrg if (dtp->u.p.async)
2961627f7eb2Smrg {
2962627f7eb2Smrg /* If this is an asynchronous I/O statement, collect errors and
2963627f7eb2Smrg return if there are any. */
2964627f7eb2Smrg if (collect_async_errors (&dtp->common, au))
2965627f7eb2Smrg return;
2966627f7eb2Smrg }
2967627f7eb2Smrg else
2968627f7eb2Smrg {
2969627f7eb2Smrg /* Synchronous statement: Perform a wait operation for any pending
2970627f7eb2Smrg asynchronous I/O. This needs to be done before all other error
2971627f7eb2Smrg checks. See F2008, 9.6.4.1. */
2972627f7eb2Smrg if (async_wait (&(dtp->common), au))
2973627f7eb2Smrg return;
2974627f7eb2Smrg }
2975627f7eb2Smrg }
2976627f7eb2Smrg
2977627f7eb2Smrg /* Check the action. */
2978627f7eb2Smrg
2979627f7eb2Smrg if (read_flag && dtp->u.p.current_unit->flags.action == ACTION_WRITE)
2980627f7eb2Smrg {
2981627f7eb2Smrg generate_error (&dtp->common, LIBERROR_BAD_ACTION,
2982627f7eb2Smrg "Cannot read from file opened for WRITE");
2983627f7eb2Smrg return;
2984627f7eb2Smrg }
2985627f7eb2Smrg
2986627f7eb2Smrg if (!read_flag && dtp->u.p.current_unit->flags.action == ACTION_READ)
2987627f7eb2Smrg {
2988627f7eb2Smrg generate_error (&dtp->common, LIBERROR_BAD_ACTION,
2989627f7eb2Smrg "Cannot write to file opened for READ");
2990627f7eb2Smrg return;
2991627f7eb2Smrg }
2992627f7eb2Smrg
2993627f7eb2Smrg dtp->u.p.first_item = 1;
2994627f7eb2Smrg
2995627f7eb2Smrg /* Check the format. */
2996627f7eb2Smrg
2997627f7eb2Smrg if ((cf & IOPARM_DT_HAS_FORMAT) != 0)
2998627f7eb2Smrg parse_format (dtp);
2999627f7eb2Smrg
3000627f7eb2Smrg if (dtp->u.p.current_unit->flags.form == FORM_UNFORMATTED
3001627f7eb2Smrg && (cf & (IOPARM_DT_HAS_FORMAT | IOPARM_DT_LIST_FORMAT))
3002627f7eb2Smrg != 0)
3003627f7eb2Smrg {
3004627f7eb2Smrg generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3005627f7eb2Smrg "Format present for UNFORMATTED data transfer");
3006627f7eb2Smrg return;
3007627f7eb2Smrg }
3008627f7eb2Smrg
3009627f7eb2Smrg if ((cf & IOPARM_DT_HAS_NAMELIST_NAME) != 0 && dtp->u.p.ionml != NULL)
3010627f7eb2Smrg {
3011627f7eb2Smrg if ((cf & IOPARM_DT_HAS_FORMAT) != 0)
3012627f7eb2Smrg {
3013627f7eb2Smrg generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3014627f7eb2Smrg "A format cannot be specified with a namelist");
3015627f7eb2Smrg return;
3016627f7eb2Smrg }
3017627f7eb2Smrg }
3018627f7eb2Smrg else if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED &&
3019627f7eb2Smrg !(cf & (IOPARM_DT_HAS_FORMAT | IOPARM_DT_LIST_FORMAT)))
3020627f7eb2Smrg {
3021627f7eb2Smrg generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3022627f7eb2Smrg "Missing format for FORMATTED data transfer");
3023627f7eb2Smrg return;
3024627f7eb2Smrg }
3025627f7eb2Smrg
3026627f7eb2Smrg if (is_internal_unit (dtp)
3027627f7eb2Smrg && dtp->u.p.current_unit->flags.form == FORM_UNFORMATTED)
3028627f7eb2Smrg {
3029627f7eb2Smrg generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3030627f7eb2Smrg "Internal file cannot be accessed by UNFORMATTED "
3031627f7eb2Smrg "data transfer");
3032627f7eb2Smrg return;
3033627f7eb2Smrg }
3034627f7eb2Smrg
3035627f7eb2Smrg /* Check the record or position number. */
3036627f7eb2Smrg
3037627f7eb2Smrg if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT
3038627f7eb2Smrg && (cf & IOPARM_DT_HAS_REC) == 0)
3039627f7eb2Smrg {
3040627f7eb2Smrg generate_error (&dtp->common, LIBERROR_MISSING_OPTION,
3041627f7eb2Smrg "Direct access data transfer requires record number");
3042627f7eb2Smrg return;
3043627f7eb2Smrg }
3044627f7eb2Smrg
3045627f7eb2Smrg if (dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL)
3046627f7eb2Smrg {
3047627f7eb2Smrg if ((cf & IOPARM_DT_HAS_REC) != 0)
3048627f7eb2Smrg {
3049627f7eb2Smrg generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3050627f7eb2Smrg "Record number not allowed for sequential access "
3051627f7eb2Smrg "data transfer");
3052627f7eb2Smrg return;
3053627f7eb2Smrg }
3054627f7eb2Smrg
3055627f7eb2Smrg if (compile_options.warn_std &&
3056627f7eb2Smrg dtp->u.p.current_unit->endfile == AFTER_ENDFILE)
3057627f7eb2Smrg {
3058627f7eb2Smrg generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3059627f7eb2Smrg "Sequential READ or WRITE not allowed after "
3060627f7eb2Smrg "EOF marker, possibly use REWIND or BACKSPACE");
3061627f7eb2Smrg return;
3062627f7eb2Smrg }
3063627f7eb2Smrg }
3064627f7eb2Smrg
3065627f7eb2Smrg /* Process the ADVANCE option. */
3066627f7eb2Smrg
3067627f7eb2Smrg dtp->u.p.advance_status
3068627f7eb2Smrg = !(cf & IOPARM_DT_HAS_ADVANCE) ? ADVANCE_UNSPECIFIED :
3069627f7eb2Smrg find_option (&dtp->common, dtp->advance, dtp->advance_len, advance_opt,
3070627f7eb2Smrg "Bad ADVANCE parameter in data transfer statement");
3071627f7eb2Smrg
3072627f7eb2Smrg if (dtp->u.p.advance_status != ADVANCE_UNSPECIFIED)
3073627f7eb2Smrg {
3074627f7eb2Smrg if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT)
3075627f7eb2Smrg {
3076627f7eb2Smrg generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3077627f7eb2Smrg "ADVANCE specification conflicts with sequential "
3078627f7eb2Smrg "access");
3079627f7eb2Smrg return;
3080627f7eb2Smrg }
3081627f7eb2Smrg
3082627f7eb2Smrg if (is_internal_unit (dtp))
3083627f7eb2Smrg {
3084627f7eb2Smrg generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3085627f7eb2Smrg "ADVANCE specification conflicts with internal file");
3086627f7eb2Smrg return;
3087627f7eb2Smrg }
3088627f7eb2Smrg
3089627f7eb2Smrg if ((cf & (IOPARM_DT_HAS_FORMAT | IOPARM_DT_LIST_FORMAT))
3090627f7eb2Smrg != IOPARM_DT_HAS_FORMAT)
3091627f7eb2Smrg {
3092627f7eb2Smrg generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3093627f7eb2Smrg "ADVANCE specification requires an explicit format");
3094627f7eb2Smrg return;
3095627f7eb2Smrg }
3096627f7eb2Smrg }
3097627f7eb2Smrg
3098627f7eb2Smrg /* Child IO is non-advancing and any ADVANCE= specifier is ignored.
3099627f7eb2Smrg F2008 9.6.2.4 */
3100627f7eb2Smrg if (dtp->u.p.current_unit->child_dtio > 0)
3101627f7eb2Smrg dtp->u.p.advance_status = ADVANCE_NO;
3102627f7eb2Smrg
3103627f7eb2Smrg if (read_flag)
3104627f7eb2Smrg {
3105627f7eb2Smrg dtp->u.p.current_unit->previous_nonadvancing_write = 0;
3106627f7eb2Smrg
3107627f7eb2Smrg if ((cf & IOPARM_EOR) != 0 && dtp->u.p.advance_status != ADVANCE_NO)
3108627f7eb2Smrg {
3109627f7eb2Smrg generate_error (&dtp->common, LIBERROR_MISSING_OPTION,
3110627f7eb2Smrg "EOR specification requires an ADVANCE specification "
3111627f7eb2Smrg "of NO");
3112627f7eb2Smrg return;
3113627f7eb2Smrg }
3114627f7eb2Smrg
3115627f7eb2Smrg if ((cf & IOPARM_DT_HAS_SIZE) != 0
3116627f7eb2Smrg && dtp->u.p.advance_status != ADVANCE_NO)
3117627f7eb2Smrg {
3118627f7eb2Smrg generate_error (&dtp->common, LIBERROR_MISSING_OPTION,
3119627f7eb2Smrg "SIZE specification requires an ADVANCE "
3120627f7eb2Smrg "specification of NO");
3121627f7eb2Smrg return;
3122627f7eb2Smrg }
3123627f7eb2Smrg }
3124627f7eb2Smrg else
3125627f7eb2Smrg { /* Write constraints. */
3126627f7eb2Smrg if ((cf & IOPARM_END) != 0)
3127627f7eb2Smrg {
3128627f7eb2Smrg generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3129627f7eb2Smrg "END specification cannot appear in a write "
3130627f7eb2Smrg "statement");
3131627f7eb2Smrg return;
3132627f7eb2Smrg }
3133627f7eb2Smrg
3134627f7eb2Smrg if ((cf & IOPARM_EOR) != 0)
3135627f7eb2Smrg {
3136627f7eb2Smrg generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3137627f7eb2Smrg "EOR specification cannot appear in a write "
3138627f7eb2Smrg "statement");
3139627f7eb2Smrg return;
3140627f7eb2Smrg }
3141627f7eb2Smrg
3142627f7eb2Smrg if ((cf & IOPARM_DT_HAS_SIZE) != 0)
3143627f7eb2Smrg {
3144627f7eb2Smrg generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3145627f7eb2Smrg "SIZE specification cannot appear in a write "
3146627f7eb2Smrg "statement");
3147627f7eb2Smrg return;
3148627f7eb2Smrg }
3149627f7eb2Smrg }
3150627f7eb2Smrg
3151627f7eb2Smrg if (dtp->u.p.advance_status == ADVANCE_UNSPECIFIED)
3152627f7eb2Smrg dtp->u.p.advance_status = ADVANCE_YES;
3153627f7eb2Smrg
3154627f7eb2Smrg /* Check the decimal mode. */
3155627f7eb2Smrg dtp->u.p.current_unit->decimal_status
3156627f7eb2Smrg = !(cf & IOPARM_DT_HAS_DECIMAL) ? DECIMAL_UNSPECIFIED :
3157627f7eb2Smrg find_option (&dtp->common, dtp->decimal, dtp->decimal_len,
3158627f7eb2Smrg decimal_opt, "Bad DECIMAL parameter in data transfer "
3159627f7eb2Smrg "statement");
3160627f7eb2Smrg
3161627f7eb2Smrg if (dtp->u.p.current_unit->decimal_status == DECIMAL_UNSPECIFIED)
3162627f7eb2Smrg dtp->u.p.current_unit->decimal_status = dtp->u.p.current_unit->flags.decimal;
3163627f7eb2Smrg
3164627f7eb2Smrg /* Check the round mode. */
3165627f7eb2Smrg dtp->u.p.current_unit->round_status
3166627f7eb2Smrg = !(cf & IOPARM_DT_HAS_ROUND) ? ROUND_UNSPECIFIED :
3167627f7eb2Smrg find_option (&dtp->common, dtp->round, dtp->round_len,
3168627f7eb2Smrg round_opt, "Bad ROUND parameter in data transfer "
3169627f7eb2Smrg "statement");
3170627f7eb2Smrg
3171627f7eb2Smrg if (dtp->u.p.current_unit->round_status == ROUND_UNSPECIFIED)
3172627f7eb2Smrg dtp->u.p.current_unit->round_status = dtp->u.p.current_unit->flags.round;
3173627f7eb2Smrg
3174627f7eb2Smrg /* Check the sign mode. */
3175627f7eb2Smrg dtp->u.p.sign_status
3176627f7eb2Smrg = !(cf & IOPARM_DT_HAS_SIGN) ? SIGN_UNSPECIFIED :
3177627f7eb2Smrg find_option (&dtp->common, dtp->sign, dtp->sign_len, sign_opt,
3178627f7eb2Smrg "Bad SIGN parameter in data transfer statement");
3179627f7eb2Smrg
3180627f7eb2Smrg if (dtp->u.p.sign_status == SIGN_UNSPECIFIED)
3181627f7eb2Smrg dtp->u.p.sign_status = dtp->u.p.current_unit->flags.sign;
3182627f7eb2Smrg
3183627f7eb2Smrg /* Check the blank mode. */
3184627f7eb2Smrg dtp->u.p.blank_status
3185627f7eb2Smrg = !(cf & IOPARM_DT_HAS_BLANK) ? BLANK_UNSPECIFIED :
3186627f7eb2Smrg find_option (&dtp->common, dtp->blank, dtp->blank_len,
3187627f7eb2Smrg blank_opt,
3188627f7eb2Smrg "Bad BLANK parameter in data transfer statement");
3189627f7eb2Smrg
3190627f7eb2Smrg if (dtp->u.p.blank_status == BLANK_UNSPECIFIED)
3191627f7eb2Smrg dtp->u.p.blank_status = dtp->u.p.current_unit->flags.blank;
3192627f7eb2Smrg
3193627f7eb2Smrg /* Check the delim mode. */
3194627f7eb2Smrg dtp->u.p.current_unit->delim_status
3195627f7eb2Smrg = !(cf & IOPARM_DT_HAS_DELIM) ? DELIM_UNSPECIFIED :
3196627f7eb2Smrg find_option (&dtp->common, dtp->delim, dtp->delim_len,
3197627f7eb2Smrg delim_opt, "Bad DELIM parameter in data transfer statement");
3198627f7eb2Smrg
3199627f7eb2Smrg if (dtp->u.p.current_unit->delim_status == DELIM_UNSPECIFIED)
3200627f7eb2Smrg {
3201627f7eb2Smrg if (ionml && dtp->u.p.current_unit->flags.delim == DELIM_UNSPECIFIED)
3202627f7eb2Smrg dtp->u.p.current_unit->delim_status = DELIM_QUOTE;
3203627f7eb2Smrg else
3204627f7eb2Smrg dtp->u.p.current_unit->delim_status = dtp->u.p.current_unit->flags.delim;
3205627f7eb2Smrg }
3206627f7eb2Smrg
3207627f7eb2Smrg /* Check the pad mode. */
3208627f7eb2Smrg dtp->u.p.current_unit->pad_status
3209627f7eb2Smrg = !(cf & IOPARM_DT_HAS_PAD) ? PAD_UNSPECIFIED :
3210627f7eb2Smrg find_option (&dtp->common, dtp->pad, dtp->pad_len, pad_opt,
3211627f7eb2Smrg "Bad PAD parameter in data transfer statement");
3212627f7eb2Smrg
3213627f7eb2Smrg if (dtp->u.p.current_unit->pad_status == PAD_UNSPECIFIED)
3214627f7eb2Smrg dtp->u.p.current_unit->pad_status = dtp->u.p.current_unit->flags.pad;
3215627f7eb2Smrg
3216627f7eb2Smrg /* Set up the subroutine that will handle the transfers. */
3217627f7eb2Smrg
3218627f7eb2Smrg if (read_flag)
3219627f7eb2Smrg {
3220627f7eb2Smrg if (dtp->u.p.current_unit->flags.form == FORM_UNFORMATTED)
3221627f7eb2Smrg dtp->u.p.transfer = unformatted_read;
3222627f7eb2Smrg else
3223627f7eb2Smrg {
3224627f7eb2Smrg if ((cf & IOPARM_DT_LIST_FORMAT) != 0)
3225627f7eb2Smrg dtp->u.p.transfer = list_formatted_read;
3226627f7eb2Smrg else
3227627f7eb2Smrg dtp->u.p.transfer = formatted_transfer;
3228627f7eb2Smrg }
3229627f7eb2Smrg }
3230627f7eb2Smrg else
3231627f7eb2Smrg {
3232627f7eb2Smrg if (dtp->u.p.current_unit->flags.form == FORM_UNFORMATTED)
3233627f7eb2Smrg dtp->u.p.transfer = unformatted_write;
3234627f7eb2Smrg else
3235627f7eb2Smrg {
3236627f7eb2Smrg if ((cf & IOPARM_DT_LIST_FORMAT) != 0)
3237627f7eb2Smrg dtp->u.p.transfer = list_formatted_write;
3238627f7eb2Smrg else
3239627f7eb2Smrg dtp->u.p.transfer = formatted_transfer;
3240627f7eb2Smrg }
3241627f7eb2Smrg }
3242627f7eb2Smrg
3243627f7eb2Smrg if (au && dtp->u.p.async)
3244627f7eb2Smrg {
3245627f7eb2Smrg NOTE ("enqueue_data_transfer");
3246627f7eb2Smrg enqueue_data_transfer_init (au, dtp, read_flag);
3247627f7eb2Smrg }
3248627f7eb2Smrg else
3249627f7eb2Smrg {
3250627f7eb2Smrg NOTE ("invoking data_transfer_init_worker");
3251627f7eb2Smrg data_transfer_init_worker (dtp, read_flag);
3252627f7eb2Smrg }
3253627f7eb2Smrg }
3254627f7eb2Smrg
3255627f7eb2Smrg void
data_transfer_init_worker(st_parameter_dt * dtp,int read_flag)3256627f7eb2Smrg data_transfer_init_worker (st_parameter_dt *dtp, int read_flag)
3257627f7eb2Smrg {
3258627f7eb2Smrg GFC_INTEGER_4 cf = dtp->common.flags;
3259627f7eb2Smrg
3260627f7eb2Smrg NOTE ("starting worker...");
3261627f7eb2Smrg
3262627f7eb2Smrg if (read_flag && dtp->u.p.current_unit->flags.form != FORM_UNFORMATTED
3263627f7eb2Smrg && ((cf & IOPARM_DT_LIST_FORMAT) != 0)
3264627f7eb2Smrg && dtp->u.p.current_unit->child_dtio == 0)
3265627f7eb2Smrg dtp->u.p.current_unit->last_char = EOF - 1;
3266627f7eb2Smrg
3267627f7eb2Smrg /* Check to see if we might be reading what we wrote before */
3268627f7eb2Smrg
3269627f7eb2Smrg if (dtp->u.p.mode != dtp->u.p.current_unit->mode
3270627f7eb2Smrg && !is_internal_unit (dtp))
3271627f7eb2Smrg {
3272627f7eb2Smrg int pos = fbuf_reset (dtp->u.p.current_unit);
3273627f7eb2Smrg if (pos != 0)
3274627f7eb2Smrg sseek (dtp->u.p.current_unit->s, pos, SEEK_CUR);
3275627f7eb2Smrg sflush(dtp->u.p.current_unit->s);
3276627f7eb2Smrg }
3277627f7eb2Smrg
3278627f7eb2Smrg /* Check the POS= specifier: that it is in range and that it is used with a
3279627f7eb2Smrg unit that has been connected for STREAM access. F2003 9.5.1.10. */
3280627f7eb2Smrg
3281627f7eb2Smrg if (((cf & IOPARM_DT_HAS_POS) != 0))
3282627f7eb2Smrg {
3283627f7eb2Smrg if (is_stream_io (dtp))
3284627f7eb2Smrg {
3285627f7eb2Smrg
3286627f7eb2Smrg if (dtp->pos <= 0)
3287627f7eb2Smrg {
3288627f7eb2Smrg generate_error (&dtp->common, LIBERROR_BAD_OPTION,
3289627f7eb2Smrg "POS=specifier must be positive");
3290627f7eb2Smrg return;
3291627f7eb2Smrg }
3292627f7eb2Smrg
3293627f7eb2Smrg if (dtp->pos >= dtp->u.p.current_unit->maxrec)
3294627f7eb2Smrg {
3295627f7eb2Smrg generate_error (&dtp->common, LIBERROR_BAD_OPTION,
3296627f7eb2Smrg "POS=specifier too large");
3297627f7eb2Smrg return;
3298627f7eb2Smrg }
3299627f7eb2Smrg
3300627f7eb2Smrg dtp->rec = dtp->pos;
3301627f7eb2Smrg
3302627f7eb2Smrg if (dtp->u.p.mode == READING)
3303627f7eb2Smrg {
3304627f7eb2Smrg /* Reset the endfile flag; if we hit EOF during reading
3305627f7eb2Smrg we'll set the flag and generate an error at that point
3306627f7eb2Smrg rather than worrying about it here. */
3307627f7eb2Smrg dtp->u.p.current_unit->endfile = NO_ENDFILE;
3308627f7eb2Smrg }
3309627f7eb2Smrg
3310627f7eb2Smrg if (dtp->pos != dtp->u.p.current_unit->strm_pos)
3311627f7eb2Smrg {
3312627f7eb2Smrg fbuf_reset (dtp->u.p.current_unit);
3313627f7eb2Smrg if (sseek (dtp->u.p.current_unit->s, dtp->pos - 1,
3314627f7eb2Smrg SEEK_SET) < 0)
3315627f7eb2Smrg {
3316627f7eb2Smrg generate_error (&dtp->common, LIBERROR_OS, NULL);
3317627f7eb2Smrg return;
3318627f7eb2Smrg }
3319627f7eb2Smrg dtp->u.p.current_unit->strm_pos = dtp->pos;
3320627f7eb2Smrg }
3321627f7eb2Smrg }
3322627f7eb2Smrg else
3323627f7eb2Smrg {
3324627f7eb2Smrg generate_error (&dtp->common, LIBERROR_BAD_OPTION,
3325627f7eb2Smrg "POS=specifier not allowed, "
3326627f7eb2Smrg "Try OPEN with ACCESS='stream'");
3327627f7eb2Smrg return;
3328627f7eb2Smrg }
3329627f7eb2Smrg }
3330627f7eb2Smrg
3331627f7eb2Smrg
3332627f7eb2Smrg /* Sanity checks on the record number. */
3333627f7eb2Smrg if ((cf & IOPARM_DT_HAS_REC) != 0)
3334627f7eb2Smrg {
3335627f7eb2Smrg if (dtp->rec <= 0)
3336627f7eb2Smrg {
3337627f7eb2Smrg generate_error (&dtp->common, LIBERROR_BAD_OPTION,
3338627f7eb2Smrg "Record number must be positive");
3339627f7eb2Smrg return;
3340627f7eb2Smrg }
3341627f7eb2Smrg
3342627f7eb2Smrg if (dtp->rec >= dtp->u.p.current_unit->maxrec)
3343627f7eb2Smrg {
3344627f7eb2Smrg generate_error (&dtp->common, LIBERROR_BAD_OPTION,
3345627f7eb2Smrg "Record number too large");
3346627f7eb2Smrg return;
3347627f7eb2Smrg }
3348627f7eb2Smrg
3349627f7eb2Smrg /* Make sure format buffer is reset. */
3350627f7eb2Smrg if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED)
3351627f7eb2Smrg fbuf_reset (dtp->u.p.current_unit);
3352627f7eb2Smrg
3353627f7eb2Smrg
3354627f7eb2Smrg /* Check whether the record exists to be read. Only
3355627f7eb2Smrg a partial record needs to exist. */
3356627f7eb2Smrg
3357627f7eb2Smrg if (dtp->u.p.mode == READING && (dtp->rec - 1)
3358627f7eb2Smrg * dtp->u.p.current_unit->recl >= ssize (dtp->u.p.current_unit->s))
3359627f7eb2Smrg {
3360627f7eb2Smrg generate_error (&dtp->common, LIBERROR_BAD_OPTION,
3361627f7eb2Smrg "Non-existing record number");
3362627f7eb2Smrg return;
3363627f7eb2Smrg }
3364627f7eb2Smrg
3365627f7eb2Smrg /* Position the file. */
3366627f7eb2Smrg if (sseek (dtp->u.p.current_unit->s, (gfc_offset) (dtp->rec - 1)
3367627f7eb2Smrg * dtp->u.p.current_unit->recl, SEEK_SET) < 0)
3368627f7eb2Smrg {
3369627f7eb2Smrg generate_error (&dtp->common, LIBERROR_OS, NULL);
3370627f7eb2Smrg return;
3371627f7eb2Smrg }
3372627f7eb2Smrg
3373627f7eb2Smrg if (dtp->u.p.current_unit->flags.access == ACCESS_STREAM)
3374627f7eb2Smrg {
3375627f7eb2Smrg generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3376627f7eb2Smrg "Record number not allowed for stream access "
3377627f7eb2Smrg "data transfer");
3378627f7eb2Smrg return;
3379627f7eb2Smrg }
3380627f7eb2Smrg }
3381627f7eb2Smrg
3382627f7eb2Smrg /* Bugware for badly written mixed C-Fortran I/O. */
3383627f7eb2Smrg if (!is_internal_unit (dtp))
3384627f7eb2Smrg flush_if_preconnected(dtp->u.p.current_unit->s);
3385627f7eb2Smrg
3386627f7eb2Smrg dtp->u.p.current_unit->mode = dtp->u.p.mode;
3387627f7eb2Smrg
3388627f7eb2Smrg /* Set the maximum position reached from the previous I/O operation. This
3389627f7eb2Smrg could be greater than zero from a previous non-advancing write. */
3390627f7eb2Smrg dtp->u.p.max_pos = dtp->u.p.current_unit->saved_pos;
3391627f7eb2Smrg
3392627f7eb2Smrg pre_position (dtp);
3393627f7eb2Smrg
3394627f7eb2Smrg /* Make sure that we don't do a read after a nonadvancing write. */
3395627f7eb2Smrg
3396627f7eb2Smrg if (read_flag)
3397627f7eb2Smrg {
3398627f7eb2Smrg if (dtp->u.p.current_unit->read_bad && !is_stream_io (dtp))
3399627f7eb2Smrg {
3400627f7eb2Smrg generate_error (&dtp->common, LIBERROR_BAD_OPTION,
3401627f7eb2Smrg "Cannot READ after a nonadvancing WRITE");
3402627f7eb2Smrg return;
3403627f7eb2Smrg }
3404627f7eb2Smrg }
3405627f7eb2Smrg else
3406627f7eb2Smrg {
3407627f7eb2Smrg if (dtp->u.p.advance_status == ADVANCE_YES && !dtp->u.p.seen_dollar)
3408627f7eb2Smrg dtp->u.p.current_unit->read_bad = 1;
3409627f7eb2Smrg }
3410627f7eb2Smrg
3411627f7eb2Smrg if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED)
3412627f7eb2Smrg {
3413627f7eb2Smrg #ifdef HAVE_USELOCALE
3414627f7eb2Smrg dtp->u.p.old_locale = uselocale (c_locale);
3415627f7eb2Smrg #else
3416627f7eb2Smrg __gthread_mutex_lock (&old_locale_lock);
3417627f7eb2Smrg if (!old_locale_ctr++)
3418627f7eb2Smrg {
3419627f7eb2Smrg old_locale = setlocale (LC_NUMERIC, NULL);
3420627f7eb2Smrg setlocale (LC_NUMERIC, "C");
3421627f7eb2Smrg }
3422627f7eb2Smrg __gthread_mutex_unlock (&old_locale_lock);
3423627f7eb2Smrg #endif
3424627f7eb2Smrg /* Start the data transfer if we are doing a formatted transfer. */
3425627f7eb2Smrg if ((cf & (IOPARM_DT_LIST_FORMAT | IOPARM_DT_HAS_NAMELIST_NAME)) == 0
3426627f7eb2Smrg && dtp->u.p.ionml == NULL)
3427627f7eb2Smrg formatted_transfer (dtp, 0, NULL, 0, 0, 1);
3428627f7eb2Smrg }
3429627f7eb2Smrg }
3430627f7eb2Smrg
3431627f7eb2Smrg
3432627f7eb2Smrg /* Initialize an array_loop_spec given the array descriptor. The function
3433627f7eb2Smrg returns the index of the last element of the array, and also returns
3434627f7eb2Smrg starting record, where the first I/O goes to (necessary in case of
3435627f7eb2Smrg negative strides). */
3436627f7eb2Smrg
3437627f7eb2Smrg gfc_offset
init_loop_spec(gfc_array_char * desc,array_loop_spec * ls,gfc_offset * start_record)3438627f7eb2Smrg init_loop_spec (gfc_array_char *desc, array_loop_spec *ls,
3439627f7eb2Smrg gfc_offset *start_record)
3440627f7eb2Smrg {
3441627f7eb2Smrg int rank = GFC_DESCRIPTOR_RANK(desc);
3442627f7eb2Smrg int i;
3443627f7eb2Smrg gfc_offset index;
3444627f7eb2Smrg int empty;
3445627f7eb2Smrg
3446627f7eb2Smrg empty = 0;
3447627f7eb2Smrg index = 1;
3448627f7eb2Smrg *start_record = 0;
3449627f7eb2Smrg
3450627f7eb2Smrg for (i=0; i<rank; i++)
3451627f7eb2Smrg {
3452627f7eb2Smrg ls[i].idx = GFC_DESCRIPTOR_LBOUND(desc,i);
3453627f7eb2Smrg ls[i].start = GFC_DESCRIPTOR_LBOUND(desc,i);
3454627f7eb2Smrg ls[i].end = GFC_DESCRIPTOR_UBOUND(desc,i);
3455627f7eb2Smrg ls[i].step = GFC_DESCRIPTOR_STRIDE(desc,i);
3456627f7eb2Smrg empty = empty || (GFC_DESCRIPTOR_UBOUND(desc,i)
3457627f7eb2Smrg < GFC_DESCRIPTOR_LBOUND(desc,i));
3458627f7eb2Smrg
3459627f7eb2Smrg if (GFC_DESCRIPTOR_STRIDE(desc,i) > 0)
3460627f7eb2Smrg {
3461627f7eb2Smrg index += (GFC_DESCRIPTOR_EXTENT(desc,i) - 1)
3462627f7eb2Smrg * GFC_DESCRIPTOR_STRIDE(desc,i);
3463627f7eb2Smrg }
3464627f7eb2Smrg else
3465627f7eb2Smrg {
3466627f7eb2Smrg index -= (GFC_DESCRIPTOR_EXTENT(desc,i) - 1)
3467627f7eb2Smrg * GFC_DESCRIPTOR_STRIDE(desc,i);
3468627f7eb2Smrg *start_record -= (GFC_DESCRIPTOR_EXTENT(desc,i) - 1)
3469627f7eb2Smrg * GFC_DESCRIPTOR_STRIDE(desc,i);
3470627f7eb2Smrg }
3471627f7eb2Smrg }
3472627f7eb2Smrg
3473627f7eb2Smrg if (empty)
3474627f7eb2Smrg return 0;
3475627f7eb2Smrg else
3476627f7eb2Smrg return index;
3477627f7eb2Smrg }
3478627f7eb2Smrg
3479627f7eb2Smrg /* Determine the index to the next record in an internal unit array by
3480627f7eb2Smrg by incrementing through the array_loop_spec. */
3481627f7eb2Smrg
3482627f7eb2Smrg gfc_offset
next_array_record(st_parameter_dt * dtp,array_loop_spec * ls,int * finished)3483627f7eb2Smrg next_array_record (st_parameter_dt *dtp, array_loop_spec *ls, int *finished)
3484627f7eb2Smrg {
3485627f7eb2Smrg int i, carry;
3486627f7eb2Smrg gfc_offset index;
3487627f7eb2Smrg
3488627f7eb2Smrg carry = 1;
3489627f7eb2Smrg index = 0;
3490627f7eb2Smrg
3491627f7eb2Smrg for (i = 0; i < dtp->u.p.current_unit->rank; i++)
3492627f7eb2Smrg {
3493627f7eb2Smrg if (carry)
3494627f7eb2Smrg {
3495627f7eb2Smrg ls[i].idx++;
3496627f7eb2Smrg if (ls[i].idx > ls[i].end)
3497627f7eb2Smrg {
3498627f7eb2Smrg ls[i].idx = ls[i].start;
3499627f7eb2Smrg carry = 1;
3500627f7eb2Smrg }
3501627f7eb2Smrg else
3502627f7eb2Smrg carry = 0;
3503627f7eb2Smrg }
3504627f7eb2Smrg index = index + (ls[i].idx - ls[i].start) * ls[i].step;
3505627f7eb2Smrg }
3506627f7eb2Smrg
3507627f7eb2Smrg *finished = carry;
3508627f7eb2Smrg
3509627f7eb2Smrg return index;
3510627f7eb2Smrg }
3511627f7eb2Smrg
3512627f7eb2Smrg
3513627f7eb2Smrg
3514627f7eb2Smrg /* Skip to the end of the current record, taking care of an optional
3515627f7eb2Smrg record marker of size bytes. If the file is not seekable, we
3516627f7eb2Smrg read chunks of size MAX_READ until we get to the right
3517627f7eb2Smrg position. */
3518627f7eb2Smrg
3519627f7eb2Smrg static void
skip_record(st_parameter_dt * dtp,gfc_offset bytes)3520627f7eb2Smrg skip_record (st_parameter_dt *dtp, gfc_offset bytes)
3521627f7eb2Smrg {
3522627f7eb2Smrg ssize_t rlength, readb;
3523627f7eb2Smrg #define MAX_READ 4096
3524627f7eb2Smrg char p[MAX_READ];
3525627f7eb2Smrg
3526627f7eb2Smrg dtp->u.p.current_unit->bytes_left_subrecord += bytes;
3527627f7eb2Smrg if (dtp->u.p.current_unit->bytes_left_subrecord == 0)
3528627f7eb2Smrg return;
3529627f7eb2Smrg
3530627f7eb2Smrg /* Direct access files do not generate END conditions,
3531627f7eb2Smrg only I/O errors. */
3532627f7eb2Smrg if (sseek (dtp->u.p.current_unit->s,
3533627f7eb2Smrg dtp->u.p.current_unit->bytes_left_subrecord, SEEK_CUR) < 0)
3534627f7eb2Smrg {
3535627f7eb2Smrg /* Seeking failed, fall back to seeking by reading data. */
3536627f7eb2Smrg while (dtp->u.p.current_unit->bytes_left_subrecord > 0)
3537627f7eb2Smrg {
3538627f7eb2Smrg rlength =
3539627f7eb2Smrg (MAX_READ < dtp->u.p.current_unit->bytes_left_subrecord) ?
3540627f7eb2Smrg MAX_READ : dtp->u.p.current_unit->bytes_left_subrecord;
3541627f7eb2Smrg
3542627f7eb2Smrg readb = sread (dtp->u.p.current_unit->s, p, rlength);
3543627f7eb2Smrg if (readb < 0)
3544627f7eb2Smrg {
3545627f7eb2Smrg generate_error (&dtp->common, LIBERROR_OS, NULL);
3546627f7eb2Smrg return;
3547627f7eb2Smrg }
3548627f7eb2Smrg
3549627f7eb2Smrg dtp->u.p.current_unit->bytes_left_subrecord -= readb;
3550627f7eb2Smrg }
3551627f7eb2Smrg return;
3552627f7eb2Smrg }
3553627f7eb2Smrg dtp->u.p.current_unit->bytes_left_subrecord = 0;
3554627f7eb2Smrg }
3555627f7eb2Smrg
3556627f7eb2Smrg
3557627f7eb2Smrg /* Advance to the next record reading unformatted files, taking
3558627f7eb2Smrg care of subrecords. If complete_record is nonzero, we loop
3559627f7eb2Smrg until all subrecords are cleared. */
3560627f7eb2Smrg
3561627f7eb2Smrg static void
next_record_r_unf(st_parameter_dt * dtp,int complete_record)3562627f7eb2Smrg next_record_r_unf (st_parameter_dt *dtp, int complete_record)
3563627f7eb2Smrg {
3564627f7eb2Smrg size_t bytes;
3565627f7eb2Smrg
3566627f7eb2Smrg bytes = compile_options.record_marker == 0 ?
3567627f7eb2Smrg sizeof (GFC_INTEGER_4) : compile_options.record_marker;
3568627f7eb2Smrg
3569627f7eb2Smrg while(1)
3570627f7eb2Smrg {
3571627f7eb2Smrg
3572627f7eb2Smrg /* Skip over tail */
3573627f7eb2Smrg
3574627f7eb2Smrg skip_record (dtp, bytes);
3575627f7eb2Smrg
3576627f7eb2Smrg if ( ! (complete_record && dtp->u.p.current_unit->continued))
3577627f7eb2Smrg return;
3578627f7eb2Smrg
3579627f7eb2Smrg us_read (dtp, 1);
3580627f7eb2Smrg }
3581627f7eb2Smrg }
3582627f7eb2Smrg
3583627f7eb2Smrg
3584627f7eb2Smrg static gfc_offset
min_off(gfc_offset a,gfc_offset b)3585627f7eb2Smrg min_off (gfc_offset a, gfc_offset b)
3586627f7eb2Smrg {
3587627f7eb2Smrg return (a < b ? a : b);
3588627f7eb2Smrg }
3589627f7eb2Smrg
3590627f7eb2Smrg
3591627f7eb2Smrg /* Space to the next record for read mode. */
3592627f7eb2Smrg
3593627f7eb2Smrg static void
next_record_r(st_parameter_dt * dtp,int done)3594627f7eb2Smrg next_record_r (st_parameter_dt *dtp, int done)
3595627f7eb2Smrg {
3596627f7eb2Smrg gfc_offset record;
3597627f7eb2Smrg char p;
3598627f7eb2Smrg int cc;
3599627f7eb2Smrg
3600627f7eb2Smrg switch (current_mode (dtp))
3601627f7eb2Smrg {
3602627f7eb2Smrg /* No records in unformatted STREAM I/O. */
3603627f7eb2Smrg case UNFORMATTED_STREAM:
3604627f7eb2Smrg return;
3605627f7eb2Smrg
3606627f7eb2Smrg case UNFORMATTED_SEQUENTIAL:
3607627f7eb2Smrg next_record_r_unf (dtp, 1);
3608627f7eb2Smrg dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
3609627f7eb2Smrg break;
3610627f7eb2Smrg
3611627f7eb2Smrg case FORMATTED_DIRECT:
3612627f7eb2Smrg case UNFORMATTED_DIRECT:
3613627f7eb2Smrg skip_record (dtp, dtp->u.p.current_unit->bytes_left);
3614627f7eb2Smrg break;
3615627f7eb2Smrg
3616627f7eb2Smrg case FORMATTED_STREAM:
3617627f7eb2Smrg case FORMATTED_SEQUENTIAL:
3618627f7eb2Smrg /* read_sf has already terminated input because of an '\n', or
3619627f7eb2Smrg we have hit EOF. */
3620627f7eb2Smrg if (dtp->u.p.sf_seen_eor)
3621627f7eb2Smrg {
3622627f7eb2Smrg dtp->u.p.sf_seen_eor = 0;
3623627f7eb2Smrg break;
3624627f7eb2Smrg }
3625627f7eb2Smrg
3626627f7eb2Smrg if (is_internal_unit (dtp))
3627627f7eb2Smrg {
3628627f7eb2Smrg if (is_array_io (dtp))
3629627f7eb2Smrg {
3630627f7eb2Smrg int finished;
3631627f7eb2Smrg
3632627f7eb2Smrg record = next_array_record (dtp, dtp->u.p.current_unit->ls,
3633627f7eb2Smrg &finished);
3634627f7eb2Smrg if (!done && finished)
3635627f7eb2Smrg hit_eof (dtp);
3636627f7eb2Smrg
3637627f7eb2Smrg /* Now seek to this record. */
3638627f7eb2Smrg record = record * dtp->u.p.current_unit->recl;
3639627f7eb2Smrg if (sseek (dtp->u.p.current_unit->s, record, SEEK_SET) < 0)
3640627f7eb2Smrg {
3641627f7eb2Smrg generate_error (&dtp->common, LIBERROR_INTERNAL_UNIT, NULL);
3642627f7eb2Smrg break;
3643627f7eb2Smrg }
3644627f7eb2Smrg dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
3645627f7eb2Smrg }
3646627f7eb2Smrg else
3647627f7eb2Smrg {
3648627f7eb2Smrg gfc_offset bytes_left = dtp->u.p.current_unit->bytes_left;
3649627f7eb2Smrg bytes_left = min_off (bytes_left,
3650627f7eb2Smrg ssize (dtp->u.p.current_unit->s)
3651627f7eb2Smrg - stell (dtp->u.p.current_unit->s));
3652627f7eb2Smrg if (sseek (dtp->u.p.current_unit->s,
3653627f7eb2Smrg bytes_left, SEEK_CUR) < 0)
3654627f7eb2Smrg {
3655627f7eb2Smrg generate_error (&dtp->common, LIBERROR_INTERNAL_UNIT, NULL);
3656627f7eb2Smrg break;
3657627f7eb2Smrg }
3658627f7eb2Smrg dtp->u.p.current_unit->bytes_left
3659627f7eb2Smrg = dtp->u.p.current_unit->recl;
3660627f7eb2Smrg }
3661627f7eb2Smrg break;
3662627f7eb2Smrg }
3663627f7eb2Smrg else if (dtp->u.p.current_unit->flags.cc != CC_NONE)
3664627f7eb2Smrg {
3665627f7eb2Smrg do
3666627f7eb2Smrg {
3667627f7eb2Smrg errno = 0;
3668627f7eb2Smrg cc = fbuf_getc (dtp->u.p.current_unit);
3669627f7eb2Smrg if (cc == EOF)
3670627f7eb2Smrg {
3671627f7eb2Smrg if (errno != 0)
3672627f7eb2Smrg generate_error (&dtp->common, LIBERROR_OS, NULL);
3673627f7eb2Smrg else
3674627f7eb2Smrg {
3675627f7eb2Smrg if (is_stream_io (dtp)
3676627f7eb2Smrg || dtp->u.p.current_unit->pad_status == PAD_NO
3677627f7eb2Smrg || dtp->u.p.current_unit->bytes_left
3678627f7eb2Smrg == dtp->u.p.current_unit->recl)
3679627f7eb2Smrg hit_eof (dtp);
3680627f7eb2Smrg }
3681627f7eb2Smrg break;
3682627f7eb2Smrg }
3683627f7eb2Smrg
3684627f7eb2Smrg if (is_stream_io (dtp))
3685627f7eb2Smrg dtp->u.p.current_unit->strm_pos++;
3686627f7eb2Smrg
3687627f7eb2Smrg p = (char) cc;
3688627f7eb2Smrg }
3689627f7eb2Smrg while (p != '\n');
3690627f7eb2Smrg }
3691627f7eb2Smrg break;
3692*4c3eb207Smrg case FORMATTED_UNSPECIFIED:
3693*4c3eb207Smrg gcc_unreachable ();
3694627f7eb2Smrg }
3695627f7eb2Smrg }
3696627f7eb2Smrg
3697627f7eb2Smrg
3698627f7eb2Smrg /* Small utility function to write a record marker, taking care of
3699627f7eb2Smrg byte swapping and of choosing the correct size. */
3700627f7eb2Smrg
3701627f7eb2Smrg static int
write_us_marker(st_parameter_dt * dtp,const gfc_offset buf)3702627f7eb2Smrg write_us_marker (st_parameter_dt *dtp, const gfc_offset buf)
3703627f7eb2Smrg {
3704627f7eb2Smrg size_t len;
3705627f7eb2Smrg GFC_INTEGER_4 buf4;
3706627f7eb2Smrg GFC_INTEGER_8 buf8;
3707627f7eb2Smrg
3708627f7eb2Smrg if (compile_options.record_marker == 0)
3709627f7eb2Smrg len = sizeof (GFC_INTEGER_4);
3710627f7eb2Smrg else
3711627f7eb2Smrg len = compile_options.record_marker;
3712627f7eb2Smrg
3713627f7eb2Smrg /* Only GFC_CONVERT_NATIVE and GFC_CONVERT_SWAP are valid here. */
3714627f7eb2Smrg if (likely (dtp->u.p.current_unit->flags.convert == GFC_CONVERT_NATIVE))
3715627f7eb2Smrg {
3716627f7eb2Smrg switch (len)
3717627f7eb2Smrg {
3718627f7eb2Smrg case sizeof (GFC_INTEGER_4):
3719627f7eb2Smrg buf4 = buf;
3720627f7eb2Smrg return swrite (dtp->u.p.current_unit->s, &buf4, len);
3721627f7eb2Smrg break;
3722627f7eb2Smrg
3723627f7eb2Smrg case sizeof (GFC_INTEGER_8):
3724627f7eb2Smrg buf8 = buf;
3725627f7eb2Smrg return swrite (dtp->u.p.current_unit->s, &buf8, len);
3726627f7eb2Smrg break;
3727627f7eb2Smrg
3728627f7eb2Smrg default:
3729627f7eb2Smrg runtime_error ("Illegal value for record marker");
3730627f7eb2Smrg break;
3731627f7eb2Smrg }
3732627f7eb2Smrg }
3733627f7eb2Smrg else
3734627f7eb2Smrg {
3735627f7eb2Smrg uint32_t u32;
3736627f7eb2Smrg uint64_t u64;
3737627f7eb2Smrg switch (len)
3738627f7eb2Smrg {
3739627f7eb2Smrg case sizeof (GFC_INTEGER_4):
3740627f7eb2Smrg buf4 = buf;
3741627f7eb2Smrg memcpy (&u32, &buf4, sizeof (u32));
3742627f7eb2Smrg u32 = __builtin_bswap32 (u32);
3743627f7eb2Smrg return swrite (dtp->u.p.current_unit->s, &u32, len);
3744627f7eb2Smrg break;
3745627f7eb2Smrg
3746627f7eb2Smrg case sizeof (GFC_INTEGER_8):
3747627f7eb2Smrg buf8 = buf;
3748627f7eb2Smrg memcpy (&u64, &buf8, sizeof (u64));
3749627f7eb2Smrg u64 = __builtin_bswap64 (u64);
3750627f7eb2Smrg return swrite (dtp->u.p.current_unit->s, &u64, len);
3751627f7eb2Smrg break;
3752627f7eb2Smrg
3753627f7eb2Smrg default:
3754627f7eb2Smrg runtime_error ("Illegal value for record marker");
3755627f7eb2Smrg break;
3756627f7eb2Smrg }
3757627f7eb2Smrg }
3758627f7eb2Smrg
3759627f7eb2Smrg }
3760627f7eb2Smrg
3761627f7eb2Smrg /* Position to the next (sub)record in write mode for
3762627f7eb2Smrg unformatted sequential files. */
3763627f7eb2Smrg
3764627f7eb2Smrg static void
next_record_w_unf(st_parameter_dt * dtp,int next_subrecord)3765627f7eb2Smrg next_record_w_unf (st_parameter_dt *dtp, int next_subrecord)
3766627f7eb2Smrg {
3767627f7eb2Smrg gfc_offset m, m_write, record_marker;
3768627f7eb2Smrg
3769627f7eb2Smrg /* Bytes written. */
3770627f7eb2Smrg m = dtp->u.p.current_unit->recl_subrecord
3771627f7eb2Smrg - dtp->u.p.current_unit->bytes_left_subrecord;
3772627f7eb2Smrg
3773627f7eb2Smrg if (compile_options.record_marker == 0)
3774627f7eb2Smrg record_marker = sizeof (GFC_INTEGER_4);
3775627f7eb2Smrg else
3776627f7eb2Smrg record_marker = compile_options.record_marker;
3777627f7eb2Smrg
3778627f7eb2Smrg /* Seek to the head and overwrite the bogus length with the real
3779627f7eb2Smrg length. */
3780627f7eb2Smrg
3781627f7eb2Smrg if (unlikely (sseek (dtp->u.p.current_unit->s, - m - record_marker,
3782627f7eb2Smrg SEEK_CUR) < 0))
3783627f7eb2Smrg goto io_error;
3784627f7eb2Smrg
3785627f7eb2Smrg if (next_subrecord)
3786627f7eb2Smrg m_write = -m;
3787627f7eb2Smrg else
3788627f7eb2Smrg m_write = m;
3789627f7eb2Smrg
3790627f7eb2Smrg if (unlikely (write_us_marker (dtp, m_write) < 0))
3791627f7eb2Smrg goto io_error;
3792627f7eb2Smrg
3793627f7eb2Smrg /* Seek past the end of the current record. */
3794627f7eb2Smrg
3795627f7eb2Smrg if (unlikely (sseek (dtp->u.p.current_unit->s, m, SEEK_CUR) < 0))
3796627f7eb2Smrg goto io_error;
3797627f7eb2Smrg
3798627f7eb2Smrg /* Write the length tail. If we finish a record containing
3799627f7eb2Smrg subrecords, we write out the negative length. */
3800627f7eb2Smrg
3801627f7eb2Smrg if (dtp->u.p.current_unit->continued)
3802627f7eb2Smrg m_write = -m;
3803627f7eb2Smrg else
3804627f7eb2Smrg m_write = m;
3805627f7eb2Smrg
3806627f7eb2Smrg if (unlikely (write_us_marker (dtp, m_write) < 0))
3807627f7eb2Smrg goto io_error;
3808627f7eb2Smrg
3809627f7eb2Smrg return;
3810627f7eb2Smrg
3811627f7eb2Smrg io_error:
3812627f7eb2Smrg generate_error (&dtp->common, LIBERROR_OS, NULL);
3813627f7eb2Smrg return;
3814627f7eb2Smrg
3815627f7eb2Smrg }
3816627f7eb2Smrg
3817627f7eb2Smrg
3818627f7eb2Smrg /* Utility function like memset() but operating on streams. Return
3819627f7eb2Smrg value is same as for POSIX write(). */
3820627f7eb2Smrg
3821627f7eb2Smrg static gfc_offset
sset(stream * s,int c,gfc_offset nbyte)3822627f7eb2Smrg sset (stream *s, int c, gfc_offset nbyte)
3823627f7eb2Smrg {
3824627f7eb2Smrg #define WRITE_CHUNK 256
3825627f7eb2Smrg char p[WRITE_CHUNK];
3826627f7eb2Smrg gfc_offset bytes_left;
3827627f7eb2Smrg ssize_t trans;
3828627f7eb2Smrg
3829627f7eb2Smrg if (nbyte < WRITE_CHUNK)
3830627f7eb2Smrg memset (p, c, nbyte);
3831627f7eb2Smrg else
3832627f7eb2Smrg memset (p, c, WRITE_CHUNK);
3833627f7eb2Smrg
3834627f7eb2Smrg bytes_left = nbyte;
3835627f7eb2Smrg while (bytes_left > 0)
3836627f7eb2Smrg {
3837627f7eb2Smrg trans = (bytes_left < WRITE_CHUNK) ? bytes_left : WRITE_CHUNK;
3838627f7eb2Smrg trans = swrite (s, p, trans);
3839627f7eb2Smrg if (trans <= 0)
3840627f7eb2Smrg return trans;
3841627f7eb2Smrg bytes_left -= trans;
3842627f7eb2Smrg }
3843627f7eb2Smrg
3844627f7eb2Smrg return nbyte - bytes_left;
3845627f7eb2Smrg }
3846627f7eb2Smrg
3847627f7eb2Smrg
3848627f7eb2Smrg /* Finish up a record according to the legacy carriagecontrol type, based
3849627f7eb2Smrg on the first character in the record. */
3850627f7eb2Smrg
3851627f7eb2Smrg static void
next_record_cc(st_parameter_dt * dtp)3852627f7eb2Smrg next_record_cc (st_parameter_dt *dtp)
3853627f7eb2Smrg {
3854627f7eb2Smrg /* Only valid with CARRIAGECONTROL=FORTRAN. */
3855627f7eb2Smrg if (dtp->u.p.current_unit->flags.cc != CC_FORTRAN)
3856627f7eb2Smrg return;
3857627f7eb2Smrg
3858627f7eb2Smrg fbuf_seek (dtp->u.p.current_unit, 0, SEEK_END);
3859627f7eb2Smrg if (dtp->u.p.cc.len > 0)
3860627f7eb2Smrg {
3861627f7eb2Smrg char *p = fbuf_alloc (dtp->u.p.current_unit, dtp->u.p.cc.len);
3862627f7eb2Smrg if (!p)
3863627f7eb2Smrg generate_error (&dtp->common, LIBERROR_OS, NULL);
3864627f7eb2Smrg
3865627f7eb2Smrg /* Output CR for the first character with default CC setting. */
3866627f7eb2Smrg *(p++) = dtp->u.p.cc.u.end;
3867627f7eb2Smrg if (dtp->u.p.cc.len > 1)
3868627f7eb2Smrg *p = dtp->u.p.cc.u.end;
3869627f7eb2Smrg }
3870627f7eb2Smrg }
3871627f7eb2Smrg
3872627f7eb2Smrg /* Position to the next record in write mode. */
3873627f7eb2Smrg
3874627f7eb2Smrg static void
next_record_w(st_parameter_dt * dtp,int done)3875627f7eb2Smrg next_record_w (st_parameter_dt *dtp, int done)
3876627f7eb2Smrg {
3877627f7eb2Smrg gfc_offset max_pos_off;
3878627f7eb2Smrg
3879627f7eb2Smrg /* Zero counters for X- and T-editing. */
3880627f7eb2Smrg max_pos_off = dtp->u.p.max_pos;
3881627f7eb2Smrg dtp->u.p.max_pos = dtp->u.p.skips = dtp->u.p.pending_spaces = 0;
3882627f7eb2Smrg
3883627f7eb2Smrg switch (current_mode (dtp))
3884627f7eb2Smrg {
3885627f7eb2Smrg /* No records in unformatted STREAM I/O. */
3886627f7eb2Smrg case UNFORMATTED_STREAM:
3887627f7eb2Smrg return;
3888627f7eb2Smrg
3889627f7eb2Smrg case FORMATTED_DIRECT:
3890627f7eb2Smrg if (dtp->u.p.current_unit->bytes_left == 0)
3891627f7eb2Smrg break;
3892627f7eb2Smrg
3893627f7eb2Smrg fbuf_seek (dtp->u.p.current_unit, 0, SEEK_END);
3894627f7eb2Smrg fbuf_flush (dtp->u.p.current_unit, WRITING);
3895627f7eb2Smrg if (sset (dtp->u.p.current_unit->s, ' ',
3896627f7eb2Smrg dtp->u.p.current_unit->bytes_left)
3897627f7eb2Smrg != dtp->u.p.current_unit->bytes_left)
3898627f7eb2Smrg goto io_error;
3899627f7eb2Smrg
3900627f7eb2Smrg break;
3901627f7eb2Smrg
3902627f7eb2Smrg case UNFORMATTED_DIRECT:
3903627f7eb2Smrg if (dtp->u.p.current_unit->bytes_left > 0)
3904627f7eb2Smrg {
3905627f7eb2Smrg gfc_offset length = dtp->u.p.current_unit->bytes_left;
3906627f7eb2Smrg if (sset (dtp->u.p.current_unit->s, 0, length) != length)
3907627f7eb2Smrg goto io_error;
3908627f7eb2Smrg }
3909627f7eb2Smrg break;
3910627f7eb2Smrg
3911627f7eb2Smrg case UNFORMATTED_SEQUENTIAL:
3912627f7eb2Smrg next_record_w_unf (dtp, 0);
3913627f7eb2Smrg dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
3914627f7eb2Smrg break;
3915627f7eb2Smrg
3916627f7eb2Smrg case FORMATTED_STREAM:
3917627f7eb2Smrg case FORMATTED_SEQUENTIAL:
3918627f7eb2Smrg
3919627f7eb2Smrg if (is_internal_unit (dtp))
3920627f7eb2Smrg {
3921627f7eb2Smrg char *p;
3922627f7eb2Smrg /* Internal unit, so must fit in memory. */
3923627f7eb2Smrg size_t length, m;
3924627f7eb2Smrg size_t max_pos = max_pos_off;
3925627f7eb2Smrg if (is_array_io (dtp))
3926627f7eb2Smrg {
3927627f7eb2Smrg int finished;
3928627f7eb2Smrg
3929627f7eb2Smrg length = dtp->u.p.current_unit->bytes_left;
3930627f7eb2Smrg
3931627f7eb2Smrg /* If the farthest position reached is greater than current
3932627f7eb2Smrg position, adjust the position and set length to pad out
3933627f7eb2Smrg whats left. Otherwise just pad whats left.
3934627f7eb2Smrg (for character array unit) */
3935627f7eb2Smrg m = dtp->u.p.current_unit->recl
3936627f7eb2Smrg - dtp->u.p.current_unit->bytes_left;
3937627f7eb2Smrg if (max_pos > m)
3938627f7eb2Smrg {
3939627f7eb2Smrg length = (max_pos - m);
3940627f7eb2Smrg if (sseek (dtp->u.p.current_unit->s,
3941627f7eb2Smrg length, SEEK_CUR) < 0)
3942627f7eb2Smrg {
3943627f7eb2Smrg generate_error (&dtp->common, LIBERROR_INTERNAL_UNIT, NULL);
3944627f7eb2Smrg return;
3945627f7eb2Smrg }
3946627f7eb2Smrg length = ((size_t) dtp->u.p.current_unit->recl - max_pos);
3947627f7eb2Smrg }
3948627f7eb2Smrg
3949627f7eb2Smrg p = write_block (dtp, length);
3950627f7eb2Smrg if (p == NULL)
3951627f7eb2Smrg return;
3952627f7eb2Smrg
3953627f7eb2Smrg if (unlikely (is_char4_unit (dtp)))
3954627f7eb2Smrg {
3955627f7eb2Smrg gfc_char4_t *p4 = (gfc_char4_t *) p;
3956627f7eb2Smrg memset4 (p4, ' ', length);
3957627f7eb2Smrg }
3958627f7eb2Smrg else
3959627f7eb2Smrg memset (p, ' ', length);
3960627f7eb2Smrg
3961627f7eb2Smrg /* Now that the current record has been padded out,
3962627f7eb2Smrg determine where the next record in the array is.
3963627f7eb2Smrg Note that this can return a negative value, so it
3964627f7eb2Smrg needs to be assigned to a signed value. */
3965627f7eb2Smrg gfc_offset record = next_array_record
3966627f7eb2Smrg (dtp, dtp->u.p.current_unit->ls, &finished);
3967627f7eb2Smrg if (finished)
3968627f7eb2Smrg dtp->u.p.current_unit->endfile = AT_ENDFILE;
3969627f7eb2Smrg
3970627f7eb2Smrg /* Now seek to this record */
3971627f7eb2Smrg record = record * dtp->u.p.current_unit->recl;
3972627f7eb2Smrg
3973627f7eb2Smrg if (sseek (dtp->u.p.current_unit->s, record, SEEK_SET) < 0)
3974627f7eb2Smrg {
3975627f7eb2Smrg generate_error (&dtp->common, LIBERROR_INTERNAL_UNIT, NULL);
3976627f7eb2Smrg return;
3977627f7eb2Smrg }
3978627f7eb2Smrg
3979627f7eb2Smrg dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
3980627f7eb2Smrg }
3981627f7eb2Smrg else
3982627f7eb2Smrg {
3983627f7eb2Smrg length = 1;
3984627f7eb2Smrg
3985627f7eb2Smrg /* If this is the last call to next_record move to the farthest
3986627f7eb2Smrg position reached and set length to pad out the remainder
3987627f7eb2Smrg of the record. (for character scaler unit) */
3988627f7eb2Smrg if (done)
3989627f7eb2Smrg {
3990627f7eb2Smrg m = dtp->u.p.current_unit->recl
3991627f7eb2Smrg - dtp->u.p.current_unit->bytes_left;
3992627f7eb2Smrg if (max_pos > m)
3993627f7eb2Smrg {
3994627f7eb2Smrg length = max_pos - m;
3995627f7eb2Smrg if (sseek (dtp->u.p.current_unit->s,
3996627f7eb2Smrg length, SEEK_CUR) < 0)
3997627f7eb2Smrg {
3998627f7eb2Smrg generate_error (&dtp->common, LIBERROR_INTERNAL_UNIT, NULL);
3999627f7eb2Smrg return;
4000627f7eb2Smrg }
4001627f7eb2Smrg length = (size_t) dtp->u.p.current_unit->recl
4002627f7eb2Smrg - max_pos;
4003627f7eb2Smrg }
4004627f7eb2Smrg else
4005627f7eb2Smrg length = dtp->u.p.current_unit->bytes_left;
4006627f7eb2Smrg }
4007627f7eb2Smrg if (length > 0)
4008627f7eb2Smrg {
4009627f7eb2Smrg p = write_block (dtp, length);
4010627f7eb2Smrg if (p == NULL)
4011627f7eb2Smrg return;
4012627f7eb2Smrg
4013627f7eb2Smrg if (unlikely (is_char4_unit (dtp)))
4014627f7eb2Smrg {
4015627f7eb2Smrg gfc_char4_t *p4 = (gfc_char4_t *) p;
4016627f7eb2Smrg memset4 (p4, (gfc_char4_t) ' ', length);
4017627f7eb2Smrg }
4018627f7eb2Smrg else
4019627f7eb2Smrg memset (p, ' ', length);
4020627f7eb2Smrg }
4021627f7eb2Smrg }
4022627f7eb2Smrg }
4023627f7eb2Smrg /* Handle legacy CARRIAGECONTROL line endings. */
4024627f7eb2Smrg else if (dtp->u.p.current_unit->flags.cc == CC_FORTRAN)
4025627f7eb2Smrg next_record_cc (dtp);
4026627f7eb2Smrg else
4027627f7eb2Smrg {
4028627f7eb2Smrg /* Skip newlines for CC=CC_NONE. */
4029627f7eb2Smrg const int len = (dtp->u.p.current_unit->flags.cc == CC_NONE)
4030627f7eb2Smrg ? 0
4031627f7eb2Smrg #ifdef HAVE_CRLF
4032627f7eb2Smrg : 2;
4033627f7eb2Smrg #else
4034627f7eb2Smrg : 1;
4035627f7eb2Smrg #endif
4036627f7eb2Smrg fbuf_seek (dtp->u.p.current_unit, 0, SEEK_END);
4037627f7eb2Smrg if (dtp->u.p.current_unit->flags.cc != CC_NONE)
4038627f7eb2Smrg {
4039627f7eb2Smrg char *p = fbuf_alloc (dtp->u.p.current_unit, len);
4040627f7eb2Smrg if (!p)
4041627f7eb2Smrg goto io_error;
4042627f7eb2Smrg #ifdef HAVE_CRLF
4043627f7eb2Smrg *(p++) = '\r';
4044627f7eb2Smrg #endif
4045627f7eb2Smrg *p = '\n';
4046627f7eb2Smrg }
4047627f7eb2Smrg if (is_stream_io (dtp))
4048627f7eb2Smrg {
4049627f7eb2Smrg dtp->u.p.current_unit->strm_pos += len;
4050627f7eb2Smrg if (dtp->u.p.current_unit->strm_pos
4051627f7eb2Smrg < ssize (dtp->u.p.current_unit->s))
4052627f7eb2Smrg unit_truncate (dtp->u.p.current_unit,
4053627f7eb2Smrg dtp->u.p.current_unit->strm_pos - 1,
4054627f7eb2Smrg &dtp->common);
4055627f7eb2Smrg }
4056627f7eb2Smrg }
4057627f7eb2Smrg
4058627f7eb2Smrg break;
4059*4c3eb207Smrg case FORMATTED_UNSPECIFIED:
4060*4c3eb207Smrg gcc_unreachable ();
4061627f7eb2Smrg
4062627f7eb2Smrg io_error:
4063627f7eb2Smrg generate_error (&dtp->common, LIBERROR_OS, NULL);
4064627f7eb2Smrg break;
4065627f7eb2Smrg }
4066627f7eb2Smrg }
4067627f7eb2Smrg
4068627f7eb2Smrg /* Position to the next record, which means moving to the end of the
4069627f7eb2Smrg current record. This can happen under several different
4070627f7eb2Smrg conditions. If the done flag is not set, we get ready to process
4071627f7eb2Smrg the next record. */
4072627f7eb2Smrg
4073627f7eb2Smrg void
next_record(st_parameter_dt * dtp,int done)4074627f7eb2Smrg next_record (st_parameter_dt *dtp, int done)
4075627f7eb2Smrg {
4076627f7eb2Smrg gfc_offset fp; /* File position. */
4077627f7eb2Smrg
4078627f7eb2Smrg dtp->u.p.current_unit->read_bad = 0;
4079627f7eb2Smrg
4080627f7eb2Smrg if (dtp->u.p.mode == READING)
4081627f7eb2Smrg next_record_r (dtp, done);
4082627f7eb2Smrg else
4083627f7eb2Smrg next_record_w (dtp, done);
4084627f7eb2Smrg
4085627f7eb2Smrg fbuf_flush (dtp->u.p.current_unit, dtp->u.p.mode);
4086627f7eb2Smrg
4087627f7eb2Smrg if (!is_stream_io (dtp))
4088627f7eb2Smrg {
4089627f7eb2Smrg /* Since we have changed the position, set it to unspecified so
4090627f7eb2Smrg that INQUIRE(POSITION=) knows it needs to look into it. */
4091627f7eb2Smrg if (done)
4092627f7eb2Smrg dtp->u.p.current_unit->flags.position = POSITION_UNSPECIFIED;
4093627f7eb2Smrg
4094627f7eb2Smrg dtp->u.p.current_unit->current_record = 0;
4095627f7eb2Smrg if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT)
4096627f7eb2Smrg {
4097627f7eb2Smrg fp = stell (dtp->u.p.current_unit->s);
4098627f7eb2Smrg /* Calculate next record, rounding up partial records. */
4099627f7eb2Smrg dtp->u.p.current_unit->last_record =
4100627f7eb2Smrg (fp + dtp->u.p.current_unit->recl) /
4101627f7eb2Smrg dtp->u.p.current_unit->recl - 1;
4102627f7eb2Smrg }
4103627f7eb2Smrg else
4104627f7eb2Smrg dtp->u.p.current_unit->last_record++;
4105627f7eb2Smrg }
4106627f7eb2Smrg
4107627f7eb2Smrg if (!done)
4108627f7eb2Smrg pre_position (dtp);
4109627f7eb2Smrg
4110627f7eb2Smrg smarkeor (dtp->u.p.current_unit->s);
4111627f7eb2Smrg }
4112627f7eb2Smrg
4113627f7eb2Smrg
4114627f7eb2Smrg /* Finalize the current data transfer. For a nonadvancing transfer,
4115627f7eb2Smrg this means advancing to the next record. For internal units close the
4116627f7eb2Smrg stream associated with the unit. */
4117627f7eb2Smrg
4118627f7eb2Smrg static void
finalize_transfer(st_parameter_dt * dtp)4119627f7eb2Smrg finalize_transfer (st_parameter_dt *dtp)
4120627f7eb2Smrg {
4121627f7eb2Smrg GFC_INTEGER_4 cf = dtp->common.flags;
4122627f7eb2Smrg
4123627f7eb2Smrg if ((dtp->u.p.ionml != NULL)
4124627f7eb2Smrg && (cf & IOPARM_DT_HAS_NAMELIST_NAME) != 0)
4125627f7eb2Smrg {
4126627f7eb2Smrg dtp->u.p.namelist_mode = 1;
4127627f7eb2Smrg if ((cf & IOPARM_DT_NAMELIST_READ_MODE) != 0)
4128627f7eb2Smrg namelist_read (dtp);
4129627f7eb2Smrg else
4130627f7eb2Smrg namelist_write (dtp);
4131627f7eb2Smrg }
4132627f7eb2Smrg
4133627f7eb2Smrg if ((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0)
4134627f7eb2Smrg *dtp->size = dtp->u.p.current_unit->size_used;
4135627f7eb2Smrg
4136627f7eb2Smrg if (dtp->u.p.eor_condition)
4137627f7eb2Smrg {
4138627f7eb2Smrg generate_error (&dtp->common, LIBERROR_EOR, NULL);
4139627f7eb2Smrg goto done;
4140627f7eb2Smrg }
4141627f7eb2Smrg
4142627f7eb2Smrg if (dtp->u.p.current_unit && (dtp->u.p.current_unit->child_dtio > 0))
4143627f7eb2Smrg {
4144627f7eb2Smrg if (cf & IOPARM_DT_HAS_FORMAT)
4145627f7eb2Smrg {
4146627f7eb2Smrg free (dtp->u.p.fmt);
4147627f7eb2Smrg free (dtp->format);
4148627f7eb2Smrg }
4149627f7eb2Smrg return;
4150627f7eb2Smrg }
4151627f7eb2Smrg
4152627f7eb2Smrg if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
4153627f7eb2Smrg {
4154627f7eb2Smrg if (dtp->u.p.current_unit && current_mode (dtp) == UNFORMATTED_SEQUENTIAL)
4155627f7eb2Smrg dtp->u.p.current_unit->current_record = 0;
4156627f7eb2Smrg goto done;
4157627f7eb2Smrg }
4158627f7eb2Smrg
4159627f7eb2Smrg dtp->u.p.transfer = NULL;
4160627f7eb2Smrg if (dtp->u.p.current_unit == NULL)
4161627f7eb2Smrg goto done;
4162627f7eb2Smrg
4163627f7eb2Smrg if ((cf & IOPARM_DT_LIST_FORMAT) != 0 && dtp->u.p.mode == READING)
4164627f7eb2Smrg {
4165627f7eb2Smrg finish_list_read (dtp);
4166627f7eb2Smrg goto done;
4167627f7eb2Smrg }
4168627f7eb2Smrg
4169627f7eb2Smrg if (dtp->u.p.mode == WRITING)
4170627f7eb2Smrg dtp->u.p.current_unit->previous_nonadvancing_write
4171627f7eb2Smrg = dtp->u.p.advance_status == ADVANCE_NO;
4172627f7eb2Smrg
4173627f7eb2Smrg if (is_stream_io (dtp))
4174627f7eb2Smrg {
4175627f7eb2Smrg if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED
4176627f7eb2Smrg && dtp->u.p.advance_status != ADVANCE_NO)
4177627f7eb2Smrg next_record (dtp, 1);
4178627f7eb2Smrg
4179627f7eb2Smrg goto done;
4180627f7eb2Smrg }
4181627f7eb2Smrg
4182627f7eb2Smrg dtp->u.p.current_unit->current_record = 0;
4183627f7eb2Smrg
4184627f7eb2Smrg if (!is_internal_unit (dtp) && dtp->u.p.seen_dollar)
4185627f7eb2Smrg {
4186627f7eb2Smrg fbuf_flush (dtp->u.p.current_unit, dtp->u.p.mode);
4187627f7eb2Smrg dtp->u.p.seen_dollar = 0;
4188627f7eb2Smrg goto done;
4189627f7eb2Smrg }
4190627f7eb2Smrg
4191627f7eb2Smrg /* For non-advancing I/O, save the current maximum position for use in the
4192627f7eb2Smrg next I/O operation if needed. */
4193627f7eb2Smrg if (dtp->u.p.advance_status == ADVANCE_NO)
4194627f7eb2Smrg {
4195627f7eb2Smrg if (dtp->u.p.skips > 0)
4196627f7eb2Smrg {
4197627f7eb2Smrg int tmp;
4198627f7eb2Smrg write_x (dtp, dtp->u.p.skips, dtp->u.p.pending_spaces);
4199627f7eb2Smrg tmp = (int)(dtp->u.p.current_unit->recl
4200627f7eb2Smrg - dtp->u.p.current_unit->bytes_left);
4201627f7eb2Smrg dtp->u.p.max_pos =
4202627f7eb2Smrg dtp->u.p.max_pos > tmp ? dtp->u.p.max_pos : tmp;
4203627f7eb2Smrg dtp->u.p.skips = 0;
4204627f7eb2Smrg }
4205627f7eb2Smrg int bytes_written = (int) (dtp->u.p.current_unit->recl
4206627f7eb2Smrg - dtp->u.p.current_unit->bytes_left);
4207627f7eb2Smrg dtp->u.p.current_unit->saved_pos =
4208627f7eb2Smrg dtp->u.p.max_pos > 0 ? dtp->u.p.max_pos - bytes_written : 0;
4209627f7eb2Smrg fbuf_flush (dtp->u.p.current_unit, dtp->u.p.mode);
4210627f7eb2Smrg goto done;
4211627f7eb2Smrg }
4212627f7eb2Smrg else if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED
4213627f7eb2Smrg && dtp->u.p.mode == WRITING && !is_internal_unit (dtp))
4214627f7eb2Smrg fbuf_seek (dtp->u.p.current_unit, 0, SEEK_END);
4215627f7eb2Smrg
4216627f7eb2Smrg dtp->u.p.current_unit->saved_pos = 0;
4217627f7eb2Smrg dtp->u.p.current_unit->last_char = EOF - 1;
4218627f7eb2Smrg next_record (dtp, 1);
4219627f7eb2Smrg
4220627f7eb2Smrg done:
4221627f7eb2Smrg
4222627f7eb2Smrg if (dtp->u.p.unit_is_internal)
4223627f7eb2Smrg {
4224627f7eb2Smrg /* The unit structure may be reused later so clear the
4225627f7eb2Smrg internal unit kind. */
4226627f7eb2Smrg dtp->u.p.current_unit->internal_unit_kind = 0;
4227627f7eb2Smrg
4228627f7eb2Smrg fbuf_destroy (dtp->u.p.current_unit);
4229627f7eb2Smrg if (dtp->u.p.current_unit
4230627f7eb2Smrg && (dtp->u.p.current_unit->child_dtio == 0)
4231627f7eb2Smrg && dtp->u.p.current_unit->s)
4232627f7eb2Smrg {
4233627f7eb2Smrg sclose (dtp->u.p.current_unit->s);
4234627f7eb2Smrg dtp->u.p.current_unit->s = NULL;
4235627f7eb2Smrg }
4236627f7eb2Smrg }
4237627f7eb2Smrg
4238627f7eb2Smrg #ifdef HAVE_USELOCALE
4239627f7eb2Smrg if (dtp->u.p.old_locale != (locale_t) 0)
4240627f7eb2Smrg {
4241627f7eb2Smrg uselocale (dtp->u.p.old_locale);
4242627f7eb2Smrg dtp->u.p.old_locale = (locale_t) 0;
4243627f7eb2Smrg }
4244627f7eb2Smrg #else
4245627f7eb2Smrg __gthread_mutex_lock (&old_locale_lock);
4246627f7eb2Smrg if (!--old_locale_ctr)
4247627f7eb2Smrg {
4248627f7eb2Smrg setlocale (LC_NUMERIC, old_locale);
4249627f7eb2Smrg old_locale = NULL;
4250627f7eb2Smrg }
4251627f7eb2Smrg __gthread_mutex_unlock (&old_locale_lock);
4252627f7eb2Smrg #endif
4253627f7eb2Smrg }
4254627f7eb2Smrg
4255627f7eb2Smrg /* Transfer function for IOLENGTH. It doesn't actually do any
4256627f7eb2Smrg data transfer, it just updates the length counter. */
4257627f7eb2Smrg
4258627f7eb2Smrg static void
iolength_transfer(st_parameter_dt * dtp,bt type,void * dest,int kind,size_t size,size_t nelems)4259627f7eb2Smrg iolength_transfer (st_parameter_dt *dtp, bt type __attribute__((unused)),
4260627f7eb2Smrg void *dest __attribute__ ((unused)),
4261627f7eb2Smrg int kind __attribute__((unused)),
4262627f7eb2Smrg size_t size, size_t nelems)
4263627f7eb2Smrg {
4264627f7eb2Smrg if ((dtp->common.flags & IOPARM_DT_HAS_IOLENGTH) != 0)
4265627f7eb2Smrg *dtp->iolength += (GFC_IO_INT) (size * nelems);
4266627f7eb2Smrg }
4267627f7eb2Smrg
4268627f7eb2Smrg
4269627f7eb2Smrg /* Initialize the IOLENGTH data transfer. This function is in essence
4270627f7eb2Smrg a very much simplified version of data_transfer_init(), because it
4271627f7eb2Smrg doesn't have to deal with units at all. */
4272627f7eb2Smrg
4273627f7eb2Smrg static void
iolength_transfer_init(st_parameter_dt * dtp)4274627f7eb2Smrg iolength_transfer_init (st_parameter_dt *dtp)
4275627f7eb2Smrg {
4276627f7eb2Smrg if ((dtp->common.flags & IOPARM_DT_HAS_IOLENGTH) != 0)
4277627f7eb2Smrg *dtp->iolength = 0;
4278627f7eb2Smrg
4279627f7eb2Smrg memset (&dtp->u.p, 0, sizeof (dtp->u.p));
4280627f7eb2Smrg
4281627f7eb2Smrg /* Set up the subroutine that will handle the transfers. */
4282627f7eb2Smrg
4283627f7eb2Smrg dtp->u.p.transfer = iolength_transfer;
4284627f7eb2Smrg }
4285627f7eb2Smrg
4286627f7eb2Smrg
4287627f7eb2Smrg /* Library entry point for the IOLENGTH form of the INQUIRE
4288627f7eb2Smrg statement. The IOLENGTH form requires no I/O to be performed, but
4289627f7eb2Smrg it must still be a runtime library call so that we can determine
4290627f7eb2Smrg the iolength for dynamic arrays and such. */
4291627f7eb2Smrg
4292627f7eb2Smrg extern void st_iolength (st_parameter_dt *);
4293627f7eb2Smrg export_proto(st_iolength);
4294627f7eb2Smrg
4295627f7eb2Smrg void
st_iolength(st_parameter_dt * dtp)4296627f7eb2Smrg st_iolength (st_parameter_dt *dtp)
4297627f7eb2Smrg {
4298627f7eb2Smrg library_start (&dtp->common);
4299627f7eb2Smrg iolength_transfer_init (dtp);
4300627f7eb2Smrg }
4301627f7eb2Smrg
4302627f7eb2Smrg extern void st_iolength_done (st_parameter_dt *);
4303627f7eb2Smrg export_proto(st_iolength_done);
4304627f7eb2Smrg
4305627f7eb2Smrg void
st_iolength_done(st_parameter_dt * dtp)4306627f7eb2Smrg st_iolength_done (st_parameter_dt *dtp __attribute__((unused)))
4307627f7eb2Smrg {
4308627f7eb2Smrg free_ionml (dtp);
4309627f7eb2Smrg library_end ();
4310627f7eb2Smrg }
4311627f7eb2Smrg
4312627f7eb2Smrg
4313627f7eb2Smrg /* The READ statement. */
4314627f7eb2Smrg
4315627f7eb2Smrg extern void st_read (st_parameter_dt *);
4316627f7eb2Smrg export_proto(st_read);
4317627f7eb2Smrg
4318627f7eb2Smrg void
st_read(st_parameter_dt * dtp)4319627f7eb2Smrg st_read (st_parameter_dt *dtp)
4320627f7eb2Smrg {
4321627f7eb2Smrg library_start (&dtp->common);
4322627f7eb2Smrg
4323627f7eb2Smrg data_transfer_init (dtp, 1);
4324627f7eb2Smrg }
4325627f7eb2Smrg
4326627f7eb2Smrg extern void st_read_done (st_parameter_dt *);
4327627f7eb2Smrg export_proto(st_read_done);
4328627f7eb2Smrg
4329627f7eb2Smrg void
st_read_done_worker(st_parameter_dt * dtp)4330627f7eb2Smrg st_read_done_worker (st_parameter_dt *dtp)
4331627f7eb2Smrg {
4332627f7eb2Smrg finalize_transfer (dtp);
4333627f7eb2Smrg
4334627f7eb2Smrg free_ionml (dtp);
4335627f7eb2Smrg
4336627f7eb2Smrg /* If this is a parent READ statement we do not need to retain the
4337627f7eb2Smrg internal unit structure for child use. */
4338627f7eb2Smrg if (dtp->u.p.current_unit != NULL
4339627f7eb2Smrg && dtp->u.p.current_unit->child_dtio == 0)
4340627f7eb2Smrg {
4341627f7eb2Smrg if (dtp->u.p.unit_is_internal)
4342627f7eb2Smrg {
4343627f7eb2Smrg if ((dtp->common.flags & IOPARM_DT_HAS_UDTIO) == 0)
4344627f7eb2Smrg {
4345627f7eb2Smrg free (dtp->u.p.current_unit->filename);
4346627f7eb2Smrg dtp->u.p.current_unit->filename = NULL;
4347627f7eb2Smrg if (dtp->u.p.current_unit->ls)
4348627f7eb2Smrg free (dtp->u.p.current_unit->ls);
4349627f7eb2Smrg dtp->u.p.current_unit->ls = NULL;
4350627f7eb2Smrg }
4351627f7eb2Smrg newunit_free (dtp->common.unit);
4352627f7eb2Smrg }
4353627f7eb2Smrg if (dtp->u.p.unit_is_internal || dtp->u.p.format_not_saved)
4354627f7eb2Smrg {
4355627f7eb2Smrg free_format_data (dtp->u.p.fmt);
4356627f7eb2Smrg free_format (dtp);
4357627f7eb2Smrg }
4358627f7eb2Smrg }
4359627f7eb2Smrg }
4360627f7eb2Smrg
4361627f7eb2Smrg void
st_read_done(st_parameter_dt * dtp)4362627f7eb2Smrg st_read_done (st_parameter_dt *dtp)
4363627f7eb2Smrg {
4364627f7eb2Smrg if (dtp->u.p.current_unit)
4365627f7eb2Smrg {
4366627f7eb2Smrg if (dtp->u.p.current_unit->au)
4367627f7eb2Smrg {
4368627f7eb2Smrg if (dtp->common.flags & IOPARM_DT_HAS_ID)
4369627f7eb2Smrg *dtp->id = enqueue_done_id (dtp->u.p.current_unit->au, AIO_READ_DONE);
4370627f7eb2Smrg else
4371627f7eb2Smrg {
4372627f7eb2Smrg if (dtp->u.p.async)
4373627f7eb2Smrg enqueue_done (dtp->u.p.current_unit->au, AIO_READ_DONE);
4374627f7eb2Smrg }
4375627f7eb2Smrg }
4376627f7eb2Smrg else
4377627f7eb2Smrg st_read_done_worker (dtp);
4378627f7eb2Smrg
4379627f7eb2Smrg unlock_unit (dtp->u.p.current_unit);
4380627f7eb2Smrg }
4381627f7eb2Smrg
4382627f7eb2Smrg library_end ();
4383627f7eb2Smrg }
4384627f7eb2Smrg
4385627f7eb2Smrg extern void st_write (st_parameter_dt *);
4386627f7eb2Smrg export_proto (st_write);
4387627f7eb2Smrg
4388627f7eb2Smrg void
st_write(st_parameter_dt * dtp)4389627f7eb2Smrg st_write (st_parameter_dt *dtp)
4390627f7eb2Smrg {
4391627f7eb2Smrg library_start (&dtp->common);
4392627f7eb2Smrg data_transfer_init (dtp, 0);
4393627f7eb2Smrg }
4394627f7eb2Smrg
4395627f7eb2Smrg
4396627f7eb2Smrg void
st_write_done_worker(st_parameter_dt * dtp)4397627f7eb2Smrg st_write_done_worker (st_parameter_dt *dtp)
4398627f7eb2Smrg {
4399627f7eb2Smrg finalize_transfer (dtp);
4400627f7eb2Smrg
4401627f7eb2Smrg if (dtp->u.p.current_unit != NULL
4402627f7eb2Smrg && dtp->u.p.current_unit->child_dtio == 0)
4403627f7eb2Smrg {
4404627f7eb2Smrg /* Deal with endfile conditions associated with sequential files. */
4405627f7eb2Smrg if (dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL)
4406627f7eb2Smrg switch (dtp->u.p.current_unit->endfile)
4407627f7eb2Smrg {
4408627f7eb2Smrg case AT_ENDFILE: /* Remain at the endfile record. */
4409627f7eb2Smrg break;
4410627f7eb2Smrg
4411627f7eb2Smrg case AFTER_ENDFILE:
4412627f7eb2Smrg dtp->u.p.current_unit->endfile = AT_ENDFILE; /* Just at it now. */
4413627f7eb2Smrg break;
4414627f7eb2Smrg
4415627f7eb2Smrg case NO_ENDFILE:
4416627f7eb2Smrg /* Get rid of whatever is after this record. */
4417627f7eb2Smrg if (!is_internal_unit (dtp))
4418627f7eb2Smrg unit_truncate (dtp->u.p.current_unit,
4419627f7eb2Smrg stell (dtp->u.p.current_unit->s),
4420627f7eb2Smrg &dtp->common);
4421627f7eb2Smrg dtp->u.p.current_unit->endfile = AT_ENDFILE;
4422627f7eb2Smrg break;
4423627f7eb2Smrg }
4424627f7eb2Smrg
4425627f7eb2Smrg free_ionml (dtp);
4426627f7eb2Smrg
4427627f7eb2Smrg /* If this is a parent WRITE statement we do not need to retain the
4428627f7eb2Smrg internal unit structure for child use. */
4429627f7eb2Smrg if (dtp->u.p.unit_is_internal)
4430627f7eb2Smrg {
4431627f7eb2Smrg if ((dtp->common.flags & IOPARM_DT_HAS_UDTIO) == 0)
4432627f7eb2Smrg {
4433627f7eb2Smrg free (dtp->u.p.current_unit->filename);
4434627f7eb2Smrg dtp->u.p.current_unit->filename = NULL;
4435627f7eb2Smrg if (dtp->u.p.current_unit->ls)
4436627f7eb2Smrg free (dtp->u.p.current_unit->ls);
4437627f7eb2Smrg dtp->u.p.current_unit->ls = NULL;
4438627f7eb2Smrg }
4439627f7eb2Smrg newunit_free (dtp->common.unit);
4440627f7eb2Smrg }
4441627f7eb2Smrg if (dtp->u.p.unit_is_internal || dtp->u.p.format_not_saved)
4442627f7eb2Smrg {
4443627f7eb2Smrg free_format_data (dtp->u.p.fmt);
4444627f7eb2Smrg free_format (dtp);
4445627f7eb2Smrg }
4446627f7eb2Smrg }
4447627f7eb2Smrg }
4448627f7eb2Smrg
4449627f7eb2Smrg extern void st_write_done (st_parameter_dt *);
4450627f7eb2Smrg export_proto(st_write_done);
4451627f7eb2Smrg
4452627f7eb2Smrg void
st_write_done(st_parameter_dt * dtp)4453627f7eb2Smrg st_write_done (st_parameter_dt *dtp)
4454627f7eb2Smrg {
4455627f7eb2Smrg if (dtp->u.p.current_unit)
4456627f7eb2Smrg {
4457627f7eb2Smrg if (dtp->u.p.current_unit->au && dtp->u.p.async)
4458627f7eb2Smrg {
4459627f7eb2Smrg if (dtp->common.flags & IOPARM_DT_HAS_ID)
4460627f7eb2Smrg *dtp->id = enqueue_done_id (dtp->u.p.current_unit->au,
4461627f7eb2Smrg AIO_WRITE_DONE);
4462627f7eb2Smrg else
4463627f7eb2Smrg {
4464627f7eb2Smrg /* We perform synchronous I/O on an asynchronous unit, so no need
4465627f7eb2Smrg to enqueue AIO_READ_DONE. */
4466627f7eb2Smrg if (dtp->u.p.async)
4467627f7eb2Smrg enqueue_done (dtp->u.p.current_unit->au, AIO_WRITE_DONE);
4468627f7eb2Smrg }
4469627f7eb2Smrg }
4470627f7eb2Smrg else
4471627f7eb2Smrg st_write_done_worker (dtp);
4472627f7eb2Smrg
4473627f7eb2Smrg unlock_unit (dtp->u.p.current_unit);
4474627f7eb2Smrg }
4475627f7eb2Smrg
4476627f7eb2Smrg library_end ();
4477627f7eb2Smrg }
4478627f7eb2Smrg
4479627f7eb2Smrg /* Wait operation. We need to keep around the do-nothing version
4480627f7eb2Smrg of st_wait for compatibility with previous versions, which had marked
4481627f7eb2Smrg the argument as unused (and thus liable to be removed).
4482627f7eb2Smrg
4483627f7eb2Smrg TODO: remove at next bump in version number. */
4484627f7eb2Smrg
4485627f7eb2Smrg void
st_wait(st_parameter_wait * wtp)4486627f7eb2Smrg st_wait (st_parameter_wait *wtp __attribute__((unused)))
4487627f7eb2Smrg {
4488627f7eb2Smrg return;
4489627f7eb2Smrg }
4490627f7eb2Smrg
4491627f7eb2Smrg void
st_wait_async(st_parameter_wait * wtp)4492627f7eb2Smrg st_wait_async (st_parameter_wait *wtp)
4493627f7eb2Smrg {
4494627f7eb2Smrg gfc_unit *u = find_unit (wtp->common.unit);
4495*4c3eb207Smrg if (ASYNC_IO && u && u->au)
4496627f7eb2Smrg {
4497627f7eb2Smrg if (wtp->common.flags & IOPARM_WAIT_HAS_ID)
4498627f7eb2Smrg async_wait_id (&(wtp->common), u->au, *wtp->id);
4499627f7eb2Smrg else
4500627f7eb2Smrg async_wait (&(wtp->common), u->au);
4501627f7eb2Smrg }
4502627f7eb2Smrg
4503627f7eb2Smrg unlock_unit (u);
4504627f7eb2Smrg }
4505627f7eb2Smrg
4506627f7eb2Smrg
4507627f7eb2Smrg /* Receives the scalar information for namelist objects and stores it
4508627f7eb2Smrg in a linked list of namelist_info types. */
4509627f7eb2Smrg
4510627f7eb2Smrg static void
set_nml_var(st_parameter_dt * dtp,void * var_addr,char * var_name,GFC_INTEGER_4 len,gfc_charlen_type string_length,dtype_type dtype,void * dtio_sub,void * vtable)4511627f7eb2Smrg set_nml_var (st_parameter_dt *dtp, void *var_addr, char *var_name,
4512627f7eb2Smrg GFC_INTEGER_4 len, gfc_charlen_type string_length,
4513627f7eb2Smrg dtype_type dtype, void *dtio_sub, void *vtable)
4514627f7eb2Smrg {
4515627f7eb2Smrg namelist_info *t1 = NULL;
4516627f7eb2Smrg namelist_info *nml;
4517627f7eb2Smrg size_t var_name_len = strlen (var_name);
4518627f7eb2Smrg
4519627f7eb2Smrg nml = (namelist_info*) xmalloc (sizeof (namelist_info));
4520627f7eb2Smrg
4521627f7eb2Smrg nml->mem_pos = var_addr;
4522627f7eb2Smrg nml->dtio_sub = dtio_sub;
4523627f7eb2Smrg nml->vtable = vtable;
4524627f7eb2Smrg
4525627f7eb2Smrg nml->var_name = (char*) xmalloc (var_name_len + 1);
4526627f7eb2Smrg memcpy (nml->var_name, var_name, var_name_len);
4527627f7eb2Smrg nml->var_name[var_name_len] = '\0';
4528627f7eb2Smrg
4529627f7eb2Smrg nml->len = (int) len;
4530627f7eb2Smrg nml->string_length = (index_type) string_length;
4531627f7eb2Smrg
4532627f7eb2Smrg nml->var_rank = (int) (dtype.rank);
4533627f7eb2Smrg nml->size = (index_type) (dtype.elem_len);
4534627f7eb2Smrg nml->type = (bt) (dtype.type);
4535627f7eb2Smrg
4536627f7eb2Smrg if (nml->var_rank > 0)
4537627f7eb2Smrg {
4538627f7eb2Smrg nml->dim = (descriptor_dimension*)
4539627f7eb2Smrg xmallocarray (nml->var_rank, sizeof (descriptor_dimension));
4540627f7eb2Smrg nml->ls = (array_loop_spec*)
4541627f7eb2Smrg xmallocarray (nml->var_rank, sizeof (array_loop_spec));
4542627f7eb2Smrg }
4543627f7eb2Smrg else
4544627f7eb2Smrg {
4545627f7eb2Smrg nml->dim = NULL;
4546627f7eb2Smrg nml->ls = NULL;
4547627f7eb2Smrg }
4548627f7eb2Smrg
4549627f7eb2Smrg nml->next = NULL;
4550627f7eb2Smrg
4551627f7eb2Smrg if ((dtp->common.flags & IOPARM_DT_IONML_SET) == 0)
4552627f7eb2Smrg {
4553627f7eb2Smrg dtp->common.flags |= IOPARM_DT_IONML_SET;
4554627f7eb2Smrg dtp->u.p.ionml = nml;
4555627f7eb2Smrg }
4556627f7eb2Smrg else
4557627f7eb2Smrg {
4558627f7eb2Smrg for (t1 = dtp->u.p.ionml; t1->next; t1 = t1->next);
4559627f7eb2Smrg t1->next = nml;
4560627f7eb2Smrg }
4561627f7eb2Smrg }
4562627f7eb2Smrg
4563627f7eb2Smrg extern void st_set_nml_var (st_parameter_dt *dtp, void *, char *,
4564627f7eb2Smrg GFC_INTEGER_4, gfc_charlen_type, dtype_type);
4565627f7eb2Smrg export_proto(st_set_nml_var);
4566627f7eb2Smrg
4567627f7eb2Smrg void
st_set_nml_var(st_parameter_dt * dtp,void * var_addr,char * var_name,GFC_INTEGER_4 len,gfc_charlen_type string_length,dtype_type dtype)4568627f7eb2Smrg st_set_nml_var (st_parameter_dt *dtp, void *var_addr, char *var_name,
4569627f7eb2Smrg GFC_INTEGER_4 len, gfc_charlen_type string_length,
4570627f7eb2Smrg dtype_type dtype)
4571627f7eb2Smrg {
4572627f7eb2Smrg set_nml_var (dtp, var_addr, var_name, len, string_length,
4573627f7eb2Smrg dtype, NULL, NULL);
4574627f7eb2Smrg }
4575627f7eb2Smrg
4576627f7eb2Smrg
4577627f7eb2Smrg /* Essentially the same as previous but carrying the dtio procedure
4578627f7eb2Smrg and the vtable as additional arguments. */
4579627f7eb2Smrg extern void st_set_nml_dtio_var (st_parameter_dt *dtp, void *, char *,
4580627f7eb2Smrg GFC_INTEGER_4, gfc_charlen_type, dtype_type,
4581627f7eb2Smrg void *, void *);
4582627f7eb2Smrg export_proto(st_set_nml_dtio_var);
4583627f7eb2Smrg
4584627f7eb2Smrg
4585627f7eb2Smrg void
st_set_nml_dtio_var(st_parameter_dt * dtp,void * var_addr,char * var_name,GFC_INTEGER_4 len,gfc_charlen_type string_length,dtype_type dtype,void * dtio_sub,void * vtable)4586627f7eb2Smrg st_set_nml_dtio_var (st_parameter_dt *dtp, void *var_addr, char *var_name,
4587627f7eb2Smrg GFC_INTEGER_4 len, gfc_charlen_type string_length,
4588627f7eb2Smrg dtype_type dtype, void *dtio_sub, void *vtable)
4589627f7eb2Smrg {
4590627f7eb2Smrg set_nml_var (dtp, var_addr, var_name, len, string_length,
4591627f7eb2Smrg dtype, dtio_sub, vtable);
4592627f7eb2Smrg }
4593627f7eb2Smrg
4594627f7eb2Smrg /* Store the dimensional information for the namelist object. */
4595627f7eb2Smrg extern void st_set_nml_var_dim (st_parameter_dt *, GFC_INTEGER_4,
4596627f7eb2Smrg index_type, index_type,
4597627f7eb2Smrg index_type);
4598627f7eb2Smrg export_proto(st_set_nml_var_dim);
4599627f7eb2Smrg
4600627f7eb2Smrg void
st_set_nml_var_dim(st_parameter_dt * dtp,GFC_INTEGER_4 n_dim,index_type stride,index_type lbound,index_type ubound)4601627f7eb2Smrg st_set_nml_var_dim (st_parameter_dt *dtp, GFC_INTEGER_4 n_dim,
4602627f7eb2Smrg index_type stride, index_type lbound,
4603627f7eb2Smrg index_type ubound)
4604627f7eb2Smrg {
4605627f7eb2Smrg namelist_info *nml;
4606627f7eb2Smrg int n;
4607627f7eb2Smrg
4608627f7eb2Smrg n = (int)n_dim;
4609627f7eb2Smrg
4610627f7eb2Smrg for (nml = dtp->u.p.ionml; nml->next; nml = nml->next);
4611627f7eb2Smrg
4612627f7eb2Smrg GFC_DIMENSION_SET(nml->dim[n],lbound,ubound,stride);
4613627f7eb2Smrg }
4614627f7eb2Smrg
4615627f7eb2Smrg
4616627f7eb2Smrg /* Once upon a time, a poor innocent Fortran program was reading a
4617627f7eb2Smrg file, when suddenly it hit the end-of-file (EOF). Unfortunately
4618627f7eb2Smrg the OS doesn't tell whether we're at the EOF or whether we already
4619627f7eb2Smrg went past it. Luckily our hero, libgfortran, keeps track of this.
4620627f7eb2Smrg Call this function when you detect an EOF condition. See Section
4621627f7eb2Smrg 9.10.2 in F2003. */
4622627f7eb2Smrg
4623627f7eb2Smrg void
hit_eof(st_parameter_dt * dtp)4624627f7eb2Smrg hit_eof (st_parameter_dt *dtp)
4625627f7eb2Smrg {
4626627f7eb2Smrg dtp->u.p.current_unit->flags.position = POSITION_APPEND;
4627627f7eb2Smrg
4628627f7eb2Smrg if (dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL)
4629627f7eb2Smrg switch (dtp->u.p.current_unit->endfile)
4630627f7eb2Smrg {
4631627f7eb2Smrg case NO_ENDFILE:
4632627f7eb2Smrg case AT_ENDFILE:
4633627f7eb2Smrg generate_error (&dtp->common, LIBERROR_END, NULL);
4634627f7eb2Smrg if (!is_internal_unit (dtp) && !dtp->u.p.namelist_mode)
4635627f7eb2Smrg {
4636627f7eb2Smrg dtp->u.p.current_unit->endfile = AFTER_ENDFILE;
4637627f7eb2Smrg dtp->u.p.current_unit->current_record = 0;
4638627f7eb2Smrg }
4639627f7eb2Smrg else
4640627f7eb2Smrg dtp->u.p.current_unit->endfile = AT_ENDFILE;
4641627f7eb2Smrg break;
4642627f7eb2Smrg
4643627f7eb2Smrg case AFTER_ENDFILE:
4644627f7eb2Smrg generate_error (&dtp->common, LIBERROR_ENDFILE, NULL);
4645627f7eb2Smrg dtp->u.p.current_unit->current_record = 0;
4646627f7eb2Smrg break;
4647627f7eb2Smrg }
4648627f7eb2Smrg else
4649627f7eb2Smrg {
4650627f7eb2Smrg /* Non-sequential files don't have an ENDFILE record, so we
4651627f7eb2Smrg can't be at AFTER_ENDFILE. */
4652627f7eb2Smrg dtp->u.p.current_unit->endfile = AT_ENDFILE;
4653627f7eb2Smrg generate_error (&dtp->common, LIBERROR_END, NULL);
4654627f7eb2Smrg dtp->u.p.current_unit->current_record = 0;
4655627f7eb2Smrg }
4656627f7eb2Smrg }
4657