* lib/stdio_.h [REPLACE_FFLUSH]: Declare rpl_fflush.
[gnulib.git] / 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 #include <errno.h>
22 #include <stdio.h>
23
24 #if HAVE_STDIO_EXT_H
25 # include <stdio_ext.h>
26 #endif
27
28 #if HAVE_FPURGE && ! HAVE_DECL_FPURGE
29 int fpurge (FILE *);
30 #endif
31
32 #undef fflush
33
34 /* Flush all pending data on STREAM according to POSIX rules.  Both
35    output and seekable input streams are supported.  */
36 int
37 rpl_fflush (FILE *stream)
38 {
39   int e1; /* Leave errno unchanged on success.  */
40   int e2; /* Capture errno of first fflush if nothing else succeeds.  */
41   int result;
42
43   /* Try flushing the stream.  C89 guarantees behavior of output
44      streams, so we only need to worry if failure might have been on
45      an input stream.  When stream is NULL, POSIX only requires
46      flushing of output streams.  */
47   e1 = errno;
48   result = fflush (stream);
49   if (! stream || result == 0 || errno != EBADF)
50     return result;
51
52   /* POSIX does not specify behavior for non-seekable streams.  */
53   e2 = errno;
54   if (fseeko (stream, 0, SEEK_CUR) != 0)
55     {
56       errno = e2;
57       return EOF;
58     }
59
60   /* To get here, we must be flushing a seekable input stream, so the
61      semantics of fpurge are now appropriate.  */
62 #if HAVE_FPURGE
63   errno = e1;
64   result = fpurge (stream);
65 #elif HAVE___FPURGE
66   /* __fpurge has no return value, and on Solaris, we can't even trust
67      errno.  So assume it succeeds.  */
68   __fpurge (stream);
69   result = 0;
70   errno = e1;
71 #else /* ! HAVE___FPURGE */
72
73   /* No single replacement; do it manually.  */
74   {
75     off_t position = ftello (stream);
76     if (position == -1)
77       {
78         result = EOF; /* Should not happen; we know stream is seekable.  */
79       }
80     /* Set position of stream; hopefully the stdio routines don't
81        overoptimize by not setting the underlying file position.  */
82     else if (fseeko (stream, position, SEEK_SET) != 0)
83       {
84         result = EOF;
85         errno = e2;
86       }
87     else
88       {
89         result = 0;
90         errno = e1;
91       }
92   }
93 #endif /* ! HAVE___FPURGE */
94
95   return result;
96 }