1219820Sjeff/* Flushing buffers of a FILE stream.
2219820Sjeff   Copyright (C) 2007-2010 Free Software Foundation, Inc.
3219820Sjeff
4219820Sjeff   This program is free software: you can redistribute it and/or modify
5219820Sjeff   it under the terms of the GNU General Public License as published by
6219820Sjeff   the Free Software Foundation; either version 3 of the License, or
7219820Sjeff   (at your option) any later version.
8219820Sjeff
9219820Sjeff   This program is distributed in the hope that it will be useful,
10219820Sjeff   but WITHOUT ANY WARRANTY; without even the implied warranty of
11219820Sjeff   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12219820Sjeff   GNU General Public License for more details.
13219820Sjeff
14219820Sjeff   You should have received a copy of the GNU General Public License
15219820Sjeff   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
16219820Sjeff
17219820Sjeff#include <config.h>
18219820Sjeff
19219820Sjeff/* Specification.  */
20219820Sjeff#include <stdio.h>
21219820Sjeff
22219820Sjeff#if HAVE___FPURGE                   /* glibc >= 2.2, Haiku, Solaris >= 7 */
23219820Sjeff# include <stdio_ext.h>
24219820Sjeff#endif
25219820Sjeff#include <stdlib.h>
26219820Sjeff
27219820Sjeff#include "stdio-impl.h"
28219820Sjeff
29219820Sjeffint
30219820Sjefffpurge (FILE *fp)
31219820Sjeff{
32219820Sjeff#if HAVE___FPURGE                   /* glibc >= 2.2, Haiku, Solaris >= 7 */
33219820Sjeff
34219820Sjeff  __fpurge (fp);
35219820Sjeff  /* The __fpurge function does not have a return value.  */
36219820Sjeff  return 0;
37219820Sjeff
38219820Sjeff#elif HAVE_FPURGE                   /* FreeBSD, NetBSD, OpenBSD, DragonFly, MacOS X, Cygwin 1.7 */
39219820Sjeff
40219820Sjeff  /* Call the system's fpurge function.  */
41219820Sjeff# undef fpurge
42219820Sjeff# if !HAVE_DECL_FPURGE
43219820Sjeff  extern int fpurge (FILE *);
44219820Sjeff# endif
45219820Sjeff  int result = fpurge (fp);
46219820Sjeff# if defined __sferror || defined __DragonFly__ /* FreeBSD, NetBSD, OpenBSD, DragonFly, MacOS X, Cygwin */
47219820Sjeff  if (result == 0)
48219820Sjeff    /* Correct the invariants that fpurge broke.
49219820Sjeff       <stdio.h> on BSD systems says:
50219820Sjeff         "The following always hold: if _flags & __SRD, _w is 0."
51219820Sjeff       If this invariant is not fulfilled and the stream is read-write but
52219820Sjeff       currently reading, subsequent putc or fputc calls will write directly
53219820Sjeff       into the buffer, although they shouldn't be allowed to.  */
54219820Sjeff    if ((fp_->_flags & __SRD) != 0)
55219820Sjeff      fp_->_w = 0;
56219820Sjeff# endif
57219820Sjeff  return result;
58219820Sjeff
59219820Sjeff#else
60219820Sjeff
61219820Sjeff  /* Most systems provide FILE as a struct and the necessary bitmask in
62219820Sjeff     <stdio.h>, because they need it for implementing getc() and putc() as
63219820Sjeff     fast macros.  */
64219820Sjeff# if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
65219820Sjeff  fp->_IO_read_end = fp->_IO_read_ptr;
66219820Sjeff  fp->_IO_write_ptr = fp->_IO_write_base;
67219820Sjeff  /* Avoid memory leak when there is an active ungetc buffer.  */
68219820Sjeff  if (fp->_IO_save_base != NULL)
69219820Sjeff    {
70219820Sjeff      free (fp->_IO_save_base);
71219820Sjeff      fp->_IO_save_base = NULL;
72219820Sjeff    }
73219820Sjeff  return 0;
74219820Sjeff# elif defined __sferror || defined __DragonFly__ /* FreeBSD, NetBSD, OpenBSD, DragonFly, MacOS X, Cygwin */
75219820Sjeff  fp_->_p = fp_->_bf._base;
76219820Sjeff  fp_->_r = 0;
77219820Sjeff  fp_->_w = ((fp_->_flags & (__SLBF | __SNBF | __SRD)) == 0 /* fully buffered and not currently reading? */
78219820Sjeff             ? fp_->_bf._size
79219820Sjeff             : 0);
80219820Sjeff  /* Avoid memory leak when there is an active ungetc buffer.  */
81219820Sjeff  if (fp_ub._base != NULL)
82219820Sjeff    {
83219820Sjeff      if (fp_ub._base != fp_->_ubuf)
84219820Sjeff        free (fp_ub._base);
85219820Sjeff      fp_ub._base = NULL;
86219820Sjeff    }
87219820Sjeff  return 0;
88219820Sjeff# elif defined __EMX__              /* emx+gcc */
89219820Sjeff  fp->_ptr = fp->_buffer;
90219820Sjeff  fp->_rcount = 0;
91219820Sjeff  fp->_wcount = 0;
92219820Sjeff  fp->_ungetc_count = 0;
93219820Sjeff  return 0;
94219820Sjeff# elif defined _IOERR               /* AIX, HP-UX, IRIX, OSF/1, Solaris, OpenServer, mingw */
95219820Sjeff  fp->_ptr = fp->_base;
96219820Sjeff  if (fp->_ptr != NULL)
97219820Sjeff    fp->_cnt = 0;
98219820Sjeff  return 0;
99219820Sjeff# elif defined __UCLIBC__           /* uClibc */
100219820Sjeff#  ifdef __STDIO_BUFFERS
101219820Sjeff  if (fp->__modeflags & __FLAG_WRITING)
102219820Sjeff    fp->__bufpos = fp->__bufstart;
103219820Sjeff  else if (fp->__modeflags & (__FLAG_READONLY | __FLAG_READING))
104219820Sjeff    fp->__bufpos = fp->__bufread;
105219820Sjeff#  endif
106219820Sjeff  return 0;
107219820Sjeff# elif defined __QNX__              /* QNX */
108219820Sjeff  fp->_Rback = fp->_Back + sizeof (fp->_Back);
109219820Sjeff  fp->_Rsave = NULL;
110219820Sjeff  if (fp->_Mode & 0x2000 /* _MWRITE */)
111219820Sjeff    /* fp->_Buf <= fp->_Next <= fp->_Wend */
112219820Sjeff    fp->_Next = fp->_Buf;
113219820Sjeff  else
114219820Sjeff    /* fp->_Buf <= fp->_Next <= fp->_Rend */
115219820Sjeff    fp->_Rend = fp->_Next;
116219820Sjeff  return 0;
117219820Sjeff# elif defined __MINT__             /* Atari FreeMiNT */
118219820Sjeff  if (fp->__pushed_back)
119219820Sjeff    {
120219820Sjeff      fp->__bufp = fp->__pushback_bufp;
121219820Sjeff      fp->__pushed_back = 0;
122219820Sjeff    }
123219820Sjeff  /* Preserve the current file position.  */
124219820Sjeff  if (fp->__target != -1)
125219820Sjeff    fp->__target += fp->__bufp - fp->__buffer;
126219820Sjeff  fp->__bufp = fp->__buffer;
127219820Sjeff  /* Nothing in the buffer, next getc is nontrivial.  */
128219820Sjeff  fp->__get_limit = fp->__bufp;
129219820Sjeff  /* Nothing in the buffer, next putc is nontrivial.  */
130219820Sjeff  fp->__put_limit = fp->__buffer;
131219820Sjeff  return 0;
132219820Sjeff# else
133219820Sjeff #error "Please port gnulib fpurge.c to your platform! Look at the definitions of fflush, setvbuf and ungetc on your system, then report this to bug-gnulib."
134219820Sjeff# endif
135219820Sjeff
136219820Sjeff#endif
137219820Sjeff}
138219820Sjeff