1*b1e83836Smrg /* Copyright (C) 2002-2022 Free Software Foundation, Inc.
2181254a7Smrg Contributed by Andy Vaught
3181254a7Smrg Namelist transfer functions contributed by Paul Thomas
4181254a7Smrg F2003 I/O support contributed by Jerry DeLisle
5181254a7Smrg
6181254a7Smrg This file is part of the GNU Fortran runtime library (libgfortran).
7181254a7Smrg
8181254a7Smrg Libgfortran is free software; you can redistribute it and/or modify
9181254a7Smrg it under the terms of the GNU General Public License as published by
10181254a7Smrg the Free Software Foundation; either version 3, or (at your option)
11181254a7Smrg any later version.
12181254a7Smrg
13181254a7Smrg Libgfortran is distributed in the hope that it will be useful,
14181254a7Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
15181254a7Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16181254a7Smrg GNU General Public License for more details.
17181254a7Smrg
18181254a7Smrg Under Section 7 of GPL version 3, you are granted additional
19181254a7Smrg permissions described in the GCC Runtime Library Exception, version
20181254a7Smrg 3.1, as published by the Free Software Foundation.
21181254a7Smrg
22181254a7Smrg You should have received a copy of the GNU General Public License and
23181254a7Smrg a copy of the GCC Runtime Library Exception along with this program;
24181254a7Smrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25181254a7Smrg <http://www.gnu.org/licenses/>. */
26181254a7Smrg
27181254a7Smrg
28181254a7Smrg /* transfer.c -- Top level handling of data transfer statements. */
29181254a7Smrg
30181254a7Smrg #include "io.h"
31181254a7Smrg #include "fbuf.h"
32181254a7Smrg #include "format.h"
33181254a7Smrg #include "unix.h"
34181254a7Smrg #include "async.h"
35181254a7Smrg #include <string.h>
36181254a7Smrg #include <errno.h>
37181254a7Smrg
38181254a7Smrg
39181254a7Smrg /* Calling conventions: Data transfer statements are unlike other
40181254a7Smrg library calls in that they extend over several calls.
41181254a7Smrg
42181254a7Smrg The first call is always a call to st_read() or st_write(). These
43181254a7Smrg subroutines return no status unless a namelist read or write is
44181254a7Smrg being done, in which case there is the usual status. No further
45181254a7Smrg calls are necessary in this case.
46181254a7Smrg
47181254a7Smrg For other sorts of data transfer, there are zero or more data
48181254a7Smrg transfer statement that depend on the format of the data transfer
49181254a7Smrg statement. For READ (and for backwards compatibily: for WRITE), one has
50181254a7Smrg
51181254a7Smrg transfer_integer
52181254a7Smrg transfer_logical
53181254a7Smrg transfer_character
54181254a7Smrg transfer_character_wide
55181254a7Smrg transfer_real
56181254a7Smrg transfer_complex
57181254a7Smrg transfer_real128
58181254a7Smrg transfer_complex128
59181254a7Smrg
60181254a7Smrg and for WRITE
61181254a7Smrg
62181254a7Smrg transfer_integer_write
63181254a7Smrg transfer_logical_write
64181254a7Smrg transfer_character_write
65181254a7Smrg transfer_character_wide_write
66181254a7Smrg transfer_real_write
67181254a7Smrg transfer_complex_write
68181254a7Smrg transfer_real128_write
69181254a7Smrg transfer_complex128_write
70181254a7Smrg
71181254a7Smrg These subroutines do not return status. The *128 functions
72181254a7Smrg are in the file transfer128.c.
73181254a7Smrg
74181254a7Smrg The last call is a call to st_[read|write]_done(). While
75181254a7Smrg something can easily go wrong with the initial st_read() or
76181254a7Smrg st_write(), an error inhibits any data from actually being
77181254a7Smrg transferred. */
78181254a7Smrg
79181254a7Smrg extern void transfer_integer (st_parameter_dt *, void *, int);
80181254a7Smrg export_proto(transfer_integer);
81181254a7Smrg
82181254a7Smrg extern void transfer_integer_write (st_parameter_dt *, void *, int);
83181254a7Smrg export_proto(transfer_integer_write);
84181254a7Smrg
85181254a7Smrg extern void transfer_real (st_parameter_dt *, void *, int);
86181254a7Smrg export_proto(transfer_real);
87181254a7Smrg
88181254a7Smrg extern void transfer_real_write (st_parameter_dt *, void *, int);
89181254a7Smrg export_proto(transfer_real_write);
90181254a7Smrg
91181254a7Smrg extern void transfer_logical (st_parameter_dt *, void *, int);
92181254a7Smrg export_proto(transfer_logical);
93181254a7Smrg
94181254a7Smrg extern void transfer_logical_write (st_parameter_dt *, void *, int);
95181254a7Smrg export_proto(transfer_logical_write);
96181254a7Smrg
97181254a7Smrg extern void transfer_character (st_parameter_dt *, void *, gfc_charlen_type);
98181254a7Smrg export_proto(transfer_character);
99181254a7Smrg
100181254a7Smrg extern void transfer_character_write (st_parameter_dt *, void *, gfc_charlen_type);
101181254a7Smrg export_proto(transfer_character_write);
102181254a7Smrg
103181254a7Smrg extern void transfer_character_wide (st_parameter_dt *, void *, gfc_charlen_type, int);
104181254a7Smrg export_proto(transfer_character_wide);
105181254a7Smrg
106181254a7Smrg extern void transfer_character_wide_write (st_parameter_dt *,
107181254a7Smrg void *, gfc_charlen_type, int);
108181254a7Smrg export_proto(transfer_character_wide_write);
109181254a7Smrg
110181254a7Smrg extern void transfer_complex (st_parameter_dt *, void *, int);
111181254a7Smrg export_proto(transfer_complex);
112181254a7Smrg
113181254a7Smrg extern void transfer_complex_write (st_parameter_dt *, void *, int);
114181254a7Smrg export_proto(transfer_complex_write);
115181254a7Smrg
116181254a7Smrg extern void transfer_array (st_parameter_dt *, gfc_array_char *, int,
117181254a7Smrg gfc_charlen_type);
118181254a7Smrg export_proto(transfer_array);
119181254a7Smrg
120181254a7Smrg extern void transfer_array_write (st_parameter_dt *, gfc_array_char *, int,
121181254a7Smrg gfc_charlen_type);
122181254a7Smrg export_proto(transfer_array_write);
123181254a7Smrg
124181254a7Smrg /* User defined derived type input/output. */
125181254a7Smrg extern void
126181254a7Smrg transfer_derived (st_parameter_dt *dtp, void *dtio_source, void *dtio_proc);
127181254a7Smrg export_proto(transfer_derived);
128181254a7Smrg
129181254a7Smrg extern void
130181254a7Smrg transfer_derived_write (st_parameter_dt *dtp, void *dtio_source, void *dtio_proc);
131181254a7Smrg export_proto(transfer_derived_write);
132181254a7Smrg
133181254a7Smrg static void us_read (st_parameter_dt *, int);
134181254a7Smrg static void us_write (st_parameter_dt *, int);
135181254a7Smrg static void next_record_r_unf (st_parameter_dt *, int);
136181254a7Smrg static void next_record_w_unf (st_parameter_dt *, int);
137181254a7Smrg
138181254a7Smrg static const st_option advance_opt[] = {
139181254a7Smrg {"yes", ADVANCE_YES},
140181254a7Smrg {"no", ADVANCE_NO},
141181254a7Smrg {NULL, 0}
142181254a7Smrg };
143181254a7Smrg
144181254a7Smrg
145181254a7Smrg static const st_option decimal_opt[] = {
146181254a7Smrg {"point", DECIMAL_POINT},
147181254a7Smrg {"comma", DECIMAL_COMMA},
148181254a7Smrg {NULL, 0}
149181254a7Smrg };
150181254a7Smrg
151181254a7Smrg static const st_option round_opt[] = {
152181254a7Smrg {"up", ROUND_UP},
153181254a7Smrg {"down", ROUND_DOWN},
154181254a7Smrg {"zero", ROUND_ZERO},
155181254a7Smrg {"nearest", ROUND_NEAREST},
156181254a7Smrg {"compatible", ROUND_COMPATIBLE},
157181254a7Smrg {"processor_defined", ROUND_PROCDEFINED},
158181254a7Smrg {NULL, 0}
159181254a7Smrg };
160181254a7Smrg
161181254a7Smrg
162181254a7Smrg static const st_option sign_opt[] = {
163181254a7Smrg {"plus", SIGN_SP},
164181254a7Smrg {"suppress", SIGN_SS},
165181254a7Smrg {"processor_defined", SIGN_S},
166181254a7Smrg {NULL, 0}
167181254a7Smrg };
168181254a7Smrg
169181254a7Smrg static const st_option blank_opt[] = {
170181254a7Smrg {"null", BLANK_NULL},
171181254a7Smrg {"zero", BLANK_ZERO},
172181254a7Smrg {NULL, 0}
173181254a7Smrg };
174181254a7Smrg
175181254a7Smrg static const st_option delim_opt[] = {
176181254a7Smrg {"apostrophe", DELIM_APOSTROPHE},
177181254a7Smrg {"quote", DELIM_QUOTE},
178181254a7Smrg {"none", DELIM_NONE},
179181254a7Smrg {NULL, 0}
180181254a7Smrg };
181181254a7Smrg
182181254a7Smrg static const st_option pad_opt[] = {
183181254a7Smrg {"yes", PAD_YES},
184181254a7Smrg {"no", PAD_NO},
185181254a7Smrg {NULL, 0}
186181254a7Smrg };
187181254a7Smrg
188181254a7Smrg static const st_option async_opt[] = {
189181254a7Smrg {"yes", ASYNC_YES},
190181254a7Smrg {"no", ASYNC_NO},
191181254a7Smrg {NULL, 0}
192181254a7Smrg };
193181254a7Smrg
194181254a7Smrg typedef enum
195181254a7Smrg { FORMATTED_SEQUENTIAL, UNFORMATTED_SEQUENTIAL,
196fb8a8121Smrg FORMATTED_DIRECT, UNFORMATTED_DIRECT, FORMATTED_STREAM,
197fb8a8121Smrg UNFORMATTED_STREAM, FORMATTED_UNSPECIFIED
198181254a7Smrg }
199181254a7Smrg file_mode;
200181254a7Smrg
201181254a7Smrg
202181254a7Smrg static file_mode
current_mode(st_parameter_dt * dtp)203181254a7Smrg current_mode (st_parameter_dt *dtp)
204181254a7Smrg {
205181254a7Smrg file_mode m;
206181254a7Smrg
207fb8a8121Smrg m = FORMATTED_UNSPECIFIED;
208181254a7Smrg
209181254a7Smrg if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT)
210181254a7Smrg {
211181254a7Smrg m = dtp->u.p.current_unit->flags.form == FORM_FORMATTED ?
212181254a7Smrg FORMATTED_DIRECT : UNFORMATTED_DIRECT;
213181254a7Smrg }
214181254a7Smrg else if (dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL)
215181254a7Smrg {
216181254a7Smrg m = dtp->u.p.current_unit->flags.form == FORM_FORMATTED ?
217181254a7Smrg FORMATTED_SEQUENTIAL : UNFORMATTED_SEQUENTIAL;
218181254a7Smrg }
219181254a7Smrg else if (dtp->u.p.current_unit->flags.access == ACCESS_STREAM)
220181254a7Smrg {
221181254a7Smrg m = dtp->u.p.current_unit->flags.form == FORM_FORMATTED ?
222181254a7Smrg FORMATTED_STREAM : UNFORMATTED_STREAM;
223181254a7Smrg }
224181254a7Smrg
225181254a7Smrg return m;
226181254a7Smrg }
227181254a7Smrg
228181254a7Smrg
229181254a7Smrg /* Mid level data transfer statements. */
230181254a7Smrg
231181254a7Smrg /* Read sequential file - internal unit */
232181254a7Smrg
233181254a7Smrg static char *
read_sf_internal(st_parameter_dt * dtp,size_t * length)234181254a7Smrg read_sf_internal (st_parameter_dt *dtp, size_t *length)
235181254a7Smrg {
236181254a7Smrg static char *empty_string[0];
237181254a7Smrg char *base = NULL;
238181254a7Smrg size_t lorig;
239181254a7Smrg
240181254a7Smrg /* Zero size array gives internal unit len of 0. Nothing to read. */
241181254a7Smrg if (dtp->internal_unit_len == 0
242181254a7Smrg && dtp->u.p.current_unit->pad_status == PAD_NO)
243181254a7Smrg hit_eof (dtp);
244181254a7Smrg
245181254a7Smrg /* There are some cases with mixed DTIO where we have read a character
246181254a7Smrg and saved it in the last character buffer, so we need to backup. */
247181254a7Smrg if (unlikely (dtp->u.p.current_unit->child_dtio > 0 &&
248181254a7Smrg dtp->u.p.current_unit->last_char != EOF - 1))
249181254a7Smrg {
250181254a7Smrg dtp->u.p.current_unit->last_char = EOF - 1;
251181254a7Smrg sseek (dtp->u.p.current_unit->s, -1, SEEK_CUR);
252181254a7Smrg }
253181254a7Smrg
254181254a7Smrg /* To support legacy code we have to scan the input string one byte
255181254a7Smrg at a time because we don't know where an early comma may be and the
256181254a7Smrg requested length could go past the end of a comma shortened
257181254a7Smrg string. We only do this if -std=legacy was given at compile
258181254a7Smrg time. We also do not support this on kind=4 strings. */
259181254a7Smrg if (unlikely(compile_options.warn_std == 0)) // the slow legacy way.
260181254a7Smrg {
261181254a7Smrg size_t n;
262181254a7Smrg size_t tmp = 1;
263181254a7Smrg char *q;
264181254a7Smrg
265181254a7Smrg /* If we have seen an eor previously, return a length of 0. The
266181254a7Smrg caller is responsible for correctly padding the input field. */
267181254a7Smrg if (dtp->u.p.sf_seen_eor)
268181254a7Smrg {
269181254a7Smrg *length = 0;
270181254a7Smrg /* Just return something that isn't a NULL pointer, otherwise the
271181254a7Smrg caller thinks an error occurred. */
272181254a7Smrg return (char*) empty_string;
273181254a7Smrg }
274181254a7Smrg
275181254a7Smrg /* Get the first character of the string to establish the base
276181254a7Smrg address and check for comma or end-of-record condition. */
277181254a7Smrg base = mem_alloc_r (dtp->u.p.current_unit->s, &tmp);
278181254a7Smrg if (tmp == 0)
279181254a7Smrg {
280181254a7Smrg dtp->u.p.sf_seen_eor = 1;
281181254a7Smrg *length = 0;
282181254a7Smrg return (char*) empty_string;
283181254a7Smrg }
284181254a7Smrg if (*base == ',')
285181254a7Smrg {
286181254a7Smrg dtp->u.p.current_unit->bytes_left--;
287181254a7Smrg *length = 0;
288181254a7Smrg return (char*) empty_string;
289181254a7Smrg }
290181254a7Smrg
291181254a7Smrg /* Now we scan the rest and deal with either an end-of-file
292181254a7Smrg condition or a comma, as needed. */
293181254a7Smrg for (n = 1; n < *length; n++)
294181254a7Smrg {
295181254a7Smrg q = mem_alloc_r (dtp->u.p.current_unit->s, &tmp);
296181254a7Smrg if (tmp == 0)
297181254a7Smrg {
298181254a7Smrg hit_eof (dtp);
299181254a7Smrg return NULL;
300181254a7Smrg }
301181254a7Smrg if (*q == ',')
302181254a7Smrg {
303181254a7Smrg dtp->u.p.current_unit->bytes_left -= n;
304181254a7Smrg *length = n;
305181254a7Smrg break;
306181254a7Smrg }
307181254a7Smrg }
308181254a7Smrg }
309181254a7Smrg else // the fast way
310181254a7Smrg {
311181254a7Smrg lorig = *length;
312181254a7Smrg if (is_char4_unit(dtp))
313181254a7Smrg {
314181254a7Smrg gfc_char4_t *p = (gfc_char4_t *) mem_alloc_r4 (dtp->u.p.current_unit->s,
315181254a7Smrg length);
316181254a7Smrg base = fbuf_alloc (dtp->u.p.current_unit, lorig);
317181254a7Smrg for (size_t i = 0; i < *length; i++, p++)
318181254a7Smrg base[i] = *p > 255 ? '?' : (unsigned char) *p;
319181254a7Smrg }
320181254a7Smrg else
321181254a7Smrg base = mem_alloc_r (dtp->u.p.current_unit->s, length);
322181254a7Smrg
323181254a7Smrg if (unlikely (lorig > *length))
324181254a7Smrg {
325181254a7Smrg hit_eof (dtp);
326181254a7Smrg return NULL;
327181254a7Smrg }
328181254a7Smrg }
329181254a7Smrg
330181254a7Smrg dtp->u.p.current_unit->bytes_left -= *length;
331181254a7Smrg
332181254a7Smrg if (((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0) ||
333181254a7Smrg dtp->u.p.current_unit->has_size)
334181254a7Smrg dtp->u.p.current_unit->size_used += (GFC_IO_INT) *length;
335181254a7Smrg
336181254a7Smrg return base;
337181254a7Smrg
338181254a7Smrg }
339181254a7Smrg
340181254a7Smrg /* When reading sequential formatted records we have a problem. We
341181254a7Smrg don't know how long the line is until we read the trailing newline,
342181254a7Smrg and we don't want to read too much. If we read too much, we might
343181254a7Smrg have to do a physical seek backwards depending on how much data is
344181254a7Smrg present, and devices like terminals aren't seekable and would cause
345181254a7Smrg an I/O error.
346181254a7Smrg
347181254a7Smrg Given this, the solution is to read a byte at a time, stopping if
348181254a7Smrg we hit the newline. For small allocations, we use a static buffer.
349181254a7Smrg For larger allocations, we are forced to allocate memory on the
350181254a7Smrg heap. Hopefully this won't happen very often. */
351181254a7Smrg
352181254a7Smrg /* Read sequential file - external unit */
353181254a7Smrg
354181254a7Smrg static char *
read_sf(st_parameter_dt * dtp,size_t * length)355181254a7Smrg read_sf (st_parameter_dt *dtp, size_t *length)
356181254a7Smrg {
357181254a7Smrg static char *empty_string[0];
358181254a7Smrg size_t lorig, n;
359181254a7Smrg int q, q2;
360181254a7Smrg int seen_comma;
361181254a7Smrg
362181254a7Smrg /* If we have seen an eor previously, return a length of 0. The
363181254a7Smrg caller is responsible for correctly padding the input field. */
364181254a7Smrg if (dtp->u.p.sf_seen_eor)
365181254a7Smrg {
366181254a7Smrg *length = 0;
367181254a7Smrg /* Just return something that isn't a NULL pointer, otherwise the
368181254a7Smrg caller thinks an error occurred. */
369181254a7Smrg return (char*) empty_string;
370181254a7Smrg }
371181254a7Smrg
372181254a7Smrg /* There are some cases with mixed DTIO where we have read a character
373181254a7Smrg and saved it in the last character buffer, so we need to backup. */
374181254a7Smrg if (unlikely (dtp->u.p.current_unit->child_dtio > 0 &&
375181254a7Smrg dtp->u.p.current_unit->last_char != EOF - 1))
376181254a7Smrg {
377181254a7Smrg dtp->u.p.current_unit->last_char = EOF - 1;
378181254a7Smrg fbuf_seek (dtp->u.p.current_unit, -1, SEEK_CUR);
379181254a7Smrg }
380181254a7Smrg
381181254a7Smrg n = seen_comma = 0;
382181254a7Smrg
383181254a7Smrg /* Read data into format buffer and scan through it. */
384181254a7Smrg lorig = *length;
385181254a7Smrg
386181254a7Smrg while (n < *length)
387181254a7Smrg {
388181254a7Smrg q = fbuf_getc (dtp->u.p.current_unit);
389181254a7Smrg if (q == EOF)
390181254a7Smrg break;
391181254a7Smrg else if (dtp->u.p.current_unit->flags.cc != CC_NONE
392181254a7Smrg && (q == '\n' || q == '\r'))
393181254a7Smrg {
394181254a7Smrg /* Unexpected end of line. Set the position. */
395181254a7Smrg dtp->u.p.sf_seen_eor = 1;
396181254a7Smrg
397181254a7Smrg /* If we see an EOR during non-advancing I/O, we need to skip
398181254a7Smrg the rest of the I/O statement. Set the corresponding flag. */
399181254a7Smrg if (dtp->u.p.advance_status == ADVANCE_NO || dtp->u.p.seen_dollar)
400181254a7Smrg dtp->u.p.eor_condition = 1;
401181254a7Smrg
402181254a7Smrg /* If we encounter a CR, it might be a CRLF. */
403181254a7Smrg if (q == '\r') /* Probably a CRLF */
404181254a7Smrg {
405181254a7Smrg /* See if there is an LF. */
406181254a7Smrg q2 = fbuf_getc (dtp->u.p.current_unit);
407181254a7Smrg if (q2 == '\n')
408181254a7Smrg dtp->u.p.sf_seen_eor = 2;
409181254a7Smrg else if (q2 != EOF) /* Oops, seek back. */
410181254a7Smrg fbuf_seek (dtp->u.p.current_unit, -1, SEEK_CUR);
411181254a7Smrg }
412181254a7Smrg
413181254a7Smrg /* Without padding, terminate the I/O statement without assigning
414181254a7Smrg the value. With padding, the value still needs to be assigned,
415181254a7Smrg so we can just continue with a short read. */
416181254a7Smrg if (dtp->u.p.current_unit->pad_status == PAD_NO)
417181254a7Smrg {
418181254a7Smrg generate_error (&dtp->common, LIBERROR_EOR, NULL);
419181254a7Smrg return NULL;
420181254a7Smrg }
421181254a7Smrg
422181254a7Smrg *length = n;
423181254a7Smrg goto done;
424181254a7Smrg }
425181254a7Smrg /* Short circuit the read if a comma is found during numeric input.
426181254a7Smrg The flag is set to zero during character reads so that commas in
427181254a7Smrg strings are not ignored */
428181254a7Smrg else if (q == ',')
429181254a7Smrg if (dtp->u.p.sf_read_comma == 1)
430181254a7Smrg {
431181254a7Smrg seen_comma = 1;
432181254a7Smrg notify_std (&dtp->common, GFC_STD_GNU,
433181254a7Smrg "Comma in formatted numeric read.");
434181254a7Smrg break;
435181254a7Smrg }
436181254a7Smrg n++;
437181254a7Smrg }
438181254a7Smrg
439181254a7Smrg *length = n;
440181254a7Smrg
441181254a7Smrg /* A short read implies we hit EOF, unless we hit EOR, a comma, or
442181254a7Smrg some other stuff. Set the relevant flags. */
443181254a7Smrg if (lorig > *length && !dtp->u.p.sf_seen_eor && !seen_comma)
444181254a7Smrg {
445181254a7Smrg if (n > 0)
446181254a7Smrg {
447181254a7Smrg if (dtp->u.p.advance_status == ADVANCE_NO)
448181254a7Smrg {
449181254a7Smrg if (dtp->u.p.current_unit->pad_status == PAD_NO)
450181254a7Smrg {
451181254a7Smrg hit_eof (dtp);
452181254a7Smrg return NULL;
453181254a7Smrg }
454181254a7Smrg else
455181254a7Smrg dtp->u.p.eor_condition = 1;
456181254a7Smrg }
457181254a7Smrg else
458181254a7Smrg dtp->u.p.at_eof = 1;
459181254a7Smrg }
460181254a7Smrg else if (dtp->u.p.advance_status == ADVANCE_NO
461181254a7Smrg || dtp->u.p.current_unit->pad_status == PAD_NO
462181254a7Smrg || dtp->u.p.current_unit->bytes_left
463181254a7Smrg == dtp->u.p.current_unit->recl)
464181254a7Smrg {
465181254a7Smrg hit_eof (dtp);
466181254a7Smrg return NULL;
467181254a7Smrg }
468181254a7Smrg }
469181254a7Smrg
470181254a7Smrg done:
471181254a7Smrg
472181254a7Smrg dtp->u.p.current_unit->bytes_left -= n;
473181254a7Smrg
474181254a7Smrg if (((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0) ||
475181254a7Smrg dtp->u.p.current_unit->has_size)
476181254a7Smrg dtp->u.p.current_unit->size_used += (GFC_IO_INT) n;
477181254a7Smrg
478181254a7Smrg /* We can't call fbuf_getptr before the loop doing fbuf_getc, because
479181254a7Smrg fbuf_getc might reallocate the buffer. So return current pointer
480181254a7Smrg minus all the advances, which is n plus up to two characters
481181254a7Smrg of newline or comma. */
482181254a7Smrg return fbuf_getptr (dtp->u.p.current_unit)
483181254a7Smrg - n - dtp->u.p.sf_seen_eor - seen_comma;
484181254a7Smrg }
485181254a7Smrg
486181254a7Smrg
487181254a7Smrg /* Function for reading the next couple of bytes from the current
488181254a7Smrg file, advancing the current position. We return NULL on end of record or
489181254a7Smrg end of file. This function is only for formatted I/O, unformatted uses
490181254a7Smrg read_block_direct.
491181254a7Smrg
492181254a7Smrg If the read is short, then it is because the current record does not
493181254a7Smrg have enough data to satisfy the read request and the file was
494*b1e83836Smrg opened with PAD=YES. The caller must assume trailing spaces for
495181254a7Smrg short reads. */
496181254a7Smrg
497181254a7Smrg void *
read_block_form(st_parameter_dt * dtp,size_t * nbytes)498181254a7Smrg read_block_form (st_parameter_dt *dtp, size_t *nbytes)
499181254a7Smrg {
500181254a7Smrg char *source;
501181254a7Smrg size_t norig;
502181254a7Smrg
503181254a7Smrg if (!is_stream_io (dtp))
504181254a7Smrg {
505181254a7Smrg if (dtp->u.p.current_unit->bytes_left < (gfc_offset) *nbytes)
506181254a7Smrg {
507181254a7Smrg /* For preconnected units with default record length, set bytes left
508181254a7Smrg to unit record length and proceed, otherwise error. */
509181254a7Smrg if (dtp->u.p.current_unit->unit_number == options.stdin_unit
510181254a7Smrg && dtp->u.p.current_unit->recl == default_recl)
511181254a7Smrg dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
512181254a7Smrg else
513181254a7Smrg {
514181254a7Smrg if (unlikely (dtp->u.p.current_unit->pad_status == PAD_NO)
515181254a7Smrg && !is_internal_unit (dtp))
516181254a7Smrg {
517181254a7Smrg /* Not enough data left. */
518181254a7Smrg generate_error (&dtp->common, LIBERROR_EOR, NULL);
519181254a7Smrg return NULL;
520181254a7Smrg }
521181254a7Smrg }
522181254a7Smrg
523181254a7Smrg if (is_internal_unit(dtp))
524181254a7Smrg {
525181254a7Smrg if (*nbytes > 0 && dtp->u.p.current_unit->bytes_left == 0)
526181254a7Smrg {
527181254a7Smrg if (dtp->u.p.advance_status == ADVANCE_NO)
528181254a7Smrg {
529181254a7Smrg generate_error (&dtp->common, LIBERROR_EOR, NULL);
530181254a7Smrg return NULL;
531181254a7Smrg }
532181254a7Smrg }
533181254a7Smrg }
534181254a7Smrg else
535181254a7Smrg {
536181254a7Smrg if (unlikely (dtp->u.p.current_unit->bytes_left == 0))
537181254a7Smrg {
538181254a7Smrg hit_eof (dtp);
539181254a7Smrg return NULL;
540181254a7Smrg }
541181254a7Smrg }
542181254a7Smrg
543181254a7Smrg *nbytes = dtp->u.p.current_unit->bytes_left;
544181254a7Smrg }
545181254a7Smrg }
546181254a7Smrg
547181254a7Smrg if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED &&
548181254a7Smrg (dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL ||
549181254a7Smrg dtp->u.p.current_unit->flags.access == ACCESS_STREAM))
550181254a7Smrg {
551181254a7Smrg if (is_internal_unit (dtp))
552181254a7Smrg source = read_sf_internal (dtp, nbytes);
553181254a7Smrg else
554181254a7Smrg source = read_sf (dtp, nbytes);
555181254a7Smrg
556181254a7Smrg dtp->u.p.current_unit->strm_pos +=
557181254a7Smrg (gfc_offset) (*nbytes + dtp->u.p.sf_seen_eor);
558181254a7Smrg return source;
559181254a7Smrg }
560181254a7Smrg
561181254a7Smrg /* If we reach here, we can assume it's direct access. */
562181254a7Smrg
563181254a7Smrg dtp->u.p.current_unit->bytes_left -= (gfc_offset) *nbytes;
564181254a7Smrg
565181254a7Smrg norig = *nbytes;
566181254a7Smrg source = fbuf_read (dtp->u.p.current_unit, nbytes);
567181254a7Smrg fbuf_seek (dtp->u.p.current_unit, *nbytes, SEEK_CUR);
568181254a7Smrg
569181254a7Smrg if (((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0) ||
570181254a7Smrg dtp->u.p.current_unit->has_size)
571181254a7Smrg dtp->u.p.current_unit->size_used += (GFC_IO_INT) *nbytes;
572181254a7Smrg
573181254a7Smrg if (norig != *nbytes)
574181254a7Smrg {
575181254a7Smrg /* Short read, this shouldn't happen. */
576181254a7Smrg if (dtp->u.p.current_unit->pad_status == PAD_NO)
577181254a7Smrg {
578181254a7Smrg generate_error (&dtp->common, LIBERROR_EOR, NULL);
579181254a7Smrg source = NULL;
580181254a7Smrg }
581181254a7Smrg }
582181254a7Smrg
583181254a7Smrg dtp->u.p.current_unit->strm_pos += (gfc_offset) *nbytes;
584181254a7Smrg
585181254a7Smrg return source;
586181254a7Smrg }
587181254a7Smrg
588181254a7Smrg
589181254a7Smrg /* Read a block from a character(kind=4) internal unit, to be transferred into
590181254a7Smrg a character(kind=4) variable. Note: Portions of this code borrowed from
591181254a7Smrg read_sf_internal. */
592181254a7Smrg void *
read_block_form4(st_parameter_dt * dtp,size_t * nbytes)593181254a7Smrg read_block_form4 (st_parameter_dt *dtp, size_t *nbytes)
594181254a7Smrg {
595181254a7Smrg static gfc_char4_t *empty_string[0];
596181254a7Smrg gfc_char4_t *source;
597181254a7Smrg size_t lorig;
598181254a7Smrg
599181254a7Smrg if (dtp->u.p.current_unit->bytes_left < (gfc_offset) *nbytes)
600181254a7Smrg *nbytes = dtp->u.p.current_unit->bytes_left;
601181254a7Smrg
602181254a7Smrg /* Zero size array gives internal unit len of 0. Nothing to read. */
603181254a7Smrg if (dtp->internal_unit_len == 0
604181254a7Smrg && dtp->u.p.current_unit->pad_status == PAD_NO)
605181254a7Smrg hit_eof (dtp);
606181254a7Smrg
607181254a7Smrg /* If we have seen an eor previously, return a length of 0. The
608181254a7Smrg caller is responsible for correctly padding the input field. */
609181254a7Smrg if (dtp->u.p.sf_seen_eor)
610181254a7Smrg {
611181254a7Smrg *nbytes = 0;
612181254a7Smrg /* Just return something that isn't a NULL pointer, otherwise the
613181254a7Smrg caller thinks an error occurred. */
614181254a7Smrg return empty_string;
615181254a7Smrg }
616181254a7Smrg
617181254a7Smrg lorig = *nbytes;
618181254a7Smrg source = (gfc_char4_t *) mem_alloc_r4 (dtp->u.p.current_unit->s, nbytes);
619181254a7Smrg
620181254a7Smrg if (unlikely (lorig > *nbytes))
621181254a7Smrg {
622181254a7Smrg hit_eof (dtp);
623181254a7Smrg return NULL;
624181254a7Smrg }
625181254a7Smrg
626181254a7Smrg dtp->u.p.current_unit->bytes_left -= *nbytes;
627181254a7Smrg
628181254a7Smrg if (((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0) ||
629181254a7Smrg dtp->u.p.current_unit->has_size)
630181254a7Smrg dtp->u.p.current_unit->size_used += (GFC_IO_INT) *nbytes;
631181254a7Smrg
632181254a7Smrg return source;
633181254a7Smrg }
634181254a7Smrg
635181254a7Smrg
636181254a7Smrg /* Reads a block directly into application data space. This is for
637181254a7Smrg unformatted files. */
638181254a7Smrg
639181254a7Smrg static void
read_block_direct(st_parameter_dt * dtp,void * buf,size_t nbytes)640181254a7Smrg read_block_direct (st_parameter_dt *dtp, void *buf, size_t nbytes)
641181254a7Smrg {
642181254a7Smrg ssize_t to_read_record;
643181254a7Smrg ssize_t have_read_record;
644181254a7Smrg ssize_t to_read_subrecord;
645181254a7Smrg ssize_t have_read_subrecord;
646181254a7Smrg int short_record;
647181254a7Smrg
648181254a7Smrg if (is_stream_io (dtp))
649181254a7Smrg {
650181254a7Smrg have_read_record = sread (dtp->u.p.current_unit->s, buf,
651181254a7Smrg nbytes);
652181254a7Smrg if (unlikely (have_read_record < 0))
653181254a7Smrg {
654181254a7Smrg generate_error (&dtp->common, LIBERROR_OS, NULL);
655181254a7Smrg return;
656181254a7Smrg }
657181254a7Smrg
658181254a7Smrg dtp->u.p.current_unit->strm_pos += (gfc_offset) have_read_record;
659181254a7Smrg
660181254a7Smrg if (unlikely ((ssize_t) nbytes != have_read_record))
661181254a7Smrg {
662181254a7Smrg /* Short read, e.g. if we hit EOF. For stream files,
663181254a7Smrg we have to set the end-of-file condition. */
664181254a7Smrg hit_eof (dtp);
665181254a7Smrg }
666181254a7Smrg return;
667181254a7Smrg }
668181254a7Smrg
669181254a7Smrg if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT)
670181254a7Smrg {
671181254a7Smrg if (dtp->u.p.current_unit->bytes_left < (gfc_offset) nbytes)
672181254a7Smrg {
673181254a7Smrg short_record = 1;
674181254a7Smrg to_read_record = dtp->u.p.current_unit->bytes_left;
675181254a7Smrg nbytes = to_read_record;
676181254a7Smrg }
677181254a7Smrg else
678181254a7Smrg {
679181254a7Smrg short_record = 0;
680181254a7Smrg to_read_record = nbytes;
681181254a7Smrg }
682181254a7Smrg
683181254a7Smrg dtp->u.p.current_unit->bytes_left -= to_read_record;
684181254a7Smrg
685181254a7Smrg to_read_record = sread (dtp->u.p.current_unit->s, buf, to_read_record);
686181254a7Smrg if (unlikely (to_read_record < 0))
687181254a7Smrg {
688181254a7Smrg generate_error (&dtp->common, LIBERROR_OS, NULL);
689181254a7Smrg return;
690181254a7Smrg }
691181254a7Smrg
692181254a7Smrg if (to_read_record != (ssize_t) nbytes)
693181254a7Smrg {
694181254a7Smrg /* Short read, e.g. if we hit EOF. Apparently, we read
695181254a7Smrg more than was written to the last record. */
696181254a7Smrg return;
697181254a7Smrg }
698181254a7Smrg
699181254a7Smrg if (unlikely (short_record))
700181254a7Smrg {
701181254a7Smrg generate_error (&dtp->common, LIBERROR_SHORT_RECORD, NULL);
702181254a7Smrg }
703181254a7Smrg return;
704181254a7Smrg }
705181254a7Smrg
706181254a7Smrg /* Unformatted sequential. We loop over the subrecords, reading
707181254a7Smrg until the request has been fulfilled or the record has run out
708181254a7Smrg of continuation subrecords. */
709181254a7Smrg
710181254a7Smrg /* Check whether we exceed the total record length. */
711181254a7Smrg
712181254a7Smrg if (dtp->u.p.current_unit->flags.has_recl
713181254a7Smrg && ((gfc_offset) nbytes > dtp->u.p.current_unit->bytes_left))
714181254a7Smrg {
715181254a7Smrg to_read_record = dtp->u.p.current_unit->bytes_left;
716181254a7Smrg short_record = 1;
717181254a7Smrg }
718181254a7Smrg else
719181254a7Smrg {
720181254a7Smrg to_read_record = nbytes;
721181254a7Smrg short_record = 0;
722181254a7Smrg }
723181254a7Smrg have_read_record = 0;
724181254a7Smrg
725181254a7Smrg while(1)
726181254a7Smrg {
727181254a7Smrg if (dtp->u.p.current_unit->bytes_left_subrecord
728181254a7Smrg < (gfc_offset) to_read_record)
729181254a7Smrg {
730181254a7Smrg to_read_subrecord = dtp->u.p.current_unit->bytes_left_subrecord;
731181254a7Smrg to_read_record -= to_read_subrecord;
732181254a7Smrg }
733181254a7Smrg else
734181254a7Smrg {
735181254a7Smrg to_read_subrecord = to_read_record;
736181254a7Smrg to_read_record = 0;
737181254a7Smrg }
738181254a7Smrg
739181254a7Smrg dtp->u.p.current_unit->bytes_left_subrecord -= to_read_subrecord;
740181254a7Smrg
741181254a7Smrg have_read_subrecord = sread (dtp->u.p.current_unit->s,
742181254a7Smrg buf + have_read_record, to_read_subrecord);
743181254a7Smrg if (unlikely (have_read_subrecord < 0))
744181254a7Smrg {
745181254a7Smrg generate_error (&dtp->common, LIBERROR_OS, NULL);
746181254a7Smrg return;
747181254a7Smrg }
748181254a7Smrg
749181254a7Smrg have_read_record += have_read_subrecord;
750181254a7Smrg
751181254a7Smrg if (unlikely (to_read_subrecord != have_read_subrecord))
752181254a7Smrg {
753181254a7Smrg /* Short read, e.g. if we hit EOF. This means the record
754181254a7Smrg structure has been corrupted, or the trailing record
755181254a7Smrg marker would still be present. */
756181254a7Smrg
757181254a7Smrg generate_error (&dtp->common, LIBERROR_CORRUPT_FILE, NULL);
758181254a7Smrg return;
759181254a7Smrg }
760181254a7Smrg
761181254a7Smrg if (to_read_record > 0)
762181254a7Smrg {
763181254a7Smrg if (likely (dtp->u.p.current_unit->continued))
764181254a7Smrg {
765181254a7Smrg next_record_r_unf (dtp, 0);
766181254a7Smrg us_read (dtp, 1);
767181254a7Smrg }
768181254a7Smrg else
769181254a7Smrg {
770181254a7Smrg /* Let's make sure the file position is correctly pre-positioned
771181254a7Smrg for the next read statement. */
772181254a7Smrg
773181254a7Smrg dtp->u.p.current_unit->current_record = 0;
774181254a7Smrg next_record_r_unf (dtp, 0);
775181254a7Smrg generate_error (&dtp->common, LIBERROR_SHORT_RECORD, NULL);
776181254a7Smrg return;
777181254a7Smrg }
778181254a7Smrg }
779181254a7Smrg else
780181254a7Smrg {
781181254a7Smrg /* Normal exit, the read request has been fulfilled. */
782181254a7Smrg break;
783181254a7Smrg }
784181254a7Smrg }
785181254a7Smrg
786181254a7Smrg dtp->u.p.current_unit->bytes_left -= have_read_record;
787181254a7Smrg if (unlikely (short_record))
788181254a7Smrg {
789181254a7Smrg generate_error (&dtp->common, LIBERROR_SHORT_RECORD, NULL);
790181254a7Smrg return;
791181254a7Smrg }
792181254a7Smrg return;
793181254a7Smrg }
794181254a7Smrg
795181254a7Smrg
796181254a7Smrg /* Function for writing a block of bytes to the current file at the
797181254a7Smrg current position, advancing the file pointer. We are given a length
798181254a7Smrg and return a pointer to a buffer that the caller must (completely)
799181254a7Smrg fill in. Returns NULL on error. */
800181254a7Smrg
801181254a7Smrg void *
write_block(st_parameter_dt * dtp,size_t length)802181254a7Smrg write_block (st_parameter_dt *dtp, size_t length)
803181254a7Smrg {
804181254a7Smrg char *dest;
805181254a7Smrg
806181254a7Smrg if (!is_stream_io (dtp))
807181254a7Smrg {
808181254a7Smrg if (dtp->u.p.current_unit->bytes_left < (gfc_offset) length)
809181254a7Smrg {
810181254a7Smrg /* For preconnected units with default record length, set bytes left
811181254a7Smrg to unit record length and proceed, otherwise error. */
812181254a7Smrg if (likely ((dtp->u.p.current_unit->unit_number
813181254a7Smrg == options.stdout_unit
814181254a7Smrg || dtp->u.p.current_unit->unit_number
815181254a7Smrg == options.stderr_unit)
816181254a7Smrg && dtp->u.p.current_unit->recl == default_recl))
817181254a7Smrg dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
818181254a7Smrg else
819181254a7Smrg {
820181254a7Smrg generate_error (&dtp->common, LIBERROR_EOR, NULL);
821181254a7Smrg return NULL;
822181254a7Smrg }
823181254a7Smrg }
824181254a7Smrg
825181254a7Smrg dtp->u.p.current_unit->bytes_left -= (gfc_offset) length;
826181254a7Smrg }
827181254a7Smrg
828181254a7Smrg if (is_internal_unit (dtp))
829181254a7Smrg {
830181254a7Smrg if (is_char4_unit(dtp)) /* char4 internel unit. */
831181254a7Smrg {
832181254a7Smrg gfc_char4_t *dest4;
833181254a7Smrg dest4 = mem_alloc_w4 (dtp->u.p.current_unit->s, &length);
834181254a7Smrg if (dest4 == NULL)
835181254a7Smrg {
836181254a7Smrg generate_error (&dtp->common, LIBERROR_END, NULL);
837181254a7Smrg return NULL;
838181254a7Smrg }
839181254a7Smrg return dest4;
840181254a7Smrg }
841181254a7Smrg else
842181254a7Smrg dest = mem_alloc_w (dtp->u.p.current_unit->s, &length);
843181254a7Smrg
844181254a7Smrg if (dest == NULL)
845181254a7Smrg {
846181254a7Smrg generate_error (&dtp->common, LIBERROR_END, NULL);
847181254a7Smrg return NULL;
848181254a7Smrg }
849181254a7Smrg
850181254a7Smrg if (unlikely (dtp->u.p.current_unit->endfile == AT_ENDFILE))
851181254a7Smrg generate_error (&dtp->common, LIBERROR_END, NULL);
852181254a7Smrg }
853181254a7Smrg else
854181254a7Smrg {
855181254a7Smrg dest = fbuf_alloc (dtp->u.p.current_unit, length);
856181254a7Smrg if (dest == NULL)
857181254a7Smrg {
858181254a7Smrg generate_error (&dtp->common, LIBERROR_OS, NULL);
859181254a7Smrg return NULL;
860181254a7Smrg }
861181254a7Smrg }
862181254a7Smrg
863181254a7Smrg if (((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0) ||
864181254a7Smrg dtp->u.p.current_unit->has_size)
865181254a7Smrg dtp->u.p.current_unit->size_used += (GFC_IO_INT) length;
866181254a7Smrg
867181254a7Smrg dtp->u.p.current_unit->strm_pos += (gfc_offset) length;
868181254a7Smrg
869181254a7Smrg return dest;
870181254a7Smrg }
871181254a7Smrg
872181254a7Smrg
873181254a7Smrg /* High level interface to swrite(), taking care of errors. This is only
874181254a7Smrg called for unformatted files. There are three cases to consider:
875181254a7Smrg Stream I/O, unformatted direct, unformatted sequential. */
876181254a7Smrg
877181254a7Smrg static bool
write_buf(st_parameter_dt * dtp,void * buf,size_t nbytes)878181254a7Smrg write_buf (st_parameter_dt *dtp, void *buf, size_t nbytes)
879181254a7Smrg {
880181254a7Smrg
881181254a7Smrg ssize_t have_written;
882181254a7Smrg ssize_t to_write_subrecord;
883181254a7Smrg int short_record;
884181254a7Smrg
885181254a7Smrg /* Stream I/O. */
886181254a7Smrg
887181254a7Smrg if (is_stream_io (dtp))
888181254a7Smrg {
889181254a7Smrg have_written = swrite (dtp->u.p.current_unit->s, buf, nbytes);
890181254a7Smrg if (unlikely (have_written < 0))
891181254a7Smrg {
892181254a7Smrg generate_error (&dtp->common, LIBERROR_OS, NULL);
893181254a7Smrg return false;
894181254a7Smrg }
895181254a7Smrg
896181254a7Smrg dtp->u.p.current_unit->strm_pos += (gfc_offset) have_written;
897181254a7Smrg
898181254a7Smrg return true;
899181254a7Smrg }
900181254a7Smrg
901181254a7Smrg /* Unformatted direct access. */
902181254a7Smrg
903181254a7Smrg if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT)
904181254a7Smrg {
905181254a7Smrg if (unlikely (dtp->u.p.current_unit->bytes_left < (gfc_offset) nbytes))
906181254a7Smrg {
907181254a7Smrg generate_error (&dtp->common, LIBERROR_DIRECT_EOR, NULL);
908181254a7Smrg return false;
909181254a7Smrg }
910181254a7Smrg
911181254a7Smrg if (buf == NULL && nbytes == 0)
912181254a7Smrg return true;
913181254a7Smrg
914181254a7Smrg have_written = swrite (dtp->u.p.current_unit->s, buf, nbytes);
915181254a7Smrg if (unlikely (have_written < 0))
916181254a7Smrg {
917181254a7Smrg generate_error (&dtp->common, LIBERROR_OS, NULL);
918181254a7Smrg return false;
919181254a7Smrg }
920181254a7Smrg
921181254a7Smrg dtp->u.p.current_unit->strm_pos += (gfc_offset) have_written;
922181254a7Smrg dtp->u.p.current_unit->bytes_left -= (gfc_offset) have_written;
923181254a7Smrg
924181254a7Smrg return true;
925181254a7Smrg }
926181254a7Smrg
927181254a7Smrg /* Unformatted sequential. */
928181254a7Smrg
929181254a7Smrg have_written = 0;
930181254a7Smrg
931181254a7Smrg if (dtp->u.p.current_unit->flags.has_recl
932181254a7Smrg && (gfc_offset) nbytes > dtp->u.p.current_unit->bytes_left)
933181254a7Smrg {
934181254a7Smrg nbytes = dtp->u.p.current_unit->bytes_left;
935181254a7Smrg short_record = 1;
936181254a7Smrg }
937181254a7Smrg else
938181254a7Smrg {
939181254a7Smrg short_record = 0;
940181254a7Smrg }
941181254a7Smrg
942181254a7Smrg while (1)
943181254a7Smrg {
944181254a7Smrg
945181254a7Smrg to_write_subrecord =
946181254a7Smrg (size_t) dtp->u.p.current_unit->bytes_left_subrecord < nbytes ?
947181254a7Smrg (size_t) dtp->u.p.current_unit->bytes_left_subrecord : nbytes;
948181254a7Smrg
949181254a7Smrg dtp->u.p.current_unit->bytes_left_subrecord -=
950181254a7Smrg (gfc_offset) to_write_subrecord;
951181254a7Smrg
952181254a7Smrg to_write_subrecord = swrite (dtp->u.p.current_unit->s,
953181254a7Smrg buf + have_written, to_write_subrecord);
954181254a7Smrg if (unlikely (to_write_subrecord < 0))
955181254a7Smrg {
956181254a7Smrg generate_error (&dtp->common, LIBERROR_OS, NULL);
957181254a7Smrg return false;
958181254a7Smrg }
959181254a7Smrg
960181254a7Smrg dtp->u.p.current_unit->strm_pos += (gfc_offset) to_write_subrecord;
961181254a7Smrg nbytes -= to_write_subrecord;
962181254a7Smrg have_written += to_write_subrecord;
963181254a7Smrg
964181254a7Smrg if (nbytes == 0)
965181254a7Smrg break;
966181254a7Smrg
967181254a7Smrg next_record_w_unf (dtp, 1);
968181254a7Smrg us_write (dtp, 1);
969181254a7Smrg }
970181254a7Smrg dtp->u.p.current_unit->bytes_left -= have_written;
971181254a7Smrg if (unlikely (short_record))
972181254a7Smrg {
973181254a7Smrg generate_error (&dtp->common, LIBERROR_SHORT_RECORD, NULL);
974181254a7Smrg return false;
975181254a7Smrg }
976181254a7Smrg return true;
977181254a7Smrg }
978181254a7Smrg
979181254a7Smrg
980181254a7Smrg /* Reverse memcpy - used for byte swapping. */
981181254a7Smrg
982181254a7Smrg static void
reverse_memcpy(void * dest,const void * src,size_t n)983181254a7Smrg reverse_memcpy (void *dest, const void *src, size_t n)
984181254a7Smrg {
985181254a7Smrg char *d, *s;
986181254a7Smrg size_t i;
987181254a7Smrg
988181254a7Smrg d = (char *) dest;
989181254a7Smrg s = (char *) src + n - 1;
990181254a7Smrg
991181254a7Smrg /* Write with ascending order - this is likely faster
992181254a7Smrg on modern architectures because of write combining. */
993181254a7Smrg for (i=0; i<n; i++)
994181254a7Smrg *(d++) = *(s--);
995181254a7Smrg }
996181254a7Smrg
997181254a7Smrg
998181254a7Smrg /* Utility function for byteswapping an array, using the bswap
999181254a7Smrg builtins if possible. dest and src can overlap completely, or then
1000181254a7Smrg they must point to separate objects; partial overlaps are not
1001181254a7Smrg allowed. */
1002181254a7Smrg
1003181254a7Smrg static void
bswap_array(void * dest,const void * src,size_t size,size_t nelems)1004181254a7Smrg bswap_array (void *dest, const void *src, size_t size, size_t nelems)
1005181254a7Smrg {
1006181254a7Smrg const char *ps;
1007181254a7Smrg char *pd;
1008181254a7Smrg
1009181254a7Smrg switch (size)
1010181254a7Smrg {
1011181254a7Smrg case 1:
1012181254a7Smrg break;
1013181254a7Smrg case 2:
1014181254a7Smrg for (size_t i = 0; i < nelems; i++)
1015181254a7Smrg ((uint16_t*)dest)[i] = __builtin_bswap16 (((uint16_t*)src)[i]);
1016181254a7Smrg break;
1017181254a7Smrg case 4:
1018181254a7Smrg for (size_t i = 0; i < nelems; i++)
1019181254a7Smrg ((uint32_t*)dest)[i] = __builtin_bswap32 (((uint32_t*)src)[i]);
1020181254a7Smrg break;
1021181254a7Smrg case 8:
1022181254a7Smrg for (size_t i = 0; i < nelems; i++)
1023181254a7Smrg ((uint64_t*)dest)[i] = __builtin_bswap64 (((uint64_t*)src)[i]);
1024181254a7Smrg break;
1025181254a7Smrg case 12:
1026181254a7Smrg ps = src;
1027181254a7Smrg pd = dest;
1028181254a7Smrg for (size_t i = 0; i < nelems; i++)
1029181254a7Smrg {
1030181254a7Smrg uint32_t tmp;
1031181254a7Smrg memcpy (&tmp, ps, 4);
1032181254a7Smrg *(uint32_t*)pd = __builtin_bswap32 (*(uint32_t*)(ps + 8));
1033181254a7Smrg *(uint32_t*)(pd + 4) = __builtin_bswap32 (*(uint32_t*)(ps + 4));
1034181254a7Smrg *(uint32_t*)(pd + 8) = __builtin_bswap32 (tmp);
1035181254a7Smrg ps += size;
1036181254a7Smrg pd += size;
1037181254a7Smrg }
1038181254a7Smrg break;
1039181254a7Smrg case 16:
1040181254a7Smrg ps = src;
1041181254a7Smrg pd = dest;
1042181254a7Smrg for (size_t i = 0; i < nelems; i++)
1043181254a7Smrg {
1044181254a7Smrg uint64_t tmp;
1045181254a7Smrg memcpy (&tmp, ps, 8);
1046181254a7Smrg *(uint64_t*)pd = __builtin_bswap64 (*(uint64_t*)(ps + 8));
1047181254a7Smrg *(uint64_t*)(pd + 8) = __builtin_bswap64 (tmp);
1048181254a7Smrg ps += size;
1049181254a7Smrg pd += size;
1050181254a7Smrg }
1051181254a7Smrg break;
1052181254a7Smrg default:
1053181254a7Smrg pd = dest;
1054181254a7Smrg if (dest != src)
1055181254a7Smrg {
1056181254a7Smrg ps = src;
1057181254a7Smrg for (size_t i = 0; i < nelems; i++)
1058181254a7Smrg {
1059181254a7Smrg reverse_memcpy (pd, ps, size);
1060181254a7Smrg ps += size;
1061181254a7Smrg pd += size;
1062181254a7Smrg }
1063181254a7Smrg }
1064181254a7Smrg else
1065181254a7Smrg {
1066181254a7Smrg /* In-place byte swap. */
1067181254a7Smrg for (size_t i = 0; i < nelems; i++)
1068181254a7Smrg {
1069181254a7Smrg char tmp, *low = pd, *high = pd + size - 1;
1070181254a7Smrg for (size_t j = 0; j < size/2; j++)
1071181254a7Smrg {
1072181254a7Smrg tmp = *low;
1073181254a7Smrg *low = *high;
1074181254a7Smrg *high = tmp;
1075181254a7Smrg low++;
1076181254a7Smrg high--;
1077181254a7Smrg }
1078181254a7Smrg pd += size;
1079181254a7Smrg }
1080181254a7Smrg }
1081181254a7Smrg }
1082181254a7Smrg }
1083181254a7Smrg
1084181254a7Smrg
1085181254a7Smrg /* Master function for unformatted reads. */
1086181254a7Smrg
1087181254a7Smrg static void
unformatted_read(st_parameter_dt * dtp,bt type,void * dest,int kind,size_t size,size_t nelems)1088181254a7Smrg unformatted_read (st_parameter_dt *dtp, bt type,
1089181254a7Smrg void *dest, int kind, size_t size, size_t nelems)
1090181254a7Smrg {
1091*b1e83836Smrg unit_convert convert;
1092*b1e83836Smrg
1093181254a7Smrg if (type == BT_CLASS)
1094181254a7Smrg {
1095181254a7Smrg int unit = dtp->u.p.current_unit->unit_number;
1096181254a7Smrg char tmp_iomsg[IOMSG_LEN] = "";
1097181254a7Smrg char *child_iomsg;
1098181254a7Smrg gfc_charlen_type child_iomsg_len;
1099181254a7Smrg int noiostat;
1100181254a7Smrg int *child_iostat = NULL;
1101181254a7Smrg
1102181254a7Smrg /* Set iostat, intent(out). */
1103181254a7Smrg noiostat = 0;
1104181254a7Smrg child_iostat = (dtp->common.flags & IOPARM_HAS_IOSTAT) ?
1105181254a7Smrg dtp->common.iostat : &noiostat;
1106181254a7Smrg
1107181254a7Smrg /* Set iomsg, intent(inout). */
1108181254a7Smrg if (dtp->common.flags & IOPARM_HAS_IOMSG)
1109181254a7Smrg {
1110181254a7Smrg child_iomsg = dtp->common.iomsg;
1111181254a7Smrg child_iomsg_len = dtp->common.iomsg_len;
1112181254a7Smrg }
1113181254a7Smrg else
1114181254a7Smrg {
1115181254a7Smrg child_iomsg = tmp_iomsg;
1116181254a7Smrg child_iomsg_len = IOMSG_LEN;
1117181254a7Smrg }
1118181254a7Smrg
1119181254a7Smrg /* Call the user defined unformatted READ procedure. */
1120181254a7Smrg dtp->u.p.current_unit->child_dtio++;
1121181254a7Smrg dtp->u.p.ufdtio_ptr (dest, &unit, child_iostat, child_iomsg,
1122181254a7Smrg child_iomsg_len);
1123181254a7Smrg dtp->u.p.current_unit->child_dtio--;
1124181254a7Smrg return;
1125181254a7Smrg }
1126181254a7Smrg
1127181254a7Smrg if (type == BT_CHARACTER)
1128181254a7Smrg size *= GFC_SIZE_OF_CHAR_KIND(kind);
1129181254a7Smrg read_block_direct (dtp, dest, size * nelems);
1130181254a7Smrg
1131*b1e83836Smrg convert = dtp->u.p.current_unit->flags.convert;
1132*b1e83836Smrg if (unlikely (convert != GFC_CONVERT_NATIVE) && kind != 1)
1133181254a7Smrg {
1134181254a7Smrg /* Handle wide chracters. */
1135181254a7Smrg if (type == BT_CHARACTER)
1136181254a7Smrg {
1137181254a7Smrg nelems *= size;
1138181254a7Smrg size = kind;
1139181254a7Smrg }
1140181254a7Smrg
1141181254a7Smrg /* Break up complex into its constituent reals. */
1142181254a7Smrg else if (type == BT_COMPLEX)
1143181254a7Smrg {
1144181254a7Smrg nelems *= 2;
1145181254a7Smrg size /= 2;
1146181254a7Smrg }
1147*b1e83836Smrg #ifndef HAVE_GFC_REAL_17
1148*b1e83836Smrg #if defined(HAVE_GFC_REAL_16) && GFC_REAL_16_DIGITS == 106
1149*b1e83836Smrg /* IBM extended format is stored as a pair of IEEE754
1150*b1e83836Smrg double values, with the more significant value first
1151*b1e83836Smrg in both big and little endian. */
1152*b1e83836Smrg if (kind == 16 && (type == BT_REAL || type == BT_COMPLEX))
1153*b1e83836Smrg {
1154*b1e83836Smrg nelems *= 2;
1155*b1e83836Smrg size /= 2;
1156*b1e83836Smrg }
1157*b1e83836Smrg #endif
1158181254a7Smrg bswap_array (dest, dest, size, nelems);
1159*b1e83836Smrg #else
1160*b1e83836Smrg unit_convert bswap = convert & ~(GFC_CONVERT_R16_IEEE | GFC_CONVERT_R16_IBM);
1161*b1e83836Smrg if (bswap == GFC_CONVERT_SWAP)
1162*b1e83836Smrg {
1163*b1e83836Smrg if ((type == BT_REAL || type == BT_COMPLEX)
1164*b1e83836Smrg && ((kind == 16 && (convert & GFC_CONVERT_R16_IEEE) == 0)
1165*b1e83836Smrg || (kind == 17 && (convert & GFC_CONVERT_R16_IBM))))
1166*b1e83836Smrg bswap_array (dest, dest, size / 2, nelems * 2);
1167*b1e83836Smrg else
1168*b1e83836Smrg bswap_array (dest, dest, size, nelems);
1169*b1e83836Smrg }
1170*b1e83836Smrg
1171*b1e83836Smrg if ((convert & GFC_CONVERT_R16_IEEE)
1172*b1e83836Smrg && kind == 16
1173*b1e83836Smrg && (type == BT_REAL || type == BT_COMPLEX))
1174*b1e83836Smrg {
1175*b1e83836Smrg char *pd = dest;
1176*b1e83836Smrg for (size_t i = 0; i < nelems; i++)
1177*b1e83836Smrg {
1178*b1e83836Smrg GFC_REAL_16 r16;
1179*b1e83836Smrg GFC_REAL_17 r17;
1180*b1e83836Smrg memcpy (&r17, pd, 16);
1181*b1e83836Smrg r16 = r17;
1182*b1e83836Smrg memcpy (pd, &r16, 16);
1183*b1e83836Smrg pd += size;
1184*b1e83836Smrg }
1185*b1e83836Smrg }
1186*b1e83836Smrg else if ((dtp->u.p.current_unit->flags.convert & GFC_CONVERT_R16_IBM)
1187*b1e83836Smrg && kind == 17
1188*b1e83836Smrg && (type == BT_REAL || type == BT_COMPLEX))
1189*b1e83836Smrg {
1190*b1e83836Smrg if (type == BT_COMPLEX && size == 32)
1191*b1e83836Smrg {
1192*b1e83836Smrg nelems *= 2;
1193*b1e83836Smrg size /= 2;
1194*b1e83836Smrg }
1195*b1e83836Smrg
1196*b1e83836Smrg char *pd = dest;
1197*b1e83836Smrg for (size_t i = 0; i < nelems; i++)
1198*b1e83836Smrg {
1199*b1e83836Smrg GFC_REAL_16 r16;
1200*b1e83836Smrg GFC_REAL_17 r17;
1201*b1e83836Smrg memcpy (&r16, pd, 16);
1202*b1e83836Smrg r17 = r16;
1203*b1e83836Smrg memcpy (pd, &r17, 16);
1204*b1e83836Smrg pd += size;
1205*b1e83836Smrg }
1206*b1e83836Smrg }
1207*b1e83836Smrg #endif /* HAVE_GFC_REAL_17. */
1208181254a7Smrg }
1209181254a7Smrg }
1210181254a7Smrg
1211181254a7Smrg
1212181254a7Smrg /* Master function for unformatted writes. NOTE: For kind=10 the size is 16
1213181254a7Smrg bytes on 64 bit machines. The unused bytes are not initialized and never
1214181254a7Smrg used, which can show an error with memory checking analyzers like
1215181254a7Smrg valgrind. We us BT_CLASS to denote a User Defined I/O call. */
1216181254a7Smrg
1217181254a7Smrg static void
unformatted_write(st_parameter_dt * dtp,bt type,void * source,int kind,size_t size,size_t nelems)1218181254a7Smrg unformatted_write (st_parameter_dt *dtp, bt type,
1219181254a7Smrg void *source, int kind, size_t size, size_t nelems)
1220181254a7Smrg {
1221*b1e83836Smrg unit_convert convert;
1222*b1e83836Smrg
1223181254a7Smrg if (type == BT_CLASS)
1224181254a7Smrg {
1225181254a7Smrg int unit = dtp->u.p.current_unit->unit_number;
1226181254a7Smrg char tmp_iomsg[IOMSG_LEN] = "";
1227181254a7Smrg char *child_iomsg;
1228181254a7Smrg gfc_charlen_type child_iomsg_len;
1229181254a7Smrg int noiostat;
1230181254a7Smrg int *child_iostat = NULL;
1231181254a7Smrg
1232181254a7Smrg /* Set iostat, intent(out). */
1233181254a7Smrg noiostat = 0;
1234181254a7Smrg child_iostat = (dtp->common.flags & IOPARM_HAS_IOSTAT) ?
1235181254a7Smrg dtp->common.iostat : &noiostat;
1236181254a7Smrg
1237181254a7Smrg /* Set iomsg, intent(inout). */
1238181254a7Smrg if (dtp->common.flags & IOPARM_HAS_IOMSG)
1239181254a7Smrg {
1240181254a7Smrg child_iomsg = dtp->common.iomsg;
1241181254a7Smrg child_iomsg_len = dtp->common.iomsg_len;
1242181254a7Smrg }
1243181254a7Smrg else
1244181254a7Smrg {
1245181254a7Smrg child_iomsg = tmp_iomsg;
1246181254a7Smrg child_iomsg_len = IOMSG_LEN;
1247181254a7Smrg }
1248181254a7Smrg
1249181254a7Smrg /* Call the user defined unformatted WRITE procedure. */
1250181254a7Smrg dtp->u.p.current_unit->child_dtio++;
1251181254a7Smrg dtp->u.p.ufdtio_ptr (source, &unit, child_iostat, child_iomsg,
1252181254a7Smrg child_iomsg_len);
1253181254a7Smrg dtp->u.p.current_unit->child_dtio--;
1254181254a7Smrg return;
1255181254a7Smrg }
1256181254a7Smrg
1257*b1e83836Smrg convert = dtp->u.p.current_unit->flags.convert;
1258*b1e83836Smrg if (likely (convert == GFC_CONVERT_NATIVE) || kind == 1
1259*b1e83836Smrg #ifdef HAVE_GFC_REAL_17
1260*b1e83836Smrg || ((type == BT_REAL || type == BT_COMPLEX)
1261*b1e83836Smrg && ((kind == 16 && convert == GFC_CONVERT_R16_IBM)
1262*b1e83836Smrg || (kind == 17 && convert == GFC_CONVERT_R16_IEEE)))
1263*b1e83836Smrg #endif
1264*b1e83836Smrg )
1265181254a7Smrg {
1266181254a7Smrg size_t stride = type == BT_CHARACTER ?
1267181254a7Smrg size * GFC_SIZE_OF_CHAR_KIND(kind) : size;
1268181254a7Smrg
1269181254a7Smrg write_buf (dtp, source, stride * nelems);
1270181254a7Smrg }
1271181254a7Smrg else
1272181254a7Smrg {
1273181254a7Smrg #define BSWAP_BUFSZ 512
1274181254a7Smrg char buffer[BSWAP_BUFSZ];
1275181254a7Smrg char *p;
1276181254a7Smrg size_t nrem;
1277181254a7Smrg
1278181254a7Smrg p = source;
1279181254a7Smrg
1280181254a7Smrg /* Handle wide chracters. */
1281181254a7Smrg if (type == BT_CHARACTER && kind != 1)
1282181254a7Smrg {
1283181254a7Smrg nelems *= size;
1284181254a7Smrg size = kind;
1285181254a7Smrg }
1286181254a7Smrg
1287181254a7Smrg /* Break up complex into its constituent reals. */
1288181254a7Smrg if (type == BT_COMPLEX)
1289181254a7Smrg {
1290181254a7Smrg nelems *= 2;
1291181254a7Smrg size /= 2;
1292181254a7Smrg }
1293181254a7Smrg
1294*b1e83836Smrg #if !defined(HAVE_GFC_REAL_17) && defined(HAVE_GFC_REAL_16) \
1295*b1e83836Smrg && GFC_REAL_16_DIGITS == 106
1296*b1e83836Smrg /* IBM extended format is stored as a pair of IEEE754
1297*b1e83836Smrg double values, with the more significant value first
1298*b1e83836Smrg in both big and little endian. */
1299*b1e83836Smrg if (kind == 16 && (type == BT_REAL || type == BT_COMPLEX))
1300*b1e83836Smrg {
1301*b1e83836Smrg nelems *= 2;
1302*b1e83836Smrg size /= 2;
1303*b1e83836Smrg }
1304*b1e83836Smrg #endif
1305*b1e83836Smrg
1306181254a7Smrg /* By now, all complex variables have been split into their
1307181254a7Smrg constituent reals. */
1308181254a7Smrg
1309181254a7Smrg nrem = nelems;
1310181254a7Smrg do
1311181254a7Smrg {
1312181254a7Smrg size_t nc;
1313181254a7Smrg if (size * nrem > BSWAP_BUFSZ)
1314181254a7Smrg nc = BSWAP_BUFSZ / size;
1315181254a7Smrg else
1316181254a7Smrg nc = nrem;
1317181254a7Smrg
1318*b1e83836Smrg #ifdef HAVE_GFC_REAL_17
1319*b1e83836Smrg if ((dtp->u.p.current_unit->flags.convert & GFC_CONVERT_R16_IEEE)
1320*b1e83836Smrg && kind == 16
1321*b1e83836Smrg && (type == BT_REAL || type == BT_COMPLEX))
1322*b1e83836Smrg {
1323*b1e83836Smrg for (size_t i = 0; i < nc; i++)
1324*b1e83836Smrg {
1325*b1e83836Smrg GFC_REAL_16 r16;
1326*b1e83836Smrg GFC_REAL_17 r17;
1327*b1e83836Smrg memcpy (&r16, p, 16);
1328*b1e83836Smrg r17 = r16;
1329*b1e83836Smrg memcpy (&buffer[i * 16], &r17, 16);
1330*b1e83836Smrg p += 16;
1331*b1e83836Smrg }
1332*b1e83836Smrg if ((dtp->u.p.current_unit->flags.convert
1333*b1e83836Smrg & ~(GFC_CONVERT_R16_IEEE | GFC_CONVERT_R16_IBM))
1334*b1e83836Smrg == GFC_CONVERT_SWAP)
1335*b1e83836Smrg bswap_array (buffer, buffer, size, nc);
1336*b1e83836Smrg }
1337*b1e83836Smrg else if ((dtp->u.p.current_unit->flags.convert & GFC_CONVERT_R16_IBM)
1338*b1e83836Smrg && kind == 17
1339*b1e83836Smrg && (type == BT_REAL || type == BT_COMPLEX))
1340*b1e83836Smrg {
1341*b1e83836Smrg for (size_t i = 0; i < nc; i++)
1342*b1e83836Smrg {
1343*b1e83836Smrg GFC_REAL_16 r16;
1344*b1e83836Smrg GFC_REAL_17 r17;
1345*b1e83836Smrg memcpy (&r17, p, 16);
1346*b1e83836Smrg r16 = r17;
1347*b1e83836Smrg memcpy (&buffer[i * 16], &r16, 16);
1348*b1e83836Smrg p += 16;
1349*b1e83836Smrg }
1350*b1e83836Smrg if ((dtp->u.p.current_unit->flags.convert
1351*b1e83836Smrg & ~(GFC_CONVERT_R16_IEEE | GFC_CONVERT_R16_IBM))
1352*b1e83836Smrg == GFC_CONVERT_SWAP)
1353*b1e83836Smrg bswap_array (buffer, buffer, size / 2, nc * 2);
1354*b1e83836Smrg }
1355*b1e83836Smrg else if (kind == 16 && (type == BT_REAL || type == BT_COMPLEX))
1356*b1e83836Smrg {
1357*b1e83836Smrg bswap_array (buffer, p, size / 2, nc * 2);
1358181254a7Smrg p += size * nc;
1359*b1e83836Smrg }
1360*b1e83836Smrg else
1361*b1e83836Smrg #endif
1362*b1e83836Smrg {
1363*b1e83836Smrg bswap_array (buffer, p, size, nc);
1364*b1e83836Smrg p += size * nc;
1365*b1e83836Smrg }
1366*b1e83836Smrg write_buf (dtp, buffer, size * nc);
1367181254a7Smrg nrem -= nc;
1368181254a7Smrg }
1369181254a7Smrg while (nrem > 0);
1370181254a7Smrg }
1371181254a7Smrg }
1372181254a7Smrg
1373181254a7Smrg
1374181254a7Smrg /* Return a pointer to the name of a type. */
1375181254a7Smrg
1376181254a7Smrg const char *
type_name(bt type)1377181254a7Smrg type_name (bt type)
1378181254a7Smrg {
1379181254a7Smrg const char *p;
1380181254a7Smrg
1381181254a7Smrg switch (type)
1382181254a7Smrg {
1383181254a7Smrg case BT_INTEGER:
1384181254a7Smrg p = "INTEGER";
1385181254a7Smrg break;
1386181254a7Smrg case BT_LOGICAL:
1387181254a7Smrg p = "LOGICAL";
1388181254a7Smrg break;
1389181254a7Smrg case BT_CHARACTER:
1390181254a7Smrg p = "CHARACTER";
1391181254a7Smrg break;
1392181254a7Smrg case BT_REAL:
1393181254a7Smrg p = "REAL";
1394181254a7Smrg break;
1395181254a7Smrg case BT_COMPLEX:
1396181254a7Smrg p = "COMPLEX";
1397181254a7Smrg break;
1398181254a7Smrg case BT_CLASS:
1399181254a7Smrg p = "CLASS or DERIVED";
1400181254a7Smrg break;
1401181254a7Smrg default:
1402181254a7Smrg internal_error (NULL, "type_name(): Bad type");
1403181254a7Smrg }
1404181254a7Smrg
1405181254a7Smrg return p;
1406181254a7Smrg }
1407181254a7Smrg
1408181254a7Smrg
1409181254a7Smrg /* Write a constant string to the output.
1410181254a7Smrg This is complicated because the string can have doubled delimiters
1411181254a7Smrg in it. The length in the format node is the true length. */
1412181254a7Smrg
1413181254a7Smrg static void
write_constant_string(st_parameter_dt * dtp,const fnode * f)1414181254a7Smrg write_constant_string (st_parameter_dt *dtp, const fnode *f)
1415181254a7Smrg {
1416181254a7Smrg char c, delimiter, *p, *q;
1417181254a7Smrg int length;
1418181254a7Smrg
1419181254a7Smrg length = f->u.string.length;
1420181254a7Smrg if (length == 0)
1421181254a7Smrg return;
1422181254a7Smrg
1423181254a7Smrg p = write_block (dtp, length);
1424181254a7Smrg if (p == NULL)
1425181254a7Smrg return;
1426181254a7Smrg
1427181254a7Smrg q = f->u.string.p;
1428181254a7Smrg delimiter = q[-1];
1429181254a7Smrg
1430181254a7Smrg for (; length > 0; length--)
1431181254a7Smrg {
1432181254a7Smrg c = *p++ = *q++;
1433181254a7Smrg if (c == delimiter && c != 'H' && c != 'h')
1434181254a7Smrg q++; /* Skip the doubled delimiter. */
1435181254a7Smrg }
1436181254a7Smrg }
1437181254a7Smrg
1438181254a7Smrg
1439181254a7Smrg /* Given actual and expected types in a formatted data transfer, make
1440181254a7Smrg sure they agree. If not, an error message is generated. Returns
1441181254a7Smrg nonzero if something went wrong. */
1442181254a7Smrg
1443181254a7Smrg static int
require_type(st_parameter_dt * dtp,bt expected,bt actual,const fnode * f)1444181254a7Smrg require_type (st_parameter_dt *dtp, bt expected, bt actual, const fnode *f)
1445181254a7Smrg {
1446181254a7Smrg #define BUFLEN 100
1447181254a7Smrg char buffer[BUFLEN];
1448181254a7Smrg
1449181254a7Smrg if (actual == expected)
1450181254a7Smrg return 0;
1451181254a7Smrg
1452181254a7Smrg /* Adjust item_count before emitting error message. */
1453181254a7Smrg snprintf (buffer, BUFLEN,
1454181254a7Smrg "Expected %s for item %d in formatted transfer, got %s",
1455181254a7Smrg type_name (expected), dtp->u.p.item_count - 1, type_name (actual));
1456181254a7Smrg
1457181254a7Smrg format_error (dtp, f, buffer);
1458181254a7Smrg return 1;
1459181254a7Smrg }
1460181254a7Smrg
1461181254a7Smrg
1462181254a7Smrg /* Check that the dtio procedure required for formatted IO is present. */
1463181254a7Smrg
1464181254a7Smrg static int
check_dtio_proc(st_parameter_dt * dtp,const fnode * f)1465181254a7Smrg check_dtio_proc (st_parameter_dt *dtp, const fnode *f)
1466181254a7Smrg {
1467181254a7Smrg char buffer[BUFLEN];
1468181254a7Smrg
1469181254a7Smrg if (dtp->u.p.fdtio_ptr != NULL)
1470181254a7Smrg return 0;
1471181254a7Smrg
1472181254a7Smrg snprintf (buffer, BUFLEN,
1473181254a7Smrg "Missing DTIO procedure or intrinsic type passed for item %d "
1474181254a7Smrg "in formatted transfer",
1475181254a7Smrg dtp->u.p.item_count - 1);
1476181254a7Smrg
1477181254a7Smrg format_error (dtp, f, buffer);
1478181254a7Smrg return 1;
1479181254a7Smrg }
1480181254a7Smrg
1481181254a7Smrg
1482181254a7Smrg static int
require_numeric_type(st_parameter_dt * dtp,bt actual,const fnode * f)1483181254a7Smrg require_numeric_type (st_parameter_dt *dtp, bt actual, const fnode *f)
1484181254a7Smrg {
1485181254a7Smrg #define BUFLEN 100
1486181254a7Smrg char buffer[BUFLEN];
1487181254a7Smrg
1488181254a7Smrg if (actual == BT_INTEGER || actual == BT_REAL || actual == BT_COMPLEX)
1489181254a7Smrg return 0;
1490181254a7Smrg
1491181254a7Smrg /* Adjust item_count before emitting error message. */
1492181254a7Smrg snprintf (buffer, BUFLEN,
1493181254a7Smrg "Expected numeric type for item %d in formatted transfer, got %s",
1494181254a7Smrg dtp->u.p.item_count - 1, type_name (actual));
1495181254a7Smrg
1496181254a7Smrg format_error (dtp, f, buffer);
1497181254a7Smrg return 1;
1498181254a7Smrg }
1499181254a7Smrg
1500181254a7Smrg static char *
get_dt_format(char * p,gfc_charlen_type * length)1501181254a7Smrg get_dt_format (char *p, gfc_charlen_type *length)
1502181254a7Smrg {
1503181254a7Smrg char delim = p[-1]; /* The delimiter is always the first character back. */
1504181254a7Smrg char c, *q, *res;
1505181254a7Smrg gfc_charlen_type len = *length; /* This length already correct, less 'DT'. */
1506181254a7Smrg
1507181254a7Smrg res = q = xmalloc (len + 2);
1508181254a7Smrg
1509181254a7Smrg /* Set the beginning of the string to 'DT', length adjusted below. */
1510181254a7Smrg *q++ = 'D';
1511181254a7Smrg *q++ = 'T';
1512181254a7Smrg
1513181254a7Smrg /* The string may contain doubled quotes so scan and skip as needed. */
1514181254a7Smrg for (; len > 0; len--)
1515181254a7Smrg {
1516181254a7Smrg c = *q++ = *p++;
1517181254a7Smrg if (c == delim)
1518181254a7Smrg p++; /* Skip the doubled delimiter. */
1519181254a7Smrg }
1520181254a7Smrg
1521181254a7Smrg /* Adjust the string length by two now that we are done. */
1522181254a7Smrg *length += 2;
1523181254a7Smrg
1524181254a7Smrg return res;
1525181254a7Smrg }
1526181254a7Smrg
1527181254a7Smrg
1528181254a7Smrg /* This function is in the main loop for a formatted data transfer
1529181254a7Smrg statement. It would be natural to implement this as a coroutine
1530181254a7Smrg with the user program, but C makes that awkward. We loop,
1531181254a7Smrg processing format elements. When we actually have to transfer
1532181254a7Smrg data instead of just setting flags, we return control to the user
1533181254a7Smrg program which calls a function that supplies the address and type
1534181254a7Smrg of the next element, then comes back here to process it. */
1535181254a7Smrg
1536181254a7Smrg static void
formatted_transfer_scalar_read(st_parameter_dt * dtp,bt type,void * p,int kind,size_t size)1537181254a7Smrg formatted_transfer_scalar_read (st_parameter_dt *dtp, bt type, void *p, int kind,
1538181254a7Smrg size_t size)
1539181254a7Smrg {
1540181254a7Smrg int pos, bytes_used;
1541181254a7Smrg const fnode *f;
1542181254a7Smrg format_token t;
1543181254a7Smrg int n;
1544181254a7Smrg int consume_data_flag;
1545181254a7Smrg
1546181254a7Smrg /* Change a complex data item into a pair of reals. */
1547181254a7Smrg
1548181254a7Smrg n = (p == NULL) ? 0 : ((type != BT_COMPLEX) ? 1 : 2);
1549181254a7Smrg if (type == BT_COMPLEX)
1550181254a7Smrg {
1551181254a7Smrg type = BT_REAL;
1552181254a7Smrg size /= 2;
1553181254a7Smrg }
1554181254a7Smrg
1555181254a7Smrg /* If there's an EOR condition, we simulate finalizing the transfer
1556181254a7Smrg by doing nothing. */
1557181254a7Smrg if (dtp->u.p.eor_condition)
1558181254a7Smrg return;
1559181254a7Smrg
1560181254a7Smrg /* Set this flag so that commas in reads cause the read to complete before
1561181254a7Smrg the entire field has been read. The next read field will start right after
1562181254a7Smrg the comma in the stream. (Set to 0 for character reads). */
1563181254a7Smrg dtp->u.p.sf_read_comma =
1564181254a7Smrg dtp->u.p.current_unit->decimal_status == DECIMAL_COMMA ? 0 : 1;
1565181254a7Smrg
1566181254a7Smrg for (;;)
1567181254a7Smrg {
1568181254a7Smrg /* If reversion has occurred and there is another real data item,
1569181254a7Smrg then we have to move to the next record. */
1570181254a7Smrg if (dtp->u.p.reversion_flag && n > 0)
1571181254a7Smrg {
1572181254a7Smrg dtp->u.p.reversion_flag = 0;
1573181254a7Smrg next_record (dtp, 0);
1574181254a7Smrg }
1575181254a7Smrg
1576181254a7Smrg consume_data_flag = 1;
1577181254a7Smrg if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
1578181254a7Smrg break;
1579181254a7Smrg
1580181254a7Smrg f = next_format (dtp);
1581181254a7Smrg if (f == NULL)
1582181254a7Smrg {
1583181254a7Smrg /* No data descriptors left. */
1584181254a7Smrg if (unlikely (n > 0))
1585181254a7Smrg generate_error (&dtp->common, LIBERROR_FORMAT,
1586181254a7Smrg "Insufficient data descriptors in format after reversion");
1587181254a7Smrg return;
1588181254a7Smrg }
1589181254a7Smrg
1590181254a7Smrg t = f->format;
1591181254a7Smrg
1592181254a7Smrg bytes_used = (int)(dtp->u.p.current_unit->recl
1593181254a7Smrg - dtp->u.p.current_unit->bytes_left);
1594181254a7Smrg
1595181254a7Smrg if (is_stream_io(dtp))
1596181254a7Smrg bytes_used = 0;
1597181254a7Smrg
1598181254a7Smrg switch (t)
1599181254a7Smrg {
1600181254a7Smrg case FMT_I:
1601181254a7Smrg if (n == 0)
1602181254a7Smrg goto need_read_data;
1603181254a7Smrg if (require_type (dtp, BT_INTEGER, type, f))
1604181254a7Smrg return;
1605181254a7Smrg read_decimal (dtp, f, p, kind);
1606181254a7Smrg break;
1607181254a7Smrg
1608181254a7Smrg case FMT_B:
1609181254a7Smrg if (n == 0)
1610181254a7Smrg goto need_read_data;
1611181254a7Smrg if (!(compile_options.allow_std & GFC_STD_GNU)
1612181254a7Smrg && require_numeric_type (dtp, type, f))
1613181254a7Smrg return;
1614181254a7Smrg if (!(compile_options.allow_std & GFC_STD_F2008)
1615181254a7Smrg && require_type (dtp, BT_INTEGER, type, f))
1616181254a7Smrg return;
1617*b1e83836Smrg #ifdef HAVE_GFC_REAL_17
1618*b1e83836Smrg if (type == BT_REAL && kind == 17)
1619*b1e83836Smrg kind = 16;
1620*b1e83836Smrg #endif
1621181254a7Smrg read_radix (dtp, f, p, kind, 2);
1622181254a7Smrg break;
1623181254a7Smrg
1624181254a7Smrg case FMT_O:
1625181254a7Smrg if (n == 0)
1626181254a7Smrg goto need_read_data;
1627181254a7Smrg if (!(compile_options.allow_std & GFC_STD_GNU)
1628181254a7Smrg && require_numeric_type (dtp, type, f))
1629181254a7Smrg return;
1630181254a7Smrg if (!(compile_options.allow_std & GFC_STD_F2008)
1631181254a7Smrg && require_type (dtp, BT_INTEGER, type, f))
1632181254a7Smrg return;
1633*b1e83836Smrg #ifdef HAVE_GFC_REAL_17
1634*b1e83836Smrg if (type == BT_REAL && kind == 17)
1635*b1e83836Smrg kind = 16;
1636*b1e83836Smrg #endif
1637181254a7Smrg read_radix (dtp, f, p, kind, 8);
1638181254a7Smrg break;
1639181254a7Smrg
1640181254a7Smrg case FMT_Z:
1641181254a7Smrg if (n == 0)
1642181254a7Smrg goto need_read_data;
1643181254a7Smrg if (!(compile_options.allow_std & GFC_STD_GNU)
1644181254a7Smrg && require_numeric_type (dtp, type, f))
1645181254a7Smrg return;
1646181254a7Smrg if (!(compile_options.allow_std & GFC_STD_F2008)
1647181254a7Smrg && require_type (dtp, BT_INTEGER, type, f))
1648181254a7Smrg return;
1649*b1e83836Smrg #ifdef HAVE_GFC_REAL_17
1650*b1e83836Smrg if (type == BT_REAL && kind == 17)
1651*b1e83836Smrg kind = 16;
1652*b1e83836Smrg #endif
1653181254a7Smrg read_radix (dtp, f, p, kind, 16);
1654181254a7Smrg break;
1655181254a7Smrg
1656181254a7Smrg case FMT_A:
1657181254a7Smrg if (n == 0)
1658181254a7Smrg goto need_read_data;
1659181254a7Smrg
1660181254a7Smrg /* It is possible to have FMT_A with something not BT_CHARACTER such
1661181254a7Smrg as when writing out hollerith strings, so check both type
1662181254a7Smrg and kind before calling wide character routines. */
1663181254a7Smrg if (type == BT_CHARACTER && kind == 4)
1664181254a7Smrg read_a_char4 (dtp, f, p, size);
1665181254a7Smrg else
1666181254a7Smrg read_a (dtp, f, p, size);
1667181254a7Smrg break;
1668181254a7Smrg
1669181254a7Smrg case FMT_L:
1670181254a7Smrg if (n == 0)
1671181254a7Smrg goto need_read_data;
1672181254a7Smrg read_l (dtp, f, p, kind);
1673181254a7Smrg break;
1674181254a7Smrg
1675181254a7Smrg case FMT_D:
1676181254a7Smrg if (n == 0)
1677181254a7Smrg goto need_read_data;
1678181254a7Smrg if (require_type (dtp, BT_REAL, type, f))
1679181254a7Smrg return;
1680181254a7Smrg read_f (dtp, f, p, kind);
1681181254a7Smrg break;
1682181254a7Smrg
1683181254a7Smrg case FMT_DT:
1684181254a7Smrg if (n == 0)
1685181254a7Smrg goto need_read_data;
1686181254a7Smrg
1687181254a7Smrg if (check_dtio_proc (dtp, f))
1688181254a7Smrg return;
1689181254a7Smrg if (require_type (dtp, BT_CLASS, type, f))
1690181254a7Smrg return;
1691181254a7Smrg int unit = dtp->u.p.current_unit->unit_number;
1692181254a7Smrg char dt[] = "DT";
1693181254a7Smrg char tmp_iomsg[IOMSG_LEN] = "";
1694181254a7Smrg char *child_iomsg;
1695181254a7Smrg gfc_charlen_type child_iomsg_len;
1696181254a7Smrg int noiostat;
1697181254a7Smrg int *child_iostat = NULL;
1698181254a7Smrg char *iotype;
1699181254a7Smrg gfc_charlen_type iotype_len = f->u.udf.string_len;
1700181254a7Smrg
1701181254a7Smrg /* Build the iotype string. */
1702181254a7Smrg if (iotype_len == 0)
1703181254a7Smrg {
1704181254a7Smrg iotype_len = 2;
1705181254a7Smrg iotype = dt;
1706181254a7Smrg }
1707181254a7Smrg else
1708181254a7Smrg iotype = get_dt_format (f->u.udf.string, &iotype_len);
1709181254a7Smrg
1710181254a7Smrg /* Set iostat, intent(out). */
1711181254a7Smrg noiostat = 0;
1712181254a7Smrg child_iostat = (dtp->common.flags & IOPARM_HAS_IOSTAT) ?
1713181254a7Smrg dtp->common.iostat : &noiostat;
1714181254a7Smrg
1715181254a7Smrg /* Set iomsg, intent(inout). */
1716181254a7Smrg if (dtp->common.flags & IOPARM_HAS_IOMSG)
1717181254a7Smrg {
1718181254a7Smrg child_iomsg = dtp->common.iomsg;
1719181254a7Smrg child_iomsg_len = dtp->common.iomsg_len;
1720181254a7Smrg }
1721181254a7Smrg else
1722181254a7Smrg {
1723181254a7Smrg child_iomsg = tmp_iomsg;
1724181254a7Smrg child_iomsg_len = IOMSG_LEN;
1725181254a7Smrg }
1726181254a7Smrg
1727181254a7Smrg /* Call the user defined formatted READ procedure. */
1728181254a7Smrg dtp->u.p.current_unit->child_dtio++;
1729181254a7Smrg dtp->u.p.current_unit->last_char = EOF - 1;
1730181254a7Smrg dtp->u.p.fdtio_ptr (p, &unit, iotype, f->u.udf.vlist,
1731181254a7Smrg child_iostat, child_iomsg,
1732181254a7Smrg iotype_len, child_iomsg_len);
1733181254a7Smrg dtp->u.p.current_unit->child_dtio--;
1734181254a7Smrg
1735181254a7Smrg if (f->u.udf.string_len != 0)
1736181254a7Smrg free (iotype);
1737181254a7Smrg /* Note: vlist is freed in free_format_data. */
1738181254a7Smrg break;
1739181254a7Smrg
1740181254a7Smrg case FMT_E:
1741181254a7Smrg if (n == 0)
1742181254a7Smrg goto need_read_data;
1743181254a7Smrg if (require_type (dtp, BT_REAL, type, f))
1744181254a7Smrg return;
1745181254a7Smrg read_f (dtp, f, p, kind);
1746181254a7Smrg break;
1747181254a7Smrg
1748181254a7Smrg case FMT_EN:
1749181254a7Smrg if (n == 0)
1750181254a7Smrg goto need_read_data;
1751181254a7Smrg if (require_type (dtp, BT_REAL, type, f))
1752181254a7Smrg return;
1753181254a7Smrg read_f (dtp, f, p, kind);
1754181254a7Smrg break;
1755181254a7Smrg
1756181254a7Smrg case FMT_ES:
1757181254a7Smrg if (n == 0)
1758181254a7Smrg goto need_read_data;
1759181254a7Smrg if (require_type (dtp, BT_REAL, type, f))
1760181254a7Smrg return;
1761181254a7Smrg read_f (dtp, f, p, kind);
1762181254a7Smrg break;
1763181254a7Smrg
1764181254a7Smrg case FMT_F:
1765181254a7Smrg if (n == 0)
1766181254a7Smrg goto need_read_data;
1767181254a7Smrg if (require_type (dtp, BT_REAL, type, f))
1768181254a7Smrg return;
1769181254a7Smrg read_f (dtp, f, p, kind);
1770181254a7Smrg break;
1771181254a7Smrg
1772181254a7Smrg case FMT_G:
1773181254a7Smrg if (n == 0)
1774181254a7Smrg goto need_read_data;
1775181254a7Smrg switch (type)
1776181254a7Smrg {
1777181254a7Smrg case BT_INTEGER:
1778181254a7Smrg read_decimal (dtp, f, p, kind);
1779181254a7Smrg break;
1780181254a7Smrg case BT_LOGICAL:
1781181254a7Smrg read_l (dtp, f, p, kind);
1782181254a7Smrg break;
1783181254a7Smrg case BT_CHARACTER:
1784181254a7Smrg if (kind == 4)
1785181254a7Smrg read_a_char4 (dtp, f, p, size);
1786181254a7Smrg else
1787181254a7Smrg read_a (dtp, f, p, size);
1788181254a7Smrg break;
1789181254a7Smrg case BT_REAL:
1790181254a7Smrg read_f (dtp, f, p, kind);
1791181254a7Smrg break;
1792181254a7Smrg default:
1793181254a7Smrg internal_error (&dtp->common,
1794181254a7Smrg "formatted_transfer (): Bad type");
1795181254a7Smrg }
1796181254a7Smrg break;
1797181254a7Smrg
1798181254a7Smrg case FMT_STRING:
1799181254a7Smrg consume_data_flag = 0;
1800181254a7Smrg format_error (dtp, f, "Constant string in input format");
1801181254a7Smrg return;
1802181254a7Smrg
1803181254a7Smrg /* Format codes that don't transfer data. */
1804181254a7Smrg case FMT_X:
1805181254a7Smrg case FMT_TR:
1806181254a7Smrg consume_data_flag = 0;
1807181254a7Smrg dtp->u.p.skips += f->u.n;
1808181254a7Smrg pos = bytes_used + dtp->u.p.skips - 1;
1809181254a7Smrg dtp->u.p.pending_spaces = pos - dtp->u.p.max_pos + 1;
1810181254a7Smrg read_x (dtp, f->u.n);
1811181254a7Smrg break;
1812181254a7Smrg
1813181254a7Smrg case FMT_TL:
1814181254a7Smrg case FMT_T:
1815181254a7Smrg consume_data_flag = 0;
1816181254a7Smrg
1817181254a7Smrg if (f->format == FMT_TL)
1818181254a7Smrg {
1819181254a7Smrg /* Handle the special case when no bytes have been used yet.
1820181254a7Smrg Cannot go below zero. */
1821181254a7Smrg if (bytes_used == 0)
1822181254a7Smrg {
1823181254a7Smrg dtp->u.p.pending_spaces -= f->u.n;
1824181254a7Smrg dtp->u.p.skips -= f->u.n;
1825181254a7Smrg dtp->u.p.skips = dtp->u.p.skips < 0 ? 0 : dtp->u.p.skips;
1826181254a7Smrg }
1827181254a7Smrg
1828181254a7Smrg pos = bytes_used - f->u.n;
1829181254a7Smrg }
1830181254a7Smrg else /* FMT_T */
1831181254a7Smrg pos = f->u.n - 1;
1832181254a7Smrg
1833181254a7Smrg /* Standard 10.6.1.1: excessive left tabbing is reset to the
1834181254a7Smrg left tab limit. We do not check if the position has gone
1835181254a7Smrg beyond the end of record because a subsequent tab could
1836181254a7Smrg bring us back again. */
1837181254a7Smrg pos = pos < 0 ? 0 : pos;
1838181254a7Smrg
1839181254a7Smrg dtp->u.p.skips = dtp->u.p.skips + pos - bytes_used;
1840181254a7Smrg dtp->u.p.pending_spaces = dtp->u.p.pending_spaces
1841181254a7Smrg + pos - dtp->u.p.max_pos;
1842181254a7Smrg dtp->u.p.pending_spaces = dtp->u.p.pending_spaces < 0
1843181254a7Smrg ? 0 : dtp->u.p.pending_spaces;
1844181254a7Smrg if (dtp->u.p.skips == 0)
1845181254a7Smrg break;
1846181254a7Smrg
1847181254a7Smrg /* Adjust everything for end-of-record condition */
1848181254a7Smrg if (dtp->u.p.sf_seen_eor && !is_internal_unit (dtp))
1849181254a7Smrg {
1850181254a7Smrg dtp->u.p.current_unit->bytes_left -= dtp->u.p.sf_seen_eor;
1851181254a7Smrg dtp->u.p.skips -= dtp->u.p.sf_seen_eor;
1852181254a7Smrg bytes_used = pos;
1853181254a7Smrg if (dtp->u.p.pending_spaces == 0)
1854181254a7Smrg dtp->u.p.sf_seen_eor = 0;
1855181254a7Smrg }
1856181254a7Smrg if (dtp->u.p.skips < 0)
1857181254a7Smrg {
1858181254a7Smrg if (is_internal_unit (dtp))
1859181254a7Smrg sseek (dtp->u.p.current_unit->s, dtp->u.p.skips, SEEK_CUR);
1860181254a7Smrg else
1861181254a7Smrg fbuf_seek (dtp->u.p.current_unit, dtp->u.p.skips, SEEK_CUR);
1862181254a7Smrg dtp->u.p.current_unit->bytes_left -= (gfc_offset) dtp->u.p.skips;
1863181254a7Smrg dtp->u.p.skips = dtp->u.p.pending_spaces = 0;
1864181254a7Smrg }
1865181254a7Smrg else
1866181254a7Smrg read_x (dtp, dtp->u.p.skips);
1867181254a7Smrg break;
1868181254a7Smrg
1869181254a7Smrg case FMT_S:
1870181254a7Smrg consume_data_flag = 0;
1871fb8a8121Smrg dtp->u.p.sign_status = SIGN_PROCDEFINED;
1872181254a7Smrg break;
1873181254a7Smrg
1874181254a7Smrg case FMT_SS:
1875181254a7Smrg consume_data_flag = 0;
1876fb8a8121Smrg dtp->u.p.sign_status = SIGN_SUPPRESS;
1877181254a7Smrg break;
1878181254a7Smrg
1879181254a7Smrg case FMT_SP:
1880181254a7Smrg consume_data_flag = 0;
1881fb8a8121Smrg dtp->u.p.sign_status = SIGN_PLUS;
1882181254a7Smrg break;
1883181254a7Smrg
1884181254a7Smrg case FMT_BN:
1885181254a7Smrg consume_data_flag = 0 ;
1886181254a7Smrg dtp->u.p.blank_status = BLANK_NULL;
1887181254a7Smrg break;
1888181254a7Smrg
1889181254a7Smrg case FMT_BZ:
1890181254a7Smrg consume_data_flag = 0;
1891181254a7Smrg dtp->u.p.blank_status = BLANK_ZERO;
1892181254a7Smrg break;
1893181254a7Smrg
1894181254a7Smrg case FMT_DC:
1895181254a7Smrg consume_data_flag = 0;
1896181254a7Smrg dtp->u.p.current_unit->decimal_status = DECIMAL_COMMA;
1897181254a7Smrg break;
1898181254a7Smrg
1899181254a7Smrg case FMT_DP:
1900181254a7Smrg consume_data_flag = 0;
1901181254a7Smrg dtp->u.p.current_unit->decimal_status = DECIMAL_POINT;
1902181254a7Smrg break;
1903181254a7Smrg
1904181254a7Smrg case FMT_RC:
1905181254a7Smrg consume_data_flag = 0;
1906181254a7Smrg dtp->u.p.current_unit->round_status = ROUND_COMPATIBLE;
1907181254a7Smrg break;
1908181254a7Smrg
1909181254a7Smrg case FMT_RD:
1910181254a7Smrg consume_data_flag = 0;
1911181254a7Smrg dtp->u.p.current_unit->round_status = ROUND_DOWN;
1912181254a7Smrg break;
1913181254a7Smrg
1914181254a7Smrg case FMT_RN:
1915181254a7Smrg consume_data_flag = 0;
1916181254a7Smrg dtp->u.p.current_unit->round_status = ROUND_NEAREST;
1917181254a7Smrg break;
1918181254a7Smrg
1919181254a7Smrg case FMT_RP:
1920181254a7Smrg consume_data_flag = 0;
1921181254a7Smrg dtp->u.p.current_unit->round_status = ROUND_PROCDEFINED;
1922181254a7Smrg break;
1923181254a7Smrg
1924181254a7Smrg case FMT_RU:
1925181254a7Smrg consume_data_flag = 0;
1926181254a7Smrg dtp->u.p.current_unit->round_status = ROUND_UP;
1927181254a7Smrg break;
1928181254a7Smrg
1929181254a7Smrg case FMT_RZ:
1930181254a7Smrg consume_data_flag = 0;
1931181254a7Smrg dtp->u.p.current_unit->round_status = ROUND_ZERO;
1932181254a7Smrg break;
1933181254a7Smrg
1934181254a7Smrg case FMT_P:
1935181254a7Smrg consume_data_flag = 0;
1936181254a7Smrg dtp->u.p.scale_factor = f->u.k;
1937181254a7Smrg break;
1938181254a7Smrg
1939181254a7Smrg case FMT_DOLLAR:
1940181254a7Smrg consume_data_flag = 0;
1941181254a7Smrg dtp->u.p.seen_dollar = 1;
1942181254a7Smrg break;
1943181254a7Smrg
1944181254a7Smrg case FMT_SLASH:
1945181254a7Smrg consume_data_flag = 0;
1946181254a7Smrg dtp->u.p.skips = dtp->u.p.pending_spaces = 0;
1947181254a7Smrg next_record (dtp, 0);
1948181254a7Smrg break;
1949181254a7Smrg
1950181254a7Smrg case FMT_COLON:
1951181254a7Smrg /* A colon descriptor causes us to exit this loop (in
1952181254a7Smrg particular preventing another / descriptor from being
1953181254a7Smrg processed) unless there is another data item to be
1954181254a7Smrg transferred. */
1955181254a7Smrg consume_data_flag = 0;
1956181254a7Smrg if (n == 0)
1957181254a7Smrg return;
1958181254a7Smrg break;
1959181254a7Smrg
1960181254a7Smrg default:
1961181254a7Smrg internal_error (&dtp->common, "Bad format node");
1962181254a7Smrg }
1963181254a7Smrg
1964181254a7Smrg /* Adjust the item count and data pointer. */
1965181254a7Smrg
1966181254a7Smrg if ((consume_data_flag > 0) && (n > 0))
1967181254a7Smrg {
1968181254a7Smrg n--;
1969181254a7Smrg p = ((char *) p) + size;
1970181254a7Smrg }
1971181254a7Smrg
1972181254a7Smrg dtp->u.p.skips = 0;
1973181254a7Smrg
1974181254a7Smrg pos = (int)(dtp->u.p.current_unit->recl - dtp->u.p.current_unit->bytes_left);
1975181254a7Smrg dtp->u.p.max_pos = (dtp->u.p.max_pos > pos) ? dtp->u.p.max_pos : pos;
1976181254a7Smrg }
1977181254a7Smrg
1978181254a7Smrg return;
1979181254a7Smrg
1980181254a7Smrg /* Come here when we need a data descriptor but don't have one. We
1981181254a7Smrg push the current format node back onto the input, then return and
1982181254a7Smrg let the user program call us back with the data. */
1983181254a7Smrg need_read_data:
1984181254a7Smrg unget_format (dtp, f);
1985181254a7Smrg }
1986181254a7Smrg
1987181254a7Smrg
1988181254a7Smrg static void
formatted_transfer_scalar_write(st_parameter_dt * dtp,bt type,void * p,int kind,size_t size)1989181254a7Smrg formatted_transfer_scalar_write (st_parameter_dt *dtp, bt type, void *p, int kind,
1990181254a7Smrg size_t size)
1991181254a7Smrg {
1992181254a7Smrg gfc_offset pos, bytes_used;
1993181254a7Smrg const fnode *f;
1994181254a7Smrg format_token t;
1995181254a7Smrg int n;
1996181254a7Smrg int consume_data_flag;
1997181254a7Smrg
1998181254a7Smrg /* Change a complex data item into a pair of reals. */
1999181254a7Smrg
2000181254a7Smrg n = (p == NULL) ? 0 : ((type != BT_COMPLEX) ? 1 : 2);
2001181254a7Smrg if (type == BT_COMPLEX)
2002181254a7Smrg {
2003181254a7Smrg type = BT_REAL;
2004181254a7Smrg size /= 2;
2005181254a7Smrg }
2006181254a7Smrg
2007181254a7Smrg /* If there's an EOR condition, we simulate finalizing the transfer
2008181254a7Smrg by doing nothing. */
2009181254a7Smrg if (dtp->u.p.eor_condition)
2010181254a7Smrg return;
2011181254a7Smrg
2012181254a7Smrg /* Set this flag so that commas in reads cause the read to complete before
2013181254a7Smrg the entire field has been read. The next read field will start right after
2014181254a7Smrg the comma in the stream. (Set to 0 for character reads). */
2015181254a7Smrg dtp->u.p.sf_read_comma =
2016181254a7Smrg dtp->u.p.current_unit->decimal_status == DECIMAL_COMMA ? 0 : 1;
2017181254a7Smrg
2018181254a7Smrg for (;;)
2019181254a7Smrg {
2020181254a7Smrg /* If reversion has occurred and there is another real data item,
2021181254a7Smrg then we have to move to the next record. */
2022181254a7Smrg if (dtp->u.p.reversion_flag && n > 0)
2023181254a7Smrg {
2024181254a7Smrg dtp->u.p.reversion_flag = 0;
2025181254a7Smrg next_record (dtp, 0);
2026181254a7Smrg }
2027181254a7Smrg
2028181254a7Smrg consume_data_flag = 1;
2029181254a7Smrg if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
2030181254a7Smrg break;
2031181254a7Smrg
2032181254a7Smrg f = next_format (dtp);
2033181254a7Smrg if (f == NULL)
2034181254a7Smrg {
2035181254a7Smrg /* No data descriptors left. */
2036181254a7Smrg if (unlikely (n > 0))
2037181254a7Smrg generate_error (&dtp->common, LIBERROR_FORMAT,
2038181254a7Smrg "Insufficient data descriptors in format after reversion");
2039181254a7Smrg return;
2040181254a7Smrg }
2041181254a7Smrg
2042181254a7Smrg /* Now discharge T, TR and X movements to the right. This is delayed
2043181254a7Smrg until a data producing format to suppress trailing spaces. */
2044181254a7Smrg
2045181254a7Smrg t = f->format;
2046181254a7Smrg if (dtp->u.p.mode == WRITING && dtp->u.p.skips != 0
2047181254a7Smrg && ((n>0 && ( t == FMT_I || t == FMT_B || t == FMT_O
2048181254a7Smrg || t == FMT_Z || t == FMT_F || t == FMT_E
2049181254a7Smrg || t == FMT_EN || t == FMT_ES || t == FMT_G
2050181254a7Smrg || t == FMT_L || t == FMT_A || t == FMT_D
2051181254a7Smrg || t == FMT_DT))
2052181254a7Smrg || t == FMT_STRING))
2053181254a7Smrg {
2054181254a7Smrg if (dtp->u.p.skips > 0)
2055181254a7Smrg {
2056181254a7Smrg gfc_offset tmp;
2057181254a7Smrg write_x (dtp, dtp->u.p.skips, dtp->u.p.pending_spaces);
2058181254a7Smrg tmp = dtp->u.p.current_unit->recl
2059181254a7Smrg - dtp->u.p.current_unit->bytes_left;
2060181254a7Smrg dtp->u.p.max_pos =
2061181254a7Smrg dtp->u.p.max_pos > tmp ? dtp->u.p.max_pos : tmp;
2062181254a7Smrg dtp->u.p.skips = 0;
2063181254a7Smrg }
2064181254a7Smrg if (dtp->u.p.skips < 0)
2065181254a7Smrg {
2066181254a7Smrg if (is_internal_unit (dtp))
2067181254a7Smrg sseek (dtp->u.p.current_unit->s, dtp->u.p.skips, SEEK_CUR);
2068181254a7Smrg else
2069181254a7Smrg fbuf_seek (dtp->u.p.current_unit, dtp->u.p.skips, SEEK_CUR);
2070181254a7Smrg dtp->u.p.current_unit->bytes_left -= (gfc_offset) dtp->u.p.skips;
2071181254a7Smrg }
2072181254a7Smrg dtp->u.p.skips = dtp->u.p.pending_spaces = 0;
2073181254a7Smrg }
2074181254a7Smrg
2075181254a7Smrg bytes_used = dtp->u.p.current_unit->recl
2076181254a7Smrg - dtp->u.p.current_unit->bytes_left;
2077181254a7Smrg
2078181254a7Smrg if (is_stream_io(dtp))
2079181254a7Smrg bytes_used = 0;
2080181254a7Smrg
2081181254a7Smrg switch (t)
2082181254a7Smrg {
2083181254a7Smrg case FMT_I:
2084181254a7Smrg if (n == 0)
2085181254a7Smrg goto need_data;
2086181254a7Smrg if (require_type (dtp, BT_INTEGER, type, f))
2087181254a7Smrg return;
2088181254a7Smrg write_i (dtp, f, p, kind);
2089181254a7Smrg break;
2090181254a7Smrg
2091181254a7Smrg case FMT_B:
2092181254a7Smrg if (n == 0)
2093181254a7Smrg goto need_data;
2094181254a7Smrg if (!(compile_options.allow_std & GFC_STD_GNU)
2095181254a7Smrg && require_numeric_type (dtp, type, f))
2096181254a7Smrg return;
2097181254a7Smrg if (!(compile_options.allow_std & GFC_STD_F2008)
2098181254a7Smrg && require_type (dtp, BT_INTEGER, type, f))
2099181254a7Smrg return;
2100*b1e83836Smrg #ifdef HAVE_GFC_REAL_17
2101*b1e83836Smrg if (type == BT_REAL && kind == 17)
2102*b1e83836Smrg kind = 16;
2103*b1e83836Smrg #endif
2104181254a7Smrg write_b (dtp, f, p, kind);
2105181254a7Smrg break;
2106181254a7Smrg
2107181254a7Smrg case FMT_O:
2108181254a7Smrg if (n == 0)
2109181254a7Smrg goto need_data;
2110181254a7Smrg if (!(compile_options.allow_std & GFC_STD_GNU)
2111181254a7Smrg && require_numeric_type (dtp, type, f))
2112181254a7Smrg return;
2113181254a7Smrg if (!(compile_options.allow_std & GFC_STD_F2008)
2114181254a7Smrg && require_type (dtp, BT_INTEGER, type, f))
2115181254a7Smrg return;
2116*b1e83836Smrg #ifdef HAVE_GFC_REAL_17
2117*b1e83836Smrg if (type == BT_REAL && kind == 17)
2118*b1e83836Smrg kind = 16;
2119*b1e83836Smrg #endif
2120181254a7Smrg write_o (dtp, f, p, kind);
2121181254a7Smrg break;
2122181254a7Smrg
2123181254a7Smrg case FMT_Z:
2124181254a7Smrg if (n == 0)
2125181254a7Smrg goto need_data;
2126181254a7Smrg if (!(compile_options.allow_std & GFC_STD_GNU)
2127181254a7Smrg && require_numeric_type (dtp, type, f))
2128181254a7Smrg return;
2129181254a7Smrg if (!(compile_options.allow_std & GFC_STD_F2008)
2130181254a7Smrg && require_type (dtp, BT_INTEGER, type, f))
2131181254a7Smrg return;
2132*b1e83836Smrg #ifdef HAVE_GFC_REAL_17
2133*b1e83836Smrg if (type == BT_REAL && kind == 17)
2134*b1e83836Smrg kind = 16;
2135*b1e83836Smrg #endif
2136181254a7Smrg write_z (dtp, f, p, kind);
2137181254a7Smrg break;
2138181254a7Smrg
2139181254a7Smrg case FMT_A:
2140181254a7Smrg if (n == 0)
2141181254a7Smrg goto need_data;
2142181254a7Smrg
2143181254a7Smrg /* It is possible to have FMT_A with something not BT_CHARACTER such
2144181254a7Smrg as when writing out hollerith strings, so check both type
2145181254a7Smrg and kind before calling wide character routines. */
2146181254a7Smrg if (type == BT_CHARACTER && kind == 4)
2147181254a7Smrg write_a_char4 (dtp, f, p, size);
2148181254a7Smrg else
2149181254a7Smrg write_a (dtp, f, p, size);
2150181254a7Smrg break;
2151181254a7Smrg
2152181254a7Smrg case FMT_L:
2153181254a7Smrg if (n == 0)
2154181254a7Smrg goto need_data;
2155181254a7Smrg write_l (dtp, f, p, kind);
2156181254a7Smrg break;
2157181254a7Smrg
2158181254a7Smrg case FMT_D:
2159181254a7Smrg if (n == 0)
2160181254a7Smrg goto need_data;
2161181254a7Smrg if (require_type (dtp, BT_REAL, type, f))
2162181254a7Smrg return;
2163fb8a8121Smrg if (f->u.real.w == 0)
2164fb8a8121Smrg write_real_w0 (dtp, p, kind, f);
2165fb8a8121Smrg else
2166181254a7Smrg write_d (dtp, f, p, kind);
2167181254a7Smrg break;
2168181254a7Smrg
2169181254a7Smrg case FMT_DT:
2170181254a7Smrg if (n == 0)
2171181254a7Smrg goto need_data;
2172181254a7Smrg int unit = dtp->u.p.current_unit->unit_number;
2173181254a7Smrg char dt[] = "DT";
2174181254a7Smrg char tmp_iomsg[IOMSG_LEN] = "";
2175181254a7Smrg char *child_iomsg;
2176181254a7Smrg gfc_charlen_type child_iomsg_len;
2177181254a7Smrg int noiostat;
2178181254a7Smrg int *child_iostat = NULL;
2179181254a7Smrg char *iotype;
2180181254a7Smrg gfc_charlen_type iotype_len = f->u.udf.string_len;
2181181254a7Smrg
2182181254a7Smrg /* Build the iotype string. */
2183181254a7Smrg if (iotype_len == 0)
2184181254a7Smrg {
2185181254a7Smrg iotype_len = 2;
2186181254a7Smrg iotype = dt;
2187181254a7Smrg }
2188181254a7Smrg else
2189181254a7Smrg iotype = get_dt_format (f->u.udf.string, &iotype_len);
2190181254a7Smrg
2191181254a7Smrg /* Set iostat, intent(out). */
2192181254a7Smrg noiostat = 0;
2193181254a7Smrg child_iostat = (dtp->common.flags & IOPARM_HAS_IOSTAT) ?
2194181254a7Smrg dtp->common.iostat : &noiostat;
2195181254a7Smrg
2196181254a7Smrg /* Set iomsg, intent(inout). */
2197181254a7Smrg if (dtp->common.flags & IOPARM_HAS_IOMSG)
2198181254a7Smrg {
2199181254a7Smrg child_iomsg = dtp->common.iomsg;
2200181254a7Smrg child_iomsg_len = dtp->common.iomsg_len;
2201181254a7Smrg }
2202181254a7Smrg else
2203181254a7Smrg {
2204181254a7Smrg child_iomsg = tmp_iomsg;
2205181254a7Smrg child_iomsg_len = IOMSG_LEN;
2206181254a7Smrg }
2207181254a7Smrg
2208181254a7Smrg if (check_dtio_proc (dtp, f))
2209181254a7Smrg return;
2210181254a7Smrg
2211181254a7Smrg /* Call the user defined formatted WRITE procedure. */
2212181254a7Smrg dtp->u.p.current_unit->child_dtio++;
2213181254a7Smrg
2214181254a7Smrg dtp->u.p.fdtio_ptr (p, &unit, iotype, f->u.udf.vlist,
2215181254a7Smrg child_iostat, child_iomsg,
2216181254a7Smrg iotype_len, child_iomsg_len);
2217181254a7Smrg dtp->u.p.current_unit->child_dtio--;
2218181254a7Smrg
2219181254a7Smrg if (f->u.udf.string_len != 0)
2220181254a7Smrg free (iotype);
2221181254a7Smrg /* Note: vlist is freed in free_format_data. */
2222181254a7Smrg break;
2223181254a7Smrg
2224181254a7Smrg case FMT_E:
2225181254a7Smrg if (n == 0)
2226181254a7Smrg goto need_data;
2227181254a7Smrg if (require_type (dtp, BT_REAL, type, f))
2228181254a7Smrg return;
2229fb8a8121Smrg if (f->u.real.w == 0)
2230fb8a8121Smrg write_real_w0 (dtp, p, kind, f);
2231fb8a8121Smrg else
2232181254a7Smrg write_e (dtp, f, p, kind);
2233181254a7Smrg break;
2234181254a7Smrg
2235181254a7Smrg case FMT_EN:
2236181254a7Smrg if (n == 0)
2237181254a7Smrg goto need_data;
2238181254a7Smrg if (require_type (dtp, BT_REAL, type, f))
2239181254a7Smrg return;
2240fb8a8121Smrg if (f->u.real.w == 0)
2241fb8a8121Smrg write_real_w0 (dtp, p, kind, f);
2242fb8a8121Smrg else
2243181254a7Smrg write_en (dtp, f, p, kind);
2244181254a7Smrg break;
2245181254a7Smrg
2246181254a7Smrg case FMT_ES:
2247181254a7Smrg if (n == 0)
2248181254a7Smrg goto need_data;
2249181254a7Smrg if (require_type (dtp, BT_REAL, type, f))
2250181254a7Smrg return;
2251fb8a8121Smrg if (f->u.real.w == 0)
2252fb8a8121Smrg write_real_w0 (dtp, p, kind, f);
2253fb8a8121Smrg else
2254181254a7Smrg write_es (dtp, f, p, kind);
2255181254a7Smrg break;
2256181254a7Smrg
2257181254a7Smrg case FMT_F:
2258181254a7Smrg if (n == 0)
2259181254a7Smrg goto need_data;
2260181254a7Smrg if (require_type (dtp, BT_REAL, type, f))
2261181254a7Smrg return;
2262181254a7Smrg write_f (dtp, f, p, kind);
2263181254a7Smrg break;
2264181254a7Smrg
2265181254a7Smrg case FMT_G:
2266181254a7Smrg if (n == 0)
2267181254a7Smrg goto need_data;
2268181254a7Smrg switch (type)
2269181254a7Smrg {
2270181254a7Smrg case BT_INTEGER:
2271181254a7Smrg write_i (dtp, f, p, kind);
2272181254a7Smrg break;
2273181254a7Smrg case BT_LOGICAL:
2274181254a7Smrg write_l (dtp, f, p, kind);
2275181254a7Smrg break;
2276181254a7Smrg case BT_CHARACTER:
2277181254a7Smrg if (kind == 4)
2278181254a7Smrg write_a_char4 (dtp, f, p, size);
2279181254a7Smrg else
2280181254a7Smrg write_a (dtp, f, p, size);
2281181254a7Smrg break;
2282181254a7Smrg case BT_REAL:
2283181254a7Smrg if (f->u.real.w == 0)
2284fb8a8121Smrg write_real_w0 (dtp, p, kind, f);
2285181254a7Smrg else
2286181254a7Smrg write_d (dtp, f, p, kind);
2287181254a7Smrg break;
2288181254a7Smrg default:
2289181254a7Smrg internal_error (&dtp->common,
2290181254a7Smrg "formatted_transfer (): Bad type");
2291181254a7Smrg }
2292181254a7Smrg break;
2293181254a7Smrg
2294181254a7Smrg case FMT_STRING:
2295181254a7Smrg consume_data_flag = 0;
2296181254a7Smrg write_constant_string (dtp, f);
2297181254a7Smrg break;
2298181254a7Smrg
2299181254a7Smrg /* Format codes that don't transfer data. */
2300181254a7Smrg case FMT_X:
2301181254a7Smrg case FMT_TR:
2302181254a7Smrg consume_data_flag = 0;
2303181254a7Smrg
2304181254a7Smrg dtp->u.p.skips += f->u.n;
2305181254a7Smrg pos = bytes_used + dtp->u.p.skips - 1;
2306181254a7Smrg dtp->u.p.pending_spaces = pos - dtp->u.p.max_pos + 1;
2307181254a7Smrg /* Writes occur just before the switch on f->format, above, so
2308181254a7Smrg that trailing blanks are suppressed, unless we are doing a
2309181254a7Smrg non-advancing write in which case we want to output the blanks
2310181254a7Smrg now. */
2311181254a7Smrg if (dtp->u.p.advance_status == ADVANCE_NO)
2312181254a7Smrg {
2313181254a7Smrg write_x (dtp, dtp->u.p.skips, dtp->u.p.pending_spaces);
2314181254a7Smrg dtp->u.p.skips = dtp->u.p.pending_spaces = 0;
2315181254a7Smrg }
2316181254a7Smrg break;
2317181254a7Smrg
2318181254a7Smrg case FMT_TL:
2319181254a7Smrg case FMT_T:
2320181254a7Smrg consume_data_flag = 0;
2321181254a7Smrg
2322181254a7Smrg if (f->format == FMT_TL)
2323181254a7Smrg {
2324181254a7Smrg
2325181254a7Smrg /* Handle the special case when no bytes have been used yet.
2326181254a7Smrg Cannot go below zero. */
2327181254a7Smrg if (bytes_used == 0)
2328181254a7Smrg {
2329181254a7Smrg dtp->u.p.pending_spaces -= f->u.n;
2330181254a7Smrg dtp->u.p.skips -= f->u.n;
2331181254a7Smrg dtp->u.p.skips = dtp->u.p.skips < 0 ? 0 : dtp->u.p.skips;
2332181254a7Smrg }
2333181254a7Smrg
2334181254a7Smrg pos = bytes_used - f->u.n;
2335181254a7Smrg }
2336181254a7Smrg else /* FMT_T */
2337181254a7Smrg pos = f->u.n - dtp->u.p.pending_spaces - 1;
2338181254a7Smrg
2339181254a7Smrg /* Standard 10.6.1.1: excessive left tabbing is reset to the
2340181254a7Smrg left tab limit. We do not check if the position has gone
2341181254a7Smrg beyond the end of record because a subsequent tab could
2342181254a7Smrg bring us back again. */
2343181254a7Smrg pos = pos < 0 ? 0 : pos;
2344181254a7Smrg
2345181254a7Smrg dtp->u.p.skips = dtp->u.p.skips + pos - bytes_used;
2346181254a7Smrg dtp->u.p.pending_spaces = dtp->u.p.pending_spaces
2347181254a7Smrg + pos - dtp->u.p.max_pos;
2348181254a7Smrg dtp->u.p.pending_spaces = dtp->u.p.pending_spaces < 0
2349181254a7Smrg ? 0 : dtp->u.p.pending_spaces;
2350181254a7Smrg break;
2351181254a7Smrg
2352181254a7Smrg case FMT_S:
2353181254a7Smrg consume_data_flag = 0;
2354fb8a8121Smrg dtp->u.p.sign_status = SIGN_PROCDEFINED;
2355181254a7Smrg break;
2356181254a7Smrg
2357181254a7Smrg case FMT_SS:
2358181254a7Smrg consume_data_flag = 0;
2359fb8a8121Smrg dtp->u.p.sign_status = SIGN_SUPPRESS;
2360181254a7Smrg break;
2361181254a7Smrg
2362181254a7Smrg case FMT_SP:
2363181254a7Smrg consume_data_flag = 0;
2364fb8a8121Smrg dtp->u.p.sign_status = SIGN_PLUS;
2365181254a7Smrg break;
2366181254a7Smrg
2367181254a7Smrg case FMT_BN:
2368181254a7Smrg consume_data_flag = 0 ;
2369181254a7Smrg dtp->u.p.blank_status = BLANK_NULL;
2370181254a7Smrg break;
2371181254a7Smrg
2372181254a7Smrg case FMT_BZ:
2373181254a7Smrg consume_data_flag = 0;
2374181254a7Smrg dtp->u.p.blank_status = BLANK_ZERO;
2375181254a7Smrg break;
2376181254a7Smrg
2377181254a7Smrg case FMT_DC:
2378181254a7Smrg consume_data_flag = 0;
2379181254a7Smrg dtp->u.p.current_unit->decimal_status = DECIMAL_COMMA;
2380181254a7Smrg break;
2381181254a7Smrg
2382181254a7Smrg case FMT_DP:
2383181254a7Smrg consume_data_flag = 0;
2384181254a7Smrg dtp->u.p.current_unit->decimal_status = DECIMAL_POINT;
2385181254a7Smrg break;
2386181254a7Smrg
2387181254a7Smrg case FMT_RC:
2388181254a7Smrg consume_data_flag = 0;
2389181254a7Smrg dtp->u.p.current_unit->round_status = ROUND_COMPATIBLE;
2390181254a7Smrg break;
2391181254a7Smrg
2392181254a7Smrg case FMT_RD:
2393181254a7Smrg consume_data_flag = 0;
2394181254a7Smrg dtp->u.p.current_unit->round_status = ROUND_DOWN;
2395181254a7Smrg break;
2396181254a7Smrg
2397181254a7Smrg case FMT_RN:
2398181254a7Smrg consume_data_flag = 0;
2399181254a7Smrg dtp->u.p.current_unit->round_status = ROUND_NEAREST;
2400181254a7Smrg break;
2401181254a7Smrg
2402181254a7Smrg case FMT_RP:
2403181254a7Smrg consume_data_flag = 0;
2404181254a7Smrg dtp->u.p.current_unit->round_status = ROUND_PROCDEFINED;
2405181254a7Smrg break;
2406181254a7Smrg
2407181254a7Smrg case FMT_RU:
2408181254a7Smrg consume_data_flag = 0;
2409181254a7Smrg dtp->u.p.current_unit->round_status = ROUND_UP;
2410181254a7Smrg break;
2411181254a7Smrg
2412181254a7Smrg case FMT_RZ:
2413181254a7Smrg consume_data_flag = 0;
2414181254a7Smrg dtp->u.p.current_unit->round_status = ROUND_ZERO;
2415181254a7Smrg break;
2416181254a7Smrg
2417181254a7Smrg case FMT_P:
2418181254a7Smrg consume_data_flag = 0;
2419181254a7Smrg dtp->u.p.scale_factor = f->u.k;
2420181254a7Smrg break;
2421181254a7Smrg
2422181254a7Smrg case FMT_DOLLAR:
2423181254a7Smrg consume_data_flag = 0;
2424181254a7Smrg dtp->u.p.seen_dollar = 1;
2425181254a7Smrg break;
2426181254a7Smrg
2427181254a7Smrg case FMT_SLASH:
2428181254a7Smrg consume_data_flag = 0;
2429181254a7Smrg dtp->u.p.skips = dtp->u.p.pending_spaces = 0;
2430181254a7Smrg next_record (dtp, 0);
2431181254a7Smrg break;
2432181254a7Smrg
2433181254a7Smrg case FMT_COLON:
2434181254a7Smrg /* A colon descriptor causes us to exit this loop (in
2435181254a7Smrg particular preventing another / descriptor from being
2436181254a7Smrg processed) unless there is another data item to be
2437181254a7Smrg transferred. */
2438181254a7Smrg consume_data_flag = 0;
2439181254a7Smrg if (n == 0)
2440181254a7Smrg return;
2441181254a7Smrg break;
2442181254a7Smrg
2443181254a7Smrg default:
2444181254a7Smrg internal_error (&dtp->common, "Bad format node");
2445181254a7Smrg }
2446181254a7Smrg
2447181254a7Smrg /* Adjust the item count and data pointer. */
2448181254a7Smrg
2449181254a7Smrg if ((consume_data_flag > 0) && (n > 0))
2450181254a7Smrg {
2451181254a7Smrg n--;
2452181254a7Smrg p = ((char *) p) + size;
2453181254a7Smrg }
2454181254a7Smrg
2455181254a7Smrg pos = dtp->u.p.current_unit->recl - dtp->u.p.current_unit->bytes_left;
2456181254a7Smrg dtp->u.p.max_pos = (dtp->u.p.max_pos > pos) ? dtp->u.p.max_pos : pos;
2457181254a7Smrg }
2458181254a7Smrg
2459181254a7Smrg return;
2460181254a7Smrg
2461181254a7Smrg /* Come here when we need a data descriptor but don't have one. We
2462181254a7Smrg push the current format node back onto the input, then return and
2463181254a7Smrg let the user program call us back with the data. */
2464181254a7Smrg need_data:
2465181254a7Smrg unget_format (dtp, f);
2466181254a7Smrg }
2467181254a7Smrg
2468181254a7Smrg /* This function is first called from data_init_transfer to initiate the loop
2469181254a7Smrg over each item in the format, transferring data as required. Subsequent
2470181254a7Smrg calls to this function occur for each data item foound in the READ/WRITE
2471181254a7Smrg statement. The item_count is incremented for each call. Since the first
2472181254a7Smrg call is from data_transfer_init, the item_count is always one greater than
2473181254a7Smrg the actual count number of the item being transferred. */
2474181254a7Smrg
2475181254a7Smrg static void
formatted_transfer(st_parameter_dt * dtp,bt type,void * p,int kind,size_t size,size_t nelems)2476181254a7Smrg formatted_transfer (st_parameter_dt *dtp, bt type, void *p, int kind,
2477181254a7Smrg size_t size, size_t nelems)
2478181254a7Smrg {
2479181254a7Smrg size_t elem;
2480181254a7Smrg char *tmp;
2481181254a7Smrg
2482181254a7Smrg tmp = (char *) p;
2483181254a7Smrg size_t stride = type == BT_CHARACTER ?
2484181254a7Smrg size * GFC_SIZE_OF_CHAR_KIND(kind) : size;
2485181254a7Smrg if (dtp->u.p.mode == READING)
2486181254a7Smrg {
2487181254a7Smrg /* Big loop over all the elements. */
2488181254a7Smrg for (elem = 0; elem < nelems; elem++)
2489181254a7Smrg {
2490181254a7Smrg dtp->u.p.item_count++;
2491181254a7Smrg formatted_transfer_scalar_read (dtp, type, tmp + stride*elem, kind, size);
2492181254a7Smrg }
2493181254a7Smrg }
2494181254a7Smrg else
2495181254a7Smrg {
2496181254a7Smrg /* Big loop over all the elements. */
2497181254a7Smrg for (elem = 0; elem < nelems; elem++)
2498181254a7Smrg {
2499181254a7Smrg dtp->u.p.item_count++;
2500181254a7Smrg formatted_transfer_scalar_write (dtp, type, tmp + stride*elem, kind, size);
2501181254a7Smrg }
2502181254a7Smrg }
2503181254a7Smrg }
2504181254a7Smrg
2505181254a7Smrg /* Wrapper function for I/O of scalar types. If this should be an async I/O
2506181254a7Smrg request, queue it. For a synchronous write on an async unit, perform the
2507181254a7Smrg wait operation and return an error. For all synchronous writes, call the
2508181254a7Smrg right transfer function. */
2509181254a7Smrg
2510181254a7Smrg static void
wrap_scalar_transfer(st_parameter_dt * dtp,bt type,void * p,int kind,size_t size,size_t n_elem)2511181254a7Smrg wrap_scalar_transfer (st_parameter_dt *dtp, bt type, void *p, int kind,
2512181254a7Smrg size_t size, size_t n_elem)
2513181254a7Smrg {
2514181254a7Smrg if (dtp->u.p.current_unit && dtp->u.p.current_unit->au)
2515181254a7Smrg {
2516181254a7Smrg if (dtp->u.p.async)
2517181254a7Smrg {
2518181254a7Smrg transfer_args args;
2519181254a7Smrg args.scalar.transfer = dtp->u.p.transfer;
2520181254a7Smrg args.scalar.arg_bt = type;
2521181254a7Smrg args.scalar.data = p;
2522181254a7Smrg args.scalar.i = kind;
2523181254a7Smrg args.scalar.s1 = size;
2524181254a7Smrg args.scalar.s2 = n_elem;
2525181254a7Smrg enqueue_transfer (dtp->u.p.current_unit->au, &args,
2526181254a7Smrg AIO_TRANSFER_SCALAR);
2527181254a7Smrg return;
2528181254a7Smrg }
2529181254a7Smrg }
2530181254a7Smrg /* Come here if there was no asynchronous I/O to be scheduled. */
2531181254a7Smrg if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
2532181254a7Smrg return;
2533181254a7Smrg
2534181254a7Smrg dtp->u.p.transfer (dtp, type, p, kind, size, 1);
2535181254a7Smrg }
2536181254a7Smrg
2537181254a7Smrg
2538181254a7Smrg /* Data transfer entry points. The type of the data entity is
2539181254a7Smrg implicit in the subroutine call. This prevents us from having to
2540181254a7Smrg share a common enum with the compiler. */
2541181254a7Smrg
2542181254a7Smrg void
transfer_integer(st_parameter_dt * dtp,void * p,int kind)2543181254a7Smrg transfer_integer (st_parameter_dt *dtp, void *p, int kind)
2544181254a7Smrg {
2545181254a7Smrg wrap_scalar_transfer (dtp, BT_INTEGER, p, kind, kind, 1);
2546181254a7Smrg }
2547181254a7Smrg
2548181254a7Smrg void
transfer_integer_write(st_parameter_dt * dtp,void * p,int kind)2549181254a7Smrg transfer_integer_write (st_parameter_dt *dtp, void *p, int kind)
2550181254a7Smrg {
2551181254a7Smrg transfer_integer (dtp, p, kind);
2552181254a7Smrg }
2553181254a7Smrg
2554181254a7Smrg void
transfer_real(st_parameter_dt * dtp,void * p,int kind)2555181254a7Smrg transfer_real (st_parameter_dt *dtp, void *p, int kind)
2556181254a7Smrg {
2557181254a7Smrg size_t size;
2558181254a7Smrg if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
2559181254a7Smrg return;
2560181254a7Smrg size = size_from_real_kind (kind);
2561181254a7Smrg wrap_scalar_transfer (dtp, BT_REAL, p, kind, size, 1);
2562181254a7Smrg }
2563181254a7Smrg
2564181254a7Smrg void
transfer_real_write(st_parameter_dt * dtp,void * p,int kind)2565181254a7Smrg transfer_real_write (st_parameter_dt *dtp, void *p, int kind)
2566181254a7Smrg {
2567181254a7Smrg transfer_real (dtp, p, kind);
2568181254a7Smrg }
2569181254a7Smrg
2570181254a7Smrg void
transfer_logical(st_parameter_dt * dtp,void * p,int kind)2571181254a7Smrg transfer_logical (st_parameter_dt *dtp, void *p, int kind)
2572181254a7Smrg {
2573181254a7Smrg wrap_scalar_transfer (dtp, BT_LOGICAL, p, kind, kind, 1);
2574181254a7Smrg }
2575181254a7Smrg
2576181254a7Smrg void
transfer_logical_write(st_parameter_dt * dtp,void * p,int kind)2577181254a7Smrg transfer_logical_write (st_parameter_dt *dtp, void *p, int kind)
2578181254a7Smrg {
2579181254a7Smrg transfer_logical (dtp, p, kind);
2580181254a7Smrg }
2581181254a7Smrg
2582181254a7Smrg void
transfer_character(st_parameter_dt * dtp,void * p,gfc_charlen_type len)2583181254a7Smrg transfer_character (st_parameter_dt *dtp, void *p, gfc_charlen_type len)
2584181254a7Smrg {
2585181254a7Smrg static char *empty_string[0];
2586181254a7Smrg
2587181254a7Smrg if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
2588181254a7Smrg return;
2589181254a7Smrg
2590181254a7Smrg /* Strings of zero length can have p == NULL, which confuses the
2591181254a7Smrg transfer routines into thinking we need more data elements. To avoid
2592181254a7Smrg this, we give them a nice pointer. */
2593181254a7Smrg if (len == 0 && p == NULL)
2594181254a7Smrg p = empty_string;
2595181254a7Smrg
2596181254a7Smrg /* Set kind here to 1. */
2597181254a7Smrg wrap_scalar_transfer (dtp, BT_CHARACTER, p, 1, len, 1);
2598181254a7Smrg }
2599181254a7Smrg
2600181254a7Smrg void
transfer_character_write(st_parameter_dt * dtp,void * p,gfc_charlen_type len)2601181254a7Smrg transfer_character_write (st_parameter_dt *dtp, void *p, gfc_charlen_type len)
2602181254a7Smrg {
2603181254a7Smrg transfer_character (dtp, p, len);
2604181254a7Smrg }
2605181254a7Smrg
2606181254a7Smrg void
transfer_character_wide(st_parameter_dt * dtp,void * p,gfc_charlen_type len,int kind)2607181254a7Smrg transfer_character_wide (st_parameter_dt *dtp, void *p, gfc_charlen_type len, int kind)
2608181254a7Smrg {
2609181254a7Smrg static char *empty_string[0];
2610181254a7Smrg
2611181254a7Smrg if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
2612181254a7Smrg return;
2613181254a7Smrg
2614181254a7Smrg /* Strings of zero length can have p == NULL, which confuses the
2615181254a7Smrg transfer routines into thinking we need more data elements. To avoid
2616181254a7Smrg this, we give them a nice pointer. */
2617181254a7Smrg if (len == 0 && p == NULL)
2618181254a7Smrg p = empty_string;
2619181254a7Smrg
2620181254a7Smrg /* Here we pass the actual kind value. */
2621181254a7Smrg wrap_scalar_transfer (dtp, BT_CHARACTER, p, kind, len, 1);
2622181254a7Smrg }
2623181254a7Smrg
2624181254a7Smrg void
transfer_character_wide_write(st_parameter_dt * dtp,void * p,gfc_charlen_type len,int kind)2625181254a7Smrg transfer_character_wide_write (st_parameter_dt *dtp, void *p, gfc_charlen_type len, int kind)
2626181254a7Smrg {
2627181254a7Smrg transfer_character_wide (dtp, p, len, kind);
2628181254a7Smrg }
2629181254a7Smrg
2630181254a7Smrg void
transfer_complex(st_parameter_dt * dtp,void * p,int kind)2631181254a7Smrg transfer_complex (st_parameter_dt *dtp, void *p, int kind)
2632181254a7Smrg {
2633181254a7Smrg size_t size;
2634181254a7Smrg if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
2635181254a7Smrg return;
2636181254a7Smrg size = size_from_complex_kind (kind);
2637181254a7Smrg wrap_scalar_transfer (dtp, BT_COMPLEX, p, kind, size, 1);
2638181254a7Smrg }
2639181254a7Smrg
2640181254a7Smrg void
transfer_complex_write(st_parameter_dt * dtp,void * p,int kind)2641181254a7Smrg transfer_complex_write (st_parameter_dt *dtp, void *p, int kind)
2642181254a7Smrg {
2643181254a7Smrg transfer_complex (dtp, p, kind);
2644181254a7Smrg }
2645181254a7Smrg
2646181254a7Smrg void
transfer_array_inner(st_parameter_dt * dtp,gfc_array_char * desc,int kind,gfc_charlen_type charlen)2647181254a7Smrg transfer_array_inner (st_parameter_dt *dtp, gfc_array_char *desc, int kind,
2648181254a7Smrg gfc_charlen_type charlen)
2649181254a7Smrg {
2650181254a7Smrg index_type count[GFC_MAX_DIMENSIONS];
2651181254a7Smrg index_type extent[GFC_MAX_DIMENSIONS];
2652181254a7Smrg index_type stride[GFC_MAX_DIMENSIONS];
2653181254a7Smrg index_type stride0, rank, size, n;
2654181254a7Smrg size_t tsize;
2655181254a7Smrg char *data;
2656181254a7Smrg bt iotype;
2657181254a7Smrg
2658181254a7Smrg /* Adjust item_count before emitting error message. */
2659181254a7Smrg
2660181254a7Smrg if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
2661181254a7Smrg return;
2662181254a7Smrg
2663181254a7Smrg iotype = (bt) GFC_DESCRIPTOR_TYPE (desc);
2664181254a7Smrg size = iotype == BT_CHARACTER ? charlen : GFC_DESCRIPTOR_SIZE (desc);
2665181254a7Smrg
2666181254a7Smrg rank = GFC_DESCRIPTOR_RANK (desc);
2667181254a7Smrg
2668181254a7Smrg for (n = 0; n < rank; n++)
2669181254a7Smrg {
2670181254a7Smrg count[n] = 0;
2671181254a7Smrg stride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(desc,n);
2672181254a7Smrg extent[n] = GFC_DESCRIPTOR_EXTENT(desc,n);
2673181254a7Smrg
2674181254a7Smrg /* If the extent of even one dimension is zero, then the entire
2675181254a7Smrg array section contains zero elements, so we return after writing
2676181254a7Smrg a zero array record. */
2677181254a7Smrg if (extent[n] <= 0)
2678181254a7Smrg {
2679181254a7Smrg data = NULL;
2680181254a7Smrg tsize = 0;
2681181254a7Smrg dtp->u.p.transfer (dtp, iotype, data, kind, size, tsize);
2682181254a7Smrg return;
2683181254a7Smrg }
2684181254a7Smrg }
2685181254a7Smrg
2686181254a7Smrg stride0 = stride[0];
2687181254a7Smrg
2688181254a7Smrg /* If the innermost dimension has a stride of 1, we can do the transfer
2689181254a7Smrg in contiguous chunks. */
2690181254a7Smrg if (stride0 == size)
2691181254a7Smrg tsize = extent[0];
2692181254a7Smrg else
2693181254a7Smrg tsize = 1;
2694181254a7Smrg
2695181254a7Smrg data = GFC_DESCRIPTOR_DATA (desc);
2696181254a7Smrg
2697181254a7Smrg /* When reading, we need to check endfile conditions so we do not miss
2698181254a7Smrg an END=label. Make this separate so we do not have an extra test
2699181254a7Smrg in a tight loop when it is not needed. */
2700181254a7Smrg
2701181254a7Smrg if (dtp->u.p.current_unit && dtp->u.p.mode == READING)
2702181254a7Smrg {
2703181254a7Smrg while (data)
2704181254a7Smrg {
2705181254a7Smrg if (unlikely (dtp->u.p.current_unit->endfile == AFTER_ENDFILE))
2706181254a7Smrg return;
2707181254a7Smrg
2708181254a7Smrg dtp->u.p.transfer (dtp, iotype, data, kind, size, tsize);
2709181254a7Smrg data += stride0 * tsize;
2710181254a7Smrg count[0] += tsize;
2711181254a7Smrg n = 0;
2712181254a7Smrg while (count[n] == extent[n])
2713181254a7Smrg {
2714181254a7Smrg count[n] = 0;
2715181254a7Smrg data -= stride[n] * extent[n];
2716181254a7Smrg n++;
2717181254a7Smrg if (n == rank)
2718181254a7Smrg {
2719181254a7Smrg data = NULL;
2720181254a7Smrg break;
2721181254a7Smrg }
2722181254a7Smrg else
2723181254a7Smrg {
2724181254a7Smrg count[n]++;
2725181254a7Smrg data += stride[n];
2726181254a7Smrg }
2727181254a7Smrg }
2728181254a7Smrg }
2729181254a7Smrg }
2730181254a7Smrg else
2731181254a7Smrg {
2732181254a7Smrg while (data)
2733181254a7Smrg {
2734181254a7Smrg dtp->u.p.transfer (dtp, iotype, data, kind, size, tsize);
2735181254a7Smrg data += stride0 * tsize;
2736181254a7Smrg count[0] += tsize;
2737181254a7Smrg n = 0;
2738181254a7Smrg while (count[n] == extent[n])
2739181254a7Smrg {
2740181254a7Smrg count[n] = 0;
2741181254a7Smrg data -= stride[n] * extent[n];
2742181254a7Smrg n++;
2743181254a7Smrg if (n == rank)
2744181254a7Smrg {
2745181254a7Smrg data = NULL;
2746181254a7Smrg break;
2747181254a7Smrg }
2748181254a7Smrg else
2749181254a7Smrg {
2750181254a7Smrg count[n]++;
2751181254a7Smrg data += stride[n];
2752181254a7Smrg }
2753181254a7Smrg }
2754181254a7Smrg }
2755181254a7Smrg }
2756181254a7Smrg }
2757181254a7Smrg
2758181254a7Smrg void
transfer_array(st_parameter_dt * dtp,gfc_array_char * desc,int kind,gfc_charlen_type charlen)2759181254a7Smrg transfer_array (st_parameter_dt *dtp, gfc_array_char *desc, int kind,
2760181254a7Smrg gfc_charlen_type charlen)
2761181254a7Smrg {
2762181254a7Smrg if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
2763181254a7Smrg return;
2764181254a7Smrg
2765181254a7Smrg if (dtp->u.p.current_unit && dtp->u.p.current_unit->au)
2766181254a7Smrg {
2767181254a7Smrg if (dtp->u.p.async)
2768181254a7Smrg {
2769181254a7Smrg transfer_args args;
2770181254a7Smrg size_t sz = sizeof (gfc_array_char)
2771181254a7Smrg + sizeof (descriptor_dimension)
2772181254a7Smrg * GFC_DESCRIPTOR_RANK (desc);
2773181254a7Smrg args.array.desc = xmalloc (sz);
2774181254a7Smrg NOTE ("desc = %p", (void *) args.array.desc);
2775181254a7Smrg memcpy (args.array.desc, desc, sz);
2776181254a7Smrg args.array.kind = kind;
2777181254a7Smrg args.array.charlen = charlen;
2778181254a7Smrg enqueue_transfer (dtp->u.p.current_unit->au, &args,
2779181254a7Smrg AIO_TRANSFER_ARRAY);
2780181254a7Smrg return;
2781181254a7Smrg }
2782181254a7Smrg }
2783181254a7Smrg /* Come here if there was no asynchronous I/O to be scheduled. */
2784181254a7Smrg transfer_array_inner (dtp, desc, kind, charlen);
2785181254a7Smrg }
2786181254a7Smrg
2787181254a7Smrg
2788181254a7Smrg void
transfer_array_write(st_parameter_dt * dtp,gfc_array_char * desc,int kind,gfc_charlen_type charlen)2789181254a7Smrg transfer_array_write (st_parameter_dt *dtp, gfc_array_char *desc, int kind,
2790181254a7Smrg gfc_charlen_type charlen)
2791181254a7Smrg {
2792181254a7Smrg transfer_array (dtp, desc, kind, charlen);
2793181254a7Smrg }
2794181254a7Smrg
2795181254a7Smrg
2796181254a7Smrg /* User defined input/output iomsg. */
2797181254a7Smrg
2798181254a7Smrg #define IOMSG_LEN 256
2799181254a7Smrg
2800181254a7Smrg void
transfer_derived(st_parameter_dt * parent,void * dtio_source,void * dtio_proc)2801181254a7Smrg transfer_derived (st_parameter_dt *parent, void *dtio_source, void *dtio_proc)
2802181254a7Smrg {
2803181254a7Smrg if (parent->u.p.current_unit)
2804181254a7Smrg {
2805181254a7Smrg if (parent->u.p.current_unit->flags.form == FORM_UNFORMATTED)
2806181254a7Smrg parent->u.p.ufdtio_ptr = (unformatted_dtio) dtio_proc;
2807181254a7Smrg else
2808181254a7Smrg parent->u.p.fdtio_ptr = (formatted_dtio) dtio_proc;
2809181254a7Smrg }
2810181254a7Smrg wrap_scalar_transfer (parent, BT_CLASS, dtio_source, 0, 0, 1);
2811181254a7Smrg }
2812181254a7Smrg
2813181254a7Smrg
2814181254a7Smrg /* Preposition a sequential unformatted file while reading. */
2815181254a7Smrg
2816181254a7Smrg static void
us_read(st_parameter_dt * dtp,int continued)2817181254a7Smrg us_read (st_parameter_dt *dtp, int continued)
2818181254a7Smrg {
2819181254a7Smrg ssize_t n, nr;
2820181254a7Smrg GFC_INTEGER_4 i4;
2821181254a7Smrg GFC_INTEGER_8 i8;
2822181254a7Smrg gfc_offset i;
2823181254a7Smrg
2824181254a7Smrg if (compile_options.record_marker == 0)
2825181254a7Smrg n = sizeof (GFC_INTEGER_4);
2826181254a7Smrg else
2827181254a7Smrg n = compile_options.record_marker;
2828181254a7Smrg
2829181254a7Smrg nr = sread (dtp->u.p.current_unit->s, &i, n);
2830181254a7Smrg if (unlikely (nr < 0))
2831181254a7Smrg {
2832181254a7Smrg generate_error (&dtp->common, LIBERROR_BAD_US, NULL);
2833181254a7Smrg return;
2834181254a7Smrg }
2835181254a7Smrg else if (nr == 0)
2836181254a7Smrg {
2837181254a7Smrg hit_eof (dtp);
2838181254a7Smrg return; /* end of file */
2839181254a7Smrg }
2840181254a7Smrg else if (unlikely (n != nr))
2841181254a7Smrg {
2842181254a7Smrg generate_error (&dtp->common, LIBERROR_BAD_US, NULL);
2843181254a7Smrg return;
2844181254a7Smrg }
2845181254a7Smrg
2846*b1e83836Smrg int convert = dtp->u.p.current_unit->flags.convert;
2847*b1e83836Smrg #ifdef HAVE_GFC_REAL_17
2848*b1e83836Smrg convert &= ~(GFC_CONVERT_R16_IEEE | GFC_CONVERT_R16_IBM);
2849*b1e83836Smrg #endif
2850181254a7Smrg /* Only GFC_CONVERT_NATIVE and GFC_CONVERT_SWAP are valid here. */
2851*b1e83836Smrg if (likely (convert == GFC_CONVERT_NATIVE))
2852181254a7Smrg {
2853181254a7Smrg switch (nr)
2854181254a7Smrg {
2855181254a7Smrg case sizeof(GFC_INTEGER_4):
2856181254a7Smrg memcpy (&i4, &i, sizeof (i4));
2857181254a7Smrg i = i4;
2858181254a7Smrg break;
2859181254a7Smrg
2860181254a7Smrg case sizeof(GFC_INTEGER_8):
2861181254a7Smrg memcpy (&i8, &i, sizeof (i8));
2862181254a7Smrg i = i8;
2863181254a7Smrg break;
2864181254a7Smrg
2865181254a7Smrg default:
2866181254a7Smrg runtime_error ("Illegal value for record marker");
2867181254a7Smrg break;
2868181254a7Smrg }
2869181254a7Smrg }
2870181254a7Smrg else
2871181254a7Smrg {
2872181254a7Smrg uint32_t u32;
2873181254a7Smrg uint64_t u64;
2874181254a7Smrg switch (nr)
2875181254a7Smrg {
2876181254a7Smrg case sizeof(GFC_INTEGER_4):
2877181254a7Smrg memcpy (&u32, &i, sizeof (u32));
2878181254a7Smrg u32 = __builtin_bswap32 (u32);
2879181254a7Smrg memcpy (&i4, &u32, sizeof (i4));
2880181254a7Smrg i = i4;
2881181254a7Smrg break;
2882181254a7Smrg
2883181254a7Smrg case sizeof(GFC_INTEGER_8):
2884181254a7Smrg memcpy (&u64, &i, sizeof (u64));
2885181254a7Smrg u64 = __builtin_bswap64 (u64);
2886181254a7Smrg memcpy (&i8, &u64, sizeof (i8));
2887181254a7Smrg i = i8;
2888181254a7Smrg break;
2889181254a7Smrg
2890181254a7Smrg default:
2891181254a7Smrg runtime_error ("Illegal value for record marker");
2892181254a7Smrg break;
2893181254a7Smrg }
2894181254a7Smrg }
2895181254a7Smrg
2896181254a7Smrg if (i >= 0)
2897181254a7Smrg {
2898181254a7Smrg dtp->u.p.current_unit->bytes_left_subrecord = i;
2899181254a7Smrg dtp->u.p.current_unit->continued = 0;
2900181254a7Smrg }
2901181254a7Smrg else
2902181254a7Smrg {
2903181254a7Smrg dtp->u.p.current_unit->bytes_left_subrecord = -i;
2904181254a7Smrg dtp->u.p.current_unit->continued = 1;
2905181254a7Smrg }
2906181254a7Smrg
2907181254a7Smrg if (! continued)
2908181254a7Smrg dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
2909181254a7Smrg }
2910181254a7Smrg
2911181254a7Smrg
2912181254a7Smrg /* Preposition a sequential unformatted file while writing. This
2913181254a7Smrg amount to writing a bogus length that will be filled in later. */
2914181254a7Smrg
2915181254a7Smrg static void
us_write(st_parameter_dt * dtp,int continued)2916181254a7Smrg us_write (st_parameter_dt *dtp, int continued)
2917181254a7Smrg {
2918181254a7Smrg ssize_t nbytes;
2919181254a7Smrg gfc_offset dummy;
2920181254a7Smrg
2921181254a7Smrg dummy = 0;
2922181254a7Smrg
2923181254a7Smrg if (compile_options.record_marker == 0)
2924181254a7Smrg nbytes = sizeof (GFC_INTEGER_4);
2925181254a7Smrg else
2926181254a7Smrg nbytes = compile_options.record_marker ;
2927181254a7Smrg
2928181254a7Smrg if (swrite (dtp->u.p.current_unit->s, &dummy, nbytes) != nbytes)
2929181254a7Smrg generate_error (&dtp->common, LIBERROR_OS, NULL);
2930181254a7Smrg
2931181254a7Smrg /* For sequential unformatted, if RECL= was not specified in the OPEN
2932181254a7Smrg we write until we have more bytes than can fit in the subrecord
2933181254a7Smrg markers, then we write a new subrecord. */
2934181254a7Smrg
2935181254a7Smrg dtp->u.p.current_unit->bytes_left_subrecord =
2936181254a7Smrg dtp->u.p.current_unit->recl_subrecord;
2937181254a7Smrg dtp->u.p.current_unit->continued = continued;
2938181254a7Smrg }
2939181254a7Smrg
2940181254a7Smrg
2941181254a7Smrg /* Position to the next record prior to transfer. We are assumed to
2942181254a7Smrg be before the next record. We also calculate the bytes in the next
2943181254a7Smrg record. */
2944181254a7Smrg
2945181254a7Smrg static void
pre_position(st_parameter_dt * dtp)2946181254a7Smrg pre_position (st_parameter_dt *dtp)
2947181254a7Smrg {
2948181254a7Smrg if (dtp->u.p.current_unit->current_record)
2949181254a7Smrg return; /* Already positioned. */
2950181254a7Smrg
2951181254a7Smrg switch (current_mode (dtp))
2952181254a7Smrg {
2953181254a7Smrg case FORMATTED_STREAM:
2954181254a7Smrg case UNFORMATTED_STREAM:
2955181254a7Smrg /* There are no records with stream I/O. If the position was specified
2956181254a7Smrg data_transfer_init has already positioned the file. If no position
2957181254a7Smrg was specified, we continue from where we last left off. I.e.
2958181254a7Smrg there is nothing to do here. */
2959181254a7Smrg break;
2960181254a7Smrg
2961181254a7Smrg case UNFORMATTED_SEQUENTIAL:
2962181254a7Smrg if (dtp->u.p.mode == READING)
2963181254a7Smrg us_read (dtp, 0);
2964181254a7Smrg else
2965181254a7Smrg us_write (dtp, 0);
2966181254a7Smrg
2967181254a7Smrg break;
2968181254a7Smrg
2969181254a7Smrg case FORMATTED_SEQUENTIAL:
2970181254a7Smrg case FORMATTED_DIRECT:
2971181254a7Smrg case UNFORMATTED_DIRECT:
2972181254a7Smrg dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
2973181254a7Smrg break;
2974fb8a8121Smrg case FORMATTED_UNSPECIFIED:
2975fb8a8121Smrg gcc_unreachable ();
2976181254a7Smrg }
2977181254a7Smrg
2978181254a7Smrg dtp->u.p.current_unit->current_record = 1;
2979181254a7Smrg }
2980181254a7Smrg
2981181254a7Smrg
2982181254a7Smrg /* Initialize things for a data transfer. This code is common for
2983181254a7Smrg both reading and writing. */
2984181254a7Smrg
2985181254a7Smrg static void
data_transfer_init(st_parameter_dt * dtp,int read_flag)2986181254a7Smrg data_transfer_init (st_parameter_dt *dtp, int read_flag)
2987181254a7Smrg {
2988181254a7Smrg unit_flags u_flags; /* Used for creating a unit if needed. */
2989181254a7Smrg GFC_INTEGER_4 cf = dtp->common.flags;
2990181254a7Smrg namelist_info *ionml;
2991181254a7Smrg async_unit *au;
2992181254a7Smrg
2993181254a7Smrg NOTE ("data_transfer_init");
2994181254a7Smrg
2995181254a7Smrg ionml = ((cf & IOPARM_DT_IONML_SET) != 0) ? dtp->u.p.ionml : NULL;
2996181254a7Smrg
2997181254a7Smrg memset (&dtp->u.p, 0, sizeof (dtp->u.p));
2998181254a7Smrg
2999181254a7Smrg dtp->u.p.ionml = ionml;
3000181254a7Smrg dtp->u.p.mode = read_flag ? READING : WRITING;
3001181254a7Smrg dtp->u.p.namelist_mode = 0;
3002181254a7Smrg dtp->u.p.cc.len = 0;
3003181254a7Smrg
3004181254a7Smrg if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
3005181254a7Smrg return;
3006181254a7Smrg
3007181254a7Smrg dtp->u.p.current_unit = get_unit (dtp, 1);
3008181254a7Smrg
3009181254a7Smrg if (dtp->u.p.current_unit == NULL)
3010181254a7Smrg {
3011181254a7Smrg /* This means we tried to access an external unit < 0 without
3012181254a7Smrg having opened it first with NEWUNIT=. */
3013181254a7Smrg generate_error (&dtp->common, LIBERROR_BAD_OPTION,
3014181254a7Smrg "Unit number is negative and unit was not already "
3015181254a7Smrg "opened with OPEN(NEWUNIT=...)");
3016181254a7Smrg return;
3017181254a7Smrg }
3018181254a7Smrg else if (dtp->u.p.current_unit->s == NULL)
3019181254a7Smrg { /* Open the unit with some default flags. */
3020181254a7Smrg st_parameter_open opp;
3021181254a7Smrg unit_convert conv;
3022181254a7Smrg NOTE ("Open the unit with some default flags.");
3023181254a7Smrg memset (&u_flags, '\0', sizeof (u_flags));
3024181254a7Smrg u_flags.access = ACCESS_SEQUENTIAL;
3025181254a7Smrg u_flags.action = ACTION_READWRITE;
3026181254a7Smrg
3027181254a7Smrg /* Is it unformatted? */
3028181254a7Smrg if (!(cf & (IOPARM_DT_HAS_FORMAT | IOPARM_DT_LIST_FORMAT
3029181254a7Smrg | IOPARM_DT_IONML_SET)))
3030181254a7Smrg u_flags.form = FORM_UNFORMATTED;
3031181254a7Smrg else
3032181254a7Smrg u_flags.form = FORM_UNSPECIFIED;
3033181254a7Smrg
3034181254a7Smrg u_flags.delim = DELIM_UNSPECIFIED;
3035181254a7Smrg u_flags.blank = BLANK_UNSPECIFIED;
3036181254a7Smrg u_flags.pad = PAD_UNSPECIFIED;
3037181254a7Smrg u_flags.decimal = DECIMAL_UNSPECIFIED;
3038181254a7Smrg u_flags.encoding = ENCODING_UNSPECIFIED;
3039181254a7Smrg u_flags.async = ASYNC_UNSPECIFIED;
3040181254a7Smrg u_flags.round = ROUND_UNSPECIFIED;
3041181254a7Smrg u_flags.sign = SIGN_UNSPECIFIED;
3042181254a7Smrg u_flags.share = SHARE_UNSPECIFIED;
3043181254a7Smrg u_flags.cc = CC_UNSPECIFIED;
3044181254a7Smrg u_flags.readonly = 0;
3045181254a7Smrg
3046181254a7Smrg u_flags.status = STATUS_UNKNOWN;
3047181254a7Smrg
3048181254a7Smrg conv = get_unformatted_convert (dtp->common.unit);
3049181254a7Smrg
3050181254a7Smrg if (conv == GFC_CONVERT_NONE)
3051181254a7Smrg conv = compile_options.convert;
3052181254a7Smrg
3053*b1e83836Smrg u_flags.convert = 0;
3054*b1e83836Smrg
3055*b1e83836Smrg #ifdef HAVE_GFC_REAL_17
3056*b1e83836Smrg u_flags.convert = conv & (GFC_CONVERT_R16_IEEE | GFC_CONVERT_R16_IBM);
3057*b1e83836Smrg conv &= ~(GFC_CONVERT_R16_IEEE | GFC_CONVERT_R16_IBM);
3058*b1e83836Smrg #endif
3059*b1e83836Smrg
3060181254a7Smrg switch (conv)
3061181254a7Smrg {
3062181254a7Smrg case GFC_CONVERT_NATIVE:
3063181254a7Smrg case GFC_CONVERT_SWAP:
3064181254a7Smrg break;
3065181254a7Smrg
3066181254a7Smrg case GFC_CONVERT_BIG:
3067181254a7Smrg conv = __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ? GFC_CONVERT_NATIVE : GFC_CONVERT_SWAP;
3068181254a7Smrg break;
3069181254a7Smrg
3070181254a7Smrg case GFC_CONVERT_LITTLE:
3071181254a7Smrg conv = __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ? GFC_CONVERT_SWAP : GFC_CONVERT_NATIVE;
3072181254a7Smrg break;
3073181254a7Smrg
3074181254a7Smrg default:
3075181254a7Smrg internal_error (&opp.common, "Illegal value for CONVERT");
3076181254a7Smrg break;
3077181254a7Smrg }
3078181254a7Smrg
3079*b1e83836Smrg u_flags.convert |= conv;
3080181254a7Smrg
3081181254a7Smrg opp.common = dtp->common;
3082181254a7Smrg opp.common.flags &= IOPARM_COMMON_MASK;
3083181254a7Smrg dtp->u.p.current_unit = new_unit (&opp, dtp->u.p.current_unit, &u_flags);
3084181254a7Smrg dtp->common.flags &= ~IOPARM_COMMON_MASK;
3085181254a7Smrg dtp->common.flags |= (opp.common.flags & IOPARM_COMMON_MASK);
3086181254a7Smrg if (dtp->u.p.current_unit == NULL)
3087181254a7Smrg return;
3088181254a7Smrg }
3089181254a7Smrg
3090181254a7Smrg if (dtp->u.p.current_unit->child_dtio == 0)
3091181254a7Smrg {
3092181254a7Smrg if ((cf & IOPARM_DT_HAS_SIZE) != 0)
3093181254a7Smrg {
3094181254a7Smrg dtp->u.p.current_unit->has_size = true;
3095181254a7Smrg /* Initialize the count. */
3096181254a7Smrg dtp->u.p.current_unit->size_used = 0;
3097181254a7Smrg }
3098181254a7Smrg else
3099181254a7Smrg dtp->u.p.current_unit->has_size = false;
3100181254a7Smrg }
3101181254a7Smrg else if (dtp->u.p.current_unit->internal_unit_kind > 0)
3102181254a7Smrg dtp->u.p.unit_is_internal = 1;
3103181254a7Smrg
3104181254a7Smrg if ((cf & IOPARM_DT_HAS_ASYNCHRONOUS) != 0)
3105181254a7Smrg {
3106181254a7Smrg int f;
3107181254a7Smrg f = find_option (&dtp->common, dtp->asynchronous, dtp->asynchronous_len,
3108181254a7Smrg async_opt, "Bad ASYNCHRONOUS in data transfer "
3109181254a7Smrg "statement");
3110181254a7Smrg if (f == ASYNC_YES && dtp->u.p.current_unit->flags.async != ASYNC_YES)
3111181254a7Smrg {
3112181254a7Smrg generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3113181254a7Smrg "ASYNCHRONOUS transfer without "
3114181254a7Smrg "ASYHCRONOUS='YES' in OPEN");
3115181254a7Smrg return;
3116181254a7Smrg }
3117181254a7Smrg dtp->u.p.async = f == ASYNC_YES;
3118181254a7Smrg }
3119181254a7Smrg
3120181254a7Smrg au = dtp->u.p.current_unit->au;
3121181254a7Smrg if (au)
3122181254a7Smrg {
3123181254a7Smrg if (dtp->u.p.async)
3124181254a7Smrg {
3125181254a7Smrg /* If this is an asynchronous I/O statement, collect errors and
3126181254a7Smrg return if there are any. */
3127181254a7Smrg if (collect_async_errors (&dtp->common, au))
3128181254a7Smrg return;
3129181254a7Smrg }
3130181254a7Smrg else
3131181254a7Smrg {
3132181254a7Smrg /* Synchronous statement: Perform a wait operation for any pending
3133181254a7Smrg asynchronous I/O. This needs to be done before all other error
3134181254a7Smrg checks. See F2008, 9.6.4.1. */
3135181254a7Smrg if (async_wait (&(dtp->common), au))
3136181254a7Smrg return;
3137181254a7Smrg }
3138181254a7Smrg }
3139181254a7Smrg
3140181254a7Smrg /* Check the action. */
3141181254a7Smrg
3142181254a7Smrg if (read_flag && dtp->u.p.current_unit->flags.action == ACTION_WRITE)
3143181254a7Smrg {
3144181254a7Smrg generate_error (&dtp->common, LIBERROR_BAD_ACTION,
3145181254a7Smrg "Cannot read from file opened for WRITE");
3146181254a7Smrg return;
3147181254a7Smrg }
3148181254a7Smrg
3149181254a7Smrg if (!read_flag && dtp->u.p.current_unit->flags.action == ACTION_READ)
3150181254a7Smrg {
3151181254a7Smrg generate_error (&dtp->common, LIBERROR_BAD_ACTION,
3152181254a7Smrg "Cannot write to file opened for READ");
3153181254a7Smrg return;
3154181254a7Smrg }
3155181254a7Smrg
3156181254a7Smrg dtp->u.p.first_item = 1;
3157181254a7Smrg
3158181254a7Smrg /* Check the format. */
3159181254a7Smrg
3160181254a7Smrg if ((cf & IOPARM_DT_HAS_FORMAT) != 0)
3161181254a7Smrg parse_format (dtp);
3162181254a7Smrg
3163181254a7Smrg if (dtp->u.p.current_unit->flags.form == FORM_UNFORMATTED
3164181254a7Smrg && (cf & (IOPARM_DT_HAS_FORMAT | IOPARM_DT_LIST_FORMAT))
3165181254a7Smrg != 0)
3166181254a7Smrg {
3167181254a7Smrg generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3168181254a7Smrg "Format present for UNFORMATTED data transfer");
3169181254a7Smrg return;
3170181254a7Smrg }
3171181254a7Smrg
3172181254a7Smrg if ((cf & IOPARM_DT_HAS_NAMELIST_NAME) != 0 && dtp->u.p.ionml != NULL)
3173181254a7Smrg {
3174181254a7Smrg if ((cf & IOPARM_DT_HAS_FORMAT) != 0)
3175181254a7Smrg {
3176181254a7Smrg generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3177181254a7Smrg "A format cannot be specified with a namelist");
3178181254a7Smrg return;
3179181254a7Smrg }
3180181254a7Smrg }
3181181254a7Smrg else if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED &&
3182181254a7Smrg !(cf & (IOPARM_DT_HAS_FORMAT | IOPARM_DT_LIST_FORMAT)))
3183181254a7Smrg {
3184181254a7Smrg generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3185181254a7Smrg "Missing format for FORMATTED data transfer");
3186181254a7Smrg return;
3187181254a7Smrg }
3188181254a7Smrg
3189181254a7Smrg if (is_internal_unit (dtp)
3190181254a7Smrg && dtp->u.p.current_unit->flags.form == FORM_UNFORMATTED)
3191181254a7Smrg {
3192181254a7Smrg generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3193181254a7Smrg "Internal file cannot be accessed by UNFORMATTED "
3194181254a7Smrg "data transfer");
3195181254a7Smrg return;
3196181254a7Smrg }
3197181254a7Smrg
3198181254a7Smrg /* Check the record or position number. */
3199181254a7Smrg
3200181254a7Smrg if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT
3201181254a7Smrg && (cf & IOPARM_DT_HAS_REC) == 0)
3202181254a7Smrg {
3203181254a7Smrg generate_error (&dtp->common, LIBERROR_MISSING_OPTION,
3204181254a7Smrg "Direct access data transfer requires record number");
3205181254a7Smrg return;
3206181254a7Smrg }
3207181254a7Smrg
3208181254a7Smrg if (dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL)
3209181254a7Smrg {
3210181254a7Smrg if ((cf & IOPARM_DT_HAS_REC) != 0)
3211181254a7Smrg {
3212181254a7Smrg generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3213181254a7Smrg "Record number not allowed for sequential access "
3214181254a7Smrg "data transfer");
3215181254a7Smrg return;
3216181254a7Smrg }
3217181254a7Smrg
3218181254a7Smrg if (compile_options.warn_std &&
3219181254a7Smrg dtp->u.p.current_unit->endfile == AFTER_ENDFILE)
3220181254a7Smrg {
3221181254a7Smrg generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3222181254a7Smrg "Sequential READ or WRITE not allowed after "
3223181254a7Smrg "EOF marker, possibly use REWIND or BACKSPACE");
3224181254a7Smrg return;
3225181254a7Smrg }
3226181254a7Smrg }
3227181254a7Smrg
3228181254a7Smrg /* Process the ADVANCE option. */
3229181254a7Smrg
3230181254a7Smrg dtp->u.p.advance_status
3231181254a7Smrg = !(cf & IOPARM_DT_HAS_ADVANCE) ? ADVANCE_UNSPECIFIED :
3232181254a7Smrg find_option (&dtp->common, dtp->advance, dtp->advance_len, advance_opt,
3233181254a7Smrg "Bad ADVANCE parameter in data transfer statement");
3234181254a7Smrg
3235181254a7Smrg if (dtp->u.p.advance_status != ADVANCE_UNSPECIFIED)
3236181254a7Smrg {
3237181254a7Smrg if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT)
3238181254a7Smrg {
3239181254a7Smrg generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3240181254a7Smrg "ADVANCE specification conflicts with sequential "
3241181254a7Smrg "access");
3242181254a7Smrg return;
3243181254a7Smrg }
3244181254a7Smrg
3245181254a7Smrg if (is_internal_unit (dtp))
3246181254a7Smrg {
3247181254a7Smrg generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3248181254a7Smrg "ADVANCE specification conflicts with internal file");
3249181254a7Smrg return;
3250181254a7Smrg }
3251181254a7Smrg
3252181254a7Smrg if ((cf & (IOPARM_DT_HAS_FORMAT | IOPARM_DT_LIST_FORMAT))
3253181254a7Smrg != IOPARM_DT_HAS_FORMAT)
3254181254a7Smrg {
3255181254a7Smrg generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3256181254a7Smrg "ADVANCE specification requires an explicit format");
3257181254a7Smrg return;
3258181254a7Smrg }
3259181254a7Smrg }
3260181254a7Smrg
3261181254a7Smrg /* Child IO is non-advancing and any ADVANCE= specifier is ignored.
3262181254a7Smrg F2008 9.6.2.4 */
3263181254a7Smrg if (dtp->u.p.current_unit->child_dtio > 0)
3264181254a7Smrg dtp->u.p.advance_status = ADVANCE_NO;
3265181254a7Smrg
3266181254a7Smrg if (read_flag)
3267181254a7Smrg {
3268181254a7Smrg dtp->u.p.current_unit->previous_nonadvancing_write = 0;
3269181254a7Smrg
3270181254a7Smrg if ((cf & IOPARM_EOR) != 0 && dtp->u.p.advance_status != ADVANCE_NO)
3271181254a7Smrg {
3272181254a7Smrg generate_error (&dtp->common, LIBERROR_MISSING_OPTION,
3273181254a7Smrg "EOR specification requires an ADVANCE specification "
3274181254a7Smrg "of NO");
3275181254a7Smrg return;
3276181254a7Smrg }
3277181254a7Smrg
3278181254a7Smrg if ((cf & IOPARM_DT_HAS_SIZE) != 0
3279181254a7Smrg && dtp->u.p.advance_status != ADVANCE_NO)
3280181254a7Smrg {
3281181254a7Smrg generate_error (&dtp->common, LIBERROR_MISSING_OPTION,
3282181254a7Smrg "SIZE specification requires an ADVANCE "
3283181254a7Smrg "specification of NO");
3284181254a7Smrg return;
3285181254a7Smrg }
3286181254a7Smrg }
3287181254a7Smrg else
3288181254a7Smrg { /* Write constraints. */
3289181254a7Smrg if ((cf & IOPARM_END) != 0)
3290181254a7Smrg {
3291181254a7Smrg generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3292181254a7Smrg "END specification cannot appear in a write "
3293181254a7Smrg "statement");
3294181254a7Smrg return;
3295181254a7Smrg }
3296181254a7Smrg
3297181254a7Smrg if ((cf & IOPARM_EOR) != 0)
3298181254a7Smrg {
3299181254a7Smrg generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3300181254a7Smrg "EOR specification cannot appear in a write "
3301181254a7Smrg "statement");
3302181254a7Smrg return;
3303181254a7Smrg }
3304181254a7Smrg
3305181254a7Smrg if ((cf & IOPARM_DT_HAS_SIZE) != 0)
3306181254a7Smrg {
3307181254a7Smrg generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3308181254a7Smrg "SIZE specification cannot appear in a write "
3309181254a7Smrg "statement");
3310181254a7Smrg return;
3311181254a7Smrg }
3312181254a7Smrg }
3313181254a7Smrg
3314181254a7Smrg if (dtp->u.p.advance_status == ADVANCE_UNSPECIFIED)
3315181254a7Smrg dtp->u.p.advance_status = ADVANCE_YES;
3316181254a7Smrg
3317181254a7Smrg /* Check the decimal mode. */
3318181254a7Smrg dtp->u.p.current_unit->decimal_status
3319181254a7Smrg = !(cf & IOPARM_DT_HAS_DECIMAL) ? DECIMAL_UNSPECIFIED :
3320181254a7Smrg find_option (&dtp->common, dtp->decimal, dtp->decimal_len,
3321181254a7Smrg decimal_opt, "Bad DECIMAL parameter in data transfer "
3322181254a7Smrg "statement");
3323181254a7Smrg
3324181254a7Smrg if (dtp->u.p.current_unit->decimal_status == DECIMAL_UNSPECIFIED)
3325181254a7Smrg dtp->u.p.current_unit->decimal_status = dtp->u.p.current_unit->flags.decimal;
3326181254a7Smrg
3327181254a7Smrg /* Check the round mode. */
3328181254a7Smrg dtp->u.p.current_unit->round_status
3329181254a7Smrg = !(cf & IOPARM_DT_HAS_ROUND) ? ROUND_UNSPECIFIED :
3330181254a7Smrg find_option (&dtp->common, dtp->round, dtp->round_len,
3331181254a7Smrg round_opt, "Bad ROUND parameter in data transfer "
3332181254a7Smrg "statement");
3333181254a7Smrg
3334181254a7Smrg if (dtp->u.p.current_unit->round_status == ROUND_UNSPECIFIED)
3335181254a7Smrg dtp->u.p.current_unit->round_status = dtp->u.p.current_unit->flags.round;
3336181254a7Smrg
3337181254a7Smrg /* Check the sign mode. */
3338181254a7Smrg dtp->u.p.sign_status
3339181254a7Smrg = !(cf & IOPARM_DT_HAS_SIGN) ? SIGN_UNSPECIFIED :
3340181254a7Smrg find_option (&dtp->common, dtp->sign, dtp->sign_len, sign_opt,
3341181254a7Smrg "Bad SIGN parameter in data transfer statement");
3342181254a7Smrg
3343181254a7Smrg if (dtp->u.p.sign_status == SIGN_UNSPECIFIED)
3344181254a7Smrg dtp->u.p.sign_status = dtp->u.p.current_unit->flags.sign;
3345181254a7Smrg
3346181254a7Smrg /* Check the blank mode. */
3347181254a7Smrg dtp->u.p.blank_status
3348181254a7Smrg = !(cf & IOPARM_DT_HAS_BLANK) ? BLANK_UNSPECIFIED :
3349181254a7Smrg find_option (&dtp->common, dtp->blank, dtp->blank_len,
3350181254a7Smrg blank_opt,
3351181254a7Smrg "Bad BLANK parameter in data transfer statement");
3352181254a7Smrg
3353181254a7Smrg if (dtp->u.p.blank_status == BLANK_UNSPECIFIED)
3354181254a7Smrg dtp->u.p.blank_status = dtp->u.p.current_unit->flags.blank;
3355181254a7Smrg
3356181254a7Smrg /* Check the delim mode. */
3357181254a7Smrg dtp->u.p.current_unit->delim_status
3358181254a7Smrg = !(cf & IOPARM_DT_HAS_DELIM) ? DELIM_UNSPECIFIED :
3359181254a7Smrg find_option (&dtp->common, dtp->delim, dtp->delim_len,
3360181254a7Smrg delim_opt, "Bad DELIM parameter in data transfer statement");
3361181254a7Smrg
3362181254a7Smrg if (dtp->u.p.current_unit->delim_status == DELIM_UNSPECIFIED)
3363181254a7Smrg {
3364181254a7Smrg if (ionml && dtp->u.p.current_unit->flags.delim == DELIM_UNSPECIFIED)
3365181254a7Smrg dtp->u.p.current_unit->delim_status = DELIM_QUOTE;
3366181254a7Smrg else
3367181254a7Smrg dtp->u.p.current_unit->delim_status = dtp->u.p.current_unit->flags.delim;
3368181254a7Smrg }
3369181254a7Smrg
3370181254a7Smrg /* Check the pad mode. */
3371181254a7Smrg dtp->u.p.current_unit->pad_status
3372181254a7Smrg = !(cf & IOPARM_DT_HAS_PAD) ? PAD_UNSPECIFIED :
3373181254a7Smrg find_option (&dtp->common, dtp->pad, dtp->pad_len, pad_opt,
3374181254a7Smrg "Bad PAD parameter in data transfer statement");
3375181254a7Smrg
3376181254a7Smrg if (dtp->u.p.current_unit->pad_status == PAD_UNSPECIFIED)
3377181254a7Smrg dtp->u.p.current_unit->pad_status = dtp->u.p.current_unit->flags.pad;
3378181254a7Smrg
3379181254a7Smrg /* Set up the subroutine that will handle the transfers. */
3380181254a7Smrg
3381181254a7Smrg if (read_flag)
3382181254a7Smrg {
3383181254a7Smrg if (dtp->u.p.current_unit->flags.form == FORM_UNFORMATTED)
3384181254a7Smrg dtp->u.p.transfer = unformatted_read;
3385181254a7Smrg else
3386181254a7Smrg {
3387181254a7Smrg if ((cf & IOPARM_DT_LIST_FORMAT) != 0)
3388181254a7Smrg dtp->u.p.transfer = list_formatted_read;
3389181254a7Smrg else
3390181254a7Smrg dtp->u.p.transfer = formatted_transfer;
3391181254a7Smrg }
3392181254a7Smrg }
3393181254a7Smrg else
3394181254a7Smrg {
3395181254a7Smrg if (dtp->u.p.current_unit->flags.form == FORM_UNFORMATTED)
3396181254a7Smrg dtp->u.p.transfer = unformatted_write;
3397181254a7Smrg else
3398181254a7Smrg {
3399181254a7Smrg if ((cf & IOPARM_DT_LIST_FORMAT) != 0)
3400181254a7Smrg dtp->u.p.transfer = list_formatted_write;
3401181254a7Smrg else
3402181254a7Smrg dtp->u.p.transfer = formatted_transfer;
3403181254a7Smrg }
3404181254a7Smrg }
3405181254a7Smrg
3406181254a7Smrg if (au && dtp->u.p.async)
3407181254a7Smrg {
3408181254a7Smrg NOTE ("enqueue_data_transfer");
3409181254a7Smrg enqueue_data_transfer_init (au, dtp, read_flag);
3410181254a7Smrg }
3411181254a7Smrg else
3412181254a7Smrg {
3413181254a7Smrg NOTE ("invoking data_transfer_init_worker");
3414181254a7Smrg data_transfer_init_worker (dtp, read_flag);
3415181254a7Smrg }
3416181254a7Smrg }
3417181254a7Smrg
3418181254a7Smrg void
data_transfer_init_worker(st_parameter_dt * dtp,int read_flag)3419181254a7Smrg data_transfer_init_worker (st_parameter_dt *dtp, int read_flag)
3420181254a7Smrg {
3421181254a7Smrg GFC_INTEGER_4 cf = dtp->common.flags;
3422181254a7Smrg
3423181254a7Smrg NOTE ("starting worker...");
3424181254a7Smrg
3425181254a7Smrg if (read_flag && dtp->u.p.current_unit->flags.form != FORM_UNFORMATTED
3426181254a7Smrg && ((cf & IOPARM_DT_LIST_FORMAT) != 0)
3427181254a7Smrg && dtp->u.p.current_unit->child_dtio == 0)
3428181254a7Smrg dtp->u.p.current_unit->last_char = EOF - 1;
3429181254a7Smrg
3430181254a7Smrg /* Check to see if we might be reading what we wrote before */
3431181254a7Smrg
3432181254a7Smrg if (dtp->u.p.mode != dtp->u.p.current_unit->mode
3433181254a7Smrg && !is_internal_unit (dtp))
3434181254a7Smrg {
3435181254a7Smrg int pos = fbuf_reset (dtp->u.p.current_unit);
3436181254a7Smrg if (pos != 0)
3437181254a7Smrg sseek (dtp->u.p.current_unit->s, pos, SEEK_CUR);
3438181254a7Smrg sflush(dtp->u.p.current_unit->s);
3439181254a7Smrg }
3440181254a7Smrg
3441181254a7Smrg /* Check the POS= specifier: that it is in range and that it is used with a
3442181254a7Smrg unit that has been connected for STREAM access. F2003 9.5.1.10. */
3443181254a7Smrg
3444181254a7Smrg if (((cf & IOPARM_DT_HAS_POS) != 0))
3445181254a7Smrg {
3446181254a7Smrg if (is_stream_io (dtp))
3447181254a7Smrg {
3448181254a7Smrg
3449181254a7Smrg if (dtp->pos <= 0)
3450181254a7Smrg {
3451181254a7Smrg generate_error (&dtp->common, LIBERROR_BAD_OPTION,
3452181254a7Smrg "POS=specifier must be positive");
3453181254a7Smrg return;
3454181254a7Smrg }
3455181254a7Smrg
3456181254a7Smrg if (dtp->pos >= dtp->u.p.current_unit->maxrec)
3457181254a7Smrg {
3458181254a7Smrg generate_error (&dtp->common, LIBERROR_BAD_OPTION,
3459181254a7Smrg "POS=specifier too large");
3460181254a7Smrg return;
3461181254a7Smrg }
3462181254a7Smrg
3463181254a7Smrg dtp->rec = dtp->pos;
3464181254a7Smrg
3465181254a7Smrg if (dtp->u.p.mode == READING)
3466181254a7Smrg {
3467181254a7Smrg /* Reset the endfile flag; if we hit EOF during reading
3468181254a7Smrg we'll set the flag and generate an error at that point
3469181254a7Smrg rather than worrying about it here. */
3470181254a7Smrg dtp->u.p.current_unit->endfile = NO_ENDFILE;
3471181254a7Smrg }
3472181254a7Smrg
3473181254a7Smrg if (dtp->pos != dtp->u.p.current_unit->strm_pos)
3474181254a7Smrg {
3475181254a7Smrg fbuf_reset (dtp->u.p.current_unit);
3476181254a7Smrg if (sseek (dtp->u.p.current_unit->s, dtp->pos - 1,
3477181254a7Smrg SEEK_SET) < 0)
3478181254a7Smrg {
3479181254a7Smrg generate_error (&dtp->common, LIBERROR_OS, NULL);
3480181254a7Smrg return;
3481181254a7Smrg }
3482181254a7Smrg dtp->u.p.current_unit->strm_pos = dtp->pos;
3483181254a7Smrg }
3484181254a7Smrg }
3485181254a7Smrg else
3486181254a7Smrg {
3487181254a7Smrg generate_error (&dtp->common, LIBERROR_BAD_OPTION,
3488181254a7Smrg "POS=specifier not allowed, "
3489181254a7Smrg "Try OPEN with ACCESS='stream'");
3490181254a7Smrg return;
3491181254a7Smrg }
3492181254a7Smrg }
3493181254a7Smrg
3494181254a7Smrg
3495181254a7Smrg /* Sanity checks on the record number. */
3496181254a7Smrg if ((cf & IOPARM_DT_HAS_REC) != 0)
3497181254a7Smrg {
3498181254a7Smrg if (dtp->rec <= 0)
3499181254a7Smrg {
3500181254a7Smrg generate_error (&dtp->common, LIBERROR_BAD_OPTION,
3501181254a7Smrg "Record number must be positive");
3502181254a7Smrg return;
3503181254a7Smrg }
3504181254a7Smrg
3505181254a7Smrg if (dtp->rec >= dtp->u.p.current_unit->maxrec)
3506181254a7Smrg {
3507181254a7Smrg generate_error (&dtp->common, LIBERROR_BAD_OPTION,
3508181254a7Smrg "Record number too large");
3509181254a7Smrg return;
3510181254a7Smrg }
3511181254a7Smrg
3512181254a7Smrg /* Make sure format buffer is reset. */
3513181254a7Smrg if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED)
3514181254a7Smrg fbuf_reset (dtp->u.p.current_unit);
3515181254a7Smrg
3516181254a7Smrg
3517181254a7Smrg /* Check whether the record exists to be read. Only
3518181254a7Smrg a partial record needs to exist. */
3519181254a7Smrg
3520181254a7Smrg if (dtp->u.p.mode == READING && (dtp->rec - 1)
3521181254a7Smrg * dtp->u.p.current_unit->recl >= ssize (dtp->u.p.current_unit->s))
3522181254a7Smrg {
3523181254a7Smrg generate_error (&dtp->common, LIBERROR_BAD_OPTION,
3524181254a7Smrg "Non-existing record number");
3525181254a7Smrg return;
3526181254a7Smrg }
3527181254a7Smrg
3528181254a7Smrg /* Position the file. */
3529181254a7Smrg if (sseek (dtp->u.p.current_unit->s, (gfc_offset) (dtp->rec - 1)
3530181254a7Smrg * dtp->u.p.current_unit->recl, SEEK_SET) < 0)
3531181254a7Smrg {
3532181254a7Smrg generate_error (&dtp->common, LIBERROR_OS, NULL);
3533181254a7Smrg return;
3534181254a7Smrg }
3535181254a7Smrg
3536181254a7Smrg if (dtp->u.p.current_unit->flags.access == ACCESS_STREAM)
3537181254a7Smrg {
3538181254a7Smrg generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3539181254a7Smrg "Record number not allowed for stream access "
3540181254a7Smrg "data transfer");
3541181254a7Smrg return;
3542181254a7Smrg }
3543181254a7Smrg }
3544181254a7Smrg
3545181254a7Smrg /* Bugware for badly written mixed C-Fortran I/O. */
3546181254a7Smrg if (!is_internal_unit (dtp))
3547181254a7Smrg flush_if_preconnected(dtp->u.p.current_unit->s);
3548181254a7Smrg
3549181254a7Smrg dtp->u.p.current_unit->mode = dtp->u.p.mode;
3550181254a7Smrg
3551181254a7Smrg /* Set the maximum position reached from the previous I/O operation. This
3552181254a7Smrg could be greater than zero from a previous non-advancing write. */
3553181254a7Smrg dtp->u.p.max_pos = dtp->u.p.current_unit->saved_pos;
3554181254a7Smrg
3555181254a7Smrg pre_position (dtp);
3556181254a7Smrg
3557181254a7Smrg /* Make sure that we don't do a read after a nonadvancing write. */
3558181254a7Smrg
3559181254a7Smrg if (read_flag)
3560181254a7Smrg {
3561181254a7Smrg if (dtp->u.p.current_unit->read_bad && !is_stream_io (dtp))
3562181254a7Smrg {
3563181254a7Smrg generate_error (&dtp->common, LIBERROR_BAD_OPTION,
3564181254a7Smrg "Cannot READ after a nonadvancing WRITE");
3565181254a7Smrg return;
3566181254a7Smrg }
3567181254a7Smrg }
3568181254a7Smrg else
3569181254a7Smrg {
3570181254a7Smrg if (dtp->u.p.advance_status == ADVANCE_YES && !dtp->u.p.seen_dollar)
3571181254a7Smrg dtp->u.p.current_unit->read_bad = 1;
3572181254a7Smrg }
3573181254a7Smrg
3574181254a7Smrg if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED)
3575181254a7Smrg {
3576*b1e83836Smrg #ifdef HAVE_POSIX_2008_LOCALE
3577181254a7Smrg dtp->u.p.old_locale = uselocale (c_locale);
3578181254a7Smrg #else
3579181254a7Smrg __gthread_mutex_lock (&old_locale_lock);
3580181254a7Smrg if (!old_locale_ctr++)
3581181254a7Smrg {
3582181254a7Smrg old_locale = setlocale (LC_NUMERIC, NULL);
3583181254a7Smrg setlocale (LC_NUMERIC, "C");
3584181254a7Smrg }
3585181254a7Smrg __gthread_mutex_unlock (&old_locale_lock);
3586181254a7Smrg #endif
3587181254a7Smrg /* Start the data transfer if we are doing a formatted transfer. */
3588181254a7Smrg if ((cf & (IOPARM_DT_LIST_FORMAT | IOPARM_DT_HAS_NAMELIST_NAME)) == 0
3589181254a7Smrg && dtp->u.p.ionml == NULL)
3590181254a7Smrg formatted_transfer (dtp, 0, NULL, 0, 0, 1);
3591181254a7Smrg }
3592181254a7Smrg }
3593181254a7Smrg
3594181254a7Smrg
3595181254a7Smrg /* Initialize an array_loop_spec given the array descriptor. The function
3596181254a7Smrg returns the index of the last element of the array, and also returns
3597181254a7Smrg starting record, where the first I/O goes to (necessary in case of
3598181254a7Smrg negative strides). */
3599181254a7Smrg
3600181254a7Smrg gfc_offset
init_loop_spec(gfc_array_char * desc,array_loop_spec * ls,gfc_offset * start_record)3601181254a7Smrg init_loop_spec (gfc_array_char *desc, array_loop_spec *ls,
3602181254a7Smrg gfc_offset *start_record)
3603181254a7Smrg {
3604181254a7Smrg int rank = GFC_DESCRIPTOR_RANK(desc);
3605181254a7Smrg int i;
3606181254a7Smrg gfc_offset index;
3607181254a7Smrg int empty;
3608181254a7Smrg
3609181254a7Smrg empty = 0;
3610181254a7Smrg index = 1;
3611181254a7Smrg *start_record = 0;
3612181254a7Smrg
3613181254a7Smrg for (i=0; i<rank; i++)
3614181254a7Smrg {
3615181254a7Smrg ls[i].idx = GFC_DESCRIPTOR_LBOUND(desc,i);
3616181254a7Smrg ls[i].start = GFC_DESCRIPTOR_LBOUND(desc,i);
3617181254a7Smrg ls[i].end = GFC_DESCRIPTOR_UBOUND(desc,i);
3618181254a7Smrg ls[i].step = GFC_DESCRIPTOR_STRIDE(desc,i);
3619181254a7Smrg empty = empty || (GFC_DESCRIPTOR_UBOUND(desc,i)
3620181254a7Smrg < GFC_DESCRIPTOR_LBOUND(desc,i));
3621181254a7Smrg
3622181254a7Smrg if (GFC_DESCRIPTOR_STRIDE(desc,i) > 0)
3623181254a7Smrg {
3624181254a7Smrg index += (GFC_DESCRIPTOR_EXTENT(desc,i) - 1)
3625181254a7Smrg * GFC_DESCRIPTOR_STRIDE(desc,i);
3626181254a7Smrg }
3627181254a7Smrg else
3628181254a7Smrg {
3629181254a7Smrg index -= (GFC_DESCRIPTOR_EXTENT(desc,i) - 1)
3630181254a7Smrg * GFC_DESCRIPTOR_STRIDE(desc,i);
3631181254a7Smrg *start_record -= (GFC_DESCRIPTOR_EXTENT(desc,i) - 1)
3632181254a7Smrg * GFC_DESCRIPTOR_STRIDE(desc,i);
3633181254a7Smrg }
3634181254a7Smrg }
3635181254a7Smrg
3636181254a7Smrg if (empty)
3637181254a7Smrg return 0;
3638181254a7Smrg else
3639181254a7Smrg return index;
3640181254a7Smrg }
3641181254a7Smrg
3642181254a7Smrg /* Determine the index to the next record in an internal unit array by
3643181254a7Smrg by incrementing through the array_loop_spec. */
3644181254a7Smrg
3645181254a7Smrg gfc_offset
next_array_record(st_parameter_dt * dtp,array_loop_spec * ls,int * finished)3646181254a7Smrg next_array_record (st_parameter_dt *dtp, array_loop_spec *ls, int *finished)
3647181254a7Smrg {
3648181254a7Smrg int i, carry;
3649181254a7Smrg gfc_offset index;
3650181254a7Smrg
3651181254a7Smrg carry = 1;
3652181254a7Smrg index = 0;
3653181254a7Smrg
3654181254a7Smrg for (i = 0; i < dtp->u.p.current_unit->rank; i++)
3655181254a7Smrg {
3656181254a7Smrg if (carry)
3657181254a7Smrg {
3658181254a7Smrg ls[i].idx++;
3659181254a7Smrg if (ls[i].idx > ls[i].end)
3660181254a7Smrg {
3661181254a7Smrg ls[i].idx = ls[i].start;
3662181254a7Smrg carry = 1;
3663181254a7Smrg }
3664181254a7Smrg else
3665181254a7Smrg carry = 0;
3666181254a7Smrg }
3667181254a7Smrg index = index + (ls[i].idx - ls[i].start) * ls[i].step;
3668181254a7Smrg }
3669181254a7Smrg
3670181254a7Smrg *finished = carry;
3671181254a7Smrg
3672181254a7Smrg return index;
3673181254a7Smrg }
3674181254a7Smrg
3675181254a7Smrg
3676181254a7Smrg
3677181254a7Smrg /* Skip to the end of the current record, taking care of an optional
3678181254a7Smrg record marker of size bytes. If the file is not seekable, we
3679181254a7Smrg read chunks of size MAX_READ until we get to the right
3680181254a7Smrg position. */
3681181254a7Smrg
3682181254a7Smrg static void
skip_record(st_parameter_dt * dtp,gfc_offset bytes)3683181254a7Smrg skip_record (st_parameter_dt *dtp, gfc_offset bytes)
3684181254a7Smrg {
3685181254a7Smrg ssize_t rlength, readb;
3686181254a7Smrg #define MAX_READ 4096
3687181254a7Smrg char p[MAX_READ];
3688181254a7Smrg
3689181254a7Smrg dtp->u.p.current_unit->bytes_left_subrecord += bytes;
3690181254a7Smrg if (dtp->u.p.current_unit->bytes_left_subrecord == 0)
3691181254a7Smrg return;
3692181254a7Smrg
3693181254a7Smrg /* Direct access files do not generate END conditions,
3694181254a7Smrg only I/O errors. */
3695181254a7Smrg if (sseek (dtp->u.p.current_unit->s,
3696181254a7Smrg dtp->u.p.current_unit->bytes_left_subrecord, SEEK_CUR) < 0)
3697181254a7Smrg {
3698181254a7Smrg /* Seeking failed, fall back to seeking by reading data. */
3699181254a7Smrg while (dtp->u.p.current_unit->bytes_left_subrecord > 0)
3700181254a7Smrg {
3701181254a7Smrg rlength =
3702181254a7Smrg (MAX_READ < dtp->u.p.current_unit->bytes_left_subrecord) ?
3703181254a7Smrg MAX_READ : dtp->u.p.current_unit->bytes_left_subrecord;
3704181254a7Smrg
3705181254a7Smrg readb = sread (dtp->u.p.current_unit->s, p, rlength);
3706181254a7Smrg if (readb < 0)
3707181254a7Smrg {
3708181254a7Smrg generate_error (&dtp->common, LIBERROR_OS, NULL);
3709181254a7Smrg return;
3710181254a7Smrg }
3711181254a7Smrg
3712181254a7Smrg dtp->u.p.current_unit->bytes_left_subrecord -= readb;
3713181254a7Smrg }
3714181254a7Smrg return;
3715181254a7Smrg }
3716181254a7Smrg dtp->u.p.current_unit->bytes_left_subrecord = 0;
3717181254a7Smrg }
3718181254a7Smrg
3719181254a7Smrg
3720181254a7Smrg /* Advance to the next record reading unformatted files, taking
3721181254a7Smrg care of subrecords. If complete_record is nonzero, we loop
3722181254a7Smrg until all subrecords are cleared. */
3723181254a7Smrg
3724181254a7Smrg static void
next_record_r_unf(st_parameter_dt * dtp,int complete_record)3725181254a7Smrg next_record_r_unf (st_parameter_dt *dtp, int complete_record)
3726181254a7Smrg {
3727181254a7Smrg size_t bytes;
3728181254a7Smrg
3729181254a7Smrg bytes = compile_options.record_marker == 0 ?
3730181254a7Smrg sizeof (GFC_INTEGER_4) : compile_options.record_marker;
3731181254a7Smrg
3732181254a7Smrg while(1)
3733181254a7Smrg {
3734181254a7Smrg
3735181254a7Smrg /* Skip over tail */
3736181254a7Smrg
3737181254a7Smrg skip_record (dtp, bytes);
3738181254a7Smrg
3739181254a7Smrg if ( ! (complete_record && dtp->u.p.current_unit->continued))
3740181254a7Smrg return;
3741181254a7Smrg
3742181254a7Smrg us_read (dtp, 1);
3743181254a7Smrg }
3744181254a7Smrg }
3745181254a7Smrg
3746181254a7Smrg
3747181254a7Smrg static gfc_offset
min_off(gfc_offset a,gfc_offset b)3748181254a7Smrg min_off (gfc_offset a, gfc_offset b)
3749181254a7Smrg {
3750181254a7Smrg return (a < b ? a : b);
3751181254a7Smrg }
3752181254a7Smrg
3753181254a7Smrg
3754181254a7Smrg /* Space to the next record for read mode. */
3755181254a7Smrg
3756181254a7Smrg static void
next_record_r(st_parameter_dt * dtp,int done)3757181254a7Smrg next_record_r (st_parameter_dt *dtp, int done)
3758181254a7Smrg {
3759181254a7Smrg gfc_offset record;
3760181254a7Smrg char p;
3761181254a7Smrg int cc;
3762181254a7Smrg
3763181254a7Smrg switch (current_mode (dtp))
3764181254a7Smrg {
3765181254a7Smrg /* No records in unformatted STREAM I/O. */
3766181254a7Smrg case UNFORMATTED_STREAM:
3767181254a7Smrg return;
3768181254a7Smrg
3769181254a7Smrg case UNFORMATTED_SEQUENTIAL:
3770181254a7Smrg next_record_r_unf (dtp, 1);
3771181254a7Smrg dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
3772181254a7Smrg break;
3773181254a7Smrg
3774181254a7Smrg case FORMATTED_DIRECT:
3775181254a7Smrg case UNFORMATTED_DIRECT:
3776181254a7Smrg skip_record (dtp, dtp->u.p.current_unit->bytes_left);
3777181254a7Smrg break;
3778181254a7Smrg
3779181254a7Smrg case FORMATTED_STREAM:
3780181254a7Smrg case FORMATTED_SEQUENTIAL:
3781181254a7Smrg /* read_sf has already terminated input because of an '\n', or
3782181254a7Smrg we have hit EOF. */
3783181254a7Smrg if (dtp->u.p.sf_seen_eor)
3784181254a7Smrg {
3785181254a7Smrg dtp->u.p.sf_seen_eor = 0;
3786181254a7Smrg break;
3787181254a7Smrg }
3788181254a7Smrg
3789181254a7Smrg if (is_internal_unit (dtp))
3790181254a7Smrg {
3791181254a7Smrg if (is_array_io (dtp))
3792181254a7Smrg {
3793181254a7Smrg int finished;
3794181254a7Smrg
3795181254a7Smrg record = next_array_record (dtp, dtp->u.p.current_unit->ls,
3796181254a7Smrg &finished);
3797181254a7Smrg if (!done && finished)
3798181254a7Smrg hit_eof (dtp);
3799181254a7Smrg
3800181254a7Smrg /* Now seek to this record. */
3801181254a7Smrg record = record * dtp->u.p.current_unit->recl;
3802181254a7Smrg if (sseek (dtp->u.p.current_unit->s, record, SEEK_SET) < 0)
3803181254a7Smrg {
3804181254a7Smrg generate_error (&dtp->common, LIBERROR_INTERNAL_UNIT, NULL);
3805181254a7Smrg break;
3806181254a7Smrg }
3807181254a7Smrg dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
3808181254a7Smrg }
3809181254a7Smrg else
3810181254a7Smrg {
3811181254a7Smrg gfc_offset bytes_left = dtp->u.p.current_unit->bytes_left;
3812181254a7Smrg bytes_left = min_off (bytes_left,
3813181254a7Smrg ssize (dtp->u.p.current_unit->s)
3814181254a7Smrg - stell (dtp->u.p.current_unit->s));
3815181254a7Smrg if (sseek (dtp->u.p.current_unit->s,
3816181254a7Smrg bytes_left, SEEK_CUR) < 0)
3817181254a7Smrg {
3818181254a7Smrg generate_error (&dtp->common, LIBERROR_INTERNAL_UNIT, NULL);
3819181254a7Smrg break;
3820181254a7Smrg }
3821181254a7Smrg dtp->u.p.current_unit->bytes_left
3822181254a7Smrg = dtp->u.p.current_unit->recl;
3823181254a7Smrg }
3824181254a7Smrg break;
3825181254a7Smrg }
3826181254a7Smrg else if (dtp->u.p.current_unit->flags.cc != CC_NONE)
3827181254a7Smrg {
3828181254a7Smrg do
3829181254a7Smrg {
3830181254a7Smrg errno = 0;
3831181254a7Smrg cc = fbuf_getc (dtp->u.p.current_unit);
3832181254a7Smrg if (cc == EOF)
3833181254a7Smrg {
3834181254a7Smrg if (errno != 0)
3835181254a7Smrg generate_error (&dtp->common, LIBERROR_OS, NULL);
3836181254a7Smrg else
3837181254a7Smrg {
3838181254a7Smrg if (is_stream_io (dtp)
3839181254a7Smrg || dtp->u.p.current_unit->pad_status == PAD_NO
3840181254a7Smrg || dtp->u.p.current_unit->bytes_left
3841181254a7Smrg == dtp->u.p.current_unit->recl)
3842181254a7Smrg hit_eof (dtp);
3843181254a7Smrg }
3844181254a7Smrg break;
3845181254a7Smrg }
3846181254a7Smrg
3847181254a7Smrg if (is_stream_io (dtp))
3848181254a7Smrg dtp->u.p.current_unit->strm_pos++;
3849181254a7Smrg
3850181254a7Smrg p = (char) cc;
3851181254a7Smrg }
3852181254a7Smrg while (p != '\n');
3853181254a7Smrg }
3854181254a7Smrg break;
3855fb8a8121Smrg case FORMATTED_UNSPECIFIED:
3856fb8a8121Smrg gcc_unreachable ();
3857181254a7Smrg }
3858181254a7Smrg }
3859181254a7Smrg
3860181254a7Smrg
3861181254a7Smrg /* Small utility function to write a record marker, taking care of
3862181254a7Smrg byte swapping and of choosing the correct size. */
3863181254a7Smrg
3864181254a7Smrg static int
write_us_marker(st_parameter_dt * dtp,const gfc_offset buf)3865181254a7Smrg write_us_marker (st_parameter_dt *dtp, const gfc_offset buf)
3866181254a7Smrg {
3867181254a7Smrg size_t len;
3868181254a7Smrg GFC_INTEGER_4 buf4;
3869181254a7Smrg GFC_INTEGER_8 buf8;
3870181254a7Smrg
3871181254a7Smrg if (compile_options.record_marker == 0)
3872181254a7Smrg len = sizeof (GFC_INTEGER_4);
3873181254a7Smrg else
3874181254a7Smrg len = compile_options.record_marker;
3875181254a7Smrg
3876*b1e83836Smrg int convert = dtp->u.p.current_unit->flags.convert;
3877*b1e83836Smrg #ifdef HAVE_GFC_REAL_17
3878*b1e83836Smrg convert &= ~(GFC_CONVERT_R16_IEEE | GFC_CONVERT_R16_IBM);
3879*b1e83836Smrg #endif
3880181254a7Smrg /* Only GFC_CONVERT_NATIVE and GFC_CONVERT_SWAP are valid here. */
3881*b1e83836Smrg if (likely (convert == GFC_CONVERT_NATIVE))
3882181254a7Smrg {
3883181254a7Smrg switch (len)
3884181254a7Smrg {
3885181254a7Smrg case sizeof (GFC_INTEGER_4):
3886181254a7Smrg buf4 = buf;
3887181254a7Smrg return swrite (dtp->u.p.current_unit->s, &buf4, len);
3888181254a7Smrg break;
3889181254a7Smrg
3890181254a7Smrg case sizeof (GFC_INTEGER_8):
3891181254a7Smrg buf8 = buf;
3892181254a7Smrg return swrite (dtp->u.p.current_unit->s, &buf8, len);
3893181254a7Smrg break;
3894181254a7Smrg
3895181254a7Smrg default:
3896181254a7Smrg runtime_error ("Illegal value for record marker");
3897181254a7Smrg break;
3898181254a7Smrg }
3899181254a7Smrg }
3900181254a7Smrg else
3901181254a7Smrg {
3902181254a7Smrg uint32_t u32;
3903181254a7Smrg uint64_t u64;
3904181254a7Smrg switch (len)
3905181254a7Smrg {
3906181254a7Smrg case sizeof (GFC_INTEGER_4):
3907181254a7Smrg buf4 = buf;
3908181254a7Smrg memcpy (&u32, &buf4, sizeof (u32));
3909181254a7Smrg u32 = __builtin_bswap32 (u32);
3910181254a7Smrg return swrite (dtp->u.p.current_unit->s, &u32, len);
3911181254a7Smrg break;
3912181254a7Smrg
3913181254a7Smrg case sizeof (GFC_INTEGER_8):
3914181254a7Smrg buf8 = buf;
3915181254a7Smrg memcpy (&u64, &buf8, sizeof (u64));
3916181254a7Smrg u64 = __builtin_bswap64 (u64);
3917181254a7Smrg return swrite (dtp->u.p.current_unit->s, &u64, len);
3918181254a7Smrg break;
3919181254a7Smrg
3920181254a7Smrg default:
3921181254a7Smrg runtime_error ("Illegal value for record marker");
3922181254a7Smrg break;
3923181254a7Smrg }
3924181254a7Smrg }
3925181254a7Smrg
3926181254a7Smrg }
3927181254a7Smrg
3928181254a7Smrg /* Position to the next (sub)record in write mode for
3929181254a7Smrg unformatted sequential files. */
3930181254a7Smrg
3931181254a7Smrg static void
next_record_w_unf(st_parameter_dt * dtp,int next_subrecord)3932181254a7Smrg next_record_w_unf (st_parameter_dt *dtp, int next_subrecord)
3933181254a7Smrg {
3934181254a7Smrg gfc_offset m, m_write, record_marker;
3935181254a7Smrg
3936181254a7Smrg /* Bytes written. */
3937181254a7Smrg m = dtp->u.p.current_unit->recl_subrecord
3938181254a7Smrg - dtp->u.p.current_unit->bytes_left_subrecord;
3939181254a7Smrg
3940181254a7Smrg if (compile_options.record_marker == 0)
3941181254a7Smrg record_marker = sizeof (GFC_INTEGER_4);
3942181254a7Smrg else
3943181254a7Smrg record_marker = compile_options.record_marker;
3944181254a7Smrg
3945181254a7Smrg /* Seek to the head and overwrite the bogus length with the real
3946181254a7Smrg length. */
3947181254a7Smrg
3948181254a7Smrg if (unlikely (sseek (dtp->u.p.current_unit->s, - m - record_marker,
3949181254a7Smrg SEEK_CUR) < 0))
3950181254a7Smrg goto io_error;
3951181254a7Smrg
3952181254a7Smrg if (next_subrecord)
3953181254a7Smrg m_write = -m;
3954181254a7Smrg else
3955181254a7Smrg m_write = m;
3956181254a7Smrg
3957181254a7Smrg if (unlikely (write_us_marker (dtp, m_write) < 0))
3958181254a7Smrg goto io_error;
3959181254a7Smrg
3960181254a7Smrg /* Seek past the end of the current record. */
3961181254a7Smrg
3962181254a7Smrg if (unlikely (sseek (dtp->u.p.current_unit->s, m, SEEK_CUR) < 0))
3963181254a7Smrg goto io_error;
3964181254a7Smrg
3965181254a7Smrg /* Write the length tail. If we finish a record containing
3966181254a7Smrg subrecords, we write out the negative length. */
3967181254a7Smrg
3968181254a7Smrg if (dtp->u.p.current_unit->continued)
3969181254a7Smrg m_write = -m;
3970181254a7Smrg else
3971181254a7Smrg m_write = m;
3972181254a7Smrg
3973181254a7Smrg if (unlikely (write_us_marker (dtp, m_write) < 0))
3974181254a7Smrg goto io_error;
3975181254a7Smrg
3976181254a7Smrg return;
3977181254a7Smrg
3978181254a7Smrg io_error:
3979181254a7Smrg generate_error (&dtp->common, LIBERROR_OS, NULL);
3980181254a7Smrg return;
3981181254a7Smrg
3982181254a7Smrg }
3983181254a7Smrg
3984181254a7Smrg
3985181254a7Smrg /* Utility function like memset() but operating on streams. Return
3986181254a7Smrg value is same as for POSIX write(). */
3987181254a7Smrg
3988181254a7Smrg static gfc_offset
sset(stream * s,int c,gfc_offset nbyte)3989181254a7Smrg sset (stream *s, int c, gfc_offset nbyte)
3990181254a7Smrg {
3991181254a7Smrg #define WRITE_CHUNK 256
3992181254a7Smrg char p[WRITE_CHUNK];
3993181254a7Smrg gfc_offset bytes_left;
3994181254a7Smrg ssize_t trans;
3995181254a7Smrg
3996181254a7Smrg if (nbyte < WRITE_CHUNK)
3997181254a7Smrg memset (p, c, nbyte);
3998181254a7Smrg else
3999181254a7Smrg memset (p, c, WRITE_CHUNK);
4000181254a7Smrg
4001181254a7Smrg bytes_left = nbyte;
4002181254a7Smrg while (bytes_left > 0)
4003181254a7Smrg {
4004181254a7Smrg trans = (bytes_left < WRITE_CHUNK) ? bytes_left : WRITE_CHUNK;
4005181254a7Smrg trans = swrite (s, p, trans);
4006181254a7Smrg if (trans <= 0)
4007181254a7Smrg return trans;
4008181254a7Smrg bytes_left -= trans;
4009181254a7Smrg }
4010181254a7Smrg
4011181254a7Smrg return nbyte - bytes_left;
4012181254a7Smrg }
4013181254a7Smrg
4014181254a7Smrg
4015181254a7Smrg /* Finish up a record according to the legacy carriagecontrol type, based
4016181254a7Smrg on the first character in the record. */
4017181254a7Smrg
4018181254a7Smrg static void
next_record_cc(st_parameter_dt * dtp)4019181254a7Smrg next_record_cc (st_parameter_dt *dtp)
4020181254a7Smrg {
4021181254a7Smrg /* Only valid with CARRIAGECONTROL=FORTRAN. */
4022181254a7Smrg if (dtp->u.p.current_unit->flags.cc != CC_FORTRAN)
4023181254a7Smrg return;
4024181254a7Smrg
4025181254a7Smrg fbuf_seek (dtp->u.p.current_unit, 0, SEEK_END);
4026181254a7Smrg if (dtp->u.p.cc.len > 0)
4027181254a7Smrg {
4028181254a7Smrg char *p = fbuf_alloc (dtp->u.p.current_unit, dtp->u.p.cc.len);
4029181254a7Smrg if (!p)
4030181254a7Smrg generate_error (&dtp->common, LIBERROR_OS, NULL);
4031181254a7Smrg
4032181254a7Smrg /* Output CR for the first character with default CC setting. */
4033181254a7Smrg *(p++) = dtp->u.p.cc.u.end;
4034181254a7Smrg if (dtp->u.p.cc.len > 1)
4035181254a7Smrg *p = dtp->u.p.cc.u.end;
4036181254a7Smrg }
4037181254a7Smrg }
4038181254a7Smrg
4039181254a7Smrg /* Position to the next record in write mode. */
4040181254a7Smrg
4041181254a7Smrg static void
next_record_w(st_parameter_dt * dtp,int done)4042181254a7Smrg next_record_w (st_parameter_dt *dtp, int done)
4043181254a7Smrg {
4044181254a7Smrg gfc_offset max_pos_off;
4045181254a7Smrg
4046181254a7Smrg /* Zero counters for X- and T-editing. */
4047181254a7Smrg max_pos_off = dtp->u.p.max_pos;
4048181254a7Smrg dtp->u.p.max_pos = dtp->u.p.skips = dtp->u.p.pending_spaces = 0;
4049181254a7Smrg
4050181254a7Smrg switch (current_mode (dtp))
4051181254a7Smrg {
4052181254a7Smrg /* No records in unformatted STREAM I/O. */
4053181254a7Smrg case UNFORMATTED_STREAM:
4054181254a7Smrg return;
4055181254a7Smrg
4056181254a7Smrg case FORMATTED_DIRECT:
4057181254a7Smrg if (dtp->u.p.current_unit->bytes_left == 0)
4058181254a7Smrg break;
4059181254a7Smrg
4060181254a7Smrg fbuf_seek (dtp->u.p.current_unit, 0, SEEK_END);
4061181254a7Smrg fbuf_flush (dtp->u.p.current_unit, WRITING);
4062181254a7Smrg if (sset (dtp->u.p.current_unit->s, ' ',
4063181254a7Smrg dtp->u.p.current_unit->bytes_left)
4064181254a7Smrg != dtp->u.p.current_unit->bytes_left)
4065181254a7Smrg goto io_error;
4066181254a7Smrg
4067181254a7Smrg break;
4068181254a7Smrg
4069181254a7Smrg case UNFORMATTED_DIRECT:
4070181254a7Smrg if (dtp->u.p.current_unit->bytes_left > 0)
4071181254a7Smrg {
4072181254a7Smrg gfc_offset length = dtp->u.p.current_unit->bytes_left;
4073181254a7Smrg if (sset (dtp->u.p.current_unit->s, 0, length) != length)
4074181254a7Smrg goto io_error;
4075181254a7Smrg }
4076181254a7Smrg break;
4077181254a7Smrg
4078181254a7Smrg case UNFORMATTED_SEQUENTIAL:
4079181254a7Smrg next_record_w_unf (dtp, 0);
4080181254a7Smrg dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
4081181254a7Smrg break;
4082181254a7Smrg
4083181254a7Smrg case FORMATTED_STREAM:
4084181254a7Smrg case FORMATTED_SEQUENTIAL:
4085181254a7Smrg
4086181254a7Smrg if (is_internal_unit (dtp))
4087181254a7Smrg {
4088181254a7Smrg char *p;
4089181254a7Smrg /* Internal unit, so must fit in memory. */
4090181254a7Smrg size_t length, m;
4091181254a7Smrg size_t max_pos = max_pos_off;
4092181254a7Smrg if (is_array_io (dtp))
4093181254a7Smrg {
4094181254a7Smrg int finished;
4095181254a7Smrg
4096181254a7Smrg length = dtp->u.p.current_unit->bytes_left;
4097181254a7Smrg
4098181254a7Smrg /* If the farthest position reached is greater than current
4099181254a7Smrg position, adjust the position and set length to pad out
4100181254a7Smrg whats left. Otherwise just pad whats left.
4101181254a7Smrg (for character array unit) */
4102181254a7Smrg m = dtp->u.p.current_unit->recl
4103181254a7Smrg - dtp->u.p.current_unit->bytes_left;
4104181254a7Smrg if (max_pos > m)
4105181254a7Smrg {
4106181254a7Smrg length = (max_pos - m);
4107181254a7Smrg if (sseek (dtp->u.p.current_unit->s,
4108181254a7Smrg length, SEEK_CUR) < 0)
4109181254a7Smrg {
4110181254a7Smrg generate_error (&dtp->common, LIBERROR_INTERNAL_UNIT, NULL);
4111181254a7Smrg return;
4112181254a7Smrg }
4113181254a7Smrg length = ((size_t) dtp->u.p.current_unit->recl - max_pos);
4114181254a7Smrg }
4115181254a7Smrg
4116181254a7Smrg p = write_block (dtp, length);
4117181254a7Smrg if (p == NULL)
4118181254a7Smrg return;
4119181254a7Smrg
4120181254a7Smrg if (unlikely (is_char4_unit (dtp)))
4121181254a7Smrg {
4122181254a7Smrg gfc_char4_t *p4 = (gfc_char4_t *) p;
4123181254a7Smrg memset4 (p4, ' ', length);
4124181254a7Smrg }
4125181254a7Smrg else
4126181254a7Smrg memset (p, ' ', length);
4127181254a7Smrg
4128181254a7Smrg /* Now that the current record has been padded out,
4129181254a7Smrg determine where the next record in the array is.
4130181254a7Smrg Note that this can return a negative value, so it
4131181254a7Smrg needs to be assigned to a signed value. */
4132181254a7Smrg gfc_offset record = next_array_record
4133181254a7Smrg (dtp, dtp->u.p.current_unit->ls, &finished);
4134181254a7Smrg if (finished)
4135181254a7Smrg dtp->u.p.current_unit->endfile = AT_ENDFILE;
4136181254a7Smrg
4137181254a7Smrg /* Now seek to this record */
4138181254a7Smrg record = record * dtp->u.p.current_unit->recl;
4139181254a7Smrg
4140181254a7Smrg if (sseek (dtp->u.p.current_unit->s, record, SEEK_SET) < 0)
4141181254a7Smrg {
4142181254a7Smrg generate_error (&dtp->common, LIBERROR_INTERNAL_UNIT, NULL);
4143181254a7Smrg return;
4144181254a7Smrg }
4145181254a7Smrg
4146181254a7Smrg dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
4147181254a7Smrg }
4148181254a7Smrg else
4149181254a7Smrg {
4150181254a7Smrg length = 1;
4151181254a7Smrg
4152181254a7Smrg /* If this is the last call to next_record move to the farthest
4153181254a7Smrg position reached and set length to pad out the remainder
4154181254a7Smrg of the record. (for character scaler unit) */
4155181254a7Smrg if (done)
4156181254a7Smrg {
4157181254a7Smrg m = dtp->u.p.current_unit->recl
4158181254a7Smrg - dtp->u.p.current_unit->bytes_left;
4159181254a7Smrg if (max_pos > m)
4160181254a7Smrg {
4161181254a7Smrg length = max_pos - m;
4162181254a7Smrg if (sseek (dtp->u.p.current_unit->s,
4163181254a7Smrg length, SEEK_CUR) < 0)
4164181254a7Smrg {
4165181254a7Smrg generate_error (&dtp->common, LIBERROR_INTERNAL_UNIT, NULL);
4166181254a7Smrg return;
4167181254a7Smrg }
4168181254a7Smrg length = (size_t) dtp->u.p.current_unit->recl
4169181254a7Smrg - max_pos;
4170181254a7Smrg }
4171181254a7Smrg else
4172181254a7Smrg length = dtp->u.p.current_unit->bytes_left;
4173181254a7Smrg }
4174181254a7Smrg if (length > 0)
4175181254a7Smrg {
4176181254a7Smrg p = write_block (dtp, length);
4177181254a7Smrg if (p == NULL)
4178181254a7Smrg return;
4179181254a7Smrg
4180181254a7Smrg if (unlikely (is_char4_unit (dtp)))
4181181254a7Smrg {
4182181254a7Smrg gfc_char4_t *p4 = (gfc_char4_t *) p;
4183181254a7Smrg memset4 (p4, (gfc_char4_t) ' ', length);
4184181254a7Smrg }
4185181254a7Smrg else
4186181254a7Smrg memset (p, ' ', length);
4187181254a7Smrg }
4188181254a7Smrg }
4189181254a7Smrg }
4190*b1e83836Smrg else if (dtp->u.p.seen_dollar == 1)
4191*b1e83836Smrg break;
4192181254a7Smrg /* Handle legacy CARRIAGECONTROL line endings. */
4193181254a7Smrg else if (dtp->u.p.current_unit->flags.cc == CC_FORTRAN)
4194181254a7Smrg next_record_cc (dtp);
4195181254a7Smrg else
4196181254a7Smrg {
4197181254a7Smrg /* Skip newlines for CC=CC_NONE. */
4198181254a7Smrg const int len = (dtp->u.p.current_unit->flags.cc == CC_NONE)
4199181254a7Smrg ? 0
4200181254a7Smrg #ifdef HAVE_CRLF
4201181254a7Smrg : 2;
4202181254a7Smrg #else
4203181254a7Smrg : 1;
4204181254a7Smrg #endif
4205181254a7Smrg fbuf_seek (dtp->u.p.current_unit, 0, SEEK_END);
4206181254a7Smrg if (dtp->u.p.current_unit->flags.cc != CC_NONE)
4207181254a7Smrg {
4208181254a7Smrg char *p = fbuf_alloc (dtp->u.p.current_unit, len);
4209181254a7Smrg if (!p)
4210181254a7Smrg goto io_error;
4211181254a7Smrg #ifdef HAVE_CRLF
4212181254a7Smrg *(p++) = '\r';
4213181254a7Smrg #endif
4214181254a7Smrg *p = '\n';
4215181254a7Smrg }
4216181254a7Smrg if (is_stream_io (dtp))
4217181254a7Smrg {
4218181254a7Smrg dtp->u.p.current_unit->strm_pos += len;
4219181254a7Smrg if (dtp->u.p.current_unit->strm_pos
4220181254a7Smrg < ssize (dtp->u.p.current_unit->s))
4221181254a7Smrg unit_truncate (dtp->u.p.current_unit,
4222181254a7Smrg dtp->u.p.current_unit->strm_pos - 1,
4223181254a7Smrg &dtp->common);
4224181254a7Smrg }
4225181254a7Smrg }
4226181254a7Smrg
4227181254a7Smrg break;
4228fb8a8121Smrg case FORMATTED_UNSPECIFIED:
4229fb8a8121Smrg gcc_unreachable ();
4230181254a7Smrg
4231181254a7Smrg io_error:
4232181254a7Smrg generate_error (&dtp->common, LIBERROR_OS, NULL);
4233181254a7Smrg break;
4234181254a7Smrg }
4235181254a7Smrg }
4236181254a7Smrg
4237181254a7Smrg /* Position to the next record, which means moving to the end of the
4238181254a7Smrg current record. This can happen under several different
4239181254a7Smrg conditions. If the done flag is not set, we get ready to process
4240181254a7Smrg the next record. */
4241181254a7Smrg
4242181254a7Smrg void
next_record(st_parameter_dt * dtp,int done)4243181254a7Smrg next_record (st_parameter_dt *dtp, int done)
4244181254a7Smrg {
4245181254a7Smrg gfc_offset fp; /* File position. */
4246181254a7Smrg
4247181254a7Smrg dtp->u.p.current_unit->read_bad = 0;
4248181254a7Smrg
4249181254a7Smrg if (dtp->u.p.mode == READING)
4250181254a7Smrg next_record_r (dtp, done);
4251181254a7Smrg else
4252181254a7Smrg next_record_w (dtp, done);
4253181254a7Smrg
4254181254a7Smrg fbuf_flush (dtp->u.p.current_unit, dtp->u.p.mode);
4255181254a7Smrg
4256181254a7Smrg if (!is_stream_io (dtp))
4257181254a7Smrg {
4258181254a7Smrg /* Since we have changed the position, set it to unspecified so
4259181254a7Smrg that INQUIRE(POSITION=) knows it needs to look into it. */
4260181254a7Smrg if (done)
4261181254a7Smrg dtp->u.p.current_unit->flags.position = POSITION_UNSPECIFIED;
4262181254a7Smrg
4263181254a7Smrg dtp->u.p.current_unit->current_record = 0;
4264181254a7Smrg if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT)
4265181254a7Smrg {
4266181254a7Smrg fp = stell (dtp->u.p.current_unit->s);
4267181254a7Smrg /* Calculate next record, rounding up partial records. */
4268181254a7Smrg dtp->u.p.current_unit->last_record =
4269181254a7Smrg (fp + dtp->u.p.current_unit->recl) /
4270181254a7Smrg dtp->u.p.current_unit->recl - 1;
4271181254a7Smrg }
4272181254a7Smrg else
4273181254a7Smrg dtp->u.p.current_unit->last_record++;
4274181254a7Smrg }
4275181254a7Smrg
4276181254a7Smrg if (!done)
4277181254a7Smrg pre_position (dtp);
4278181254a7Smrg
4279181254a7Smrg smarkeor (dtp->u.p.current_unit->s);
4280181254a7Smrg }
4281181254a7Smrg
4282181254a7Smrg
4283181254a7Smrg /* Finalize the current data transfer. For a nonadvancing transfer,
4284181254a7Smrg this means advancing to the next record. For internal units close the
4285181254a7Smrg stream associated with the unit. */
4286181254a7Smrg
4287181254a7Smrg static void
finalize_transfer(st_parameter_dt * dtp)4288181254a7Smrg finalize_transfer (st_parameter_dt *dtp)
4289181254a7Smrg {
4290181254a7Smrg GFC_INTEGER_4 cf = dtp->common.flags;
4291181254a7Smrg
4292181254a7Smrg if ((dtp->u.p.ionml != NULL)
4293181254a7Smrg && (cf & IOPARM_DT_HAS_NAMELIST_NAME) != 0)
4294181254a7Smrg {
4295*b1e83836Smrg if (dtp->u.p.current_unit->flags.form == FORM_UNFORMATTED)
4296*b1e83836Smrg {
4297*b1e83836Smrg generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
4298*b1e83836Smrg "Namelist formatting for unit connected "
4299*b1e83836Smrg "with FORM='UNFORMATTED'");
4300*b1e83836Smrg return;
4301*b1e83836Smrg }
4302*b1e83836Smrg
4303181254a7Smrg dtp->u.p.namelist_mode = 1;
4304181254a7Smrg if ((cf & IOPARM_DT_NAMELIST_READ_MODE) != 0)
4305181254a7Smrg namelist_read (dtp);
4306181254a7Smrg else
4307181254a7Smrg namelist_write (dtp);
4308181254a7Smrg }
4309181254a7Smrg
4310181254a7Smrg if ((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0)
4311181254a7Smrg *dtp->size = dtp->u.p.current_unit->size_used;
4312181254a7Smrg
4313181254a7Smrg if (dtp->u.p.eor_condition)
4314181254a7Smrg {
4315181254a7Smrg generate_error (&dtp->common, LIBERROR_EOR, NULL);
4316181254a7Smrg goto done;
4317181254a7Smrg }
4318181254a7Smrg
4319181254a7Smrg if (dtp->u.p.current_unit && (dtp->u.p.current_unit->child_dtio > 0))
4320181254a7Smrg {
4321181254a7Smrg if (cf & IOPARM_DT_HAS_FORMAT)
4322181254a7Smrg {
4323181254a7Smrg free (dtp->u.p.fmt);
4324181254a7Smrg free (dtp->format);
4325181254a7Smrg }
4326181254a7Smrg return;
4327181254a7Smrg }
4328181254a7Smrg
4329181254a7Smrg if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
4330181254a7Smrg {
4331181254a7Smrg if (dtp->u.p.current_unit && current_mode (dtp) == UNFORMATTED_SEQUENTIAL)
4332181254a7Smrg dtp->u.p.current_unit->current_record = 0;
4333181254a7Smrg goto done;
4334181254a7Smrg }
4335181254a7Smrg
4336181254a7Smrg dtp->u.p.transfer = NULL;
4337181254a7Smrg if (dtp->u.p.current_unit == NULL)
4338181254a7Smrg goto done;
4339181254a7Smrg
4340181254a7Smrg if ((cf & IOPARM_DT_LIST_FORMAT) != 0 && dtp->u.p.mode == READING)
4341181254a7Smrg {
4342181254a7Smrg finish_list_read (dtp);
4343181254a7Smrg goto done;
4344181254a7Smrg }
4345181254a7Smrg
4346181254a7Smrg if (dtp->u.p.mode == WRITING)
4347181254a7Smrg dtp->u.p.current_unit->previous_nonadvancing_write
4348181254a7Smrg = dtp->u.p.advance_status == ADVANCE_NO;
4349181254a7Smrg
4350181254a7Smrg if (is_stream_io (dtp))
4351181254a7Smrg {
4352181254a7Smrg if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED
4353181254a7Smrg && dtp->u.p.advance_status != ADVANCE_NO)
4354181254a7Smrg next_record (dtp, 1);
4355181254a7Smrg
4356181254a7Smrg goto done;
4357181254a7Smrg }
4358181254a7Smrg
4359181254a7Smrg dtp->u.p.current_unit->current_record = 0;
4360181254a7Smrg
4361181254a7Smrg if (!is_internal_unit (dtp) && dtp->u.p.seen_dollar)
4362181254a7Smrg {
4363181254a7Smrg fbuf_flush (dtp->u.p.current_unit, dtp->u.p.mode);
4364181254a7Smrg dtp->u.p.seen_dollar = 0;
4365181254a7Smrg goto done;
4366181254a7Smrg }
4367181254a7Smrg
4368181254a7Smrg /* For non-advancing I/O, save the current maximum position for use in the
4369181254a7Smrg next I/O operation if needed. */
4370181254a7Smrg if (dtp->u.p.advance_status == ADVANCE_NO)
4371181254a7Smrg {
4372181254a7Smrg if (dtp->u.p.skips > 0)
4373181254a7Smrg {
4374181254a7Smrg int tmp;
4375181254a7Smrg write_x (dtp, dtp->u.p.skips, dtp->u.p.pending_spaces);
4376181254a7Smrg tmp = (int)(dtp->u.p.current_unit->recl
4377181254a7Smrg - dtp->u.p.current_unit->bytes_left);
4378181254a7Smrg dtp->u.p.max_pos =
4379181254a7Smrg dtp->u.p.max_pos > tmp ? dtp->u.p.max_pos : tmp;
4380181254a7Smrg dtp->u.p.skips = 0;
4381181254a7Smrg }
4382181254a7Smrg int bytes_written = (int) (dtp->u.p.current_unit->recl
4383181254a7Smrg - dtp->u.p.current_unit->bytes_left);
4384181254a7Smrg dtp->u.p.current_unit->saved_pos =
4385181254a7Smrg dtp->u.p.max_pos > 0 ? dtp->u.p.max_pos - bytes_written : 0;
4386181254a7Smrg fbuf_flush (dtp->u.p.current_unit, dtp->u.p.mode);
4387181254a7Smrg goto done;
4388181254a7Smrg }
4389181254a7Smrg else if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED
4390181254a7Smrg && dtp->u.p.mode == WRITING && !is_internal_unit (dtp))
4391181254a7Smrg fbuf_seek (dtp->u.p.current_unit, 0, SEEK_END);
4392181254a7Smrg
4393181254a7Smrg dtp->u.p.current_unit->saved_pos = 0;
4394181254a7Smrg dtp->u.p.current_unit->last_char = EOF - 1;
4395181254a7Smrg next_record (dtp, 1);
4396181254a7Smrg
4397181254a7Smrg done:
4398181254a7Smrg
4399181254a7Smrg if (dtp->u.p.unit_is_internal)
4400181254a7Smrg {
4401181254a7Smrg /* The unit structure may be reused later so clear the
4402181254a7Smrg internal unit kind. */
4403181254a7Smrg dtp->u.p.current_unit->internal_unit_kind = 0;
4404181254a7Smrg
4405181254a7Smrg fbuf_destroy (dtp->u.p.current_unit);
4406181254a7Smrg if (dtp->u.p.current_unit
4407181254a7Smrg && (dtp->u.p.current_unit->child_dtio == 0)
4408181254a7Smrg && dtp->u.p.current_unit->s)
4409181254a7Smrg {
4410181254a7Smrg sclose (dtp->u.p.current_unit->s);
4411181254a7Smrg dtp->u.p.current_unit->s = NULL;
4412181254a7Smrg }
4413181254a7Smrg }
4414181254a7Smrg
4415*b1e83836Smrg #ifdef HAVE_POSIX_2008_LOCALE
4416181254a7Smrg if (dtp->u.p.old_locale != (locale_t) 0)
4417181254a7Smrg {
4418181254a7Smrg uselocale (dtp->u.p.old_locale);
4419181254a7Smrg dtp->u.p.old_locale = (locale_t) 0;
4420181254a7Smrg }
4421181254a7Smrg #else
4422181254a7Smrg __gthread_mutex_lock (&old_locale_lock);
4423181254a7Smrg if (!--old_locale_ctr)
4424181254a7Smrg {
4425181254a7Smrg setlocale (LC_NUMERIC, old_locale);
4426181254a7Smrg old_locale = NULL;
4427181254a7Smrg }
4428181254a7Smrg __gthread_mutex_unlock (&old_locale_lock);
4429181254a7Smrg #endif
4430181254a7Smrg }
4431181254a7Smrg
4432181254a7Smrg /* Transfer function for IOLENGTH. It doesn't actually do any
4433181254a7Smrg data transfer, it just updates the length counter. */
4434181254a7Smrg
4435181254a7Smrg static void
iolength_transfer(st_parameter_dt * dtp,bt type,void * dest,int kind,size_t size,size_t nelems)4436181254a7Smrg iolength_transfer (st_parameter_dt *dtp, bt type __attribute__((unused)),
4437181254a7Smrg void *dest __attribute__ ((unused)),
4438181254a7Smrg int kind __attribute__((unused)),
4439181254a7Smrg size_t size, size_t nelems)
4440181254a7Smrg {
4441181254a7Smrg if ((dtp->common.flags & IOPARM_DT_HAS_IOLENGTH) != 0)
4442181254a7Smrg *dtp->iolength += (GFC_IO_INT) (size * nelems);
4443181254a7Smrg }
4444181254a7Smrg
4445181254a7Smrg
4446181254a7Smrg /* Initialize the IOLENGTH data transfer. This function is in essence
4447181254a7Smrg a very much simplified version of data_transfer_init(), because it
4448181254a7Smrg doesn't have to deal with units at all. */
4449181254a7Smrg
4450181254a7Smrg static void
iolength_transfer_init(st_parameter_dt * dtp)4451181254a7Smrg iolength_transfer_init (st_parameter_dt *dtp)
4452181254a7Smrg {
4453181254a7Smrg if ((dtp->common.flags & IOPARM_DT_HAS_IOLENGTH) != 0)
4454181254a7Smrg *dtp->iolength = 0;
4455181254a7Smrg
4456181254a7Smrg memset (&dtp->u.p, 0, sizeof (dtp->u.p));
4457181254a7Smrg
4458181254a7Smrg /* Set up the subroutine that will handle the transfers. */
4459181254a7Smrg
4460181254a7Smrg dtp->u.p.transfer = iolength_transfer;
4461181254a7Smrg }
4462181254a7Smrg
4463181254a7Smrg
4464181254a7Smrg /* Library entry point for the IOLENGTH form of the INQUIRE
4465181254a7Smrg statement. The IOLENGTH form requires no I/O to be performed, but
4466181254a7Smrg it must still be a runtime library call so that we can determine
4467181254a7Smrg the iolength for dynamic arrays and such. */
4468181254a7Smrg
4469181254a7Smrg extern void st_iolength (st_parameter_dt *);
4470181254a7Smrg export_proto(st_iolength);
4471181254a7Smrg
4472181254a7Smrg void
st_iolength(st_parameter_dt * dtp)4473181254a7Smrg st_iolength (st_parameter_dt *dtp)
4474181254a7Smrg {
4475181254a7Smrg library_start (&dtp->common);
4476181254a7Smrg iolength_transfer_init (dtp);
4477181254a7Smrg }
4478181254a7Smrg
4479181254a7Smrg extern void st_iolength_done (st_parameter_dt *);
4480181254a7Smrg export_proto(st_iolength_done);
4481181254a7Smrg
4482181254a7Smrg void
st_iolength_done(st_parameter_dt * dtp)4483181254a7Smrg st_iolength_done (st_parameter_dt *dtp __attribute__((unused)))
4484181254a7Smrg {
4485181254a7Smrg free_ionml (dtp);
4486181254a7Smrg library_end ();
4487181254a7Smrg }
4488181254a7Smrg
4489181254a7Smrg
4490181254a7Smrg /* The READ statement. */
4491181254a7Smrg
4492181254a7Smrg extern void st_read (st_parameter_dt *);
4493181254a7Smrg export_proto(st_read);
4494181254a7Smrg
4495181254a7Smrg void
st_read(st_parameter_dt * dtp)4496181254a7Smrg st_read (st_parameter_dt *dtp)
4497181254a7Smrg {
4498181254a7Smrg library_start (&dtp->common);
4499181254a7Smrg
4500181254a7Smrg data_transfer_init (dtp, 1);
4501181254a7Smrg }
4502181254a7Smrg
4503181254a7Smrg extern void st_read_done (st_parameter_dt *);
4504181254a7Smrg export_proto(st_read_done);
4505181254a7Smrg
4506181254a7Smrg void
st_read_done_worker(st_parameter_dt * dtp,bool unlock)4507*b1e83836Smrg st_read_done_worker (st_parameter_dt *dtp, bool unlock)
4508181254a7Smrg {
4509*b1e83836Smrg bool free_newunit = false;
4510181254a7Smrg finalize_transfer (dtp);
4511181254a7Smrg
4512181254a7Smrg free_ionml (dtp);
4513181254a7Smrg
4514181254a7Smrg /* If this is a parent READ statement we do not need to retain the
4515181254a7Smrg internal unit structure for child use. */
4516181254a7Smrg if (dtp->u.p.current_unit != NULL
4517181254a7Smrg && dtp->u.p.current_unit->child_dtio == 0)
4518181254a7Smrg {
4519181254a7Smrg if (dtp->u.p.unit_is_internal)
4520181254a7Smrg {
4521181254a7Smrg if ((dtp->common.flags & IOPARM_DT_HAS_UDTIO) == 0)
4522181254a7Smrg {
4523181254a7Smrg free (dtp->u.p.current_unit->filename);
4524181254a7Smrg dtp->u.p.current_unit->filename = NULL;
4525181254a7Smrg if (dtp->u.p.current_unit->ls)
4526181254a7Smrg free (dtp->u.p.current_unit->ls);
4527181254a7Smrg dtp->u.p.current_unit->ls = NULL;
4528181254a7Smrg }
4529*b1e83836Smrg free_newunit = true;
4530181254a7Smrg }
4531181254a7Smrg if (dtp->u.p.unit_is_internal || dtp->u.p.format_not_saved)
4532181254a7Smrg {
4533181254a7Smrg free_format_data (dtp->u.p.fmt);
4534181254a7Smrg free_format (dtp);
4535181254a7Smrg }
4536181254a7Smrg }
4537*b1e83836Smrg if (unlock)
4538*b1e83836Smrg unlock_unit (dtp->u.p.current_unit);
4539*b1e83836Smrg if (free_newunit)
4540*b1e83836Smrg {
4541*b1e83836Smrg /* Avoid inverse lock issues by placing after unlock_unit. */
4542*b1e83836Smrg LOCK (&unit_lock);
4543*b1e83836Smrg newunit_free (dtp->common.unit);
4544*b1e83836Smrg UNLOCK (&unit_lock);
4545*b1e83836Smrg }
4546181254a7Smrg }
4547181254a7Smrg
4548181254a7Smrg void
st_read_done(st_parameter_dt * dtp)4549181254a7Smrg st_read_done (st_parameter_dt *dtp)
4550181254a7Smrg {
4551181254a7Smrg if (dtp->u.p.current_unit)
4552181254a7Smrg {
4553181254a7Smrg if (dtp->u.p.current_unit->au)
4554181254a7Smrg {
4555181254a7Smrg if (dtp->common.flags & IOPARM_DT_HAS_ID)
4556181254a7Smrg *dtp->id = enqueue_done_id (dtp->u.p.current_unit->au, AIO_READ_DONE);
4557181254a7Smrg else
4558181254a7Smrg {
4559181254a7Smrg if (dtp->u.p.async)
4560181254a7Smrg enqueue_done (dtp->u.p.current_unit->au, AIO_READ_DONE);
4561181254a7Smrg }
4562*b1e83836Smrg unlock_unit (dtp->u.p.current_unit);
4563181254a7Smrg }
4564181254a7Smrg else
4565*b1e83836Smrg st_read_done_worker (dtp, true); /* Calls unlock_unit. */
4566181254a7Smrg }
4567181254a7Smrg
4568181254a7Smrg library_end ();
4569181254a7Smrg }
4570181254a7Smrg
4571181254a7Smrg extern void st_write (st_parameter_dt *);
4572181254a7Smrg export_proto (st_write);
4573181254a7Smrg
4574181254a7Smrg void
st_write(st_parameter_dt * dtp)4575181254a7Smrg st_write (st_parameter_dt *dtp)
4576181254a7Smrg {
4577181254a7Smrg library_start (&dtp->common);
4578181254a7Smrg data_transfer_init (dtp, 0);
4579181254a7Smrg }
4580181254a7Smrg
4581181254a7Smrg
4582181254a7Smrg void
st_write_done_worker(st_parameter_dt * dtp,bool unlock)4583*b1e83836Smrg st_write_done_worker (st_parameter_dt *dtp, bool unlock)
4584181254a7Smrg {
4585*b1e83836Smrg bool free_newunit = false;
4586181254a7Smrg finalize_transfer (dtp);
4587181254a7Smrg
4588181254a7Smrg if (dtp->u.p.current_unit != NULL
4589181254a7Smrg && dtp->u.p.current_unit->child_dtio == 0)
4590181254a7Smrg {
4591181254a7Smrg /* Deal with endfile conditions associated with sequential files. */
4592181254a7Smrg if (dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL)
4593181254a7Smrg switch (dtp->u.p.current_unit->endfile)
4594181254a7Smrg {
4595181254a7Smrg case AT_ENDFILE: /* Remain at the endfile record. */
4596181254a7Smrg break;
4597181254a7Smrg
4598181254a7Smrg case AFTER_ENDFILE:
4599181254a7Smrg dtp->u.p.current_unit->endfile = AT_ENDFILE; /* Just at it now. */
4600181254a7Smrg break;
4601181254a7Smrg
4602181254a7Smrg case NO_ENDFILE:
4603181254a7Smrg /* Get rid of whatever is after this record. */
4604181254a7Smrg if (!is_internal_unit (dtp))
4605181254a7Smrg unit_truncate (dtp->u.p.current_unit,
4606181254a7Smrg stell (dtp->u.p.current_unit->s),
4607181254a7Smrg &dtp->common);
4608181254a7Smrg dtp->u.p.current_unit->endfile = AT_ENDFILE;
4609181254a7Smrg break;
4610181254a7Smrg }
4611181254a7Smrg
4612181254a7Smrg free_ionml (dtp);
4613181254a7Smrg
4614181254a7Smrg /* If this is a parent WRITE statement we do not need to retain the
4615181254a7Smrg internal unit structure for child use. */
4616181254a7Smrg if (dtp->u.p.unit_is_internal)
4617181254a7Smrg {
4618181254a7Smrg if ((dtp->common.flags & IOPARM_DT_HAS_UDTIO) == 0)
4619181254a7Smrg {
4620181254a7Smrg free (dtp->u.p.current_unit->filename);
4621181254a7Smrg dtp->u.p.current_unit->filename = NULL;
4622181254a7Smrg if (dtp->u.p.current_unit->ls)
4623181254a7Smrg free (dtp->u.p.current_unit->ls);
4624181254a7Smrg dtp->u.p.current_unit->ls = NULL;
4625181254a7Smrg }
4626*b1e83836Smrg free_newunit = true;
4627181254a7Smrg }
4628181254a7Smrg if (dtp->u.p.unit_is_internal || dtp->u.p.format_not_saved)
4629181254a7Smrg {
4630181254a7Smrg free_format_data (dtp->u.p.fmt);
4631181254a7Smrg free_format (dtp);
4632181254a7Smrg }
4633181254a7Smrg }
4634*b1e83836Smrg if (unlock)
4635*b1e83836Smrg unlock_unit (dtp->u.p.current_unit);
4636*b1e83836Smrg if (free_newunit)
4637*b1e83836Smrg {
4638*b1e83836Smrg /* Avoid inverse lock issues by placing after unlock_unit. */
4639*b1e83836Smrg LOCK (&unit_lock);
4640*b1e83836Smrg newunit_free (dtp->common.unit);
4641*b1e83836Smrg UNLOCK (&unit_lock);
4642*b1e83836Smrg }
4643181254a7Smrg }
4644181254a7Smrg
4645181254a7Smrg extern void st_write_done (st_parameter_dt *);
4646181254a7Smrg export_proto(st_write_done);
4647181254a7Smrg
4648181254a7Smrg void
st_write_done(st_parameter_dt * dtp)4649181254a7Smrg st_write_done (st_parameter_dt *dtp)
4650181254a7Smrg {
4651181254a7Smrg if (dtp->u.p.current_unit)
4652181254a7Smrg {
4653181254a7Smrg if (dtp->u.p.current_unit->au && dtp->u.p.async)
4654181254a7Smrg {
4655181254a7Smrg if (dtp->common.flags & IOPARM_DT_HAS_ID)
4656181254a7Smrg *dtp->id = enqueue_done_id (dtp->u.p.current_unit->au,
4657181254a7Smrg AIO_WRITE_DONE);
4658181254a7Smrg else
4659181254a7Smrg {
4660181254a7Smrg /* We perform synchronous I/O on an asynchronous unit, so no need
4661181254a7Smrg to enqueue AIO_READ_DONE. */
4662181254a7Smrg if (dtp->u.p.async)
4663181254a7Smrg enqueue_done (dtp->u.p.current_unit->au, AIO_WRITE_DONE);
4664181254a7Smrg }
4665*b1e83836Smrg unlock_unit (dtp->u.p.current_unit);
4666181254a7Smrg }
4667181254a7Smrg else
4668*b1e83836Smrg st_write_done_worker (dtp, true); /* Calls unlock_unit. */
4669181254a7Smrg }
4670181254a7Smrg
4671181254a7Smrg library_end ();
4672181254a7Smrg }
4673181254a7Smrg
4674181254a7Smrg /* Wait operation. We need to keep around the do-nothing version
4675181254a7Smrg of st_wait for compatibility with previous versions, which had marked
4676181254a7Smrg the argument as unused (and thus liable to be removed).
4677181254a7Smrg
4678181254a7Smrg TODO: remove at next bump in version number. */
4679181254a7Smrg
4680181254a7Smrg void
st_wait(st_parameter_wait * wtp)4681181254a7Smrg st_wait (st_parameter_wait *wtp __attribute__((unused)))
4682181254a7Smrg {
4683181254a7Smrg return;
4684181254a7Smrg }
4685181254a7Smrg
4686181254a7Smrg void
st_wait_async(st_parameter_wait * wtp)4687181254a7Smrg st_wait_async (st_parameter_wait *wtp)
4688181254a7Smrg {
4689181254a7Smrg gfc_unit *u = find_unit (wtp->common.unit);
4690fb8a8121Smrg if (ASYNC_IO && u && u->au)
4691181254a7Smrg {
4692181254a7Smrg if (wtp->common.flags & IOPARM_WAIT_HAS_ID)
4693181254a7Smrg async_wait_id (&(wtp->common), u->au, *wtp->id);
4694181254a7Smrg else
4695181254a7Smrg async_wait (&(wtp->common), u->au);
4696181254a7Smrg }
4697181254a7Smrg
4698181254a7Smrg unlock_unit (u);
4699181254a7Smrg }
4700181254a7Smrg
4701181254a7Smrg
4702181254a7Smrg /* Receives the scalar information for namelist objects and stores it
4703181254a7Smrg in a linked list of namelist_info types. */
4704181254a7Smrg
4705181254a7Smrg 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)4706181254a7Smrg set_nml_var (st_parameter_dt *dtp, void *var_addr, char *var_name,
4707181254a7Smrg GFC_INTEGER_4 len, gfc_charlen_type string_length,
4708181254a7Smrg dtype_type dtype, void *dtio_sub, void *vtable)
4709181254a7Smrg {
4710181254a7Smrg namelist_info *t1 = NULL;
4711181254a7Smrg namelist_info *nml;
4712181254a7Smrg size_t var_name_len = strlen (var_name);
4713181254a7Smrg
4714181254a7Smrg nml = (namelist_info*) xmalloc (sizeof (namelist_info));
4715181254a7Smrg
4716181254a7Smrg nml->mem_pos = var_addr;
4717181254a7Smrg nml->dtio_sub = dtio_sub;
4718181254a7Smrg nml->vtable = vtable;
4719181254a7Smrg
4720181254a7Smrg nml->var_name = (char*) xmalloc (var_name_len + 1);
4721181254a7Smrg memcpy (nml->var_name, var_name, var_name_len);
4722181254a7Smrg nml->var_name[var_name_len] = '\0';
4723181254a7Smrg
4724181254a7Smrg nml->len = (int) len;
4725181254a7Smrg nml->string_length = (index_type) string_length;
4726181254a7Smrg
4727181254a7Smrg nml->var_rank = (int) (dtype.rank);
4728181254a7Smrg nml->size = (index_type) (dtype.elem_len);
4729181254a7Smrg nml->type = (bt) (dtype.type);
4730181254a7Smrg
4731181254a7Smrg if (nml->var_rank > 0)
4732181254a7Smrg {
4733181254a7Smrg nml->dim = (descriptor_dimension*)
4734181254a7Smrg xmallocarray (nml->var_rank, sizeof (descriptor_dimension));
4735181254a7Smrg nml->ls = (array_loop_spec*)
4736181254a7Smrg xmallocarray (nml->var_rank, sizeof (array_loop_spec));
4737181254a7Smrg }
4738181254a7Smrg else
4739181254a7Smrg {
4740181254a7Smrg nml->dim = NULL;
4741181254a7Smrg nml->ls = NULL;
4742181254a7Smrg }
4743181254a7Smrg
4744181254a7Smrg nml->next = NULL;
4745181254a7Smrg
4746181254a7Smrg if ((dtp->common.flags & IOPARM_DT_IONML_SET) == 0)
4747181254a7Smrg {
4748181254a7Smrg dtp->common.flags |= IOPARM_DT_IONML_SET;
4749181254a7Smrg dtp->u.p.ionml = nml;
4750181254a7Smrg }
4751181254a7Smrg else
4752181254a7Smrg {
4753181254a7Smrg for (t1 = dtp->u.p.ionml; t1->next; t1 = t1->next);
4754181254a7Smrg t1->next = nml;
4755181254a7Smrg }
4756181254a7Smrg }
4757181254a7Smrg
4758181254a7Smrg extern void st_set_nml_var (st_parameter_dt *dtp, void *, char *,
4759181254a7Smrg GFC_INTEGER_4, gfc_charlen_type, dtype_type);
4760181254a7Smrg export_proto(st_set_nml_var);
4761181254a7Smrg
4762181254a7Smrg 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)4763181254a7Smrg st_set_nml_var (st_parameter_dt *dtp, void *var_addr, char *var_name,
4764181254a7Smrg GFC_INTEGER_4 len, gfc_charlen_type string_length,
4765181254a7Smrg dtype_type dtype)
4766181254a7Smrg {
4767181254a7Smrg set_nml_var (dtp, var_addr, var_name, len, string_length,
4768181254a7Smrg dtype, NULL, NULL);
4769181254a7Smrg }
4770181254a7Smrg
4771181254a7Smrg
4772181254a7Smrg /* Essentially the same as previous but carrying the dtio procedure
4773181254a7Smrg and the vtable as additional arguments. */
4774181254a7Smrg extern void st_set_nml_dtio_var (st_parameter_dt *dtp, void *, char *,
4775181254a7Smrg GFC_INTEGER_4, gfc_charlen_type, dtype_type,
4776181254a7Smrg void *, void *);
4777181254a7Smrg export_proto(st_set_nml_dtio_var);
4778181254a7Smrg
4779181254a7Smrg
4780181254a7Smrg 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)4781181254a7Smrg st_set_nml_dtio_var (st_parameter_dt *dtp, void *var_addr, char *var_name,
4782181254a7Smrg GFC_INTEGER_4 len, gfc_charlen_type string_length,
4783181254a7Smrg dtype_type dtype, void *dtio_sub, void *vtable)
4784181254a7Smrg {
4785181254a7Smrg set_nml_var (dtp, var_addr, var_name, len, string_length,
4786181254a7Smrg dtype, dtio_sub, vtable);
4787181254a7Smrg }
4788181254a7Smrg
4789181254a7Smrg /* Store the dimensional information for the namelist object. */
4790181254a7Smrg extern void st_set_nml_var_dim (st_parameter_dt *, GFC_INTEGER_4,
4791181254a7Smrg index_type, index_type,
4792181254a7Smrg index_type);
4793181254a7Smrg export_proto(st_set_nml_var_dim);
4794181254a7Smrg
4795181254a7Smrg void
st_set_nml_var_dim(st_parameter_dt * dtp,GFC_INTEGER_4 n_dim,index_type stride,index_type lbound,index_type ubound)4796181254a7Smrg st_set_nml_var_dim (st_parameter_dt *dtp, GFC_INTEGER_4 n_dim,
4797181254a7Smrg index_type stride, index_type lbound,
4798181254a7Smrg index_type ubound)
4799181254a7Smrg {
4800181254a7Smrg namelist_info *nml;
4801181254a7Smrg int n;
4802181254a7Smrg
4803181254a7Smrg n = (int)n_dim;
4804181254a7Smrg
4805181254a7Smrg for (nml = dtp->u.p.ionml; nml->next; nml = nml->next);
4806181254a7Smrg
4807181254a7Smrg GFC_DIMENSION_SET(nml->dim[n],lbound,ubound,stride);
4808181254a7Smrg }
4809181254a7Smrg
4810181254a7Smrg
4811181254a7Smrg /* Once upon a time, a poor innocent Fortran program was reading a
4812181254a7Smrg file, when suddenly it hit the end-of-file (EOF). Unfortunately
4813181254a7Smrg the OS doesn't tell whether we're at the EOF or whether we already
4814181254a7Smrg went past it. Luckily our hero, libgfortran, keeps track of this.
4815181254a7Smrg Call this function when you detect an EOF condition. See Section
4816181254a7Smrg 9.10.2 in F2003. */
4817181254a7Smrg
4818181254a7Smrg void
hit_eof(st_parameter_dt * dtp)4819181254a7Smrg hit_eof (st_parameter_dt *dtp)
4820181254a7Smrg {
4821181254a7Smrg dtp->u.p.current_unit->flags.position = POSITION_APPEND;
4822181254a7Smrg
4823181254a7Smrg if (dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL)
4824181254a7Smrg switch (dtp->u.p.current_unit->endfile)
4825181254a7Smrg {
4826181254a7Smrg case NO_ENDFILE:
4827181254a7Smrg case AT_ENDFILE:
4828181254a7Smrg generate_error (&dtp->common, LIBERROR_END, NULL);
4829181254a7Smrg if (!is_internal_unit (dtp) && !dtp->u.p.namelist_mode)
4830181254a7Smrg {
4831181254a7Smrg dtp->u.p.current_unit->endfile = AFTER_ENDFILE;
4832181254a7Smrg dtp->u.p.current_unit->current_record = 0;
4833181254a7Smrg }
4834181254a7Smrg else
4835181254a7Smrg dtp->u.p.current_unit->endfile = AT_ENDFILE;
4836181254a7Smrg break;
4837181254a7Smrg
4838181254a7Smrg case AFTER_ENDFILE:
4839181254a7Smrg generate_error (&dtp->common, LIBERROR_ENDFILE, NULL);
4840181254a7Smrg dtp->u.p.current_unit->current_record = 0;
4841181254a7Smrg break;
4842181254a7Smrg }
4843181254a7Smrg else
4844181254a7Smrg {
4845181254a7Smrg /* Non-sequential files don't have an ENDFILE record, so we
4846181254a7Smrg can't be at AFTER_ENDFILE. */
4847181254a7Smrg dtp->u.p.current_unit->endfile = AT_ENDFILE;
4848181254a7Smrg generate_error (&dtp->common, LIBERROR_END, NULL);
4849181254a7Smrg dtp->u.p.current_unit->current_record = 0;
4850181254a7Smrg }
4851181254a7Smrg }
4852