xref: /netbsd-src/external/gpl3/gcc/dist/libgfortran/io/file_pos.c (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1*b1e83836Smrg /* Copyright (C) 2002-2022 Free Software Foundation, Inc.
2181254a7Smrg    Contributed by Andy Vaught and Janne Blomqvist
3181254a7Smrg 
4181254a7Smrg This file is part of the GNU Fortran runtime library (libgfortran).
5181254a7Smrg 
6181254a7Smrg Libgfortran is free software; you can redistribute it and/or modify
7181254a7Smrg it under the terms of the GNU General Public License as published by
8181254a7Smrg the Free Software Foundation; either version 3, or (at your option)
9181254a7Smrg any later version.
10181254a7Smrg 
11181254a7Smrg Libgfortran is distributed in the hope that it will be useful,
12181254a7Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
13181254a7Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14181254a7Smrg GNU General Public License for more details.
15181254a7Smrg 
16181254a7Smrg Under Section 7 of GPL version 3, you are granted additional
17181254a7Smrg permissions described in the GCC Runtime Library Exception, version
18181254a7Smrg 3.1, as published by the Free Software Foundation.
19181254a7Smrg 
20181254a7Smrg You should have received a copy of the GNU General Public License and
21181254a7Smrg a copy of the GCC Runtime Library Exception along with this program;
22181254a7Smrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23181254a7Smrg <http://www.gnu.org/licenses/>.  */
24181254a7Smrg 
25181254a7Smrg #include "io.h"
26181254a7Smrg #include "fbuf.h"
27181254a7Smrg #include "unix.h"
28181254a7Smrg #include "async.h"
29181254a7Smrg #include <string.h>
30181254a7Smrg 
31181254a7Smrg /* file_pos.c-- Implement the file positioning statements, i.e. BACKSPACE,
32181254a7Smrg    ENDFILE, and REWIND as well as the FLUSH statement.  */
33181254a7Smrg 
34181254a7Smrg 
35181254a7Smrg /* formatted_backspace(fpp, u)-- Move the file back one line.  The
36181254a7Smrg    current position is after the newline that terminates the previous
37181254a7Smrg    record, and we have to sift backwards to find the newline before
38181254a7Smrg    that or the start of the file, whichever comes first.  */
39181254a7Smrg 
40181254a7Smrg #define READ_CHUNK 4096
41181254a7Smrg 
42181254a7Smrg static void
formatted_backspace(st_parameter_filepos * fpp,gfc_unit * u)43181254a7Smrg formatted_backspace (st_parameter_filepos *fpp, gfc_unit *u)
44181254a7Smrg {
45181254a7Smrg   gfc_offset base;
46181254a7Smrg   char p[READ_CHUNK];
47181254a7Smrg   ssize_t n;
48181254a7Smrg 
49181254a7Smrg   base = stell (u->s) - 1;
50181254a7Smrg 
51181254a7Smrg   do
52181254a7Smrg     {
53181254a7Smrg       n = (base < READ_CHUNK) ? base : READ_CHUNK;
54181254a7Smrg       base -= n;
55181254a7Smrg       if (sseek (u->s, base, SEEK_SET) < 0)
56181254a7Smrg         goto io_error;
57181254a7Smrg       if (sread (u->s, p, n) != n)
58181254a7Smrg 	goto io_error;
59181254a7Smrg 
60181254a7Smrg       /* We have moved backwards from the current position, it should
61181254a7Smrg          not be possible to get a short read.  Because it is not
62181254a7Smrg          clear what to do about such thing, we ignore the possibility.  */
63181254a7Smrg 
64181254a7Smrg       /* There is no memrchr() in the C library, so we have to do it
65181254a7Smrg          ourselves.  */
66181254a7Smrg 
67181254a7Smrg       while (n > 0)
68181254a7Smrg 	{
69181254a7Smrg           n--;
70181254a7Smrg 	  if (p[n] == '\n')
71181254a7Smrg 	    {
72181254a7Smrg 	      base += n + 1;
73181254a7Smrg 	      goto done;
74181254a7Smrg 	    }
75181254a7Smrg 	}
76181254a7Smrg 
77181254a7Smrg     }
78181254a7Smrg   while (base != 0);
79181254a7Smrg 
80181254a7Smrg   /* base is the new pointer.  Seek to it exactly.  */
81181254a7Smrg  done:
82181254a7Smrg   if (sseek (u->s, base, SEEK_SET) < 0)
83181254a7Smrg     goto io_error;
84181254a7Smrg   u->last_record--;
85181254a7Smrg   u->endfile = NO_ENDFILE;
86181254a7Smrg   u->last_char = EOF - 1;
87181254a7Smrg   return;
88181254a7Smrg 
89181254a7Smrg  io_error:
90181254a7Smrg   generate_error (&fpp->common, LIBERROR_OS, NULL);
91181254a7Smrg }
92181254a7Smrg 
93181254a7Smrg 
94181254a7Smrg /* unformatted_backspace(fpp) -- Move the file backwards for an unformatted
95181254a7Smrg    sequential file.  We are guaranteed to be between records on entry and
96181254a7Smrg    we have to shift to the previous record.  Loop over subrecords.  */
97181254a7Smrg 
98181254a7Smrg static void
unformatted_backspace(st_parameter_filepos * fpp,gfc_unit * u)99181254a7Smrg unformatted_backspace (st_parameter_filepos *fpp, gfc_unit *u)
100181254a7Smrg {
101181254a7Smrg   gfc_offset m, slen;
102181254a7Smrg   GFC_INTEGER_4 m4;
103181254a7Smrg   GFC_INTEGER_8 m8;
104181254a7Smrg   ssize_t length;
105181254a7Smrg   int continued;
106181254a7Smrg   char p[sizeof (GFC_INTEGER_8)];
107*b1e83836Smrg   int convert = u->flags.convert;
108*b1e83836Smrg 
109*b1e83836Smrg #ifdef HAVE_GFC_REAL_17
110*b1e83836Smrg   convert &= ~(GFC_CONVERT_R16_IEEE | GFC_CONVERT_R16_IBM);
111*b1e83836Smrg #endif
112181254a7Smrg 
113181254a7Smrg   if (compile_options.record_marker == 0)
114181254a7Smrg     length = sizeof (GFC_INTEGER_4);
115181254a7Smrg   else
116181254a7Smrg     length = compile_options.record_marker;
117181254a7Smrg 
118181254a7Smrg   do
119181254a7Smrg     {
120181254a7Smrg       slen = - (gfc_offset) length;
121181254a7Smrg       if (sseek (u->s, slen, SEEK_CUR) < 0)
122181254a7Smrg         goto io_error;
123181254a7Smrg       if (sread (u->s, p, length) != length)
124181254a7Smrg         goto io_error;
125181254a7Smrg 
126181254a7Smrg       /* Only GFC_CONVERT_NATIVE and GFC_CONVERT_SWAP are valid here.  */
127*b1e83836Smrg       if (likely (convert == GFC_CONVERT_NATIVE))
128181254a7Smrg 	{
129181254a7Smrg 	  switch (length)
130181254a7Smrg 	    {
131181254a7Smrg 	    case sizeof(GFC_INTEGER_4):
132181254a7Smrg 	      memcpy (&m4, p, sizeof (m4));
133181254a7Smrg 	      m = m4;
134181254a7Smrg 	      break;
135181254a7Smrg 
136181254a7Smrg 	    case sizeof(GFC_INTEGER_8):
137181254a7Smrg 	      memcpy (&m8, p, sizeof (m8));
138181254a7Smrg 	      m = m8;
139181254a7Smrg 	      break;
140181254a7Smrg 
141181254a7Smrg 	    default:
142181254a7Smrg 	      runtime_error ("Illegal value for record marker");
143181254a7Smrg 	      break;
144181254a7Smrg 	    }
145181254a7Smrg 	}
146181254a7Smrg       else
147181254a7Smrg 	{
148181254a7Smrg 	  uint32_t u32;
149181254a7Smrg 	  uint64_t u64;
150181254a7Smrg 	  switch (length)
151181254a7Smrg 	    {
152181254a7Smrg 	    case sizeof(GFC_INTEGER_4):
153181254a7Smrg 	      memcpy (&u32, p, sizeof (u32));
154181254a7Smrg 	      u32 = __builtin_bswap32 (u32);
155181254a7Smrg 	      memcpy (&m4, &u32, sizeof (m4));
156181254a7Smrg 	      m = m4;
157181254a7Smrg 	      break;
158181254a7Smrg 
159181254a7Smrg 	    case sizeof(GFC_INTEGER_8):
160181254a7Smrg 	      memcpy (&u64, p, sizeof (u64));
161181254a7Smrg 	      u64 = __builtin_bswap64 (u64);
162181254a7Smrg 	      memcpy (&m8, &u64, sizeof (m8));
163181254a7Smrg 	      m = m8;
164181254a7Smrg 	      break;
165181254a7Smrg 
166181254a7Smrg 	    default:
167181254a7Smrg 	      runtime_error ("Illegal value for record marker");
168181254a7Smrg 	      break;
169181254a7Smrg 	    }
170181254a7Smrg 
171181254a7Smrg 	}
172181254a7Smrg 
173181254a7Smrg       continued = m < 0;
174181254a7Smrg       if (continued)
175181254a7Smrg 	m = -m;
176181254a7Smrg 
177181254a7Smrg       if (sseek (u->s, -m -2 * length, SEEK_CUR) < 0)
178181254a7Smrg 	goto io_error;
179181254a7Smrg     } while (continued);
180181254a7Smrg 
181181254a7Smrg   u->last_record--;
182181254a7Smrg   return;
183181254a7Smrg 
184181254a7Smrg  io_error:
185181254a7Smrg   generate_error (&fpp->common, LIBERROR_OS, NULL);
186181254a7Smrg }
187181254a7Smrg 
188181254a7Smrg 
189181254a7Smrg extern void st_backspace (st_parameter_filepos *);
190181254a7Smrg export_proto(st_backspace);
191181254a7Smrg 
192181254a7Smrg void
st_backspace(st_parameter_filepos * fpp)193181254a7Smrg st_backspace (st_parameter_filepos *fpp)
194181254a7Smrg {
195181254a7Smrg   gfc_unit *u;
196181254a7Smrg   bool needs_unlock = false;
197181254a7Smrg 
198181254a7Smrg   library_start (&fpp->common);
199181254a7Smrg 
200181254a7Smrg   u = find_unit (fpp->common.unit);
201181254a7Smrg   if (u == NULL)
202181254a7Smrg     {
203181254a7Smrg       generate_error (&fpp->common, LIBERROR_BAD_UNIT, NULL);
204181254a7Smrg       goto done;
205181254a7Smrg     }
206181254a7Smrg 
207181254a7Smrg   /* Direct access is prohibited, and so is unformatted stream access.  */
208181254a7Smrg 
209181254a7Smrg 
210181254a7Smrg   if (u->flags.access == ACCESS_DIRECT)
211181254a7Smrg     {
212181254a7Smrg       generate_error (&fpp->common, LIBERROR_OPTION_CONFLICT,
213181254a7Smrg 		      "Cannot BACKSPACE a file opened for DIRECT access");
214181254a7Smrg       goto done;
215181254a7Smrg     }
216181254a7Smrg 
217181254a7Smrg   if (u->flags.access == ACCESS_STREAM && u->flags.form == FORM_UNFORMATTED)
218181254a7Smrg     {
219181254a7Smrg       generate_error (&fpp->common, LIBERROR_OPTION_CONFLICT,
220181254a7Smrg                       "Cannot BACKSPACE an unformatted stream file");
221181254a7Smrg       goto done;
222181254a7Smrg     }
223181254a7Smrg 
224181254a7Smrg   if (ASYNC_IO && u->au)
225181254a7Smrg     {
226181254a7Smrg       if (async_wait (&(fpp->common), u->au))
227181254a7Smrg 	return;
228181254a7Smrg       else
229181254a7Smrg 	{
230181254a7Smrg 	  needs_unlock = true;
231181254a7Smrg 	  LOCK (&u->au->io_lock);
232181254a7Smrg 	}
233181254a7Smrg     }
234181254a7Smrg 
235181254a7Smrg   /* Make sure format buffer is flushed and reset.  */
236181254a7Smrg   if (u->flags.form == FORM_FORMATTED)
237181254a7Smrg     {
238181254a7Smrg       int pos = fbuf_reset (u);
239181254a7Smrg       if (pos != 0)
240181254a7Smrg         sseek (u->s, pos, SEEK_CUR);
241181254a7Smrg     }
242181254a7Smrg 
243181254a7Smrg 
244181254a7Smrg   /* Check for special cases involving the ENDFILE record first.  */
245181254a7Smrg 
246181254a7Smrg   if (u->endfile == AFTER_ENDFILE)
247181254a7Smrg     {
248181254a7Smrg       u->endfile = AT_ENDFILE;
249181254a7Smrg       u->flags.position = POSITION_APPEND;
250181254a7Smrg       sflush (u->s);
251181254a7Smrg     }
252181254a7Smrg   else
253181254a7Smrg     {
254181254a7Smrg       if (stell (u->s) == 0)
255181254a7Smrg 	{
256181254a7Smrg 	  u->flags.position = POSITION_REWIND;
257181254a7Smrg 	  goto done;		/* Common special case */
258181254a7Smrg 	}
259181254a7Smrg 
260181254a7Smrg       if (u->mode == WRITING)
261181254a7Smrg 	{
262181254a7Smrg 	  /* If there are previously written bytes from a write with
263181254a7Smrg 	     ADVANCE="no", add a record marker before performing the
264181254a7Smrg 	     BACKSPACE.  */
265181254a7Smrg 
266181254a7Smrg 	  if (u->previous_nonadvancing_write)
267181254a7Smrg 	    finish_last_advance_record (u);
268181254a7Smrg 
269181254a7Smrg 	  u->previous_nonadvancing_write = 0;
270181254a7Smrg 
271181254a7Smrg 	  unit_truncate (u, stell (u->s), &fpp->common);
272181254a7Smrg 	  u->mode = READING;
273181254a7Smrg         }
274181254a7Smrg 
275181254a7Smrg       if (u->flags.form == FORM_FORMATTED)
276181254a7Smrg 	formatted_backspace (fpp, u);
277181254a7Smrg       else
278181254a7Smrg 	unformatted_backspace (fpp, u);
279181254a7Smrg 
280181254a7Smrg       u->flags.position = POSITION_UNSPECIFIED;
281181254a7Smrg       u->endfile = NO_ENDFILE;
282181254a7Smrg       u->current_record = 0;
283181254a7Smrg       u->bytes_left = 0;
284181254a7Smrg     }
285181254a7Smrg 
286181254a7Smrg  done:
287181254a7Smrg   if (u != NULL)
288181254a7Smrg     {
289181254a7Smrg       unlock_unit (u);
290181254a7Smrg 
291181254a7Smrg       if (ASYNC_IO && u->au && needs_unlock)
292181254a7Smrg 	UNLOCK (&u->au->io_lock);
293181254a7Smrg     }
294181254a7Smrg 
295181254a7Smrg   library_end ();
296181254a7Smrg }
297181254a7Smrg 
298181254a7Smrg 
299181254a7Smrg extern void st_endfile (st_parameter_filepos *);
300181254a7Smrg export_proto(st_endfile);
301181254a7Smrg 
302181254a7Smrg void
st_endfile(st_parameter_filepos * fpp)303181254a7Smrg st_endfile (st_parameter_filepos *fpp)
304181254a7Smrg {
305181254a7Smrg   gfc_unit *u;
306181254a7Smrg   bool needs_unlock = false;
307181254a7Smrg 
308181254a7Smrg   library_start (&fpp->common);
309181254a7Smrg 
310181254a7Smrg   u = find_unit (fpp->common.unit);
311181254a7Smrg   if (u != NULL)
312181254a7Smrg     {
313181254a7Smrg       if (u->flags.access == ACCESS_DIRECT)
314181254a7Smrg 	{
315181254a7Smrg 	  generate_error (&fpp->common, LIBERROR_OPTION_CONFLICT,
316181254a7Smrg 			  "Cannot perform ENDFILE on a file opened "
317181254a7Smrg 			  "for DIRECT access");
318181254a7Smrg 	  goto done;
319181254a7Smrg 	}
320181254a7Smrg 
321181254a7Smrg       if (ASYNC_IO && u->au)
322181254a7Smrg 	{
323181254a7Smrg 	  if (async_wait (&(fpp->common), u->au))
324181254a7Smrg 	    return;
325181254a7Smrg 	  else
326181254a7Smrg 	    {
327181254a7Smrg 	      needs_unlock = true;
328181254a7Smrg 	      LOCK (&u->au->io_lock);
329181254a7Smrg 	    }
330181254a7Smrg 	}
331181254a7Smrg 
332181254a7Smrg       if (u->flags.access == ACCESS_SEQUENTIAL
333181254a7Smrg       	  && u->endfile == AFTER_ENDFILE)
334181254a7Smrg 	{
335181254a7Smrg 	  generate_error (&fpp->common, LIBERROR_OPTION_CONFLICT,
336181254a7Smrg 			  "Cannot perform ENDFILE on a file already "
337181254a7Smrg 			  "positioned after the EOF marker");
338181254a7Smrg 	  goto done;
339181254a7Smrg 	}
340181254a7Smrg 
341181254a7Smrg       /* If there are previously written bytes from a write with ADVANCE="no",
342181254a7Smrg 	 add a record marker before performing the ENDFILE.  */
343181254a7Smrg 
344181254a7Smrg       if (u->previous_nonadvancing_write)
345181254a7Smrg 	finish_last_advance_record (u);
346181254a7Smrg 
347181254a7Smrg       u->previous_nonadvancing_write = 0;
348181254a7Smrg 
349181254a7Smrg       if (u->current_record)
350181254a7Smrg 	{
351181254a7Smrg 	  st_parameter_dt dtp;
352181254a7Smrg 	  dtp.common = fpp->common;
353181254a7Smrg 	  memset (&dtp.u.p, 0, sizeof (dtp.u.p));
354181254a7Smrg 	  dtp.u.p.current_unit = u;
355181254a7Smrg 	  next_record (&dtp, 1);
356181254a7Smrg 	}
357181254a7Smrg 
358181254a7Smrg       unit_truncate (u, stell (u->s), &fpp->common);
359181254a7Smrg       u->endfile = AFTER_ENDFILE;
360181254a7Smrg       u->last_char = EOF - 1;
361181254a7Smrg       if (0 == stell (u->s))
362181254a7Smrg         u->flags.position = POSITION_REWIND;
363181254a7Smrg     }
364181254a7Smrg   else
365181254a7Smrg     {
366181254a7Smrg       if (fpp->common.unit < 0)
367181254a7Smrg 	{
368181254a7Smrg 	  generate_error (&fpp->common, LIBERROR_BAD_OPTION,
369181254a7Smrg 			  "Bad unit number in statement");
370181254a7Smrg 	  return;
371181254a7Smrg 	}
372181254a7Smrg 
373181254a7Smrg       u = find_or_create_unit (fpp->common.unit);
374181254a7Smrg       if (u->s == NULL)
375181254a7Smrg 	{
376181254a7Smrg 	  /* Open the unit with some default flags.  */
377181254a7Smrg 	  st_parameter_open opp;
378181254a7Smrg 	  unit_flags u_flags;
379181254a7Smrg 
380181254a7Smrg 	  memset (&u_flags, '\0', sizeof (u_flags));
381181254a7Smrg 	  u_flags.access = ACCESS_SEQUENTIAL;
382181254a7Smrg 	  u_flags.action = ACTION_READWRITE;
383181254a7Smrg 
384181254a7Smrg 	  /* Is it unformatted?  */
385181254a7Smrg 	  if (!(fpp->common.flags & (IOPARM_DT_HAS_FORMAT | IOPARM_DT_LIST_FORMAT
386181254a7Smrg 				     | IOPARM_DT_IONML_SET)))
387181254a7Smrg 	    u_flags.form = FORM_UNFORMATTED;
388181254a7Smrg 	  else
389181254a7Smrg 	    u_flags.form = FORM_UNSPECIFIED;
390181254a7Smrg 
391181254a7Smrg 	  u_flags.delim = DELIM_UNSPECIFIED;
392181254a7Smrg 	  u_flags.blank = BLANK_UNSPECIFIED;
393181254a7Smrg 	  u_flags.pad = PAD_UNSPECIFIED;
394181254a7Smrg 	  u_flags.decimal = DECIMAL_UNSPECIFIED;
395181254a7Smrg 	  u_flags.encoding = ENCODING_UNSPECIFIED;
396181254a7Smrg 	  u_flags.async = ASYNC_UNSPECIFIED;
397181254a7Smrg 	  u_flags.round = ROUND_UNSPECIFIED;
398181254a7Smrg 	  u_flags.sign = SIGN_UNSPECIFIED;
399181254a7Smrg 	  u_flags.status = STATUS_UNKNOWN;
400181254a7Smrg 	  u_flags.convert = GFC_CONVERT_NATIVE;
401181254a7Smrg 	  u_flags.share = SHARE_UNSPECIFIED;
402181254a7Smrg 	  u_flags.cc = CC_UNSPECIFIED;
403181254a7Smrg 
404181254a7Smrg 	  opp.common = fpp->common;
405181254a7Smrg 	  opp.common.flags &= IOPARM_COMMON_MASK;
406181254a7Smrg 	  u = new_unit (&opp, u, &u_flags);
407181254a7Smrg 	  if (u == NULL)
408181254a7Smrg 	    return;
409181254a7Smrg 	  u->endfile = AFTER_ENDFILE;
410181254a7Smrg 	  u->last_char = EOF - 1;
411181254a7Smrg 	}
412181254a7Smrg     }
413181254a7Smrg 
414181254a7Smrg  done:
415181254a7Smrg   if (ASYNC_IO && u->au && needs_unlock)
416181254a7Smrg     UNLOCK (&u->au->io_lock);
417181254a7Smrg 
418181254a7Smrg   unlock_unit (u);
419181254a7Smrg 
420181254a7Smrg   library_end ();
421181254a7Smrg }
422181254a7Smrg 
423181254a7Smrg 
424181254a7Smrg extern void st_rewind (st_parameter_filepos *);
425181254a7Smrg export_proto(st_rewind);
426181254a7Smrg 
427181254a7Smrg void
st_rewind(st_parameter_filepos * fpp)428181254a7Smrg st_rewind (st_parameter_filepos *fpp)
429181254a7Smrg {
430181254a7Smrg   gfc_unit *u;
431181254a7Smrg   bool needs_unlock = true;
432181254a7Smrg 
433181254a7Smrg   library_start (&fpp->common);
434181254a7Smrg 
435181254a7Smrg   u = find_unit (fpp->common.unit);
436181254a7Smrg   if (u != NULL)
437181254a7Smrg     {
438181254a7Smrg       if (u->flags.access == ACCESS_DIRECT)
439181254a7Smrg 	generate_error (&fpp->common, LIBERROR_BAD_OPTION,
440181254a7Smrg 			"Cannot REWIND a file opened for DIRECT access");
441181254a7Smrg       else
442181254a7Smrg 	{
443181254a7Smrg 	  if (ASYNC_IO && u->au)
444181254a7Smrg 	    {
445181254a7Smrg 	      if (async_wait (&(fpp->common), u->au))
446181254a7Smrg 		return;
447181254a7Smrg 	      else
448181254a7Smrg 		{
449181254a7Smrg 		  needs_unlock = true;
450181254a7Smrg 		  LOCK (&u->au->io_lock);
451181254a7Smrg 		}
452181254a7Smrg 	    }
453181254a7Smrg 
454181254a7Smrg 	  /* If there are previously written bytes from a write with ADVANCE="no",
455181254a7Smrg 	     add a record marker before performing the ENDFILE.  */
456181254a7Smrg 
457181254a7Smrg 	  if (u->previous_nonadvancing_write)
458181254a7Smrg 	    finish_last_advance_record (u);
459181254a7Smrg 
460181254a7Smrg 	  u->previous_nonadvancing_write = 0;
461181254a7Smrg 
462181254a7Smrg 	  fbuf_reset (u);
463181254a7Smrg 
464181254a7Smrg 	  u->last_record = 0;
465181254a7Smrg 
466181254a7Smrg 	  if (sseek (u->s, 0, SEEK_SET) < 0)
467181254a7Smrg 	    {
468181254a7Smrg 	      generate_error (&fpp->common, LIBERROR_OS, NULL);
469181254a7Smrg 	      library_end ();
470181254a7Smrg 	      return;
471181254a7Smrg 	    }
472181254a7Smrg 
473181254a7Smrg 	  /* Set this for compatibilty with g77 for /dev/null.  */
474181254a7Smrg 	  if (ssize (u->s) == 0)
475181254a7Smrg 	    u->endfile = AT_ENDFILE;
476181254a7Smrg 	  else
477181254a7Smrg 	    {
478181254a7Smrg 	      /* We are rewinding so we are not at the end.  */
479181254a7Smrg 	      u->endfile = NO_ENDFILE;
480181254a7Smrg 	    }
481181254a7Smrg 
482181254a7Smrg 	  u->current_record = 0;
483181254a7Smrg 	  u->strm_pos = 1;
484181254a7Smrg 	  u->read_bad = 0;
485181254a7Smrg 	  u->last_char = EOF - 1;
486181254a7Smrg 	}
487181254a7Smrg       /* Update position for INQUIRE.  */
488181254a7Smrg       u->flags.position = POSITION_REWIND;
489181254a7Smrg 
490181254a7Smrg       if (ASYNC_IO && u->au && needs_unlock)
491181254a7Smrg 	UNLOCK (&u->au->io_lock);
492181254a7Smrg 
493181254a7Smrg       unlock_unit (u);
494181254a7Smrg     }
495181254a7Smrg 
496181254a7Smrg   library_end ();
497181254a7Smrg }
498181254a7Smrg 
499181254a7Smrg 
500181254a7Smrg extern void st_flush (st_parameter_filepos *);
501181254a7Smrg export_proto(st_flush);
502181254a7Smrg 
503181254a7Smrg void
st_flush(st_parameter_filepos * fpp)504181254a7Smrg st_flush (st_parameter_filepos *fpp)
505181254a7Smrg {
506181254a7Smrg   gfc_unit *u;
507181254a7Smrg   bool needs_unlock = false;
508181254a7Smrg 
509181254a7Smrg   library_start (&fpp->common);
510181254a7Smrg 
511181254a7Smrg   u = find_unit (fpp->common.unit);
512181254a7Smrg   if (u != NULL)
513181254a7Smrg     {
514181254a7Smrg       if (ASYNC_IO && u->au)
515181254a7Smrg 	{
516181254a7Smrg 	  if (async_wait (&(fpp->common), u->au))
517181254a7Smrg 	    return;
518181254a7Smrg 	  else
519181254a7Smrg 	    {
520181254a7Smrg 	      needs_unlock = true;
521181254a7Smrg 	      LOCK (&u->au->io_lock);
522181254a7Smrg 	    }
523181254a7Smrg 	}
524181254a7Smrg 
525181254a7Smrg       /* Make sure format buffer is flushed.  */
526181254a7Smrg       if (u->flags.form == FORM_FORMATTED)
527181254a7Smrg         fbuf_flush (u, u->mode);
528181254a7Smrg 
529181254a7Smrg       sflush (u->s);
530181254a7Smrg       u->last_char = EOF - 1;
531181254a7Smrg       unlock_unit (u);
532181254a7Smrg     }
533181254a7Smrg   else
534181254a7Smrg     /* FLUSH on unconnected unit is illegal: F95 std., 9.3.5. */
535*b1e83836Smrg     generate_error (&fpp->common, -LIBERROR_BAD_UNIT,
536181254a7Smrg 			"Specified UNIT in FLUSH is not connected");
537181254a7Smrg 
538181254a7Smrg   if (needs_unlock)
539181254a7Smrg     UNLOCK (&u->au->io_lock);
540181254a7Smrg 
541181254a7Smrg   library_end ();
542181254a7Smrg }
543