#include <sm/gen.h>
SM_RCSID("@(#)$Id: fvwrite.c,v 1.47 2001/08/27 13:02:20 ca Exp $")
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <sm/io.h>
#include <sm/setjmp.h>
#include <sm/conf.h>
#include "local.h"
#include "fvwrite.h"
#define COPY(n) (void)memcpy((void *)fp->f_p, (void *)p, (size_t)(n))
#define GETIOV(extra_work) \
while (len == 0) \
{ \
extra_work; \
p = iov->iov_base; \
len = iov->iov_len; \
iov++; \
}
int
sm_fvwrite(fp, timeout, uio)
register SM_FILE_T *fp;
int timeout;
register struct sm_uio *uio;
{
register size_t len;
register char *p;
register struct sm_iov *iov;
register int w, s;
char *nl;
int nlknown, nldist;
int fd;
struct timeval to;
if (uio->uio_resid == 0)
return 0;
if (cantwrite(fp))
{
errno = EBADF;
return SM_IO_EOF;
}
SM_CONVERT_TIME(fp, fd, timeout, &to);
iov = uio->uio_iov;
p = iov->iov_base;
len = iov->iov_len;
iov++;
if (fp->f_flags & SMNBF)
{
do
{
GETIOV(;);
errno = 0;
w = (*fp->f_write)(fp, p, SM_MIN(len, SM_IO_BUFSIZ));
if (w <= 0)
{
if (w == 0 && errno == 0)
break;
if (IS_IO_ERROR(fd, w, timeout))
goto err;
SM_IO_WR_TIMEOUT(fp, fd, timeout);
w = 0;
}
else
{
p += w;
len -= w;
}
} while ((uio->uio_resid -= w) != 0);
}
else if ((fp->f_flags & SMLBF) == 0)
{
do
{
GETIOV(;);
if ((((fp->f_flags & (SMALC | SMSTR)) == (SMALC | SMSTR))
|| ((fp->f_flags & SMNOW) != 0))
&& (size_t) fp->f_w < len)
{
size_t blen = fp->f_p - fp->f_bf.smb_base;
unsigned char *tbase;
int tsize;
tsize = fp->f_bf.smb_size;
do
{
tsize = (tsize << 1) + 1;
} while ((size_t) tsize < blen + len);
tbase = (unsigned char *) sm_realloc(fp->f_bf.smb_base,
tsize + 1);
if (tbase == NULL)
{
errno = ENOMEM;
goto err;
}
fp->f_w += tsize - fp->f_bf.smb_size;
fp->f_bf.smb_base = tbase;
fp->f_bf.smb_size = tsize;
fp->f_p = tbase + blen;
}
w = fp->f_w;
errno = 0;
if (fp->f_flags & SMSTR)
{
if (len < (size_t) w)
w = len;
COPY(w);
fp->f_w -= w;
fp->f_p += w;
w = len;
}
else if (fp->f_p > fp->f_bf.smb_base
&& len > (size_t) w)
{
COPY(w);
fp->f_p += w;
if (sm_flush(fp, &timeout))
goto err;
}
else if (len >= (size_t) (w = fp->f_bf.smb_size))
{
w = (*fp->f_write)(fp, p, w);
if (w <= 0)
{
if (w == 0 && errno == 0)
break;
if (IS_IO_ERROR(fd, w, timeout))
goto err;
SM_IO_WR_TIMEOUT(fp, fd, timeout);
w = 0;
}
}
else
{
w = len;
COPY(w);
fp->f_w -= w;
fp->f_p += w;
}
p += w;
len -= w;
} while ((uio->uio_resid -= w) != 0);
if ((fp->f_flags & SMNOW) != 0 && sm_flush(fp, &timeout))
goto err;
}
else
{
nlknown = 0;
nldist = 0;
do
{
GETIOV(nlknown = 0);
if (!nlknown)
{
nl = memchr((void *)p, '\n', len);
nldist = nl != NULL ? nl + 1 - p : len + 1;
nlknown = 1;
}
s = SM_MIN(len, ((size_t) nldist));
w = fp->f_w + fp->f_bf.smb_size;
errno = 0;
if (fp->f_p > fp->f_bf.smb_base && s > w)
{
COPY(w);
fp->f_p += w;
if (sm_flush(fp, &timeout))
goto err;
}
else if (s >= (w = fp->f_bf.smb_size))
{
w = (*fp->f_write)(fp, p, w);
if (w <= 0)
{
if (w == 0 && errno == 0)
break;
if (IS_IO_ERROR(fd, w, timeout))
goto err;
SM_IO_WR_TIMEOUT(fp, fd, timeout);
w = 0;
}
}
else
{
w = s;
COPY(w);
fp->f_w -= w;
fp->f_p += w;
}
if ((nldist -= w) == 0)
{
if (sm_flush(fp, &timeout))
goto err;
nlknown = 0;
}
p += w;
len -= w;
} while ((uio->uio_resid -= w) != 0);
}
return 0;
err:
fp->f_flags |= SMERR;
return SM_IO_EOF;
}