Merge branch 'silc.1.1.branch' of silc repo
[runtime.git] / lib / silcutil / silcbuffmt.c
1 /*
2
3   silcbuffmt.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2008 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
20 #include "silcruntime.h"
21
22 /************************** Types and definitions ***************************/
23
24 /* Check that buffer has enough room to format data in it, if not
25    allocate more. */
26 #define FORMAT_HAS_SPACE(s, b, req)                     \
27 do {                                                    \
28   if (silc_unlikely(!silc_buffer_senlarge(s, b, req)))  \
29     goto fail;                                          \
30   flen += req;                                          \
31 } while(0)
32
33 /* Check that buffer has enough room to format data in it, if not
34    allocate more.  This will append, thus not replacing any existing data. */
35 #define FORMAT_HAS_SPACE_APPEND(s, b, req)                              \
36 do {                                                                    \
37   if (silc_buffer_len(b) < req)                                         \
38     if (silc_unlikely(!silc_buffer_sappend(s, b, req - silc_buffer_len(b)))) \
39       goto fail;                                                        \
40   flen += req;                                                          \
41 } while(0)
42
43 /* Check that there is data to be unformatted */
44 #define UNFORMAT_HAS_SPACE(b, req)                      \
45 do {                                                    \
46   if (silc_unlikely(req > silc_buffer_len(b))) {        \
47     silc_set_errno(SILC_ERR_OVERFLOW);                  \
48     goto fail;                                          \
49   }                                                     \
50   if (silc_unlikely((req + 1) <= 0)) {                  \
51     silc_set_errno(SILC_ERR_OVERFLOW);                  \
52     goto fail;                                          \
53   }                                                     \
54 } while(0)
55
56 #if defined(SILC_DEBUG)
57 static const char *silc_param_string(SilcParam fmt)
58 {
59   if (fmt == SILC_PARAM_SINT8)
60     return "SINT8";
61   if (fmt == SILC_PARAM_UINT8)
62     return "UINT8";
63   if (fmt == SILC_PARAM_SINT16)
64     return "SINT16";
65   if (fmt == SILC_PARAM_UINT16)
66     return "UINT16";
67   if (fmt == SILC_PARAM_SINT32)
68     return "SINT32";
69   if (fmt == SILC_PARAM_UINT32)
70     return "UINT32";
71   if (fmt == SILC_PARAM_SINT64)
72     return "SINT64";
73   if (fmt == SILC_PARAM_UINT64)
74     return "UINT64";
75   if (fmt == SILC_PARAM_SICHAR)
76     return "SICHAR";
77   if (fmt == (SILC_PARAM_SICHAR | SILC_PARAM_ALLOC))
78     return "SICHAR ALLOC";
79   if (fmt == SILC_PARAM_UICHAR)
80     return "UICHAR";
81   if (fmt == (SILC_PARAM_UICHAR | SILC_PARAM_ALLOC))
82     return "UICHAR ALLOC";
83   if (fmt == (SILC_PARAM_UICHAR | SILC_PARAM_REPLACE))
84     return "UICHAR REPLACE";
85   if (fmt == SILC_PARAM_BUFFER)
86     return "BUFFER";
87   if (fmt == (SILC_PARAM_BUFFER | SILC_PARAM_ALLOC))
88     return "BUFFER ALLOC";
89   if (fmt == SILC_PARAM_PTR)
90     return "PTR";
91   if (fmt == SILC_PARAM_END)
92     return "END";
93   if (fmt == SILC_PARAM_UI8_STRING)
94     return "UI8_STRING";
95   if (fmt == SILC_PARAM_UI16_STRING)
96     return "UI16_STRING";
97   if (fmt == SILC_PARAM_UI32_STRING)
98     return "UI32_STRING";
99   if (fmt == SILC_PARAM_UI8_NSTRING)
100     return "UI8_STRING";
101   if (fmt == SILC_PARAM_UI16_NSTRING)
102     return "UI16_STRING";
103   if (fmt == SILC_PARAM_UI32_NSTRING)
104     return "UI32_STRING";
105   if (fmt == (SILC_PARAM_UI8_STRING | SILC_PARAM_ALLOC))
106     return "UI8_STRING ALLOC";
107   if (fmt == (SILC_PARAM_UI16_STRING | SILC_PARAM_ALLOC))
108     return "UI16_STRING ALLOC";
109   if (fmt == (SILC_PARAM_UI32_STRING | SILC_PARAM_ALLOC))
110     return "UI32_STRING ALLOC";
111   if (fmt == (SILC_PARAM_UI8_NSTRING | SILC_PARAM_ALLOC))
112     return "UI8_STRING ALLOC";
113   if (fmt == (SILC_PARAM_UI16_NSTRING | SILC_PARAM_ALLOC))
114     return "UI16_STRING ALLOC";
115   if (fmt == (SILC_PARAM_UI32_NSTRING | SILC_PARAM_ALLOC))
116     return "UI32_STRING";
117   if (fmt == SILC_PARAM_OFFSET)
118     return "OFFSET";
119   if (fmt == SILC_PARAM_ADVANCE)
120     return "ADDVANCE";
121   if (fmt == SILC_PARAM_FUNC)
122     return "FUNC";
123   if (fmt == SILC_PARAM_REGEX)
124     return "REGEX";
125   if (fmt == SILC_PARAM_OFFSET_START)
126     return "OFFSET_START";
127   if (fmt == SILC_PARAM_OFFSET_END)
128     return "OFFSET_END";
129   if (fmt == SILC_PARAM_DELETE)
130     return "DELETE";
131   return "";
132 }
133 #endif /* SILC_DEBUG */
134
135 /******************************* Formatting *********************************/
136
137 int silc_buffer_sformat_vp_i(SilcStack stack, SilcBuffer dst, va_list ap,
138                              SilcBool process)
139 {
140   SilcParam fmt;
141   int flen = 0;
142   SilcBool advance = FALSE;
143
144   /* Parse the arguments by formatting type. */
145   while (1) {
146     fmt = va_arg(ap, SilcParam);
147
148 #if defined(SILC_DEBUG)
149     if (process)
150       SILC_LOG_DEBUG(("Buffer format type %s (%d)",
151                       silc_param_string(fmt), fmt));
152 #endif /* SILC_DEBUG */
153
154     switch (fmt) {
155     case SILC_PARAM_FUNC:
156       {
157         SilcBufferFormatFunc func;
158         void *val;
159         void *context;
160         int tmp_len;
161
162         func = va_arg(ap, SilcBufferFormatFunc);
163         val = va_arg(ap, void *);
164         context = va_arg(ap, void *);
165
166         if (!process)
167           break;
168
169         tmp_len = func(stack, dst, val, context);
170         if (tmp_len < 0)
171           goto fail;
172         if (tmp_len) {
173           silc_buffer_pull(dst, tmp_len);
174           flen += tmp_len;
175         }
176         break;
177       }
178
179     case SILC_PARAM_REGEX:
180       {
181         const char *regex = va_arg(ap, char *);
182         SilcBufferRegexFlags rflags = va_arg(ap, SilcBufferRegexFlags);
183         SilcBufferStruct match;
184         SilcBool match_all = (rflags & SILC_STR_REGEX_ALL) != 0;
185         SilcBool match_nl = (rflags & SILC_STR_REGEX_NL) != 0;
186         SilcBool ret;
187         SilcUInt32 inclusive_pos = 0;
188         int matched = 0, ret_len;
189         va_list cp;
190
191         if (!process)
192           break;
193
194         if (!regex)
195           break;
196
197         if (match_nl) {
198         start_nl_match:
199           /* Match for '\n' in the buffer.  If not found, treat as line
200              without '\n' (buffer has only one line, or this is last line). */
201           if (silc_regex_buffer(dst, "\n", &match, NULL))
202             dst->tail = match.tail;
203         }
204
205       start_match:
206         /* Match */
207         ret = silc_regex_buffer(dst, regex, &match, NULL);
208         ret ^= (rflags & SILC_STR_REGEX_NOT) != 0;
209         if (!ret) {
210           if (!matched && rflags & SILC_STR_REGEX_MISMATCH) {
211             silc_set_errno(SILC_ERR_NOT_FOUND);
212             goto fail;
213           }
214           goto end_match;
215         }
216         matched++;
217
218         if (rflags & SILC_STR_REGEX_NOT)
219           match = *dst;
220
221         if (!(rflags & SILC_STR_REGEX_NO_ADVANCE)) {
222           /* Advance buffer after match */
223           flen += (match.data - dst->data);
224           if (!silc_buffer_pull(dst, (match.data - dst->data)))
225             goto fail;
226         }
227
228         if (rflags & SILC_STR_REGEX_INCLUSIVE) {
229           inclusive_pos = dst->tail - match.tail;
230           dst->tail = match.tail;
231         }
232
233         /* Recursively format */
234         silc_va_copy(cp, ap);
235         ret_len = silc_buffer_sformat_vp_i(stack, dst, cp, TRUE);
236         va_end(cp);
237         if (ret_len < 0)
238           goto fail;
239
240         if (rflags & SILC_STR_REGEX_INCLUSIVE)
241           if (!silc_buffer_pull_tail(dst, inclusive_pos))
242             goto fail;
243
244         /* Advance buffer after formatting */
245         flen += ret_len;
246         if (!silc_buffer_pull(dst, ret_len))
247           goto fail;
248
249         if (match_all && (!match_nl || silc_buffer_len(dst) > 1))
250           goto start_match;
251
252       end_match:
253         if (match_nl) {
254           /* Go to next line, it is at the end of the data area.  Adjust
255              the tail area of the target buffer to show rest of the buffer. */
256           flen += (dst->tail - dst->data);
257           if (!silc_buffer_pull(dst, (dst->tail - dst->data)))
258             goto fail;
259           if (!silc_buffer_pull_tail(dst, silc_buffer_taillen(dst)))
260             goto fail;
261
262           if (silc_buffer_len(dst) > 0)
263             goto start_nl_match;
264         }
265
266         /* Skip to the next SILC_PARAM_END */
267         silc_buffer_sformat_vp_i(NULL, NULL, ap, FALSE);
268         break;
269       }
270
271     case SILC_PARAM_UI8_STRING:
272     case SILC_PARAM_UI16_STRING:
273     case SILC_PARAM_UI32_STRING:
274     case SILC_PARAM_UI8_STRING | SILC_PARAM_ALLOC:
275     case SILC_PARAM_UI16_STRING | SILC_PARAM_ALLOC:
276     case SILC_PARAM_UI32_STRING | SILC_PARAM_ALLOC:
277       {
278         char *x = va_arg(ap, char *);
279         SilcUInt32 tmp_len = x ? strlen(x) : 0;
280
281         if (!process)
282           break;
283
284         if (x && tmp_len) {
285           FORMAT_HAS_SPACE(stack, dst, tmp_len);
286           silc_buffer_put(dst, (unsigned char *)x, tmp_len);
287           silc_buffer_pull(dst, tmp_len);
288         }
289         break;
290       }
291
292     case SILC_PARAM_UICHAR | SILC_PARAM_REPLACE:
293       {
294         unsigned char *x = va_arg(ap, unsigned char *);
295         SilcUInt32 x_len = va_arg(ap, SilcUInt32);
296
297         if (!process)
298           break;
299
300         if (!x)
301           break;
302
303         if (silc_buffer_len(dst) == x_len) {
304           /* Replace */
305           if (x_len) {
306             silc_buffer_put(dst, x, x_len);
307             silc_buffer_pull(dst, x_len);
308             flen += x_len;
309           }
310         } else if (silc_buffer_len(dst) < x_len) {
311           /* Append */
312           if (x_len) {
313             FORMAT_HAS_SPACE_APPEND(stack, dst, x_len);
314             silc_buffer_put(dst, x, x_len);
315             silc_buffer_pull(dst, x_len);
316           }
317         } else {
318           /* Delete */
319           if (x_len) {
320             silc_buffer_put(dst, x, x_len);
321             silc_buffer_pull(dst, x_len);
322             flen += x_len;
323           }
324           goto delete_rest;
325         }
326         break;
327       }
328
329     case SILC_PARAM_UI8_NSTRING:
330     case SILC_PARAM_UI16_NSTRING:
331     case SILC_PARAM_UI32_NSTRING:
332     case SILC_PARAM_UICHAR:
333     case SILC_PARAM_UI8_NSTRING | SILC_PARAM_ALLOC:
334     case SILC_PARAM_UI16_NSTRING | SILC_PARAM_ALLOC:
335     case SILC_PARAM_UI32_NSTRING | SILC_PARAM_ALLOC:
336     case SILC_PARAM_UICHAR | SILC_PARAM_ALLOC:
337       {
338         unsigned char *x = va_arg(ap, unsigned char *);
339         SilcUInt32 tmp_len = va_arg(ap, SilcUInt32);
340
341         if (!process)
342           break;
343
344         if (x && tmp_len) {
345           FORMAT_HAS_SPACE(stack, dst, tmp_len);
346           silc_buffer_put(dst, x, tmp_len);
347           silc_buffer_pull(dst, tmp_len);
348         }
349         break;
350       }
351
352     case SILC_PARAM_UINT8:
353       {
354         unsigned char x = (unsigned char)va_arg(ap, int);
355
356         if (!process)
357           break;
358
359         FORMAT_HAS_SPACE(stack, dst, 1);
360         silc_buffer_put(dst, &x, 1);
361         silc_buffer_pull(dst, 1);
362         break;
363       }
364
365     case SILC_PARAM_UINT16:
366       {
367         unsigned char xf[2];
368         SilcUInt16 x = (SilcUInt16)va_arg(ap, int);
369
370         if (!process)
371           break;
372
373         FORMAT_HAS_SPACE(stack, dst, 2);
374         SILC_PUT16_MSB(x, xf);
375         silc_buffer_put(dst, xf, 2);
376         silc_buffer_pull(dst, 2);
377         break;
378       }
379
380     case SILC_PARAM_UINT32:
381       {
382         unsigned char xf[4];
383         SilcUInt32 x = va_arg(ap, SilcUInt32);
384
385         if (!process)
386           break;
387
388         FORMAT_HAS_SPACE(stack, dst, 4);
389         SILC_PUT32_MSB(x, xf);
390         silc_buffer_put(dst, xf, 4);
391         silc_buffer_pull(dst, 4);
392         break;
393       }
394
395     case SILC_PARAM_UINT64:
396       {
397         unsigned char xf[8];
398         SilcUInt64 x = va_arg(ap, SilcUInt64);
399
400         if (!process)
401           break;
402
403         FORMAT_HAS_SPACE(stack, dst, sizeof(SilcUInt64));
404         SILC_PUT64_MSB(x, xf);
405         silc_buffer_put(dst, xf, sizeof(SilcUInt64));
406         silc_buffer_pull(dst, sizeof(SilcUInt64));
407         break;
408       }
409
410     case SILC_PARAM_SINT8:
411       {
412         char x = (char)va_arg(ap, int);
413
414         if (!process)
415           break;
416
417         FORMAT_HAS_SPACE(stack, dst, 1);
418         silc_buffer_put(dst, (unsigned char *)&x, 1);
419         silc_buffer_pull(dst, 1);
420         break;
421       }
422
423     case SILC_PARAM_SINT16:
424       {
425         unsigned char xf[2];
426         SilcInt16 x = (SilcInt16)va_arg(ap, int);
427
428         if (!process)
429           break;
430
431         FORMAT_HAS_SPACE(stack, dst, 2);
432         SILC_PUT16_MSB(x, xf);
433         silc_buffer_put(dst, xf, 2);
434         silc_buffer_pull(dst, 2);
435         break;
436       }
437
438     case SILC_PARAM_SINT32:
439       {
440         unsigned char xf[4];
441         SilcInt32 x = va_arg(ap, SilcInt32);
442
443         if (!process)
444           break;
445
446         FORMAT_HAS_SPACE(stack, dst, 4);
447         SILC_PUT32_MSB(x, xf);
448         silc_buffer_put(dst, xf, 4);
449         silc_buffer_pull(dst, 4);
450         break;
451       }
452
453     case SILC_PARAM_SINT64:
454       {
455         unsigned char xf[8];
456         SilcInt64 x = va_arg(ap, SilcInt64);
457
458         if (!process)
459           break;
460
461         FORMAT_HAS_SPACE(stack, dst, sizeof(SilcInt64));
462         SILC_PUT64_MSB(x, xf);
463         silc_buffer_put(dst, xf, sizeof(SilcInt64));
464         silc_buffer_pull(dst, sizeof(SilcInt64));
465         break;
466       }
467
468     case SILC_PARAM_BUFFER:
469     case SILC_PARAM_BUFFER | SILC_PARAM_ALLOC:
470       {
471         SilcBuffer x = va_arg(ap, SilcBuffer);
472         unsigned char xf[4];
473
474         if (!process)
475           break;
476
477         if (x && silc_buffer_len(x)) {
478           FORMAT_HAS_SPACE(stack, dst, silc_buffer_len(x) + 4);
479           SILC_PUT32_MSB(silc_buffer_len(x), xf);
480           silc_buffer_put(dst, xf, 4);
481           silc_buffer_pull(dst, 4);
482           silc_buffer_put(dst, silc_buffer_data(x), silc_buffer_len(x));
483           silc_buffer_pull(dst, silc_buffer_len(x));
484         }
485       }
486       break;
487
488     case SILC_PARAM_DELETE:
489       {
490         int n = va_arg(ap, int);
491
492         if (!process)
493           break;
494
495         if (n == -1) {
496           /* Move all data from tail to data area */
497           if (dst->data != dst->tail) {
498           delete_rest:
499             n = silc_buffer_len(dst);
500             memmove(dst->data, dst->tail, silc_buffer_taillen(dst));
501             silc_buffer_push_tail(dst, n);
502             if (!silc_buffer_srealloc(stack, dst,
503                                       silc_buffer_truelen(dst) - n))
504               goto fail;
505           }
506           break;
507         }
508
509         if (n > silc_buffer_len(dst))
510           goto fail;
511
512         memmove(dst->data, dst->data + n, (silc_buffer_len(dst) - n) +
513                 silc_buffer_taillen(dst));
514         silc_buffer_push_tail(dst, silc_buffer_len(dst) - n);
515         if (!silc_buffer_srealloc(stack, dst, silc_buffer_truelen(dst) - n))
516           goto fail;
517
518         break;
519       }
520
521     case SILC_PARAM_OFFSET:
522       {
523         int offst = va_arg(ap, int);
524
525         if (!process)
526           break;
527
528         if (!offst)
529           break;
530
531         if (offst > 1) {
532           if (offst > silc_buffer_len(dst)) {
533             silc_set_errno(SILC_ERR_OVERFLOW);
534             goto fail;
535           }
536           silc_buffer_pull(dst, offst);
537           flen += offst;
538         } else {
539           silc_buffer_push(dst, -(offst));
540           flen += -(offst);
541         }
542         break;
543       }
544
545     case SILC_PARAM_OFFSET_START:
546       if (!process)
547         break;
548       if (!silc_buffer_push(dst, flen))
549         goto fail;
550       flen = 0;
551       break;
552
553     case SILC_PARAM_OFFSET_END:
554       if (!process)
555         break;
556       flen += silc_buffer_len(dst);
557       silc_buffer_pull(dst, silc_buffer_len(dst));
558       break;
559
560     case SILC_PARAM_ADVANCE:
561       if (!process)
562         break;
563       advance = TRUE;
564       break;
565
566     case SILC_PARAM_END:
567       goto ok;
568       break;
569
570     default:
571       SILC_LOG_DEBUG(("Bad buffer formatting type `%d'. Could not "
572                       "format the data.", fmt));
573       silc_set_errno_reason(SILC_ERR_INVALID_ARGUMENT,
574                             "Bad buffer formatting type %d", fmt);
575       goto fail;
576       break;
577     }
578   }
579
580  fail:
581   SILC_LOG_DEBUG(("Error occured while formatting data"));
582   if (process && !advance)
583     silc_buffer_push(dst, flen);
584   return -1;
585
586  ok:
587   /* Push the buffer back to where it belongs. */
588   if (process && !advance)
589     silc_buffer_push(dst, flen);
590   return flen;
591 }
592
593 int silc_buffer_format(SilcBuffer dst, ...)
594 {
595   va_list ap;
596   int ret;
597
598   va_start(ap, dst);
599   ret = silc_buffer_sformat_vp(NULL, dst, ap);
600   va_end(ap);
601
602   return ret;
603 }
604
605 int silc_buffer_format_vp(SilcBuffer dst, va_list ap)
606 {
607   return silc_buffer_sformat_vp(NULL, dst, ap);
608 }
609
610 int silc_buffer_sformat(SilcStack stack, SilcBuffer dst, ...)
611 {
612   va_list ap;
613   int ret;
614
615   va_start(ap, dst);
616   ret = silc_buffer_sformat_vp(stack, dst, ap);
617   va_end(ap);
618
619   return ret;
620 }
621
622 int silc_buffer_sformat_vp(SilcStack stack, SilcBuffer dst, va_list ap)
623 {
624   return silc_buffer_sformat_vp_i(stack, dst, ap, TRUE);
625 }
626
627 /****************************** Unformatting ********************************/
628
629 int silc_buffer_sunformat_vp_i(SilcStack stack, SilcBuffer src, va_list ap,
630                                SilcBool process)
631 {
632   SilcParam fmt;
633   unsigned char *start_ptr = src->data;
634   int len = 0;
635   SilcBool advance = FALSE;
636
637   /* Parse the arguments by formatting type. */
638   while (1) {
639     fmt = va_arg(ap, SilcParam);
640
641     SILC_LOG_DEBUG(("Buffer unformat type %s (%d)",
642                     silc_param_string(fmt), fmt));
643
644     switch (fmt) {
645     case SILC_PARAM_FUNC:
646       {
647         SilcBufferUnformatFunc func;
648         void **val;
649         void *context;
650         int tmp_len;
651         func = va_arg(ap, SilcBufferUnformatFunc);
652         val = va_arg(ap, void **);
653         context = va_arg(ap, void *);
654
655         if (!process)
656           break;
657
658         tmp_len = func(stack, src, val, context);
659         if (tmp_len < 0)
660           goto fail;
661         if (tmp_len) {
662           UNFORMAT_HAS_SPACE(src, tmp_len);
663           silc_buffer_pull(src, tmp_len);
664         }
665       }
666       break;
667
668     case SILC_PARAM_REGEX:
669       {
670         const char *regex = va_arg(ap, char *);
671         SilcBufferRegexFlags rflags = va_arg(ap, SilcBufferRegexFlags);
672         SilcBufferStruct match;
673         SilcBool match_all = (rflags & SILC_STR_REGEX_ALL) != 0;
674         SilcBool match_nl = (rflags & SILC_STR_REGEX_NL) != 0;
675         SilcBool ret;
676         SilcUInt32 inclusive_pos = 0;
677         int matched = 0, ret_len;
678         va_list cp;
679
680         if (!process)
681           break;
682
683         if (!regex)
684           break;
685
686         if (match_nl) {
687         start_nl_match:
688           /* Match for '\n' in the buffer.  If not found, treat as line
689              without '\n' (buffer has only one line, or this is last line). */
690           if (silc_regex_buffer(src, "\n", &match, NULL))
691             src->tail = match.tail;
692         }
693
694       start_match:
695         /* Match */
696         ret = silc_regex_buffer(src, regex, &match, NULL);
697         ret ^= (rflags & SILC_STR_REGEX_NOT) != 0;
698         if (!ret) {
699           if (!matched && rflags & SILC_STR_REGEX_MISMATCH) {
700             silc_set_errno(SILC_ERR_NOT_FOUND);
701             goto fail;
702           }
703           goto end_match;
704         }
705         matched++;
706
707         if (rflags & SILC_STR_REGEX_NOT)
708           match = *src;
709
710         if (!(rflags & SILC_STR_REGEX_NO_ADVANCE)) {
711           /* Advance buffer after match */
712           if (!silc_buffer_pull(src, (match.data - src->data)))
713             goto fail;
714         }
715
716         if (rflags & SILC_STR_REGEX_INCLUSIVE) {
717           inclusive_pos = src->tail - match.tail;
718           src->tail = match.tail;
719         }
720
721         /* Recursively format */
722         silc_va_copy(cp, ap);
723         ret_len = silc_buffer_sunformat_vp_i(stack, src, cp, TRUE);
724         va_end(cp);
725         if (ret_len < 0)
726           goto fail;
727
728         if (rflags & SILC_STR_REGEX_INCLUSIVE)
729           if (!silc_buffer_pull_tail(src, inclusive_pos))
730             goto fail;
731
732         /* Advance buffer after formatting */
733         if (!silc_buffer_pull(src, ret_len))
734           goto fail;
735
736         if (match_all && (!match_nl || silc_buffer_len(src) > 1))
737           goto start_match;
738
739       end_match:
740         if (match_nl) {
741           /* Go to next line, it is at the end of the data area.  Adjust
742              the tail area of the target buffer to show rest of the buffer. */
743           if (!silc_buffer_pull(src, (src->tail - src->data)))
744             goto fail;
745           if (!silc_buffer_pull_tail(src, silc_buffer_taillen(src)))
746             goto fail;
747
748           if (silc_buffer_len(src) > 0)
749             goto start_nl_match;
750         }
751
752         /* Skip to the next SILC_PARAM_END */
753         silc_buffer_sunformat_vp_i(NULL, src, ap, FALSE);
754         break;
755       }
756       break;
757
758     case SILC_PARAM_UICHAR:
759       {
760         unsigned char **x = va_arg(ap, unsigned char **);
761         SilcUInt32 len2 = va_arg(ap, SilcUInt32);
762
763         if (!process)
764           break;
765
766         UNFORMAT_HAS_SPACE(src, len2);
767         if (silc_likely(len2 && x))
768           *x = src->data;
769         silc_buffer_pull(src, len2);
770         break;
771       }
772
773     case SILC_PARAM_UICHAR | SILC_PARAM_ALLOC:
774       {
775         unsigned char **x = va_arg(ap, unsigned char **);
776         SilcUInt32 len2 = va_arg(ap, SilcUInt32);
777
778         if (!process)
779           break;
780
781         UNFORMAT_HAS_SPACE(src, len2);
782         if (silc_likely(len2 && x)) {
783           *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
784           if (*x)
785             memcpy(*x, src->data, len2);
786         }
787         silc_buffer_pull(src, len2);
788         break;
789       }
790
791     case SILC_PARAM_UINT8:
792       {
793         unsigned char *x = va_arg(ap, unsigned char *);
794
795         if (!process)
796           break;
797
798         UNFORMAT_HAS_SPACE(src, 1);
799         if (silc_likely(x))
800           *x = src->data[0];
801         silc_buffer_pull(src, 1);
802         break;
803       }
804
805     case SILC_PARAM_UINT16:
806       {
807         SilcUInt16 *x = va_arg(ap, SilcUInt16 *);
808
809         if (!process)
810           break;
811
812         UNFORMAT_HAS_SPACE(src, 2);
813         if (silc_likely(x))
814           SILC_GET16_MSB(*x, src->data);
815         silc_buffer_pull(src, 2);
816         break;
817       }
818
819     case SILC_PARAM_UINT32:
820       {
821         SilcUInt32 *x = va_arg(ap, SilcUInt32 *);
822
823         if (!process)
824           break;
825
826         UNFORMAT_HAS_SPACE(src, 4);
827         if (silc_likely(x))
828           SILC_GET32_MSB(*x, src->data);
829         silc_buffer_pull(src, 4);
830         break;
831       }
832
833     case SILC_PARAM_UINT64:
834       {
835         SilcUInt64 *x = va_arg(ap, SilcUInt64 *);
836
837         if (!process)
838           break;
839
840         UNFORMAT_HAS_SPACE(src, sizeof(SilcUInt64));
841         if (silc_likely(x))
842           SILC_GET64_MSB(*x, src->data);
843         silc_buffer_pull(src, sizeof(SilcUInt64));
844         break;
845       }
846
847     case SILC_PARAM_SINT8:
848       {
849         char *x = va_arg(ap, char *);
850
851         if (!process)
852           break;
853
854         UNFORMAT_HAS_SPACE(src, 1);
855         if (silc_likely(x))
856           *x = src->data[0];
857         silc_buffer_pull(src, 1);
858         break;
859       }
860
861     case SILC_PARAM_SINT16:
862       {
863         SilcInt16 *x = va_arg(ap, SilcInt16 *);
864
865         if (!process)
866           break;
867
868         UNFORMAT_HAS_SPACE(src, 2);
869         if (silc_likely(x))
870           SILC_GET16_MSB(*x, src->data);
871         silc_buffer_pull(src, 2);
872         break;
873       }
874
875     case SILC_PARAM_SINT32:
876       {
877         SilcInt32 *x = va_arg(ap, SilcInt32 *);
878
879         if (!process)
880           break;
881
882         UNFORMAT_HAS_SPACE(src, 4);
883         if (silc_likely(x))
884           SILC_GET32_MSB(*x, src->data);
885         silc_buffer_pull(src, 4);
886         break;
887       }
888
889     case SILC_PARAM_SINT64:
890       {
891         SilcInt64 *x = va_arg(ap, SilcInt64 *);
892
893         if (!process)
894           break;
895
896         UNFORMAT_HAS_SPACE(src, sizeof(SilcInt64));
897         if (silc_likely(x))
898           SILC_GET64_MSB(*x, src->data);
899         silc_buffer_pull(src, sizeof(SilcInt64));
900         break;
901       }
902
903     case SILC_PARAM_UI8_STRING:
904       {
905         SilcUInt8 len2;
906         unsigned char **x = va_arg(ap, unsigned char **);
907
908         if (!process)
909           break;
910
911         UNFORMAT_HAS_SPACE(src, 1);
912         len2 = (SilcUInt8)src->data[0];
913         silc_buffer_pull(src, 1);
914         UNFORMAT_HAS_SPACE(src, len2);
915         if (silc_likely(x))
916           *x = src->data;
917         silc_buffer_pull(src, len2);
918         break;
919       }
920
921     case SILC_PARAM_UI8_STRING | SILC_PARAM_ALLOC:
922       {
923         SilcUInt8 len2;
924         unsigned char **x = va_arg(ap, unsigned char **);
925
926         if (!process)
927           break;
928
929         UNFORMAT_HAS_SPACE(src, 1);
930         len2 = (SilcUInt8)src->data[0];
931         silc_buffer_pull(src, 1);
932         UNFORMAT_HAS_SPACE(src, len2);
933         if (silc_likely(x && len2)) {
934           *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
935           memcpy(*x, src->data, len2);
936         }
937         silc_buffer_pull(src, len2);
938         break;
939       }
940
941     case SILC_PARAM_UI16_STRING:
942       {
943         SilcUInt16 len2;
944         unsigned char **x = va_arg(ap, unsigned char **);
945
946         if (!process)
947           break;
948
949         UNFORMAT_HAS_SPACE(src, 2);
950         SILC_GET16_MSB(len2, src->data);
951         silc_buffer_pull(src, 2);
952         UNFORMAT_HAS_SPACE(src, len2);
953         if (silc_likely(x))
954           *x = src->data;
955         silc_buffer_pull(src, len2);
956         break;
957       }
958
959     case SILC_PARAM_UI16_STRING | SILC_PARAM_ALLOC:
960       {
961         SilcUInt16 len2;
962         unsigned char **x = va_arg(ap, unsigned char **);
963
964         if (!process)
965           break;
966
967         UNFORMAT_HAS_SPACE(src, 2);
968         SILC_GET16_MSB(len2, src->data);
969         silc_buffer_pull(src, 2);
970         UNFORMAT_HAS_SPACE(src, len2);
971         if (silc_likely(x && len2)) {
972           *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
973           if (*x)
974             memcpy(*x, src->data, len2);
975         }
976         silc_buffer_pull(src, len2);
977         break;
978       }
979
980     case SILC_PARAM_UI32_STRING:
981       {
982         SilcUInt32 len2;
983         unsigned char **x = va_arg(ap, unsigned char **);
984
985         if (!process)
986           break;
987
988         UNFORMAT_HAS_SPACE(src, 4);
989         SILC_GET32_MSB(len2, src->data);
990         silc_buffer_pull(src, 4);
991         UNFORMAT_HAS_SPACE(src, len2);
992         if (silc_likely(x))
993           *x = src->data;
994         silc_buffer_pull(src, len2);
995         break;
996       }
997
998     case SILC_PARAM_UI32_STRING | SILC_PARAM_ALLOC:
999       {
1000         SilcUInt32 len2;
1001         unsigned char **x = va_arg(ap, unsigned char **);
1002
1003         if (!process)
1004           break;
1005
1006         UNFORMAT_HAS_SPACE(src, 4);
1007         SILC_GET32_MSB(len2, src->data);
1008         silc_buffer_pull(src, 4);
1009         UNFORMAT_HAS_SPACE(src, len2);
1010         if (silc_likely(x && len2)) {
1011           *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
1012           if (*x)
1013             memcpy(*x, src->data, len2);
1014         }
1015         silc_buffer_pull(src, len2);
1016         break;
1017       }
1018
1019     case SILC_PARAM_UI8_NSTRING:
1020       {
1021         SilcUInt8 len2;
1022         unsigned char **x = va_arg(ap, unsigned char **);
1023         SilcUInt8 *len3 = va_arg(ap, SilcUInt8 *);
1024
1025         if (!process)
1026           break;
1027
1028         UNFORMAT_HAS_SPACE(src, 1);
1029         len2 = (SilcUInt8)src->data[0];
1030         silc_buffer_pull(src, 1);
1031         UNFORMAT_HAS_SPACE(src, len2);
1032         if (len3)
1033           *len3 = len2;
1034         if (x)
1035           *x = src->data;
1036         silc_buffer_pull(src, len2);
1037         break;
1038       }
1039
1040     case SILC_PARAM_UI8_NSTRING | SILC_PARAM_ALLOC:
1041       {
1042         SilcUInt8 len2;
1043         unsigned char **x = va_arg(ap, unsigned char **);
1044         SilcUInt8 *len3 = va_arg(ap, SilcUInt8 *);
1045
1046         if (!process)
1047           break;
1048
1049         UNFORMAT_HAS_SPACE(src, 1);
1050         len2 = (SilcUInt8)src->data[0];
1051         silc_buffer_pull(src, 1);
1052         UNFORMAT_HAS_SPACE(src, len2);
1053         if (len3)
1054           *len3 = len2;
1055         if (x && len2) {
1056           *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
1057           memcpy(*x, src->data, len2);
1058         }
1059         silc_buffer_pull(src, len2);
1060         break;
1061       }
1062
1063     case SILC_PARAM_UI16_NSTRING:
1064       {
1065         SilcUInt16 len2;
1066         unsigned char **x = va_arg(ap, unsigned char **);
1067         SilcUInt16 *len3 = va_arg(ap, SilcUInt16 *);
1068
1069         if (!process)
1070           break;
1071
1072         UNFORMAT_HAS_SPACE(src, 2);
1073         SILC_GET16_MSB(len2, src->data);
1074         silc_buffer_pull(src, 2);
1075         UNFORMAT_HAS_SPACE(src, len2);
1076         if (len3)
1077           *len3 = len2;
1078         if (x)
1079           *x = src->data;
1080         silc_buffer_pull(src, len2);
1081         break;
1082       }
1083
1084     case SILC_PARAM_UI16_NSTRING | SILC_PARAM_ALLOC:
1085       {
1086         SilcUInt16 len2;
1087         unsigned char **x = va_arg(ap, unsigned char **);
1088         SilcUInt16 *len3 = va_arg(ap, SilcUInt16 *);
1089
1090         if (!process)
1091           break;
1092
1093         UNFORMAT_HAS_SPACE(src, 2);
1094         SILC_GET16_MSB(len2, src->data);
1095         silc_buffer_pull(src, 2);
1096         UNFORMAT_HAS_SPACE(src, len2);
1097         if (len3)
1098           *len3 = len2;
1099         if (x && len2) {
1100           *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
1101           if (*x)
1102             memcpy(*x, src->data, len2);
1103         }
1104         silc_buffer_pull(src, len2);
1105         break;
1106       }
1107
1108     case SILC_PARAM_UI32_NSTRING:
1109       {
1110         SilcUInt32 len2;
1111         unsigned char **x = va_arg(ap, unsigned char **);
1112         SilcUInt32 *len3 = va_arg(ap, SilcUInt32 *);
1113
1114         if (!process)
1115           break;
1116
1117         UNFORMAT_HAS_SPACE(src, 4);
1118         SILC_GET32_MSB(len2, src->data);
1119         silc_buffer_pull(src, 4);
1120         UNFORMAT_HAS_SPACE(src, len2);
1121         if (len3)
1122           *len3 = len2;
1123         if (x)
1124           *x = src->data;
1125         silc_buffer_pull(src, len2);
1126         break;
1127       }
1128
1129     case SILC_PARAM_UI32_NSTRING | SILC_PARAM_ALLOC:
1130       {
1131         SilcUInt32 len2;
1132         unsigned char **x = va_arg(ap, unsigned char **);
1133         SilcUInt32 *len3 = va_arg(ap, SilcUInt32 *);
1134
1135         if (!process)
1136           break;
1137
1138         UNFORMAT_HAS_SPACE(src, 4);
1139         SILC_GET32_MSB(len2, src->data);
1140         silc_buffer_pull(src, 4);
1141         UNFORMAT_HAS_SPACE(src, len2);
1142         if (len3)
1143           *len3 = len2;
1144         if (silc_likely(x && len2)) {
1145           *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
1146           memcpy(*x, src->data, len2);
1147         }
1148         silc_buffer_pull(src, len2);
1149         break;
1150       }
1151
1152     case SILC_PARAM_BUFFER:
1153       {
1154         SilcBuffer x = va_arg(ap, SilcBuffer);
1155         SilcUInt32 len2;
1156
1157         if (!process)
1158           break;
1159
1160         UNFORMAT_HAS_SPACE(src, 4);
1161         SILC_GET32_MSB(len2, src->data);
1162         silc_buffer_pull(src, 4);
1163         UNFORMAT_HAS_SPACE(src, len2);
1164         silc_buffer_set(x, src->data, len2);
1165         silc_buffer_pull(src, len2);
1166       }
1167       break;
1168
1169     case SILC_PARAM_BUFFER | SILC_PARAM_ALLOC:
1170       {
1171         SilcBuffer x = va_arg(ap, SilcBuffer);
1172         SilcUInt32 len2;
1173
1174         if (!process)
1175           break;
1176
1177         UNFORMAT_HAS_SPACE(src, 4);
1178         SILC_GET32_MSB(len2, src->data);
1179         silc_buffer_pull(src, 4);
1180         UNFORMAT_HAS_SPACE(src, len2);
1181         if (silc_buffer_sformat(stack, x,
1182                                 SILC_STR_DATA(src->data, len2),
1183                                 SILC_STR_END) < 0)
1184           goto fail;
1185         silc_buffer_pull(src, len2);
1186       }
1187       break;
1188
1189     case SILC_PARAM_OFFSET:
1190       {
1191         int offst = va_arg(ap, int);
1192
1193         if (!process)
1194           break;
1195
1196         if (!offst)
1197           break;
1198
1199         if (offst > 1) {
1200           UNFORMAT_HAS_SPACE(src, offst);
1201           silc_buffer_pull(src, offst);
1202         } else {
1203           silc_buffer_push(src, -(offst));
1204         }
1205         break;
1206       }
1207
1208     case SILC_PARAM_OFFSET_START:
1209       if (!process)
1210         break;
1211       silc_buffer_push(src, (src->data - start_ptr));
1212       break;
1213
1214     case SILC_PARAM_OFFSET_END:
1215       if (!process)
1216         break;
1217       silc_buffer_pull(src, silc_buffer_len(src));
1218       break;
1219
1220     case SILC_PARAM_ADVANCE:
1221       if (!process)
1222         break;
1223       advance = TRUE;
1224       break;
1225
1226     case SILC_PARAM_END:
1227       goto ok;
1228       break;
1229
1230     case SILC_PARAM_DELETE:
1231       break;
1232
1233     default:
1234       SILC_LOG_DEBUG(("Bad buffer formatting type `%d'. Could not "
1235                       "format the data.", fmt));
1236       silc_set_errno_reason(SILC_ERR_INVALID_ARGUMENT,
1237                             "Bad buffer formatting type %d", fmt);
1238       goto fail;
1239       break;
1240     }
1241   }
1242
1243  fail:
1244   SILC_LOG_DEBUG(("Error occured while unformatting buffer, type %d", fmt));
1245   if (process && !advance) {
1246     len = src->data - start_ptr;
1247     silc_buffer_push(src, len);
1248   }
1249   return -1;
1250
1251  ok:
1252   len = src->data - start_ptr;
1253
1254   /* Push the buffer back to the start. */
1255   if (process && !advance)
1256     silc_buffer_push(src, len);
1257
1258   return len;
1259 }
1260
1261 int silc_buffer_unformat(SilcBuffer src, ...)
1262 {
1263   va_list ap;
1264   int ret;
1265
1266   va_start(ap, src);
1267   ret = silc_buffer_sunformat_vp(NULL, src, ap);
1268   va_end(ap);
1269
1270   return ret;
1271 }
1272
1273 int silc_buffer_unformat_vp(SilcBuffer src, va_list ap)
1274 {
1275   return silc_buffer_sunformat_vp(NULL, src, ap);
1276 }
1277
1278 int silc_buffer_sunformat(SilcStack stack, SilcBuffer src, ...)
1279 {
1280   va_list ap;
1281   int ret;
1282
1283   va_start(ap, src);
1284   ret = silc_buffer_sunformat_vp(stack, src, ap);
1285   va_end(ap);
1286
1287   return ret;
1288 }
1289
1290 int silc_buffer_sunformat_vp(SilcStack stack, SilcBuffer src, va_list ap)
1291 {
1292   return silc_buffer_sunformat_vp_i(stack, src, ap, TRUE);
1293 }
1294
1295 /**************************** Utility functions *****************************/
1296
1297 /* Formats strings into a buffer */
1298
1299 int silc_buffer_strformat(SilcBuffer dst, ...)
1300 {
1301   int len = silc_buffer_truelen(dst);
1302   int hlen = silc_buffer_headlen(dst);
1303   va_list va;
1304
1305   va_start(va, dst);
1306
1307   /* Parse the arguments by formatting type. */
1308   while(1) {
1309     char *string = va_arg(va, char *);
1310     unsigned char *d;
1311     SilcInt32 slen;
1312
1313     if (!string)
1314       continue;
1315     if (string == (char *)SILC_PARAM_END)
1316       goto ok;
1317
1318     slen = strlen(string);
1319     d = silc_realloc(dst->head, sizeof(*dst->head) * (slen + len + 1));
1320     if (silc_unlikely(!d))
1321       return -1;
1322     dst->head = d;
1323     memcpy(dst->head + len, string, slen);
1324     len += slen;
1325     dst->head[len] = '\0';
1326   }
1327
1328   SILC_LOG_DEBUG(("Error occured while formatting buffer"));
1329   va_end(va);
1330   return -1;
1331
1332  ok:
1333   dst->end = dst->head + len;
1334   dst->data = dst->head + hlen;
1335   dst->tail = dst->end;
1336
1337   va_end(va);
1338   return len;
1339 }
1340
1341 /* Formats strings into a buffer.  Allocates memory from SilcStack. */
1342
1343 int silc_buffer_sstrformat(SilcStack stack, SilcBuffer dst, ...)
1344 {
1345   int len = silc_buffer_truelen(dst);
1346   int hlen = silc_buffer_headlen(dst);
1347   va_list va;
1348
1349   va_start(va, dst);
1350
1351   /* Parse the arguments by formatting type. */
1352   while(1) {
1353     char *string = va_arg(va, char *);
1354     unsigned char *d;
1355     SilcInt32 slen;
1356
1357     if (!string)
1358       continue;
1359     if (string == (char *)SILC_PARAM_END)
1360       goto ok;
1361
1362     slen = strlen(string);
1363     d = silc_srealloc(stack, len + 1, dst->head,
1364                       sizeof(*dst->head) * (slen + len + 1));
1365     if (silc_unlikely(!d))
1366       return -1;
1367     dst->head = d;
1368     memcpy(dst->head + len, string, slen);
1369     len += slen;
1370     dst->head[len] = '\0';
1371   }
1372
1373   SILC_LOG_DEBUG(("Error occured while formatting buffer"));
1374   va_end(va);
1375   return -1;
1376
1377  ok:
1378   dst->end = dst->head + len;
1379   dst->data = dst->head + hlen;
1380   dst->tail = dst->end;
1381
1382   va_end(va);
1383   return len;
1384 }