blob: 13e8c78eefe685956154330b7a7af4d6364e1768 [file] [log] [blame]
Jari Aalto31859422009-01-12 13:36:28 +00001/* fpurge - Flushing buffers of a FILE stream. */
2
Chet Ramey495aee42011-11-22 19:11:26 -05003/* Copyright (C) 2007-2010 Free Software Foundation, Inc.
Jari Aalto31859422009-01-12 13:36:28 +00004
5 This file is part of GNU Bash, the Bourne Again SHell.
6
7 Bash is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 Bash is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Bash. If not, see <http://www.gnu.org/licenses/>.
19*/
20
21#include <config.h>
22
23#include "stdc.h"
24
25#include <stdio.h>
26
27/* Specification. Same as in ../../externs.h. */
28#define NEED_FPURGE_DECL
29#if HAVE_FPURGE
30# define fpurge _bash_fpurge
31#endif
32extern int fpurge __P((FILE *stream));
33
Chet Ramey00018032011-11-21 20:51:19 -050034#if HAVE___FPURGE /* glibc >= 2.2, Haiku, Solaris >= 7 */
Jari Aalto31859422009-01-12 13:36:28 +000035# include <stdio_ext.h>
36#endif
37#include <stdlib.h>
38
Chet Ramey495aee42011-11-22 19:11:26 -050039/* Inline contents of gnulib:stdio-impl.h */
40
41/* Many stdio implementations have the same logic and therefore can share
42 the same implementation of stdio extension API, except that some fields
43 have different naming conventions, or their access requires some casts. */
44
45/* BSD stdio derived implementations. */
46
47#if defined __NetBSD__ /* NetBSD */
48/* Get __NetBSD_Version__. */
49# include <sys/param.h>
50#endif
51
52#if defined __sferror || defined __DragonFly__ /* FreeBSD, NetBSD, OpenBSD, DragonFly, MacOS X, Cygwin */
53
54# if defined __DragonFly__ /* DragonFly */
55 /* See <http://www.dragonflybsd.org/cvsweb/src/lib/libc/stdio/priv_stdio.h?rev=HEAD&content-type=text/x-cvsweb-markup>. */
56# define fp_ ((struct { struct __FILE_public pub; \
57 struct { unsigned char *_base; int _size; } _bf; \
58 void *cookie; \
59 void *_close; \
60 void *_read; \
61 void *_seek; \
62 void *_write; \
63 struct { unsigned char *_base; int _size; } _ub; \
64 int _ur; \
65 unsigned char _ubuf[3]; \
66 unsigned char _nbuf[1]; \
67 struct { unsigned char *_base; int _size; } _lb; \
68 int _blksize; \
69 fpos_t _offset; \
70 /* More fields, not relevant here. */ \
71 } *) fp)
72 /* See <http://www.dragonflybsd.org/cvsweb/src/include/stdio.h?rev=HEAD&content-type=text/x-cvsweb-markup>. */
73# define _p pub._p
74# define _flags pub._flags
75# define _r pub._r
76# define _w pub._w
77# else
78# define fp_ fp
79# endif
80
81# if (defined __NetBSD__ && __NetBSD_Version__ >= 105270000) || defined __OpenBSD__ /* NetBSD >= 1.5ZA, OpenBSD */
82 /* See <http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/stdio/fileext.h?rev=HEAD&content-type=text/x-cvsweb-markup>
83 and <http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/stdio/fileext.h?rev=HEAD&content-type=text/x-cvsweb-markup> */
84 struct __sfileext
85 {
86 struct __sbuf _ub; /* ungetc buffer */
87 /* More fields, not relevant here. */
88 };
89# define fp_ub ((struct __sfileext *) fp->_ext._base)->_ub
90# else /* FreeBSD, NetBSD <= 1.5Z, DragonFly, MacOS X, Cygwin */
91# define fp_ub fp_->_ub
92# endif
93
94# define HASUB(fp) (fp_ub._base != NULL)
95
96#endif
97
98/* SystemV derived implementations. */
99
100#if defined _IOERR
101
102# if defined __sun && defined _LP64 /* Solaris/{SPARC,AMD64} 64-bit */
103# define fp_ ((struct { unsigned char *_ptr; \
104 unsigned char *_base; \
105 unsigned char *_end; \
106 long _cnt; \
107 int _file; \
108 unsigned int _flag; \
109 } *) fp)
110# else
111# define fp_ fp
112# endif
113
114# if defined _SCO_DS /* OpenServer */
115# define _cnt __cnt
116# define _ptr __ptr
117# define _base __base
118# define _flag __flag
119# endif
120
121#endif
122
Jari Aalto31859422009-01-12 13:36:28 +0000123int
124fpurge (FILE *fp)
125{
Chet Ramey00018032011-11-21 20:51:19 -0500126#if HAVE___FPURGE /* glibc >= 2.2, Haiku, Solaris >= 7 */
Jari Aalto31859422009-01-12 13:36:28 +0000127
128 __fpurge (fp);
129 /* The __fpurge function does not have a return value. */
130 return 0;
131
Chet Ramey495aee42011-11-22 19:11:26 -0500132#elif HAVE_FPURGE /* FreeBSD, NetBSD, OpenBSD, DragonFly, MacOS X, Cygwin 1.7 */
Jari Aalto31859422009-01-12 13:36:28 +0000133
134 /* Call the system's fpurge function. */
135# undef fpurge
136# if !HAVE_DECL_FPURGE
137 extern int fpurge (FILE *);
138# endif
139 int result = fpurge (fp);
Chet Ramey00018032011-11-21 20:51:19 -0500140# if defined __sferror || defined __DragonFly__ /* FreeBSD, NetBSD, OpenBSD, DragonFly, MacOS X, Cygwin */
Jari Aalto31859422009-01-12 13:36:28 +0000141 if (result == 0)
142 /* Correct the invariants that fpurge broke.
143 <stdio.h> on BSD systems says:
144 "The following always hold: if _flags & __SRD, _w is 0."
145 If this invariant is not fulfilled and the stream is read-write but
Chet Ramey495aee42011-11-22 19:11:26 -0500146 currently reading, subsequent putc or fputc calls will write directly
Jari Aalto31859422009-01-12 13:36:28 +0000147 into the buffer, although they shouldn't be allowed to. */
Chet Ramey495aee42011-11-22 19:11:26 -0500148 if ((fp_->_flags & __SRD) != 0)
149 fp_->_w = 0;
Jari Aalto31859422009-01-12 13:36:28 +0000150# endif
151 return result;
152
153#else
154
155 /* Most systems provide FILE as a struct and the necessary bitmask in
156 <stdio.h>, because they need it for implementing getc() and putc() as
157 fast macros. */
Chet Ramey00018032011-11-21 20:51:19 -0500158# if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
Jari Aalto31859422009-01-12 13:36:28 +0000159 fp->_IO_read_end = fp->_IO_read_ptr;
160 fp->_IO_write_ptr = fp->_IO_write_base;
161 /* Avoid memory leak when there is an active ungetc buffer. */
162 if (fp->_IO_save_base != NULL)
163 {
164 free (fp->_IO_save_base);
165 fp->_IO_save_base = NULL;
166 }
167 return 0;
Chet Ramey00018032011-11-21 20:51:19 -0500168# elif defined __sferror || defined __DragonFly__ /* FreeBSD, NetBSD, OpenBSD, DragonFly, MacOS X, Cygwin */
169 fp_->_p = fp_->_bf._base;
170 fp_->_r = 0;
171 fp_->_w = ((fp_->_flags & (__SLBF | __SNBF | __SRD)) == 0 /* fully buffered and not currently reading? */
172 ? fp_->_bf._size
173 : 0);
Jari Aalto31859422009-01-12 13:36:28 +0000174 /* Avoid memory leak when there is an active ungetc buffer. */
Jari Aalto31859422009-01-12 13:36:28 +0000175 if (fp_ub._base != NULL)
176 {
Chet Ramey00018032011-11-21 20:51:19 -0500177 if (fp_ub._base != fp_->_ubuf)
Jari Aalto31859422009-01-12 13:36:28 +0000178 free (fp_ub._base);
179 fp_ub._base = NULL;
180 }
181 return 0;
Chet Ramey00018032011-11-21 20:51:19 -0500182# elif defined __EMX__ /* emx+gcc */
183 fp->_ptr = fp->_buffer;
184 fp->_rcount = 0;
185 fp->_wcount = 0;
186 fp->_ungetc_count = 0;
187 return 0;
Chet Ramey495aee42011-11-22 19:11:26 -0500188# elif defined _IOERR || defined __TANDEM /* AIX, HP-UX, IRIX, OSF/1, Solaris, OpenServer, mingw */
Jari Aalto31859422009-01-12 13:36:28 +0000189 fp->_ptr = fp->_base;
190 if (fp->_ptr != NULL)
191 fp->_cnt = 0;
192 return 0;
193# elif defined __UCLIBC__ /* uClibc */
194# ifdef __STDIO_BUFFERS
195 if (fp->__modeflags & __FLAG_WRITING)
196 fp->__bufpos = fp->__bufstart;
197 else if (fp->__modeflags & (__FLAG_READONLY | __FLAG_READING))
198 fp->__bufpos = fp->__bufread;
199# endif
200 return 0;
Chet Ramey00018032011-11-21 20:51:19 -0500201# elif defined __QNX__ /* QNX */
202 fp->_Rback = fp->_Back + sizeof (fp->_Back);
203 fp->_Rsave = NULL;
204 if (fp->_Mode & 0x2000 /* _MWRITE */)
205 /* fp->_Buf <= fp->_Next <= fp->_Wend */
206 fp->_Next = fp->_Buf;
207 else
208 /* fp->_Buf <= fp->_Next <= fp->_Rend */
209 fp->_Rend = fp->_Next;
210 return 0;
211# elif defined __MINT__ /* Atari FreeMiNT */
212 if (fp->__pushed_back)
213 {
214 fp->__bufp = fp->__pushback_bufp;
215 fp->__pushed_back = 0;
216 }
217 /* Preserve the current file position. */
218 if (fp->__target != -1)
219 fp->__target += fp->__bufp - fp->__buffer;
220 fp->__bufp = fp->__buffer;
221 /* Nothing in the buffer, next getc is nontrivial. */
222 fp->__get_limit = fp->__bufp;
223 /* Nothing in the buffer, next putc is nontrivial. */
224 fp->__put_limit = fp->__buffer;
225 return 0;
Jari Aalto31859422009-01-12 13:36:28 +0000226# else
Chet Ramey00018032011-11-21 20:51:19 -0500227# warning "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."
228 return 0;
Jari Aalto31859422009-01-12 13:36:28 +0000229# endif
230
231#endif
232}