11573Srgrimes/*- 21573Srgrimes * Copyright (c) 1990, 1993 31573Srgrimes * The Regents of the University of California. All rights reserved. 41573Srgrimes * 51573Srgrimes * This code is derived from software contributed to Berkeley by 61573Srgrimes * Chris Torek. 71573Srgrimes * 81573Srgrimes * Redistribution and use in source and binary forms, with or without 91573Srgrimes * modification, are permitted provided that the following conditions 101573Srgrimes * are met: 111573Srgrimes * 1. Redistributions of source code must retain the above copyright 121573Srgrimes * notice, this list of conditions and the following disclaimer. 131573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141573Srgrimes * notice, this list of conditions and the following disclaimer in the 151573Srgrimes * documentation and/or other materials provided with the distribution. 16249808Semaste * 3. Neither the name of the University nor the names of its contributors 171573Srgrimes * may be used to endorse or promote products derived from this software 181573Srgrimes * without specific prior written permission. 191573Srgrimes * 201573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231573Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301573Srgrimes * SUCH DAMAGE. 311573Srgrimes */ 321573Srgrimes 331573Srgrimes#if defined(LIBC_SCCS) && !defined(lint) 341573Srgrimesstatic char sccsid[] = "@(#)fvwrite.c 8.1 (Berkeley) 6/4/93"; 351573Srgrimes#endif /* LIBC_SCCS and not lint */ 3692986Sobrien#include <sys/cdefs.h> 3792986Sobrien__FBSDID("$FreeBSD$"); 381573Srgrimes 391573Srgrimes#include <stdio.h> 4037487Speter#include <stdlib.h> 411573Srgrimes#include <string.h> 421573Srgrimes#include "local.h" 431573Srgrimes#include "fvwrite.h" 441573Srgrimes 451573Srgrimes/* 461573Srgrimes * Write some memory regions. Return zero on success, EOF on error. 471573Srgrimes * 481573Srgrimes * This routine is large and unsightly, but most of the ugliness due 491573Srgrimes * to the three different kinds of output buffering is handled here. 501573Srgrimes */ 5116586Sjraynardint 52249810Semaste__sfvwrite(FILE *fp, struct __suio *uio) 531573Srgrimes{ 5492889Sobrien size_t len; 5592889Sobrien char *p; 5692889Sobrien struct __siov *iov; 5792889Sobrien int w, s; 581573Srgrimes char *nl; 5982838Sache int nlknown, nldist; 601573Srgrimes 61199781Swollman if (uio->uio_resid == 0) 621573Srgrimes return (0); 631573Srgrimes /* make sure we can write */ 64130232Sdas if (prepwrite(fp) != 0) 651573Srgrimes return (EOF); 661573Srgrimes 671573Srgrimes#define MIN(a, b) ((a) < (b) ? (a) : (b)) 681573Srgrimes#define COPY(n) (void)memcpy((void *)fp->_p, (void *)p, (size_t)(n)) 691573Srgrimes 701573Srgrimes iov = uio->uio_iov; 711573Srgrimes p = iov->iov_base; 721573Srgrimes len = iov->iov_len; 731573Srgrimes iov++; 741573Srgrimes#define GETIOV(extra_work) \ 751573Srgrimes while (len == 0) { \ 761573Srgrimes extra_work; \ 771573Srgrimes p = iov->iov_base; \ 781573Srgrimes len = iov->iov_len; \ 791573Srgrimes iov++; \ 801573Srgrimes } 811573Srgrimes if (fp->_flags & __SNBF) { 821573Srgrimes /* 831573Srgrimes * Unbuffered: write up to BUFSIZ bytes at a time. 841573Srgrimes */ 851573Srgrimes do { 861573Srgrimes GETIOV(;); 8782838Sache w = _swrite(fp, p, MIN(len, BUFSIZ)); 881573Srgrimes if (w <= 0) 891573Srgrimes goto err; 901573Srgrimes p += w; 911573Srgrimes len -= w; 921573Srgrimes } while ((uio->uio_resid -= w) != 0); 931573Srgrimes } else if ((fp->_flags & __SLBF) == 0) { 941573Srgrimes /* 951573Srgrimes * Fully buffered: fill partially full buffer, if any, 961573Srgrimes * and then flush. If there is no partial buffer, write 971573Srgrimes * one _bf._size byte chunk directly (without copying). 981573Srgrimes * 991573Srgrimes * String output is a special case: write as many bytes 10031981Sache * as fit, but pretend we wrote everything. This makes 10131981Sache * snprintf() return the number of bytes needed, rather 10231981Sache * than the number used, and avoids its write function 10331981Sache * (so that the write function can be invalid). 1041573Srgrimes */ 1051573Srgrimes do { 1061573Srgrimes GETIOV(;); 10737487Speter if ((fp->_flags & (__SALC | __SSTR)) == 10837487Speter (__SALC | __SSTR) && fp->_w < len) { 10937487Speter size_t blen = fp->_p - fp->_bf._base; 11037487Speter 11137487Speter /* 11237487Speter * Alloc an extra 128 bytes (+ 1 for NULL) 11337487Speter * so we don't call realloc(3) so often. 11437487Speter */ 11537487Speter fp->_w = len + 128; 11637487Speter fp->_bf._size = blen + len + 128; 11737487Speter fp->_bf._base = 11839327Simp reallocf(fp->_bf._base, fp->_bf._size + 1); 11937487Speter if (fp->_bf._base == NULL) 12037487Speter goto err; 12137487Speter fp->_p = fp->_bf._base + blen; 12237487Speter } 1231573Srgrimes w = fp->_w; 1241573Srgrimes if (fp->_flags & __SSTR) { 1251573Srgrimes if (len < w) 1261573Srgrimes w = len; 12731981Sache if (w > 0) { 12831981Sache COPY(w); /* copy MIN(fp->_w,len), */ 12931981Sache fp->_w -= w; 13031981Sache fp->_p += w; 13131981Sache } 1321573Srgrimes w = len; /* but pretend copied all */ 1331573Srgrimes } else if (fp->_p > fp->_bf._base && len > w) { 1341573Srgrimes /* fill and flush */ 1351573Srgrimes COPY(w); 1361573Srgrimes /* fp->_w -= w; */ /* unneeded */ 1371573Srgrimes fp->_p += w; 13871579Sdeischen if (__fflush(fp)) 1391573Srgrimes goto err; 1401573Srgrimes } else if (len >= (w = fp->_bf._size)) { 1411573Srgrimes /* write directly */ 14282838Sache w = _swrite(fp, p, w); 1431573Srgrimes if (w <= 0) 1441573Srgrimes goto err; 1451573Srgrimes } else { 1461573Srgrimes /* fill and done */ 1471573Srgrimes w = len; 1481573Srgrimes COPY(w); 1491573Srgrimes fp->_w -= w; 1501573Srgrimes fp->_p += w; 1511573Srgrimes } 1521573Srgrimes p += w; 1531573Srgrimes len -= w; 1541573Srgrimes } while ((uio->uio_resid -= w) != 0); 1551573Srgrimes } else { 1561573Srgrimes /* 1571573Srgrimes * Line buffered: like fully buffered, but we 1581573Srgrimes * must check for newlines. Compute the distance 1591573Srgrimes * to the first newline (including the newline), 1601573Srgrimes * or `infinity' if there is none, then pretend 1611573Srgrimes * that the amount to write is MIN(len,nldist). 1621573Srgrimes */ 1631573Srgrimes nlknown = 0; 1641573Srgrimes nldist = 0; /* XXX just to keep gcc happy */ 1651573Srgrimes do { 1661573Srgrimes GETIOV(nlknown = 0); 1671573Srgrimes if (!nlknown) { 1681573Srgrimes nl = memchr((void *)p, '\n', len); 1691573Srgrimes nldist = nl ? nl + 1 - p : len + 1; 1701573Srgrimes nlknown = 1; 1711573Srgrimes } 1721573Srgrimes s = MIN(len, nldist); 1731573Srgrimes w = fp->_w + fp->_bf._size; 1741573Srgrimes if (fp->_p > fp->_bf._base && s > w) { 1751573Srgrimes COPY(w); 1761573Srgrimes /* fp->_w -= w; */ 1771573Srgrimes fp->_p += w; 17871579Sdeischen if (__fflush(fp)) 1791573Srgrimes goto err; 1801573Srgrimes } else if (s >= (w = fp->_bf._size)) { 18182838Sache w = _swrite(fp, p, w); 1821573Srgrimes if (w <= 0) 1831573Srgrimes goto err; 1841573Srgrimes } else { 1851573Srgrimes w = s; 1861573Srgrimes COPY(w); 1871573Srgrimes fp->_w -= w; 1881573Srgrimes fp->_p += w; 1891573Srgrimes } 1901573Srgrimes if ((nldist -= w) == 0) { 1911573Srgrimes /* copied the newline: flush and forget */ 19271579Sdeischen if (__fflush(fp)) 1931573Srgrimes goto err; 1941573Srgrimes nlknown = 0; 1951573Srgrimes } 1961573Srgrimes p += w; 1971573Srgrimes len -= w; 1981573Srgrimes } while ((uio->uio_resid -= w) != 0); 1991573Srgrimes } 2001573Srgrimes return (0); 2011573Srgrimes 2021573Srgrimeserr: 2031573Srgrimes fp->_flags |= __SERR; 2041573Srgrimes return (EOF); 2051573Srgrimes} 206