/*++ /* NAME /* vbuf 3 /* SUMMARY /* generic buffer package /* SYNOPSIS /* #include /* /* 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 /* 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 }