Added the `ratequeue' program.
[ashd.git] / lib / utils.c
... / ...
CommitLineData
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 <stdio.h>
24#include <string.h>
25#include <ctype.h>
26#include <errno.h>
27
28#include <utils.h>
29
30static char *base64set = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
31static int base64rev[] = {
32 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
33 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
34 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
35 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
36 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
37 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
38 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
39 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
40 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
41 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
42 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
43 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
44 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
45 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
46 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
47 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
48};
49
50void _sizebuf(struct buffer *buf, size_t wanted, size_t el)
51{
52 size_t n;
53
54 n = buf->s;
55 if(n == 0)
56 n = 1;
57 while(n < wanted)
58 n <<= 1;
59 if(n <= buf->s)
60 return;
61 if(buf->b != NULL)
62 buf->b = srealloc(buf->b, n * el);
63 else
64 buf->b = smalloc(n * el);
65 buf->s = n;
66}
67
68char *decstr(char **p, size_t *len)
69{
70 char *p2, *ret;
71
72 for(p2 = *p; (p2 - *p) < *len; p2++) {
73 if(*p2 == 0)
74 break;
75 }
76 if((p2 - *p) == *len)
77 return(NULL);
78 p2++;
79 ret = *p;
80 *len -= p2 - *p;
81 *p = p2;
82 return(ret);
83}
84
85char *vsprintf2(char *format, va_list al)
86{
87 int ret;
88 char *buf;
89 va_list al2;
90
91 va_copy(al2, al);
92 ret = vsnprintf(NULL, 0, format, al2);
93 va_end(al2);
94 buf = smalloc(ret + 1);
95 va_copy(al2, al);
96 vsnprintf(buf, ret + 1, format, al2);
97 va_end(al2);
98 return(buf);
99}
100
101char *sprintf2(char *format, ...)
102{
103 va_list args;
104 char *buf;
105
106 va_start(args, format);
107 buf = vsprintf2(format, args);
108 va_end(args);
109 return(buf);
110}
111
112char *sprintf3(char *format, ...)
113{
114 static char *buf = NULL;
115 va_list args;
116
117 if(buf != NULL)
118 free(buf);
119 va_start(args, format);
120 buf = vsprintf2(format, args);
121 va_end(args);
122 return(buf);
123}
124
125off_t atoo(char *n)
126{
127 return((off_t)strtoll(n, NULL, 10));
128}
129
130char **tokenize(char *src)
131{
132 char **ret;
133 char *p, *p2, *n;
134 int s, q, cl;
135
136 p = src;
137 s = 0;
138 ret = NULL;
139 while(1) {
140 while(isspace(*p))
141 p++;
142 if(!*p)
143 break;
144 p2 = p;
145 q = 0;
146 while(1) {
147 if(q) {
148 if(*p == '\"')
149 q = 0;
150 else if(*p == '\\')
151 p++;
152 } else {
153 if(*p == '\"')
154 q = 1;
155 else if(isspace(*p) || !*p)
156 break;
157 else if(*p == '\\')
158 p++;
159 }
160 p++;
161 }
162 cl = p - p2;
163 n = memcpy(malloc(cl + 1), p2, cl);
164 n[cl] = 0;
165 for(p2 = n; *p2; cl--) {
166 if(*p2 == '\\') {
167 memmove(p2, p2 + 1, cl--);
168 p2++;
169 } else if(*p2 == '\"') {
170 memmove(p2, p2 + 1, cl);
171 } else {
172 p2++;
173 }
174 }
175 ret = realloc(ret, sizeof(char *) * (++s));
176 ret[s - 1] = n;
177 }
178 ret = realloc(ret, sizeof(char *) * (++s));
179 ret[s - 1] = NULL;
180 return(ret);
181}
182
183void freeca(char **ca)
184{
185 char **c;
186
187 if(ca == NULL)
188 return;
189 for(c = ca; *c; c++)
190 free(*c);
191 free(ca);
192}
193
194int calen(char **a)
195{
196 int i;
197
198 for(i = 0; *a; a++, i++);
199 return(i);
200}
201
202void bvprintf(struct charbuf *buf, char *format, va_list al)
203{
204 va_list al2;
205 int ret;
206
207 while(1) {
208 va_copy(al2, al);
209 ret = vsnprintf(buf->b + buf->d, buf->s - buf->d, format, al2);
210 va_end(al2);
211 if(ret < buf->s - buf->d) {
212 buf->d += ret;
213 return;
214 }
215 sizebuf(*buf, buf->d + ret + 1);
216 }
217}
218
219void bprintf(struct charbuf *buf, char *format, ...)
220{
221 va_list args;
222
223 va_start(args, format);
224 bvprintf(buf, format, args);
225 va_end(args);
226}
227
228void replstr(char **p, char *n)
229{
230 char *tmp;
231
232 tmp = *p;
233 if(n)
234 *p = sstrdup(n);
235 else
236 *p = NULL;
237 if(tmp)
238 free(tmp);
239}
240
241char *base64encode(char *data, size_t datalen)
242{
243 struct charbuf buf;
244
245 if(datalen == 0)
246 return(sstrdup(""));
247 bufinit(buf);
248 while(datalen >= 3)
249 {
250 bufadd(buf, base64set[(data[0] & 0xfc) >> 2]);
251 bufadd(buf, base64set[((data[0] & 0x03) << 4) | ((data[1] & 0xf0) >> 4)]);
252 bufadd(buf, base64set[((data[1] & 0x0f) << 2) | ((data[2] & 0xc0) >> 6)]);
253 bufadd(buf, base64set[data[2] & 0x3f]);
254 datalen -= 3;
255 data += 3;
256 }
257 if(datalen == 1)
258 {
259 bufadd(buf, base64set[(data[0] & 0xfc) >> 2]);
260 bufadd(buf, base64set[(data[0] & 0x03) << 4]);
261 bufcat(buf, "==", 2);
262 }
263 if(datalen == 2)
264 {
265 bufadd(buf, base64set[(data[0] & 0xfc) >> 2]);
266 bufadd(buf, base64set[((data[0] & 0x03) << 4) | ((data[1] & 0xf0) >> 4)]);
267 bufadd(buf, base64set[(data[1] & 0x0f) << 2]);
268 bufadd(buf, '=');
269 }
270 bufadd(buf, 0);
271 return(buf.b);
272}
273
274char *base64decode(char *data, size_t *datalen)
275{
276 int b, c;
277 char cur;
278 struct charbuf buf;
279
280 bufinit(buf);
281 cur = 0;
282 b = 8;
283 for(; *data > 0; data++)
284 {
285 c = (int)(unsigned char)*data;
286 if(c == '=')
287 break;
288 if(c == '\n')
289 continue;
290 if(base64rev[c] == -1)
291 {
292 buffree(buf);
293 return(NULL);
294 }
295 b -= 6;
296 if(b <= 0)
297 {
298 cur |= base64rev[c] >> -b;
299 bufadd(buf, cur);
300 b += 8;
301 cur = 0;
302 }
303 cur |= base64rev[c] << b;
304 }
305 if(datalen != NULL)
306 *datalen = buf.d;
307 bufadd(buf, 0);
308 return(buf.b);
309}
310
311int hexdigit(char c)
312{
313 if((c >= '0') && (c <= '9')) return(c - '0');
314 else if((c >= 'a') && (c <= 'f')) return(c - 'a' + 10);
315 else if((c >= 'A') && (c <= 'F')) return(c - 'A' + 10);
316 return(-1);
317}
318
319static int btheight(struct btree *tree)
320{
321 if(tree == NULL)
322 return(0);
323 return(tree->h);
324}
325
326static void btsetheight(struct btree *tree)
327{
328 if(tree == NULL)
329 return;
330 tree->h = max(btheight(tree->l), btheight(tree->r)) + 1;
331}
332
333static void bbtrl(struct btree **tree);
334
335static void bbtrr(struct btree **tree)
336{
337 struct btree *m, *l, *r;
338
339 if(btheight((*tree)->l->r) > btheight((*tree)->l->l))
340 bbtrl(&(*tree)->l);
341 r = (*tree);
342 l = r->l;
343 m = l->r;
344 r->l = m;
345 btsetheight(r);
346 l->r = r;
347 btsetheight(l);
348 *tree = l;
349}
350
351static void bbtrl(struct btree **tree)
352{
353 struct btree *m, *l, *r;
354
355 if(btheight((*tree)->r->l) > btheight((*tree)->r->r))
356 bbtrr(&(*tree)->r);
357 l = (*tree);
358 r = l->r;
359 m = r->l;
360 l->r = m;
361 btsetheight(l);
362 r->l = l;
363 btsetheight(r);
364 *tree = r;
365}
366
367static int ptrcmp(void *a, void *b)
368{
369 if(a < b)
370 return(-1);
371 else if(a > b)
372 return(1);
373 return(0);
374}
375
376int bbtreedel(struct btree **tree, void *item, int (*cmp)(void *, void *))
377{
378 int c, r;
379 struct btree *s, **sp, *o;
380
381 if(cmp == NULL)
382 cmp = ptrcmp;
383 if(*tree == NULL)
384 return(0);
385 if((c = cmp(item, (*tree)->d)) < 0) {
386 r = bbtreedel(&(*tree)->l, item, cmp);
387 } else if(c > 0) {
388 r = bbtreedel(&(*tree)->r, item, cmp);
389 } else {
390 r = 1;
391 o = *tree;
392 if(((*tree)->r != NULL) && ((*tree)->l != NULL)) {
393 sp = &(*tree)->r;
394 s = *sp;
395 while(s->l != NULL) {
396 sp = &(s->l);
397 s = *sp;
398 }
399 *sp = (*sp)->r;
400 s->l = (*tree)->l;
401 s->r = (*tree)->r;
402 *tree = s;
403 } else if((*tree)->l != NULL) {
404 *tree = (*tree)->l;
405 } else if((*tree)->r != NULL) {
406 *tree = (*tree)->r;
407 } else {
408 *tree = NULL;
409 }
410 free(o);
411 }
412 if(*tree != NULL) {
413 btsetheight(*tree);
414 if(btheight((*tree)->l) > btheight((*tree)->r) + 1)
415 bbtrr(tree);
416 if(btheight((*tree)->r) > btheight((*tree)->l) + 1)
417 bbtrl(tree);
418 }
419 return(r);
420}
421
422void freebtree(struct btree **tree, void (*ffunc)(void *))
423{
424 if(*tree == NULL)
425 return;
426 freebtree(&(*tree)->l, ffunc);
427 freebtree(&(*tree)->r, ffunc);
428 if(ffunc != NULL)
429 ffunc((*tree)->d);
430 free(*tree);
431 *tree = NULL;
432}
433
434int bbtreeput(struct btree **tree, void *item, int (*cmp)(void *, void *))
435{
436 int c, r;
437
438 if(cmp == NULL)
439 cmp = ptrcmp;
440 if(*tree == NULL) {
441 *tree = szmalloc(sizeof(**tree));
442 (*tree)->d = item;
443 (*tree)->h = 1;
444 return(1);
445 }
446 if((c = cmp(item, (*tree)->d)) < 0)
447 r = bbtreeput(&(*tree)->l, item, cmp);
448 else if(c > 0)
449 r = bbtreeput(&(*tree)->r, item, cmp);
450 else
451 return(0);
452 btsetheight(*tree);
453 if(btheight((*tree)->l) > btheight((*tree)->r) + 1)
454 bbtrr(tree);
455 if(btheight((*tree)->r) > btheight((*tree)->l) + 1)
456 bbtrl(tree);
457 return(r);
458}
459
460void *btreeget(struct btree *tree, void *key, int (*cmp)(void *, void *))
461{
462 int c;
463
464 if(cmp == NULL)
465 cmp = ptrcmp;
466 while(1) {
467 if(tree == NULL)
468 return(NULL);
469 c = cmp(key, tree->d);
470 if(c < 0)
471 tree = tree->l;
472 else if(c > 0)
473 tree = tree->r;
474 else
475 return(tree->d);
476 }
477}
478
479struct stdif {
480 ssize_t (*read)(void *pdata, void *buf, size_t len);
481 ssize_t (*write)(void *pdata, const void *buf, size_t len);
482 off_t (*seek)(void *pdata, off_t offset, int whence);
483 int (*close)(void *pdata);
484 void *pdata;
485};
486
487#if defined(HAVE_GLIBC_STDIO)
488static ssize_t wrapread(void *pdata, char *buf, size_t len)
489{
490 struct stdif *nf = pdata;
491
492 return(nf->read(nf->pdata, buf, len));
493}
494
495static ssize_t wrapwrite(void *pdata, const char *buf, size_t len)
496{
497 struct stdif *nf = pdata;
498 size_t off;
499 ssize_t ret;
500
501 /*
502 * XXX? In seeming violation of its own manual, glibc requires the
503 * cookie-write function to complete writing the entire buffer,
504 * rather than working like write(2).
505 */
506 off = 0;
507 while(off < len) {
508 ret = nf->write(nf->pdata, buf + off, len - off);
509 if(ret < 0)
510 return(off);
511 off += ret;
512 }
513 return(off);
514}
515
516static int wrapseek(void *pdata, off64_t *pos, int whence)
517{
518 struct stdif *nf = pdata;
519 off_t ret;
520
521 ret = nf->seek(nf->pdata, *pos, whence);
522 if(ret < 0)
523 return(-1);
524 *pos = ret;
525 return(0);
526}
527
528static int wrapclose(void *pdata)
529{
530 struct stdif *nf = pdata;
531 int ret;
532
533 if(nf->close != NULL)
534 ret = nf->close(nf->pdata);
535 else
536 ret = 0;
537 free(nf);
538 return(ret);
539}
540
541FILE *funstdio(void *pdata,
542 ssize_t (*read)(void *pdata, void *buf, size_t len),
543 ssize_t (*write)(void *pdata, const void *buf, size_t len),
544 off_t (*seek)(void *pdata, off_t offset, int whence),
545 int (*close)(void *pdata))
546{
547 struct stdif *nf;
548 cookie_io_functions_t io;
549 char *mode;
550
551 if(read && write) {
552 mode = "r+";
553 } else if(read) {
554 mode = "r";
555 } else if(write) {
556 mode = "w";
557 } else {
558 errno = EINVAL;
559 return(NULL);
560 }
561 omalloc(nf);
562 *nf = (struct stdif){.read = read, .write = write, .seek = seek, .close = close, .pdata = pdata};
563 io = (cookie_io_functions_t) {
564 .read = read?wrapread:NULL,
565 .write = write?wrapwrite:NULL,
566 .seek = seek?wrapseek:NULL,
567 .close = wrapclose,
568 };
569 return(fopencookie(nf, mode, io));
570}
571#elif defined(HAVE_BSD_STDIO)
572static int wrapread(void *pdata, char *buf, int len)
573{
574 struct stdif *nf = pdata;
575
576 return(nf->read(nf->pdata, buf, len));
577}
578
579static int wrapwrite(void *pdata, const char *buf, int len)
580{
581 struct stdif *nf = pdata;
582
583 return(nf->write(nf->pdata, buf, len));
584}
585
586static fpos_t wrapseek(void *pdata, fpos_t pos, int whence)
587{
588 struct stdif *nf = pdata;
589
590 return(nf->seek(nf->pdata, pos, whence));
591}
592
593static int wrapclose(void *pdata)
594{
595 struct stdif *nf = pdata;
596 int ret;
597
598 if(nf->close != NULL)
599 ret = nf->close(nf->pdata);
600 else
601 ret = 0;
602 free(nf);
603 return(ret);
604}
605
606FILE *funstdio(void *pdata,
607 ssize_t (*read)(void *pdata, void *buf, size_t len),
608 ssize_t (*write)(void *pdata, const void *buf, size_t len),
609 off_t (*seek)(void *pdata, off_t offset, int whence),
610 int (*close)(void *pdata))
611{
612 struct stdif *nf;
613
614 omalloc(nf);
615 *nf = (struct stdif){.read = read, .write = write, .seek = seek, .close = close, .pdata = pdata};
616 return(funopen(nf, read?wrapread:NULL, write?wrapwrite:NULL, seek?wrapseek:NULL, wrapclose));
617}
618#else
619#error "No stdio implementation for this system"
620#endif