Line data Source code
1 : /* fpurge - Flushing buffers of a FILE stream. */
2 :
3 : /* Copyright (C) 2007-2010 Free Software Foundation, Inc.
4 :
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
32 : extern int fpurge __P((FILE *stream));
33 :
34 : #if HAVE___FPURGE /* glibc >= 2.2, Haiku, Solaris >= 7 */
35 : # include <stdio_ext.h>
36 : #endif
37 : #include <stdlib.h>
38 :
39 : /* 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 :
123 : int
124 42808431 : fpurge (FILE *fp)
125 : {
126 : #if HAVE___FPURGE /* glibc >= 2.2, Haiku, Solaris >= 7 */
127 :
128 42808431 : __fpurge (fp);
129 : /* The __fpurge function does not have a return value. */
130 42808431 : return 0;
131 :
132 : #elif HAVE_FPURGE /* FreeBSD, NetBSD, OpenBSD, DragonFly, MacOS X, Cygwin 1.7 */
133 :
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);
140 : # if defined __sferror || defined __DragonFly__ /* FreeBSD, NetBSD, OpenBSD, DragonFly, MacOS X, Cygwin */
141 : 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
146 : currently reading, subsequent putc or fputc calls will write directly
147 : into the buffer, although they shouldn't be allowed to. */
148 : if ((fp_->_flags & __SRD) != 0)
149 : fp_->_w = 0;
150 : # 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. */
158 : # if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
159 : 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;
168 : # 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);
174 : /* Avoid memory leak when there is an active ungetc buffer. */
175 : if (fp_ub._base != NULL)
176 : {
177 : if (fp_ub._base != fp_->_ubuf)
178 : free (fp_ub._base);
179 : fp_ub._base = NULL;
180 : }
181 : return 0;
182 : # 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;
188 : # elif defined _IOERR || defined __TANDEM /* AIX, HP-UX, IRIX, OSF/1, Solaris, OpenServer, mingw */
189 : 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;
201 : # 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;
226 : # else
227 : # 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;
229 : # endif
230 :
231 : #endif
232 : }
|