5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1998 - 2006 Pekka Riikonen
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.
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.
21 /****h* silcutil/SILC Buffer Interface
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.
35 /****s* silcutil/SilcBufferAPI/SilcBuffer
39 * typedef struct { ... } *SilcBuffer, SilcBufferStruct;
43 * SILC Buffer object. Following short description of the fields
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.
55 * --------------------------------
56 * | head | data | tail |
57 * --------------------------------
60 * Current head section in the buffer is sb->data - sb->head.
62 * unsigned char *data;
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.
67 * --------------------------------
68 * | head | data | tail |
69 * --------------------------------
72 * Current valid data area in the buffer is sb->tail - sb->data.
74 * unsigned char *tail;
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.
79 * --------------------------------
80 * | head | data | tail |
81 * --------------------------------
84 * Current tail section in the buffer is sb->end - sb->tail.
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
93 * --------------------------------
94 * | head | data | tail |
95 * --------------------------------
98 * Length of the entire buffer is (ie. truelen) sb->end - sb->head.
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.
108 * SILC Buffer is not thread-safe. If the same SilcBuffer context must be
109 * used in multithreaded environment concurrency control must be employed.
118 } *SilcBuffer, SilcBufferStruct;
123 /****d* silcutil/SilcBufferAPI/silc_buffer_truelen
127 * SilcUInt32 silc_buffer_truelen(SilcBuffer sb)
131 * Returns the true length of the buffer.
135 #define silc_buffer_truelen(x) (SilcUInt32)((x)->end - (x)->head)
138 /****d* silcutil/SilcBufferAPI/silc_buffer_len
142 * SilcUInt32 silc_buffer_len(SilcBuffer sb)
146 * Returns the current length of the data area of the buffer.
150 #define silc_buffer_len(x) (SilcUInt32)((x)->tail - (x)->data)
153 /****d* silcutil/SilcBufferAPI/silc_buffer_headlen
157 * SilcUInt32 silc_buffer_headlen(SilcBuffer sb)
161 * Returns the current length of the head data area of the buffer.
165 #define silc_buffer_headlen(x) (SilcUInt32)((x)->data - (x)->head)
168 /****d* silcutil/SilcBufferAPI/silc_buffer_taillen
172 * SilcUInt32 silc_buffer_taillen(SilcBuffer sb)
176 * Returns the current length of the tail data area of the buffer.
180 #define silc_buffer_taillen(x) (SilcUInt32)((x)->end - (x)->tail)
183 /****f* silcutil/SilcBufferAPI/silc_buffer_data
187 * unsigned char *silc_buffer_data(SilcBuffer sb)
191 * Returns pointer to the data area of the buffer.
195 #define silc_buffer_data(x) (x)->data
198 /****f* silcutil/SilcBufferAPI/silc_buffer_datalen
202 * #define silc_buffer_datalen ...
206 * Macro that can be used in function argument list to give the data
207 * pointer and the data length, instead of calling both silc_buffer_data
208 * and silc_buffer_len separately.
212 * // Following are the same thing
213 * silc_foo_function(foo, silc_buffer_datalen(buf));
214 * silc_foo_function(foo, silc_buffer_data(buf), silc_buffer_len(buf));
218 #define silc_buffer_datalen(x) (x) ? silc_buffer_data((x)) : NULL, \
219 (x) ? silc_buffer_len((x)) : 0
222 /* Inline functions */
224 /****f* silcutil/SilcBufferAPI/silc_buffer_alloc
229 * SilcBuffer silc_buffer_alloc(SilcUInt32 len);
233 * Allocates new SilcBuffer and returns it. Returns NULL on error.
238 SilcBuffer silc_buffer_alloc(SilcUInt32 len)
242 /* Allocate new SilcBuffer */
243 sb = (SilcBuffer)silc_calloc(1, sizeof(*sb));
244 if (silc_unlikely(!sb))
247 if (silc_likely(len)) {
248 /* Allocate the actual data area */
249 sb->head = (unsigned char *)silc_calloc(len, sizeof(*sb->head));
250 if (silc_unlikely(!sb->head))
253 /* Set pointers to the new buffer */
256 sb->end = sb->head + len;
262 /****f* silcutil/SilcBufferAPI/silc_buffer_free
267 * void silc_buffer_free(SilcBuffer sb);
271 * Frees SilcBuffer. Can be called safely `sb' as NULL.
275 * Must not be called for buffers allocated with silc_buffer_salloc,
276 * silc_buffer_salloc_size, silc_buffer_scopy and silc_buffer_sclone.
281 void silc_buffer_free(SilcBuffer sb)
284 #if defined(SILC_DEBUG)
286 memset(sb->head, 'F', silc_buffer_truelen(sb));
293 /****f* silcutil/SilcBufferAPI/silc_buffer_steal
298 * unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len);
302 * Steals the data from the buffer `sb'. This returns pointer to the
303 * start of the buffer and the true length of that buffer. The `sb'
304 * cannot be used anymore after calling this function because the
305 * data buffer was stolen. The `sb' must be freed with silc_buffer_free.
306 * The caller is responsible of freeing the stolen data buffer with
312 unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len)
314 unsigned char *buf = sb->head;
316 *data_len = silc_buffer_truelen(sb);
317 sb->head = sb->data = sb->tail = sb->end = NULL;
321 /****f* silcutil/SilcBufferAPI/silc_buffer_purge
326 * void silc_buffer_purge(SilcBuffer sb);
330 * Same as silc_buffer_free but free's only the contents of the buffer
331 * not the buffer itself. The `sb' remains intact, data is freed. Buffer
332 * is ready for re-use after calling this function.
336 * Must not be called for buffers allocated with silc_buffer_salloc,
337 * silc_buffer_salloc_size, silc_buffer_scopy and silc_buffer_sclone.
342 void silc_buffer_purge(SilcBuffer sb)
344 silc_free(silc_buffer_steal(sb, NULL));
347 /****f* silcutil/SilcBufferAPI/silc_buffer_set
352 * void silc_buffer_set(SilcBuffer sb,
353 * unsigned char *data,
354 * SilcUInt32 data_len);
358 * Sets the `data' and `data_len' to the buffer pointer sent as argument.
359 * The data area is automatically set to the `data_len'. This function
360 * can be used to set the data to static buffer without needing any
361 * memory allocations. The `data' will not be copied to the buffer.
365 * SilcBufferStruct buf;
366 * silc_buffer_set(&buf, data, data_len);
371 void silc_buffer_set(SilcBuffer sb, unsigned char *data, SilcUInt32 data_len)
373 sb->data = sb->head = data;
374 sb->tail = sb->end = data + data_len;
377 /****f* silcutil/SilcBufferAPI/silc_buffer_pull
382 * unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len);
386 * Pulls current data area towards end. The length of the currently
387 * valid data area is also decremented. Returns pointer to the data
388 * area before pulling. Returns NULL on error.
392 * ---------------------------------
393 * | head | data | tail |
394 * ---------------------------------
396 * Pulls the start of the data area.
398 * ---------------------------------
399 * | head | data | tail |
400 * ---------------------------------
403 * silc_buffer_pull(sb, 20);
408 unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len)
410 unsigned char *old_data = sb->data;
411 #if defined(SILC_DEBUG)
412 SILC_ASSERT(len <= silc_buffer_len(sb));
414 if (silc_unlikely(len > silc_buffer_len(sb)))
421 /****f* silcutil/SilcBufferAPI/silc_buffer_push
426 * unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len);
430 * Pushes current data area towards beginning. Length of the currently
431 * valid data area is also incremented. Returns a pointer to the
432 * data area before pushing. Returns NULL on error.
436 * ---------------------------------
437 * | head | data | tail |
438 * ---------------------------------
440 * Pushes the start of the data area.
442 * ---------------------------------
443 * | head | data | tail |
444 * ---------------------------------
447 * silc_buffer_push(sb, 20);
452 unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len)
454 unsigned char *old_data = sb->data;
455 #if defined(SILC_DEBUG)
456 SILC_ASSERT((sb->data - len) >= sb->head);
458 if (silc_unlikely((sb->data - len) < sb->head))
465 /****f* silcutil/SilcBufferAPI/silc_buffer_pull_tail
470 * unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len);
474 * Pulls current tail section towards end. Length of the current valid
475 * data area is also incremented. Returns a pointer to the data area
476 * before pulling. Returns NULL on error.
480 * ---------------------------------
481 * | head | data | tail |
482 * ---------------------------------
484 * Pulls the start of the tail section.
486 * ---------------------------------
487 * | head | data | tail |
488 * ---------------------------------
491 * silc_buffer_pull_tail(sb, 23);
496 unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len)
498 unsigned char *old_tail = sb->tail;
499 #if defined(SILC_DEBUG)
500 SILC_ASSERT(len <= silc_buffer_taillen(sb));
502 if (silc_unlikely(len > silc_buffer_taillen(sb)))
509 /****f* silcutil/SilcBufferAPI/silc_buffer_push_tail
514 * unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len);
518 * Pushes current tail section towards beginning. Length of the current
519 * valid data area is also decremented. Returns a pointer to the
520 * tail section before pushing. Returns NULL on error.
524 * ---------------------------------
525 * | head | data | tail |
526 * ---------------------------------
528 * Pushes the start of the tail section.
530 * ---------------------------------
531 * | head | data | tail |
532 * ---------------------------------
535 * silc_buffer_push_tail(sb, 23);
540 unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len)
542 unsigned char *old_tail = sb->tail;
543 #if defined(SILC_DEBUG)
544 SILC_ASSERT((sb->tail - len) >= sb->data);
546 if (silc_unlikely((sb->tail - len) < sb->data))
553 /****f* silcutil/SilcBufferAPI/silc_buffer_put_head
558 * unsigned char *silc_buffer_put_head(SilcBuffer sb,
559 * const unsigned char *data,
564 * Puts data at the head of the buffer. Returns pointer to the copied
565 * data area. Returns NULL on error.
569 * ---------------------------------
570 * | head | data | tail |
571 * ---------------------------------
573 * Puts data to the head section.
575 * silc_buffer_put_head(sb, data, data_len);
580 unsigned char *silc_buffer_put_head(SilcBuffer sb,
581 const unsigned char *data,
584 #if defined(SILC_DEBUG)
585 SILC_ASSERT(len <= silc_buffer_headlen(sb));
587 if (silc_unlikely(len > silc_buffer_headlen(sb)))
590 return (unsigned char *)memcpy(sb->head, data, len);
593 /****f* silcutil/SilcBufferAPI/silc_buffer_put
598 * unsigned char *silc_buffer_put(SilcBuffer sb,
599 * const unsigned char *data,
604 * Puts data at the start of the valid data area. Returns a pointer
605 * to the copied data area. Returns NULL on error.
609 * ---------------------------------
610 * | head | data | tail |
611 * ---------------------------------
613 * Puts data to the data section.
615 * silc_buffer_put(sb, data, data_len);
620 unsigned char *silc_buffer_put(SilcBuffer sb,
621 const unsigned char *data,
624 #if defined(SILC_DEBUG)
625 SILC_ASSERT(len <= silc_buffer_len(sb));
627 if (silc_unlikely(len > silc_buffer_len(sb)))
630 return (unsigned char *)memcpy(sb->data, data, len);
633 /****f* silcutil/SilcBufferAPI/silc_buffer_put_tail
638 * unsigned char *silc_buffer_put_tail(SilcBuffer sb,
639 * const unsigned char *data,
644 * Puts data at the tail of the buffer. Returns pointer to the copied
645 * data area. Returns NULL on error.
649 * ---------------------------------
650 * | head | data | tail |
651 * ---------------------------------
653 * Puts data to the tail section.
655 * silc_buffer_put_tail(sb, data, data_len);
660 unsigned char *silc_buffer_put_tail(SilcBuffer sb,
661 const unsigned char *data,
664 #if defined(SILC_DEBUG)
665 SILC_ASSERT(len <= silc_buffer_taillen(sb));
667 if (silc_unlikely(len > silc_buffer_taillen(sb)))
670 return (unsigned char *)memcpy(sb->tail, data, len);
673 /****f* silcutil/SilcBufferAPI/silc_buffer_alloc_size
678 * SilcBuffer silc_buffer_alloc_size(SilcUInt32 len);
682 * Allocates `len' bytes size buffer and moves the tail area automatically
683 * `len' bytes so that the buffer is ready to use without calling the
684 * silc_buffer_pull_tail. Returns NULL on error.
689 SilcBuffer silc_buffer_alloc_size(SilcUInt32 len)
691 SilcBuffer sb = silc_buffer_alloc(len);
692 if (silc_unlikely(!sb))
694 silc_buffer_pull_tail(sb, len);
698 /****f* silcutil/SilcBufferAPI/silc_buffer_reset
703 * void silc_buffer_reset(SilcBuffer sb);
707 * Resets the buffer to the state as if it was just allocated by
708 * silc_buffer_alloc. This does not clear the data area. Use
709 * silc_buffer_clear if you also want to clear the data area.
714 void silc_buffer_reset(SilcBuffer sb)
716 sb->data = sb->tail = sb->head;
719 /****f* silcutil/SilcBufferAPI/silc_buffer_clear
724 * void silc_buffer_clear(SilcBuffer sb);
728 * Clears and initialiazes the buffer to the state as if it was just
729 * allocated by silc_buffer_alloc.
734 void silc_buffer_clear(SilcBuffer sb)
736 memset(sb->head, 0, silc_buffer_truelen(sb));
737 silc_buffer_reset(sb);
740 /****f* silcutil/SilcBufferAPI/silc_buffer_start
745 * void silc_buffer_start(SilcBuffer sb);
749 * Moves the data area at the start of the buffer. The tail area remains
755 void silc_buffer_start(SilcBuffer sb)
760 /****f* silcutil/SilcBufferAPI/silc_buffer_end
765 * void silc_buffer_end(SilcBuffer sb);
769 * Moves the end of the data area to the end of the buffer. The start
770 * of the data area remains same. If the start of data area is at the
771 * start of the buffer, after this function returns the buffer's data
772 * area length is the length of the entire buffer.
777 void silc_buffer_end(SilcBuffer sb)
782 /****f* silcutil/SilcBufferAPI/silc_buffer_copy
787 * SilcBuffer silc_buffer_copy(SilcBuffer sb);
791 * Generates copy of a SilcBuffer. This copies everything inside the
792 * currently valid data area, nothing more. Use silc_buffer_clone to
793 * copy entire buffer. Returns NULL on error.
798 SilcBuffer silc_buffer_copy(SilcBuffer sb)
802 sb_new = silc_buffer_alloc_size(silc_buffer_len(sb));
803 if (silc_unlikely(!sb_new))
805 silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
810 /****f* silcutil/SilcBufferAPI/silc_buffer_clone
815 * SilcBuffer silc_buffer_clone(SilcBuffer sb);
819 * Clones SilcBuffer. This generates new SilcBuffer and copies
820 * everything from the source buffer. The result is exact clone of
821 * the original buffer. Returns NULL on error.
826 SilcBuffer silc_buffer_clone(SilcBuffer sb)
830 sb_new = silc_buffer_alloc_size(silc_buffer_truelen(sb));
831 if (silc_unlikely(!sb_new))
833 silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
834 sb_new->data = sb_new->head + silc_buffer_headlen(sb);
835 sb_new->tail = sb_new->data + silc_buffer_len(sb);
840 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc
845 * SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize);
849 * Reallocates buffer. Old data is saved into the new buffer. The buffer
850 * is exact clone of the old one except that there is now more space
851 * at the end of buffer. This always returns the same `sb' unless `sb'
852 * was NULL. Returns NULL on error.
857 SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize)
859 SilcUInt32 hlen, dlen;
863 return silc_buffer_alloc(newsize);
865 if (silc_unlikely(newsize <= silc_buffer_truelen(sb)))
868 hlen = silc_buffer_headlen(sb);
869 dlen = silc_buffer_len(sb);
870 h = (unsigned char *)silc_realloc(sb->head, newsize);
871 if (silc_unlikely(!h))
874 sb->data = sb->head + hlen;
875 sb->tail = sb->data + dlen;
876 sb->end = sb->head + newsize;
881 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc_size
886 * SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize);
890 * Same as silc_buffer_realloc but moves moves the tail area
891 * automatically so that the buffer is ready to use without calling the
892 * silc_buffer_pull_tail. Returns NULL on error.
897 SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize)
899 sb = silc_buffer_realloc(sb, newsize);
900 if (silc_unlikely(!sb))
902 silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
906 /****f* silcutil/SilcBufferAPI/silc_buffer_enlarge
911 * SilcBuffer silc_buffer_enlarge(SilcBuffer sb, SilcUInt32 size);
915 * Enlarges the buffer by the amount of `size' if it doesn't have that
916 * must space in the data area and in the tail area. Moves the tail
917 * area automatically after enlarging so that the current data area
918 * is at least the size of `size'. If there is more space than `size'
919 * in the data area this does not do anything. If there is enough
920 * space in the tail area this merely moves the tail area to reveal
921 * the extra space. Returns FALSE on error.
926 SilcBool silc_buffer_enlarge(SilcBuffer sb, SilcUInt32 size)
928 if (size > silc_buffer_len(sb)) {
929 if (size > silc_buffer_taillen(sb) + silc_buffer_len(sb))
930 if (silc_unlikely(!silc_buffer_realloc(sb, silc_buffer_truelen(sb) +
931 (size - silc_buffer_taillen(sb) -
932 silc_buffer_len(sb)))))
934 silc_buffer_pull_tail(sb, size - silc_buffer_len(sb));
940 /* SilcStack aware SilcBuffer routines */
942 /****f* silcutil/SilcBufferAPI/silc_buffer_salloc
947 * SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len);
951 * Allocates new SilcBuffer and returns it.
953 * This routine use SilcStack are memory source. If `stack' is NULL
954 * reverts back to normal allocating routine.
959 SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len)
964 return silc_buffer_alloc(len);
966 /* Allocate new SilcBuffer */
967 sb = (SilcBuffer)silc_scalloc(stack, 1, sizeof(*sb));
968 if (silc_unlikely(!sb))
971 /* Allocate the actual data area */
972 sb->head = (unsigned char *)silc_smalloc_ua(stack, len);
973 if (silc_unlikely(!sb->head))
976 /* Set pointers to the new buffer */
979 sb->end = sb->head + len;
984 /****f* silcutil/SilcBufferAPI/silc_buffer_salloc_size
989 * SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len);
993 * Allocates `len' bytes size buffer and moves the tail area automatically
994 * `len' bytes so that the buffer is ready to use without calling the
995 * silc_buffer_pull_tail.
997 * This routine use SilcStack are memory source. If `stack' is NULL
998 * reverts back to normal allocating routine.
1003 SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len)
1005 SilcBuffer sb = silc_buffer_salloc(stack, len);
1006 if (silc_unlikely(!sb))
1008 silc_buffer_pull_tail(sb, len);
1012 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc
1017 * SilcBuffer silc_buffer_srealloc(SilcStack stack,
1018 * SilcBuffer sb, SilcUInt32 newsize);
1022 * Reallocates buffer. Old data is saved into the new buffer. The buffer
1023 * is exact clone of the old one except that there is now more space
1024 * at the end of buffer.
1026 * This routine use SilcStack are memory source. If `stack' is NULL
1027 * reverts back to normal allocating routine.
1032 SilcBuffer silc_buffer_srealloc(SilcStack stack,
1033 SilcBuffer sb, SilcUInt32 newsize)
1035 SilcUInt32 hlen, dlen;
1039 return silc_buffer_realloc(sb, newsize);
1042 return silc_buffer_salloc(stack, newsize);
1044 if (newsize <= silc_buffer_truelen(sb))
1047 hlen = silc_buffer_headlen(sb);
1048 dlen = silc_buffer_len(sb);
1049 h = (unsigned char *)silc_srealloc_ua(stack, silc_buffer_truelen(sb),
1052 /* Do slow and stack wasting realloc. The old sb->head is lost and
1053 is freed eventually. */
1054 h = (unsigned char *)silc_smalloc_ua(stack, newsize);
1055 if (silc_unlikely(!h))
1057 memcpy(h, sb->head, silc_buffer_truelen(sb));
1061 sb->data = sb->head + hlen;
1062 sb->tail = sb->data + dlen;
1063 sb->end = sb->head + newsize;
1068 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc_size
1073 * SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
1074 * SilcBuffer sb, SilcUInt32 newsize);
1078 * Same as silc_buffer_srealloc but moves moves the tail area
1079 * automatically so that the buffer is ready to use without calling the
1080 * silc_buffer_pull_tail.
1082 * This routine use SilcStack are memory source. If `stack' is NULL
1083 * reverts back to normal allocating routine.
1088 SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
1089 SilcBuffer sb, SilcUInt32 newsize)
1091 sb = silc_buffer_srealloc(stack, sb, newsize);
1092 if (silc_unlikely(!sb))
1094 silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
1098 /****f* silcutil/SilcBufferAPI/silc_buffer_senlarge
1103 * SilcBuffer silc_buffer_senlarge(SilcStack stack, SilcBuffer sb,
1108 * Enlarges the buffer by the amount of `size' if it doesn't have that
1109 * must space in the data area and in the tail area. Moves the tail
1110 * area automatically after enlarging so that the current data area
1111 * is at least the size of `size'. If there is more space than `size'
1112 * in the data area this does not do anything. If there is enough
1113 * space in the tail area this merely moves the tail area to reveal
1114 * the extra space. Returns FALSE on error.
1116 * This routine use SilcStack are memory source. If `stack' is NULL
1117 * reverts back to normal allocating routine.
1122 SilcBool silc_buffer_senlarge(SilcStack stack, SilcBuffer sb, SilcUInt32 size)
1124 if (size > silc_buffer_len(sb)) {
1125 if (size > silc_buffer_taillen(sb) + silc_buffer_len(sb))
1126 if (silc_unlikely(!silc_buffer_srealloc(stack, sb,
1127 silc_buffer_truelen(sb) +
1128 (size - silc_buffer_taillen(sb) -
1129 silc_buffer_len(sb)))))
1131 silc_buffer_pull_tail(sb, size - silc_buffer_len(sb));
1136 /****f* silcutil/SilcBufferAPI/silc_buffer_scopy
1141 * SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb);
1145 * Generates copy of a SilcBuffer. This copies everything inside the
1146 * currently valid data area, nothing more. Use silc_buffer_clone to
1147 * copy entire buffer.
1149 * This routine use SilcStack are memory source. If `stack' is NULL
1150 * reverts back to normal allocating routine.
1155 SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb)
1159 sb_new = silc_buffer_salloc_size(stack, silc_buffer_len(sb));
1160 if (silc_unlikely(!sb_new))
1162 silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
1167 /****f* silcutil/SilcBufferAPI/silc_buffer_sclone
1172 * SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb);
1176 * Clones SilcBuffer. This generates new SilcBuffer and copies
1177 * everything from the source buffer. The result is exact clone of
1178 * the original buffer.
1180 * This routine use SilcStack are memory source. If `stack' is NULL
1181 * reverts back to normal allocating routine.
1186 SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb)
1190 sb_new = silc_buffer_salloc_size(stack, silc_buffer_truelen(sb));
1191 if (silc_unlikely(!sb_new))
1193 silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
1194 sb_new->data = sb_new->head + silc_buffer_headlen(sb);
1195 sb_new->tail = sb_new->data + silc_buffer_len(sb);
1200 #endif /* SILCBUFFER_H */