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