Fixed silc_buffer_stdout compilation warning.
[runtime.git] / lib / silcutil / silcbuffer.h
index 5fb70b84ffafb515387d4d3d82dceeef5c06eb41..07146cdf8be68c980c463a9a77b1ad0ad2fa7f76 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1998 - 2007 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
   GNU General Public License for more details.
 
 */
-/* $Id$ */
 
-/****h* silcutil/SILC Buffer Interface
+/****h* silcutil/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
+ * Data buffer interface that provides buffer allocation and manipulation
+ * routines.  SilcBuffer is 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.
+ * the allocated data area.  See the SilcBuffer context for more information.
+ *
+ * The SilcBuffer context is not thread-safe and if same context must be
+ * used from multiple threads concurrency control must be employed.
  *
  ***/
 
 #ifndef SILCBUFFER_H
 #define SILCBUFFER_H
 
-/****s* silcutil/SilcBufferAPI/SilcBuffer
+/****s* silcutil/SilcBuffer
  *
  * NAME
  *
  *    SILC Buffer object. Following short description of the fields
  *    of the buffer.
  *
- * EXAMPLE
- *
- *    unsiged char *head;
+ *     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.
+ *        data area is variable.  Reallocating the buffer may change the
+ *        pointer.
  *
  *        --------------------------------
  *        | head  | data         | tail  |
@@ -59,7 +61,7 @@
  *
  *        Current head section in the buffer is sb->data - sb->head.
  *
- *    unsigned char *data;
+ *     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.
@@ -71,7 +73,7 @@
  *
  *        Current valid data area in the buffer is sb->tail - sb->data.
  *
- *     unsigned char *tail;
+ *      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.
@@ -83,7 +85,7 @@
  *
  *        Current tail section in the buffer is sb->end - sb->tail.
  *
- *    unsigned char *end;
+ *     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.
  *
  *        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.
+ *    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.
  *
  * SOURCE
  */
 typedef struct SilcBufferObject {
-  unsigned char *head;
-  unsigned char *data;
-  unsigned char *tail;
-  unsigned char *end;
+  unsigned char *head;         /* Head of the allocated buffer area */
+  unsigned char *data;         /* Start of the data area */
+  unsigned char *tail;         /* Start of the tail area */
+  unsigned char *end;          /* End of the buffer */
 } *SilcBuffer, SilcBufferStruct;
 /***/
 
 /* Macros */
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_data
+/****f* silcutil/silc_buffer_data
  *
  * NAME
  *
@@ -135,7 +134,22 @@ typedef struct SilcBufferObject {
 #define silc_buffer_data(x) (x)->data
 /***/
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_datalen
+/****f* silcutil/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/silc_buffer_datalen
  *
  * NAME
  *
@@ -161,7 +175,7 @@ typedef struct SilcBufferObject {
 
 /* Inline functions */
 
-/****d* silcutil/SilcBufferAPI/silc_buffer_truelen
+/****d* silcutil/silc_buffer_truelen
  *
  * NAME
  *
@@ -178,7 +192,7 @@ SilcUInt32 silc_buffer_truelen(SilcBuffer x)
   return (SilcUInt32)(x->end - x->head);
 }
 
-/****d* silcutil/SilcBufferAPI/silc_buffer_len
+/****d* silcutil/silc_buffer_len
  *
  * NAME
  *
@@ -195,7 +209,7 @@ SilcUInt32 silc_buffer_len(SilcBuffer x)
   return (SilcUInt32)(x->tail - x->data);
 }
 
-/****d* silcutil/SilcBufferAPI/silc_buffer_headlen
+/****d* silcutil/silc_buffer_headlen
  *
  * NAME
  *
@@ -212,7 +226,7 @@ SilcUInt32 silc_buffer_headlen(SilcBuffer x)
   return (SilcUInt32)(x->data - x->head);
 }
 
-/****d* silcutil/SilcBufferAPI/silc_buffer_taillen
+/****d* silcutil/silc_buffer_taillen
  *
  * NAME
  *
@@ -229,7 +243,7 @@ SilcUInt32 silc_buffer_taillen(SilcBuffer x)
   return (SilcUInt32)(x->end - x->tail);
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_alloc
+/****f* silcutil/silc_buffer_alloc
  *
  * SYNOPSIS
  *
@@ -238,7 +252,8 @@ SilcUInt32 silc_buffer_taillen(SilcBuffer x)
  *
  * DESCRIPTION
  *
- *    Allocates new SilcBuffer and returns it.  Returns NULL on error.
+ *    Allocates new SilcBuffer and returns it.  Returns NULL if system is
+ *    out of memory.
  *
  ***/
 
@@ -267,7 +282,7 @@ SilcBuffer silc_buffer_alloc(SilcUInt32 len)
   return sb;
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_salloc
+/****f* silcutil/silc_buffer_salloc
  *
  * SYNOPSIS
  *
@@ -276,7 +291,8 @@ SilcBuffer silc_buffer_alloc(SilcUInt32 len)
  *
  * DESCRIPTION
  *
- *    Allocates new SilcBuffer and returns it.
+ *    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.
@@ -314,7 +330,7 @@ SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len)
   return sb;
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_free
+/****f* silcutil/silc_buffer_free
  *
  * SYNOPSIS
  *
@@ -346,7 +362,7 @@ void silc_buffer_free(SilcBuffer sb)
   }
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_sfree
+/****f* silcutil/silc_buffer_sfree
  *
  * SYNOPSIS
  *
@@ -377,7 +393,7 @@ void silc_buffer_sfree(SilcStack stack, SilcBuffer sb)
   silc_buffer_free(sb);
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_steal
+/****f* silcutil/silc_buffer_steal
  *
  * SYNOPSIS
  *
@@ -405,7 +421,7 @@ unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len)
   return buf;
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_purge
+/****f* silcutil/silc_buffer_purge
  *
  * SYNOPSIS
  *
@@ -432,7 +448,7 @@ void silc_buffer_purge(SilcBuffer sb)
   silc_free(silc_buffer_steal(sb, NULL));
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_spurge
+/****f* silcutil/silc_buffer_spurge
  *
  * SYNOPSIS
  *
@@ -462,7 +478,7 @@ void silc_buffer_spurge(SilcStack stack, SilcBuffer sb)
   silc_buffer_purge(sb);
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_set
+/****f* silcutil/silc_buffer_set
  *
  * SYNOPSIS
  *
@@ -492,7 +508,7 @@ void silc_buffer_set(SilcBuffer sb, unsigned char *data, SilcUInt32 data_len)
   sb->tail = sb->end = data + data_len;
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_pull
+/****f* silcutil/silc_buffer_pull
  *
  * SYNOPSIS
  *
@@ -503,7 +519,8 @@ 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. Returns NULL on error.
+ *    area before pulling. Returns NULL if the pull would lead to buffer
+ *    overflow or would go beyond the valid data area.
  *
  * EXAMPLE
  *
@@ -526,17 +543,20 @@ static inline
 unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len)
 {
   unsigned char *old_data = sb->data;
-#if defined(SILC_DEBUG)
+
+#ifdef SILC_DIST_INPLACE
   SILC_ASSERT(len <= silc_buffer_len(sb));
-#else
-  if (silc_unlikely(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;
-#endif
+  }
+
   sb->data += len;
   return old_data;
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_push
+/****f* silcutil/silc_buffer_push
  *
  * SYNOPSIS
  *
@@ -547,7 +567,8 @@ unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len)
  *
  *    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 on error.
+ *    data area before pushing. Returns NULL if the push would lead to
+ *    go beyond the buffer boundaries or current data area.
  *
  * EXAMPLE
  *
@@ -570,17 +591,20 @@ static inline
 unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len)
 {
   unsigned char *old_data = sb->data;
-#if defined(SILC_DEBUG)
+
+#ifdef SILC_DIST_INPLACE
   SILC_ASSERT((sb->data - len) >= sb->head);
-#else
-  if (silc_unlikely((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;
-#endif
+  }
+
   sb->data -= len;
   return old_data;
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_pull_tail
+/****f* silcutil/silc_buffer_pull_tail
  *
  * SYNOPSIS
  *
@@ -591,7 +615,7 @@ unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len)
  *
  *    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 on error.
+ *    before pulling. Returns NULL if the pull would lead to buffer overflow.
  *
  * EXAMPLE
  *
@@ -614,17 +638,20 @@ static inline
 unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len)
 {
   unsigned char *old_tail = sb->tail;
-#if defined(SILC_DEBUG)
+
+#ifdef SILC_DIST_INPLACE
   SILC_ASSERT(len <= silc_buffer_taillen(sb));
-#else
-  if (silc_unlikely(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;
-#endif
+  }
+
   sb->tail += len;
   return old_tail;
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_push_tail
+/****f* silcutil/silc_buffer_push_tail
  *
  * SYNOPSIS
  *
@@ -635,7 +662,8 @@ 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. Returns NULL on error.
+ *    tail section before pushing. Returns NULL if the push would lead to
+ *    go beyond buffer boundaries or current tail area.
  *
  * EXAMPLE
  *
@@ -658,17 +686,20 @@ static inline
 unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len)
 {
   unsigned char *old_tail = sb->tail;
-#if defined(SILC_DEBUG)
+
+#ifdef SILC_DIST_INPLACE
   SILC_ASSERT((sb->tail - len) >= sb->data);
-#else
-  if (silc_unlikely((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;
-#endif
+  }
+
   sb->tail -= len;
   return old_tail;
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_put_head
+/****f* silcutil/silc_buffer_put_head
  *
  * SYNOPSIS
  *
@@ -680,7 +711,8 @@ unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len)
  * DESCRIPTION
  *
  *    Puts data at the head of the buffer. Returns pointer to the copied
- *    data area. Returns NULL on error.
+ *    data area. Returns NULL if the data is longer that the current head
+ *    area.
  *
  * EXAMPLE
  *
@@ -699,16 +731,26 @@ unsigned char *silc_buffer_put_head(SilcBuffer sb,
                                    const unsigned char *data,
                                    SilcUInt32 len)
 {
-#if defined(SILC_DEBUG)
+#ifdef SILC_DIST_INPLACE
   SILC_ASSERT(len <= silc_buffer_headlen(sb));
-#else
-  if (silc_unlikely(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;
-#endif
+  }
+
+  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);
+  }
+
   return (unsigned char *)memcpy(sb->head, data, len);
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_put
+/****f* silcutil/silc_buffer_put
  *
  * SYNOPSIS
  *
@@ -720,7 +762,8 @@ 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.  Returns NULL on error.
+ *    to the copied data area.  Returns NULL if the data is longer than the
+ *    current data area.
  *
  * EXAMPLE
  *
@@ -739,16 +782,26 @@ unsigned char *silc_buffer_put(SilcBuffer sb,
                               const unsigned char *data,
                               SilcUInt32 len)
 {
-#if defined(SILC_DEBUG)
+#ifdef SILC_DIST_INPLACE
   SILC_ASSERT(len <= silc_buffer_len(sb));
-#else
-  if (silc_unlikely(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;
-#endif
+  }
+
+  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);
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_put_tail
+/****f* silcutil/silc_buffer_put_tail
  *
  * SYNOPSIS
  *
@@ -760,7 +813,8 @@ unsigned char *silc_buffer_put(SilcBuffer sb,
  * DESCRIPTION
  *
  *    Puts data at the tail of the buffer. Returns pointer to the copied
- *    data area.  Returns NULL on error.
+ *    data area.  Returns NULL if the data is longer than the current tail
+ *    area.
  *
  * EXAMPLE
  *
@@ -779,16 +833,26 @@ unsigned char *silc_buffer_put_tail(SilcBuffer sb,
                                    const unsigned char *data,
                                    SilcUInt32 len)
 {
-#if defined(SILC_DEBUG)
+#ifdef SILC_DIST_INPLACE
   SILC_ASSERT(len <= silc_buffer_taillen(sb));
-#else
-  if (silc_unlikely(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;
-#endif
+  }
+
+  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);
+  }
+
   return (unsigned char *)memcpy(sb->tail, data, len);
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_alloc_size
+/****f* silcutil/silc_buffer_alloc_size
  *
  * SYNOPSIS
  *
@@ -799,7 +863,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.  Returns NULL on error.
+ *    silc_buffer_pull_tail.  Returns NULL if system is out of memory.
  *
  ***/
 
@@ -813,7 +877,7 @@ SilcBuffer silc_buffer_alloc_size(SilcUInt32 len)
   return sb;
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_salloc_size
+/****f* silcutil/silc_buffer_salloc_size
  *
  * SYNOPSIS
  *
@@ -824,7 +888,7 @@ SilcBuffer silc_buffer_alloc_size(SilcUInt32 len)
  *
  *    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 if system is out of memory.
  *
  *    This routine use SilcStack are memory source.  If `stack' is NULL
  *    reverts back to normal allocating routine.
@@ -844,7 +908,7 @@ SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len)
   return sb;
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_reset
+/****f* silcutil/silc_buffer_reset
  *
  * SYNOPSIS
  *
@@ -865,7 +929,7 @@ void silc_buffer_reset(SilcBuffer sb)
   sb->data = sb->tail = sb->head;
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_clear
+/****f* silcutil/silc_buffer_clear
  *
  * SYNOPSIS
  *
@@ -886,7 +950,7 @@ void silc_buffer_clear(SilcBuffer sb)
   silc_buffer_reset(sb);
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_start
+/****f* silcutil/silc_buffer_start
  *
  * SYNOPSIS
  *
@@ -906,7 +970,7 @@ void silc_buffer_start(SilcBuffer sb)
   sb->data = sb->head;
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_end
+/****f* silcutil/silc_buffer_end
  *
  * SYNOPSIS
  *
@@ -928,7 +992,7 @@ void silc_buffer_end(SilcBuffer sb)
   sb->tail = sb->end;
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_copy
+/****f* silcutil/silc_buffer_copy
  *
  * SYNOPSIS
  *
@@ -939,7 +1003,7 @@ void silc_buffer_end(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.  Returns NULL on error.
+ *    copy entire buffer.  Returns NULL if system is out of memory.
  *
  ***/
 
@@ -956,7 +1020,7 @@ SilcBuffer silc_buffer_copy(SilcBuffer sb)
   return sb_new;
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_scopy
+/****f* silcutil/silc_buffer_scopy
  *
  * SYNOPSIS
  *
@@ -967,7 +1031,7 @@ SilcBuffer silc_buffer_copy(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 if system is out of memory.
  *
  *    This routine use SilcStack are memory source.  If `stack' is NULL
  *    reverts back to normal allocating routine.
@@ -990,7 +1054,7 @@ SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb)
   return sb_new;
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_clone
+/****f* silcutil/silc_buffer_clone
  *
  * SYNOPSIS
  *
@@ -1001,7 +1065,7 @@ SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb)
  *
  *    Clones SilcBuffer. This generates new SilcBuffer and copies
  *    everything from the source buffer. The result is exact clone of
- *    the original buffer.  Returns NULL on error.
+ *    the original buffer.  Returns NULL if system is out of memory.
  *
  ***/
 
@@ -1020,7 +1084,7 @@ SilcBuffer silc_buffer_clone(SilcBuffer sb)
   return sb_new;
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_sclone
+/****f* silcutil/silc_buffer_sclone
  *
  * SYNOPSIS
  *
@@ -1031,7 +1095,7 @@ SilcBuffer silc_buffer_clone(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 if system is out of memory.
  *
  *    This routine use SilcStack are memory source.  If `stack' is NULL
  *    reverts back to normal allocating routine.
@@ -1056,7 +1120,7 @@ SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb)
   return sb_new;
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_realloc
+/****f* silcutil/silc_buffer_realloc
  *
  * SYNOPSIS
  *
@@ -1066,9 +1130,14 @@ SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb)
  * 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
+ *    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 on error.
+ *    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.
  *
  ***/
 
@@ -1081,7 +1150,7 @@ SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize)
   if (!sb)
     return silc_buffer_alloc(newsize);
 
-  if (silc_unlikely(newsize <= silc_buffer_truelen(sb)))
+  if (silc_unlikely(newsize == silc_buffer_truelen(sb)))
     return sb;
 
   hlen = silc_buffer_headlen(sb);
@@ -1097,7 +1166,7 @@ SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize)
   return sb;
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_srealloc
+/****f* silcutil/silc_buffer_srealloc
  *
  * SYNOPSIS
  *
@@ -1108,8 +1177,14 @@ 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 space
- *    at the end of 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.
@@ -1132,21 +1207,15 @@ SilcBuffer silc_buffer_srealloc(SilcStack stack,
   if (!sb)
     return silc_buffer_salloc(stack, newsize);
 
-  if (newsize <= silc_buffer_truelen(sb))
+  if (newsize == silc_buffer_truelen(sb))
     return sb;
 
   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) {
-    /* Do slow and stack wasting realloc.  The old sb->head is lost and
-       is freed eventually. */
-    h = (unsigned char *)silc_smalloc(stack, newsize);
-    if (silc_unlikely(!h))
-      return NULL;
-    memcpy(h, sb->head, silc_buffer_truelen(sb));
-  }
+  if (!h)
+    return NULL;
 
   sb->head = h;
   sb->data = sb->head + hlen;
@@ -1156,7 +1225,7 @@ SilcBuffer silc_buffer_srealloc(SilcStack stack,
   return sb;
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_realloc_size
+/****f* silcutil/silc_buffer_realloc_size
  *
  * SYNOPSIS
  *
@@ -1167,7 +1236,7 @@ SilcBuffer silc_buffer_srealloc(SilcStack stack,
  *
  *    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.
+ *    silc_buffer_pull_tail.  Returns NULL if system is out of memory.
  *
  ***/
 
@@ -1181,7 +1250,7 @@ SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize)
   return sb;
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_srealloc_size
+/****f* silcutil/silc_buffer_srealloc_size
  *
  * SYNOPSIS
  *
@@ -1193,7 +1262,7 @@ SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize)
  *
  *    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.
+ *    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.
@@ -1214,7 +1283,7 @@ SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
   return sb;
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_enlarge
+/****f* silcutil/silc_buffer_enlarge
  *
  * SYNOPSIS
  *
@@ -1229,7 +1298,7 @@ SilcBuffer silc_buffer_srealloc_size(SilcStack stack,
  *    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 on error.
+ *    the extra space.  Returns FALSE if system is out of memory.
  *
  ***/
 
@@ -1247,7 +1316,7 @@ SilcBool silc_buffer_enlarge(SilcBuffer sb, SilcUInt32 size)
   return TRUE;
 }
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_senlarge
+/****f* silcutil/silc_buffer_senlarge
  *
  * SYNOPSIS
  *
@@ -1263,7 +1332,7 @@ SilcBool silc_buffer_enlarge(SilcBuffer sb, SilcUInt32 size)
  *    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 on error.
+ *    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.
@@ -1288,4 +1357,228 @@ SilcBool silc_buffer_senlarge(SilcStack stack, SilcBuffer sb, SilcUInt32 size)
   return TRUE;
 }
 
+/****f* silcutil/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)
+{
+  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;
+}
+
+/****f* silcutil/silc_buffer_sappend
+ *
+ * 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;
+
+  /* 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/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;
+}
+
+/****f* silcutil/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)
+{
+  if (silc_buffer_len(sb1) != silc_buffer_len(sb2))
+    return FALSE;
+  return memcmp(sb1->data, sb2->data, silc_buffer_len(sb1)) == 0;
+}
+
+/****f* silcutil/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;
+}
+
+/****f* silcutil/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, (const char *)silc_buffer_data(sb),
+                 silc_buffer_len(sb));
+  if (newline)
+    printf("\n");
+  fflush(stdout);
+}
+
 #endif /* SILCBUFFER_H */