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