1/*++ 2/* NAME 3/* vbuf 3 4/* SUMMARY 5/* generic buffer package 6/* SYNOPSIS 7/* #include <vbuf.h> 8/* 9/* int VBUF_GET(bp) 10/* VBUF *bp; 11/* 12/* int VBUF_PUT(bp, ch) 13/* VBUF *bp; 14/* int ch; 15/* 16/* int VBUF_SPACE(bp, len) 17/* VBUF *bp; 18/* ssize_t len; 19/* 20/* int vbuf_unget(bp, ch) 21/* VBUF *bp; 22/* int ch; 23/* 24/* ssize_t vbuf_read(bp, buf, len) 25/* VBUF *bp; 26/* char *buf; 27/* ssize_t len; 28/* 29/* ssize_t vbuf_write(bp, buf, len) 30/* VBUF *bp; 31/* const char *buf; 32/* ssize_t len; 33/* 34/* int vbuf_err(bp) 35/* VBUF *bp; 36/* 37/* int vbuf_eof(bp) 38/* VBUF *bp; 39/* 40/* int vbuf_timeout(bp) 41/* VBUF *bp; 42/* 43/* int vbuf_clearerr(bp) 44/* VBUF *bp; 45/* 46/* int vbuf_rd_err(bp) 47/* VBUF *bp; 48/* 49/* int vbuf_wr_err(bp) 50/* VBUF *bp; 51/* 52/* int vbuf_rd_timeout(bp) 53/* VBUF *bp; 54/* 55/* int vbuf_wr_timeout(bp) 56/* VBUF *bp; 57/* DESCRIPTION 58/* This module implements a buffer with read/write primitives that 59/* automatically handle buffer-empty or buffer-full conditions. 60/* The application is expected to provide callback routines that run 61/* when the read-write primitives detect a buffer-empty/full condition. 62/* 63/* VBUF buffers provide primitives to store and retrieve characters, 64/* and to look up buffer status information. 65/* By design, VBUF buffers provide no explicit primitives for buffer 66/* memory management. This is left to the application to avoid any bias 67/* toward specific management models. The application is free to use 68/* whatever strategy suits best: memory-resident buffer, memory mapped 69/* file, or stdio-like window to an open file. 70/* 71/* VBUF_GET() returns the next character from the specified buffer, 72/* or VBUF_EOF when none is available. VBUF_GET() is an unsafe macro 73/* that evaluates its argument more than once. 74/* 75/* VBUF_PUT() stores one character into the specified buffer. The result 76/* is the stored character, or VBUF_EOF in case of problems. VBUF_PUT() 77/* is an unsafe macro that evaluates its arguments more than once. 78/* 79/* VBUF_SPACE() requests that the requested amount of buffer space be 80/* made available, so that it can be accessed without using VBUF_PUT(). 81/* The result value is 0 for success, VBUF_EOF for problems. 82/* VBUF_SPACE() is an unsafe macro that evaluates its arguments more 83/* than once. VBUF_SPACE() does not support read-only streams. 84/* 85/* vbuf_unget() provides at least one character of pushback, and returns 86/* the pushed back character, or VBUF_EOF in case of problems. It is 87/* an error to call vbuf_unget() on a buffer before reading any data 88/* from it. vbuf_unget() clears the buffer's end-of-file indicator upon 89/* success, and sets the buffer's error indicator when an attempt is 90/* made to push back a non-character value. 91/* 92/* vbuf_read() and vbuf_write() do bulk I/O. The result value is the 93/* number of bytes transferred. A short count is returned in case of 94/* an error. 95/* 96/* vbuf_timeout() is a macro that returns non-zero if a timeout error 97/* condition was detected while reading or writing the buffer. The 98/* error status can be reset by calling vbuf_clearerr(). 99/* 100/* vbuf_err() is a macro that returns non-zero if a non-EOF error 101/* (including timeout) condition was detected while reading or writing 102/* the buffer. The error status can be reset by calling vbuf_clearerr(). 103/* 104/* The vbuf_rd_mumble() and vbuf_wr_mumble() macros report on 105/* read and write error conditions, respectively. 106/* 107/* vbuf_eof() is a macro that returns non-zero if an end-of-file 108/* condition was detected while reading or writing the buffer. The error 109/* status can be reset by calling vbuf_clearerr(). 110/* APPLICATION CALLBACK SYNOPSIS 111/* int get_ready(bp) 112/* VBUF *bp; 113/* 114/* int put_ready(bp) 115/* VBUF *bp; 116/* 117/* int space(bp, len) 118/* VBUF *bp; 119/* ssize_t len; 120/* APPLICATION CALLBACK DESCRIPTION 121/* .ad 122/* .fi 123/* get_ready() is called when VBUF_GET() detects a buffer-empty condition. 124/* The result is zero when more data could be read, VBUF_EOF otherwise. 125/* 126/* put_ready() is called when VBUF_PUT() detects a buffer-full condition. 127/* The result is zero when the buffer could be flushed, VBUF_EOF otherwise. 128/* 129/* space() performs whatever magic necessary to make at least \fIlen\fR 130/* bytes available for access without using VBUF_PUT(). The result is 0 131/* in case of success, VBUF_EOF otherwise. 132/* SEE ALSO 133/* vbuf(3h) layout of the VBUF data structure. 134/* LICENSE 135/* .ad 136/* .fi 137/* The Secure Mailer license must be distributed with this software. 138/* AUTHOR(S) 139/* Wietse Venema 140/* IBM T.J. Watson Research 141/* P.O. Box 704 142/* Yorktown Heights, NY 10598, USA 143/*--*/ 144 145/* System library. */ 146 147#include "sys_defs.h" 148#include <string.h> 149 150/* Utility library. */ 151 152#include "vbuf.h" 153 154/* vbuf_unget - implement at least one character pushback */ 155 156int vbuf_unget(VBUF *bp, int ch) 157{ 158 if ((ch & 0xff) != ch || -bp->cnt >= bp->len) { 159 bp->flags |= VBUF_FLAG_RD_ERR; /* This error affects reads! */ 160 return (VBUF_EOF); 161 } else { 162 bp->cnt--; 163 bp->flags &= ~VBUF_FLAG_EOF; 164 return (*--bp->ptr = ch); 165 } 166} 167 168/* vbuf_get - handle read buffer empty condition */ 169 170int vbuf_get(VBUF *bp) 171{ 172 return (bp->get_ready(bp) ? VBUF_EOF : VBUF_GET(bp)); 173} 174 175/* vbuf_put - handle write buffer full condition */ 176 177int vbuf_put(VBUF *bp, int ch) 178{ 179 return (bp->put_ready(bp) ? VBUF_EOF : VBUF_PUT(bp, ch)); 180} 181 182/* vbuf_read - bulk read from buffer */ 183 184ssize_t vbuf_read(VBUF *bp, char *buf, ssize_t len) 185{ 186 ssize_t count; 187 char *cp; 188 ssize_t n; 189 190#if 0 191 for (count = 0; count < len; count++) 192 if ((buf[count] = VBUF_GET(bp)) < 0) 193 break; 194 return (count); 195#else 196 for (cp = buf, count = len; count > 0; cp += n, count -= n) { 197 if (bp->cnt >= 0 && bp->get_ready(bp)) 198 break; 199 n = (count < -bp->cnt ? count : -bp->cnt); 200 memcpy(cp, bp->ptr, n); 201 bp->ptr += n; 202 bp->cnt += n; 203 } 204 return (len - count); 205#endif 206} 207 208/* vbuf_write - bulk write to buffer */ 209 210ssize_t vbuf_write(VBUF *bp, const char *buf, ssize_t len) 211{ 212 ssize_t count; 213 const char *cp; 214 ssize_t n; 215 216#if 0 217 for (count = 0; count < len; count++) 218 if (VBUF_PUT(bp, buf[count]) < 0) 219 break; 220 return (count); 221#else 222 for (cp = buf, count = len; count > 0; cp += n, count -= n) { 223 if (bp->cnt <= 0 && bp->put_ready(bp) != 0) 224 break; 225 n = (count < bp->cnt ? count : bp->cnt); 226 memcpy(bp->ptr, cp, n); 227 bp->ptr += n; 228 bp->cnt -= n; 229 } 230 return (len - count); 231#endif 232} 233