appending with SilcBuffer format API.
Added silc_buffer_equal.
+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
#include "silcthread.h"
#include "silcschedule.h"
#include "silclog.h"
+#include "silcfileutil.h"
#include "silcbuffer.h"
#include "silcbuffmt.h"
#include "silcasync.h"
#include "silchashtable.h"
#include "silcstream.h"
#include "silcnet.h"
-#include "silcfileutil.h"
#include "silcbase64.h"
#include "silcstrutil.h"
#include "silcutf8.h"
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
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);
}
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);
}
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);
}
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;
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
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 */
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 { \
silc_buffer_pull(dst, tmp_len);
flen += tmp_len;
}
+ break;
}
- break;
case SILC_PARAM_REGEX:
{
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;
}
if (rflags & SILC_STR_REGEX_INCLUSIVE) {
- saved_incl = dst->tail;
+ inclusive_pos = dst->tail - match.tail;
dst->tail = match.tail;
}
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;
/* 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:
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;
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;
}
if (rflags & SILC_STR_REGEX_INCLUSIVE) {
- saved_incl = src->tail;
+ inclusive_pos = src->tail - match.tail;
src->tail = match.tail;
}
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);
***/
#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
* 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
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
#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 */
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);
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/'"));