[libvirt] [PATCH] virBuffer: add way to trim back extra text

Eric Blake eblake at redhat.com
Fri May 18 22:42:36 UTC 2012


I'm tired of writing:

bool sep = false;
while (...) {
    if (sep)
       virBufferAddChar(buf, ',');
    sep = true;
    virBufferAdd(buf, str);
}

This makes it easier, allowing one to write:

while (...)
    virBufferAsprintf(buf, "%s,", str);
virBufferTrim(buf, ",", -1);

to trim any remaining comma.

* src/util/buf.h (virBufferTrim): Declare.
* src/util/buf.c (virBufferTrim): New function.
* tests/virbuftest.c (testBufTrim): Test it.
---

I've threatened to do this enough times, so I finally carried through
with my threat :)

 src/util/buf.c     |   36 +++++++++++++++++++++++++++++++++
 src/util/buf.h     |    2 +
 tests/virbuftest.c |   56 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 94 insertions(+), 0 deletions(-)

diff --git a/src/util/buf.c b/src/util/buf.c
index d18f6af..630e4c9 100644
--- a/src/util/buf.c
+++ b/src/util/buf.c
@@ -612,3 +612,39 @@ virBufferStrcat(virBufferPtr buf, ...)
         virBufferAdd(buf, str, -1);
     va_end(ap);
 }
+
+/**
+ * virBufferTrim:
+ * @buf: the buffer to trim
+ * @str: the optional string, to force an exact trim
+ * @len: the number of bytes to trim, or -1 to use @str
+ *
+ * Trim the tail of a buffer.  If @str is provided, the trim only occurs
+ * if the current tail of the buffer matches @str; a non-negative @len
+ * further limits how much of the tail is trimmed.  If @str is NULL, then
+ * @len must be non-negative.
+ *
+ * Returns -1 if @buf has previously encountered an error or if @len is
+ * invalid, 0 if there was nothing to trim (@buf was too short or @str
+ * didn't match), and 1 if the trim was successful.
+ */
+int
+virBufferTrim(virBufferPtr buf, const char *str, int len)
+{
+    size_t len2 = 0;
+
+    if (!buf || buf->error || (!str && len < 0))
+        return -1;
+
+    if (len > 0 && len > buf->use)
+        return 0;
+    if (str) {
+        len2 = strlen(str);
+        if (len2 > buf->use ||
+            memcmp(&buf->content[buf->use - len2], str, len2) != 0)
+            return 0;
+    }
+    buf->use -= len < 0 ? len2 : len;
+    buf->content[buf->use] = '\0';
+    return 1;
+}
diff --git a/src/util/buf.h b/src/util/buf.h
index d6bc8f3..a8e2eb5 100644
--- a/src/util/buf.h
+++ b/src/util/buf.h
@@ -64,4 +64,6 @@ void virBufferURIEncodeString(virBufferPtr buf, const char *str);
 void virBufferAdjustIndent(virBufferPtr buf, int indent);
 int virBufferGetIndent(const virBufferPtr buf, bool dynamic);

+int virBufferTrim(virBufferPtr buf, const char *trim, int len);
+
 #endif /* __VIR_BUFFER_H__ */
diff --git a/tests/virbuftest.c b/tests/virbuftest.c
index 9058920..cd02db1 100644
--- a/tests/virbuftest.c
+++ b/tests/virbuftest.c
@@ -133,6 +133,61 @@ static int testBufAutoIndent(const void *data ATTRIBUTE_UNUSED)
     return ret;
 }

+static int testBufTrim(const void *data ATTRIBUTE_UNUSED)
+{
+    virBuffer bufinit = VIR_BUFFER_INITIALIZER;
+    virBufferPtr buf = NULL;
+    char *result = NULL;
+    const char *expected = "a,b";
+    int ret = -1;
+    int i = 1;
+
+#define ACT(str, len, result) \
+    do {                                          \
+        if (virBufferTrim(buf, str, len) != result) {   \
+            TEST_ERROR("trim %d failed", i);            \
+            goto cleanup;                               \
+        }                                               \
+        i++;                                            \
+    } while (0);
+
+    if (virBufferTrim(buf, "", 0) != -1) {
+        TEST_ERROR("Wrong failure detection 1");
+        goto cleanup;
+    }
+    buf = &bufinit;
+    if (virBufferTrim(buf, NULL, -1) != -1) {
+        TEST_ERROR("Wrong failure detection 2");
+        goto cleanup;
+    }
+
+    virBufferAddLit(buf, "a;");
+    ACT("", 0, 1);
+    ACT("", -1, 1);
+    ACT(NULL, 1, 1);
+    ACT(NULL, 5, 0);
+    ACT("a", 2, 0);
+
+    virBufferAddLit(buf, ",b,,");
+    ACT("b", -1, 0);
+    ACT("b,,", 1, 1);
+    ACT(",", -1, 1);
+
+    result = virBufferContentAndReset(buf);
+    if (!result || STRNEQ(result, expected)) {
+        virtTestDifference(stderr, expected, result);
+        goto cleanup;
+    }
+
+    ret = 0;
+
+cleanup:
+    virBufferFreeAndReset(buf);
+    VIR_FREE(result);
+    return ret;
+}
+
+
 static int
 mymain(void)
 {
@@ -149,6 +204,7 @@ mymain(void)
     DO_TEST("EscapeString infinite loop", testBufInfiniteLoop, 1);
     DO_TEST("VSprintf infinite loop", testBufInfiniteLoop, 0);
     DO_TEST("Auto-indentation", testBufAutoIndent, 0);
+    DO_TEST("Trim", testBufTrim, 0);

     return ret==0 ? EXIT_SUCCESS : EXIT_FAILURE;
 }
-- 
1.7.7.6




More information about the libvir-list mailing list