Blob


1 /*
2 * This is free and unencumbered software released into the public domain.
3 *
4 * Anyone is free to copy, modify, publish, use, compile, sell, or
5 * distribute this software, either in source code form or as a compiled
6 * binary, for any purpose, commercial or non-commercial, and by any
7 * means.
8 *
9 * In jurisdictions that recognize copyright laws, the author or authors
10 * of this software dedicate any and all copyright interest in the
11 * software to the public domain. We make this dedication for the benefit
12 * of the public at large and to the detriment of our heirs and
13 * successors. We intend this dedication to be an overt act of
14 * relinquishment in perpetuity of all present and future rights to this
15 * software under copyright law.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
24 */
26 #include "config.h"
28 #include <assert.h>
29 #include <errno.h>
30 #include <poll.h>
31 #include <stdarg.h>
32 #include <stdint.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
38 #include "bufio.h"
40 int
41 buf_init(struct buffer *buf)
42 {
43 const size_t cap = BIO_CHUNK;
45 memset(buf, 0, sizeof(*buf));
46 if ((buf->buf = malloc(cap)) == NULL)
47 return (-1);
48 buf->cap = cap;
49 return (0);
50 }
52 static int
53 buf_grow(struct buffer *buf)
54 {
55 size_t newcap;
56 void *t;
58 newcap = buf->cap + BIO_CHUNK;
59 t = realloc(buf->buf, newcap);
60 if (t == NULL)
61 return (-1);
62 buf->buf = t;
63 buf->cap = newcap;
64 return (0);
65 }
67 int
68 buf_has_line(struct buffer *buf, const char *nl)
69 {
70 return (memmem(buf->buf, buf->len, nl, strlen(nl)) != NULL);
71 }
73 void
74 buf_drain(struct buffer *buf, size_t l)
75 {
76 if (l >= buf->len) {
77 buf->len = 0;
78 return;
79 }
81 memmove(buf->buf, buf->buf + l, buf->len - l);
82 buf->len -= l;
83 }
85 void
86 buf_drain_line(struct buffer *buf, const char *nl)
87 {
88 uint8_t *endln;
89 size_t nlen;
91 nlen = strlen(nl);
92 if ((endln = memmem(buf->buf, buf->len, nl, nlen)) == NULL)
93 return;
94 buf_drain(buf, endln + nlen - buf->buf);
95 }
97 void
98 buf_free(struct buffer *buf)
99 {
100 free(buf->buf);
101 memset(buf, 0, sizeof(*buf));
104 int
105 bufio_init(struct bufio *bio)
107 memset(bio, 0, sizeof(*bio));
108 bio->fd = -1;
110 if (buf_init(&bio->wbuf) == -1)
111 return (-1);
112 if (buf_init(&bio->rbuf) == -1) {
113 buf_free(&bio->wbuf);
114 return (-1);
116 return (0);
119 void
120 bufio_free(struct bufio *bio)
122 if (bio->fd != -1)
123 close(bio->fd);
125 buf_free(&bio->rbuf);
126 buf_free(&bio->wbuf);
129 int
130 bufio_reset(struct bufio *bio)
132 bufio_free(bio);
133 return (bufio_init(bio));
136 void
137 bufio_set_fd(struct bufio *bio, int fd)
139 bio->fd = fd;
142 void
143 bufio_set_chunked(struct bufio *bio, int chunked)
145 bio->chunked = chunked;
148 short
149 bufio_pollev(struct bufio *bio)
151 short ev;
153 ev = POLLIN;
154 if (bio->wbuf.len != 0)
155 ev |= POLLOUT;
157 return (ev);
160 ssize_t
161 bufio_read(struct bufio *bio)
163 struct buffer *rbuf = &bio->rbuf;
164 ssize_t r;
166 assert(rbuf->cap >= rbuf->len);
167 if (rbuf->cap - rbuf->len < BIO_CHUNK) {
168 if (buf_grow(rbuf) == -1)
169 return (-1);
172 r = read(bio->fd, rbuf->buf + rbuf->len, rbuf->cap - rbuf->len);
173 if (r == -1)
174 return (-1);
175 rbuf->len += r;
176 return (r);
179 size_t
180 bufio_drain(struct bufio *bio, void *d, size_t len)
182 struct buffer *rbuf = &bio->rbuf;
184 if (len > rbuf->len)
185 len = rbuf->len;
186 memcpy(d, rbuf->buf, len);
187 buf_drain(rbuf, len);
188 return (len);
191 ssize_t
192 bufio_write(struct bufio *bio)
194 struct buffer *wbuf = &bio->wbuf;
195 ssize_t w;
197 w = write(bio->fd, wbuf->buf, wbuf->len);
198 if (w == -1)
199 return (-1);
200 buf_drain(wbuf, w);
201 return (w);
204 static int
205 bufio_append(struct bufio *bio, const void *d, size_t len)
207 struct buffer *wbuf = &bio->wbuf;
209 if (len == 0)
210 return (0);
212 while (wbuf->cap - wbuf->len < len) {
213 if (buf_grow(wbuf) == -1)
214 return (-1);
217 memcpy(wbuf->buf + wbuf->len, d, len);
218 wbuf->len += len;
219 return (0);
222 int
223 bufio_compose(struct bufio *bio, const void *d, size_t len)
225 char n[16];
226 int r;
228 if (bio->chunked) {
229 r = snprintf(n, sizeof(n), "%zx\r\n", len);
230 if (r < 0 || (size_t)r >= sizeof(n))
231 return (-1);
232 if (bufio_append(bio, n, r) == -1)
233 return (-1);
236 if (bufio_append(bio, d, len) == -1)
237 return (-1);
239 if (bio->chunked)
240 return bufio_append(bio, "\r\n", 2);
242 return (0);
245 int
246 bufio_compose_str(struct bufio *bio, const char *str)
248 return (bufio_compose(bio, str, strlen(str)));
251 int
252 bufio_compose_fmt(struct bufio *bio, const char *fmt, ...)
254 va_list ap;
255 char *str;
256 int r;
258 va_start(ap, fmt);
259 r = vasprintf(&str, fmt, ap);
260 va_end(ap);
262 if (r == -1)
263 return (-1);
264 r = bufio_compose(bio, str, r);
265 free(str);
266 return (r);