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