1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
|
/*
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* and/or other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
/* No user fns here. Pesch 15apr92. */
#define _DEFAULT_SOURCE
#include <_ansi.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include "local.h"
#include "fvwrite.h"
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define COPY(n) (void) memmove ((void *) fp->_p, (void *) p, (size_t) (n))
#define GETIOV(extra_work) \
while (len == 0) \
{ \
extra_work; \
p = iov->iov_base; \
len = iov->iov_len; \
iov++; \
}
/*
* Write some memory regions. Return zero on success, EOF on error.
*
* This routine is large and unsightly, but most of the ugliness due
* to the three different kinds of output buffering is handled here.
*/
int
_sfvwrite (
register FILE *fp,
register struct __suio *uio)
{
register size_t len;
register const char *p = NULL;
register struct __siov *iov;
register ssize_t w, s;
char *nl;
int nlknown, nldist;
if ((len = uio->uio_resid) == 0)
return 0;
/* make sure we can write */
if (cantwrite (ptr, fp))
return EOF;
iov = uio->uio_iov;
len = 0;
#ifdef __SCLE
if (fp->_flags & __SCLE) /* text mode */
{
do
{
GETIOV (;);
while (len > 0)
{
if (putc (*p, fp) == EOF)
return EOF;
p++;
len--;
uio->uio_resid--;
}
}
while (uio->uio_resid > 0);
return 0;
}
#endif
if (fp->_flags & __SNBF)
{
/*
* Unbuffered: Split buffer in the largest multiple of BUFSIZ < INT_MAX
* as some legacy code may expect int instead of size_t.
*/
do
{
GETIOV (;);
w = fp->_write (fp->_cookie, p,
MIN (len, INT_MAX - INT_MAX % BUFSIZ));
if (w <= 0)
goto err;
p += w;
len -= w;
}
while ((uio->uio_resid -= w) != 0);
}
else if ((fp->_flags & __SLBF) == 0)
{
/*
* Fully buffered: fill partially full buffer, if any,
* and then flush. If there is no partial buffer, write
* one _bf._size byte chunk directly (without copying).
*
* String output is a special case: write as many bytes
* as fit, but pretend we wrote everything. This makes
* snprintf() return the number of bytes needed, rather
* than the number used, and avoids its write function
* (so that the write function can be invalid). If
* we are dealing with the asprintf routines, we will
* dynamically increase the buffer size as needed.
*/
do
{
GETIOV (;);
w = fp->_w;
if (fp->_flags & __SSTR)
{
if (len >= (size_t) w && fp->_flags & (__SMBF | __SOPT))
{ /* must be asprintf family */
unsigned char *str;
int curpos = (fp->_p - fp->_bf._base);
/* Choose a geometric growth factor to avoid
quadratic realloc behavior, but use a rate less
than (1+sqrt(5))/2 to accomodate malloc
overhead. asprintf EXPECTS us to overallocate, so
that it can add a trailing \0 without
reallocating. The new allocation should thus be
max(prev_size*1.5, curpos+len+1). */
int newsize = fp->_bf._size * 3 / 2;
if ((size_t) newsize < curpos + len + 1)
newsize = curpos + len + 1;
if (fp->_flags & __SOPT)
{
/* asnprintf leaves original buffer alone. */
str = (unsigned char *)malloc (newsize);
if (!str)
{
_REENT_ERRNO(ptr) = ENOMEM;
goto err;
}
memcpy (str, fp->_bf._base, curpos);
fp->_flags = (fp->_flags & ~__SOPT) | __SMBF;
}
else
{
str = (unsigned char *)realloc (fp->_bf._base,
newsize);
if (!str)
{
/* Free buffer which is no longer used and clear
__SMBF flag to avoid double free in fclose. */
free (fp->_bf._base);
fp->_flags &= ~__SMBF;
/* Ensure correct errno, even if free changed it. */
_REENT_ERRNO(ptr) = ENOMEM;
goto err;
}
}
fp->_bf._base = str;
fp->_p = str + curpos;
fp->_bf._size = newsize;
w = len;
fp->_w = newsize - curpos;
}
if (len < (size_t) w)
w = len;
COPY (w); /* copy MIN(fp->_w,len), */
fp->_w -= w;
fp->_p += w;
w = len; /* but pretend copied all */
}
else if (fp->_p > fp->_bf._base || len < (size_t) fp->_bf._size)
{
/* pass through the buffer */
w = MIN (len, (size_t) w);
COPY (w);
fp->_w -= w;
fp->_p += w;
if (fp->_w == 0 && fflush ( fp))
goto err;
}
else
{
/* write directly */
w = ((int)MIN (len, INT_MAX)) / fp->_bf._size * fp->_bf._size;
w = fp->_write (fp->_cookie, p, w);
if (w <= 0)
goto err;
}
p += w;
len -= w;
}
while ((uio->uio_resid -= w) != 0);
}
else
{
/*
* Line buffered: like fully buffered, but we
* must check for newlines. Compute the distance
* to the first newline (including the newline),
* or `infinity' if there is none, then pretend
* that the amount to write is MIN(len,nldist).
*/
nlknown = 0;
nldist = 0;
do
{
GETIOV (nlknown = 0);
if (!nlknown)
{
nl = memchr ((void *) p, '\n', len);
nldist = nl ? nl + 1 - p : (int) (len + 1);
nlknown = 1;
}
s = MIN (len, (size_t) nldist);
w = fp->_w + fp->_bf._size;
if (fp->_p > fp->_bf._base && s > w)
{
COPY (w);
/* fp->_w -= w; */
fp->_p += w;
if (fflush ( fp))
goto err;
}
else if (s >= (w = fp->_bf._size))
{
w = fp->_write (fp->_cookie, p, w);
if (w <= 0)
goto err;
}
else
{
w = s;
COPY (w);
fp->_w -= w;
fp->_p += w;
}
if ((nldist -= w) == 0)
{
/* copied the newline: flush and forget */
if (fflush ( fp))
goto err;
nlknown = 0;
}
p += w;
len -= w;
}
while ((uio->uio_resid -= w) != 0);
}
return 0;
err:
fp->_flags |= __SERR;
return EOF;
}
|