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