2007-03-15 17:30:04 +00:00
|
|
|
/*
|
2012-12-04 12:04:07 +00:00
|
|
|
* virbuffer.c: buffers for libvirt
|
2007-03-15 17:30:04 +00:00
|
|
|
*
|
2015-03-13 15:41:42 +00:00
|
|
|
* Copyright (C) 2005-2008, 2010-2015 Red Hat, Inc.
|
2007-03-15 17:30:04 +00:00
|
|
|
*
|
2012-07-27 09:39:53 +00:00
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-07-27 09:39:53 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
2007-03-15 17:30:04 +00:00
|
|
|
*
|
|
|
|
* Daniel Veillard <veillard@redhat.com>
|
|
|
|
*/
|
|
|
|
|
2008-01-29 18:15:54 +00:00
|
|
|
#include <config.h>
|
2007-12-05 21:40:15 +00:00
|
|
|
|
2007-03-15 17:30:04 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdarg.h>
|
start using c-ctype functions
Up to now, we've been avoiding ctype functions like isspace, isdigit,
etc. because they are locale-dependent. Now that we have the c-ctype
functions, we can start using *them*, to make the code more readable
with changes like these:
- /* This may not work on EBCDIC. */
- if ((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9'))
+ if (c_isalnum(*p))
- while ((*cur >= '0') && (*cur <= '9')) {
+ while (c_isdigit(*cur)) {
Also, some macros in conf.c used names that conflicted with
standard meaning of "BLANK" and "SPACE", so I've adjusted them
to be in line with the definition of e.g., isblank.
In addition, I've wrapped those statement macros with do {...} while (0),
so that we can't forget the ";" after a use. There was one like that
already (fixed below). The missing semicolon would mess up automatic
indenting.
* src/buf.c (virBufferURIEncodeString):
* src/conf.c (IS_EOL, SKIP_BLANKS_AND_EOL, SKIP_BLANKS)
(virConfParseLong, virConfParseValue, virConfParseName)
(virConfParseSeparator, virConfParseStatement, IS_BLANK, IS_CHAR)
(IS_DIGIT, IS_SPACE, SKIP_SPACES):
* src/nodeinfo.c:
* src/qemu_conf.c (qemudParseInterfaceXML):
* src/qemu_driver.c (qemudDomainBlockStats):
* src/sexpr.c:
* src/stats_linux.c:
* src/util.c (virParseNumber, virDiskNameToIndex):
* src/uuid.c (hextobin, virUUIDParse):
* src/virsh.c:
* src/xml.c (parseCpuNumber, virParseCpuSet):
2008-05-16 09:37:44 +00:00
|
|
|
#include "c-ctype.h"
|
2007-12-17 10:05:35 +00:00
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
#define __VIR_BUFFER_C__
|
|
|
|
|
2012-12-04 12:04:07 +00:00
|
|
|
#include "virbuffer.h"
|
2014-06-27 07:23:13 +00:00
|
|
|
#include "virerror.h"
|
2017-02-23 12:43:32 +00:00
|
|
|
#include "virstring.h"
|
2007-03-15 17:30:04 +00:00
|
|
|
|
2018-07-24 15:52:04 +00:00
|
|
|
#define VIR_FROM_THIS VIR_FROM_NONE
|
2008-04-28 15:14:59 +00:00
|
|
|
|
|
|
|
/* If adding more fields, ensure to edit buf.h to match
|
|
|
|
the number of fields */
|
|
|
|
struct _virBuffer {
|
|
|
|
unsigned int size;
|
|
|
|
unsigned int use;
|
2011-09-27 19:37:23 +00:00
|
|
|
unsigned int error; /* errno value, or -1 for usage error */
|
2011-10-20 21:48:47 +00:00
|
|
|
int indent;
|
2008-04-28 15:14:59 +00:00
|
|
|
char *content;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virBufferFail
|
|
|
|
* @buf: the buffer
|
2011-09-27 19:37:23 +00:00
|
|
|
* @error: which error occurred (errno value, or -1 for usage)
|
2008-04-28 15:14:59 +00:00
|
|
|
*
|
2011-09-27 19:37:23 +00:00
|
|
|
* Mark the buffer as failed, free the content and set the error flag.
|
2008-04-28 15:14:59 +00:00
|
|
|
*/
|
|
|
|
static void
|
2011-09-27 19:37:23 +00:00
|
|
|
virBufferSetError(virBufferPtr buf, int error)
|
2008-04-28 15:14:59 +00:00
|
|
|
{
|
2008-05-29 18:45:36 +00:00
|
|
|
VIR_FREE(buf->content);
|
2008-04-28 15:14:59 +00:00
|
|
|
buf->size = 0;
|
|
|
|
buf->use = 0;
|
2011-10-20 21:48:47 +00:00
|
|
|
buf->indent = 0;
|
2011-09-27 19:37:23 +00:00
|
|
|
buf->error = error;
|
2008-04-28 15:14:59 +00:00
|
|
|
}
|
|
|
|
|
2011-10-20 21:48:47 +00:00
|
|
|
/**
|
|
|
|
* virBufferAdjustIndent:
|
|
|
|
* @buf: the buffer
|
|
|
|
* @indent: adjustment to make
|
|
|
|
*
|
|
|
|
* Alter the auto-indent value by adding indent (positive to increase,
|
|
|
|
* negative to decrease). Automatic indentation is performed by all
|
|
|
|
* additive functions when the existing buffer is empty or ends with a
|
|
|
|
* newline (however, note that no indentation is added after newlines
|
|
|
|
* embedded in an appended string). If @indent would cause overflow,
|
|
|
|
* the buffer error indicator is set.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
virBufferAdjustIndent(virBufferPtr buf, int indent)
|
|
|
|
{
|
|
|
|
if (!buf || buf->error)
|
|
|
|
return;
|
|
|
|
if (indent > 0 ? INT_MAX - indent < buf->indent
|
|
|
|
: buf->indent < -indent) {
|
|
|
|
virBufferSetError(buf, -1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
buf->indent += indent;
|
|
|
|
}
|
|
|
|
|
2017-03-09 16:02:19 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* virBufferSetIndent:
|
|
|
|
* @buf: the buffer
|
|
|
|
* @indent: new indentation size.
|
|
|
|
*
|
|
|
|
* Set the auto-indent value to @indent. See virBufferAdjustIndent on how auto
|
|
|
|
* indentation is applied.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
virBufferSetIndent(virBufferPtr buf, int indent)
|
|
|
|
{
|
|
|
|
if (!buf || buf->error)
|
|
|
|
return;
|
|
|
|
|
|
|
|
buf->indent = indent;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-10-20 21:48:47 +00:00
|
|
|
/**
|
|
|
|
* virBufferGetIndent:
|
|
|
|
* @buf: the buffer
|
|
|
|
* @dynamic: if false, return set value; if true, return 0 unless next
|
|
|
|
* append would be affected by auto-indent
|
|
|
|
*
|
|
|
|
* Return the current auto-indent value, or -1 if there has been an error.
|
|
|
|
*/
|
|
|
|
int
|
maint: avoid 'const fooPtr' in several util files
'const fooPtr' is the same as 'foo * const' (the pointer won't
change, but it's contents can). But in general, if an interface
is trying to be const-correct, it should be using 'const foo *'
(the pointer is to data that can't be changed).
Fix up offenders in src/util outside of the virnet namespace.
Also, make a few virSocketAddr functions const-correct, for easier
conversions in future patches.
* src/util/virbuffer.h (virBufferError, virBufferUse)
(virBufferGetIndent): Use intended type.
* src/util/virmacaddr.h (virMacAddrCmp, virMacAddrCmpRaw)
(virMacAddrSet, virMcAddrFormat, virMacAddrIsUnicast)
(virMacAddrIsMulticast): Likewise.
* src/util/virebtables.h (ebtablesAddForwardAllowIn)
(ebtablesRemoveForwardAllowIn): Likewise.
* src/util/virsocketaddr.h (virSocketAddrSetIPv4Addr): Drop
incorrect const.
(virMacAddrGetRaw, virSocketAddrFormat, virSocketAddrFormatFull):
Make const-correct.
(virSocketAddrMask, virSocketAddrMaskByPrefix)
(virSocketAddrBroadcast, virSocketAddrBroadcastByPrefix)
(virSocketAddrGetNumNetmaskBits, virSocketAddrGetIpPrefix)
(virSocketAddrEqual, virSocketAddrIsPrivate)
(virSocketAddrIsWildcard): Use intended type.
* src/util/virbuffer.c (virBufferError, virBufferUse)
(virBufferGetIndent): Fix fallout.
* src/util/virmacaddr.c (virMacAddrCmp, virMacAddrCmpRaw)
(virMacAddrSet, virMcAddrFormat, virMacAddrIsUnicast)
(virMacAddrIsMulticast): Likewise.
* src/util/virebtables.c (ebtablesAddForwardAllowIn)
(ebtablesRemoveForwardAllowIn): Likewise.
* src/util/virsocketaddr.c (virSocketAddrMask, virMacAddrGetRaw)
(virSocketAddrMaskByPrefix, virSocketAddrBroadcast)
(virSocketAddrBroadcastByPrefix, virSocketAddrGetNumNetmaskBits)
(virSocketAddrGetIpPrefix, virSocketAddrEqual)
(virSocketAddrIsPrivate, virSocketAddrIsWildcard)
(virSocketAddrGetIPv4Addr, virSocketAddrGetIPv6Addr)
(virSocketAddrFormat, virSocketAddrFormatFull): Likewise.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-10-05 15:51:55 +00:00
|
|
|
virBufferGetIndent(const virBuffer *buf, bool dynamic)
|
2011-10-20 21:48:47 +00:00
|
|
|
{
|
|
|
|
if (!buf || buf->error)
|
|
|
|
return -1;
|
|
|
|
if (dynamic && buf->use && buf->content[buf->use - 1] != '\n')
|
|
|
|
return 0;
|
|
|
|
return buf->indent;
|
|
|
|
}
|
|
|
|
|
2007-03-15 17:30:04 +00:00
|
|
|
/**
|
2007-06-26 22:21:22 +00:00
|
|
|
* virBufferGrow:
|
2012-12-19 22:00:13 +00:00
|
|
|
* @buf: the buffer
|
|
|
|
* @len: the minimum free size to allocate on top of existing used space
|
2007-03-15 17:30:04 +00:00
|
|
|
*
|
2007-03-21 15:24:56 +00:00
|
|
|
* Grow the available space of a buffer to at least @len bytes.
|
2007-03-15 17:30:04 +00:00
|
|
|
*
|
2008-04-28 15:14:59 +00:00
|
|
|
* Returns zero on success or -1 on error
|
2007-03-15 17:30:04 +00:00
|
|
|
*/
|
|
|
|
static int
|
2007-06-26 22:21:22 +00:00
|
|
|
virBufferGrow(virBufferPtr buf, unsigned int len)
|
2007-03-15 17:30:04 +00:00
|
|
|
{
|
|
|
|
int size;
|
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
if (buf->error)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if ((len + buf->use) < buf->size)
|
|
|
|
return 0;
|
2007-03-15 17:30:04 +00:00
|
|
|
|
|
|
|
size = buf->use + len + 1000;
|
|
|
|
|
2013-06-07 08:37:25 +00:00
|
|
|
if (VIR_REALLOC_N_QUIET(buf->content, size) < 0) {
|
2011-09-27 19:37:23 +00:00
|
|
|
virBufferSetError(buf, errno);
|
2008-04-28 15:14:59 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2007-03-15 17:30:04 +00:00
|
|
|
buf->size = size;
|
2008-04-28 15:14:59 +00:00
|
|
|
return 0;
|
2007-03-15 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2007-06-26 22:21:22 +00:00
|
|
|
* virBufferAdd:
|
2011-10-20 21:48:47 +00:00
|
|
|
* @buf: the buffer to append to
|
|
|
|
* @str: the string
|
|
|
|
* @len: the number of bytes to add, or -1
|
2007-03-15 17:30:04 +00:00
|
|
|
*
|
2011-10-20 21:48:47 +00:00
|
|
|
* 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.
|
2007-03-15 17:30:04 +00:00
|
|
|
*
|
|
|
|
*/
|
2008-04-28 15:14:59 +00:00
|
|
|
void
|
2011-09-27 19:50:03 +00:00
|
|
|
virBufferAdd(virBufferPtr buf, const char *str, int len)
|
2007-03-15 17:30:04 +00:00
|
|
|
{
|
|
|
|
unsigned int needSize;
|
2011-10-20 21:48:47 +00:00
|
|
|
int indent;
|
2007-03-15 17:30:04 +00:00
|
|
|
|
2011-10-20 21:48:47 +00:00
|
|
|
if (!str || !buf || (len == 0 && buf->indent == 0))
|
2008-04-28 15:14:59 +00:00
|
|
|
return;
|
|
|
|
|
2011-10-20 21:48:47 +00:00
|
|
|
indent = virBufferGetIndent(buf, true);
|
2013-01-15 18:12:59 +00:00
|
|
|
if (indent < 0)
|
|
|
|
return;
|
2011-10-20 21:48:47 +00:00
|
|
|
|
2007-03-15 17:30:04 +00:00
|
|
|
if (len < 0)
|
|
|
|
len = strlen(str);
|
|
|
|
|
2011-10-20 21:48:47 +00:00
|
|
|
needSize = buf->use + indent + len + 2;
|
2015-02-19 09:56:58 +00:00
|
|
|
if (virBufferGrow(buf, needSize - buf->use) < 0)
|
2008-04-28 15:14:59 +00:00
|
|
|
return;
|
2007-12-17 10:05:35 +00:00
|
|
|
|
2011-10-20 21:48:47 +00:00
|
|
|
memset(&buf->content[buf->use], ' ', indent);
|
|
|
|
memcpy(&buf->content[buf->use + indent], str, len);
|
|
|
|
buf->use += indent + len;
|
2008-04-28 15:14:59 +00:00
|
|
|
buf->content[buf->use] = '\0';
|
2007-03-15 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
2015-02-19 09:56:58 +00:00
|
|
|
/**
|
|
|
|
* 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 (intentionally) NOT applied!
|
|
|
|
*
|
2016-01-07 13:18:21 +00:00
|
|
|
* The @toadd virBuffer is consumed and cleared.
|
2015-02-19 09:56:58 +00:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
virBufferAddBuffer(virBufferPtr buf, virBufferPtr toadd)
|
|
|
|
{
|
2015-03-13 15:41:42 +00:00
|
|
|
if (!toadd)
|
2015-02-19 09:56:58 +00:00
|
|
|
return;
|
|
|
|
|
2015-03-13 15:41:42 +00:00
|
|
|
if (!buf)
|
|
|
|
goto done;
|
|
|
|
|
2015-02-19 09:56:58 +00:00
|
|
|
if (buf->error || toadd->error) {
|
|
|
|
if (!buf->error)
|
|
|
|
buf->error = toadd->error;
|
2015-03-13 15:41:42 +00:00
|
|
|
goto done;
|
2015-02-19 09:56:58 +00:00
|
|
|
}
|
|
|
|
|
2015-11-14 06:56:06 +00:00
|
|
|
if (virBufferGrow(buf, toadd->use) < 0)
|
2015-03-13 15:41:42 +00:00
|
|
|
goto done;
|
2015-02-19 09:56:58 +00:00
|
|
|
|
|
|
|
memcpy(&buf->content[buf->use], toadd->content, toadd->use);
|
|
|
|
buf->use += toadd->use;
|
|
|
|
buf->content[buf->use] = '\0';
|
2015-03-13 15:41:42 +00:00
|
|
|
|
|
|
|
done:
|
2015-02-19 09:56:58 +00:00
|
|
|
virBufferFreeAndReset(toadd);
|
|
|
|
}
|
|
|
|
|
2007-12-17 10:05:35 +00:00
|
|
|
/**
|
|
|
|
* virBufferAddChar:
|
2011-09-27 19:50:03 +00:00
|
|
|
* @buf: the buffer to append to
|
2007-12-17 10:05:35 +00:00
|
|
|
* @c: the character to add
|
|
|
|
*
|
2011-10-20 21:48:47 +00:00
|
|
|
* Add a single character 'c' to a buffer. Auto indentation may be applied.
|
2007-12-17 10:05:35 +00:00
|
|
|
*
|
|
|
|
*/
|
2008-04-28 15:14:59 +00:00
|
|
|
void
|
2011-10-20 21:48:47 +00:00
|
|
|
virBufferAddChar(virBufferPtr buf, char c)
|
2007-12-17 10:05:35 +00:00
|
|
|
{
|
2011-10-20 21:48:47 +00:00
|
|
|
virBufferAdd(buf, &c, 1);
|
2007-12-17 10:05:35 +00:00
|
|
|
}
|
|
|
|
|
2012-06-08 19:50:23 +00:00
|
|
|
/**
|
|
|
|
* virBufferCurrentContent:
|
|
|
|
* @buf: Buffer
|
|
|
|
*
|
|
|
|
* Get the current content from the buffer. The content is only valid
|
|
|
|
* until the next operation on @buf, and an empty string is returned if
|
|
|
|
* no content is present yet.
|
|
|
|
*
|
|
|
|
* Returns the buffer content or NULL in case of error.
|
|
|
|
*/
|
|
|
|
const char *
|
|
|
|
virBufferCurrentContent(virBufferPtr buf)
|
|
|
|
{
|
|
|
|
if (!buf || buf->error)
|
|
|
|
return NULL;
|
|
|
|
return buf->use ? buf->content : "";
|
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
/**
|
2008-04-28 15:14:59 +00:00
|
|
|
* virBufferContentAndReset:
|
|
|
|
* @buf: Buffer
|
2007-06-29 13:23:13 +00:00
|
|
|
*
|
2008-04-28 15:14:59 +00:00
|
|
|
* Get the content from the buffer and free (only) the buffer structure.
|
|
|
|
* The caller owns the returned string & should free it when no longer
|
2012-06-08 19:50:23 +00:00
|
|
|
* required. The buffer object is reset to its initial state. This
|
|
|
|
* interface intentionally returns NULL instead of an empty string if
|
|
|
|
* there is no content.
|
2007-06-29 13:23:13 +00:00
|
|
|
*
|
2008-04-28 15:14:59 +00:00
|
|
|
* Returns the buffer content or NULL in case of error.
|
2007-06-29 13:23:13 +00:00
|
|
|
*/
|
2008-04-28 15:14:59 +00:00
|
|
|
char *
|
2011-09-27 19:50:03 +00:00
|
|
|
virBufferContentAndReset(virBufferPtr buf)
|
2007-03-15 17:30:04 +00:00
|
|
|
{
|
2008-04-28 15:14:59 +00:00
|
|
|
char *str;
|
|
|
|
if (buf == NULL)
|
|
|
|
return NULL;
|
2007-03-15 17:30:04 +00:00
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
if (buf->error) {
|
|
|
|
memset(buf, 0, sizeof(*buf));
|
2007-03-15 17:30:04 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
str = buf->content;
|
|
|
|
memset(buf, 0, sizeof(*buf));
|
|
|
|
return str;
|
2007-03-15 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
2009-12-09 23:00:50 +00:00
|
|
|
/**
|
|
|
|
* virBufferFreeAndReset:
|
|
|
|
* @buf: the buffer to free and reset
|
|
|
|
*
|
|
|
|
* Frees the buffer content and resets the buffer structure.
|
|
|
|
*/
|
2011-09-27 19:50:03 +00:00
|
|
|
void virBufferFreeAndReset(virBufferPtr buf)
|
2009-12-09 23:00:50 +00:00
|
|
|
{
|
|
|
|
char *str = virBufferContentAndReset(buf);
|
|
|
|
|
|
|
|
VIR_FREE(str);
|
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
/**
|
2008-04-28 15:14:59 +00:00
|
|
|
* virBufferError:
|
|
|
|
* @buf: the buffer
|
2007-06-29 13:23:13 +00:00
|
|
|
*
|
2008-04-28 15:14:59 +00:00
|
|
|
* Check to see if the buffer is in an error state due
|
2011-09-27 19:37:23 +00:00
|
|
|
* to failed memory allocation or usage error
|
2008-04-28 15:14:59 +00:00
|
|
|
*
|
2011-09-27 19:37:23 +00:00
|
|
|
* Return positive errno value or -1 on usage error, 0 if normal
|
2007-06-29 13:23:13 +00:00
|
|
|
*/
|
2008-04-28 15:14:59 +00:00
|
|
|
int
|
maint: avoid 'const fooPtr' in several util files
'const fooPtr' is the same as 'foo * const' (the pointer won't
change, but it's contents can). But in general, if an interface
is trying to be const-correct, it should be using 'const foo *'
(the pointer is to data that can't be changed).
Fix up offenders in src/util outside of the virnet namespace.
Also, make a few virSocketAddr functions const-correct, for easier
conversions in future patches.
* src/util/virbuffer.h (virBufferError, virBufferUse)
(virBufferGetIndent): Use intended type.
* src/util/virmacaddr.h (virMacAddrCmp, virMacAddrCmpRaw)
(virMacAddrSet, virMcAddrFormat, virMacAddrIsUnicast)
(virMacAddrIsMulticast): Likewise.
* src/util/virebtables.h (ebtablesAddForwardAllowIn)
(ebtablesRemoveForwardAllowIn): Likewise.
* src/util/virsocketaddr.h (virSocketAddrSetIPv4Addr): Drop
incorrect const.
(virMacAddrGetRaw, virSocketAddrFormat, virSocketAddrFormatFull):
Make const-correct.
(virSocketAddrMask, virSocketAddrMaskByPrefix)
(virSocketAddrBroadcast, virSocketAddrBroadcastByPrefix)
(virSocketAddrGetNumNetmaskBits, virSocketAddrGetIpPrefix)
(virSocketAddrEqual, virSocketAddrIsPrivate)
(virSocketAddrIsWildcard): Use intended type.
* src/util/virbuffer.c (virBufferError, virBufferUse)
(virBufferGetIndent): Fix fallout.
* src/util/virmacaddr.c (virMacAddrCmp, virMacAddrCmpRaw)
(virMacAddrSet, virMcAddrFormat, virMacAddrIsUnicast)
(virMacAddrIsMulticast): Likewise.
* src/util/virebtables.c (ebtablesAddForwardAllowIn)
(ebtablesRemoveForwardAllowIn): Likewise.
* src/util/virsocketaddr.c (virSocketAddrMask, virMacAddrGetRaw)
(virSocketAddrMaskByPrefix, virSocketAddrBroadcast)
(virSocketAddrBroadcastByPrefix, virSocketAddrGetNumNetmaskBits)
(virSocketAddrGetIpPrefix, virSocketAddrEqual)
(virSocketAddrIsPrivate, virSocketAddrIsWildcard)
(virSocketAddrGetIPv4Addr, virSocketAddrGetIPv6Addr)
(virSocketAddrFormat, virSocketAddrFormatFull): Likewise.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-10-05 15:51:55 +00:00
|
|
|
virBufferError(const virBuffer *buf)
|
2007-03-15 17:30:04 +00:00
|
|
|
{
|
2008-04-28 15:14:59 +00:00
|
|
|
if (buf == NULL)
|
2011-09-27 19:37:23 +00:00
|
|
|
return -1;
|
2008-04-28 15:14:59 +00:00
|
|
|
|
|
|
|
return buf->error;
|
2007-03-15 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
2014-06-27 07:23:13 +00:00
|
|
|
/**
|
|
|
|
* virBufferCheckErrorInternal:
|
|
|
|
* @buf: the buffer
|
|
|
|
*
|
|
|
|
* Report an error if the buffer is in an error state.
|
|
|
|
*
|
|
|
|
* Return -1 if an error has been reported, 0 otherwise.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virBufferCheckErrorInternal(const virBuffer *buf,
|
|
|
|
int domcode,
|
|
|
|
const char *filename,
|
|
|
|
const char *funcname,
|
|
|
|
size_t linenr)
|
|
|
|
{
|
|
|
|
if (buf->error == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (buf->error == ENOMEM) {
|
|
|
|
virReportOOMErrorFull(domcode, filename, funcname, linenr);
|
|
|
|
errno = ENOMEM;
|
|
|
|
} else {
|
|
|
|
virReportErrorHelper(domcode, VIR_ERR_INTERNAL_ERROR, filename,
|
|
|
|
funcname, linenr, "%s",
|
|
|
|
_("Invalid buffer API usage"));
|
|
|
|
errno = EINVAL;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-03-15 17:30:04 +00:00
|
|
|
/**
|
2008-04-28 15:14:59 +00:00
|
|
|
* virBufferUse:
|
|
|
|
* @buf: the usage of the string in the buffer
|
2007-03-15 17:30:04 +00:00
|
|
|
*
|
2008-04-28 15:14:59 +00:00
|
|
|
* Return the string usage in bytes
|
2007-03-15 17:30:04 +00:00
|
|
|
*/
|
2008-04-28 15:14:59 +00:00
|
|
|
unsigned int
|
maint: avoid 'const fooPtr' in several util files
'const fooPtr' is the same as 'foo * const' (the pointer won't
change, but it's contents can). But in general, if an interface
is trying to be const-correct, it should be using 'const foo *'
(the pointer is to data that can't be changed).
Fix up offenders in src/util outside of the virnet namespace.
Also, make a few virSocketAddr functions const-correct, for easier
conversions in future patches.
* src/util/virbuffer.h (virBufferError, virBufferUse)
(virBufferGetIndent): Use intended type.
* src/util/virmacaddr.h (virMacAddrCmp, virMacAddrCmpRaw)
(virMacAddrSet, virMcAddrFormat, virMacAddrIsUnicast)
(virMacAddrIsMulticast): Likewise.
* src/util/virebtables.h (ebtablesAddForwardAllowIn)
(ebtablesRemoveForwardAllowIn): Likewise.
* src/util/virsocketaddr.h (virSocketAddrSetIPv4Addr): Drop
incorrect const.
(virMacAddrGetRaw, virSocketAddrFormat, virSocketAddrFormatFull):
Make const-correct.
(virSocketAddrMask, virSocketAddrMaskByPrefix)
(virSocketAddrBroadcast, virSocketAddrBroadcastByPrefix)
(virSocketAddrGetNumNetmaskBits, virSocketAddrGetIpPrefix)
(virSocketAddrEqual, virSocketAddrIsPrivate)
(virSocketAddrIsWildcard): Use intended type.
* src/util/virbuffer.c (virBufferError, virBufferUse)
(virBufferGetIndent): Fix fallout.
* src/util/virmacaddr.c (virMacAddrCmp, virMacAddrCmpRaw)
(virMacAddrSet, virMcAddrFormat, virMacAddrIsUnicast)
(virMacAddrIsMulticast): Likewise.
* src/util/virebtables.c (ebtablesAddForwardAllowIn)
(ebtablesRemoveForwardAllowIn): Likewise.
* src/util/virsocketaddr.c (virSocketAddrMask, virMacAddrGetRaw)
(virSocketAddrMaskByPrefix, virSocketAddrBroadcast)
(virSocketAddrBroadcastByPrefix, virSocketAddrGetNumNetmaskBits)
(virSocketAddrGetIpPrefix, virSocketAddrEqual)
(virSocketAddrIsPrivate, virSocketAddrIsWildcard)
(virSocketAddrGetIPv4Addr, virSocketAddrGetIPv6Addr)
(virSocketAddrFormat, virSocketAddrFormatFull): Likewise.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-10-05 15:51:55 +00:00
|
|
|
virBufferUse(const virBuffer *buf)
|
2007-03-15 17:30:04 +00:00
|
|
|
{
|
2007-06-29 13:23:13 +00:00
|
|
|
if (buf == NULL)
|
2008-04-28 15:14:59 +00:00
|
|
|
return 0;
|
2007-03-15 17:30:04 +00:00
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
return buf->use;
|
2007-03-15 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2011-04-30 16:34:49 +00:00
|
|
|
* virBufferAsprintf:
|
2011-09-27 19:50:03 +00:00
|
|
|
* @buf: the buffer to append to
|
2012-12-19 22:00:13 +00:00
|
|
|
* @format: the format
|
|
|
|
* @...: the variable list of arguments
|
2007-03-15 17:30:04 +00:00
|
|
|
*
|
2011-10-20 21:48:47 +00:00
|
|
|
* Do a formatted print to an XML buffer. Auto indentation may be applied.
|
2007-03-15 17:30:04 +00:00
|
|
|
*/
|
2008-04-28 15:14:59 +00:00
|
|
|
void
|
2011-09-27 19:50:03 +00:00
|
|
|
virBufferAsprintf(virBufferPtr buf, const char *format, ...)
|
2007-03-15 17:30:04 +00:00
|
|
|
{
|
buf: Fix possible infinite loop in EscapeString, VSnprintf
The current code will go into an infinite loop if the printf generated
string is >= 1000, AND exactly 1 character smaller than the amount of free
space in the buffer. When this happens, we are dropped into the loop body,
but nothing will actually change, because count == (buf->size - buf->use - 1),
and virBufferGrow returns unchanged if count < (buf->size - buf->use)
Fix this by removing the '- 1' bit from 'size'. The *nprintf functions handle
the NULL byte for us anyways, so we shouldn't need to manually accommodate
for it.
Here's a bug where we are actually hitting this issue:
https://bugzilla.redhat.com/show_bug.cgi?id=602772
v2: Eric's improvements: while -> if (), remove extra va_list variable,
make sure we report buffer error if snprintf fails
v3: Add tests/virbuftest which reproduces the infinite loop before this
patch, works correctly after
2010-09-01 17:51:35 +00:00
|
|
|
va_list argptr;
|
2011-04-30 16:44:42 +00:00
|
|
|
va_start(argptr, format);
|
|
|
|
virBufferVasprintf(buf, format, argptr);
|
|
|
|
va_end(argptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virBufferVasprintf:
|
2011-10-20 21:48:47 +00:00
|
|
|
* @buf: the buffer to append to
|
2012-12-19 22:00:13 +00:00
|
|
|
* @format: the format
|
|
|
|
* @argptr: the variable list of arguments
|
2011-04-30 16:44:42 +00:00
|
|
|
*
|
2011-10-20 21:48:47 +00:00
|
|
|
* Do a formatted print to an XML buffer. Auto indentation may be applied.
|
2011-04-30 16:44:42 +00:00
|
|
|
*/
|
|
|
|
void
|
2011-09-27 19:50:03 +00:00
|
|
|
virBufferVasprintf(virBufferPtr buf, const char *format, va_list argptr)
|
2011-04-30 16:44:42 +00:00
|
|
|
{
|
|
|
|
int size, count, grow_size;
|
|
|
|
va_list copy;
|
2007-03-15 17:30:04 +00:00
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
if ((format == NULL) || (buf == NULL))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (buf->error)
|
|
|
|
return;
|
2008-02-20 15:29:13 +00:00
|
|
|
|
2011-10-20 21:48:47 +00:00
|
|
|
virBufferAddLit(buf, ""); /* auto-indent */
|
|
|
|
|
2008-02-20 15:29:13 +00:00
|
|
|
if (buf->size == 0 &&
|
|
|
|
virBufferGrow(buf, 100) < 0)
|
2008-04-28 15:14:59 +00:00
|
|
|
return;
|
2008-02-20 15:29:13 +00:00
|
|
|
|
2011-04-30 16:44:42 +00:00
|
|
|
va_copy(copy, argptr);
|
buf: Fix possible infinite loop in EscapeString, VSnprintf
The current code will go into an infinite loop if the printf generated
string is >= 1000, AND exactly 1 character smaller than the amount of free
space in the buffer. When this happens, we are dropped into the loop body,
but nothing will actually change, because count == (buf->size - buf->use - 1),
and virBufferGrow returns unchanged if count < (buf->size - buf->use)
Fix this by removing the '- 1' bit from 'size'. The *nprintf functions handle
the NULL byte for us anyways, so we shouldn't need to manually accommodate
for it.
Here's a bug where we are actually hitting this issue:
https://bugzilla.redhat.com/show_bug.cgi?id=602772
v2: Eric's improvements: while -> if (), remove extra va_list variable,
make sure we report buffer error if snprintf fails
v3: Add tests/virbuftest which reproduces the infinite loop before this
patch, works correctly after
2010-09-01 17:51:35 +00:00
|
|
|
|
|
|
|
size = buf->size - buf->use;
|
|
|
|
if ((count = vsnprintf(&buf->content[buf->use],
|
2011-04-30 16:44:42 +00:00
|
|
|
size, format, copy)) < 0) {
|
2011-09-27 19:37:23 +00:00
|
|
|
virBufferSetError(buf, errno);
|
2011-04-30 16:44:42 +00:00
|
|
|
va_end(copy);
|
|
|
|
return;
|
buf: Fix possible infinite loop in EscapeString, VSnprintf
The current code will go into an infinite loop if the printf generated
string is >= 1000, AND exactly 1 character smaller than the amount of free
space in the buffer. When this happens, we are dropped into the loop body,
but nothing will actually change, because count == (buf->size - buf->use - 1),
and virBufferGrow returns unchanged if count < (buf->size - buf->use)
Fix this by removing the '- 1' bit from 'size'. The *nprintf functions handle
the NULL byte for us anyways, so we shouldn't need to manually accommodate
for it.
Here's a bug where we are actually hitting this issue:
https://bugzilla.redhat.com/show_bug.cgi?id=602772
v2: Eric's improvements: while -> if (), remove extra va_list variable,
make sure we report buffer error if snprintf fails
v3: Add tests/virbuftest which reproduces the infinite loop before this
patch, works correctly after
2010-09-01 17:51:35 +00:00
|
|
|
}
|
2011-04-30 16:44:42 +00:00
|
|
|
va_end(copy);
|
buf: Fix possible infinite loop in EscapeString, VSnprintf
The current code will go into an infinite loop if the printf generated
string is >= 1000, AND exactly 1 character smaller than the amount of free
space in the buffer. When this happens, we are dropped into the loop body,
but nothing will actually change, because count == (buf->size - buf->use - 1),
and virBufferGrow returns unchanged if count < (buf->size - buf->use)
Fix this by removing the '- 1' bit from 'size'. The *nprintf functions handle
the NULL byte for us anyways, so we shouldn't need to manually accommodate
for it.
Here's a bug where we are actually hitting this issue:
https://bugzilla.redhat.com/show_bug.cgi?id=602772
v2: Eric's improvements: while -> if (), remove extra va_list variable,
make sure we report buffer error if snprintf fails
v3: Add tests/virbuftest which reproduces the infinite loop before this
patch, works correctly after
2010-09-01 17:51:35 +00:00
|
|
|
|
|
|
|
/* Grow buffer if necessary and retry */
|
|
|
|
if (count >= size) {
|
2007-03-15 17:30:04 +00:00
|
|
|
buf->content[buf->use] = 0;
|
2008-04-28 15:14:59 +00:00
|
|
|
|
buf: Fix possible infinite loop in EscapeString, VSnprintf
The current code will go into an infinite loop if the printf generated
string is >= 1000, AND exactly 1 character smaller than the amount of free
space in the buffer. When this happens, we are dropped into the loop body,
but nothing will actually change, because count == (buf->size - buf->use - 1),
and virBufferGrow returns unchanged if count < (buf->size - buf->use)
Fix this by removing the '- 1' bit from 'size'. The *nprintf functions handle
the NULL byte for us anyways, so we shouldn't need to manually accommodate
for it.
Here's a bug where we are actually hitting this issue:
https://bugzilla.redhat.com/show_bug.cgi?id=602772
v2: Eric's improvements: while -> if (), remove extra va_list variable,
make sure we report buffer error if snprintf fails
v3: Add tests/virbuftest which reproduces the infinite loop before this
patch, works correctly after
2010-09-01 17:51:35 +00:00
|
|
|
grow_size = (count + 1 > 1000) ? count + 1 : 1000;
|
2014-11-13 14:28:18 +00:00
|
|
|
if (virBufferGrow(buf, grow_size) < 0)
|
2011-04-30 16:44:42 +00:00
|
|
|
return;
|
2008-04-28 15:14:59 +00:00
|
|
|
|
buf: Fix possible infinite loop in EscapeString, VSnprintf
The current code will go into an infinite loop if the printf generated
string is >= 1000, AND exactly 1 character smaller than the amount of free
space in the buffer. When this happens, we are dropped into the loop body,
but nothing will actually change, because count == (buf->size - buf->use - 1),
and virBufferGrow returns unchanged if count < (buf->size - buf->use)
Fix this by removing the '- 1' bit from 'size'. The *nprintf functions handle
the NULL byte for us anyways, so we shouldn't need to manually accommodate
for it.
Here's a bug where we are actually hitting this issue:
https://bugzilla.redhat.com/show_bug.cgi?id=602772
v2: Eric's improvements: while -> if (), remove extra va_list variable,
make sure we report buffer error if snprintf fails
v3: Add tests/virbuftest which reproduces the infinite loop before this
patch, works correctly after
2010-09-01 17:51:35 +00:00
|
|
|
size = buf->size - buf->use;
|
|
|
|
if ((count = vsnprintf(&buf->content[buf->use],
|
|
|
|
size, format, argptr)) < 0) {
|
2011-09-27 19:37:23 +00:00
|
|
|
virBufferSetError(buf, errno);
|
2011-04-30 16:44:42 +00:00
|
|
|
return;
|
buf: Fix possible infinite loop in EscapeString, VSnprintf
The current code will go into an infinite loop if the printf generated
string is >= 1000, AND exactly 1 character smaller than the amount of free
space in the buffer. When this happens, we are dropped into the loop body,
but nothing will actually change, because count == (buf->size - buf->use - 1),
and virBufferGrow returns unchanged if count < (buf->size - buf->use)
Fix this by removing the '- 1' bit from 'size'. The *nprintf functions handle
the NULL byte for us anyways, so we shouldn't need to manually accommodate
for it.
Here's a bug where we are actually hitting this issue:
https://bugzilla.redhat.com/show_bug.cgi?id=602772
v2: Eric's improvements: while -> if (), remove extra va_list variable,
make sure we report buffer error if snprintf fails
v3: Add tests/virbuftest which reproduces the infinite loop before this
patch, works correctly after
2010-09-01 17:51:35 +00:00
|
|
|
}
|
2007-03-15 17:30:04 +00:00
|
|
|
}
|
|
|
|
buf->use += count;
|
|
|
|
}
|
|
|
|
|
2016-04-10 16:21:13 +00:00
|
|
|
|
|
|
|
VIR_WARNINGS_NO_WLOGICALOP_STRCHR
|
|
|
|
|
2015-04-16 16:32:26 +00:00
|
|
|
|
2007-07-09 11:24:52 +00:00
|
|
|
/**
|
|
|
|
* virBufferEscapeString:
|
2011-09-27 19:50:03 +00:00
|
|
|
* @buf: the buffer to append to
|
2007-07-09 11:24:52 +00:00
|
|
|
* @format: a printf like format string but with only one %s parameter
|
2011-10-20 21:48:47 +00:00
|
|
|
* @str: the string argument which needs to be escaped
|
2007-07-09 11:24:52 +00:00
|
|
|
*
|
2011-10-20 21:48:47 +00:00
|
|
|
* Do a formatted print with a single string to an XML buffer. The
|
|
|
|
* string is escaped for use in XML. If @str is NULL, nothing is
|
|
|
|
* added (not even the rest of @format). Auto indentation may be
|
|
|
|
* applied.
|
2007-07-09 11:24:52 +00:00
|
|
|
*/
|
2008-04-28 15:14:59 +00:00
|
|
|
void
|
2011-09-27 19:50:03 +00:00
|
|
|
virBufferEscapeString(virBufferPtr buf, const char *format, const char *str)
|
2007-07-09 11:24:52 +00:00
|
|
|
{
|
2010-11-22 17:04:45 +00:00
|
|
|
int len;
|
2018-07-24 15:52:05 +00:00
|
|
|
VIR_AUTOFREE(char *) escaped = NULL;
|
|
|
|
char *out;
|
2007-07-09 11:24:52 +00:00
|
|
|
const char *cur;
|
2015-03-30 10:41:40 +00:00
|
|
|
const char forbidden_characters[] = {
|
|
|
|
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
|
|
|
/*\t*/ /*\n*/ 0x0B, 0x0C, /*\r*/ 0x0E, 0x0F, 0x10,
|
|
|
|
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
|
|
|
0x19, '"', '&', '\'', '<', '>',
|
|
|
|
'\0'
|
|
|
|
};
|
2007-07-09 11:24:52 +00:00
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
if ((format == NULL) || (buf == NULL) || (str == NULL))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (buf->error)
|
|
|
|
return;
|
2007-07-09 11:24:52 +00:00
|
|
|
|
|
|
|
len = strlen(str);
|
2015-03-30 10:41:40 +00:00
|
|
|
if (strcspn(str, forbidden_characters) == len) {
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(buf, format, str);
|
2010-11-22 17:04:45 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-06-24 20:04:04 +00:00
|
|
|
if (xalloc_oversized(6, len) ||
|
2013-06-07 08:37:25 +00:00
|
|
|
VIR_ALLOC_N_QUIET(escaped, 6 * len + 1) < 0) {
|
2011-09-27 19:37:23 +00:00
|
|
|
virBufferSetError(buf, errno);
|
2008-04-28 15:14:59 +00:00
|
|
|
return;
|
2007-07-09 11:24:52 +00:00
|
|
|
}
|
2008-04-28 15:14:59 +00:00
|
|
|
|
2007-07-09 11:24:52 +00:00
|
|
|
cur = str;
|
|
|
|
out = escaped;
|
|
|
|
while (*cur != 0) {
|
|
|
|
if (*cur == '<') {
|
2008-04-10 16:54:54 +00:00
|
|
|
*out++ = '&';
|
|
|
|
*out++ = 'l';
|
|
|
|
*out++ = 't';
|
|
|
|
*out++ = ';';
|
|
|
|
} else if (*cur == '>') {
|
|
|
|
*out++ = '&';
|
|
|
|
*out++ = 'g';
|
|
|
|
*out++ = 't';
|
|
|
|
*out++ = ';';
|
|
|
|
} else if (*cur == '&') {
|
|
|
|
*out++ = '&';
|
|
|
|
*out++ = 'a';
|
|
|
|
*out++ = 'm';
|
|
|
|
*out++ = 'p';
|
|
|
|
*out++ = ';';
|
2009-05-13 16:19:59 +00:00
|
|
|
} else if (*cur == '"') {
|
|
|
|
*out++ = '&';
|
|
|
|
*out++ = 'q';
|
|
|
|
*out++ = 'u';
|
|
|
|
*out++ = 'o';
|
|
|
|
*out++ = 't';
|
|
|
|
*out++ = ';';
|
|
|
|
} else if (*cur == '\'') {
|
|
|
|
*out++ = '&';
|
|
|
|
*out++ = 'a';
|
|
|
|
*out++ = 'p';
|
|
|
|
*out++ = 'o';
|
|
|
|
*out++ = 's';
|
|
|
|
*out++ = ';';
|
2015-03-30 10:41:40 +00:00
|
|
|
} else if (!strchr(forbidden_characters, *cur)) {
|
2008-04-10 16:54:54 +00:00
|
|
|
/*
|
|
|
|
* default case, just copy !
|
|
|
|
* Note that character over 0x80 are likely to give problem
|
|
|
|
* with UTF-8 XML, but since our string don't have an encoding
|
|
|
|
* it's hard to handle properly we have to assume it's UTF-8 too
|
|
|
|
*/
|
|
|
|
*out++ = *cur;
|
2015-03-30 10:41:40 +00:00
|
|
|
} else {
|
|
|
|
/* silently ignore control characters */
|
2008-04-10 16:54:54 +00:00
|
|
|
}
|
|
|
|
cur++;
|
2007-07-09 11:24:52 +00:00
|
|
|
}
|
|
|
|
*out = 0;
|
|
|
|
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(buf, format, escaped);
|
2007-07-09 11:24:52 +00:00
|
|
|
}
|
|
|
|
|
2010-11-19 15:51:57 +00:00
|
|
|
/**
|
|
|
|
* virBufferEscapeSexpr:
|
2011-09-27 19:50:03 +00:00
|
|
|
* @buf: the buffer to append to
|
2010-11-19 15:51:57 +00:00
|
|
|
* @format: a printf like format string but with only one %s parameter
|
2011-10-20 21:48:47 +00:00
|
|
|
* @str: the string argument which needs to be escaped
|
2010-11-19 15:51:57 +00:00
|
|
|
*
|
2011-10-20 21:48:47 +00:00
|
|
|
* Do a formatted print with a single string to an sexpr buffer. The
|
|
|
|
* string is escaped to avoid generating a sexpr that xen will choke
|
|
|
|
* on. This doesn't fully escape the sexpr, just enough for our code
|
|
|
|
* to work. Auto indentation may be applied.
|
2010-11-19 15:51:57 +00:00
|
|
|
*/
|
|
|
|
void
|
2011-09-27 19:50:03 +00:00
|
|
|
virBufferEscapeSexpr(virBufferPtr buf,
|
2010-11-19 15:51:57 +00:00
|
|
|
const char *format,
|
|
|
|
const char *str)
|
2011-09-20 04:13:42 +00:00
|
|
|
{
|
2012-03-09 19:13:30 +00:00
|
|
|
virBufferEscape(buf, '\\', "\\'", format, str);
|
2017-05-12 12:26:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virBufferEscapeRegex:
|
|
|
|
* @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
|
|
|
|
*
|
|
|
|
* Do a formatted print with a single string to a buffer. The @str is
|
|
|
|
* escaped to avoid using POSIX extended regular expression meta-characters.
|
|
|
|
* Escaping is not applied to characters specified in @format. Auto
|
|
|
|
* indentation may be applied.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
virBufferEscapeRegex(virBufferPtr buf,
|
|
|
|
const char *format,
|
|
|
|
const char *str)
|
|
|
|
{
|
|
|
|
virBufferEscape(buf, '\\', "^$.|?*+()[]{}\\", format, str);
|
2011-09-20 04:13:42 +00:00
|
|
|
}
|
|
|
|
|
2017-10-06 06:47:34 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* virBufferEscapeSQL:
|
|
|
|
* @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
|
|
|
|
*
|
|
|
|
* Do a formatted print with a single string to a buffer. The @str is
|
|
|
|
* escaped to prevent SQL injection (format is expected to contain \"%s\").
|
|
|
|
* Auto indentation may be applied.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
virBufferEscapeSQL(virBufferPtr buf,
|
|
|
|
const char *format,
|
|
|
|
const char *str)
|
|
|
|
{
|
|
|
|
virBufferEscape(buf, '\\', "'\"\\", format, str);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-09-20 04:13:42 +00:00
|
|
|
/**
|
|
|
|
* virBufferEscape:
|
2011-09-27 19:50:03 +00:00
|
|
|
* @buf: the buffer to append to
|
2012-03-09 19:13:30 +00:00
|
|
|
* @escape: the escape character to inject
|
2011-09-27 19:50:03 +00:00
|
|
|
* @toescape: NUL-terminated list of characters to escape
|
2011-09-20 04:13:42 +00:00
|
|
|
* @format: a printf like format string but with only one %s parameter
|
2011-09-27 19:50:03 +00:00
|
|
|
* @str: the string argument which needs to be escaped
|
2011-09-20 04:13:42 +00:00
|
|
|
*
|
|
|
|
* Do a formatted print with a single string to a buffer. Any characters
|
2014-11-11 16:23:49 +00:00
|
|
|
* in the provided list that are contained in @str are escaped with the
|
|
|
|
* given escape. Escaping is not applied to characters specified in @format.
|
|
|
|
* Auto indentation may be applied.
|
2011-09-20 04:13:42 +00:00
|
|
|
*/
|
|
|
|
void
|
2012-03-09 19:13:30 +00:00
|
|
|
virBufferEscape(virBufferPtr buf, char escape, const char *toescape,
|
2011-09-27 19:50:03 +00:00
|
|
|
const char *format, const char *str)
|
2010-11-19 15:51:57 +00:00
|
|
|
{
|
|
|
|
int len;
|
2018-07-24 15:52:05 +00:00
|
|
|
VIR_AUTOFREE(char *) escaped = NULL;
|
|
|
|
char *out;
|
2010-11-19 15:51:57 +00:00
|
|
|
const char *cur;
|
|
|
|
|
|
|
|
if ((format == NULL) || (buf == NULL) || (str == NULL))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (buf->error)
|
|
|
|
return;
|
|
|
|
|
|
|
|
len = strlen(str);
|
2011-09-20 04:13:42 +00:00
|
|
|
if (strcspn(str, toescape) == len) {
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(buf, format, str);
|
2010-11-19 15:51:57 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-06-24 20:04:04 +00:00
|
|
|
if (xalloc_oversized(2, len) ||
|
2013-06-07 08:37:25 +00:00
|
|
|
VIR_ALLOC_N_QUIET(escaped, 2 * len + 1) < 0) {
|
2011-09-27 19:37:23 +00:00
|
|
|
virBufferSetError(buf, errno);
|
2010-11-19 15:51:57 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cur = str;
|
|
|
|
out = escaped;
|
|
|
|
while (*cur != 0) {
|
2012-12-19 19:28:48 +00:00
|
|
|
if (strchr(toescape, *cur))
|
2012-03-09 19:13:30 +00:00
|
|
|
*out++ = escape;
|
2011-09-20 04:13:42 +00:00
|
|
|
*out++ = *cur;
|
2010-11-19 15:51:57 +00:00
|
|
|
cur++;
|
|
|
|
}
|
|
|
|
*out = 0;
|
|
|
|
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(buf, format, escaped);
|
2010-11-19 15:51:57 +00:00
|
|
|
}
|
|
|
|
|
2017-02-23 12:43:32 +00:00
|
|
|
|
2018-07-24 15:52:03 +00:00
|
|
|
typedef struct _virBufferEscapePair virBufferEscapePair;
|
|
|
|
typedef virBufferEscapePair *virBufferEscapePairPtr;
|
|
|
|
|
2017-02-23 12:43:32 +00:00
|
|
|
struct _virBufferEscapePair {
|
|
|
|
char escape;
|
|
|
|
char *toescape;
|
|
|
|
};
|
|
|
|
|
2018-07-24 15:52:04 +00:00
|
|
|
static void
|
|
|
|
virBufferEscapePairFree(virBufferEscapePairPtr pair)
|
|
|
|
{
|
|
|
|
if (!pair)
|
|
|
|
return;
|
|
|
|
|
|
|
|
VIR_FREE(pair->toescape);
|
|
|
|
VIR_FREE(pair);
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_DEFINE_AUTOPTR_FUNC(virBufferEscapePair, virBufferEscapePairFree)
|
|
|
|
|
|
|
|
|
2017-02-23 12:43:32 +00:00
|
|
|
/**
|
|
|
|
* 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;
|
2018-07-24 15:52:05 +00:00
|
|
|
VIR_AUTOFREE(char *) escaped = NULL;
|
2017-02-23 12:43:32 +00:00
|
|
|
char *out;
|
|
|
|
const char *cur;
|
2018-07-24 15:52:03 +00:00
|
|
|
virBufferEscapePair escapeItem;
|
2018-07-24 15:52:06 +00:00
|
|
|
VIR_AUTOPTR(virBufferEscapePair) escapeList = NULL;
|
2017-02-23 12:43:32 +00:00
|
|
|
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))) {
|
2018-07-24 15:52:04 +00:00
|
|
|
if (VIR_STRDUP(escapeItem.toescape, va_arg(ap, char *)) < 0) {
|
2017-02-23 12:43:32 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-12-17 10:05:35 +00:00
|
|
|
/**
|
|
|
|
* virBufferURIEncodeString:
|
2011-09-27 19:50:03 +00:00
|
|
|
* @buf: the buffer to append to
|
2012-12-19 22:00:13 +00:00
|
|
|
* @str: the string argument which will be URI-encoded
|
2007-12-17 10:05:35 +00:00
|
|
|
*
|
|
|
|
* Append the string to the buffer. The string will be URI-encoded
|
|
|
|
* during the append (ie any non alpha-numeric characters are replaced
|
2011-10-20 21:48:47 +00:00
|
|
|
* with '%xx' hex sequences). Auto indentation may be applied.
|
2007-12-17 10:05:35 +00:00
|
|
|
*/
|
2008-04-28 15:14:59 +00:00
|
|
|
void
|
2011-09-27 19:50:03 +00:00
|
|
|
virBufferURIEncodeString(virBufferPtr buf, const char *str)
|
2007-12-17 10:05:35 +00:00
|
|
|
{
|
|
|
|
int grow_size = 0;
|
|
|
|
const char *p;
|
|
|
|
unsigned char uc;
|
|
|
|
const char *hex = "0123456789abcdef";
|
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
if ((buf == NULL) || (str == NULL))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (buf->error)
|
|
|
|
return;
|
|
|
|
|
2011-10-20 21:48:47 +00:00
|
|
|
virBufferAddLit(buf, ""); /* auto-indent */
|
|
|
|
|
2007-12-17 10:05:35 +00:00
|
|
|
for (p = str; *p; ++p) {
|
start using c-ctype functions
Up to now, we've been avoiding ctype functions like isspace, isdigit,
etc. because they are locale-dependent. Now that we have the c-ctype
functions, we can start using *them*, to make the code more readable
with changes like these:
- /* This may not work on EBCDIC. */
- if ((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9'))
+ if (c_isalnum(*p))
- while ((*cur >= '0') && (*cur <= '9')) {
+ while (c_isdigit(*cur)) {
Also, some macros in conf.c used names that conflicted with
standard meaning of "BLANK" and "SPACE", so I've adjusted them
to be in line with the definition of e.g., isblank.
In addition, I've wrapped those statement macros with do {...} while (0),
so that we can't forget the ";" after a use. There was one like that
already (fixed below). The missing semicolon would mess up automatic
indenting.
* src/buf.c (virBufferURIEncodeString):
* src/conf.c (IS_EOL, SKIP_BLANKS_AND_EOL, SKIP_BLANKS)
(virConfParseLong, virConfParseValue, virConfParseName)
(virConfParseSeparator, virConfParseStatement, IS_BLANK, IS_CHAR)
(IS_DIGIT, IS_SPACE, SKIP_SPACES):
* src/nodeinfo.c:
* src/qemu_conf.c (qemudParseInterfaceXML):
* src/qemu_driver.c (qemudDomainBlockStats):
* src/sexpr.c:
* src/stats_linux.c:
* src/util.c (virParseNumber, virDiskNameToIndex):
* src/uuid.c (hextobin, virUUIDParse):
* src/virsh.c:
* src/xml.c (parseCpuNumber, virParseCpuSet):
2008-05-16 09:37:44 +00:00
|
|
|
if (c_isalnum(*p))
|
2007-12-17 10:05:35 +00:00
|
|
|
grow_size++;
|
|
|
|
else
|
|
|
|
grow_size += 3; /* %ab */
|
|
|
|
}
|
|
|
|
|
2011-10-20 21:48:47 +00:00
|
|
|
if (virBufferGrow(buf, grow_size) < 0)
|
2008-04-28 15:14:59 +00:00
|
|
|
return;
|
2007-12-17 10:05:35 +00:00
|
|
|
|
|
|
|
for (p = str; *p; ++p) {
|
2014-09-03 19:39:21 +00:00
|
|
|
if (c_isalnum(*p)) {
|
2007-12-17 10:05:35 +00:00
|
|
|
buf->content[buf->use++] = *p;
|
2014-09-03 19:39:21 +00:00
|
|
|
} else {
|
2007-12-17 10:05:35 +00:00
|
|
|
uc = (unsigned char) *p;
|
|
|
|
buf->content[buf->use++] = '%';
|
|
|
|
buf->content[buf->use++] = hex[uc >> 4];
|
|
|
|
buf->content[buf->use++] = hex[uc & 0xf];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
buf->content[buf->use] = '\0';
|
|
|
|
}
|
|
|
|
|
2011-07-28 13:25:00 +00:00
|
|
|
/**
|
|
|
|
* virBufferEscapeShell:
|
2011-10-20 21:48:47 +00:00
|
|
|
* @buf: the buffer to append to
|
|
|
|
* @str: an unquoted string
|
2011-07-28 13:25:00 +00:00
|
|
|
*
|
|
|
|
* Quotes a string so that the shell (/bin/sh) will interpret the
|
2011-10-20 21:48:47 +00:00
|
|
|
* quoted string to mean str. Auto indentation may be applied.
|
2011-07-28 13:25:00 +00:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
virBufferEscapeShell(virBufferPtr buf, const char *str)
|
|
|
|
{
|
|
|
|
int len;
|
2018-07-24 15:52:05 +00:00
|
|
|
VIR_AUTOFREE(char *) escaped = NULL;
|
|
|
|
char *out;
|
2011-07-28 13:25:00 +00:00
|
|
|
const char *cur;
|
|
|
|
|
|
|
|
if ((buf == NULL) || (str == NULL))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (buf->error)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Only quote if str includes shell metacharacters. */
|
2011-10-13 21:48:40 +00:00
|
|
|
if (*str && !strpbrk(str, "\r\t\n !\"#$&'()*;<>?[\\]^`{|}~")) {
|
2011-07-28 13:25:00 +00:00
|
|
|
virBufferAdd(buf, str, -1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-10-13 21:48:40 +00:00
|
|
|
if (*str) {
|
|
|
|
len = strlen(str);
|
|
|
|
if (xalloc_oversized(4, len) ||
|
2013-06-07 08:37:25 +00:00
|
|
|
VIR_ALLOC_N_QUIET(escaped, 4 * len + 3) < 0) {
|
2011-09-27 19:37:23 +00:00
|
|
|
virBufferSetError(buf, errno);
|
2011-10-13 21:48:40 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
2011-10-19 08:44:08 +00:00
|
|
|
virBufferAddLit(buf, "''");
|
2011-07-28 13:25:00 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cur = str;
|
|
|
|
out = escaped;
|
|
|
|
|
|
|
|
*out++ = '\'';
|
|
|
|
while (*cur != 0) {
|
|
|
|
if (*cur == '\'') {
|
2011-10-18 07:07:41 +00:00
|
|
|
*out++ = '\'';
|
2011-07-28 13:25:00 +00:00
|
|
|
/* Replace literal ' with a close ', a \', and a open ' */
|
|
|
|
*out++ = '\\';
|
|
|
|
*out++ = '\'';
|
|
|
|
}
|
2011-10-18 07:07:41 +00:00
|
|
|
*out++ = *cur++;
|
2011-07-28 13:25:00 +00:00
|
|
|
}
|
|
|
|
*out++ = '\'';
|
|
|
|
*out = 0;
|
|
|
|
|
|
|
|
virBufferAdd(buf, escaped, -1);
|
|
|
|
}
|
|
|
|
|
2017-07-24 16:54:15 +00:00
|
|
|
/**
|
|
|
|
* virBufferStrcatVArgs:
|
|
|
|
* @buf: the buffer to append to
|
|
|
|
* @ap: variable argument structure
|
|
|
|
*
|
|
|
|
* See virBufferStrcat.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
virBufferStrcatVArgs(virBufferPtr buf,
|
|
|
|
va_list ap)
|
|
|
|
{
|
|
|
|
char *str;
|
|
|
|
|
|
|
|
if (buf->error)
|
|
|
|
return;
|
|
|
|
|
|
|
|
while ((str = va_arg(ap, char *)) != NULL)
|
|
|
|
virBufferAdd(buf, str, -1);
|
|
|
|
}
|
|
|
|
|
2007-03-15 17:30:04 +00:00
|
|
|
/**
|
2007-06-26 22:21:22 +00:00
|
|
|
* virBufferStrcat:
|
2011-09-27 19:50:03 +00:00
|
|
|
* @buf: the buffer to append to
|
2012-12-19 22:00:13 +00:00
|
|
|
* @...: the variable list of strings, the last argument must be NULL
|
2007-03-15 17:30:04 +00:00
|
|
|
*
|
2011-10-20 21:48:47 +00:00
|
|
|
* Concatenate strings to an XML buffer. Auto indentation may be applied
|
|
|
|
* after each string argument.
|
2007-03-15 17:30:04 +00:00
|
|
|
*/
|
2008-04-28 15:14:59 +00:00
|
|
|
void
|
2007-06-26 22:21:22 +00:00
|
|
|
virBufferStrcat(virBufferPtr buf, ...)
|
2007-03-15 17:30:04 +00:00
|
|
|
{
|
|
|
|
va_list ap;
|
2008-04-28 15:14:59 +00:00
|
|
|
|
2018-03-22 12:10:40 +00:00
|
|
|
if (!buf)
|
|
|
|
return;
|
|
|
|
|
2007-03-15 17:30:04 +00:00
|
|
|
va_start(ap, buf);
|
2017-07-24 16:54:15 +00:00
|
|
|
virBufferStrcatVArgs(buf, ap);
|
2007-03-15 17:30:04 +00:00
|
|
|
va_end(ap);
|
|
|
|
}
|
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.
2012-05-18 22:36:59 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*
|
2013-06-18 15:52:00 +00:00
|
|
|
* Sets error to -1 (usage) if str is NULL and len is less than zero.
|
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.
2012-05-18 22:36:59 +00:00
|
|
|
*/
|
2013-06-18 15:52:00 +00:00
|
|
|
void
|
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.
2012-05-18 22:36:59 +00:00
|
|
|
virBufferTrim(virBufferPtr buf, const char *str, int len)
|
|
|
|
{
|
|
|
|
size_t len2 = 0;
|
|
|
|
|
2013-06-18 15:52:00 +00:00
|
|
|
if (!buf || buf->error)
|
|
|
|
return;
|
|
|
|
if (!str && len < 0) {
|
|
|
|
virBufferSetError(buf, -1);
|
|
|
|
return;
|
|
|
|
}
|
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.
2012-05-18 22:36:59 +00:00
|
|
|
|
|
|
|
if (len > 0 && len > buf->use)
|
2013-06-18 15:52:00 +00:00
|
|
|
return;
|
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.
2012-05-18 22:36:59 +00:00
|
|
|
if (str) {
|
|
|
|
len2 = strlen(str);
|
|
|
|
if (len2 > buf->use ||
|
|
|
|
memcmp(&buf->content[buf->use - len2], str, len2) != 0)
|
2013-06-18 15:52:00 +00:00
|
|
|
return;
|
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.
2012-05-18 22:36:59 +00:00
|
|
|
}
|
|
|
|
buf->use -= len < 0 ? len2 : len;
|
|
|
|
buf->content[buf->use] = '\0';
|
|
|
|
}
|
2015-03-24 09:53:29 +00:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virBufferAddStr:
|
|
|
|
* @buf: the buffer to append to
|
|
|
|
* @str: string to append
|
|
|
|
*
|
|
|
|
* Appends @str to @buffer. Applies autoindentation on the separate lines of
|
|
|
|
* @str.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
virBufferAddStr(virBufferPtr buf,
|
|
|
|
const char *str)
|
|
|
|
{
|
|
|
|
const char *end;
|
|
|
|
|
|
|
|
if (!buf || !str || buf->error)
|
|
|
|
return;
|
|
|
|
|
|
|
|
while (*str) {
|
|
|
|
if ((end = strchr(str, '\n'))) {
|
|
|
|
virBufferAdd(buf, str, (end - str) + 1);
|
|
|
|
str = end + 1;
|
|
|
|
} else {
|
|
|
|
virBufferAdd(buf, str, -1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|