1*0bfacb9bSmrg /* Copyright (C) 2002-2020 Free Software Foundation, Inc.
2760c2415Smrg    Contributed by Andy Vaught
3760c2415Smrg    Namelist transfer functions contributed by Paul Thomas
4760c2415Smrg    F2003 I/O support contributed by Jerry DeLisle
5760c2415Smrg 
6760c2415Smrg This file is part of the GNU Fortran runtime library (libgfortran).
7760c2415Smrg 
8760c2415Smrg Libgfortran is free software; you can redistribute it and/or modify
9760c2415Smrg it under the terms of the GNU General Public License as published by
10760c2415Smrg the Free Software Foundation; either version 3, or (at your option)
11760c2415Smrg any later version.
12760c2415Smrg 
13760c2415Smrg Libgfortran is distributed in the hope that it will be useful,
14760c2415Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
15760c2415Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16760c2415Smrg GNU General Public License for more details.
17760c2415Smrg 
18760c2415Smrg Under Section 7 of GPL version 3, you are granted additional
19760c2415Smrg permissions described in the GCC Runtime Library Exception, version
20760c2415Smrg 3.1, as published by the Free Software Foundation.
21760c2415Smrg 
22760c2415Smrg You should have received a copy of the GNU General Public License and
23760c2415Smrg a copy of the GCC Runtime Library Exception along with this program;
24760c2415Smrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
25760c2415Smrg <http://www.gnu.org/licenses/>.  */
26760c2415Smrg 
27760c2415Smrg 
28760c2415Smrg /* transfer.c -- Top level handling of data transfer statements.  */
29760c2415Smrg 
30760c2415Smrg #include "io.h"
31760c2415Smrg #include "fbuf.h"
32760c2415Smrg #include "format.h"
33760c2415Smrg #include "unix.h"
34760c2415Smrg #include "async.h"
35760c2415Smrg #include <string.h>
36760c2415Smrg #include <errno.h>
37760c2415Smrg 
38760c2415Smrg 
39760c2415Smrg /* Calling conventions:  Data transfer statements are unlike other
40760c2415Smrg    library calls in that they extend over several calls.
41760c2415Smrg 
42760c2415Smrg    The first call is always a call to st_read() or st_write().  These
43760c2415Smrg    subroutines return no status unless a namelist read or write is
44760c2415Smrg    being done, in which case there is the usual status.  No further
45760c2415Smrg    calls are necessary in this case.
46760c2415Smrg 
47760c2415Smrg    For other sorts of data transfer, there are zero or more data
48760c2415Smrg    transfer statement that depend on the format of the data transfer
49760c2415Smrg    statement. For READ (and for backwards compatibily: for WRITE), one has
50760c2415Smrg 
51760c2415Smrg       transfer_integer
52760c2415Smrg       transfer_logical
53760c2415Smrg       transfer_character
54760c2415Smrg       transfer_character_wide
55760c2415Smrg       transfer_real
56760c2415Smrg       transfer_complex
57760c2415Smrg       transfer_real128
58760c2415Smrg       transfer_complex128
59760c2415Smrg 
60760c2415Smrg     and for WRITE
61760c2415Smrg 
62760c2415Smrg       transfer_integer_write
63760c2415Smrg       transfer_logical_write
64760c2415Smrg       transfer_character_write
65760c2415Smrg       transfer_character_wide_write
66760c2415Smrg       transfer_real_write
67760c2415Smrg       transfer_complex_write
68760c2415Smrg       transfer_real128_write
69760c2415Smrg       transfer_complex128_write
70760c2415Smrg 
71760c2415Smrg     These subroutines do not return status. The *128 functions
72760c2415Smrg     are in the file transfer128.c.
73760c2415Smrg 
74760c2415Smrg     The last call is a call to st_[read|write]_done().  While
75760c2415Smrg     something can easily go wrong with the initial st_read() or
76760c2415Smrg     st_write(), an error inhibits any data from actually being
77760c2415Smrg     transferred.  */
78760c2415Smrg 
79760c2415Smrg extern void transfer_integer (st_parameter_dt *, void *, int);
80760c2415Smrg export_proto(transfer_integer);
81760c2415Smrg 
82760c2415Smrg extern void transfer_integer_write (st_parameter_dt *, void *, int);
83760c2415Smrg export_proto(transfer_integer_write);
84760c2415Smrg 
85760c2415Smrg extern void transfer_real (st_parameter_dt *, void *, int);
86760c2415Smrg export_proto(transfer_real);
87760c2415Smrg 
88760c2415Smrg extern void transfer_real_write (st_parameter_dt *, void *, int);
89760c2415Smrg export_proto(transfer_real_write);
90760c2415Smrg 
91760c2415Smrg extern void transfer_logical (st_parameter_dt *, void *, int);
92760c2415Smrg export_proto(transfer_logical);
93760c2415Smrg 
94760c2415Smrg extern void transfer_logical_write (st_parameter_dt *, void *, int);
95760c2415Smrg export_proto(transfer_logical_write);
96760c2415Smrg 
97760c2415Smrg extern void transfer_character (st_parameter_dt *, void *, gfc_charlen_type);
98760c2415Smrg export_proto(transfer_character);
99760c2415Smrg 
100760c2415Smrg extern void transfer_character_write (st_parameter_dt *, void *, gfc_charlen_type);
101760c2415Smrg export_proto(transfer_character_write);
102760c2415Smrg 
103760c2415Smrg extern void transfer_character_wide (st_parameter_dt *, void *, gfc_charlen_type, int);
104760c2415Smrg export_proto(transfer_character_wide);
105760c2415Smrg 
106760c2415Smrg extern void transfer_character_wide_write (st_parameter_dt *,
107760c2415Smrg 					   void *, gfc_charlen_type, int);
108760c2415Smrg export_proto(transfer_character_wide_write);
109760c2415Smrg 
110760c2415Smrg extern void transfer_complex (st_parameter_dt *, void *, int);
111760c2415Smrg export_proto(transfer_complex);
112760c2415Smrg 
113760c2415Smrg extern void transfer_complex_write (st_parameter_dt *, void *, int);
114760c2415Smrg export_proto(transfer_complex_write);
115760c2415Smrg 
116760c2415Smrg extern void transfer_array (st_parameter_dt *, gfc_array_char *, int,
117760c2415Smrg 			    gfc_charlen_type);
118760c2415Smrg export_proto(transfer_array);
119760c2415Smrg 
120760c2415Smrg extern void transfer_array_write (st_parameter_dt *, gfc_array_char *, int,
121760c2415Smrg 			    gfc_charlen_type);
122760c2415Smrg export_proto(transfer_array_write);
123760c2415Smrg 
124760c2415Smrg /* User defined derived type input/output.  */
125760c2415Smrg extern void
126760c2415Smrg transfer_derived (st_parameter_dt *dtp, void *dtio_source, void *dtio_proc);
127760c2415Smrg export_proto(transfer_derived);
128760c2415Smrg 
129760c2415Smrg extern void
130760c2415Smrg transfer_derived_write (st_parameter_dt *dtp, void *dtio_source, void *dtio_proc);
131760c2415Smrg export_proto(transfer_derived_write);
132760c2415Smrg 
133760c2415Smrg static void us_read (st_parameter_dt *, int);
134760c2415Smrg static void us_write (st_parameter_dt *, int);
135760c2415Smrg static void next_record_r_unf (st_parameter_dt *, int);
136760c2415Smrg static void next_record_w_unf (st_parameter_dt *, int);
137760c2415Smrg 
138760c2415Smrg static const st_option advance_opt[] = {
139760c2415Smrg   {"yes", ADVANCE_YES},
140760c2415Smrg   {"no", ADVANCE_NO},
141760c2415Smrg   {NULL, 0}
142760c2415Smrg };
143760c2415Smrg 
144760c2415Smrg 
145760c2415Smrg static const st_option decimal_opt[] = {
146760c2415Smrg   {"point", DECIMAL_POINT},
147760c2415Smrg   {"comma", DECIMAL_COMMA},
148760c2415Smrg   {NULL, 0}
149760c2415Smrg };
150760c2415Smrg 
151760c2415Smrg static const st_option round_opt[] = {
152760c2415Smrg   {"up", ROUND_UP},
153760c2415Smrg   {"down", ROUND_DOWN},
154760c2415Smrg   {"zero", ROUND_ZERO},
155760c2415Smrg   {"nearest", ROUND_NEAREST},
156760c2415Smrg   {"compatible", ROUND_COMPATIBLE},
157760c2415Smrg   {"processor_defined", ROUND_PROCDEFINED},
158760c2415Smrg   {NULL, 0}
159760c2415Smrg };
160760c2415Smrg 
161760c2415Smrg 
162760c2415Smrg static const st_option sign_opt[] = {
163760c2415Smrg   {"plus", SIGN_SP},
164760c2415Smrg   {"suppress", SIGN_SS},
165760c2415Smrg   {"processor_defined", SIGN_S},
166760c2415Smrg   {NULL, 0}
167760c2415Smrg };
168760c2415Smrg 
169760c2415Smrg static const st_option blank_opt[] = {
170760c2415Smrg   {"null", BLANK_NULL},
171760c2415Smrg   {"zero", BLANK_ZERO},
172760c2415Smrg   {NULL, 0}
173760c2415Smrg };
174760c2415Smrg 
175760c2415Smrg static const st_option delim_opt[] = {
176760c2415Smrg   {"apostrophe", DELIM_APOSTROPHE},
177760c2415Smrg   {"quote", DELIM_QUOTE},
178760c2415Smrg   {"none", DELIM_NONE},
179760c2415Smrg   {NULL, 0}
180760c2415Smrg };
181760c2415Smrg 
182760c2415Smrg static const st_option pad_opt[] = {
183760c2415Smrg   {"yes", PAD_YES},
184760c2415Smrg   {"no", PAD_NO},
185760c2415Smrg   {NULL, 0}
186760c2415Smrg };
187760c2415Smrg 
188760c2415Smrg static const st_option async_opt[] = {
189760c2415Smrg   {"yes", ASYNC_YES},
190760c2415Smrg   {"no", ASYNC_NO},
191760c2415Smrg   {NULL, 0}
192760c2415Smrg };
193760c2415Smrg 
194760c2415Smrg typedef enum
195760c2415Smrg { FORMATTED_SEQUENTIAL, UNFORMATTED_SEQUENTIAL,
196*0bfacb9bSmrg   FORMATTED_DIRECT, UNFORMATTED_DIRECT, FORMATTED_STREAM,
197*0bfacb9bSmrg   UNFORMATTED_STREAM, FORMATTED_UNSPECIFIED
198760c2415Smrg }
199760c2415Smrg file_mode;
200760c2415Smrg 
201760c2415Smrg 
202760c2415Smrg static file_mode
current_mode(st_parameter_dt * dtp)203760c2415Smrg current_mode (st_parameter_dt *dtp)
204760c2415Smrg {
205760c2415Smrg   file_mode m;
206760c2415Smrg 
207*0bfacb9bSmrg   m = FORMATTED_UNSPECIFIED;
208760c2415Smrg 
209760c2415Smrg   if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT)
210760c2415Smrg     {
211760c2415Smrg       m = dtp->u.p.current_unit->flags.form == FORM_FORMATTED ?
212760c2415Smrg 	FORMATTED_DIRECT : UNFORMATTED_DIRECT;
213760c2415Smrg     }
214760c2415Smrg   else if (dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL)
215760c2415Smrg     {
216760c2415Smrg       m = dtp->u.p.current_unit->flags.form == FORM_FORMATTED ?
217760c2415Smrg 	FORMATTED_SEQUENTIAL : UNFORMATTED_SEQUENTIAL;
218760c2415Smrg     }
219760c2415Smrg   else if (dtp->u.p.current_unit->flags.access == ACCESS_STREAM)
220760c2415Smrg     {
221760c2415Smrg       m = dtp->u.p.current_unit->flags.form == FORM_FORMATTED ?
222760c2415Smrg 	FORMATTED_STREAM : UNFORMATTED_STREAM;
223760c2415Smrg     }
224760c2415Smrg 
225760c2415Smrg   return m;
226760c2415Smrg }
227760c2415Smrg 
228760c2415Smrg 
229760c2415Smrg /* Mid level data transfer statements.  */
230760c2415Smrg 
231760c2415Smrg /* Read sequential file - internal unit  */
232760c2415Smrg 
233760c2415Smrg static char *
read_sf_internal(st_parameter_dt * dtp,size_t * length)234760c2415Smrg read_sf_internal (st_parameter_dt *dtp, size_t *length)
235760c2415Smrg {
236760c2415Smrg   static char *empty_string[0];
237760c2415Smrg   char *base = NULL;
238760c2415Smrg   size_t lorig;
239760c2415Smrg 
240760c2415Smrg   /* Zero size array gives internal unit len of 0.  Nothing to read. */
241760c2415Smrg   if (dtp->internal_unit_len == 0
242760c2415Smrg       && dtp->u.p.current_unit->pad_status == PAD_NO)
243760c2415Smrg     hit_eof (dtp);
244760c2415Smrg 
245760c2415Smrg   /* There are some cases with mixed DTIO where we have read a character
246760c2415Smrg      and saved it in the last character buffer, so we need to backup.  */
247760c2415Smrg   if (unlikely (dtp->u.p.current_unit->child_dtio > 0 &&
248760c2415Smrg 		dtp->u.p.current_unit->last_char != EOF - 1))
249760c2415Smrg     {
250760c2415Smrg       dtp->u.p.current_unit->last_char = EOF - 1;
251760c2415Smrg       sseek (dtp->u.p.current_unit->s, -1, SEEK_CUR);
252760c2415Smrg     }
253760c2415Smrg 
254760c2415Smrg   /* To support legacy code we have to scan the input string one byte
255760c2415Smrg      at a time because we don't know where an early comma may be and the
256760c2415Smrg      requested length could go past the end of a comma shortened
257760c2415Smrg      string.  We only do this if -std=legacy was given at compile
258760c2415Smrg      time.  We also do not support this on kind=4 strings.  */
259760c2415Smrg   if (unlikely(compile_options.warn_std == 0)) // the slow legacy way.
260760c2415Smrg     {
261760c2415Smrg       size_t n;
262760c2415Smrg       size_t tmp = 1;
263760c2415Smrg       char *q;
264760c2415Smrg 
265760c2415Smrg       /* If we have seen an eor previously, return a length of 0.  The
266760c2415Smrg 	 caller is responsible for correctly padding the input field.  */
267760c2415Smrg       if (dtp->u.p.sf_seen_eor)
268760c2415Smrg 	{
269760c2415Smrg 	  *length = 0;
270760c2415Smrg 	  /* Just return something that isn't a NULL pointer, otherwise the
271760c2415Smrg 	     caller thinks an error occurred.  */
272760c2415Smrg 	  return (char*) empty_string;
273760c2415Smrg 	}
274760c2415Smrg 
275760c2415Smrg       /* Get the first character of the string to establish the base
276760c2415Smrg 	 address and check for comma or end-of-record condition.  */
277760c2415Smrg       base = mem_alloc_r (dtp->u.p.current_unit->s, &tmp);
278760c2415Smrg       if (tmp == 0)
279760c2415Smrg 	{
280760c2415Smrg 	  dtp->u.p.sf_seen_eor = 1;
281760c2415Smrg 	  *length = 0;
282760c2415Smrg 	  return (char*) empty_string;
283760c2415Smrg 	}
284760c2415Smrg       if (*base == ',')
285760c2415Smrg 	{
286760c2415Smrg 	  dtp->u.p.current_unit->bytes_left--;
287760c2415Smrg 	  *length = 0;
288760c2415Smrg 	  return (char*) empty_string;
289760c2415Smrg 	}
290760c2415Smrg 
291760c2415Smrg       /* Now we scan the rest and deal with either an end-of-file
292760c2415Smrg          condition or a comma, as needed.  */
293760c2415Smrg       for (n = 1; n < *length; n++)
294760c2415Smrg 	{
295760c2415Smrg 	  q = mem_alloc_r (dtp->u.p.current_unit->s, &tmp);
296760c2415Smrg 	  if (tmp == 0)
297760c2415Smrg 	    {
298760c2415Smrg 	      hit_eof (dtp);
299760c2415Smrg 	      return NULL;
300760c2415Smrg 	    }
301760c2415Smrg 	  if (*q == ',')
302760c2415Smrg 	    {
303760c2415Smrg 	      dtp->u.p.current_unit->bytes_left -= n;
304760c2415Smrg 	      *length = n;
305760c2415Smrg 	      break;
306760c2415Smrg 	    }
307760c2415Smrg 	}
308760c2415Smrg     }
309760c2415Smrg   else // the fast way
310760c2415Smrg     {
311760c2415Smrg       lorig = *length;
312760c2415Smrg       if (is_char4_unit(dtp))
313760c2415Smrg 	{
314760c2415Smrg 	  gfc_char4_t *p = (gfc_char4_t *) mem_alloc_r4 (dtp->u.p.current_unit->s,
315760c2415Smrg 			    length);
316760c2415Smrg 	  base = fbuf_alloc (dtp->u.p.current_unit, lorig);
317760c2415Smrg 	  for (size_t i = 0; i < *length; i++, p++)
318760c2415Smrg 	    base[i] = *p > 255 ? '?' : (unsigned char) *p;
319760c2415Smrg 	}
320760c2415Smrg       else
321760c2415Smrg 	base = mem_alloc_r (dtp->u.p.current_unit->s, length);
322760c2415Smrg 
323760c2415Smrg       if (unlikely (lorig > *length))
324760c2415Smrg 	{
325760c2415Smrg 	  hit_eof (dtp);
326760c2415Smrg 	  return NULL;
327760c2415Smrg 	}
328760c2415Smrg     }
329760c2415Smrg 
330760c2415Smrg   dtp->u.p.current_unit->bytes_left -= *length;
331760c2415Smrg 
332760c2415Smrg   if (((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0) ||
333760c2415Smrg       dtp->u.p.current_unit->has_size)
334760c2415Smrg     dtp->u.p.current_unit->size_used += (GFC_IO_INT) *length;
335760c2415Smrg 
336760c2415Smrg   return base;
337760c2415Smrg 
338760c2415Smrg }
339760c2415Smrg 
340760c2415Smrg /* When reading sequential formatted records we have a problem.  We
341760c2415Smrg    don't know how long the line is until we read the trailing newline,
342760c2415Smrg    and we don't want to read too much.  If we read too much, we might
343760c2415Smrg    have to do a physical seek backwards depending on how much data is
344760c2415Smrg    present, and devices like terminals aren't seekable and would cause
345760c2415Smrg    an I/O error.
346760c2415Smrg 
347760c2415Smrg    Given this, the solution is to read a byte at a time, stopping if
348760c2415Smrg    we hit the newline.  For small allocations, we use a static buffer.
349760c2415Smrg    For larger allocations, we are forced to allocate memory on the
350760c2415Smrg    heap.  Hopefully this won't happen very often.  */
351760c2415Smrg 
352760c2415Smrg /* Read sequential file - external unit */
353760c2415Smrg 
354760c2415Smrg static char *
read_sf(st_parameter_dt * dtp,size_t * length)355760c2415Smrg read_sf (st_parameter_dt *dtp, size_t *length)
356760c2415Smrg {
357760c2415Smrg   static char *empty_string[0];
358760c2415Smrg   size_t lorig, n;
359760c2415Smrg   int q, q2;
360760c2415Smrg   int seen_comma;
361760c2415Smrg 
362760c2415Smrg   /* If we have seen an eor previously, return a length of 0.  The
363760c2415Smrg      caller is responsible for correctly padding the input field.  */
364760c2415Smrg   if (dtp->u.p.sf_seen_eor)
365760c2415Smrg     {
366760c2415Smrg       *length = 0;
367760c2415Smrg       /* Just return something that isn't a NULL pointer, otherwise the
368760c2415Smrg          caller thinks an error occurred.  */
369760c2415Smrg       return (char*) empty_string;
370760c2415Smrg     }
371760c2415Smrg 
372760c2415Smrg   /* There are some cases with mixed DTIO where we have read a character
373760c2415Smrg      and saved it in the last character buffer, so we need to backup.  */
374760c2415Smrg   if (unlikely (dtp->u.p.current_unit->child_dtio > 0 &&
375760c2415Smrg 		dtp->u.p.current_unit->last_char != EOF - 1))
376760c2415Smrg     {
377760c2415Smrg       dtp->u.p.current_unit->last_char = EOF - 1;
378760c2415Smrg       fbuf_seek (dtp->u.p.current_unit, -1, SEEK_CUR);
379760c2415Smrg     }
380760c2415Smrg 
381760c2415Smrg   n = seen_comma = 0;
382760c2415Smrg 
383760c2415Smrg   /* Read data into format buffer and scan through it.  */
384760c2415Smrg   lorig = *length;
385760c2415Smrg 
386760c2415Smrg   while (n < *length)
387760c2415Smrg     {
388760c2415Smrg       q = fbuf_getc (dtp->u.p.current_unit);
389760c2415Smrg       if (q == EOF)
390760c2415Smrg 	break;
391760c2415Smrg       else if (dtp->u.p.current_unit->flags.cc != CC_NONE
392760c2415Smrg 	       && (q == '\n' || q == '\r'))
393760c2415Smrg 	{
394760c2415Smrg 	  /* Unexpected end of line. Set the position.  */
395760c2415Smrg 	  dtp->u.p.sf_seen_eor = 1;
396760c2415Smrg 
397760c2415Smrg 	  /* If we see an EOR during non-advancing I/O, we need to skip
398760c2415Smrg 	     the rest of the I/O statement.  Set the corresponding flag.  */
399760c2415Smrg 	  if (dtp->u.p.advance_status == ADVANCE_NO || dtp->u.p.seen_dollar)
400760c2415Smrg 	    dtp->u.p.eor_condition = 1;
401760c2415Smrg 
402760c2415Smrg 	  /* If we encounter a CR, it might be a CRLF.  */
403760c2415Smrg 	  if (q == '\r') /* Probably a CRLF */
404760c2415Smrg 	    {
405760c2415Smrg 	      /* See if there is an LF.  */
406760c2415Smrg 	      q2 = fbuf_getc (dtp->u.p.current_unit);
407760c2415Smrg 	      if (q2 == '\n')
408760c2415Smrg 		dtp->u.p.sf_seen_eor = 2;
409760c2415Smrg 	      else if (q2 != EOF) /* Oops, seek back.  */
410760c2415Smrg 		fbuf_seek (dtp->u.p.current_unit, -1, SEEK_CUR);
411760c2415Smrg 	    }
412760c2415Smrg 
413760c2415Smrg 	  /* Without padding, terminate the I/O statement without assigning
414760c2415Smrg 	     the value.  With padding, the value still needs to be assigned,
415760c2415Smrg 	     so we can just continue with a short read.  */
416760c2415Smrg 	  if (dtp->u.p.current_unit->pad_status == PAD_NO)
417760c2415Smrg 	    {
418760c2415Smrg 	      generate_error (&dtp->common, LIBERROR_EOR, NULL);
419760c2415Smrg 	      return NULL;
420760c2415Smrg 	    }
421760c2415Smrg 
422760c2415Smrg 	  *length = n;
423760c2415Smrg 	  goto done;
424760c2415Smrg 	}
425760c2415Smrg       /*  Short circuit the read if a comma is found during numeric input.
426760c2415Smrg 	  The flag is set to zero during character reads so that commas in
427760c2415Smrg 	  strings are not ignored  */
428760c2415Smrg       else if (q == ',')
429760c2415Smrg 	if (dtp->u.p.sf_read_comma == 1)
430760c2415Smrg 	  {
431760c2415Smrg             seen_comma = 1;
432760c2415Smrg 	    notify_std (&dtp->common, GFC_STD_GNU,
433760c2415Smrg 			"Comma in formatted numeric read.");
434760c2415Smrg 	    break;
435760c2415Smrg 	  }
436760c2415Smrg       n++;
437760c2415Smrg     }
438760c2415Smrg 
439760c2415Smrg   *length = n;
440760c2415Smrg 
441760c2415Smrg   /* A short read implies we hit EOF, unless we hit EOR, a comma, or
442760c2415Smrg      some other stuff. Set the relevant flags.  */
443760c2415Smrg   if (lorig > *length && !dtp->u.p.sf_seen_eor && !seen_comma)
444760c2415Smrg     {
445760c2415Smrg       if (n > 0)
446760c2415Smrg         {
447760c2415Smrg 	  if (dtp->u.p.advance_status == ADVANCE_NO)
448760c2415Smrg 	    {
449760c2415Smrg 	      if (dtp->u.p.current_unit->pad_status == PAD_NO)
450760c2415Smrg 	        {
451760c2415Smrg 		  hit_eof (dtp);
452760c2415Smrg 		  return NULL;
453760c2415Smrg 		}
454760c2415Smrg 	      else
455760c2415Smrg 		dtp->u.p.eor_condition = 1;
456760c2415Smrg 	    }
457760c2415Smrg 	  else
458760c2415Smrg 	    dtp->u.p.at_eof = 1;
459760c2415Smrg 	}
460760c2415Smrg       else if (dtp->u.p.advance_status == ADVANCE_NO
461760c2415Smrg 	       || dtp->u.p.current_unit->pad_status == PAD_NO
462760c2415Smrg 	       || dtp->u.p.current_unit->bytes_left
463760c2415Smrg 		    == dtp->u.p.current_unit->recl)
464760c2415Smrg 	{
465760c2415Smrg 	  hit_eof (dtp);
466760c2415Smrg 	  return NULL;
467760c2415Smrg 	}
468760c2415Smrg     }
469760c2415Smrg 
470760c2415Smrg  done:
471760c2415Smrg 
472760c2415Smrg   dtp->u.p.current_unit->bytes_left -= n;
473760c2415Smrg 
474760c2415Smrg   if (((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0) ||
475760c2415Smrg       dtp->u.p.current_unit->has_size)
476760c2415Smrg     dtp->u.p.current_unit->size_used += (GFC_IO_INT) n;
477760c2415Smrg 
478760c2415Smrg   /* We can't call fbuf_getptr before the loop doing fbuf_getc, because
479760c2415Smrg      fbuf_getc might reallocate the buffer.  So return current pointer
480760c2415Smrg      minus all the advances, which is n plus up to two characters
481760c2415Smrg      of newline or comma.  */
482760c2415Smrg   return fbuf_getptr (dtp->u.p.current_unit)
483760c2415Smrg 	 - n - dtp->u.p.sf_seen_eor - seen_comma;
484760c2415Smrg }
485760c2415Smrg 
486760c2415Smrg 
487760c2415Smrg /* Function for reading the next couple of bytes from the current
488760c2415Smrg    file, advancing the current position. We return NULL on end of record or
489760c2415Smrg    end of file. This function is only for formatted I/O, unformatted uses
490760c2415Smrg    read_block_direct.
491760c2415Smrg 
492760c2415Smrg    If the read is short, then it is because the current record does not
493760c2415Smrg    have enough data to satisfy the read request and the file was
494760c2415Smrg    opened with PAD=YES.  The caller must assume tailing spaces for
495760c2415Smrg    short reads.  */
496760c2415Smrg 
497760c2415Smrg void *
read_block_form(st_parameter_dt * dtp,size_t * nbytes)498760c2415Smrg read_block_form (st_parameter_dt *dtp, size_t *nbytes)
499760c2415Smrg {
500760c2415Smrg   char *source;
501760c2415Smrg   size_t norig;
502760c2415Smrg 
503760c2415Smrg   if (!is_stream_io (dtp))
504760c2415Smrg     {
505760c2415Smrg       if (dtp->u.p.current_unit->bytes_left < (gfc_offset) *nbytes)
506760c2415Smrg 	{
507760c2415Smrg 	  /* For preconnected units with default record length, set bytes left
508760c2415Smrg 	   to unit record length and proceed, otherwise error.  */
509760c2415Smrg 	  if (dtp->u.p.current_unit->unit_number == options.stdin_unit
510760c2415Smrg 	      && dtp->u.p.current_unit->recl == default_recl)
511760c2415Smrg             dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
512760c2415Smrg 	  else
513760c2415Smrg 	    {
514760c2415Smrg 	      if (unlikely (dtp->u.p.current_unit->pad_status == PAD_NO)
515760c2415Smrg 		  && !is_internal_unit (dtp))
516760c2415Smrg 		{
517760c2415Smrg 		  /* Not enough data left.  */
518760c2415Smrg 		  generate_error (&dtp->common, LIBERROR_EOR, NULL);
519760c2415Smrg 		  return NULL;
520760c2415Smrg 		}
521760c2415Smrg 	    }
522760c2415Smrg 
523760c2415Smrg 	  if (is_internal_unit(dtp))
524760c2415Smrg 	    {
525760c2415Smrg 	      if (*nbytes > 0 && dtp->u.p.current_unit->bytes_left == 0)
526760c2415Smrg 	        {
527760c2415Smrg 		  if (dtp->u.p.advance_status == ADVANCE_NO)
528760c2415Smrg 		    {
529760c2415Smrg 		      generate_error (&dtp->common, LIBERROR_EOR, NULL);
530760c2415Smrg 		      return NULL;
531760c2415Smrg 		    }
532760c2415Smrg 		}
533760c2415Smrg 	    }
534760c2415Smrg 	  else
535760c2415Smrg 	    {
536760c2415Smrg 	      if (unlikely (dtp->u.p.current_unit->bytes_left == 0))
537760c2415Smrg 		{
538760c2415Smrg 		  hit_eof (dtp);
539760c2415Smrg 		  return NULL;
540760c2415Smrg 		}
541760c2415Smrg 	    }
542760c2415Smrg 
543760c2415Smrg 	  *nbytes = dtp->u.p.current_unit->bytes_left;
544760c2415Smrg 	}
545760c2415Smrg     }
546760c2415Smrg 
547760c2415Smrg   if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED &&
548760c2415Smrg       (dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL ||
549760c2415Smrg        dtp->u.p.current_unit->flags.access == ACCESS_STREAM))
550760c2415Smrg     {
551760c2415Smrg       if (is_internal_unit (dtp))
552760c2415Smrg 	source = read_sf_internal (dtp, nbytes);
553760c2415Smrg       else
554760c2415Smrg 	source = read_sf (dtp, nbytes);
555760c2415Smrg 
556760c2415Smrg       dtp->u.p.current_unit->strm_pos +=
557760c2415Smrg 	(gfc_offset) (*nbytes + dtp->u.p.sf_seen_eor);
558760c2415Smrg       return source;
559760c2415Smrg     }
560760c2415Smrg 
561760c2415Smrg   /* If we reach here, we can assume it's direct access.  */
562760c2415Smrg 
563760c2415Smrg   dtp->u.p.current_unit->bytes_left -= (gfc_offset) *nbytes;
564760c2415Smrg 
565760c2415Smrg   norig = *nbytes;
566760c2415Smrg   source = fbuf_read (dtp->u.p.current_unit, nbytes);
567760c2415Smrg   fbuf_seek (dtp->u.p.current_unit, *nbytes, SEEK_CUR);
568760c2415Smrg 
569760c2415Smrg   if (((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0) ||
570760c2415Smrg       dtp->u.p.current_unit->has_size)
571760c2415Smrg     dtp->u.p.current_unit->size_used += (GFC_IO_INT) *nbytes;
572760c2415Smrg 
573760c2415Smrg   if (norig != *nbytes)
574760c2415Smrg     {
575760c2415Smrg       /* Short read, this shouldn't happen.  */
576760c2415Smrg       if (dtp->u.p.current_unit->pad_status == PAD_NO)
577760c2415Smrg 	{
578760c2415Smrg 	  generate_error (&dtp->common, LIBERROR_EOR, NULL);
579760c2415Smrg 	  source = NULL;
580760c2415Smrg 	}
581760c2415Smrg     }
582760c2415Smrg 
583760c2415Smrg   dtp->u.p.current_unit->strm_pos += (gfc_offset) *nbytes;
584760c2415Smrg 
585760c2415Smrg   return source;
586760c2415Smrg }
587760c2415Smrg 
588760c2415Smrg 
589760c2415Smrg /* Read a block from a character(kind=4) internal unit, to be transferred into
590760c2415Smrg    a character(kind=4) variable.  Note: Portions of this code borrowed from
591760c2415Smrg    read_sf_internal.  */
592760c2415Smrg void *
read_block_form4(st_parameter_dt * dtp,size_t * nbytes)593760c2415Smrg read_block_form4 (st_parameter_dt *dtp, size_t *nbytes)
594760c2415Smrg {
595760c2415Smrg   static gfc_char4_t *empty_string[0];
596760c2415Smrg   gfc_char4_t *source;
597760c2415Smrg   size_t lorig;
598760c2415Smrg 
599760c2415Smrg   if (dtp->u.p.current_unit->bytes_left < (gfc_offset) *nbytes)
600760c2415Smrg     *nbytes = dtp->u.p.current_unit->bytes_left;
601760c2415Smrg 
602760c2415Smrg   /* Zero size array gives internal unit len of 0.  Nothing to read. */
603760c2415Smrg   if (dtp->internal_unit_len == 0
604760c2415Smrg       && dtp->u.p.current_unit->pad_status == PAD_NO)
605760c2415Smrg     hit_eof (dtp);
606760c2415Smrg 
607760c2415Smrg   /* If we have seen an eor previously, return a length of 0.  The
608760c2415Smrg      caller is responsible for correctly padding the input field.  */
609760c2415Smrg   if (dtp->u.p.sf_seen_eor)
610760c2415Smrg     {
611760c2415Smrg       *nbytes = 0;
612760c2415Smrg       /* Just return something that isn't a NULL pointer, otherwise the
613760c2415Smrg          caller thinks an error occurred.  */
614760c2415Smrg       return empty_string;
615760c2415Smrg     }
616760c2415Smrg 
617760c2415Smrg   lorig = *nbytes;
618760c2415Smrg   source = (gfc_char4_t *) mem_alloc_r4 (dtp->u.p.current_unit->s, nbytes);
619760c2415Smrg 
620760c2415Smrg   if (unlikely (lorig > *nbytes))
621760c2415Smrg     {
622760c2415Smrg       hit_eof (dtp);
623760c2415Smrg       return NULL;
624760c2415Smrg     }
625760c2415Smrg 
626760c2415Smrg   dtp->u.p.current_unit->bytes_left -= *nbytes;
627760c2415Smrg 
628760c2415Smrg   if (((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0) ||
629760c2415Smrg       dtp->u.p.current_unit->has_size)
630760c2415Smrg     dtp->u.p.current_unit->size_used += (GFC_IO_INT) *nbytes;
631760c2415Smrg 
632760c2415Smrg   return source;
633760c2415Smrg }
634760c2415Smrg 
635760c2415Smrg 
636760c2415Smrg /* Reads a block directly into application data space.  This is for
637760c2415Smrg    unformatted files.  */
638760c2415Smrg 
639760c2415Smrg static void
read_block_direct(st_parameter_dt * dtp,void * buf,size_t nbytes)640760c2415Smrg read_block_direct (st_parameter_dt *dtp, void *buf, size_t nbytes)
641760c2415Smrg {
642760c2415Smrg   ssize_t to_read_record;
643760c2415Smrg   ssize_t have_read_record;
644760c2415Smrg   ssize_t to_read_subrecord;
645760c2415Smrg   ssize_t have_read_subrecord;
646760c2415Smrg   int short_record;
647760c2415Smrg 
648760c2415Smrg   if (is_stream_io (dtp))
649760c2415Smrg     {
650760c2415Smrg       have_read_record = sread (dtp->u.p.current_unit->s, buf,
651760c2415Smrg 				nbytes);
652760c2415Smrg       if (unlikely (have_read_record < 0))
653760c2415Smrg 	{
654760c2415Smrg 	  generate_error (&dtp->common, LIBERROR_OS, NULL);
655760c2415Smrg 	  return;
656760c2415Smrg 	}
657760c2415Smrg 
658760c2415Smrg       dtp->u.p.current_unit->strm_pos += (gfc_offset) have_read_record;
659760c2415Smrg 
660760c2415Smrg       if (unlikely ((ssize_t) nbytes != have_read_record))
661760c2415Smrg 	{
662760c2415Smrg 	  /* Short read,  e.g. if we hit EOF.  For stream files,
663760c2415Smrg 	   we have to set the end-of-file condition.  */
664760c2415Smrg           hit_eof (dtp);
665760c2415Smrg 	}
666760c2415Smrg       return;
667760c2415Smrg     }
668760c2415Smrg 
669760c2415Smrg   if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT)
670760c2415Smrg     {
671760c2415Smrg       if (dtp->u.p.current_unit->bytes_left < (gfc_offset) nbytes)
672760c2415Smrg 	{
673760c2415Smrg 	  short_record = 1;
674760c2415Smrg 	  to_read_record = dtp->u.p.current_unit->bytes_left;
675760c2415Smrg 	  nbytes = to_read_record;
676760c2415Smrg 	}
677760c2415Smrg       else
678760c2415Smrg 	{
679760c2415Smrg 	  short_record = 0;
680760c2415Smrg 	  to_read_record = nbytes;
681760c2415Smrg 	}
682760c2415Smrg 
683760c2415Smrg       dtp->u.p.current_unit->bytes_left -= to_read_record;
684760c2415Smrg 
685760c2415Smrg       to_read_record = sread (dtp->u.p.current_unit->s, buf, to_read_record);
686760c2415Smrg       if (unlikely (to_read_record < 0))
687760c2415Smrg 	{
688760c2415Smrg 	  generate_error (&dtp->common, LIBERROR_OS, NULL);
689760c2415Smrg 	  return;
690760c2415Smrg 	}
691760c2415Smrg 
692760c2415Smrg       if (to_read_record != (ssize_t) nbytes)
693760c2415Smrg 	{
694760c2415Smrg 	  /* Short read, e.g. if we hit EOF.  Apparently, we read
695760c2415Smrg 	   more than was written to the last record.  */
696760c2415Smrg 	  return;
697760c2415Smrg 	}
698760c2415Smrg 
699760c2415Smrg       if (unlikely (short_record))
700760c2415Smrg 	{
701760c2415Smrg 	  generate_error (&dtp->common, LIBERROR_SHORT_RECORD, NULL);
702760c2415Smrg 	}
703760c2415Smrg       return;
704760c2415Smrg     }
705760c2415Smrg 
706760c2415Smrg   /* Unformatted sequential.  We loop over the subrecords, reading
707760c2415Smrg      until the request has been fulfilled or the record has run out
708760c2415Smrg      of continuation subrecords.  */
709760c2415Smrg 
710760c2415Smrg   /* Check whether we exceed the total record length.  */
711760c2415Smrg 
712760c2415Smrg   if (dtp->u.p.current_unit->flags.has_recl
713760c2415Smrg       && ((gfc_offset) nbytes > dtp->u.p.current_unit->bytes_left))
714760c2415Smrg     {
715760c2415Smrg       to_read_record = dtp->u.p.current_unit->bytes_left;
716760c2415Smrg       short_record = 1;
717760c2415Smrg     }
718760c2415Smrg   else
719760c2415Smrg     {
720760c2415Smrg       to_read_record = nbytes;
721760c2415Smrg       short_record = 0;
722760c2415Smrg     }
723760c2415Smrg   have_read_record = 0;
724760c2415Smrg 
725760c2415Smrg   while(1)
726760c2415Smrg     {
727760c2415Smrg       if (dtp->u.p.current_unit->bytes_left_subrecord
728760c2415Smrg 	  < (gfc_offset) to_read_record)
729760c2415Smrg 	{
730760c2415Smrg 	  to_read_subrecord = dtp->u.p.current_unit->bytes_left_subrecord;
731760c2415Smrg 	  to_read_record -= to_read_subrecord;
732760c2415Smrg 	}
733760c2415Smrg       else
734760c2415Smrg 	{
735760c2415Smrg 	  to_read_subrecord = to_read_record;
736760c2415Smrg 	  to_read_record = 0;
737760c2415Smrg 	}
738760c2415Smrg 
739760c2415Smrg       dtp->u.p.current_unit->bytes_left_subrecord -= to_read_subrecord;
740760c2415Smrg 
741760c2415Smrg       have_read_subrecord = sread (dtp->u.p.current_unit->s,
742760c2415Smrg 				   buf + have_read_record, to_read_subrecord);
743760c2415Smrg       if (unlikely (have_read_subrecord < 0))
744760c2415Smrg 	{
745760c2415Smrg 	  generate_error (&dtp->common, LIBERROR_OS, NULL);
746760c2415Smrg 	  return;
747760c2415Smrg 	}
748760c2415Smrg 
749760c2415Smrg       have_read_record += have_read_subrecord;
750760c2415Smrg 
751760c2415Smrg       if (unlikely (to_read_subrecord != have_read_subrecord))
752760c2415Smrg 	{
753760c2415Smrg 	  /* Short read, e.g. if we hit EOF.  This means the record
754760c2415Smrg 	     structure has been corrupted, or the trailing record
755760c2415Smrg 	     marker would still be present.  */
756760c2415Smrg 
757760c2415Smrg 	  generate_error (&dtp->common, LIBERROR_CORRUPT_FILE, NULL);
758760c2415Smrg 	  return;
759760c2415Smrg 	}
760760c2415Smrg 
761760c2415Smrg       if (to_read_record > 0)
762760c2415Smrg 	{
763760c2415Smrg 	  if (likely (dtp->u.p.current_unit->continued))
764760c2415Smrg 	    {
765760c2415Smrg 	      next_record_r_unf (dtp, 0);
766760c2415Smrg 	      us_read (dtp, 1);
767760c2415Smrg 	    }
768760c2415Smrg 	  else
769760c2415Smrg 	    {
770760c2415Smrg 	      /* Let's make sure the file position is correctly pre-positioned
771760c2415Smrg 		 for the next read statement.  */
772760c2415Smrg 
773760c2415Smrg 	      dtp->u.p.current_unit->current_record = 0;
774760c2415Smrg 	      next_record_r_unf (dtp, 0);
775760c2415Smrg 	      generate_error (&dtp->common, LIBERROR_SHORT_RECORD, NULL);
776760c2415Smrg 	      return;
777760c2415Smrg 	    }
778760c2415Smrg 	}
779760c2415Smrg       else
780760c2415Smrg 	{
781760c2415Smrg 	  /* Normal exit, the read request has been fulfilled.  */
782760c2415Smrg 	  break;
783760c2415Smrg 	}
784760c2415Smrg     }
785760c2415Smrg 
786760c2415Smrg   dtp->u.p.current_unit->bytes_left -= have_read_record;
787760c2415Smrg   if (unlikely (short_record))
788760c2415Smrg     {
789760c2415Smrg       generate_error (&dtp->common, LIBERROR_SHORT_RECORD, NULL);
790760c2415Smrg       return;
791760c2415Smrg     }
792760c2415Smrg   return;
793760c2415Smrg }
794760c2415Smrg 
795760c2415Smrg 
796760c2415Smrg /* Function for writing a block of bytes to the current file at the
797760c2415Smrg    current position, advancing the file pointer. We are given a length
798760c2415Smrg    and return a pointer to a buffer that the caller must (completely)
799760c2415Smrg    fill in.  Returns NULL on error.  */
800760c2415Smrg 
801760c2415Smrg void *
write_block(st_parameter_dt * dtp,size_t length)802760c2415Smrg write_block (st_parameter_dt *dtp, size_t length)
803760c2415Smrg {
804760c2415Smrg   char *dest;
805760c2415Smrg 
806760c2415Smrg   if (!is_stream_io (dtp))
807760c2415Smrg     {
808760c2415Smrg       if (dtp->u.p.current_unit->bytes_left < (gfc_offset) length)
809760c2415Smrg 	{
810760c2415Smrg 	  /* For preconnected units with default record length, set bytes left
811760c2415Smrg 	     to unit record length and proceed, otherwise error.  */
812760c2415Smrg 	  if (likely ((dtp->u.p.current_unit->unit_number
813760c2415Smrg 		       == options.stdout_unit
814760c2415Smrg 		       || dtp->u.p.current_unit->unit_number
815760c2415Smrg 		       == options.stderr_unit)
816760c2415Smrg 		      && dtp->u.p.current_unit->recl == default_recl))
817760c2415Smrg 	    dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
818760c2415Smrg 	  else
819760c2415Smrg 	    {
820760c2415Smrg 	      generate_error (&dtp->common, LIBERROR_EOR, NULL);
821760c2415Smrg 	      return NULL;
822760c2415Smrg 	    }
823760c2415Smrg 	}
824760c2415Smrg 
825760c2415Smrg       dtp->u.p.current_unit->bytes_left -= (gfc_offset) length;
826760c2415Smrg     }
827760c2415Smrg 
828760c2415Smrg   if (is_internal_unit (dtp))
829760c2415Smrg     {
830760c2415Smrg       if (is_char4_unit(dtp)) /* char4 internel unit.  */
831760c2415Smrg 	{
832760c2415Smrg 	  gfc_char4_t *dest4;
833760c2415Smrg 	  dest4 = mem_alloc_w4 (dtp->u.p.current_unit->s, &length);
834760c2415Smrg 	  if (dest4 == NULL)
835760c2415Smrg 	  {
836760c2415Smrg             generate_error (&dtp->common, LIBERROR_END, NULL);
837760c2415Smrg             return NULL;
838760c2415Smrg 	  }
839760c2415Smrg 	  return dest4;
840760c2415Smrg 	}
841760c2415Smrg       else
842760c2415Smrg 	dest = mem_alloc_w (dtp->u.p.current_unit->s, &length);
843760c2415Smrg 
844760c2415Smrg       if (dest == NULL)
845760c2415Smrg 	{
846760c2415Smrg           generate_error (&dtp->common, LIBERROR_END, NULL);
847760c2415Smrg           return NULL;
848760c2415Smrg 	}
849760c2415Smrg 
850760c2415Smrg       if (unlikely (dtp->u.p.current_unit->endfile == AT_ENDFILE))
851760c2415Smrg 	generate_error (&dtp->common, LIBERROR_END, NULL);
852760c2415Smrg     }
853760c2415Smrg   else
854760c2415Smrg     {
855760c2415Smrg       dest = fbuf_alloc (dtp->u.p.current_unit, length);
856760c2415Smrg       if (dest == NULL)
857760c2415Smrg 	{
858760c2415Smrg 	  generate_error (&dtp->common, LIBERROR_OS, NULL);
859760c2415Smrg 	  return NULL;
860760c2415Smrg 	}
861760c2415Smrg     }
862760c2415Smrg 
863760c2415Smrg   if (((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0) ||
864760c2415Smrg       dtp->u.p.current_unit->has_size)
865760c2415Smrg     dtp->u.p.current_unit->size_used += (GFC_IO_INT) length;
866760c2415Smrg 
867760c2415Smrg   dtp->u.p.current_unit->strm_pos += (gfc_offset) length;
868760c2415Smrg 
869760c2415Smrg   return dest;
870760c2415Smrg }
871760c2415Smrg 
872760c2415Smrg 
873760c2415Smrg /* High level interface to swrite(), taking care of errors.  This is only
874760c2415Smrg    called for unformatted files.  There are three cases to consider:
875760c2415Smrg    Stream I/O, unformatted direct, unformatted sequential.  */
876760c2415Smrg 
877760c2415Smrg static bool
write_buf(st_parameter_dt * dtp,void * buf,size_t nbytes)878760c2415Smrg write_buf (st_parameter_dt *dtp, void *buf, size_t nbytes)
879760c2415Smrg {
880760c2415Smrg 
881760c2415Smrg   ssize_t have_written;
882760c2415Smrg   ssize_t to_write_subrecord;
883760c2415Smrg   int short_record;
884760c2415Smrg 
885760c2415Smrg   /* Stream I/O.  */
886760c2415Smrg 
887760c2415Smrg   if (is_stream_io (dtp))
888760c2415Smrg     {
889760c2415Smrg       have_written = swrite (dtp->u.p.current_unit->s, buf, nbytes);
890760c2415Smrg       if (unlikely (have_written < 0))
891760c2415Smrg 	{
892760c2415Smrg 	  generate_error (&dtp->common, LIBERROR_OS, NULL);
893760c2415Smrg 	  return false;
894760c2415Smrg 	}
895760c2415Smrg 
896760c2415Smrg       dtp->u.p.current_unit->strm_pos += (gfc_offset) have_written;
897760c2415Smrg 
898760c2415Smrg       return true;
899760c2415Smrg     }
900760c2415Smrg 
901760c2415Smrg   /* Unformatted direct access.  */
902760c2415Smrg 
903760c2415Smrg   if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT)
904760c2415Smrg     {
905760c2415Smrg       if (unlikely (dtp->u.p.current_unit->bytes_left < (gfc_offset) nbytes))
906760c2415Smrg 	{
907760c2415Smrg 	  generate_error (&dtp->common, LIBERROR_DIRECT_EOR, NULL);
908760c2415Smrg 	  return false;
909760c2415Smrg 	}
910760c2415Smrg 
911760c2415Smrg       if (buf == NULL && nbytes == 0)
912760c2415Smrg 	return true;
913760c2415Smrg 
914760c2415Smrg       have_written = swrite (dtp->u.p.current_unit->s, buf, nbytes);
915760c2415Smrg       if (unlikely (have_written < 0))
916760c2415Smrg 	{
917760c2415Smrg 	  generate_error (&dtp->common, LIBERROR_OS, NULL);
918760c2415Smrg 	  return false;
919760c2415Smrg 	}
920760c2415Smrg 
921760c2415Smrg       dtp->u.p.current_unit->strm_pos += (gfc_offset) have_written;
922760c2415Smrg       dtp->u.p.current_unit->bytes_left -= (gfc_offset) have_written;
923760c2415Smrg 
924760c2415Smrg       return true;
925760c2415Smrg     }
926760c2415Smrg 
927760c2415Smrg   /* Unformatted sequential.  */
928760c2415Smrg 
929760c2415Smrg   have_written = 0;
930760c2415Smrg 
931760c2415Smrg   if (dtp->u.p.current_unit->flags.has_recl
932760c2415Smrg       && (gfc_offset) nbytes > dtp->u.p.current_unit->bytes_left)
933760c2415Smrg     {
934760c2415Smrg       nbytes = dtp->u.p.current_unit->bytes_left;
935760c2415Smrg       short_record = 1;
936760c2415Smrg     }
937760c2415Smrg   else
938760c2415Smrg     {
939760c2415Smrg       short_record = 0;
940760c2415Smrg     }
941760c2415Smrg 
942760c2415Smrg   while (1)
943760c2415Smrg     {
944760c2415Smrg 
945760c2415Smrg       to_write_subrecord =
946760c2415Smrg 	(size_t) dtp->u.p.current_unit->bytes_left_subrecord < nbytes ?
947760c2415Smrg 	(size_t) dtp->u.p.current_unit->bytes_left_subrecord : nbytes;
948760c2415Smrg 
949760c2415Smrg       dtp->u.p.current_unit->bytes_left_subrecord -=
950760c2415Smrg 	(gfc_offset) to_write_subrecord;
951760c2415Smrg 
952760c2415Smrg       to_write_subrecord = swrite (dtp->u.p.current_unit->s,
953760c2415Smrg 				   buf + have_written, to_write_subrecord);
954760c2415Smrg       if (unlikely (to_write_subrecord < 0))
955760c2415Smrg 	{
956760c2415Smrg 	  generate_error (&dtp->common, LIBERROR_OS, NULL);
957760c2415Smrg 	  return false;
958760c2415Smrg 	}
959760c2415Smrg 
960760c2415Smrg       dtp->u.p.current_unit->strm_pos += (gfc_offset) to_write_subrecord;
961760c2415Smrg       nbytes -= to_write_subrecord;
962760c2415Smrg       have_written += to_write_subrecord;
963760c2415Smrg 
964760c2415Smrg       if (nbytes == 0)
965760c2415Smrg 	break;
966760c2415Smrg 
967760c2415Smrg       next_record_w_unf (dtp, 1);
968760c2415Smrg       us_write (dtp, 1);
969760c2415Smrg     }
970760c2415Smrg   dtp->u.p.current_unit->bytes_left -= have_written;
971760c2415Smrg   if (unlikely (short_record))
972760c2415Smrg     {
973760c2415Smrg       generate_error (&dtp->common, LIBERROR_SHORT_RECORD, NULL);
974760c2415Smrg       return false;
975760c2415Smrg     }
976760c2415Smrg   return true;
977760c2415Smrg }
978760c2415Smrg 
979760c2415Smrg 
980760c2415Smrg /* Reverse memcpy - used for byte swapping.  */
981760c2415Smrg 
982760c2415Smrg static void
reverse_memcpy(void * dest,const void * src,size_t n)983760c2415Smrg reverse_memcpy (void *dest, const void *src, size_t n)
984760c2415Smrg {
985760c2415Smrg   char *d, *s;
986760c2415Smrg   size_t i;
987760c2415Smrg 
988760c2415Smrg   d = (char *) dest;
989760c2415Smrg   s = (char *) src + n - 1;
990760c2415Smrg 
991760c2415Smrg   /* Write with ascending order - this is likely faster
992760c2415Smrg      on modern architectures because of write combining.  */
993760c2415Smrg   for (i=0; i<n; i++)
994760c2415Smrg       *(d++) = *(s--);
995760c2415Smrg }
996760c2415Smrg 
997760c2415Smrg 
998760c2415Smrg /* Utility function for byteswapping an array, using the bswap
999760c2415Smrg    builtins if possible. dest and src can overlap completely, or then
1000760c2415Smrg    they must point to separate objects; partial overlaps are not
1001760c2415Smrg    allowed.  */
1002760c2415Smrg 
1003760c2415Smrg static void
bswap_array(void * dest,const void * src,size_t size,size_t nelems)1004760c2415Smrg bswap_array (void *dest, const void *src, size_t size, size_t nelems)
1005760c2415Smrg {
1006760c2415Smrg   const char *ps;
1007760c2415Smrg   char *pd;
1008760c2415Smrg 
1009760c2415Smrg   switch (size)
1010760c2415Smrg     {
1011760c2415Smrg     case 1:
1012760c2415Smrg       break;
1013760c2415Smrg     case 2:
1014760c2415Smrg       for (size_t i = 0; i < nelems; i++)
1015760c2415Smrg 	((uint16_t*)dest)[i] = __builtin_bswap16 (((uint16_t*)src)[i]);
1016760c2415Smrg       break;
1017760c2415Smrg     case 4:
1018760c2415Smrg       for (size_t i = 0; i < nelems; i++)
1019760c2415Smrg 	((uint32_t*)dest)[i] = __builtin_bswap32 (((uint32_t*)src)[i]);
1020760c2415Smrg       break;
1021760c2415Smrg     case 8:
1022760c2415Smrg       for (size_t i = 0; i < nelems; i++)
1023760c2415Smrg 	((uint64_t*)dest)[i] = __builtin_bswap64 (((uint64_t*)src)[i]);
1024760c2415Smrg       break;
1025760c2415Smrg     case 12:
1026760c2415Smrg       ps = src;
1027760c2415Smrg       pd = dest;
1028760c2415Smrg       for (size_t i = 0; i < nelems; i++)
1029760c2415Smrg 	{
1030760c2415Smrg 	  uint32_t tmp;
1031760c2415Smrg 	  memcpy (&tmp, ps, 4);
1032760c2415Smrg 	  *(uint32_t*)pd = __builtin_bswap32 (*(uint32_t*)(ps + 8));
1033760c2415Smrg 	  *(uint32_t*)(pd + 4) = __builtin_bswap32 (*(uint32_t*)(ps + 4));
1034760c2415Smrg 	  *(uint32_t*)(pd + 8) = __builtin_bswap32 (tmp);
1035760c2415Smrg 	  ps += size;
1036760c2415Smrg 	  pd += size;
1037760c2415Smrg 	}
1038760c2415Smrg       break;
1039760c2415Smrg     case 16:
1040760c2415Smrg       ps = src;
1041760c2415Smrg       pd = dest;
1042760c2415Smrg       for (size_t i = 0; i < nelems; i++)
1043760c2415Smrg 	{
1044760c2415Smrg 	  uint64_t tmp;
1045760c2415Smrg 	  memcpy (&tmp, ps, 8);
1046760c2415Smrg 	  *(uint64_t*)pd = __builtin_bswap64 (*(uint64_t*)(ps + 8));
1047760c2415Smrg 	  *(uint64_t*)(pd + 8) = __builtin_bswap64 (tmp);
1048760c2415Smrg 	  ps += size;
1049760c2415Smrg 	  pd += size;
1050760c2415Smrg 	}
1051760c2415Smrg       break;
1052760c2415Smrg     default:
1053760c2415Smrg       pd = dest;
1054760c2415Smrg       if (dest != src)
1055760c2415Smrg 	{
1056760c2415Smrg 	  ps = src;
1057760c2415Smrg 	  for (size_t i = 0; i < nelems; i++)
1058760c2415Smrg 	    {
1059760c2415Smrg 	      reverse_memcpy (pd, ps, size);
1060760c2415Smrg 	      ps += size;
1061760c2415Smrg 	      pd += size;
1062760c2415Smrg 	    }
1063760c2415Smrg 	}
1064760c2415Smrg       else
1065760c2415Smrg 	{
1066760c2415Smrg 	  /* In-place byte swap.  */
1067760c2415Smrg 	  for (size_t i = 0; i < nelems; i++)
1068760c2415Smrg 	    {
1069760c2415Smrg 	      char tmp, *low = pd, *high = pd + size - 1;
1070760c2415Smrg 	      for (size_t j = 0; j < size/2; j++)
1071760c2415Smrg 		{
1072760c2415Smrg 		  tmp = *low;
1073760c2415Smrg 		  *low = *high;
1074760c2415Smrg 		  *high = tmp;
1075760c2415Smrg 		  low++;
1076760c2415Smrg 		  high--;
1077760c2415Smrg 		}
1078760c2415Smrg 	      pd += size;
1079760c2415Smrg 	    }
1080760c2415Smrg 	}
1081760c2415Smrg     }
1082760c2415Smrg }
1083760c2415Smrg 
1084760c2415Smrg 
1085760c2415Smrg /* Master function for unformatted reads.  */
1086760c2415Smrg 
1087760c2415Smrg static void
unformatted_read(st_parameter_dt * dtp,bt type,void * dest,int kind,size_t size,size_t nelems)1088760c2415Smrg unformatted_read (st_parameter_dt *dtp, bt type,
1089760c2415Smrg 		  void *dest, int kind, size_t size, size_t nelems)
1090760c2415Smrg {
1091760c2415Smrg   if (type == BT_CLASS)
1092760c2415Smrg     {
1093760c2415Smrg 	  int unit = dtp->u.p.current_unit->unit_number;
1094760c2415Smrg 	  char tmp_iomsg[IOMSG_LEN] = "";
1095760c2415Smrg 	  char *child_iomsg;
1096760c2415Smrg 	  gfc_charlen_type child_iomsg_len;
1097760c2415Smrg 	  int noiostat;
1098760c2415Smrg 	  int *child_iostat = NULL;
1099760c2415Smrg 
1100760c2415Smrg 	  /* Set iostat, intent(out).  */
1101760c2415Smrg 	  noiostat = 0;
1102760c2415Smrg 	  child_iostat = (dtp->common.flags & IOPARM_HAS_IOSTAT) ?
1103760c2415Smrg 			  dtp->common.iostat : &noiostat;
1104760c2415Smrg 
1105760c2415Smrg 	  /* Set iomsg, intent(inout).  */
1106760c2415Smrg 	  if (dtp->common.flags & IOPARM_HAS_IOMSG)
1107760c2415Smrg 	    {
1108760c2415Smrg 	      child_iomsg = dtp->common.iomsg;
1109760c2415Smrg 	      child_iomsg_len = dtp->common.iomsg_len;
1110760c2415Smrg 	    }
1111760c2415Smrg 	  else
1112760c2415Smrg 	    {
1113760c2415Smrg 	      child_iomsg = tmp_iomsg;
1114760c2415Smrg 	      child_iomsg_len = IOMSG_LEN;
1115760c2415Smrg 	    }
1116760c2415Smrg 
1117760c2415Smrg 	  /* Call the user defined unformatted READ procedure.  */
1118760c2415Smrg 	  dtp->u.p.current_unit->child_dtio++;
1119760c2415Smrg 	  dtp->u.p.ufdtio_ptr (dest, &unit, child_iostat, child_iomsg,
1120760c2415Smrg 			      child_iomsg_len);
1121760c2415Smrg 	  dtp->u.p.current_unit->child_dtio--;
1122760c2415Smrg 	  return;
1123760c2415Smrg     }
1124760c2415Smrg 
1125760c2415Smrg   if (type == BT_CHARACTER)
1126760c2415Smrg     size *= GFC_SIZE_OF_CHAR_KIND(kind);
1127760c2415Smrg   read_block_direct (dtp, dest, size * nelems);
1128760c2415Smrg 
1129760c2415Smrg   if (unlikely (dtp->u.p.current_unit->flags.convert == GFC_CONVERT_SWAP)
1130760c2415Smrg       && kind != 1)
1131760c2415Smrg     {
1132760c2415Smrg       /* Handle wide chracters.  */
1133760c2415Smrg       if (type == BT_CHARACTER)
1134760c2415Smrg   	{
1135760c2415Smrg   	  nelems *= size;
1136760c2415Smrg   	  size = kind;
1137760c2415Smrg   	}
1138760c2415Smrg 
1139760c2415Smrg       /* Break up complex into its constituent reals.  */
1140760c2415Smrg       else if (type == BT_COMPLEX)
1141760c2415Smrg   	{
1142760c2415Smrg   	  nelems *= 2;
1143760c2415Smrg   	  size /= 2;
1144760c2415Smrg   	}
1145760c2415Smrg       bswap_array (dest, dest, size, nelems);
1146760c2415Smrg     }
1147760c2415Smrg }
1148760c2415Smrg 
1149760c2415Smrg 
1150760c2415Smrg /* Master function for unformatted writes.  NOTE: For kind=10 the size is 16
1151760c2415Smrg    bytes on 64 bit machines.  The unused bytes are not initialized and never
1152760c2415Smrg    used, which can show an error with memory checking analyzers like
1153760c2415Smrg    valgrind.  We us BT_CLASS to denote a User Defined I/O call.  */
1154760c2415Smrg 
1155760c2415Smrg static void
unformatted_write(st_parameter_dt * dtp,bt type,void * source,int kind,size_t size,size_t nelems)1156760c2415Smrg unformatted_write (st_parameter_dt *dtp, bt type,
1157760c2415Smrg 		   void *source, int kind, size_t size, size_t nelems)
1158760c2415Smrg {
1159760c2415Smrg   if (type == BT_CLASS)
1160760c2415Smrg     {
1161760c2415Smrg 	  int unit = dtp->u.p.current_unit->unit_number;
1162760c2415Smrg 	  char tmp_iomsg[IOMSG_LEN] = "";
1163760c2415Smrg 	  char *child_iomsg;
1164760c2415Smrg 	  gfc_charlen_type child_iomsg_len;
1165760c2415Smrg 	  int noiostat;
1166760c2415Smrg 	  int *child_iostat = NULL;
1167760c2415Smrg 
1168760c2415Smrg 	  /* Set iostat, intent(out).  */
1169760c2415Smrg 	  noiostat = 0;
1170760c2415Smrg 	  child_iostat = (dtp->common.flags & IOPARM_HAS_IOSTAT) ?
1171760c2415Smrg 			  dtp->common.iostat : &noiostat;
1172760c2415Smrg 
1173760c2415Smrg 	  /* Set iomsg, intent(inout).  */
1174760c2415Smrg 	  if (dtp->common.flags & IOPARM_HAS_IOMSG)
1175760c2415Smrg 	    {
1176760c2415Smrg 	      child_iomsg = dtp->common.iomsg;
1177760c2415Smrg 	      child_iomsg_len = dtp->common.iomsg_len;
1178760c2415Smrg 	    }
1179760c2415Smrg 	  else
1180760c2415Smrg 	    {
1181760c2415Smrg 	      child_iomsg = tmp_iomsg;
1182760c2415Smrg 	      child_iomsg_len = IOMSG_LEN;
1183760c2415Smrg 	    }
1184760c2415Smrg 
1185760c2415Smrg 	  /* Call the user defined unformatted WRITE procedure.  */
1186760c2415Smrg 	  dtp->u.p.current_unit->child_dtio++;
1187760c2415Smrg 	  dtp->u.p.ufdtio_ptr (source, &unit, child_iostat, child_iomsg,
1188760c2415Smrg 			      child_iomsg_len);
1189760c2415Smrg 	  dtp->u.p.current_unit->child_dtio--;
1190760c2415Smrg 	  return;
1191760c2415Smrg     }
1192760c2415Smrg 
1193760c2415Smrg   if (likely (dtp->u.p.current_unit->flags.convert == GFC_CONVERT_NATIVE)
1194760c2415Smrg       || kind == 1)
1195760c2415Smrg     {
1196760c2415Smrg       size_t stride = type == BT_CHARACTER ?
1197760c2415Smrg 		  size * GFC_SIZE_OF_CHAR_KIND(kind) : size;
1198760c2415Smrg 
1199760c2415Smrg       write_buf (dtp, source, stride * nelems);
1200760c2415Smrg     }
1201760c2415Smrg   else
1202760c2415Smrg     {
1203760c2415Smrg #define BSWAP_BUFSZ 512
1204760c2415Smrg       char buffer[BSWAP_BUFSZ];
1205760c2415Smrg       char *p;
1206760c2415Smrg       size_t nrem;
1207760c2415Smrg 
1208760c2415Smrg       p = source;
1209760c2415Smrg 
1210760c2415Smrg       /* Handle wide chracters.  */
1211760c2415Smrg       if (type == BT_CHARACTER && kind != 1)
1212760c2415Smrg 	{
1213760c2415Smrg 	  nelems *= size;
1214760c2415Smrg 	  size = kind;
1215760c2415Smrg 	}
1216760c2415Smrg 
1217760c2415Smrg       /* Break up complex into its constituent reals.  */
1218760c2415Smrg       if (type == BT_COMPLEX)
1219760c2415Smrg 	{
1220760c2415Smrg 	  nelems *= 2;
1221760c2415Smrg 	  size /= 2;
1222760c2415Smrg 	}
1223760c2415Smrg 
1224760c2415Smrg       /* By now, all complex variables have been split into their
1225760c2415Smrg 	 constituent reals.  */
1226760c2415Smrg 
1227760c2415Smrg       nrem = nelems;
1228760c2415Smrg       do
1229760c2415Smrg 	{
1230760c2415Smrg 	  size_t nc;
1231760c2415Smrg 	  if (size * nrem > BSWAP_BUFSZ)
1232760c2415Smrg 	    nc = BSWAP_BUFSZ / size;
1233760c2415Smrg 	  else
1234760c2415Smrg 	    nc = nrem;
1235760c2415Smrg 
1236760c2415Smrg 	  bswap_array (buffer, p, size, nc);
1237760c2415Smrg 	  write_buf (dtp, buffer, size * nc);
1238760c2415Smrg 	  p += size * nc;
1239760c2415Smrg 	  nrem -= nc;
1240760c2415Smrg 	}
1241760c2415Smrg       while (nrem > 0);
1242760c2415Smrg     }
1243760c2415Smrg }
1244760c2415Smrg 
1245760c2415Smrg 
1246760c2415Smrg /* Return a pointer to the name of a type.  */
1247760c2415Smrg 
1248760c2415Smrg const char *
type_name(bt type)1249760c2415Smrg type_name (bt type)
1250760c2415Smrg {
1251760c2415Smrg   const char *p;
1252760c2415Smrg 
1253760c2415Smrg   switch (type)
1254760c2415Smrg     {
1255760c2415Smrg     case BT_INTEGER:
1256760c2415Smrg       p = "INTEGER";
1257760c2415Smrg       break;
1258760c2415Smrg     case BT_LOGICAL:
1259760c2415Smrg       p = "LOGICAL";
1260760c2415Smrg       break;
1261760c2415Smrg     case BT_CHARACTER:
1262760c2415Smrg       p = "CHARACTER";
1263760c2415Smrg       break;
1264760c2415Smrg     case BT_REAL:
1265760c2415Smrg       p = "REAL";
1266760c2415Smrg       break;
1267760c2415Smrg     case BT_COMPLEX:
1268760c2415Smrg       p = "COMPLEX";
1269760c2415Smrg       break;
1270760c2415Smrg     case BT_CLASS:
1271760c2415Smrg       p = "CLASS or DERIVED";
1272760c2415Smrg       break;
1273760c2415Smrg     default:
1274760c2415Smrg       internal_error (NULL, "type_name(): Bad type");
1275760c2415Smrg     }
1276760c2415Smrg 
1277760c2415Smrg   return p;
1278760c2415Smrg }
1279760c2415Smrg 
1280760c2415Smrg 
1281760c2415Smrg /* Write a constant string to the output.
1282760c2415Smrg    This is complicated because the string can have doubled delimiters
1283760c2415Smrg    in it.  The length in the format node is the true length.  */
1284760c2415Smrg 
1285760c2415Smrg static void
write_constant_string(st_parameter_dt * dtp,const fnode * f)1286760c2415Smrg write_constant_string (st_parameter_dt *dtp, const fnode *f)
1287760c2415Smrg {
1288760c2415Smrg   char c, delimiter, *p, *q;
1289760c2415Smrg   int length;
1290760c2415Smrg 
1291760c2415Smrg   length = f->u.string.length;
1292760c2415Smrg   if (length == 0)
1293760c2415Smrg     return;
1294760c2415Smrg 
1295760c2415Smrg   p = write_block (dtp, length);
1296760c2415Smrg   if (p == NULL)
1297760c2415Smrg     return;
1298760c2415Smrg 
1299760c2415Smrg   q = f->u.string.p;
1300760c2415Smrg   delimiter = q[-1];
1301760c2415Smrg 
1302760c2415Smrg   for (; length > 0; length--)
1303760c2415Smrg     {
1304760c2415Smrg       c = *p++ = *q++;
1305760c2415Smrg       if (c == delimiter && c != 'H' && c != 'h')
1306760c2415Smrg 	q++;			/* Skip the doubled delimiter.  */
1307760c2415Smrg     }
1308760c2415Smrg }
1309760c2415Smrg 
1310760c2415Smrg 
1311760c2415Smrg /* Given actual and expected types in a formatted data transfer, make
1312760c2415Smrg    sure they agree.  If not, an error message is generated.  Returns
1313760c2415Smrg    nonzero if something went wrong.  */
1314760c2415Smrg 
1315760c2415Smrg static int
require_type(st_parameter_dt * dtp,bt expected,bt actual,const fnode * f)1316760c2415Smrg require_type (st_parameter_dt *dtp, bt expected, bt actual, const fnode *f)
1317760c2415Smrg {
1318760c2415Smrg #define BUFLEN 100
1319760c2415Smrg   char buffer[BUFLEN];
1320760c2415Smrg 
1321760c2415Smrg   if (actual == expected)
1322760c2415Smrg     return 0;
1323760c2415Smrg 
1324760c2415Smrg   /* Adjust item_count before emitting error message.  */
1325760c2415Smrg   snprintf (buffer, BUFLEN,
1326760c2415Smrg 	    "Expected %s for item %d in formatted transfer, got %s",
1327760c2415Smrg 	   type_name (expected), dtp->u.p.item_count - 1, type_name (actual));
1328760c2415Smrg 
1329760c2415Smrg   format_error (dtp, f, buffer);
1330760c2415Smrg   return 1;
1331760c2415Smrg }
1332760c2415Smrg 
1333760c2415Smrg 
1334760c2415Smrg /* Check that the dtio procedure required for formatted IO is present.  */
1335760c2415Smrg 
1336760c2415Smrg static int
check_dtio_proc(st_parameter_dt * dtp,const fnode * f)1337760c2415Smrg check_dtio_proc (st_parameter_dt *dtp, const fnode *f)
1338760c2415Smrg {
1339760c2415Smrg   char buffer[BUFLEN];
1340760c2415Smrg 
1341760c2415Smrg   if (dtp->u.p.fdtio_ptr != NULL)
1342760c2415Smrg     return 0;
1343760c2415Smrg 
1344760c2415Smrg   snprintf (buffer, BUFLEN,
1345760c2415Smrg 	    "Missing DTIO procedure or intrinsic type passed for item %d "
1346760c2415Smrg 	    "in formatted transfer",
1347760c2415Smrg 	    dtp->u.p.item_count - 1);
1348760c2415Smrg 
1349760c2415Smrg   format_error (dtp, f, buffer);
1350760c2415Smrg   return 1;
1351760c2415Smrg }
1352760c2415Smrg 
1353760c2415Smrg 
1354760c2415Smrg static int
require_numeric_type(st_parameter_dt * dtp,bt actual,const fnode * f)1355760c2415Smrg require_numeric_type (st_parameter_dt *dtp, bt actual, const fnode *f)
1356760c2415Smrg {
1357760c2415Smrg #define BUFLEN 100
1358760c2415Smrg   char buffer[BUFLEN];
1359760c2415Smrg 
1360760c2415Smrg   if (actual == BT_INTEGER || actual == BT_REAL || actual == BT_COMPLEX)
1361760c2415Smrg     return 0;
1362760c2415Smrg 
1363760c2415Smrg   /* Adjust item_count before emitting error message.  */
1364760c2415Smrg   snprintf (buffer, BUFLEN,
1365760c2415Smrg 	    "Expected numeric type for item %d in formatted transfer, got %s",
1366760c2415Smrg 	    dtp->u.p.item_count - 1, type_name (actual));
1367760c2415Smrg 
1368760c2415Smrg   format_error (dtp, f, buffer);
1369760c2415Smrg   return 1;
1370760c2415Smrg }
1371760c2415Smrg 
1372760c2415Smrg static char *
get_dt_format(char * p,gfc_charlen_type * length)1373760c2415Smrg get_dt_format (char *p, gfc_charlen_type *length)
1374760c2415Smrg {
1375760c2415Smrg   char delim = p[-1];  /* The delimiter is always the first character back.  */
1376760c2415Smrg   char c, *q, *res;
1377760c2415Smrg   gfc_charlen_type len = *length; /* This length already correct, less 'DT'.  */
1378760c2415Smrg 
1379760c2415Smrg   res = q = xmalloc (len + 2);
1380760c2415Smrg 
1381760c2415Smrg   /* Set the beginning of the string to 'DT', length adjusted below.  */
1382760c2415Smrg   *q++ = 'D';
1383760c2415Smrg   *q++ = 'T';
1384760c2415Smrg 
1385760c2415Smrg   /* The string may contain doubled quotes so scan and skip as needed.  */
1386760c2415Smrg   for (; len > 0; len--)
1387760c2415Smrg     {
1388760c2415Smrg       c = *q++ = *p++;
1389760c2415Smrg       if (c == delim)
1390760c2415Smrg 	p++;  /* Skip the doubled delimiter.  */
1391760c2415Smrg     }
1392760c2415Smrg 
1393760c2415Smrg   /* Adjust the string length by two now that we are done.  */
1394760c2415Smrg   *length += 2;
1395760c2415Smrg 
1396760c2415Smrg   return res;
1397760c2415Smrg }
1398760c2415Smrg 
1399760c2415Smrg 
1400760c2415Smrg /* This function is in the main loop for a formatted data transfer
1401760c2415Smrg    statement.  It would be natural to implement this as a coroutine
1402760c2415Smrg    with the user program, but C makes that awkward.  We loop,
1403760c2415Smrg    processing format elements.  When we actually have to transfer
1404760c2415Smrg    data instead of just setting flags, we return control to the user
1405760c2415Smrg    program which calls a function that supplies the address and type
1406760c2415Smrg    of the next element, then comes back here to process it.  */
1407760c2415Smrg 
1408760c2415Smrg static void
formatted_transfer_scalar_read(st_parameter_dt * dtp,bt type,void * p,int kind,size_t size)1409760c2415Smrg formatted_transfer_scalar_read (st_parameter_dt *dtp, bt type, void *p, int kind,
1410760c2415Smrg 				size_t size)
1411760c2415Smrg {
1412760c2415Smrg   int pos, bytes_used;
1413760c2415Smrg   const fnode *f;
1414760c2415Smrg   format_token t;
1415760c2415Smrg   int n;
1416760c2415Smrg   int consume_data_flag;
1417760c2415Smrg 
1418760c2415Smrg   /* Change a complex data item into a pair of reals.  */
1419760c2415Smrg 
1420760c2415Smrg   n = (p == NULL) ? 0 : ((type != BT_COMPLEX) ? 1 : 2);
1421760c2415Smrg   if (type == BT_COMPLEX)
1422760c2415Smrg     {
1423760c2415Smrg       type = BT_REAL;
1424760c2415Smrg       size /= 2;
1425760c2415Smrg     }
1426760c2415Smrg 
1427760c2415Smrg   /* If there's an EOR condition, we simulate finalizing the transfer
1428760c2415Smrg      by doing nothing.  */
1429760c2415Smrg   if (dtp->u.p.eor_condition)
1430760c2415Smrg     return;
1431760c2415Smrg 
1432760c2415Smrg   /* Set this flag so that commas in reads cause the read to complete before
1433760c2415Smrg      the entire field has been read.  The next read field will start right after
1434760c2415Smrg      the comma in the stream.  (Set to 0 for character reads).  */
1435760c2415Smrg   dtp->u.p.sf_read_comma =
1436760c2415Smrg     dtp->u.p.current_unit->decimal_status == DECIMAL_COMMA ? 0 : 1;
1437760c2415Smrg 
1438760c2415Smrg   for (;;)
1439760c2415Smrg     {
1440760c2415Smrg       /* If reversion has occurred and there is another real data item,
1441760c2415Smrg 	 then we have to move to the next record.  */
1442760c2415Smrg       if (dtp->u.p.reversion_flag && n > 0)
1443760c2415Smrg 	{
1444760c2415Smrg 	  dtp->u.p.reversion_flag = 0;
1445760c2415Smrg 	  next_record (dtp, 0);
1446760c2415Smrg 	}
1447760c2415Smrg 
1448760c2415Smrg       consume_data_flag = 1;
1449760c2415Smrg       if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
1450760c2415Smrg 	break;
1451760c2415Smrg 
1452760c2415Smrg       f = next_format (dtp);
1453760c2415Smrg       if (f == NULL)
1454760c2415Smrg 	{
1455760c2415Smrg 	  /* No data descriptors left.  */
1456760c2415Smrg 	  if (unlikely (n > 0))
1457760c2415Smrg 	    generate_error (&dtp->common, LIBERROR_FORMAT,
1458760c2415Smrg 		"Insufficient data descriptors in format after reversion");
1459760c2415Smrg 	  return;
1460760c2415Smrg 	}
1461760c2415Smrg 
1462760c2415Smrg       t = f->format;
1463760c2415Smrg 
1464760c2415Smrg       bytes_used = (int)(dtp->u.p.current_unit->recl
1465760c2415Smrg 		   - dtp->u.p.current_unit->bytes_left);
1466760c2415Smrg 
1467760c2415Smrg       if (is_stream_io(dtp))
1468760c2415Smrg 	bytes_used = 0;
1469760c2415Smrg 
1470760c2415Smrg       switch (t)
1471760c2415Smrg 	{
1472760c2415Smrg 	case FMT_I:
1473760c2415Smrg 	  if (n == 0)
1474760c2415Smrg 	    goto need_read_data;
1475760c2415Smrg 	  if (require_type (dtp, BT_INTEGER, type, f))
1476760c2415Smrg 	    return;
1477760c2415Smrg 	  read_decimal (dtp, f, p, kind);
1478760c2415Smrg 	  break;
1479760c2415Smrg 
1480760c2415Smrg 	case FMT_B:
1481760c2415Smrg 	  if (n == 0)
1482760c2415Smrg 	    goto need_read_data;
1483760c2415Smrg 	  if (!(compile_options.allow_std & GFC_STD_GNU)
1484760c2415Smrg 	      && require_numeric_type (dtp, type, f))
1485760c2415Smrg 	    return;
1486760c2415Smrg 	  if (!(compile_options.allow_std & GFC_STD_F2008)
1487760c2415Smrg               && require_type (dtp, BT_INTEGER, type, f))
1488760c2415Smrg 	    return;
1489760c2415Smrg 	  read_radix (dtp, f, p, kind, 2);
1490760c2415Smrg 	  break;
1491760c2415Smrg 
1492760c2415Smrg 	case FMT_O:
1493760c2415Smrg 	  if (n == 0)
1494760c2415Smrg 	    goto need_read_data;
1495760c2415Smrg 	  if (!(compile_options.allow_std & GFC_STD_GNU)
1496760c2415Smrg 	      && require_numeric_type (dtp, type, f))
1497760c2415Smrg 	    return;
1498760c2415Smrg 	  if (!(compile_options.allow_std & GFC_STD_F2008)
1499760c2415Smrg               && require_type (dtp, BT_INTEGER, type, f))
1500760c2415Smrg 	    return;
1501760c2415Smrg 	  read_radix (dtp, f, p, kind, 8);
1502760c2415Smrg 	  break;
1503760c2415Smrg 
1504760c2415Smrg 	case FMT_Z:
1505760c2415Smrg 	  if (n == 0)
1506760c2415Smrg 	    goto need_read_data;
1507760c2415Smrg 	  if (!(compile_options.allow_std & GFC_STD_GNU)
1508760c2415Smrg 	      && require_numeric_type (dtp, type, f))
1509760c2415Smrg 	    return;
1510760c2415Smrg 	  if (!(compile_options.allow_std & GFC_STD_F2008)
1511760c2415Smrg               && require_type (dtp, BT_INTEGER, type, f))
1512760c2415Smrg 	    return;
1513760c2415Smrg 	  read_radix (dtp, f, p, kind, 16);
1514760c2415Smrg 	  break;
1515760c2415Smrg 
1516760c2415Smrg 	case FMT_A:
1517760c2415Smrg 	  if (n == 0)
1518760c2415Smrg 	    goto need_read_data;
1519760c2415Smrg 
1520760c2415Smrg 	  /* It is possible to have FMT_A with something not BT_CHARACTER such
1521760c2415Smrg 	     as when writing out hollerith strings, so check both type
1522760c2415Smrg 	     and kind before calling wide character routines.  */
1523760c2415Smrg 	  if (type == BT_CHARACTER && kind == 4)
1524760c2415Smrg 	    read_a_char4 (dtp, f, p, size);
1525760c2415Smrg 	  else
1526760c2415Smrg 	    read_a (dtp, f, p, size);
1527760c2415Smrg 	  break;
1528760c2415Smrg 
1529760c2415Smrg 	case FMT_L:
1530760c2415Smrg 	  if (n == 0)
1531760c2415Smrg 	    goto need_read_data;
1532760c2415Smrg 	  read_l (dtp, f, p, kind);
1533760c2415Smrg 	  break;
1534760c2415Smrg 
1535760c2415Smrg 	case FMT_D:
1536760c2415Smrg 	  if (n == 0)
1537760c2415Smrg 	    goto need_read_data;
1538760c2415Smrg 	  if (require_type (dtp, BT_REAL, type, f))
1539760c2415Smrg 	    return;
1540760c2415Smrg 	  read_f (dtp, f, p, kind);
1541760c2415Smrg 	  break;
1542760c2415Smrg 
1543760c2415Smrg 	case FMT_DT:
1544760c2415Smrg 	  if (n == 0)
1545760c2415Smrg 	    goto need_read_data;
1546760c2415Smrg 
1547760c2415Smrg 	  if (check_dtio_proc (dtp, f))
1548760c2415Smrg 	    return;
1549760c2415Smrg 	  if (require_type (dtp, BT_CLASS, type, f))
1550760c2415Smrg 	    return;
1551760c2415Smrg 	  int unit = dtp->u.p.current_unit->unit_number;
1552760c2415Smrg 	  char dt[] = "DT";
1553760c2415Smrg 	  char tmp_iomsg[IOMSG_LEN] = "";
1554760c2415Smrg 	  char *child_iomsg;
1555760c2415Smrg 	  gfc_charlen_type child_iomsg_len;
1556760c2415Smrg 	  int noiostat;
1557760c2415Smrg 	  int *child_iostat = NULL;
1558760c2415Smrg 	  char *iotype;
1559760c2415Smrg 	  gfc_charlen_type iotype_len = f->u.udf.string_len;
1560760c2415Smrg 
1561760c2415Smrg 	  /* Build the iotype string.  */
1562760c2415Smrg 	  if (iotype_len == 0)
1563760c2415Smrg 	    {
1564760c2415Smrg 	      iotype_len = 2;
1565760c2415Smrg 	      iotype = dt;
1566760c2415Smrg 	    }
1567760c2415Smrg 	  else
1568760c2415Smrg 	    iotype = get_dt_format (f->u.udf.string, &iotype_len);
1569760c2415Smrg 
1570760c2415Smrg 	  /* Set iostat, intent(out).  */
1571760c2415Smrg 	  noiostat = 0;
1572760c2415Smrg 	  child_iostat = (dtp->common.flags & IOPARM_HAS_IOSTAT) ?
1573760c2415Smrg 			  dtp->common.iostat : &noiostat;
1574760c2415Smrg 
1575760c2415Smrg 	  /* Set iomsg, intent(inout).  */
1576760c2415Smrg 	  if (dtp->common.flags & IOPARM_HAS_IOMSG)
1577760c2415Smrg 	    {
1578760c2415Smrg 	      child_iomsg = dtp->common.iomsg;
1579760c2415Smrg 	      child_iomsg_len = dtp->common.iomsg_len;
1580760c2415Smrg 	    }
1581760c2415Smrg 	  else
1582760c2415Smrg 	    {
1583760c2415Smrg 	      child_iomsg = tmp_iomsg;
1584760c2415Smrg 	      child_iomsg_len = IOMSG_LEN;
1585760c2415Smrg 	    }
1586760c2415Smrg 
1587760c2415Smrg 	  /* Call the user defined formatted READ procedure.  */
1588760c2415Smrg 	  dtp->u.p.current_unit->child_dtio++;
1589760c2415Smrg 	  dtp->u.p.current_unit->last_char = EOF - 1;
1590760c2415Smrg 	  dtp->u.p.fdtio_ptr (p, &unit, iotype, f->u.udf.vlist,
1591760c2415Smrg 			      child_iostat, child_iomsg,
1592760c2415Smrg 			      iotype_len, child_iomsg_len);
1593760c2415Smrg 	  dtp->u.p.current_unit->child_dtio--;
1594760c2415Smrg 
1595760c2415Smrg 	  if (f->u.udf.string_len != 0)
1596760c2415Smrg 	    free (iotype);
1597760c2415Smrg 	  /* Note: vlist is freed in free_format_data.  */
1598760c2415Smrg 	  break;
1599760c2415Smrg 
1600760c2415Smrg 	case FMT_E:
1601760c2415Smrg 	  if (n == 0)
1602760c2415Smrg 	    goto need_read_data;
1603760c2415Smrg 	  if (require_type (dtp, BT_REAL, type, f))
1604760c2415Smrg 	    return;
1605760c2415Smrg 	  read_f (dtp, f, p, kind);
1606760c2415Smrg 	  break;
1607760c2415Smrg 
1608760c2415Smrg 	case FMT_EN:
1609760c2415Smrg 	  if (n == 0)
1610760c2415Smrg 	    goto need_read_data;
1611760c2415Smrg 	  if (require_type (dtp, BT_REAL, type, f))
1612760c2415Smrg 	    return;
1613760c2415Smrg 	  read_f (dtp, f, p, kind);
1614760c2415Smrg 	  break;
1615760c2415Smrg 
1616760c2415Smrg 	case FMT_ES:
1617760c2415Smrg 	  if (n == 0)
1618760c2415Smrg 	    goto need_read_data;
1619760c2415Smrg 	  if (require_type (dtp, BT_REAL, type, f))
1620760c2415Smrg 	    return;
1621760c2415Smrg 	  read_f (dtp, f, p, kind);
1622760c2415Smrg 	  break;
1623760c2415Smrg 
1624760c2415Smrg 	case FMT_F:
1625760c2415Smrg 	  if (n == 0)
1626760c2415Smrg 	    goto need_read_data;
1627760c2415Smrg 	  if (require_type (dtp, BT_REAL, type, f))
1628760c2415Smrg 	    return;
1629760c2415Smrg 	  read_f (dtp, f, p, kind);
1630760c2415Smrg 	  break;
1631760c2415Smrg 
1632760c2415Smrg 	case FMT_G:
1633760c2415Smrg 	  if (n == 0)
1634760c2415Smrg 	    goto need_read_data;
1635760c2415Smrg 	  switch (type)
1636760c2415Smrg 	    {
1637760c2415Smrg 	      case BT_INTEGER:
1638760c2415Smrg 		read_decimal (dtp, f, p, kind);
1639760c2415Smrg 		break;
1640760c2415Smrg 	      case BT_LOGICAL:
1641760c2415Smrg 		read_l (dtp, f, p, kind);
1642760c2415Smrg 		break;
1643760c2415Smrg 	      case BT_CHARACTER:
1644760c2415Smrg 		if (kind == 4)
1645760c2415Smrg 		  read_a_char4 (dtp, f, p, size);
1646760c2415Smrg 		else
1647760c2415Smrg 		  read_a (dtp, f, p, size);
1648760c2415Smrg 		break;
1649760c2415Smrg 	      case BT_REAL:
1650760c2415Smrg 		read_f (dtp, f, p, kind);
1651760c2415Smrg 		break;
1652760c2415Smrg 	      default:
1653760c2415Smrg 		internal_error (&dtp->common,
1654760c2415Smrg 				"formatted_transfer (): Bad type");
1655760c2415Smrg 	    }
1656760c2415Smrg 	  break;
1657760c2415Smrg 
1658760c2415Smrg 	case FMT_STRING:
1659760c2415Smrg 	  consume_data_flag = 0;
1660760c2415Smrg 	  format_error (dtp, f, "Constant string in input format");
1661760c2415Smrg 	  return;
1662760c2415Smrg 
1663760c2415Smrg 	/* Format codes that don't transfer data.  */
1664760c2415Smrg 	case FMT_X:
1665760c2415Smrg 	case FMT_TR:
1666760c2415Smrg 	  consume_data_flag = 0;
1667760c2415Smrg 	  dtp->u.p.skips += f->u.n;
1668760c2415Smrg 	  pos = bytes_used + dtp->u.p.skips - 1;
1669760c2415Smrg 	  dtp->u.p.pending_spaces = pos - dtp->u.p.max_pos + 1;
1670760c2415Smrg 	  read_x (dtp, f->u.n);
1671760c2415Smrg 	  break;
1672760c2415Smrg 
1673760c2415Smrg 	case FMT_TL:
1674760c2415Smrg 	case FMT_T:
1675760c2415Smrg 	  consume_data_flag = 0;
1676760c2415Smrg 
1677760c2415Smrg 	  if (f->format == FMT_TL)
1678760c2415Smrg 	    {
1679760c2415Smrg 	      /* Handle the special case when no bytes have been used yet.
1680760c2415Smrg 	         Cannot go below zero. */
1681760c2415Smrg 	      if (bytes_used == 0)
1682760c2415Smrg 		{
1683760c2415Smrg 		  dtp->u.p.pending_spaces -= f->u.n;
1684760c2415Smrg 		  dtp->u.p.skips -= f->u.n;
1685760c2415Smrg 		  dtp->u.p.skips = dtp->u.p.skips < 0 ? 0 : dtp->u.p.skips;
1686760c2415Smrg 		}
1687760c2415Smrg 
1688760c2415Smrg 	      pos = bytes_used - f->u.n;
1689760c2415Smrg 	    }
1690760c2415Smrg 	  else /* FMT_T */
1691760c2415Smrg 	    pos = f->u.n - 1;
1692760c2415Smrg 
1693760c2415Smrg 	  /* Standard 10.6.1.1: excessive left tabbing is reset to the
1694760c2415Smrg 	     left tab limit.  We do not check if the position has gone
1695760c2415Smrg 	     beyond the end of record because a subsequent tab could
1696760c2415Smrg 	     bring us back again.  */
1697760c2415Smrg 	  pos = pos < 0 ? 0 : pos;
1698760c2415Smrg 
1699760c2415Smrg 	  dtp->u.p.skips = dtp->u.p.skips + pos - bytes_used;
1700760c2415Smrg 	  dtp->u.p.pending_spaces = dtp->u.p.pending_spaces
1701760c2415Smrg 				    + pos - dtp->u.p.max_pos;
1702760c2415Smrg 	  dtp->u.p.pending_spaces = dtp->u.p.pending_spaces < 0
1703760c2415Smrg 				    ? 0 : dtp->u.p.pending_spaces;
1704760c2415Smrg 	  if (dtp->u.p.skips == 0)
1705760c2415Smrg 	    break;
1706760c2415Smrg 
1707760c2415Smrg 	  /* Adjust everything for end-of-record condition */
1708760c2415Smrg 	  if (dtp->u.p.sf_seen_eor && !is_internal_unit (dtp))
1709760c2415Smrg 	    {
1710760c2415Smrg               dtp->u.p.current_unit->bytes_left -= dtp->u.p.sf_seen_eor;
1711760c2415Smrg               dtp->u.p.skips -= dtp->u.p.sf_seen_eor;
1712760c2415Smrg 	      bytes_used = pos;
1713760c2415Smrg 	      if (dtp->u.p.pending_spaces == 0)
1714760c2415Smrg 		dtp->u.p.sf_seen_eor = 0;
1715760c2415Smrg 	    }
1716760c2415Smrg 	  if (dtp->u.p.skips < 0)
1717760c2415Smrg 	    {
1718760c2415Smrg               if (is_internal_unit (dtp))
1719760c2415Smrg                 sseek (dtp->u.p.current_unit->s, dtp->u.p.skips, SEEK_CUR);
1720760c2415Smrg               else
1721760c2415Smrg                 fbuf_seek (dtp->u.p.current_unit, dtp->u.p.skips, SEEK_CUR);
1722760c2415Smrg 	      dtp->u.p.current_unit->bytes_left -= (gfc_offset) dtp->u.p.skips;
1723760c2415Smrg 	      dtp->u.p.skips = dtp->u.p.pending_spaces = 0;
1724760c2415Smrg 	    }
1725760c2415Smrg 	  else
1726760c2415Smrg 	    read_x (dtp, dtp->u.p.skips);
1727760c2415Smrg 	  break;
1728760c2415Smrg 
1729760c2415Smrg 	case FMT_S:
1730760c2415Smrg 	  consume_data_flag = 0;
1731*0bfacb9bSmrg 	  dtp->u.p.sign_status = SIGN_PROCDEFINED;
1732760c2415Smrg 	  break;
1733760c2415Smrg 
1734760c2415Smrg 	case FMT_SS:
1735760c2415Smrg 	  consume_data_flag = 0;
1736*0bfacb9bSmrg 	  dtp->u.p.sign_status = SIGN_SUPPRESS;
1737760c2415Smrg 	  break;
1738760c2415Smrg 
1739760c2415Smrg 	case FMT_SP:
1740760c2415Smrg 	  consume_data_flag = 0;
1741*0bfacb9bSmrg 	  dtp->u.p.sign_status = SIGN_PLUS;
1742760c2415Smrg 	  break;
1743760c2415Smrg 
1744760c2415Smrg 	case FMT_BN:
1745760c2415Smrg 	  consume_data_flag = 0 ;
1746760c2415Smrg 	  dtp->u.p.blank_status = BLANK_NULL;
1747760c2415Smrg 	  break;
1748760c2415Smrg 
1749760c2415Smrg 	case FMT_BZ:
1750760c2415Smrg 	  consume_data_flag = 0;
1751760c2415Smrg 	  dtp->u.p.blank_status = BLANK_ZERO;
1752760c2415Smrg 	  break;
1753760c2415Smrg 
1754760c2415Smrg 	case FMT_DC:
1755760c2415Smrg 	  consume_data_flag = 0;
1756760c2415Smrg 	  dtp->u.p.current_unit->decimal_status = DECIMAL_COMMA;
1757760c2415Smrg 	  break;
1758760c2415Smrg 
1759760c2415Smrg 	case FMT_DP:
1760760c2415Smrg 	  consume_data_flag = 0;
1761760c2415Smrg 	  dtp->u.p.current_unit->decimal_status = DECIMAL_POINT;
1762760c2415Smrg 	  break;
1763760c2415Smrg 
1764760c2415Smrg 	case FMT_RC:
1765760c2415Smrg 	  consume_data_flag = 0;
1766760c2415Smrg 	  dtp->u.p.current_unit->round_status = ROUND_COMPATIBLE;
1767760c2415Smrg 	  break;
1768760c2415Smrg 
1769760c2415Smrg 	case FMT_RD:
1770760c2415Smrg 	  consume_data_flag = 0;
1771760c2415Smrg 	  dtp->u.p.current_unit->round_status = ROUND_DOWN;
1772760c2415Smrg 	  break;
1773760c2415Smrg 
1774760c2415Smrg 	case FMT_RN:
1775760c2415Smrg 	  consume_data_flag = 0;
1776760c2415Smrg 	  dtp->u.p.current_unit->round_status = ROUND_NEAREST;
1777760c2415Smrg 	  break;
1778760c2415Smrg 
1779760c2415Smrg 	case FMT_RP:
1780760c2415Smrg 	  consume_data_flag = 0;
1781760c2415Smrg 	  dtp->u.p.current_unit->round_status = ROUND_PROCDEFINED;
1782760c2415Smrg 	  break;
1783760c2415Smrg 
1784760c2415Smrg 	case FMT_RU:
1785760c2415Smrg 	  consume_data_flag = 0;
1786760c2415Smrg 	  dtp->u.p.current_unit->round_status = ROUND_UP;
1787760c2415Smrg 	  break;
1788760c2415Smrg 
1789760c2415Smrg 	case FMT_RZ:
1790760c2415Smrg 	  consume_data_flag = 0;
1791760c2415Smrg 	  dtp->u.p.current_unit->round_status = ROUND_ZERO;
1792760c2415Smrg 	  break;
1793760c2415Smrg 
1794760c2415Smrg 	case FMT_P:
1795760c2415Smrg 	  consume_data_flag = 0;
1796760c2415Smrg 	  dtp->u.p.scale_factor = f->u.k;
1797760c2415Smrg 	  break;
1798760c2415Smrg 
1799760c2415Smrg 	case FMT_DOLLAR:
1800760c2415Smrg 	  consume_data_flag = 0;
1801760c2415Smrg 	  dtp->u.p.seen_dollar = 1;
1802760c2415Smrg 	  break;
1803760c2415Smrg 
1804760c2415Smrg 	case FMT_SLASH:
1805760c2415Smrg 	  consume_data_flag = 0;
1806760c2415Smrg 	  dtp->u.p.skips = dtp->u.p.pending_spaces = 0;
1807760c2415Smrg 	  next_record (dtp, 0);
1808760c2415Smrg 	  break;
1809760c2415Smrg 
1810760c2415Smrg 	case FMT_COLON:
1811760c2415Smrg 	  /* A colon descriptor causes us to exit this loop (in
1812760c2415Smrg 	     particular preventing another / descriptor from being
1813760c2415Smrg 	     processed) unless there is another data item to be
1814760c2415Smrg 	     transferred.  */
1815760c2415Smrg 	  consume_data_flag = 0;
1816760c2415Smrg 	  if (n == 0)
1817760c2415Smrg 	    return;
1818760c2415Smrg 	  break;
1819760c2415Smrg 
1820760c2415Smrg 	default:
1821760c2415Smrg 	  internal_error (&dtp->common, "Bad format node");
1822760c2415Smrg 	}
1823760c2415Smrg 
1824760c2415Smrg       /* Adjust the item count and data pointer.  */
1825760c2415Smrg 
1826760c2415Smrg       if ((consume_data_flag > 0) && (n > 0))
1827760c2415Smrg 	{
1828760c2415Smrg 	  n--;
1829760c2415Smrg 	  p = ((char *) p) + size;
1830760c2415Smrg 	}
1831760c2415Smrg 
1832760c2415Smrg       dtp->u.p.skips = 0;
1833760c2415Smrg 
1834760c2415Smrg       pos = (int)(dtp->u.p.current_unit->recl - dtp->u.p.current_unit->bytes_left);
1835760c2415Smrg       dtp->u.p.max_pos = (dtp->u.p.max_pos > pos) ? dtp->u.p.max_pos : pos;
1836760c2415Smrg     }
1837760c2415Smrg 
1838760c2415Smrg   return;
1839760c2415Smrg 
1840760c2415Smrg   /* Come here when we need a data descriptor but don't have one.  We
1841760c2415Smrg      push the current format node back onto the input, then return and
1842760c2415Smrg      let the user program call us back with the data.  */
1843760c2415Smrg  need_read_data:
1844760c2415Smrg   unget_format (dtp, f);
1845760c2415Smrg }
1846760c2415Smrg 
1847760c2415Smrg 
1848760c2415Smrg static void
formatted_transfer_scalar_write(st_parameter_dt * dtp,bt type,void * p,int kind,size_t size)1849760c2415Smrg formatted_transfer_scalar_write (st_parameter_dt *dtp, bt type, void *p, int kind,
1850760c2415Smrg 				 size_t size)
1851760c2415Smrg {
1852760c2415Smrg   gfc_offset pos, bytes_used;
1853760c2415Smrg   const fnode *f;
1854760c2415Smrg   format_token t;
1855760c2415Smrg   int n;
1856760c2415Smrg   int consume_data_flag;
1857760c2415Smrg 
1858760c2415Smrg   /* Change a complex data item into a pair of reals.  */
1859760c2415Smrg 
1860760c2415Smrg   n = (p == NULL) ? 0 : ((type != BT_COMPLEX) ? 1 : 2);
1861760c2415Smrg   if (type == BT_COMPLEX)
1862760c2415Smrg     {
1863760c2415Smrg       type = BT_REAL;
1864760c2415Smrg       size /= 2;
1865760c2415Smrg     }
1866760c2415Smrg 
1867760c2415Smrg   /* If there's an EOR condition, we simulate finalizing the transfer
1868760c2415Smrg      by doing nothing.  */
1869760c2415Smrg   if (dtp->u.p.eor_condition)
1870760c2415Smrg     return;
1871760c2415Smrg 
1872760c2415Smrg   /* Set this flag so that commas in reads cause the read to complete before
1873760c2415Smrg      the entire field has been read.  The next read field will start right after
1874760c2415Smrg      the comma in the stream.  (Set to 0 for character reads).  */
1875760c2415Smrg   dtp->u.p.sf_read_comma =
1876760c2415Smrg     dtp->u.p.current_unit->decimal_status == DECIMAL_COMMA ? 0 : 1;
1877760c2415Smrg 
1878760c2415Smrg   for (;;)
1879760c2415Smrg     {
1880760c2415Smrg       /* If reversion has occurred and there is another real data item,
1881760c2415Smrg 	 then we have to move to the next record.  */
1882760c2415Smrg       if (dtp->u.p.reversion_flag && n > 0)
1883760c2415Smrg 	{
1884760c2415Smrg 	  dtp->u.p.reversion_flag = 0;
1885760c2415Smrg 	  next_record (dtp, 0);
1886760c2415Smrg 	}
1887760c2415Smrg 
1888760c2415Smrg       consume_data_flag = 1;
1889760c2415Smrg       if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
1890760c2415Smrg 	break;
1891760c2415Smrg 
1892760c2415Smrg       f = next_format (dtp);
1893760c2415Smrg       if (f == NULL)
1894760c2415Smrg 	{
1895760c2415Smrg 	  /* No data descriptors left.  */
1896760c2415Smrg 	  if (unlikely (n > 0))
1897760c2415Smrg 	    generate_error (&dtp->common, LIBERROR_FORMAT,
1898760c2415Smrg 		"Insufficient data descriptors in format after reversion");
1899760c2415Smrg 	  return;
1900760c2415Smrg 	}
1901760c2415Smrg 
1902760c2415Smrg       /* Now discharge T, TR and X movements to the right.  This is delayed
1903760c2415Smrg 	 until a data producing format to suppress trailing spaces.  */
1904760c2415Smrg 
1905760c2415Smrg       t = f->format;
1906760c2415Smrg       if (dtp->u.p.mode == WRITING && dtp->u.p.skips != 0
1907760c2415Smrg 	&& ((n>0 && (  t == FMT_I  || t == FMT_B  || t == FMT_O
1908760c2415Smrg 		    || t == FMT_Z  || t == FMT_F  || t == FMT_E
1909760c2415Smrg 		    || t == FMT_EN || t == FMT_ES || t == FMT_G
1910760c2415Smrg 		    || t == FMT_L  || t == FMT_A  || t == FMT_D
1911760c2415Smrg 		    || t == FMT_DT))
1912760c2415Smrg 	    || t == FMT_STRING))
1913760c2415Smrg 	{
1914760c2415Smrg 	  if (dtp->u.p.skips > 0)
1915760c2415Smrg 	    {
1916760c2415Smrg 	      gfc_offset tmp;
1917760c2415Smrg 	      write_x (dtp, dtp->u.p.skips, dtp->u.p.pending_spaces);
1918760c2415Smrg 	      tmp = dtp->u.p.current_unit->recl
1919760c2415Smrg 			  - dtp->u.p.current_unit->bytes_left;
1920760c2415Smrg 	      dtp->u.p.max_pos =
1921760c2415Smrg 		dtp->u.p.max_pos > tmp ? dtp->u.p.max_pos : tmp;
1922760c2415Smrg 	      dtp->u.p.skips = 0;
1923760c2415Smrg 	    }
1924760c2415Smrg 	  if (dtp->u.p.skips < 0)
1925760c2415Smrg 	    {
1926760c2415Smrg               if (is_internal_unit (dtp))
1927760c2415Smrg 	        sseek (dtp->u.p.current_unit->s, dtp->u.p.skips, SEEK_CUR);
1928760c2415Smrg               else
1929760c2415Smrg                 fbuf_seek (dtp->u.p.current_unit, dtp->u.p.skips, SEEK_CUR);
1930760c2415Smrg 	      dtp->u.p.current_unit->bytes_left -= (gfc_offset) dtp->u.p.skips;
1931760c2415Smrg 	    }
1932760c2415Smrg 	  dtp->u.p.skips = dtp->u.p.pending_spaces = 0;
1933760c2415Smrg 	}
1934760c2415Smrg 
1935760c2415Smrg       bytes_used = dtp->u.p.current_unit->recl
1936760c2415Smrg 		   - dtp->u.p.current_unit->bytes_left;
1937760c2415Smrg 
1938760c2415Smrg       if (is_stream_io(dtp))
1939760c2415Smrg 	bytes_used = 0;
1940760c2415Smrg 
1941760c2415Smrg       switch (t)
1942760c2415Smrg 	{
1943760c2415Smrg 	case FMT_I:
1944760c2415Smrg 	  if (n == 0)
1945760c2415Smrg 	    goto need_data;
1946760c2415Smrg 	  if (require_type (dtp, BT_INTEGER, type, f))
1947760c2415Smrg 	    return;
1948760c2415Smrg 	  write_i (dtp, f, p, kind);
1949760c2415Smrg 	  break;
1950760c2415Smrg 
1951760c2415Smrg 	case FMT_B:
1952760c2415Smrg 	  if (n == 0)
1953760c2415Smrg 	    goto need_data;
1954760c2415Smrg 	  if (!(compile_options.allow_std & GFC_STD_GNU)
1955760c2415Smrg 	      && require_numeric_type (dtp, type, f))
1956760c2415Smrg 	    return;
1957760c2415Smrg 	  if (!(compile_options.allow_std & GFC_STD_F2008)
1958760c2415Smrg               && require_type (dtp, BT_INTEGER, type, f))
1959760c2415Smrg 	    return;
1960760c2415Smrg 	  write_b (dtp, f, p, kind);
1961760c2415Smrg 	  break;
1962760c2415Smrg 
1963760c2415Smrg 	case FMT_O:
1964760c2415Smrg 	  if (n == 0)
1965760c2415Smrg 	    goto need_data;
1966760c2415Smrg 	  if (!(compile_options.allow_std & GFC_STD_GNU)
1967760c2415Smrg 	      && require_numeric_type (dtp, type, f))
1968760c2415Smrg 	    return;
1969760c2415Smrg 	  if (!(compile_options.allow_std & GFC_STD_F2008)
1970760c2415Smrg               && require_type (dtp, BT_INTEGER, type, f))
1971760c2415Smrg 	    return;
1972760c2415Smrg 	  write_o (dtp, f, p, kind);
1973760c2415Smrg 	  break;
1974760c2415Smrg 
1975760c2415Smrg 	case FMT_Z:
1976760c2415Smrg 	  if (n == 0)
1977760c2415Smrg 	    goto need_data;
1978760c2415Smrg 	  if (!(compile_options.allow_std & GFC_STD_GNU)
1979760c2415Smrg 	      && require_numeric_type (dtp, type, f))
1980760c2415Smrg 	    return;
1981760c2415Smrg 	  if (!(compile_options.allow_std & GFC_STD_F2008)
1982760c2415Smrg               && require_type (dtp, BT_INTEGER, type, f))
1983760c2415Smrg 	    return;
1984760c2415Smrg 	  write_z (dtp, f, p, kind);
1985760c2415Smrg 	  break;
1986760c2415Smrg 
1987760c2415Smrg 	case FMT_A:
1988760c2415Smrg 	  if (n == 0)
1989760c2415Smrg 	    goto need_data;
1990760c2415Smrg 
1991760c2415Smrg 	  /* It is possible to have FMT_A with something not BT_CHARACTER such
1992760c2415Smrg 	     as when writing out hollerith strings, so check both type
1993760c2415Smrg 	     and kind before calling wide character routines.  */
1994760c2415Smrg 	  if (type == BT_CHARACTER && kind == 4)
1995760c2415Smrg 	    write_a_char4 (dtp, f, p, size);
1996760c2415Smrg 	  else
1997760c2415Smrg 	    write_a (dtp, f, p, size);
1998760c2415Smrg 	  break;
1999760c2415Smrg 
2000760c2415Smrg 	case FMT_L:
2001760c2415Smrg 	  if (n == 0)
2002760c2415Smrg 	    goto need_data;
2003760c2415Smrg 	  write_l (dtp, f, p, kind);
2004760c2415Smrg 	  break;
2005760c2415Smrg 
2006760c2415Smrg 	case FMT_D:
2007760c2415Smrg 	  if (n == 0)
2008760c2415Smrg 	    goto need_data;
2009760c2415Smrg 	  if (require_type (dtp, BT_REAL, type, f))
2010760c2415Smrg 	    return;
2011*0bfacb9bSmrg 	  if (f->u.real.w == 0)
2012*0bfacb9bSmrg 	    write_real_w0 (dtp, p, kind, f);
2013*0bfacb9bSmrg 	  else
2014760c2415Smrg 	    write_d (dtp, f, p, kind);
2015760c2415Smrg 	  break;
2016760c2415Smrg 
2017760c2415Smrg 	case FMT_DT:
2018760c2415Smrg 	  if (n == 0)
2019760c2415Smrg 	    goto need_data;
2020760c2415Smrg 	  int unit = dtp->u.p.current_unit->unit_number;
2021760c2415Smrg 	  char dt[] = "DT";
2022760c2415Smrg 	  char tmp_iomsg[IOMSG_LEN] = "";
2023760c2415Smrg 	  char *child_iomsg;
2024760c2415Smrg 	  gfc_charlen_type child_iomsg_len;
2025760c2415Smrg 	  int noiostat;
2026760c2415Smrg 	  int *child_iostat = NULL;
2027760c2415Smrg 	  char *iotype;
2028760c2415Smrg 	  gfc_charlen_type iotype_len = f->u.udf.string_len;
2029760c2415Smrg 
2030760c2415Smrg 	  /* Build the iotype string.  */
2031760c2415Smrg 	  if (iotype_len == 0)
2032760c2415Smrg 	    {
2033760c2415Smrg 	      iotype_len = 2;
2034760c2415Smrg 	      iotype = dt;
2035760c2415Smrg 	    }
2036760c2415Smrg 	  else
2037760c2415Smrg 	    iotype = get_dt_format (f->u.udf.string, &iotype_len);
2038760c2415Smrg 
2039760c2415Smrg 	  /* Set iostat, intent(out).  */
2040760c2415Smrg 	  noiostat = 0;
2041760c2415Smrg 	  child_iostat = (dtp->common.flags & IOPARM_HAS_IOSTAT) ?
2042760c2415Smrg 			  dtp->common.iostat : &noiostat;
2043760c2415Smrg 
2044760c2415Smrg 	  /* Set iomsg, intent(inout).  */
2045760c2415Smrg 	  if (dtp->common.flags & IOPARM_HAS_IOMSG)
2046760c2415Smrg 	    {
2047760c2415Smrg 	      child_iomsg = dtp->common.iomsg;
2048760c2415Smrg 	      child_iomsg_len = dtp->common.iomsg_len;
2049760c2415Smrg 	    }
2050760c2415Smrg 	  else
2051760c2415Smrg 	    {
2052760c2415Smrg 	      child_iomsg = tmp_iomsg;
2053760c2415Smrg 	      child_iomsg_len = IOMSG_LEN;
2054760c2415Smrg 	    }
2055760c2415Smrg 
2056760c2415Smrg 	  if (check_dtio_proc (dtp, f))
2057760c2415Smrg 	    return;
2058760c2415Smrg 
2059760c2415Smrg 	  /* Call the user defined formatted WRITE procedure.  */
2060760c2415Smrg 	  dtp->u.p.current_unit->child_dtio++;
2061760c2415Smrg 
2062760c2415Smrg 	  dtp->u.p.fdtio_ptr (p, &unit, iotype, f->u.udf.vlist,
2063760c2415Smrg 			      child_iostat, child_iomsg,
2064760c2415Smrg 			      iotype_len, child_iomsg_len);
2065760c2415Smrg 	  dtp->u.p.current_unit->child_dtio--;
2066760c2415Smrg 
2067760c2415Smrg 	  if (f->u.udf.string_len != 0)
2068760c2415Smrg 	    free (iotype);
2069760c2415Smrg 	  /* Note: vlist is freed in free_format_data.  */
2070760c2415Smrg 	  break;
2071760c2415Smrg 
2072760c2415Smrg 	case FMT_E:
2073760c2415Smrg 	  if (n == 0)
2074760c2415Smrg 	    goto need_data;
2075760c2415Smrg 	  if (require_type (dtp, BT_REAL, type, f))
2076760c2415Smrg 	    return;
2077*0bfacb9bSmrg 	  if (f->u.real.w == 0)
2078*0bfacb9bSmrg 	    write_real_w0 (dtp, p, kind, f);
2079*0bfacb9bSmrg 	  else
2080760c2415Smrg 	    write_e (dtp, f, p, kind);
2081760c2415Smrg 	  break;
2082760c2415Smrg 
2083760c2415Smrg 	case FMT_EN:
2084760c2415Smrg 	  if (n == 0)
2085760c2415Smrg 	    goto need_data;
2086760c2415Smrg 	  if (require_type (dtp, BT_REAL, type, f))
2087760c2415Smrg 	    return;
2088*0bfacb9bSmrg 	  if (f->u.real.w == 0)
2089*0bfacb9bSmrg 	    write_real_w0 (dtp, p, kind, f);
2090*0bfacb9bSmrg 	  else
2091760c2415Smrg 	    write_en (dtp, f, p, kind);
2092760c2415Smrg 	  break;
2093760c2415Smrg 
2094760c2415Smrg 	case FMT_ES:
2095760c2415Smrg 	  if (n == 0)
2096760c2415Smrg 	    goto need_data;
2097760c2415Smrg 	  if (require_type (dtp, BT_REAL, type, f))
2098760c2415Smrg 	    return;
2099*0bfacb9bSmrg 	  if (f->u.real.w == 0)
2100*0bfacb9bSmrg 	    write_real_w0 (dtp, p, kind, f);
2101*0bfacb9bSmrg 	  else
2102760c2415Smrg 	    write_es (dtp, f, p, kind);
2103760c2415Smrg 	  break;
2104760c2415Smrg 
2105760c2415Smrg 	case FMT_F:
2106760c2415Smrg 	  if (n == 0)
2107760c2415Smrg 	    goto need_data;
2108760c2415Smrg 	  if (require_type (dtp, BT_REAL, type, f))
2109760c2415Smrg 	    return;
2110760c2415Smrg 	  write_f (dtp, f, p, kind);
2111760c2415Smrg 	  break;
2112760c2415Smrg 
2113760c2415Smrg 	case FMT_G:
2114760c2415Smrg 	  if (n == 0)
2115760c2415Smrg 	    goto need_data;
2116760c2415Smrg 	  switch (type)
2117760c2415Smrg 	    {
2118760c2415Smrg 	      case BT_INTEGER:
2119760c2415Smrg 		write_i (dtp, f, p, kind);
2120760c2415Smrg 		break;
2121760c2415Smrg 	      case BT_LOGICAL:
2122760c2415Smrg 		write_l (dtp, f, p, kind);
2123760c2415Smrg 		break;
2124760c2415Smrg 	      case BT_CHARACTER:
2125760c2415Smrg 		if (kind == 4)
2126760c2415Smrg 		  write_a_char4 (dtp, f, p, size);
2127760c2415Smrg 		else
2128760c2415Smrg 		  write_a (dtp, f, p, size);
2129760c2415Smrg 		break;
2130760c2415Smrg 	      case BT_REAL:
2131760c2415Smrg 		if (f->u.real.w == 0)
2132*0bfacb9bSmrg 		  write_real_w0 (dtp, p, kind, f);
2133760c2415Smrg 		else
2134760c2415Smrg 		  write_d (dtp, f, p, kind);
2135760c2415Smrg 		break;
2136760c2415Smrg 	      default:
2137760c2415Smrg 		internal_error (&dtp->common,
2138760c2415Smrg 				"formatted_transfer (): Bad type");
2139760c2415Smrg 	    }
2140760c2415Smrg 	  break;
2141760c2415Smrg 
2142760c2415Smrg 	case FMT_STRING:
2143760c2415Smrg 	  consume_data_flag = 0;
2144760c2415Smrg 	  write_constant_string (dtp, f);
2145760c2415Smrg 	  break;
2146760c2415Smrg 
2147760c2415Smrg 	/* Format codes that don't transfer data.  */
2148760c2415Smrg 	case FMT_X:
2149760c2415Smrg 	case FMT_TR:
2150760c2415Smrg 	  consume_data_flag = 0;
2151760c2415Smrg 
2152760c2415Smrg 	  dtp->u.p.skips += f->u.n;
2153760c2415Smrg 	  pos = bytes_used + dtp->u.p.skips - 1;
2154760c2415Smrg 	  dtp->u.p.pending_spaces = pos - dtp->u.p.max_pos + 1;
2155760c2415Smrg 	  /* Writes occur just before the switch on f->format, above, so
2156760c2415Smrg 	     that trailing blanks are suppressed, unless we are doing a
2157760c2415Smrg 	     non-advancing write in which case we want to output the blanks
2158760c2415Smrg 	     now.  */
2159760c2415Smrg 	  if (dtp->u.p.advance_status == ADVANCE_NO)
2160760c2415Smrg 	    {
2161760c2415Smrg 	      write_x (dtp, dtp->u.p.skips, dtp->u.p.pending_spaces);
2162760c2415Smrg 	      dtp->u.p.skips = dtp->u.p.pending_spaces = 0;
2163760c2415Smrg 	    }
2164760c2415Smrg 	  break;
2165760c2415Smrg 
2166760c2415Smrg 	case FMT_TL:
2167760c2415Smrg 	case FMT_T:
2168760c2415Smrg 	  consume_data_flag = 0;
2169760c2415Smrg 
2170760c2415Smrg 	  if (f->format == FMT_TL)
2171760c2415Smrg 	    {
2172760c2415Smrg 
2173760c2415Smrg 	      /* Handle the special case when no bytes have been used yet.
2174760c2415Smrg 	         Cannot go below zero. */
2175760c2415Smrg 	      if (bytes_used == 0)
2176760c2415Smrg 		{
2177760c2415Smrg 		  dtp->u.p.pending_spaces -= f->u.n;
2178760c2415Smrg 		  dtp->u.p.skips -= f->u.n;
2179760c2415Smrg 		  dtp->u.p.skips = dtp->u.p.skips < 0 ? 0 : dtp->u.p.skips;
2180760c2415Smrg 		}
2181760c2415Smrg 
2182760c2415Smrg 	      pos = bytes_used - f->u.n;
2183760c2415Smrg 	    }
2184760c2415Smrg 	  else /* FMT_T */
2185760c2415Smrg 	    pos = f->u.n - dtp->u.p.pending_spaces - 1;
2186760c2415Smrg 
2187760c2415Smrg 	  /* Standard 10.6.1.1: excessive left tabbing is reset to the
2188760c2415Smrg 	     left tab limit.  We do not check if the position has gone
2189760c2415Smrg 	     beyond the end of record because a subsequent tab could
2190760c2415Smrg 	     bring us back again.  */
2191760c2415Smrg 	  pos = pos < 0 ? 0 : pos;
2192760c2415Smrg 
2193760c2415Smrg 	  dtp->u.p.skips = dtp->u.p.skips + pos - bytes_used;
2194760c2415Smrg 	  dtp->u.p.pending_spaces = dtp->u.p.pending_spaces
2195760c2415Smrg 				    + pos - dtp->u.p.max_pos;
2196760c2415Smrg 	  dtp->u.p.pending_spaces = dtp->u.p.pending_spaces < 0
2197760c2415Smrg 				    ? 0 : dtp->u.p.pending_spaces;
2198760c2415Smrg 	  break;
2199760c2415Smrg 
2200760c2415Smrg 	case FMT_S:
2201760c2415Smrg 	  consume_data_flag = 0;
2202*0bfacb9bSmrg 	  dtp->u.p.sign_status = SIGN_PROCDEFINED;
2203760c2415Smrg 	  break;
2204760c2415Smrg 
2205760c2415Smrg 	case FMT_SS:
2206760c2415Smrg 	  consume_data_flag = 0;
2207*0bfacb9bSmrg 	  dtp->u.p.sign_status = SIGN_SUPPRESS;
2208760c2415Smrg 	  break;
2209760c2415Smrg 
2210760c2415Smrg 	case FMT_SP:
2211760c2415Smrg 	  consume_data_flag = 0;
2212*0bfacb9bSmrg 	  dtp->u.p.sign_status = SIGN_PLUS;
2213760c2415Smrg 	  break;
2214760c2415Smrg 
2215760c2415Smrg 	case FMT_BN:
2216760c2415Smrg 	  consume_data_flag = 0 ;
2217760c2415Smrg 	  dtp->u.p.blank_status = BLANK_NULL;
2218760c2415Smrg 	  break;
2219760c2415Smrg 
2220760c2415Smrg 	case FMT_BZ:
2221760c2415Smrg 	  consume_data_flag = 0;
2222760c2415Smrg 	  dtp->u.p.blank_status = BLANK_ZERO;
2223760c2415Smrg 	  break;
2224760c2415Smrg 
2225760c2415Smrg 	case FMT_DC:
2226760c2415Smrg 	  consume_data_flag = 0;
2227760c2415Smrg 	  dtp->u.p.current_unit->decimal_status = DECIMAL_COMMA;
2228760c2415Smrg 	  break;
2229760c2415Smrg 
2230760c2415Smrg 	case FMT_DP:
2231760c2415Smrg 	  consume_data_flag = 0;
2232760c2415Smrg 	  dtp->u.p.current_unit->decimal_status = DECIMAL_POINT;
2233760c2415Smrg 	  break;
2234760c2415Smrg 
2235760c2415Smrg 	case FMT_RC:
2236760c2415Smrg 	  consume_data_flag = 0;
2237760c2415Smrg 	  dtp->u.p.current_unit->round_status = ROUND_COMPATIBLE;
2238760c2415Smrg 	  break;
2239760c2415Smrg 
2240760c2415Smrg 	case FMT_RD:
2241760c2415Smrg 	  consume_data_flag = 0;
2242760c2415Smrg 	  dtp->u.p.current_unit->round_status = ROUND_DOWN;
2243760c2415Smrg 	  break;
2244760c2415Smrg 
2245760c2415Smrg 	case FMT_RN:
2246760c2415Smrg 	  consume_data_flag = 0;
2247760c2415Smrg 	  dtp->u.p.current_unit->round_status = ROUND_NEAREST;
2248760c2415Smrg 	  break;
2249760c2415Smrg 
2250760c2415Smrg 	case FMT_RP:
2251760c2415Smrg 	  consume_data_flag = 0;
2252760c2415Smrg 	  dtp->u.p.current_unit->round_status = ROUND_PROCDEFINED;
2253760c2415Smrg 	  break;
2254760c2415Smrg 
2255760c2415Smrg 	case FMT_RU:
2256760c2415Smrg 	  consume_data_flag = 0;
2257760c2415Smrg 	  dtp->u.p.current_unit->round_status = ROUND_UP;
2258760c2415Smrg 	  break;
2259760c2415Smrg 
2260760c2415Smrg 	case FMT_RZ:
2261760c2415Smrg 	  consume_data_flag = 0;
2262760c2415Smrg 	  dtp->u.p.current_unit->round_status = ROUND_ZERO;
2263760c2415Smrg 	  break;
2264760c2415Smrg 
2265760c2415Smrg 	case FMT_P:
2266760c2415Smrg 	  consume_data_flag = 0;
2267760c2415Smrg 	  dtp->u.p.scale_factor = f->u.k;
2268760c2415Smrg 	  break;
2269760c2415Smrg 
2270760c2415Smrg 	case FMT_DOLLAR:
2271760c2415Smrg 	  consume_data_flag = 0;
2272760c2415Smrg 	  dtp->u.p.seen_dollar = 1;
2273760c2415Smrg 	  break;
2274760c2415Smrg 
2275760c2415Smrg 	case FMT_SLASH:
2276760c2415Smrg 	  consume_data_flag = 0;
2277760c2415Smrg 	  dtp->u.p.skips = dtp->u.p.pending_spaces = 0;
2278760c2415Smrg 	  next_record (dtp, 0);
2279760c2415Smrg 	  break;
2280760c2415Smrg 
2281760c2415Smrg 	case FMT_COLON:
2282760c2415Smrg 	  /* A colon descriptor causes us to exit this loop (in
2283760c2415Smrg 	     particular preventing another / descriptor from being
2284760c2415Smrg 	     processed) unless there is another data item to be
2285760c2415Smrg 	     transferred.  */
2286760c2415Smrg 	  consume_data_flag = 0;
2287760c2415Smrg 	  if (n == 0)
2288760c2415Smrg 	    return;
2289760c2415Smrg 	  break;
2290760c2415Smrg 
2291760c2415Smrg 	default:
2292760c2415Smrg 	  internal_error (&dtp->common, "Bad format node");
2293760c2415Smrg 	}
2294760c2415Smrg 
2295760c2415Smrg       /* Adjust the item count and data pointer.  */
2296760c2415Smrg 
2297760c2415Smrg       if ((consume_data_flag > 0) && (n > 0))
2298760c2415Smrg 	{
2299760c2415Smrg 	  n--;
2300760c2415Smrg 	  p = ((char *) p) + size;
2301760c2415Smrg 	}
2302760c2415Smrg 
2303760c2415Smrg       pos = dtp->u.p.current_unit->recl - dtp->u.p.current_unit->bytes_left;
2304760c2415Smrg       dtp->u.p.max_pos = (dtp->u.p.max_pos > pos) ? dtp->u.p.max_pos : pos;
2305760c2415Smrg     }
2306760c2415Smrg 
2307760c2415Smrg   return;
2308760c2415Smrg 
2309760c2415Smrg   /* Come here when we need a data descriptor but don't have one.  We
2310760c2415Smrg      push the current format node back onto the input, then return and
2311760c2415Smrg      let the user program call us back with the data.  */
2312760c2415Smrg  need_data:
2313760c2415Smrg   unget_format (dtp, f);
2314760c2415Smrg }
2315760c2415Smrg 
2316760c2415Smrg   /* This function is first called from data_init_transfer to initiate the loop
2317760c2415Smrg      over each item in the format, transferring data as required.  Subsequent
2318760c2415Smrg      calls to this function occur for each data item foound in the READ/WRITE
2319760c2415Smrg      statement.  The item_count is incremented for each call.  Since the first
2320760c2415Smrg      call is from data_transfer_init, the item_count is always one greater than
2321760c2415Smrg      the actual count number of the item being transferred.  */
2322760c2415Smrg 
2323760c2415Smrg static void
formatted_transfer(st_parameter_dt * dtp,bt type,void * p,int kind,size_t size,size_t nelems)2324760c2415Smrg formatted_transfer (st_parameter_dt *dtp, bt type, void *p, int kind,
2325760c2415Smrg 		    size_t size, size_t nelems)
2326760c2415Smrg {
2327760c2415Smrg   size_t elem;
2328760c2415Smrg   char *tmp;
2329760c2415Smrg 
2330760c2415Smrg   tmp = (char *) p;
2331760c2415Smrg   size_t stride = type == BT_CHARACTER ?
2332760c2415Smrg 		  size * GFC_SIZE_OF_CHAR_KIND(kind) : size;
2333760c2415Smrg   if (dtp->u.p.mode == READING)
2334760c2415Smrg     {
2335760c2415Smrg       /* Big loop over all the elements.  */
2336760c2415Smrg       for (elem = 0; elem < nelems; elem++)
2337760c2415Smrg 	{
2338760c2415Smrg 	  dtp->u.p.item_count++;
2339760c2415Smrg 	  formatted_transfer_scalar_read (dtp, type, tmp + stride*elem, kind, size);
2340760c2415Smrg 	}
2341760c2415Smrg     }
2342760c2415Smrg   else
2343760c2415Smrg     {
2344760c2415Smrg       /* Big loop over all the elements.  */
2345760c2415Smrg       for (elem = 0; elem < nelems; elem++)
2346760c2415Smrg 	{
2347760c2415Smrg 	  dtp->u.p.item_count++;
2348760c2415Smrg 	  formatted_transfer_scalar_write (dtp, type, tmp + stride*elem, kind, size);
2349760c2415Smrg 	}
2350760c2415Smrg     }
2351760c2415Smrg }
2352760c2415Smrg 
2353760c2415Smrg /* Wrapper function for I/O of scalar types.  If this should be an async I/O
2354760c2415Smrg    request, queue it.  For a synchronous write on an async unit, perform the
2355760c2415Smrg    wait operation and return an error.  For all synchronous writes, call the
2356760c2415Smrg    right transfer function.  */
2357760c2415Smrg 
2358760c2415Smrg static void
wrap_scalar_transfer(st_parameter_dt * dtp,bt type,void * p,int kind,size_t size,size_t n_elem)2359760c2415Smrg wrap_scalar_transfer (st_parameter_dt *dtp, bt type, void *p, int kind,
2360760c2415Smrg 		      size_t size, size_t n_elem)
2361760c2415Smrg {
2362760c2415Smrg   if (dtp->u.p.current_unit && dtp->u.p.current_unit->au)
2363760c2415Smrg     {
2364760c2415Smrg       if (dtp->u.p.async)
2365760c2415Smrg 	{
2366760c2415Smrg 	  transfer_args args;
2367760c2415Smrg 	  args.scalar.transfer = dtp->u.p.transfer;
2368760c2415Smrg 	  args.scalar.arg_bt = type;
2369760c2415Smrg 	  args.scalar.data = p;
2370760c2415Smrg 	  args.scalar.i = kind;
2371760c2415Smrg 	  args.scalar.s1 = size;
2372760c2415Smrg 	  args.scalar.s2 = n_elem;
2373760c2415Smrg 	  enqueue_transfer (dtp->u.p.current_unit->au, &args,
2374760c2415Smrg 			    AIO_TRANSFER_SCALAR);
2375760c2415Smrg 	  return;
2376760c2415Smrg 	}
2377760c2415Smrg     }
2378760c2415Smrg   /* Come here if there was no asynchronous I/O to be scheduled.  */
2379760c2415Smrg   if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
2380760c2415Smrg     return;
2381760c2415Smrg 
2382760c2415Smrg   dtp->u.p.transfer (dtp, type, p, kind, size, 1);
2383760c2415Smrg }
2384760c2415Smrg 
2385760c2415Smrg 
2386760c2415Smrg /* Data transfer entry points.  The type of the data entity is
2387760c2415Smrg    implicit in the subroutine call.  This prevents us from having to
2388760c2415Smrg    share a common enum with the compiler.  */
2389760c2415Smrg 
2390760c2415Smrg void
transfer_integer(st_parameter_dt * dtp,void * p,int kind)2391760c2415Smrg transfer_integer (st_parameter_dt *dtp, void *p, int kind)
2392760c2415Smrg {
2393760c2415Smrg     wrap_scalar_transfer (dtp, BT_INTEGER, p, kind, kind, 1);
2394760c2415Smrg }
2395760c2415Smrg 
2396760c2415Smrg void
transfer_integer_write(st_parameter_dt * dtp,void * p,int kind)2397760c2415Smrg transfer_integer_write (st_parameter_dt *dtp, void *p, int kind)
2398760c2415Smrg {
2399760c2415Smrg   transfer_integer (dtp, p, kind);
2400760c2415Smrg }
2401760c2415Smrg 
2402760c2415Smrg void
transfer_real(st_parameter_dt * dtp,void * p,int kind)2403760c2415Smrg transfer_real (st_parameter_dt *dtp, void *p, int kind)
2404760c2415Smrg {
2405760c2415Smrg   size_t size;
2406760c2415Smrg   if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
2407760c2415Smrg     return;
2408760c2415Smrg   size = size_from_real_kind (kind);
2409760c2415Smrg   wrap_scalar_transfer (dtp, BT_REAL, p, kind, size, 1);
2410760c2415Smrg }
2411760c2415Smrg 
2412760c2415Smrg void
transfer_real_write(st_parameter_dt * dtp,void * p,int kind)2413760c2415Smrg transfer_real_write (st_parameter_dt *dtp, void *p, int kind)
2414760c2415Smrg {
2415760c2415Smrg   transfer_real (dtp, p, kind);
2416760c2415Smrg }
2417760c2415Smrg 
2418760c2415Smrg void
transfer_logical(st_parameter_dt * dtp,void * p,int kind)2419760c2415Smrg transfer_logical (st_parameter_dt *dtp, void *p, int kind)
2420760c2415Smrg {
2421760c2415Smrg   wrap_scalar_transfer (dtp, BT_LOGICAL, p, kind, kind, 1);
2422760c2415Smrg }
2423760c2415Smrg 
2424760c2415Smrg void
transfer_logical_write(st_parameter_dt * dtp,void * p,int kind)2425760c2415Smrg transfer_logical_write (st_parameter_dt *dtp, void *p, int kind)
2426760c2415Smrg {
2427760c2415Smrg   transfer_logical (dtp, p, kind);
2428760c2415Smrg }
2429760c2415Smrg 
2430760c2415Smrg void
transfer_character(st_parameter_dt * dtp,void * p,gfc_charlen_type len)2431760c2415Smrg transfer_character (st_parameter_dt *dtp, void *p, gfc_charlen_type len)
2432760c2415Smrg {
2433760c2415Smrg   static char *empty_string[0];
2434760c2415Smrg 
2435760c2415Smrg   if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
2436760c2415Smrg     return;
2437760c2415Smrg 
2438760c2415Smrg   /* Strings of zero length can have p == NULL, which confuses the
2439760c2415Smrg      transfer routines into thinking we need more data elements.  To avoid
2440760c2415Smrg      this, we give them a nice pointer.  */
2441760c2415Smrg   if (len == 0 && p == NULL)
2442760c2415Smrg     p = empty_string;
2443760c2415Smrg 
2444760c2415Smrg   /* Set kind here to 1.  */
2445760c2415Smrg   wrap_scalar_transfer (dtp, BT_CHARACTER, p, 1, len, 1);
2446760c2415Smrg }
2447760c2415Smrg 
2448760c2415Smrg void
transfer_character_write(st_parameter_dt * dtp,void * p,gfc_charlen_type len)2449760c2415Smrg transfer_character_write (st_parameter_dt *dtp, void *p, gfc_charlen_type len)
2450760c2415Smrg {
2451760c2415Smrg   transfer_character (dtp, p, len);
2452760c2415Smrg }
2453760c2415Smrg 
2454760c2415Smrg void
transfer_character_wide(st_parameter_dt * dtp,void * p,gfc_charlen_type len,int kind)2455760c2415Smrg transfer_character_wide (st_parameter_dt *dtp, void *p, gfc_charlen_type len, int kind)
2456760c2415Smrg {
2457760c2415Smrg   static char *empty_string[0];
2458760c2415Smrg 
2459760c2415Smrg   if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
2460760c2415Smrg     return;
2461760c2415Smrg 
2462760c2415Smrg   /* Strings of zero length can have p == NULL, which confuses the
2463760c2415Smrg      transfer routines into thinking we need more data elements.  To avoid
2464760c2415Smrg      this, we give them a nice pointer.  */
2465760c2415Smrg   if (len == 0 && p == NULL)
2466760c2415Smrg     p = empty_string;
2467760c2415Smrg 
2468760c2415Smrg   /* Here we pass the actual kind value.  */
2469760c2415Smrg   wrap_scalar_transfer (dtp, BT_CHARACTER, p, kind, len, 1);
2470760c2415Smrg }
2471760c2415Smrg 
2472760c2415Smrg void
transfer_character_wide_write(st_parameter_dt * dtp,void * p,gfc_charlen_type len,int kind)2473760c2415Smrg transfer_character_wide_write (st_parameter_dt *dtp, void *p, gfc_charlen_type len, int kind)
2474760c2415Smrg {
2475760c2415Smrg   transfer_character_wide (dtp, p, len, kind);
2476760c2415Smrg }
2477760c2415Smrg 
2478760c2415Smrg void
transfer_complex(st_parameter_dt * dtp,void * p,int kind)2479760c2415Smrg transfer_complex (st_parameter_dt *dtp, void *p, int kind)
2480760c2415Smrg {
2481760c2415Smrg   size_t size;
2482760c2415Smrg   if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
2483760c2415Smrg     return;
2484760c2415Smrg   size = size_from_complex_kind (kind);
2485760c2415Smrg   wrap_scalar_transfer (dtp, BT_COMPLEX, p, kind, size, 1);
2486760c2415Smrg }
2487760c2415Smrg 
2488760c2415Smrg void
transfer_complex_write(st_parameter_dt * dtp,void * p,int kind)2489760c2415Smrg transfer_complex_write (st_parameter_dt *dtp, void *p, int kind)
2490760c2415Smrg {
2491760c2415Smrg   transfer_complex (dtp, p, kind);
2492760c2415Smrg }
2493760c2415Smrg 
2494760c2415Smrg void
transfer_array_inner(st_parameter_dt * dtp,gfc_array_char * desc,int kind,gfc_charlen_type charlen)2495760c2415Smrg transfer_array_inner (st_parameter_dt *dtp, gfc_array_char *desc, int kind,
2496760c2415Smrg 		      gfc_charlen_type charlen)
2497760c2415Smrg {
2498760c2415Smrg   index_type count[GFC_MAX_DIMENSIONS];
2499760c2415Smrg   index_type extent[GFC_MAX_DIMENSIONS];
2500760c2415Smrg   index_type stride[GFC_MAX_DIMENSIONS];
2501760c2415Smrg   index_type stride0, rank, size, n;
2502760c2415Smrg   size_t tsize;
2503760c2415Smrg   char *data;
2504760c2415Smrg   bt iotype;
2505760c2415Smrg 
2506760c2415Smrg   /* Adjust item_count before emitting error message.  */
2507760c2415Smrg 
2508760c2415Smrg   if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
2509760c2415Smrg     return;
2510760c2415Smrg 
2511760c2415Smrg   iotype = (bt) GFC_DESCRIPTOR_TYPE (desc);
2512760c2415Smrg   size = iotype == BT_CHARACTER ? charlen : GFC_DESCRIPTOR_SIZE (desc);
2513760c2415Smrg 
2514760c2415Smrg   rank = GFC_DESCRIPTOR_RANK (desc);
2515760c2415Smrg 
2516760c2415Smrg   for (n = 0; n < rank; n++)
2517760c2415Smrg     {
2518760c2415Smrg       count[n] = 0;
2519760c2415Smrg       stride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(desc,n);
2520760c2415Smrg       extent[n] = GFC_DESCRIPTOR_EXTENT(desc,n);
2521760c2415Smrg 
2522760c2415Smrg       /* If the extent of even one dimension is zero, then the entire
2523760c2415Smrg 	 array section contains zero elements, so we return after writing
2524760c2415Smrg 	 a zero array record.  */
2525760c2415Smrg       if (extent[n] <= 0)
2526760c2415Smrg 	{
2527760c2415Smrg 	  data = NULL;
2528760c2415Smrg 	  tsize = 0;
2529760c2415Smrg 	  dtp->u.p.transfer (dtp, iotype, data, kind, size, tsize);
2530760c2415Smrg 	  return;
2531760c2415Smrg 	}
2532760c2415Smrg     }
2533760c2415Smrg 
2534760c2415Smrg   stride0 = stride[0];
2535760c2415Smrg 
2536760c2415Smrg   /* If the innermost dimension has a stride of 1, we can do the transfer
2537760c2415Smrg      in contiguous chunks.  */
2538760c2415Smrg   if (stride0 == size)
2539760c2415Smrg     tsize = extent[0];
2540760c2415Smrg   else
2541760c2415Smrg     tsize = 1;
2542760c2415Smrg 
2543760c2415Smrg   data = GFC_DESCRIPTOR_DATA (desc);
2544760c2415Smrg 
2545760c2415Smrg   /* When reading, we need to check endfile conditions so we do not miss
2546760c2415Smrg      an END=label.  Make this separate so we do not have an extra test
2547760c2415Smrg      in a tight loop when it is not needed.  */
2548760c2415Smrg 
2549760c2415Smrg   if (dtp->u.p.current_unit && dtp->u.p.mode == READING)
2550760c2415Smrg     {
2551760c2415Smrg       while (data)
2552760c2415Smrg 	{
2553760c2415Smrg 	  if (unlikely (dtp->u.p.current_unit->endfile == AFTER_ENDFILE))
2554760c2415Smrg 	    return;
2555760c2415Smrg 
2556760c2415Smrg 	  dtp->u.p.transfer (dtp, iotype, data, kind, size, tsize);
2557760c2415Smrg 	  data += stride0 * tsize;
2558760c2415Smrg 	  count[0] += tsize;
2559760c2415Smrg 	  n = 0;
2560760c2415Smrg 	  while (count[n] == extent[n])
2561760c2415Smrg 	    {
2562760c2415Smrg 	      count[n] = 0;
2563760c2415Smrg 	      data -= stride[n] * extent[n];
2564760c2415Smrg 	      n++;
2565760c2415Smrg 	      if (n == rank)
2566760c2415Smrg 		{
2567760c2415Smrg 		  data = NULL;
2568760c2415Smrg 		  break;
2569760c2415Smrg 		}
2570760c2415Smrg 	      else
2571760c2415Smrg 		{
2572760c2415Smrg 		  count[n]++;
2573760c2415Smrg 		  data += stride[n];
2574760c2415Smrg 		}
2575760c2415Smrg 	    }
2576760c2415Smrg 	}
2577760c2415Smrg     }
2578760c2415Smrg   else
2579760c2415Smrg     {
2580760c2415Smrg       while (data)
2581760c2415Smrg 	{
2582760c2415Smrg 	  dtp->u.p.transfer (dtp, iotype, data, kind, size, tsize);
2583760c2415Smrg 	  data += stride0 * tsize;
2584760c2415Smrg 	  count[0] += tsize;
2585760c2415Smrg 	  n = 0;
2586760c2415Smrg 	  while (count[n] == extent[n])
2587760c2415Smrg 	    {
2588760c2415Smrg 	      count[n] = 0;
2589760c2415Smrg 	      data -= stride[n] * extent[n];
2590760c2415Smrg 	      n++;
2591760c2415Smrg 	      if (n == rank)
2592760c2415Smrg 		{
2593760c2415Smrg 		  data = NULL;
2594760c2415Smrg 		  break;
2595760c2415Smrg 		}
2596760c2415Smrg 	      else
2597760c2415Smrg 		{
2598760c2415Smrg 		  count[n]++;
2599760c2415Smrg 		  data += stride[n];
2600760c2415Smrg 		}
2601760c2415Smrg 	    }
2602760c2415Smrg 	}
2603760c2415Smrg     }
2604760c2415Smrg }
2605760c2415Smrg 
2606760c2415Smrg void
transfer_array(st_parameter_dt * dtp,gfc_array_char * desc,int kind,gfc_charlen_type charlen)2607760c2415Smrg transfer_array (st_parameter_dt *dtp, gfc_array_char *desc, int kind,
2608760c2415Smrg 	        gfc_charlen_type charlen)
2609760c2415Smrg {
2610760c2415Smrg   if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
2611760c2415Smrg     return;
2612760c2415Smrg 
2613760c2415Smrg   if (dtp->u.p.current_unit && dtp->u.p.current_unit->au)
2614760c2415Smrg     {
2615760c2415Smrg       if (dtp->u.p.async)
2616760c2415Smrg 	{
2617760c2415Smrg 	  transfer_args args;
2618760c2415Smrg 	  size_t sz = sizeof (gfc_array_char)
2619760c2415Smrg 			+ sizeof (descriptor_dimension)
2620760c2415Smrg        			* GFC_DESCRIPTOR_RANK (desc);
2621760c2415Smrg 	  args.array.desc = xmalloc (sz);
2622760c2415Smrg 	  NOTE ("desc = %p", (void *) args.array.desc);
2623760c2415Smrg 	  memcpy (args.array.desc, desc, sz);
2624760c2415Smrg 	  args.array.kind = kind;
2625760c2415Smrg 	  args.array.charlen = charlen;
2626760c2415Smrg 	  enqueue_transfer (dtp->u.p.current_unit->au, &args,
2627760c2415Smrg 			    AIO_TRANSFER_ARRAY);
2628760c2415Smrg 	  return;
2629760c2415Smrg 	}
2630760c2415Smrg     }
2631760c2415Smrg   /* Come here if there was no asynchronous I/O to be scheduled.  */
2632760c2415Smrg   transfer_array_inner (dtp, desc, kind, charlen);
2633760c2415Smrg }
2634760c2415Smrg 
2635760c2415Smrg 
2636760c2415Smrg void
transfer_array_write(st_parameter_dt * dtp,gfc_array_char * desc,int kind,gfc_charlen_type charlen)2637760c2415Smrg transfer_array_write (st_parameter_dt *dtp, gfc_array_char *desc, int kind,
2638760c2415Smrg 		      gfc_charlen_type charlen)
2639760c2415Smrg {
2640760c2415Smrg   transfer_array (dtp, desc, kind, charlen);
2641760c2415Smrg }
2642760c2415Smrg 
2643760c2415Smrg 
2644760c2415Smrg /* User defined input/output iomsg. */
2645760c2415Smrg 
2646760c2415Smrg #define IOMSG_LEN 256
2647760c2415Smrg 
2648760c2415Smrg void
transfer_derived(st_parameter_dt * parent,void * dtio_source,void * dtio_proc)2649760c2415Smrg transfer_derived (st_parameter_dt *parent, void *dtio_source, void *dtio_proc)
2650760c2415Smrg {
2651760c2415Smrg   if (parent->u.p.current_unit)
2652760c2415Smrg     {
2653760c2415Smrg       if (parent->u.p.current_unit->flags.form == FORM_UNFORMATTED)
2654760c2415Smrg 	parent->u.p.ufdtio_ptr = (unformatted_dtio) dtio_proc;
2655760c2415Smrg       else
2656760c2415Smrg 	parent->u.p.fdtio_ptr = (formatted_dtio) dtio_proc;
2657760c2415Smrg     }
2658760c2415Smrg   wrap_scalar_transfer (parent, BT_CLASS, dtio_source, 0, 0, 1);
2659760c2415Smrg }
2660760c2415Smrg 
2661760c2415Smrg 
2662760c2415Smrg /* Preposition a sequential unformatted file while reading.  */
2663760c2415Smrg 
2664760c2415Smrg static void
us_read(st_parameter_dt * dtp,int continued)2665760c2415Smrg us_read (st_parameter_dt *dtp, int continued)
2666760c2415Smrg {
2667760c2415Smrg   ssize_t n, nr;
2668760c2415Smrg   GFC_INTEGER_4 i4;
2669760c2415Smrg   GFC_INTEGER_8 i8;
2670760c2415Smrg   gfc_offset i;
2671760c2415Smrg 
2672760c2415Smrg   if (compile_options.record_marker == 0)
2673760c2415Smrg     n = sizeof (GFC_INTEGER_4);
2674760c2415Smrg   else
2675760c2415Smrg     n = compile_options.record_marker;
2676760c2415Smrg 
2677760c2415Smrg   nr = sread (dtp->u.p.current_unit->s, &i, n);
2678760c2415Smrg   if (unlikely (nr < 0))
2679760c2415Smrg     {
2680760c2415Smrg       generate_error (&dtp->common, LIBERROR_BAD_US, NULL);
2681760c2415Smrg       return;
2682760c2415Smrg     }
2683760c2415Smrg   else if (nr == 0)
2684760c2415Smrg     {
2685760c2415Smrg       hit_eof (dtp);
2686760c2415Smrg       return;  /* end of file */
2687760c2415Smrg     }
2688760c2415Smrg   else if (unlikely (n != nr))
2689760c2415Smrg     {
2690760c2415Smrg       generate_error (&dtp->common, LIBERROR_BAD_US, NULL);
2691760c2415Smrg       return;
2692760c2415Smrg     }
2693760c2415Smrg 
2694760c2415Smrg   /* Only GFC_CONVERT_NATIVE and GFC_CONVERT_SWAP are valid here.  */
2695760c2415Smrg   if (likely (dtp->u.p.current_unit->flags.convert == GFC_CONVERT_NATIVE))
2696760c2415Smrg     {
2697760c2415Smrg       switch (nr)
2698760c2415Smrg 	{
2699760c2415Smrg 	case sizeof(GFC_INTEGER_4):
2700760c2415Smrg 	  memcpy (&i4, &i, sizeof (i4));
2701760c2415Smrg 	  i = i4;
2702760c2415Smrg 	  break;
2703760c2415Smrg 
2704760c2415Smrg 	case sizeof(GFC_INTEGER_8):
2705760c2415Smrg 	  memcpy (&i8, &i, sizeof (i8));
2706760c2415Smrg 	  i = i8;
2707760c2415Smrg 	  break;
2708760c2415Smrg 
2709760c2415Smrg 	default:
2710760c2415Smrg 	  runtime_error ("Illegal value for record marker");
2711760c2415Smrg 	  break;
2712760c2415Smrg 	}
2713760c2415Smrg     }
2714760c2415Smrg   else
2715760c2415Smrg     {
2716760c2415Smrg       uint32_t u32;
2717760c2415Smrg       uint64_t u64;
2718760c2415Smrg       switch (nr)
2719760c2415Smrg 	{
2720760c2415Smrg 	case sizeof(GFC_INTEGER_4):
2721760c2415Smrg 	  memcpy (&u32, &i, sizeof (u32));
2722760c2415Smrg 	  u32 = __builtin_bswap32 (u32);
2723760c2415Smrg 	  memcpy (&i4, &u32, sizeof (i4));
2724760c2415Smrg 	  i = i4;
2725760c2415Smrg 	  break;
2726760c2415Smrg 
2727760c2415Smrg 	case sizeof(GFC_INTEGER_8):
2728760c2415Smrg 	  memcpy (&u64, &i, sizeof (u64));
2729760c2415Smrg 	  u64 = __builtin_bswap64 (u64);
2730760c2415Smrg 	  memcpy (&i8, &u64, sizeof (i8));
2731760c2415Smrg 	  i = i8;
2732760c2415Smrg 	  break;
2733760c2415Smrg 
2734760c2415Smrg 	default:
2735760c2415Smrg 	  runtime_error ("Illegal value for record marker");
2736760c2415Smrg 	  break;
2737760c2415Smrg 	}
2738760c2415Smrg     }
2739760c2415Smrg 
2740760c2415Smrg   if (i >= 0)
2741760c2415Smrg     {
2742760c2415Smrg       dtp->u.p.current_unit->bytes_left_subrecord = i;
2743760c2415Smrg       dtp->u.p.current_unit->continued = 0;
2744760c2415Smrg     }
2745760c2415Smrg   else
2746760c2415Smrg     {
2747760c2415Smrg       dtp->u.p.current_unit->bytes_left_subrecord = -i;
2748760c2415Smrg       dtp->u.p.current_unit->continued = 1;
2749760c2415Smrg     }
2750760c2415Smrg 
2751760c2415Smrg   if (! continued)
2752760c2415Smrg     dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
2753760c2415Smrg }
2754760c2415Smrg 
2755760c2415Smrg 
2756760c2415Smrg /* Preposition a sequential unformatted file while writing.  This
2757760c2415Smrg    amount to writing a bogus length that will be filled in later.  */
2758760c2415Smrg 
2759760c2415Smrg static void
us_write(st_parameter_dt * dtp,int continued)2760760c2415Smrg us_write (st_parameter_dt *dtp, int continued)
2761760c2415Smrg {
2762760c2415Smrg   ssize_t nbytes;
2763760c2415Smrg   gfc_offset dummy;
2764760c2415Smrg 
2765760c2415Smrg   dummy = 0;
2766760c2415Smrg 
2767760c2415Smrg   if (compile_options.record_marker == 0)
2768760c2415Smrg     nbytes = sizeof (GFC_INTEGER_4);
2769760c2415Smrg   else
2770760c2415Smrg     nbytes = compile_options.record_marker ;
2771760c2415Smrg 
2772760c2415Smrg   if (swrite (dtp->u.p.current_unit->s, &dummy, nbytes) != nbytes)
2773760c2415Smrg     generate_error (&dtp->common, LIBERROR_OS, NULL);
2774760c2415Smrg 
2775760c2415Smrg   /* For sequential unformatted, if RECL= was not specified in the OPEN
2776760c2415Smrg      we write until we have more bytes than can fit in the subrecord
2777760c2415Smrg      markers, then we write a new subrecord.  */
2778760c2415Smrg 
2779760c2415Smrg   dtp->u.p.current_unit->bytes_left_subrecord =
2780760c2415Smrg     dtp->u.p.current_unit->recl_subrecord;
2781760c2415Smrg   dtp->u.p.current_unit->continued = continued;
2782760c2415Smrg }
2783760c2415Smrg 
2784760c2415Smrg 
2785760c2415Smrg /* Position to the next record prior to transfer.  We are assumed to
2786760c2415Smrg    be before the next record.  We also calculate the bytes in the next
2787760c2415Smrg    record.  */
2788760c2415Smrg 
2789760c2415Smrg static void
pre_position(st_parameter_dt * dtp)2790760c2415Smrg pre_position (st_parameter_dt *dtp)
2791760c2415Smrg {
2792760c2415Smrg   if (dtp->u.p.current_unit->current_record)
2793760c2415Smrg     return;			/* Already positioned.  */
2794760c2415Smrg 
2795760c2415Smrg   switch (current_mode (dtp))
2796760c2415Smrg     {
2797760c2415Smrg     case FORMATTED_STREAM:
2798760c2415Smrg     case UNFORMATTED_STREAM:
2799760c2415Smrg       /* There are no records with stream I/O.  If the position was specified
2800760c2415Smrg 	 data_transfer_init has already positioned the file. If no position
2801760c2415Smrg 	 was specified, we continue from where we last left off.  I.e.
2802760c2415Smrg 	 there is nothing to do here.  */
2803760c2415Smrg       break;
2804760c2415Smrg 
2805760c2415Smrg     case UNFORMATTED_SEQUENTIAL:
2806760c2415Smrg       if (dtp->u.p.mode == READING)
2807760c2415Smrg 	us_read (dtp, 0);
2808760c2415Smrg       else
2809760c2415Smrg 	us_write (dtp, 0);
2810760c2415Smrg 
2811760c2415Smrg       break;
2812760c2415Smrg 
2813760c2415Smrg     case FORMATTED_SEQUENTIAL:
2814760c2415Smrg     case FORMATTED_DIRECT:
2815760c2415Smrg     case UNFORMATTED_DIRECT:
2816760c2415Smrg       dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
2817760c2415Smrg       break;
2818*0bfacb9bSmrg     case FORMATTED_UNSPECIFIED:
2819*0bfacb9bSmrg       gcc_unreachable ();
2820760c2415Smrg     }
2821760c2415Smrg 
2822760c2415Smrg   dtp->u.p.current_unit->current_record = 1;
2823760c2415Smrg }
2824760c2415Smrg 
2825760c2415Smrg 
2826760c2415Smrg /* Initialize things for a data transfer.  This code is common for
2827760c2415Smrg    both reading and writing.  */
2828760c2415Smrg 
2829760c2415Smrg static void
data_transfer_init(st_parameter_dt * dtp,int read_flag)2830760c2415Smrg data_transfer_init (st_parameter_dt *dtp, int read_flag)
2831760c2415Smrg {
2832760c2415Smrg   unit_flags u_flags;  /* Used for creating a unit if needed.  */
2833760c2415Smrg   GFC_INTEGER_4 cf = dtp->common.flags;
2834760c2415Smrg   namelist_info *ionml;
2835760c2415Smrg   async_unit *au;
2836760c2415Smrg 
2837760c2415Smrg   NOTE ("data_transfer_init");
2838760c2415Smrg 
2839760c2415Smrg   ionml = ((cf & IOPARM_DT_IONML_SET) != 0) ? dtp->u.p.ionml : NULL;
2840760c2415Smrg 
2841760c2415Smrg   memset (&dtp->u.p, 0, sizeof (dtp->u.p));
2842760c2415Smrg 
2843760c2415Smrg   dtp->u.p.ionml = ionml;
2844760c2415Smrg   dtp->u.p.mode = read_flag ? READING : WRITING;
2845760c2415Smrg   dtp->u.p.namelist_mode = 0;
2846760c2415Smrg   dtp->u.p.cc.len = 0;
2847760c2415Smrg 
2848760c2415Smrg   if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
2849760c2415Smrg     return;
2850760c2415Smrg 
2851760c2415Smrg   dtp->u.p.current_unit = get_unit (dtp, 1);
2852760c2415Smrg 
2853760c2415Smrg   if (dtp->u.p.current_unit == NULL)
2854760c2415Smrg     {
2855760c2415Smrg       /* This means we tried to access an external unit < 0 without
2856760c2415Smrg 	 having opened it first with NEWUNIT=.  */
2857760c2415Smrg       generate_error (&dtp->common, LIBERROR_BAD_OPTION,
2858760c2415Smrg 		      "Unit number is negative and unit was not already "
2859760c2415Smrg 		      "opened with OPEN(NEWUNIT=...)");
2860760c2415Smrg       return;
2861760c2415Smrg     }
2862760c2415Smrg   else if (dtp->u.p.current_unit->s == NULL)
2863760c2415Smrg     {  /* Open the unit with some default flags.  */
2864760c2415Smrg       st_parameter_open opp;
2865760c2415Smrg       unit_convert conv;
2866760c2415Smrg       NOTE ("Open the unit with some default flags.");
2867760c2415Smrg       memset (&u_flags, '\0', sizeof (u_flags));
2868760c2415Smrg       u_flags.access = ACCESS_SEQUENTIAL;
2869760c2415Smrg       u_flags.action = ACTION_READWRITE;
2870760c2415Smrg 
2871760c2415Smrg       /* Is it unformatted?  */
2872760c2415Smrg       if (!(cf & (IOPARM_DT_HAS_FORMAT | IOPARM_DT_LIST_FORMAT
2873760c2415Smrg 		  | IOPARM_DT_IONML_SET)))
2874760c2415Smrg 	u_flags.form = FORM_UNFORMATTED;
2875760c2415Smrg       else
2876760c2415Smrg 	u_flags.form = FORM_UNSPECIFIED;
2877760c2415Smrg 
2878760c2415Smrg       u_flags.delim = DELIM_UNSPECIFIED;
2879760c2415Smrg       u_flags.blank = BLANK_UNSPECIFIED;
2880760c2415Smrg       u_flags.pad = PAD_UNSPECIFIED;
2881760c2415Smrg       u_flags.decimal = DECIMAL_UNSPECIFIED;
2882760c2415Smrg       u_flags.encoding = ENCODING_UNSPECIFIED;
2883760c2415Smrg       u_flags.async = ASYNC_UNSPECIFIED;
2884760c2415Smrg       u_flags.round = ROUND_UNSPECIFIED;
2885760c2415Smrg       u_flags.sign = SIGN_UNSPECIFIED;
2886760c2415Smrg       u_flags.share = SHARE_UNSPECIFIED;
2887760c2415Smrg       u_flags.cc = CC_UNSPECIFIED;
2888760c2415Smrg       u_flags.readonly = 0;
2889760c2415Smrg 
2890760c2415Smrg       u_flags.status = STATUS_UNKNOWN;
2891760c2415Smrg 
2892760c2415Smrg       conv = get_unformatted_convert (dtp->common.unit);
2893760c2415Smrg 
2894760c2415Smrg       if (conv == GFC_CONVERT_NONE)
2895760c2415Smrg 	conv = compile_options.convert;
2896760c2415Smrg 
2897760c2415Smrg       switch (conv)
2898760c2415Smrg 	{
2899760c2415Smrg 	case GFC_CONVERT_NATIVE:
2900760c2415Smrg 	case GFC_CONVERT_SWAP:
2901760c2415Smrg 	  break;
2902760c2415Smrg 
2903760c2415Smrg 	case GFC_CONVERT_BIG:
2904760c2415Smrg 	  conv = __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ? GFC_CONVERT_NATIVE : GFC_CONVERT_SWAP;
2905760c2415Smrg 	  break;
2906760c2415Smrg 
2907760c2415Smrg 	case GFC_CONVERT_LITTLE:
2908760c2415Smrg 	  conv = __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ? GFC_CONVERT_SWAP : GFC_CONVERT_NATIVE;
2909760c2415Smrg 	  break;
2910760c2415Smrg 
2911760c2415Smrg 	default:
2912760c2415Smrg 	  internal_error (&opp.common, "Illegal value for CONVERT");
2913760c2415Smrg 	  break;
2914760c2415Smrg 	}
2915760c2415Smrg 
2916760c2415Smrg       u_flags.convert = conv;
2917760c2415Smrg 
2918760c2415Smrg       opp.common = dtp->common;
2919760c2415Smrg       opp.common.flags &= IOPARM_COMMON_MASK;
2920760c2415Smrg       dtp->u.p.current_unit = new_unit (&opp, dtp->u.p.current_unit, &u_flags);
2921760c2415Smrg       dtp->common.flags &= ~IOPARM_COMMON_MASK;
2922760c2415Smrg       dtp->common.flags |= (opp.common.flags & IOPARM_COMMON_MASK);
2923760c2415Smrg       if (dtp->u.p.current_unit == NULL)
2924760c2415Smrg 	return;
2925760c2415Smrg     }
2926760c2415Smrg 
2927760c2415Smrg   if (dtp->u.p.current_unit->child_dtio == 0)
2928760c2415Smrg     {
2929760c2415Smrg       if ((cf & IOPARM_DT_HAS_SIZE) != 0)
2930760c2415Smrg 	{
2931760c2415Smrg 	  dtp->u.p.current_unit->has_size = true;
2932760c2415Smrg 	  /* Initialize the count.  */
2933760c2415Smrg 	  dtp->u.p.current_unit->size_used = 0;
2934760c2415Smrg 	}
2935760c2415Smrg       else
2936760c2415Smrg 	dtp->u.p.current_unit->has_size = false;
2937760c2415Smrg     }
2938760c2415Smrg   else if (dtp->u.p.current_unit->internal_unit_kind > 0)
2939760c2415Smrg     dtp->u.p.unit_is_internal = 1;
2940760c2415Smrg 
2941760c2415Smrg   if ((cf & IOPARM_DT_HAS_ASYNCHRONOUS) != 0)
2942760c2415Smrg     {
2943760c2415Smrg       int f;
2944760c2415Smrg       f = find_option (&dtp->common, dtp->asynchronous, dtp->asynchronous_len,
2945760c2415Smrg 		       async_opt, "Bad ASYNCHRONOUS in data transfer "
2946760c2415Smrg 		       "statement");
2947760c2415Smrg       if (f == ASYNC_YES && dtp->u.p.current_unit->flags.async != ASYNC_YES)
2948760c2415Smrg 	{
2949760c2415Smrg 	  generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
2950760c2415Smrg 			  "ASYNCHRONOUS transfer without "
2951760c2415Smrg 			  "ASYHCRONOUS='YES' in OPEN");
2952760c2415Smrg 	  return;
2953760c2415Smrg 	}
2954760c2415Smrg       dtp->u.p.async = f == ASYNC_YES;
2955760c2415Smrg     }
2956760c2415Smrg 
2957760c2415Smrg   au = dtp->u.p.current_unit->au;
2958760c2415Smrg   if (au)
2959760c2415Smrg     {
2960760c2415Smrg       if (dtp->u.p.async)
2961760c2415Smrg 	{
2962760c2415Smrg 	  /* If this is an asynchronous I/O statement, collect errors and
2963760c2415Smrg 	     return if there are any.  */
2964760c2415Smrg 	  if (collect_async_errors (&dtp->common, au))
2965760c2415Smrg 	    return;
2966760c2415Smrg 	}
2967760c2415Smrg       else
2968760c2415Smrg 	{
2969760c2415Smrg 	  /* Synchronous statement: Perform a wait operation for any pending
2970760c2415Smrg 	     asynchronous I/O.  This needs to be done before all other error
2971760c2415Smrg 	     checks.  See F2008, 9.6.4.1.  */
2972760c2415Smrg 	  if (async_wait (&(dtp->common), au))
2973760c2415Smrg 	    return;
2974760c2415Smrg 	}
2975760c2415Smrg     }
2976760c2415Smrg 
2977760c2415Smrg   /* Check the action.  */
2978760c2415Smrg 
2979760c2415Smrg   if (read_flag && dtp->u.p.current_unit->flags.action == ACTION_WRITE)
2980760c2415Smrg     {
2981760c2415Smrg       generate_error (&dtp->common, LIBERROR_BAD_ACTION,
2982760c2415Smrg 		      "Cannot read from file opened for WRITE");
2983760c2415Smrg       return;
2984760c2415Smrg     }
2985760c2415Smrg 
2986760c2415Smrg   if (!read_flag && dtp->u.p.current_unit->flags.action == ACTION_READ)
2987760c2415Smrg     {
2988760c2415Smrg       generate_error (&dtp->common, LIBERROR_BAD_ACTION,
2989760c2415Smrg 		      "Cannot write to file opened for READ");
2990760c2415Smrg       return;
2991760c2415Smrg     }
2992760c2415Smrg 
2993760c2415Smrg   dtp->u.p.first_item = 1;
2994760c2415Smrg 
2995760c2415Smrg   /* Check the format.  */
2996760c2415Smrg 
2997760c2415Smrg   if ((cf & IOPARM_DT_HAS_FORMAT) != 0)
2998760c2415Smrg     parse_format (dtp);
2999760c2415Smrg 
3000760c2415Smrg   if (dtp->u.p.current_unit->flags.form == FORM_UNFORMATTED
3001760c2415Smrg       && (cf & (IOPARM_DT_HAS_FORMAT | IOPARM_DT_LIST_FORMAT))
3002760c2415Smrg 	 != 0)
3003760c2415Smrg     {
3004760c2415Smrg       generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3005760c2415Smrg 		      "Format present for UNFORMATTED data transfer");
3006760c2415Smrg       return;
3007760c2415Smrg     }
3008760c2415Smrg 
3009760c2415Smrg   if ((cf & IOPARM_DT_HAS_NAMELIST_NAME) != 0 && dtp->u.p.ionml != NULL)
3010760c2415Smrg      {
3011760c2415Smrg 	if ((cf & IOPARM_DT_HAS_FORMAT) != 0)
3012760c2415Smrg 	  {
3013760c2415Smrg 	    generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3014760c2415Smrg 			"A format cannot be specified with a namelist");
3015760c2415Smrg 	    return;
3016760c2415Smrg 	  }
3017760c2415Smrg      }
3018760c2415Smrg   else if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED &&
3019760c2415Smrg 	   !(cf & (IOPARM_DT_HAS_FORMAT | IOPARM_DT_LIST_FORMAT)))
3020760c2415Smrg     {
3021760c2415Smrg       generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3022760c2415Smrg 		      "Missing format for FORMATTED data transfer");
3023760c2415Smrg       return;
3024760c2415Smrg     }
3025760c2415Smrg 
3026760c2415Smrg   if (is_internal_unit (dtp)
3027760c2415Smrg       && dtp->u.p.current_unit->flags.form == FORM_UNFORMATTED)
3028760c2415Smrg     {
3029760c2415Smrg       generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3030760c2415Smrg 		      "Internal file cannot be accessed by UNFORMATTED "
3031760c2415Smrg 		      "data transfer");
3032760c2415Smrg       return;
3033760c2415Smrg     }
3034760c2415Smrg 
3035760c2415Smrg   /* Check the record or position number.  */
3036760c2415Smrg 
3037760c2415Smrg   if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT
3038760c2415Smrg       && (cf & IOPARM_DT_HAS_REC) == 0)
3039760c2415Smrg     {
3040760c2415Smrg       generate_error (&dtp->common, LIBERROR_MISSING_OPTION,
3041760c2415Smrg 		      "Direct access data transfer requires record number");
3042760c2415Smrg       return;
3043760c2415Smrg     }
3044760c2415Smrg 
3045760c2415Smrg   if (dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL)
3046760c2415Smrg     {
3047760c2415Smrg       if ((cf & IOPARM_DT_HAS_REC) != 0)
3048760c2415Smrg 	{
3049760c2415Smrg 	  generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3050760c2415Smrg 			"Record number not allowed for sequential access "
3051760c2415Smrg 			"data transfer");
3052760c2415Smrg 	  return;
3053760c2415Smrg 	}
3054760c2415Smrg 
3055760c2415Smrg       if (compile_options.warn_std &&
3056760c2415Smrg 	  dtp->u.p.current_unit->endfile == AFTER_ENDFILE)
3057760c2415Smrg       	{
3058760c2415Smrg 	  generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3059760c2415Smrg 			"Sequential READ or WRITE not allowed after "
3060760c2415Smrg 			"EOF marker, possibly use REWIND or BACKSPACE");
3061760c2415Smrg 	  return;
3062760c2415Smrg 	}
3063760c2415Smrg     }
3064760c2415Smrg 
3065760c2415Smrg   /* Process the ADVANCE option.  */
3066760c2415Smrg 
3067760c2415Smrg   dtp->u.p.advance_status
3068760c2415Smrg     = !(cf & IOPARM_DT_HAS_ADVANCE) ? ADVANCE_UNSPECIFIED :
3069760c2415Smrg       find_option (&dtp->common, dtp->advance, dtp->advance_len, advance_opt,
3070760c2415Smrg 		   "Bad ADVANCE parameter in data transfer statement");
3071760c2415Smrg 
3072760c2415Smrg   if (dtp->u.p.advance_status != ADVANCE_UNSPECIFIED)
3073760c2415Smrg     {
3074760c2415Smrg       if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT)
3075760c2415Smrg 	{
3076760c2415Smrg 	  generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3077760c2415Smrg 			  "ADVANCE specification conflicts with sequential "
3078760c2415Smrg 			  "access");
3079760c2415Smrg 	  return;
3080760c2415Smrg 	}
3081760c2415Smrg 
3082760c2415Smrg       if (is_internal_unit (dtp))
3083760c2415Smrg 	{
3084760c2415Smrg 	  generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3085760c2415Smrg 			  "ADVANCE specification conflicts with internal file");
3086760c2415Smrg 	  return;
3087760c2415Smrg 	}
3088760c2415Smrg 
3089760c2415Smrg       if ((cf & (IOPARM_DT_HAS_FORMAT | IOPARM_DT_LIST_FORMAT))
3090760c2415Smrg 	  != IOPARM_DT_HAS_FORMAT)
3091760c2415Smrg 	{
3092760c2415Smrg 	  generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3093760c2415Smrg 			  "ADVANCE specification requires an explicit format");
3094760c2415Smrg 	  return;
3095760c2415Smrg 	}
3096760c2415Smrg     }
3097760c2415Smrg 
3098760c2415Smrg   /* Child IO is non-advancing and any ADVANCE= specifier is ignored.
3099760c2415Smrg      F2008 9.6.2.4  */
3100760c2415Smrg   if (dtp->u.p.current_unit->child_dtio  > 0)
3101760c2415Smrg     dtp->u.p.advance_status = ADVANCE_NO;
3102760c2415Smrg 
3103760c2415Smrg   if (read_flag)
3104760c2415Smrg     {
3105760c2415Smrg       dtp->u.p.current_unit->previous_nonadvancing_write = 0;
3106760c2415Smrg 
3107760c2415Smrg       if ((cf & IOPARM_EOR) != 0 && dtp->u.p.advance_status != ADVANCE_NO)
3108760c2415Smrg 	{
3109760c2415Smrg 	  generate_error (&dtp->common, LIBERROR_MISSING_OPTION,
3110760c2415Smrg 			  "EOR specification requires an ADVANCE specification "
3111760c2415Smrg 			  "of NO");
3112760c2415Smrg 	  return;
3113760c2415Smrg 	}
3114760c2415Smrg 
3115760c2415Smrg       if ((cf & IOPARM_DT_HAS_SIZE) != 0
3116760c2415Smrg 	  && dtp->u.p.advance_status != ADVANCE_NO)
3117760c2415Smrg 	{
3118760c2415Smrg 	  generate_error (&dtp->common, LIBERROR_MISSING_OPTION,
3119760c2415Smrg 			  "SIZE specification requires an ADVANCE "
3120760c2415Smrg 			  "specification of NO");
3121760c2415Smrg 	  return;
3122760c2415Smrg 	}
3123760c2415Smrg     }
3124760c2415Smrg   else
3125760c2415Smrg     {				/* Write constraints.  */
3126760c2415Smrg       if ((cf & IOPARM_END) != 0)
3127760c2415Smrg 	{
3128760c2415Smrg 	  generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3129760c2415Smrg 			  "END specification cannot appear in a write "
3130760c2415Smrg 			  "statement");
3131760c2415Smrg 	  return;
3132760c2415Smrg 	}
3133760c2415Smrg 
3134760c2415Smrg       if ((cf & IOPARM_EOR) != 0)
3135760c2415Smrg 	{
3136760c2415Smrg 	  generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3137760c2415Smrg 			  "EOR specification cannot appear in a write "
3138760c2415Smrg 			  "statement");
3139760c2415Smrg 	  return;
3140760c2415Smrg 	}
3141760c2415Smrg 
3142760c2415Smrg       if ((cf & IOPARM_DT_HAS_SIZE) != 0)
3143760c2415Smrg 	{
3144760c2415Smrg 	  generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3145760c2415Smrg 			  "SIZE specification cannot appear in a write "
3146760c2415Smrg 			  "statement");
3147760c2415Smrg 	  return;
3148760c2415Smrg 	}
3149760c2415Smrg     }
3150760c2415Smrg 
3151760c2415Smrg   if (dtp->u.p.advance_status == ADVANCE_UNSPECIFIED)
3152760c2415Smrg     dtp->u.p.advance_status = ADVANCE_YES;
3153760c2415Smrg 
3154760c2415Smrg   /* Check the decimal mode.  */
3155760c2415Smrg   dtp->u.p.current_unit->decimal_status
3156760c2415Smrg 	= !(cf & IOPARM_DT_HAS_DECIMAL) ? DECIMAL_UNSPECIFIED :
3157760c2415Smrg 	  find_option (&dtp->common, dtp->decimal, dtp->decimal_len,
3158760c2415Smrg 			decimal_opt, "Bad DECIMAL parameter in data transfer "
3159760c2415Smrg 			"statement");
3160760c2415Smrg 
3161760c2415Smrg   if (dtp->u.p.current_unit->decimal_status == DECIMAL_UNSPECIFIED)
3162760c2415Smrg 	dtp->u.p.current_unit->decimal_status = dtp->u.p.current_unit->flags.decimal;
3163760c2415Smrg 
3164760c2415Smrg   /* Check the round mode.  */
3165760c2415Smrg   dtp->u.p.current_unit->round_status
3166760c2415Smrg 	= !(cf & IOPARM_DT_HAS_ROUND) ? ROUND_UNSPECIFIED :
3167760c2415Smrg 	  find_option (&dtp->common, dtp->round, dtp->round_len,
3168760c2415Smrg 			round_opt, "Bad ROUND parameter in data transfer "
3169760c2415Smrg 			"statement");
3170760c2415Smrg 
3171760c2415Smrg   if (dtp->u.p.current_unit->round_status == ROUND_UNSPECIFIED)
3172760c2415Smrg 	dtp->u.p.current_unit->round_status = dtp->u.p.current_unit->flags.round;
3173760c2415Smrg 
3174760c2415Smrg   /* Check the sign mode. */
3175760c2415Smrg   dtp->u.p.sign_status
3176760c2415Smrg 	= !(cf & IOPARM_DT_HAS_SIGN) ? SIGN_UNSPECIFIED :
3177760c2415Smrg 	  find_option (&dtp->common, dtp->sign, dtp->sign_len, sign_opt,
3178760c2415Smrg 			"Bad SIGN parameter in data transfer statement");
3179760c2415Smrg 
3180760c2415Smrg   if (dtp->u.p.sign_status == SIGN_UNSPECIFIED)
3181760c2415Smrg 	dtp->u.p.sign_status = dtp->u.p.current_unit->flags.sign;
3182760c2415Smrg 
3183760c2415Smrg   /* Check the blank mode.  */
3184760c2415Smrg   dtp->u.p.blank_status
3185760c2415Smrg 	= !(cf & IOPARM_DT_HAS_BLANK) ? BLANK_UNSPECIFIED :
3186760c2415Smrg 	  find_option (&dtp->common, dtp->blank, dtp->blank_len,
3187760c2415Smrg 			blank_opt,
3188760c2415Smrg 			"Bad BLANK parameter in data transfer statement");
3189760c2415Smrg 
3190760c2415Smrg   if (dtp->u.p.blank_status == BLANK_UNSPECIFIED)
3191760c2415Smrg 	dtp->u.p.blank_status = dtp->u.p.current_unit->flags.blank;
3192760c2415Smrg 
3193760c2415Smrg   /* Check the delim mode.  */
3194760c2415Smrg   dtp->u.p.current_unit->delim_status
3195760c2415Smrg 	= !(cf & IOPARM_DT_HAS_DELIM) ? DELIM_UNSPECIFIED :
3196760c2415Smrg 	  find_option (&dtp->common, dtp->delim, dtp->delim_len,
3197760c2415Smrg 	  delim_opt, "Bad DELIM parameter in data transfer statement");
3198760c2415Smrg 
3199760c2415Smrg   if (dtp->u.p.current_unit->delim_status == DELIM_UNSPECIFIED)
3200760c2415Smrg     {
3201760c2415Smrg       if (ionml && dtp->u.p.current_unit->flags.delim == DELIM_UNSPECIFIED)
3202760c2415Smrg 	dtp->u.p.current_unit->delim_status = DELIM_QUOTE;
3203760c2415Smrg       else
3204760c2415Smrg 	dtp->u.p.current_unit->delim_status = dtp->u.p.current_unit->flags.delim;
3205760c2415Smrg     }
3206760c2415Smrg 
3207760c2415Smrg   /* Check the pad mode.  */
3208760c2415Smrg   dtp->u.p.current_unit->pad_status
3209760c2415Smrg 	= !(cf & IOPARM_DT_HAS_PAD) ? PAD_UNSPECIFIED :
3210760c2415Smrg 	  find_option (&dtp->common, dtp->pad, dtp->pad_len, pad_opt,
3211760c2415Smrg 			"Bad PAD parameter in data transfer statement");
3212760c2415Smrg 
3213760c2415Smrg   if (dtp->u.p.current_unit->pad_status == PAD_UNSPECIFIED)
3214760c2415Smrg 	dtp->u.p.current_unit->pad_status = dtp->u.p.current_unit->flags.pad;
3215760c2415Smrg 
3216760c2415Smrg   /* Set up the subroutine that will handle the transfers.  */
3217760c2415Smrg 
3218760c2415Smrg   if (read_flag)
3219760c2415Smrg     {
3220760c2415Smrg       if (dtp->u.p.current_unit->flags.form == FORM_UNFORMATTED)
3221760c2415Smrg 	dtp->u.p.transfer = unformatted_read;
3222760c2415Smrg       else
3223760c2415Smrg 	{
3224760c2415Smrg 	  if ((cf & IOPARM_DT_LIST_FORMAT) != 0)
3225760c2415Smrg 	    dtp->u.p.transfer = list_formatted_read;
3226760c2415Smrg 	  else
3227760c2415Smrg 	    dtp->u.p.transfer = formatted_transfer;
3228760c2415Smrg 	}
3229760c2415Smrg     }
3230760c2415Smrg   else
3231760c2415Smrg     {
3232760c2415Smrg       if (dtp->u.p.current_unit->flags.form == FORM_UNFORMATTED)
3233760c2415Smrg 	dtp->u.p.transfer = unformatted_write;
3234760c2415Smrg       else
3235760c2415Smrg 	{
3236760c2415Smrg 	  if ((cf & IOPARM_DT_LIST_FORMAT) != 0)
3237760c2415Smrg 	    dtp->u.p.transfer = list_formatted_write;
3238760c2415Smrg 	  else
3239760c2415Smrg 	    dtp->u.p.transfer = formatted_transfer;
3240760c2415Smrg 	}
3241760c2415Smrg     }
3242760c2415Smrg 
3243760c2415Smrg   if (au && dtp->u.p.async)
3244760c2415Smrg     {
3245760c2415Smrg       NOTE ("enqueue_data_transfer");
3246760c2415Smrg       enqueue_data_transfer_init (au, dtp, read_flag);
3247760c2415Smrg     }
3248760c2415Smrg   else
3249760c2415Smrg     {
3250760c2415Smrg       NOTE ("invoking data_transfer_init_worker");
3251760c2415Smrg       data_transfer_init_worker (dtp, read_flag);
3252760c2415Smrg     }
3253760c2415Smrg }
3254760c2415Smrg 
3255760c2415Smrg void
data_transfer_init_worker(st_parameter_dt * dtp,int read_flag)3256760c2415Smrg data_transfer_init_worker (st_parameter_dt *dtp, int read_flag)
3257760c2415Smrg {
3258760c2415Smrg   GFC_INTEGER_4 cf = dtp->common.flags;
3259760c2415Smrg 
3260760c2415Smrg   NOTE ("starting worker...");
3261760c2415Smrg 
3262760c2415Smrg   if (read_flag && dtp->u.p.current_unit->flags.form != FORM_UNFORMATTED
3263760c2415Smrg       && ((cf & IOPARM_DT_LIST_FORMAT) != 0)
3264760c2415Smrg       && dtp->u.p.current_unit->child_dtio  == 0)
3265760c2415Smrg     dtp->u.p.current_unit->last_char = EOF - 1;
3266760c2415Smrg 
3267760c2415Smrg   /* Check to see if we might be reading what we wrote before  */
3268760c2415Smrg 
3269760c2415Smrg   if (dtp->u.p.mode != dtp->u.p.current_unit->mode
3270760c2415Smrg       && !is_internal_unit (dtp))
3271760c2415Smrg     {
3272760c2415Smrg       int pos = fbuf_reset (dtp->u.p.current_unit);
3273760c2415Smrg       if (pos != 0)
3274760c2415Smrg         sseek (dtp->u.p.current_unit->s, pos, SEEK_CUR);
3275760c2415Smrg       sflush(dtp->u.p.current_unit->s);
3276760c2415Smrg     }
3277760c2415Smrg 
3278760c2415Smrg   /* Check the POS= specifier: that it is in range and that it is used with a
3279760c2415Smrg      unit that has been connected for STREAM access. F2003 9.5.1.10.  */
3280760c2415Smrg 
3281760c2415Smrg   if (((cf & IOPARM_DT_HAS_POS) != 0))
3282760c2415Smrg     {
3283760c2415Smrg       if (is_stream_io (dtp))
3284760c2415Smrg         {
3285760c2415Smrg 
3286760c2415Smrg           if (dtp->pos <= 0)
3287760c2415Smrg             {
3288760c2415Smrg               generate_error (&dtp->common, LIBERROR_BAD_OPTION,
3289760c2415Smrg                               "POS=specifier must be positive");
3290760c2415Smrg               return;
3291760c2415Smrg             }
3292760c2415Smrg 
3293760c2415Smrg           if (dtp->pos >= dtp->u.p.current_unit->maxrec)
3294760c2415Smrg             {
3295760c2415Smrg               generate_error (&dtp->common, LIBERROR_BAD_OPTION,
3296760c2415Smrg                               "POS=specifier too large");
3297760c2415Smrg               return;
3298760c2415Smrg             }
3299760c2415Smrg 
3300760c2415Smrg           dtp->rec = dtp->pos;
3301760c2415Smrg 
3302760c2415Smrg           if (dtp->u.p.mode == READING)
3303760c2415Smrg             {
3304760c2415Smrg               /* Reset the endfile flag; if we hit EOF during reading
3305760c2415Smrg                  we'll set the flag and generate an error at that point
3306760c2415Smrg                  rather than worrying about it here.  */
3307760c2415Smrg               dtp->u.p.current_unit->endfile = NO_ENDFILE;
3308760c2415Smrg             }
3309760c2415Smrg 
3310760c2415Smrg           if (dtp->pos != dtp->u.p.current_unit->strm_pos)
3311760c2415Smrg             {
3312760c2415Smrg 	      fbuf_reset (dtp->u.p.current_unit);
3313760c2415Smrg 	      if (sseek (dtp->u.p.current_unit->s, dtp->pos - 1,
3314760c2415Smrg 			 SEEK_SET) < 0)
3315760c2415Smrg                 {
3316760c2415Smrg                   generate_error (&dtp->common, LIBERROR_OS, NULL);
3317760c2415Smrg                   return;
3318760c2415Smrg                 }
3319760c2415Smrg               dtp->u.p.current_unit->strm_pos = dtp->pos;
3320760c2415Smrg             }
3321760c2415Smrg         }
3322760c2415Smrg       else
3323760c2415Smrg         {
3324760c2415Smrg           generate_error (&dtp->common, LIBERROR_BAD_OPTION,
3325760c2415Smrg                           "POS=specifier not allowed, "
3326760c2415Smrg                           "Try OPEN with ACCESS='stream'");
3327760c2415Smrg           return;
3328760c2415Smrg         }
3329760c2415Smrg     }
3330760c2415Smrg 
3331760c2415Smrg 
3332760c2415Smrg   /* Sanity checks on the record number.  */
3333760c2415Smrg   if ((cf & IOPARM_DT_HAS_REC) != 0)
3334760c2415Smrg     {
3335760c2415Smrg       if (dtp->rec <= 0)
3336760c2415Smrg 	{
3337760c2415Smrg 	  generate_error (&dtp->common, LIBERROR_BAD_OPTION,
3338760c2415Smrg 			  "Record number must be positive");
3339760c2415Smrg 	  return;
3340760c2415Smrg 	}
3341760c2415Smrg 
3342760c2415Smrg       if (dtp->rec >= dtp->u.p.current_unit->maxrec)
3343760c2415Smrg 	{
3344760c2415Smrg 	  generate_error (&dtp->common, LIBERROR_BAD_OPTION,
3345760c2415Smrg 			  "Record number too large");
3346760c2415Smrg 	  return;
3347760c2415Smrg 	}
3348760c2415Smrg 
3349760c2415Smrg       /* Make sure format buffer is reset.  */
3350760c2415Smrg       if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED)
3351760c2415Smrg         fbuf_reset (dtp->u.p.current_unit);
3352760c2415Smrg 
3353760c2415Smrg 
3354760c2415Smrg       /* Check whether the record exists to be read.  Only
3355760c2415Smrg 	 a partial record needs to exist.  */
3356760c2415Smrg 
3357760c2415Smrg       if (dtp->u.p.mode == READING && (dtp->rec - 1)
3358760c2415Smrg 	  * dtp->u.p.current_unit->recl >= ssize (dtp->u.p.current_unit->s))
3359760c2415Smrg 	{
3360760c2415Smrg 	  generate_error (&dtp->common, LIBERROR_BAD_OPTION,
3361760c2415Smrg 			  "Non-existing record number");
3362760c2415Smrg 	  return;
3363760c2415Smrg 	}
3364760c2415Smrg 
3365760c2415Smrg       /* Position the file.  */
3366760c2415Smrg       if (sseek (dtp->u.p.current_unit->s, (gfc_offset) (dtp->rec - 1)
3367760c2415Smrg 		 * dtp->u.p.current_unit->recl, SEEK_SET) < 0)
3368760c2415Smrg 	{
3369760c2415Smrg 	  generate_error (&dtp->common, LIBERROR_OS, NULL);
3370760c2415Smrg 	  return;
3371760c2415Smrg 	}
3372760c2415Smrg 
3373760c2415Smrg       if (dtp->u.p.current_unit->flags.access == ACCESS_STREAM)
3374760c2415Smrg        {
3375760c2415Smrg          generate_error (&dtp->common, LIBERROR_OPTION_CONFLICT,
3376760c2415Smrg                      "Record number not allowed for stream access "
3377760c2415Smrg                      "data transfer");
3378760c2415Smrg          return;
3379760c2415Smrg        }
3380760c2415Smrg     }
3381760c2415Smrg 
3382760c2415Smrg   /* Bugware for badly written mixed C-Fortran I/O.  */
3383760c2415Smrg   if (!is_internal_unit (dtp))
3384760c2415Smrg     flush_if_preconnected(dtp->u.p.current_unit->s);
3385760c2415Smrg 
3386760c2415Smrg   dtp->u.p.current_unit->mode = dtp->u.p.mode;
3387760c2415Smrg 
3388760c2415Smrg   /* Set the maximum position reached from the previous I/O operation.  This
3389760c2415Smrg      could be greater than zero from a previous non-advancing write.  */
3390760c2415Smrg   dtp->u.p.max_pos = dtp->u.p.current_unit->saved_pos;
3391760c2415Smrg 
3392760c2415Smrg   pre_position (dtp);
3393760c2415Smrg 
3394760c2415Smrg   /* Make sure that we don't do a read after a nonadvancing write.  */
3395760c2415Smrg 
3396760c2415Smrg   if (read_flag)
3397760c2415Smrg     {
3398760c2415Smrg       if (dtp->u.p.current_unit->read_bad && !is_stream_io (dtp))
3399760c2415Smrg 	{
3400760c2415Smrg 	  generate_error (&dtp->common, LIBERROR_BAD_OPTION,
3401760c2415Smrg 			  "Cannot READ after a nonadvancing WRITE");
3402760c2415Smrg 	  return;
3403760c2415Smrg 	}
3404760c2415Smrg     }
3405760c2415Smrg   else
3406760c2415Smrg     {
3407760c2415Smrg       if (dtp->u.p.advance_status == ADVANCE_YES && !dtp->u.p.seen_dollar)
3408760c2415Smrg 	dtp->u.p.current_unit->read_bad = 1;
3409760c2415Smrg     }
3410760c2415Smrg 
3411760c2415Smrg   if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED)
3412760c2415Smrg     {
3413760c2415Smrg #ifdef HAVE_USELOCALE
3414760c2415Smrg       dtp->u.p.old_locale = uselocale (c_locale);
3415760c2415Smrg #else
3416760c2415Smrg       __gthread_mutex_lock (&old_locale_lock);
3417760c2415Smrg       if (!old_locale_ctr++)
3418760c2415Smrg 	{
3419760c2415Smrg 	  old_locale = setlocale (LC_NUMERIC, NULL);
3420760c2415Smrg 	  setlocale (LC_NUMERIC, "C");
3421760c2415Smrg 	}
3422760c2415Smrg       __gthread_mutex_unlock (&old_locale_lock);
3423760c2415Smrg #endif
3424760c2415Smrg       /* Start the data transfer if we are doing a formatted transfer.  */
3425760c2415Smrg       if ((cf & (IOPARM_DT_LIST_FORMAT | IOPARM_DT_HAS_NAMELIST_NAME)) == 0
3426760c2415Smrg 	&& dtp->u.p.ionml == NULL)
3427760c2415Smrg 	formatted_transfer (dtp, 0, NULL, 0, 0, 1);
3428760c2415Smrg     }
3429760c2415Smrg }
3430760c2415Smrg 
3431760c2415Smrg 
3432760c2415Smrg /* Initialize an array_loop_spec given the array descriptor.  The function
3433760c2415Smrg    returns the index of the last element of the array, and also returns
3434760c2415Smrg    starting record, where the first I/O goes to (necessary in case of
3435760c2415Smrg    negative strides).  */
3436760c2415Smrg 
3437760c2415Smrg gfc_offset
init_loop_spec(gfc_array_char * desc,array_loop_spec * ls,gfc_offset * start_record)3438760c2415Smrg init_loop_spec (gfc_array_char *desc, array_loop_spec *ls,
3439760c2415Smrg 		gfc_offset *start_record)
3440760c2415Smrg {
3441760c2415Smrg   int rank = GFC_DESCRIPTOR_RANK(desc);
3442760c2415Smrg   int i;
3443760c2415Smrg   gfc_offset index;
3444760c2415Smrg   int empty;
3445760c2415Smrg 
3446760c2415Smrg   empty = 0;
3447760c2415Smrg   index = 1;
3448760c2415Smrg   *start_record = 0;
3449760c2415Smrg 
3450760c2415Smrg   for (i=0; i<rank; i++)
3451760c2415Smrg     {
3452760c2415Smrg       ls[i].idx = GFC_DESCRIPTOR_LBOUND(desc,i);
3453760c2415Smrg       ls[i].start = GFC_DESCRIPTOR_LBOUND(desc,i);
3454760c2415Smrg       ls[i].end = GFC_DESCRIPTOR_UBOUND(desc,i);
3455760c2415Smrg       ls[i].step = GFC_DESCRIPTOR_STRIDE(desc,i);
3456760c2415Smrg       empty = empty || (GFC_DESCRIPTOR_UBOUND(desc,i)
3457760c2415Smrg 			< GFC_DESCRIPTOR_LBOUND(desc,i));
3458760c2415Smrg 
3459760c2415Smrg       if (GFC_DESCRIPTOR_STRIDE(desc,i) > 0)
3460760c2415Smrg 	{
3461760c2415Smrg 	  index += (GFC_DESCRIPTOR_EXTENT(desc,i) - 1)
3462760c2415Smrg 	    * GFC_DESCRIPTOR_STRIDE(desc,i);
3463760c2415Smrg 	}
3464760c2415Smrg       else
3465760c2415Smrg 	{
3466760c2415Smrg 	  index -= (GFC_DESCRIPTOR_EXTENT(desc,i) - 1)
3467760c2415Smrg 	    * GFC_DESCRIPTOR_STRIDE(desc,i);
3468760c2415Smrg 	  *start_record -= (GFC_DESCRIPTOR_EXTENT(desc,i) - 1)
3469760c2415Smrg 	    * GFC_DESCRIPTOR_STRIDE(desc,i);
3470760c2415Smrg 	}
3471760c2415Smrg     }
3472760c2415Smrg 
3473760c2415Smrg   if (empty)
3474760c2415Smrg     return 0;
3475760c2415Smrg   else
3476760c2415Smrg     return index;
3477760c2415Smrg }
3478760c2415Smrg 
3479760c2415Smrg /* Determine the index to the next record in an internal unit array by
3480760c2415Smrg    by incrementing through the array_loop_spec.  */
3481760c2415Smrg 
3482760c2415Smrg gfc_offset
next_array_record(st_parameter_dt * dtp,array_loop_spec * ls,int * finished)3483760c2415Smrg next_array_record (st_parameter_dt *dtp, array_loop_spec *ls, int *finished)
3484760c2415Smrg {
3485760c2415Smrg   int i, carry;
3486760c2415Smrg   gfc_offset index;
3487760c2415Smrg 
3488760c2415Smrg   carry = 1;
3489760c2415Smrg   index = 0;
3490760c2415Smrg 
3491760c2415Smrg   for (i = 0; i < dtp->u.p.current_unit->rank; i++)
3492760c2415Smrg     {
3493760c2415Smrg       if (carry)
3494760c2415Smrg         {
3495760c2415Smrg           ls[i].idx++;
3496760c2415Smrg           if (ls[i].idx > ls[i].end)
3497760c2415Smrg             {
3498760c2415Smrg               ls[i].idx = ls[i].start;
3499760c2415Smrg               carry = 1;
3500760c2415Smrg             }
3501760c2415Smrg           else
3502760c2415Smrg             carry = 0;
3503760c2415Smrg         }
3504760c2415Smrg       index = index + (ls[i].idx - ls[i].start) * ls[i].step;
3505760c2415Smrg     }
3506760c2415Smrg 
3507760c2415Smrg   *finished = carry;
3508760c2415Smrg 
3509760c2415Smrg   return index;
3510760c2415Smrg }
3511760c2415Smrg 
3512760c2415Smrg 
3513760c2415Smrg 
3514760c2415Smrg /* Skip to the end of the current record, taking care of an optional
3515760c2415Smrg    record marker of size bytes.  If the file is not seekable, we
3516760c2415Smrg    read chunks of size MAX_READ until we get to the right
3517760c2415Smrg    position.  */
3518760c2415Smrg 
3519760c2415Smrg static void
skip_record(st_parameter_dt * dtp,gfc_offset bytes)3520760c2415Smrg skip_record (st_parameter_dt *dtp, gfc_offset bytes)
3521760c2415Smrg {
3522760c2415Smrg   ssize_t rlength, readb;
3523760c2415Smrg #define MAX_READ 4096
3524760c2415Smrg   char p[MAX_READ];
3525760c2415Smrg 
3526760c2415Smrg   dtp->u.p.current_unit->bytes_left_subrecord += bytes;
3527760c2415Smrg   if (dtp->u.p.current_unit->bytes_left_subrecord == 0)
3528760c2415Smrg     return;
3529760c2415Smrg 
3530760c2415Smrg   /* Direct access files do not generate END conditions,
3531760c2415Smrg      only I/O errors.  */
3532760c2415Smrg   if (sseek (dtp->u.p.current_unit->s,
3533760c2415Smrg 	     dtp->u.p.current_unit->bytes_left_subrecord, SEEK_CUR) < 0)
3534760c2415Smrg     {
3535760c2415Smrg       /* Seeking failed, fall back to seeking by reading data.  */
3536760c2415Smrg       while (dtp->u.p.current_unit->bytes_left_subrecord > 0)
3537760c2415Smrg 	{
3538760c2415Smrg 	  rlength =
3539760c2415Smrg 	    (MAX_READ < dtp->u.p.current_unit->bytes_left_subrecord) ?
3540760c2415Smrg 	    MAX_READ : dtp->u.p.current_unit->bytes_left_subrecord;
3541760c2415Smrg 
3542760c2415Smrg 	  readb = sread (dtp->u.p.current_unit->s, p, rlength);
3543760c2415Smrg 	  if (readb < 0)
3544760c2415Smrg 	    {
3545760c2415Smrg 	      generate_error (&dtp->common, LIBERROR_OS, NULL);
3546760c2415Smrg 	      return;
3547760c2415Smrg 	    }
3548760c2415Smrg 
3549760c2415Smrg 	  dtp->u.p.current_unit->bytes_left_subrecord -= readb;
3550760c2415Smrg 	}
3551760c2415Smrg       return;
3552760c2415Smrg     }
3553760c2415Smrg   dtp->u.p.current_unit->bytes_left_subrecord = 0;
3554760c2415Smrg }
3555760c2415Smrg 
3556760c2415Smrg 
3557760c2415Smrg /* Advance to the next record reading unformatted files, taking
3558760c2415Smrg    care of subrecords.  If complete_record is nonzero, we loop
3559760c2415Smrg    until all subrecords are cleared.  */
3560760c2415Smrg 
3561760c2415Smrg static void
next_record_r_unf(st_parameter_dt * dtp,int complete_record)3562760c2415Smrg next_record_r_unf (st_parameter_dt *dtp, int complete_record)
3563760c2415Smrg {
3564760c2415Smrg   size_t bytes;
3565760c2415Smrg 
3566760c2415Smrg   bytes =  compile_options.record_marker == 0 ?
3567760c2415Smrg     sizeof (GFC_INTEGER_4) : compile_options.record_marker;
3568760c2415Smrg 
3569760c2415Smrg   while(1)
3570760c2415Smrg     {
3571760c2415Smrg 
3572760c2415Smrg       /* Skip over tail */
3573760c2415Smrg 
3574760c2415Smrg       skip_record (dtp, bytes);
3575760c2415Smrg 
3576760c2415Smrg       if ( ! (complete_record && dtp->u.p.current_unit->continued))
3577760c2415Smrg 	return;
3578760c2415Smrg 
3579760c2415Smrg       us_read (dtp, 1);
3580760c2415Smrg     }
3581760c2415Smrg }
3582760c2415Smrg 
3583760c2415Smrg 
3584760c2415Smrg static gfc_offset
min_off(gfc_offset a,gfc_offset b)3585760c2415Smrg min_off (gfc_offset a, gfc_offset b)
3586760c2415Smrg {
3587760c2415Smrg   return (a < b ? a : b);
3588760c2415Smrg }
3589760c2415Smrg 
3590760c2415Smrg 
3591760c2415Smrg /* Space to the next record for read mode.  */
3592760c2415Smrg 
3593760c2415Smrg static void
next_record_r(st_parameter_dt * dtp,int done)3594760c2415Smrg next_record_r (st_parameter_dt *dtp, int done)
3595760c2415Smrg {
3596760c2415Smrg   gfc_offset record;
3597760c2415Smrg   char p;
3598760c2415Smrg   int cc;
3599760c2415Smrg 
3600760c2415Smrg   switch (current_mode (dtp))
3601760c2415Smrg     {
3602760c2415Smrg     /* No records in unformatted STREAM I/O.  */
3603760c2415Smrg     case UNFORMATTED_STREAM:
3604760c2415Smrg       return;
3605760c2415Smrg 
3606760c2415Smrg     case UNFORMATTED_SEQUENTIAL:
3607760c2415Smrg       next_record_r_unf (dtp, 1);
3608760c2415Smrg       dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
3609760c2415Smrg       break;
3610760c2415Smrg 
3611760c2415Smrg     case FORMATTED_DIRECT:
3612760c2415Smrg     case UNFORMATTED_DIRECT:
3613760c2415Smrg       skip_record (dtp, dtp->u.p.current_unit->bytes_left);
3614760c2415Smrg       break;
3615760c2415Smrg 
3616760c2415Smrg     case FORMATTED_STREAM:
3617760c2415Smrg     case FORMATTED_SEQUENTIAL:
3618760c2415Smrg       /* read_sf has already terminated input because of an '\n', or
3619760c2415Smrg          we have hit EOF.  */
3620760c2415Smrg       if (dtp->u.p.sf_seen_eor)
3621760c2415Smrg 	{
3622760c2415Smrg 	  dtp->u.p.sf_seen_eor = 0;
3623760c2415Smrg 	  break;
3624760c2415Smrg 	}
3625760c2415Smrg 
3626760c2415Smrg       if (is_internal_unit (dtp))
3627760c2415Smrg 	{
3628760c2415Smrg 	  if (is_array_io (dtp))
3629760c2415Smrg 	    {
3630760c2415Smrg 	      int finished;
3631760c2415Smrg 
3632760c2415Smrg 	      record = next_array_record (dtp, dtp->u.p.current_unit->ls,
3633760c2415Smrg 					  &finished);
3634760c2415Smrg 	      if (!done && finished)
3635760c2415Smrg 		hit_eof (dtp);
3636760c2415Smrg 
3637760c2415Smrg 	      /* Now seek to this record.  */
3638760c2415Smrg 	      record = record * dtp->u.p.current_unit->recl;
3639760c2415Smrg 	      if (sseek (dtp->u.p.current_unit->s, record, SEEK_SET) < 0)
3640760c2415Smrg 		{
3641760c2415Smrg 		  generate_error (&dtp->common, LIBERROR_INTERNAL_UNIT, NULL);
3642760c2415Smrg 		  break;
3643760c2415Smrg 		}
3644760c2415Smrg 	      dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
3645760c2415Smrg 	    }
3646760c2415Smrg 	  else
3647760c2415Smrg 	    {
3648760c2415Smrg 	      gfc_offset bytes_left = dtp->u.p.current_unit->bytes_left;
3649760c2415Smrg 	      bytes_left = min_off (bytes_left,
3650760c2415Smrg 		      ssize (dtp->u.p.current_unit->s)
3651760c2415Smrg 		      - stell (dtp->u.p.current_unit->s));
3652760c2415Smrg 	      if (sseek (dtp->u.p.current_unit->s,
3653760c2415Smrg 			 bytes_left, SEEK_CUR) < 0)
3654760c2415Smrg 	        {
3655760c2415Smrg 		  generate_error (&dtp->common, LIBERROR_INTERNAL_UNIT, NULL);
3656760c2415Smrg 		  break;
3657760c2415Smrg 		}
3658760c2415Smrg 	      dtp->u.p.current_unit->bytes_left
3659760c2415Smrg 		= dtp->u.p.current_unit->recl;
3660760c2415Smrg 	    }
3661760c2415Smrg 	  break;
3662760c2415Smrg 	}
3663760c2415Smrg       else if (dtp->u.p.current_unit->flags.cc != CC_NONE)
3664760c2415Smrg 	{
3665760c2415Smrg 	  do
3666760c2415Smrg 	    {
3667760c2415Smrg               errno = 0;
3668760c2415Smrg               cc = fbuf_getc (dtp->u.p.current_unit);
3669760c2415Smrg 	      if (cc == EOF)
3670760c2415Smrg 		{
3671760c2415Smrg                   if (errno != 0)
3672760c2415Smrg                     generate_error (&dtp->common, LIBERROR_OS, NULL);
3673760c2415Smrg 		  else
3674760c2415Smrg 		    {
3675760c2415Smrg 		      if (is_stream_io (dtp)
3676760c2415Smrg 			  || dtp->u.p.current_unit->pad_status == PAD_NO
3677760c2415Smrg 			  || dtp->u.p.current_unit->bytes_left
3678760c2415Smrg 			     == dtp->u.p.current_unit->recl)
3679760c2415Smrg 			hit_eof (dtp);
3680760c2415Smrg 		    }
3681760c2415Smrg 		  break;
3682760c2415Smrg                 }
3683760c2415Smrg 
3684760c2415Smrg 	      if (is_stream_io (dtp))
3685760c2415Smrg 		dtp->u.p.current_unit->strm_pos++;
3686760c2415Smrg 
3687760c2415Smrg               p = (char) cc;
3688760c2415Smrg 	    }
3689760c2415Smrg 	  while (p != '\n');
3690760c2415Smrg 	}
3691760c2415Smrg       break;
3692*0bfacb9bSmrg     case FORMATTED_UNSPECIFIED:
3693*0bfacb9bSmrg       gcc_unreachable ();
3694760c2415Smrg     }
3695760c2415Smrg }
3696760c2415Smrg 
3697760c2415Smrg 
3698760c2415Smrg /* Small utility function to write a record marker, taking care of
3699760c2415Smrg    byte swapping and of choosing the correct size.  */
3700760c2415Smrg 
3701760c2415Smrg static int
write_us_marker(st_parameter_dt * dtp,const gfc_offset buf)3702760c2415Smrg write_us_marker (st_parameter_dt *dtp, const gfc_offset buf)
3703760c2415Smrg {
3704760c2415Smrg   size_t len;
3705760c2415Smrg   GFC_INTEGER_4 buf4;
3706760c2415Smrg   GFC_INTEGER_8 buf8;
3707760c2415Smrg 
3708760c2415Smrg   if (compile_options.record_marker == 0)
3709760c2415Smrg     len = sizeof (GFC_INTEGER_4);
3710760c2415Smrg   else
3711760c2415Smrg     len = compile_options.record_marker;
3712760c2415Smrg 
3713760c2415Smrg   /* Only GFC_CONVERT_NATIVE and GFC_CONVERT_SWAP are valid here.  */
3714760c2415Smrg   if (likely (dtp->u.p.current_unit->flags.convert == GFC_CONVERT_NATIVE))
3715760c2415Smrg     {
3716760c2415Smrg       switch (len)
3717760c2415Smrg 	{
3718760c2415Smrg 	case sizeof (GFC_INTEGER_4):
3719760c2415Smrg 	  buf4 = buf;
3720760c2415Smrg 	  return swrite (dtp->u.p.current_unit->s, &buf4, len);
3721760c2415Smrg 	  break;
3722760c2415Smrg 
3723760c2415Smrg 	case sizeof (GFC_INTEGER_8):
3724760c2415Smrg 	  buf8 = buf;
3725760c2415Smrg 	  return swrite (dtp->u.p.current_unit->s, &buf8, len);
3726760c2415Smrg 	  break;
3727760c2415Smrg 
3728760c2415Smrg 	default:
3729760c2415Smrg 	  runtime_error ("Illegal value for record marker");
3730760c2415Smrg 	  break;
3731760c2415Smrg 	}
3732760c2415Smrg     }
3733760c2415Smrg   else
3734760c2415Smrg     {
3735760c2415Smrg       uint32_t u32;
3736760c2415Smrg       uint64_t u64;
3737760c2415Smrg       switch (len)
3738760c2415Smrg 	{
3739760c2415Smrg 	case sizeof (GFC_INTEGER_4):
3740760c2415Smrg 	  buf4 = buf;
3741760c2415Smrg 	  memcpy (&u32, &buf4, sizeof (u32));
3742760c2415Smrg 	  u32 = __builtin_bswap32 (u32);
3743760c2415Smrg 	  return swrite (dtp->u.p.current_unit->s, &u32, len);
3744760c2415Smrg 	  break;
3745760c2415Smrg 
3746760c2415Smrg 	case sizeof (GFC_INTEGER_8):
3747760c2415Smrg 	  buf8 = buf;
3748760c2415Smrg 	  memcpy (&u64, &buf8, sizeof (u64));
3749760c2415Smrg 	  u64 = __builtin_bswap64 (u64);
3750760c2415Smrg 	  return swrite (dtp->u.p.current_unit->s, &u64, len);
3751760c2415Smrg 	  break;
3752760c2415Smrg 
3753760c2415Smrg 	default:
3754760c2415Smrg 	  runtime_error ("Illegal value for record marker");
3755760c2415Smrg 	  break;
3756760c2415Smrg 	}
3757760c2415Smrg     }
3758760c2415Smrg 
3759760c2415Smrg }
3760760c2415Smrg 
3761760c2415Smrg /* Position to the next (sub)record in write mode for
3762760c2415Smrg    unformatted sequential files.  */
3763760c2415Smrg 
3764760c2415Smrg static void
next_record_w_unf(st_parameter_dt * dtp,int next_subrecord)3765760c2415Smrg next_record_w_unf (st_parameter_dt *dtp, int next_subrecord)
3766760c2415Smrg {
3767760c2415Smrg   gfc_offset m, m_write, record_marker;
3768760c2415Smrg 
3769760c2415Smrg   /* Bytes written.  */
3770760c2415Smrg   m = dtp->u.p.current_unit->recl_subrecord
3771760c2415Smrg     - dtp->u.p.current_unit->bytes_left_subrecord;
3772760c2415Smrg 
3773760c2415Smrg   if (compile_options.record_marker == 0)
3774760c2415Smrg     record_marker = sizeof (GFC_INTEGER_4);
3775760c2415Smrg   else
3776760c2415Smrg     record_marker = compile_options.record_marker;
3777760c2415Smrg 
3778760c2415Smrg   /* Seek to the head and overwrite the bogus length with the real
3779760c2415Smrg      length.  */
3780760c2415Smrg 
3781760c2415Smrg   if (unlikely (sseek (dtp->u.p.current_unit->s, - m - record_marker,
3782760c2415Smrg 		       SEEK_CUR) < 0))
3783760c2415Smrg     goto io_error;
3784760c2415Smrg 
3785760c2415Smrg   if (next_subrecord)
3786760c2415Smrg     m_write = -m;
3787760c2415Smrg   else
3788760c2415Smrg     m_write = m;
3789760c2415Smrg 
3790760c2415Smrg   if (unlikely (write_us_marker (dtp, m_write) < 0))
3791760c2415Smrg     goto io_error;
3792760c2415Smrg 
3793760c2415Smrg   /* Seek past the end of the current record.  */
3794760c2415Smrg 
3795760c2415Smrg   if (unlikely (sseek (dtp->u.p.current_unit->s, m, SEEK_CUR) < 0))
3796760c2415Smrg     goto io_error;
3797760c2415Smrg 
3798760c2415Smrg   /* Write the length tail.  If we finish a record containing
3799760c2415Smrg      subrecords, we write out the negative length.  */
3800760c2415Smrg 
3801760c2415Smrg   if (dtp->u.p.current_unit->continued)
3802760c2415Smrg     m_write = -m;
3803760c2415Smrg   else
3804760c2415Smrg     m_write = m;
3805760c2415Smrg 
3806760c2415Smrg   if (unlikely (write_us_marker (dtp, m_write) < 0))
3807760c2415Smrg     goto io_error;
3808760c2415Smrg 
3809760c2415Smrg   return;
3810760c2415Smrg 
3811760c2415Smrg  io_error:
3812760c2415Smrg   generate_error (&dtp->common, LIBERROR_OS, NULL);
3813760c2415Smrg   return;
3814760c2415Smrg 
3815760c2415Smrg }
3816760c2415Smrg 
3817760c2415Smrg 
3818760c2415Smrg /* Utility function like memset() but operating on streams. Return
3819760c2415Smrg    value is same as for POSIX write().  */
3820760c2415Smrg 
3821760c2415Smrg static gfc_offset
sset(stream * s,int c,gfc_offset nbyte)3822760c2415Smrg sset (stream *s, int c, gfc_offset nbyte)
3823760c2415Smrg {
3824760c2415Smrg #define WRITE_CHUNK 256
3825760c2415Smrg   char p[WRITE_CHUNK];
3826760c2415Smrg   gfc_offset bytes_left;
3827760c2415Smrg   ssize_t trans;
3828760c2415Smrg 
3829760c2415Smrg   if (nbyte < WRITE_CHUNK)
3830760c2415Smrg     memset (p, c, nbyte);
3831760c2415Smrg   else
3832760c2415Smrg     memset (p, c, WRITE_CHUNK);
3833760c2415Smrg 
3834760c2415Smrg   bytes_left = nbyte;
3835760c2415Smrg   while (bytes_left > 0)
3836760c2415Smrg     {
3837760c2415Smrg       trans = (bytes_left < WRITE_CHUNK) ? bytes_left : WRITE_CHUNK;
3838760c2415Smrg       trans = swrite (s, p, trans);
3839760c2415Smrg       if (trans <= 0)
3840760c2415Smrg 	return trans;
3841760c2415Smrg       bytes_left -= trans;
3842760c2415Smrg     }
3843760c2415Smrg 
3844760c2415Smrg   return nbyte - bytes_left;
3845760c2415Smrg }
3846760c2415Smrg 
3847760c2415Smrg 
3848760c2415Smrg /* Finish up a record according to the legacy carriagecontrol type, based
3849760c2415Smrg    on the first character in the record.  */
3850760c2415Smrg 
3851760c2415Smrg static void
next_record_cc(st_parameter_dt * dtp)3852760c2415Smrg next_record_cc (st_parameter_dt *dtp)
3853760c2415Smrg {
3854760c2415Smrg   /* Only valid with CARRIAGECONTROL=FORTRAN.  */
3855760c2415Smrg   if (dtp->u.p.current_unit->flags.cc != CC_FORTRAN)
3856760c2415Smrg     return;
3857760c2415Smrg 
3858760c2415Smrg   fbuf_seek (dtp->u.p.current_unit, 0, SEEK_END);
3859760c2415Smrg   if (dtp->u.p.cc.len > 0)
3860760c2415Smrg     {
3861760c2415Smrg       char *p = fbuf_alloc (dtp->u.p.current_unit, dtp->u.p.cc.len);
3862760c2415Smrg       if (!p)
3863760c2415Smrg 	generate_error (&dtp->common, LIBERROR_OS, NULL);
3864760c2415Smrg 
3865760c2415Smrg       /* Output CR for the first character with default CC setting.  */
3866760c2415Smrg       *(p++) = dtp->u.p.cc.u.end;
3867760c2415Smrg       if (dtp->u.p.cc.len > 1)
3868760c2415Smrg 	*p = dtp->u.p.cc.u.end;
3869760c2415Smrg     }
3870760c2415Smrg }
3871760c2415Smrg 
3872760c2415Smrg /* Position to the next record in write mode.  */
3873760c2415Smrg 
3874760c2415Smrg static void
next_record_w(st_parameter_dt * dtp,int done)3875760c2415Smrg next_record_w (st_parameter_dt *dtp, int done)
3876760c2415Smrg {
3877760c2415Smrg   gfc_offset max_pos_off;
3878760c2415Smrg 
3879760c2415Smrg   /* Zero counters for X- and T-editing.  */
3880760c2415Smrg   max_pos_off = dtp->u.p.max_pos;
3881760c2415Smrg   dtp->u.p.max_pos = dtp->u.p.skips = dtp->u.p.pending_spaces = 0;
3882760c2415Smrg 
3883760c2415Smrg   switch (current_mode (dtp))
3884760c2415Smrg     {
3885760c2415Smrg     /* No records in unformatted STREAM I/O.  */
3886760c2415Smrg     case UNFORMATTED_STREAM:
3887760c2415Smrg       return;
3888760c2415Smrg 
3889760c2415Smrg     case FORMATTED_DIRECT:
3890760c2415Smrg       if (dtp->u.p.current_unit->bytes_left == 0)
3891760c2415Smrg 	break;
3892760c2415Smrg 
3893760c2415Smrg       fbuf_seek (dtp->u.p.current_unit, 0, SEEK_END);
3894760c2415Smrg       fbuf_flush (dtp->u.p.current_unit, WRITING);
3895760c2415Smrg       if (sset (dtp->u.p.current_unit->s, ' ',
3896760c2415Smrg 		dtp->u.p.current_unit->bytes_left)
3897760c2415Smrg 	  != dtp->u.p.current_unit->bytes_left)
3898760c2415Smrg 	goto io_error;
3899760c2415Smrg 
3900760c2415Smrg       break;
3901760c2415Smrg 
3902760c2415Smrg     case UNFORMATTED_DIRECT:
3903760c2415Smrg       if (dtp->u.p.current_unit->bytes_left > 0)
3904760c2415Smrg 	{
3905760c2415Smrg 	  gfc_offset length = dtp->u.p.current_unit->bytes_left;
3906760c2415Smrg 	  if (sset (dtp->u.p.current_unit->s, 0, length) != length)
3907760c2415Smrg 	    goto io_error;
3908760c2415Smrg 	}
3909760c2415Smrg       break;
3910760c2415Smrg 
3911760c2415Smrg     case UNFORMATTED_SEQUENTIAL:
3912760c2415Smrg       next_record_w_unf (dtp, 0);
3913760c2415Smrg       dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
3914760c2415Smrg       break;
3915760c2415Smrg 
3916760c2415Smrg     case FORMATTED_STREAM:
3917760c2415Smrg     case FORMATTED_SEQUENTIAL:
3918760c2415Smrg 
3919760c2415Smrg       if (is_internal_unit (dtp))
3920760c2415Smrg 	{
3921760c2415Smrg 	  char *p;
3922760c2415Smrg 	  /* Internal unit, so must fit in memory.  */
3923760c2415Smrg 	  size_t length, m;
3924760c2415Smrg 	  size_t max_pos = max_pos_off;
3925760c2415Smrg 	  if (is_array_io (dtp))
3926760c2415Smrg 	    {
3927760c2415Smrg 	      int finished;
3928760c2415Smrg 
3929760c2415Smrg 	      length = dtp->u.p.current_unit->bytes_left;
3930760c2415Smrg 
3931760c2415Smrg 	      /* If the farthest position reached is greater than current
3932760c2415Smrg 	      position, adjust the position and set length to pad out
3933760c2415Smrg 	      whats left.  Otherwise just pad whats left.
3934760c2415Smrg 	      (for character array unit) */
3935760c2415Smrg 	      m = dtp->u.p.current_unit->recl
3936760c2415Smrg 			- dtp->u.p.current_unit->bytes_left;
3937760c2415Smrg 	      if (max_pos > m)
3938760c2415Smrg 		{
3939760c2415Smrg 		  length = (max_pos - m);
3940760c2415Smrg 		  if (sseek (dtp->u.p.current_unit->s,
3941760c2415Smrg 			     length, SEEK_CUR) < 0)
3942760c2415Smrg 		    {
3943760c2415Smrg 		      generate_error (&dtp->common, LIBERROR_INTERNAL_UNIT, NULL);
3944760c2415Smrg 		      return;
3945760c2415Smrg 		    }
3946760c2415Smrg 		  length = ((size_t) dtp->u.p.current_unit->recl - max_pos);
3947760c2415Smrg 		}
3948760c2415Smrg 
3949760c2415Smrg 	      p = write_block (dtp, length);
3950760c2415Smrg 	      if (p == NULL)
3951760c2415Smrg 		return;
3952760c2415Smrg 
3953760c2415Smrg 	      if (unlikely (is_char4_unit (dtp)))
3954760c2415Smrg 	        {
3955760c2415Smrg 		  gfc_char4_t *p4 = (gfc_char4_t *) p;
3956760c2415Smrg 		  memset4 (p4, ' ', length);
3957760c2415Smrg 		}
3958760c2415Smrg 	      else
3959760c2415Smrg 		memset (p, ' ', length);
3960760c2415Smrg 
3961760c2415Smrg 	      /* Now that the current record has been padded out,
3962760c2415Smrg 		 determine where the next record in the array is.
3963760c2415Smrg 		 Note that this can return a negative value, so it
3964760c2415Smrg 		 needs to be assigned to a signed value.  */
3965760c2415Smrg 	      gfc_offset record = next_array_record
3966760c2415Smrg 		(dtp, dtp->u.p.current_unit->ls, &finished);
3967760c2415Smrg 	      if (finished)
3968760c2415Smrg 		dtp->u.p.current_unit->endfile = AT_ENDFILE;
3969760c2415Smrg 
3970760c2415Smrg 	      /* Now seek to this record */
3971760c2415Smrg 	      record = record * dtp->u.p.current_unit->recl;
3972760c2415Smrg 
3973760c2415Smrg 	      if (sseek (dtp->u.p.current_unit->s, record, SEEK_SET) < 0)
3974760c2415Smrg 		{
3975760c2415Smrg 		  generate_error (&dtp->common, LIBERROR_INTERNAL_UNIT, NULL);
3976760c2415Smrg 		  return;
3977760c2415Smrg 		}
3978760c2415Smrg 
3979760c2415Smrg 	      dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
3980760c2415Smrg 	    }
3981760c2415Smrg 	  else
3982760c2415Smrg 	    {
3983760c2415Smrg 	      length = 1;
3984760c2415Smrg 
3985760c2415Smrg 	      /* If this is the last call to next_record move to the farthest
3986760c2415Smrg 		 position reached and set length to pad out the remainder
3987760c2415Smrg 		 of the record. (for character scaler unit) */
3988760c2415Smrg 	      if (done)
3989760c2415Smrg 		{
3990760c2415Smrg 		  m = dtp->u.p.current_unit->recl
3991760c2415Smrg 			- dtp->u.p.current_unit->bytes_left;
3992760c2415Smrg 		  if (max_pos > m)
3993760c2415Smrg 		    {
3994760c2415Smrg 		      length = max_pos - m;
3995760c2415Smrg 		      if (sseek (dtp->u.p.current_unit->s,
3996760c2415Smrg 				 length, SEEK_CUR) < 0)
3997760c2415Smrg 		        {
3998760c2415Smrg 			  generate_error (&dtp->common, LIBERROR_INTERNAL_UNIT, NULL);
3999760c2415Smrg 			  return;
4000760c2415Smrg 			}
4001760c2415Smrg 		      length = (size_t) dtp->u.p.current_unit->recl
4002760c2415Smrg 			- max_pos;
4003760c2415Smrg 		    }
4004760c2415Smrg 		  else
4005760c2415Smrg 		    length = dtp->u.p.current_unit->bytes_left;
4006760c2415Smrg 		}
4007760c2415Smrg 	      if (length > 0)
4008760c2415Smrg 		{
4009760c2415Smrg 		  p = write_block (dtp, length);
4010760c2415Smrg 		  if (p == NULL)
4011760c2415Smrg 		    return;
4012760c2415Smrg 
4013760c2415Smrg 		  if (unlikely (is_char4_unit (dtp)))
4014760c2415Smrg 		    {
4015760c2415Smrg 		      gfc_char4_t *p4 = (gfc_char4_t *) p;
4016760c2415Smrg 		      memset4 (p4, (gfc_char4_t) ' ', length);
4017760c2415Smrg 		    }
4018760c2415Smrg 		  else
4019760c2415Smrg 		    memset (p, ' ', length);
4020760c2415Smrg 		}
4021760c2415Smrg 	    }
4022760c2415Smrg 	}
4023760c2415Smrg       /* Handle legacy CARRIAGECONTROL line endings.  */
4024760c2415Smrg       else if (dtp->u.p.current_unit->flags.cc == CC_FORTRAN)
4025760c2415Smrg 	next_record_cc (dtp);
4026760c2415Smrg       else
4027760c2415Smrg 	{
4028760c2415Smrg 	  /* Skip newlines for CC=CC_NONE.  */
4029760c2415Smrg 	  const int len = (dtp->u.p.current_unit->flags.cc == CC_NONE)
4030760c2415Smrg 	    ? 0
4031760c2415Smrg #ifdef HAVE_CRLF
4032760c2415Smrg 	    : 2;
4033760c2415Smrg #else
4034760c2415Smrg 	    : 1;
4035760c2415Smrg #endif
4036760c2415Smrg 	  fbuf_seek (dtp->u.p.current_unit, 0, SEEK_END);
4037760c2415Smrg 	  if (dtp->u.p.current_unit->flags.cc != CC_NONE)
4038760c2415Smrg 	    {
4039760c2415Smrg 	      char *p = fbuf_alloc (dtp->u.p.current_unit, len);
4040760c2415Smrg 	      if (!p)
4041760c2415Smrg 		goto io_error;
4042760c2415Smrg #ifdef HAVE_CRLF
4043760c2415Smrg 	      *(p++) = '\r';
4044760c2415Smrg #endif
4045760c2415Smrg 	      *p = '\n';
4046760c2415Smrg 	    }
4047760c2415Smrg 	  if (is_stream_io (dtp))
4048760c2415Smrg 	    {
4049760c2415Smrg 	      dtp->u.p.current_unit->strm_pos += len;
4050760c2415Smrg 	      if (dtp->u.p.current_unit->strm_pos
4051760c2415Smrg 		  < ssize (dtp->u.p.current_unit->s))
4052760c2415Smrg 		unit_truncate (dtp->u.p.current_unit,
4053760c2415Smrg                                dtp->u.p.current_unit->strm_pos - 1,
4054760c2415Smrg                                &dtp->common);
4055760c2415Smrg 	    }
4056760c2415Smrg 	}
4057760c2415Smrg 
4058760c2415Smrg       break;
4059*0bfacb9bSmrg     case FORMATTED_UNSPECIFIED:
4060*0bfacb9bSmrg       gcc_unreachable ();
4061760c2415Smrg 
4062760c2415Smrg     io_error:
4063760c2415Smrg       generate_error (&dtp->common, LIBERROR_OS, NULL);
4064760c2415Smrg       break;
4065760c2415Smrg     }
4066760c2415Smrg }
4067760c2415Smrg 
4068760c2415Smrg /* Position to the next record, which means moving to the end of the
4069760c2415Smrg    current record.  This can happen under several different
4070760c2415Smrg    conditions.  If the done flag is not set, we get ready to process
4071760c2415Smrg    the next record.  */
4072760c2415Smrg 
4073760c2415Smrg void
next_record(st_parameter_dt * dtp,int done)4074760c2415Smrg next_record (st_parameter_dt *dtp, int done)
4075760c2415Smrg {
4076760c2415Smrg   gfc_offset fp; /* File position.  */
4077760c2415Smrg 
4078760c2415Smrg   dtp->u.p.current_unit->read_bad = 0;
4079760c2415Smrg 
4080760c2415Smrg   if (dtp->u.p.mode == READING)
4081760c2415Smrg     next_record_r (dtp, done);
4082760c2415Smrg   else
4083760c2415Smrg     next_record_w (dtp, done);
4084760c2415Smrg 
4085760c2415Smrg   fbuf_flush (dtp->u.p.current_unit, dtp->u.p.mode);
4086760c2415Smrg 
4087760c2415Smrg   if (!is_stream_io (dtp))
4088760c2415Smrg     {
4089760c2415Smrg       /* Since we have changed the position, set it to unspecified so
4090760c2415Smrg 	 that INQUIRE(POSITION=) knows it needs to look into it.  */
4091760c2415Smrg       if (done)
4092760c2415Smrg 	dtp->u.p.current_unit->flags.position = POSITION_UNSPECIFIED;
4093760c2415Smrg 
4094760c2415Smrg       dtp->u.p.current_unit->current_record = 0;
4095760c2415Smrg       if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT)
4096760c2415Smrg 	{
4097760c2415Smrg 	  fp = stell (dtp->u.p.current_unit->s);
4098760c2415Smrg 	  /* Calculate next record, rounding up partial records.  */
4099760c2415Smrg 	  dtp->u.p.current_unit->last_record =
4100760c2415Smrg 	    (fp + dtp->u.p.current_unit->recl) /
4101760c2415Smrg 	      dtp->u.p.current_unit->recl - 1;
4102760c2415Smrg 	}
4103760c2415Smrg       else
4104760c2415Smrg 	dtp->u.p.current_unit->last_record++;
4105760c2415Smrg     }
4106760c2415Smrg 
4107760c2415Smrg   if (!done)
4108760c2415Smrg     pre_position (dtp);
4109760c2415Smrg 
4110760c2415Smrg   smarkeor (dtp->u.p.current_unit->s);
4111760c2415Smrg }
4112760c2415Smrg 
4113760c2415Smrg 
4114760c2415Smrg /* Finalize the current data transfer.  For a nonadvancing transfer,
4115760c2415Smrg    this means advancing to the next record.  For internal units close the
4116760c2415Smrg    stream associated with the unit.  */
4117760c2415Smrg 
4118760c2415Smrg static void
finalize_transfer(st_parameter_dt * dtp)4119760c2415Smrg finalize_transfer (st_parameter_dt *dtp)
4120760c2415Smrg {
4121760c2415Smrg   GFC_INTEGER_4 cf = dtp->common.flags;
4122760c2415Smrg 
4123760c2415Smrg   if ((dtp->u.p.ionml != NULL)
4124760c2415Smrg       && (cf & IOPARM_DT_HAS_NAMELIST_NAME) != 0)
4125760c2415Smrg     {
4126760c2415Smrg        dtp->u.p.namelist_mode = 1;
4127760c2415Smrg        if ((cf & IOPARM_DT_NAMELIST_READ_MODE) != 0)
4128760c2415Smrg 	 namelist_read (dtp);
4129760c2415Smrg        else
4130760c2415Smrg 	 namelist_write (dtp);
4131760c2415Smrg     }
4132760c2415Smrg 
4133760c2415Smrg   if ((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0)
4134760c2415Smrg     *dtp->size = dtp->u.p.current_unit->size_used;
4135760c2415Smrg 
4136760c2415Smrg   if (dtp->u.p.eor_condition)
4137760c2415Smrg     {
4138760c2415Smrg       generate_error (&dtp->common, LIBERROR_EOR, NULL);
4139760c2415Smrg       goto done;
4140760c2415Smrg     }
4141760c2415Smrg 
4142760c2415Smrg   if (dtp->u.p.current_unit && (dtp->u.p.current_unit->child_dtio  > 0))
4143760c2415Smrg     {
4144760c2415Smrg       if (cf & IOPARM_DT_HAS_FORMAT)
4145760c2415Smrg         {
4146760c2415Smrg 	  free (dtp->u.p.fmt);
4147760c2415Smrg 	  free (dtp->format);
4148760c2415Smrg 	}
4149760c2415Smrg       return;
4150760c2415Smrg     }
4151760c2415Smrg 
4152760c2415Smrg   if ((dtp->common.flags & IOPARM_LIBRETURN_MASK) != IOPARM_LIBRETURN_OK)
4153760c2415Smrg     {
4154760c2415Smrg       if (dtp->u.p.current_unit && current_mode (dtp) == UNFORMATTED_SEQUENTIAL)
4155760c2415Smrg 	dtp->u.p.current_unit->current_record = 0;
4156760c2415Smrg       goto done;
4157760c2415Smrg     }
4158760c2415Smrg 
4159760c2415Smrg   dtp->u.p.transfer = NULL;
4160760c2415Smrg   if (dtp->u.p.current_unit == NULL)
4161760c2415Smrg     goto done;
4162760c2415Smrg 
4163760c2415Smrg   if ((cf & IOPARM_DT_LIST_FORMAT) != 0 && dtp->u.p.mode == READING)
4164760c2415Smrg     {
4165760c2415Smrg       finish_list_read (dtp);
4166760c2415Smrg       goto done;
4167760c2415Smrg     }
4168760c2415Smrg 
4169760c2415Smrg   if (dtp->u.p.mode == WRITING)
4170760c2415Smrg     dtp->u.p.current_unit->previous_nonadvancing_write
4171760c2415Smrg       = dtp->u.p.advance_status == ADVANCE_NO;
4172760c2415Smrg 
4173760c2415Smrg   if (is_stream_io (dtp))
4174760c2415Smrg     {
4175760c2415Smrg       if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED
4176760c2415Smrg 	  && dtp->u.p.advance_status != ADVANCE_NO)
4177760c2415Smrg 	next_record (dtp, 1);
4178760c2415Smrg 
4179760c2415Smrg       goto done;
4180760c2415Smrg     }
4181760c2415Smrg 
4182760c2415Smrg   dtp->u.p.current_unit->current_record = 0;
4183760c2415Smrg 
4184760c2415Smrg   if (!is_internal_unit (dtp) && dtp->u.p.seen_dollar)
4185760c2415Smrg     {
4186760c2415Smrg       fbuf_flush (dtp->u.p.current_unit, dtp->u.p.mode);
4187760c2415Smrg       dtp->u.p.seen_dollar = 0;
4188760c2415Smrg       goto done;
4189760c2415Smrg     }
4190760c2415Smrg 
4191760c2415Smrg   /* For non-advancing I/O, save the current maximum position for use in the
4192760c2415Smrg      next I/O operation if needed.  */
4193760c2415Smrg   if (dtp->u.p.advance_status == ADVANCE_NO)
4194760c2415Smrg     {
4195760c2415Smrg       if (dtp->u.p.skips > 0)
4196760c2415Smrg 	{
4197760c2415Smrg 	  int tmp;
4198760c2415Smrg 	  write_x (dtp, dtp->u.p.skips, dtp->u.p.pending_spaces);
4199760c2415Smrg 	  tmp = (int)(dtp->u.p.current_unit->recl
4200760c2415Smrg 		      - dtp->u.p.current_unit->bytes_left);
4201760c2415Smrg 	  dtp->u.p.max_pos =
4202760c2415Smrg 	    dtp->u.p.max_pos > tmp ? dtp->u.p.max_pos : tmp;
4203760c2415Smrg 	  dtp->u.p.skips = 0;
4204760c2415Smrg 	}
4205760c2415Smrg       int bytes_written = (int) (dtp->u.p.current_unit->recl
4206760c2415Smrg 	- dtp->u.p.current_unit->bytes_left);
4207760c2415Smrg       dtp->u.p.current_unit->saved_pos =
4208760c2415Smrg 	dtp->u.p.max_pos > 0 ? dtp->u.p.max_pos - bytes_written : 0;
4209760c2415Smrg       fbuf_flush (dtp->u.p.current_unit, dtp->u.p.mode);
4210760c2415Smrg       goto done;
4211760c2415Smrg     }
4212760c2415Smrg   else if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED
4213760c2415Smrg            && dtp->u.p.mode == WRITING && !is_internal_unit (dtp))
4214760c2415Smrg       fbuf_seek (dtp->u.p.current_unit, 0, SEEK_END);
4215760c2415Smrg 
4216760c2415Smrg   dtp->u.p.current_unit->saved_pos = 0;
4217760c2415Smrg   dtp->u.p.current_unit->last_char = EOF - 1;
4218760c2415Smrg   next_record (dtp, 1);
4219760c2415Smrg 
4220760c2415Smrg  done:
4221760c2415Smrg 
4222760c2415Smrg   if (dtp->u.p.unit_is_internal)
4223760c2415Smrg     {
4224760c2415Smrg       /* The unit structure may be reused later so clear the
4225760c2415Smrg 	 internal unit kind.  */
4226760c2415Smrg       dtp->u.p.current_unit->internal_unit_kind = 0;
4227760c2415Smrg 
4228760c2415Smrg       fbuf_destroy (dtp->u.p.current_unit);
4229760c2415Smrg       if (dtp->u.p.current_unit
4230760c2415Smrg 	  && (dtp->u.p.current_unit->child_dtio  == 0)
4231760c2415Smrg 	  && dtp->u.p.current_unit->s)
4232760c2415Smrg 	{
4233760c2415Smrg 	  sclose (dtp->u.p.current_unit->s);
4234760c2415Smrg 	  dtp->u.p.current_unit->s = NULL;
4235760c2415Smrg 	}
4236760c2415Smrg     }
4237760c2415Smrg 
4238760c2415Smrg #ifdef HAVE_USELOCALE
4239760c2415Smrg   if (dtp->u.p.old_locale != (locale_t) 0)
4240760c2415Smrg     {
4241760c2415Smrg       uselocale (dtp->u.p.old_locale);
4242760c2415Smrg       dtp->u.p.old_locale = (locale_t) 0;
4243760c2415Smrg     }
4244760c2415Smrg #else
4245760c2415Smrg   __gthread_mutex_lock (&old_locale_lock);
4246760c2415Smrg   if (!--old_locale_ctr)
4247760c2415Smrg     {
4248760c2415Smrg       setlocale (LC_NUMERIC, old_locale);
4249760c2415Smrg       old_locale = NULL;
4250760c2415Smrg     }
4251760c2415Smrg   __gthread_mutex_unlock (&old_locale_lock);
4252760c2415Smrg #endif
4253760c2415Smrg }
4254760c2415Smrg 
4255760c2415Smrg /* Transfer function for IOLENGTH. It doesn't actually do any
4256760c2415Smrg    data transfer, it just updates the length counter.  */
4257760c2415Smrg 
4258760c2415Smrg static void
iolength_transfer(st_parameter_dt * dtp,bt type,void * dest,int kind,size_t size,size_t nelems)4259760c2415Smrg iolength_transfer (st_parameter_dt *dtp, bt type __attribute__((unused)),
4260760c2415Smrg 		   void *dest __attribute__ ((unused)),
4261760c2415Smrg 		   int kind __attribute__((unused)),
4262760c2415Smrg 		   size_t size, size_t nelems)
4263760c2415Smrg {
4264760c2415Smrg   if ((dtp->common.flags & IOPARM_DT_HAS_IOLENGTH) != 0)
4265760c2415Smrg     *dtp->iolength += (GFC_IO_INT) (size * nelems);
4266760c2415Smrg }
4267760c2415Smrg 
4268760c2415Smrg 
4269760c2415Smrg /* Initialize the IOLENGTH data transfer. This function is in essence
4270760c2415Smrg    a very much simplified version of data_transfer_init(), because it
4271760c2415Smrg    doesn't have to deal with units at all.  */
4272760c2415Smrg 
4273760c2415Smrg static void
iolength_transfer_init(st_parameter_dt * dtp)4274760c2415Smrg iolength_transfer_init (st_parameter_dt *dtp)
4275760c2415Smrg {
4276760c2415Smrg   if ((dtp->common.flags & IOPARM_DT_HAS_IOLENGTH) != 0)
4277760c2415Smrg     *dtp->iolength = 0;
4278760c2415Smrg 
4279760c2415Smrg   memset (&dtp->u.p, 0, sizeof (dtp->u.p));
4280760c2415Smrg 
4281760c2415Smrg   /* Set up the subroutine that will handle the transfers.  */
4282760c2415Smrg 
4283760c2415Smrg   dtp->u.p.transfer = iolength_transfer;
4284760c2415Smrg }
4285760c2415Smrg 
4286760c2415Smrg 
4287760c2415Smrg /* Library entry point for the IOLENGTH form of the INQUIRE
4288760c2415Smrg    statement. The IOLENGTH form requires no I/O to be performed, but
4289760c2415Smrg    it must still be a runtime library call so that we can determine
4290760c2415Smrg    the iolength for dynamic arrays and such.  */
4291760c2415Smrg 
4292760c2415Smrg extern void st_iolength (st_parameter_dt *);
4293760c2415Smrg export_proto(st_iolength);
4294760c2415Smrg 
4295760c2415Smrg void
st_iolength(st_parameter_dt * dtp)4296760c2415Smrg st_iolength (st_parameter_dt *dtp)
4297760c2415Smrg {
4298760c2415Smrg   library_start (&dtp->common);
4299760c2415Smrg   iolength_transfer_init (dtp);
4300760c2415Smrg }
4301760c2415Smrg 
4302760c2415Smrg extern void st_iolength_done (st_parameter_dt *);
4303760c2415Smrg export_proto(st_iolength_done);
4304760c2415Smrg 
4305760c2415Smrg void
st_iolength_done(st_parameter_dt * dtp)4306760c2415Smrg st_iolength_done (st_parameter_dt *dtp __attribute__((unused)))
4307760c2415Smrg {
4308760c2415Smrg   free_ionml (dtp);
4309760c2415Smrg   library_end ();
4310760c2415Smrg }
4311760c2415Smrg 
4312760c2415Smrg 
4313760c2415Smrg /* The READ statement.  */
4314760c2415Smrg 
4315760c2415Smrg extern void st_read (st_parameter_dt *);
4316760c2415Smrg export_proto(st_read);
4317760c2415Smrg 
4318760c2415Smrg void
st_read(st_parameter_dt * dtp)4319760c2415Smrg st_read (st_parameter_dt *dtp)
4320760c2415Smrg {
4321760c2415Smrg   library_start (&dtp->common);
4322760c2415Smrg 
4323760c2415Smrg   data_transfer_init (dtp, 1);
4324760c2415Smrg }
4325760c2415Smrg 
4326760c2415Smrg extern void st_read_done (st_parameter_dt *);
4327760c2415Smrg export_proto(st_read_done);
4328760c2415Smrg 
4329760c2415Smrg void
st_read_done_worker(st_parameter_dt * dtp)4330760c2415Smrg st_read_done_worker (st_parameter_dt *dtp)
4331760c2415Smrg {
4332760c2415Smrg   finalize_transfer (dtp);
4333760c2415Smrg 
4334760c2415Smrg   free_ionml (dtp);
4335760c2415Smrg 
4336760c2415Smrg   /* If this is a parent READ statement we do not need to retain the
4337760c2415Smrg      internal unit structure for child use.  */
4338760c2415Smrg   if (dtp->u.p.current_unit != NULL
4339760c2415Smrg       && dtp->u.p.current_unit->child_dtio == 0)
4340760c2415Smrg     {
4341760c2415Smrg       if (dtp->u.p.unit_is_internal)
4342760c2415Smrg 	{
4343760c2415Smrg 	  if ((dtp->common.flags & IOPARM_DT_HAS_UDTIO) == 0)
4344760c2415Smrg 	    {
4345760c2415Smrg 	      free (dtp->u.p.current_unit->filename);
4346760c2415Smrg 	      dtp->u.p.current_unit->filename = NULL;
4347760c2415Smrg 	      if (dtp->u.p.current_unit->ls)
4348760c2415Smrg 		free (dtp->u.p.current_unit->ls);
4349760c2415Smrg 	      dtp->u.p.current_unit->ls = NULL;
4350760c2415Smrg 	    }
4351760c2415Smrg 	  newunit_free (dtp->common.unit);
4352760c2415Smrg 	}
4353760c2415Smrg       if (dtp->u.p.unit_is_internal || dtp->u.p.format_not_saved)
4354760c2415Smrg 	{
4355760c2415Smrg 	  free_format_data (dtp->u.p.fmt);
4356760c2415Smrg 	  free_format (dtp);
4357760c2415Smrg 	}
4358760c2415Smrg     }
4359760c2415Smrg }
4360760c2415Smrg 
4361760c2415Smrg void
st_read_done(st_parameter_dt * dtp)4362760c2415Smrg st_read_done (st_parameter_dt *dtp)
4363760c2415Smrg {
4364760c2415Smrg   if (dtp->u.p.current_unit)
4365760c2415Smrg     {
4366760c2415Smrg       if (dtp->u.p.current_unit->au)
4367760c2415Smrg 	{
4368760c2415Smrg 	  if (dtp->common.flags & IOPARM_DT_HAS_ID)
4369760c2415Smrg 	    *dtp->id = enqueue_done_id (dtp->u.p.current_unit->au, AIO_READ_DONE);
4370760c2415Smrg 	  else
4371760c2415Smrg 	    {
4372760c2415Smrg 	      if (dtp->u.p.async)
4373760c2415Smrg 		enqueue_done (dtp->u.p.current_unit->au, AIO_READ_DONE);
4374760c2415Smrg 	    }
4375760c2415Smrg 	}
4376760c2415Smrg       else
4377760c2415Smrg 	st_read_done_worker (dtp);
4378760c2415Smrg 
4379760c2415Smrg       unlock_unit (dtp->u.p.current_unit);
4380760c2415Smrg     }
4381760c2415Smrg 
4382760c2415Smrg   library_end ();
4383760c2415Smrg }
4384760c2415Smrg 
4385760c2415Smrg extern void st_write (st_parameter_dt *);
4386760c2415Smrg export_proto (st_write);
4387760c2415Smrg 
4388760c2415Smrg void
st_write(st_parameter_dt * dtp)4389760c2415Smrg st_write (st_parameter_dt *dtp)
4390760c2415Smrg {
4391760c2415Smrg   library_start (&dtp->common);
4392760c2415Smrg   data_transfer_init (dtp, 0);
4393760c2415Smrg }
4394760c2415Smrg 
4395760c2415Smrg 
4396760c2415Smrg void
st_write_done_worker(st_parameter_dt * dtp)4397760c2415Smrg st_write_done_worker (st_parameter_dt *dtp)
4398760c2415Smrg {
4399760c2415Smrg   finalize_transfer (dtp);
4400760c2415Smrg 
4401760c2415Smrg   if (dtp->u.p.current_unit != NULL
4402760c2415Smrg       && dtp->u.p.current_unit->child_dtio == 0)
4403760c2415Smrg     {
4404760c2415Smrg       /* Deal with endfile conditions associated with sequential files.  */
4405760c2415Smrg       if (dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL)
4406760c2415Smrg 	switch (dtp->u.p.current_unit->endfile)
4407760c2415Smrg 	  {
4408760c2415Smrg 	  case AT_ENDFILE:		/* Remain at the endfile record.  */
4409760c2415Smrg 	    break;
4410760c2415Smrg 
4411760c2415Smrg 	  case AFTER_ENDFILE:
4412760c2415Smrg 	    dtp->u.p.current_unit->endfile = AT_ENDFILE; /* Just at it now.  */
4413760c2415Smrg 	    break;
4414760c2415Smrg 
4415760c2415Smrg 	  case NO_ENDFILE:
4416760c2415Smrg 	    /* Get rid of whatever is after this record.  */
4417760c2415Smrg 	    if (!is_internal_unit (dtp))
4418760c2415Smrg 	      unit_truncate (dtp->u.p.current_unit,
4419760c2415Smrg 			     stell (dtp->u.p.current_unit->s),
4420760c2415Smrg 			     &dtp->common);
4421760c2415Smrg 	    dtp->u.p.current_unit->endfile = AT_ENDFILE;
4422760c2415Smrg 	    break;
4423760c2415Smrg 	  }
4424760c2415Smrg 
4425760c2415Smrg       free_ionml (dtp);
4426760c2415Smrg 
4427760c2415Smrg       /* If this is a parent WRITE statement we do not need to retain the
4428760c2415Smrg 	 internal unit structure for child use.  */
4429760c2415Smrg       if (dtp->u.p.unit_is_internal)
4430760c2415Smrg 	{
4431760c2415Smrg 	  if ((dtp->common.flags & IOPARM_DT_HAS_UDTIO) == 0)
4432760c2415Smrg 	    {
4433760c2415Smrg 	      free (dtp->u.p.current_unit->filename);
4434760c2415Smrg 	      dtp->u.p.current_unit->filename = NULL;
4435760c2415Smrg 	      if (dtp->u.p.current_unit->ls)
4436760c2415Smrg 		free (dtp->u.p.current_unit->ls);
4437760c2415Smrg 	      dtp->u.p.current_unit->ls = NULL;
4438760c2415Smrg 	    }
4439760c2415Smrg 	  newunit_free (dtp->common.unit);
4440760c2415Smrg 	}
4441760c2415Smrg       if (dtp->u.p.unit_is_internal || dtp->u.p.format_not_saved)
4442760c2415Smrg 	{
4443760c2415Smrg 	  free_format_data (dtp->u.p.fmt);
4444760c2415Smrg 	  free_format (dtp);
4445760c2415Smrg 	}
4446760c2415Smrg     }
4447760c2415Smrg }
4448760c2415Smrg 
4449760c2415Smrg extern void st_write_done (st_parameter_dt *);
4450760c2415Smrg export_proto(st_write_done);
4451760c2415Smrg 
4452760c2415Smrg void
st_write_done(st_parameter_dt * dtp)4453760c2415Smrg st_write_done (st_parameter_dt *dtp)
4454760c2415Smrg {
4455760c2415Smrg   if (dtp->u.p.current_unit)
4456760c2415Smrg     {
4457760c2415Smrg       if (dtp->u.p.current_unit->au && dtp->u.p.async)
4458760c2415Smrg 	{
4459760c2415Smrg 	  if (dtp->common.flags & IOPARM_DT_HAS_ID)
4460760c2415Smrg 	    *dtp->id = enqueue_done_id (dtp->u.p.current_unit->au,
4461760c2415Smrg 					AIO_WRITE_DONE);
4462760c2415Smrg 	  else
4463760c2415Smrg 	    {
4464760c2415Smrg 	      /* We perform synchronous I/O on an asynchronous unit, so no need
4465760c2415Smrg 		 to enqueue AIO_READ_DONE.  */
4466760c2415Smrg 	      if (dtp->u.p.async)
4467760c2415Smrg 		enqueue_done (dtp->u.p.current_unit->au, AIO_WRITE_DONE);
4468760c2415Smrg 	    }
4469760c2415Smrg 	}
4470760c2415Smrg       else
4471760c2415Smrg 	st_write_done_worker (dtp);
4472760c2415Smrg 
4473760c2415Smrg       unlock_unit (dtp->u.p.current_unit);
4474760c2415Smrg     }
4475760c2415Smrg 
4476760c2415Smrg   library_end ();
4477760c2415Smrg }
4478760c2415Smrg 
4479760c2415Smrg /* Wait operation.  We need to keep around the do-nothing version
4480760c2415Smrg  of st_wait for compatibility with previous versions, which had marked
4481760c2415Smrg  the argument as unused (and thus liable to be removed).
4482760c2415Smrg 
4483760c2415Smrg  TODO: remove at next bump in version number.  */
4484760c2415Smrg 
4485760c2415Smrg void
st_wait(st_parameter_wait * wtp)4486760c2415Smrg st_wait (st_parameter_wait *wtp __attribute__((unused)))
4487760c2415Smrg {
4488760c2415Smrg   return;
4489760c2415Smrg }
4490760c2415Smrg 
4491760c2415Smrg void
st_wait_async(st_parameter_wait * wtp)4492760c2415Smrg st_wait_async (st_parameter_wait *wtp)
4493760c2415Smrg {
4494760c2415Smrg   gfc_unit *u = find_unit (wtp->common.unit);
4495*0bfacb9bSmrg   if (ASYNC_IO && u && u->au)
4496760c2415Smrg     {
4497760c2415Smrg       if (wtp->common.flags & IOPARM_WAIT_HAS_ID)
4498760c2415Smrg 	async_wait_id (&(wtp->common), u->au, *wtp->id);
4499760c2415Smrg       else
4500760c2415Smrg 	async_wait (&(wtp->common), u->au);
4501760c2415Smrg     }
4502760c2415Smrg 
4503760c2415Smrg   unlock_unit (u);
4504760c2415Smrg }
4505760c2415Smrg 
4506760c2415Smrg 
4507760c2415Smrg /* Receives the scalar information for namelist objects and stores it
4508760c2415Smrg    in a linked list of namelist_info types.  */
4509760c2415Smrg 
4510760c2415Smrg 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)4511760c2415Smrg set_nml_var (st_parameter_dt *dtp, void *var_addr, char *var_name,
4512760c2415Smrg 	     GFC_INTEGER_4 len, gfc_charlen_type string_length,
4513760c2415Smrg 	     dtype_type dtype, void *dtio_sub, void *vtable)
4514760c2415Smrg {
4515760c2415Smrg   namelist_info *t1 = NULL;
4516760c2415Smrg   namelist_info *nml;
4517760c2415Smrg   size_t var_name_len = strlen (var_name);
4518760c2415Smrg 
4519760c2415Smrg   nml = (namelist_info*) xmalloc (sizeof (namelist_info));
4520760c2415Smrg 
4521760c2415Smrg   nml->mem_pos = var_addr;
4522760c2415Smrg   nml->dtio_sub = dtio_sub;
4523760c2415Smrg   nml->vtable = vtable;
4524760c2415Smrg 
4525760c2415Smrg   nml->var_name = (char*) xmalloc (var_name_len + 1);
4526760c2415Smrg   memcpy (nml->var_name, var_name, var_name_len);
4527760c2415Smrg   nml->var_name[var_name_len] = '\0';
4528760c2415Smrg 
4529760c2415Smrg   nml->len = (int) len;
4530760c2415Smrg   nml->string_length = (index_type) string_length;
4531760c2415Smrg 
4532760c2415Smrg   nml->var_rank = (int) (dtype.rank);
4533760c2415Smrg   nml->size = (index_type) (dtype.elem_len);
4534760c2415Smrg   nml->type = (bt) (dtype.type);
4535760c2415Smrg 
4536760c2415Smrg   if (nml->var_rank > 0)
4537760c2415Smrg     {
4538760c2415Smrg       nml->dim = (descriptor_dimension*)
4539760c2415Smrg 	xmallocarray (nml->var_rank, sizeof (descriptor_dimension));
4540760c2415Smrg       nml->ls = (array_loop_spec*)
4541760c2415Smrg 	xmallocarray (nml->var_rank, sizeof (array_loop_spec));
4542760c2415Smrg     }
4543760c2415Smrg   else
4544760c2415Smrg     {
4545760c2415Smrg       nml->dim = NULL;
4546760c2415Smrg       nml->ls = NULL;
4547760c2415Smrg     }
4548760c2415Smrg 
4549760c2415Smrg   nml->next = NULL;
4550760c2415Smrg 
4551760c2415Smrg   if ((dtp->common.flags & IOPARM_DT_IONML_SET) == 0)
4552760c2415Smrg     {
4553760c2415Smrg       dtp->common.flags |= IOPARM_DT_IONML_SET;
4554760c2415Smrg       dtp->u.p.ionml = nml;
4555760c2415Smrg     }
4556760c2415Smrg   else
4557760c2415Smrg     {
4558760c2415Smrg       for (t1 = dtp->u.p.ionml; t1->next; t1 = t1->next);
4559760c2415Smrg       t1->next = nml;
4560760c2415Smrg     }
4561760c2415Smrg }
4562760c2415Smrg 
4563760c2415Smrg extern void st_set_nml_var (st_parameter_dt *dtp, void *, char *,
4564760c2415Smrg 			    GFC_INTEGER_4, gfc_charlen_type, dtype_type);
4565760c2415Smrg export_proto(st_set_nml_var);
4566760c2415Smrg 
4567760c2415Smrg 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)4568760c2415Smrg st_set_nml_var (st_parameter_dt *dtp, void *var_addr, char *var_name,
4569760c2415Smrg 		GFC_INTEGER_4 len, gfc_charlen_type string_length,
4570760c2415Smrg 		dtype_type dtype)
4571760c2415Smrg {
4572760c2415Smrg   set_nml_var (dtp, var_addr, var_name, len, string_length,
4573760c2415Smrg 	       dtype, NULL, NULL);
4574760c2415Smrg }
4575760c2415Smrg 
4576760c2415Smrg 
4577760c2415Smrg /* Essentially the same as previous but carrying the dtio procedure
4578760c2415Smrg    and the vtable as additional arguments.  */
4579760c2415Smrg extern void st_set_nml_dtio_var (st_parameter_dt *dtp, void *, char *,
4580760c2415Smrg 				 GFC_INTEGER_4, gfc_charlen_type, dtype_type,
4581760c2415Smrg 				 void *, void *);
4582760c2415Smrg export_proto(st_set_nml_dtio_var);
4583760c2415Smrg 
4584760c2415Smrg 
4585760c2415Smrg 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)4586760c2415Smrg st_set_nml_dtio_var (st_parameter_dt *dtp, void *var_addr, char *var_name,
4587760c2415Smrg 		     GFC_INTEGER_4 len, gfc_charlen_type string_length,
4588760c2415Smrg 		     dtype_type dtype, void *dtio_sub, void *vtable)
4589760c2415Smrg {
4590760c2415Smrg   set_nml_var (dtp, var_addr, var_name, len, string_length,
4591760c2415Smrg 	       dtype, dtio_sub, vtable);
4592760c2415Smrg }
4593760c2415Smrg 
4594760c2415Smrg /* Store the dimensional information for the namelist object.  */
4595760c2415Smrg extern void st_set_nml_var_dim (st_parameter_dt *, GFC_INTEGER_4,
4596760c2415Smrg 				index_type, index_type,
4597760c2415Smrg 				index_type);
4598760c2415Smrg export_proto(st_set_nml_var_dim);
4599760c2415Smrg 
4600760c2415Smrg void
st_set_nml_var_dim(st_parameter_dt * dtp,GFC_INTEGER_4 n_dim,index_type stride,index_type lbound,index_type ubound)4601760c2415Smrg st_set_nml_var_dim (st_parameter_dt *dtp, GFC_INTEGER_4 n_dim,
4602760c2415Smrg 		    index_type stride, index_type lbound,
4603760c2415Smrg 		    index_type ubound)
4604760c2415Smrg {
4605760c2415Smrg   namelist_info *nml;
4606760c2415Smrg   int n;
4607760c2415Smrg 
4608760c2415Smrg   n = (int)n_dim;
4609760c2415Smrg 
4610760c2415Smrg   for (nml = dtp->u.p.ionml; nml->next; nml = nml->next);
4611760c2415Smrg 
4612760c2415Smrg   GFC_DIMENSION_SET(nml->dim[n],lbound,ubound,stride);
4613760c2415Smrg }
4614760c2415Smrg 
4615760c2415Smrg 
4616760c2415Smrg /* Once upon a time, a poor innocent Fortran program was reading a
4617760c2415Smrg    file, when suddenly it hit the end-of-file (EOF).  Unfortunately
4618760c2415Smrg    the OS doesn't tell whether we're at the EOF or whether we already
4619760c2415Smrg    went past it.  Luckily our hero, libgfortran, keeps track of this.
4620760c2415Smrg    Call this function when you detect an EOF condition.  See Section
4621760c2415Smrg    9.10.2 in F2003.  */
4622760c2415Smrg 
4623760c2415Smrg void
hit_eof(st_parameter_dt * dtp)4624760c2415Smrg hit_eof (st_parameter_dt *dtp)
4625760c2415Smrg {
4626760c2415Smrg   dtp->u.p.current_unit->flags.position = POSITION_APPEND;
4627760c2415Smrg 
4628760c2415Smrg   if (dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL)
4629760c2415Smrg     switch (dtp->u.p.current_unit->endfile)
4630760c2415Smrg       {
4631760c2415Smrg       case NO_ENDFILE:
4632760c2415Smrg       case AT_ENDFILE:
4633760c2415Smrg         generate_error (&dtp->common, LIBERROR_END, NULL);
4634760c2415Smrg 	if (!is_internal_unit (dtp) && !dtp->u.p.namelist_mode)
4635760c2415Smrg 	  {
4636760c2415Smrg 	    dtp->u.p.current_unit->endfile = AFTER_ENDFILE;
4637760c2415Smrg 	    dtp->u.p.current_unit->current_record = 0;
4638760c2415Smrg 	  }
4639760c2415Smrg         else
4640760c2415Smrg           dtp->u.p.current_unit->endfile = AT_ENDFILE;
4641760c2415Smrg 	break;
4642760c2415Smrg 
4643760c2415Smrg       case AFTER_ENDFILE:
4644760c2415Smrg 	generate_error (&dtp->common, LIBERROR_ENDFILE, NULL);
4645760c2415Smrg 	dtp->u.p.current_unit->current_record = 0;
4646760c2415Smrg 	break;
4647760c2415Smrg       }
4648760c2415Smrg   else
4649760c2415Smrg     {
4650760c2415Smrg       /* Non-sequential files don't have an ENDFILE record, so we
4651760c2415Smrg          can't be at AFTER_ENDFILE.  */
4652760c2415Smrg       dtp->u.p.current_unit->endfile = AT_ENDFILE;
4653760c2415Smrg       generate_error (&dtp->common, LIBERROR_END, NULL);
4654760c2415Smrg       dtp->u.p.current_unit->current_record = 0;
4655760c2415Smrg     }
4656760c2415Smrg }
4657