xref: /netbsd-src/external/gpl3/gcc.old/dist/libgfortran/io/file_pos.c (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
1*4c3eb207Smrg /* Copyright (C) 2002-2020 Free Software Foundation, Inc.
2627f7eb2Smrg    Contributed by Andy Vaught and Janne Blomqvist
3627f7eb2Smrg 
4627f7eb2Smrg This file is part of the GNU Fortran runtime library (libgfortran).
5627f7eb2Smrg 
6627f7eb2Smrg Libgfortran is free software; you can redistribute it and/or modify
7627f7eb2Smrg it under the terms of the GNU General Public License as published by
8627f7eb2Smrg the Free Software Foundation; either version 3, or (at your option)
9627f7eb2Smrg any later version.
10627f7eb2Smrg 
11627f7eb2Smrg Libgfortran is distributed in the hope that it will be useful,
12627f7eb2Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
13627f7eb2Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14627f7eb2Smrg GNU General Public License for more details.
15627f7eb2Smrg 
16627f7eb2Smrg Under Section 7 of GPL version 3, you are granted additional
17627f7eb2Smrg permissions described in the GCC Runtime Library Exception, version
18627f7eb2Smrg 3.1, as published by the Free Software Foundation.
19627f7eb2Smrg 
20627f7eb2Smrg You should have received a copy of the GNU General Public License and
21627f7eb2Smrg a copy of the GCC Runtime Library Exception along with this program;
22627f7eb2Smrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23627f7eb2Smrg <http://www.gnu.org/licenses/>.  */
24627f7eb2Smrg 
25627f7eb2Smrg #include "io.h"
26627f7eb2Smrg #include "fbuf.h"
27627f7eb2Smrg #include "unix.h"
28627f7eb2Smrg #include "async.h"
29627f7eb2Smrg #include <string.h>
30627f7eb2Smrg 
31627f7eb2Smrg /* file_pos.c-- Implement the file positioning statements, i.e. BACKSPACE,
32627f7eb2Smrg    ENDFILE, and REWIND as well as the FLUSH statement.  */
33627f7eb2Smrg 
34627f7eb2Smrg 
35627f7eb2Smrg /* formatted_backspace(fpp, u)-- Move the file back one line.  The
36627f7eb2Smrg    current position is after the newline that terminates the previous
37627f7eb2Smrg    record, and we have to sift backwards to find the newline before
38627f7eb2Smrg    that or the start of the file, whichever comes first.  */
39627f7eb2Smrg 
40627f7eb2Smrg #define READ_CHUNK 4096
41627f7eb2Smrg 
42627f7eb2Smrg static void
formatted_backspace(st_parameter_filepos * fpp,gfc_unit * u)43627f7eb2Smrg formatted_backspace (st_parameter_filepos *fpp, gfc_unit *u)
44627f7eb2Smrg {
45627f7eb2Smrg   gfc_offset base;
46627f7eb2Smrg   char p[READ_CHUNK];
47627f7eb2Smrg   ssize_t n;
48627f7eb2Smrg 
49627f7eb2Smrg   base = stell (u->s) - 1;
50627f7eb2Smrg 
51627f7eb2Smrg   do
52627f7eb2Smrg     {
53627f7eb2Smrg       n = (base < READ_CHUNK) ? base : READ_CHUNK;
54627f7eb2Smrg       base -= n;
55627f7eb2Smrg       if (sseek (u->s, base, SEEK_SET) < 0)
56627f7eb2Smrg         goto io_error;
57627f7eb2Smrg       if (sread (u->s, p, n) != n)
58627f7eb2Smrg 	goto io_error;
59627f7eb2Smrg 
60627f7eb2Smrg       /* We have moved backwards from the current position, it should
61627f7eb2Smrg          not be possible to get a short read.  Because it is not
62627f7eb2Smrg          clear what to do about such thing, we ignore the possibility.  */
63627f7eb2Smrg 
64627f7eb2Smrg       /* There is no memrchr() in the C library, so we have to do it
65627f7eb2Smrg          ourselves.  */
66627f7eb2Smrg 
67627f7eb2Smrg       while (n > 0)
68627f7eb2Smrg 	{
69627f7eb2Smrg           n--;
70627f7eb2Smrg 	  if (p[n] == '\n')
71627f7eb2Smrg 	    {
72627f7eb2Smrg 	      base += n + 1;
73627f7eb2Smrg 	      goto done;
74627f7eb2Smrg 	    }
75627f7eb2Smrg 	}
76627f7eb2Smrg 
77627f7eb2Smrg     }
78627f7eb2Smrg   while (base != 0);
79627f7eb2Smrg 
80627f7eb2Smrg   /* base is the new pointer.  Seek to it exactly.  */
81627f7eb2Smrg  done:
82627f7eb2Smrg   if (sseek (u->s, base, SEEK_SET) < 0)
83627f7eb2Smrg     goto io_error;
84627f7eb2Smrg   u->last_record--;
85627f7eb2Smrg   u->endfile = NO_ENDFILE;
86627f7eb2Smrg   u->last_char = EOF - 1;
87627f7eb2Smrg   return;
88627f7eb2Smrg 
89627f7eb2Smrg  io_error:
90627f7eb2Smrg   generate_error (&fpp->common, LIBERROR_OS, NULL);
91627f7eb2Smrg }
92627f7eb2Smrg 
93627f7eb2Smrg 
94627f7eb2Smrg /* unformatted_backspace(fpp) -- Move the file backwards for an unformatted
95627f7eb2Smrg    sequential file.  We are guaranteed to be between records on entry and
96627f7eb2Smrg    we have to shift to the previous record.  Loop over subrecords.  */
97627f7eb2Smrg 
98627f7eb2Smrg static void
unformatted_backspace(st_parameter_filepos * fpp,gfc_unit * u)99627f7eb2Smrg unformatted_backspace (st_parameter_filepos *fpp, gfc_unit *u)
100627f7eb2Smrg {
101627f7eb2Smrg   gfc_offset m, slen;
102627f7eb2Smrg   GFC_INTEGER_4 m4;
103627f7eb2Smrg   GFC_INTEGER_8 m8;
104627f7eb2Smrg   ssize_t length;
105627f7eb2Smrg   int continued;
106627f7eb2Smrg   char p[sizeof (GFC_INTEGER_8)];
107627f7eb2Smrg 
108627f7eb2Smrg   if (compile_options.record_marker == 0)
109627f7eb2Smrg     length = sizeof (GFC_INTEGER_4);
110627f7eb2Smrg   else
111627f7eb2Smrg     length = compile_options.record_marker;
112627f7eb2Smrg 
113627f7eb2Smrg   do
114627f7eb2Smrg     {
115627f7eb2Smrg       slen = - (gfc_offset) length;
116627f7eb2Smrg       if (sseek (u->s, slen, SEEK_CUR) < 0)
117627f7eb2Smrg         goto io_error;
118627f7eb2Smrg       if (sread (u->s, p, length) != length)
119627f7eb2Smrg         goto io_error;
120627f7eb2Smrg 
121627f7eb2Smrg       /* Only GFC_CONVERT_NATIVE and GFC_CONVERT_SWAP are valid here.  */
122627f7eb2Smrg       if (likely (u->flags.convert == GFC_CONVERT_NATIVE))
123627f7eb2Smrg 	{
124627f7eb2Smrg 	  switch (length)
125627f7eb2Smrg 	    {
126627f7eb2Smrg 	    case sizeof(GFC_INTEGER_4):
127627f7eb2Smrg 	      memcpy (&m4, p, sizeof (m4));
128627f7eb2Smrg 	      m = m4;
129627f7eb2Smrg 	      break;
130627f7eb2Smrg 
131627f7eb2Smrg 	    case sizeof(GFC_INTEGER_8):
132627f7eb2Smrg 	      memcpy (&m8, p, sizeof (m8));
133627f7eb2Smrg 	      m = m8;
134627f7eb2Smrg 	      break;
135627f7eb2Smrg 
136627f7eb2Smrg 	    default:
137627f7eb2Smrg 	      runtime_error ("Illegal value for record marker");
138627f7eb2Smrg 	      break;
139627f7eb2Smrg 	    }
140627f7eb2Smrg 	}
141627f7eb2Smrg       else
142627f7eb2Smrg 	{
143627f7eb2Smrg 	  uint32_t u32;
144627f7eb2Smrg 	  uint64_t u64;
145627f7eb2Smrg 	  switch (length)
146627f7eb2Smrg 	    {
147627f7eb2Smrg 	    case sizeof(GFC_INTEGER_4):
148627f7eb2Smrg 	      memcpy (&u32, p, sizeof (u32));
149627f7eb2Smrg 	      u32 = __builtin_bswap32 (u32);
150627f7eb2Smrg 	      memcpy (&m4, &u32, sizeof (m4));
151627f7eb2Smrg 	      m = m4;
152627f7eb2Smrg 	      break;
153627f7eb2Smrg 
154627f7eb2Smrg 	    case sizeof(GFC_INTEGER_8):
155627f7eb2Smrg 	      memcpy (&u64, p, sizeof (u64));
156627f7eb2Smrg 	      u64 = __builtin_bswap64 (u64);
157627f7eb2Smrg 	      memcpy (&m8, &u64, sizeof (m8));
158627f7eb2Smrg 	      m = m8;
159627f7eb2Smrg 	      break;
160627f7eb2Smrg 
161627f7eb2Smrg 	    default:
162627f7eb2Smrg 	      runtime_error ("Illegal value for record marker");
163627f7eb2Smrg 	      break;
164627f7eb2Smrg 	    }
165627f7eb2Smrg 
166627f7eb2Smrg 	}
167627f7eb2Smrg 
168627f7eb2Smrg       continued = m < 0;
169627f7eb2Smrg       if (continued)
170627f7eb2Smrg 	m = -m;
171627f7eb2Smrg 
172627f7eb2Smrg       if (sseek (u->s, -m -2 * length, SEEK_CUR) < 0)
173627f7eb2Smrg 	goto io_error;
174627f7eb2Smrg     } while (continued);
175627f7eb2Smrg 
176627f7eb2Smrg   u->last_record--;
177627f7eb2Smrg   return;
178627f7eb2Smrg 
179627f7eb2Smrg  io_error:
180627f7eb2Smrg   generate_error (&fpp->common, LIBERROR_OS, NULL);
181627f7eb2Smrg }
182627f7eb2Smrg 
183627f7eb2Smrg 
184627f7eb2Smrg extern void st_backspace (st_parameter_filepos *);
185627f7eb2Smrg export_proto(st_backspace);
186627f7eb2Smrg 
187627f7eb2Smrg void
st_backspace(st_parameter_filepos * fpp)188627f7eb2Smrg st_backspace (st_parameter_filepos *fpp)
189627f7eb2Smrg {
190627f7eb2Smrg   gfc_unit *u;
191627f7eb2Smrg   bool needs_unlock = false;
192627f7eb2Smrg 
193627f7eb2Smrg   library_start (&fpp->common);
194627f7eb2Smrg 
195627f7eb2Smrg   u = find_unit (fpp->common.unit);
196627f7eb2Smrg   if (u == NULL)
197627f7eb2Smrg     {
198627f7eb2Smrg       generate_error (&fpp->common, LIBERROR_BAD_UNIT, NULL);
199627f7eb2Smrg       goto done;
200627f7eb2Smrg     }
201627f7eb2Smrg 
202627f7eb2Smrg   /* Direct access is prohibited, and so is unformatted stream access.  */
203627f7eb2Smrg 
204627f7eb2Smrg 
205627f7eb2Smrg   if (u->flags.access == ACCESS_DIRECT)
206627f7eb2Smrg     {
207627f7eb2Smrg       generate_error (&fpp->common, LIBERROR_OPTION_CONFLICT,
208627f7eb2Smrg 		      "Cannot BACKSPACE a file opened for DIRECT access");
209627f7eb2Smrg       goto done;
210627f7eb2Smrg     }
211627f7eb2Smrg 
212627f7eb2Smrg   if (u->flags.access == ACCESS_STREAM && u->flags.form == FORM_UNFORMATTED)
213627f7eb2Smrg     {
214627f7eb2Smrg       generate_error (&fpp->common, LIBERROR_OPTION_CONFLICT,
215627f7eb2Smrg                       "Cannot BACKSPACE an unformatted stream file");
216627f7eb2Smrg       goto done;
217627f7eb2Smrg     }
218627f7eb2Smrg 
219627f7eb2Smrg   if (ASYNC_IO && u->au)
220627f7eb2Smrg     {
221627f7eb2Smrg       if (async_wait (&(fpp->common), u->au))
222627f7eb2Smrg 	return;
223627f7eb2Smrg       else
224627f7eb2Smrg 	{
225627f7eb2Smrg 	  needs_unlock = true;
226627f7eb2Smrg 	  LOCK (&u->au->io_lock);
227627f7eb2Smrg 	}
228627f7eb2Smrg     }
229627f7eb2Smrg 
230627f7eb2Smrg   /* Make sure format buffer is flushed and reset.  */
231627f7eb2Smrg   if (u->flags.form == FORM_FORMATTED)
232627f7eb2Smrg     {
233627f7eb2Smrg       int pos = fbuf_reset (u);
234627f7eb2Smrg       if (pos != 0)
235627f7eb2Smrg         sseek (u->s, pos, SEEK_CUR);
236627f7eb2Smrg     }
237627f7eb2Smrg 
238627f7eb2Smrg 
239627f7eb2Smrg   /* Check for special cases involving the ENDFILE record first.  */
240627f7eb2Smrg 
241627f7eb2Smrg   if (u->endfile == AFTER_ENDFILE)
242627f7eb2Smrg     {
243627f7eb2Smrg       u->endfile = AT_ENDFILE;
244627f7eb2Smrg       u->flags.position = POSITION_APPEND;
245627f7eb2Smrg       sflush (u->s);
246627f7eb2Smrg     }
247627f7eb2Smrg   else
248627f7eb2Smrg     {
249627f7eb2Smrg       if (stell (u->s) == 0)
250627f7eb2Smrg 	{
251627f7eb2Smrg 	  u->flags.position = POSITION_REWIND;
252627f7eb2Smrg 	  goto done;		/* Common special case */
253627f7eb2Smrg 	}
254627f7eb2Smrg 
255627f7eb2Smrg       if (u->mode == WRITING)
256627f7eb2Smrg 	{
257627f7eb2Smrg 	  /* If there are previously written bytes from a write with
258627f7eb2Smrg 	     ADVANCE="no", add a record marker before performing the
259627f7eb2Smrg 	     BACKSPACE.  */
260627f7eb2Smrg 
261627f7eb2Smrg 	  if (u->previous_nonadvancing_write)
262627f7eb2Smrg 	    finish_last_advance_record (u);
263627f7eb2Smrg 
264627f7eb2Smrg 	  u->previous_nonadvancing_write = 0;
265627f7eb2Smrg 
266627f7eb2Smrg 	  unit_truncate (u, stell (u->s), &fpp->common);
267627f7eb2Smrg 	  u->mode = READING;
268627f7eb2Smrg         }
269627f7eb2Smrg 
270627f7eb2Smrg       if (u->flags.form == FORM_FORMATTED)
271627f7eb2Smrg 	formatted_backspace (fpp, u);
272627f7eb2Smrg       else
273627f7eb2Smrg 	unformatted_backspace (fpp, u);
274627f7eb2Smrg 
275627f7eb2Smrg       u->flags.position = POSITION_UNSPECIFIED;
276627f7eb2Smrg       u->endfile = NO_ENDFILE;
277627f7eb2Smrg       u->current_record = 0;
278627f7eb2Smrg       u->bytes_left = 0;
279627f7eb2Smrg     }
280627f7eb2Smrg 
281627f7eb2Smrg  done:
282627f7eb2Smrg   if (u != NULL)
283627f7eb2Smrg     {
284627f7eb2Smrg       unlock_unit (u);
285627f7eb2Smrg 
286627f7eb2Smrg       if (ASYNC_IO && u->au && needs_unlock)
287627f7eb2Smrg 	UNLOCK (&u->au->io_lock);
288627f7eb2Smrg     }
289627f7eb2Smrg 
290627f7eb2Smrg   library_end ();
291627f7eb2Smrg }
292627f7eb2Smrg 
293627f7eb2Smrg 
294627f7eb2Smrg extern void st_endfile (st_parameter_filepos *);
295627f7eb2Smrg export_proto(st_endfile);
296627f7eb2Smrg 
297627f7eb2Smrg void
st_endfile(st_parameter_filepos * fpp)298627f7eb2Smrg st_endfile (st_parameter_filepos *fpp)
299627f7eb2Smrg {
300627f7eb2Smrg   gfc_unit *u;
301627f7eb2Smrg   bool needs_unlock = false;
302627f7eb2Smrg 
303627f7eb2Smrg   library_start (&fpp->common);
304627f7eb2Smrg 
305627f7eb2Smrg   u = find_unit (fpp->common.unit);
306627f7eb2Smrg   if (u != NULL)
307627f7eb2Smrg     {
308627f7eb2Smrg       if (u->flags.access == ACCESS_DIRECT)
309627f7eb2Smrg 	{
310627f7eb2Smrg 	  generate_error (&fpp->common, LIBERROR_OPTION_CONFLICT,
311627f7eb2Smrg 			  "Cannot perform ENDFILE on a file opened "
312627f7eb2Smrg 			  "for DIRECT access");
313627f7eb2Smrg 	  goto done;
314627f7eb2Smrg 	}
315627f7eb2Smrg 
316627f7eb2Smrg       if (ASYNC_IO && u->au)
317627f7eb2Smrg 	{
318627f7eb2Smrg 	  if (async_wait (&(fpp->common), u->au))
319627f7eb2Smrg 	    return;
320627f7eb2Smrg 	  else
321627f7eb2Smrg 	    {
322627f7eb2Smrg 	      needs_unlock = true;
323627f7eb2Smrg 	      LOCK (&u->au->io_lock);
324627f7eb2Smrg 	    }
325627f7eb2Smrg 	}
326627f7eb2Smrg 
327627f7eb2Smrg       if (u->flags.access == ACCESS_SEQUENTIAL
328627f7eb2Smrg       	  && u->endfile == AFTER_ENDFILE)
329627f7eb2Smrg 	{
330627f7eb2Smrg 	  generate_error (&fpp->common, LIBERROR_OPTION_CONFLICT,
331627f7eb2Smrg 			  "Cannot perform ENDFILE on a file already "
332627f7eb2Smrg 			  "positioned after the EOF marker");
333627f7eb2Smrg 	  goto done;
334627f7eb2Smrg 	}
335627f7eb2Smrg 
336627f7eb2Smrg       /* If there are previously written bytes from a write with ADVANCE="no",
337627f7eb2Smrg 	 add a record marker before performing the ENDFILE.  */
338627f7eb2Smrg 
339627f7eb2Smrg       if (u->previous_nonadvancing_write)
340627f7eb2Smrg 	finish_last_advance_record (u);
341627f7eb2Smrg 
342627f7eb2Smrg       u->previous_nonadvancing_write = 0;
343627f7eb2Smrg 
344627f7eb2Smrg       if (u->current_record)
345627f7eb2Smrg 	{
346627f7eb2Smrg 	  st_parameter_dt dtp;
347627f7eb2Smrg 	  dtp.common = fpp->common;
348627f7eb2Smrg 	  memset (&dtp.u.p, 0, sizeof (dtp.u.p));
349627f7eb2Smrg 	  dtp.u.p.current_unit = u;
350627f7eb2Smrg 	  next_record (&dtp, 1);
351627f7eb2Smrg 	}
352627f7eb2Smrg 
353627f7eb2Smrg       unit_truncate (u, stell (u->s), &fpp->common);
354627f7eb2Smrg       u->endfile = AFTER_ENDFILE;
355627f7eb2Smrg       u->last_char = EOF - 1;
356627f7eb2Smrg       if (0 == stell (u->s))
357627f7eb2Smrg         u->flags.position = POSITION_REWIND;
358627f7eb2Smrg     }
359627f7eb2Smrg   else
360627f7eb2Smrg     {
361627f7eb2Smrg       if (fpp->common.unit < 0)
362627f7eb2Smrg 	{
363627f7eb2Smrg 	  generate_error (&fpp->common, LIBERROR_BAD_OPTION,
364627f7eb2Smrg 			  "Bad unit number in statement");
365627f7eb2Smrg 	  return;
366627f7eb2Smrg 	}
367627f7eb2Smrg 
368627f7eb2Smrg       u = find_or_create_unit (fpp->common.unit);
369627f7eb2Smrg       if (u->s == NULL)
370627f7eb2Smrg 	{
371627f7eb2Smrg 	  /* Open the unit with some default flags.  */
372627f7eb2Smrg 	  st_parameter_open opp;
373627f7eb2Smrg 	  unit_flags u_flags;
374627f7eb2Smrg 
375627f7eb2Smrg 	  memset (&u_flags, '\0', sizeof (u_flags));
376627f7eb2Smrg 	  u_flags.access = ACCESS_SEQUENTIAL;
377627f7eb2Smrg 	  u_flags.action = ACTION_READWRITE;
378627f7eb2Smrg 
379627f7eb2Smrg 	  /* Is it unformatted?  */
380627f7eb2Smrg 	  if (!(fpp->common.flags & (IOPARM_DT_HAS_FORMAT | IOPARM_DT_LIST_FORMAT
381627f7eb2Smrg 				     | IOPARM_DT_IONML_SET)))
382627f7eb2Smrg 	    u_flags.form = FORM_UNFORMATTED;
383627f7eb2Smrg 	  else
384627f7eb2Smrg 	    u_flags.form = FORM_UNSPECIFIED;
385627f7eb2Smrg 
386627f7eb2Smrg 	  u_flags.delim = DELIM_UNSPECIFIED;
387627f7eb2Smrg 	  u_flags.blank = BLANK_UNSPECIFIED;
388627f7eb2Smrg 	  u_flags.pad = PAD_UNSPECIFIED;
389627f7eb2Smrg 	  u_flags.decimal = DECIMAL_UNSPECIFIED;
390627f7eb2Smrg 	  u_flags.encoding = ENCODING_UNSPECIFIED;
391627f7eb2Smrg 	  u_flags.async = ASYNC_UNSPECIFIED;
392627f7eb2Smrg 	  u_flags.round = ROUND_UNSPECIFIED;
393627f7eb2Smrg 	  u_flags.sign = SIGN_UNSPECIFIED;
394627f7eb2Smrg 	  u_flags.status = STATUS_UNKNOWN;
395627f7eb2Smrg 	  u_flags.convert = GFC_CONVERT_NATIVE;
396627f7eb2Smrg 	  u_flags.share = SHARE_UNSPECIFIED;
397627f7eb2Smrg 	  u_flags.cc = CC_UNSPECIFIED;
398627f7eb2Smrg 
399627f7eb2Smrg 	  opp.common = fpp->common;
400627f7eb2Smrg 	  opp.common.flags &= IOPARM_COMMON_MASK;
401627f7eb2Smrg 	  u = new_unit (&opp, u, &u_flags);
402627f7eb2Smrg 	  if (u == NULL)
403627f7eb2Smrg 	    return;
404627f7eb2Smrg 	  u->endfile = AFTER_ENDFILE;
405627f7eb2Smrg 	  u->last_char = EOF - 1;
406627f7eb2Smrg 	}
407627f7eb2Smrg     }
408627f7eb2Smrg 
409627f7eb2Smrg  done:
410627f7eb2Smrg   if (ASYNC_IO && u->au && needs_unlock)
411627f7eb2Smrg     UNLOCK (&u->au->io_lock);
412627f7eb2Smrg 
413627f7eb2Smrg   unlock_unit (u);
414627f7eb2Smrg 
415627f7eb2Smrg   library_end ();
416627f7eb2Smrg }
417627f7eb2Smrg 
418627f7eb2Smrg 
419627f7eb2Smrg extern void st_rewind (st_parameter_filepos *);
420627f7eb2Smrg export_proto(st_rewind);
421627f7eb2Smrg 
422627f7eb2Smrg void
st_rewind(st_parameter_filepos * fpp)423627f7eb2Smrg st_rewind (st_parameter_filepos *fpp)
424627f7eb2Smrg {
425627f7eb2Smrg   gfc_unit *u;
426627f7eb2Smrg   bool needs_unlock = true;
427627f7eb2Smrg 
428627f7eb2Smrg   library_start (&fpp->common);
429627f7eb2Smrg 
430627f7eb2Smrg   u = find_unit (fpp->common.unit);
431627f7eb2Smrg   if (u != NULL)
432627f7eb2Smrg     {
433627f7eb2Smrg       if (u->flags.access == ACCESS_DIRECT)
434627f7eb2Smrg 	generate_error (&fpp->common, LIBERROR_BAD_OPTION,
435627f7eb2Smrg 			"Cannot REWIND a file opened for DIRECT access");
436627f7eb2Smrg       else
437627f7eb2Smrg 	{
438627f7eb2Smrg 	  if (ASYNC_IO && u->au)
439627f7eb2Smrg 	    {
440627f7eb2Smrg 	      if (async_wait (&(fpp->common), u->au))
441627f7eb2Smrg 		return;
442627f7eb2Smrg 	      else
443627f7eb2Smrg 		{
444627f7eb2Smrg 		  needs_unlock = true;
445627f7eb2Smrg 		  LOCK (&u->au->io_lock);
446627f7eb2Smrg 		}
447627f7eb2Smrg 	    }
448627f7eb2Smrg 
449627f7eb2Smrg 	  /* If there are previously written bytes from a write with ADVANCE="no",
450627f7eb2Smrg 	     add a record marker before performing the ENDFILE.  */
451627f7eb2Smrg 
452627f7eb2Smrg 	  if (u->previous_nonadvancing_write)
453627f7eb2Smrg 	    finish_last_advance_record (u);
454627f7eb2Smrg 
455627f7eb2Smrg 	  u->previous_nonadvancing_write = 0;
456627f7eb2Smrg 
457627f7eb2Smrg 	  fbuf_reset (u);
458627f7eb2Smrg 
459627f7eb2Smrg 	  u->last_record = 0;
460627f7eb2Smrg 
461627f7eb2Smrg 	  if (sseek (u->s, 0, SEEK_SET) < 0)
462627f7eb2Smrg 	    {
463627f7eb2Smrg 	      generate_error (&fpp->common, LIBERROR_OS, NULL);
464627f7eb2Smrg 	      library_end ();
465627f7eb2Smrg 	      return;
466627f7eb2Smrg 	    }
467627f7eb2Smrg 
468627f7eb2Smrg 	  /* Set this for compatibilty with g77 for /dev/null.  */
469627f7eb2Smrg 	  if (ssize (u->s) == 0)
470627f7eb2Smrg 	    u->endfile = AT_ENDFILE;
471627f7eb2Smrg 	  else
472627f7eb2Smrg 	    {
473627f7eb2Smrg 	      /* We are rewinding so we are not at the end.  */
474627f7eb2Smrg 	      u->endfile = NO_ENDFILE;
475627f7eb2Smrg 	    }
476627f7eb2Smrg 
477627f7eb2Smrg 	  u->current_record = 0;
478627f7eb2Smrg 	  u->strm_pos = 1;
479627f7eb2Smrg 	  u->read_bad = 0;
480627f7eb2Smrg 	  u->last_char = EOF - 1;
481627f7eb2Smrg 	}
482627f7eb2Smrg       /* Update position for INQUIRE.  */
483627f7eb2Smrg       u->flags.position = POSITION_REWIND;
484627f7eb2Smrg 
485627f7eb2Smrg       if (ASYNC_IO && u->au && needs_unlock)
486627f7eb2Smrg 	UNLOCK (&u->au->io_lock);
487627f7eb2Smrg 
488627f7eb2Smrg       unlock_unit (u);
489627f7eb2Smrg     }
490627f7eb2Smrg 
491627f7eb2Smrg   library_end ();
492627f7eb2Smrg }
493627f7eb2Smrg 
494627f7eb2Smrg 
495627f7eb2Smrg extern void st_flush (st_parameter_filepos *);
496627f7eb2Smrg export_proto(st_flush);
497627f7eb2Smrg 
498627f7eb2Smrg void
st_flush(st_parameter_filepos * fpp)499627f7eb2Smrg st_flush (st_parameter_filepos *fpp)
500627f7eb2Smrg {
501627f7eb2Smrg   gfc_unit *u;
502627f7eb2Smrg   bool needs_unlock = false;
503627f7eb2Smrg 
504627f7eb2Smrg   library_start (&fpp->common);
505627f7eb2Smrg 
506627f7eb2Smrg   u = find_unit (fpp->common.unit);
507627f7eb2Smrg   if (u != NULL)
508627f7eb2Smrg     {
509627f7eb2Smrg       if (ASYNC_IO && u->au)
510627f7eb2Smrg 	{
511627f7eb2Smrg 	  if (async_wait (&(fpp->common), u->au))
512627f7eb2Smrg 	    return;
513627f7eb2Smrg 	  else
514627f7eb2Smrg 	    {
515627f7eb2Smrg 	      needs_unlock = true;
516627f7eb2Smrg 	      LOCK (&u->au->io_lock);
517627f7eb2Smrg 	    }
518627f7eb2Smrg 	}
519627f7eb2Smrg 
520627f7eb2Smrg       /* Make sure format buffer is flushed.  */
521627f7eb2Smrg       if (u->flags.form == FORM_FORMATTED)
522627f7eb2Smrg         fbuf_flush (u, u->mode);
523627f7eb2Smrg 
524627f7eb2Smrg       sflush (u->s);
525627f7eb2Smrg       u->last_char = EOF - 1;
526627f7eb2Smrg       unlock_unit (u);
527627f7eb2Smrg     }
528627f7eb2Smrg   else
529627f7eb2Smrg     /* FLUSH on unconnected unit is illegal: F95 std., 9.3.5. */
530627f7eb2Smrg     generate_error (&fpp->common, LIBERROR_BAD_OPTION,
531627f7eb2Smrg 			"Specified UNIT in FLUSH is not connected");
532627f7eb2Smrg 
533627f7eb2Smrg   if (needs_unlock)
534627f7eb2Smrg     UNLOCK (&u->au->io_lock);
535627f7eb2Smrg 
536627f7eb2Smrg   library_end ();
537627f7eb2Smrg }
538