Commit | Line | Data |
---|---|---|
4930589b FT |
1 | /* |
2 | ashd - A Sane HTTP Daemon | |
3 | Copyright (C) 2008 Fredrik Tolf <fredrik@dolda2000.com> | |
4 | ||
5 | This program is free software: you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License as published by | |
7 | the Free Software Foundation, either version 3 of the License, or | |
8 | (at your option) any later version. | |
9 | ||
10 | This program is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License | |
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | |
17 | */ | |
18 | ||
19 | #ifdef HAVE_CONFIG_H | |
20 | #include <config.h> | |
21 | #endif | |
22 | #include <stdlib.h> | |
23 | #include <string.h> | |
24 | #include <errno.h> | |
25 | ||
26 | #include <utils.h> | |
27 | #include <bufio.h> | |
28 | ||
29 | struct bufio *bioopen(void *pdata, struct bufioops *ops) | |
30 | { | |
31 | struct bufio *bio; | |
32 | ||
33 | omalloc(bio); | |
34 | bio->pdata = pdata; | |
35 | bio->ops = ops; | |
36 | bio->bufhint = 4096; | |
37 | return(bio); | |
38 | } | |
39 | ||
40 | int bioclose(struct bufio *bio) | |
41 | { | |
42 | int rv; | |
43 | ||
44 | bioflush(bio); | |
45 | if(bio->ops->close) | |
46 | rv = bio->ops->close(bio->pdata); | |
47 | else | |
48 | rv = 0; | |
49 | buffree(bio->rbuf); | |
50 | buffree(bio->wbuf); | |
51 | free(bio); | |
52 | return(rv); | |
53 | } | |
54 | ||
55 | size_t biordata(struct bufio *bio) | |
56 | { | |
57 | return(bio->rbuf.d - bio->rh); | |
58 | } | |
59 | ||
60 | size_t biorspace(struct bufio *bio) | |
61 | { | |
62 | if((bio->rbuf.d - bio->rh) >= bio->bufhint) | |
63 | return(0); | |
64 | return(bio->bufhint - (bio->rbuf.d - bio->rh)); | |
65 | } | |
66 | ||
67 | int bioeof(struct bufio *bio) | |
68 | { | |
69 | return(bio->eof && (bio->rh >= bio->rbuf.d)); | |
70 | } | |
71 | ||
72 | static ssize_t biofill(struct bufio *bio) | |
73 | { | |
74 | size_t ns; | |
75 | ssize_t ret; | |
76 | ||
77 | if(!bio->ops->read) { | |
78 | bio->eof = 1; | |
79 | return(0); | |
80 | } | |
81 | if(bio->eof) | |
82 | return(0); | |
83 | if(bio->rh == bio->rbuf.d) | |
84 | bio->rh = bio->rbuf.d = 0; | |
85 | if(bio->rbuf.d == bio->rbuf.s) { | |
86 | if(bio->rh > 0) { | |
87 | memmove(bio->rbuf.b, bio->rbuf.b + bio->rh, bio->rbuf.d -= bio->rh); | |
88 | bio->rh = 0; | |
89 | } else { | |
90 | if((ns = bio->rbuf.s * 2) < bio->bufhint) | |
91 | ns = bio->bufhint; | |
92 | sizebuf(bio->rbuf, ns); | |
93 | } | |
94 | } | |
95 | if((bio->rbuf.s > bio->bufhint) && (bio->rbuf.d < bio->bufhint)) | |
96 | bio->rbuf.b = srealloc(bio->rbuf.b, bio->rbuf.s = bio->bufhint); | |
97 | ret = bio->ops->read(bio->pdata, bio->rbuf.b + bio->rbuf.d, bio->rbuf.s - bio->rbuf.d); | |
98 | if(ret < 0) { | |
99 | bio->err = errno; | |
100 | return(-1); | |
101 | } else if(ret == 0) { | |
102 | bio->eof = 1; | |
103 | return(0); | |
104 | } | |
105 | bio->rbuf.d += ret; | |
106 | return(bio->rbuf.d - bio->rh); | |
107 | } | |
108 | ||
109 | ssize_t biorensure(struct bufio *bio, size_t bytes) | |
110 | { | |
111 | ssize_t ret; | |
112 | ||
113 | while(bio->rbuf.d - bio->rh < bytes) { | |
114 | if((ret = biofill(bio)) <= 0) | |
115 | return(ret); | |
116 | } | |
117 | return(bio->rbuf.d - bio->rh); | |
118 | } | |
119 | ||
120 | ssize_t biofillsome(struct bufio *bio) | |
121 | { | |
122 | return(biofill(bio)); | |
123 | } | |
124 | ||
125 | int biogetc(struct bufio *bio) | |
126 | { | |
127 | ssize_t ret; | |
128 | ||
129 | while(bio->rbuf.d <= bio->rh) { | |
130 | if((ret = biofill(bio)) <= 0) | |
131 | return(EOF); | |
132 | } | |
133 | return((unsigned char)bio->rbuf.b[bio->rh++]); | |
134 | } | |
135 | ||
136 | ssize_t bioreadsome(struct bufio *bio, void *buf, size_t len) | |
137 | { | |
138 | ssize_t ret; | |
139 | ||
140 | if((bio->rh >= bio->rbuf.d) && ((ret = biofill(bio)) <= 0)) | |
141 | return(ret); | |
142 | ret = min(len, bio->rbuf.d - bio->rh); | |
143 | memcpy(buf, bio->rbuf.b + bio->rh, ret); | |
144 | bio->rh += ret; | |
145 | return(ret); | |
146 | } | |
147 | ||
148 | size_t biowdata(struct bufio *bio) | |
149 | { | |
150 | return(bio->wbuf.d - bio->wh); | |
151 | } | |
152 | ||
153 | size_t biowspace(struct bufio *bio) | |
154 | { | |
155 | if((bio->wbuf.d - bio->wh) >= bio->bufhint) | |
156 | return(0); | |
157 | return(bio->bufhint - (bio->wbuf.d - bio->wh)); | |
158 | } | |
159 | ||
160 | int bioflush(struct bufio *bio) | |
161 | { | |
162 | ssize_t ret; | |
163 | ||
164 | while(bio->wh < bio->wbuf.d) { | |
165 | ret = bio->ops->write(bio->pdata, bio->wbuf.b + bio->wh, bio->wbuf.d - bio->wh); | |
166 | if(ret < 0) { | |
167 | bio->err = errno; | |
168 | return(-1); | |
169 | } | |
170 | bio->wh += ret; | |
171 | } | |
172 | return(0); | |
173 | } | |
174 | ||
175 | int bioflushsome(struct bufio *bio) | |
176 | { | |
177 | ssize_t ret; | |
178 | ||
179 | if(bio->wh < bio->wbuf.d) { | |
180 | ret = bio->ops->write(bio->pdata, bio->wbuf.b + bio->wh, bio->wbuf.d - bio->wh); | |
181 | if(ret < 0) { | |
182 | bio->err = errno; | |
183 | return(-1); | |
184 | } | |
185 | bio->wh += ret; | |
186 | return(1); | |
187 | } else { | |
188 | return(0); | |
189 | } | |
190 | } | |
191 | ||
192 | ssize_t biowensure(struct bufio *bio, size_t bytes) | |
193 | { | |
194 | if(bio->wbuf.s - bio->wbuf.d < bytes) { | |
195 | if(!bio->ops->write) { | |
196 | errno = bio->err = EPIPE; | |
197 | return(-1); | |
198 | } | |
199 | if(bioflush(bio) < 0) | |
200 | return(-1); | |
201 | bio->wh = bio->wbuf.d = 0; | |
202 | if((bio->wbuf.s > bio->bufhint) && (bytes <= bio->bufhint)) | |
203 | bio->wbuf.b = srealloc(bio->wbuf.b, bio->wbuf.s = bio->bufhint); | |
204 | else | |
205 | sizebuf(bio->wbuf, (bytes < bio->bufhint)?bio->bufhint:bytes); | |
206 | } | |
207 | return(0); | |
208 | } | |
209 | ||
210 | int bioputc(struct bufio *bio, int c) | |
211 | { | |
212 | if(biowensure(bio, 1) < 0) | |
213 | return(-1); | |
214 | bio->wbuf.b[bio->wbuf.d++] = c; | |
215 | return(0); | |
216 | } | |
217 | ||
218 | ssize_t biowrite(struct bufio *bio, const void *data, size_t len) | |
219 | { | |
220 | ssize_t wb, ret; | |
221 | ||
222 | wb = 0; | |
223 | while(len > 0) { | |
224 | if(biowensure(bio, min(len, bio->bufhint)) < 0) { | |
225 | if(wb > 0) | |
226 | return(wb); | |
227 | return(-1); | |
228 | } | |
229 | if(len < bio->wbuf.s - bio->wbuf.d) { | |
230 | memcpy(bio->wbuf.b + bio->wbuf.d, data, len); | |
029ce99b | 231 | bio->wbuf.d += len; |
4930589b FT |
232 | wb += len; |
233 | len = 0; | |
234 | } else { | |
235 | if(bioflush(bio) < 0) { | |
236 | if(wb > 0) | |
237 | return(wb); | |
238 | return(-1); | |
239 | } | |
240 | bio->wh = bio->wbuf.d = 0; | |
241 | ret = bio->ops->write(bio->pdata, data, len); | |
242 | if(ret < 0) { | |
243 | if(wb > 0) | |
244 | return(wb); | |
245 | bio->err = errno; | |
246 | return(-1); | |
247 | } | |
248 | data += ret; len -= ret; wb += ret; | |
249 | } | |
250 | } | |
029ce99b | 251 | return(wb); |
4930589b FT |
252 | } |
253 | ||
254 | ssize_t biowritesome(struct bufio *bio, const void *data, size_t len) | |
255 | { | |
256 | ssize_t ret; | |
257 | ||
258 | sizebuf(bio->wbuf, bio->bufhint); | |
259 | if(bio->wh == bio->wbuf.d) | |
260 | bio->wh = bio->wbuf.d = 0; | |
261 | if(bio->wbuf.d == bio->wbuf.s) { | |
ba2bdc3d | 262 | if(bio->wh > 0) { |
4930589b | 263 | memmove(bio->wbuf.b, bio->wbuf.b + bio->wh, bio->wbuf.d -= bio->wh); |
ba2bdc3d FT |
264 | bio->wh = 0; |
265 | } | |
4930589b FT |
266 | } |
267 | ret = min(len, bio->wbuf.s - bio->wbuf.d); | |
268 | memcpy(bio->wbuf.b + bio->wbuf.d, data, ret); | |
269 | bio->wbuf.d += ret; | |
8e01353e FT |
270 | if(bioflushsome(bio) < 0) { |
271 | if(ret == 0) | |
272 | return(-1); | |
273 | if(ret < bio->wbuf.d - bio->wh) { /* Should never be false */ | |
274 | bio->wbuf.d -= ret; | |
275 | return(-1); | |
276 | } | |
277 | } | |
4930589b FT |
278 | return(ret); |
279 | } | |
280 | ||
281 | int bioprintf(struct bufio *bio, const char *format, ...) | |
282 | { | |
283 | va_list args; | |
284 | int ret; | |
285 | ||
286 | if(biowensure(bio, strlen(format)) < 0) | |
287 | return(-1); | |
288 | while(1) { | |
289 | va_start(args, format); | |
290 | ret = vsnprintf(bio->wbuf.b + bio->wbuf.d, bio->wbuf.s - bio->wbuf.d, format, args); | |
291 | va_end(args); | |
f9db90c1 | 292 | if(ret < bio->wbuf.s - bio->wbuf.d) { |
4930589b FT |
293 | bio->wbuf.d += ret; |
294 | return(0); | |
295 | } | |
f9db90c1 | 296 | if(biowensure(bio, ret + 1) < 0) |
4930589b FT |
297 | return(-1); |
298 | } | |
299 | } | |
300 | ||
301 | ssize_t biocopysome(struct bufio *dst, struct bufio *src) | |
302 | { | |
303 | ssize_t ret; | |
304 | ||
305 | if(src->rh >= src->rbuf.d) | |
306 | return(0); | |
307 | if((ret = biowritesome(dst, src->rbuf.b + src->rh, src->rbuf.d - src->rh)) < 0) | |
308 | return(-1); | |
309 | src->rh += ret; | |
310 | return(ret); | |
311 | } | |
99a520b6 FT |
312 | |
313 | ssize_t biocopybuf(struct bufio *dst, struct bufio *src) | |
314 | { | |
315 | ssize_t ret; | |
316 | ||
317 | sizebuf(dst->wbuf, dst->bufhint); | |
318 | if(dst->wbuf.d == dst->wbuf.s) { | |
319 | if(dst->wh > 0) { | |
320 | memmove(dst->wbuf.b, dst->wbuf.b + dst->wh, dst->wbuf.d -= dst->wh); | |
321 | dst->wh = 0; | |
322 | } | |
323 | } | |
324 | ret = min(src->rbuf.d - src->rh, dst->wbuf.s - dst->wbuf.d); | |
325 | memcpy(dst->wbuf.b + dst->wbuf.d, src->rbuf.b + src->rh, ret); | |
326 | src->rh += ret; | |
327 | dst->wbuf.d += ret; | |
328 | return(ret); | |
329 | } |