No need to preserve errno on success.
[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 e; /* Capture errno of first fflush if nothing else succeeds.  */
40   int result;
41
42   /* Try flushing the stream.  C89 guarantees behavior of output
43      streams, so we only need to worry if failure might have been on
44      an input stream.  When stream is NULL, POSIX only requires
45      flushing of output streams.  */
46   result = fflush (stream);
47   if (! stream || result == 0 || (e = errno) != EBADF)
48     return result;
49
50   /* POSIX does not specify behavior for non-seekable streams.  */
51   if (fseeko (stream, 0, SEEK_CUR) != 0)
52     {
53       errno = e;
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.  */
59 #if HAVE_FPURGE
60   result = fpurge (stream);
61 #elif HAVE___FPURGE
62   /* __fpurge has no return value, and on Solaris, we can't even trust
63      errno.  So assume it succeeds.  */
64   __fpurge (stream);
65   result = 0;
66 #else /* ! HAVE___FPURGE */
67
68   /* No single replacement; do it manually.  */
69   {
70     off_t position = ftello (stream);
71     if (position == -1)
72       {
73         result = EOF; /* Should not happen; we know stream is seekable.  */
74       }
75     /* Set position of stream; hopefully the stdio routines don't
76        overoptimize by not setting the underlying file position.  */
77     else if (fseeko (stream, position, SEEK_SET) != 0)
78       {
79         result = EOF;
80         errno = e;
81       }
82     else
83       result = 0;
84   }
85 #endif /* ! HAVE___FPURGE */
86
87   return result;
88 }