root/cherokee/trunk/cherokee/buffer.c

Revision 1852, 39.6 kB (checked in by alo, 3 weeks ago)

--

Line 
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /* Cherokee
4  *
5  * Authors:
6  *      Alvaro Lopez Ortega <alvaro@alobbs.com>
7  *
8  * Copyright (C) 2001-2008 Alvaro Lopez Ortega
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of version 2 of the GNU General Public
12  * License as published by the Free Software Foundation.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22  * USA
23  */
24
25 #include "common-internal.h"
26 #include "buffer.h"
27
28 #include <string.h>
29 #include <strings.h>
30 #include <ctype.h>
31 #include <stdlib.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <errno.h>
37
38 #include "md5.h"
39 #include "util.h"
40 #include "crc32.h"
41 #include "sha1.h"
42
43 #define ENTRIES "core,buffer"
44
45 #define REALLOC_EXTRA_SIZE     16
46 #define IOS_NUMBUF             64       /* I/O size of digits buffer */
47
48 #define TO_HEX(c)               ((c) > 9 ? (c) + 'a' - 10 : (c) + '0')
49
50
51 /* Implements _new() and _free()
52  */
53 CHEROKEE_ADD_FUNC_NEW  (buffer);
54 CHEROKEE_ADD_FUNC_FREE (buffer);
55
56 ret_t
57 cherokee_buffer_init (cherokee_buffer_t *buf)
58 {
59         buf->buf  = NULL;
60         buf->len  = 0;
61         buf->size = 0;
62
63         return ret_ok;
64 }
65
66 void
67 cherokee_buffer_fake (cherokee_buffer_t *buf, const char *str, cuint_t len)
68 {
69         buf->buf  = (char *)str;
70         buf->len  = len;
71         buf->size = len + 1;
72 }
73
74
75 ret_t
76 cherokee_buffer_mrproper (cherokee_buffer_t *buf)
77 {
78         if (buf->buf) {
79                 free (buf->buf);
80                 buf->buf = NULL;
81         }
82
83         buf->len  = 0;
84         buf->size = 0;
85
86         return ret_ok;
87 }
88
89 void
90 cherokee_buffer_clean (cherokee_buffer_t *buf)
91 {
92         if (buf->buf != NULL)
93                 buf->buf[0] = '\0';
94         buf->len = 0;
95 }
96
97 void
98 cherokee_buffer_swap_buffers (cherokee_buffer_t *buf, cherokee_buffer_t *second)
99 {
100         char    *tmp_buf;
101         cuint_t  tmp_len;
102         cuint_t  tmp_size;
103
104         tmp_buf  = buf->buf;
105         tmp_len  = buf->len;
106         tmp_size = buf->size;
107
108         buf->buf  = second->buf;
109         buf->len  = second->len;
110         buf->size = second->size;
111
112         second->buf = tmp_buf;
113         second->len = tmp_len;
114         second->size = tmp_size;
115 }
116
117 ret_t
118 cherokee_buffer_dup (cherokee_buffer_t *buf, cherokee_buffer_t **dup)
119 {
120         CHEROKEE_NEW_STRUCT(n, buffer);
121
122         n->buf = (char *) malloc(buf->len + 1);
123         if (unlikely (n->buf == NULL)) {
124                 free(n);
125                 return ret_nomem;
126         }
127
128         memcpy (n->buf, buf->buf, buf->len + 1);
129
130         n->len  = buf->len;
131         n->size = buf->len + 1;
132
133         *dup = n;
134         return ret_ok;
135 }
136
137
138 static ret_t
139 realloc_inc_bufsize (cherokee_buffer_t *buf, size_t incsize)
140 {
141         char *pbuf;
142         size_t newsize = buf->size + incsize + REALLOC_EXTRA_SIZE + 1;
143
144         pbuf = (char *) realloc(buf->buf, newsize);
145         if (unlikely (pbuf == NULL))
146                 return ret_nomem;
147         buf->buf = pbuf;
148         buf->size = (int) newsize;
149
150         return ret_ok;
151 }
152
153
154 static ret_t
155 realloc_new_bufsize (cherokee_buffer_t *buf, size_t newsize)
156 {
157         char *pbuf;
158         newsize += REALLOC_EXTRA_SIZE + 1;
159
160         pbuf = (char *) realloc(buf->buf, newsize);
161         if (unlikely (pbuf == NULL))
162                 return ret_nomem;
163         buf->buf = pbuf;
164         buf->size = (int) newsize;
165
166         return ret_ok;
167 }
168
169
170 ret_t
171 cherokee_buffer_add (cherokee_buffer_t *buf, const char *txt, size_t size)
172 {         
173         int free = buf->size - buf->len;
174
175         if (unlikely (size <= 0))
176                 return ret_ok;
177
178         /* Get memory
179          */
180         if ((cuint_t) free < (size+1)) {
181                 if (unlikely (realloc_inc_bufsize(buf, size - free)) != ret_ok)
182                         return ret_nomem;
183         }
184
185         /* Copy
186          */
187         memcpy (buf->buf + buf->len, txt, size);
188
189         buf->len += size;
190         buf->buf[buf->len] = '\0';
191
192         return ret_ok;
193 }
194
195
196 ret_t
197 cherokee_buffer_add_buffer (cherokee_buffer_t *buf, cherokee_buffer_t *buf2)
198 {
199         return cherokee_buffer_add (buf, buf2->buf, buf2->len);
200 }
201
202
203 ret_t
204 cherokee_buffer_add_fsize (cherokee_buffer_t *buf, CST_SIZE size)
205 {
206         ret_t       ret;
207         int         remain;
208         const char  ord[]  = "KMGTPE";
209         const char *o      = ord;
210
211         ret = cherokee_buffer_ensure_size (buf, buf->len + 8);
212         if (unlikely (ret != ret_ok))
213                 return ret;
214
215         if (size < 973)
216                 return cherokee_buffer_add_ulong10 (buf, (culong_t)size);
217
218         do {
219                 remain = (int)(size & 1023);
220                 size >>= 10;
221                 if (size >= 973) {
222                         ++o;
223                         continue;
224                 }
225                 if (size < 9 || (size == 9 && remain < 973)) {
226                         if ((remain = ((remain * 5) + 256) / 512) >= 10)
227                                 ++size, remain = 0;
228                         return cherokee_buffer_add_va_fixed (buf, "%d.%d%c", (int) size, remain, *o);
229                 }
230                 if (remain >= 512)
231                         ++size;
232                 return cherokee_buffer_add_va_fixed (buf, "%3d%c", (int) size, *o);
233         } while (1);
234        
235         return ret_ok;
236 }
237
238
239 ret_t
240 cherokee_buffer_add_long10 (cherokee_buffer_t *buf, clong_t lNum)
241 {
242         culong_t ulNum                 = (culong_t) lNum;
243         cuint_t  flgNeg                = 0;
244         int      newlen                = 0;
245         size_t   i                     = (IOS_NUMBUF - 1);
246         char     szOutBuf[IOS_NUMBUF];
247
248         if (lNum < 0L) {
249                 flgNeg = 1;
250                 ulNum = -ulNum;
251         }
252
253         szOutBuf[i] = '\0';
254
255         /* Convert number to string
256          */
257         do {
258                 szOutBuf[--i] = (char) ((ulNum % 10) + '0');
259         }
260         while ((ulNum /= 10) != 0);
261
262         /* Set sign in any case
263         */
264         szOutBuf[--i] = '-';
265         i += (flgNeg ^ 1);
266
267         /* Verify free space in buffer and if needed then enlarge it.
268         */
269         newlen = buf->len + (int) ((IOS_NUMBUF - 1) - i);
270         if (unlikely ((cuint_t)newlen >= buf->size)) {
271                 if (unlikely (realloc_new_bufsize(buf, newlen)) != ret_ok)
272                         return ret_nomem;
273         }
274
275         /* Copy including '\0'
276          */
277         strcpy (buf->buf + buf->len, &szOutBuf[i]);
278
279         buf->len = newlen;
280         return ret_ok;
281 }
282
283
284 ret_t
285 cherokee_buffer_add_llong10 (cherokee_buffer_t *buf, cllong_t lNum)
286 {
287         cullong_t ulNum                 = (cullong_t) lNum;
288         cuint_t   flgNeg                = 0;
289         int       newlen                = 0;
290         size_t    i                     = (IOS_NUMBUF - 1);
291         char      szOutBuf[IOS_NUMBUF];
292
293         if (lNum < 0L) {
294                 flgNeg = 1;
295                 ulNum = -ulNum;
296         }
297
298         szOutBuf[i] = '\0';
299
300         /* Convert number to string
301          */
302         do {
303                 szOutBuf[--i] = (char) ((ulNum % 10) + '0');
304         }
305         while ((ulNum /= 10) != 0);
306
307         /* Set sign in any case
308         */
309         szOutBuf[--i] = '-';
310         i += (flgNeg ^ 1);
311
312         /* Verify free space in buffer and if needed then enlarge it.
313         */
314         newlen = buf->len + (int) ((IOS_NUMBUF - 1) - i);
315         if (unlikely ((cuint_t)newlen >= buf->size)) {
316                 if (unlikely (realloc_new_bufsize(buf, newlen)) != ret_ok)
317                         return ret_nomem;
318         }
319
320         /* Copy including '\0'
321          */
322         strcpy (buf->buf + buf->len, &szOutBuf[i]);
323
324         buf->len = newlen;
325
326         return ret_ok;
327 }
328
329
330 ret_t
331 cherokee_buffer_add_ulong10 (cherokee_buffer_t *buf, culong_t ulNum)
332 {
333         int     newlen               = 0;
334         size_t  i                    = (IOS_NUMBUF - 1);
335         char    szOutBuf[IOS_NUMBUF];
336
337         szOutBuf[i] = '\0';
338
339         /* Convert number to string
340          */
341         do {
342                 szOutBuf[--i] = (char) ((ulNum % 10) + '0');
343         }
344         while ((ulNum /= 10) != 0);
345
346         /* Verify free space in buffer and if needed then enlarge it.
347         */
348         newlen = buf->len + (int) ((IOS_NUMBUF - 1) - i);
349         if (unlikely ((cuint_t)newlen >= buf->size)) {
350                 if (unlikely (realloc_new_bufsize(buf, newlen)) != ret_ok)
351                         return ret_nomem;
352         }
353
354         /* Copy including '\0'
355          */
356         strcpy (buf->buf + buf->len, &szOutBuf[i]);
357
358         buf->len = newlen;
359
360         return ret_ok;
361 }
362
363
364 ret_t
365 cherokee_buffer_add_ullong10 (cherokee_buffer_t *buf, cullong_t ulNum)
366 {
367         int     newlen               = 0;
368         size_t  i                    = (IOS_NUMBUF - 1);
369         char    szOutBuf[IOS_NUMBUF];
370
371         szOutBuf[i] = '\0';
372
373         /* Convert number to string
374          */
375         do {
376                 szOutBuf[--i] = (char) ((ulNum % 10) + '0');
377         }
378         while ((ulNum /= 10) != 0);
379
380         /* Verify free space in buffer and if needed then enlarge it.
381         */
382         newlen = buf->len + (int) ((IOS_NUMBUF - 1) - i);
383         if (unlikely ((cuint_t)newlen >= buf->size)) {
384                 if (unlikely (realloc_new_bufsize(buf, newlen)) != ret_ok)
385                         return ret_nomem;
386         }
387
388         /* Copy including '\0'
389          */
390         strcpy (buf->buf + buf->len, &szOutBuf[i]);
391
392         buf->len = newlen;
393
394         return ret_ok;
395 }
396
397
398 /*
399 ** Add a number in hexadecimal format to (buf).
400 */
401 ret_t
402 cherokee_buffer_add_ulong16 (cherokee_buffer_t *buf, culong_t ulNum)
403 {
404         size_t  i                     = (IOS_NUMBUF - 1);
405         int     ival                  = 0;
406         int     newlen                = 0;
407         char    szOutBuf[IOS_NUMBUF];
408
409         szOutBuf[i] = '\0';
410
411         /* Convert number to string
412          */
413         do {
414                 ival = (int) (ulNum & 0xF);
415                 szOutBuf[--i] = (char) TO_HEX(ival);
416         }
417         while ((ulNum >>= 4) != 0);
418
419         /* Verify free space in buffer and if needed then enlarge it.
420         */
421         newlen = buf->len + (int) ((IOS_NUMBUF - 1) - i);
422         if (unlikely ((cuint_t)newlen >= buf->size)) {
423                 if (unlikely (realloc_new_bufsize(buf, newlen)) != ret_ok)
424                         return ret_nomem;
425         }
426
427         /* Copy including '\0'
428          */
429         strcpy (buf->buf + buf->len, &szOutBuf[i]);
430
431         buf->len = newlen;
432
433         return ret_ok;
434 }
435
436
437 /*
438 ** Add a number in hexadecimal format to (buf).
439 */
440 ret_t
441 cherokee_buffer_add_ullong16 (cherokee_buffer_t *buf, cullong_t ulNum)
442 {
443         size_t  i                     = (IOS_NUMBUF - 1);
444         int     ival                  = 0;
445         int     newlen                = 0;
446         char    szOutBuf[IOS_NUMBUF];
447
448         szOutBuf[i] = '\0';
449
450         /* Convert number to string
451          */
452         do {
453                 ival = (int) (ulNum & 0xF);
454                 szOutBuf[--i] = (char) TO_HEX(ival);
455         }
456         while ((ulNum >>= 4) != 0);
457
458         /* Verify free space in buffer and if needed then enlarge it.
459         */
460         newlen = buf->len + (int) ((IOS_NUMBUF - 1) - i);
461         if (unlikely ((cuint_t)newlen >= buf->size)) {
462                 if (unlikely (realloc_new_bufsize(buf, newlen)) != ret_ok)
463                         return ret_nomem;
464         }
465
466         /* Copy including '\0'
467          */
468         strcpy (buf->buf + buf->len, &szOutBuf[i]);
469
470         buf->len = newlen;
471
472         return ret_ok;
473 }
474
475
476 ret_t
477 cherokee_buffer_add_va_fixed (cherokee_buffer_t *buf, char *format, ...)
478 {
479         int len;
480         int size = buf->size - buf->len;        /* final '\0' is always available */
481         va_list ap;
482
483         /* Test for minimum buffer size.
484          */
485         if (size < 1)
486                 return ret_error;
487
488         /* Format the string into the buffer.
489          * NOTE: len does NOT include '\0', size includes '\0' (len + 1)
490          */
491         va_start (ap, format);
492         len = vsnprintf (buf->buf + buf->len, size, format, ap);
493         va_end (ap);
494
495         if (unlikely (len < 0))
496                 return ret_error;
497
498         /* Don't expand buffer if there is not enough space.
499          */
500         if (unlikely ( len >= size ))
501                 return ret_error;
502
503         buf->len += len;
504         return ret_ok;
505 }
506
507
508 ret_t
509 cherokee_buffer_add_va_list (cherokee_buffer_t *buf, char *format, va_list args)
510 {
511         int len;
512         int estimation;
513         int size;
514         ret_t ret;
515         va_list args2;
516
517         va_copy (args2, args);
518
519         /* Estimate resulting formatted string length.
520          */
521         estimation = cherokee_estimate_va_length (format, args);
522         if (unlikely (estimation) < 0) {
523                 PRINT_ERROR ("  -> '%s', esti=%d ( < 0)\n", format, estimation);
524                 return ret_error;
525         }
526
527         /* Ensure enough size for buffer.
528          */
529         ret = cherokee_buffer_ensure_size (buf, buf->len + estimation + 2);
530         if (ret != ret_ok) {
531                 PRINT_ERROR ("  -> '%s', esti=%d ensure_size=%d failed !\n", format, estimation, buf->len + estimation + 2);
532                 return ret;
533         }
534
535         /* Format the string into the buffer.
536          * NOTE: len does NOT include '\0', size includes '\0' (len + 1)
537          */
538         size = buf->size - buf->len;
539         if (size < 1) {
540                 PRINT_ERROR ("  -> '%s', esti=%d size=%d ( < 1)!\n", format, estimation, size);
541                 return ret_error;
542         }
543         len = vsnprintf (buf->buf + buf->len, size, format, args2);
544
545 #if 0
546         if (estimation < len)
547                 PRINT_ERROR ("  -> '%s' -> '%s', esti=%d real=%d size=%d\n",
548                              format, buf->buf + buf->len, estimation, len, size);
549 #endif
550
551         if (unlikely (len < 0))
552                 return ret_error;
553
554         /* At this point buf-size is always greater than buf-len, thus size > 0.
555          */
556         if (len >= size) {
557                 PRINT_ERROR ("Failed estimation=%d, needed=%d available size=%d: %s\n",
558                              estimation, len, size, format);
559
560                 cherokee_buffer_ensure_size (buf, buf->len + len + 2);
561                 size = buf->size - buf->len;
562                 len = vsnprintf (buf->buf + buf->len, size, format, args2);
563
564                 if (unlikely (len < 0))
565                         return ret_error;
566
567                 if (unlikely (len >= size))
568                         return ret_error;
569         }
570
571         buf->len += len;
572         return ret_ok;
573 }
574
575
576 ret_t
577 cherokee_buffer_add_va (cherokee_buffer_t *buf, char *format, ...)
578 {
579         ret_t   ret;
580         va_list ap;
581
582         va_start (ap, format);
583         ret = cherokee_buffer_add_va_list (buf, format, ap);
584         va_end (ap);
585
586         return ret;
587 }
588
589
590 ret_t
591 cherokee_buffer_add_char (cherokee_buffer_t *buf, char c)
592 {         
593         /* Add char (fast path)
594          */
595         if (likely (buf->len + 1 < buf->size)) {
596                 buf->buf[buf->len++] = c;
597                 buf->buf[buf->len] = '\0';
598                 return ret_ok;
599         }
600
601         /* Get memory
602          */
603         if (unlikely (realloc_inc_bufsize(buf, 1)) != ret_ok)
604                 return ret_nomem;
605
606         /* Add char
607          */
608         buf->buf[buf->len++] = c;
609         buf->buf[buf->len] = '\0';
610
611         return ret_ok;
612 }
613
614
615 ret_t
616 cherokee_buffer_add_char_n (cherokee_buffer_t *buf, char c, int num)
617 {
618         int free = buf->size - buf->len;
619
620         if (num <= 0)
621                 return ret_ok;
622
623         /* Get memory
624          */
625         if (free < (num+1)) {
626                 if (unlikely (realloc_inc_bufsize(buf, num - free)) != ret_ok)
627                         return ret_nomem;
628         }
629
630         memset (buf->buf+buf->len, c, num);
631         buf->len += num;
632         buf->buf[buf->len] = '\0';
633
634         return ret_ok;
635 }
636
637
638 ret_t
639 cherokee_buffer_prepend (cherokee_buffer_t *buf, char *txt, size_t size)
640 {
641         int free = buf->size - buf->len;
642
643         /* Get memory
644          */
645         if ((cuint_t) free < (size+1)) {
646                 if (unlikely (realloc_inc_bufsize(buf, size - free)) != ret_ok)
647                         return ret_nomem;
648         }
649
650         memmove (buf->buf+size, buf->buf, buf->len);
651
652         memcpy (buf->buf, txt, size);
653         buf->len += size;
654         buf->buf[buf->len] = '\0';
655  
656         return ret_ok;
657 }
658
659
660 int   
661 cherokee_buffer_is_ending (cherokee_buffer_t *buf, char c)
662 {
663         if (cherokee_buffer_is_empty(buf))
664                 return 0;
665
666         return (buf->buf[buf->len - 1] == c);
667 }
668
669
670 ret_t
671 cherokee_buffer_move_to_begin (cherokee_buffer_t *buf, cuint_t pos)
672 {
673         if (pos >= buf->len) {
674                 cherokee_buffer_clean(buf);
675                 return ret_ok;
676         }
677
678         /* At this point: 0 < pos < buf->len
679          */
680         memmove (buf->buf, buf->buf+pos, (buf->len - pos) + 1);
681         buf->len -= pos;
682
683 #if 0
684         if (strlen(buf->buf) != buf->len) {
685                 PRINT_ERROR ("ERROR: cherokee_buffer_move_to_begin(): strlen=%d buf->len=%d\n",
686                              strlen(buf->buf), buf->len);
687         }
688 #endif
689
690         return ret_ok;
691 }
692
693
694 /*
695  * Ensure there is enough (addlen) free space left in the buffer.
696  */
697 ret_t
698 cherokee_buffer_ensure_addlen (cherokee_buffer_t *buf, size_t addlen)
699 {
700         if (buf->len + addlen < buf->size)
701                 return ret_ok;
702
703         return cherokee_buffer_ensure_size (buf, ((size_t)buf->len + addlen + 1));
704 }
705
706
707 ret_t
708 cherokee_buffer_ensure_size (cherokee_buffer_t *buf, size_t size)
709 {
710         char *pbuf;
711
712         /* Maybe it doesn't need it
713          * if buf->size == 0 and size == 0 then buf can be NULL.
714          */
715         if (size <= buf->size)
716                 return ret_ok;
717
718         /* If it is a new buffer, take memory and return
719          */
720         if (buf->buf == NULL) {
721                 buf->buf = (char *) malloc (size);
722                 if (unlikely (buf->buf == NULL))
723                         return ret_nomem;
724                 buf->size = size;
725                 return ret_ok;
726         }
727
728         /* It already has memory, but it needs more..
729          */
730         pbuf = (char *) realloc(buf->buf, size);
731         if (unlikely (pbuf == NULL))
732                 return ret_nomem;
733
734         buf->buf = pbuf;
735         buf->size = size;
736
737         return ret_ok;
738 }
739
740
741 ret_t
742 cherokee_buffer_drop_ending (cherokee_buffer_t *buffer, cuint_t num_chars)
743 {
744         int num;
745
746         if (buffer->buf == NULL) {
747                 return ret_ok;
748         }
749
750         num = MIN (num_chars, buffer->len);
751
752         buffer->buf[buffer->len - num] = '\0';
753         buffer->len -= num;
754
755         return ret_ok;
756 }
757
758
759 ret_t
760 cherokee_buffer_swap_chars (cherokee_buffer_t *buffer, char a, char b)
761 {
762         cuint_t i;
763
764         if (buffer->buf == NULL) {
765                 return ret_ok;
766         }
767
768         for (i=0; i < buffer->len; i++) {
769                 if (buffer->buf[i] == a) {
770                         buffer->buf[i] = b;
771                 }
772         }
773
774         return ret_ok;
775 }
776
777
778 ret_t
779 cherokee_buffer_remove_dups (cherokee_buffer_t *buffer, char c)
780 {
781         char       *a      = buffer->buf;
782         const char *end    = buffer->buf + buffer->len;
783         cuint_t     offset = 0;
784
785         if (buffer->len < 2) {
786                 return ret_ok;
787         }
788
789         do {
790                 if ((*a == c) && (a[offset+1] == c)) {
791                         offset++;
792                         continue;
793                 }
794                
795                 a++;
796                 *a = a[offset];
797
798         } while ((a < end) && (offset+1 < buffer->len));
799
800         buffer->len -= offset;
801         buffer->buf[buffer->len] = '\0';
802
803         return ret_ok;
804 }
805
806
807 ret_t
808 cherokee_buffer_remove_string (cherokee_buffer_t *buf, char *string, int string_len)
809 {
810         char *tmp;
811         int   offset;
812
813         if (buf->len <= 0) {
814                 return ret_ok;
815         }
816
817         while ((tmp = strstr (buf->buf, string)) != NULL) {
818                 offset = tmp - buf->buf;
819                 memmove (tmp, tmp+string_len, buf->len - (offset+string_len) +1);
820                 buf->len -= string_len;
821         }
822
823         return ret_ok;
824 }
825
826
827 ret_t
828 cherokee_buffer_remove_chunk (cherokee_buffer_t *buf, cuint_t from, cuint_t len)
829 {
830         char *end;
831         char *begin;
832
833         if (len == buf->len) {
834                 cherokee_buffer_clean (buf);
835                 return ret_ok;
836         }
837
838         begin = buf->buf + from;
839         end   = begin + len;
840
841         memmove (begin, end, ((buf->buf + buf->len) - end) + 1);
842         buf->len -= len;
843
844         return ret_ok;
845 }
846
847
848 cint_t
849 cherokee_buffer_cmp_buf (cherokee_buffer_t *A, cherokee_buffer_t *B)
850 {
851         if (A->len > B->len)
852                 return A->len - B->len;
853         else if (B->len > A->len)
854                 return - (B->len - A->len);
855
856         return strncmp (A->buf, B->buf, B->len);
857 }
858
859 cint_t
860 cherokee_buffer_cmp (cherokee_buffer_t *buf, char *txt, cuint_t txt_len)
861 {
862         cherokee_buffer_t tmp;
863         cherokee_buffer_fake (&tmp, txt, txt_len);
864         return cherokee_buffer_cmp_buf (buf, &tmp);
865 }
866
867
868 cint_t
869 cherokee_buffer_case_cmp_buf (cherokee_buffer_t *A, cherokee_buffer_t *B)
870 {
871         if (A->len > B->len)
872                 return A->len - B->len;
873         else if (B->len > A->len)
874                 return - (B->len - A->len);
875
876         return strncasecmp (A->buf, B->buf, B->len);
877 }
878
879 cint_t
880 cherokee_buffer_case_cmp (cherokee_buffer_t *buf, char *txt, cuint_t txt_len)
881 {
882         cherokee_buffer_t tmp;
883         cherokee_buffer_fake (&tmp, txt, txt_len);
884         return cherokee_buffer_case_cmp_buf (buf, &tmp);
885 }
886
887
888 size_t
889 cherokee_buffer_cnt_spn (cherokee_buffer_t *buf, cuint_t offset, char *str)
890 {
891         if (unlikely ((buf->buf == NULL) || (buf->len <= offset)))
892                 return 0;
893
894         return strspn (buf->buf + offset, str);
895 }
896
897
898 size_t
899 cherokee_buffer_cnt_cspn (cherokee_buffer_t *buf, cuint_t offset, char *str)
900 {
901         if (unlikely ((buf->buf == NULL) || (buf->len <= offset)))
902                 return 0;
903
904         return strcspn (buf->buf + offset, str);
905 }
906
907
908 crc_t
909 cherokee_buffer_crc32 (cherokee_buffer_t *buf)
910 {
911         return crc32_sz (buf->buf, buf->len);
912 }
913
914
915 ret_t
916 cherokee_buffer_read_file (cherokee_buffer_t *buf, char *filename)
917 {
918         int r, f;
919         ret_t ret;
920         struct stat info;
921
922         /* Stat() the file
923          */
924         r = stat (filename, &info);
925         if (r != 0)
926                 return ret_error;
927
928         /* Is a regular file?
929          */
930         if (S_ISREG(info.st_mode) == 0)
931                 return ret_error;
932
933         /* Maybe get memory
934          */
935         ret = cherokee_buffer_ensure_size (buf, buf->len + info.st_size + 1);
936         if (unlikely (ret != ret_ok))
937                 return ret;
938
939         /* Open the file
940          */
941         f = open (filename, CHE_O_READ);
942         if (f < 0)
943                 return ret_error;
944
945         /* Read the content
946          */
947         r = read (f, buf->buf + buf->len, info.st_size);
948         if (r < 0) {
949                 buf->buf[buf->len] = '\0';
950
951                 close(f);
952                 return ret_error;
953         }
954
955         /* Close it and exit
956          */
957         close(f);
958
959         buf->len += r;
960         buf->buf[buf->len] = '\0';
961
962         return ret_ok;
963 }
964
965
966 ret_t
967 cherokee_buffer_read_from_fd (cherokee_buffer_t *buf, int fd, size_t size, size_t *ret_size)
968 {
969         int  len;
970
971         /* Ensure there is enough space in buffer
972          * NOTE: usually the caller should have already allocated
973          *       enough space for the buffer, so this is a security measure
974          */
975         cherokee_buffer_ensure_addlen(buf, size);
976
977         /* Read data at the end of the buffer
978          */
979         len = read (fd, &(buf->buf[buf->len]), size);
980         if (len < 0) {
981                 /* On error
982                  */
983                 switch (errno) {
984                 case EINTR:
985                 case EAGAIN:
986 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
987                 case EWOULDBLOCK:
988 #endif
989                         return ret_eagain;
990                 case EPIPE:
991                 case EBADF:
992                 case ECONNRESET:
993                         return ret_eof;
994                 case EIO:
995                         return ret_error;
996                 }
997
998                 PRINT_ERRNO (errno, "read(%d, %u,..): '${errno}'", fd, size);
999                 return ret_error;
1000         }
1001         else if (len == 0) {
1002                 /* On EOF
1003                  */
1004                 return ret_eof;
1005         }
1006
1007         /* Add read length, terminate buffer and return
1008          */
1009         *ret_size = len;
1010         buf->len += len;
1011
1012         buf->buf[buf->len] = '\0';
1013
1014         return ret_ok;
1015 }
1016
1017
1018 ret_t
1019 cherokee_buffer_multiply (cherokee_buffer_t *buf, int num)
1020 {
1021         int i, initial_size;
1022
1023         initial_size = buf->len;
1024         cherokee_buffer_ensure_size (buf, buf->len * num + 1);
1025
1026         for (i=0; i<num; i++) {
1027                 cherokee_buffer_add (buf, buf->buf, initial_size);
1028         }
1029
1030         return ret_ok;
1031 }
1032
1033
1034 ret_t
1035 cherokee_buffer_print_debug (cherokee_buffer_t *buf, int len)
1036 {
1037         int            i, length;
1038         char           text[67];
1039         unsigned char  tmp;
1040         char          *hex_text   = NULL;
1041         char          *ascii_text = NULL;
1042
1043         if ((len == -1) || (buf->len <= (cuint_t)len)) {
1044                 length = buf->len;
1045         } else {
1046                 length = len;
1047         }
1048
1049         if (length <= 0)
1050                 return ret_ok;
1051
1052         memset(text, 0, 67);
1053         for (i=0; i < length; i++) {
1054                 if (i%16 == 0) {
1055                         if (text[0] != 0){
1056                                 printf ("%s%s", text, CRLF);
1057                         }
1058                         sprintf (text, "%08x%57c", i, ' ');
1059                         hex_text = text + 9;
1060                         ascii_text = text + 49;
1061                 }
1062
1063                 tmp = buf->buf[i];
1064                 sprintf (hex_text, "%02x",  tmp & 0xFF);
1065                 hex_text += 2;
1066                 *hex_text = ' ';
1067                 if ((i+1)%2 == 0) {
1068                         hex_text++;
1069                 }
1070
1071                 if ((tmp > ' ') &&  (tmp < 128))
1072                         *ascii_text = tmp;
1073                 else
1074                         *ascii_text = '.';
1075                 ascii_text += 1;
1076         }
1077         printf ("%s%s", text, CRLF);
1078         fflush(stdout);
1079
1080         return ret_ok;
1081 }
1082
1083
1084 /*
1085  * Unescape a string that may have escaped characters %xx
1086  * where xx is the hexadecimal number equal to the character ascii value.
1087  */
1088 ret_t
1089 cherokee_buffer_unescape_uri (cherokee_buffer_t *buffer)
1090 {
1091         static const char hex2dec_tab[256] = {
1092                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 00-0F */
1093                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 10-1F */
1094                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 20-2F */
1095                 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,  /* 30-3F */
1096                 0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 40-4F */
1097                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 50-5F */
1098                 0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 60-6F */
1099                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 70-7F */
1100                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 80-8F */
1101                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 90-9F */
1102                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* A0-AF */
1103                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* B0-BF */
1104                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* C0-CF */
1105                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* D0-DF */
1106                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* E0-EF */
1107                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0   /* F0-FF */
1108         };
1109
1110         char *psrc;
1111         char *ptgt;
1112         int   len;
1113
1114 #define hex2dec_m(c)       ( (int) hex2dec_tab[ ( (unsigned char )(c) ) ] )
1115 #define hex2dec_m2(c1, c2) ( hex2dec_m(c1) * 16 + hex2dec_m(c2) )
1116
1117         TRACE(ENTRIES, "Prev: %s\n", buffer->buf);
1118
1119         if (unlikely (buffer->buf == NULL))
1120                 return ret_error;
1121
1122         /* Verify string termination,
1123          * we assume there are no '\0' inside buffer.
1124          */
1125         if (buffer->buf[buffer->len] != '\0')
1126                 buffer->buf[buffer->len]  = '\0';
1127
1128         /* Verify if unescaping is needed.
1129          */
1130         if ((psrc = strchr (buffer->buf, '%')) == NULL)
1131                 return ret_ok;
1132
1133         /* Yes, unescape string.
1134          */
1135         len = buffer->len;
1136         for (ptgt = psrc; *psrc != '\0'; ++ptgt, ++psrc) {
1137                 if (psrc[0] != '%' ||
1138                     !isxdigit(psrc[1]) || !isxdigit(psrc[2])) {
1139                         *ptgt = *psrc;
1140                         continue;
1141                 }
1142                 /* Escape sequence %xx
1143                  */
1144                 if (likely ((*ptgt = hex2dec_m2(psrc[1], psrc[2])) != '\0')) {
1145                         psrc += 2;
1146                         len  -= 2;
1147                         continue;
1148                 }
1149                 /* Replace null bytes (%00) with
1150                  * spaces, to prevent attacks
1151                  */
1152                 *ptgt = ' ';
1153                 psrc += 2;
1154                 len  -= 2;
1155         }
1156         *ptgt = '\0';
1157         buffer->len = len;
1158
1159 #undef hex2dec_m2
1160 #undef hex2dec_m
1161
1162         TRACE(ENTRIES, "Post: %s\n", buffer->buf);
1163         return ret_ok;
1164 }
1165
1166
1167 ret_t
1168 cherokee_buffer_add_escape_html (cherokee_buffer_t *buf, cherokee_buffer_t *src)
1169 {
1170         ret_t   ret;
1171         size_t  len0 = 0;
1172         size_t  extra = 0;
1173         char   *p0, *p1, *p2;
1174
1175         /* Verify that source string is not empty.
1176          */
1177         if (unlikely (src->buf == NULL))
1178                 return ret_error;
1179
1180         /* Verify string termination,
1181          * we assume there are no '\0' inside buffer.
1182          */
1183         if (src->buf[src->len] != '\0')
1184