30f11dc344d7c9177988f2d3a9ba79e528abb751
[silc.git] / lib / silcutil / silcbuffer.h
1 /*
2
3   silcbuffer.h
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1998 - 2007 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19 /* $Id$ */
20
21 /****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   return (unsigned char *)memcpy(sb->head, data, len);
729 }
730
731 /****f* silcutil/SilcBufferAPI/silc_buffer_put
732  *
733  * SYNOPSIS
734  *
735  *    static inline
736  *    unsigned char *silc_buffer_put(SilcBuffer sb,
737  *                                   const unsigned char *data,
738  *                                   SilcUInt32 len);
739  *
740  * DESCRIPTION
741  *
742  *    Puts data at the start of the valid data area. Returns a pointer
743  *    to the copied data area.  Returns NULL if the data is longer than the
744  *    current data area.
745  *
746  * EXAMPLE
747  *
748  *    ---------------------------------
749  *    | head  | data       | tail     |
750  *    ---------------------------------
751  *            ^
752  *            Puts data to the data section.
753  *
754  *    silc_buffer_put(sb, data, data_len);
755  *
756  ***/
757
758 static inline
759 unsigned char *silc_buffer_put(SilcBuffer sb,
760                                const unsigned char *data,
761                                SilcUInt32 len)
762 {
763 #ifdef SILC_DIST_INPLACE
764   SILC_ASSERT(len <= silc_buffer_len(sb));
765 #endif /* SILC_DIST_INPLACE */
766   if (silc_unlikely(len > silc_buffer_len(sb))) {
767     silc_set_errno(SILC_ERR_OVERFLOW);
768     return NULL;
769   }
770
771   return (unsigned char *)memcpy(sb->data, data, len);
772 }
773
774 /****f* silcutil/SilcBufferAPI/silc_buffer_put_tail
775  *
776  * SYNOPSIS
777  *
778  *    static inline
779  *    unsigned char *silc_buffer_put_tail(SilcBuffer sb,
780  *                                        const unsigned char *data,
781  *                                        SilcUInt32 len);
782  *
783  * DESCRIPTION
784  *
785  *    Puts data at the tail of the buffer. Returns pointer to the copied
786  *    data area.  Returns NULL if the data is longer than the current tail
787  *    area.
788  *
789  * EXAMPLE
790  *
791  *    ---------------------------------
792  *    | head  | data           | tail |
793  *    ---------------------------------
794  *                             ^
795  *                             Puts data to the tail section.
796  *
797  *    silc_buffer_put_tail(sb, data, data_len);
798  *
799  ***/
800
801 static inline
802 unsigned char *silc_buffer_put_tail(SilcBuffer sb,
803                                     const unsigned char *data,
804                                     SilcUInt32 len)
805 {
806 #ifdef SILC_DIST_INPLACE
807   SILC_ASSERT(len <= silc_buffer_taillen(sb));
808 #endif /* SILC_DIST_INPLACE */
809   if (silc_unlikely(len > silc_buffer_taillen(sb))) {
810     silc_set_errno(SILC_ERR_OVERFLOW);
811     return NULL;
812   }
813
814   return (unsigned char *)memcpy(sb->tail, data, len);
815 }
816
817 /****f* silcutil/SilcBufferAPI/silc_buffer_alloc_size
818  *
819  * SYNOPSIS
820  *
821  *    static inline
822  *    SilcBuffer silc_buffer_alloc_size(SilcUInt32 len);
823  *
824  * DESCRIPTION
825  *
826  *    Allocates `len' bytes size buffer and moves the tail area automatically
827  *    `len' bytes so that the buffer is ready to use without calling the
828  *    silc_buffer_pull_tail.  Returns NULL if system is out of memory.
829  *
830  ***/
831
832 static inline
833 SilcBuffer silc_buffer_alloc_size(SilcUInt32 len)
834 {
835   SilcBuffer sb = silc_buffer_alloc(len);
836   if (silc_unlikely(!sb))
837     return NULL;
838   silc_buffer_pull_tail(sb, len);
839   return sb;
840 }
841
842 /****f* silcutil/SilcBufferAPI/silc_buffer_salloc_size
843  *
844  * SYNOPSIS
845  *
846  *    static inline
847  *    SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len);
848  *
849  * DESCRIPTION
850  *
851  *    Allocates `len' bytes size buffer and moves the tail area automatically
852  *    `len' bytes so that the buffer is ready to use without calling the
853  *    silc_buffer_pull_tail.  Returns NULL if system is out of memory.
854  *
855  *    This routine use SilcStack are memory source.  If `stack' is NULL
856  *    reverts back to normal allocating routine.
857  *
858  *    Note that this call consumes the `stack'.  The caller should push the
859  *    stack before calling the function and pop it later.
860  *
861  ***/
862
863 static inline
864 SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len)
865 {
866   SilcBuffer sb = silc_buffer_salloc(stack, len);
867   if (silc_unlikely(!sb))
868     return NULL;
869   silc_buffer_pull_tail(sb, len);
870   return sb;
871 }
872
873 /****f* silcutil/SilcBufferAPI/silc_buffer_reset
874  *
875  * SYNOPSIS
876  *
877  *    static inline
878  *    void silc_buffer_reset(SilcBuffer sb);
879  *
880  * DESCRIPTION
881  *
882  *    Resets the buffer to the state as if it was just allocated by
883  *    silc_buffer_alloc.  This does not clear the data area.  Use
884  *    silc_buffer_clear if you also want to clear the data area.
885  *
886  ***/
887
888 static inline
889 void silc_buffer_reset(SilcBuffer sb)
890 {
891   sb->data = sb->tail = sb->head;
892 }
893
894 /****f* silcutil/SilcBufferAPI/silc_buffer_clear
895  *
896  * SYNOPSIS
897  *
898  *    static inline
899  *    void silc_buffer_clear(SilcBuffer sb);
900  *
901  * DESCRIPTION
902  *
903  *    Clears and initialiazes the buffer to the state as if it was just
904  *    allocated by silc_buffer_alloc.
905  *
906  ***/
907
908 static inline
909 void silc_buffer_clear(SilcBuffer sb)
910 {
911   memset(sb->head, 0, silc_buffer_truelen(sb));
912   silc_buffer_reset(sb);
913 }
914
915 /****f* silcutil/SilcBufferAPI/silc_buffer_start
916  *
917  * SYNOPSIS
918  *
919  *    static inline
920  *    void silc_buffer_start(SilcBuffer sb);
921  *
922  * DESCRIPTION
923  *
924  *    Moves the data area at the start of the buffer.  The tail area remains
925  *    as is.
926  *
927  ***/
928
929 static inline
930 void silc_buffer_start(SilcBuffer sb)
931 {
932   sb->data = sb->head;
933 }
934
935 /****f* silcutil/SilcBufferAPI/silc_buffer_end
936  *
937  * SYNOPSIS
938  *
939  *    static inline
940  *    void silc_buffer_end(SilcBuffer sb);
941  *
942  * DESCRIPTION
943  *
944  *    Moves the end of the data area to the end of the buffer.  The start
945  *    of the data area remains same.  If the start of data area is at the
946  *    start of the buffer, after this function returns the buffer's data
947  *    area length is the length of the entire buffer.
948  *
949  ***/
950
951 static inline
952 void silc_buffer_end(SilcBuffer sb)
953 {
954   sb->tail = sb->end;
955 }
956
957 /****f* silcutil/SilcBufferAPI/silc_buffer_copy
958  *
959  * SYNOPSIS
960  *
961  *    static inline
962  *    SilcBuffer silc_buffer_copy(SilcBuffer sb);
963  *
964  * DESCRIPTION
965  *
966  *    Generates copy of a SilcBuffer. This copies everything inside the
967  *    currently valid data area, nothing more. Use silc_buffer_clone to
968  *    copy entire buffer.  Returns NULL if system is out of memory.
969  *
970  ***/
971
972 static inline
973 SilcBuffer silc_buffer_copy(SilcBuffer sb)
974 {
975   SilcBuffer sb_new;
976
977   sb_new = silc_buffer_alloc_size(silc_buffer_len(sb));
978   if (silc_unlikely(!sb_new))
979     return NULL;
980   silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
981
982   return sb_new;
983 }
984
985 /****f* silcutil/SilcBufferAPI/silc_buffer_scopy
986  *
987  * SYNOPSIS
988  *
989  *    static inline
990  *    SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb);
991  *
992  * DESCRIPTION
993  *
994  *    Generates copy of a SilcBuffer. This copies everything inside the
995  *    currently valid data area, nothing more. Use silc_buffer_clone to
996  *    copy entire buffer.  Returns NULL if system is out of memory.
997  *
998  *    This routine use SilcStack are memory source.  If `stack' is NULL
999  *    reverts back to normal allocating routine.
1000  *
1001  *    Note that this call consumes the `stack'.  The caller should push the
1002  *    stack before calling the function and pop it later.
1003  *
1004  ***/
1005
1006 static inline
1007 SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb)
1008 {
1009   SilcBuffer sb_new;
1010
1011   sb_new = silc_buffer_salloc_size(stack, silc_buffer_len(sb));
1012   if (silc_unlikely(!sb_new))
1013     return NULL;
1014   silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
1015
1016   return sb_new;
1017 }
1018
1019 /****f* silcutil/SilcBufferAPI/silc_buffer_clone
1020  *
1021  * SYNOPSIS
1022  *
1023  *    static inline
1024  *    SilcBuffer silc_buffer_clone(SilcBuffer sb);
1025  *
1026  * DESCRIPTION
1027  *
1028  *    Clones SilcBuffer. This generates new SilcBuffer and copies
1029  *    everything from the source buffer. The result is exact clone of
1030  *    the original buffer.  Returns NULL if system is out of memory.
1031  *
1032  ***/
1033
1034 static inline
1035 SilcBuffer silc_buffer_clone(SilcBuffer sb)
1036 {
1037   SilcBuffer sb_new;
1038
1039   sb_new = silc_buffer_alloc_size(silc_buffer_truelen(sb));
1040   if (silc_unlikely(!sb_new))
1041     return NULL;
1042   silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
1043   sb_new->data = sb_new->head + silc_buffer_headlen(sb);
1044   sb_new->tail = sb_new->data + silc_buffer_len(sb);
1045
1046   return sb_new;
1047 }
1048
1049 /****f* silcutil/SilcBufferAPI/silc_buffer_sclone
1050  *
1051  * SYNOPSIS
1052  *
1053  *    static inline
1054  *    SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb);
1055  *
1056  * DESCRIPTION
1057  *
1058  *    Clones SilcBuffer. This generates new SilcBuffer and copies
1059  *    everything from the source buffer. The result is exact clone of
1060  *    the original buffer.  Returns NULL if system is out of memory.
1061  *
1062  *    This routine use SilcStack are memory source.  If `stack' is NULL
1063  *    reverts back to normal allocating routine.
1064  *
1065  *    Note that this call consumes the `stack'.  The caller should push the
1066  *    stack before calling the function and pop it later.
1067  *
1068  ***/
1069
1070 static inline
1071 SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb)
1072 {
1073   SilcBuffer sb_new;
1074
1075   sb_new = silc_buffer_salloc_size(stack, silc_buffer_truelen(sb));
1076   if (silc_unlikely(!sb_new))
1077     return NULL;
1078   silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
1079   sb_new->data = sb_new->head + silc_buffer_headlen(sb);
1080   sb_new->tail = sb_new->data + silc_buffer_len(sb);
1081
1082   return sb_new;
1083 }
1084
1085 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc
1086  *
1087  * SYNOPSIS
1088  *
1089  *    static inline
1090  *    SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize);
1091  *
1092  * DESCRIPTION
1093  *
1094  *    Reallocates buffer. Old data is saved into the new buffer. The buffer
1095  *    is exact clone of the old one except that there is now more space
1096  *    at the end of buffer.  This always returns the same `sb' unless `sb'
1097  *    was NULL. Returns NULL if system is out of memory.
1098  *
1099  ***/
1100
1101 static inline
1102 SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize)
1103 {
1104   SilcUInt32 hlen, dlen;
1105   unsigned char *h;
1106
1107   if (!sb)
1108     return silc_buffer_alloc(newsize);
1109
1110   if (silc_unlikely(newsize <= silc_buffer_truelen(sb)))
1111     return sb;
1112
1113   hlen = silc_buffer_headlen(sb);
1114   dlen = silc_buffer_len(sb);
1115   h = (unsigned char *)silc_realloc(sb->head, newsize);
1116   if (silc_unlikely(!h))
1117     return NULL;
1118   sb->head = h;
1119   sb->data = sb->head + hlen;
1120   sb->tail = sb->data + dlen;
1121   sb->end = sb->head + newsize;
1122
1123   return sb;
1124 }
1125
1126 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc
1127  *
1128  * SYNOPSIS
1129  *
1130  *    static inline
1131  *    SilcBuffer silc_buffer_srealloc(SilcStack stack,
1132  *                                    SilcBuffer sb, SilcUInt32 newsize);
1133  *
1134  * DESCRIPTION
1135  *
1136  *    Reallocates buffer. Old data is saved into the new buffer. The buffer
1137  *    is exact clone of the old one except that there is now more space
1138  *    at the end of buffer.  Returns NULL if system is out of memory.
1139  *
1140  *    This routine use SilcStack are memory source.  If `stack' is NULL
1141  *    reverts back to normal allocating routine.
1142  *
1143  *    Note that this call consumes the `stack'.  The caller should push the
1144  *    stack before calling the function and pop it later.
1145  *
1146  ***/
1147
1148 static inline
1149 SilcBuffer silc_buffer_srealloc(SilcStack stack,
1150                                 SilcBuffer sb, SilcUInt32 newsize)
1151 {
1152   SilcUInt32 hlen, dlen;
1153   unsigned char *h;
1154
1155   if (!stack)
1156     return silc_buffer_realloc(sb, newsize);
1157
1158   if (!sb)
1159     return silc_buffer_salloc(stack, newsize);
1160
1161   if (newsize <= silc_buffer_truelen(sb))
1162     return sb;
1163
1164   hlen = silc_buffer_headlen(sb);
1165   dlen = silc_buffer_len(sb);
1166   h = (unsigned char *)silc_srealloc(stack, silc_buffer_truelen(sb),
1167                                      sb->head, newsize);
1168   if (!h) {
1169     /* Do slow and stack wasting realloc.  The old sb->head is lost and
1170        is freed eventually. */
1171     h = (unsigned char *)silc_smalloc(stack, newsize);
1172     if (silc_unlikely(!h))
1173       return NULL;
1174     memcpy(h, sb->head, silc_buffer_truelen(sb));
1175   }
1176
1177   sb->head = h;
1178   sb->data = sb->head + hlen;
1179   sb->tail = sb->data + dlen;
1180   sb->end = sb->head + newsize;
1181
1182   return sb;
1183 }
1184
1185 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc_size
1186  *
1187  * SYNOPSIS
1188  *
1189  *    static inline
1190  *    SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize);
1191  *
1192  * DESCRIPTION
1193  *
1194  *    Same as silc_buffer_realloc but moves moves the tail area
1195  *    automatically so that the buffer is ready to use without calling the
1196  *    silc_buffer_pull_tail.  Returns NULL if system is out of memory.
1197  *
1198  ***/
1199
1200 static inline
1201 SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize)
1202 {
1203   sb = silc_buffer_realloc(sb, newsize);
1204   if (silc_unlikely(!sb))
1205     return NULL;
1206   silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
1207   return sb;
1208 }
1209
1210 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc_size
1211  *
1212  * SYNOPSIS
1213  *
1214  *    static inline
1215  *    SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
1216  *                                         SilcBuffer sb, SilcUInt32 newsize);
1217  *
1218  * DESCRIPTION
1219  *
1220  *    Same as silc_buffer_srealloc but moves moves the tail area
1221  *    automatically so that the buffer is ready to use without calling the
1222  *    silc_buffer_pull_tail.  Returns NULL if system is out of memory.
1223  *
1224  *    This routine use SilcStack are memory source.  If `stack' is NULL
1225  *    reverts back to normal allocating routine.
1226  *
1227  *    Note that this call consumes the `stack'.  The caller should push the
1228  *    stack before calling the function and pop it later.
1229  *
1230  ***/
1231
1232 static inline
1233 SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
1234                                      SilcBuffer sb, SilcUInt32 newsize)
1235 {
1236   sb = silc_buffer_srealloc(stack, sb, newsize);
1237   if (silc_unlikely(!sb))
1238     return NULL;
1239   silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
1240   return sb;
1241 }
1242
1243 /****f* silcutil/SilcBufferAPI/silc_buffer_enlarge
1244  *
1245  * SYNOPSIS
1246  *
1247  *    static inline
1248  *    SilcBuffer silc_buffer_enlarge(SilcBuffer sb, SilcUInt32 size);
1249  *
1250  * DESCRIPTION
1251  *
1252  *    Enlarges the buffer by the amount of `size' if it doesn't have that
1253  *    must space in the data area and in the tail area.  Moves the tail
1254  *    area automatically after enlarging so that the current data area
1255  *    is at least the size of `size'.  If there is more space than `size'
1256  *    in the data area this does not do anything.  If there is enough
1257  *    space in the tail area this merely moves the tail area to reveal
1258  *    the extra space.  Returns FALSE if system is out of memory.
1259  *
1260  ***/
1261
1262 static inline
1263 SilcBool silc_buffer_enlarge(SilcBuffer sb, SilcUInt32 size)
1264 {
1265   if (size > silc_buffer_len(sb)) {
1266     if (size > silc_buffer_taillen(sb) + silc_buffer_len(sb))
1267       if (silc_unlikely(!silc_buffer_realloc(sb, silc_buffer_truelen(sb) +
1268                                              (size - silc_buffer_taillen(sb) -
1269                                               silc_buffer_len(sb)))))
1270         return FALSE;
1271     silc_buffer_pull_tail(sb, size - silc_buffer_len(sb));
1272   }
1273   return TRUE;
1274 }
1275
1276 /****f* silcutil/SilcBufferAPI/silc_buffer_senlarge
1277  *
1278  * SYNOPSIS
1279  *
1280  *    static inline
1281  *    SilcBuffer silc_buffer_senlarge(SilcStack stack, SilcBuffer sb,
1282  *                                    SilcUInt32 size);
1283  *
1284  * DESCRIPTION
1285  *
1286  *    Enlarges the buffer by the amount of `size' if it doesn't have that
1287  *    must space in the data area and in the tail area.  Moves the tail
1288  *    area automatically after enlarging so that the current data area
1289  *    is at least the size of `size'.  If there is more space than `size'
1290  *    in the data area this does not do anything.  If there is enough
1291  *    space in the tail area this merely moves the tail area to reveal
1292  *    the extra space.  Returns FALSE if system is out of memory.
1293  *
1294  *    This routine use SilcStack are memory source.  If `stack' is NULL
1295  *    reverts back to normal allocating routine.
1296  *
1297  *    Note that this call consumes the `stack'.  The caller should push the
1298  *    stack before calling the function and pop it later.
1299  *
1300  ***/
1301
1302 static inline
1303 SilcBool silc_buffer_senlarge(SilcStack stack, SilcBuffer sb, SilcUInt32 size)
1304 {
1305   if (size > silc_buffer_len(sb)) {
1306     if (size > silc_buffer_taillen(sb) + silc_buffer_len(sb))
1307       if (silc_unlikely(!silc_buffer_srealloc(stack, sb,
1308                                               silc_buffer_truelen(sb) +
1309                                               (size - silc_buffer_taillen(sb) -
1310                                                silc_buffer_len(sb)))))
1311         return FALSE;
1312     silc_buffer_pull_tail(sb, size - silc_buffer_len(sb));
1313   }
1314   return TRUE;
1315 }
1316
1317 /****f* silcutil/SilcBufferAPI/silc_buffer_strchr
1318  *
1319  * SYNOPSIS
1320  *
1321  *    static inline
1322  *    unsigned char *silc_buffer_strchr(SilcBuffer sb, int c, SilcBool first);
1323  *
1324  * DESCRIPTION
1325  *
1326  *    Returns pointer to the occurence of the character `c' in the buffer
1327  *    `sb'.  If the `first' is TRUE this finds the first occurene of `c',
1328  *    if it is FALSE this finds the last occurence of `c'.  If the character
1329  *    is found the `sb' data area is moved to that location and its pointer
1330  *    is returned.  The silc_buffer_data call will return the same pointer.
1331  *    Returns NULL if such character could not be located and the buffer
1332  *    remains unmodified.
1333  *
1334  *    This call is equivalent to strchr(), strrchr(), memchr() and memrchr()
1335  *    except it works with SilcBuffer.
1336  *
1337  * NOTES
1338  *
1339  *    This searches only the data area of the buffer.  Head and tail area
1340  *    are not searched.
1341  *
1342  *    The `sb' data need not be NULL terminated.
1343  *
1344  ***/
1345
1346 static inline
1347 unsigned char *silc_buffer_strchr(SilcBuffer sb, int c, SilcBool first)
1348 {
1349   int i;
1350
1351   if (first) {
1352     for (i = 0; i < silc_buffer_len(sb); i++) {
1353       if (sb->data[i] == (unsigned char)c) {
1354         sb->data = &sb->data[i];
1355         return sb->data;
1356       }
1357     }
1358   } else {
1359     for (i = silc_buffer_len(sb) - 1; 1 >= 0; i--) {
1360       if (sb->data[i] == (unsigned char)c) {
1361         sb->data = &sb->data[i];
1362         return sb->data;
1363       }
1364     }
1365   }
1366
1367   return NULL;
1368 }
1369
1370 #endif /* SILCBUFFER_H */