944841d4f284896fdaccf805126ba8f1319b13a2
[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           memcpy(*x, src->data, len2);
785         }
786         silc_buffer_pull(src, len2);
787         break;
788       }
789
790     case SILC_PARAM_UINT8:
791       {
792         unsigned char *x = va_arg(ap, unsigned char *);
793
794         if (!process)
795           break;
796
797         UNFORMAT_HAS_SPACE(src, 1);
798         if (silc_likely(x))
799           *x = src->data[0];
800         silc_buffer_pull(src, 1);
801         break;
802       }
803
804     case SILC_PARAM_UINT16:
805       {
806         SilcUInt16 *x = va_arg(ap, SilcUInt16 *);
807
808         if (!process)
809           break;
810
811         UNFORMAT_HAS_SPACE(src, 2);
812         if (silc_likely(x))
813           SILC_GET16_MSB(*x, src->data);
814         silc_buffer_pull(src, 2);
815         break;
816       }
817
818     case SILC_PARAM_UINT32:
819       {
820         SilcUInt32 *x = va_arg(ap, SilcUInt32 *);
821
822         if (!process)
823           break;
824
825         UNFORMAT_HAS_SPACE(src, 4);
826         if (silc_likely(x))
827           SILC_GET32_MSB(*x, src->data);
828         silc_buffer_pull(src, 4);
829         break;
830       }
831
832     case SILC_PARAM_UINT64:
833       {
834         SilcUInt64 *x = va_arg(ap, SilcUInt64 *);
835
836         if (!process)
837           break;
838
839         UNFORMAT_HAS_SPACE(src, sizeof(SilcUInt64));
840         if (silc_likely(x))
841           SILC_GET64_MSB(*x, src->data);
842         silc_buffer_pull(src, sizeof(SilcUInt64));
843         break;
844       }
845
846     case SILC_PARAM_SINT8:
847       {
848         char *x = va_arg(ap, char *);
849
850         if (!process)
851           break;
852
853         UNFORMAT_HAS_SPACE(src, 1);
854         if (silc_likely(x))
855           *x = src->data[0];
856         silc_buffer_pull(src, 1);
857         break;
858       }
859
860     case SILC_PARAM_SINT16:
861       {
862         SilcInt16 *x = va_arg(ap, SilcInt16 *);
863
864         if (!process)
865           break;
866
867         UNFORMAT_HAS_SPACE(src, 2);
868         if (silc_likely(x))
869           SILC_GET16_MSB(*x, src->data);
870         silc_buffer_pull(src, 2);
871         break;
872       }
873
874     case SILC_PARAM_SINT32:
875       {
876         SilcInt32 *x = va_arg(ap, SilcInt32 *);
877
878         if (!process)
879           break;
880
881         UNFORMAT_HAS_SPACE(src, 4);
882         if (silc_likely(x))
883           SILC_GET32_MSB(*x, src->data);
884         silc_buffer_pull(src, 4);
885         break;
886       }
887
888     case SILC_PARAM_SINT64:
889       {
890         SilcInt64 *x = va_arg(ap, SilcInt64 *);
891
892         if (!process)
893           break;
894
895         UNFORMAT_HAS_SPACE(src, sizeof(SilcInt64));
896         if (silc_likely(x))
897           SILC_GET64_MSB(*x, src->data);
898         silc_buffer_pull(src, sizeof(SilcInt64));
899         break;
900       }
901
902     case SILC_PARAM_UI8_STRING:
903       {
904         SilcUInt8 len2;
905         unsigned char **x = va_arg(ap, unsigned char **);
906
907         if (!process)
908           break;
909
910         UNFORMAT_HAS_SPACE(src, 1);
911         len2 = (SilcUInt8)src->data[0];
912         silc_buffer_pull(src, 1);
913         UNFORMAT_HAS_SPACE(src, len2);
914         if (silc_likely(x))
915           *x = src->data;
916         silc_buffer_pull(src, len2);
917         break;
918       }
919
920     case SILC_PARAM_UI8_STRING | SILC_PARAM_ALLOC:
921       {
922         SilcUInt8 len2;
923         unsigned char **x = va_arg(ap, unsigned char **);
924
925         if (!process)
926           break;
927
928         UNFORMAT_HAS_SPACE(src, 1);
929         len2 = (SilcUInt8)src->data[0];
930         silc_buffer_pull(src, 1);
931         UNFORMAT_HAS_SPACE(src, len2);
932         if (silc_likely(x && len2)) {
933           *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
934           memcpy(*x, src->data, len2);
935         }
936         silc_buffer_pull(src, len2);
937         break;
938       }
939
940     case SILC_PARAM_UI16_STRING:
941       {
942         SilcUInt16 len2;
943         unsigned char **x = va_arg(ap, unsigned char **);
944
945         if (!process)
946           break;
947
948         UNFORMAT_HAS_SPACE(src, 2);
949         SILC_GET16_MSB(len2, src->data);
950         silc_buffer_pull(src, 2);
951         UNFORMAT_HAS_SPACE(src, len2);
952         if (silc_likely(x))
953           *x = src->data;
954         silc_buffer_pull(src, len2);
955         break;
956       }
957
958     case SILC_PARAM_UI16_STRING | SILC_PARAM_ALLOC:
959       {
960         SilcUInt16 len2;
961         unsigned char **x = va_arg(ap, unsigned char **);
962
963         if (!process)
964           break;
965
966         UNFORMAT_HAS_SPACE(src, 2);
967         SILC_GET16_MSB(len2, src->data);
968         silc_buffer_pull(src, 2);
969         UNFORMAT_HAS_SPACE(src, len2);
970         if (silc_likely(x && len2)) {
971           *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
972           memcpy(*x, src->data, len2);
973         }
974         silc_buffer_pull(src, len2);
975         break;
976       }
977
978     case SILC_PARAM_UI32_STRING:
979       {
980         SilcUInt32 len2;
981         unsigned char **x = va_arg(ap, unsigned char **);
982
983         if (!process)
984           break;
985
986         UNFORMAT_HAS_SPACE(src, 4);
987         SILC_GET32_MSB(len2, src->data);
988         silc_buffer_pull(src, 4);
989         UNFORMAT_HAS_SPACE(src, len2);
990         if (silc_likely(x))
991           *x = src->data;
992         silc_buffer_pull(src, len2);
993         break;
994       }
995
996     case SILC_PARAM_UI32_STRING | SILC_PARAM_ALLOC:
997       {
998         SilcUInt32 len2;
999         unsigned char **x = va_arg(ap, unsigned char **);
1000
1001         if (!process)
1002           break;
1003
1004         UNFORMAT_HAS_SPACE(src, 4);
1005         SILC_GET32_MSB(len2, src->data);
1006         silc_buffer_pull(src, 4);
1007         UNFORMAT_HAS_SPACE(src, len2);
1008         if (silc_likely(x && len2)) {
1009           *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
1010           memcpy(*x, src->data, len2);
1011         }
1012         silc_buffer_pull(src, len2);
1013         break;
1014       }
1015
1016     case SILC_PARAM_UI8_NSTRING:
1017       {
1018         SilcUInt8 len2;
1019         unsigned char **x = va_arg(ap, unsigned char **);
1020         SilcUInt8 *len3 = va_arg(ap, SilcUInt8 *);
1021
1022         if (!process)
1023           break;
1024
1025         UNFORMAT_HAS_SPACE(src, 1);
1026         len2 = (SilcUInt8)src->data[0];
1027         silc_buffer_pull(src, 1);
1028         UNFORMAT_HAS_SPACE(src, len2);
1029         if (len3)
1030           *len3 = len2;
1031         if (x)
1032           *x = src->data;
1033         silc_buffer_pull(src, len2);
1034         break;
1035       }
1036
1037     case SILC_PARAM_UI8_NSTRING | SILC_PARAM_ALLOC:
1038       {
1039         SilcUInt8 len2;
1040         unsigned char **x = va_arg(ap, unsigned char **);
1041         SilcUInt8 *len3 = va_arg(ap, SilcUInt8 *);
1042
1043         if (!process)
1044           break;
1045
1046         UNFORMAT_HAS_SPACE(src, 1);
1047         len2 = (SilcUInt8)src->data[0];
1048         silc_buffer_pull(src, 1);
1049         UNFORMAT_HAS_SPACE(src, len2);
1050         if (len3)
1051           *len3 = len2;
1052         if (x && len2) {
1053           *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
1054           memcpy(*x, src->data, len2);
1055         }
1056         silc_buffer_pull(src, len2);
1057         break;
1058       }
1059
1060     case SILC_PARAM_UI16_NSTRING:
1061       {
1062         SilcUInt16 len2;
1063         unsigned char **x = va_arg(ap, unsigned char **);
1064         SilcUInt16 *len3 = va_arg(ap, SilcUInt16 *);
1065
1066         if (!process)
1067           break;
1068
1069         UNFORMAT_HAS_SPACE(src, 2);
1070         SILC_GET16_MSB(len2, src->data);
1071         silc_buffer_pull(src, 2);
1072         UNFORMAT_HAS_SPACE(src, len2);
1073         if (len3)
1074           *len3 = len2;
1075         if (x)
1076           *x = src->data;
1077         silc_buffer_pull(src, len2);
1078         break;
1079       }
1080
1081     case SILC_PARAM_UI16_NSTRING | SILC_PARAM_ALLOC:
1082       {
1083         SilcUInt16 len2;
1084         unsigned char **x = va_arg(ap, unsigned char **);
1085         SilcUInt16 *len3 = va_arg(ap, SilcUInt16 *);
1086
1087         if (!process)
1088           break;
1089
1090         UNFORMAT_HAS_SPACE(src, 2);
1091         SILC_GET16_MSB(len2, src->data);
1092         silc_buffer_pull(src, 2);
1093         UNFORMAT_HAS_SPACE(src, len2);
1094         if (len3)
1095           *len3 = len2;
1096         if (x && len2) {
1097           *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
1098           memcpy(*x, src->data, len2);
1099         }
1100         silc_buffer_pull(src, len2);
1101         break;
1102       }
1103
1104     case SILC_PARAM_UI32_NSTRING:
1105       {
1106         SilcUInt32 len2;
1107         unsigned char **x = va_arg(ap, unsigned char **);
1108         SilcUInt32 *len3 = va_arg(ap, SilcUInt32 *);
1109
1110         if (!process)
1111           break;
1112
1113         UNFORMAT_HAS_SPACE(src, 4);
1114         SILC_GET32_MSB(len2, src->data);
1115         silc_buffer_pull(src, 4);
1116         UNFORMAT_HAS_SPACE(src, len2);
1117         if (len3)
1118           *len3 = len2;
1119         if (x)
1120           *x = src->data;
1121         silc_buffer_pull(src, len2);
1122         break;
1123       }
1124
1125     case SILC_PARAM_UI32_NSTRING | SILC_PARAM_ALLOC:
1126       {
1127         SilcUInt32 len2;
1128         unsigned char **x = va_arg(ap, unsigned char **);
1129         SilcUInt32 *len3 = va_arg(ap, SilcUInt32 *);
1130
1131         if (!process)
1132           break;
1133
1134         UNFORMAT_HAS_SPACE(src, 4);
1135         SILC_GET32_MSB(len2, src->data);
1136         silc_buffer_pull(src, 4);
1137         UNFORMAT_HAS_SPACE(src, len2);
1138         if (len3)
1139           *len3 = len2;
1140         if (silc_likely(x && len2)) {
1141           *x = silc_scalloc(stack, len2 + 1, sizeof(unsigned char));
1142           memcpy(*x, src->data, len2);
1143         }
1144         silc_buffer_pull(src, len2);
1145         break;
1146       }
1147
1148     case SILC_PARAM_BUFFER:
1149       {
1150         SilcBuffer x = va_arg(ap, SilcBuffer);
1151         SilcUInt32 len2;
1152
1153         if (!process)
1154           break;
1155
1156         UNFORMAT_HAS_SPACE(src, 4);
1157         SILC_GET32_MSB(len2, src->data);
1158         silc_buffer_pull(src, 4);
1159         UNFORMAT_HAS_SPACE(src, len2);
1160         silc_buffer_set(x, src->data, len2);
1161         silc_buffer_pull(src, len2);
1162       }
1163       break;
1164
1165     case SILC_PARAM_BUFFER | SILC_PARAM_ALLOC:
1166       {
1167         SilcBuffer x = va_arg(ap, SilcBuffer);
1168         SilcUInt32 len2;
1169
1170         if (!process)
1171           break;
1172
1173         UNFORMAT_HAS_SPACE(src, 4);
1174         SILC_GET32_MSB(len2, src->data);
1175         silc_buffer_pull(src, 4);
1176         UNFORMAT_HAS_SPACE(src, len2);
1177         silc_buffer_sformat(stack, x,
1178                             SILC_STR_DATA(src->data, len2),
1179                             SILC_STR_END);
1180         silc_buffer_pull(src, len2);
1181       }
1182       break;
1183
1184     case SILC_PARAM_OFFSET:
1185       {
1186         int offst = va_arg(ap, int);
1187
1188         if (!process)
1189           break;
1190
1191         if (!offst)
1192           break;
1193
1194         if (offst > 1) {
1195           UNFORMAT_HAS_SPACE(src, offst);
1196           silc_buffer_pull(src, offst);
1197         } else {
1198           silc_buffer_push(src, -(offst));
1199         }
1200         break;
1201       }
1202
1203     case SILC_PARAM_OFFSET_START:
1204       if (!process)
1205         break;
1206       silc_buffer_push(src, (src->data - start_ptr));
1207       break;
1208
1209     case SILC_PARAM_OFFSET_END:
1210       if (!process)
1211         break;
1212       silc_buffer_pull(src, silc_buffer_len(src));
1213       break;
1214
1215     case SILC_PARAM_ADVANCE:
1216       if (!process)
1217         break;
1218       advance = TRUE;
1219       break;
1220
1221     case SILC_PARAM_END:
1222       goto ok;
1223       break;
1224
1225     case SILC_PARAM_DELETE:
1226       break;
1227
1228     default:
1229       SILC_LOG_DEBUG(("Bad buffer formatting type `%d'. Could not "
1230                       "format the data.", fmt));
1231       silc_set_errno_reason(SILC_ERR_INVALID_ARGUMENT,
1232                             "Bad buffer formatting type %d", fmt);
1233       goto fail;
1234       break;
1235     }
1236   }
1237
1238  fail:
1239   SILC_LOG_DEBUG(("Error occured while unformatting buffer, type %d", fmt));
1240   if (process && !advance) {
1241     len = src->data - start_ptr;
1242     silc_buffer_push(src, len);
1243   }
1244   return -1;
1245
1246  ok:
1247   /* Push the buffer back to the start. */
1248   if (process && !advance) {
1249     len = src->data - start_ptr;
1250     silc_buffer_push(src, len);
1251   }
1252   return len;
1253 }
1254
1255 int silc_buffer_unformat(SilcBuffer src, ...)
1256 {
1257   va_list ap;
1258   int ret;
1259
1260   va_start(ap, src);
1261   ret = silc_buffer_sunformat_vp(NULL, src, ap);
1262   va_end(ap);
1263
1264   return ret;
1265 }
1266
1267 int silc_buffer_unformat_vp(SilcBuffer src, va_list ap)
1268 {
1269   return silc_buffer_sunformat_vp(NULL, src, ap);
1270 }
1271
1272 int silc_buffer_sunformat(SilcStack stack, SilcBuffer src, ...)
1273 {
1274   va_list ap;
1275   int ret;
1276
1277   va_start(ap, src);
1278   ret = silc_buffer_sunformat_vp(stack, src, ap);
1279   va_end(ap);
1280
1281   return ret;
1282 }
1283
1284 int silc_buffer_sunformat_vp(SilcStack stack, SilcBuffer src, va_list ap)
1285 {
1286   return silc_buffer_sunformat_vp_i(stack, src, ap, TRUE);
1287 }
1288
1289 /**************************** Utility functions *****************************/
1290
1291 /* Formats strings into a buffer */
1292
1293 int silc_buffer_strformat(SilcBuffer dst, ...)
1294 {
1295   int len = silc_buffer_truelen(dst);
1296   int hlen = silc_buffer_headlen(dst);
1297   va_list va;
1298
1299   va_start(va, dst);
1300
1301   /* Parse the arguments by formatting type. */
1302   while(1) {
1303     char *string = va_arg(va, char *);
1304     unsigned char *d;
1305     SilcInt32 slen;
1306
1307     if (!string)
1308       continue;
1309     if (string == (char *)SILC_PARAM_END)
1310       goto ok;
1311
1312     slen = strlen(string);
1313     d = silc_realloc(dst->head, sizeof(*dst->head) * (slen + len + 1));
1314     if (silc_unlikely(!d))
1315       return -1;
1316     dst->head = d;
1317     memcpy(dst->head + len, string, slen);
1318     len += slen;
1319     dst->head[len] = '\0';
1320   }
1321
1322   SILC_LOG_DEBUG(("Error occured while formatting buffer"));
1323   va_end(va);
1324   return -1;
1325
1326  ok:
1327   dst->end = dst->head + len;
1328   dst->data = dst->head + hlen;
1329   dst->tail = dst->end;
1330
1331   va_end(va);
1332   return len;
1333 }
1334
1335 /* Formats strings into a buffer.  Allocates memory from SilcStack. */
1336
1337 int silc_buffer_sstrformat(SilcStack stack, SilcBuffer dst, ...)
1338 {
1339   int len = silc_buffer_truelen(dst);
1340   int hlen = silc_buffer_headlen(dst);
1341   va_list va;
1342
1343   va_start(va, dst);
1344
1345   /* Parse the arguments by formatting type. */
1346   while(1) {
1347     char *string = va_arg(va, char *);
1348     unsigned char *d;
1349     SilcInt32 slen;
1350
1351     if (!string)
1352       continue;
1353     if (string == (char *)SILC_PARAM_END)
1354       goto ok;
1355
1356     slen = strlen(string);
1357     d = silc_srealloc(stack, len + 1, dst->head,
1358                       sizeof(*dst->head) * (slen + len + 1));
1359     if (silc_unlikely(!d))
1360       return -1;
1361     dst->head = d;
1362     memcpy(dst->head + len, string, slen);
1363     len += slen;
1364     dst->head[len] = '\0';
1365   }
1366
1367   SILC_LOG_DEBUG(("Error occured while formatting buffer"));
1368   va_end(va);
1369   return -1;
1370
1371  ok:
1372   dst->end = dst->head + len;
1373   dst->data = dst->head + hlen;
1374   dst->tail = dst->end;
1375
1376   va_end(va);
1377   return len;
1378 }