util: virbuffer: introduce virBufferEscapeN

Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
This commit is contained in:
Pavel Hrdina 2017-02-23 13:43:32 +01:00
parent 67ad1487c7
commit 726403461b
4 changed files with 140 additions and 0 deletions

View File

@ -1286,6 +1286,7 @@ virBufferContentAndReset;
virBufferCurrentContent;
virBufferError;
virBufferEscape;
virBufferEscapeN;
virBufferEscapeSexpr;
virBufferEscapeShell;
virBufferEscapeString;

View File

@ -33,6 +33,7 @@
#include "virbuffer.h"
#include "viralloc.h"
#include "virerror.h"
#include "virstring.h"
/* If adding more fields, ensure to edit buf.h to match
@ -588,6 +589,101 @@ virBufferEscape(virBufferPtr buf, char escape, const char *toescape,
VIR_FREE(escaped);
}
struct _virBufferEscapePair {
char escape;
char *toescape;
};
/**
* virBufferEscapeN:
* @buf: the buffer to append to
* @format: a printf like format string but with only one %s parameter
* @str: the string argument which needs to be escaped
* @...: the variable list of escape pairs
*
* The variable list of arguments @... must be composed of
* 'char escape, char *toescape' pairs followed by NULL.
*
* This has the same functionality as virBufferEscape with the extension
* that allows to specify multiple pairs of chars that needs to be escaped.
*/
void
virBufferEscapeN(virBufferPtr buf,
const char *format,
const char *str,
...)
{
int len;
size_t i;
char *escaped = NULL;
char *out;
const char *cur;
struct _virBufferEscapePair escapeItem;
struct _virBufferEscapePair *escapeList = NULL;
size_t nescapeList = 0;
va_list ap;
if ((format == NULL) || (buf == NULL) || (str == NULL))
return;
if (buf->error)
return;
len = strlen(str);
va_start(ap, str);
while ((escapeItem.escape = va_arg(ap, int))) {
if (!(escapeItem.toescape = va_arg(ap, char *))) {
virBufferSetError(buf, errno);
goto cleanup;
}
if (strcspn(str, escapeItem.toescape) == len)
continue;
if (VIR_APPEND_ELEMENT_QUIET(escapeList, nescapeList, escapeItem) < 0) {
virBufferSetError(buf, errno);
goto cleanup;
}
}
if (nescapeList == 0) {
virBufferAsprintf(buf, format, str);
goto cleanup;
}
if (xalloc_oversized(2, len) ||
VIR_ALLOC_N_QUIET(escaped, 2 * len + 1) < 0) {
virBufferSetError(buf, errno);
goto cleanup;
}
cur = str;
out = escaped;
while (*cur != 0) {
for (i = 0; i < nescapeList; i++) {
if (strchr(escapeList[i].toescape, *cur)) {
*out++ = escapeList[i].escape;
break;
}
}
*out++ = *cur;
cur++;
}
*out = 0;
virBufferAsprintf(buf, format, escaped);
cleanup:
va_end(ap);
VIR_FREE(escapeList);
VIR_FREE(escaped);
}
/**
* virBufferURIEncodeString:
* @buf: the buffer to append to

View File

@ -82,6 +82,8 @@ void virBufferStrcat(virBufferPtr buf, ...)
ATTRIBUTE_SENTINEL;
void virBufferEscape(virBufferPtr buf, char escape, const char *toescape,
const char *format, const char *str);
void virBufferEscapeN(virBufferPtr buf, const char *format,
const char *str, ...);
void virBufferEscapeString(virBufferPtr buf, const char *format,
const char *str);
void virBufferEscapeSexpr(virBufferPtr buf, const char *format,

View File

@ -375,6 +375,35 @@ testBufEscapeStr(const void *opaque ATTRIBUTE_UNUSED)
}
static int
testBufEscapeN(const void *opaque)
{
const struct testBufAddStrData *data = opaque;
virBuffer buf = VIR_BUFFER_INITIALIZER;
char *actual;
int ret = -1;
virBufferEscapeN(&buf, "%s", data->data, '\\', "=", ',', ",", NULL);
if (!(actual = virBufferContentAndReset(&buf))) {
VIR_TEST_DEBUG("testBufEscapeN: buf is empty");
goto cleanup;
}
if (STRNEQ_NULLABLE(actual, data->expect)) {
VIR_TEST_DEBUG("testBufEscapeN: Strings don't match:\n");
virTestDifference(stderr, data->expect, actual);
goto cleanup;
}
ret = 0;
cleanup:
VIR_FREE(actual);
return ret;
}
static int
mymain(void)
{
@ -422,6 +451,18 @@ mymain(void)
DO_TEST_ESCAPE("\x01\x01\x02\x03\x05\x08",
"<c>\n <el></el>\n</c>");
#define DO_TEST_ESCAPEN(data, expect) \
do { \
struct testBufAddStrData info = { data, expect }; \
if (virTestRun("Buf: EscapeN", testBufEscapeN, &info) < 0) \
ret = -1; \
} while (0)
DO_TEST_ESCAPEN("noescape", "noescape");
DO_TEST_ESCAPEN("comma,escape", "comma,,escape");
DO_TEST_ESCAPEN("equal=escape", "equal\\=escape");
DO_TEST_ESCAPEN("comma,equal=escape", "comma,,equal\\=escape");
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}