No specific user configuration
[platform/upstream/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 }