b0c5d5c5beb8dfa110eb2eef704902daa205dfed
[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     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   SilcParam 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, SilcParam);
88
89     SILC_LOG_DEBUG(("Buffer format type %x", fmt));
90
91     switch (fmt) {
92     case SILC_PARAM_FUNC:
93       {
94         SilcBufferFormatFunc func;
95         void *val;
96         void *context;
97         int tmp_len;
98         func = va_arg(ap, SilcBufferFormatFunc);
99         val = va_arg(ap, void *);
100         context = va_arg(ap, void *);
101         tmp_len = func(stack, dst, val, context);
102         if (tmp_len < 0)
103           goto fail;
104         if (tmp_len) {
105           silc_buffer_pull(dst, tmp_len);
106           flen += tmp_len;
107         }
108       }
109       break;
110     case SILC_PARAM_UI8_STRING:
111     case SILC_PARAM_UI16_STRING:
112     case SILC_PARAM_UI32_STRING:
113     case SILC_PARAM_UI8_STRING | SILC_PARAM_ALLOC:
114     case SILC_PARAM_UI16_STRING | SILC_PARAM_ALLOC:
115     case SILC_PARAM_UI32_STRING | SILC_PARAM_ALLOC:
116       {
117         char *x = va_arg(ap, char *);
118         SilcUInt32 tmp_len = x ? strlen(x) : 0;
119         if (x && tmp_len) {
120           FORMAT_HAS_SPACE(stack, dst, tmp_len);
121           silc_buffer_put(dst, (unsigned char *)x, tmp_len);
122           silc_buffer_pull(dst, tmp_len);
123         }
124         break;
125       }
126     case SILC_PARAM_UI8_NSTRING:
127     case SILC_PARAM_UI16_NSTRING:
128     case SILC_PARAM_UI32_NSTRING:
129     case SILC_PARAM_UICHAR:
130     case SILC_PARAM_UI8_NSTRING | SILC_PARAM_ALLOC:
131     case SILC_PARAM_UI16_NSTRING | SILC_PARAM_ALLOC:
132     case SILC_PARAM_UI32_NSTRING | SILC_PARAM_ALLOC:
133     case SILC_PARAM_UICHAR | SILC_PARAM_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_UINT8:
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_UINT16:
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_UINT32:
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_UINT64:
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_SINT8:
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_SINT16:
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_SINT32:
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_SINT64:
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 | SILC_PARAM_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   SilcParam 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, SilcParam);
324
325     SILC_LOG_DEBUG(("Buffer unformat type %x", fmt));
326
327     switch (fmt) {
328     case SILC_PARAM_FUNC:
329       {
330         SilcBufferUnformatFunc func;
331         void **val;
332         void *context;
333         int tmp_len;
334         func = va_arg(ap, SilcBufferUnformatFunc);
335         val = va_arg(ap, void **);
336         context = va_arg(ap, void *);
337         tmp_len = func(stack, src, val, context);
338         if (tmp_len < 0)
339           goto fail;
340         if (tmp_len) {
341           UNFORMAT_HAS_SPACE(src, tmp_len);
342           silc_buffer_pull(src, tmp_len);
343         }
344       }
345     case SILC_PARAM_UICHAR:
346       {
347         unsigned char **x = va_arg(ap, unsigned char **);
348         SilcUInt32 len2 = va_arg(ap, SilcUInt32);
349         UNFORMAT_HAS_SPACE(src, len2);
350         if (silc_likely(len2 && x))
351           *x = src->data;
352         silc_buffer_pull(src, len2);
353         break;
354       }
355     case SILC_PARAM_UICHAR | SILC_PARAM_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_UINT8:
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_UINT16:
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_UINT32:
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_UINT64:
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_SINT8:
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_SINT16:
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_SINT32:
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_SINT64:
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_UI8_STRING | SILC_PARAM_ALLOC:
453       {
454         SilcUInt8 len2;
455         unsigned char **x = va_arg(ap, unsigned char **);
456         UNFORMAT_HAS_SPACE(src, 1);
457         len2 = (SilcUInt8)src->data[0];
458         silc_buffer_pull(src, 1);
459         UNFORMAT_HAS_SPACE(src, len2);
460         if (silc_likely(x && len2)) {
461           *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
462           memcpy(*x, src->data, len2);
463         }
464         silc_buffer_pull(src, len2);
465         break;
466       }
467     case SILC_PARAM_UI16_STRING:
468       {
469         SilcUInt16 len2;
470         unsigned char **x = va_arg(ap, unsigned char **);
471         UNFORMAT_HAS_SPACE(src, 2);
472         SILC_GET16_MSB(len2, src->data);
473         silc_buffer_pull(src, 2);
474         UNFORMAT_HAS_SPACE(src, len2);
475         if (silc_likely(x))
476           *x = src->data;
477         silc_buffer_pull(src, len2);
478         break;
479       }
480     case SILC_PARAM_UI16_STRING | SILC_PARAM_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 | SILC_PARAM_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_UI8_NSTRING | SILC_PARAM_ALLOC:
540       {
541         SilcUInt8 len2;
542         unsigned char **x = va_arg(ap, unsigned char **);
543         SilcUInt8 *len3 = va_arg(ap, SilcUInt8 *);
544         UNFORMAT_HAS_SPACE(src, 1);
545         len2 = (SilcUInt8)src->data[0];
546         silc_buffer_pull(src, 1);
547         UNFORMAT_HAS_SPACE(src, len2);
548         if (len3)
549           *len3 = len2;
550         if (x && len2) {
551           *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
552           memcpy(*x, src->data, len2);
553         }
554         silc_buffer_pull(src, len2);
555         break;
556       }
557     case SILC_PARAM_UI16_NSTRING:
558       {
559         SilcUInt16 len2;
560         unsigned char **x = va_arg(ap, unsigned char **);
561         SilcUInt16 *len3 = va_arg(ap, SilcUInt16 *);
562         UNFORMAT_HAS_SPACE(src, 2);
563         SILC_GET16_MSB(len2, src->data);
564         silc_buffer_pull(src, 2);
565         UNFORMAT_HAS_SPACE(src, len2);
566         if (len3)
567           *len3 = len2;
568         if (x)
569           *x = src->data;
570         silc_buffer_pull(src, len2);
571         break;
572       }
573     case SILC_PARAM_UI16_NSTRING | SILC_PARAM_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_UI32_NSTRING | SILC_PARAM_ALLOC:
608       {
609         SilcUInt32 len2;
610         unsigned char **x = va_arg(ap, unsigned char **);
611         SilcUInt32 *len3 = va_arg(ap, SilcUInt32 *);
612         UNFORMAT_HAS_SPACE(src, 4);
613         SILC_GET32_MSB(len2, src->data);
614         silc_buffer_pull(src, 4);
615         UNFORMAT_HAS_SPACE(src, len2);
616         if (len3)
617           *len3 = len2;
618         if (silc_likely(x && len2)) {
619           *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
620           memcpy(*x, src->data, len2);
621         }
622         silc_buffer_pull(src, len2);
623         break;
624       }
625     case SILC_PARAM_BUFFER:
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_set(x, src->data, len2);
634         silc_buffer_pull(src, len2);
635       }
636       break;
637     case SILC_PARAM_BUFFER | SILC_PARAM_ALLOC:
638       {
639         SilcBuffer x = va_arg(ap, SilcBuffer);
640         SilcUInt32 len2;
641         UNFORMAT_HAS_SPACE(src, 4);
642         SILC_GET32_MSB(len2, src->data);
643         silc_buffer_pull(src, 4);
644         UNFORMAT_HAS_SPACE(src, len2);
645         silc_buffer_sformat(stack, x,
646                             SILC_STR_DATA(src->data, len2),
647                             SILC_STR_END);
648         silc_buffer_pull(src, len2);
649       }
650       break;
651     case SILC_PARAM_OFFSET:
652       {
653         int offst = va_arg(ap, int);
654         if (!offst)
655           break;
656         if (offst > 1) {
657           UNFORMAT_HAS_SPACE(src, offst);
658           silc_buffer_pull(src, offst);
659         } else {
660           silc_buffer_push(src, -(offst));
661         }
662         break;
663       }
664     case SILC_PARAM_ADVANCE:
665       advance = TRUE;
666       break;
667     case SILC_PARAM_END:
668       goto ok;
669       break;
670     default:
671       SILC_LOG_DEBUG(("Bad buffer formatting type `%d'. Could not "
672                       "format the data.", fmt));
673       silc_set_errno_reason(SILC_ERR_INVALID_ARGUMENT,
674                             "Bad buffer formatting type %d", fmt);
675       goto fail;
676       break;
677     }
678   }
679
680  fail:
681   SILC_LOG_DEBUG(("Error occured while unformatting buffer, type %d", fmt));
682   len = src->data - start_ptr;
683   silc_buffer_push(src, len);
684   return -1;
685
686  ok:
687   /* Push the buffer back to the start. */
688   if (!advance) {
689     len = src->data - start_ptr;
690     silc_buffer_push(src, len);
691   }
692   return len;
693 }
694
695
696 /**************************** Utility functions *****************************/
697
698 /* Formats strings into a buffer */
699
700 int silc_buffer_strformat(SilcBuffer dst, ...)
701 {
702   int len = silc_buffer_truelen(dst);
703   int hlen = silc_buffer_headlen(dst);
704   va_list va;
705
706   va_start(va, dst);
707
708   /* Parse the arguments by formatting type. */
709   while(1) {
710     char *string = va_arg(va, char *);
711     unsigned char *d;
712     SilcInt32 slen;
713
714     if (!string)
715       continue;
716     if (string == (char *)SILC_PARAM_END)
717       goto ok;
718
719     slen = strlen(string);
720     d = silc_realloc(dst->head, sizeof(*dst->head) * (slen + len + 1));
721     if (silc_unlikely(!d))
722       return -1;
723     dst->head = d;
724     memcpy(dst->head + len, string, slen);
725     len += slen;
726     dst->head[len] = '\0';
727   }
728
729   SILC_LOG_DEBUG(("Error occured while formatting buffer"));
730   va_end(va);
731   return -1;
732
733  ok:
734   dst->end = dst->head + len;
735   dst->data = dst->head + hlen;
736   dst->tail = dst->end;
737
738   va_end(va);
739   return len;
740 }
741
742 /* Formats strings into a buffer.  Allocates memory from SilcStack. */
743
744 int silc_buffer_sstrformat(SilcStack stack, SilcBuffer dst, ...)
745 {
746   int len = silc_buffer_truelen(dst);
747   int hlen = silc_buffer_headlen(dst);
748   va_list va;
749
750   va_start(va, dst);
751
752   /* Parse the arguments by formatting type. */
753   while(1) {
754     char *string = va_arg(va, char *);
755     unsigned char *d;
756     SilcInt32 slen;
757
758     if (!string)
759       continue;
760     if (string == (char *)SILC_PARAM_END)
761       goto ok;
762
763     slen = strlen(string);
764     d = silc_srealloc(stack, len + 1, dst->head,
765                       sizeof(*dst->head) * (slen + len + 1));
766     if (silc_unlikely(!d))
767       return -1;
768     dst->head = d;
769     memcpy(dst->head + len, string, slen);
770     len += slen;
771     dst->head[len] = '\0';
772   }
773
774   SILC_LOG_DEBUG(("Error occured while formatting buffer"));
775   va_end(va);
776   return -1;
777
778  ok:
779   dst->end = dst->head + len;
780   dst->data = dst->head + hlen;
781   dst->tail = dst->end;
782
783   va_end(va);
784   return len;
785 }