Added SILC_STR_DELETE buffer format macro.
[crypto.git] / lib / silcutil / silcbuffmt.c
index 366c4478fa9d84eecaa579c2ac4a5ab76c2998cb..7f92c6bf0dc2f84fd6c138ed772436932b217b35 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,18 +92,18 @@ 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:
       {
        const char *regex = va_arg(ap, char *);
        SilcBufferRegexFlags rflags = va_arg(ap, SilcUInt32);
-       SilcBufferStruct match, saved;
+       SilcBufferStruct match;
        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 saved_pos = 0, inclusive_pos = 0;
        int matched = 0, ret_len;
        va_list cp;
 
@@ -103,13 +113,11 @@ int silc_buffer_sformat_vp_i(SilcStack stack, SilcBuffer dst, va_list ap,
        if (!regex)
          goto fail;
 
-       memset(&saved, 0, sizeof(saved));
-
        if (match_nl) {
        start_nl_match:
          /* Match for '\n' in the buffer.  If not found, treat as line
             without '\n' (buffer has only one line, or this is last line). */
-         saved = *dst;
+         saved_pos = silc_buffer_headlen(dst) + silc_buffer_len(dst);
          if (silc_regex_buffer(dst, "\n", &match, NULL))
            dst->tail = match.tail;
        }
@@ -138,7 +146,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 +158,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;
@@ -167,7 +176,9 @@ int silc_buffer_sformat_vp_i(SilcStack stack, SilcBuffer dst, va_list ap,
          flen += (dst->tail - dst->data);
          if (!silc_buffer_pull(dst, (dst->tail - dst->data)))
            goto fail;
-         if (!silc_buffer_pull_tail(dst, (saved.tail - dst->tail)))
+         if (!silc_buffer_pull_tail(dst, (saved_pos -
+                                          silc_buffer_headlen(dst) +
+                                          silc_buffer_len(dst))))
            goto fail;
 
          if (silc_buffer_len(dst) > 0)
@@ -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;
@@ -359,6 +388,34 @@ int silc_buffer_sformat_vp_i(SilcStack stack, SilcBuffer dst, va_list ap,
       }
       break;
 
+    case SILC_PARAM_DELETE:
+      {
+       int n = va_arg(ap, int);
+
+       if (!process)
+         break;
+
+       if (n == -1) {
+         /* Move all data from tail to data area */
+         if (dst->data != dst->tail) {
+           memmove(dst->data, dst->tail, silc_buffer_taillen(dst));
+           memset(dst->end - silc_buffer_len(dst), 0, silc_buffer_len(dst));
+           silc_buffer_push_tail(dst, silc_buffer_len(dst));
+         }
+         break;
+       }
+
+       if (n > silc_buffer_len(dst))
+         goto fail;
+
+       memmove(dst->data, dst->data + n, (silc_buffer_len(dst) - n) +
+               silc_buffer_taillen(dst));
+       memset(dst->end - n, 0, n);
+       silc_buffer_push_tail(dst, silc_buffer_len(dst) - n);
+
+       break;
+      }
+
     case SILC_PARAM_OFFSET:
       {
        int offst = va_arg(ap, int);
@@ -509,11 +566,11 @@ int silc_buffer_sunformat_vp_i(SilcStack stack, SilcBuffer src, va_list ap,
       {
        const char *regex = va_arg(ap, char *);
        SilcBufferRegexFlags rflags = va_arg(ap, SilcUInt32);
-       SilcBufferStruct match, saved;
+       SilcBufferStruct match;
        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 saved_pos = 0, inclusive_pos = 0;
        int matched = 0, ret_len;
        va_list cp;
 
@@ -523,13 +580,12 @@ int silc_buffer_sunformat_vp_i(SilcStack stack, SilcBuffer src, va_list ap,
        if (!regex)
          goto fail;
 
-       memset(&saved, 0, sizeof(saved));
 
        if (match_nl) {
        start_nl_match:
          /* Match for '\n' in the buffer.  If not found, treat as line
             without '\n' (buffer has only one line, or this is last line). */
-         saved = *src;
+         saved_pos = silc_buffer_headlen(src) + silc_buffer_len(src);
          if (silc_regex_buffer(src, "\n", &match, NULL))
            src->tail = match.tail;
        }
@@ -558,7 +614,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 +626,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);
@@ -587,7 +644,9 @@ int silc_buffer_sunformat_vp_i(SilcStack stack, SilcBuffer src, va_list ap,
          UNFORMAT_HAS_SPACE(src, src->tail - src->data);
          if (!silc_buffer_pull(src, (src->tail - src->data)))
            goto fail;
-         if (!silc_buffer_pull_tail(src, (saved.tail - src->tail)))
+         if (!silc_buffer_pull_tail(src, (saved_pos -
+                                          silc_buffer_headlen(src) +
+                                          silc_buffer_len(src))))
            goto fail;
 
          if (silc_buffer_len(src) > 0)
@@ -1066,6 +1125,9 @@ int silc_buffer_sunformat_vp_i(SilcStack stack, SilcBuffer src, va_list ap,
       goto ok;
       break;
 
+    case SILC_PARAM_DELETE:
+      break;
+
     default:
       SILC_LOG_DEBUG(("Bad buffer formatting type `%d'. Could not "
                      "format the data.", fmt));