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