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