Initial code commit for Toolkit 1.1.
[silc.git] / lib / silcutil / silcbuffer.h
index 4dc1472ae6822fc5bff68575c5db519c7e0c3604..9d35047082e03741eb6d0816f8a960f650b7c49f 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  silcbuffer.h 
+  silcbuffer.h
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1998 - 2002 Pekka Riikonen
+  Copyright (C) 1998 - 2005 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
 
 */
 /* $Id$ */
-/* Optimized buffer managing routines.  These are short inline functions. */
-
-#ifndef SILCBUFFER_H
-#define SILCBUFFER_H
 
 /****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.
- *
- *    This buffer scheme is based on Linux kernel's Socket Buffer, the
- *    idea were taken directly from there and credits should go there.
+ * 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
+
 /****s* silcutil/SilcBufferAPI/SilcBuffer
  *
  * NAME
  *
  * EXAMPLE
  *
- *    SilcUInt32 truelen;
- *
- *        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.
- *
- *    SilcUInt32 len;
- *
- *        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.
- *
  *    unsiged char *head;
  *
  *        Head of the allocated buffer. This is the start of the allocated
  * SOURCE
  */
 typedef struct {
-  SilcUInt32 truelen;
-  SilcUInt32 len;
   unsigned char *head;
   unsigned char *data;
   unsigned char *tail;
@@ -137,20 +117,64 @@ typedef struct {
 
 /* Macros */
 
-/****d* silcutil/SilcBufferAPI/SILC_BUFFER_END
- * 
+/****d* silcutil/SilcBufferAPI/silc_buffer_truelen
+ *
+ * NAME
+ *
+ *    #define silc_buffer_truelen(buffer)
+ *
+ * DESCRIPTION
+ *
+ *    Returns the true length of the buffer.
+ *
+ * SOURCE
+ */
+#define silc_buffer_truelen(x) (SilcUInt32)((x)->end - (x)->head)
+/***/
+
+/****d* silcutil/SilcBufferAPI/silc_buffer_len
+ *
+ * NAME
+ *
+ *    #define silc_buffer_len(buffer)
+ *
+ * DESCRIPTION
+ *
+ *    Returns the current length of the data area of the buffer.
+ *
+ * SOURCE
+ */
+#define silc_buffer_len(x) (SilcUInt32)((x)->tail - (x)->data)
+/***/
+
+/****d* silcutil/SilcBufferAPI/silc_buffer_headlen
+ *
  * NAME
  *
- *    #define SILC_BUFFER_END(...)
+ *    #define silc_buffer_headlen(buffer)
  *
  * DESCRIPTION
  *
- *    Returns the true length of the buffer. This is used to pull
- *    the buffer area to the end of the buffer.
+ *    Returns the current length of the head data area of the buffer.
  *
  * SOURCE
  */
-#define SILC_BUFFER_END(x) ((x)->end - (x)->head)
+#define silc_buffer_headlen(x) (SilcUInt32)((x)->data - (x)->head)
+/***/
+
+/****d* silcutil/SilcBufferAPI/silc_buffer_taillen
+ *
+ * NAME
+ *
+ *    #define silc_buffer_taillen(buffer)
+ *
+ * DESCRIPTION
+ *
+ *    Returns the current length of the tail data area of the buffer.
+ *
+ * SOURCE
+ */
+#define silc_buffer_taillen(x) (SilcUInt32)((x)->end - (x)->tail)
 /***/
 
 /* Inline functions */
@@ -164,10 +188,10 @@ typedef struct {
  *
  * DESCRIPTION
  *
- *    Allocates new SilcBuffer and returns it.
+ *    Allocates new SilcBuffer and returns it.  Returns NULL on error.
  *
  ***/
+
 static inline
 SilcBuffer silc_buffer_alloc(SilcUInt32 len)
 {
@@ -184,10 +208,9 @@ SilcBuffer silc_buffer_alloc(SilcUInt32 len)
     return NULL;
 
   /* Set pointers to the new buffer */
-  sb->truelen = len;
   sb->data = sb->head;
   sb->tail = sb->head;
-  sb->end = sb->head + sb->truelen;
+  sb->end = sb->head + len;
 
   return sb;
 }
@@ -211,7 +234,7 @@ void silc_buffer_free(SilcBuffer sb)
   if (sb) {
 #if defined(SILC_DEBUG)
     if (sb->head)
-      memset(sb->head, 'F', sb->truelen);
+      memset(sb->head, 'F', silc_buffer_truelen(sb));
 #endif
     silc_free(sb->head);
     silc_free(sb);
@@ -241,9 +264,8 @@ unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len)
 {
   unsigned char *buf = sb->head;
   if (data_len)
-    *data_len = sb->truelen;
+    *data_len = silc_buffer_truelen(sb);
   sb->head = sb->data = sb->tail = sb->end = NULL;
-  sb->len = sb->truelen = 0;
   return buf;
 }
 
@@ -263,6 +285,11 @@ unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len)
  *    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
@@ -270,7 +297,6 @@ void silc_buffer_set(SilcBuffer sb, unsigned char *data, SilcUInt32 data_len)
 {
   sb->data = sb->head = data;
   sb->tail = sb->end = data + data_len;
-  sb->len = sb->truelen = data_len;
 }
 
 /****f* silcutil/SilcBufferAPI/silc_buffer_pull
@@ -284,7 +310,7 @@ void silc_buffer_set(SilcBuffer sb, unsigned char *data, SilcUInt32 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.
+ *    area before pulling. Returns NULL on error.
  *
  * EXAMPLE
  *
@@ -298,20 +324,22 @@ void silc_buffer_set(SilcBuffer sb, unsigned char *data, SilcUInt32 data_len)
  *    | 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;
-
 #if defined(SILC_DEBUG)
-  assert(len <= (SilcUInt32)(sb->tail - sb->data));
+  assert(len <= silc_buffer_len(sb));
+#else
+  if (len > silc_buffer_len(sb))
+    return NULL;
 #endif
-
   sb->data += len;
-  sb->len -= len;
-
   return old_data;
 }
 
@@ -325,8 +353,8 @@ unsigned char *silc_buffer_pull(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. 
+ *    valid data area is also incremented. Returns a pointer to the
+ *    data area before pushing. Returns NULL on error.
  *
  * EXAMPLE
  *
@@ -341,20 +369,21 @@ unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len)
  *    ---------------------------------
  *               ^
  *
+ *    silc_buffer_push(sb, 20);
+ *
  ***/
 
 static inline
 unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len)
 {
   unsigned char *old_data = sb->data;
-
 #if defined(SILC_DEBUG)
   assert((sb->data - len) >= sb->head);
+#else
+  if ((sb->data - len) < sb->head)
+    return NULL;
 #endif
-
   sb->data -= len;
-  sb->len += len;
-
   return old_data;
 }
 
@@ -362,14 +391,14 @@ unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len)
  *
  * SYNOPSIS
  *
- *    static inline 
+ *    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.
+ *    data area is also incremented. Returns a pointer to the data area
+ *    before pulling. Returns NULL on error.
  *
  * EXAMPLE
  *
@@ -384,20 +413,21 @@ unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len)
  *    ---------------------------------
  *                         ^
  *
+ *    silc_buffer_pull_tail(sb, 23);
+ *
  ***/
 
 static inline
 unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len)
 {
   unsigned char *old_tail = sb->tail;
-
 #if defined(SILC_DEBUG)
-  assert((SilcUInt32)(sb->end - sb->tail) >= len);
+  assert(len <= silc_buffer_taillen(sb));
+#else
+  if (len > silc_buffer_taillen(sb))
+    return NULL;
 #endif
-
   sb->tail += len;
-  sb->len += len;
-
   return old_tail;
 }
 
@@ -412,7 +442,7 @@ unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len)
  *
  *    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.
+ *    tail section before pushing. Returns NULL on error.
  *
  * EXAMPLE
  *
@@ -427,20 +457,21 @@ unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len)
  *    ---------------------------------
  *                             ^
  *
+ *    silc_buffer_push_tail(sb, 23);
+ *
  ***/
 
 static inline
 unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len)
 {
   unsigned char *old_tail = sb->tail;
-
 #if defined(SILC_DEBUG)
   assert((sb->tail - len) >= sb->data);
+#else
+  if ((sb->tail - len) < sb->data)
+    return NULL;
 #endif
-
   sb->tail -= len;
-  sb->len -= len;
-
   return old_tail;
 }
 
@@ -449,14 +480,14 @@ unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len)
  * SYNOPSIS
  *
  *    static inline
- *    unsigned char *silc_buffer_put_head(SilcBuffer sb, 
+ *    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. 
+ *    data area. Returns NULL on error.
  *
  * EXAMPLE
  *
@@ -464,7 +495,9 @@ unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len)
  *    | head  | data       | tail     |
  *    ---------------------------------
  *    ^
- *    Puts data to the head section. 
+ *    Puts data to the head section.
+ *
+ *    silc_buffer_put_head(sb, data, data_len);
  *
  ***/
 
@@ -474,7 +507,10 @@ unsigned char *silc_buffer_put_head(SilcBuffer sb,
                                    SilcUInt32 len)
 {
 #if defined(SILC_DEBUG)
-  assert((SilcUInt32)(sb->data - sb->head) >= len);
+  assert(len <= silc_buffer_headlen(sb));
+#else
+  if (len > silc_buffer_headlen(sb))
+    return NULL;
 #endif
   return (unsigned char *)memcpy(sb->head, data, len);
 }
@@ -491,7 +527,7 @@ unsigned char *silc_buffer_put_head(SilcBuffer sb,
  * DESCRIPTION
  *
  *    Puts data at the start of the valid data area. Returns a pointer
- *    to the copied data area.
+ *    to the copied data area.  Returns NULL on error.
  *
  * EXAMPLE
  *
@@ -501,6 +537,8 @@ unsigned char *silc_buffer_put_head(SilcBuffer sb,
  *            ^
  *            Puts data to the data section.
  *
+ *    silc_buffer_put(sb, data, data_len);
+ *
  ***/
 
 static inline
@@ -509,7 +547,10 @@ unsigned char *silc_buffer_put(SilcBuffer sb,
                               SilcUInt32 len)
 {
 #if defined(SILC_DEBUG)
-  assert((SilcUInt32)(sb->tail - sb->data) >= len);
+  assert(len <= silc_buffer_len(sb));
+#else
+  if (len > silc_buffer_len(sb))
+    return NULL;
 #endif
   return (unsigned char *)memcpy(sb->data, data, len);
 }
@@ -526,7 +567,7 @@ unsigned char *silc_buffer_put(SilcBuffer sb,
  * DESCRIPTION
  *
  *    Puts data at the tail of the buffer. Returns pointer to the copied
- *    data area. 
+ *    data area.  Returns NULL on error.
  *
  * EXAMPLE
  *
@@ -536,6 +577,8 @@ unsigned char *silc_buffer_put(SilcBuffer sb,
  *                             ^
  *                            Puts data to the tail section.
  *
+ *    silc_buffer_put_tail(sb, data, data_len);
+ *
  ***/
 
 static inline
@@ -544,7 +587,10 @@ unsigned char *silc_buffer_put_tail(SilcBuffer sb,
                                    SilcUInt32 len)
 {
 #if defined(SILC_DEBUG)
-  assert((SilcUInt32)(sb->end - sb->tail) >= len);
+  assert(len <= silc_buffer_taillen(sb));
+#else
+  if (len > silc_buffer_taillen(sb))
+    return NULL;
 #endif
   return (unsigned char *)memcpy(sb->tail, data, len);
 }
@@ -560,7 +606,7 @@ unsigned char *silc_buffer_put_tail(SilcBuffer sb,
  *
  *    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.
+ *    silc_buffer_pull_tail.  Returns NULL on error.
  *
  ***/
 
@@ -574,6 +620,27 @@ SilcBuffer silc_buffer_alloc_size(SilcUInt32 len)
   return sb;
 }
 
+/****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;
+}
+
 /****f* silcutil/SilcBufferAPI/silc_buffer_clear
  *
  * SYNOPSIS
@@ -591,12 +658,8 @@ SilcBuffer silc_buffer_alloc_size(SilcUInt32 len)
 static inline
 void silc_buffer_clear(SilcBuffer sb)
 {
-  if (!sb)
-    return;
-  memset(sb->head, 0, sb->truelen);
-  sb->data = sb->head;
-  sb->tail = sb->head;
-  sb->len = 0;
+  memset(sb->head, 0, silc_buffer_truelen(sb));
+  silc_buffer_reset(sb);
 }
 
 /****f* silcutil/SilcBufferAPI/silc_buffer_copy
@@ -610,7 +673,7 @@ void silc_buffer_clear(SilcBuffer sb)
  *
  *    Generates copy of a SilcBuffer. This copies everything inside the
  *    currently valid data area, nothing more. Use silc_buffer_clone to
- *    copy entire buffer.
+ *    copy entire buffer.  Returns NULL on error.
  *
  ***/
 
@@ -619,10 +682,10 @@ SilcBuffer silc_buffer_copy(SilcBuffer sb)
 {
   SilcBuffer sb_new;
 
-  sb_new = silc_buffer_alloc_size(sb->len);
+  sb_new = silc_buffer_alloc_size(silc_buffer_len(sb));
   if (!sb_new)
     return NULL;
-  silc_buffer_put(sb_new, sb->data, sb->len);
+  silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
 
   return sb_new;
 }
@@ -638,7 +701,7 @@ SilcBuffer silc_buffer_copy(SilcBuffer sb)
  *
  *    Clones SilcBuffer. This generates new SilcBuffer and copies
  *    everything from the source buffer. The result is exact clone of
- *    the original buffer.
+ *    the original buffer.  Returns NULL on error.
  *
  ***/
 
@@ -647,13 +710,12 @@ SilcBuffer silc_buffer_clone(SilcBuffer sb)
 {
   SilcBuffer sb_new;
 
-  sb_new = silc_buffer_alloc_size(sb->truelen);
+  sb_new = silc_buffer_alloc_size(silc_buffer_truelen(sb));
   if (!sb_new)
     return NULL;
-  silc_buffer_put(sb_new, sb->head, sb->truelen);
-  sb_new->data = sb_new->head + (sb->data - sb->head);
-  sb_new->tail = sb_new->data + sb->len;
-  sb_new->len = sb->len;
+  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;
 }
@@ -667,34 +729,272 @@ SilcBuffer silc_buffer_clone(SilcBuffer sb)
  *
  * DESCRIPTION
  *
- *    Reallocates buffer. Old data is saved into the new buffer. Returns
- *    new SilcBuffer pointer. The buffer is exact clone of the old one
- *    except that there is now more space at the end of buffer.
+ *    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 space
+ *    at the end of buffer.  This always returns the same `sb' unless `sb'
+ *    was NULL. Returns NULL on error.
  *
  ***/
 
 static inline
 SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize)
 {
-  SilcBuffer sb_new;
+  SilcUInt32 hlen, dlen;
+  unsigned char *h;
 
   if (!sb)
     return silc_buffer_alloc(newsize);
 
-  if (newsize <= sb->truelen)
+  if (newsize <= silc_buffer_truelen(sb))
     return sb;
 
-  sb_new = silc_buffer_alloc_size(newsize);
+  hlen = silc_buffer_headlen(sb);
+  dlen = silc_buffer_len(sb);
+  h = (unsigned char *)silc_realloc(sb->head, newsize);
+  if (!h)
+    return NULL;
+  sb->head = h;
+  sb->data = sb->head + hlen;
+  sb->tail = sb->data + dlen;
+  sb->end = sb->head + newsize;
+
+  return sb;
+}
+
+/****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 on error.
+ *
+ ***/
+
+static inline
+SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize)
+{
+  sb = silc_buffer_realloc(sb, newsize);
+  if (!sb)
+    return NULL;
+  silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
+  return sb;
+}
+
+
+/* SilcStack aware SilcBuffer routines */
+
+/****f* silcutil/SilcBufferAPI/silc_buffer_salloc
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len);
+ *
+ * DESCRIPTION
+ *
+ *    Allocates new SilcBuffer and returns it.
+ *
+ *    This routine use SilcStack are memory source.
+ *
+ ***/
+
+static inline
+SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len)
+{
+  SilcBuffer sb;
+
+  /* Allocate new SilcBuffer */
+  sb = (SilcBuffer)silc_scalloc(stack, 1, sizeof(*sb));
+  if (!sb)
+    return NULL;
+
+  /* Allocate the actual data area */
+  sb->head = (unsigned char *)silc_smalloc_ua(stack, len);
+  if (!sb->head)
+    return NULL;
+
+  /* Set pointers to the new buffer */
+  sb->data = sb->head;
+  sb->tail = sb->head;
+  sb->end = sb->head + len;
+
+  return sb;
+}
+
+/****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.
+ *
+ *    This routine use SilcStack are memory source.
+ *
+ ***/
+
+static inline
+SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len)
+{
+  SilcBuffer sb = silc_buffer_salloc(stack, len);
+  if (!sb)
+    return NULL;
+  silc_buffer_pull_tail(sb, len);
+  return sb;
+}
+
+/****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 space
+ *    at the end of buffer.
+ *
+ *    This routine use SilcStack are memory source.
+ *
+ ***/
+
+static inline
+SilcBuffer silc_buffer_srealloc(SilcStack stack,
+                               SilcBuffer sb, SilcUInt32 newsize)
+{
+  SilcUInt32 hlen, dlen;
+  unsigned char *h;
+
+  if (!sb)
+    return silc_buffer_salloc(stack, newsize);
+
+  if (newsize <= silc_buffer_truelen(sb))
+    return sb;
+
+  hlen = silc_buffer_headlen(sb);
+  dlen = silc_buffer_len(sb);
+  h = (unsigned char *)silc_srealloc_ua(stack, silc_buffer_truelen(sb),
+                                       sb->head, newsize);
+  if (!h) {
+    /* Do slow and stack wasting realloc.  The old sb->head is lost and
+       is freed eventually. */
+    h = silc_smalloc_ua(stack, newsize);
+    if (!h)
+      return NULL;
+    memcpy(h, sb->head, silc_buffer_truelen(sb));
+  }
+
+  sb->head = h;
+  sb->data = sb->head + hlen;
+  sb->tail = sb->data + dlen;
+  sb->end = sb->head + newsize;
+
+  return sb;
+}
+
+/****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.
+ *
+ *    This routine use SilcStack are memory source.
+ *
+ ***/
+
+static inline
+SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
+                                    SilcBuffer sb, SilcUInt32 newsize)
+{
+  sb = silc_buffer_srealloc(stack, sb, newsize);
+  if (!sb)
+    return NULL;
+  silc_buffer_pull_tail(sb, silc_buffer_taillen(sb));
+  return sb;
+}
+
+/****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.
+ *
+ *    This routine use SilcStack are memory source.
+ *
+ ***/
+
+static inline
+SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb)
+{
+  SilcBuffer sb_new;
+
+  sb_new = silc_buffer_salloc_size(stack, silc_buffer_len(sb));
   if (!sb_new)
     return NULL;
-  silc_buffer_put(sb_new, sb->head, sb->truelen);
-  sb_new->data = sb_new->head + (sb->data - sb->head);
-  sb_new->tail = sb_new->data + sb->len;
-  sb_new->len = sb->len;
+  silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb));
+
+  return sb_new;
+}
+
+/****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.
+ *
+ *    This routine use SilcStack are memory source.
+ *
+ ***/
+
+static inline
+SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb)
+{
+  SilcBuffer sb_new;
 
-  silc_buffer_free(sb);
+  sb_new = silc_buffer_salloc_size(stack, silc_buffer_truelen(sb));
+  if (!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;
 }
 
-#endif
+#endif /* SILCBUFFER_H */