From cdb87b1c4b3c325c61e2a6a7d8edcca3ca73a765 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Fri, 18 May 2012 16:36:59 -0600 Subject: [PATCH] virBuffer: add way to trim back extra text 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. --- src/util/buf.c | 36 +++++++++++++++++++++++++++++ src/util/buf.h | 2 ++ tests/virbuftest.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+) diff --git a/src/util/buf.c b/src/util/buf.c index d18f6afff9..630e4c9c2f 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 d6bc8f3523..a8e2eb5fcc 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 9058920ac9..cd02db12f3 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; }