diff options
Diffstat (limited to '')
-rw-r--r-- | src/util/vbuf.c | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/src/util/vbuf.c b/src/util/vbuf.c new file mode 100644 index 0000000..924e230 --- /dev/null +++ b/src/util/vbuf.c @@ -0,0 +1,238 @@ +/*++ +/* NAME +/* vbuf 3 +/* SUMMARY +/* generic buffer package +/* SYNOPSIS +/* #include <vbuf.h> +/* +/* int VBUF_GET(bp) +/* VBUF *bp; +/* +/* int VBUF_PUT(bp, ch) +/* VBUF *bp; +/* int ch; +/* +/* int VBUF_SPACE(bp, len) +/* VBUF *bp; +/* ssize_t len; +/* +/* int vbuf_unget(bp, ch) +/* VBUF *bp; +/* int ch; +/* +/* ssize_t vbuf_read(bp, buf, len) +/* VBUF *bp; +/* void *buf; +/* ssize_t len; +/* +/* ssize_t vbuf_write(bp, buf, len) +/* VBUF *bp; +/* const void *buf; +/* ssize_t len; +/* +/* int vbuf_err(bp) +/* VBUF *bp; +/* +/* int vbuf_eof(bp) +/* VBUF *bp; +/* +/* int vbuf_timeout(bp) +/* VBUF *bp; +/* +/* int vbuf_clearerr(bp) +/* VBUF *bp; +/* +/* int vbuf_rd_err(bp) +/* VBUF *bp; +/* +/* int vbuf_wr_err(bp) +/* VBUF *bp; +/* +/* int vbuf_rd_timeout(bp) +/* VBUF *bp; +/* +/* int vbuf_wr_timeout(bp) +/* VBUF *bp; +/* DESCRIPTION +/* This module implements a buffer with read/write primitives that +/* automatically handle buffer-empty or buffer-full conditions. +/* The application is expected to provide callback routines that run +/* when the read-write primitives detect a buffer-empty/full condition. +/* +/* VBUF buffers provide primitives to store and retrieve characters, +/* and to look up buffer status information. +/* By design, VBUF buffers provide no explicit primitives for buffer +/* memory management. This is left to the application to avoid any bias +/* toward specific management models. The application is free to use +/* whatever strategy suits best: memory-resident buffer, memory mapped +/* file, or stdio-like window to an open file. +/* +/* VBUF_GET() returns the next character from the specified buffer, +/* or VBUF_EOF when none is available. VBUF_GET() is an unsafe macro +/* that evaluates its argument more than once. +/* +/* VBUF_PUT() stores one character into the specified buffer. The result +/* is the stored character, or VBUF_EOF in case of problems. VBUF_PUT() +/* is an unsafe macro that evaluates its arguments more than once. +/* +/* VBUF_SPACE() requests that the requested amount of buffer space be +/* made available, so that it can be accessed without using VBUF_PUT(). +/* The result value is 0 for success, VBUF_EOF for problems. +/* VBUF_SPACE() is an unsafe macro that evaluates its arguments more +/* than once. VBUF_SPACE() does not support read-only streams. +/* +/* vbuf_unget() provides at least one character of pushback, and returns +/* the pushed back character, or VBUF_EOF in case of problems. It is +/* an error to call vbuf_unget() on a buffer before reading any data +/* from it. vbuf_unget() clears the buffer's end-of-file indicator upon +/* success, and sets the buffer's error indicator when an attempt is +/* made to push back a non-character value. +/* +/* vbuf_read() and vbuf_write() do bulk I/O. The result value is the +/* number of bytes transferred. A short count is returned in case of +/* an error. +/* +/* vbuf_timeout() is a macro that returns non-zero if a timeout error +/* condition was detected while reading or writing the buffer. The +/* error status can be reset by calling vbuf_clearerr(). +/* +/* vbuf_err() is a macro that returns non-zero if a non-EOF error +/* (including timeout) condition was detected while reading or writing +/* the buffer. The error status can be reset by calling vbuf_clearerr(). +/* +/* The vbuf_rd_mumble() and vbuf_wr_mumble() macros report on +/* read and write error conditions, respectively. +/* +/* vbuf_eof() is a macro that returns non-zero if an end-of-file +/* condition was detected while reading or writing the buffer. The error +/* status can be reset by calling vbuf_clearerr(). +/* APPLICATION CALLBACK SYNOPSIS +/* int get_ready(bp) +/* VBUF *bp; +/* +/* int put_ready(bp) +/* VBUF *bp; +/* +/* int space(bp, len) +/* VBUF *bp; +/* ssize_t len; +/* APPLICATION CALLBACK DESCRIPTION +/* .ad +/* .fi +/* get_ready() is called when VBUF_GET() detects a buffer-empty condition. +/* The result is zero when more data could be read, VBUF_EOF otherwise. +/* +/* put_ready() is called when VBUF_PUT() detects a buffer-full condition. +/* The result is zero when the buffer could be flushed, VBUF_EOF otherwise. +/* +/* space() performs whatever magic necessary to make at least \fIlen\fR +/* bytes available for access without using VBUF_PUT(). The result is 0 +/* in case of success, VBUF_EOF otherwise. +/* SEE ALSO +/* vbuf(3h) layout of the VBUF data structure. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/* +/* Wietse Venema +/* Google, Inc. +/* 111 8th Avenue +/* New York, NY 10011, USA +/*--*/ + +/* System library. */ + +#include "sys_defs.h" +#include <string.h> + +/* Utility library. */ + +#include "vbuf.h" + +/* vbuf_unget - implement at least one character pushback */ + +int vbuf_unget(VBUF *bp, int ch) +{ + if ((ch & 0xff) != ch || -bp->cnt >= bp->len) { + bp->flags |= VBUF_FLAG_RD_ERR; /* This error affects reads! */ + return (VBUF_EOF); + } else { + bp->cnt--; + bp->flags &= ~VBUF_FLAG_EOF; + return (*--bp->ptr = ch); + } +} + +/* vbuf_get - handle read buffer empty condition */ + +int vbuf_get(VBUF *bp) +{ + return (bp->get_ready(bp) ? + ((bp->flags |= VBUF_FLAG_EOF), VBUF_EOF) : VBUF_GET(bp)); +} + +/* vbuf_put - handle write buffer full condition */ + +int vbuf_put(VBUF *bp, int ch) +{ + return (bp->put_ready(bp) ? VBUF_EOF : VBUF_PUT(bp, ch)); +} + +/* vbuf_read - bulk read from buffer */ + +ssize_t vbuf_read(VBUF *bp, void *buf, ssize_t len) +{ + ssize_t count; + void *cp; + ssize_t n; + +#if 0 + for (count = 0; count < len; count++) + if ((buf[count] = VBUF_GET(bp)) < 0) + break; + return (count); +#else + for (cp = buf, count = len; count > 0; cp += n, count -= n) { + if (bp->cnt >= 0 && bp->get_ready(bp)) + break; + n = (count < -bp->cnt ? count : -bp->cnt); + memcpy(cp, bp->ptr, n); + bp->ptr += n; + bp->cnt += n; + } + return (len - count); +#endif +} + +/* vbuf_write - bulk write to buffer */ + +ssize_t vbuf_write(VBUF *bp, const void *buf, ssize_t len) +{ + ssize_t count; + const void *cp; + ssize_t n; + +#if 0 + for (count = 0; count < len; count++) + if (VBUF_PUT(bp, buf[count]) < 0) + break; + return (count); +#else + for (cp = buf, count = len; count > 0; cp += n, count -= n) { + if (bp->cnt <= 0 && bp->put_ready(bp) != 0) + break; + n = (count < bp->cnt ? count : bp->cnt); + memcpy(bp->ptr, cp, n); + bp->ptr += n; + bp->cnt -= n; + } + return (len - count); +#endif +} |