Sun Mar 11 15:22:42 CET 2007 Jochen Eisinger <coffee@silcnet.org>
[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_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 = 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   SilcBool advance = FALSE;
317
318   /* Parse the arguments by formatting type. */
319   while(1) {
320     fmt = va_arg(ap, SilcBufferParamType);
321
322     switch(fmt) {
323     case SILC_PARAM_FUNC:
324       {
325         SilcBufferUnformatFunc func = NULL;
326         SilcBufferSUnformatFunc funcs = NULL;
327         void **val;
328         void *context;
329         int tmp_len;
330         if (!stack)
331           func = va_arg(ap, SilcBufferUnformatFunc);
332         else
333           funcs = va_arg(ap, SilcBufferSUnformatFunc);
334         val = va_arg(ap, void **);
335         context = va_arg(ap, void *);
336         if (!stack)
337           tmp_len = func(src, val, context);
338         else
339           tmp_len = funcs(stack, src, val, context);
340         if (tmp_len < 0)
341           goto fail;
342         if (tmp_len) {
343           UNFORMAT_HAS_SPACE(src, tmp_len);
344           silc_buffer_pull(src, tmp_len);
345         }
346       }
347     case SILC_PARAM_UI_XNSTRING:
348     case SILC_PARAM_DATA:
349       {
350         unsigned char **x = va_arg(ap, unsigned char **);
351         SilcUInt32 len2 = va_arg(ap, SilcUInt32);
352         UNFORMAT_HAS_SPACE(src, len2);
353         if (silc_likely(len2 && x))
354           *x = src->data;
355         silc_buffer_pull(src, len2);
356         break;
357       }
358     case SILC_PARAM_UI_XNSTRING_ALLOC:
359     case SILC_PARAM_DATA_ALLOC:
360       {
361         unsigned char **x = va_arg(ap, unsigned char **);
362         SilcUInt32 len2 = va_arg(ap, SilcUInt32);
363         UNFORMAT_HAS_SPACE(src, len2);
364         if (silc_likely(len2 && x)) {
365           *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
366           memcpy(*x, src->data, len2);
367         }
368         silc_buffer_pull(src, len2);
369         break;
370       }
371     case SILC_PARAM_UI8_CHAR:
372       {
373         unsigned char *x = va_arg(ap, unsigned char *);
374         UNFORMAT_HAS_SPACE(src, 1);
375         if (silc_likely(x))
376           *x = src->data[0];
377         silc_buffer_pull(src, 1);
378         break;
379       }
380     case SILC_PARAM_UI16_SHORT:
381       {
382         SilcUInt16 *x = va_arg(ap, SilcUInt16 *);
383         UNFORMAT_HAS_SPACE(src, 2);
384         if (silc_likely(x))
385           SILC_GET16_MSB(*x, src->data);
386         silc_buffer_pull(src, 2);
387         break;
388       }
389     case SILC_PARAM_UI32_INT:
390       {
391         SilcUInt32 *x = va_arg(ap, SilcUInt32 *);
392         UNFORMAT_HAS_SPACE(src, 4);
393         if (silc_likely(x))
394           SILC_GET32_MSB(*x, src->data);
395         silc_buffer_pull(src, 4);
396         break;
397       }
398     case SILC_PARAM_UI64_INT:
399       {
400         SilcUInt64 *x = va_arg(ap, SilcUInt64 *);
401         UNFORMAT_HAS_SPACE(src, sizeof(SilcUInt64));
402         if (silc_likely(x))
403           SILC_GET64_MSB(*x, src->data);
404         silc_buffer_pull(src, sizeof(SilcUInt64));
405         break;
406       }
407     case SILC_PARAM_SI8_CHAR:
408       {
409         char *x = va_arg(ap, char *);
410         UNFORMAT_HAS_SPACE(src, 1);
411         if (silc_likely(x))
412           *x = src->data[0];
413         silc_buffer_pull(src, 1);
414         break;
415       }
416     case SILC_PARAM_SI16_SHORT:
417       {
418         SilcInt16 *x = va_arg(ap, SilcInt16 *);
419         UNFORMAT_HAS_SPACE(src, 2);
420         if (silc_likely(x))
421           SILC_GET16_MSB(*x, src->data);
422         silc_buffer_pull(src, 2);
423         break;
424       }
425     case SILC_PARAM_SI32_INT:
426       {
427         SilcInt32 *x = va_arg(ap, SilcInt32 *);
428         UNFORMAT_HAS_SPACE(src, 4);
429         if (silc_likely(x))
430           SILC_GET32_MSB(*x, src->data);
431         silc_buffer_pull(src, 4);
432         break;
433       }
434     case SILC_PARAM_SI64_INT:
435       {
436         SilcInt64 *x = va_arg(ap, SilcInt64 *);
437         UNFORMAT_HAS_SPACE(src, sizeof(SilcInt64));
438         if (silc_likely(x))
439           SILC_GET64_MSB(*x, src->data);
440         silc_buffer_pull(src, sizeof(SilcInt64));
441         break;
442       }
443     case SILC_PARAM_UI8_STRING:
444       {
445         SilcUInt8 len2;
446         unsigned char **x = va_arg(ap, unsigned char **);
447         UNFORMAT_HAS_SPACE(src, 1);
448         len2 = (SilcUInt8)src->data[0];
449         silc_buffer_pull(src, 1);
450         UNFORMAT_HAS_SPACE(src, len2);
451         if (silc_likely(x))
452           *x = src->data;
453         silc_buffer_pull(src, len2);
454         break;
455       }
456     case SILC_PARAM_UI16_STRING:
457       {
458         SilcUInt16 len2;
459         unsigned char **x = va_arg(ap, unsigned char **);
460         UNFORMAT_HAS_SPACE(src, 2);
461         SILC_GET16_MSB(len2, src->data);
462         silc_buffer_pull(src, 2);
463         UNFORMAT_HAS_SPACE(src, len2);
464         if (silc_likely(x))
465           *x = src->data;
466         silc_buffer_pull(src, len2);
467         break;
468       }
469     case SILC_PARAM_UI8_STRING_ALLOC:
470       {
471         SilcUInt8 len2;
472         unsigned char **x = va_arg(ap, unsigned char **);
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 (silc_likely(x && len2)) {
478           *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
479           memcpy(*x, src->data, len2);
480         }
481         silc_buffer_pull(src, len2);
482         break;
483       }
484     case SILC_PARAM_UI16_STRING_ALLOC:
485       {
486         SilcUInt16 len2;
487         unsigned char **x = va_arg(ap, unsigned char **);
488         UNFORMAT_HAS_SPACE(src, 2);
489         SILC_GET16_MSB(len2, src->data);
490         silc_buffer_pull(src, 2);
491         UNFORMAT_HAS_SPACE(src, len2);
492         if (silc_likely(x && len2)) {
493           *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
494           memcpy(*x, src->data, len2);
495         }
496         silc_buffer_pull(src, len2);
497         break;
498       }
499     case SILC_PARAM_UI32_STRING:
500       {
501         SilcUInt32 len2;
502         unsigned char **x = va_arg(ap, unsigned char **);
503         UNFORMAT_HAS_SPACE(src, 4);
504         SILC_GET32_MSB(len2, src->data);
505         silc_buffer_pull(src, 4);
506         UNFORMAT_HAS_SPACE(src, len2);
507         if (silc_likely(x))
508           *x = src->data;
509         silc_buffer_pull(src, len2);
510         break;
511       }
512     case SILC_PARAM_UI32_STRING_ALLOC:
513       {
514         SilcUInt32 len2;
515         unsigned char **x = va_arg(ap, unsigned char **);
516         UNFORMAT_HAS_SPACE(src, 4);
517         SILC_GET32_MSB(len2, src->data);
518         silc_buffer_pull(src, 4);
519         UNFORMAT_HAS_SPACE(src, len2);
520         if (silc_likely(x && len2)) {
521           *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
522           memcpy(*x, src->data, len2);
523         }
524         silc_buffer_pull(src, len2);
525         break;
526       }
527     case SILC_PARAM_UI8_NSTRING:
528       {
529         SilcUInt8 len2;
530         unsigned char **x = va_arg(ap, unsigned char **);
531         SilcUInt8 *len3 = va_arg(ap, SilcUInt8 *);
532         UNFORMAT_HAS_SPACE(src, 1);
533         len2 = (SilcUInt8)src->data[0];
534         silc_buffer_pull(src, 1);
535         UNFORMAT_HAS_SPACE(src, len2);
536         if (len3)
537           *len3 = len2;
538         if (x)
539           *x = src->data;
540         silc_buffer_pull(src, len2);
541         break;
542       }
543     case SILC_PARAM_UI16_NSTRING:
544       {
545         SilcUInt16 len2;
546         unsigned char **x = va_arg(ap, unsigned char **);
547         SilcUInt16 *len3 = va_arg(ap, SilcUInt16 *);
548         UNFORMAT_HAS_SPACE(src, 2);
549         SILC_GET16_MSB(len2, src->data);
550         silc_buffer_pull(src, 2);
551         UNFORMAT_HAS_SPACE(src, len2);
552         if (len3)
553           *len3 = len2;
554         if (x)
555           *x = src->data;
556         silc_buffer_pull(src, len2);
557         break;
558       }
559     case SILC_PARAM_UI8_NSTRING_ALLOC:
560       {
561         SilcUInt8 len2;
562         unsigned char **x = va_arg(ap, unsigned char **);
563         SilcUInt8 *len3 = va_arg(ap, SilcUInt8 *);
564         UNFORMAT_HAS_SPACE(src, 1);
565         len2 = (SilcUInt8)src->data[0];
566         silc_buffer_pull(src, 1);
567         UNFORMAT_HAS_SPACE(src, len2);
568         if (len3)
569           *len3 = len2;
570         if (x && len2) {
571           *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
572           memcpy(*x, src->data, len2);
573         }
574         silc_buffer_pull(src, len2);
575         break;
576       }
577     case SILC_PARAM_UI16_NSTRING_ALLOC:
578       {
579         SilcUInt16 len2;
580         unsigned char **x = va_arg(ap, unsigned char **);
581         SilcUInt16 *len3 = va_arg(ap, SilcUInt16 *);
582         UNFORMAT_HAS_SPACE(src, 2);
583         SILC_GET16_MSB(len2, src->data);
584         silc_buffer_pull(src, 2);
585         UNFORMAT_HAS_SPACE(src, len2);
586         if (len3)
587           *len3 = len2;
588         if (x && len2) {
589           *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
590           memcpy(*x, src->data, len2);
591         }
592         silc_buffer_pull(src, len2);
593         break;
594       }
595     case SILC_PARAM_UI32_NSTRING:
596       {
597         SilcUInt32 len2;
598         unsigned char **x = va_arg(ap, unsigned char **);
599         SilcUInt32 *len3 = va_arg(ap, SilcUInt32 *);
600         UNFORMAT_HAS_SPACE(src, 4);
601         SILC_GET32_MSB(len2, src->data);
602         silc_buffer_pull(src, 4);
603         UNFORMAT_HAS_SPACE(src, len2);
604         if (len3)
605           *len3 = len2;
606         if (x)
607           *x = src->data;
608         silc_buffer_pull(src, len2);
609         break;
610       }
611     case SILC_PARAM_BUFFER:
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_set(x, src->data, len2);
620         silc_buffer_pull(src, len2);
621       }
622       break;
623     case SILC_PARAM_BUFFER_ALLOC:
624       {
625         SilcBuffer x = va_arg(ap, SilcBuffer);
626         SilcUInt32 len2;
627         UNFORMAT_HAS_SPACE(src, 4);
628         SILC_GET32_MSB(len2, src->data);
629         silc_buffer_pull(src, 4);
630         UNFORMAT_HAS_SPACE(src, len2);
631         silc_buffer_sformat(stack, x,
632                             SILC_STR_DATA(src->data, len2),
633                             SILC_STR_END);
634         silc_buffer_pull(src, len2);
635       }
636       break;
637     case SILC_PARAM_OFFSET:
638       {
639         int offst = va_arg(ap, int);
640         if (!offst)
641           break;
642         if (offst > 1) {
643           UNFORMAT_HAS_SPACE(src, offst);
644           silc_buffer_pull(src, offst);
645         } else {
646           silc_buffer_push(src, -(offst));
647         }
648         break;
649       }
650     case SILC_PARAM_ADVANCE:
651       advance = TRUE;
652       break;
653     case SILC_PARAM_END:
654       goto ok;
655       break;
656     default:
657       SILC_LOG_DEBUG(("Bad buffer formatting type `%d'. Could not "
658                       "format the data.", fmt));
659       goto fail;
660       break;
661     }
662   }
663
664  fail:
665   SILC_LOG_DEBUG(("Error occured while unformatting buffer, type %d", fmt));
666   len = src->data - start_ptr;
667   silc_buffer_push(src, len);
668   return -1;
669
670  ok:
671   /* Push the buffer back to the start. */
672   if (!advance) {
673     len = src->data - start_ptr;
674     silc_buffer_push(src, len);
675   }
676   return len;
677 }
678
679
680 /**************************** Utility functions *****************************/
681
682 /* Formats strings into a buffer */
683
684 int silc_buffer_strformat(SilcBuffer dst, ...)
685 {
686   int len = silc_buffer_truelen(dst);
687   int hlen = silc_buffer_headlen(dst);
688   va_list va;
689
690   va_start(va, dst);
691
692   /* Parse the arguments by formatting type. */
693   while(1) {
694     char *string = va_arg(va, char *);
695     unsigned char *d;
696     SilcInt32 slen;
697
698     if (!string)
699       continue;
700     if (string == (char *)SILC_PARAM_END)
701       goto ok;
702
703     slen = strlen(string);
704     d = silc_realloc(dst->head, sizeof(*dst->head) * (slen + len + 1));
705     if (silc_unlikely(!d))
706       return -1;
707     dst->head = d;
708     memcpy(dst->head + len, string, slen);
709     len += slen;
710     dst->head[len] = '\0';
711   }
712
713   SILC_LOG_DEBUG(("Error occured while formatting buffer"));
714   va_end(va);
715   return -1;
716
717  ok:
718   dst->end = dst->head + len;
719   dst->data = dst->head + hlen;
720   dst->tail = dst->end;
721
722   va_end(va);
723   return len;
724 }
725
726 /* Formats strings into a buffer.  Allocates memory from SilcStack. */
727
728 int silc_buffer_sstrformat(SilcStack stack, SilcBuffer dst, ...)
729 {
730   int len = silc_buffer_truelen(dst);
731   int hlen = silc_buffer_headlen(dst);
732   va_list va;
733
734   va_start(va, dst);
735
736   /* Parse the arguments by formatting type. */
737   while(1) {
738     char *string = va_arg(va, char *);
739     unsigned char *d;
740     SilcInt32 slen;
741
742     if (!string)
743       continue;
744     if (string == (char *)SILC_PARAM_END)
745       goto ok;
746
747     slen = strlen(string);
748     d = silc_srealloc_ua(stack, len + 1, dst->head,
749                          sizeof(*dst->head) * (slen + len + 1));
750     if (silc_unlikely(!d))
751       return -1;
752     dst->head = d;
753     memcpy(dst->head + len, string, slen);
754     len += slen;
755     dst->head[len] = '\0';
756   }
757
758   SILC_LOG_DEBUG(("Error occured while formatting buffer"));
759   va_end(va);
760   return -1;
761
762  ok:
763   dst->end = dst->head + len;
764   dst->data = dst->head + hlen;
765   dst->tail = dst->end;
766
767   va_end(va);
768   return len;
769 }