36d9b4817bae692966f26b8d3b815b2d69da7348
[silc.git] / lib / silcutil / silcbuffmt.c
1 /*
2
3   silcbuffmt.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2007 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19 /* $Id$ */
20
21 #include "silc.h"
22
23 /************************** Types and definitions ***************************/
24
25 /* Check that buffer has enough room to format data in it, if not
26    allocate more. */
27 #define FORMAT_HAS_SPACE(s, b, req)                     \
28 do {                                                    \
29   if (silc_unlikely(!silc_buffer_senlarge(s, b, req)))  \
30     goto fail;                                          \
31   flen += req;                                          \
32 } while(0)
33
34 /* Check that there is data to be unformatted */
35 #define UNFORMAT_HAS_SPACE(b, req)              \
36 do {                                            \
37   if (silc_unlikely(req > silc_buffer_len(b)))  \
38     goto fail;                                  \
39   if (silc_unlikely((req + 1) <= 0))            \
40     goto fail;                                  \
41 } while(0)
42
43
44 /******************************* Formatting *********************************/
45
46 int silc_buffer_format(SilcBuffer dst, ...)
47 {
48   va_list ap;
49   int ret;
50
51   va_start(ap, dst);
52   ret = silc_buffer_sformat_vp(NULL, dst, ap);
53   va_end(ap);
54
55   return ret;
56 }
57
58 int silc_buffer_format_vp(SilcBuffer dst, va_list ap)
59 {
60   return silc_buffer_sformat_vp(NULL, dst, ap);
61 }
62
63 int silc_buffer_sformat(SilcStack stack, SilcBuffer dst, ...)
64 {
65   va_list ap;
66   int ret;
67
68   va_start(ap, dst);
69   ret = silc_buffer_sformat_vp(stack, dst, ap);
70   va_end(ap);
71
72   return ret;
73 }
74
75 int silc_buffer_sformat_vp(SilcStack stack, SilcBuffer dst, va_list ap)
76 {
77   SilcBufferParamType fmt;
78   int flen = 0;
79   SilcBool advance = FALSE;
80
81   /* Parse the arguments by formatting type. */
82   while (1) {
83     fmt = va_arg(ap, SilcBufferParamType);
84
85     switch(fmt) {
86     case SILC_PARAM_FUNC:
87       {
88         SilcBufferFormatFunc func;
89         void *val;
90         void *context;
91         int tmp_len;
92         func = va_arg(ap, SilcBufferFormatFunc);
93         val = va_arg(ap, void *);
94         context = va_arg(ap, void *);
95         tmp_len = func(stack, dst, val, context);
96         if (tmp_len < 0)
97           goto fail;
98         if (tmp_len) {
99           silc_buffer_pull(dst, tmp_len);
100           flen += tmp_len;
101         }
102       }
103       break;
104     case SILC_PARAM_UI8_STRING:
105     case SILC_PARAM_UI16_STRING:
106     case SILC_PARAM_UI32_STRING:
107     case SILC_PARAM_UI8_STRING_ALLOC:
108     case SILC_PARAM_UI16_STRING_ALLOC:
109     case SILC_PARAM_UI32_STRING_ALLOC:
110       {
111         char *x = va_arg(ap, char *);
112         SilcUInt32 tmp_len = x ? strlen(x) : 0;
113         if (x && tmp_len) {
114           FORMAT_HAS_SPACE(stack, dst, tmp_len);
115           silc_buffer_put(dst, (unsigned char *)x, tmp_len);
116           silc_buffer_pull(dst, tmp_len);
117         }
118         break;
119       }
120     case SILC_PARAM_UI8_NSTRING:
121     case SILC_PARAM_UI16_NSTRING:
122     case SILC_PARAM_UI32_NSTRING:
123     case SILC_PARAM_UI_XNSTRING:
124     case SILC_PARAM_DATA:
125     case SILC_PARAM_UI8_NSTRING_ALLOC:
126     case SILC_PARAM_UI16_NSTRING_ALLOC:
127     case SILC_PARAM_UI32_NSTRING_ALLOC:
128     case SILC_PARAM_UI_XNSTRING_ALLOC:
129     case SILC_PARAM_DATA_ALLOC:
130       {
131         unsigned char *x = va_arg(ap, unsigned char *);
132         SilcUInt32 tmp_len = va_arg(ap, SilcUInt32);
133         if (x && tmp_len) {
134           FORMAT_HAS_SPACE(stack, dst, tmp_len);
135           silc_buffer_put(dst, x, tmp_len);
136           silc_buffer_pull(dst, tmp_len);
137         }
138         break;
139       }
140     case SILC_PARAM_UI8_CHAR:
141       {
142         unsigned char x = (unsigned char)va_arg(ap, int);
143         FORMAT_HAS_SPACE(stack, dst, 1);
144         silc_buffer_put(dst, &x, 1);
145         silc_buffer_pull(dst, 1);
146         break;
147       }
148     case SILC_PARAM_UI16_SHORT:
149       {
150         unsigned char xf[2];
151         SilcUInt16 x = (SilcUInt16)va_arg(ap, int);
152         FORMAT_HAS_SPACE(stack, dst, 2);
153         SILC_PUT16_MSB(x, xf);
154         silc_buffer_put(dst, xf, 2);
155         silc_buffer_pull(dst, 2);
156         break;
157       }
158     case SILC_PARAM_UI32_INT:
159       {
160         unsigned char xf[4];
161         SilcUInt32 x = va_arg(ap, SilcUInt32);
162         FORMAT_HAS_SPACE(stack, dst, 4);
163         SILC_PUT32_MSB(x, xf);
164         silc_buffer_put(dst, xf, 4);
165         silc_buffer_pull(dst, 4);
166         break;
167       }
168     case SILC_PARAM_UI64_INT:
169       {
170         unsigned char xf[8];
171         SilcUInt64 x = va_arg(ap, SilcUInt64);
172         FORMAT_HAS_SPACE(stack, dst, sizeof(SilcUInt64));
173         SILC_PUT64_MSB(x, xf);
174         silc_buffer_put(dst, xf, sizeof(SilcUInt64));
175         silc_buffer_pull(dst, sizeof(SilcUInt64));
176         break;
177       }
178     case SILC_PARAM_SI8_CHAR:
179       {
180         char x = (char)va_arg(ap, int);
181         FORMAT_HAS_SPACE(stack, dst, 1);
182         silc_buffer_put(dst, (unsigned char *)&x, 1);
183         silc_buffer_pull(dst, 1);
184         break;
185       }
186     case SILC_PARAM_SI16_SHORT:
187       {
188         unsigned char xf[2];
189         SilcInt16 x = (SilcInt16)va_arg(ap, int);
190         FORMAT_HAS_SPACE(stack, dst, 2);
191         SILC_PUT16_MSB(x, xf);
192         silc_buffer_put(dst, xf, 2);
193         silc_buffer_pull(dst, 2);
194         break;
195       }
196     case SILC_PARAM_SI32_INT:
197       {
198         unsigned char xf[4];
199         SilcInt32 x = va_arg(ap, SilcInt32);
200         FORMAT_HAS_SPACE(stack, dst, 4);
201         SILC_PUT32_MSB(x, xf);
202         silc_buffer_put(dst, xf, 4);
203         silc_buffer_pull(dst, 4);
204         break;
205       }
206     case SILC_PARAM_SI64_INT:
207       {
208         unsigned char xf[8];
209         SilcInt64 x = va_arg(ap, SilcInt64);
210         FORMAT_HAS_SPACE(stack, dst, sizeof(SilcInt64));
211         SILC_PUT64_MSB(x, xf);
212         silc_buffer_put(dst, xf, sizeof(SilcInt64));
213         silc_buffer_pull(dst, sizeof(SilcInt64));
214         break;
215       }
216     case SILC_PARAM_BUFFER:
217     case SILC_PARAM_BUFFER_ALLOC:
218       {
219         SilcBuffer x = va_arg(ap, SilcBuffer);
220         unsigned char xf[4];
221         if (x && silc_buffer_len(x)) {
222           FORMAT_HAS_SPACE(stack, dst, silc_buffer_len(x) + 4);
223           SILC_PUT32_MSB(silc_buffer_len(x), xf);
224           silc_buffer_put(dst, xf, 4);
225           silc_buffer_pull(dst, 4);
226           silc_buffer_put(dst, silc_buffer_data(x), silc_buffer_len(x));
227           silc_buffer_pull(dst, silc_buffer_len(x));
228         }
229       }
230       break;
231     case SILC_PARAM_OFFSET:
232       {
233         int offst = va_arg(ap, int);
234         if (!offst)
235           break;
236         if (offst > 1) {
237           if (offst > silc_buffer_len(dst))
238             goto fail;
239           silc_buffer_pull(dst, offst);
240           flen += offst;
241         } else {
242           silc_buffer_push(dst, -(offst));
243           flen += -(offst);
244         }
245         break;
246       }
247     case SILC_PARAM_ADVANCE:
248       advance = TRUE;
249       break;
250     case SILC_PARAM_END:
251       goto ok;
252       break;
253     default:
254       SILC_LOG_DEBUG(("Bad buffer formatting type `%d'. Could not "
255                       "format the data.", fmt));
256       goto fail;
257       break;
258     }
259   }
260
261  fail:
262   SILC_LOG_DEBUG(("Error occured while formatting data"));
263   if (!advance)
264     silc_buffer_push(dst, flen);
265   return -1;
266
267  ok:
268   /* Push the buffer back to where it belongs. */
269   if (!advance)
270     silc_buffer_push(dst, flen);
271   return flen;
272 }
273
274
275 /****************************** Unformatting ********************************/
276
277 int silc_buffer_unformat(SilcBuffer src, ...)
278 {
279   va_list ap;
280   int ret;
281
282   va_start(ap, src);
283   ret = silc_buffer_sunformat_vp(NULL, src, ap);
284   va_end(ap);
285
286   return ret;
287 }
288
289 int silc_buffer_unformat_vp(SilcBuffer src, va_list ap)
290 {
291   return silc_buffer_sunformat_vp(NULL, src, ap);
292 }
293
294 int silc_buffer_sunformat(SilcStack stack, SilcBuffer src, ...)
295 {
296   va_list ap;
297   int ret;
298
299   va_start(ap, src);
300   ret = silc_buffer_sunformat_vp(stack, src, ap);
301   va_end(ap);
302
303   return ret;
304 }
305
306 int silc_buffer_sunformat_vp(SilcStack stack, SilcBuffer src, va_list ap)
307 {
308   SilcBufferParamType fmt;
309   unsigned char *start_ptr = src->data;
310   int len = 0;
311   SilcBool advance = FALSE;
312
313   /* Parse the arguments by formatting type. */
314   while(1) {
315     fmt = va_arg(ap, SilcBufferParamType);
316
317     switch(fmt) {
318     case SILC_PARAM_FUNC:
319       {
320         SilcBufferUnformatFunc func;
321         void **val;
322         void *context;
323         int tmp_len;
324         func = va_arg(ap, SilcBufferUnformatFunc);
325         val = va_arg(ap, void **);
326         context = va_arg(ap, void *);
327         tmp_len = func(stack, src, val, context);
328         if (tmp_len < 0)
329           goto fail;
330         if (tmp_len) {
331           UNFORMAT_HAS_SPACE(src, tmp_len);
332           silc_buffer_pull(src, tmp_len);
333         }
334       }
335     case SILC_PARAM_UI_XNSTRING:
336     case SILC_PARAM_DATA:
337       {
338         unsigned char **x = va_arg(ap, unsigned char **);
339         SilcUInt32 len2 = va_arg(ap, SilcUInt32);
340         UNFORMAT_HAS_SPACE(src, len2);
341         if (silc_likely(len2 && x))
342           *x = src->data;
343         silc_buffer_pull(src, len2);
344         break;
345       }
346     case SILC_PARAM_UI_XNSTRING_ALLOC:
347     case SILC_PARAM_DATA_ALLOC:
348       {
349         unsigned char **x = va_arg(ap, unsigned char **);
350         SilcUInt32 len2 = va_arg(ap, SilcUInt32);
351         UNFORMAT_HAS_SPACE(src, len2);
352         if (silc_likely(len2 && x)) {
353           *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
354           memcpy(*x, src->data, len2);
355         }
356         silc_buffer_pull(src, len2);
357         break;
358       }
359     case SILC_PARAM_UI8_CHAR:
360       {
361         unsigned char *x = va_arg(ap, unsigned char *);
362         UNFORMAT_HAS_SPACE(src, 1);
363         if (silc_likely(x))
364           *x = src->data[0];
365         silc_buffer_pull(src, 1);
366         break;
367       }
368     case SILC_PARAM_UI16_SHORT:
369       {
370         SilcUInt16 *x = va_arg(ap, SilcUInt16 *);
371         UNFORMAT_HAS_SPACE(src, 2);
372         if (silc_likely(x))
373           SILC_GET16_MSB(*x, src->data);
374         silc_buffer_pull(src, 2);
375         break;
376       }
377     case SILC_PARAM_UI32_INT:
378       {
379         SilcUInt32 *x = va_arg(ap, SilcUInt32 *);
380         UNFORMAT_HAS_SPACE(src, 4);
381         if (silc_likely(x))
382           SILC_GET32_MSB(*x, src->data);
383         silc_buffer_pull(src, 4);
384         break;
385       }
386     case SILC_PARAM_UI64_INT:
387       {
388         SilcUInt64 *x = va_arg(ap, SilcUInt64 *);
389         UNFORMAT_HAS_SPACE(src, sizeof(SilcUInt64));
390         if (silc_likely(x))
391           SILC_GET64_MSB(*x, src->data);
392         silc_buffer_pull(src, sizeof(SilcUInt64));
393         break;
394       }
395     case SILC_PARAM_SI8_CHAR:
396       {
397         char *x = va_arg(ap, char *);
398         UNFORMAT_HAS_SPACE(src, 1);
399         if (silc_likely(x))
400           *x = src->data[0];
401         silc_buffer_pull(src, 1);
402         break;
403       }
404     case SILC_PARAM_SI16_SHORT:
405       {
406         SilcInt16 *x = va_arg(ap, SilcInt16 *);
407         UNFORMAT_HAS_SPACE(src, 2);
408         if (silc_likely(x))
409           SILC_GET16_MSB(*x, src->data);
410         silc_buffer_pull(src, 2);
411         break;
412       }
413     case SILC_PARAM_SI32_INT:
414       {
415         SilcInt32 *x = va_arg(ap, SilcInt32 *);
416         UNFORMAT_HAS_SPACE(src, 4);
417         if (silc_likely(x))
418           SILC_GET32_MSB(*x, src->data);
419         silc_buffer_pull(src, 4);
420         break;
421       }
422     case SILC_PARAM_SI64_INT:
423       {
424         SilcInt64 *x = va_arg(ap, SilcInt64 *);
425         UNFORMAT_HAS_SPACE(src, sizeof(SilcInt64));
426         if (silc_likely(x))
427           SILC_GET64_MSB(*x, src->data);
428         silc_buffer_pull(src, sizeof(SilcInt64));
429         break;
430       }
431     case SILC_PARAM_UI8_STRING:
432       {
433         SilcUInt8 len2;
434         unsigned char **x = va_arg(ap, unsigned char **);
435         UNFORMAT_HAS_SPACE(src, 1);
436         len2 = (SilcUInt8)src->data[0];
437         silc_buffer_pull(src, 1);
438         UNFORMAT_HAS_SPACE(src, len2);
439         if (silc_likely(x))
440           *x = src->data;
441         silc_buffer_pull(src, len2);
442         break;
443       }
444     case SILC_PARAM_UI16_STRING:
445       {
446         SilcUInt16 len2;
447         unsigned char **x = va_arg(ap, unsigned char **);
448         UNFORMAT_HAS_SPACE(src, 2);
449         SILC_GET16_MSB(len2, src->data);
450         silc_buffer_pull(src, 2);
451         UNFORMAT_HAS_SPACE(src, len2);
452         if (silc_likely(x))
453           *x = src->data;
454         silc_buffer_pull(src, len2);
455         break;
456       }
457     case SILC_PARAM_UI8_STRING_ALLOC:
458       {
459         SilcUInt8 len2;
460         unsigned char **x = va_arg(ap, unsigned char **);
461         UNFORMAT_HAS_SPACE(src, 1);
462         len2 = (SilcUInt8)src->data[0];
463         silc_buffer_pull(src, 1);
464         UNFORMAT_HAS_SPACE(src, len2);
465         if (silc_likely(x && len2)) {
466           *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
467           memcpy(*x, src->data, len2);
468         }
469         silc_buffer_pull(src, len2);
470         break;
471       }
472     case SILC_PARAM_UI16_STRING_ALLOC:
473       {
474         SilcUInt16 len2;
475         unsigned char **x = va_arg(ap, unsigned char **);
476         UNFORMAT_HAS_SPACE(src, 2);
477         SILC_GET16_MSB(len2, src->data);
478         silc_buffer_pull(src, 2);
479         UNFORMAT_HAS_SPACE(src, len2);
480         if (silc_likely(x && len2)) {
481           *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
482           memcpy(*x, src->data, len2);
483         }
484         silc_buffer_pull(src, len2);
485         break;
486       }
487     case SILC_PARAM_UI32_STRING:
488       {
489         SilcUInt32 len2;
490         unsigned char **x = va_arg(ap, unsigned char **);
491         UNFORMAT_HAS_SPACE(src, 4);
492         SILC_GET32_MSB(len2, src->data);
493         silc_buffer_pull(src, 4);
494         UNFORMAT_HAS_SPACE(src, len2);
495         if (silc_likely(x))
496           *x = src->data;
497         silc_buffer_pull(src, len2);
498         break;
499       }
500     case SILC_PARAM_UI32_STRING_ALLOC:
501       {
502         SilcUInt32 len2;
503         unsigned char **x = va_arg(ap, unsigned char **);
504         UNFORMAT_HAS_SPACE(src, 4);
505         SILC_GET32_MSB(len2, src->data);
506         silc_buffer_pull(src, 4);
507         UNFORMAT_HAS_SPACE(src, len2);
508         if (silc_likely(x && len2)) {
509           *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
510           memcpy(*x, src->data, len2);
511         }
512         silc_buffer_pull(src, len2);
513         break;
514       }
515     case SILC_PARAM_UI8_NSTRING:
516       {
517         SilcUInt8 len2;
518         unsigned char **x = va_arg(ap, unsigned char **);
519         SilcUInt8 *len3 = va_arg(ap, SilcUInt8 *);
520         UNFORMAT_HAS_SPACE(src, 1);
521         len2 = (SilcUInt8)src->data[0];
522         silc_buffer_pull(src, 1);
523         UNFORMAT_HAS_SPACE(src, len2);
524         if (len3)
525           *len3 = len2;
526         if (x)
527           *x = src->data;
528         silc_buffer_pull(src, len2);
529         break;
530       }
531     case SILC_PARAM_UI16_NSTRING:
532       {
533         SilcUInt16 len2;
534         unsigned char **x = va_arg(ap, unsigned char **);
535         SilcUInt16 *len3 = va_arg(ap, SilcUInt16 *);
536         UNFORMAT_HAS_SPACE(src, 2);
537         SILC_GET16_MSB(len2, src->data);
538         silc_buffer_pull(src, 2);
539         UNFORMAT_HAS_SPACE(src, len2);
540         if (len3)
541           *len3 = len2;
542         if (x)
543           *x = src->data;
544         silc_buffer_pull(src, len2);
545         break;
546       }
547     case SILC_PARAM_UI8_NSTRING_ALLOC:
548       {
549         SilcUInt8 len2;
550         unsigned char **x = va_arg(ap, unsigned char **);
551         SilcUInt8 *len3 = va_arg(ap, SilcUInt8 *);
552         UNFORMAT_HAS_SPACE(src, 1);
553         len2 = (SilcUInt8)src->data[0];
554         silc_buffer_pull(src, 1);
555         UNFORMAT_HAS_SPACE(src, len2);
556         if (len3)
557           *len3 = len2;
558         if (x && len2) {
559           *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
560           memcpy(*x, src->data, len2);
561         }
562         silc_buffer_pull(src, len2);
563         break;
564       }
565     case SILC_PARAM_UI16_NSTRING_ALLOC:
566       {
567         SilcUInt16 len2;
568         unsigned char **x = va_arg(ap, unsigned char **);
569         SilcUInt16 *len3 = va_arg(ap, SilcUInt16 *);
570         UNFORMAT_HAS_SPACE(src, 2);
571         SILC_GET16_MSB(len2, src->data);
572         silc_buffer_pull(src, 2);
573         UNFORMAT_HAS_SPACE(src, len2);
574         if (len3)
575           *len3 = len2;
576         if (x && len2) {
577           *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
578           memcpy(*x, src->data, len2);
579         }
580         silc_buffer_pull(src, len2);
581         break;
582       }
583     case SILC_PARAM_UI32_NSTRING:
584       {
585         SilcUInt32 len2;
586         unsigned char **x = va_arg(ap, unsigned char **);
587         SilcUInt32 *len3 = va_arg(ap, SilcUInt32 *);
588         UNFORMAT_HAS_SPACE(src, 4);
589         SILC_GET32_MSB(len2, src->data);
590         silc_buffer_pull(src, 4);
591         UNFORMAT_HAS_SPACE(src, len2);
592         if (len3)
593           *len3 = len2;
594         if (x)
595           *x = src->data;
596         silc_buffer_pull(src, len2);
597         break;
598       }
599     case SILC_PARAM_BUFFER:
600       {
601         SilcBuffer x = va_arg(ap, SilcBuffer);
602         SilcUInt32 len2;
603         UNFORMAT_HAS_SPACE(src, 4);
604         SILC_GET32_MSB(len2, src->data);
605         silc_buffer_pull(src, 4);
606         UNFORMAT_HAS_SPACE(src, len2);
607         silc_buffer_set(x, src->data, len2);
608         silc_buffer_pull(src, len2);
609       }
610       break;
611     case SILC_PARAM_BUFFER_ALLOC:
612       {
613         SilcBuffer x = va_arg(ap, SilcBuffer);
614         SilcUInt32 len2;
615         UNFORMAT_HAS_SPACE(src, 4);
616         SILC_GET32_MSB(len2, src->data);
617         silc_buffer_pull(src, 4);
618         UNFORMAT_HAS_SPACE(src, len2);
619         silc_buffer_sformat(stack, x,
620                             SILC_STR_DATA(src->data, len2),
621                             SILC_STR_END);
622         silc_buffer_pull(src, len2);
623       }
624       break;
625     case SILC_PARAM_OFFSET:
626       {
627         int offst = va_arg(ap, int);
628         if (!offst)
629           break;
630         if (offst > 1) {
631           UNFORMAT_HAS_SPACE(src, offst);
632           silc_buffer_pull(src, offst);
633         } else {
634           silc_buffer_push(src, -(offst));
635         }
636         break;
637       }
638     case SILC_PARAM_ADVANCE:
639       advance = TRUE;
640       break;
641     case SILC_PARAM_END:
642       goto ok;
643       break;
644     default:
645       SILC_LOG_DEBUG(("Bad buffer formatting type `%d'. Could not "
646                       "format the data.", fmt));
647       goto fail;
648       break;
649     }
650   }
651
652  fail:
653   SILC_LOG_DEBUG(("Error occured while unformatting buffer, type %d", fmt));
654   len = src->data - start_ptr;
655   silc_buffer_push(src, len);
656   return -1;
657
658  ok:
659   /* Push the buffer back to the start. */
660   if (!advance) {
661     len = src->data - start_ptr;
662     silc_buffer_push(src, len);
663   }
664   return len;
665 }
666
667
668 /**************************** Utility functions *****************************/
669
670 /* Formats strings into a buffer */
671
672 int silc_buffer_strformat(SilcBuffer dst, ...)
673 {
674   int len = silc_buffer_truelen(dst);
675   int hlen = silc_buffer_headlen(dst);
676   va_list va;
677
678   va_start(va, dst);
679
680   /* Parse the arguments by formatting type. */
681   while(1) {
682     char *string = va_arg(va, char *);
683     unsigned char *d;
684     SilcInt32 slen;
685
686     if (!string)
687       continue;
688     if (string == (char *)SILC_PARAM_END)
689       goto ok;
690
691     slen = strlen(string);
692     d = silc_realloc(dst->head, sizeof(*dst->head) * (slen + len + 1));
693     if (silc_unlikely(!d))
694       return -1;
695     dst->head = d;
696     memcpy(dst->head + len, string, slen);
697     len += slen;
698     dst->head[len] = '\0';
699   }
700
701   SILC_LOG_DEBUG(("Error occured while formatting buffer"));
702   va_end(va);
703   return -1;
704
705  ok:
706   dst->end = dst->head + len;
707   dst->data = dst->head + hlen;
708   dst->tail = dst->end;
709
710   va_end(va);
711   return len;
712 }
713
714 /* Formats strings into a buffer.  Allocates memory from SilcStack. */
715
716 int silc_buffer_sstrformat(SilcStack stack, SilcBuffer dst, ...)
717 {
718   int len = silc_buffer_truelen(dst);
719   int hlen = silc_buffer_headlen(dst);
720   va_list va;
721
722   va_start(va, dst);
723
724   /* Parse the arguments by formatting type. */
725   while(1) {
726     char *string = va_arg(va, char *);
727     unsigned char *d;
728     SilcInt32 slen;
729
730     if (!string)
731       continue;
732     if (string == (char *)SILC_PARAM_END)
733       goto ok;
734
735     slen = strlen(string);
736     d = silc_srealloc(stack, len + 1, dst->head,
737                       sizeof(*dst->head) * (slen + len + 1));
738     if (silc_unlikely(!d))
739       return -1;
740     dst->head = d;
741     memcpy(dst->head + len, string, slen);
742     len += slen;
743     dst->head[len] = '\0';
744   }
745
746   SILC_LOG_DEBUG(("Error occured while formatting buffer"));
747   va_end(va);
748   return -1;
749
750  ok:
751   dst->end = dst->head + len;
752   dst->data = dst->head + hlen;
753   dst->tail = dst->end;
754
755   va_end(va);
756   return len;
757 }