]> code.citadel.org Git - citadel.git/blob - libcitadel/lib/stringbuf.c
* move StrBufNum_tokens and StrBufPlain to more apropriate places
[citadel.git] / libcitadel / lib / stringbuf.c
1 #include <ctype.h>
2 #include <errno.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <string.h>
6 #include <stdio.h>
7 #include <sys/select.h>
8 #include <fcntl.h>
9 #define SHOW_ME_VAPPEND_PRINTF
10 #include <stdarg.h>
11 #include "libcitadel.h"
12
13
14 /**
15  * Private Structure for the Stringbuffer
16  */
17 struct StrBuf {
18         char *buf;         /**< the pointer to the dynamic buffer */
19         long BufSize;      /**< how many spcae do we optain */
20         long BufUsed;      /**< Number of Chars used excluding the trailing \0 */
21         int ConstBuf;      /**< are we just a wrapper arround a static buffer and musn't we be changed? */
22 };
23
24
25 /** 
26  * \Brief Cast operator to Plain String 
27  * \param Str the string we want to get the c-string representation for
28  * \returns the Pointer to the Content. Don't mess with it!
29  */
30 inline const char *ChrPtr(const StrBuf *Str)
31 {
32         if (Str == NULL)
33                 return "";
34         return Str->buf;
35 }
36
37 /**
38  * \brief since we know strlen()'s result, provide it here.
39  * \param Str the string to return the length to
40  * \returns contentlength of the buffer
41  */
42 inline int StrLength(const StrBuf *Str)
43 {
44         return (Str != NULL) ? Str->BufUsed : 0;
45 }
46
47 /**
48  * Allocate a new buffer with default buffer size
49  * \returns the new stringbuffer
50  */
51 StrBuf* NewStrBuf(void)
52 {
53         StrBuf *NewBuf;
54
55         NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
56         NewBuf->buf = (char*) malloc(SIZ);
57         NewBuf->buf[0] = '\0';
58         NewBuf->BufSize = SIZ;
59         NewBuf->BufUsed = 0;
60         NewBuf->ConstBuf = 0;
61         return NewBuf;
62 }
63
64 /** 
65  * \brief Copy Constructor; returns a duplicate of CopyMe
66  * \params CopyMe Buffer to faxmilate
67  * \returns the new stringbuffer
68  */
69 StrBuf* NewStrBufDup(const StrBuf *CopyMe)
70 {
71         StrBuf *NewBuf;
72         
73         if (CopyMe == NULL)
74                 return NewStrBuf();
75
76         NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
77         NewBuf->buf = (char*) malloc(CopyMe->BufSize);
78         memcpy(NewBuf->buf, CopyMe->buf, CopyMe->BufUsed + 1);
79         NewBuf->BufUsed = CopyMe->BufUsed;
80         NewBuf->BufSize = CopyMe->BufSize;
81         NewBuf->ConstBuf = 0;
82         return NewBuf;
83 }
84
85 /**
86  * \brief create a new Buffer using an existing c-string
87  * this function should also be used if you want to pre-suggest
88  * the buffer size to allocate in conjunction with ptr == NULL
89  * \param ptr the c-string to copy; may be NULL to create a blank instance
90  * \param nChars How many chars should we copy; -1 if we should measure the length ourselves
91  * \returns the new stringbuffer
92  */
93 StrBuf* NewStrBufPlain(const char* ptr, int nChars)
94 {
95         StrBuf *NewBuf;
96         size_t Siz = SIZ;
97         size_t CopySize;
98
99         NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
100         if (nChars < 0)
101                 CopySize = strlen((ptr != NULL)?ptr:"");
102         else
103                 CopySize = nChars;
104
105         while (Siz <= CopySize)
106                 Siz *= 2;
107
108         NewBuf->buf = (char*) malloc(Siz);
109         NewBuf->BufSize = Siz;
110         if (ptr != NULL) {
111                 memcpy(NewBuf->buf, ptr, CopySize);
112                 NewBuf->buf[CopySize] = '\0';
113                 NewBuf->BufUsed = CopySize;
114         }
115         else {
116                 NewBuf->buf[0] = '\0';
117                 NewBuf->BufUsed = 0;
118         }
119         NewBuf->ConstBuf = 0;
120         return NewBuf;
121 }
122
123 /**
124  * \brief Set an existing buffer from a c-string
125  * \param ptr c-string to put into 
126  * \param nChars set to -1 if we should work 0-terminated
127  * \returns the new length of the string
128  */
129 int StrBufPlain(StrBuf *Buf, const char* ptr, int nChars)
130 {
131         size_t Siz = Buf->BufSize;
132         size_t CopySize;
133
134         if (nChars < 0)
135                 CopySize = strlen(ptr);
136         else
137                 CopySize = nChars;
138
139         while (Siz <= CopySize)
140                 Siz *= 2;
141
142         if (Siz != Buf->BufSize)
143                 IncreaseBuf(Buf, 0, Siz);
144         memcpy(Buf->buf, ptr, CopySize);
145         Buf->buf[CopySize] = '\0';
146         Buf->BufUsed = CopySize;
147         Buf->ConstBuf = 0;
148         return CopySize;
149 }
150
151
152 /**
153  * \brief use strbuf as wrapper for a string constant for easy handling
154  * \param StringConstant a string to wrap
155  * \param SizeOfConstant should be sizeof(StringConstant)-1
156  */
157 StrBuf* _NewConstStrBuf(const char* StringConstant, size_t SizeOfStrConstant)
158 {
159         StrBuf *NewBuf;
160
161         NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
162         NewBuf->buf = (char*) StringConstant;
163         NewBuf->BufSize = SizeOfStrConstant;
164         NewBuf->BufUsed = SizeOfStrConstant;
165         NewBuf->ConstBuf = 1;
166         return NewBuf;
167 }
168
169 /**
170  * \brief local utility function to resize the buffer
171  * \param Buf the buffer whichs storage we should increase
172  * \param KeepOriginal should we copy the original buffer or just start over with a new one
173  * \param DestSize what should fit in after?
174  */
175 static int IncreaseBuf(StrBuf *Buf, int KeepOriginal, int DestSize)
176 {
177         char *NewBuf;
178         size_t NewSize = Buf->BufSize * 2;
179
180         if (Buf->ConstBuf)
181                 return -1;
182                 
183         if (DestSize > 0)
184                 while (NewSize < DestSize)
185                         NewSize *= 2;
186
187         NewBuf= (char*) malloc(NewSize);
188         if (KeepOriginal && (Buf->BufUsed > 0))
189         {
190                 memcpy(NewBuf, Buf->buf, Buf->BufUsed);
191         }
192         else
193         {
194                 NewBuf[0] = '\0';
195                 Buf->BufUsed = 0;
196         }
197         free (Buf->buf);
198         Buf->buf = NewBuf;
199         Buf->BufSize *= 2;
200         return Buf->BufSize;
201 }
202
203 /**
204  * \brief flush the content of a Buf; keep its struct
205  * \param buf Buffer to flush
206  */
207 int FlushStrBuf(StrBuf *buf)
208 {
209         if (buf->ConstBuf)
210                 return -1;       
211         buf->buf[0] ='\0';
212         buf->BufUsed = 0;
213         return 0;
214 }
215
216 /**
217  * \brief Release a Buffer
218  * Its a double pointer, so it can NULL your pointer
219  * so fancy SIG11 appear instead of random results
220  * \param FreeMe Pointer Pointer to the buffer to free
221  */
222 void FreeStrBuf (StrBuf **FreeMe)
223 {
224         if (*FreeMe == NULL)
225                 return;
226         if (!(*FreeMe)->ConstBuf) 
227                 free((*FreeMe)->buf);
228         free(*FreeMe);
229         *FreeMe = NULL;
230 }
231
232 /**
233  * \brief Release the buffer
234  * If you want put your StrBuf into a Hash, use this as Destructor.
235  * \param VFreeMe untyped pointer to a StrBuf. be shure to do the right thing [TM]
236  */
237 void HFreeStrBuf (void *VFreeMe)
238 {
239         StrBuf *FreeMe = (StrBuf*)VFreeMe;
240         if (FreeMe == NULL)
241                 return;
242         if (!FreeMe->ConstBuf) 
243                 free(FreeMe->buf);
244         free(FreeMe);
245 }
246
247 /**
248  * \brief Wrapper around atol
249  */
250 long StrTol(const StrBuf *Buf)
251 {
252         if(Buf->BufUsed > 0)
253                 return atol(Buf->buf);
254         else
255                 return 0;
256 }
257
258 /**
259  * \brief Wrapper around atoi
260  */
261 int StrToi(const StrBuf *Buf)
262 {
263         if(Buf->BufUsed > 0)
264                 return atoi(Buf->buf);
265         else
266                 return 0;
267 }
268
269 /**
270  * \brief modifies a Single char of the Buf
271  * You can point to it via char* or a zero-based integer
272  * \param ptr char* to zero; use NULL if unused
273  * \param nThChar zero based pointer into the string; use -1 if unused
274  * \param PeekValue The Character to place into the position
275  */
276 long StrBufPeek(StrBuf *Buf, const char* ptr, long nThChar, char PeekValue)
277 {
278         if (Buf == NULL)
279                 return -1;
280         if (ptr != NULL)
281                 nThChar = ptr - Buf->buf;
282         if ((nThChar < 0) || (nThChar > Buf->BufUsed))
283                 return -1;
284         Buf->buf[nThChar] = PeekValue;
285         return nThChar;
286 }
287
288 /**
289  * \brief Append a StringBuffer to the buffer
290  * \param Buf Buffer to modify
291  * \param AppendBuf Buffer to copy at the end of our buffer
292  * \param Offset Should we start copying from an offset?
293  */
294 void StrBufAppendBuf(StrBuf *Buf, const StrBuf *AppendBuf, size_t Offset)
295 {
296         if ((AppendBuf == NULL) || (Buf == NULL))
297                 return;
298
299         if (Buf->BufSize - Offset < AppendBuf->BufUsed + Buf->BufUsed)
300                 IncreaseBuf(Buf, 
301                             (Buf->BufUsed > 0), 
302                             AppendBuf->BufUsed + Buf->BufUsed);
303
304         memcpy(Buf->buf + Buf->BufUsed, 
305                AppendBuf->buf + Offset, 
306                AppendBuf->BufUsed - Offset);
307         Buf->BufUsed += AppendBuf->BufUsed - Offset;
308         Buf->buf[Buf->BufUsed] = '\0';
309 }
310
311
312 /**
313  * \brief Append a C-String to the buffer
314  * \param Buf Buffer to modify
315  * \param AppendBuf Buffer to copy at the end of our buffer
316  * \param AppendSize number of bytes to copy; set to -1 if we should count it in advance
317  * \param Offset Should we start copying from an offset?
318  */
319 void StrBufAppendBufPlain(StrBuf *Buf, const char *AppendBuf, long AppendSize, size_t Offset)
320 {
321         long aps;
322
323         if ((AppendBuf == NULL) || (Buf == NULL))
324                 return;
325
326         if (AppendSize < 0 )
327                 aps = strlen(AppendBuf + Offset);
328         else
329                 aps = AppendSize - Offset;
330
331         if (Buf->BufSize < Buf->BufUsed + aps)
332                 IncreaseBuf(Buf, (Buf->BufUsed > 0), Buf->BufUsed + aps);
333
334         memcpy(Buf->buf + Buf->BufUsed, 
335                AppendBuf + Offset, 
336                aps);
337         Buf->BufUsed += aps;
338         Buf->buf[Buf->BufUsed] = '\0';
339 }
340
341
342 /** 
343  * \brief Escape a string for feeding out as a URL while appending it to a Buffer
344  * \param outbuf the output buffer
345  * \param oblen the size of outbuf to sanitize
346  * \param strbuf the input buffer
347  */
348 void StrBufUrlescAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn)
349 {
350         const char *pch, *pche;
351         char *pt, *pte;
352         int b, c, len;
353         const char ec[] = " +#&;`'|*?-~<>^()[]{}/$\"\\";
354         int eclen = sizeof(ec) -1;
355
356         if (((In == NULL) && (PlainIn == NULL)) || (OutBuf == NULL) )
357                 return;
358         if (PlainIn != NULL) {
359                 len = strlen(PlainIn);
360                 pch = PlainIn;
361                 pche = pch + len;
362         }
363         else {
364                 pch = In->buf;
365                 pche = pch + In->BufUsed;
366                 len = In->BufUsed;
367         }
368
369         if (len == 0) 
370                 return;
371
372         pt = OutBuf->buf + OutBuf->BufUsed;
373         pte = OutBuf->buf + OutBuf->BufSize - 4; /**< we max append 3 chars at once plus the \0 */
374
375         while (pch < pche) {
376                 if (pt >= pte) {
377                         IncreaseBuf(OutBuf, 1, -1);
378                         pte = OutBuf->buf + OutBuf->BufSize - 4; /**< we max append 3 chars at once plus the \0 */
379                         pt = OutBuf->buf + OutBuf->BufUsed;
380                 }
381                 
382                 c = 0;
383                 for (b = 0; b < eclen; ++b) {
384                         if (*pch == ec[b]) {
385                                 c = 1;
386                                 b += eclen;
387                         }
388                 }
389                 if (c == 1) {
390                         sprintf(pt,"%%%02X", *pch);
391                         pt += 3;
392                         OutBuf->BufUsed += 3;
393                         pch ++;
394                 }
395                 else {
396                         *(pt++) = *(pch++);
397                         OutBuf->BufUsed++;
398                 }
399         }
400         *pt = '\0';
401 }
402
403 /*
404  * \brief Append a string, escaping characters which have meaning in HTML.  
405  *
406  * \param Target        target buffer
407  * \param Source        source buffer; set to NULL if you just have a C-String
408  * \param PlainIn       Plain-C string to append; set to NULL if unused
409  * \param nbsp          If nonzero, spaces are converted to non-breaking spaces.
410  * \param nolinebreaks  if set, linebreaks are removed from the string.
411  */
412 long StrEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn, int nbsp, int nolinebreaks)
413 {
414         const char *aptr, *eiptr;
415         char *bptr, *eptr;
416         long len;
417
418         if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
419                 return -1;
420
421         if (PlainIn != NULL) {
422                 aptr = PlainIn;
423                 len = strlen(PlainIn);
424                 eiptr = aptr + len;
425         }
426         else {
427                 aptr = Source->buf;
428                 eiptr = aptr + Source->BufUsed;
429                 len = Source->BufUsed;
430         }
431
432         if (len == 0) 
433                 return -1;
434
435         bptr = Target->buf + Target->BufUsed;
436         eptr = Target->buf + Target->BufSize - 6; /* our biggest unit to put in...  */
437
438         while (aptr < eiptr){
439                 if(bptr >= eptr) {
440                         IncreaseBuf(Target, 1, -1);
441                         eptr = Target->buf + Target->BufSize - 6; 
442                         bptr = Target->buf + Target->BufUsed;
443                 }
444                 if (*aptr == '<') {
445                         memcpy(bptr, "&lt;", 4);
446                         bptr += 4;
447                         Target->BufUsed += 4;
448                 }
449                 else if (*aptr == '>') {
450                         memcpy(bptr, "&gt;", 4);
451                         bptr += 4;
452                         Target->BufUsed += 4;
453                 }
454                 else if (*aptr == '&') {
455                         memcpy(bptr, "&amp;", 5);
456                         bptr += 5;
457                         Target->BufUsed += 5;
458                 }
459                 else if (*aptr == '\"') {
460                         memcpy(bptr, "&quot;", 6);
461                         bptr += 6;
462                         Target->BufUsed += 6;
463                 }
464                 else if (*aptr == '\'') {
465                         memcpy(bptr, "&#39;", 5);
466                         bptr += 5;
467                         Target->BufUsed += 5;
468                 }
469                 else if (*aptr == LB) {
470                         *bptr = '<';
471                         bptr ++;
472                         Target->BufUsed ++;
473                 }
474                 else if (*aptr == RB) {
475                         *bptr = '>';
476                         bptr ++;
477                         Target->BufUsed ++;
478                 }
479                 else if (*aptr == QU) {
480                         *bptr ='"';
481                         bptr ++;
482                         Target->BufUsed ++;
483                 }
484                 else if ((*aptr == 32) && (nbsp == 1)) {
485                         memcpy(bptr, "&nbsp;", 6);
486                         bptr += 6;
487                         Target->BufUsed += 6;
488                 }
489                 else if ((*aptr == '\n') && (nolinebreaks)) {
490                         *bptr='\0';     /* nothing */
491                 }
492                 else if ((*aptr == '\r') && (nolinebreaks)) {
493                         *bptr='\0';     /* nothing */
494                 }
495                 else{
496                         *bptr = *aptr;
497                         bptr++;
498                         Target->BufUsed ++;
499                 }
500                 aptr ++;
501         }
502         *bptr = '\0';
503         if ((bptr = eptr - 1 ) && !IsEmptyStr(aptr) )
504                 return -1;
505         return Target->BufUsed;
506 }
507
508 /*
509  * \brief Append a string, escaping characters which have meaning in HTML.  
510  * Converts linebreaks into blanks; escapes single quotes
511  * \param Target        target buffer
512  * \param Source        source buffer; set to NULL if you just have a C-String
513  * \param PlainIn       Plain-C string to append; set to NULL if unused
514  */
515 void StrMsgEscAppend(StrBuf *Target, StrBuf *Source, const char *PlainIn)
516 {
517         const char *aptr, *eiptr;
518         char *tptr, *eptr;
519         long len;
520
521         if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
522                 return ;
523
524         if (PlainIn != NULL) {
525                 aptr = PlainIn;
526                 len = strlen(PlainIn);
527                 eiptr = aptr + len;
528         }
529         else {
530                 aptr = Source->buf;
531                 eiptr = aptr + Source->BufUsed;
532                 len = Source->BufUsed;
533         }
534
535         if (len == 0) 
536                 return;
537
538         eptr = Target->buf + Target->BufSize - 6; 
539         tptr = Target->buf + Target->BufUsed;
540         
541         while (aptr < eiptr){
542                 if(tptr >= eptr) {
543                         IncreaseBuf(Target, 1, -1);
544                         eptr = Target->buf + Target->BufSize - 6; 
545                         tptr = Target->buf + Target->BufUsed;
546                 }
547                
548                 if (*aptr == '\n') {
549                         *tptr = ' ';
550                         Target->BufUsed++;
551                 }
552                 else if (*aptr == '\r') {
553                         *tptr = ' ';
554                         Target->BufUsed++;
555                 }
556                 else if (*aptr == '\'') {
557                         *(tptr++) = '&';
558                         *(tptr++) = '#';
559                         *(tptr++) = '3';
560                         *(tptr++) = '9';
561                         *tptr = ';';
562                         Target->BufUsed += 5;
563                 } else {
564                         *tptr = *aptr;
565                         Target->BufUsed++;
566                 }
567                 tptr++; aptr++;
568         }
569         *tptr = '\0';
570 }
571
572
573 /**
574  * \brief extracts a substring from Source into dest
575  * \param dest buffer to place substring into
576  * \param Source string to copy substring from
577  * \param Offset chars to skip from start
578  * \param nChars number of chars to copy
579  * \returns the number of chars copied; may be different from nChars due to the size of Source
580  */
581 int StrBufSub(StrBuf *dest, const StrBuf *Source, size_t Offset, size_t nChars)
582 {
583         size_t NCharsRemain;
584         if (Offset > Source->BufUsed)
585         {
586                 FlushStrBuf(dest);
587                 return 0;
588         }
589         if (Offset + nChars < Source->BufUsed)
590         {
591                 if (nChars > dest->BufSize)
592                         IncreaseBuf(dest, 0, nChars + 1);
593                 memcpy(dest->buf, Source->buf + Offset, nChars);
594                 dest->BufUsed = nChars;
595                 dest->buf[dest->BufUsed] = '\0';
596                 return nChars;
597         }
598         NCharsRemain = Source->BufUsed - Offset;
599         if (NCharsRemain > dest->BufSize)
600                 IncreaseBuf(dest, 0, NCharsRemain + 1);
601         memcpy(dest->buf, Source->buf + Offset, NCharsRemain);
602         dest->BufUsed = NCharsRemain;
603         dest->buf[dest->BufUsed] = '\0';
604         return NCharsRemain;
605 }
606
607 /**
608  * \brief sprintf like function appending the formated string to the buffer
609  * vsnprintf version to wrap into own calls
610  * \param Buf Buffer to extend by format and params
611  * \param format printf alike format to add
612  * \param ap va_list containing the items for format
613  */
614 void StrBufVAppendPrintf(StrBuf *Buf, const char *format, va_list ap)
615 {
616         va_list apl;
617         size_t BufSize = Buf->BufSize;
618         size_t nWritten = Buf->BufSize + 1;
619         size_t Offset = Buf->BufUsed;
620         size_t newused = Offset + nWritten;
621         
622         while (newused >= BufSize) {
623                 va_copy(apl, ap);
624                 nWritten = vsnprintf(Buf->buf + Offset, 
625                                      Buf->BufSize - Offset, 
626                                      format, apl);
627                 va_end(apl);
628                 newused = Offset + nWritten;
629                 if (newused >= Buf->BufSize) {
630                         IncreaseBuf(Buf, 1, newused);
631                 }
632                 else {
633                         Buf->BufUsed = Offset + nWritten;
634                         BufSize = Buf->BufSize;
635                 }
636
637         }
638 }
639
640 /**
641  * \brief sprintf like function appending the formated string to the buffer
642  * \param Buf Buffer to extend by format and params
643  * \param format printf alike format to add
644  * \param ap va_list containing the items for format
645  */
646 void StrBufAppendPrintf(StrBuf *Buf, const char *format, ...)
647 {
648         size_t BufSize = Buf->BufSize;
649         size_t nWritten = Buf->BufSize + 1;
650         size_t Offset = Buf->BufUsed;
651         size_t newused = Offset + nWritten;
652         va_list arg_ptr;
653         
654         while (newused >= BufSize) {
655                 va_start(arg_ptr, format);
656                 nWritten = vsnprintf(Buf->buf + Buf->BufUsed, 
657                                      Buf->BufSize - Buf->BufUsed, 
658                                      format, arg_ptr);
659                 va_end(arg_ptr);
660                 newused = Buf->BufUsed + nWritten;
661                 if (newused >= Buf->BufSize) {
662                         IncreaseBuf(Buf, 1, newused);
663                 }
664                 else {
665                         Buf->BufUsed += nWritten;
666                         BufSize = Buf->BufSize;
667                 }
668
669         }
670 }
671
672 /**
673  * \brief sprintf like function putting the formated string into the buffer
674  * \param Buf Buffer to extend by format and params
675  * \param format printf alike format to add
676  * \param ap va_list containing the items for format
677  */
678 void StrBufPrintf(StrBuf *Buf, const char *format, ...)
679 {
680         size_t nWritten = Buf->BufSize + 1;
681         va_list arg_ptr;
682         
683         while (nWritten >= Buf->BufSize) {
684                 va_start(arg_ptr, format);
685                 nWritten = vsnprintf(Buf->buf, Buf->BufSize, format, arg_ptr);
686                 va_end(arg_ptr);
687                 Buf->BufUsed = nWritten ;
688                 if (nWritten >= Buf->BufSize)
689                         IncreaseBuf(Buf, 0, 0);
690         }
691 }
692
693
694 /**
695  * \brief Counts the numbmer of tokens in a buffer
696  * \param Source String to count tokens in
697  * \param tok    Tokenizer char to count
698  * \returns numbers of tokenizer chars found
699  */
700 inline int StrBufNum_tokens(const StrBuf *source, char tok)
701 {
702         return num_tokens(source->buf, tok);
703 }
704
705 /**
706  * \brief a string tokenizer
707  * \param dest Destination StringBuffer
708  * \param Source StringBuffer to read into
709  * \param parmnum n'th parameter to extract
710  * \param separator tokenizer param
711  * \returns -1 if not found, else length of token.
712  */
713 int StrBufExtract_token(StrBuf *dest, const StrBuf *Source, int parmnum, char separator)
714 {
715         const char *s, *e;              //* source * /
716         int len = 0;                    //* running total length of extracted string * /
717         int current_token = 0;          //* token currently being processed * /
718
719         if ((Source == NULL) || (Source->BufUsed ==0)) {
720                 return(-1);
721         }
722         s = Source->buf;
723         e = s + Source->BufUsed;
724         if (dest == NULL) {
725                 return(-1);
726         }
727
728         //cit_backtrace();
729         //lprintf (CTDL_DEBUG, "test >: n: %d sep: %c source: %s \n willi \n", parmnum, separator, source);
730         dest->buf[0] = '\0';
731         dest->BufUsed = 0;
732
733         while ((s<e) && !IsEmptyStr(s)) {
734                 if (*s == separator) {
735                         ++current_token;
736                 }
737                 if (len >= dest->BufSize)
738                         if (!IncreaseBuf(dest, 1, -1))
739                                 break;
740                 if ( (current_token == parmnum) && 
741                      (*s != separator)) {
742                         dest->buf[len] = *s;
743                         ++len;
744                 }
745                 else if (current_token > parmnum) {
746                         break;
747                 }
748                 ++s;
749         }
750         
751         dest->buf[len] = '\0';
752         dest->BufUsed = len;
753                 
754         if (current_token < parmnum) {
755                 //lprintf (CTDL_DEBUG,"test <!: %s\n", dest);
756                 return(-1);
757         }
758         //lprintf (CTDL_DEBUG,"test <: %d; %s\n", len, dest);
759         return(len);
760 }
761
762
763 /**
764  * \brief a string tokenizer to fetch an integer
765  * \param dest Destination StringBuffer
766  * \param parmnum n'th parameter to extract
767  * \param separator tokenizer param
768  * \returns 0 if not found, else integer representation of the token
769  */
770 int StrBufExtract_int(const StrBuf* Source, int parmnum, char separator)
771 {
772         StrBuf tmp;
773         char buf[64];
774         
775         tmp.buf = buf;
776         buf[0] = '\0';
777         tmp.BufSize = 64;
778         tmp.BufUsed = 0;
779         if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
780                 return(atoi(buf));
781         else
782                 return 0;
783 }
784
785 /**
786  * \brief a string tokenizer to fetch a long integer
787  * \param dest Destination StringBuffer
788  * \param parmnum n'th parameter to extract
789  * \param separator tokenizer param
790  * \returns 0 if not found, else long integer representation of the token
791  */
792 long StrBufExtract_long(const StrBuf* Source, int parmnum, char separator)
793 {
794         StrBuf tmp;
795         char buf[64];
796         
797         tmp.buf = buf;
798         buf[0] = '\0';
799         tmp.BufSize = 64;
800         tmp.BufUsed = 0;
801         if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
802                 return(atoi(buf));
803         else
804                 return 0;
805 }
806
807
808 /**
809  * \brief a string tokenizer to fetch an unsigned long
810  * \param dest Destination StringBuffer
811  * \param parmnum n'th parameter to extract
812  * \param separator tokenizer param
813  * \returns 0 if not found, else unsigned long representation of the token
814  */
815 unsigned long StrBufExtract_unsigned_long(const StrBuf* Source, int parmnum, char separator)
816 {
817         StrBuf tmp;
818         char buf[64];
819         char *pnum;
820         
821         tmp.buf = buf;
822         buf[0] = '\0';
823         tmp.BufSize = 64;
824         tmp.BufUsed = 0;
825         if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0) {
826                 pnum = &buf[0];
827                 if (*pnum == '-')
828                         pnum ++;
829                 return (unsigned long) atol(pnum);
830         }
831         else 
832                 return 0;
833 }
834
835
836
837 /**
838  * \brief Read a line from socket
839  * flushes and closes the FD on error
840  * \param buf the buffer to get the input to
841  * \param fd pointer to the filedescriptor to read
842  * \param append Append to an existing string or replace?
843  * \param Error strerror() on error 
844  * \returns numbers of chars read
845  */
846 int StrBufTCP_read_line(StrBuf *buf, int *fd, int append, const char **Error)
847 {
848         int len, rlen, slen;
849
850         if (!append)
851                 FlushStrBuf(buf);
852
853         slen = len = buf->BufUsed;
854         while (1) {
855                 rlen = read(*fd, &buf->buf[len], 1);
856                 if (rlen < 1) {
857                         *Error = strerror(errno);
858                         
859                         close(*fd);
860                         *fd = -1;
861                         
862                         return -1;
863                 }
864                 if (buf->buf[len] == '\n')
865                         break;
866                 if (buf->buf[len] != '\r')
867                         len ++;
868                 if (!(len < buf->BufSize)) {
869                         buf->BufUsed = len;
870                         buf->buf[len+1] = '\0';
871                         IncreaseBuf(buf, 1, -1);
872                 }
873         }
874         buf->BufUsed = len;
875         buf->buf[len] = '\0';
876         return len - slen;
877 }
878
879 /**
880  * \brief Input binary data from socket
881  * flushes and closes the FD on error
882  * \param buf the buffer to get the input to
883  * \param fd pointer to the filedescriptor to read
884  * \param append Append to an existing string or replace?
885  * \param nBytes the maximal number of bytes to read
886  * \param Error strerror() on error 
887  * \returns numbers of chars read
888  */
889 int StrBufReadBLOB(StrBuf *Buf, int *fd, int append, long nBytes, const char **Error)
890 {
891         fd_set wset;
892         int fdflags;
893         int len, rlen, slen;
894         int nRead = 0;
895         char *ptr;
896
897         if ((Buf == NULL) || (*fd == -1))
898                 return -1;
899         if (!append)
900                 FlushStrBuf(Buf);
901         if (Buf->BufUsed + nBytes > Buf->BufSize)
902                 IncreaseBuf(Buf, 1, Buf->BufUsed + nBytes);
903
904         ptr = Buf->buf + Buf->BufUsed;
905
906         slen = len = Buf->BufUsed;
907
908         fdflags = fcntl(*fd, F_GETFL);
909
910         while (nRead < nBytes) {
911                if ((fdflags & O_NONBLOCK) == O_NONBLOCK) {
912                         FD_ZERO(&wset);
913                         FD_SET(*fd, &wset);
914                         if (select(*fd + 1, NULL, &wset, NULL, NULL) == -1) {
915                                 *Error = strerror(errno);
916                                 return -1;
917                         }
918                 }
919
920                 if ((rlen = read(*fd, 
921                                  ptr,
922                                  nBytes - nRead)) == -1) {
923                         close(*fd);
924                         *fd = -1;
925                         *Error = strerror(errno);
926                         return rlen;
927                 }
928                 nRead += rlen;
929                 ptr += rlen;
930                 Buf->BufUsed += rlen;
931         }
932         Buf->buf[Buf->BufUsed] = '\0';
933         return nRead;
934 }
935
936 /**
937  * \brief Cut nChars from the start of the string
938  * \param Buf Buffer to modify
939  * \param nChars how many chars should be skipped?
940  */
941 void StrBufCutLeft(StrBuf *Buf, int nChars)
942 {
943         if (nChars >= Buf->BufUsed) {
944                 FlushStrBuf(Buf);
945                 return;
946         }
947         memmove(Buf->buf, Buf->buf + nChars, Buf->BufUsed - nChars);
948         Buf->BufUsed -= nChars;
949         Buf->buf[Buf->BufUsed] = '\0';
950 }
951
952 /**
953  * \brief Cut the trailing n Chars from the string
954  * \param Buf Buffer to modify
955  * \param nChars how many chars should be trunkated?
956  */
957 void StrBufCutRight(StrBuf *Buf, int nChars)
958 {
959         if (nChars >= Buf->BufUsed) {
960                 FlushStrBuf(Buf);
961                 return;
962         }
963         Buf->BufUsed -= nChars;
964         Buf->buf[Buf->BufUsed] = '\0';
965 }
966
967
968 /**
969  * \brief unhide special chars hidden to the HTML escaper
970  * \param target buffer to put the unescaped string in
971  * \param source buffer to unescape
972  */
973 void StrBufEUid_unescapize(StrBuf *target, const StrBuf *source) 
974 {
975         int a, b, len;
976         char hex[3];
977
978         if (target != NULL)
979                 FlushStrBuf(target);
980
981         if (source == NULL ||target == NULL)
982         {
983                 return;
984         }
985
986         len = source->BufUsed;
987         for (a = 0; a < len; ++a) {
988                 if (target->BufUsed >= target->BufSize)
989                         IncreaseBuf(target, 1, -1);
990
991                 if (source->buf[a] == '=') {
992                         hex[0] = source->buf[a + 1];
993                         hex[1] = source->buf[a + 2];
994                         hex[2] = 0;
995                         b = 0;
996                         sscanf(hex, "%02x", &b);
997                         target->buf[target->BufUsed] = b;
998                         target->buf[++target->BufUsed] = 0;
999                         a += 2;
1000                 }
1001                 else {
1002                         target->buf[target->BufUsed] = source->buf[a];
1003                         target->buf[++target->BufUsed] = 0;
1004                 }
1005         }
1006 }
1007
1008
1009 /**
1010  * \brief hide special chars from the HTML escapers and friends
1011  * \param target buffer to put the escaped string in
1012  * \param source buffer to escape
1013  */
1014 void StrBufEUid_escapize(StrBuf *target, const StrBuf *source) 
1015 {
1016         int i, len;
1017
1018         if (target != NULL)
1019                 FlushStrBuf(target);
1020
1021         if (source == NULL ||target == NULL)
1022         {
1023                 return;
1024         }
1025
1026         len = source->BufUsed;
1027         for (i=0; i<len; ++i) {
1028                 if (target->BufUsed + 4 >= target->BufSize)
1029                         IncreaseBuf(target, 1, -1);
1030                 if ( (isalnum(source->buf[i])) || 
1031                      (source->buf[i]=='-') || 
1032                      (source->buf[i]=='_') ) {
1033                         target->buf[target->BufUsed++] = source->buf[i];
1034                 }
1035                 else {
1036                         sprintf(&target->buf[target->BufUsed], 
1037                                 "=%02X", 
1038                                 (0xFF &source->buf[i]));
1039                         target->BufUsed += 3;
1040                 }
1041         }
1042         target->buf[target->BufUsed + 1] = '\0';
1043 }
1044
1045 /*
1046  * \brief uses the same calling syntax as compress2(), but it
1047  * creates a stream compatible with HTTP "Content-encoding: gzip"
1048  */
1049 #ifdef HAVE_ZLIB
1050 #define DEF_MEM_LEVEL 8 /*< memlevel??? */
1051 #define OS_CODE 0x03    /*< unix */
1052 int ZEXPORT compress_gzip(Bytef * dest,         /*< compressed buffer*/
1053                           size_t * destLen,     /*< length of the compresed data */
1054                           const Bytef * source, /*< source to encode */
1055                           uLong sourceLen,      /*< length of source to encode */
1056                           int level)            /*< compression level */
1057 {
1058         const int gz_magic[2] = { 0x1f, 0x8b }; /* gzip magic header */
1059
1060         /* write gzip header */
1061         snprintf((char *) dest, *destLen, 
1062                  "%c%c%c%c%c%c%c%c%c%c",
1063                  gz_magic[0], gz_magic[1], Z_DEFLATED,
1064                  0 /*flags */ , 0, 0, 0, 0 /*time */ , 0 /* xflags */ ,
1065                  OS_CODE);
1066
1067         /* normal deflate */
1068         z_stream stream;
1069         int err;
1070         stream.next_in = (Bytef *) source;
1071         stream.avail_in = (uInt) sourceLen;
1072         stream.next_out = dest + 10L;   // after header
1073         stream.avail_out = (uInt) * destLen;
1074         if ((uLong) stream.avail_out != *destLen)
1075                 return Z_BUF_ERROR;
1076
1077         stream.zalloc = (alloc_func) 0;
1078         stream.zfree = (free_func) 0;
1079         stream.opaque = (voidpf) 0;
1080
1081         err = deflateInit2(&stream, level, Z_DEFLATED, -MAX_WBITS,
1082                            DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
1083         if (err != Z_OK)
1084                 return err;
1085
1086         err = deflate(&stream, Z_FINISH);
1087         if (err != Z_STREAM_END) {
1088                 deflateEnd(&stream);
1089                 return err == Z_OK ? Z_BUF_ERROR : err;
1090         }
1091         *destLen = stream.total_out + 10L;
1092
1093         /* write CRC and Length */
1094         uLong crc = crc32(0L, source, sourceLen);
1095         int n;
1096         for (n = 0; n < 4; ++n, ++*destLen) {
1097                 dest[*destLen] = (int) (crc & 0xff);
1098                 crc >>= 8;
1099         }
1100         uLong len = stream.total_in;
1101         for (n = 0; n < 4; ++n, ++*destLen) {
1102                 dest[*destLen] = (int) (len & 0xff);
1103                 len >>= 8;
1104         }
1105         err = deflateEnd(&stream);
1106         return err;
1107 }
1108 #endif
1109
1110
1111 /**
1112  * Attention! If you feed this a Const String, you must maintain the uncompressed buffer yourself!
1113  */
1114 int CompressBuffer(StrBuf *Buf)
1115 {
1116 #ifdef HAVE_ZLIB
1117         char *compressed_data = NULL;
1118         size_t compressed_len, bufsize;
1119         
1120         bufsize = compressed_len = ((Buf->BufUsed * 101) / 100) + 100;
1121         compressed_data = malloc(compressed_len);
1122         
1123         if (compress_gzip((Bytef *) compressed_data,
1124                           &compressed_len,
1125                           (Bytef *) Buf->buf,
1126                           (uLongf) Buf->BufUsed, Z_BEST_SPEED) == Z_OK) {
1127                 if (!ConstBuf)
1128                         free(Buf->buf);
1129                 Buf->buf = compressed_data;
1130                 Buf->BufUsed = compressed_len;
1131                 Buf->BufSize = bufsize;
1132                 return 1;
1133         } else {
1134                 free(compressed_data);
1135         }
1136 #endif  /* HAVE_ZLIB */
1137         return 0;
1138 }
1139
1140 /**
1141  * \brief decode a buffer from base 64 encoding; destroys original
1142  * \param Buf Buffor to transform
1143  */
1144 int StrBufDecodeBase64(StrBuf *Buf)
1145 {
1146         char *xferbuf;
1147         size_t siz;
1148         if (Buf == NULL) return -1;
1149
1150         xferbuf = (char*) malloc(Buf->BufSize);
1151         siz = CtdlDecodeBase64(xferbuf,
1152                                Buf->buf,
1153                                Buf->BufUsed);
1154         free(Buf->buf);
1155         Buf->buf = xferbuf;
1156         Buf->BufUsed = siz;
1157         return siz;
1158 }
1159
1160
1161 /**
1162  * \brief  remove escaped strings from i.e. the url string (like %20 for blanks)
1163  * \param Buf Buffer to translate
1164  * \param StripBlanks Reduce several blanks to one?
1165  */
1166 long StrBufUnescape(StrBuf *Buf, int StripBlanks)
1167 {
1168         int a, b;
1169         char hex[3];
1170         long len;
1171
1172         while ((Buf->BufUsed > 0) && (isspace(Buf->buf[Buf->BufUsed - 1]))){
1173                 Buf->buf[Buf->BufUsed - 1] = '\0';
1174                 Buf->BufUsed --;
1175         }
1176
1177         a = 0; 
1178         while (a < Buf->BufUsed) {
1179                 if (Buf->buf[a] == '+')
1180                         Buf->buf[a] = ' ';
1181                 else if (Buf->buf[a] == '%') {
1182                         /* don't let % chars through, rather truncate the input. */
1183                         if (a + 2 > Buf->BufUsed) {
1184                                 Buf->buf[a] = '\0';
1185                                 Buf->BufUsed = a;
1186                         }
1187                         else {                  
1188                                 hex[0] = Buf->buf[a + 1];
1189                                 hex[1] = Buf->buf[a + 2];
1190                                 hex[2] = 0;
1191                                 b = 0;
1192                                 sscanf(hex, "%02x", &b);
1193                                 Buf->buf[a] = (char) b;
1194                                 len = Buf->BufUsed - a - 2;
1195                                 if (len > 0)
1196                                         memmove(&Buf->buf[a + 1], &Buf->buf[a + 3], len);
1197                         
1198                                 Buf->BufUsed -=2;
1199                         }
1200                 }
1201                 a++;
1202         }
1203         return a;
1204 }
1205
1206
1207 /**
1208  * \brief       RFC2047-encode a header field if necessary.
1209  *              If no non-ASCII characters are found, the string
1210  *              will be copied verbatim without encoding.
1211  *
1212  * \param       target          Target buffer.
1213  * \param       source          Source string to be encoded.
1214  * \returns     encoded length; -1 if non success.
1215  */
1216 int StrBufRFC2047encode(StrBuf **target, const StrBuf *source)
1217 {
1218         const char headerStr[] = "=?UTF-8?Q?";
1219         int need_to_encode = 0;
1220         int i = 0;
1221         unsigned char ch;
1222
1223         if ((source == NULL) || 
1224             (target == NULL))
1225             return -1;
1226
1227         while ((i < source->BufUsed) &&
1228                (!IsEmptyStr (&source->buf[i])) &&
1229                (need_to_encode == 0)) {
1230                 if (((unsigned char) source->buf[i] < 32) || 
1231                     ((unsigned char) source->buf[i] > 126)) {
1232                         need_to_encode = 1;
1233                 }
1234                 i++;
1235         }
1236
1237         if (!need_to_encode) {
1238                 if (*target == NULL) {
1239                         *target = NewStrBufPlain(source->buf, source->BufUsed);
1240                 }
1241                 else {
1242                         FlushStrBuf(*target);
1243                         StrBufAppendBuf(*target, source, 0);
1244                 }
1245                 return (*target)->BufUsed;
1246         }
1247         if (*target == NULL)
1248                 *target = NewStrBufPlain(NULL, sizeof(headerStr) + source->BufUsed * 2);
1249         else if (sizeof(headerStr) + source->BufUsed > (*target)->BufSize)
1250                 IncreaseBuf(*target, sizeof(headerStr) + source->BufUsed, 0);
1251         memcpy ((*target)->buf, headerStr, sizeof(headerStr) - 1);
1252         (*target)->BufUsed = sizeof(headerStr) - 1;
1253         for (i=0; (i < source->BufUsed); ++i) {
1254                 if ((*target)->BufUsed + 4 > (*target)->BufSize)
1255                         IncreaseBuf(*target, 1, 0);
1256                 ch = (unsigned char) source->buf[i];
1257                 if ((ch < 32) || (ch > 126) || (ch == 61)) {
1258                         sprintf(&(*target)->buf[(*target)->BufUsed], "=%02X", ch);
1259                         (*target)->BufUsed += 3;
1260                 }
1261                 else {
1262                         (*target)->buf[(*target)->BufUsed] = ch;
1263                         (*target)->BufUsed++;
1264                 }
1265         }
1266         
1267         if ((*target)->BufUsed + 4 > (*target)->BufSize)
1268                 IncreaseBuf(*target, 1, 0);
1269
1270         (*target)->buf[(*target)->BufUsed++] = '?';
1271         (*target)->buf[(*target)->BufUsed++] = '=';
1272         (*target)->buf[(*target)->BufUsed] = '\0';
1273         return (*target)->BufUsed;;
1274 }
1275
1276 /**
1277  * \brief replaces all occurances of 'search' by 'replace'
1278  * \param buf Buffer to modify
1279  * \param search character to search
1280  * \param relpace character to replace search by
1281  */
1282 void StrBufReplaceChars(StrBuf *buf, char search, char replace)
1283 {
1284         long i;
1285         if (buf == NULL)
1286                 return;
1287         for (i=0; i<buf->BufUsed; i++)
1288                 if (buf->buf[i] == search)
1289                         buf->buf[i] = replace;
1290
1291 }