/* * 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); }