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