Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / util / vbuf.c
blobcb46b4f9ff1f51131086801996ee3264bd662959
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* vbuf 3
6 /* SUMMARY
7 /* generic buffer package
8 /* SYNOPSIS
9 /* #include <vbuf.h>
11 /* int VBUF_GET(bp)
12 /* VBUF *bp;
14 /* int VBUF_PUT(bp, ch)
15 /* VBUF *bp;
16 /* int ch;
18 /* int VBUF_SPACE(bp, len)
19 /* VBUF *bp;
20 /* ssize_t len;
22 /* int vbuf_unget(bp, ch)
23 /* VBUF *bp;
24 /* int ch;
26 /* ssize_t vbuf_read(bp, buf, len)
27 /* VBUF *bp;
28 /* char *buf;
29 /* ssize_t len;
31 /* ssize_t vbuf_write(bp, buf, len)
32 /* VBUF *bp;
33 /* const char *buf;
34 /* ssize_t len;
36 /* int vbuf_err(bp)
37 /* VBUF *bp;
39 /* int vbuf_eof(bp)
40 /* VBUF *bp;
42 /* int vbuf_timeout(bp)
43 /* VBUF *bp;
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.
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.
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.
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.
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.
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.
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.
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().
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().
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;
101 /* int put_ready(bp)
102 /* VBUF *bp;
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.
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.
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 /*--*/
132 /* System library. */
134 #include "sys_defs.h"
135 #include <string.h>
137 /* Utility library. */
139 #include "vbuf.h"
141 /* vbuf_unget - implement at least one character pushback */
143 int vbuf_unget(VBUF *bp, int ch)
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);
155 /* vbuf_get - handle read buffer empty condition */
157 int vbuf_get(VBUF *bp)
159 return (bp->get_ready(bp) ? VBUF_EOF : VBUF_GET(bp));
162 /* vbuf_put - handle write buffer full condition */
164 int vbuf_put(VBUF *bp, int ch)
166 return (bp->put_ready(bp) ? VBUF_EOF : VBUF_PUT(bp, ch));
169 /* vbuf_read - bulk read from buffer */
171 ssize_t vbuf_read(VBUF *bp, char *buf, ssize_t len)
173 ssize_t count;
174 char *cp;
175 ssize_t n;
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;
191 return (len - count);
192 #endif
195 /* vbuf_write - bulk write to buffer */
197 ssize_t vbuf_write(VBUF *bp, const char *buf, ssize_t len)
199 ssize_t count;
200 const char *cp;
201 ssize_t n;
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;
217 return (len - count);
218 #endif