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