66af63a67e1618a7feb8065cba6d88b34b62d8b6
[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 "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 == NULL)
131                 return;
132         if (!FreeMe->ConstBuf) 
133                 free(FreeMe->buf);
134         free(FreeMe);
135 }
136
137 long StrTol(StrBuf *Buf)
138 {
139         if(Buf->BufUsed > 0)
140                 return atol(Buf->buf);
141         else
142                 return 0;
143 }
144
145
146 void StrBufAppendBuf(StrBuf *Buf, StrBuf *AppendBuf, size_t Offset)
147 {
148         if ((AppendBuf == NULL) || (Buf == NULL))
149                 return;
150         if (Buf->BufSize - Offset < AppendBuf->BufUsed)
151                 IncreaseBuf(Buf, (Buf->BufUsed > 0), AppendBuf->BufUsed);
152         memcpy(Buf->buf + Buf->BufUsed, 
153                AppendBuf->buf + Offset, 
154                AppendBuf->BufUsed - Offset);
155         Buf->BufUsed += AppendBuf->BufUsed - Offset;
156         Buf->buf[Buf->BufUsed] = '\0';
157 }
158
159
160 inline int StrBufNum_tokens(const StrBuf *source, char tok)
161 {
162         return num_tokens(source->buf, tok);
163 }
164
165
166 int StrBufSub(StrBuf *dest, const StrBuf *Source, size_t Offset, size_t nChars)
167 {
168         size_t NCharsRemain;
169         if (Offset > Source->BufUsed)
170         {
171                 FlushStrBuf(dest);
172                 return 0;
173         }
174         if (Offset + nChars < Source->BufUsed)
175         {
176                 if (nChars > dest->BufSize)
177                         IncreaseBuf(dest, 0, nChars + 1);
178                 memcpy(dest->buf, Source->buf + Offset, nChars);
179                 dest->BufUsed = nChars;
180                 dest->buf[dest->BufUsed] = '\0';
181                 return nChars;
182         }
183         NCharsRemain = Source->BufUsed - Offset;
184         if (NCharsRemain > dest->BufSize)
185                 IncreaseBuf(dest, 0, NCharsRemain + 1);
186         memcpy(dest->buf, Source->buf + Offset, NCharsRemain);
187         dest->BufUsed = NCharsRemain;
188         dest->buf[dest->BufUsed] = '\0';
189         return NCharsRemain;
190 }
191
192 void StrBufPrintf(StrBuf *Buf, const char *format, ...)
193 {
194         size_t nWritten = Buf->BufSize + 1;
195         va_list arg_ptr;
196         
197         while (nWritten >= Buf->BufSize) {
198                 va_start(arg_ptr, format);
199                 nWritten = vsnprintf(Buf->buf, Buf->BufSize, format, arg_ptr);
200                 va_end(arg_ptr);
201                 Buf->BufUsed = nWritten ;
202                 if (nWritten >= Buf->BufSize)
203                         IncreaseBuf(Buf, 0, 0);
204         }
205 }
206
207
208 /**
209  * \brief a string tokenizer
210  * \param dest Destination StringBuffer
211  * \param Source StringBuffer to read into
212  * \param separator tokenizer param
213  * \returns -1 if not found, else length of token.
214  */
215 int StrBufExtract_token(StrBuf *dest, const StrBuf *Source, int parmnum, char separator)
216 {
217         const char *s, *e;              //* source * /
218         int len = 0;                    //* running total length of extracted string * /
219         int current_token = 0;          //* token currently being processed * /
220
221         if ((Source == NULL) || (Source->BufUsed ==0)) {
222                 return(-1);
223         }
224         s = Source->buf;
225         e = s + Source->BufUsed;
226         if (dest == NULL) {
227                 return(-1);
228         }
229
230         //cit_backtrace();
231         //lprintf (CTDL_DEBUG, "test >: n: %d sep: %c source: %s \n willi \n", parmnum, separator, source);
232         dest->buf[0] = '\0';
233         dest->BufUsed = 0;
234
235         while ((s<e) && !IsEmptyStr(s)) {
236                 if (*s == separator) {
237                         ++current_token;
238                 }
239                 if (len >= dest->BufSize)
240                         if (!IncreaseBuf(dest, 1, -1))
241                                 break;
242                 if ( (current_token == parmnum) && 
243                      (*s != separator)) {
244                         dest->buf[len] = *s;
245                         ++len;
246                 }
247                 else if (current_token > parmnum) {
248                         break;
249                 }
250                 ++s;
251         }
252         
253         dest->buf[len] = '\0';
254         dest->BufUsed = len;
255                 
256         if (current_token < parmnum) {
257                 //lprintf (CTDL_DEBUG,"test <!: %s\n", dest);
258                 return(-1);
259         }
260         //lprintf (CTDL_DEBUG,"test <: %d; %s\n", len, dest);
261         return(len);
262 }
263
264
265 /*
266  * extract_int()  -  extract an int parm w/o supplying a buffer
267  */
268 int StrBufExtract_int(const StrBuf* Source, int parmnum, char separator)
269 {
270         StrBuf tmp;
271         char buf[64];
272         
273         tmp.buf = buf;
274         buf[0] = '\0';
275         tmp.BufSize = 64;
276         tmp.BufUsed = 0;
277         if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
278                 return(atoi(buf));
279         else
280                 return 0;
281 }
282
283 /*
284  * extract_long()  -  extract an long parm w/o supplying a buffer
285  */
286 long StrBufExtract_long(const StrBuf* Source, int parmnum, char separator)
287 {
288         StrBuf tmp;
289         char buf[64];
290         
291         tmp.buf = buf;
292         buf[0] = '\0';
293         tmp.BufSize = 64;
294         tmp.BufUsed = 0;
295         if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
296                 return(atoi(buf));
297         else
298                 return 0;
299 }
300
301
302 /*
303  * extract_unsigned_long() - extract an unsigned long parm
304  */
305 unsigned long StrBufExtract_unsigned_long(const StrBuf* Source, int parmnum, char separator)
306 {
307         StrBuf tmp;
308         char buf[64];
309         
310         tmp.buf = buf;
311         buf[0] = '\0';
312         tmp.BufSize = 64;
313         tmp.BufUsed = 0;
314         if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
315                 return(atoi(buf));
316         else 
317                 return 0;
318 }
319
320
321
322 /**
323  * \brief Input binary data from socket
324  * \param buf the buffer to get the input to
325  * \param bytes the maximal number of bytes to read
326  */
327 int StrBufTCP_read_line(StrBuf *buf, int fd, int append, const char **Error)
328 {
329         int len, rlen, slen;
330
331         if (!append)
332                 FlushStrBuf(buf);
333
334         slen = len = buf->BufUsed;
335         while (1) {
336                 rlen = read(fd, &buf->buf[len], 1);
337                 if (rlen < 1) {
338                         *Error = strerror(errno);
339                         
340                         close(fd);
341                         
342                         return -1;
343                 }
344                 if (buf->buf[len] == '\n')
345                         break;
346                 if (buf->buf[len] != '\r')
347                         len ++;
348                 if (!(len < buf->BufSize)) {
349                         buf->BufUsed = len;
350                         buf->buf[len+1] = '\0';
351                         IncreaseBuf(buf, 1, -1);
352                 }
353         }
354         buf->BufUsed = len;
355         buf->buf[len] = '\0';
356         return len - slen;
357 }
358
359 void StrBufCutLeft(StrBuf *Buf, int nChars)
360 {
361         if (nChars >= Buf->BufUsed) {
362                 FlushStrBuf(Buf);
363                 return;
364         }
365         memmove(Buf->buf, Buf->buf + nChars, Buf->BufUsed - nChars);
366         Buf->BufUsed -= nChars;
367 }
368
369 void StrBufCutRight(StrBuf *Buf, int nChars)
370 {
371         if (nChars >= Buf->BufUsed) {
372                 FlushStrBuf(Buf);
373                 return;
374         }
375         Buf->BufUsed -= nChars;
376         Buf->buf[Buf->BufUsed] = '\0';
377 }
378
379
380 /*
381  * string conversion function
382  */
383 void StrBufEUid_unescapize(StrBuf *target, StrBuf *source) 
384 {
385         int a, b, len;
386         char hex[3];
387
388         if (target != NULL)
389                 FlushStrBuf(target);
390
391         if (source == NULL ||target == NULL)
392         {
393                 return;
394         }
395
396         len = source->BufUsed;
397         for (a = 0; a < len; ++a) {
398                 if (target->BufUsed >= target->BufSize)
399                         IncreaseBuf(target, 1, -1);
400
401                 if (source->buf[a] == '=') {
402                         hex[0] = source->buf[a + 1];
403                         hex[1] = source->buf[a + 2];
404                         hex[2] = 0;
405                         b = 0;
406                         sscanf(hex, "%02x", &b);
407                         target->buf[target->BufUsed] = b;
408                         target->buf[++target->BufUsed] = 0;
409                         a += 2;
410                 }
411                 else {
412                         target->buf[target->BufUsed] = source->buf[a];
413                         target->buf[++target->BufUsed] = 0;
414                 }
415         }
416 }
417
418
419 /*
420  * string conversion function
421  */
422 void StrBufEUid_escapize(StrBuf *target, StrBuf *source) 
423 {
424         int i, len;
425
426         if (target != NULL)
427                 FlushStrBuf(target);
428
429         if (source == NULL ||target == NULL)
430         {
431                 return;
432         }
433
434         len = source->BufUsed;
435         for (i=0; i<len; ++i) {
436                 if (target->BufUsed + 4 >= target->BufSize)
437                         IncreaseBuf(target, 1, -1);
438                 if ( (isalnum(source->buf[i])) || 
439                      (source->buf[i]=='-') || 
440                      (source->buf[i]=='_') ) {
441                         target->buf[target->BufUsed++] = source->buf[i];
442                 }
443                 else {
444                         sprintf(&target->buf[target->BufUsed], 
445                                 "=%02X", 
446                                 (0xFF &source->buf[i]));
447                         target->BufUsed += 3;
448                 }
449         }
450         target->buf[target->BufUsed + 1] = '\0';
451 }