Future patches can take advantage of this to generate nicer XML output with parameterizable indentation. On the side, I had some temporary test failures as I was using these functions in later patches, with output that looked like: Expected [<] Actual [ <] which is pretty hard to figure out. Adding an Offset designation made it much easier to find which particular '<' was at the wrong indentation, to fix the right part of the code. * src/util/buf.h (virBufferIndentAdd, virBufferIndentAddLit) (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): New function. * tests/virbuftest.c (testBufIndentation): Test it. * tests/testutils.c (virtTestDifference): Make it easier to diagnose test failures. --- src/libvirt_private.syms | 2 + src/util/buf.c | 70 ++++++++++++++++++++++++++++++++++++--------- src/util/buf.h | 19 ++++++++++-- tests/testutils.c | 2 +- tests/virbuftest.c | 32 ++++++++++++++++++++- 5 files changed, 105 insertions(+), 20 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 8235ea1..1523289 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -28,6 +28,8 @@ virBufferError; virBufferEscapeSexpr; virBufferEscapeString; virBufferFreeAndReset; +virBufferIndentAdd; +virBufferIndentEscapeString; virBufferStrcat; virBufferURIEncodeString; virBufferUse; diff --git a/src/util/buf.c b/src/util/buf.c index 5002486..061d83b 100644 --- a/src/util/buf.c +++ b/src/util/buf.c @@ -78,21 +78,23 @@ virBufferGrow(virBufferPtr buf, unsigned int len) } /** - * virBufferAdd: - * @buf: the buffer to add to - * @str: the string - * @len: the number of bytes to add + * virBufferIndentAdd: + * @buf: the buffer to add to + * @indent: amount of 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. + * Add indentation, 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(const virBufferPtr buf, int indent, + const char *str, int len) { unsigned int needSize; - if ((str == NULL) || (buf == NULL) || (len == 0)) + if (!str || !buf || (len == 0 && indent == 0)) return; if (buf->error) @@ -101,17 +103,34 @@ virBufferAdd(const virBufferPtr buf, const char *str, int len) if (len < 0) len = strlen(str); - needSize = buf->use + len + 2; + needSize = buf->use + indent + len + 2; if (needSize > buf->size && virBufferGrow(buf, needSize - buf->use) < 0) return; - memcpy (&buf->content[buf->use], str, len); - buf->use += len; + memset (&buf->content[buf->use], ' ', indent); + memcpy (&buf->content[buf->use + indent], str, len); + buf->use += indent + len; buf->content[buf->use] = '\0'; } /** + * virBufferAdd: + * @buf: the buffer to add 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. + * + */ +void +virBufferAdd(const virBufferPtr buf, const char *str, int len) +{ + virBufferIndentAdd(buf, 0, str, len); +} + +/** * virBufferAddChar: * @buf: the buffer to add to * @c: the character to add @@ -120,7 +139,7 @@ virBufferAdd(const virBufferPtr buf, const char *str, int len) * */ void -virBufferAddChar (virBufferPtr buf, char c) +virBufferAddChar(virBufferPtr buf, char c) { unsigned int needSize; @@ -290,10 +309,12 @@ virBufferVasprintf(const virBufferPtr buf, const char *format, va_list argptr) * @str: the string argument which need to be escaped * * Do a formatted print with a single string to an XML buffer. The string - * is escaped to avoid generating a not well-formed XML instance. + * is escaped to avoid generating a not well-formed XML instance. If + * @str is NULL, nothing is added (not even the rest of @format). */ void -virBufferEscapeString(const virBufferPtr buf, const char *format, const char *str) +virBufferEscapeString(const virBufferPtr buf, const char *format, + const char *str) { int len; char *escaped, *out; @@ -369,6 +390,27 @@ virBufferEscapeString(const virBufferPtr buf, const char *format, const char *st } /** + * virBufferIndentEscapeString: + * @buf: the buffer to dump + * @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. The single %s string is escaped to avoid generating a not + * well-formed XML instance. + */ +void +virBufferIndentEscapeString(const 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 dump * @format: a printf like format string but with only one %s parameter diff --git a/src/util/buf.h b/src/util/buf.h index 06d01ba..c5e2874 100644 --- a/src/util/buf.h +++ b/src/util/buf.h @@ -48,11 +48,22 @@ void virBufferVasprintf(const virBufferPtr buf, const char *format, va_list ap) ATTRIBUTE_FMT_PRINTF(2, 0); void virBufferStrcat(const virBufferPtr buf, ...) ATTRIBUTE_SENTINEL; -void virBufferEscapeString(const virBufferPtr buf, const char *format, const char *str); -void virBufferEscapeSexpr(const virBufferPtr buf, const char *format, const char *str); -void virBufferURIEncodeString (const virBufferPtr buf, const char *str); +void virBufferEscapeString(const virBufferPtr buf, const char *format, + const char *str); +void virBufferEscapeSexpr(const virBufferPtr buf, const char *format, + const char *str); +void virBufferURIEncodeString(const virBufferPtr buf, const char *str); # define virBufferAddLit(buf_, literal_string_) \ - virBufferAdd (buf_, "" literal_string_ "", sizeof literal_string_ - 1) + virBufferAdd(buf_, "" literal_string_ "", sizeof literal_string_ - 1) + +void virBufferIndentAdd(const virBufferPtr buf, int indent, + const char *str, int len); +void virBufferIndentEscapeString(const virBufferPtr buf, int indent, + const char *format, const char *str); + +# define virBufferIndentAddLit(buf_, indent_, literal_string_) \ + virBufferIndentAdd(buf_, indent_, "" literal_string_ "", \ + sizeof literal_string_ - 1) #endif /* __VIR_BUFFER_H__ */ diff --git a/tests/testutils.c b/tests/testutils.c index d9582af..b107d3c 100644 --- a/tests/testutils.c +++ b/tests/testutils.c @@ -359,7 +359,7 @@ int virtTestDifference(FILE *stream, } /* Show the trimmed differences */ - fprintf(stream, "\nExpect ["); + fprintf(stream, "\nOffset %d\nExpect [", (int) (expectStart - expect)); if ((expectEnd - expectStart + 1) && fwrite(expectStart, (expectEnd-expectStart+1), 1, stream) != 1) return -1; diff --git a/tests/virbuftest.c b/tests/virbuftest.c index 01db313..0a99e78 100644 --- a/tests/virbuftest.c +++ b/tests/virbuftest.c @@ -20,7 +20,7 @@ struct testInfo { int doEscape; }; -static int testBufInfiniteLoop(const void *data ATTRIBUTE_UNUSED) +static int testBufInfiniteLoop(const void *data) { virBuffer bufinit = VIR_BUFFER_INITIALIZER; virBufferPtr buf = &bufinit; @@ -63,6 +63,35 @@ 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 &"; + 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", "&"); + + result = virBufferContentAndReset(buf); + if (!result || STRNEQ(result, expected)) { + TEST_ERROR("Built buffer was wrong: %s", NULLSTR(result)); + ret = -1; + } + VIR_FREE(result); + return ret; +} + static int mymain(void) { @@ -78,6 +107,7 @@ mymain(void) DO_TEST("EscapeString infinite loop", testBufInfiniteLoop, 1); DO_TEST("VSprintf infinite loop", testBufInfiniteLoop, 0); + DO_TEST("Indentation", testBufIndentation, 0); return(ret==0 ? EXIT_SUCCESS : EXIT_FAILURE); } -- 1.7.4.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list