Rev 4921 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4349 | Serge | 1 | /* |
2 | * Copyright (c) 1990 The Regents of the University of California. |
||
3 | * All rights reserved. |
||
4 | * |
||
5 | * Redistribution and use in source and binary forms are permitted |
||
6 | * provided that the above copyright notice and this paragraph are |
||
7 | * duplicated in all such forms and that any documentation, |
||
8 | * advertising materials, and other materials related to such |
||
9 | * distribution and use acknowledge that the software was developed |
||
10 | * by the University of California, Berkeley. The name of the |
||
11 | * University may not be used to endorse or promote products derived |
||
12 | * from this software without specific prior written permission. |
||
13 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
||
14 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
||
15 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
||
16 | */ |
||
17 | |||
18 | /* |
||
19 | FUNCTION |
||
6099 | serge | 20 | < |
4349 | Serge | 21 | |
22 | INDEX |
||
23 | fflush |
||
24 | INDEX |
||
6099 | serge | 25 | fflush_unlocked |
26 | INDEX |
||
4349 | Serge | 27 | _fflush_r |
6099 | serge | 28 | INDEX |
29 | _fflush_unlocked_r |
||
4349 | Serge | 30 | |
31 | ANSI_SYNOPSIS |
||
32 | #include |
||
33 | int fflush(FILE *<[fp]>); |
||
34 | |||
6099 | serge | 35 | #define _BSD_SOURCE |
36 | #include |
||
37 | int fflush_unlocked(FILE *<[fp]>); |
||
38 | |||
39 | #include |
||
4349 | Serge | 40 | int _fflush_r(struct _reent *<[reent]>, FILE *<[fp]>); |
41 | |||
6099 | serge | 42 | #define _BSD_SOURCE |
43 | #include |
||
44 | int _fflush_unlocked_r(struct _reent *<[reent]>, FILE *<[fp]>); |
||
45 | |||
4349 | Serge | 46 | DESCRIPTION |
47 | The < |
||
48 | to the host system, in order to minimize the overhead of system calls. |
||
49 | |||
50 | Use < |
||
51 | or stream identified by <[fp]>) to the host system. |
||
52 | |||
53 | If <[fp]> is < |
||
54 | open files. |
||
55 | |||
56 | Additionally, if <[fp]> is a seekable input stream visiting a file |
||
57 | descriptor, set the position of the file descriptor to match next |
||
58 | unread byte, useful for obeying POSIX semantics when ending a process |
||
59 | without consuming all input from the stream. |
||
60 | |||
6099 | serge | 61 | < |
62 | < |
||
63 | protected by flockfile() (or ftrylockfile()) and funlockfile(). This |
||
64 | function may safely be used in a multi-threaded program if and only |
||
65 | if they are called while the invoking thread owns the (FILE *) |
||
66 | object, as is the case after a successful call to the flockfile() or |
||
67 | ftrylockfile() functions. If threads are disabled, then |
||
68 | < |
||
4349 | Serge | 69 | |
6099 | serge | 70 | The alternate functions <<_fflush_r>> and <<_fflush_unlocked_r>> are |
71 | reentrant versions, where the extra argument <[reent]> is a pointer to |
||
72 | a reentrancy structure, and <[fp]> must not be NULL. |
||
73 | |||
4349 | Serge | 74 | RETURNS |
75 | < |
||
76 | situation, it returns < |
||
77 | |||
78 | PORTABILITY |
||
79 | ANSI C requires < |
||
80 | specified by POSIX, and not all implementations follow POSIX rules. |
||
81 | |||
6099 | serge | 82 | < |
83 | |||
4349 | Serge | 84 | No supporting OS subroutines are required. |
85 | */ |
||
86 | |||
87 | #include <_ansi.h> |
||
88 | #include |
||
89 | #include |
||
90 | #include "local.h" |
||
91 | |||
6099 | serge | 92 | #ifdef __IMPL_UNLOCKED__ |
93 | #define _fflush_r _fflush_unlocked_r |
||
94 | #define fflush fflush_unlocked |
||
95 | #endif |
||
96 | |||
97 | #ifndef __IMPL_UNLOCKED__ |
||
4349 | Serge | 98 | /* Flush a single file, or (if fp is NULL) all files. */ |
99 | |||
100 | /* Core function which does not lock file pointer. This gets called |
||
101 | directly from __srefill. */ |
||
102 | int |
||
103 | _DEFUN(__sflush_r, (ptr, fp), |
||
104 | struct _reent *ptr _AND |
||
105 | register FILE * fp) |
||
106 | { |
||
107 | register unsigned char *p; |
||
4921 | Serge | 108 | register _READ_WRITE_BUFSIZE_TYPE n; |
109 | register _READ_WRITE_RETURN_TYPE t; |
||
110 | short flags; |
||
4349 | Serge | 111 | |
4921 | Serge | 112 | flags = fp->_flags; |
113 | if ((flags & __SWR) == 0) |
||
4349 | Serge | 114 | { |
4921 | Serge | 115 | #ifdef _FSEEK_OPTIMIZATION |
4349 | Serge | 116 | /* For a read stream, an fflush causes the next seek to be |
117 | unoptimized (i.e. forces a system-level seek). This conforms |
||
118 | to the POSIX and SUSv3 standards. */ |
||
119 | fp->_flags |= __SNPT; |
||
4921 | Serge | 120 | #endif |
4349 | Serge | 121 | |
122 | /* For a seekable stream with buffered read characters, we will attempt |
||
123 | a seek to the current position now. A subsequent read will then get |
||
124 | the next byte from the file rather than the buffer. This conforms |
||
125 | to the POSIX and SUSv3 standards. Note that the standards allow |
||
126 | this seek to be deferred until necessary, but we choose to do it here |
||
127 | to make the change simpler, more contained, and less likely |
||
128 | to miss a code scenario. */ |
||
129 | if ((fp->_r > 0 || fp->_ur > 0) && fp->_seek != NULL) |
||
130 | { |
||
131 | int tmp_errno; |
||
132 | #ifdef __LARGE64_FILES |
||
133 | _fpos64_t curoff; |
||
134 | #else |
||
135 | _fpos_t curoff; |
||
136 | #endif |
||
137 | |||
138 | /* Save last errno and set errno to 0, so we can check if a device |
||
139 | returns with a valid position -1. We restore the last errno if |
||
140 | no other error condition has been encountered. */ |
||
141 | tmp_errno = ptr->_errno; |
||
142 | ptr->_errno = 0; |
||
143 | /* Get the physical position we are at in the file. */ |
||
144 | if (fp->_flags & __SOFF) |
||
145 | curoff = fp->_offset; |
||
146 | else |
||
147 | { |
||
148 | /* We don't know current physical offset, so ask for it. |
||
149 | Only ESPIPE and EINVAL are ignorable. */ |
||
150 | #ifdef __LARGE64_FILES |
||
151 | if (fp->_flags & __SL64) |
||
152 | curoff = fp->_seek64 (ptr, fp->_cookie, 0, SEEK_CUR); |
||
153 | else |
||
154 | #endif |
||
155 | curoff = fp->_seek (ptr, fp->_cookie, 0, SEEK_CUR); |
||
156 | if (curoff == -1L && ptr->_errno != 0) |
||
157 | { |
||
158 | int result = EOF; |
||
159 | if (ptr->_errno == ESPIPE || ptr->_errno == EINVAL) |
||
160 | { |
||
161 | result = 0; |
||
162 | ptr->_errno = tmp_errno; |
||
163 | } |
||
164 | else |
||
165 | fp->_flags |= __SERR; |
||
166 | return result; |
||
167 | } |
||
168 | } |
||
169 | if (fp->_flags & __SRD) |
||
170 | { |
||
171 | /* Current offset is at end of buffer. Compensate for |
||
172 | characters not yet read. */ |
||
173 | curoff -= fp->_r; |
||
174 | if (HASUB (fp)) |
||
175 | curoff -= fp->_ur; |
||
176 | } |
||
177 | /* Now physically seek to after byte last read. */ |
||
178 | #ifdef __LARGE64_FILES |
||
179 | if (fp->_flags & __SL64) |
||
180 | curoff = fp->_seek64 (ptr, fp->_cookie, curoff, SEEK_SET); |
||
181 | else |
||
182 | #endif |
||
183 | curoff = fp->_seek (ptr, fp->_cookie, curoff, SEEK_SET); |
||
184 | if (curoff != -1 || ptr->_errno == 0 |
||
185 | || ptr->_errno == ESPIPE || ptr->_errno == EINVAL) |
||
186 | { |
||
187 | /* Seek successful or ignorable error condition. |
||
188 | We can clear read buffer now. */ |
||
4921 | Serge | 189 | #ifdef _FSEEK_OPTIMIZATION |
4349 | Serge | 190 | fp->_flags &= ~__SNPT; |
4921 | Serge | 191 | #endif |
4349 | Serge | 192 | fp->_r = 0; |
193 | fp->_p = fp->_bf._base; |
||
194 | if ((fp->_flags & __SOFF) && (curoff != -1 || ptr->_errno == 0)) |
||
195 | fp->_offset = curoff; |
||
196 | ptr->_errno = tmp_errno; |
||
197 | if (HASUB (fp)) |
||
198 | FREEUB (ptr, fp); |
||
199 | } |
||
200 | else |
||
201 | { |
||
202 | fp->_flags |= __SERR; |
||
203 | return EOF; |
||
204 | } |
||
205 | } |
||
206 | return 0; |
||
207 | } |
||
208 | if ((p = fp->_bf._base) == NULL) |
||
209 | { |
||
210 | /* Nothing to flush. */ |
||
211 | return 0; |
||
212 | } |
||
213 | n = fp->_p - p; /* write this much */ |
||
214 | |||
215 | /* |
||
216 | * Set these immediately to avoid problems with longjmp |
||
217 | * and to allow exchange buffering (via setvbuf) in user |
||
218 | * write function. |
||
219 | */ |
||
220 | fp->_p = p; |
||
4921 | Serge | 221 | fp->_w = flags & (__SLBF | __SNBF) ? 0 : fp->_bf._size; |
4349 | Serge | 222 | |
223 | while (n > 0) |
||
224 | { |
||
225 | t = fp->_write (ptr, fp->_cookie, (char *) p, n); |
||
226 | if (t <= 0) |
||
227 | { |
||
228 | fp->_flags |= __SERR; |
||
229 | return EOF; |
||
230 | } |
||
231 | p += t; |
||
232 | n -= t; |
||
233 | } |
||
234 | return 0; |
||
235 | } |
||
236 | |||
6099 | serge | 237 | #ifdef _STDIO_BSD_SEMANTICS |
238 | /* Called from _cleanup_r. At exit time, we don't need file locking, |
||
239 | and we don't want to move the underlying file pointer unless we're |
||
240 | writing. */ |
||
4349 | Serge | 241 | int |
6099 | serge | 242 | _DEFUN(__sflushw_r, (ptr, fp), |
243 | struct _reent *ptr _AND |
||
244 | register FILE *fp) |
||
245 | { |
||
246 | return (fp->_flags & __SWR) ? __sflush_r (ptr, fp) : 0; |
||
247 | } |
||
248 | #endif |
||
249 | |||
250 | #endif /* __IMPL_UNLOCKED__ */ |
||
251 | |||
252 | int |
||
4349 | Serge | 253 | _DEFUN(_fflush_r, (ptr, fp), |
254 | struct _reent *ptr _AND |
||
255 | register FILE * fp) |
||
256 | { |
||
257 | int ret; |
||
258 | |||
259 | #ifdef _REENT_SMALL |
||
260 | /* For REENT_SMALL platforms, it is possible we are being |
||
261 | called for the first time on a std stream. This std |
||
262 | stream can belong to a reentrant struct that is not |
||
263 | _REENT. If CHECK_INIT gets called below based on _REENT, |
||
264 | we will end up changing said file pointers to the equivalent |
||
265 | std stream off of _REENT. This causes unexpected behavior if |
||
266 | there is any data to flush on the _REENT std stream. There |
||
267 | are two alternatives to fix this: 1) make a reentrant fflush |
||
268 | or 2) simply recognize that this file has nothing to flush |
||
269 | and return immediately before performing a CHECK_INIT. Choice |
||
270 | 2 is implemented here due to its simplicity. */ |
||
271 | if (fp->_bf._base == NULL) |
||
272 | return 0; |
||
273 | #endif /* _REENT_SMALL */ |
||
274 | |||
275 | CHECK_INIT (ptr, fp); |
||
276 | |||
277 | if (!fp->_flags) |
||
278 | return 0; |
||
279 | |||
4921 | Serge | 280 | _newlib_flockfile_start (fp); |
4349 | Serge | 281 | ret = __sflush_r (ptr, fp); |
4921 | Serge | 282 | _newlib_flockfile_end (fp); |
4349 | Serge | 283 | return ret; |
284 | } |
||
285 | |||
286 | #ifndef _REENT_ONLY |
||
287 | |||
288 | int |
||
289 | _DEFUN(fflush, (fp), |
||
290 | register FILE * fp) |
||
291 | { |
||
292 | if (fp == NULL) |
||
293 | return _fwalk_reent (_GLOBAL_REENT, _fflush_r); |
||
294 | |||
295 | return _fflush_r (_REENT, fp); |
||
296 | } |
||
297 | |||
298 | #endif /* _REENT_ONLY */=> |