sl@0: /* FVWRITE.C sl@0: * sl@0: * Portions Copyright (c) 1990-2004 Nokia Corporation and/or its subsidiary(-ies). sl@0: * All rights reserved. sl@0: */ sl@0: sl@0: /* No user fns here. Pesch 15apr92. */ sl@0: sl@0: /* sl@0: * Copyright (c) 1990 The Regents of the University of California. sl@0: * All rights reserved. sl@0: * sl@0: * Redistribution and use in source and binary forms are permitted sl@0: * provided that the above copyright notice and this paragraph are sl@0: * duplicated in all such forms and that any documentation, sl@0: * advertising materials, and other materials related to such sl@0: * distribution and use acknowledge that the software was developed sl@0: * by the University of California, Berkeley. The name of the sl@0: * University may not be used to endorse or promote products derived sl@0: * from this software without specific prior written permission. sl@0: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR sl@0: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED sl@0: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. sl@0: */ sl@0: sl@0: #include sl@0: #include sl@0: #include "LOCAL.H" sl@0: #include "FVWRITE.H" sl@0: sl@0: #define MIN(a, b) ((a) < (b) ? (a) : (b)) sl@0: #define COPY(n) (void) memmove((void *) fp->_p, (void *) p, (size_t) (n)) sl@0: sl@0: #define GETIOV(extra_work) \ sl@0: while (len == 0) \ sl@0: { \ sl@0: extra_work; \ sl@0: p = (const char*)iov->iov_base; \ sl@0: len = iov->iov_len; \ sl@0: iov++; \ sl@0: } sl@0: sl@0: /* sl@0: * Write some memory regions. Return zero on success, EOF on error. sl@0: * sl@0: * This routine is large and unsightly, but most of the ugliness due sl@0: * to the three different kinds of output buffering is handled here. sl@0: */ sl@0: sl@0: int sl@0: __sfvwrite (register FILE *fp,register struct __suio *uio) sl@0: { sl@0: register size_t len; sl@0: register const char *p; sl@0: register struct __siov *iov; sl@0: register int w, s; sl@0: char *nl; sl@0: int nlknown, nldist = -1; sl@0: sl@0: if ((len = uio->uio_resid) == 0) sl@0: return 0; sl@0: sl@0: /* make sure we can write */ sl@0: if (cantwrite (fp)) sl@0: return EOF; sl@0: sl@0: iov = uio->uio_iov; sl@0: len = 0; sl@0: if (fp->_flags & __SNBF) sl@0: { sl@0: /* sl@0: * Unbuffered: write up to BUFSIZ bytes at a time. sl@0: */ sl@0: do sl@0: { sl@0: GETIOV (;); sl@0: w = (*fp->_write) (fp->_cookie, p, MIN (len, BUFSIZ)); sl@0: if (w <= 0) sl@0: goto err; sl@0: p += w; sl@0: len -= w; sl@0: } sl@0: while ((uio->uio_resid -= w) != 0); sl@0: } sl@0: else if ((fp->_flags & __SLBF) == 0) sl@0: { sl@0: /* sl@0: * Fully buffered: fill partially full buffer, if any, sl@0: * and then flush. If there is no partial buffer, write sl@0: * one _bf._size byte chunk directly (without copying). sl@0: * sl@0: * String output is a special case: write as many bytes sl@0: * as fit, but pretend we wrote everything. This makes sl@0: * snprintf() return the number of bytes needed, rather sl@0: * than the number used, and avoids its write function sl@0: * (so that the write function can be invalid). sl@0: */ sl@0: do sl@0: { sl@0: GETIOV (;); sl@0: w = fp->_w; sl@0: if (fp->_flags & __SSTR) sl@0: { sl@0: if ((int)len < w) sl@0: w = len; sl@0: COPY (w); /* copy MIN(fp->_w,len), */ sl@0: fp->_w -= w; sl@0: fp->_p += w; sl@0: w = len; /* but pretend copied all */ sl@0: } sl@0: else if (fp->_p > fp->_bf._base && (int)len > w) sl@0: { sl@0: /* fill and flush */ sl@0: COPY (w); sl@0: /* fp->_w -= w; *//* unneeded */ sl@0: fp->_p += w; sl@0: if (fflush (fp)) sl@0: goto err; sl@0: } sl@0: else if ((int)len >= (w = fp->_bf._size)) sl@0: { sl@0: /* write directly */ sl@0: w = (*fp->_write) (fp->_cookie, p, w); sl@0: if (w <= 0) sl@0: goto err; sl@0: } sl@0: else sl@0: { sl@0: /* fill and done */ sl@0: w = len; sl@0: COPY (w); sl@0: fp->_w -= w; sl@0: fp->_p += w; sl@0: } sl@0: p += w; sl@0: len -= w; sl@0: } sl@0: while ((uio->uio_resid -= w) != 0); sl@0: } sl@0: else sl@0: { sl@0: /* sl@0: * Line buffered: like fully buffered, but we sl@0: * must check for newlines. Compute the distance sl@0: * to the first newline (including the newline), sl@0: * or `infinity' if there is none, then pretend sl@0: * that the amount to write is MIN(len,nldist). sl@0: */ sl@0: nlknown = 0; sl@0: do sl@0: { sl@0: GETIOV (nlknown = 0); sl@0: if (!nlknown) sl@0: { sl@0: nl = (char *)memchr ((void *) p, '\n', len); sl@0: nldist = nl ? nl + 1 - p : len + 1; sl@0: nlknown = 1; sl@0: } sl@0: s = MIN ((int)len, nldist); sl@0: w = fp->_w + fp->_bf._size; sl@0: if (fp->_p > fp->_bf._base && s > w) sl@0: { sl@0: COPY (w); sl@0: /* fp->_w -= w; */ sl@0: fp->_p += w; sl@0: if (fflush (fp)) sl@0: goto err; sl@0: } sl@0: else if (s >= (w = fp->_bf._size)) sl@0: { sl@0: w = (*fp->_write) (fp->_cookie, p, w); sl@0: if (w <= 0) sl@0: goto err; sl@0: } sl@0: else sl@0: { sl@0: w = s; sl@0: COPY (w); sl@0: fp->_w -= w; sl@0: fp->_p += w; sl@0: } sl@0: if ((nldist -= w) == 0) sl@0: { sl@0: /* copied the newline: flush and forget */ sl@0: if (fflush (fp)) sl@0: goto err; sl@0: nlknown = 0; sl@0: } sl@0: p += w; sl@0: len -= w; sl@0: } sl@0: while ((uio->uio_resid -= w) != 0); sl@0: } sl@0: return 0; sl@0: sl@0: err: sl@0: fp->_flags |= __SERR; sl@0: return EOF; sl@0: }