/*
* reimplementation of Daniel Bernstein's buffer library.
* placed in the public domain by Uwe Ohse, uwe@ohse.de.
*/
#include "buffer.h"
#include "byte.h"
#include "error.h"
#define READPOS(b) ((b)->buf+(b)->len)
static int
do_op (buffer_op op, int fd, char *buf, unsigned int len)
{
while (1) {
int r;
r = op (fd, buf, len);
if (r == -1)
if (errno == error_intr)
continue;
/* EAGAIN? */
return r;
}
}
static int
copy2user (buffer * b, char *buf, unsigned int len)
{
if (len > b->pos)
len = b->pos;
b->pos -= len;
byte_copy (buf, len, READPOS(b));
b->len += len;
return len;
}
int
buffer_feed (buffer * b)
{
int r;
/* If the string is nonempty, buffer_feed returns the length of the
* string. */
if (b->pos)
return b->pos;
/* If the string is empty, buffer_feed uses the read operation to
* feed data into the string; it then returns the new length of the
* string, or 0 for end of input, or -1 for error. */
r = do_op (b->op, b->fd, b->buf, b->len);
if (r <= 0)
return r;
b->pos = r;
b->len -= r;
/* Note: this strange construction is needed because DJB didn't
* include the buffer size in struct buffer */
if (b->len > 0)
byte_copyr (READPOS(b), r, b->buf);
return r;
}
char *
buffer_peek (buffer * b)
{
return READPOS(b);
}
/* "skip this many bytes" */
void
buffer_seek(buffer *b,unsigned int len)
{
b->len += len;
b->pos -= len;
}
int
buffer_get (buffer * b, char *buf, unsigned int len)
{
int ret;
/* Normally buffer_get copies data to x[0], x[1], ..., x[len-1] from the
* beginning of a string stored in preallocated space; removes these len
* bytes from the string; and returns len.
* If, however, the string has fewer than len (but more than 0) bytes,
* buffer_get copies only that many bytes, and returns that number.
* If the string is empty, buffer_get first uses a read operation to feed
* data into the string. The read operation may indicate end of input, in
* which case buffer_get returns 0; or a read error, in which case
* buffer_get returns -1, setting errno approporiately. */
/* fewer than len, but more than 0 */
if (b->pos)
return copy2user (b, buf, len);
/* buffer too small, read directly */
if (b->len <= len)
return do_op (b->op, b->fd, buf, len);
/* "read operation" to feed data into the string */
ret = buffer_feed (b);
if (ret <= 0)
return ret;
return copy2user (b, buf, len);
}
/* undocumented interface: like _get, but reads one block max. */
int
buffer_bget (buffer * b, char *buf, unsigned int len)
{
int ret;
if (b->pos > 0)
return copy2user (b, buf, len);
if (b->len <= len)
return do_op (b->op, b->fd, buf, b->len);
ret = buffer_feed (b);
if (ret <= 0)
return ret;
return copy2user (b, buf, len);
}
syntax highlighted by Code2HTML, v. 0.9.1