/*
* Copyright (c) 2000-2005 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*/
#include "sm/generic.h"
SM_RCSID("@(#)$Id: refill.c,v 1.30 2005/07/25 20:19:45 ca Exp $")
#include "sm/error.h"
#include "sm/io.h"
#include "sm/assert.h"
#include "sm/memops.h"
#include "io-int.h"
/*
** SM_REFILL -- refill a buffer
**
** This should be called if the read buffer is empty.
** However, when we switch from write to read and we use double buffering
** the read buffer may not actually be empty. In that case just return
** with the old buffer.
**
** Parameters:
** fp -- file pointer for buffer refill
**
** Returns:
** usual return type (including EOF).
*/
sm_ret_T
sm_refill(sm_file_T *fp)
{
ssize_t r;
sm_ret_T res;
/* largely a convenience for callers */
f_r(*fp) = 0;
/* XXX double buffering: keep EOF? */
if (f_flags(*fp) & SMFEOF)
return SM_IO_EOF;
/* if not already reading, have to be reading and writing */
if ((f_flags(*fp) & SMRD) == 0)
{
if ((f_flags(*fp) & SMRW) == 0)
{
f_flags(*fp) |= SMERR;
#if SM_IO_ERR_VAL
f_error(*fp) = sm_error_perm(SM_EM_IO, EBADF);
#endif
return sm_error_perm(SM_EM_IO, EBADF);
}
/* switch to reading */
if (f_flags(*fp) & SMWR)
{
if (!sm_io_double(fp) ||
sm_io_getinfo(fp, SM_IO_IS_READABLE, NULL) <= 0)
{
res = sm_flush(fp);
if (sm_is_err(res))
return SM_IO_EOF; /* XXX res? */
}
f_flags(*fp) &= ~SMWR;
}
SM_IO_TO_RD(fp);
f_flags(*fp) |= SMRD;
/* shortcut: still something in the read buffer? */
if (sm_io_double(fp) && f_r(*fp) > 0)
return SM_SUCCESS;
}
/* invariant: read buffer is empty */
if (f_bfbase(*fp) == NULL)
sm_makefilebuf(fp);
/* needed to ensure EOF correctly found (unless f_read does it) */
errno = 0;
/* reset buffer pointer (always), see invariant above */
f_p(*fp) = f_bfbase(*fp);
res = (*f_read(*fp))(fp, f_p(*fp), f_bfsize(*fp), &r);
if (sm_is_err(res))
{
/*
** Should we distinguish the error here?
** E.g, timeout, dropped connection?
*/
if (r <= 0)
{
f_flags(*fp) |= SMERR;
#if SM_IO_ERR_VAL
f_error(*fp) = res;
#endif
}
else
f_r(*fp) += r;
#if 0
if (sm_io_double(fp) && f_r(*fp) > 0)
return SM_SUCCESS;
#endif
return res;
}
if (r <= 0)
{
if (r == 0)
f_flags(*fp) |= SMFEOF;
else
{
f_flags(*fp) |= SMERR; /* should be caught above */
#if SM_IO_ERR_VAL
f_error(*fp) = sm_error_perm(SM_EM_IO, EINVAL);
/* correct error? */
#endif
}
if (!sm_io_double(fp))
f_r(*fp) = 0;
return SM_IO_EOF;
}
f_r(*fp) += r;
return SM_SUCCESS;
}
/*
** SM_RGET -- refills buffer and returns first character
**
** Handle sm_getc() when the buffer ran out:
** Refill, then return the first character in the newly-filled buffer.
**
** Parameters:
** fp -- file pointer to work on
**
** Returns:
** Success: first character in refilled buffer as an int
** Failure: SM_IO_EOF
*/
int
sm_rget(sm_file_T *fp)
{
sm_ret_T res;
res = sm_refill(fp);
if (sm_is_success(res))
{
f_r(*fp)--;
return *f_p(*fp)++;
}
/* return res of EOF? */
return res;
}
syntax highlighted by Code2HTML, v. 0.9.1