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