5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1998 - 2007 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 on error.
246 SilcBuffer silc_buffer_alloc(SilcUInt32 len)
250 /* Allocate new SilcBuffer */
251 sb = (SilcBuffer)silc_calloc(1, sizeof(*sb));
252 if (silc_unlikely(!sb))
255 if (silc_likely(len)) {
256 /* Allocate the actual data area */
257 sb->head = (unsigned char *)silc_malloc(len * sizeof(*sb->head));
258 if (silc_unlikely(!sb->head))
261 /* Set pointers to the new buffer */
264 sb->end = sb->head + len;
270 /****f* silcutil/SilcBufferAPI/silc_buffer_salloc
275 * SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len);
279 * Allocates new SilcBuffer and returns it.
281 * This routine use SilcStack are memory source. If `stack' is NULL
282 * reverts back to normal allocating routine.
284 * Note that this call consumes the `stack'. The caller should push the
285 * stack before calling the function and pop it later.
290 SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len)
295 return silc_buffer_alloc(len);
297 /* Allocate new SilcBuffer */
298 sb = (SilcBuffer)silc_scalloc(stack, 1, sizeof(*sb));
299 if (silc_unlikely(!sb))
302 if (silc_likely(len)) {
303 /* Allocate the actual data area */
304 sb->head = (unsigned char *)silc_smalloc(stack, len * sizeof(*sb->head));
305 if (silc_unlikely(!sb->head))
308 /* Set pointers to the new buffer */
311 sb->end = sb->head + len;
317 /****f* silcutil/SilcBufferAPI/silc_buffer_free
322 * void silc_buffer_free(SilcBuffer sb);
326 * Frees SilcBuffer. Can be called safely `sb' as NULL.
330 * Must not be called for buffers allocated with silc_buffer_salloc,
331 * silc_buffer_salloc_size, silc_buffer_scopy and silc_buffer_sclone.
332 * Call silc_buffer_sfree instead.
337 void silc_buffer_free(SilcBuffer sb)
340 #if defined(SILC_DEBUG)
342 memset(sb->head, 'F', silc_buffer_truelen(sb));
349 /****f* silcutil/SilcBufferAPI/silc_buffer_sfree
354 * void silc_buffer_free(SilcStack stack, SilcBuffer sb);
358 * Frees SilcBuffer. If `stack' is NULL this calls silc_buffer_free. Can
359 * be called safely `sb' as NULL.
364 void silc_buffer_sfree(SilcStack stack, SilcBuffer sb)
370 memset(sb->head, 'F', silc_buffer_truelen(sb));
371 memset(sb, 'F', sizeof(*sb));
373 #endif /* SILC_DEBUG */
377 silc_buffer_free(sb);
380 /****f* silcutil/SilcBufferAPI/silc_buffer_steal
385 * unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len);
389 * Steals the data from the buffer `sb'. This returns pointer to the
390 * start of the buffer and the true length of that buffer. The `sb'
391 * cannot be used anymore after calling this function because the
392 * data buffer was stolen. The `sb' must be freed with silc_buffer_free.
393 * The caller is responsible of freeing the stolen data buffer with
399 unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len)
401 unsigned char *buf = sb->head;
403 *data_len = silc_buffer_truelen(sb);
404 sb->head = sb->data = sb->tail = sb->end = NULL;
408 /****f* silcutil/SilcBufferAPI/silc_buffer_purge
413 * void silc_buffer_purge(SilcBuffer sb);
417 * Same as silc_buffer_free but free's only the contents of the buffer
418 * not the buffer itself. The `sb' remains intact, data is freed. Buffer
419 * is ready for re-use after calling this function.
423 * Must not be called for buffers allocated with silc_buffer_salloc,
424 * silc_buffer_salloc_size, silc_buffer_scopy and silc_buffer_sclone.
425 * Use silc_buffer_spurge instead.
430 void silc_buffer_purge(SilcBuffer sb)
432 silc_free(silc_buffer_steal(sb, NULL));
435 /****f* silcutil/SilcBufferAPI/silc_buffer_spurge
440 * void silc_buffer_spurge(SilcStack stack, SilcBuffer sb);
444 * Same as silc_buffer_free but free's only the contents of the buffer
445 * not the buffer itself. The `sb' remains intact, data is freed. Buffer
446 * is ready for re-use after calling this function. If `stack' is NULL
447 * this calls silc_buffer_purge.
452 void silc_buffer_spurge(SilcStack stack, SilcBuffer sb)
457 memset(silc_buffer_steal(sb, NULL), 'F', silc_buffer_truelen(sb));
458 #endif /* SILC_DEBUG */
462 silc_buffer_purge(sb);
465 /****f* silcutil/SilcBufferAPI/silc_buffer_set
470 * void silc_buffer_set(SilcBuffer sb,
471 * unsigned char *data,
472 * SilcUInt32 data_len);
476 * Sets the `data' and `data_len' to the buffer pointer sent as argument.
477 * The data area is automatically set to the `data_len'. This function
478 * can be used to set the data to static buffer without needing any
479 * memory allocations. The `data' will not be copied to the buffer.
483 * SilcBufferStruct buf;
484 * silc_buffer_set(&buf, data, data_len);
489 void silc_buffer_set(SilcBuffer sb, unsigned char *data, SilcUInt32 data_len)
491 sb->data = sb->head = data;
492 sb->tail = sb->end = data + data_len;
495 /****f* silcutil/SilcBufferAPI/silc_buffer_pull
500 * unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len);
504 * Pulls current data area towards end. The length of the currently
505 * valid data area is also decremented. Returns pointer to the data
506 * area before pulling. Returns NULL on error.
510 * ---------------------------------
511 * | head | data | tail |
512 * ---------------------------------
514 * Pulls the start of the data area.
516 * ---------------------------------
517 * | head | data | tail |
518 * ---------------------------------
521 * silc_buffer_pull(sb, 20);
526 unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len)
528 unsigned char *old_data = sb->data;
530 #ifdef SILC_DIST_INPLACE
531 SILC_ASSERT(len <= silc_buffer_len(sb));
532 #endif /* SILC_DIST_INPLACE */
533 if (silc_unlikely(len > silc_buffer_len(sb)))
540 /****f* silcutil/SilcBufferAPI/silc_buffer_push
545 * unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len);
549 * Pushes current data area towards beginning. Length of the currently
550 * valid data area is also incremented. Returns a pointer to the
551 * data area before pushing. Returns NULL on error.
555 * ---------------------------------
556 * | head | data | tail |
557 * ---------------------------------
559 * Pushes the start of the data area.
561 * ---------------------------------
562 * | head | data | tail |
563 * ---------------------------------
566 * silc_buffer_push(sb, 20);
571 unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len)
573 unsigned char *old_data = sb->data;
575 #ifdef SILC_DIST_INPLACE
576 SILC_ASSERT((sb->data - len) >= sb->head);
577 #endif /* SILC_DIST_INPLACE */
578 if (silc_unlikely((sb->data - len) < sb->head))
585 /****f* silcutil/SilcBufferAPI/silc_buffer_pull_tail
590 * unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len);
594 * Pulls current tail section towards end. Length of the current valid
595 * data area is also incremented. Returns a pointer to the data area
596 * before pulling. Returns NULL on error.
600 * ---------------------------------
601 * | head | data | tail |
602 * ---------------------------------
604 * Pulls the start of the tail section.
606 * ---------------------------------
607 * | head | data | tail |
608 * ---------------------------------
611 * silc_buffer_pull_tail(sb, 23);
616 unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len)
618 unsigned char *old_tail = sb->tail;
620 #ifdef SILC_DIST_INPLACE
621 SILC_ASSERT(len <= silc_buffer_taillen(sb));
622 #endif /* SILC_DIST_INPLACE */
623 if (silc_unlikely(len > silc_buffer_taillen(sb)))
630 /****f* silcutil/SilcBufferAPI/silc_buffer_push_tail
635 * unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len);
639 * Pushes current tail section towards beginning. Length of the current
640 * valid data area is also decremented. Returns a pointer to the
641 * tail section before pushing. Returns NULL on error.
645 * ---------------------------------
646 * | head | data | tail |
647 * ---------------------------------
649 * Pushes the start of the tail section.
651 * ---------------------------------
652 * | head | data | tail |
653 * ---------------------------------
656 * silc_buffer_push_tail(sb, 23);
661 unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len)
663 unsigned char *old_tail = sb->tail;
665 #ifdef SILC_DIST_INPLACE
666 SILC_ASSERT((sb->tail - len) >= sb->data);
667 #endif /* SILC_DIST_INPLACE */
668 if (silc_unlikely((sb->tail - len) < sb->data))
675 /****f* silcutil/SilcBufferAPI/silc_buffer_put_head
680 * unsigned char *silc_buffer_put_head(SilcBuffer sb,
681 * const unsigned char *data,
686 * Puts data at the head of the buffer. Returns pointer to the copied
687 * data area. Returns NULL on error.
691 * ---------------------------------
692 * | head | data | tail |
693 * ---------------------------------
695 * Puts data to the head section.
697 * silc_buffer_put_head(sb, data, data_len);
702 unsigned char *silc_buffer_put_head(SilcBuffer sb,
703 const unsigned char *data,
706 #ifdef SILC_DIST_INPLACE
707 SILC_ASSERT(len <= silc_buffer_headlen(sb));
708 #endif /* SILC_DIST_INPLACE */
709 if (silc_unlikely(len > silc_buffer_headlen(sb)))
712 return (unsigned char *)memcpy(sb->head, data, len);
715 /****f* silcutil/SilcBufferAPI/silc_buffer_put
720 * unsigned char *silc_buffer_put(SilcBuffer sb,
721 * const unsigned char *data,
726 * Puts data at the start of the valid data area. Returns a pointer
727 * to the copied data area. Returns NULL on error.
731 * ---------------------------------
732 * | head | data | tail |
733 * ---------------------------------
735 * Puts data to the data section.
737 * silc_buffer_put(sb, data, data_len);
742 unsigned char *silc_buffer_put(SilcBuffer sb,
743 const unsigned char *data,
746 #ifdef SILC_DIST_INPLACE
747 SILC_ASSERT(len <= silc_buffer_len(sb));
748 #endif /* SILC_DIST_INPLACE */
749 if (silc_unlikely(len > silc_buffer_len(sb)))
752 return (unsigned char *)memcpy(sb->data, data, len);
755 /****f* silcutil/SilcBufferAPI/silc_buffer_put_tail
760 * unsigned char *silc_buffer_put_tail(SilcBuffer sb,
761 * const unsigned char *data,
766 * Puts data at the tail of the buffer. Returns pointer to the copied
767 * data area. Returns NULL on error.
771 * ---------------------------------
772 * | head | data | tail |
773 * ---------------------------------
775 * Puts data to the tail section.
777 * silc_buffer_put_tail(sb, data, data_len);
782 unsigned char *silc_buffer_put_tail(SilcBuffer sb,
783 const unsigned char *data,
786 #ifdef SILC_DIST_INPLACE
787 SILC_ASSERT(len <= silc_buffer_taillen(sb));
788 #endif /* SILC_DIST_INPLACE */
789 if (silc_unlikely(len > silc_buffer_taillen(sb)))
792 return (unsigned char *)memcpy(sb->tail, data, len);
795 /****f* silcutil/SilcBufferAPI/silc_buffer_alloc_size
800 * SilcBuffer silc_buffer_alloc_size(SilcUInt32 len);
804 * Allocates `len' bytes size buffer and moves the tail area automatically
805 * `len' bytes so that the buffer is ready to use without calling the
806 * silc_buffer_pull_tail. Returns NULL on error.
811 SilcBuffer silc_buffer_alloc_size(SilcUInt32 len)
813 SilcBuffer sb = silc_buffer_alloc(len);
814 if (silc_unlikely(!sb))
816 silc_buffer_pull_tail(sb, len);
820 /****f* silcutil/SilcBufferAPI/silc_buffer_salloc_size
825 * SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len);
829 * Allocates `len' bytes size buffer and moves the tail area automatically
830 * `len' bytes so that the buffer is ready to use without calling the
831 * silc_buffer_pull_tail.
833 * This routine use SilcStack are memory source. If `stack' is NULL
834 * reverts back to normal allocating routine.
836 * Note that this call consumes the `stack'. The caller should push the
837 * stack before calling the function and pop it later.
842 SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len)
844 SilcBuffer sb = silc_buffer_salloc(stack, len);
845 if (silc_unlikely(!sb))
847 silc_buffer_pull_tail(sb, len);
851 /****f* silcutil/SilcBufferAPI/silc_buffer_reset
856 * void silc_buffer_reset(SilcBuffer sb);
860 * Resets the buffer to the state as if it was just allocated by
861 * silc_buffer_alloc. This does not clear the data area. Use
862 * silc_buffer_clear if you also want to clear the data area.
867 void silc_buffer_reset(SilcBuffer sb)
869 sb->data = sb->tail = sb->head;
872 /****f* silcutil/SilcBufferAPI/silc_buffer_clear
877 * void silc_buffer_clear(SilcBuffer sb);
881 * Clears and initialiazes the buffer to the state as if it was just
882 * allocated by silc_buffer_alloc.
887 void silc_buffer_clear(SilcBuffer sb)
889 memset(sb->head, 0, silc_buffer_truelen(sb));
890 silc_buffer_reset(sb);
893 /****f* silcutil/SilcBufferAPI/silc_buffer_start
898 * void silc_buffer_start(SilcBuffer sb);
902 * Moves the data area at the start of the buffer. The tail area remains
908 void silc_buffer_start(SilcBuffer sb)
913 /****f* silcutil/SilcBufferAPI/silc_buffer_end
918 * void silc_buffer_end(SilcBuffer sb);
922 * Moves the end of the data area to the end of the buffer. The start
923 * of the data area remains same. If the start of data area is at the
924 * start of the buffer, after this function returns the buffer's data
925 * area length is the length of the entire buffer.
930 void silc_buffer_end(SilcBuffer sb)
935 /****f* silcutil/SilcBufferAPI/silc_buffer_copy
940 * SilcBuffer silc_buffer_copy(SilcBuffer sb);
944 * Generates copy of a SilcBuffer. This copies everything inside the
945 * currently valid data area, nothing more. Use silc_buffer_clone to
946 * copy entire buffer. Returns NULL on error.
951 SilcBuffer silc_buffer_copy(SilcBuffer sb)
955 sb_new = silc_buffer_alloc_size(silc_buffer_len(sb));
956 if (silc_unlikely(!sb_new))
958 silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
963 /****f* silcutil/SilcBufferAPI/silc_buffer_scopy
968 * SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb);
972 * Generates copy of a SilcBuffer. This copies everything inside the
973 * currently valid data area, nothing more. Use silc_buffer_clone to
974 * copy entire buffer.
976 * This routine use SilcStack are memory source. If `stack' is NULL
977 * reverts back to normal allocating routine.
979 * Note that this call consumes the `stack'. The caller should push the
980 * stack before calling the function and pop it later.
985 SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb)
989 sb_new = silc_buffer_salloc_size(stack, silc_buffer_len(sb));
990 if (silc_unlikely(!sb_new))
992 silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
997 /****f* silcutil/SilcBufferAPI/silc_buffer_clone
1002 * SilcBuffer silc_buffer_clone(SilcBuffer sb);
1006 * Clones SilcBuffer. This generates new SilcBuffer and copies
1007 * everything from the source buffer. The result is exact clone of
1008 * the original buffer. Returns NULL on error.
1013 SilcBuffer silc_buffer_clone(SilcBuffer sb)
1017 sb_new = silc_buffer_alloc_size(silc_buffer_truelen(sb));
1018 if (silc_unlikely(!sb_new))
1020 silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
1021 sb_new->data = sb_new->head + silc_buffer_headlen(sb);
1022 sb_new->tail = sb_new->data + silc_buffer_len(sb);
1027 /****f* silcutil/SilcBufferAPI/silc_buffer_sclone
1032 * SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb);
1036 * Clones SilcBuffer. This generates new SilcBuffer and copies
1037 * everything from the source buffer. The result is exact clone of
1038 * the original buffer.
1040 * This routine use SilcStack are memory source. If `stack' is NULL
1041 * reverts back to normal allocating routine.
1043 * Note that this call consumes the `stack'. The caller should push the
1044 * stack before calling the function and pop it later.
1049 SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb)
1053 sb_new = silc_buffer_salloc_size(stack, silc_buffer_truelen(sb));
1054 if (silc_unlikely(!sb_new))
1056 silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
1057 sb_new->data = sb_new->head + silc_buffer_headlen(sb);
1058 sb_new->tail = sb_new->data + silc_buffer_len(sb);
1063 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc
1068 * SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize);
1072 * Reallocates buffer. Old data is saved into the new buffer. The buffer
1073 * is exact clone of the old one except that there is now more space
1074 * at the end of buffer. This always returns the same `sb' unless `sb'
1075 * was NULL. Returns NULL on error.
1080 SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize)
1082 SilcUInt32 hlen, dlen;
1086 return silc_buffer_alloc(newsize);
1088 if (silc_unlikely(newsize <= silc_buffer_truelen(sb)))
1091 hlen = silc_buffer_headlen(sb);
1092 dlen = silc_buffer_len(sb);
1093 h = (unsigned char *)silc_realloc(sb->head, newsize);
1094 if (silc_unlikely(!h))
1097 sb->data = sb->head + hlen;
1098 sb->tail = sb->data + dlen;
1099 sb->end = sb->head + newsize;
1104 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc
1109 * SilcBuffer silc_buffer_srealloc(SilcStack stack,
1110 * SilcBuffer sb, SilcUInt32 newsize);
1114 * Reallocates buffer. Old data is saved into the new buffer. The buffer
1115 * is exact clone of the old one except that there is now more space
1116 * at the end of buffer.
1118 * This routine use SilcStack are memory source. If `stack' is NULL
1119 * reverts back to normal allocating routine.
1121 * Note that this call consumes the `stack'. The caller should push the
1122 * stack before calling the function and pop it later.
1127 SilcBuffer silc_buffer_srealloc(SilcStack stack,
1128 SilcBuffer sb, SilcUInt32 newsize)
1130 SilcUInt32 hlen, dlen;
1134 return silc_buffer_realloc(sb, newsize);
1137 return silc_buffer_salloc(stack, newsize);
1139 if (newsize <= silc_buffer_truelen(sb))
1142 hlen = silc_buffer_headlen(sb);
1143 dlen = silc_buffer_len(sb);
1144 h = (unsigned char *)silc_srealloc(stack, silc_buffer_truelen(sb),
1147 /* Do slow and stack wasting realloc. The old sb->head is lost and
1148 is freed eventually. */
1149 h = (unsigned char *)silc_smalloc(stack, newsize);
1150 if (silc_unlikely(!h))
1152 memcpy(h, sb->head, silc_buffer_truelen(sb));
1156 sb->data = sb->head + hlen;
1157 sb->tail = sb->data + dlen;
1158 sb->end = sb->head + newsize;
1163 /****f* silcutil/SilcBufferAPI/silc_buffer_realloc_size
1168 * SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize);
1172 * Same as silc_buffer_realloc but moves moves the tail area
1173 * automatically so that the buffer is ready to use without calling the
1174 * silc_buffer_pull_tail. Returns NULL on error.
1179 SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize)
1181 sb = silc_buffer_realloc(sb, newsize);
1182 if (silc_unlikely(!sb))
1184 silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
1188 /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc_size
1193 * SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
1194 * SilcBuffer sb, SilcUInt32 newsize);
1198 * Same as silc_buffer_srealloc but moves moves the tail area
1199 * automatically so that the buffer is ready to use without calling the
1200 * silc_buffer_pull_tail.
1202 * This routine use SilcStack are memory source. If `stack' is NULL
1203 * reverts back to normal allocating routine.
1205 * Note that this call consumes the `stack'. The caller should push the
1206 * stack before calling the function and pop it later.
1211 SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
1212 SilcBuffer sb, SilcUInt32 newsize)
1214 sb = silc_buffer_srealloc(stack, sb, newsize);
1215 if (silc_unlikely(!sb))
1217 silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
1221 /****f* silcutil/SilcBufferAPI/silc_buffer_enlarge
1226 * SilcBuffer silc_buffer_enlarge(SilcBuffer sb, SilcUInt32 size);
1230 * Enlarges the buffer by the amount of `size' if it doesn't have that
1231 * must space in the data area and in the tail area. Moves the tail
1232 * area automatically after enlarging so that the current data area
1233 * is at least the size of `size'. If there is more space than `size'
1234 * in the data area this does not do anything. If there is enough
1235 * space in the tail area this merely moves the tail area to reveal
1236 * the extra space. Returns FALSE on error.
1241 SilcBool silc_buffer_enlarge(SilcBuffer sb, SilcUInt32 size)
1243 if (size > silc_buffer_len(sb)) {
1244 if (size > silc_buffer_taillen(sb) + silc_buffer_len(sb))
1245 if (silc_unlikely(!silc_buffer_realloc(sb, silc_buffer_truelen(sb) +
1246 (size - silc_buffer_taillen(sb) -
1247 silc_buffer_len(sb)))))
1249 silc_buffer_pull_tail(sb, size - silc_buffer_len(sb));
1254 /****f* silcutil/SilcBufferAPI/silc_buffer_senlarge
1259 * SilcBuffer silc_buffer_senlarge(SilcStack stack, SilcBuffer sb,
1264 * Enlarges the buffer by the amount of `size' if it doesn't have that
1265 * must space in the data area and in the tail area. Moves the tail
1266 * area automatically after enlarging so that the current data area
1267 * is at least the size of `size'. If there is more space than `size'
1268 * in the data area this does not do anything. If there is enough
1269 * space in the tail area this merely moves the tail area to reveal
1270 * the extra space. Returns FALSE on error.
1272 * This routine use SilcStack are memory source. If `stack' is NULL
1273 * reverts back to normal allocating routine.
1275 * Note that this call consumes the `stack'. The caller should push the
1276 * stack before calling the function and pop it later.
1281 SilcBool silc_buffer_senlarge(SilcStack stack, 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_srealloc(stack, sb,
1286 silc_buffer_truelen(sb) +
1287 (size - silc_buffer_taillen(sb) -
1288 silc_buffer_len(sb)))))
1290 silc_buffer_pull_tail(sb, size - silc_buffer_len(sb));
1295 /****f* silcutil/SilcBufferAPI/silc_buffer_strchr
1300 * unsigned char *silc_buffer_strchr(SilcBuffer sb, int c, SilcBool first);
1304 * Returns pointer to the occurence of the character `c' in the buffer
1305 * `sb'. If the `first' is TRUE this finds the first occurene of `c',
1306 * if it is FALSE this finds the last occurence of `c'. If the character
1307 * is found the `sb' data area is moved to that location and its pointer
1308 * is returned. The silc_buffer_data call will return the same pointer.
1309 * Returns NULL if such character could not be located and the buffer
1310 * remains unmodified.
1312 * This call is equivalent to strchr(), strrchr(), memchr() and memrchr()
1313 * except it works with SilcBuffer.
1317 * This searches only the data area of the buffer. Head and tail area
1320 * The `sb' data need not be NULL terminated.
1325 unsigned char *silc_buffer_strchr(SilcBuffer sb, int c, SilcBool first)
1330 for (i = 0; i < silc_buffer_len(sb); i++) {
1331 if (sb->data[i] == (unsigned char)c) {
1332 sb->data = &sb->data[i];
1337 for (i = silc_buffer_len(sb) - 1; 1 >= 0; i--) {
1338 if (sb->data[i] == (unsigned char)c) {
1339 sb->data = &sb->data[i];
1348 #endif /* SILCBUFFER_H */