1*46111Sbostic /*- 2*46111Sbostic * Copyright (c) 1990 The Regents of the University of California. 3*46111Sbostic * All rights reserved. 4*46111Sbostic * 5*46111Sbostic * This code is derived from software contributed to Berkeley by 6*46111Sbostic * Chris Torek. 7*46111Sbostic * 8*46111Sbostic * %sccs.include.redist.c% 9*46111Sbostic */ 10*46111Sbostic 11*46111Sbostic #if defined(LIBC_SCCS) && !defined(lint) 12*46111Sbostic static char sccsid[] = "@(#)fvwrite.c 5.1 (Berkeley) 01/20/91"; 13*46111Sbostic #endif /* LIBC_SCCS and not lint */ 14*46111Sbostic 15*46111Sbostic #include <stdio.h> 16*46111Sbostic #include <string.h> 17*46111Sbostic #include "local.h" 18*46111Sbostic #include "fvwrite.h" 19*46111Sbostic 20*46111Sbostic /* 21*46111Sbostic * Write some memory regions. Return zero on success, EOF on error. 22*46111Sbostic * 23*46111Sbostic * This routine is large and unsightly, but most of the ugliness due 24*46111Sbostic * to the three different kinds of output buffering is handled here. 25*46111Sbostic */ 26*46111Sbostic __sfvwrite(fp, uio) 27*46111Sbostic register FILE *fp; 28*46111Sbostic register struct __suio *uio; 29*46111Sbostic { 30*46111Sbostic register size_t len; 31*46111Sbostic register char *p; 32*46111Sbostic register struct __siov *iov; 33*46111Sbostic register int w, s; 34*46111Sbostic char *nl; 35*46111Sbostic int nlknown, nldist; 36*46111Sbostic 37*46111Sbostic if ((len = uio->uio_resid) == 0) 38*46111Sbostic return (0); 39*46111Sbostic /* make sure we can write */ 40*46111Sbostic if (cantwrite(fp)) 41*46111Sbostic return (EOF); 42*46111Sbostic 43*46111Sbostic #define MIN(a, b) ((a) < (b) ? (a) : (b)) 44*46111Sbostic #define COPY(n) (void) memcpy((void *)fp->_p, (void *)p, (size_t)(n)); 45*46111Sbostic 46*46111Sbostic iov = uio->uio_iov; 47*46111Sbostic len = 0; 48*46111Sbostic #define GETIOV(extra_work) \ 49*46111Sbostic while (len == 0) { \ 50*46111Sbostic extra_work; \ 51*46111Sbostic p = iov->iov_base; \ 52*46111Sbostic len = iov->iov_len; \ 53*46111Sbostic iov++; \ 54*46111Sbostic } 55*46111Sbostic if (fp->_flags & __SNBF) { 56*46111Sbostic /* 57*46111Sbostic * Unbuffered: write up to BUFSIZ bytes at a time. 58*46111Sbostic */ 59*46111Sbostic do { 60*46111Sbostic GETIOV(;); 61*46111Sbostic w = (*fp->_write)(fp->_cookie, p, MIN(len, BUFSIZ)); 62*46111Sbostic if (w <= 0) 63*46111Sbostic goto err; 64*46111Sbostic p += w; 65*46111Sbostic len -= w; 66*46111Sbostic } while ((uio->uio_resid -= w) != 0); 67*46111Sbostic } else if ((fp->_flags & __SLBF) == 0) { 68*46111Sbostic /* 69*46111Sbostic * Fully buffered: fill partially full buffer, if any, 70*46111Sbostic * and then flush. If there is no partial buffer, write 71*46111Sbostic * one _bf._size byte chunk directly (without copying). 72*46111Sbostic * 73*46111Sbostic * String output is a special case: write as many bytes 74*46111Sbostic * as fit, but pretend we wrote everything. This makes 75*46111Sbostic * snprintf() return the number of bytes needed, rather 76*46111Sbostic * than the number used, and avoids its write function 77*46111Sbostic * (so that the write function can be invalid). 78*46111Sbostic */ 79*46111Sbostic do { 80*46111Sbostic GETIOV(;); 81*46111Sbostic w = fp->_w; 82*46111Sbostic if (fp->_flags & __SSTR) { 83*46111Sbostic if (len < w) 84*46111Sbostic w = len; 85*46111Sbostic COPY(w); /* copy MIN(fp->_w,len), */ 86*46111Sbostic fp->_w -= w; 87*46111Sbostic fp->_p += w; 88*46111Sbostic w = len; /* but pretend copied all */ 89*46111Sbostic } else if (fp->_p > fp->_bf._base && len > w) { 90*46111Sbostic /* fill and flush */ 91*46111Sbostic COPY(w); 92*46111Sbostic /* fp->_w -= w; */ /* unneeded */ 93*46111Sbostic fp->_p += w; 94*46111Sbostic if (fflush(fp)) 95*46111Sbostic goto err; 96*46111Sbostic } else if (len >= (w = fp->_bf._size)) { 97*46111Sbostic /* write directly */ 98*46111Sbostic w = (*fp->_write)(fp->_cookie, p, w); 99*46111Sbostic if (w <= 0) 100*46111Sbostic goto err; 101*46111Sbostic } else { 102*46111Sbostic /* fill and done */ 103*46111Sbostic w = len; 104*46111Sbostic COPY(w); 105*46111Sbostic fp->_w -= w; 106*46111Sbostic fp->_p += w; 107*46111Sbostic } 108*46111Sbostic p += w; 109*46111Sbostic len -= w; 110*46111Sbostic } while ((uio->uio_resid -= w) != 0); 111*46111Sbostic } else { 112*46111Sbostic /* 113*46111Sbostic * Line buffered: like fully buffered, but we 114*46111Sbostic * must check for newlines. Compute the distance 115*46111Sbostic * to the first newline (including the newline), 116*46111Sbostic * or `infinity' if there is none, then pretend 117*46111Sbostic * that the amount to write is MIN(len,nldist). 118*46111Sbostic */ 119*46111Sbostic nlknown = 0; 120*46111Sbostic do { 121*46111Sbostic GETIOV(nlknown = 0); 122*46111Sbostic if (!nlknown) { 123*46111Sbostic nl = memchr((void *)p, '\n', len); 124*46111Sbostic nldist = nl ? nl + 1 - p : len + 1; 125*46111Sbostic nlknown = 1; 126*46111Sbostic } 127*46111Sbostic s = MIN(len, nldist); 128*46111Sbostic w = fp->_w + fp->_bf._size; 129*46111Sbostic if (fp->_p > fp->_bf._base && s > w) { 130*46111Sbostic COPY(w); 131*46111Sbostic /* fp->_w -= w; */ 132*46111Sbostic fp->_p += w; 133*46111Sbostic if (fflush(fp)) 134*46111Sbostic goto err; 135*46111Sbostic } else if (s >= (w = fp->_bf._size)) { 136*46111Sbostic w = (*fp->_write)(fp->_cookie, p, w); 137*46111Sbostic if (w <= 0) 138*46111Sbostic goto err; 139*46111Sbostic } else { 140*46111Sbostic w = s; 141*46111Sbostic COPY(w); 142*46111Sbostic fp->_w -= w; 143*46111Sbostic fp->_p += w; 144*46111Sbostic } 145*46111Sbostic if ((nldist -= w) == 0) { 146*46111Sbostic /* copied the newline: flush and forget */ 147*46111Sbostic if (fflush(fp)) 148*46111Sbostic goto err; 149*46111Sbostic nlknown = 0; 150*46111Sbostic } 151*46111Sbostic p += w; 152*46111Sbostic len -= w; 153*46111Sbostic } while ((uio->uio_resid -= w) != 0); 154*46111Sbostic } 155*46111Sbostic return (0); 156*46111Sbostic 157*46111Sbostic err: 158*46111Sbostic fp->_flags |= __SERR; 159*46111Sbostic return (EOF); 160*46111Sbostic } 161