Rev 4874 | Go to most recent revision | 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 |
||
20 | < |
||
21 | |||
22 | INDEX |
||
23 | fflush |
||
24 | INDEX |
||
25 | _fflush_r |
||
26 | |||
27 | ANSI_SYNOPSIS |
||
28 | #include |
||
29 | int fflush(FILE *<[fp]>); |
||
30 | |||
31 | int _fflush_r(struct _reent *<[reent]>, FILE *<[fp]>); |
||
32 | |||
33 | DESCRIPTION |
||
34 | The < |
||
35 | to the host system, in order to minimize the overhead of system calls. |
||
36 | |||
37 | Use < |
||
38 | or stream identified by <[fp]>) to the host system. |
||
39 | |||
40 | If <[fp]> is < |
||
41 | open files. |
||
42 | |||
43 | Additionally, if <[fp]> is a seekable input stream visiting a file |
||
44 | descriptor, set the position of the file descriptor to match next |
||
45 | unread byte, useful for obeying POSIX semantics when ending a process |
||
46 | without consuming all input from the stream. |
||
47 | |||
48 | The alternate function <<_fflush_r>> is a reentrant version, where the |
||
49 | extra argument <[reent]> is a pointer to a reentrancy structure, and |
||
50 | <[fp]> must not be NULL. |
||
51 | |||
52 | RETURNS |
||
53 | < |
||
54 | situation, it returns < |
||
55 | |||
56 | PORTABILITY |
||
57 | ANSI C requires < |
||
58 | specified by POSIX, and not all implementations follow POSIX rules. |
||
59 | |||
60 | No supporting OS subroutines are required. |
||
61 | */ |
||
62 | |||
63 | #include <_ansi.h> |
||
64 | #include |
||
65 | #include |
||
66 | #include "local.h" |
||
67 | |||
68 | /* Flush a single file, or (if fp is NULL) all files. */ |
||
69 | |||
70 | /* Core function which does not lock file pointer. This gets called |
||
71 | directly from __srefill. */ |
||
72 | int |
||
73 | _DEFUN(__sflush_r, (ptr, fp), |
||
74 | struct _reent *ptr _AND |
||
75 | register FILE * fp) |
||
76 | { |
||
77 | register unsigned char *p; |
||
4921 | Serge | 78 | register _READ_WRITE_BUFSIZE_TYPE n; |
79 | register _READ_WRITE_RETURN_TYPE t; |
||
80 | short flags; |
||
4349 | Serge | 81 | |
4921 | Serge | 82 | flags = fp->_flags; |
83 | if ((flags & __SWR) == 0) |
||
4349 | Serge | 84 | { |
4921 | Serge | 85 | #ifdef _FSEEK_OPTIMIZATION |
4349 | Serge | 86 | /* For a read stream, an fflush causes the next seek to be |
87 | unoptimized (i.e. forces a system-level seek). This conforms |
||
88 | to the POSIX and SUSv3 standards. */ |
||
89 | fp->_flags |= __SNPT; |
||
4921 | Serge | 90 | #endif |
4349 | Serge | 91 | |
92 | /* For a seekable stream with buffered read characters, we will attempt |
||
93 | a seek to the current position now. A subsequent read will then get |
||
94 | the next byte from the file rather than the buffer. This conforms |
||
95 | to the POSIX and SUSv3 standards. Note that the standards allow |
||
96 | this seek to be deferred until necessary, but we choose to do it here |
||
97 | to make the change simpler, more contained, and less likely |
||
98 | to miss a code scenario. */ |
||
99 | if ((fp->_r > 0 || fp->_ur > 0) && fp->_seek != NULL) |
||
100 | { |
||
101 | int tmp_errno; |
||
102 | #ifdef __LARGE64_FILES |
||
103 | _fpos64_t curoff; |
||
104 | #else |
||
105 | _fpos_t curoff; |
||
106 | #endif |
||
107 | |||
108 | /* Save last errno and set errno to 0, so we can check if a device |
||
109 | returns with a valid position -1. We restore the last errno if |
||
110 | no other error condition has been encountered. */ |
||
111 | tmp_errno = ptr->_errno; |
||
112 | ptr->_errno = 0; |
||
113 | /* Get the physical position we are at in the file. */ |
||
114 | if (fp->_flags & __SOFF) |
||
115 | curoff = fp->_offset; |
||
116 | else |
||
117 | { |
||
118 | /* We don't know current physical offset, so ask for it. |
||
119 | Only ESPIPE and EINVAL are ignorable. */ |
||
120 | #ifdef __LARGE64_FILES |
||
121 | if (fp->_flags & __SL64) |
||
122 | curoff = fp->_seek64 (ptr, fp->_cookie, 0, SEEK_CUR); |
||
123 | else |
||
124 | #endif |
||
125 | curoff = fp->_seek (ptr, fp->_cookie, 0, SEEK_CUR); |
||
126 | if (curoff == -1L && ptr->_errno != 0) |
||
127 | { |
||
128 | int result = EOF; |
||
129 | if (ptr->_errno == ESPIPE || ptr->_errno == EINVAL) |
||
130 | { |
||
131 | result = 0; |
||
132 | ptr->_errno = tmp_errno; |
||
133 | } |
||
134 | else |
||
135 | fp->_flags |= __SERR; |
||
136 | return result; |
||
137 | } |
||
138 | } |
||
139 | if (fp->_flags & __SRD) |
||
140 | { |
||
141 | /* Current offset is at end of buffer. Compensate for |
||
142 | characters not yet read. */ |
||
143 | curoff -= fp->_r; |
||
144 | if (HASUB (fp)) |
||
145 | curoff -= fp->_ur; |
||
146 | } |
||
147 | /* Now physically seek to after byte last read. */ |
||
148 | #ifdef __LARGE64_FILES |
||
149 | if (fp->_flags & __SL64) |
||
150 | curoff = fp->_seek64 (ptr, fp->_cookie, curoff, SEEK_SET); |
||
151 | else |
||
152 | #endif |
||
153 | curoff = fp->_seek (ptr, fp->_cookie, curoff, SEEK_SET); |
||
154 | if (curoff != -1 || ptr->_errno == 0 |
||
155 | || ptr->_errno == ESPIPE || ptr->_errno == EINVAL) |
||
156 | { |
||
157 | /* Seek successful or ignorable error condition. |
||
158 | We can clear read buffer now. */ |
||
4921 | Serge | 159 | #ifdef _FSEEK_OPTIMIZATION |
4349 | Serge | 160 | fp->_flags &= ~__SNPT; |
4921 | Serge | 161 | #endif |
4349 | Serge | 162 | fp->_r = 0; |
163 | fp->_p = fp->_bf._base; |
||
164 | if ((fp->_flags & __SOFF) && (curoff != -1 || ptr->_errno == 0)) |
||
165 | fp->_offset = curoff; |
||
166 | ptr->_errno = tmp_errno; |
||
167 | if (HASUB (fp)) |
||
168 | FREEUB (ptr, fp); |
||
169 | } |
||
170 | else |
||
171 | { |
||
172 | fp->_flags |= __SERR; |
||
173 | return EOF; |
||
174 | } |
||
175 | } |
||
176 | return 0; |
||
177 | } |
||
178 | if ((p = fp->_bf._base) == NULL) |
||
179 | { |
||
180 | /* Nothing to flush. */ |
||
181 | return 0; |
||
182 | } |
||
183 | n = fp->_p - p; /* write this much */ |
||
184 | |||
185 | /* |
||
186 | * Set these immediately to avoid problems with longjmp |
||
187 | * and to allow exchange buffering (via setvbuf) in user |
||
188 | * write function. |
||
189 | */ |
||
190 | fp->_p = p; |
||
4921 | Serge | 191 | fp->_w = flags & (__SLBF | __SNBF) ? 0 : fp->_bf._size; |
4349 | Serge | 192 | |
193 | while (n > 0) |
||
194 | { |
||
195 | t = fp->_write (ptr, fp->_cookie, (char *) p, n); |
||
196 | if (t <= 0) |
||
197 | { |
||
198 | fp->_flags |= __SERR; |
||
199 | return EOF; |
||
200 | } |
||
201 | p += t; |
||
202 | n -= t; |
||
203 | } |
||
204 | return 0; |
||
205 | } |
||
206 | |||
207 | int |
||
208 | _DEFUN(_fflush_r, (ptr, fp), |
||
209 | struct _reent *ptr _AND |
||
210 | register FILE * fp) |
||
211 | { |
||
212 | int ret; |
||
213 | |||
214 | #ifdef _REENT_SMALL |
||
215 | /* For REENT_SMALL platforms, it is possible we are being |
||
216 | called for the first time on a std stream. This std |
||
217 | stream can belong to a reentrant struct that is not |
||
218 | _REENT. If CHECK_INIT gets called below based on _REENT, |
||
219 | we will end up changing said file pointers to the equivalent |
||
220 | std stream off of _REENT. This causes unexpected behavior if |
||
221 | there is any data to flush on the _REENT std stream. There |
||
222 | are two alternatives to fix this: 1) make a reentrant fflush |
||
223 | or 2) simply recognize that this file has nothing to flush |
||
224 | and return immediately before performing a CHECK_INIT. Choice |
||
225 | 2 is implemented here due to its simplicity. */ |
||
226 | if (fp->_bf._base == NULL) |
||
227 | return 0; |
||
228 | #endif /* _REENT_SMALL */ |
||
229 | |||
230 | CHECK_INIT (ptr, fp); |
||
231 | |||
232 | if (!fp->_flags) |
||
233 | return 0; |
||
234 | |||
4921 | Serge | 235 | _newlib_flockfile_start (fp); |
4349 | Serge | 236 | ret = __sflush_r (ptr, fp); |
4921 | Serge | 237 | _newlib_flockfile_end (fp); |
4349 | Serge | 238 | return ret; |
239 | } |
||
240 | |||
241 | #ifndef _REENT_ONLY |
||
242 | |||
243 | int |
||
244 | _DEFUN(fflush, (fp), |
||
245 | register FILE * fp) |
||
246 | { |
||
247 | if (fp == NULL) |
||
248 | return _fwalk_reent (_GLOBAL_REENT, _fflush_r); |
||
249 | |||
250 | return _fflush_r (_REENT, fp); |
||
251 | } |
||
252 | |||
253 | #endif /* _REENT_ONLY */=> |