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