5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1998 - 2008 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.
19 /* $Id: silcbuffer.h,v 1.43 2008/01/15 06:36:54 priikone Exp $ */
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.
113 typedef struct SilcBufferObject {
118 } *SilcBuffer, SilcBufferStruct;
123 /****f* silcutil/SilcBufferAPI/silc_buffer_data
127 * unsigned char *silc_buffer_data(SilcBuffer sb)
131 * Returns pointer to the data area of the buffer.
135 #define silc_buffer_data(x) (x)->data
138 /****f* silcutil/SilcBufferAPI/silc_buffer_tail
142 * unsigned char *silc_buffer_tail(SilcBuffer sb)
146 * Returns pointer to the tail area of the buffer.
150 #define silc_buffer_tail(x) (x)->tail
153 /****f* silcutil/SilcBufferAPI/silc_buffer_datalen
157 * #define silc_buffer_datalen ...
161 * Macro that can be used in function argument list to give the data
162 * pointer and the data length, instead of calling both silc_buffer_data
163 * and silc_buffer_len separately.
167 * // Following are the same thing
168 * silc_foo_function(foo, silc_buffer_datalen(buf));
169 * silc_foo_function(foo, silc_buffer_data(buf), silc_buffer_len(buf));
173 #define silc_buffer_datalen(x) (x) ? silc_buffer_data((x)) : NULL, \
174 (x) ? silc_buffer_len((x)) : 0
177 /* Inline functions */
179 /****d* silcutil/SilcBufferAPI/silc_buffer_truelen
183 * SilcUInt32 silc_buffer_truelen(SilcBuffer sb)
187 * Returns the true length of the buffer.
191 SilcUInt32 silc_buffer_truelen(SilcBuffer x)
193 return (SilcUInt32)(x->end - x->head);
196 /****d* silcutil/SilcBufferAPI/silc_buffer_len
200 * SilcUInt32 silc_buffer_len(SilcBuffer sb)
204 * Returns the current length of the data area of the buffer.
208 SilcUInt32 silc_buffer_len(SilcBuffer x)
210 return (SilcUInt32)(x->tail - x->data);
213 /****d* silcutil/SilcBufferAPI/silc_buffer_headlen
217 * SilcUInt32 silc_buffer_headlen(SilcBuffer sb)
221 * Returns the current length of the head data area of the buffer.
225 SilcUInt32 silc_buffer_headlen(SilcBuffer x)
227 return (SilcUInt32)(x->data - x->head);
230 /****d* silcutil/SilcBufferAPI/silc_buffer_taillen
234 * SilcUInt32 silc_buffer_taillen(SilcBuffer sb)
238 * Returns the current length of the tail data area of the buffer.
242 SilcUInt32 silc_buffer_taillen(SilcBuffer x)
244 return (SilcUInt32)(x->end - x->tail);
247 /****f* silcutil/SilcBufferAPI/silc_buffer_alloc
252 * SilcBuffer silc_buffer_alloc(SilcUInt32 len);
256 * Allocates new SilcBuffer and returns it. Returns NULL if system is
262 SilcBuffer silc_buffer_alloc(SilcUInt32 len)
266 /* Allocate new SilcBuffer */
267 sb = (SilcBuffer)silc_calloc(1, sizeof(*sb));
268 if (silc_unlikely(!sb))
271 if (silc_likely(len)) {
272 /* Allocate the actual data area */
273 sb->head = (unsigned char *)silc_malloc(len * sizeof(*sb->head));
274 if (silc_unlikely(!sb->head))
277 /* Set pointers to the new buffer */
280 sb->end = sb->head + len;
286 /****f* silcutil/SilcBufferAPI/silc_buffer_salloc
291 * SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len);
295 * Allocates new SilcBuffer and returns it. Returns NULL if system is
298 * This routine use SilcStack are memory source. If `stack' is NULL
299 * reverts back to normal allocating routine.
301 * Note that this call consumes the `stack'. The caller should push the
302 * stack before calling the function and pop it later.
307 SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len)
312 return silc_buffer_alloc(len);
314 /* Allocate new SilcBuffer */
315 sb = (SilcBuffer)silc_scalloc(stack, 1, sizeof(*sb));
316 if (silc_unlikely(!sb))
319 if (silc_likely(len)) {
320 /* Allocate the actual data area */
321 sb->head = (unsigned char *)silc_smalloc(stack, len * sizeof(*sb->head));
322 if (silc_unlikely(!sb->head))
325 /* Set pointers to the new buffer */
328 sb->end = sb->head + len;
334 /****f* silcutil/SilcBufferAPI/silc_buffer_free
339 * void silc_buffer_free(SilcBuffer sb);
343 * Frees SilcBuffer. Can be called safely `sb' as NULL.
347 * Must not be called for buffers allocated with silc_buffer_salloc,
348 * silc_buffer_salloc_size, silc_buffer_scopy and silc_buffer_sclone.
349 * Call silc_buffer_sfree instead.
354 void silc_buffer_free(SilcBuffer sb)
357 #if defined(SILC_DEBUG)
359 memset(sb->head, 'F', silc_buffer_truelen(sb));
366 /****f* silcutil/SilcBufferAPI/silc_buffer_sfree
371 * void silc_buffer_free(SilcStack stack, SilcBuffer sb);
375 * Frees SilcBuffer. If `stack' is NULL this calls silc_buffer_free. Can
376 * be called safely `sb' as NULL.
381 void silc_buffer_sfree(SilcStack stack, SilcBuffer sb)
387 memset(sb->head, 'F', silc_buffer_truelen(sb));
388 memset(sb, 'F', sizeof(*sb));
390 #endif /* SILC_DEBUG */
394 silc_buffer_free(sb);
397 /****f* silcutil/SilcBufferAPI/silc_buffer_steal
402 * unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len);
406 * Steals the data from the buffer `sb'. This returns pointer to the
407 * start of the buffer and the true length of that buffer. The `sb'
408 * cannot be used anymore after calling this function because the
409 * data buffer was stolen. The `sb' must be freed with silc_buffer_free.
410 * The caller is responsible of freeing the stolen data buffer with
416 unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len)
418 unsigned char *buf = sb->head;
420 *data_len = silc_buffer_truelen(sb);
421 sb->head = sb->data = sb->tail = sb->end = NULL;
425 /****f* silcutil/SilcBufferAPI/silc_buffer_purge
430 * void silc_buffer_purge(SilcBuffer sb);
434 * Same as silc_buffer_free but free's only the contents of the buffer
435 * not the buffer itself. The `sb' remains intact, data is freed. Buffer
436 * is ready for re-use after calling this function.
440 * Must not be called for buffers allocated with silc_buffer_salloc,
441 * silc_buffer_salloc_size, silc_buffer_scopy and silc_buffer_sclone.
442 * Use silc_buffer_spurge instead.
447 void silc_buffer_purge(SilcBuffer sb)
449 silc_free(silc_buffer_steal(sb, NULL));
452 /****f* silcutil/SilcBufferAPI/silc_buffer_spurge
457 * void silc_buffer_spurge(SilcStack stack, SilcBuffer sb);
461 * Same as silc_buffer_free but free's only the contents of the buffer
462 * not the buffer itself. The `sb' remains intact, data is freed. Buffer
463 * is ready for re-use after calling this function. If `stack' is NULL
464 * this calls silc_buffer_purge.
469 void silc_buffer_spurge(SilcStack stack, SilcBuffer sb)
474 memset(silc_buffer_steal(sb, NULL), 'F', silc_buffer_truelen(sb));
475 #endif /* SILC_DEBUG */
479 silc_buffer_purge(sb);
482 /****f* silcutil/SilcBufferAPI/silc_buffer_set
487 * void silc_buffer_set(SilcBuffer sb,
488 * unsigned char *data,
489 * SilcUInt32 data_len);
493 * Sets the `data' and `data_len' to the buffer pointer sent as argument.
494 * The data area is automatically set to the `data_len'. This function
495 * can be used to set the data to static buffer without needing any
496 * memory allocations. The `data' will not be copied to the buffer.
500 * SilcBufferStruct buf;
501 * silc_buffer_set(&buf, data, data_len);
506 void silc_buffer_set(SilcBuffer sb, unsigned char *data, SilcUInt32 data_len)
508 sb->data = sb->head = data;
509 sb->tail = sb->end = data + data_len;
512 /****f* silcutil/SilcBufferAPI/silc_buffer_pull
517 * unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len);
521 * Pulls current data area towards end. The length of the currently
522 * valid data area is also decremented. Returns pointer to the data
523 * area before pulling. Returns NULL if the pull would lead to buffer
524 * overflow or would go beyond the valid data area.
528 * ---------------------------------
529 * | head | data | tail |
530 * ---------------------------------
532 * Pulls the start of the data area.
534 * ---------------------------------
535 * | head | data | tail |
536 * ---------------------------------
539 * silc_buffer_pull(sb, 20);
544 unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len)
546 unsigned char *old_data = sb->data;
548 #ifdef SILC_DIST_INPLACE
549 SILC_ASSERT(len <= silc_buffer_len(sb));
550 #endif /* SILC_DIST_INPLACE */
551 if (silc_unlikely(len > silc_buffer_len(sb))) {
552 silc_set_errno(SILC_ERR_OVERFLOW);
560 /****f* silcutil/SilcBufferAPI/silc_buffer_push
565 * unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len);
569 * Pushes current data area towards beginning. Length of the currently
570 * valid data area is also incremented. Returns a pointer to the
571 * data area before pushing. Returns NULL if the push would lead to
572 * go beyond the buffer boundaries or current data area.
576 * ---------------------------------
577 * | head | data | tail |
578 * ---------------------------------
580 * Pushes the start of the data area.
582 * ---------------------------------
583 * | head | data | tail |
584 * ---------------------------------
587 * silc_buffer_push(sb, 20);
592 unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len)
594 unsigned char *old_data = sb->data;
596 #ifdef SILC_DIST_INPLACE
597 SILC_ASSERT((sb->data - len) >= sb->head);
598 #endif /* SILC_DIST_INPLACE */
599 if (silc_unlikely((sb->data - len) < sb->head)) {
600 silc_set_errno(SILC_ERR_OVERFLOW);
608 /****f* silcutil/SilcBufferAPI/silc_buffer_pull_tail
613 * unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len);
617 * Pulls current tail section towards end. Length of the current valid
618 * data area is also incremented. Returns a pointer to the data area
619 * before pulling. Returns NULL if the pull would lead to buffer overflow.
623 * ---------------------------------
624 * | head | data | tail |
625 * ---------------------------------
627 * Pulls the start of the tail section.
629 * ---------------------------------
630 * | head | data | tail |
631 * ---------------------------------
634 * silc_buffer_pull_tail(sb, 23);
639 unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len)
641 unsigned char *old_tail = sb->tail;
643 #ifdef SILC_DIST_INPLACE
644 SILC_ASSERT(len <= silc_buffer_taillen(sb));
645 #endif /* SILC_DIST_INPLACE */
646 if (silc_unlikely(len > silc_buffer_taillen(sb))) {
647 silc_set_errno(SILC_ERR_OVERFLOW);
655 /****f* silcutil/SilcBufferAPI/silc_buffer_push_tail
660 * unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len);
664 * Pushes current tail section towards beginning. Length of the current
665 * valid data area is also decremented. Returns a pointer to the
666 * tail section before pushing. Returns NULL if the push would lead to
667 * go beyond buffer boundaries or current tail area.
671 * ---------------------------------
672 * | head | data | tail |
673 * ---------------------------------
675 * Pushes the start of the tail section.
677 * ---------------------------------
678 * | head | data | tail |
679 * ---------------------------------
682 * silc_buffer_push_tail(sb, 23);
687 unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len)
689 unsigned char *old_tail = sb->tail;
691 #ifdef SILC_DIST_INPLACE
692 SILC_ASSERT((sb->tail - len) >= sb->data);
693 #endif /* SILC_DIST_INPLACE */
694 if (silc_unlikely((sb->tail - len) < sb->data)) {
695 silc_set_errno(SILC_ERR_OVERFLOW);
703 /****f* silcutil/SilcBufferAPI/silc_buffer_put_head
708 * unsigned char *silc_buffer_put_head(SilcBuffer sb,
709 * const unsigned char *data,
714 * Puts data at the head of the buffer. Returns pointer to the copied
715 * data area. Returns NULL if the data is longer that the current head
720 * ---------------------------------
721 * | head | data | tail |
722 * ---------------------------------
724 * Puts data to the head section.
726 * silc_buffer_put_head(sb, data, data_len);
731 unsigned char *silc_buffer_put_head(SilcBuffer sb,
732 const unsigned char *data,
735 #ifdef SILC_DIST_INPLACE
736 SILC_ASSERT(len <= silc_buffer_headlen(sb));
737 #endif /* SILC_DIST_INPLACE */
738 if (silc_unlikely(len > silc_buffer_headlen(sb))) {
739 silc_set_errno(SILC_ERR_OVERFLOW);
743 if (sb->head > data) {
744 if (sb->head - data <= len)
745 return (unsigned char *)memmove(sb->head, data, len);
747 if (data - sb->head <= len)
748 return (unsigned char *)memmove(sb->head, data, len);
751 return (unsigned char *)memcpy(sb->head, data, len);
754 /****f* silcutil/SilcBufferAPI/silc_buffer_put
759 * unsigned char *silc_buffer_put(SilcBuffer sb,
760 * const unsigned char *data,
765 * Puts data at the start of the valid data area. Returns a pointer
766 * to the copied data area. Returns NULL if the data is longer than the
771 * ---------------------------------
772 * | head | data | tail |
773 * ---------------------------------
775 * Puts data to the data section.
777 * silc_buffer_put(sb, data, data_len);
782 unsigned char *silc_buffer_put(SilcBuffer sb,
783 const unsigned char *data,
786 #ifdef SILC_DIST_INPLACE
787 SILC_ASSERT(len <= silc_buffer_len(sb));
788 #endif /* SILC_DIST_INPLACE */
789 if (silc_unlikely(len > silc_buffer_len(sb))) {
790 silc_set_errno(SILC_ERR_OVERFLOW);
794 if (sb->data > data) {
795 if (sb->data - data <= len)
796 return (unsigned char *)memmove(sb->data, data, len);
798 if (data - sb->data <= len)
799 return (unsigned char *)memmove(sb->data, data, len);
802 return (unsigned char *)memcpy(sb->data, data, len);
805 /****f* silcutil/SilcBufferAPI/silc_buffer_put_tail
810 * unsigned char *silc_buffer_put_tail(SilcBuffer sb,
811 * const unsigned char *data,
816 * Puts data at the tail of the buffer. Returns pointer to the copied
817 * data area. Returns NULL if the data is longer than the current tail
822 * ---------------------------------
823 * | head | data | tail |
824 * ---------------------------------
826 * Puts data to the tail section.
828 * silc_buffer_put_tail(sb, data, data_len);
833 unsigned char *silc_buffer_put_tail(SilcBuffer sb,
834 const unsigned char *data,
837 #ifdef SILC_DIST_INPLACE
838 SILC_ASSERT(len <= silc_buffer_taillen(sb));
839 #endif /* SILC_DIST_INPLACE */
840 if (silc_unlikely(len > silc_buffer_taillen(sb))) {
841 silc_set_errno(SILC_ERR_OVERFLOW);
845 if (sb->tail > data) {
846 if (sb->tail - data <= len)
847 return (unsigned char *)memmove(sb->tail, data, len);
849 if (data - sb->tail <= len)
850 return (unsigned char *)memmove(sb->tail, data, len);
853 return (unsigned char *)memcpy(sb->tail, data, len);
856 /****f* silcutil/SilcBufferAPI/silc_buffer_alloc_size
861 * SilcBuffer silc_buffer_alloc_size(SilcUInt32 len);
865 * Allocates `len' bytes size buffer and moves the tail area automatically
866 * `len' bytes so that the buffer is ready to use without calling the
867 * silc_buffer_pull_tail. Returns NULL if system is out of memory.
872 SilcBuffer silc_buffer_alloc_size(SilcUInt32 len)
874 SilcBuffer sb = silc_buffer_alloc(len);
875 if (silc_unlikely(!sb))
877 silc_buffer_pull_tail(sb, len);
881 /****f* silcutil/SilcBufferAPI/silc_buffer_salloc_size
886 * SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len);
890 * Allocates `len' bytes size buffer and moves the tail area automatically
891 * `len' bytes so that the buffer is ready to use without calling the
892 * silc_buffer_pull_tail. Returns NULL if system is out of memory.
894 * This routine use SilcStack are memory source. If `stack' is NULL
895 * reverts back to normal allocating routine.
897 * Note that this call consumes the `stack'. The caller should push the
898 * stack before calling the function and pop it later.
903 SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len)
905 SilcBuffer sb = silc_buffer_salloc(stack, len);
906 if (silc_unlikely(!sb))
908 silc_buffer_pull_tail(sb, len);
912 /****f* silcutil/SilcBufferAPI/silc_buffer_reset
917 * void silc_buffer_reset(SilcBuffer sb);
921 * Resets the buffer to the state as if it was just allocated by
922 * silc_buffer_alloc. This does not clear the data area. Use
923 * silc_buffer_clear if you also want to clear the data area.
928 void silc_buffer_reset(SilcBuffer sb)
930 sb->data = sb->tail = sb->head;
933 /****f* silcutil/SilcBufferAPI/silc_buffer_clear
938 * void silc_buffer_clear(SilcBuffer sb);
942 * Clears and initialiazes the buffer to the state as if it was just
943 * allocated by silc_buffer_alloc.
948 void silc_buffer_clear(SilcBuffer sb)
950 memset(sb->head, 0, silc_buffer_truelen(sb));
951 silc_buffer_reset(sb);
954 /****f* silcutil/SilcBufferAPI/silc_buffer_start
959 * void silc_buffer_start(SilcBuffer sb);
963 * Moves the data area at the start of the buffer. The tail area remains
969 void silc_buffer_start(SilcBuffer sb)
974 /****f* silcutil/SilcBufferAPI/silc_buffer_end
979 * void silc_buffer_end(SilcBuffer sb);
983 * Moves the end of the data area to the end of the buffer. The start
984 * of the data area remains same. If the start of data area is at the
985 * start of the buffer, after this function returns the buffer's data
986 * area length is the length of the entire buffer.
991 void silc_buffer_end(SilcBuffer sb)
996 /****f* silcutil/SilcBufferAPI/silc_buffer_copy
1001 * SilcBuffer silc_buffer_copy(SilcBuffer sb);
1005 * Generates copy of a SilcBuffer. This copies everything inside the
1006 * currently valid data area, nothing more. Use silc_buffer_clone to
1007 * copy entire buffer. Returns NULL if system is out of memory.
1012 SilcBuffer silc_buffer_copy(SilcBuffer sb)
1016 sb_new = silc_buffer_alloc_size(silc_buffer_len(sb));
1017 if (silc_unlikely(!sb_new))
1019 silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
1024 /****f* silcutil/SilcBufferAPI/silc_buffer_scopy
1029 * SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb);
1033 * Generates copy of a SilcBuffer. This copies everything inside the
1034 * currently valid data area, nothing more. Use silc_buffer_clone to
1035 * copy entire buffer. Returns NULL if system is out of memory.
1037 * This routine use SilcStack are memory source. If `stack' is NULL
1038 * reverts back to normal allocating routine.
1040 * Note that this call consumes the `stack'. The caller should push the
1041 * stack before calling the function and pop it later.
1046 SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb)
1050 sb_new = silc_buffer_salloc_size(stack, silc_buffer_len(sb));
1051 if (silc_unlikely(!sb_new))
1053 silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
1058 /****f* silcutil/SilcBufferAPI/silc_buffer_clone
1063 * SilcBuffer silc_buffer_clone(SilcBuffer sb);
1067 * Clones SilcBuffer. This generates new SilcBuffer and copies
1068 * everything from the source buffer. The result is exact clone of
1069 * the original buffer. Returns NULL if system is out of memory.
1074 SilcBuffer silc_buffer_clone(SilcBuffer sb)
1078 sb_new = silc_buffer_alloc_size(silc_buffer_truelen(sb));
1079 if (silc_unlikely(!sb_new))
1081 silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
1082 sb_new->data = sb_new->head + silc_buffer_headlen(sb);
1083 sb_new->tail = sb_new->data + silc_buffer_len(sb);
1088 /****f* silcutil/SilcBufferAPI/silc_buffer_sclone
1093 * SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb);
1097 * Clones SilcBuffer. This generates new SilcBuffer and copies
1098 * everything from the source buffer. The result is exact clone of
1099 * the original buffer. Returns NULL if system is out of memory.
1101 * This routine use SilcStack are memory source. If `stack' is NULL
1102 * reverts back to normal allocating routine.
1104 * Note that this call consumes the `stack'. The caller should push the
1105 * stack before calling the function and pop it later.
1110 SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb)
1114 sb_new = silc_buffer_salloc_size(stack, silc_buffer_truelen(sb));
1115 if (silc_unlikely(!sb_new))
1117 silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
1118 sb_new->data = sb_new->head + silc_buffer_headlen(sb);
1119 sb_new->tail = sb_new->data + silc_buffer_len(sb);
1124 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc
1129 * SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize);
1133 * Reallocates buffer. Old data is saved into the new buffer. The buffer
1134 * is exact clone of the old one except that there is now more/less space
1135 * at the end of buffer. This always returns the same `sb' unless `sb'
1136 * was NULL. Returns NULL if system is out of memory.
1138 * If the `newsize' is shorter than the current buffer size, the data
1139 * and tail area of the buffer must be set to correct position before
1140 * calling this function so that buffer overflow would not occur when
1141 * the buffer size is reduced.
1146 SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize)
1148 SilcUInt32 hlen, dlen;
1152 return silc_buffer_alloc(newsize);
1154 if (silc_unlikely(newsize == silc_buffer_truelen(sb)))
1157 hlen = silc_buffer_headlen(sb);
1158 dlen = silc_buffer_len(sb);
1159 h = (unsigned char *)silc_realloc(sb->head, newsize);
1160 if (silc_unlikely(!h))
1163 sb->data = sb->head + hlen;
1164 sb->tail = sb->data + dlen;
1165 sb->end = sb->head + newsize;
1170 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc
1175 * SilcBuffer silc_buffer_srealloc(SilcStack stack,
1176 * SilcBuffer sb, SilcUInt32 newsize);
1180 * Reallocates buffer. Old data is saved into the new buffer. The buffer
1181 * is exact clone of the old one except that there is now more/less space
1182 * at the end of buffer. Returns NULL if system is out of memory. This
1183 * always returns `sb' unless `sb' was NULL.
1185 * If the `newsize' is shorter than the current buffer size, the data
1186 * and tail area of the buffer must be set to correct position before
1187 * calling this function so that buffer overflow would not occur when
1188 * the buffer size is reduced.
1190 * This routine use SilcStack are memory source. If `stack' is NULL
1191 * reverts back to normal allocating routine.
1193 * Note that this call consumes the `stack'. The caller should push the
1194 * stack before calling the function and pop it later.
1199 SilcBuffer silc_buffer_srealloc(SilcStack stack,
1200 SilcBuffer sb, SilcUInt32 newsize)
1202 SilcUInt32 hlen, dlen;
1206 return silc_buffer_realloc(sb, newsize);
1209 return silc_buffer_salloc(stack, newsize);
1211 if (newsize == silc_buffer_truelen(sb))
1214 hlen = silc_buffer_headlen(sb);
1215 dlen = silc_buffer_len(sb);
1216 h = (unsigned char *)silc_srealloc(stack, silc_buffer_truelen(sb),
1222 sb->data = sb->head + hlen;
1223 sb->tail = sb->data + dlen;
1224 sb->end = sb->head + newsize;
1229 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc_size
1234 * SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize);
1238 * Same as silc_buffer_realloc but moves moves the tail area
1239 * automatically so that the buffer is ready to use without calling the
1240 * silc_buffer_pull_tail. Returns NULL if system is out of memory.
1245 SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize)
1247 sb = silc_buffer_realloc(sb, newsize);
1248 if (silc_unlikely(!sb))
1250 silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
1254 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc_size
1259 * SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
1260 * SilcBuffer sb, SilcUInt32 newsize);
1264 * Same as silc_buffer_srealloc but moves moves the tail area
1265 * automatically so that the buffer is ready to use without calling the
1266 * silc_buffer_pull_tail. Returns NULL if system is out of memory.
1268 * This routine use SilcStack are memory source. If `stack' is NULL
1269 * reverts back to normal allocating routine.
1271 * Note that this call consumes the `stack'. The caller should push the
1272 * stack before calling the function and pop it later.
1277 SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
1278 SilcBuffer sb, SilcUInt32 newsize)
1280 sb = silc_buffer_srealloc(stack, sb, newsize);
1281 if (silc_unlikely(!sb))
1283 silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
1287 /****f* silcutil/SilcBufferAPI/silc_buffer_enlarge
1292 * SilcBuffer silc_buffer_enlarge(SilcBuffer sb, SilcUInt32 size);
1296 * Enlarges the buffer by the amount of `size' if it doesn't have that
1297 * must space in the data area and in the tail area. Moves the tail
1298 * area automatically after enlarging so that the current data area
1299 * is at least the size of `size'. If there is more space than `size'
1300 * in the data area this does not do anything. If there is enough
1301 * space in the tail area this merely moves the tail area to reveal
1302 * the extra space. Returns FALSE if system is out of memory.
1307 SilcBool silc_buffer_enlarge(SilcBuffer sb, SilcUInt32 size)
1309 if (size > silc_buffer_len(sb)) {
1310 if (size > silc_buffer_taillen(sb) + silc_buffer_len(sb))
1311 if (silc_unlikely(!silc_buffer_realloc(sb, silc_buffer_truelen(sb) +
1312 (size - silc_buffer_taillen(sb) -
1313 silc_buffer_len(sb)))))
1315 silc_buffer_pull_tail(sb, size - silc_buffer_len(sb));
1320 /****f* silcutil/SilcBufferAPI/silc_buffer_senlarge
1325 * SilcBuffer silc_buffer_senlarge(SilcStack stack, SilcBuffer sb,
1330 * Enlarges the buffer by the amount of `size' if it doesn't have that
1331 * must space in the data area and in the tail area. Moves the tail
1332 * area automatically after enlarging so that the current data area
1333 * is at least the size of `size'. If there is more space than `size'
1334 * in the data area this does not do anything. If there is enough
1335 * space in the tail area this merely moves the tail area to reveal
1336 * the extra space. Returns FALSE if system is out of memory.
1338 * This routine use SilcStack are memory source. If `stack' is NULL
1339 * reverts back to normal allocating routine.
1341 * Note that this call consumes the `stack'. The caller should push the
1342 * stack before calling the function and pop it later.
1347 SilcBool silc_buffer_senlarge(SilcStack stack, SilcBuffer sb, SilcUInt32 size)
1349 if (size > silc_buffer_len(sb)) {
1350 if (size > silc_buffer_taillen(sb) + silc_buffer_len(sb))
1351 if (silc_unlikely(!silc_buffer_srealloc(stack, sb,
1352 silc_buffer_truelen(sb) +
1353 (size - silc_buffer_taillen(sb) -
1354 silc_buffer_len(sb)))))
1356 silc_buffer_pull_tail(sb, size - silc_buffer_len(sb));
1361 /****f* silcutil/SilcBufferAPI/silc_buffer_append
1366 * SilcBuffer silc_buffer_append(SilcBuffer sb, SilcUInt32 size);
1370 * Appends the current data area by the amount of `size'. The tail area
1371 * of the buffer remains intact and contains the same data than the old
1372 * tail area (the data is copied to the new tail area). After appending
1373 * there is now `size' bytes more free area in the data area. Returns
1374 * FALSE if system is out of memory.
1379 * ---------------------------------
1380 * | head | data | tail |
1381 * ---------------------------------
1384 * ------------------------------------
1385 * | head | data | tail |
1386 * -------------------------------------
1388 * silc_buffer_append(sb, 5);
1393 SilcBool silc_buffer_append(SilcBuffer sb, SilcUInt32 size)
1395 if (silc_unlikely(!silc_buffer_realloc(sb, silc_buffer_truelen(sb) + size)))
1398 /* Enlarge data area */
1399 silc_buffer_pull_tail(sb, size);
1401 /* Copy old tail area to new tail area */
1402 silc_buffer_put_tail(sb, sb->tail - size, silc_buffer_taillen(sb));
1407 /****f* silcutil/SilcBufferAPI/silc_buffer_append
1412 * SilcBool silc_buffer_sappend(SilcStack stack, SilcBuffer sb,
1417 * Appends the current data area by the amount of `size'. The tail area
1418 * of the buffer remains intact and contains the same data than the old
1419 * tail area (the data is copied to the new tail area). After appending
1420 * there is now `size' bytes more free area in the data area. Returns
1421 * FALSE if system is out of memory.
1423 * This routine use SilcStack are memory source. If `stack' is NULL
1424 * reverts back to normal allocating routine.
1426 * Note that this call consumes the `stack'. The caller should push the
1427 * stack before calling the function and pop it later.
1432 * ---------------------------------
1433 * | head | data | tail |
1434 * ---------------------------------
1437 * ------------------------------------
1438 * | head | data | tail |
1439 * -------------------------------------
1441 * silc_buffer_append(sb, 5);
1446 SilcBool silc_buffer_sappend(SilcStack stack, SilcBuffer sb, SilcUInt32 size)
1448 if (silc_unlikely(!silc_buffer_srealloc(stack, sb,
1449 silc_buffer_truelen(sb) + size)))
1452 /* Enlarge data area */
1453 silc_buffer_pull_tail(sb, size);
1455 /* Copy old tail area to new tail area */
1456 silc_buffer_put_tail(sb, sb->tail - size, silc_buffer_taillen(sb));
1461 /****f* silcutil/SilcBufferAPI/silc_buffer_strchr
1466 * unsigned char *silc_buffer_strchr(SilcBuffer sb, int c, SilcBool first);
1470 * Returns pointer to the occurence of the character `c' in the buffer
1471 * `sb'. If the `first' is TRUE this finds the first occurene of `c',
1472 * if it is FALSE this finds the last occurence of `c'. If the character
1473 * is found the `sb' data area is moved to that location and its pointer
1474 * is returned. The silc_buffer_data call will return the same pointer.
1475 * Returns NULL if such character could not be located and the buffer
1476 * remains unmodified.
1478 * This call is equivalent to strchr(), strrchr(), memchr() and memrchr()
1479 * except it works with SilcBuffer.
1483 * This searches only the data area of the buffer. Head and tail area
1486 * The `sb' data need not be NULL terminated.
1491 unsigned char *silc_buffer_strchr(SilcBuffer sb, int c, SilcBool first)
1496 for (i = 0; i < silc_buffer_len(sb); i++) {
1497 if (sb->data[i] == (unsigned char)c) {
1498 sb->data = &sb->data[i];
1503 for (i = silc_buffer_len(sb) - 1; 1 >= 0; i--) {
1504 if (sb->data[i] == (unsigned char)c) {
1505 sb->data = &sb->data[i];
1514 /****f* silcutil/SilcBufferAPI/silc_buffer_equal
1519 * SilcBool silc_buffer_equal(SilcBuffer sb1, SilcBuffer sb2)
1523 * Compares if the data area of the buffer `sb1' and `sb2' are identical.
1524 * Returns TRUE if they match and FALSE if they differ.
1529 SilcBool silc_buffer_equal(SilcBuffer sb1, SilcBuffer sb2)
1531 if (silc_buffer_len(sb1) != silc_buffer_len(sb2))
1533 return memcmp(sb1->data, sb2->data, silc_buffer_len(sb1)) == 0;
1536 /****f* silcutil/SilcBufferAPI/silc_buffer_memcmp
1541 * SilcBool silc_buffer_memcmp(SilcBuffer buffer,
1542 * const unsigned char *data,
1543 * SilcUInt32 data_len)
1547 * Compares the data area of the buffer with the `data'. Returns TRUE
1548 * if the data area is identical to `data' or FALSE if they differ.
1553 SilcBool silc_buffer_memcmp(SilcBuffer buffer, const unsigned char *data,
1554 SilcUInt32 data_len)
1556 if (silc_buffer_len(buffer) != data_len)
1558 return memcmp(buffer->data, data, data_len) == 0;
1561 /****f* silcutil/SilcBufferAPI/silc_buffer_printf
1566 * void silc_buffer_printf(SilcBuffer sb, SilcBool newline);
1570 * Prints the current data area of `sb' into stdout. If `newline' is
1571 * TRUE prints '\n' after the data in the buffer.
1576 void silc_buffer_printf(SilcBuffer sb, SilcBool newline)
1578 silc_file_write(1, silc_buffer_data(sb), silc_buffer_len(sb));
1584 #endif /* SILCBUFFER_H */