diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index b97906b852..f46ed29eac 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1642,6 +1642,7 @@ virBufferSetIndent; virBufferStrcat; virBufferStrcatVArgs; virBufferTrim; +virBufferTrimChars; virBufferURIEncodeString; virBufferUse; virBufferVasprintf; diff --git a/src/util/virbuffer.c b/src/util/virbuffer.c index 1b93110919..914c386b18 100644 --- a/src/util/virbuffer.c +++ b/src/util/virbuffer.c @@ -673,6 +673,32 @@ virBufferTrim(virBufferPtr buf, const char *str, int len) g_string_truncate(buf->str, buf->str->len - len); } +/** + * virBufferTrimChars: + * @buf: the buffer to trim + * @trim: the characters to be trimmed + * + * Trim the tail of the buffer. The longest string that can be formed with + * the characters from @trim is trimmed. + */ +void +virBufferTrimChars(virBufferPtr buf, const char *trim) +{ + ssize_t i; + + if (!buf || !buf->str) + return; + + if (!trim) + return; + + for (i = buf->str->len - 1; i > 0; i--) { + if (!strchr(trim, buf->str->str[i])) + break; + } + + g_string_truncate(buf->str, i + 1); +} /** * virBufferAddStr: diff --git a/src/util/virbuffer.h b/src/util/virbuffer.h index 38758a9125..183f78f279 100644 --- a/src/util/virbuffer.h +++ b/src/util/virbuffer.h @@ -92,4 +92,5 @@ size_t virBufferGetIndent(const virBuffer *buf); size_t virBufferGetEffectiveIndent(const virBuffer *buf); void virBufferTrim(virBufferPtr buf, const char *trim, int len); +void virBufferTrimChars(virBufferPtr buf, const char *trim); void virBufferAddStr(virBufferPtr buf, const char *str); diff --git a/tests/virbuftest.c b/tests/virbuftest.c index 1780b62bf4..7919075000 100644 --- a/tests/virbuftest.c +++ b/tests/virbuftest.c @@ -12,6 +12,7 @@ struct testBufAddStrData { const char *data; const char *expect; + const char *arg; }; static int testBufAutoIndent(const void *data G_GNUC_UNUSED) @@ -130,6 +131,30 @@ static int testBufTrim(const void *data G_GNUC_UNUSED) return ret; } +static int +testBufTrimChars(const void *opaque) +{ + const struct testBufAddStrData *data = opaque; + virBuffer buf = VIR_BUFFER_INITIALIZER; + g_autofree char *actual = NULL; + + virBufferAddStr(&buf, data->data); + virBufferTrimChars(&buf, data->arg); + + if (!(actual = virBufferContentAndReset(&buf))) { + VIR_TEST_DEBUG("buf is empty"); + return -1; + } + + if (STRNEQ_NULLABLE(actual, data->expect)) { + VIR_TEST_DEBUG("testBufEscapeStr(): Strings don't match:"); + virTestDifference(stderr, data->expect, actual); + return -1; + } + + return 0; +} + static int testBufAddBuffer(const void *data G_GNUC_UNUSED) { virBuffer buf1 = VIR_BUFFER_INITIALIZER; @@ -411,6 +436,17 @@ mymain(void) DO_TEST_ESCAPE_REGEX("^$.|?*+()[]{}\\", "\\^\\$\\.\\|\\?\\*\\+\\(\\)\\[\\]\\{\\}\\\\"); +#define DO_TEST_TRIM_CHARS(_data, _arg, _expect) \ + do { \ + struct testBufAddStrData info = { .data = _data, .expect = _expect, .arg = _arg }; \ + if (virTestRun("Buf: Trim: " #_data, testBufTrimChars, &info) < 0) \ + ret = -1; \ + } while (0) + + DO_TEST_TRIM_CHARS("Trimmm", "m", "Tri"); + DO_TEST_TRIM_CHARS("-abcd-efgh--", "-", "-abcd-efgh"); + DO_TEST_TRIM_CHARS("-hABC-efgh--", "-h", "-hABC-efg"); + return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; }