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