There are some places in our code base which follow the following
pattern:
char *s = virBufferContentAndReset(buf1);
virBufferAdd(buf2, s, -1);
How about introducing an API to join those two lines into one?
Something like:
virBufferAddBuffer(buf2, buf1);
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
src/libvirt_private.syms | 1 +
src/util/virbuffer.c | 33 +++++++++++++-
src/util/virbuffer.h | 1 +
tests/virbuftest.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 145 insertions(+), 2 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 46a1613..c145421 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1073,6 +1073,7 @@ virBitmapToData;
# util/virbuffer.h
virBufferAdd;
+virBufferAddBuffer;
virBufferAddChar;
virBufferAdjustIndent;
virBufferAsprintf;
diff --git a/src/util/virbuffer.c b/src/util/virbuffer.c
index e94b35d..73c9dd3 100644
--- a/src/util/virbuffer.c
+++ b/src/util/virbuffer.c
@@ -162,8 +162,7 @@ virBufferAdd(virBufferPtr buf, const char *str, int len)
len = strlen(str);
needSize = buf->use + indent + len + 2;
- if (needSize > buf->size &&
- virBufferGrow(buf, needSize - buf->use) < 0)
+ if (virBufferGrow(buf, needSize - buf->use) < 0)
return;
memset(&buf->content[buf->use], ' ', indent);
@@ -173,6 +172,36 @@ virBufferAdd(virBufferPtr buf, const char *str, int len)
}
/**
+ * virBufferAddBuffer:
+ * @buf: the buffer to append to
+ * @toadd: the buffer to append
+ *
+ * Add a buffer into another buffer without need to go through:
+ * virBufferContentAndReset(), virBufferAdd(). Auto indentation
+ * is NOT applied!
+ *
+ * Moreover, be aware that @toadd is eaten with hair. IOW, the
+ * @toadd buffer is reset after this.
+ */
+void
+virBufferAddBuffer(virBufferPtr buf, virBufferPtr toadd)
+{
+ unsigned int needSize;
+
+ if (!buf || !toadd || buf->error || toadd->error)
+ return;
+
+ needSize = buf->use + toadd->use;
+ if (virBufferGrow(buf, needSize - buf->use) < 0)
+ return;
+
+ memcpy(&buf->content[buf->use], toadd->content, toadd->use);
+ buf->use += toadd->use;
+ buf->content[buf->use] = '\0';
+ virBufferFreeAndReset(toadd);
+}
+
+/**
* virBufferAddChar:
* @buf: the buffer to append to
* @c: the character to add
diff --git a/src/util/virbuffer.h b/src/util/virbuffer.h
index 90e248d..24e81c7 100644
--- a/src/util/virbuffer.h
+++ b/src/util/virbuffer.h
@@ -72,6 +72,7 @@ int virBufferCheckErrorInternal(const virBuffer *buf,
__LINE__)
unsigned int virBufferUse(const virBuffer *buf);
void virBufferAdd(virBufferPtr buf, const char *str, int len);
+void virBufferAddBuffer(virBufferPtr buf, virBufferPtr toadd);
void virBufferAddChar(virBufferPtr buf, char c);
void virBufferAsprintf(virBufferPtr buf, const char *format, ...)
ATTRIBUTE_FMT_PRINTF(2, 3);
diff --git a/tests/virbuftest.c b/tests/virbuftest.c
index 554a8c0..884468c 100644
--- a/tests/virbuftest.c
+++ b/tests/virbuftest.c
@@ -199,6 +199,117 @@ static int testBufTrim(const void *data ATTRIBUTE_UNUSED)
return ret;
}
+static int testBufAddBuffer(const void *data ATTRIBUTE_UNUSED)
+{
+ virBuffer buf1 = VIR_BUFFER_INITIALIZER;
+ virBuffer buf2 = VIR_BUFFER_INITIALIZER;
+ virBuffer buf3 = VIR_BUFFER_INITIALIZER;
+ int ret = -1;
+ char *result = NULL;
+ const char *expected = \
+" A long time ago, in a galaxy far,\n" \
+" far away...\n" \
+" It is a period of civil war,\n" \
+" Rebel spaceships, striking\n" \
+" from a hidden base, have won\n" \
+" their first victory against\n" \
+" the evil Galactic Empire.\n" \
+" During the battle, rebel\n" \
+" spies managed to steal secret\n" \
+" plans to the Empire's\n" \
+" ultimate weapon, the DEATH\n" \
+" STAR, an armored space\n" \
+" station with enough power to\n" \
+" destroy an entire planet.\n";
+
+ if (virBufferUse(&buf1)) {
+ TEST_ERROR("buf1 already in use");
+ goto cleanup;
+ }
+
+ if (virBufferUse(&buf2)) {
+ TEST_ERROR("buf2 already in use");
+ goto cleanup;
+ }
+
+ if (virBufferUse(&buf3)) {
+ TEST_ERROR("buf3 already in use");
+ goto cleanup;
+ }
+
+ virBufferAdjustIndent(&buf1, 2);
+ virBufferAddLit(&buf1, "A long time ago, in a galaxy far,\n");
+ virBufferAddLit(&buf1, "far away...\n");
+
+ virBufferAdjustIndent(&buf2, 4);
+ virBufferAddLit(&buf2, "It is a period of civil war,\n");
+ virBufferAddLit(&buf2, "Rebel spaceships, striking\n");
+ virBufferAddLit(&buf2, "from a hidden base, have won\n");
+ virBufferAddLit(&buf2, "their first victory against\n");
+ virBufferAddLit(&buf2, "the evil Galactic Empire.\n");
+
+ virBufferAdjustIndent(&buf3, 2);
+ virBufferAddLit(&buf3, "During the battle, rebel\n");
+ virBufferAddLit(&buf3, "spies managed to steal secret\n");
+ virBufferAddLit(&buf3, "plans to the Empire's\n");
+ virBufferAddLit(&buf3, "ultimate weapon, the DEATH\n");
+ virBufferAddLit(&buf3, "STAR, an armored space\n");
+ virBufferAddLit(&buf3, "station with enough power to\n");
+ virBufferAddLit(&buf3, "destroy an entire planet.\n");
+
+ if (!virBufferUse(&buf1)) {
+ TEST_ERROR("Error adding to buf1");
+ goto cleanup;
+ }
+
+ if (!virBufferUse(&buf2)) {
+ TEST_ERROR("Error adding to buf2");
+ goto cleanup;
+ }
+
+ if (!virBufferUse(&buf3)) {
+ TEST_ERROR("Error adding to buf3");
+ goto cleanup;
+ }
+
+ virBufferAddBuffer(&buf2, &buf3);
+
+ if (!virBufferUse(&buf2)) {
+ TEST_ERROR("buf2 cleared mistakenly");
+ goto cleanup;
+ }
+
+ if (virBufferUse(&buf3)) {
+ TEST_ERROR("buf3 is not clear even though it should be");
+ goto cleanup;
+ }
+
+ virBufferAddBuffer(&buf1, &buf2);
+
+ if (!virBufferUse(&buf1)) {
+ TEST_ERROR("buf1 cleared mistakenly");
+ goto cleanup;
+ }
+
+ if (virBufferUse(&buf2)) {
+ TEST_ERROR("buf2 is not clear even though it should be");
+ goto cleanup;
+ }
+
+ result = virBufferContentAndReset(&buf1);
+ if (!result || STRNEQ(result, expected)) {
+ virtTestDifference(stderr, expected, result);
+ goto cleanup;
+ }
+
+ ret = 0;
+ cleanup:
+ virBufferFreeAndReset(&buf1);
+ virBufferFreeAndReset(&buf2);
+ VIR_FREE(result);
+ return ret;
+}
+
static int
mymain(void)
@@ -217,6 +328,7 @@ mymain(void)
DO_TEST("VSprintf infinite loop", testBufInfiniteLoop, 0);
DO_TEST("Auto-indentation", testBufAutoIndent, 0);
DO_TEST("Trim", testBufTrim, 0);
+ DO_TEST("AddBuffer", testBufAddBuffer, 0);
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
--
2.0.5