]> xenbits.xensource.com Git - libvirt.git/commitdiff
util: virbuffer: introduce virBufferEscapeN
authorPavel Hrdina <phrdina@redhat.com>
Thu, 23 Feb 2017 12:43:32 +0000 (13:43 +0100)
committerPavel Hrdina <phrdina@redhat.com>
Fri, 24 Feb 2017 11:58:23 +0000 (12:58 +0100)
Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
src/libvirt_private.syms
src/util/virbuffer.c
src/util/virbuffer.h
tests/virbuftest.c

index 07a35333b144626d2c1bebff4cf92fab103bbcc5..28e595fe584b44a000ca98902ddeac25c5f670d0 100644 (file)
@@ -1286,6 +1286,7 @@ virBufferContentAndReset;
 virBufferCurrentContent;
 virBufferError;
 virBufferEscape;
+virBufferEscapeN;
 virBufferEscapeSexpr;
 virBufferEscapeShell;
 virBufferEscapeString;
index d582e7dbec1ae6af4815d942c08c845958a563b1..41d541b32188c871c9f91970b4837c1e56e29d19 100644 (file)
@@ -33,6 +33,7 @@
 #include "virbuffer.h"
 #include "viralloc.h"
 #include "virerror.h"
+#include "virstring.h"
 
 
 /* If adding more fields, ensure to edit buf.h to match
@@ -588,6 +589,101 @@ virBufferEscape(virBufferPtr buf, char escape, const char *toescape,
     VIR_FREE(escaped);
 }
 
+
+struct _virBufferEscapePair {
+    char escape;
+    char *toescape;
+};
+
+
+/**
+ * virBufferEscapeN:
+ * @buf: the buffer to append to
+ * @format: a printf like format string but with only one %s parameter
+ * @str: the string argument which needs to be escaped
+ * @...: the variable list of escape pairs
+ *
+ * The variable list of arguments @... must be composed of
+ * 'char escape, char *toescape' pairs followed by NULL.
+ *
+ * This has the same functionality as virBufferEscape with the extension
+ * that allows to specify multiple pairs of chars that needs to be escaped.
+ */
+void
+virBufferEscapeN(virBufferPtr buf,
+                 const char *format,
+                 const char *str,
+                 ...)
+{
+    int len;
+    size_t i;
+    char *escaped = NULL;
+    char *out;
+    const char *cur;
+    struct _virBufferEscapePair escapeItem;
+    struct _virBufferEscapePair *escapeList = NULL;
+    size_t nescapeList = 0;
+    va_list ap;
+
+    if ((format == NULL) || (buf == NULL) || (str == NULL))
+        return;
+
+    if (buf->error)
+        return;
+
+    len = strlen(str);
+
+    va_start(ap, str);
+
+    while ((escapeItem.escape = va_arg(ap, int))) {
+        if (!(escapeItem.toescape = va_arg(ap, char *))) {
+            virBufferSetError(buf, errno);
+            goto cleanup;
+        }
+
+        if (strcspn(str, escapeItem.toescape) == len)
+            continue;
+
+        if (VIR_APPEND_ELEMENT_QUIET(escapeList, nescapeList, escapeItem) < 0) {
+            virBufferSetError(buf, errno);
+            goto cleanup;
+        }
+    }
+
+    if (nescapeList == 0) {
+        virBufferAsprintf(buf, format, str);
+        goto cleanup;
+    }
+
+    if (xalloc_oversized(2, len) ||
+        VIR_ALLOC_N_QUIET(escaped, 2 * len + 1) < 0) {
+        virBufferSetError(buf, errno);
+        goto cleanup;
+    }
+
+    cur = str;
+    out = escaped;
+    while (*cur != 0) {
+        for (i = 0; i < nescapeList; i++) {
+            if (strchr(escapeList[i].toescape, *cur)) {
+                *out++ = escapeList[i].escape;
+                break;
+            }
+        }
+        *out++ = *cur;
+        cur++;
+    }
+    *out = 0;
+
+    virBufferAsprintf(buf, format, escaped);
+
+ cleanup:
+    va_end(ap);
+    VIR_FREE(escapeList);
+    VIR_FREE(escaped);
+}
+
+
 /**
  * virBufferURIEncodeString:
  * @buf: the buffer to append to
index 144a1ba06e152d08876b42e07146fe2713093b04..94f14b5b16b7f94a31b34f782d78739958d7461d 100644 (file)
@@ -82,6 +82,8 @@ void virBufferStrcat(virBufferPtr buf, ...)
   ATTRIBUTE_SENTINEL;
 void virBufferEscape(virBufferPtr buf, char escape, const char *toescape,
                      const char *format, const char *str);
+void virBufferEscapeN(virBufferPtr buf, const char *format,
+                      const char *str, ...);
 void virBufferEscapeString(virBufferPtr buf, const char *format,
                            const char *str);
 void virBufferEscapeSexpr(virBufferPtr buf, const char *format,
index 22407ab6a840c7b5216e7cb26a58344bd6f645fe..34160e6b28b3fbd36706c156917b98474d17d556 100644 (file)
@@ -375,6 +375,35 @@ testBufEscapeStr(const void *opaque ATTRIBUTE_UNUSED)
 }
 
 
+static int
+testBufEscapeN(const void *opaque)
+{
+    const struct testBufAddStrData *data = opaque;
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    char *actual;
+    int ret = -1;
+
+    virBufferEscapeN(&buf, "%s", data->data, '\\', "=", ',', ",", NULL);
+
+    if (!(actual = virBufferContentAndReset(&buf))) {
+        VIR_TEST_DEBUG("testBufEscapeN: buf is empty");
+        goto cleanup;
+    }
+
+    if (STRNEQ_NULLABLE(actual, data->expect)) {
+        VIR_TEST_DEBUG("testBufEscapeN: Strings don't match:\n");
+        virTestDifference(stderr, data->expect, actual);
+        goto cleanup;
+    }
+
+    ret = 0;
+
+ cleanup:
+    VIR_FREE(actual);
+    return ret;
+}
+
+
 static int
 mymain(void)
 {
@@ -422,6 +451,18 @@ mymain(void)
     DO_TEST_ESCAPE("\x01\x01\x02\x03\x05\x08",
                    "<c>\n  <el></el>\n</c>");
 
+#define DO_TEST_ESCAPEN(data, expect)                                   \
+    do {                                                                \
+        struct testBufAddStrData info = { data, expect };               \
+        if (virTestRun("Buf: EscapeN", testBufEscapeN, &info) < 0)      \
+            ret = -1;                                                   \
+    } while (0)
+
+    DO_TEST_ESCAPEN("noescape", "noescape");
+    DO_TEST_ESCAPEN("comma,escape", "comma,,escape");
+    DO_TEST_ESCAPEN("equal=escape", "equal\\=escape");
+    DO_TEST_ESCAPEN("comma,equal=escape", "comma,,equal\\=escape");
+
     return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
 }