146111Sbostic /*- 246111Sbostic * Copyright (c) 1990 The Regents of the University of California. 346111Sbostic * All rights reserved. 446111Sbostic * 546111Sbostic * This code is derived from software contributed to Berkeley by 646111Sbostic * Chris Torek. 746111Sbostic * 846111Sbostic * %sccs.include.redist.c% 946111Sbostic */ 1046111Sbostic 1146111Sbostic #if defined(LIBC_SCCS) && !defined(lint) 12*58451Storek static char sccsid[] = "@(#)fvwrite.c 5.4 (Berkeley) 03/04/93"; 1346111Sbostic #endif /* LIBC_SCCS and not lint */ 1446111Sbostic 1546111Sbostic #include <stdio.h> 1646111Sbostic #include <string.h> 1746111Sbostic #include "local.h" 1846111Sbostic #include "fvwrite.h" 1946111Sbostic 2046111Sbostic /* 2146111Sbostic * Write some memory regions. Return zero on success, EOF on error. 2246111Sbostic * 2346111Sbostic * This routine is large and unsightly, but most of the ugliness due 2446111Sbostic * to the three different kinds of output buffering is handled here. 2546111Sbostic */ 2646111Sbostic __sfvwrite(fp, uio) 2746111Sbostic register FILE *fp; 2846111Sbostic register struct __suio *uio; 2946111Sbostic { 3046111Sbostic register size_t len; 3146111Sbostic register char *p; 3246111Sbostic register struct __siov *iov; 3346111Sbostic register int w, s; 3446111Sbostic char *nl; 3546111Sbostic int nlknown, nldist; 3646111Sbostic 3746111Sbostic if ((len = uio->uio_resid) == 0) 3846111Sbostic return (0); 3946111Sbostic /* make sure we can write */ 4046111Sbostic if (cantwrite(fp)) 4146111Sbostic return (EOF); 4246111Sbostic 4346111Sbostic #define MIN(a, b) ((a) < (b) ? (a) : (b)) 44*58451Storek #define COPY(n) (void)memcpy((void *)fp->_p, (void *)p, (size_t)(n)) 4546111Sbostic 4646111Sbostic iov = uio->uio_iov; 4746275Storek p = iov->iov_base; 4846275Storek len = iov->iov_len; 4946275Storek iov++; 5046111Sbostic #define GETIOV(extra_work) \ 5146111Sbostic while (len == 0) { \ 5246111Sbostic extra_work; \ 5346111Sbostic p = iov->iov_base; \ 5446111Sbostic len = iov->iov_len; \ 5546111Sbostic iov++; \ 5646111Sbostic } 5746111Sbostic if (fp->_flags & __SNBF) { 5846111Sbostic /* 5946111Sbostic * Unbuffered: write up to BUFSIZ bytes at a time. 6046111Sbostic */ 6146111Sbostic do { 6246111Sbostic GETIOV(;); 6346111Sbostic w = (*fp->_write)(fp->_cookie, p, MIN(len, BUFSIZ)); 6446111Sbostic if (w <= 0) 6546111Sbostic goto err; 6646111Sbostic p += w; 6746111Sbostic len -= w; 6846111Sbostic } while ((uio->uio_resid -= w) != 0); 6946111Sbostic } else if ((fp->_flags & __SLBF) == 0) { 7046111Sbostic /* 7146111Sbostic * Fully buffered: fill partially full buffer, if any, 7246111Sbostic * and then flush. If there is no partial buffer, write 7346111Sbostic * one _bf._size byte chunk directly (without copying). 7446111Sbostic * 7546111Sbostic * String output is a special case: write as many bytes 7646111Sbostic * as fit, but pretend we wrote everything. This makes 7746111Sbostic * snprintf() return the number of bytes needed, rather 7846111Sbostic * than the number used, and avoids its write function 7946111Sbostic * (so that the write function can be invalid). 8046111Sbostic */ 8146111Sbostic do { 8246111Sbostic GETIOV(;); 8346111Sbostic w = fp->_w; 8446111Sbostic if (fp->_flags & __SSTR) { 8546111Sbostic if (len < w) 8646111Sbostic w = len; 8746111Sbostic COPY(w); /* copy MIN(fp->_w,len), */ 8846111Sbostic fp->_w -= w; 8946111Sbostic fp->_p += w; 9046111Sbostic w = len; /* but pretend copied all */ 9146111Sbostic } else if (fp->_p > fp->_bf._base && len > w) { 9246111Sbostic /* fill and flush */ 9346111Sbostic COPY(w); 9446111Sbostic /* fp->_w -= w; */ /* unneeded */ 9546111Sbostic fp->_p += w; 9646111Sbostic if (fflush(fp)) 9746111Sbostic goto err; 9846111Sbostic } else if (len >= (w = fp->_bf._size)) { 9946111Sbostic /* write directly */ 10046111Sbostic w = (*fp->_write)(fp->_cookie, p, w); 10146111Sbostic if (w <= 0) 10246111Sbostic goto err; 10346111Sbostic } else { 10446111Sbostic /* fill and done */ 10546111Sbostic w = len; 10646111Sbostic COPY(w); 10746111Sbostic fp->_w -= w; 10846111Sbostic fp->_p += w; 10946111Sbostic } 11046111Sbostic p += w; 11146111Sbostic len -= w; 11246111Sbostic } while ((uio->uio_resid -= w) != 0); 11346111Sbostic } else { 11446111Sbostic /* 11546111Sbostic * Line buffered: like fully buffered, but we 11646111Sbostic * must check for newlines. Compute the distance 11746111Sbostic * to the first newline (including the newline), 11846111Sbostic * or `infinity' if there is none, then pretend 11946111Sbostic * that the amount to write is MIN(len,nldist). 12046111Sbostic */ 12146111Sbostic nlknown = 0; 12246275Storek nldist = 0; /* XXX just to keep gcc happy */ 12346111Sbostic do { 12446111Sbostic GETIOV(nlknown = 0); 12546111Sbostic if (!nlknown) { 12646111Sbostic nl = memchr((void *)p, '\n', len); 12746111Sbostic nldist = nl ? nl + 1 - p : len + 1; 12846111Sbostic nlknown = 1; 12946111Sbostic } 13046111Sbostic s = MIN(len, nldist); 13146111Sbostic w = fp->_w + fp->_bf._size; 13246111Sbostic if (fp->_p > fp->_bf._base && s > w) { 13346111Sbostic COPY(w); 13446111Sbostic /* fp->_w -= w; */ 13546111Sbostic fp->_p += w; 13646111Sbostic if (fflush(fp)) 13746111Sbostic goto err; 13846111Sbostic } else if (s >= (w = fp->_bf._size)) { 13946111Sbostic w = (*fp->_write)(fp->_cookie, p, w); 14046111Sbostic if (w <= 0) 14146111Sbostic goto err; 14246111Sbostic } else { 14346111Sbostic w = s; 14446111Sbostic COPY(w); 14546111Sbostic fp->_w -= w; 14646111Sbostic fp->_p += w; 14746111Sbostic } 14846111Sbostic if ((nldist -= w) == 0) { 14946111Sbostic /* copied the newline: flush and forget */ 15046111Sbostic if (fflush(fp)) 15146111Sbostic goto err; 15246111Sbostic nlknown = 0; 15346111Sbostic } 15446111Sbostic p += w; 15546111Sbostic len -= w; 15646111Sbostic } while ((uio->uio_resid -= w) != 0); 15746111Sbostic } 15846111Sbostic return (0); 15946111Sbostic 16046111Sbostic err: 16146111Sbostic fp->_flags |= __SERR; 16246111Sbostic return (EOF); 16346111Sbostic } 164