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.
This commit is contained in:
Eric Blake 2012-05-18 16:36:59 -06:00
parent 74951eadef
commit cdb87b1c4b
3 changed files with 94 additions and 0 deletions

View File

@ -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;
}

View File

@ -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__ */

View File

@ -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;
}