summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorGergely Nagy <algernon@balabit.hu>2012-06-22 15:28:53 +0200
committerGergely Nagy <algernon@balabit.hu>2012-06-22 15:28:53 +0200
commit76a5b0ad508949707cd77c61c173e543221fcef9 (patch)
treeaf52fdef24a95ba9b313b704b28afa474a0f67dc /lib
parent168dc768a7e5f70f2a0b03402f42a173924522c7 (diff)
downloadlibumberlog-76a5b0ad508949707cd77c61c173e543221fcef9.tar.gz
libumberlog-76a5b0ad508949707cd77c61c173e543221fcef9.tar.xz
libumberlog-76a5b0ad508949707cd77c61c173e543221fcef9.zip
Escape values directly into a buffer
Instead of precomputing a buffer length, do only one pass, extending the buffer as necessary. Signed-off-by: Miloslav Trmač <mitr@redhat.com> Signed-off-by: Gergely Nagy <algernon@balabit.hu>
Diffstat (limited to 'lib')
-rw-r--r--lib/buffer.c80
1 files changed, 55 insertions, 25 deletions
diff --git a/lib/buffer.c b/lib/buffer.c
index 5cc94ed..ef4e2d7 100644
--- a/lib/buffer.c
+++ b/lib/buffer.c
@@ -70,7 +70,7 @@ _ul_buffer_reserve_size (ul_buffer_t *buffer, size_t size)
}
static inline int
-_ul_str_escape (const char *str, char *dest, size_t *length)
+_ul_str_escape (ul_buffer_t *dest, const char *str)
{
/* Assumes ASCII! Keep in sync with the switch! */
static const unsigned char json_exceptions[UCHAR_MAX + 1] =
@@ -84,51 +84,85 @@ _ul_str_escape (const char *str, char *dest, size_t *length)
};
const unsigned char *p;
- char *q;
+ char *q, *end;
if (!str)
return -1;
p = (unsigned char *)str;
- q = dest;
+ q = dest->ptr;
+ end = dest->alloc_end;
+
+#define BUFFER_RESERVE(SIZE) \
+ do \
+ { \
+ if (end - q < (SIZE)) \
+ { \
+ dest->ptr = q; \
+ if (_ul_buffer_reserve_size (dest, (SIZE)) != 0) \
+ return -1; \
+ q = dest->ptr; \
+ end = dest->alloc_end; \
+ } \
+ } \
+ while (0)
while (*p)
{
if (json_exceptions[*p] == 0)
- *q++ = *p;
+ {
+ /* This is a slightly faster variant of equivalent to
+ BUFFER_RESERVE (1) */
+ if (q == end)
+ {
+ dest->ptr = q;
+ if (_ul_buffer_reserve_size (dest, 1) != 0)
+ return -1;
+ q = dest->ptr;
+ end = dest->alloc_end;
+ }
+ *q++ = *p;
+ }
else
{
/* Keep in sync with json_exceptions! */
switch (*p)
{
case '\b':
- *q++ = '\\';
- *q++ = 'b';
+ BUFFER_RESERVE (2);
+ memcpy (q, "\\b", 2);
+ q += 2;
break;
case '\n':
- *q++ = '\\';
- *q++ = 'n';
+ BUFFER_RESERVE (2);
+ memcpy (q, "\\n", 2);
+ q += 2;
break;
case '\r':
- *q++ = '\\';
- *q++ = 'r';
+ BUFFER_RESERVE (2);
+ memcpy (q, "\\r", 2);
+ q += 2;
break;
case '\t':
- *q++ = '\\';
- *q++ = 't';
+ BUFFER_RESERVE (2);
+ memcpy (q, "\\t", 2);
+ q += 2;
break;
case '\\':
- *q++ = '\\';
- *q++ = '\\';
+ BUFFER_RESERVE (2);
+ memcpy (q, "\\\\", 2);
+ q += 2;
break;
case '"':
- *q++ = '\\';
- *q++ = '"';
+ BUFFER_RESERVE (2);
+ memcpy (q, "\\\"", 2);
+ q += 2;
break;
default:
{
static const char json_hex_chars[16] = "0123456789abcdef";
+ BUFFER_RESERVE (6);
*q++ = '\\';
*q++ = 'u';
*q++ = '0';
@@ -141,10 +175,8 @@ _ul_str_escape (const char *str, char *dest, size_t *length)
}
p++;
}
+ dest->ptr = q;
- *q = 0;
- if (length)
- *length = q - dest;
return 0;
}
@@ -166,10 +198,9 @@ ul_buffer_append (ul_buffer_t *buffer, const char *key, const char *value)
/* Append the key to the buffer */
escape_buffer.ptr = escape_buffer.msg;
- if (_ul_buffer_reserve_size (&escape_buffer, strlen (key) * 6 + 1) != 0)
- goto err;
- if (_ul_str_escape (key, escape_buffer.msg, &lk) != 0)
+ if (_ul_str_escape (&escape_buffer, key) != 0)
goto err;
+ lk = escape_buffer.ptr - escape_buffer.msg;
if (_ul_buffer_reserve_size (buffer, lk + 4) != 0)
goto err;
@@ -182,10 +213,9 @@ ul_buffer_append (ul_buffer_t *buffer, const char *key, const char *value)
/* Append the value to the buffer */
escape_buffer.ptr = escape_buffer.msg;
- if (_ul_buffer_reserve_size (&escape_buffer, strlen (value) * 6 + 1) != 0)
- goto err;
- if (_ul_str_escape (value, escape_buffer.msg, &lv) != 0)
+ if (_ul_str_escape (&escape_buffer, value) != 0)
goto err;
+ lv = escape_buffer.ptr - escape_buffer.msg;
if (_ul_buffer_reserve_size (buffer, lv + 2) != 0)
goto err;