Future patches can take advantage of this to generate nicer
XML output with parameterizable indentation.
* src/util/buf.h (virBufferIndentAdd, virBufferIndentAddLit)
(virBufferIndentAsprintf, virBufferIndentEscapeString): New
prototypes and macro.
* src/libvirt_private.syms (buf.h): Export new functions.
* src/util/buf.c (virBufferAdd): Move body...
(virBufferIndentAdd): ...to new function.
(virBufferIndentEscapeString, virBufferIndentAsprintf): New
functions.
* tests/virbuftest.c (testBufIndentation): Test it.
---
At this point, since no one else is using these functions, I'm
inclined to ditch this patch. I'm posting it only for completeness,
since it added virBufferIndentAsprintf, and since it took quite
a bit of reshuffling to rebase this on top of the auto-indent stuff.
src/libvirt_private.syms | 3 ++
src/util/buf.c | 90 +++++++++++++++++++++++++++++++++++++++-------
src/util/buf.h | 12 ++++++
tests/virbuftest.c | 52 +++++++++++++++++++++++----
4 files changed, 137 insertions(+), 20 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 89cd6da..6505eae 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -30,6 +30,9 @@ virBufferEscapeSexpr;
virBufferEscapeString;
virBufferFreeAndReset;
virBufferGetIndent;
+virBufferIndentAdd;
+virBufferIndentAsprintf;
+virBufferIndentEscapeString;
virBufferStrcat;
virBufferURIEncodeString;
virBufferUse;
diff --git a/src/util/buf.c b/src/util/buf.c
index b409de4..d4c4bcc 100644
--- a/src/util/buf.c
+++ b/src/util/buf.c
@@ -123,28 +123,34 @@ virBufferGrow(virBufferPtr buf, unsigned int len)
}
/**
- * virBufferAdd:
+ * virBufferIndentAdd:
* @buf: the buffer to append to
- * @str: the string
- * @len: the number of bytes to add, or -1
+ * @indent: amount of explicit indentation
+ * @str: the string, or NULL to skip indentation
+ * @len: the number of bytes to add
*
- * Add a string range to an XML buffer. If @len == -1, the length of
- * str is recomputed to the full string. Auto indentation may be applied.
+ * Add indentation (both from @indent and any auto-indent), then a string
+ * range to an XML buffer. If @len == -1, the length of str is recomputed
+ * to the full string.
*
*/
void
-virBufferAdd(const virBufferPtr buf, const char *str, int len)
+virBufferIndentAdd(virBufferPtr buf, int indent,
+ const char *str, int len)
{
unsigned int needSize;
- int indent;
- if (!str || !buf || (len == 0 && buf->indent == 0))
+ if (!str || !buf || (len == 0 && indent == 0))
return;
if (buf->error)
return;
- indent = virBufferGetIndent(buf, true);
+ if (indent < 0 || INT_MAX - indent < buf->indent) {
+ virBufferSetError(buf, -1);
+ return;
+ }
+ indent += virBufferGetIndent(buf, true);
if (len < 0)
len = strlen(str);
@@ -161,6 +167,22 @@ virBufferAdd(const virBufferPtr buf, const char *str, int len)
}
/**
+ * virBufferAdd:
+ * @buf: the buffer to append to
+ * @str: the string
+ * @len: the number of bytes to add
+ *
+ * Add a string range to an XML buffer. if len == -1, the length of
+ * str is recomputed to the full string. Auto indentation may be applied.
+ *
+ */
+void
+virBufferAdd(const virBufferPtr buf, const char *str, int len)
+{
+ virBufferIndentAdd(buf, 0, str, len);
+}
+
+/**
* virBufferAddChar:
* @buf: the buffer to append to
* @c: the character to add
@@ -171,7 +193,7 @@ virBufferAdd(const virBufferPtr buf, const char *str, int len)
void
virBufferAddChar(virBufferPtr buf, char c)
{
- virBufferAdd(buf, &c, 1);
+ virBufferIndentAdd(buf, 0, &c, 1);
}
/**
@@ -265,6 +287,27 @@ virBufferAsprintf(virBufferPtr buf, const char *format, ...)
}
/**
+ * virBufferIndentAsprintf:
+ * @buf: the buffer to append to
+ * @indent: amount of explicit indentation
+ * @format: the format
+ * @...: the variable list of arguments
+ *
+ * Do a formatted print to an XML buffer, with leading indentation
+ * (both from @indent and any auto-indentation).
+ */
+void
+virBufferIndentAsprintf(virBufferPtr buf, int indent,
+ const char *format, ...)
+{
+ va_list argptr;
+ va_start(argptr, format);
+ virBufferIndentAdd(buf, indent, "", 0);
+ virBufferVasprintf(buf, format, argptr);
+ va_end(argptr);
+}
+
+/**
* virBufferVasprintf:
* @buf: the buffer to append to
* @format: the format
@@ -285,7 +328,7 @@ virBufferVasprintf(virBufferPtr buf, const char *format, va_list
argptr)
return;
if (buf->indent)
- virBufferAdd(buf, "", -1);
+ virBufferIndentAdd(buf, 0, "", -1);
if (buf->size == 0 &&
virBufferGrow(buf, 100) < 0)
@@ -409,6 +452,27 @@ virBufferEscapeString(virBufferPtr buf, const char *format, const
char *str)
}
/**
+ * virBufferIndentEscapeString:
+ * @buf: the buffer to append to
+ * @indent: amount of indentation
+ * @format: a printf like format string but with only one %s parameter
+ * @str: the string argument which need to be escaped, or NULL for no action
+ *
+ * Do a formatted print with a single string to an XML buffer, with
+ * leading indentation (both from @indent and auto-indent). The single
+ * %s string is escaped to form valid XML.
+ */
+void
+virBufferIndentEscapeString(virBufferPtr buf, int indent,
+ const char *format, const char *str)
+{
+ if (str) {
+ virBufferIndentAdd(buf, indent, "", 0);
+ virBufferEscapeString(buf, format, str);
+ }
+}
+
+/**
* virBufferEscapeSexpr:
* @buf: the buffer to append to
* @format: a printf like format string but with only one %s parameter
@@ -489,7 +553,7 @@ virBufferURIEncodeString(virBufferPtr buf, const char *str)
return;
if (buf->indent)
- virBufferAdd(buf, "", -1);
+ virBufferIndentAdd(buf, 0, "", -1);
for (p = str; *p; ++p) {
if (c_isalnum(*p))
@@ -534,6 +598,6 @@ virBufferStrcat(virBufferPtr buf, ...)
va_start(ap, buf);
while ((str = va_arg(ap, char *)) != NULL)
- virBufferAdd(buf, str, -1);
+ virBufferIndentAdd(buf, 0, str, -1);
va_end(ap);
}
diff --git a/src/util/buf.h b/src/util/buf.h
index 08cb727..d913c69 100644
--- a/src/util/buf.h
+++ b/src/util/buf.h
@@ -61,4 +61,16 @@ void virBufferURIEncodeString(virBufferPtr buf, const char *str);
void virBufferAdjustIndent(virBufferPtr buf, int indent);
int virBufferGetIndent(const virBufferPtr buf, bool dynamic);
+void virBufferIndentAdd(virBufferPtr buf, int indent,
+ const char *str, int len);
+void virBufferIndentEscapeString(virBufferPtr buf, int indent,
+ const char *format, const char *str);
+void virBufferIndentAsprintf(virBufferPtr buf, int indent,
+ const char *format, ...)
+ ATTRIBUTE_FMT_PRINTF(3, 4);
+
+# define virBufferIndentAddLit(buf_, indent_, literal_string_) \
+ virBufferIndentAdd(buf_, indent_, "" literal_string_ "",
\
+ sizeof literal_string_ - 1)
+
#endif /* __VIR_BUFFER_H__ */
diff --git a/tests/virbuftest.c b/tests/virbuftest.c
index 2f94e1c..a6dd84a 100644
--- a/tests/virbuftest.c
+++ b/tests/virbuftest.c
@@ -58,12 +58,44 @@ out:
return ret;
}
+static int testBufIndentation(const void *data ATTRIBUTE_UNUSED)
+{
+ virBuffer bufinit = VIR_BUFFER_INITIALIZER;
+ virBufferPtr buf = &bufinit;
+ const char expected[] = "ab c d & e";
+ char *result = NULL;
+ int ret = 0;
+
+ virBufferIndentAdd(buf, 0, "a", -1);
+ virBufferIndentAdd(buf, 0, "", -1);
+ virBufferIndentAdd(buf, 0, "", 0);
+ virBufferIndentAddLit(buf, 0, "");
+ virBufferIndentAddLit(buf, 0, "b");
+ virBufferIndentAdd(buf, 3, NULL, -1);
+ virBufferIndentAdd(buf, 2, "c", -1);
+ virBufferIndentAddLit(buf, 1, "");
+ virBufferIndentEscapeString(buf, 1, "%s", "d");
+ virBufferIndentEscapeString(buf, 3, "%s", NULL);
+ virBufferIndentEscapeString(buf, 2, "%s", "&");
+ virBufferIndentAsprintf(buf, 1, "%s%s", "", "");
+ virBufferIndentAsprintf(buf, 1, "%c", 'e');
+
+ result = virBufferContentAndReset(buf);
+ if (!result || STRNEQ(result, expected)) {
+ virtTestDifference(stderr, expected, result);
+ ret = -1;
+ }
+ VIR_FREE(result);
+ return ret;
+}
+
static int testBufAutoIndent(const void *data ATTRIBUTE_UNUSED)
{
virBuffer bufinit = VIR_BUFFER_INITIALIZER;
virBufferPtr buf = &bufinit;
const char expected[] =
- " 1\n 2\n 3\n 4\n 5\n 6\n 7\n &\n 8\n 9\n";
+ " 1\n 2\n 3\n 4\n 5\n 6 7\n 8\n 9\n 10\n"
+ " <\n 11\n >\n 12\n 13\n";
char *result = NULL;
int ret = 0;
@@ -111,13 +143,18 @@ static int testBufAutoIndent(const void *data ATTRIBUTE_UNUSED)
virBufferAdd(buf, "" "2\n", -1); /* Extra "" appeases
syntax-check */
virBufferAddChar(buf, '3');
virBufferAddChar(buf, '\n');
- virBufferAsprintf(buf, "%d", 4);
+ virBufferIndentAdd(buf, 2, "4\n", 2);
+ virBufferAsprintf(buf, "%d", 5);
virBufferAsprintf(buf, "%c", '\n');
- virBufferStrcat(buf, "5", "\n", "6\n", NULL);
- virBufferEscapeString(buf, "%s\n", "7");
- virBufferEscapeString(buf, "%s\n", "&");
- virBufferEscapeSexpr(buf, "%s", "8\n");
- virBufferURIEncodeString(buf, "9");
+ virBufferIndentAsprintf(buf, 2, "%s", "6");
+ virBufferIndentAsprintf(buf, 2, "%s\n", "7");
+ virBufferStrcat(buf, "8", "\n", "9\n", NULL);
+ virBufferEscapeString(buf, "%s\n", "10");
+ virBufferEscapeString(buf, "%s\n", "<");
+ virBufferIndentEscapeString(buf, 2, "%s\n", "11");
+ virBufferIndentEscapeString(buf, 2, "%s\n", ">");
+ virBufferEscapeSexpr(buf, "%s", "12\n");
+ virBufferURIEncodeString(buf, "13");
virBufferAddChar(buf, '\n');
result = virBufferContentAndReset(buf);
@@ -144,6 +181,7 @@ mymain(void)
DO_TEST("EscapeString infinite loop", testBufInfiniteLoop, 1);
DO_TEST("VSprintf infinite loop", testBufInfiniteLoop, 0);
+ DO_TEST("Indentation", testBufIndentation, 0);
DO_TEST("Auto-indentation", testBufAutoIndent, 0);
return(ret==0 ? EXIT_SUCCESS : EXIT_FAILURE);
--
1.7.4.4