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