mirror of
https://github.com/libvirt/libvirt.git
synced 2025-02-25 18:55:26 -06:00
util: buffer: Reimplement virBuffer internals using glib's GString
GString is surprisingly similar to what libvirt was doing painstakingly manually. Yet it doesn't support the automatic indentation features we use for XML so we rather keep those in form of virBuffer using GString internally. Signed-off-by: Peter Krempa <pkrempa@redhat.com> Reviewed-by: Ján Tomko <jtomko@redhat.com>
This commit is contained in:
parent
c721cc1670
commit
244f906b16
@ -21,7 +21,6 @@
|
|||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include "c-ctype.h"
|
|
||||||
|
|
||||||
#include "virbuffer.h"
|
#include "virbuffer.h"
|
||||||
#include "virerror.h"
|
#include "virerror.h"
|
||||||
@ -40,10 +39,7 @@
|
|||||||
static void
|
static void
|
||||||
virBufferSetError(virBufferPtr buf, int error)
|
virBufferSetError(virBufferPtr buf, int error)
|
||||||
{
|
{
|
||||||
VIR_FREE(buf->content);
|
virBufferFreeAndReset(buf);
|
||||||
buf->size = 0;
|
|
||||||
buf->use = 0;
|
|
||||||
buf->indent = 0;
|
|
||||||
buf->error = error;
|
buf->error = error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,7 +118,7 @@ virBufferGetIndent(const virBuffer *buf)
|
|||||||
size_t
|
size_t
|
||||||
virBufferGetEffectiveIndent(const virBuffer *buf)
|
virBufferGetEffectiveIndent(const virBuffer *buf)
|
||||||
{
|
{
|
||||||
if (buf->use && buf->content[buf->use - 1] != '\n')
|
if (buf->str && buf->str->len && buf->str->str[buf->str->len - 1] != '\n')
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return buf->indent;
|
return buf->indent;
|
||||||
@ -130,35 +126,38 @@ virBufferGetEffectiveIndent(const virBuffer *buf)
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* virBufferGrow:
|
* virBufferInitialize
|
||||||
* @buf: the buffer
|
* @buf: the buffer
|
||||||
* @len: the minimum free size to allocate on top of existing used space
|
|
||||||
*
|
*
|
||||||
* Grow the available space of a buffer to at least @len bytes.
|
* Ensures that the internal GString container is allocated.
|
||||||
*
|
|
||||||
* Returns zero on success or -1 on error
|
|
||||||
*/
|
*/
|
||||||
static int
|
static void
|
||||||
virBufferGrow(virBufferPtr buf, unsigned int len)
|
virBufferInitialize(virBufferPtr buf)
|
||||||
{
|
{
|
||||||
int size;
|
if (!buf->str)
|
||||||
|
buf->str = g_string_new(NULL);
|
||||||
if (buf->error)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if ((len + buf->use) < buf->size)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
size = buf->use + len + 1000;
|
|
||||||
|
|
||||||
if (VIR_REALLOC_N_QUIET(buf->content, size) < 0) {
|
|
||||||
virBufferSetError(buf, errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
buf->size = size;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
virBufferApplyIndent(virBufferPtr buf)
|
||||||
|
{
|
||||||
|
const char space[] = " ";
|
||||||
|
size_t spacesz = sizeof(space) - 1;
|
||||||
|
size_t toindent = virBufferGetEffectiveIndent(buf);
|
||||||
|
|
||||||
|
if (toindent == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (toindent > spacesz) {
|
||||||
|
g_string_append_len(buf->str, space, spacesz);
|
||||||
|
toindent -= spacesz;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_string_append_len(buf->str, space, toindent);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* virBufferAdd:
|
* virBufferAdd:
|
||||||
* @buf: the buffer to append to
|
* @buf: the buffer to append to
|
||||||
@ -172,25 +171,16 @@ virBufferGrow(virBufferPtr buf, unsigned int len)
|
|||||||
void
|
void
|
||||||
virBufferAdd(virBufferPtr buf, const char *str, int len)
|
virBufferAdd(virBufferPtr buf, const char *str, int len)
|
||||||
{
|
{
|
||||||
unsigned int needSize;
|
|
||||||
size_t indent;
|
|
||||||
|
|
||||||
if (!str || !buf || buf->error || (len == 0 && buf->indent == 0))
|
if (!str || !buf || buf->error || (len == 0 && buf->indent == 0))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
indent = virBufferGetEffectiveIndent(buf);
|
virBufferInitialize(buf);
|
||||||
|
virBufferApplyIndent(buf);
|
||||||
|
|
||||||
if (len < 0)
|
if (len < 0)
|
||||||
len = strlen(str);
|
g_string_append(buf->str, str);
|
||||||
|
else
|
||||||
needSize = buf->use + indent + len + 2;
|
g_string_append_len(buf->str, str, len);
|
||||||
if (virBufferGrow(buf, needSize - buf->use) < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
memset(&buf->content[buf->use], ' ', indent);
|
|
||||||
memcpy(&buf->content[buf->use + indent], str, len);
|
|
||||||
buf->use += indent + len;
|
|
||||||
buf->content[buf->use] = '\0';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -207,7 +197,7 @@ virBufferAdd(virBufferPtr buf, const char *str, int len)
|
|||||||
void
|
void
|
||||||
virBufferAddBuffer(virBufferPtr buf, virBufferPtr toadd)
|
virBufferAddBuffer(virBufferPtr buf, virBufferPtr toadd)
|
||||||
{
|
{
|
||||||
if (!toadd)
|
if (!toadd || !toadd->str)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!buf)
|
if (!buf)
|
||||||
@ -219,12 +209,8 @@ virBufferAddBuffer(virBufferPtr buf, virBufferPtr toadd)
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (virBufferGrow(buf, toadd->use) < 0)
|
virBufferInitialize(buf);
|
||||||
goto cleanup;
|
g_string_append_len(buf->str, toadd->str->str, toadd->str->len);
|
||||||
|
|
||||||
memcpy(&buf->content[buf->use], toadd->content, toadd->use);
|
|
||||||
buf->use += toadd->use;
|
|
||||||
buf->content[buf->use] = '\0';
|
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
virBufferFreeAndReset(toadd);
|
virBufferFreeAndReset(toadd);
|
||||||
@ -259,7 +245,12 @@ virBufferCurrentContent(virBufferPtr buf)
|
|||||||
{
|
{
|
||||||
if (!buf || buf->error)
|
if (!buf || buf->error)
|
||||||
return NULL;
|
return NULL;
|
||||||
return buf->use ? buf->content : "";
|
|
||||||
|
if (!buf->str ||
|
||||||
|
buf->str->len == 0)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
return buf->str->str;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -277,16 +268,14 @@ virBufferCurrentContent(virBufferPtr buf)
|
|||||||
char *
|
char *
|
||||||
virBufferContentAndReset(virBufferPtr buf)
|
virBufferContentAndReset(virBufferPtr buf)
|
||||||
{
|
{
|
||||||
char *str;
|
char *str = NULL;
|
||||||
if (buf == NULL)
|
|
||||||
|
if (!buf)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (buf->error) {
|
if (buf->str)
|
||||||
memset(buf, 0, sizeof(*buf));
|
str = g_string_free(buf->str, false);
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
str = buf->content;
|
|
||||||
memset(buf, 0, sizeof(*buf));
|
memset(buf, 0, sizeof(*buf));
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
@ -299,8 +288,13 @@ virBufferContentAndReset(virBufferPtr buf)
|
|||||||
*/
|
*/
|
||||||
void virBufferFreeAndReset(virBufferPtr buf)
|
void virBufferFreeAndReset(virBufferPtr buf)
|
||||||
{
|
{
|
||||||
if (buf)
|
if (!buf)
|
||||||
virBufferSetError(buf, 0);
|
return;
|
||||||
|
|
||||||
|
if (buf->str)
|
||||||
|
g_string_free(buf->str, true);
|
||||||
|
|
||||||
|
memset(buf, 0, sizeof(*buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -360,10 +354,10 @@ virBufferCheckErrorInternal(const virBuffer *buf,
|
|||||||
size_t
|
size_t
|
||||||
virBufferUse(const virBuffer *buf)
|
virBufferUse(const virBuffer *buf)
|
||||||
{
|
{
|
||||||
if (buf == NULL)
|
if (!buf || !buf->str)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return buf->use;
|
return buf->str->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -394,48 +388,16 @@ virBufferAsprintf(virBufferPtr buf, const char *format, ...)
|
|||||||
void
|
void
|
||||||
virBufferVasprintf(virBufferPtr buf, const char *format, va_list argptr)
|
virBufferVasprintf(virBufferPtr buf, const char *format, va_list argptr)
|
||||||
{
|
{
|
||||||
int size, count, grow_size;
|
|
||||||
va_list copy;
|
|
||||||
|
|
||||||
if ((format == NULL) || (buf == NULL))
|
if ((format == NULL) || (buf == NULL))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (buf->error)
|
if (buf->error)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
virBufferAddLit(buf, ""); /* auto-indent */
|
virBufferInitialize(buf);
|
||||||
|
virBufferApplyIndent(buf);
|
||||||
|
|
||||||
if (buf->size == 0 &&
|
g_string_append_vprintf(buf->str, format, argptr);
|
||||||
virBufferGrow(buf, 100) < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
va_copy(copy, argptr);
|
|
||||||
|
|
||||||
size = buf->size - buf->use;
|
|
||||||
if ((count = vsnprintf(&buf->content[buf->use],
|
|
||||||
size, format, copy)) < 0) {
|
|
||||||
virBufferSetError(buf, errno);
|
|
||||||
va_end(copy);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
va_end(copy);
|
|
||||||
|
|
||||||
/* Grow buffer if necessary and retry */
|
|
||||||
if (count >= size) {
|
|
||||||
buf->content[buf->use] = 0;
|
|
||||||
|
|
||||||
grow_size = (count + 1 > 1000) ? count + 1 : 1000;
|
|
||||||
if (virBufferGrow(buf, grow_size) < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
size = buf->size - buf->use;
|
|
||||||
if ((count = vsnprintf(&buf->content[buf->use],
|
|
||||||
size, format, argptr)) < 0) {
|
|
||||||
virBufferSetError(buf, errno);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buf->use += count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -638,16 +600,6 @@ virBufferEscape(virBufferPtr buf, char escape, const char *toescape,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool
|
|
||||||
virBufferURIEncodeCharIsUnencoded(char c)
|
|
||||||
{
|
|
||||||
if (c == '-' || c == '.' || c == '_' || c == '~')
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return c_isalnum(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* virBufferURIEncodeString:
|
* virBufferURIEncodeString:
|
||||||
* @buf: the buffer to append to
|
* @buf: the buffer to append to
|
||||||
@ -660,41 +612,16 @@ virBufferURIEncodeCharIsUnencoded(char c)
|
|||||||
void
|
void
|
||||||
virBufferURIEncodeString(virBufferPtr buf, const char *str)
|
virBufferURIEncodeString(virBufferPtr buf, const char *str)
|
||||||
{
|
{
|
||||||
int grow_size = 0;
|
|
||||||
const char *p;
|
|
||||||
unsigned char uc;
|
|
||||||
const char *hex = "0123456789ABCDEF";
|
|
||||||
|
|
||||||
if ((buf == NULL) || (str == NULL))
|
if ((buf == NULL) || (str == NULL))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (buf->error)
|
if (buf->error)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
virBufferAddLit(buf, ""); /* auto-indent */
|
virBufferInitialize(buf);
|
||||||
|
virBufferApplyIndent(buf);
|
||||||
|
|
||||||
for (p = str; *p; ++p) {
|
g_string_append_uri_escaped(buf->str, str, NULL, false);
|
||||||
if (virBufferURIEncodeCharIsUnencoded(*p))
|
|
||||||
grow_size++;
|
|
||||||
else
|
|
||||||
grow_size += 3; /* %ab */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (virBufferGrow(buf, grow_size) < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (p = str; *p; ++p) {
|
|
||||||
if (virBufferURIEncodeCharIsUnencoded(*p)) {
|
|
||||||
buf->content[buf->use++] = *p;
|
|
||||||
} else {
|
|
||||||
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';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -810,21 +737,27 @@ virBufferTrim(virBufferPtr buf, const char *str, int len)
|
|||||||
{
|
{
|
||||||
size_t len2 = 0;
|
size_t len2 = 0;
|
||||||
|
|
||||||
if (!buf || buf->error)
|
if (!buf || buf->error || !buf->str)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!str && len < 0)
|
if (!str && len < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (len > 0 && len > buf->use)
|
|
||||||
|
if (len > 0 && len > buf->str->len)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (str) {
|
if (str) {
|
||||||
len2 = strlen(str);
|
len2 = strlen(str);
|
||||||
if (len2 > buf->use ||
|
if (len2 > buf->str->len ||
|
||||||
memcmp(&buf->content[buf->use - len2], str, len2) != 0)
|
memcmp(&buf->str->str[buf->str->len - len2], str, len2) != 0)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
buf->use -= len < 0 ? len2 : len;
|
|
||||||
buf->content[buf->use] = '\0';
|
if (len < 0)
|
||||||
|
len = len2;
|
||||||
|
|
||||||
|
g_string_truncate(buf->str, buf->str->len - len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,14 +33,12 @@
|
|||||||
typedef struct _virBuffer virBuffer;
|
typedef struct _virBuffer virBuffer;
|
||||||
typedef virBuffer *virBufferPtr;
|
typedef virBuffer *virBufferPtr;
|
||||||
|
|
||||||
#define VIR_BUFFER_INITIALIZER { 0, 0, 0, 0, NULL }
|
#define VIR_BUFFER_INITIALIZER { NULL, 0, 0 }
|
||||||
|
|
||||||
struct _virBuffer {
|
struct _virBuffer {
|
||||||
size_t size;
|
GString *str;
|
||||||
size_t use;
|
|
||||||
int error; /* errno value, or -1 for usage error */
|
int error; /* errno value, or -1 for usage error */
|
||||||
int indent;
|
int indent;
|
||||||
char *content;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *virBufferCurrentContent(virBufferPtr buf);
|
const char *virBufferCurrentContent(virBufferPtr buf);
|
||||||
|
Loading…
Reference in New Issue
Block a user