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