]> git.ipfire.org Git - thirdparty/bash.git/blob - lib/sh/fpurge.c
Bash-4.2 distribution sources and documentation
[thirdparty/bash.git] / lib / sh / fpurge.c
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 fpurge (FILE *fp)
125 {
126 #if HAVE___FPURGE /* glibc >= 2.2, Haiku, Solaris >= 7 */
127
128 __fpurge (fp);
129 /* The __fpurge function does not have a return value. */
130 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 }