9361c09f3fa15d5855aa9caf366168e14a53679c
[pspp] / lib / fflush.c
1 /* fflush.c -- allow flushing input streams
2    Copyright (C) 2007 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software Foundation,
16    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
17
18 /* Written by Eric Blake. */
19
20 #include <config.h>
21
22 /* Specification.  */
23 #include <stdio.h>
24
25 #include <errno.h>
26 #include <unistd.h>
27
28 #include "freading.h"
29 #include "fpurge.h"
30
31 #undef fflush
32
33 /* Flush all pending data on STREAM according to POSIX rules.  Both
34    output and seekable input streams are supported.  */
35 int
36 rpl_fflush (FILE *stream)
37 {
38   int result;
39   off_t pos;
40
41   /* When stream is NULL, POSIX only requires flushing of output
42      streams.  C89 guarantees behavior of output streams, and fflush
43      should be safe on read-write streams that are not currently
44      reading.  */
45   if (! stream || ! freading (stream))
46     return fflush (stream);
47
48   /* POSIX does not specify fflush behavior for non-seekable input
49      streams.  */
50   pos = ftello (stream);
51   if (pos == -1)
52     {
53       errno = EBADF;
54       return EOF;
55     }
56
57   /* To get here, we must be flushing a seekable input stream, so the
58      semantics of fpurge are now appropriate to clear the buffer.  To
59      avoid losing data, the lseek is also necessary.  */
60   result = fpurge (stream);
61   if (result != 0)
62     return result;
63   pos = lseek (fileno (stream), pos, SEEK_SET);
64   if (pos == -1)
65     return EOF;
66 #if defined __sferror               /* FreeBSD, NetBSD, OpenBSD, MacOS X, Cygwin */
67   stream->_offset = pos;
68   stream->_flags |= __SOFF;
69 #endif
70   return 0;
71 }