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.
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_datalen
142 * #define silc_buffer_datalen ...
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.
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));
158 #define silc_buffer_datalen(x) (x) ? silc_buffer_data((x)) : NULL, \
159 (x) ? silc_buffer_len((x)) : 0
162 /* Inline functions */
164 /****d* silcutil/SilcBufferAPI/silc_buffer_truelen
168 * SilcUInt32 silc_buffer_truelen(SilcBuffer sb)
172 * Returns the true length of the buffer.
176 SilcUInt32 silc_buffer_truelen(SilcBuffer x)
178 return (SilcUInt32)(x->end - x->head);
181 /****d* silcutil/SilcBufferAPI/silc_buffer_len
185 * SilcUInt32 silc_buffer_len(SilcBuffer sb)
189 * Returns the current length of the data area of the buffer.
193 SilcUInt32 silc_buffer_len(SilcBuffer x)
195 return (SilcUInt32)(x->tail - x->data);
198 /****d* silcutil/SilcBufferAPI/silc_buffer_headlen
202 * SilcUInt32 silc_buffer_headlen(SilcBuffer sb)
206 * Returns the current length of the head data area of the buffer.
210 SilcUInt32 silc_buffer_headlen(SilcBuffer x)
212 return (SilcUInt32)(x->data - x->head);
215 /****d* silcutil/SilcBufferAPI/silc_buffer_taillen
219 * SilcUInt32 silc_buffer_taillen(SilcBuffer sb)
223 * Returns the current length of the tail data area of the buffer.
227 SilcUInt32 silc_buffer_taillen(SilcBuffer x)
229 return (SilcUInt32)(x->end - x->tail);
232 /****f* silcutil/SilcBufferAPI/silc_buffer_alloc
237 * SilcBuffer silc_buffer_alloc(SilcUInt32 len);
241 * Allocates new SilcBuffer and returns it. Returns NULL if system is
247 SilcBuffer silc_buffer_alloc(SilcUInt32 len)
251 /* Allocate new SilcBuffer */
252 sb = (SilcBuffer)silc_calloc(1, sizeof(*sb));
253 if (silc_unlikely(!sb))
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))
262 /* Set pointers to the new buffer */
265 sb->end = sb->head + len;
271 /****f* silcutil/SilcBufferAPI/silc_buffer_salloc
276 * SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len);
280 * Allocates new SilcBuffer and returns it. Returns NULL if system is
283 * This routine use SilcStack are memory source. If `stack' is NULL
284 * reverts back to normal allocating routine.
286 * Note that this call consumes the `stack'. The caller should push the
287 * stack before calling the function and pop it later.
292 SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len)
297 return silc_buffer_alloc(len);
299 /* Allocate new SilcBuffer */
300 sb = (SilcBuffer)silc_scalloc(stack, 1, sizeof(*sb));
301 if (silc_unlikely(!sb))
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))
310 /* Set pointers to the new buffer */
313 sb->end = sb->head + len;
319 /****f* silcutil/SilcBufferAPI/silc_buffer_free
324 * void silc_buffer_free(SilcBuffer sb);
328 * Frees SilcBuffer. Can be called safely `sb' as NULL.
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.
339 void silc_buffer_free(SilcBuffer sb)
342 #if defined(SILC_DEBUG)
344 memset(sb->head, 'F', silc_buffer_truelen(sb));
351 /****f* silcutil/SilcBufferAPI/silc_buffer_sfree
356 * void silc_buffer_free(SilcStack stack, SilcBuffer sb);
360 * Frees SilcBuffer. If `stack' is NULL this calls silc_buffer_free. Can
361 * be called safely `sb' as NULL.
366 void silc_buffer_sfree(SilcStack stack, SilcBuffer sb)
372 memset(sb->head, 'F', silc_buffer_truelen(sb));
373 memset(sb, 'F', sizeof(*sb));
375 #endif /* SILC_DEBUG */
379 silc_buffer_free(sb);
382 /****f* silcutil/SilcBufferAPI/silc_buffer_steal
387 * unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len);
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
401 unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len)
403 unsigned char *buf = sb->head;
405 *data_len = silc_buffer_truelen(sb);
406 sb->head = sb->data = sb->tail = sb->end = NULL;
410 /****f* silcutil/SilcBufferAPI/silc_buffer_purge
415 * void silc_buffer_purge(SilcBuffer sb);
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.
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.
432 void silc_buffer_purge(SilcBuffer sb)
434 silc_free(silc_buffer_steal(sb, NULL));
437 /****f* silcutil/SilcBufferAPI/silc_buffer_spurge
442 * void silc_buffer_spurge(SilcStack stack, SilcBuffer sb);
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.
454 void silc_buffer_spurge(SilcStack stack, SilcBuffer sb)
459 memset(silc_buffer_steal(sb, NULL), 'F', silc_buffer_truelen(sb));
460 #endif /* SILC_DEBUG */
464 silc_buffer_purge(sb);
467 /****f* silcutil/SilcBufferAPI/silc_buffer_set
472 * void silc_buffer_set(SilcBuffer sb,
473 * unsigned char *data,
474 * SilcUInt32 data_len);
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.
485 * SilcBufferStruct buf;
486 * silc_buffer_set(&buf, data, data_len);
491 void silc_buffer_set(SilcBuffer sb, unsigned char *data, SilcUInt32 data_len)
493 sb->data = sb->head = data;
494 sb->tail = sb->end = data + data_len;
497 /****f* silcutil/SilcBufferAPI/silc_buffer_pull
502 * unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len);
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.
513 * ---------------------------------
514 * | head | data | tail |
515 * ---------------------------------
517 * Pulls the start of the data area.
519 * ---------------------------------
520 * | head | data | tail |
521 * ---------------------------------
524 * silc_buffer_pull(sb, 20);
529 unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len)
531 unsigned char *old_data = sb->data;
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);
545 /****f* silcutil/SilcBufferAPI/silc_buffer_push
550 * unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len);
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.
561 * ---------------------------------
562 * | head | data | tail |
563 * ---------------------------------
565 * Pushes the start of the data area.
567 * ---------------------------------
568 * | head | data | tail |
569 * ---------------------------------
572 * silc_buffer_push(sb, 20);
577 unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len)
579 unsigned char *old_data = sb->data;
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);
593 /****f* silcutil/SilcBufferAPI/silc_buffer_pull_tail
598 * unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len);
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.
608 * ---------------------------------
609 * | head | data | tail |
610 * ---------------------------------
612 * Pulls the start of the tail section.
614 * ---------------------------------
615 * | head | data | tail |
616 * ---------------------------------
619 * silc_buffer_pull_tail(sb, 23);
624 unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len)
626 unsigned char *old_tail = sb->tail;
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);
640 /****f* silcutil/SilcBufferAPI/silc_buffer_push_tail
645 * unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len);
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.
656 * ---------------------------------
657 * | head | data | tail |
658 * ---------------------------------
660 * Pushes the start of the tail section.
662 * ---------------------------------
663 * | head | data | tail |
664 * ---------------------------------
667 * silc_buffer_push_tail(sb, 23);
672 unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len)
674 unsigned char *old_tail = sb->tail;
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);
688 /****f* silcutil/SilcBufferAPI/silc_buffer_put_head
693 * unsigned char *silc_buffer_put_head(SilcBuffer sb,
694 * const unsigned char *data,
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
705 * ---------------------------------
706 * | head | data | tail |
707 * ---------------------------------
709 * Puts data to the head section.
711 * silc_buffer_put_head(sb, data, data_len);
716 unsigned char *silc_buffer_put_head(SilcBuffer sb,
717 const unsigned char *data,
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);
728 if (sb->head > data) {
729 if (sb->head - data <= len)
730 return (unsigned char *)memmove(sb->head, data, len);
732 if (data - sb->head <= len)
733 return (unsigned char *)memmove(sb->head, data, len);
736 return (unsigned char *)memcpy(sb->head, data, len);
739 /****f* silcutil/SilcBufferAPI/silc_buffer_put
744 * unsigned char *silc_buffer_put(SilcBuffer sb,
745 * const unsigned char *data,
750 * Puts data at the start of the valid data area. Returns a pointer
751 * to the copied data area. Returns NULL if the data is longer than the
756 * ---------------------------------
757 * | head | data | tail |
758 * ---------------------------------
760 * Puts data to the data section.
762 * silc_buffer_put(sb, data, data_len);
767 unsigned char *silc_buffer_put(SilcBuffer sb,
768 const unsigned char *data,
771 #ifdef SILC_DIST_INPLACE
772 SILC_ASSERT(len <= silc_buffer_len(sb));
773 #endif /* SILC_DIST_INPLACE */
774 if (silc_unlikely(len > silc_buffer_len(sb))) {
775 silc_set_errno(SILC_ERR_OVERFLOW);
779 if (sb->data > data) {
780 if (sb->data - data <= len)
781 return (unsigned char *)memmove(sb->data, data, len);
783 if (data - sb->data <= len)
784 return (unsigned char *)memmove(sb->data, data, len);
787 return (unsigned char *)memcpy(sb->data, data, len);
790 /****f* silcutil/SilcBufferAPI/silc_buffer_put_tail
795 * unsigned char *silc_buffer_put_tail(SilcBuffer sb,
796 * const unsigned char *data,
801 * Puts data at the tail of the buffer. Returns pointer to the copied
802 * data area. Returns NULL if the data is longer than the current tail
807 * ---------------------------------
808 * | head | data | tail |
809 * ---------------------------------
811 * Puts data to the tail section.
813 * silc_buffer_put_tail(sb, data, data_len);
818 unsigned char *silc_buffer_put_tail(SilcBuffer sb,
819 const unsigned char *data,
822 #ifdef SILC_DIST_INPLACE
823 SILC_ASSERT(len <= silc_buffer_taillen(sb));
824 #endif /* SILC_DIST_INPLACE */
825 if (silc_unlikely(len > silc_buffer_taillen(sb))) {
826 silc_set_errno(SILC_ERR_OVERFLOW);
830 if (sb->tail > data) {
831 if (sb->tail - data <= len)
832 return (unsigned char *)memmove(sb->tail, data, len);
834 if (data - sb->tail <= len)
835 return (unsigned char *)memmove(sb->tail, data, len);
838 return (unsigned char *)memcpy(sb->tail, data, len);
841 /****f* silcutil/SilcBufferAPI/silc_buffer_alloc_size
846 * SilcBuffer silc_buffer_alloc_size(SilcUInt32 len);
850 * Allocates `len' bytes size buffer and moves the tail area automatically
851 * `len' bytes so that the buffer is ready to use without calling the
852 * silc_buffer_pull_tail. Returns NULL if system is out of memory.
857 SilcBuffer silc_buffer_alloc_size(SilcUInt32 len)
859 SilcBuffer sb = silc_buffer_alloc(len);
860 if (silc_unlikely(!sb))
862 silc_buffer_pull_tail(sb, len);
866 /****f* silcutil/SilcBufferAPI/silc_buffer_salloc_size
871 * SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len);
875 * Allocates `len' bytes size buffer and moves the tail area automatically
876 * `len' bytes so that the buffer is ready to use without calling the
877 * silc_buffer_pull_tail. Returns NULL if system is out of memory.
879 * This routine use SilcStack are memory source. If `stack' is NULL
880 * reverts back to normal allocating routine.
882 * Note that this call consumes the `stack'. The caller should push the
883 * stack before calling the function and pop it later.
888 SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len)
890 SilcBuffer sb = silc_buffer_salloc(stack, len);
891 if (silc_unlikely(!sb))
893 silc_buffer_pull_tail(sb, len);
897 /****f* silcutil/SilcBufferAPI/silc_buffer_reset
902 * void silc_buffer_reset(SilcBuffer sb);
906 * Resets the buffer to the state as if it was just allocated by
907 * silc_buffer_alloc. This does not clear the data area. Use
908 * silc_buffer_clear if you also want to clear the data area.
913 void silc_buffer_reset(SilcBuffer sb)
915 sb->data = sb->tail = sb->head;
918 /****f* silcutil/SilcBufferAPI/silc_buffer_clear
923 * void silc_buffer_clear(SilcBuffer sb);
927 * Clears and initialiazes the buffer to the state as if it was just
928 * allocated by silc_buffer_alloc.
933 void silc_buffer_clear(SilcBuffer sb)
935 memset(sb->head, 0, silc_buffer_truelen(sb));
936 silc_buffer_reset(sb);
939 /****f* silcutil/SilcBufferAPI/silc_buffer_start
944 * void silc_buffer_start(SilcBuffer sb);
948 * Moves the data area at the start of the buffer. The tail area remains
954 void silc_buffer_start(SilcBuffer sb)
959 /****f* silcutil/SilcBufferAPI/silc_buffer_end
964 * void silc_buffer_end(SilcBuffer sb);
968 * Moves the end of the data area to the end of the buffer. The start
969 * of the data area remains same. If the start of data area is at the
970 * start of the buffer, after this function returns the buffer's data
971 * area length is the length of the entire buffer.
976 void silc_buffer_end(SilcBuffer sb)
981 /****f* silcutil/SilcBufferAPI/silc_buffer_copy
986 * SilcBuffer silc_buffer_copy(SilcBuffer sb);
990 * Generates copy of a SilcBuffer. This copies everything inside the
991 * currently valid data area, nothing more. Use silc_buffer_clone to
992 * copy entire buffer. Returns NULL if system is out of memory.
997 SilcBuffer silc_buffer_copy(SilcBuffer sb)
1001 sb_new = silc_buffer_alloc_size(silc_buffer_len(sb));
1002 if (silc_unlikely(!sb_new))
1004 silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
1009 /****f* silcutil/SilcBufferAPI/silc_buffer_scopy
1014 * SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb);
1018 * Generates copy of a SilcBuffer. This copies everything inside the
1019 * currently valid data area, nothing more. Use silc_buffer_clone to
1020 * copy entire buffer. Returns NULL if system is out of memory.
1022 * This routine use SilcStack are memory source. If `stack' is NULL
1023 * reverts back to normal allocating routine.
1025 * Note that this call consumes the `stack'. The caller should push the
1026 * stack before calling the function and pop it later.
1031 SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb)
1035 sb_new = silc_buffer_salloc_size(stack, silc_buffer_len(sb));
1036 if (silc_unlikely(!sb_new))
1038 silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
1043 /****f* silcutil/SilcBufferAPI/silc_buffer_clone
1048 * SilcBuffer silc_buffer_clone(SilcBuffer sb);
1052 * Clones SilcBuffer. This generates new SilcBuffer and copies
1053 * everything from the source buffer. The result is exact clone of
1054 * the original buffer. Returns NULL if system is out of memory.
1059 SilcBuffer silc_buffer_clone(SilcBuffer sb)
1063 sb_new = silc_buffer_alloc_size(silc_buffer_truelen(sb));
1064 if (silc_unlikely(!sb_new))
1066 silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
1067 sb_new->data = sb_new->head + silc_buffer_headlen(sb);
1068 sb_new->tail = sb_new->data + silc_buffer_len(sb);
1073 /****f* silcutil/SilcBufferAPI/silc_buffer_sclone
1078 * SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb);
1082 * Clones SilcBuffer. This generates new SilcBuffer and copies
1083 * everything from the source buffer. The result is exact clone of
1084 * the original buffer. Returns NULL if system is out of memory.
1086 * This routine use SilcStack are memory source. If `stack' is NULL
1087 * reverts back to normal allocating routine.
1089 * Note that this call consumes the `stack'. The caller should push the
1090 * stack before calling the function and pop it later.
1095 SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb)
1099 sb_new = silc_buffer_salloc_size(stack, silc_buffer_truelen(sb));
1100 if (silc_unlikely(!sb_new))
1102 silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
1103 sb_new->data = sb_new->head + silc_buffer_headlen(sb);
1104 sb_new->tail = sb_new->data + silc_buffer_len(sb);
1109 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc
1114 * SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize);
1118 * Reallocates buffer. Old data is saved into the new buffer. The buffer
1119 * is exact clone of the old one except that there is now more space
1120 * at the end of buffer. This always returns the same `sb' unless `sb'
1121 * was NULL. Returns NULL if system is out of memory.
1126 SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize)
1128 SilcUInt32 hlen, dlen;
1132 return silc_buffer_alloc(newsize);
1134 if (silc_unlikely(newsize <= silc_buffer_truelen(sb)))
1137 hlen = silc_buffer_headlen(sb);
1138 dlen = silc_buffer_len(sb);
1139 h = (unsigned char *)silc_realloc(sb->head, newsize);
1140 if (silc_unlikely(!h))
1143 sb->data = sb->head + hlen;
1144 sb->tail = sb->data + dlen;
1145 sb->end = sb->head + newsize;
1150 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc
1155 * SilcBuffer silc_buffer_srealloc(SilcStack stack,
1156 * SilcBuffer sb, SilcUInt32 newsize);
1160 * Reallocates buffer. Old data is saved into the new buffer. The buffer
1161 * is exact clone of the old one except that there is now more space
1162 * at the end of buffer. Returns NULL if system is out of memory.
1164 * This routine use SilcStack are memory source. If `stack' is NULL
1165 * reverts back to normal allocating routine.
1167 * Note that this call consumes the `stack'. The caller should push the
1168 * stack before calling the function and pop it later.
1173 SilcBuffer silc_buffer_srealloc(SilcStack stack,
1174 SilcBuffer sb, SilcUInt32 newsize)
1176 SilcUInt32 hlen, dlen;
1180 return silc_buffer_realloc(sb, newsize);
1183 return silc_buffer_salloc(stack, newsize);
1185 if (newsize <= silc_buffer_truelen(sb))
1188 hlen = silc_buffer_headlen(sb);
1189 dlen = silc_buffer_len(sb);
1190 h = (unsigned char *)silc_srealloc(stack, silc_buffer_truelen(sb),
1196 sb->data = sb->head + hlen;
1197 sb->tail = sb->data + dlen;
1198 sb->end = sb->head + newsize;
1203 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc_size
1208 * SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize);
1212 * Same as silc_buffer_realloc but moves moves the tail area
1213 * automatically so that the buffer is ready to use without calling the
1214 * silc_buffer_pull_tail. Returns NULL if system is out of memory.
1219 SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize)
1221 sb = silc_buffer_realloc(sb, newsize);
1222 if (silc_unlikely(!sb))
1224 silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
1228 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc_size
1233 * SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
1234 * SilcBuffer sb, SilcUInt32 newsize);
1238 * Same as silc_buffer_srealloc 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.
1242 * This routine use SilcStack are memory source. If `stack' is NULL
1243 * reverts back to normal allocating routine.
1245 * Note that this call consumes the `stack'. The caller should push the
1246 * stack before calling the function and pop it later.
1251 SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
1252 SilcBuffer sb, SilcUInt32 newsize)
1254 sb = silc_buffer_srealloc(stack, sb, newsize);
1255 if (silc_unlikely(!sb))
1257 silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
1261 /****f* silcutil/SilcBufferAPI/silc_buffer_enlarge
1266 * SilcBuffer silc_buffer_enlarge(SilcBuffer sb, SilcUInt32 size);
1270 * Enlarges the buffer by the amount of `size' if it doesn't have that
1271 * must space in the data area and in the tail area. Moves the tail
1272 * area automatically after enlarging so that the current data area
1273 * is at least the size of `size'. If there is more space than `size'
1274 * in the data area this does not do anything. If there is enough
1275 * space in the tail area this merely moves the tail area to reveal
1276 * the extra space. Returns FALSE if system is out of memory.
1281 SilcBool silc_buffer_enlarge(SilcBuffer sb, SilcUInt32 size)
1283 if (size > silc_buffer_len(sb)) {
1284 if (size > silc_buffer_taillen(sb) + silc_buffer_len(sb))
1285 if (silc_unlikely(!silc_buffer_realloc(sb, silc_buffer_truelen(sb) +
1286 (size - silc_buffer_taillen(sb) -
1287 silc_buffer_len(sb)))))
1289 silc_buffer_pull_tail(sb, size - silc_buffer_len(sb));
1294 /****f* silcutil/SilcBufferAPI/silc_buffer_senlarge
1299 * SilcBuffer silc_buffer_senlarge(SilcStack stack, SilcBuffer sb,
1304 * Enlarges the buffer by the amount of `size' if it doesn't have that
1305 * must space in the data area and in the tail area. Moves the tail
1306 * area automatically after enlarging so that the current data area
1307 * is at least the size of `size'. If there is more space than `size'
1308 * in the data area this does not do anything. If there is enough
1309 * space in the tail area this merely moves the tail area to reveal
1310 * the extra space. Returns FALSE if system is out of memory.
1312 * This routine use SilcStack are memory source. If `stack' is NULL
1313 * reverts back to normal allocating routine.
1315 * Note that this call consumes the `stack'. The caller should push the
1316 * stack before calling the function and pop it later.
1321 SilcBool silc_buffer_senlarge(SilcStack stack, SilcBuffer sb, SilcUInt32 size)
1323 if (size > silc_buffer_len(sb)) {
1324 if (size > silc_buffer_taillen(sb) + silc_buffer_len(sb))
1325 if (silc_unlikely(!silc_buffer_srealloc(stack, sb,
1326 silc_buffer_truelen(sb) +
1327 (size - silc_buffer_taillen(sb) -
1328 silc_buffer_len(sb)))))
1330 silc_buffer_pull_tail(sb, size - silc_buffer_len(sb));
1335 /****f* silcutil/SilcBufferAPI/silc_buffer_append
1340 * SilcBuffer silc_buffer_append(SilcBuffer sb, SilcUInt32 size);
1344 * Appends the current data area by the amount of `size'. The tail area
1345 * of the buffer remains intact and contains the same data than the old
1346 * tail area (the data is copied to the new tail area). After appending
1347 * there is now `size' bytes more free area in the data area. Returns
1348 * FALSE if system is out of memory.
1353 * ---------------------------------
1354 * | head | data | tail |
1355 * ---------------------------------
1358 * ------------------------------------
1359 * | head | data | tail |
1360 * -------------------------------------
1362 * silc_buffer_append(sb, 5);
1367 SilcBool silc_buffer_append(SilcBuffer sb, SilcUInt32 size)
1369 if (silc_unlikely(!silc_buffer_realloc(sb, silc_buffer_truelen(sb) + size)))
1372 /* Enlarge data area */
1373 silc_buffer_pull_tail(sb, size);
1375 /* Copy old tail area to new tail area */
1376 silc_buffer_put_tail(sb, sb->tail - size, silc_buffer_taillen(sb));
1381 /****f* silcutil/SilcBufferAPI/silc_buffer_append
1386 * SilcBool silc_buffer_sappend(SilcStack stack, SilcBuffer sb,
1391 * Appends the current data area by the amount of `size'. The tail area
1392 * of the buffer remains intact and contains the same data than the old
1393 * tail area (the data is copied to the new tail area). After appending
1394 * there is now `size' bytes more free area in the data area. Returns
1395 * FALSE if system is out of memory.
1397 * This routine use SilcStack are memory source. If `stack' is NULL
1398 * reverts back to normal allocating routine.
1400 * Note that this call consumes the `stack'. The caller should push the
1401 * stack before calling the function and pop it later.
1406 * ---------------------------------
1407 * | head | data | tail |
1408 * ---------------------------------
1411 * ------------------------------------
1412 * | head | data | tail |
1413 * -------------------------------------
1415 * silc_buffer_append(sb, 5);
1420 SilcBool silc_buffer_sappend(SilcStack stack, SilcBuffer sb, SilcUInt32 size)
1422 if (silc_unlikely(!silc_buffer_srealloc(stack, sb,
1423 silc_buffer_truelen(sb) + size)))
1426 /* Enlarge data area */
1427 silc_buffer_pull_tail(sb, size);
1429 /* Copy old tail area to new tail area */
1430 silc_buffer_put_tail(sb, sb->tail - size, silc_buffer_taillen(sb));
1435 /****f* silcutil/SilcBufferAPI/silc_buffer_strchr
1440 * unsigned char *silc_buffer_strchr(SilcBuffer sb, int c, SilcBool first);
1444 * Returns pointer to the occurence of the character `c' in the buffer
1445 * `sb'. If the `first' is TRUE this finds the first occurene of `c',
1446 * if it is FALSE this finds the last occurence of `c'. If the character
1447 * is found the `sb' data area is moved to that location and its pointer
1448 * is returned. The silc_buffer_data call will return the same pointer.
1449 * Returns NULL if such character could not be located and the buffer
1450 * remains unmodified.
1452 * This call is equivalent to strchr(), strrchr(), memchr() and memrchr()
1453 * except it works with SilcBuffer.
1457 * This searches only the data area of the buffer. Head and tail area
1460 * The `sb' data need not be NULL terminated.
1465 unsigned char *silc_buffer_strchr(SilcBuffer sb, int c, SilcBool first)
1470 for (i = 0; i < silc_buffer_len(sb); i++) {
1471 if (sb->data[i] == (unsigned char)c) {
1472 sb->data = &sb->data[i];
1477 for (i = silc_buffer_len(sb) - 1; 1 >= 0; i--) {
1478 if (sb->data[i] == (unsigned char)c) {
1479 sb->data = &sb->data[i];
1488 /****f* silcutil/SilcBufferAPI/silc_buffer_cmp
1493 * SilcBool silc_buffer_equal(SilcBuffer sb1, SilcBuffer sb2)
1497 * Compares if the data area of the buffer `sb1' and `sb2' are identical.
1498 * Returns TRUE if they match and FALSE if they differ.
1503 SilcBool silc_buffer_equal(SilcBuffer sb1, SilcBuffer sb2)
1505 if (silc_buffer_len(sb1) != silc_buffer_len(sb2))
1507 return memcmp(sb1->data, sb2->data, silc_buffer_len(sb1)) == 0;
1510 /****f* silcutil/SilcBufferAPI/silc_buffer_printf
1515 * void silc_buffer_printf(SilcBuffer sb, SilcBool newline);
1519 * Prints the current data area of `sb' into stdout. If `newline' is
1520 * TRUE prints '\n' after the data in the buffer.
1525 void silc_buffer_printf(SilcBuffer sb, SilcBool newline)
1527 silc_file_write(1, silc_buffer_data(sb), silc_buffer_len(sb));
1533 #endif /* SILCBUFFER_H */