Initial code commit for Toolkit 1.1.
[silc.git] / lib / silcutil / silcbuffer.h
1 /*
2
3   silcbuffer.h
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1998 - 2005 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  * SOURCE
109  */
110 typedef struct {
111   unsigned char *head;
112   unsigned char *data;
113   unsigned char *tail;
114   unsigned char *end;
115 } *SilcBuffer, SilcBufferStruct;
116 /***/
117
118 /* Macros */
119
120 /****d* silcutil/SilcBufferAPI/silc_buffer_truelen
121  *
122  * NAME
123  *
124  *    #define silc_buffer_truelen(buffer)
125  *
126  * DESCRIPTION
127  *
128  *    Returns the true length of the buffer.
129  *
130  * SOURCE
131  */
132 #define silc_buffer_truelen(x) (SilcUInt32)((x)->end - (x)->head)
133 /***/
134
135 /****d* silcutil/SilcBufferAPI/silc_buffer_len
136  *
137  * NAME
138  *
139  *    #define silc_buffer_len(buffer)
140  *
141  * DESCRIPTION
142  *
143  *    Returns the current length of the data area of the buffer.
144  *
145  * SOURCE
146  */
147 #define silc_buffer_len(x) (SilcUInt32)((x)->tail - (x)->data)
148 /***/
149
150 /****d* silcutil/SilcBufferAPI/silc_buffer_headlen
151  *
152  * NAME
153  *
154  *    #define silc_buffer_headlen(buffer)
155  *
156  * DESCRIPTION
157  *
158  *    Returns the current length of the head data area of the buffer.
159  *
160  * SOURCE
161  */
162 #define silc_buffer_headlen(x) (SilcUInt32)((x)->data - (x)->head)
163 /***/
164
165 /****d* silcutil/SilcBufferAPI/silc_buffer_taillen
166  *
167  * NAME
168  *
169  *    #define silc_buffer_taillen(buffer)
170  *
171  * DESCRIPTION
172  *
173  *    Returns the current length of the tail data area of the buffer.
174  *
175  * SOURCE
176  */
177 #define silc_buffer_taillen(x) (SilcUInt32)((x)->end - (x)->tail)
178 /***/
179
180 /* Inline functions */
181
182 /****f* silcutil/SilcBufferAPI/silc_buffer_alloc
183  *
184  * SYNOPSIS
185  *
186  *    static inline
187  *    SilcBuffer silc_buffer_alloc(SilcUInt32 len);
188  *
189  * DESCRIPTION
190  *
191  *    Allocates new SilcBuffer and returns it.  Returns NULL on error.
192  *
193  ***/
194
195 static inline
196 SilcBuffer silc_buffer_alloc(SilcUInt32 len)
197 {
198   SilcBuffer sb;
199
200   /* Allocate new SilcBuffer */
201   sb = (SilcBuffer)silc_calloc(1, sizeof(*sb));
202   if (!sb)
203     return NULL;
204
205   /* Allocate the actual data area */
206   sb->head = (unsigned char *)silc_calloc(len, sizeof(*sb->head));
207   if (!sb->head)
208     return NULL;
209
210   /* Set pointers to the new buffer */
211   sb->data = sb->head;
212   sb->tail = sb->head;
213   sb->end = sb->head + len;
214
215   return sb;
216 }
217
218 /****f* silcutil/SilcBufferAPI/silc_buffer_free
219  *
220  * SYNOPSIS
221  *
222  *    static inline
223  *    void silc_buffer_free(SilcBuffer sb);
224  *
225  * DESCRIPTION
226  *
227  *    Frees SilcBuffer.
228  *
229  ***/
230
231 static inline
232 void silc_buffer_free(SilcBuffer sb)
233 {
234   if (sb) {
235 #if defined(SILC_DEBUG)
236     if (sb->head)
237       memset(sb->head, 'F', silc_buffer_truelen(sb));
238 #endif
239     silc_free(sb->head);
240     silc_free(sb);
241   }
242 }
243
244 /****f* silcutil/SilcBufferAPI/silc_buffer_steal
245  *
246  * SYNOPSIS
247  *
248  *    static inline
249  *    unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len);
250  *
251  * DESCRIPTION
252  *
253  *    Steals the data from the buffer `sb'.  This returns pointer to the
254  *    start of the buffer and the true length of that buffer.  The `sb'
255  *    cannot be used anymore after calling this function because the
256  *    data buffer was stolen.  The `sb' must be freed with silc_buffer_free.
257  *    The caller is responsible of freeing the stolen data buffer with
258  *    silc_free.
259  *
260  ***/
261
262 static inline
263 unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len)
264 {
265   unsigned char *buf = sb->head;
266   if (data_len)
267     *data_len = silc_buffer_truelen(sb);
268   sb->head = sb->data = sb->tail = sb->end = NULL;
269   return buf;
270 }
271
272 /****f* silcutil/SilcBufferAPI/silc_buffer_set
273  *
274  * SYNOPSIS
275  *
276  *    static inline
277  *    void silc_buffer_set(SilcBuffer sb,
278  *                         unsigned char *data,
279  *                         SilcUInt32 data_len);
280  *
281  * DESCRIPTION
282  *
283  *    Sets the `data' and `data_len' to the buffer pointer sent as argument.
284  *    The data area is automatically set to the `data_len'. This function
285  *    can be used to set the data to static buffer without needing any
286  *    memory allocations. The `data' will not be copied to the buffer.
287  *
288  * EXAMPLE
289  *
290  *    SilcBufferStruct buf;
291  *    silc_buffer_set(&buf, data, data_len);
292  *
293  ***/
294
295 static inline
296 void silc_buffer_set(SilcBuffer sb, unsigned char *data, SilcUInt32 data_len)
297 {
298   sb->data = sb->head = data;
299   sb->tail = sb->end = data + data_len;
300 }
301
302 /****f* silcutil/SilcBufferAPI/silc_buffer_pull
303  *
304  * SYNOPSIS
305  *
306  *    static inline
307  *    unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len);
308  *
309  * DESCRIPTION
310  *
311  *    Pulls current data area towards end. The length of the currently
312  *    valid data area is also decremented. Returns pointer to the data
313  *    area before pulling. Returns NULL on error.
314  *
315  * EXAMPLE
316  *
317  *    ---------------------------------
318  *    | head  | data       | tail     |
319  *    ---------------------------------
320  *            ^
321  *            Pulls the start of the data area.
322  *
323  *    ---------------------------------
324  *    | head     | data    | tail     |
325  *    ---------------------------------
326  *            ^
327  *
328  *    silc_buffer_pull(sb, 20);
329  *
330  ***/
331
332 static inline
333 unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len)
334 {
335   unsigned char *old_data = sb->data;
336 #if defined(SILC_DEBUG)
337   assert(len <= silc_buffer_len(sb));
338 #else
339   if (len > silc_buffer_len(sb))
340     return NULL;
341 #endif
342   sb->data += len;
343   return old_data;
344 }
345
346 /****f* silcutil/SilcBufferAPI/silc_buffer_push
347  *
348  * SYNOPSIS
349  *
350  *    static inline
351  *    unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len);
352  *
353  * DESCRIPTION
354  *
355  *    Pushes current data area towards beginning. Length of the currently
356  *    valid data area is also incremented. Returns a pointer to the
357  *    data area before pushing. Returns NULL on error.
358  *
359  * EXAMPLE
360  *
361  *    ---------------------------------
362  *    | head     | data    | tail     |
363  *    ---------------------------------
364  *               ^
365  *               Pushes the start of the data area.
366  *
367  *    ---------------------------------
368  *    | head  | data       | tail     |
369  *    ---------------------------------
370  *               ^
371  *
372  *    silc_buffer_push(sb, 20);
373  *
374  ***/
375
376 static inline
377 unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len)
378 {
379   unsigned char *old_data = sb->data;
380 #if defined(SILC_DEBUG)
381   assert((sb->data - len) >= sb->head);
382 #else
383   if ((sb->data - len) < sb->head)
384     return NULL;
385 #endif
386   sb->data -= len;
387   return old_data;
388 }
389
390 /****f* silcutil/SilcBufferAPI/silc_buffer_pull_tail
391  *
392  * SYNOPSIS
393  *
394  *    static inline
395  *    unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len);
396  *
397  * DESCRIPTION
398  *
399  *    Pulls current tail section towards end. Length of the current valid
400  *    data area is also incremented. Returns a pointer to the data area
401  *    before pulling. Returns NULL on error.
402  *
403  * EXAMPLE
404  *
405  *    ---------------------------------
406  *    | head  | data       | tail     |
407  *    ---------------------------------
408  *                         ^
409  *                         Pulls the start of the tail section.
410  *
411  *    ---------------------------------
412  *    | head  | data           | tail |
413  *    ---------------------------------
414  *                         ^
415  *
416  *    silc_buffer_pull_tail(sb, 23);
417  *
418  ***/
419
420 static inline
421 unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len)
422 {
423   unsigned char *old_tail = sb->tail;
424 #if defined(SILC_DEBUG)
425   assert(len <= silc_buffer_taillen(sb));
426 #else
427   if (len > silc_buffer_taillen(sb))
428     return NULL;
429 #endif
430   sb->tail += len;
431   return old_tail;
432 }
433
434 /****f* silcutil/SilcBufferAPI/silc_buffer_push_tail
435  *
436  * SYNOPSIS
437  *
438  *    static inline
439  *    unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len);
440  *
441  * DESCRIPTION
442  *
443  *    Pushes current tail section towards beginning. Length of the current
444  *    valid data area is also decremented. Returns a pointer to the
445  *    tail section before pushing. Returns NULL on error.
446  *
447  * EXAMPLE
448  *
449  *    ---------------------------------
450  *    | head  | data           | tail |
451  *    ---------------------------------
452  *                             ^
453  *                             Pushes the start of the tail section.
454  *
455  *    ---------------------------------
456  *    | head  | data       | tail     |
457  *    ---------------------------------
458  *                             ^
459  *
460  *    silc_buffer_push_tail(sb, 23);
461  *
462  ***/
463
464 static inline
465 unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len)
466 {
467   unsigned char *old_tail = sb->tail;
468 #if defined(SILC_DEBUG)
469   assert((sb->tail - len) >= sb->data);
470 #else
471   if ((sb->tail - len) < sb->data)
472     return NULL;
473 #endif
474   sb->tail -= len;
475   return old_tail;
476 }
477
478 /****f* silcutil/SilcBufferAPI/silc_buffer_put_head
479  *
480  * SYNOPSIS
481  *
482  *    static inline
483  *    unsigned char *silc_buffer_put_head(SilcBuffer sb,
484  *                                        const unsigned char *data,
485  *                                        SilcUInt32 len);
486  *
487  * DESCRIPTION
488  *
489  *    Puts data at the head of the buffer. Returns pointer to the copied
490  *    data area. Returns NULL on error.
491  *
492  * EXAMPLE
493  *
494  *    ---------------------------------
495  *    | head  | data       | tail     |
496  *    ---------------------------------
497  *    ^
498  *    Puts data to the head section.
499  *
500  *    silc_buffer_put_head(sb, data, data_len);
501  *
502  ***/
503
504 static inline
505 unsigned char *silc_buffer_put_head(SilcBuffer sb,
506                                     const unsigned char *data,
507                                     SilcUInt32 len)
508 {
509 #if defined(SILC_DEBUG)
510   assert(len <= silc_buffer_headlen(sb));
511 #else
512   if (len > silc_buffer_headlen(sb))
513     return NULL;
514 #endif
515   return (unsigned char *)memcpy(sb->head, data, len);
516 }
517
518 /****f* silcutil/SilcBufferAPI/silc_buffer_put
519  *
520  * SYNOPSIS
521  *
522  *    static inline
523  *    unsigned char *silc_buffer_put(SilcBuffer sb,
524  *                                   const unsigned char *data,
525  *                                   SilcUInt32 len);
526  *
527  * DESCRIPTION
528  *
529  *    Puts data at the start of the valid data area. Returns a pointer
530  *    to the copied data area.  Returns NULL on error.
531  *
532  * EXAMPLE
533  *
534  *    ---------------------------------
535  *    | head  | data       | tail     |
536  *    ---------------------------------
537  *            ^
538  *            Puts data to the data section.
539  *
540  *    silc_buffer_put(sb, data, data_len);
541  *
542  ***/
543
544 static inline
545 unsigned char *silc_buffer_put(SilcBuffer sb,
546                                const unsigned char *data,
547                                SilcUInt32 len)
548 {
549 #if defined(SILC_DEBUG)
550   assert(len <= silc_buffer_len(sb));
551 #else
552   if (len > silc_buffer_len(sb))
553     return NULL;
554 #endif
555   return (unsigned char *)memcpy(sb->data, data, len);
556 }
557
558 /****f* silcutil/SilcBufferAPI/silc_buffer_put_tail
559  *
560  * SYNOPSIS
561  *
562  *    static inline
563  *    unsigned char *silc_buffer_put_tail(SilcBuffer sb,
564  *                                        const unsigned char *data,
565  *                                        SilcUInt32 len);
566  *
567  * DESCRIPTION
568  *
569  *    Puts data at the tail of the buffer. Returns pointer to the copied
570  *    data area.  Returns NULL on error.
571  *
572  * EXAMPLE
573  *
574  *    ---------------------------------
575  *    | head  | data           | tail |
576  *    ---------------------------------
577  *                             ^
578  *                             Puts data to the tail section.
579  *
580  *    silc_buffer_put_tail(sb, data, data_len);
581  *
582  ***/
583
584 static inline
585 unsigned char *silc_buffer_put_tail(SilcBuffer sb,
586                                     const unsigned char *data,
587                                     SilcUInt32 len)
588 {
589 #if defined(SILC_DEBUG)
590   assert(len <= silc_buffer_taillen(sb));
591 #else
592   if (len > silc_buffer_taillen(sb))
593     return NULL;
594 #endif
595   return (unsigned char *)memcpy(sb->tail, data, len);
596 }
597
598 /****f* silcutil/SilcBufferAPI/silc_buffer_alloc_size
599  *
600  * SYNOPSIS
601  *
602  *    static inline
603  *    SilcBuffer silc_buffer_alloc_size(SilcUInt32 len);
604  *
605  * DESCRIPTION
606  *
607  *    Allocates `len' bytes size buffer and moves the tail area automatically
608  *    `len' bytes so that the buffer is ready to use without calling the
609  *    silc_buffer_pull_tail.  Returns NULL on error.
610  *
611  ***/
612
613 static inline
614 SilcBuffer silc_buffer_alloc_size(SilcUInt32 len)
615 {
616   SilcBuffer sb = silc_buffer_alloc(len);
617   if (!sb)
618     return NULL;
619   silc_buffer_pull_tail(sb, len);
620   return sb;
621 }
622
623 /****f* silcutil/SilcBufferAPI/silc_buffer_reset
624  *
625  * SYNOPSIS
626  *
627  *    static inline
628  *    void silc_buffer_reset(SilcBuffer sb);
629  *
630  * DESCRIPTION
631  *
632  *    Resets the buffer to the state as if it was just allocated by
633  *    silc_buffer_alloc.  This does not clear the data area.  Use
634  *    silc_buffer_clear if you also want to clear the data area.
635  *
636  ***/
637
638 static inline
639 void silc_buffer_reset(SilcBuffer sb)
640 {
641   sb->data = sb->tail = sb->head;
642 }
643
644 /****f* silcutil/SilcBufferAPI/silc_buffer_clear
645  *
646  * SYNOPSIS
647  *
648  *    static inline
649  *    void silc_buffer_clear(SilcBuffer sb);
650  *
651  * DESCRIPTION
652  *
653  *    Clears and initialiazes the buffer to the state as if it was just
654  *    allocated by silc_buffer_alloc.
655  *
656  ***/
657
658 static inline
659 void silc_buffer_clear(SilcBuffer sb)
660 {
661   memset(sb->head, 0, silc_buffer_truelen(sb));
662   silc_buffer_reset(sb);
663 }
664
665 /****f* silcutil/SilcBufferAPI/silc_buffer_copy
666  *
667  * SYNOPSIS
668  *
669  *    static inline
670  *    SilcBuffer silc_buffer_copy(SilcBuffer sb);
671  *
672  * DESCRIPTION
673  *
674  *    Generates copy of a SilcBuffer. This copies everything inside the
675  *    currently valid data area, nothing more. Use silc_buffer_clone to
676  *    copy entire buffer.  Returns NULL on error.
677  *
678  ***/
679
680 static inline
681 SilcBuffer silc_buffer_copy(SilcBuffer sb)
682 {
683   SilcBuffer sb_new;
684
685   sb_new = silc_buffer_alloc_size(silc_buffer_len(sb));
686   if (!sb_new)
687     return NULL;
688   silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
689
690   return sb_new;
691 }
692
693 /****f* silcutil/SilcBufferAPI/silc_buffer_clone
694  *
695  * SYNOPSIS
696  *
697  *    static inline
698  *    SilcBuffer silc_buffer_clone(SilcBuffer sb);
699  *
700  * DESCRIPTION
701  *
702  *    Clones SilcBuffer. This generates new SilcBuffer and copies
703  *    everything from the source buffer. The result is exact clone of
704  *    the original buffer.  Returns NULL on error.
705  *
706  ***/
707
708 static inline
709 SilcBuffer silc_buffer_clone(SilcBuffer sb)
710 {
711   SilcBuffer sb_new;
712
713   sb_new = silc_buffer_alloc_size(silc_buffer_truelen(sb));
714   if (!sb_new)
715     return NULL;
716   silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
717   sb_new->data = sb_new->head + silc_buffer_headlen(sb);
718   sb_new->tail = sb_new->data + silc_buffer_len(sb);
719
720   return sb_new;
721 }
722
723 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc
724  *
725  * SYNOPSIS
726  *
727  *    static inline
728  *    SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize);
729  *
730  * DESCRIPTION
731  *
732  *    Reallocates buffer. Old data is saved into the new buffer. The buffer
733  *    is exact clone of the old one except that there is now more space
734  *    at the end of buffer.  This always returns the same `sb' unless `sb'
735  *    was NULL. Returns NULL on error.
736  *
737  ***/
738
739 static inline
740 SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize)
741 {
742   SilcUInt32 hlen, dlen;
743   unsigned char *h;
744
745   if (!sb)
746     return silc_buffer_alloc(newsize);
747
748   if (newsize <= silc_buffer_truelen(sb))
749     return sb;
750
751   hlen = silc_buffer_headlen(sb);
752   dlen = silc_buffer_len(sb);
753   h = (unsigned char *)silc_realloc(sb->head, newsize);
754   if (!h)
755     return NULL;
756   sb->head = h;
757   sb->data = sb->head + hlen;
758   sb->tail = sb->data + dlen;
759   sb->end = sb->head + newsize;
760
761   return sb;
762 }
763
764 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc_size
765  *
766  * SYNOPSIS
767  *
768  *    static inline
769  *    SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize);
770  *
771  * DESCRIPTION
772  *
773  *    Same as silc_buffer_realloc but moves moves the tail area
774  *    automatically so that the buffer is ready to use without calling the
775  *    silc_buffer_pull_tail.  Returns NULL on error.
776  *
777  ***/
778
779 static inline
780 SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize)
781 {
782   sb = silc_buffer_realloc(sb, newsize);
783   if (!sb)
784     return NULL;
785   silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
786   return sb;
787 }
788
789
790 /* SilcStack aware SilcBuffer routines */
791
792 /****f* silcutil/SilcBufferAPI/silc_buffer_salloc
793  *
794  * SYNOPSIS
795  *
796  *    static inline
797  *    SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len);
798  *
799  * DESCRIPTION
800  *
801  *    Allocates new SilcBuffer and returns it.
802  *
803  *    This routine use SilcStack are memory source.
804  *
805  ***/
806
807 static inline
808 SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len)
809 {
810   SilcBuffer sb;
811
812   /* Allocate new SilcBuffer */
813   sb = (SilcBuffer)silc_scalloc(stack, 1, sizeof(*sb));
814   if (!sb)
815     return NULL;
816
817   /* Allocate the actual data area */
818   sb->head = (unsigned char *)silc_smalloc_ua(stack, len);
819   if (!sb->head)
820     return NULL;
821
822   /* Set pointers to the new buffer */
823   sb->data = sb->head;
824   sb->tail = sb->head;
825   sb->end = sb->head + len;
826
827   return sb;
828 }
829
830 /****f* silcutil/SilcBufferAPI/silc_buffer_salloc_size
831  *
832  * SYNOPSIS
833  *
834  *    static inline
835  *    SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len);
836  *
837  * DESCRIPTION
838  *
839  *    Allocates `len' bytes size buffer and moves the tail area automatically
840  *    `len' bytes so that the buffer is ready to use without calling the
841  *    silc_buffer_pull_tail.
842  *
843  *    This routine use SilcStack are memory source.
844  *
845  ***/
846
847 static inline
848 SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len)
849 {
850   SilcBuffer sb = silc_buffer_salloc(stack, len);
851   if (!sb)
852     return NULL;
853   silc_buffer_pull_tail(sb, len);
854   return sb;
855 }
856
857 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc
858  *
859  * SYNOPSIS
860  *
861  *    static inline
862  *    SilcBuffer silc_buffer_srealloc(SilcStack stack,
863  *                                    SilcBuffer sb, SilcUInt32 newsize);
864  *
865  * DESCRIPTION
866  *
867  *    Reallocates buffer. Old data is saved into the new buffer. The buffer
868  *    is exact clone of the old one except that there is now more space
869  *    at the end of buffer.
870  *
871  *    This routine use SilcStack are memory source.
872  *
873  ***/
874
875 static inline
876 SilcBuffer silc_buffer_srealloc(SilcStack stack,
877                                 SilcBuffer sb, SilcUInt32 newsize)
878 {
879   SilcUInt32 hlen, dlen;
880   unsigned char *h;
881
882   if (!sb)
883     return silc_buffer_salloc(stack, newsize);
884
885   if (newsize <= silc_buffer_truelen(sb))
886     return sb;
887
888   hlen = silc_buffer_headlen(sb);
889   dlen = silc_buffer_len(sb);
890   h = (unsigned char *)silc_srealloc_ua(stack, silc_buffer_truelen(sb),
891                                         sb->head, newsize);
892   if (!h) {
893     /* Do slow and stack wasting realloc.  The old sb->head is lost and
894        is freed eventually. */
895     h = silc_smalloc_ua(stack, newsize);
896     if (!h)
897       return NULL;
898     memcpy(h, sb->head, silc_buffer_truelen(sb));
899   }
900
901   sb->head = h;
902   sb->data = sb->head + hlen;
903   sb->tail = sb->data + dlen;
904   sb->end = sb->head + newsize;
905
906   return sb;
907 }
908
909 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc_size
910  *
911  * SYNOPSIS
912  *
913  *    static inline
914  *    SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
915  *                                         SilcBuffer sb, SilcUInt32 newsize);
916  *
917  * DESCRIPTION
918  *
919  *    Same as silc_buffer_srealloc but moves moves the tail area
920  *    automatically so that the buffer is ready to use without calling the
921  *    silc_buffer_pull_tail.
922  *
923  *    This routine use SilcStack are memory source.
924  *
925  ***/
926
927 static inline
928 SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
929                                      SilcBuffer sb, SilcUInt32 newsize)
930 {
931   sb = silc_buffer_srealloc(stack, sb, newsize);
932   if (!sb)
933     return NULL;
934   silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
935   return sb;
936 }
937
938 /****f* silcutil/SilcBufferAPI/silc_buffer_scopy
939  *
940  * SYNOPSIS
941  *
942  *    static inline
943  *    SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb);
944  *
945  * DESCRIPTION
946  *
947  *    Generates copy of a SilcBuffer. This copies everything inside the
948  *    currently valid data area, nothing more. Use silc_buffer_clone to
949  *    copy entire buffer.
950  *
951  *    This routine use SilcStack are memory source.
952  *
953  ***/
954
955 static inline
956 SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb)
957 {
958   SilcBuffer sb_new;
959
960   sb_new = silc_buffer_salloc_size(stack, silc_buffer_len(sb));
961   if (!sb_new)
962     return NULL;
963   silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
964
965   return sb_new;
966 }
967
968 /****f* silcutil/SilcBufferAPI/silc_buffer_sclone
969  *
970  * SYNOPSIS
971  *
972  *    static inline
973  *    SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb);
974  *
975  * DESCRIPTION
976  *
977  *    Clones SilcBuffer. This generates new SilcBuffer and copies
978  *    everything from the source buffer. The result is exact clone of
979  *    the original buffer.
980  *
981  *    This routine use SilcStack are memory source.
982  *
983  ***/
984
985 static inline
986 SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb)
987 {
988   SilcBuffer sb_new;
989
990   sb_new = silc_buffer_salloc_size(stack, silc_buffer_truelen(sb));
991   if (!sb_new)
992     return NULL;
993   silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
994   sb_new->data = sb_new->head + silc_buffer_headlen(sb);
995   sb_new->tail = sb_new->data + silc_buffer_len(sb);
996
997   return sb_new;
998 }
999
1000 #endif /* SILCBUFFER_H */