Added SILC_STR_STRING and SILC_STR_STRING_APPEND and support for
[crypto.git] / lib / silcutil / silcbuffer.h
1 /*
2
3   silcbuffer.h
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1998 - 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 /* $Id$ */
20
21 /****h* silcutil/SILC Buffer Interface
22  *
23  * DESCRIPTION
24  *
25  * SilcBuffer is very simple and easy to use, yet you can do to the
26  * buffer almost anything you want with its method functions. The buffer
27  * is constructed of four different data sections that in whole creates
28  * the allocated data area.
29  *
30  ***/
31
32 #ifndef SILCBUFFER_H
33 #define SILCBUFFER_H
34
35 /****s* silcutil/SilcBufferAPI/SilcBuffer
36  *
37  * NAME
38  *
39  *    typedef struct { ... } *SilcBuffer, SilcBufferStruct;
40  *
41  * DESCRIPTION
42  *
43  *    SILC Buffer object. Following short description of the fields
44  *    of the buffer.
45  *
46  * EXAMPLE
47  *
48  *    unsiged char *head;
49  *
50  *        Head of the allocated buffer. This is the start of the allocated
51  *        data area and remains as same throughout the lifetime of the buffer.
52  *        However, the end of the head area or the start of the currently valid
53  *        data area is variable.
54  *
55  *        --------------------------------
56  *        | head  | data         | tail  |
57  *        --------------------------------
58  *        ^       ^
59  *
60  *        Current head section in the buffer is sb->data - sb->head.
61  *
62  *    unsigned char *data;
63  *
64  *        Currently valid data area. This is the start of the currently valid
65  *        main data area. The data area is variable in all directions.
66  *
67  *        --------------------------------
68  *        | head  | data         | tail  |
69  *        --------------------------------
70  *                ^              ^
71  *
72  *        Current valid data area in the buffer is sb->tail - sb->data.
73  *
74  *     unsigned char *tail;
75  *
76  *        Tail of the buffer. This is the end of the currently valid data area
77  *        or start of the tail area. The start of the tail area is variable.
78  *
79  *        --------------------------------
80  *        | head  | data         | tail  |
81  *        --------------------------------
82  *                               ^       ^
83  *
84  *        Current tail section in the buffer is sb->end - sb->tail.
85  *
86  *    unsigned char *end;
87  *
88  *        End of the allocated buffer. This is the end of the allocated data
89  *        area and remains as same throughout the lifetime of the buffer.
90  *        Usually this field is not needed except when checking the size
91  *        of the buffer.
92  *
93  *        --------------------------------
94  *        | head  | data         | tail  |
95  *        --------------------------------
96  *                                       ^
97  *
98  *        Length of the entire buffer is (ie. truelen) sb->end - sb->head.
99  *
100  *     Currently valid data area is considered to be the main data area in
101  *     the buffer. However, the entire buffer is of course valid data and can
102  *     be used as such. Usually head section of the buffer includes different
103  *     kind of headers or similar. Data section includes the main data of
104  *     the buffer. Tail section can be seen as a reserve space of the data
105  *     section. Tail section can be pulled towards end, and thus the data
106  *     section becomes larger.
107  *
108  * SILC Buffer is not thread-safe.  If the same SilcBuffer context must be
109  * used in multithreaded environment concurrency control must be employed.
110  *
111  * SOURCE
112  */
113 typedef struct SilcBufferObject {
114   unsigned char *head;
115   unsigned char *data;
116   unsigned char *tail;
117   unsigned char *end;
118 } *SilcBuffer, SilcBufferStruct;
119 /***/
120
121 /* Macros */
122
123 /****f* silcutil/SilcBufferAPI/silc_buffer_data
124  *
125  * NAME
126  *
127  *    unsigned char *silc_buffer_data(SilcBuffer sb)
128  *
129  * DESCRIPTION
130  *
131  *    Returns pointer to the data area of the buffer.
132  *
133  * SOURCE
134  */
135 #define silc_buffer_data(x) (x)->data
136 /***/
137
138 /****f* silcutil/SilcBufferAPI/silc_buffer_datalen
139  *
140  * NAME
141  *
142  *    #define silc_buffer_datalen ...
143  *
144  * DESCRIPTION
145  *
146  *    Macro that can be used in function argument list to give the data
147  *    pointer and the data length, instead of calling both silc_buffer_data
148  *    and silc_buffer_len separately.
149  *
150  * EXAMPLE
151  *
152  *    // Following are the same thing
153  *    silc_foo_function(foo, silc_buffer_datalen(buf));
154  *    silc_foo_function(foo, silc_buffer_data(buf), silc_buffer_len(buf));
155  *
156  * SOURCE
157  */
158 #define silc_buffer_datalen(x) (x) ? silc_buffer_data((x)) : NULL, \
159   (x) ? silc_buffer_len((x)) : 0
160 /***/
161
162 /* Inline functions */
163
164 /****d* silcutil/SilcBufferAPI/silc_buffer_truelen
165  *
166  * NAME
167  *
168  *    SilcUInt32 silc_buffer_truelen(SilcBuffer sb)
169  *
170  * DESCRIPTION
171  *
172  *    Returns the true length of the buffer.
173  *
174  ***/
175 static inline
176 SilcUInt32 silc_buffer_truelen(SilcBuffer x)
177 {
178   return (SilcUInt32)(x->end - x->head);
179 }
180
181 /****d* silcutil/SilcBufferAPI/silc_buffer_len
182  *
183  * NAME
184  *
185  *    SilcUInt32 silc_buffer_len(SilcBuffer sb)
186  *
187  * DESCRIPTION
188  *
189  *    Returns the current length of the data area of the buffer.
190  *
191  ***/
192 static inline
193 SilcUInt32 silc_buffer_len(SilcBuffer x)
194 {
195   return (SilcUInt32)(x->tail - x->data);
196 }
197
198 /****d* silcutil/SilcBufferAPI/silc_buffer_headlen
199  *
200  * NAME
201  *
202  *    SilcUInt32 silc_buffer_headlen(SilcBuffer sb)
203  *
204  * DESCRIPTION
205  *
206  *    Returns the current length of the head data area of the buffer.
207  *
208  ***/
209 static inline
210 SilcUInt32 silc_buffer_headlen(SilcBuffer x)
211 {
212   return (SilcUInt32)(x->data - x->head);
213 }
214
215 /****d* silcutil/SilcBufferAPI/silc_buffer_taillen
216  *
217  * NAME
218  *
219  *    SilcUInt32 silc_buffer_taillen(SilcBuffer sb)
220  *
221  * DESCRIPTION
222  *
223  *    Returns the current length of the tail data area of the buffer.
224  *
225  ***/
226 static inline
227 SilcUInt32 silc_buffer_taillen(SilcBuffer x)
228 {
229   return (SilcUInt32)(x->end - x->tail);
230 }
231
232 /****f* silcutil/SilcBufferAPI/silc_buffer_alloc
233  *
234  * SYNOPSIS
235  *
236  *    static inline
237  *    SilcBuffer silc_buffer_alloc(SilcUInt32 len);
238  *
239  * DESCRIPTION
240  *
241  *    Allocates new SilcBuffer and returns it.  Returns NULL if system is
242  *    out of memory.
243  *
244  ***/
245
246 static inline
247 SilcBuffer silc_buffer_alloc(SilcUInt32 len)
248 {
249   SilcBuffer sb;
250
251   /* Allocate new SilcBuffer */
252   sb = (SilcBuffer)silc_calloc(1, sizeof(*sb));
253   if (silc_unlikely(!sb))
254     return NULL;
255
256   if (silc_likely(len)) {
257     /* Allocate the actual data area */
258     sb->head = (unsigned char *)silc_malloc(len * sizeof(*sb->head));
259     if (silc_unlikely(!sb->head))
260       return NULL;
261
262     /* Set pointers to the new buffer */
263     sb->data = sb->head;
264     sb->tail = sb->head;
265     sb->end = sb->head + len;
266   }
267
268   return sb;
269 }
270
271 /****f* silcutil/SilcBufferAPI/silc_buffer_salloc
272  *
273  * SYNOPSIS
274  *
275  *    static inline
276  *    SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len);
277  *
278  * DESCRIPTION
279  *
280  *    Allocates new SilcBuffer and returns it.  Returns NULL if system is
281  *    out of memory.
282  *
283  *    This routine use SilcStack are memory source.  If `stack' is NULL
284  *    reverts back to normal allocating routine.
285  *
286  *    Note that this call consumes the `stack'.  The caller should push the
287  *    stack before calling the function and pop it later.
288  *
289  ***/
290
291 static inline
292 SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len)
293 {
294   SilcBuffer sb;
295
296   if (!stack)
297     return silc_buffer_alloc(len);
298
299   /* Allocate new SilcBuffer */
300   sb = (SilcBuffer)silc_scalloc(stack, 1, sizeof(*sb));
301   if (silc_unlikely(!sb))
302     return NULL;
303
304   if (silc_likely(len)) {
305     /* Allocate the actual data area */
306     sb->head = (unsigned char *)silc_smalloc(stack, len * sizeof(*sb->head));
307     if (silc_unlikely(!sb->head))
308       return NULL;
309
310     /* Set pointers to the new buffer */
311     sb->data = sb->head;
312     sb->tail = sb->head;
313     sb->end = sb->head + len;
314   }
315
316   return sb;
317 }
318
319 /****f* silcutil/SilcBufferAPI/silc_buffer_free
320  *
321  * SYNOPSIS
322  *
323  *    static inline
324  *    void silc_buffer_free(SilcBuffer sb);
325  *
326  * DESCRIPTION
327  *
328  *    Frees SilcBuffer.  Can be called safely `sb' as NULL.
329  *
330  * NOTES
331  *
332  *    Must not be called for buffers allocated with silc_buffer_salloc,
333  *    silc_buffer_salloc_size, silc_buffer_scopy and silc_buffer_sclone.
334  *    Call silc_buffer_sfree instead.
335  *
336  ***/
337
338 static inline
339 void silc_buffer_free(SilcBuffer sb)
340 {
341   if (sb) {
342 #if defined(SILC_DEBUG)
343     if (sb->head)
344       memset(sb->head, 'F', silc_buffer_truelen(sb));
345 #endif
346     silc_free(sb->head);
347     silc_free(sb);
348   }
349 }
350
351 /****f* silcutil/SilcBufferAPI/silc_buffer_sfree
352  *
353  * SYNOPSIS
354  *
355  *    static inline
356  *    void silc_buffer_free(SilcStack stack, SilcBuffer sb);
357  *
358  * DESCRIPTION
359  *
360  *    Frees SilcBuffer.  If `stack' is NULL this calls silc_buffer_free.  Can
361  *    be called safely `sb' as NULL.
362  *
363  ***/
364
365 static inline
366 void silc_buffer_sfree(SilcStack stack, SilcBuffer sb)
367 {
368   if (stack) {
369 #ifdef SILC_DEBUG
370     if (sb) {
371       if (sb->head)
372         memset(sb->head, 'F', silc_buffer_truelen(sb));
373       memset(sb, 'F', sizeof(*sb));
374     }
375 #endif /* SILC_DEBUG */
376     return;
377   }
378
379   silc_buffer_free(sb);
380 }
381
382 /****f* silcutil/SilcBufferAPI/silc_buffer_steal
383  *
384  * SYNOPSIS
385  *
386  *    static inline
387  *    unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len);
388  *
389  * DESCRIPTION
390  *
391  *    Steals the data from the buffer `sb'.  This returns pointer to the
392  *    start of the buffer and the true length of that buffer.  The `sb'
393  *    cannot be used anymore after calling this function because the
394  *    data buffer was stolen.  The `sb' must be freed with silc_buffer_free.
395  *    The caller is responsible of freeing the stolen data buffer with
396  *    silc_free.
397  *
398  ***/
399
400 static inline
401 unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len)
402 {
403   unsigned char *buf = sb->head;
404   if (data_len)
405     *data_len = silc_buffer_truelen(sb);
406   sb->head = sb->data = sb->tail = sb->end = NULL;
407   return buf;
408 }
409
410 /****f* silcutil/SilcBufferAPI/silc_buffer_purge
411  *
412  * SYNOPSIS
413  *
414  *    static inline
415  *    void silc_buffer_purge(SilcBuffer sb);
416  *
417  * DESCRIPTION
418  *
419  *    Same as silc_buffer_free but free's only the contents of the buffer
420  *    not the buffer itself.  The `sb' remains intact, data is freed.  Buffer
421  *    is ready for re-use after calling this function.
422  *
423  * NOTES
424  *
425  *    Must not be called for buffers allocated with silc_buffer_salloc,
426  *    silc_buffer_salloc_size, silc_buffer_scopy and silc_buffer_sclone.
427  *    Use silc_buffer_spurge instead.
428  *
429  ***/
430
431 static inline
432 void silc_buffer_purge(SilcBuffer sb)
433 {
434   silc_free(silc_buffer_steal(sb, NULL));
435 }
436
437 /****f* silcutil/SilcBufferAPI/silc_buffer_spurge
438  *
439  * SYNOPSIS
440  *
441  *    static inline
442  *    void silc_buffer_spurge(SilcStack stack, SilcBuffer sb);
443  *
444  * DESCRIPTION
445  *
446  *    Same as silc_buffer_free but free's only the contents of the buffer
447  *    not the buffer itself.  The `sb' remains intact, data is freed.  Buffer
448  *    is ready for re-use after calling this function.  If `stack' is NULL
449  *    this calls silc_buffer_purge.
450  *
451  ***/
452
453 static inline
454 void silc_buffer_spurge(SilcStack stack, SilcBuffer sb)
455 {
456   if (stack) {
457 #ifdef SILC_DEBUG
458     if (sb && sb->head)
459       memset(silc_buffer_steal(sb, NULL), 'F', silc_buffer_truelen(sb));
460 #endif /* SILC_DEBUG */
461     return;
462   }
463
464   silc_buffer_purge(sb);
465 }
466
467 /****f* silcutil/SilcBufferAPI/silc_buffer_set
468  *
469  * SYNOPSIS
470  *
471  *    static inline
472  *    void silc_buffer_set(SilcBuffer sb,
473  *                         unsigned char *data,
474  *                         SilcUInt32 data_len);
475  *
476  * DESCRIPTION
477  *
478  *    Sets the `data' and `data_len' to the buffer pointer sent as argument.
479  *    The data area is automatically set to the `data_len'. This function
480  *    can be used to set the data to static buffer without needing any
481  *    memory allocations. The `data' will not be copied to the buffer.
482  *
483  * EXAMPLE
484  *
485  *    SilcBufferStruct buf;
486  *    silc_buffer_set(&buf, data, data_len);
487  *
488  ***/
489
490 static inline
491 void silc_buffer_set(SilcBuffer sb, unsigned char *data, SilcUInt32 data_len)
492 {
493   sb->data = sb->head = data;
494   sb->tail = sb->end = data + data_len;
495 }
496
497 /****f* silcutil/SilcBufferAPI/silc_buffer_pull
498  *
499  * SYNOPSIS
500  *
501  *    static inline
502  *    unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len);
503  *
504  * DESCRIPTION
505  *
506  *    Pulls current data area towards end. The length of the currently
507  *    valid data area is also decremented. Returns pointer to the data
508  *    area before pulling. Returns NULL if the pull would lead to buffer
509  *    overflow or would go beyond the valid data area.
510  *
511  * EXAMPLE
512  *
513  *    ---------------------------------
514  *    | head  | data       | tail     |
515  *    ---------------------------------
516  *            ^
517  *            Pulls the start of the data area.
518  *
519  *    ---------------------------------
520  *    | head     | data    | tail     |
521  *    ---------------------------------
522  *            ^
523  *
524  *    silc_buffer_pull(sb, 20);
525  *
526  ***/
527
528 static inline
529 unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len)
530 {
531   unsigned char *old_data = sb->data;
532
533 #ifdef SILC_DIST_INPLACE
534   SILC_ASSERT(len <= silc_buffer_len(sb));
535 #endif /* SILC_DIST_INPLACE */
536   if (silc_unlikely(len > silc_buffer_len(sb))) {
537     silc_set_errno(SILC_ERR_OVERFLOW);
538     return NULL;
539   }
540
541   sb->data += len;
542   return old_data;
543 }
544
545 /****f* silcutil/SilcBufferAPI/silc_buffer_push
546  *
547  * SYNOPSIS
548  *
549  *    static inline
550  *    unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len);
551  *
552  * DESCRIPTION
553  *
554  *    Pushes current data area towards beginning. Length of the currently
555  *    valid data area is also incremented. Returns a pointer to the
556  *    data area before pushing. Returns NULL if the push would lead to
557  *    buffer underflow or would go under the valid data area.
558  *
559  * EXAMPLE
560  *
561  *    ---------------------------------
562  *    | head     | data    | tail     |
563  *    ---------------------------------
564  *               ^
565  *               Pushes the start of the data area.
566  *
567  *    ---------------------------------
568  *    | head  | data       | tail     |
569  *    ---------------------------------
570  *               ^
571  *
572  *    silc_buffer_push(sb, 20);
573  *
574  ***/
575
576 static inline
577 unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len)
578 {
579   unsigned char *old_data = sb->data;
580
581 #ifdef SILC_DIST_INPLACE
582   SILC_ASSERT((sb->data - len) >= sb->head);
583 #endif /* SILC_DIST_INPLACE */
584   if (silc_unlikely((sb->data - len) < sb->head)) {
585     silc_set_errno(SILC_ERR_UNDERFLOW);
586     return NULL;
587   }
588
589   sb->data -= len;
590   return old_data;
591 }
592
593 /****f* silcutil/SilcBufferAPI/silc_buffer_pull_tail
594  *
595  * SYNOPSIS
596  *
597  *    static inline
598  *    unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len);
599  *
600  * DESCRIPTION
601  *
602  *    Pulls current tail section towards end. Length of the current valid
603  *    data area is also incremented. Returns a pointer to the data area
604  *    before pulling. Returns NULL if the pull would lead to buffer overflow.
605  *
606  * EXAMPLE
607  *
608  *    ---------------------------------
609  *    | head  | data       | tail     |
610  *    ---------------------------------
611  *                         ^
612  *                         Pulls the start of the tail section.
613  *
614  *    ---------------------------------
615  *    | head  | data           | tail |
616  *    ---------------------------------
617  *                         ^
618  *
619  *    silc_buffer_pull_tail(sb, 23);
620  *
621  ***/
622
623 static inline
624 unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len)
625 {
626   unsigned char *old_tail = sb->tail;
627
628 #ifdef SILC_DIST_INPLACE
629   SILC_ASSERT(len <= silc_buffer_taillen(sb));
630 #endif /* SILC_DIST_INPLACE */
631   if (silc_unlikely(len > silc_buffer_taillen(sb))) {
632     silc_set_errno(SILC_ERR_OVERFLOW);
633     return NULL;
634   }
635
636   sb->tail += len;
637   return old_tail;
638 }
639
640 /****f* silcutil/SilcBufferAPI/silc_buffer_push_tail
641  *
642  * SYNOPSIS
643  *
644  *    static inline
645  *    unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len);
646  *
647  * DESCRIPTION
648  *
649  *    Pushes current tail section towards beginning. Length of the current
650  *    valid data area is also decremented. Returns a pointer to the
651  *    tail section before pushing. Returns NULL if the push would lead to
652  *    buffer underflow or go under valid tail area.
653  *
654  * EXAMPLE
655  *
656  *    ---------------------------------
657  *    | head  | data           | tail |
658  *    ---------------------------------
659  *                             ^
660  *                             Pushes the start of the tail section.
661  *
662  *    ---------------------------------
663  *    | head  | data       | tail     |
664  *    ---------------------------------
665  *                             ^
666  *
667  *    silc_buffer_push_tail(sb, 23);
668  *
669  ***/
670
671 static inline
672 unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len)
673 {
674   unsigned char *old_tail = sb->tail;
675
676 #ifdef SILC_DIST_INPLACE
677   SILC_ASSERT((sb->tail - len) >= sb->data);
678 #endif /* SILC_DIST_INPLACE */
679   if (silc_unlikely((sb->tail - len) < sb->data)) {
680     silc_set_errno(SILC_ERR_UNDERFLOW);
681     return NULL;
682   }
683
684   sb->tail -= len;
685   return old_tail;
686 }
687
688 /****f* silcutil/SilcBufferAPI/silc_buffer_put_head
689  *
690  * SYNOPSIS
691  *
692  *    static inline
693  *    unsigned char *silc_buffer_put_head(SilcBuffer sb,
694  *                                        const unsigned char *data,
695  *                                        SilcUInt32 len);
696  *
697  * DESCRIPTION
698  *
699  *    Puts data at the head of the buffer. Returns pointer to the copied
700  *    data area. Returns NULL if the data is longer that the current head
701  *    area.
702  *
703  * EXAMPLE
704  *
705  *    ---------------------------------
706  *    | head  | data       | tail     |
707  *    ---------------------------------
708  *    ^
709  *    Puts data to the head section.
710  *
711  *    silc_buffer_put_head(sb, data, data_len);
712  *
713  ***/
714
715 static inline
716 unsigned char *silc_buffer_put_head(SilcBuffer sb,
717                                     const unsigned char *data,
718                                     SilcUInt32 len)
719 {
720 #ifdef SILC_DIST_INPLACE
721   SILC_ASSERT(len <= silc_buffer_headlen(sb));
722 #endif /* SILC_DIST_INPLACE */
723   if (silc_unlikely(len > silc_buffer_headlen(sb))) {
724     silc_set_errno(SILC_ERR_OVERFLOW);
725     return NULL;
726   }
727
728   if (sb->head > data) {
729     if (sb->head - data <= len)
730       return (unsigned char *)memmove(sb->head, data, len);
731   } else {
732     if (data - sb->head <= len)
733       return (unsigned char *)memmove(sb->head, data, len);
734   }
735
736   return (unsigned char *)memcpy(sb->head, data, len);
737 }
738
739 /****f* silcutil/SilcBufferAPI/silc_buffer_put
740  *
741  * SYNOPSIS
742  *
743  *    static inline
744  *    unsigned char *silc_buffer_put(SilcBuffer sb,
745  *                                   const unsigned char *data,
746  *                                   SilcUInt32 len);
747  *
748  * DESCRIPTION
749  *
750  *    Puts data at the start of the valid data area. Returns a pointer
751  *    to the copied data area.  Returns NULL if the data is longer than the
752  *    current data area.
753  *
754  * EXAMPLE
755  *
756  *    ---------------------------------
757  *    | head  | data       | tail     |
758  *    ---------------------------------
759  *            ^
760  *            Puts data to the data section.
761  *
762  *    silc_buffer_put(sb, data, data_len);
763  *
764  ***/
765
766 static inline
767 unsigned char *silc_buffer_put(SilcBuffer sb,
768                                const unsigned char *data,
769                                SilcUInt32 len)
770 {
771 #ifdef SILC_DIST_INPLACE
772   SILC_ASSERT(len <= silc_buffer_len(sb));
773 #endif /* SILC_DIST_INPLACE */
774   if (silc_unlikely(len > silc_buffer_len(sb))) {
775     silc_set_errno(SILC_ERR_OVERFLOW);
776     return NULL;
777   }
778
779   if (sb->data > data) {
780     if (sb->data - data <= len)
781       return (unsigned char *)memmove(sb->data, data, len);
782   } else {
783     if (data - sb->data <= len)
784       return (unsigned char *)memmove(sb->data, data, len);
785   }
786
787   return (unsigned char *)memcpy(sb->data, data, len);
788 }
789
790 /****f* silcutil/SilcBufferAPI/silc_buffer_put_tail
791  *
792  * SYNOPSIS
793  *
794  *    static inline
795  *    unsigned char *silc_buffer_put_tail(SilcBuffer sb,
796  *                                        const unsigned char *data,
797  *                                        SilcUInt32 len);
798  *
799  * DESCRIPTION
800  *
801  *    Puts data at the tail of the buffer. Returns pointer to the copied
802  *    data area.  Returns NULL if the data is longer than the current tail
803  *    area.
804  *
805  * EXAMPLE
806  *
807  *    ---------------------------------
808  *    | head  | data           | tail |
809  *    ---------------------------------
810  *                             ^
811  *                             Puts data to the tail section.
812  *
813  *    silc_buffer_put_tail(sb, data, data_len);
814  *
815  ***/
816
817 static inline
818 unsigned char *silc_buffer_put_tail(SilcBuffer sb,
819                                     const unsigned char *data,
820                                     SilcUInt32 len)
821 {
822 #ifdef SILC_DIST_INPLACE
823   SILC_ASSERT(len <= silc_buffer_taillen(sb));
824 #endif /* SILC_DIST_INPLACE */
825   if (silc_unlikely(len > silc_buffer_taillen(sb))) {
826     silc_set_errno(SILC_ERR_OVERFLOW);
827     return NULL;
828   }
829
830   if (sb->tail > data) {
831     if (sb->tail - data <= len)
832       return (unsigned char *)memmove(sb->tail, data, len);
833   } else {
834     if (data - sb->tail <= len)
835       return (unsigned char *)memmove(sb->tail, data, len);
836   }
837
838   return (unsigned char *)memcpy(sb->tail, data, len);
839 }
840
841 /****f* silcutil/SilcBufferAPI/silc_buffer_alloc_size
842  *
843  * SYNOPSIS
844  *
845  *    static inline
846  *    SilcBuffer silc_buffer_alloc_size(SilcUInt32 len);
847  *
848  * DESCRIPTION
849  *
850  *    Allocates `len' bytes size buffer and moves the tail area automatically
851  *    `len' bytes so that the buffer is ready to use without calling the
852  *    silc_buffer_pull_tail.  Returns NULL if system is out of memory.
853  *
854  ***/
855
856 static inline
857 SilcBuffer silc_buffer_alloc_size(SilcUInt32 len)
858 {
859   SilcBuffer sb = silc_buffer_alloc(len);
860   if (silc_unlikely(!sb))
861     return NULL;
862   silc_buffer_pull_tail(sb, len);
863   return sb;
864 }
865
866 /****f* silcutil/SilcBufferAPI/silc_buffer_salloc_size
867  *
868  * SYNOPSIS
869  *
870  *    static inline
871  *    SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len);
872  *
873  * DESCRIPTION
874  *
875  *    Allocates `len' bytes size buffer and moves the tail area automatically
876  *    `len' bytes so that the buffer is ready to use without calling the
877  *    silc_buffer_pull_tail.  Returns NULL if system is out of memory.
878  *
879  *    This routine use SilcStack are memory source.  If `stack' is NULL
880  *    reverts back to normal allocating routine.
881  *
882  *    Note that this call consumes the `stack'.  The caller should push the
883  *    stack before calling the function and pop it later.
884  *
885  ***/
886
887 static inline
888 SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len)
889 {
890   SilcBuffer sb = silc_buffer_salloc(stack, len);
891   if (silc_unlikely(!sb))
892     return NULL;
893   silc_buffer_pull_tail(sb, len);
894   return sb;
895 }
896
897 /****f* silcutil/SilcBufferAPI/silc_buffer_reset
898  *
899  * SYNOPSIS
900  *
901  *    static inline
902  *    void silc_buffer_reset(SilcBuffer sb);
903  *
904  * DESCRIPTION
905  *
906  *    Resets the buffer to the state as if it was just allocated by
907  *    silc_buffer_alloc.  This does not clear the data area.  Use
908  *    silc_buffer_clear if you also want to clear the data area.
909  *
910  ***/
911
912 static inline
913 void silc_buffer_reset(SilcBuffer sb)
914 {
915   sb->data = sb->tail = sb->head;
916 }
917
918 /****f* silcutil/SilcBufferAPI/silc_buffer_clear
919  *
920  * SYNOPSIS
921  *
922  *    static inline
923  *    void silc_buffer_clear(SilcBuffer sb);
924  *
925  * DESCRIPTION
926  *
927  *    Clears and initialiazes the buffer to the state as if it was just
928  *    allocated by silc_buffer_alloc.
929  *
930  ***/
931
932 static inline
933 void silc_buffer_clear(SilcBuffer sb)
934 {
935   memset(sb->head, 0, silc_buffer_truelen(sb));
936   silc_buffer_reset(sb);
937 }
938
939 /****f* silcutil/SilcBufferAPI/silc_buffer_start
940  *
941  * SYNOPSIS
942  *
943  *    static inline
944  *    void silc_buffer_start(SilcBuffer sb);
945  *
946  * DESCRIPTION
947  *
948  *    Moves the data area at the start of the buffer.  The tail area remains
949  *    as is.
950  *
951  ***/
952
953 static inline
954 void silc_buffer_start(SilcBuffer sb)
955 {
956   sb->data = sb->head;
957 }
958
959 /****f* silcutil/SilcBufferAPI/silc_buffer_end
960  *
961  * SYNOPSIS
962  *
963  *    static inline
964  *    void silc_buffer_end(SilcBuffer sb);
965  *
966  * DESCRIPTION
967  *
968  *    Moves the end of the data area to the end of the buffer.  The start
969  *    of the data area remains same.  If the start of data area is at the
970  *    start of the buffer, after this function returns the buffer's data
971  *    area length is the length of the entire buffer.
972  *
973  ***/
974
975 static inline
976 void silc_buffer_end(SilcBuffer sb)
977 {
978   sb->tail = sb->end;
979 }
980
981 /****f* silcutil/SilcBufferAPI/silc_buffer_copy
982  *
983  * SYNOPSIS
984  *
985  *    static inline
986  *    SilcBuffer silc_buffer_copy(SilcBuffer sb);
987  *
988  * DESCRIPTION
989  *
990  *    Generates copy of a SilcBuffer. This copies everything inside the
991  *    currently valid data area, nothing more. Use silc_buffer_clone to
992  *    copy entire buffer.  Returns NULL if system is out of memory.
993  *
994  ***/
995
996 static inline
997 SilcBuffer silc_buffer_copy(SilcBuffer sb)
998 {
999   SilcBuffer sb_new;
1000
1001   sb_new = silc_buffer_alloc_size(silc_buffer_len(sb));
1002   if (silc_unlikely(!sb_new))
1003     return NULL;
1004   silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
1005
1006   return sb_new;
1007 }
1008
1009 /****f* silcutil/SilcBufferAPI/silc_buffer_scopy
1010  *
1011  * SYNOPSIS
1012  *
1013  *    static inline
1014  *    SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb);
1015  *
1016  * DESCRIPTION
1017  *
1018  *    Generates copy of a SilcBuffer. This copies everything inside the
1019  *    currently valid data area, nothing more. Use silc_buffer_clone to
1020  *    copy entire buffer.  Returns NULL if system is out of memory.
1021  *
1022  *    This routine use SilcStack are memory source.  If `stack' is NULL
1023  *    reverts back to normal allocating routine.
1024  *
1025  *    Note that this call consumes the `stack'.  The caller should push the
1026  *    stack before calling the function and pop it later.
1027  *
1028  ***/
1029
1030 static inline
1031 SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb)
1032 {
1033   SilcBuffer sb_new;
1034
1035   sb_new = silc_buffer_salloc_size(stack, silc_buffer_len(sb));
1036   if (silc_unlikely(!sb_new))
1037     return NULL;
1038   silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
1039
1040   return sb_new;
1041 }
1042
1043 /****f* silcutil/SilcBufferAPI/silc_buffer_clone
1044  *
1045  * SYNOPSIS
1046  *
1047  *    static inline
1048  *    SilcBuffer silc_buffer_clone(SilcBuffer sb);
1049  *
1050  * DESCRIPTION
1051  *
1052  *    Clones SilcBuffer. This generates new SilcBuffer and copies
1053  *    everything from the source buffer. The result is exact clone of
1054  *    the original buffer.  Returns NULL if system is out of memory.
1055  *
1056  ***/
1057
1058 static inline
1059 SilcBuffer silc_buffer_clone(SilcBuffer sb)
1060 {
1061   SilcBuffer sb_new;
1062
1063   sb_new = silc_buffer_alloc_size(silc_buffer_truelen(sb));
1064   if (silc_unlikely(!sb_new))
1065     return NULL;
1066   silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
1067   sb_new->data = sb_new->head + silc_buffer_headlen(sb);
1068   sb_new->tail = sb_new->data + silc_buffer_len(sb);
1069
1070   return sb_new;
1071 }
1072
1073 /****f* silcutil/SilcBufferAPI/silc_buffer_sclone
1074  *
1075  * SYNOPSIS
1076  *
1077  *    static inline
1078  *    SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb);
1079  *
1080  * DESCRIPTION
1081  *
1082  *    Clones SilcBuffer. This generates new SilcBuffer and copies
1083  *    everything from the source buffer. The result is exact clone of
1084  *    the original buffer.  Returns NULL if system is out of memory.
1085  *
1086  *    This routine use SilcStack are memory source.  If `stack' is NULL
1087  *    reverts back to normal allocating routine.
1088  *
1089  *    Note that this call consumes the `stack'.  The caller should push the
1090  *    stack before calling the function and pop it later.
1091  *
1092  ***/
1093
1094 static inline
1095 SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb)
1096 {
1097   SilcBuffer sb_new;
1098
1099   sb_new = silc_buffer_salloc_size(stack, silc_buffer_truelen(sb));
1100   if (silc_unlikely(!sb_new))
1101     return NULL;
1102   silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
1103   sb_new->data = sb_new->head + silc_buffer_headlen(sb);
1104   sb_new->tail = sb_new->data + silc_buffer_len(sb);
1105
1106   return sb_new;
1107 }
1108
1109 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc
1110  *
1111  * SYNOPSIS
1112  *
1113  *    static inline
1114  *    SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize);
1115  *
1116  * DESCRIPTION
1117  *
1118  *    Reallocates buffer. Old data is saved into the new buffer. The buffer
1119  *    is exact clone of the old one except that there is now more space
1120  *    at the end of buffer.  This always returns the same `sb' unless `sb'
1121  *    was NULL. Returns NULL if system is out of memory.
1122  *
1123  ***/
1124
1125 static inline
1126 SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize)
1127 {
1128   SilcUInt32 hlen, dlen;
1129   unsigned char *h;
1130
1131   if (!sb)
1132     return silc_buffer_alloc(newsize);
1133
1134   if (silc_unlikely(newsize <= silc_buffer_truelen(sb)))
1135     return sb;
1136
1137   hlen = silc_buffer_headlen(sb);
1138   dlen = silc_buffer_len(sb);
1139   h = (unsigned char *)silc_realloc(sb->head, newsize);
1140   if (silc_unlikely(!h))
1141     return NULL;
1142   sb->head = h;
1143   sb->data = sb->head + hlen;
1144   sb->tail = sb->data + dlen;
1145   sb->end = sb->head + newsize;
1146
1147   return sb;
1148 }
1149
1150 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc
1151  *
1152  * SYNOPSIS
1153  *
1154  *    static inline
1155  *    SilcBuffer silc_buffer_srealloc(SilcStack stack,
1156  *                                    SilcBuffer sb, SilcUInt32 newsize);
1157  *
1158  * DESCRIPTION
1159  *
1160  *    Reallocates buffer. Old data is saved into the new buffer. The buffer
1161  *    is exact clone of the old one except that there is now more space
1162  *    at the end of buffer.  Returns NULL if system is out of memory.
1163  *
1164  *    This routine use SilcStack are memory source.  If `stack' is NULL
1165  *    reverts back to normal allocating routine.
1166  *
1167  *    Note that this call consumes the `stack'.  The caller should push the
1168  *    stack before calling the function and pop it later.
1169  *
1170  ***/
1171
1172 static inline
1173 SilcBuffer silc_buffer_srealloc(SilcStack stack,
1174                                 SilcBuffer sb, SilcUInt32 newsize)
1175 {
1176   SilcUInt32 hlen, dlen;
1177   unsigned char *h;
1178
1179   if (!stack)
1180     return silc_buffer_realloc(sb, newsize);
1181
1182   if (!sb)
1183     return silc_buffer_salloc(stack, newsize);
1184
1185   if (newsize <= silc_buffer_truelen(sb))
1186     return sb;
1187
1188   hlen = silc_buffer_headlen(sb);
1189   dlen = silc_buffer_len(sb);
1190   h = (unsigned char *)silc_srealloc(stack, silc_buffer_truelen(sb),
1191                                      sb->head, newsize);
1192   if (!h)
1193     return NULL;
1194
1195   sb->head = h;
1196   sb->data = sb->head + hlen;
1197   sb->tail = sb->data + dlen;
1198   sb->end = sb->head + newsize;
1199
1200   return sb;
1201 }
1202
1203 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc_size
1204  *
1205  * SYNOPSIS
1206  *
1207  *    static inline
1208  *    SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize);
1209  *
1210  * DESCRIPTION
1211  *
1212  *    Same as silc_buffer_realloc but moves moves the tail area
1213  *    automatically so that the buffer is ready to use without calling the
1214  *    silc_buffer_pull_tail.  Returns NULL if system is out of memory.
1215  *
1216  ***/
1217
1218 static inline
1219 SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize)
1220 {
1221   sb = silc_buffer_realloc(sb, newsize);
1222   if (silc_unlikely(!sb))
1223     return NULL;
1224   silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
1225   return sb;
1226 }
1227
1228 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc_size
1229  *
1230  * SYNOPSIS
1231  *
1232  *    static inline
1233  *    SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
1234  *                                         SilcBuffer sb, SilcUInt32 newsize);
1235  *
1236  * DESCRIPTION
1237  *
1238  *    Same as silc_buffer_srealloc but moves moves the tail area
1239  *    automatically so that the buffer is ready to use without calling the
1240  *    silc_buffer_pull_tail.  Returns NULL if system is out of memory.
1241  *
1242  *    This routine use SilcStack are memory source.  If `stack' is NULL
1243  *    reverts back to normal allocating routine.
1244  *
1245  *    Note that this call consumes the `stack'.  The caller should push the
1246  *    stack before calling the function and pop it later.
1247  *
1248  ***/
1249
1250 static inline
1251 SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
1252                                      SilcBuffer sb, SilcUInt32 newsize)
1253 {
1254   sb = silc_buffer_srealloc(stack, sb, newsize);
1255   if (silc_unlikely(!sb))
1256     return NULL;
1257   silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
1258   return sb;
1259 }
1260
1261 /****f* silcutil/SilcBufferAPI/silc_buffer_enlarge
1262  *
1263  * SYNOPSIS
1264  *
1265  *    static inline
1266  *    SilcBuffer silc_buffer_enlarge(SilcBuffer sb, SilcUInt32 size);
1267  *
1268  * DESCRIPTION
1269  *
1270  *    Enlarges the buffer by the amount of `size' if it doesn't have that
1271  *    must space in the data area and in the tail area.  Moves the tail
1272  *    area automatically after enlarging so that the current data area
1273  *    is at least the size of `size'.  If there is more space than `size'
1274  *    in the data area this does not do anything.  If there is enough
1275  *    space in the tail area this merely moves the tail area to reveal
1276  *    the extra space.  Returns FALSE if system is out of memory.
1277  *
1278  ***/
1279
1280 static inline
1281 SilcBool silc_buffer_enlarge(SilcBuffer sb, SilcUInt32 size)
1282 {
1283   if (size > silc_buffer_len(sb)) {
1284     if (size > silc_buffer_taillen(sb) + silc_buffer_len(sb))
1285       if (silc_unlikely(!silc_buffer_realloc(sb, silc_buffer_truelen(sb) +
1286                                              (size - silc_buffer_taillen(sb) -
1287                                               silc_buffer_len(sb)))))
1288         return FALSE;
1289     silc_buffer_pull_tail(sb, size - silc_buffer_len(sb));
1290   }
1291   return TRUE;
1292 }
1293
1294 /****f* silcutil/SilcBufferAPI/silc_buffer_senlarge
1295  *
1296  * SYNOPSIS
1297  *
1298  *    static inline
1299  *    SilcBuffer silc_buffer_senlarge(SilcStack stack, SilcBuffer sb,
1300  *                                    SilcUInt32 size);
1301  *
1302  * DESCRIPTION
1303  *
1304  *    Enlarges the buffer by the amount of `size' if it doesn't have that
1305  *    must space in the data area and in the tail area.  Moves the tail
1306  *    area automatically after enlarging so that the current data area
1307  *    is at least the size of `size'.  If there is more space than `size'
1308  *    in the data area this does not do anything.  If there is enough
1309  *    space in the tail area this merely moves the tail area to reveal
1310  *    the extra space.  Returns FALSE if system is out of memory.
1311  *
1312  *    This routine use SilcStack are memory source.  If `stack' is NULL
1313  *    reverts back to normal allocating routine.
1314  *
1315  *    Note that this call consumes the `stack'.  The caller should push the
1316  *    stack before calling the function and pop it later.
1317  *
1318  ***/
1319
1320 static inline
1321 SilcBool silc_buffer_senlarge(SilcStack stack, SilcBuffer sb, SilcUInt32 size)
1322 {
1323   if (size > silc_buffer_len(sb)) {
1324     if (size > silc_buffer_taillen(sb) + silc_buffer_len(sb))
1325       if (silc_unlikely(!silc_buffer_srealloc(stack, sb,
1326                                               silc_buffer_truelen(sb) +
1327                                               (size - silc_buffer_taillen(sb) -
1328                                                silc_buffer_len(sb)))))
1329         return FALSE;
1330     silc_buffer_pull_tail(sb, size - silc_buffer_len(sb));
1331   }
1332   return TRUE;
1333 }
1334
1335 /****f* silcutil/SilcBufferAPI/silc_buffer_append
1336  *
1337  * SYNOPSIS
1338  *
1339  *    static inline
1340  *    SilcBuffer silc_buffer_append(SilcBuffer sb, SilcUInt32 size);
1341  *
1342  * DESCRIPTION
1343  *
1344  *    Appends the current data area by the amount of `size'.  The tail area
1345  *    of the buffer remains intact and contains the same data than the old
1346  *    tail area (the data is copied to the new tail area).  After appending
1347  *    there is now `size' bytes more free area in the data area.  Returns
1348  *    FALSE if system is out of memory.
1349  *
1350  * EXAMPLE
1351  *
1352  *    Before appending:
1353  *    ---------------------------------
1354  *    | head  | data           | tail |
1355  *    ---------------------------------
1356  *
1357  *    After appending:
1358  *    ------------------------------------
1359  *    | head  | data               | tail |
1360  *    -------------------------------------
1361  *
1362  *    silc_buffer_append(sb, 5);
1363  *
1364  ***/
1365
1366 static inline
1367 SilcBool silc_buffer_append(SilcBuffer sb, SilcUInt32 size)
1368 {
1369   if (silc_unlikely(!silc_buffer_realloc(sb, silc_buffer_truelen(sb) + size)))
1370     return FALSE;
1371
1372   /* Enlarge data area */
1373   silc_buffer_pull_tail(sb, size);
1374
1375   /* Copy old tail area to new tail area */
1376   silc_buffer_put_tail(sb, sb->tail - size, silc_buffer_taillen(sb));
1377
1378   return TRUE;
1379 }
1380
1381 /****f* silcutil/SilcBufferAPI/silc_buffer_append
1382  *
1383  * SYNOPSIS
1384  *
1385  *    static inline
1386  *    SilcBool silc_buffer_sappend(SilcStack stack, SilcBuffer sb,
1387  *                                 SilcUInt32 size)
1388  *
1389  * DESCRIPTION
1390  *
1391  *    Appends the current data area by the amount of `size'.  The tail area
1392  *    of the buffer remains intact and contains the same data than the old
1393  *    tail area (the data is copied to the new tail area).  After appending
1394  *    there is now `size' bytes more free area in the data area.  Returns
1395  *    FALSE if system is out of memory.
1396  *
1397  *    This routine use SilcStack are memory source.  If `stack' is NULL
1398  *    reverts back to normal allocating routine.
1399  *
1400  *    Note that this call consumes the `stack'.  The caller should push the
1401  *    stack before calling the function and pop it later.
1402  *
1403  * EXAMPLE
1404  *
1405  *    Before appending:
1406  *    ---------------------------------
1407  *    | head  | data           | tail |
1408  *    ---------------------------------
1409  *
1410  *    After appending:
1411  *    ------------------------------------
1412  *    | head  | data               | tail |
1413  *    -------------------------------------
1414  *
1415  *    silc_buffer_append(sb, 5);
1416  *
1417  ***/
1418
1419 static inline
1420 SilcBool silc_buffer_sappend(SilcStack stack, SilcBuffer sb, SilcUInt32 size)
1421 {
1422   if (silc_unlikely(!silc_buffer_srealloc(stack, sb,
1423                                           silc_buffer_truelen(sb) + size)))
1424     return FALSE;
1425
1426   /* Enlarge data area */
1427   silc_buffer_pull_tail(sb, size);
1428
1429   /* Copy old tail area to new tail area */
1430   silc_buffer_put_tail(sb, sb->tail - size, silc_buffer_taillen(sb));
1431
1432   return TRUE;
1433 }
1434
1435 /****f* silcutil/SilcBufferAPI/silc_buffer_strchr
1436  *
1437  * SYNOPSIS
1438  *
1439  *    static inline
1440  *    unsigned char *silc_buffer_strchr(SilcBuffer sb, int c, SilcBool first);
1441  *
1442  * DESCRIPTION
1443  *
1444  *    Returns pointer to the occurence of the character `c' in the buffer
1445  *    `sb'.  If the `first' is TRUE this finds the first occurene of `c',
1446  *    if it is FALSE this finds the last occurence of `c'.  If the character
1447  *    is found the `sb' data area is moved to that location and its pointer
1448  *    is returned.  The silc_buffer_data call will return the same pointer.
1449  *    Returns NULL if such character could not be located and the buffer
1450  *    remains unmodified.
1451  *
1452  *    This call is equivalent to strchr(), strrchr(), memchr() and memrchr()
1453  *    except it works with SilcBuffer.
1454  *
1455  * NOTES
1456  *
1457  *    This searches only the data area of the buffer.  Head and tail area
1458  *    are not searched.
1459  *
1460  *    The `sb' data need not be NULL terminated.
1461  *
1462  ***/
1463
1464 static inline
1465 unsigned char *silc_buffer_strchr(SilcBuffer sb, int c, SilcBool first)
1466 {
1467   int i;
1468
1469   if (first) {
1470     for (i = 0; i < silc_buffer_len(sb); i++) {
1471       if (sb->data[i] == (unsigned char)c) {
1472         sb->data = &sb->data[i];
1473         return sb->data;
1474       }
1475     }
1476   } else {
1477     for (i = silc_buffer_len(sb) - 1; 1 >= 0; i--) {
1478       if (sb->data[i] == (unsigned char)c) {
1479         sb->data = &sb->data[i];
1480         return sb->data;
1481       }
1482     }
1483   }
1484
1485   return NULL;
1486 }
1487
1488 /****f* silcutil/SilcBufferAPI/silc_buffer_cmp
1489  *
1490  * SYNOPSIS
1491  *
1492  *    static inline
1493  *    SilcBool silc_buffer_equal(SilcBuffer sb1, SilcBuffer sb2)
1494  *
1495  * DESCRIPTION
1496  *
1497  *    Compares if the data area of the buffer `sb1' and `sb2' are identical.
1498  *    Returns TRUE if they match and FALSE if they differ.
1499  *
1500  ***/
1501
1502 static inline
1503 SilcBool silc_buffer_equal(SilcBuffer sb1, SilcBuffer sb2)
1504 {
1505   if (silc_buffer_len(sb1) != silc_buffer_len(sb2))
1506     return FALSE;
1507   return memcmp(sb1->data, sb2->data, silc_buffer_len(sb1)) == 0;
1508 }
1509
1510 /****f* silcutil/SilcBufferAPI/silc_buffer_printf
1511  *
1512  * SYNOPSIS
1513  *
1514  *    static inline
1515  *    void silc_buffer_printf(SilcBuffer sb, SilcBool newline);
1516  *
1517  * DESCRIPTION
1518  *
1519  *    Prints the current data area of `sb' into stdout.  If `newline' is
1520  *    TRUE prints '\n' after the data in the buffer.
1521  *
1522  ***/
1523
1524 static inline
1525 void silc_buffer_printf(SilcBuffer sb, SilcBool newline)
1526 {
1527   silc_file_write(1, silc_buffer_data(sb), silc_buffer_len(sb));
1528   if (newline)
1529     printf("\n");
1530   fflush(stdout);
1531 }
1532
1533 #endif /* SILCBUFFER_H */