Added SILC_STR_STRING and SILC_STR_STRING_APPEND and support for
authorPekka Riikonen <priikone@silcnet.org>
Sat, 5 Jan 2008 16:09:07 +0000 (16:09 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Sat, 5 Jan 2008 16:09:07 +0000 (16:09 +0000)
appending with SilcBuffer format API.
Added silc_buffer_equal.

CHANGES.RUNTIME
includes/silc.h.in
lib/silcutil/silcbuffer.h
lib/silcutil/silcbuffmt.c
lib/silcutil/silcbuffmt.h
lib/silcutil/silctypes.h
lib/silcutil/tests/test_silcbuffmt.c

index cbe2cca6005ee1e690b15368b75ff9da26818198..b04693d63cf5ba80b67676e7a79616a557dc04eb 100644 (file)
@@ -1,3 +1,14 @@
+Sat Jan  5 18:00:06 EET 2008  Pekka Riikonen <priikone@silcnet.org>
+
+       * Added silc_buffer_equal to lib/silcutil/silcbuffer.h.
+
+       * Added SILC_STR_STRING and SILC_STR_STRING_APPEND buffer format
+         macros.  Affected files are lib/silcutil/silcbuffmt.[ch].
+
+       * Added support for matching and appending with SILC_STR_REGEX
+         and SILC_STR_STRING_APPEND.  Affected files are
+         lib/silcutil/silcbuffmt.[ch].
+
 Thu Jan  3 18:37:42 EET 2008  Pekka Riikonen <priikone@silcnet.org>
 
        * Added SilcStack support to silc_regex and silc_regex_buffer
index 88fa7d16e449b126ff716a788c84be55b4b985a1..669c1343c375d0bcdc4352a20f12be5acfb4f528 100644 (file)
@@ -255,6 +255,7 @@ extern "C" {
 #include "silcthread.h"
 #include "silcschedule.h"
 #include "silclog.h"
+#include "silcfileutil.h"
 #include "silcbuffer.h"
 #include "silcbuffmt.h"
 #include "silcasync.h"
@@ -283,7 +284,6 @@ extern "C" {
 #include "silchashtable.h"
 #include "silcstream.h"
 #include "silcnet.h"
-#include "silcfileutil.h"
 #include "silcbase64.h"
 #include "silcstrutil.h"
 #include "silcutf8.h"
index 30f11dc344d7c9177988f2d3a9ba79e528abb751..3a3db7b679ffc7283060054813544fc80e2b69a7 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
@@ -725,6 +725,14 @@ unsigned char *silc_buffer_put_head(SilcBuffer sb,
     return NULL;
   }
 
+  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);
 }
 
@@ -768,6 +776,14 @@ unsigned char *silc_buffer_put(SilcBuffer sb,
     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);
 }
 
@@ -811,6 +827,14 @@ unsigned char *silc_buffer_put_tail(SilcBuffer sb,
     return NULL;
   }
 
+  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);
 }
 
@@ -1165,14 +1189,8 @@ SilcBuffer silc_buffer_srealloc(SilcStack stack,
   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;
@@ -1314,6 +1332,106 @@ SilcBool silc_buffer_senlarge(SilcStack stack, SilcBuffer sb, SilcUInt32 size)
   return TRUE;
 }
 
+/****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)
+{
+  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/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;
+
+  /* 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
@@ -1367,4 +1485,49 @@ unsigned char *silc_buffer_strchr(SilcBuffer sb, int c, SilcBool first)
   return NULL;
 }
 
+/****f* silcutil/SilcBufferAPI/silc_buffer_cmp
+ *
+ * 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/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 /* SILCBUFFER_H */
index 366c4478fa9d84eecaa579c2ac4a5ab76c2998cb..559e7309d9cf700ce2cc9259dbe173ea7a4e60b4 100644 (file)
@@ -31,6 +31,16 @@ do {                                                 \
   flen += req;                                         \
 } while(0)
 
+/* Check that buffer has enough room to format data in it, if not
+   allocate more.  This will append, thus not replacing any existing data. */
+#define FORMAT_HAS_SPACE_APPEND(s, b, req)                             \
+do {                                                                   \
+  if (silc_buffer_len(b) < req)                                                \
+    if (silc_unlikely(!silc_buffer_sappend(s, b, req - silc_buffer_len(b)))) \
+      goto fail;                                                       \
+  flen += req;                                                         \
+} while(0)
+
 /* Check that there is data to be unformatted */
 #define UNFORMAT_HAS_SPACE(b, req)                     \
 do {                                                   \
@@ -82,8 +92,8 @@ int silc_buffer_sformat_vp_i(SilcStack stack, SilcBuffer dst, va_list ap,
          silc_buffer_pull(dst, tmp_len);
          flen += tmp_len;
        }
+       break;
       }
-      break;
 
     case SILC_PARAM_REGEX:
       {
@@ -93,7 +103,7 @@ int silc_buffer_sformat_vp_i(SilcStack stack, SilcBuffer dst, va_list ap,
        SilcBool match_all = (rflags & SILC_STR_REGEX_ALL) != 0;
        SilcBool match_nl = (rflags & SILC_STR_REGEX_NL) != 0;
        SilcBool ret;
-       unsigned char *saved_incl = NULL;
+       SilcUInt32 inclusive_pos = 0;
        int matched = 0, ret_len;
        va_list cp;
 
@@ -138,7 +148,7 @@ int silc_buffer_sformat_vp_i(SilcStack stack, SilcBuffer dst, va_list ap,
        }
 
        if (rflags & SILC_STR_REGEX_INCLUSIVE) {
-         saved_incl = dst->tail;
+         inclusive_pos = dst->tail - match.tail;
          dst->tail = match.tail;
        }
 
@@ -150,7 +160,8 @@ int silc_buffer_sformat_vp_i(SilcStack stack, SilcBuffer dst, va_list ap,
          goto fail;
 
        if (rflags & SILC_STR_REGEX_INCLUSIVE)
-         dst->tail = saved_incl;
+         if (!silc_buffer_pull_tail(dst, inclusive_pos))
+           goto fail;
 
        /* Advance buffer after formatting */
        flen += ret_len;
@@ -176,8 +187,8 @@ int silc_buffer_sformat_vp_i(SilcStack stack, SilcBuffer dst, va_list ap,
 
        /* Skip to the next SILC_PARAM_END */
        silc_buffer_sformat_vp_i(NULL, NULL, ap, FALSE);
+       break;
       }
-      break;
 
     case SILC_PARAM_UI8_STRING:
     case SILC_PARAM_UI16_STRING:
@@ -194,7 +205,25 @@ int silc_buffer_sformat_vp_i(SilcStack stack, SilcBuffer dst, va_list ap,
 
        if (x && tmp_len) {
          FORMAT_HAS_SPACE(stack, dst, tmp_len);
-         silc_buffer_put(dst, (unsigned char *)x, tmp_len);
+         silc_buffer_put(dst, x, tmp_len);
+         silc_buffer_pull(dst, tmp_len);
+       }
+       break;
+      }
+
+    case SILC_PARAM_UI8_STRING | SILC_PARAM_APPEND:
+    case SILC_PARAM_UI16_STRING | SILC_PARAM_APPEND:
+    case SILC_PARAM_UI32_STRING | SILC_PARAM_APPEND:
+      {
+       char *x = va_arg(ap, char *);
+       SilcUInt32 tmp_len = x ? strlen(x) : 0;
+
+       if (!process)
+         break;
+
+       if (x && tmp_len) {
+         FORMAT_HAS_SPACE_APPEND(stack, dst, tmp_len);
+         silc_buffer_put(dst, x, tmp_len);
          silc_buffer_pull(dst, tmp_len);
        }
        break;
@@ -513,7 +542,7 @@ int silc_buffer_sunformat_vp_i(SilcStack stack, SilcBuffer src, va_list ap,
        SilcBool match_all = (rflags & SILC_STR_REGEX_ALL) != 0;
        SilcBool match_nl = (rflags & SILC_STR_REGEX_NL) != 0;
        SilcBool ret;
-       unsigned char *saved_incl = NULL;
+       SilcUInt32 inclusive_pos = 0;
        int matched = 0, ret_len;
        va_list cp;
 
@@ -558,7 +587,7 @@ int silc_buffer_sunformat_vp_i(SilcStack stack, SilcBuffer src, va_list ap,
        }
 
        if (rflags & SILC_STR_REGEX_INCLUSIVE) {
-         saved_incl = src->tail;
+         inclusive_pos = src->tail - match.tail;
          src->tail = match.tail;
        }
 
@@ -570,7 +599,8 @@ int silc_buffer_sunformat_vp_i(SilcStack stack, SilcBuffer src, va_list ap,
          goto fail;
 
        if (rflags & SILC_STR_REGEX_INCLUSIVE)
-         src->tail = saved_incl;
+         if (!silc_buffer_pull_tail(src, inclusive_pos))
+           goto fail;
 
        /* Advance buffer after formatting */
        UNFORMAT_HAS_SPACE(src, ret_len);
index 4334dc571793470dd77dae602cdb3810c5b64cda..32aa9bb69a77f9493a0744ba17c2b690e82774d9 100644 (file)
@@ -531,6 +531,41 @@ int silc_buffer_sstrformat(SilcStack stack, SilcBuffer dst, ...);
  ***/
 #define SILC_STR_STRING(x) SILC_PARAM_UI8_STRING, (x)
 
+/****d* silcutil/SilcBufferFormatAPI/SILC_STR_STRING_APPEND
+ *
+ * NAME
+ *
+ *    #define SILC_STR_STRING_APPEND() ...
+ *
+ * DESCRIPTION
+ *
+ *    Encode NULL terminated string and append it to the buffer without
+ *    replacing any data if the end of the data area is reached before
+ *    encoding the whole string.  If buffer has tail area, it will not be
+ *    replaced if the string is longer than the current data area, but the
+ *    buffer will be enlarged and the tail area will be copied to the new
+ *    tail area in order not to replace any data while appending the string.
+ *    This will then enlarge the current data area.
+ *
+ *    Use this only for formatting.
+ *
+ *    Formatting:  SILC_STR_STRING_APPEND(char *)
+ *
+ *    For unformatting use one of the SILC_STR_*_STRING macros, which
+ *    automatically gets the length of the string from the buffer.  Note
+ *    SILC_STR_STRING_APPEND does not save the length of the string into the
+ *    buffer.  The caller must do that in order for the unformatting macros
+ *    to work.
+ *
+ *    Example:
+ *
+ *    Formatting:    ..., SILC_STR_UINT32(strlen(string)),
+ *                        SILC_STR_STRING_APPEND(string), ...
+ *    Unformatting:  ..., SILC_STR_UI32_STRING(&string), ...
+ *
+ ***/
+#define SILC_STR_STRING_APPEND(x) SILC_PARAM_UI8_STRING | SILC_PARAM_APPEND, (x)
+
 /****d* silcutil/SilcBufferFormatAPI/SILC_STR_*_STRING
  *
  * NAME
@@ -839,10 +874,13 @@ typedef enum {
  *                         SILC_STR_STRING("bar"),
  *                       SILC_STR_END, SILC_STR_END);
  *
- *    // sed 's/foo/bar/g', replace all foo's with bar
+ *    // sed 's/foo/barbar/g', replace all foo's with barbar, without
+ *    // overwriting any data in the buffer, but appending it.  The match
+ *    // must be SILC_STR_REGEX_INCLUSIVE to make appending work.
  *    silc_buffer_format(buffer,
- *                       SILC_STR_REGEX("foo", SILC_STR_REGEX_ALL),
- *                         SILC_STR_STRING("bar"),
+ *                       SILC_STR_REGEX("foo", SILC_STR_REGEX_ALL |
+ *                                             SILC_STR_REGEX_INCLUSIVE),
+ *                         SILC_STR_STRING_APPEND("barbar"),
  *                       SILC_STR_END, SILC_STR_END);
  *
  *    // sed '/baz/s/foo/bar/g, replace all foo's with bar on lines with baz
index a4a06d9e2cbdb772b7c0d19018e89a84b8193d84..f060a3e08f80e04d1b6a2815b6fb8d8a706d149c 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2002 - 2007 Pekka Riikonen
+  Copyright (C) 2002 - 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
@@ -312,6 +312,7 @@ typedef SilcUInt32 SilcParam;
 #define SILC_PARAM_REGEX         109
 #define SILC_PARAM_OFFSET_START  110
 #define SILC_PARAM_OFFSET_END    111
+#define SILC_PARAM_APPEND        112
 #define SILC_PARAM_ALLOC         0x00010000     /* Allocate, bitmask */
 
 /* Macros */
index dba97fd02451170693536d49ada3dbe72424e154..16c4483cf9cc554bdc8cfd7b6a30d9a7aafd9e23 100644 (file)
@@ -14,8 +14,8 @@ int print(SilcStack stack, SilcBuffer buf, void *value, void *context)
 int main(int argc, char **argv)
 {
   SilcBool success = FALSE;
-  char string[1024];
-  SilcBufferStruct buf;
+  char string[1024], *astring;
+  SilcBufferStruct buf, buf2;
 
   if (argc > 1 && !strcmp(argv[1], "-d")) {
     silc_log_debug(TRUE);
@@ -38,6 +38,23 @@ int main(int argc, char **argv)
   if (strcmp("This is barbar", silc_buffer_data(&buf)))
     goto err;
 
+  silc_snprintf(string, sizeof(string), "This is foobar string!!");
+  astring = silc_memdup(string, strlen(string));
+  silc_buffer_set(&buf, astring, strlen(astring) + 1);
+  SILC_LOG_DEBUG(("sed 's/foo/barbar/g'"));
+  SILC_LOG_DEBUG(("string: %s", astring));
+  if (silc_buffer_format(&buf,
+                        SILC_STR_REGEX("foo", SILC_STR_REGEX_ALL |
+                                              SILC_STR_REGEX_INCLUSIVE),
+                          SILC_STR_STRING_APPEND("barbar"),
+                        SILC_STR_END,
+                        SILC_STR_END) < 0)
+    goto err;
+  silc_buffer_printf(&buf, TRUE);
+  if (strcmp("This is barbarbar string!!", silc_buffer_data(&buf)))
+    goto err;
+  silc_buffer_purge(&buf);
+
   silc_snprintf(string, sizeof(string), "This is foobar\n");
   silc_buffer_set(&buf, string, strlen(string));
   SILC_LOG_DEBUG(("sed 's/\\n/\\0/'"));