ad28086eaf41b1c2dfb379714479192dbe9354e9
[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     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
516 static int wrapseek(void *pdata, off_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
528 static 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
541 FILE *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)
572 static 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
579 static 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
586 static 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
593 static 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
606 FILE *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