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