lib: Introduced a portable abstraction layer for custom stdio streams.
[ashd.git] / lib / utils.c
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
30 static char *base64set = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
31 static 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
50 void _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
68 char *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
85 char *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
101 char *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
112 char *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
125 off_t atoo(char *n)
126 {
127     return((off_t)strtoll(n, NULL, 10));
128 }
129
130 char **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
183 void 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
194 int calen(char **a)
195 {
196     int i;
197     
198     for(i = 0; *a; a++, i++);
199     return(i);
200 }
201
202 void 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
219 void 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
228 void 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
241 char *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
274 char *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
311 int 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
319 static int btheight(struct btree *tree)
320 {
321     if(tree == NULL)
322         return(0);
323     return(tree->h);
324 }
325
326 static 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
333 static void bbtrl(struct btree **tree);
334
335 static 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
351 static 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
367 static 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
376 int 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
422 void 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
434 int 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
460 void *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
479 struct 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)
488 static 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
495 static ssize_t wrapwrite(void *pdata, const char *buf, size_t len)
496 {
497     struct stdif *nf = pdata;
498     
499     return(nf->write(nf->pdata, buf, len));
500 }
501
502 static int wrapseek(void *pdata, off_t *pos, int whence)
503 {
504     struct stdif *nf = pdata;
505     off_t ret;
506     
507     ret = nf->seek(nf->pdata, *pos, whence);
508     if(ret < 0)
509         return(-1);
510     *pos = ret;
511     return(0);
512 }
513
514 static int wrapclose(void *pdata)
515 {
516     struct stdif *nf = pdata;
517     int ret;
518     
519     if(nf->close != NULL)
520         ret = nf->close(nf->pdata);
521     free(nf);
522     return(ret);
523 }
524
525 FILE *funstdio(void *pdata,
526                ssize_t (*read)(void *pdata, void *buf, size_t len),
527                ssize_t (*write)(void *pdata, const void *buf, size_t len),
528                off_t (*seek)(void *pdata, off_t offset, int whence),
529                int (*close)(void *pdata))
530 {
531     struct stdif *nf;
532     cookie_io_functions_t io;
533     char *mode;
534     
535     if(read && write) {
536         mode = "r+";
537     } else if(read) {
538         mode = "r";
539     } else if(write) {
540         mode = "w";
541     } else {
542         errno = EINVAL;
543         return(NULL);
544     }
545     omalloc(nf);
546     *nf = (struct stdif){.read = read, .write = write, .seek = seek, .close = close, .pdata = pdata};
547     io = (cookie_io_functions_t) {
548         .read = read?wrapread:NULL,
549         .write = write?wrapwrite:NULL,
550         .seek = seek?wrapseek:NULL,
551         .close = wrapclose,
552     };
553     return(fopencookie(nf, mode, io));
554 }
555 #elif defined(HAVE_BSD_STDIO)
556 static int wrapread(void *pdata, char *buf, int len)
557 {
558     struct stdif *nf = pdata;
559     
560     return(nf->read(nf->pdata, buf, len));
561 }
562
563 static int wrapwrite(void *pdata, const char *buf, int len)
564 {
565     struct stdif *nf = pdata;
566     
567     return(nf->write(nf->pdata, buf, len));
568 }
569
570 static fpos_t wrapseek(void *pdata, fpos_t pos, int whence)
571 {
572     struct stdif *nf = pdata;
573     
574     return(nf->seek(nf->pdata, pos, whence));
575 }
576
577 static int wrapclose(void *pdata)
578 {
579     struct stdif *nf = pdata;
580     int ret;
581     
582     if(nf->close != NULL)
583         ret = nf->close(nf->pdata);
584     free(nf);
585     return(ret);
586 }
587
588 FILE *funstdio(void *pdata,
589                ssize_t (*read)(void *pdata, void *buf, size_t len),
590                ssize_t (*write)(void *pdata, const void *buf, size_t len),
591                off_t (*seek)(void *pdata, off_t offset, int whence),
592                int (*close)(void *pdata))
593 {
594     struct stdif *nf;
595     
596     omalloc(nf);
597     return(funopen(pdata, read?wrapread:NULL, write:wrapwrite:NULL, seek:wrapseek:NULL, wrapclose));
598 }
599 #else
600 #error "No stdio implementation for this system"
601 #endif