silcbuffer.h
- Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+ Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1998 - 2000 Pekka Riikonen
+ Copyright (C) 1998 - 2008 Pekka Riikonen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
+ the Free Software Foundation; version 2 of the License.
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
+/* $Id$ */
+
+/****h* silcutil/SILC Buffer Interface
+ *
+ * DESCRIPTION
+ *
+ * SilcBuffer is very simple and easy to use, yet you can do to the
+ * buffer almost anything you want with its method functions. The buffer
+ * is constructed of four different data sections that in whole creates
+ * the allocated data area.
+ *
+ ***/
#ifndef SILCBUFFER_H
#define SILCBUFFER_H
-/*
- SILC Buffer object.
+/****s* silcutil/SilcBufferAPI/SilcBuffer
+ *
+ * NAME
+ *
+ * typedef struct { ... } *SilcBuffer, SilcBufferStruct;
+ *
+ * DESCRIPTION
+ *
+ * SILC Buffer object. Following short description of the fields
+ * of the buffer.
+ *
+ * EXAMPLE
+ *
+ * unsiged char *head;
+ *
+ * Head of the allocated buffer. This is the start of the allocated
+ * data area and remains as same throughout the lifetime of the buffer.
+ * However, the end of the head area or the start of the currently valid
+ * data area is variable.
+ *
+ * --------------------------------
+ * | head | data | tail |
+ * --------------------------------
+ * ^ ^
+ *
+ * Current head section in the buffer is sb->data - sb->head.
+ *
+ * unsigned char *data;
+ *
+ * Currently valid data area. This is the start of the currently valid
+ * main data area. The data area is variable in all directions.
+ *
+ * --------------------------------
+ * | head | data | tail |
+ * --------------------------------
+ * ^ ^
+ *
+ * Current valid data area in the buffer is sb->tail - sb->data.
+ *
+ * unsigned char *tail;
+ *
+ * Tail of the buffer. This is the end of the currently valid data area
+ * or start of the tail area. The start of the tail area is variable.
+ *
+ * --------------------------------
+ * | head | data | tail |
+ * --------------------------------
+ * ^ ^
+ *
+ * Current tail section in the buffer is sb->end - sb->tail.
+ *
+ * unsigned char *end;
+ *
+ * End of the allocated buffer. This is the end of the allocated data
+ * area and remains as same throughout the lifetime of the buffer.
+ * Usually this field is not needed except when checking the size
+ * of the buffer.
+ *
+ * --------------------------------
+ * | head | data | tail |
+ * --------------------------------
+ * ^
+ *
+ * Length of the entire buffer is (ie. truelen) sb->end - sb->head.
+ *
+ * Currently valid data area is considered to be the main data area in
+ * the buffer. However, the entire buffer is of course valid data and can
+ * be used as such. Usually head section of the buffer includes different
+ * kind of headers or similar. Data section includes the main data of
+ * the buffer. Tail section can be seen as a reserve space of the data
+ * section. Tail section can be pulled towards end, and thus the data
+ * section becomes larger.
+ *
+ * SILC Buffer is not thread-safe. If the same SilcBuffer context must be
+ * used in multithreaded environment concurrency control must be employed.
+ *
+ * SOURCE
+ */
+typedef struct SilcBufferObject {
+ unsigned char *head;
+ unsigned char *data;
+ unsigned char *tail;
+ unsigned char *end;
+} *SilcBuffer, SilcBufferStruct;
+/***/
- SilcBuffer is very simple and easy to use, yet you can do to the
- buffer almost anything you want with its method functions. The buffer
- is constructed of four different data sections that in whole creates
- the allocated data area. Following short description of the fields
- of the buffer.
+/* Macros */
- unsigned int truelen;
+/****f* silcutil/SilcBufferAPI/silc_buffer_data
+ *
+ * NAME
+ *
+ * unsigned char *silc_buffer_data(SilcBuffer sb)
+ *
+ * DESCRIPTION
+ *
+ * Returns pointer to the data area of the buffer.
+ *
+ * SOURCE
+ */
+#define silc_buffer_data(x) (x)->data
+/***/
+
+/****f* silcutil/SilcBufferAPI/silc_buffer_tail
+ *
+ * NAME
+ *
+ * unsigned char *silc_buffer_tail(SilcBuffer sb)
+ *
+ * DESCRIPTION
+ *
+ * Returns pointer to the tail area of the buffer.
+ *
+ * SOURCE
+ */
+#define silc_buffer_tail(x) (x)->tail
+/***/
+
+/****f* silcutil/SilcBufferAPI/silc_buffer_datalen
+ *
+ * NAME
+ *
+ * #define silc_buffer_datalen ...
+ *
+ * DESCRIPTION
+ *
+ * Macro that can be used in function argument list to give the data
+ * pointer and the data length, instead of calling both silc_buffer_data
+ * and silc_buffer_len separately.
+ *
+ * EXAMPLE
+ *
+ * // Following are the same thing
+ * silc_foo_function(foo, silc_buffer_datalen(buf));
+ * silc_foo_function(foo, silc_buffer_data(buf), silc_buffer_len(buf));
+ *
+ * SOURCE
+ */
+#define silc_buffer_datalen(x) (x) ? silc_buffer_data((x)) : NULL, \
+ (x) ? silc_buffer_len((x)) : 0
+/***/
+
+/* Inline functions */
+
+/****d* silcutil/SilcBufferAPI/silc_buffer_truelen
+ *
+ * NAME
+ *
+ * SilcUInt32 silc_buffer_truelen(SilcBuffer sb)
+ *
+ * DESCRIPTION
+ *
+ * Returns the true length of the buffer.
+ *
+ ***/
+static inline
+SilcUInt32 silc_buffer_truelen(SilcBuffer x)
+{
+ return (SilcUInt32)(x->end - x->head);
+}
- True length of the buffer. This is set at the allocation of the
- buffer and it should not be touched after that. This field should
- be considered read-only.
+/****d* silcutil/SilcBufferAPI/silc_buffer_len
+ *
+ * NAME
+ *
+ * SilcUInt32 silc_buffer_len(SilcBuffer sb)
+ *
+ * DESCRIPTION
+ *
+ * Returns the current length of the data area of the buffer.
+ *
+ ***/
+static inline
+SilcUInt32 silc_buffer_len(SilcBuffer x)
+{
+ return (SilcUInt32)(x->tail - x->data);
+}
- unsigned int len;
+/****d* silcutil/SilcBufferAPI/silc_buffer_headlen
+ *
+ * NAME
+ *
+ * SilcUInt32 silc_buffer_headlen(SilcBuffer sb)
+ *
+ * DESCRIPTION
+ *
+ * Returns the current length of the head data area of the buffer.
+ *
+ ***/
+static inline
+SilcUInt32 silc_buffer_headlen(SilcBuffer x)
+{
+ return (SilcUInt32)(x->data - x->head);
+}
- Length of the currently valid data area. Tells the length of the
- data at the buffer. This is set to zero at the allocation of the
- buffer and should not be updated by hand. Method functions of the
- buffer automatically updates this field. However, it is not
- read-only field and can be updated manually if necessary.
+/****d* silcutil/SilcBufferAPI/silc_buffer_taillen
+ *
+ * NAME
+ *
+ * SilcUInt32 silc_buffer_taillen(SilcBuffer sb)
+ *
+ * DESCRIPTION
+ *
+ * Returns the current length of the tail data area of the buffer.
+ *
+ ***/
+static inline
+SilcUInt32 silc_buffer_taillen(SilcBuffer x)
+{
+ return (SilcUInt32)(x->end - x->tail);
+}
- unsiged char *head;
+/****f* silcutil/SilcBufferAPI/silc_buffer_alloc
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * SilcBuffer silc_buffer_alloc(SilcUInt32 len);
+ *
+ * DESCRIPTION
+ *
+ * Allocates new SilcBuffer and returns it. Returns NULL if system is
+ * out of memory.
+ *
+ ***/
+
+static inline
+SilcBuffer silc_buffer_alloc(SilcUInt32 len)
+{
+ SilcBuffer sb;
- Head of the allocated buffer. This is the start of the allocated
- data area and remains as same throughout the lifetime of the buffer.
- However, the end of the head area or the start of the currently valid
- data area is variable.
+ /* Allocate new SilcBuffer */
+ sb = (SilcBuffer)silc_calloc(1, sizeof(*sb));
+ if (silc_unlikely(!sb))
+ return NULL;
+
+ if (silc_likely(len)) {
+ /* Allocate the actual data area */
+ sb->head = (unsigned char *)silc_malloc(len * sizeof(*sb->head));
+ if (silc_unlikely(!sb->head))
+ return NULL;
+
+ /* Set pointers to the new buffer */
+ sb->data = sb->head;
+ sb->tail = sb->head;
+ sb->end = sb->head + len;
+ }
- --------------------------------
- | head | data | tail |
- --------------------------------
- ^ ^
+ return sb;
+}
- Current head section in the buffer is sb->data - sb->head.
+/****f* silcutil/SilcBufferAPI/silc_buffer_salloc
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len);
+ *
+ * DESCRIPTION
+ *
+ * Allocates new SilcBuffer and returns it. Returns NULL if system is
+ * out of memory.
+ *
+ * This routine use SilcStack are memory source. If `stack' is NULL
+ * reverts back to normal allocating routine.
+ *
+ * Note that this call consumes the `stack'. The caller should push the
+ * stack before calling the function and pop it later.
+ *
+ ***/
+
+static inline
+SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len)
+{
+ SilcBuffer sb;
- unsigned char *data;
+ if (!stack)
+ return silc_buffer_alloc(len);
- Currently valid data area. This is the start of the currently valid
- main data area. The data area is variable in all directions.
+ /* Allocate new SilcBuffer */
+ sb = (SilcBuffer)silc_scalloc(stack, 1, sizeof(*sb));
+ if (silc_unlikely(!sb))
+ return NULL;
+
+ if (silc_likely(len)) {
+ /* Allocate the actual data area */
+ sb->head = (unsigned char *)silc_smalloc(stack, len * sizeof(*sb->head));
+ if (silc_unlikely(!sb->head))
+ return NULL;
+
+ /* Set pointers to the new buffer */
+ sb->data = sb->head;
+ sb->tail = sb->head;
+ sb->end = sb->head + len;
+ }
- --------------------------------
- | head | data | tail |
- --------------------------------
- ^ ^
-
- Current valid data area in the buffer is sb->tail - sb->data.
+ return sb;
+}
- unsigned char *tail;
+/****f* silcutil/SilcBufferAPI/silc_buffer_free
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * void silc_buffer_free(SilcBuffer sb);
+ *
+ * DESCRIPTION
+ *
+ * Frees SilcBuffer. Can be called safely `sb' as NULL.
+ *
+ * NOTES
+ *
+ * Must not be called for buffers allocated with silc_buffer_salloc,
+ * silc_buffer_salloc_size, silc_buffer_scopy and silc_buffer_sclone.
+ * Call silc_buffer_sfree instead.
+ *
+ ***/
+
+static inline
+void silc_buffer_free(SilcBuffer sb)
+{
+ if (sb) {
+#if defined(SILC_DEBUG)
+ if (sb->head)
+ memset(sb->head, 'F', silc_buffer_truelen(sb));
+#endif
+ silc_free(sb->head);
+ silc_free(sb);
+ }
+}
- Tail of the buffer. This is the end of the currently valid data area
- or start of the tail area. The start of the tail area is variable.
+/****f* silcutil/SilcBufferAPI/silc_buffer_sfree
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * void silc_buffer_free(SilcStack stack, SilcBuffer sb);
+ *
+ * DESCRIPTION
+ *
+ * Frees SilcBuffer. If `stack' is NULL this calls silc_buffer_free. Can
+ * be called safely `sb' as NULL.
+ *
+ ***/
+
+static inline
+void silc_buffer_sfree(SilcStack stack, SilcBuffer sb)
+{
+ if (stack) {
+#ifdef SILC_DEBUG
+ if (sb) {
+ if (sb->head)
+ memset(sb->head, 'F', silc_buffer_truelen(sb));
+ memset(sb, 'F', sizeof(*sb));
+ }
+#endif /* SILC_DEBUG */
+ return;
+ }
- --------------------------------
- | head | data | tail |
- --------------------------------
- ^ ^
+ silc_buffer_free(sb);
+}
- Current tail section in the buffer is sb->end - sb->tail.
+/****f* silcutil/SilcBufferAPI/silc_buffer_steal
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len);
+ *
+ * DESCRIPTION
+ *
+ * Steals the data from the buffer `sb'. This returns pointer to the
+ * start of the buffer and the true length of that buffer. The `sb'
+ * cannot be used anymore after calling this function because the
+ * data buffer was stolen. The `sb' must be freed with silc_buffer_free.
+ * The caller is responsible of freeing the stolen data buffer with
+ * silc_free.
+ *
+ ***/
+
+static inline
+unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len)
+{
+ unsigned char *buf = sb->head;
+ if (data_len)
+ *data_len = silc_buffer_truelen(sb);
+ sb->head = sb->data = sb->tail = sb->end = NULL;
+ return buf;
+}
- unsigned char *end;
+/****f* silcutil/SilcBufferAPI/silc_buffer_purge
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * void silc_buffer_purge(SilcBuffer sb);
+ *
+ * DESCRIPTION
+ *
+ * Same as silc_buffer_free but free's only the contents of the buffer
+ * not the buffer itself. The `sb' remains intact, data is freed. Buffer
+ * is ready for re-use after calling this function.
+ *
+ * NOTES
+ *
+ * Must not be called for buffers allocated with silc_buffer_salloc,
+ * silc_buffer_salloc_size, silc_buffer_scopy and silc_buffer_sclone.
+ * Use silc_buffer_spurge instead.
+ *
+ ***/
+
+static inline
+void silc_buffer_purge(SilcBuffer sb)
+{
+ silc_free(silc_buffer_steal(sb, NULL));
+}
- End of the allocated buffer. This is the end of the allocated data
- area and remains as same throughout the lifetime of the buffer.
- Usually this field is not needed except when checking the size
- of the buffer.
+/****f* silcutil/SilcBufferAPI/silc_buffer_spurge
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * void silc_buffer_spurge(SilcStack stack, SilcBuffer sb);
+ *
+ * DESCRIPTION
+ *
+ * Same as silc_buffer_free but free's only the contents of the buffer
+ * not the buffer itself. The `sb' remains intact, data is freed. Buffer
+ * is ready for re-use after calling this function. If `stack' is NULL
+ * this calls silc_buffer_purge.
+ *
+ ***/
+
+static inline
+void silc_buffer_spurge(SilcStack stack, SilcBuffer sb)
+{
+ if (stack) {
+#ifdef SILC_DEBUG
+ if (sb && sb->head)
+ memset(silc_buffer_steal(sb, NULL), 'F', silc_buffer_truelen(sb));
+#endif /* SILC_DEBUG */
+ return;
+ }
- --------------------------------
- | head | data | tail |
- --------------------------------
- ^
+ silc_buffer_purge(sb);
+}
- Length of the entire buffer is (ie. truelen) sb->end - sb->head.
+/****f* silcutil/SilcBufferAPI/silc_buffer_set
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * void silc_buffer_set(SilcBuffer sb,
+ * unsigned char *data,
+ * SilcUInt32 data_len);
+ *
+ * DESCRIPTION
+ *
+ * Sets the `data' and `data_len' to the buffer pointer sent as argument.
+ * The data area is automatically set to the `data_len'. This function
+ * can be used to set the data to static buffer without needing any
+ * memory allocations. The `data' will not be copied to the buffer.
+ *
+ * EXAMPLE
+ *
+ * SilcBufferStruct buf;
+ * silc_buffer_set(&buf, data, data_len);
+ *
+ ***/
+
+static inline
+void silc_buffer_set(SilcBuffer sb, unsigned char *data, SilcUInt32 data_len)
+{
+ sb->data = sb->head = data;
+ sb->tail = sb->end = data + data_len;
+}
- Currently valid data area is considered to be the main data area in
- the buffer. However, the entire buffer is of course valid data and can
- be used as such. Usually head section of the buffer includes different
- kind of headers or similiar. Data section includes the main data of
- the buffer. Tail section can be seen as a reserve space of the data
- section. Tail section can be pulled towards end thus the data section
- becomes larger.
+/****f* silcutil/SilcBufferAPI/silc_buffer_pull
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len);
+ *
+ * DESCRIPTION
+ *
+ * Pulls current data area towards end. The length of the currently
+ * valid data area is also decremented. Returns pointer to the data
+ * area before pulling. Returns NULL if the pull would lead to buffer
+ * overflow or would go beyond the valid data area.
+ *
+ * EXAMPLE
+ *
+ * ---------------------------------
+ * | head | data | tail |
+ * ---------------------------------
+ * ^
+ * Pulls the start of the data area.
+ *
+ * ---------------------------------
+ * | head | data | tail |
+ * ---------------------------------
+ * ^
+ *
+ * silc_buffer_pull(sb, 20);
+ *
+ ***/
+
+static inline
+unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len)
+{
+ unsigned char *old_data = sb->data;
- This buffer scheme is based on Linux kernel's Socket Buffer, the
- idea were taken directly from there and credits should go there.
+#ifdef SILC_DIST_INPLACE
+ SILC_ASSERT(len <= silc_buffer_len(sb));
+#endif /* SILC_DIST_INPLACE */
+ if (silc_unlikely(len > silc_buffer_len(sb))) {
+ silc_set_errno(SILC_ERR_OVERFLOW);
+ return NULL;
+ }
-*/
+ sb->data += len;
+ return old_data;
+}
-typedef struct SilcBufferStruct {
- unsigned int truelen;
- unsigned int len;
- unsigned char *head;
- unsigned char *data;
- unsigned char *tail;
- unsigned char *end;
-} SilcBufferObject;
+/****f* silcutil/SilcBufferAPI/silc_buffer_push
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len);
+ *
+ * DESCRIPTION
+ *
+ * Pushes current data area towards beginning. Length of the currently
+ * valid data area is also incremented. Returns a pointer to the
+ * data area before pushing. Returns NULL if the push would lead to
+ * go beyond the buffer boundaries or current data area.
+ *
+ * EXAMPLE
+ *
+ * ---------------------------------
+ * | head | data | tail |
+ * ---------------------------------
+ * ^
+ * Pushes the start of the data area.
+ *
+ * ---------------------------------
+ * | head | data | tail |
+ * ---------------------------------
+ * ^
+ *
+ * silc_buffer_push(sb, 20);
+ *
+ ***/
+
+static inline
+unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len)
+{
+ unsigned char *old_data = sb->data;
-typedef SilcBufferObject *SilcBuffer;
+#ifdef SILC_DIST_INPLACE
+ SILC_ASSERT((sb->data - len) >= sb->head);
+#endif /* SILC_DIST_INPLACE */
+ if (silc_unlikely((sb->data - len) < sb->head)) {
+ silc_set_errno(SILC_ERR_OVERFLOW);
+ return NULL;
+ }
-/* Macros */
+ sb->data -= len;
+ return old_data;
+}
-/* Returns the true length of the buffer. This is used to pull
- the buffer area to the end of the buffer. */
-#define SILC_BUFFER_END(x) ((x)->end - (x)->head)
+/****f* silcutil/SilcBufferAPI/silc_buffer_pull_tail
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len);
+ *
+ * DESCRIPTION
+ *
+ * Pulls current tail section towards end. Length of the current valid
+ * data area is also incremented. Returns a pointer to the data area
+ * before pulling. Returns NULL if the pull would lead to buffer overflow.
+ *
+ * EXAMPLE
+ *
+ * ---------------------------------
+ * | head | data | tail |
+ * ---------------------------------
+ * ^
+ * Pulls the start of the tail section.
+ *
+ * ---------------------------------
+ * | head | data | tail |
+ * ---------------------------------
+ * ^
+ *
+ * silc_buffer_pull_tail(sb, 23);
+ *
+ ***/
+
+static inline
+unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len)
+{
+ unsigned char *old_tail = sb->tail;
-#ifndef SILC_DEBUG /* When we are not doing debugging we use
- optimized inline buffer functions. */
-/*
- * Optimized buffer managing routines. These are short inline
- * functions.
- */
+#ifdef SILC_DIST_INPLACE
+ SILC_ASSERT(len <= silc_buffer_taillen(sb));
+#endif /* SILC_DIST_INPLACE */
+ if (silc_unlikely(len > silc_buffer_taillen(sb))) {
+ silc_set_errno(SILC_ERR_OVERFLOW);
+ return NULL;
+ }
+
+ sb->tail += len;
+ return old_tail;
+}
-extern inline
-SilcBuffer silc_buffer_alloc(unsigned int len)
+/****f* silcutil/SilcBufferAPI/silc_buffer_push_tail
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len);
+ *
+ * DESCRIPTION
+ *
+ * Pushes current tail section towards beginning. Length of the current
+ * valid data area is also decremented. Returns a pointer to the
+ * tail section before pushing. Returns NULL if the push would lead to
+ * go beyond buffer boundaries or current tail area.
+ *
+ * EXAMPLE
+ *
+ * ---------------------------------
+ * | head | data | tail |
+ * ---------------------------------
+ * ^
+ * Pushes the start of the tail section.
+ *
+ * ---------------------------------
+ * | head | data | tail |
+ * ---------------------------------
+ * ^
+ *
+ * silc_buffer_push_tail(sb, 23);
+ *
+ ***/
+
+static inline
+unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len)
{
- SilcBuffer sb;
- unsigned char *data;
+ unsigned char *old_tail = sb->tail;
- /* Allocate new SilcBuffer */
- sb = silc_calloc(1, sizeof(*sb));
+#ifdef SILC_DIST_INPLACE
+ SILC_ASSERT((sb->tail - len) >= sb->data);
+#endif /* SILC_DIST_INPLACE */
+ if (silc_unlikely((sb->tail - len) < sb->data)) {
+ silc_set_errno(SILC_ERR_OVERFLOW);
+ return NULL;
+ }
- /* Allocate the actual data area */
- data = silc_calloc(len, sizeof(*data));
+ sb->tail -= len;
+ return old_tail;
+}
- /* Set pointers to the new buffer */
- sb->truelen = len;
- sb->len = 0;
- sb->head = data;
- sb->data = data;
- sb->tail = data;
- sb->end = data + sb->truelen;
+/****f* silcutil/SilcBufferAPI/silc_buffer_put_head
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * unsigned char *silc_buffer_put_head(SilcBuffer sb,
+ * const unsigned char *data,
+ * SilcUInt32 len);
+ *
+ * DESCRIPTION
+ *
+ * Puts data at the head of the buffer. Returns pointer to the copied
+ * data area. Returns NULL if the data is longer that the current head
+ * area.
+ *
+ * EXAMPLE
+ *
+ * ---------------------------------
+ * | head | data | tail |
+ * ---------------------------------
+ * ^
+ * Puts data to the head section.
+ *
+ * silc_buffer_put_head(sb, data, data_len);
+ *
+ ***/
+
+static inline
+unsigned char *silc_buffer_put_head(SilcBuffer sb,
+ const unsigned char *data,
+ SilcUInt32 len)
+{
+#ifdef SILC_DIST_INPLACE
+ SILC_ASSERT(len <= silc_buffer_headlen(sb));
+#endif /* SILC_DIST_INPLACE */
+ if (silc_unlikely(len > silc_buffer_headlen(sb))) {
+ silc_set_errno(SILC_ERR_OVERFLOW);
+ return NULL;
+ }
- return sb;
-}
+ if (sb->head > data) {
+ if (sb->head - data <= len)
+ return (unsigned char *)memmove(sb->head, data, len);
+ } else {
+ if (data - sb->head <= len)
+ return (unsigned char *)memmove(sb->head, data, len);
+ }
-/* Free's a SilcBuffer */
+ return (unsigned char *)memcpy(sb->head, data, len);
+}
-extern inline
-void silc_buffer_free(SilcBuffer sb)
+/****f* silcutil/SilcBufferAPI/silc_buffer_put
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * unsigned char *silc_buffer_put(SilcBuffer sb,
+ * const unsigned char *data,
+ * SilcUInt32 len);
+ *
+ * DESCRIPTION
+ *
+ * Puts data at the start of the valid data area. Returns a pointer
+ * to the copied data area. Returns NULL if the data is longer than the
+ * current data area.
+ *
+ * EXAMPLE
+ *
+ * ---------------------------------
+ * | head | data | tail |
+ * ---------------------------------
+ * ^
+ * Puts data to the data section.
+ *
+ * silc_buffer_put(sb, data, data_len);
+ *
+ ***/
+
+static inline
+unsigned char *silc_buffer_put(SilcBuffer sb,
+ const unsigned char *data,
+ SilcUInt32 len)
{
- if (sb) {
- memset(sb->head, 'F', sb->truelen);
- silc_free(sb->head);
- silc_free(sb);
+#ifdef SILC_DIST_INPLACE
+ SILC_ASSERT(len <= silc_buffer_len(sb));
+#endif /* SILC_DIST_INPLACE */
+ if (silc_unlikely(len > silc_buffer_len(sb))) {
+ silc_set_errno(SILC_ERR_OVERFLOW);
+ return NULL;
+ }
+
+ if (sb->data > data) {
+ if (sb->data - data <= len)
+ return (unsigned char *)memmove(sb->data, data, len);
+ } else {
+ if (data - sb->data <= len)
+ return (unsigned char *)memmove(sb->data, data, len);
}
+
+ return (unsigned char *)memcpy(sb->data, data, len);
}
-/* Pulls current data area towards end. The length of the currently
- valid data area is also decremented. Returns pointer to the data
- area before pulling.
+/****f* silcutil/SilcBufferAPI/silc_buffer_put_tail
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * unsigned char *silc_buffer_put_tail(SilcBuffer sb,
+ * const unsigned char *data,
+ * SilcUInt32 len);
+ *
+ * DESCRIPTION
+ *
+ * Puts data at the tail of the buffer. Returns pointer to the copied
+ * data area. Returns NULL if the data is longer than the current tail
+ * area.
+ *
+ * EXAMPLE
+ *
+ * ---------------------------------
+ * | head | data | tail |
+ * ---------------------------------
+ * ^
+ * Puts data to the tail section.
+ *
+ * silc_buffer_put_tail(sb, data, data_len);
+ *
+ ***/
+
+static inline
+unsigned char *silc_buffer_put_tail(SilcBuffer sb,
+ const unsigned char *data,
+ SilcUInt32 len)
+{
+#ifdef SILC_DIST_INPLACE
+ SILC_ASSERT(len <= silc_buffer_taillen(sb));
+#endif /* SILC_DIST_INPLACE */
+ if (silc_unlikely(len > silc_buffer_taillen(sb))) {
+ silc_set_errno(SILC_ERR_OVERFLOW);
+ return NULL;
+ }
- Example:
- ---------------------------------
- | head | data | tail |
- ---------------------------------
- ^
- Pulls the start of the data area.
+ if (sb->tail > data) {
+ if (sb->tail - data <= len)
+ return (unsigned char *)memmove(sb->tail, data, len);
+ } else {
+ if (data - sb->tail <= len)
+ return (unsigned char *)memmove(sb->tail, data, len);
+ }
- ---------------------------------
- | head | data | tail |
- ---------------------------------
- ^
-*/
+ return (unsigned char *)memcpy(sb->tail, data, len);
+}
-extern inline
-unsigned char *silc_buffer_pull(SilcBuffer sb, unsigned int len)
+/****f* silcutil/SilcBufferAPI/silc_buffer_alloc_size
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * SilcBuffer silc_buffer_alloc_size(SilcUInt32 len);
+ *
+ * DESCRIPTION
+ *
+ * Allocates `len' bytes size buffer and moves the tail area automatically
+ * `len' bytes so that the buffer is ready to use without calling the
+ * silc_buffer_pull_tail. Returns NULL if system is out of memory.
+ *
+ ***/
+
+static inline
+SilcBuffer silc_buffer_alloc_size(SilcUInt32 len)
{
- unsigned char *old_data = sb->data;
+ SilcBuffer sb = silc_buffer_alloc(len);
+ if (silc_unlikely(!sb))
+ return NULL;
+ silc_buffer_pull_tail(sb, len);
+ return sb;
+}
- assert(len <= (sb->tail - sb->data));
+/****f* silcutil/SilcBufferAPI/silc_buffer_salloc_size
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len);
+ *
+ * DESCRIPTION
+ *
+ * Allocates `len' bytes size buffer and moves the tail area automatically
+ * `len' bytes so that the buffer is ready to use without calling the
+ * silc_buffer_pull_tail. Returns NULL if system is out of memory.
+ *
+ * This routine use SilcStack are memory source. If `stack' is NULL
+ * reverts back to normal allocating routine.
+ *
+ * Note that this call consumes the `stack'. The caller should push the
+ * stack before calling the function and pop it later.
+ *
+ ***/
+
+static inline
+SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len)
+{
+ SilcBuffer sb = silc_buffer_salloc(stack, len);
+ if (silc_unlikely(!sb))
+ return NULL;
+ silc_buffer_pull_tail(sb, len);
+ return sb;
+}
- sb->data += len;
- sb->len -= len;
+/****f* silcutil/SilcBufferAPI/silc_buffer_reset
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * void silc_buffer_reset(SilcBuffer sb);
+ *
+ * DESCRIPTION
+ *
+ * Resets the buffer to the state as if it was just allocated by
+ * silc_buffer_alloc. This does not clear the data area. Use
+ * silc_buffer_clear if you also want to clear the data area.
+ *
+ ***/
+
+static inline
+void silc_buffer_reset(SilcBuffer sb)
+{
+ sb->data = sb->tail = sb->head;
+}
- return old_data;
+/****f* silcutil/SilcBufferAPI/silc_buffer_clear
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * void silc_buffer_clear(SilcBuffer sb);
+ *
+ * DESCRIPTION
+ *
+ * Clears and initialiazes the buffer to the state as if it was just
+ * allocated by silc_buffer_alloc.
+ *
+ ***/
+
+static inline
+void silc_buffer_clear(SilcBuffer sb)
+{
+ memset(sb->head, 0, silc_buffer_truelen(sb));
+ silc_buffer_reset(sb);
}
-/* Pushes current data area towards beginning. Length of the currently
- valid data area is also incremented. Returns a pointer to the
- data area before pushing.
+/****f* silcutil/SilcBufferAPI/silc_buffer_start
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * void silc_buffer_start(SilcBuffer sb);
+ *
+ * DESCRIPTION
+ *
+ * Moves the data area at the start of the buffer. The tail area remains
+ * as is.
+ *
+ ***/
+
+static inline
+void silc_buffer_start(SilcBuffer sb)
+{
+ sb->data = sb->head;
+}
- Example:
- ---------------------------------
- | head | data | tail |
- ---------------------------------
- ^
- Pushes the start of the data area.
+/****f* silcutil/SilcBufferAPI/silc_buffer_end
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * void silc_buffer_end(SilcBuffer sb);
+ *
+ * DESCRIPTION
+ *
+ * Moves the end of the data area to the end of the buffer. The start
+ * of the data area remains same. If the start of data area is at the
+ * start of the buffer, after this function returns the buffer's data
+ * area length is the length of the entire buffer.
+ *
+ ***/
+
+static inline
+void silc_buffer_end(SilcBuffer sb)
+{
+ sb->tail = sb->end;
+}
- ---------------------------------
- | head | data | tail |
- ---------------------------------
- ^
-*/
+/****f* silcutil/SilcBufferAPI/silc_buffer_copy
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * SilcBuffer silc_buffer_copy(SilcBuffer sb);
+ *
+ * DESCRIPTION
+ *
+ * Generates copy of a SilcBuffer. This copies everything inside the
+ * currently valid data area, nothing more. Use silc_buffer_clone to
+ * copy entire buffer. Returns NULL if system is out of memory.
+ *
+ ***/
+
+static inline
+SilcBuffer silc_buffer_copy(SilcBuffer sb)
+{
+ SilcBuffer sb_new;
+
+ sb_new = silc_buffer_alloc_size(silc_buffer_len(sb));
+ if (silc_unlikely(!sb_new))
+ return NULL;
+ silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
+
+ return sb_new;
+}
-extern inline
-unsigned char *silc_buffer_push(SilcBuffer sb, unsigned int len)
+/****f* silcutil/SilcBufferAPI/silc_buffer_scopy
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb);
+ *
+ * DESCRIPTION
+ *
+ * Generates copy of a SilcBuffer. This copies everything inside the
+ * currently valid data area, nothing more. Use silc_buffer_clone to
+ * copy entire buffer. Returns NULL if system is out of memory.
+ *
+ * This routine use SilcStack are memory source. If `stack' is NULL
+ * reverts back to normal allocating routine.
+ *
+ * Note that this call consumes the `stack'. The caller should push the
+ * stack before calling the function and pop it later.
+ *
+ ***/
+
+static inline
+SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb)
{
- unsigned char *old_data = sb->data;
+ SilcBuffer sb_new;
- assert((sb->data - len) >= sb->head);
+ sb_new = silc_buffer_salloc_size(stack, silc_buffer_len(sb));
+ if (silc_unlikely(!sb_new))
+ return NULL;
+ silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
- sb->data -= len;
- sb->len += len;
+ return sb_new;
+}
- return old_data;
+/****f* silcutil/SilcBufferAPI/silc_buffer_clone
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * SilcBuffer silc_buffer_clone(SilcBuffer sb);
+ *
+ * DESCRIPTION
+ *
+ * Clones SilcBuffer. This generates new SilcBuffer and copies
+ * everything from the source buffer. The result is exact clone of
+ * the original buffer. Returns NULL if system is out of memory.
+ *
+ ***/
+
+static inline
+SilcBuffer silc_buffer_clone(SilcBuffer sb)
+{
+ SilcBuffer sb_new;
+
+ sb_new = silc_buffer_alloc_size(silc_buffer_truelen(sb));
+ if (silc_unlikely(!sb_new))
+ return NULL;
+ silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
+ sb_new->data = sb_new->head + silc_buffer_headlen(sb);
+ sb_new->tail = sb_new->data + silc_buffer_len(sb);
+
+ return sb_new;
}
-/* Pulls current tail section towards end. Length of the current valid
- data area is also incremented. Returns a pointer to the data area
- before pulling.
+/****f* silcutil/SilcBufferAPI/silc_buffer_sclone
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb);
+ *
+ * DESCRIPTION
+ *
+ * Clones SilcBuffer. This generates new SilcBuffer and copies
+ * everything from the source buffer. The result is exact clone of
+ * the original buffer. Returns NULL if system is out of memory.
+ *
+ * This routine use SilcStack are memory source. If `stack' is NULL
+ * reverts back to normal allocating routine.
+ *
+ * Note that this call consumes the `stack'. The caller should push the
+ * stack before calling the function and pop it later.
+ *
+ ***/
+
+static inline
+SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb)
+{
+ SilcBuffer sb_new;
- Example:
- ---------------------------------
- | head | data | tail |
- ---------------------------------
- ^
- Pulls the start of the tail section.
+ sb_new = silc_buffer_salloc_size(stack, silc_buffer_truelen(sb));
+ if (silc_unlikely(!sb_new))
+ return NULL;
+ silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb));
+ sb_new->data = sb_new->head + silc_buffer_headlen(sb);
+ sb_new->tail = sb_new->data + silc_buffer_len(sb);
- ---------------------------------
- | head | data | tail |
- ---------------------------------
- ^
-*/
+ return sb_new;
+}
-extern inline
-unsigned char *silc_buffer_pull_tail(SilcBuffer sb, unsigned int len)
+/****f* silcutil/SilcBufferAPI/silc_buffer_realloc
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize);
+ *
+ * DESCRIPTION
+ *
+ * Reallocates buffer. Old data is saved into the new buffer. The buffer
+ * is exact clone of the old one except that there is now more/less space
+ * at the end of buffer. This always returns the same `sb' unless `sb'
+ * was NULL. Returns NULL if system is out of memory.
+ *
+ * If the `newsize' is shorter than the current buffer size, the data
+ * and tail area of the buffer must be set to correct position before
+ * calling this function so that buffer overflow would not occur when
+ * the buffer size is reduced.
+ *
+ ***/
+
+static inline
+SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize)
{
- unsigned char *old_tail = sb->tail;
+ SilcUInt32 hlen, dlen;
+ unsigned char *h;
- assert((sb->end - sb->tail) >= len);
+ if (!sb)
+ return silc_buffer_alloc(newsize);
- sb->tail += len;
- sb->len += len;
+ if (silc_unlikely(newsize == silc_buffer_truelen(sb)))
+ return sb;
- return old_tail;
+ hlen = silc_buffer_headlen(sb);
+ dlen = silc_buffer_len(sb);
+ h = (unsigned char *)silc_realloc(sb->head, newsize);
+ if (silc_unlikely(!h))
+ return NULL;
+ sb->head = h;
+ sb->data = sb->head + hlen;
+ sb->tail = sb->data + dlen;
+ sb->end = sb->head + newsize;
+
+ return sb;
}
-/* Pushes current tail section towards beginning. Length of the current
- valid data area is also decremented. Returns a pointer to the
- tail section before pushing.
+/****f* silcutil/SilcBufferAPI/silc_buffer_srealloc
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * SilcBuffer silc_buffer_srealloc(SilcStack stack,
+ * SilcBuffer sb, SilcUInt32 newsize);
+ *
+ * DESCRIPTION
+ *
+ * Reallocates buffer. Old data is saved into the new buffer. The buffer
+ * is exact clone of the old one except that there is now more/less space
+ * at the end of buffer. Returns NULL if system is out of memory. This
+ * always returns `sb' unless `sb' was NULL.
+ *
+ * If the `newsize' is shorter than the current buffer size, the data
+ * and tail area of the buffer must be set to correct position before
+ * calling this function so that buffer overflow would not occur when
+ * the buffer size is reduced.
+ *
+ * This routine use SilcStack are memory source. If `stack' is NULL
+ * reverts back to normal allocating routine.
+ *
+ * Note that this call consumes the `stack'. The caller should push the
+ * stack before calling the function and pop it later.
+ *
+ ***/
+
+static inline
+SilcBuffer silc_buffer_srealloc(SilcStack stack,
+ SilcBuffer sb, SilcUInt32 newsize)
+{
+ SilcUInt32 hlen, dlen;
+ unsigned char *h;
- Example:
- ---------------------------------
- | head | data | tail |
- ---------------------------------
- ^
- Pushes the start of the tail section.
+ if (!stack)
+ return silc_buffer_realloc(sb, newsize);
- ---------------------------------
- | head | data | tail |
- ---------------------------------
- ^
-*/
+ if (!sb)
+ return silc_buffer_salloc(stack, newsize);
-extern inline
-unsigned char *silc_buffer_push_tail(SilcBuffer sb, unsigned int len)
-{
- unsigned char *old_tail = sb->tail;
+ if (newsize == silc_buffer_truelen(sb))
+ return sb;
- assert((sb->tail - len) >= sb->data);
+ hlen = silc_buffer_headlen(sb);
+ dlen = silc_buffer_len(sb);
+ h = (unsigned char *)silc_srealloc(stack, silc_buffer_truelen(sb),
+ sb->head, newsize);
+ if (!h)
+ return NULL;
- sb->tail -= len;
- sb->len -= len;
+ sb->head = h;
+ sb->data = sb->head + hlen;
+ sb->tail = sb->data + dlen;
+ sb->end = sb->head + newsize;
- return old_tail;
+ return sb;
}
-/* Puts data at the head of the buffer. Returns pointer to the copied
- data area.
-
- Example:
- ---------------------------------
- | head | data | tail |
- ---------------------------------
- ^
- Puts data to the head section.
-*/
+/****f* silcutil/SilcBufferAPI/silc_buffer_realloc_size
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize);
+ *
+ * DESCRIPTION
+ *
+ * Same as silc_buffer_realloc but moves moves the tail area
+ * automatically so that the buffer is ready to use without calling the
+ * silc_buffer_pull_tail. Returns NULL if system is out of memory.
+ *
+ ***/
+
+static inline
+SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize)
+{
+ sb = silc_buffer_realloc(sb, newsize);
+ if (silc_unlikely(!sb))
+ return NULL;
+ silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
+ return sb;
+}
-extern inline
-unsigned char *silc_buffer_put_head(SilcBuffer sb,
- unsigned char *data,
- unsigned int len)
+/****f* silcutil/SilcBufferAPI/silc_buffer_srealloc_size
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
+ * SilcBuffer sb, SilcUInt32 newsize);
+ *
+ * DESCRIPTION
+ *
+ * Same as silc_buffer_srealloc but moves moves the tail area
+ * automatically so that the buffer is ready to use without calling the
+ * silc_buffer_pull_tail. Returns NULL if system is out of memory.
+ *
+ * This routine use SilcStack are memory source. If `stack' is NULL
+ * reverts back to normal allocating routine.
+ *
+ * Note that this call consumes the `stack'. The caller should push the
+ * stack before calling the function and pop it later.
+ *
+ ***/
+
+static inline
+SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
+ SilcBuffer sb, SilcUInt32 newsize)
{
- assert((sb->data - sb->head) >= len);
- return memcpy(sb->head, data, len);
+ sb = silc_buffer_srealloc(stack, sb, newsize);
+ if (silc_unlikely(!sb))
+ return NULL;
+ silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
+ return sb;
}
-/* Puts data at the start of the valid data area. Returns a pointer
- to the copied data area.
+/****f* silcutil/SilcBufferAPI/silc_buffer_enlarge
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * SilcBuffer silc_buffer_enlarge(SilcBuffer sb, SilcUInt32 size);
+ *
+ * DESCRIPTION
+ *
+ * Enlarges the buffer by the amount of `size' if it doesn't have that
+ * must space in the data area and in the tail area. Moves the tail
+ * area automatically after enlarging so that the current data area
+ * is at least the size of `size'. If there is more space than `size'
+ * in the data area this does not do anything. If there is enough
+ * space in the tail area this merely moves the tail area to reveal
+ * the extra space. Returns FALSE if system is out of memory.
+ *
+ ***/
+
+static inline
+SilcBool silc_buffer_enlarge(SilcBuffer sb, SilcUInt32 size)
+{
+ if (size > silc_buffer_len(sb)) {
+ if (size > silc_buffer_taillen(sb) + silc_buffer_len(sb))
+ if (silc_unlikely(!silc_buffer_realloc(sb, silc_buffer_truelen(sb) +
+ (size - silc_buffer_taillen(sb) -
+ silc_buffer_len(sb)))))
+ return FALSE;
+ silc_buffer_pull_tail(sb, size - silc_buffer_len(sb));
+ }
+ return TRUE;
+}
- Example:
- ---------------------------------
- | head | data | tail |
- ---------------------------------
- ^
- Puts data to the data section.
-*/
+/****f* silcutil/SilcBufferAPI/silc_buffer_senlarge
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * SilcBuffer silc_buffer_senlarge(SilcStack stack, SilcBuffer sb,
+ * SilcUInt32 size);
+ *
+ * DESCRIPTION
+ *
+ * Enlarges the buffer by the amount of `size' if it doesn't have that
+ * must space in the data area and in the tail area. Moves the tail
+ * area automatically after enlarging so that the current data area
+ * is at least the size of `size'. If there is more space than `size'
+ * in the data area this does not do anything. If there is enough
+ * space in the tail area this merely moves the tail area to reveal
+ * the extra space. Returns FALSE if system is out of memory.
+ *
+ * This routine use SilcStack are memory source. If `stack' is NULL
+ * reverts back to normal allocating routine.
+ *
+ * Note that this call consumes the `stack'. The caller should push the
+ * stack before calling the function and pop it later.
+ *
+ ***/
+
+static inline
+SilcBool silc_buffer_senlarge(SilcStack stack, SilcBuffer sb, SilcUInt32 size)
+{
+ if (size > silc_buffer_len(sb)) {
+ if (size > silc_buffer_taillen(sb) + silc_buffer_len(sb))
+ if (silc_unlikely(!silc_buffer_srealloc(stack, sb,
+ silc_buffer_truelen(sb) +
+ (size - silc_buffer_taillen(sb) -
+ silc_buffer_len(sb)))))
+ return FALSE;
+ silc_buffer_pull_tail(sb, size - silc_buffer_len(sb));
+ }
+ return TRUE;
+}
-extern inline
-unsigned char *silc_buffer_put(SilcBuffer sb,
- unsigned char *data,
- unsigned int len)
+/****f* silcutil/SilcBufferAPI/silc_buffer_append
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * SilcBuffer silc_buffer_append(SilcBuffer sb, SilcUInt32 size);
+ *
+ * DESCRIPTION
+ *
+ * Appends the current data area by the amount of `size'. The tail area
+ * of the buffer remains intact and contains the same data than the old
+ * tail area (the data is copied to the new tail area). After appending
+ * there is now `size' bytes more free area in the data area. Returns
+ * FALSE if system is out of memory.
+ *
+ * EXAMPLE
+ *
+ * Before appending:
+ * ---------------------------------
+ * | head | data | tail |
+ * ---------------------------------
+ *
+ * After appending:
+ * ------------------------------------
+ * | head | data | tail |
+ * -------------------------------------
+ *
+ * silc_buffer_append(sb, 5);
+ *
+ ***/
+
+static inline
+SilcBool silc_buffer_append(SilcBuffer sb, SilcUInt32 size)
{
- assert((sb->tail - sb->data) >= len);
- return memcpy(sb->data, data, len);
+ if (silc_unlikely(!silc_buffer_realloc(sb, silc_buffer_truelen(sb) + size)))
+ return FALSE;
+
+ /* Enlarge data area */
+ silc_buffer_pull_tail(sb, size);
+
+ /* Copy old tail area to new tail area */
+ silc_buffer_put_tail(sb, sb->tail - size, silc_buffer_taillen(sb));
+
+ return TRUE;
}
-/* Puts data at the tail of the buffer. Returns pointer to the copied
- data area.
+/****f* silcutil/SilcBufferAPI/silc_buffer_append
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * SilcBool silc_buffer_sappend(SilcStack stack, SilcBuffer sb,
+ * SilcUInt32 size)
+ *
+ * DESCRIPTION
+ *
+ * Appends the current data area by the amount of `size'. The tail area
+ * of the buffer remains intact and contains the same data than the old
+ * tail area (the data is copied to the new tail area). After appending
+ * there is now `size' bytes more free area in the data area. Returns
+ * FALSE if system is out of memory.
+ *
+ * This routine use SilcStack are memory source. If `stack' is NULL
+ * reverts back to normal allocating routine.
+ *
+ * Note that this call consumes the `stack'. The caller should push the
+ * stack before calling the function and pop it later.
+ *
+ * EXAMPLE
+ *
+ * Before appending:
+ * ---------------------------------
+ * | head | data | tail |
+ * ---------------------------------
+ *
+ * After appending:
+ * ------------------------------------
+ * | head | data | tail |
+ * -------------------------------------
+ *
+ * silc_buffer_append(sb, 5);
+ *
+ ***/
+
+static inline
+SilcBool silc_buffer_sappend(SilcStack stack, SilcBuffer sb, SilcUInt32 size)
+{
+ if (silc_unlikely(!silc_buffer_srealloc(stack, sb,
+ silc_buffer_truelen(sb) + size)))
+ return FALSE;
- Example:
- ---------------------------------
- | head | data | tail |
- ---------------------------------
- ^
- Puts data to the tail section.
-*/
+ /* Enlarge data area */
+ silc_buffer_pull_tail(sb, size);
+
+ /* Copy old tail area to new tail area */
+ silc_buffer_put_tail(sb, sb->tail - size, silc_buffer_taillen(sb));
+
+ return TRUE;
+}
+
+/****f* silcutil/SilcBufferAPI/silc_buffer_strchr
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * unsigned char *silc_buffer_strchr(SilcBuffer sb, int c, SilcBool first);
+ *
+ * DESCRIPTION
+ *
+ * Returns pointer to the occurence of the character `c' in the buffer
+ * `sb'. If the `first' is TRUE this finds the first occurene of `c',
+ * if it is FALSE this finds the last occurence of `c'. If the character
+ * is found the `sb' data area is moved to that location and its pointer
+ * is returned. The silc_buffer_data call will return the same pointer.
+ * Returns NULL if such character could not be located and the buffer
+ * remains unmodified.
+ *
+ * This call is equivalent to strchr(), strrchr(), memchr() and memrchr()
+ * except it works with SilcBuffer.
+ *
+ * NOTES
+ *
+ * This searches only the data area of the buffer. Head and tail area
+ * are not searched.
+ *
+ * The `sb' data need not be NULL terminated.
+ *
+ ***/
+
+static inline
+unsigned char *silc_buffer_strchr(SilcBuffer sb, int c, SilcBool first)
+{
+ int i;
+
+ if (first) {
+ for (i = 0; i < silc_buffer_len(sb); i++) {
+ if (sb->data[i] == (unsigned char)c) {
+ sb->data = &sb->data[i];
+ return sb->data;
+ }
+ }
+ } else {
+ for (i = silc_buffer_len(sb) - 1; 1 >= 0; i--) {
+ if (sb->data[i] == (unsigned char)c) {
+ sb->data = &sb->data[i];
+ return sb->data;
+ }
+ }
+ }
+
+ return NULL;
+}
-extern inline
-unsigned char *silc_buffer_put_tail(SilcBuffer sb,
- unsigned char *data,
- unsigned int len)
+/****f* silcutil/SilcBufferAPI/silc_buffer_equal
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * SilcBool silc_buffer_equal(SilcBuffer sb1, SilcBuffer sb2)
+ *
+ * DESCRIPTION
+ *
+ * Compares if the data area of the buffer `sb1' and `sb2' are identical.
+ * Returns TRUE if they match and FALSE if they differ.
+ *
+ ***/
+
+static inline
+SilcBool silc_buffer_equal(SilcBuffer sb1, SilcBuffer sb2)
{
- assert((sb->end - sb->tail) >= len);
- return memcpy(sb->tail, data, len);
+ if (silc_buffer_len(sb1) != silc_buffer_len(sb2))
+ return FALSE;
+ return memcmp(sb1->data, sb2->data, silc_buffer_len(sb1)) == 0;
}
-#endif /* !SILC_DEBUG */
+/****f* silcutil/SilcBufferAPI/silc_buffer_memcmp
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * SilcBool silc_buffer_memcmp(SilcBuffer buffer,
+ * const unsigned char *data,
+ * SilcUInt32 data_len)
+ *
+ * DESCRIPTION
+ *
+ * Compares the data area of the buffer with the `data'. Returns TRUE
+ * if the data area is identical to `data' or FALSE if they differ.
+ *
+ ***/
+
+static inline
+SilcBool silc_buffer_memcmp(SilcBuffer buffer, const unsigned char *data,
+ SilcUInt32 data_len)
+{
+ if (silc_buffer_len(buffer) != data_len)
+ return FALSE;
+ return memcmp(buffer->data, data, data_len) == 0;
+}
-/* Prototypes */
-#ifdef SILC_DEBUG
-SilcBuffer silc_buffer_alloc(unsigned int len);
-void silc_buffer_free(SilcBuffer sb);
-unsigned char *silc_buffer_pull(SilcBuffer sb, unsigned int len);
-unsigned char *silc_buffer_push(SilcBuffer sb, unsigned int len);
-unsigned char *silc_buffer_pull_tail(SilcBuffer sb, unsigned int len);
-unsigned char *silc_buffer_push_tail(SilcBuffer sb, unsigned int len);
-unsigned char *silc_buffer_put_head(SilcBuffer sb,
- unsigned char *data,
- unsigned int len);
-unsigned char *silc_buffer_put(SilcBuffer sb,
- unsigned char *data,
- unsigned int len);
-unsigned char *silc_buffer_put_tail(SilcBuffer sb,
- unsigned char *data,
- unsigned int len);
-#endif
+/****f* silcutil/SilcBufferAPI/silc_buffer_printf
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * void silc_buffer_printf(SilcBuffer sb, SilcBool newline);
+ *
+ * DESCRIPTION
+ *
+ * Prints the current data area of `sb' into stdout. If `newline' is
+ * TRUE prints '\n' after the data in the buffer.
+ *
+ ***/
+
+static inline
+void silc_buffer_printf(SilcBuffer sb, SilcBool newline)
+{
+ silc_file_write(1, silc_buffer_data(sb), silc_buffer_len(sb));
+ if (newline)
+ printf("\n");
+ fflush(stdout);
+}
-#endif
+#endif /* SILCBUFFER_H */