xref: /csrg-svn/lib/libc/stdio/fvwrite.c (revision 61180)
146111Sbostic /*-
2*61180Sbostic  * Copyright (c) 1990, 1993
3*61180Sbostic  *	The Regents of the University of California.  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*61180Sbostic static char sccsid[] = "@(#)fvwrite.c	8.1 (Berkeley) 06/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  */
__sfvwrite(fp,uio)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))
4458451Storek #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