* add new buffer class which handles concatenation of strings in dynamic buffers...
[citadel.git] / libcitadel / lib / stringbuf.c
1
2 #include <errno.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <string.h>
6 #include <stdio.h>
7 #include "libcitadel.h"
8
9 #include <stdarg.h>
10
11 struct StrBuf {
12         char *buf;
13         long BufSize;
14         long BufUsed;
15         int ConstBuf;
16 };
17
18
19 inline const char *ChrPtr(StrBuf *Str)
20 {
21         if (Str == NULL)
22                 return "";
23         return Str->buf;
24 }
25
26 inline int StrLength(StrBuf *Str)
27 {
28         return Str->BufUsed;
29 }
30
31 StrBuf* NewStrBuf(void)
32 {
33         StrBuf *NewBuf;
34
35         NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
36         NewBuf->buf = (char*) malloc(SIZ);
37         NewBuf->buf[0] = '\0';
38         NewBuf->BufSize = SIZ;
39         NewBuf->BufUsed = 0;
40         NewBuf->ConstBuf = 0;
41         return NewBuf;
42 }
43
44
45 StrBuf* NewStrBufPlain(const char* ptr, int nChars)
46 {
47         StrBuf *NewBuf;
48         size_t Siz = SIZ;
49         size_t CopySize;
50
51         NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
52         if (nChars < 0)
53                 CopySize = strlen(ptr);
54         else
55                 CopySize = nChars;
56
57         while (Siz <= CopySize)
58                 Siz *= 2;
59
60         NewBuf->buf = (char*) malloc(Siz);
61         memcpy(NewBuf->buf, ptr, CopySize);
62         NewBuf->buf[CopySize] = '\0';
63         NewBuf->BufSize = Siz;
64         NewBuf->BufUsed = CopySize;
65         NewBuf->ConstBuf = 0;
66         return NewBuf;
67 }
68
69 StrBuf* _NewConstStrBuf(const char* StringConstant, size_t SizeOfStrConstant)
70 {
71         StrBuf *NewBuf;
72
73         NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
74         NewBuf->buf = (char*) StringConstant;
75         NewBuf->BufSize = SizeOfStrConstant;
76         NewBuf->BufUsed = SizeOfStrConstant;
77         NewBuf->ConstBuf = 1;
78         return NewBuf;
79 }
80
81
82 static int IncreaseBuf(StrBuf *Buf, int KeepOriginal, int DestSize)
83 {
84         char *NewBuf;
85         size_t NewSize = Buf->BufSize * 2;
86
87         if (Buf->ConstBuf)
88                 return -1;
89                 
90         if (DestSize > 0)
91                 while (NewSize < DestSize)
92                         NewSize *= 2;
93
94         NewBuf= (char*) malloc(NewSize);
95         if (KeepOriginal)
96         {
97                 memcpy(NewBuf, Buf->buf, Buf->BufUsed);
98         }
99         else
100         {
101                 NewBuf[0] = '\0';
102                 Buf->BufUsed = 0;
103         }
104         free (Buf->buf);
105         Buf->buf = NewBuf;
106         Buf->BufSize *= 2;
107         return Buf->BufSize;
108 }
109
110 int FlushStrBuf(StrBuf *buf)
111 {
112         if (buf->ConstBuf)
113                 return -1;       
114         buf->buf[0] ='\0';
115         buf->BufUsed = 0;
116         return 0;
117 }
118
119 void FreeStrBuf (StrBuf **FreeMe)
120 {
121         if (!(*FreeMe)->ConstBuf) 
122                 free((*FreeMe)->buf);
123         free(*FreeMe);
124         *FreeMe = NULL;
125 }
126
127 void HFreeStrBuf (void *VFreeMe)
128 {
129         StrBuf *FreeMe = (StrBuf*)VFreeMe;
130         if (!FreeMe->ConstBuf) 
131                 free(FreeMe->buf);
132         free(FreeMe);
133 }
134
135 long StrTol(StrBuf *Buf)
136 {
137         if(Buf->BufUsed > 0)
138                 return atol(Buf->buf);
139         else
140                 return 0;
141 }
142
143
144 void StrBufAppendBuf(StrBuf *Buf, StrBuf *AppendBuf, size_t Offset)
145 {
146         if ((AppendBuf == NULL) || (Buf == NULL))
147                 return;
148         if (Buf->BufSize - Offset < AppendBuf->BufUsed)
149                 IncreaseBuf(Buf, (Buf->BufUsed > 0), AppendBuf->BufUsed);
150         memcpy(Buf->buf + Buf->BufUsed - 1, 
151                AppendBuf->buf + Offset, 
152                AppendBuf->BufUsed - Offset);
153         Buf->BufUsed += AppendBuf->BufUsed - Offset;
154         Buf->buf[Buf->BufUsed] = '\0';
155 }
156
157
158 inline int StrBufNum_tokens(const StrBuf *source, char tok)
159 {
160         return num_tokens(source->buf, tok);
161 }
162
163
164 int StrBufSub(StrBuf *dest, const StrBuf *Source, size_t Offset, size_t nChars)
165 {
166         size_t NCharsRemain;
167         if (Offset > Source->BufUsed)
168         {
169                 FlushStrBuf(dest);
170                 return 0;
171         }
172         if (Offset + nChars < Source->BufUsed)
173         {
174                 if (nChars < dest->BufSize)
175                         IncreaseBuf(dest, 0, nChars + 1);
176                 memcpy(dest->buf, Source->buf + Offset, nChars);
177                 dest->BufUsed = nChars + 1;
178                 dest->buf[dest->BufUsed] = '\0';
179                 return nChars;
180         }
181         NCharsRemain = Source->BufUsed - Offset;
182         if (NCharsRemain < dest->BufSize)
183                 IncreaseBuf(dest, 0, NCharsRemain + 1);
184         memcpy(dest->buf, Source->buf + Offset, NCharsRemain);
185         dest->BufUsed = NCharsRemain + 1;
186         dest->buf[dest->BufUsed] = '\0';
187         return NCharsRemain;
188 }
189
190 void StrBufPrintf(StrBuf *Buf, const char *format, ...)
191 {
192         size_t nWritten = Buf->BufSize + 1;
193         va_list arg_ptr;
194         
195         while (nWritten >= Buf->BufSize) {
196                 va_start(arg_ptr, format);
197                 nWritten = vsnprintf(Buf->buf, Buf->BufSize, format, arg_ptr);
198                 va_end(arg_ptr);
199                 Buf->BufUsed = nWritten ;
200                 if (nWritten >= Buf->BufSize)
201                         IncreaseBuf(Buf, 0, 0);
202         }
203 }
204
205
206 /**
207  * \brief a string tokenizer
208  * \param dest Destination StringBuffer
209  * \param Source StringBuffer to read into
210  * \param separator tokenizer param
211  * \returns -1 if not found, else length of token.
212  */
213 int StrBufExtract_token(StrBuf *dest, const StrBuf *Source, int parmnum, char separator)
214 {
215         const char *s;                  //* source * /
216         int len = 0;                    //* running total length of extracted string * /
217         int current_token = 0;          //* token currently being processed * /
218
219         if ((Source == NULL) || (Source->BufUsed ==0)) {
220                 return(-1);
221         }
222         s = Source->buf;
223
224         if (dest == NULL) {
225                 return(-1);
226         }
227
228         //cit_backtrace();
229         //lprintf (CTDL_DEBUG, "test >: n: %d sep: %c source: %s \n willi \n", parmnum, separator, source);
230         dest->buf[0] = '\0';
231         dest->BufUsed = 0;
232
233         while (*s) {
234                 if (*s == separator) {
235                         ++current_token;
236                 }
237                 if (len >= dest->BufSize)
238                         if (!IncreaseBuf(dest, 1, -1))
239                                 break;
240                 if ( (current_token == parmnum) && 
241                      (*s != separator)) {
242                         dest->buf[len] = *s;
243                         ++len;
244                 }
245                 else if (current_token > parmnum) {
246                         break;
247                 }
248                 ++s;
249         }
250         
251         dest->buf[len] = '\0';
252         dest->BufUsed = len;
253                 
254         if (current_token < parmnum) {
255                 //lprintf (CTDL_DEBUG,"test <!: %s\n", dest);
256                 return(-1);
257         }
258         //lprintf (CTDL_DEBUG,"test <: %d; %s\n", len, dest);
259         return(len);
260 }
261
262
263 /*
264  * extract_int()  -  extract an int parm w/o supplying a buffer
265  */
266 int StrBufExtract_int(const StrBuf* Source, int parmnum, char separator)
267 {
268         StrBuf tmp;
269         char buf[64];
270         
271         tmp.buf = buf;
272         buf[0] = '\0';
273         tmp.BufSize = 64;
274         tmp.BufUsed = 0;
275         if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
276                 return(atoi(buf));
277         else
278                 return 0;
279 }
280
281 /*
282  * extract_long()  -  extract an long parm w/o supplying a buffer
283  */
284 long StrBufExtract_long(const StrBuf* Source, int parmnum, char separator)
285 {
286         StrBuf tmp;
287         char buf[64];
288         
289         tmp.buf = buf;
290         buf[0] = '\0';
291         tmp.BufSize = 64;
292         tmp.BufUsed = 0;
293         if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
294                 return(atoi(buf));
295         else
296                 return 0;
297 }
298
299
300 /*
301  * extract_unsigned_long() - extract an unsigned long parm
302  */
303 unsigned long StrBufExtract_unsigned_long(const StrBuf* Source, int parmnum, char separator)
304 {
305         StrBuf tmp;
306         char buf[64];
307         
308         tmp.buf = buf;
309         buf[0] = '\0';
310         tmp.BufSize = 64;
311         tmp.BufUsed = 0;
312         if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
313                 return(atoi(buf));
314         else 
315                 return 0;
316 }
317
318
319
320 /**
321  * \brief Input binary data from socket
322  * \param buf the buffer to get the input to
323  * \param bytes the maximal number of bytes to read
324  */
325 int StrBufTCP_read_line(StrBuf *buf, int fd, int append, const char **Error)
326 {
327         int len, rlen, slen;
328
329         if (!append)
330                 FlushStrBuf(buf);
331
332         slen = len = buf->BufUsed;
333         while (buf->buf[len] != '\n') {
334                 rlen = read(fd, &buf->buf[len], 1);
335                 if (rlen < 1) {
336                         *Error = strerror(errno);
337                         
338                         close(fd);
339                         
340                         return -1;
341                 }
342                 if (buf->buf[len] == '\n')
343                         break;
344                 if (buf->buf[len] != '\r')
345                         len ++;
346                 if (!(len < buf->BufSize)) {
347                         buf->BufUsed = len;
348                         buf->buf[len+1] = '\0';
349                         IncreaseBuf(buf, 1, -1);
350                 }
351         }
352         buf->BufUsed = len;
353         buf->buf[len] = '\0';
354         return len - slen;
355 }
356
357 void StrBufCutLeft(StrBuf *Buf, int nChars)
358 {
359         if (nChars >= Buf->BufUsed) {
360                 FlushStrBuf(Buf);
361                 return;
362         }
363         memmove(Buf->buf, Buf->buf + nChars, Buf->BufUsed - nChars);
364         Buf->BufUsed -= nChars;
365 }
366
367 void StrBufCutRight(StrBuf *Buf, int nChars)
368 {
369         if (nChars >= Buf->BufUsed) {
370                 FlushStrBuf(Buf);
371                 return;
372         }
373         Buf->BufUsed -= nChars;
374         Buf->buf[Buf->BufUsed] = '\0';
375 }
376
377
378 /*
379  * string conversion function
380  */
381 void StrBufEUid_unescapize(StrBuf *target, StrBuf *source) 
382 {
383         int a, b, len;
384         char hex[3];
385         int target_length = 0;
386
387         if (target != NULL)
388                 FlushStrBuf(target);
389
390         if (source == NULL ||target == NULL)
391         {
392                 return;
393         }
394
395         len = source->BufUsed;
396         for (a = 0; a < len; ++a) {
397                 if (target_length >= target->BufSize)
398                         IncreaseBuf(target, 1, -1);
399
400                 if (source->buf[a] == '=') {
401                         hex[0] = source->buf[a + 1];
402                         hex[1] = source->buf[a + 2];
403                         hex[2] = 0;
404                         b = 0;
405                         sscanf(hex, "%02x", &b);
406                         target->buf[target_length] = b;
407                         target->buf[++target_length] = 0;
408                         a += 2;
409                 }
410                 else {
411                         target->buf[target_length] = source->buf[a];
412                         target->buf[++target_length] = 0;
413                 }
414         }
415 }
416