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