123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119 |
- /* Copyright (C) 2004 Manuel Novoa III <mjn3@codepoet.org>
- *
- * GNU Library General Public License (LGPL) version 2 or later.
- *
- * Dedicated to Toni. See uClibc/DEDICATION.mjn3 for details.
- */
- #include "_stdio.h"
- /* Given a writing stream with no buffered output, write the
- * data in 'buf' (which may be the stream's bufstart) of size
- * 'bufsize' to the stream. If a write error occurs, set the
- * stream's error indicator and (if buffering) buffer as much
- * data as possible (FBF) or only up to '\n' (LBF) to implement
- * "as if fputc()" clause in the standard.
- *
- * Returns the number of bytes written and/or buffered.
- *
- * Notes:
- * Calling with bufsize == 0 is permitted, and buf is ignored in
- * that case.
- * We implement fflush() by setting bufpos to bufstart and passing
- * bufstart as the buf arg. If there is a write error, the
- * unwritten buffered data will simply be moved to the beginning
- * of the buffer. Since the data obviously fits in the buffer
- * and since there will be no '\n' chars in the buffer in the LBF
- * case, no data will be lost.
- * NOT THREADSAFE! Assumes stream already locked if necessary.
- */
- size_t attribute_hidden __stdio_WRITE(register FILE *stream,
- register const unsigned char *buf, size_t bufsize)
- {
- size_t todo;
- ssize_t rv, stodo;
- __STDIO_STREAM_VALIDATE(stream);
- assert(stream->__filedes >= -1);
- assert(__STDIO_STREAM_IS_WRITING(stream));
- assert(!__STDIO_STREAM_BUFFER_WUSED(stream)); /* Buffer must be empty. */
- todo = bufsize;
- while (todo != 0) {
- stodo = (todo <= SSIZE_MAX) ? todo : SSIZE_MAX;
- rv = __WRITE(stream, (char *) buf, stodo);
- if (rv >= 0) {
- #ifdef __UCLIBC_MJN3_ONLY__
- #warning TODO: Make custom stream write return check optional.
- #endif
- #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__
- assert(rv <= stodo);
- if (rv > stodo) { /* Wrote more than stodo! */
- /* abort(); */
- }
- #endif
- todo -= rv;
- buf += rv;
- } else {
- __STDIO_STREAM_SET_ERROR(stream);
- /* We buffer data on "transient" errors, but discard it
- * on "hard" ones. Example of a hard error:
- *
- * close(fileno(stdout));
- * printf("Hi there 1\n"); // EBADF
- * dup2(good_fd, fileno(stdout));
- * printf("Hi there 2\n"); // buffers new data
- *
- * This program should not print "Hi there 1" to good_fd.
- * The rationale is that the caller of writing operation
- * should check for error and act on it.
- * If he didn't, then future users of the stream
- * have no idea what to do.
- * It's least confusing to at least not burden them with
- * some hidden buffered crap in the buffer.
- */
- if (errno != EINTR && errno != EAGAIN) {
- /* do we have other "soft" errors? */
- break;
- }
- #ifdef __STDIO_BUFFERS
- stodo = __STDIO_STREAM_BUFFER_SIZE(stream);
- if (stodo != 0) {
- unsigned char *s;
- if (stodo > todo) {
- stodo = todo;
- }
- s = stream->__bufstart;
- do {
- *s = *buf;
- if ((*s == '\n')
- && __STDIO_STREAM_IS_LBF(stream)
- ) {
- break;
- }
- ++s;
- ++buf;
- } while (--stodo);
- stream->__bufpos = s;
- todo -= (s - stream->__bufstart);
- }
- #endif /* __STDIO_BUFFERS */
- bufsize -= todo;
- break;
- }
- }
- __STDIO_STREAM_VALIDATE(stream);
- return bufsize;
- }
|