Postfix3.3.1
vbuf.c
[詳解]
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 /* void *buf;
27 /* ssize_t len;
28 /*
29 /* ssize_t vbuf_write(bp, buf, len)
30 /* VBUF *bp;
31 /* const void *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 
156 int 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 
170 int 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 
177 int 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 
184 ssize_t vbuf_read(VBUF *bp, void *buf, ssize_t len)
185 {
186  ssize_t count;
187  void *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 
210 ssize_t vbuf_write(VBUF *bp, const void *buf, ssize_t len)
211 {
212  ssize_t count;
213  const void *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 }
VBUF_GET_READY_FN get_ready
Definition: vbuf.h:43
ssize_t cnt
Definition: vbuf.h:41
unsigned char * ptr
Definition: vbuf.h:42
#define VBUF_FLAG_EOF
Definition: vbuf.h:65
ssize_t vbuf_write(VBUF *bp, const void *buf, ssize_t len)
Definition: vbuf.c:210
#define VBUF_PUT(v, c)
Definition: vbuf.h:87
int vbuf_unget(VBUF *bp, int ch)
Definition: vbuf.c:156
#define VBUF_GET(v)
Definition: vbuf.h:85
#define VBUF_EOF
Definition: vbuf.h:91
int flags
Definition: vbuf.h:38
Definition: vbuf.h:37
int vbuf_get(VBUF *bp)
Definition: vbuf.c:170
ssize_t vbuf_read(VBUF *bp, void *buf, ssize_t len)
Definition: vbuf.c:184
VBUF_PUT_READY_FN put_ready
Definition: vbuf.h:44
#define VBUF_FLAG_RD_ERR
Definition: vbuf.h:62
ssize_t len
Definition: vbuf.h:40
int vbuf_put(VBUF *bp, int ch)
Definition: vbuf.c:177