1 /* $NetBSD: fvwrite.c,v 1.7 1997/07/13 20:15:08 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Chris Torek. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 #if defined(LIBC_SCCS) && !defined(lint) 41 #if 0 42 static char sccsid[] = "@(#)fvwrite.c 8.1 (Berkeley) 6/4/93"; 43 #else 44 __RCSID("$NetBSD: fvwrite.c,v 1.7 1997/07/13 20:15:08 christos Exp $"); 45 #endif 46 #endif /* LIBC_SCCS and not lint */ 47 48 #include <errno.h> 49 #include <stdio.h> 50 #include <string.h> 51 #include "local.h" 52 #include "fvwrite.h" 53 54 /* 55 * Write some memory regions. Return zero on success, EOF on error. 56 * 57 * This routine is large and unsightly, but most of the ugliness due 58 * to the three different kinds of output buffering is handled here. 59 */ 60 int 61 __sfvwrite(fp, uio) 62 register FILE *fp; 63 register struct __suio *uio; 64 { 65 register size_t len; 66 register char *p; 67 register struct __siov *iov; 68 register int w, s; 69 char *nl; 70 int nlknown, nldist; 71 72 if ((len = uio->uio_resid) == 0) 73 return (0); 74 /* make sure we can write */ 75 if (cantwrite(fp)) { 76 errno = EBADF; 77 return (EOF); 78 } 79 80 #define MIN(a, b) ((a) < (b) ? (a) : (b)) 81 #define COPY(n) (void)memcpy((void *)fp->_p, (void *)p, (size_t)(n)) 82 83 iov = uio->uio_iov; 84 p = iov->iov_base; 85 len = iov->iov_len; 86 iov++; 87 #define GETIOV(extra_work) \ 88 while (len == 0) { \ 89 extra_work; \ 90 p = iov->iov_base; \ 91 len = iov->iov_len; \ 92 iov++; \ 93 } 94 if (fp->_flags & __SNBF) { 95 /* 96 * Unbuffered: write up to BUFSIZ bytes at a time. 97 */ 98 do { 99 GETIOV(;); 100 w = (*fp->_write)(fp->_cookie, p, MIN(len, BUFSIZ)); 101 if (w <= 0) 102 goto err; 103 p += w; 104 len -= w; 105 } while ((uio->uio_resid -= w) != 0); 106 } else if ((fp->_flags & __SLBF) == 0) { 107 /* 108 * Fully buffered: fill partially full buffer, if any, 109 * and then flush. If there is no partial buffer, write 110 * one _bf._size byte chunk directly (without copying). 111 * 112 * String output is a special case: write as many bytes 113 * as fit, but pretend we wrote everything. This makes 114 * snprintf() return the number of bytes needed, rather 115 * than the number used, and avoids its write function 116 * (so that the write function can be invalid). 117 */ 118 do { 119 GETIOV(;); 120 w = fp->_w; 121 if (fp->_flags & __SSTR) { 122 if (len < w) 123 w = len; 124 COPY(w); /* copy MIN(fp->_w,len), */ 125 fp->_w -= w; 126 fp->_p += w; 127 w = len; /* but pretend copied all */ 128 } else if (fp->_p > fp->_bf._base && len > w) { 129 /* fill and flush */ 130 COPY(w); 131 /* fp->_w -= w; */ /* unneeded */ 132 fp->_p += w; 133 if (fflush(fp)) 134 goto err; 135 } else if (len >= (w = fp->_bf._size)) { 136 /* write directly */ 137 w = (*fp->_write)(fp->_cookie, p, w); 138 if (w <= 0) 139 goto err; 140 } else { 141 /* fill and done */ 142 w = len; 143 COPY(w); 144 fp->_w -= w; 145 fp->_p += w; 146 } 147 p += w; 148 len -= w; 149 } while ((uio->uio_resid -= w) != 0); 150 } else { 151 /* 152 * Line buffered: like fully buffered, but we 153 * must check for newlines. Compute the distance 154 * to the first newline (including the newline), 155 * or `infinity' if there is none, then pretend 156 * that the amount to write is MIN(len,nldist). 157 */ 158 nlknown = 0; 159 nldist = 0; /* XXX just to keep gcc happy */ 160 do { 161 GETIOV(nlknown = 0); 162 if (!nlknown) { 163 nl = memchr((void *)p, '\n', len); 164 nldist = nl ? nl + 1 - p : len + 1; 165 nlknown = 1; 166 } 167 s = MIN(len, nldist); 168 w = fp->_w + fp->_bf._size; 169 if (fp->_p > fp->_bf._base && s > w) { 170 COPY(w); 171 /* fp->_w -= w; */ 172 fp->_p += w; 173 if (fflush(fp)) 174 goto err; 175 } else if (s >= (w = fp->_bf._size)) { 176 w = (*fp->_write)(fp->_cookie, p, w); 177 if (w <= 0) 178 goto err; 179 } else { 180 w = s; 181 COPY(w); 182 fp->_w -= w; 183 fp->_p += w; 184 } 185 if ((nldist -= w) == 0) { 186 /* copied the newline: flush and forget */ 187 if (fflush(fp)) 188 goto err; 189 nlknown = 0; 190 } 191 p += w; 192 len -= w; 193 } while ((uio->uio_resid -= w) != 0); 194 } 195 return (0); 196 197 err: 198 fp->_flags |= __SERR; 199 return (EOF); 200 } 201