xref: /netbsd-src/external/ibm-public/postfix/dist/src/util/vbuf.c (revision daf6c4152fcddc27c445489775ed1f66ab4ea9a9)
1 /*	$NetBSD: vbuf.c,v 1.1.1.1 2009/06/23 10:09:01 tron 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 /*	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 
143 int     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 
157 int     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 
164 int     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 
171 ssize_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 
197 ssize_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