mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-04 16:23:55 -06:00
QAPI patches for 2016-07-06
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJXfMjDAAoJEDhwtADrkYZTyKwP/i5Lva3qhDk9AJhvPNSbnps/ sxVGVkUTeUM0UoXdKmDChkk2zScv2AOVxL3oibb22PmU1MvDU+XoKYokae/VucVS WL16t/Z77QxSJ1yKhXT3i0P7+9sR9Gq2eDHchSSITLreVO8/jNb7u1JjnV4nPyQP Scg6sCCnfgSw8W4EOz0wDhwXHbRv7obSY0lGUD1R6FifETHQ98rTpII0BS1AyvbF HIJMcGpirAe62BGNQeJv933mrD1EgRfBytQAkEL/l6DDlz/xk9AE26bsjdP5Xa9A MwEBje9CPm0ICleqq1ZVKNQQqng2PVfXXXdJYKQKVnIHL+REzRDKbTGTlS4njdVi v2i4E7MwDPIf86zRUXJ6eUkWDHgld4of2WZmoxNPZmWWmHMb31iqGcb0//mYmP06 QOPd/uxpxg9pze4JeQMhzHCbFum2/s43cyqaH24lrwhTw3EsI45t4sgJQTG1NIFt ZdPXVwNBfa6ur50dsRWHYonQimpofW94YYupWLggiVGKTzvfSWVQJGc9Ho65P23y ZJrkbN3bWNnwVFzIbWFI5TKnE/TsnWvTPwk+9cGSP4MKf1sy6t5nIycoTiP3vC9x PesENYYKy5ZkOkKQpC6lGwjkMl24ii3lVl5g4vWXXjtZHwGNmq/7/UJ7Dm4htqIk B5gm5gQ/2Tul4Dihlteb =BgpV -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2016-07-06' into staging QAPI patches for 2016-07-06 # gpg: Signature made Wed 06 Jul 2016 10:00:51 BST # gpg: using RSA key 0x3870B400EB918653 # gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" # gpg: aka "Markus Armbruster <armbru@pond.sub.org>" # Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867 4E5F 3870 B400 EB91 8653 * remotes/armbru/tags/pull-qapi-2016-07-06: replay: Use new QAPI cloning sockets: Use new QAPI cloning qapi: Add new clone visitor qapi: Add new visit_complete() function tests: Factor out common code in qapi output tests tests: Clean up test-string-output-visitor qmp-output-visitor: Favor new visit_free() function string-output-visitor: Favor new visit_free() function qmp-input-visitor: Favor new visit_free() function string-input-visitor: Favor new visit_free() function opts-visitor: Favor new visit_free() function qapi: Add new visit_free() function qapi: Add parameter to visit_end_* qemu-img: Don't leak errors when outputting JSON qapi: Improve use of qmp/types.h Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
975b1c3ac6
63 changed files with 1027 additions and 715 deletions
|
@ -1,6 +1,6 @@
|
|||
util-obj-y = qapi-visit-core.o qapi-dealloc-visitor.o qmp-input-visitor.o
|
||||
util-obj-y += qmp-output-visitor.o qmp-registry.o qmp-dispatch.o
|
||||
util-obj-y += string-input-visitor.o string-output-visitor.o
|
||||
util-obj-y += opts-visitor.o
|
||||
util-obj-y += opts-visitor.o qapi-clone-visitor.o
|
||||
util-obj-y += qmp-event.o
|
||||
util-obj-y += qapi-util.o
|
||||
|
|
|
@ -180,7 +180,7 @@ opts_check_struct(Visitor *v, Error **errp)
|
|||
|
||||
|
||||
static void
|
||||
opts_end_struct(Visitor *v)
|
||||
opts_end_struct(Visitor *v, void **obj)
|
||||
{
|
||||
OptsVisitor *ov = to_ov(v);
|
||||
|
||||
|
@ -273,7 +273,7 @@ opts_next_list(Visitor *v, GenericList *tail, size_t size)
|
|||
|
||||
|
||||
static void
|
||||
opts_end_list(Visitor *v)
|
||||
opts_end_list(Visitor *v, void **obj)
|
||||
{
|
||||
OptsVisitor *ov = to_ov(v);
|
||||
|
||||
|
@ -513,7 +513,20 @@ opts_optional(Visitor *v, const char *name, bool *present)
|
|||
}
|
||||
|
||||
|
||||
OptsVisitor *
|
||||
static void
|
||||
opts_free(Visitor *v)
|
||||
{
|
||||
OptsVisitor *ov = to_ov(v);
|
||||
|
||||
if (ov->unprocessed_opts != NULL) {
|
||||
g_hash_table_destroy(ov->unprocessed_opts);
|
||||
}
|
||||
g_free(ov->fake_id_opt);
|
||||
g_free(ov);
|
||||
}
|
||||
|
||||
|
||||
Visitor *
|
||||
opts_visitor_new(const QemuOpts *opts)
|
||||
{
|
||||
OptsVisitor *ov;
|
||||
|
@ -540,26 +553,9 @@ opts_visitor_new(const QemuOpts *opts)
|
|||
* skip some mandatory methods... */
|
||||
|
||||
ov->visitor.optional = &opts_optional;
|
||||
ov->visitor.free = opts_free;
|
||||
|
||||
ov->opts_root = opts;
|
||||
|
||||
return ov;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
opts_visitor_cleanup(OptsVisitor *ov)
|
||||
{
|
||||
if (ov->unprocessed_opts != NULL) {
|
||||
g_hash_table_destroy(ov->unprocessed_opts);
|
||||
}
|
||||
g_free(ov->fake_id_opt);
|
||||
g_free(ov);
|
||||
}
|
||||
|
||||
|
||||
Visitor *
|
||||
opts_get_visitor(OptsVisitor *ov)
|
||||
{
|
||||
return &ov->visitor;
|
||||
}
|
||||
|
|
182
qapi/qapi-clone-visitor.c
Normal file
182
qapi/qapi-clone-visitor.c
Normal file
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
* Copy one QAPI object to another
|
||||
*
|
||||
* Copyright (C) 2016 Red Hat, Inc.
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/clone-visitor.h"
|
||||
#include "qapi/visitor-impl.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
struct QapiCloneVisitor {
|
||||
Visitor visitor;
|
||||
size_t depth;
|
||||
};
|
||||
|
||||
static QapiCloneVisitor *to_qcv(Visitor *v)
|
||||
{
|
||||
return container_of(v, QapiCloneVisitor, visitor);
|
||||
}
|
||||
|
||||
static void qapi_clone_start_struct(Visitor *v, const char *name, void **obj,
|
||||
size_t size, Error **errp)
|
||||
{
|
||||
QapiCloneVisitor *qcv = to_qcv(v);
|
||||
|
||||
if (!obj) {
|
||||
assert(qcv->depth);
|
||||
/* Only possible when visiting an alternate's object
|
||||
* branch. Nothing further to do here, since the earlier
|
||||
* visit_start_alternate() already copied memory. */
|
||||
return;
|
||||
}
|
||||
|
||||
*obj = g_memdup(*obj, size);
|
||||
qcv->depth++;
|
||||
}
|
||||
|
||||
static void qapi_clone_end(Visitor *v, void **obj)
|
||||
{
|
||||
QapiCloneVisitor *qcv = to_qcv(v);
|
||||
|
||||
assert(qcv->depth);
|
||||
if (obj) {
|
||||
qcv->depth--;
|
||||
}
|
||||
}
|
||||
|
||||
static void qapi_clone_start_list(Visitor *v, const char *name,
|
||||
GenericList **listp, size_t size,
|
||||
Error **errp)
|
||||
{
|
||||
qapi_clone_start_struct(v, name, (void **)listp, size, errp);
|
||||
}
|
||||
|
||||
static GenericList *qapi_clone_next_list(Visitor *v, GenericList *tail,
|
||||
size_t size)
|
||||
{
|
||||
QapiCloneVisitor *qcv = to_qcv(v);
|
||||
|
||||
assert(qcv->depth);
|
||||
/* Unshare the tail of the list cloned by g_memdup() */
|
||||
tail->next = g_memdup(tail->next, size);
|
||||
return tail->next;
|
||||
}
|
||||
|
||||
static void qapi_clone_start_alternate(Visitor *v, const char *name,
|
||||
GenericAlternate **obj, size_t size,
|
||||
bool promote_int, Error **errp)
|
||||
{
|
||||
qapi_clone_start_struct(v, name, (void **)obj, size, errp);
|
||||
}
|
||||
|
||||
static void qapi_clone_type_int64(Visitor *v, const char *name, int64_t *obj,
|
||||
Error **errp)
|
||||
{
|
||||
QapiCloneVisitor *qcv = to_qcv(v);
|
||||
|
||||
assert(qcv->depth);
|
||||
/* Value was already cloned by g_memdup() */
|
||||
}
|
||||
|
||||
static void qapi_clone_type_uint64(Visitor *v, const char *name,
|
||||
uint64_t *obj, Error **errp)
|
||||
{
|
||||
QapiCloneVisitor *qcv = to_qcv(v);
|
||||
|
||||
assert(qcv->depth);
|
||||
/* Value was already cloned by g_memdup() */
|
||||
}
|
||||
|
||||
static void qapi_clone_type_bool(Visitor *v, const char *name, bool *obj,
|
||||
Error **errp)
|
||||
{
|
||||
QapiCloneVisitor *qcv = to_qcv(v);
|
||||
|
||||
assert(qcv->depth);
|
||||
/* Value was already cloned by g_memdup() */
|
||||
}
|
||||
|
||||
static void qapi_clone_type_str(Visitor *v, const char *name, char **obj,
|
||||
Error **errp)
|
||||
{
|
||||
QapiCloneVisitor *qcv = to_qcv(v);
|
||||
|
||||
assert(qcv->depth);
|
||||
/*
|
||||
* Pointer was already cloned by g_memdup; create fresh copy.
|
||||
* Note that as long as qmp-output-visitor accepts NULL instead of
|
||||
* "", then we must do likewise. However, we want to obey the
|
||||
* input visitor semantics of never producing NULL when the empty
|
||||
* string is intended.
|
||||
*/
|
||||
*obj = g_strdup(*obj ?: "");
|
||||
}
|
||||
|
||||
static void qapi_clone_type_number(Visitor *v, const char *name, double *obj,
|
||||
Error **errp)
|
||||
{
|
||||
QapiCloneVisitor *qcv = to_qcv(v);
|
||||
|
||||
assert(qcv->depth);
|
||||
/* Value was already cloned by g_memdup() */
|
||||
}
|
||||
|
||||
static void qapi_clone_type_null(Visitor *v, const char *name, Error **errp)
|
||||
{
|
||||
QapiCloneVisitor *qcv = to_qcv(v);
|
||||
|
||||
assert(qcv->depth);
|
||||
/* Nothing to do */
|
||||
}
|
||||
|
||||
static void qapi_clone_free(Visitor *v)
|
||||
{
|
||||
g_free(v);
|
||||
}
|
||||
|
||||
static Visitor *qapi_clone_visitor_new(void)
|
||||
{
|
||||
QapiCloneVisitor *v;
|
||||
|
||||
v = g_malloc0(sizeof(*v));
|
||||
|
||||
v->visitor.type = VISITOR_CLONE;
|
||||
v->visitor.start_struct = qapi_clone_start_struct;
|
||||
v->visitor.end_struct = qapi_clone_end;
|
||||
v->visitor.start_list = qapi_clone_start_list;
|
||||
v->visitor.next_list = qapi_clone_next_list;
|
||||
v->visitor.end_list = qapi_clone_end;
|
||||
v->visitor.start_alternate = qapi_clone_start_alternate;
|
||||
v->visitor.end_alternate = qapi_clone_end;
|
||||
v->visitor.type_int64 = qapi_clone_type_int64;
|
||||
v->visitor.type_uint64 = qapi_clone_type_uint64;
|
||||
v->visitor.type_bool = qapi_clone_type_bool;
|
||||
v->visitor.type_str = qapi_clone_type_str;
|
||||
v->visitor.type_number = qapi_clone_type_number;
|
||||
v->visitor.type_null = qapi_clone_type_null;
|
||||
v->visitor.free = qapi_clone_free;
|
||||
|
||||
return &v->visitor;
|
||||
}
|
||||
|
||||
void *qapi_clone(const void *src, void (*visit_type)(Visitor *, const char *,
|
||||
void **, Error **))
|
||||
{
|
||||
Visitor *v;
|
||||
void *dst = (void *) src; /* Cast away const */
|
||||
|
||||
if (!src) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
v = qapi_clone_visitor_new();
|
||||
visit_type(v, NULL, &dst, &error_abort);
|
||||
visit_free(v);
|
||||
return dst;
|
||||
}
|
|
@ -19,53 +19,18 @@
|
|||
#include "qapi/qmp/types.h"
|
||||
#include "qapi/visitor-impl.h"
|
||||
|
||||
typedef struct StackEntry
|
||||
{
|
||||
void *value;
|
||||
QTAILQ_ENTRY(StackEntry) node;
|
||||
} StackEntry;
|
||||
|
||||
struct QapiDeallocVisitor
|
||||
{
|
||||
Visitor visitor;
|
||||
QTAILQ_HEAD(, StackEntry) stack;
|
||||
};
|
||||
|
||||
static QapiDeallocVisitor *to_qov(Visitor *v)
|
||||
{
|
||||
return container_of(v, QapiDeallocVisitor, visitor);
|
||||
}
|
||||
|
||||
static void qapi_dealloc_push(QapiDeallocVisitor *qov, void *value)
|
||||
{
|
||||
StackEntry *e = g_malloc0(sizeof(*e));
|
||||
|
||||
e->value = value;
|
||||
|
||||
QTAILQ_INSERT_HEAD(&qov->stack, e, node);
|
||||
}
|
||||
|
||||
static void *qapi_dealloc_pop(QapiDeallocVisitor *qov)
|
||||
{
|
||||
StackEntry *e = QTAILQ_FIRST(&qov->stack);
|
||||
QObject *value;
|
||||
QTAILQ_REMOVE(&qov->stack, e, node);
|
||||
value = e->value;
|
||||
g_free(e);
|
||||
return value;
|
||||
}
|
||||
|
||||
static void qapi_dealloc_start_struct(Visitor *v, const char *name, void **obj,
|
||||
size_t unused, Error **errp)
|
||||
{
|
||||
QapiDeallocVisitor *qov = to_qov(v);
|
||||
qapi_dealloc_push(qov, obj);
|
||||
}
|
||||
|
||||
static void qapi_dealloc_end_struct(Visitor *v)
|
||||
static void qapi_dealloc_end_struct(Visitor *v, void **obj)
|
||||
{
|
||||
QapiDeallocVisitor *qov = to_qov(v);
|
||||
void **obj = qapi_dealloc_pop(qov);
|
||||
if (obj) {
|
||||
g_free(*obj);
|
||||
}
|
||||
|
@ -75,14 +40,10 @@ static void qapi_dealloc_start_alternate(Visitor *v, const char *name,
|
|||
GenericAlternate **obj, size_t size,
|
||||
bool promote_int, Error **errp)
|
||||
{
|
||||
QapiDeallocVisitor *qov = to_qov(v);
|
||||
qapi_dealloc_push(qov, obj);
|
||||
}
|
||||
|
||||
static void qapi_dealloc_end_alternate(Visitor *v)
|
||||
static void qapi_dealloc_end_alternate(Visitor *v, void **obj)
|
||||
{
|
||||
QapiDeallocVisitor *qov = to_qov(v);
|
||||
void **obj = qapi_dealloc_pop(qov);
|
||||
if (obj) {
|
||||
g_free(*obj);
|
||||
}
|
||||
|
@ -102,7 +63,7 @@ static GenericList *qapi_dealloc_next_list(Visitor *v, GenericList *tail,
|
|||
return next;
|
||||
}
|
||||
|
||||
static void qapi_dealloc_end_list(Visitor *v)
|
||||
static void qapi_dealloc_end_list(Visitor *v, void **obj)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -146,17 +107,12 @@ static void qapi_dealloc_type_null(Visitor *v, const char *name, Error **errp)
|
|||
{
|
||||
}
|
||||
|
||||
Visitor *qapi_dealloc_get_visitor(QapiDeallocVisitor *v)
|
||||
static void qapi_dealloc_free(Visitor *v)
|
||||
{
|
||||
return &v->visitor;
|
||||
g_free(container_of(v, QapiDeallocVisitor, visitor));
|
||||
}
|
||||
|
||||
void qapi_dealloc_visitor_cleanup(QapiDeallocVisitor *v)
|
||||
{
|
||||
g_free(v);
|
||||
}
|
||||
|
||||
QapiDeallocVisitor *qapi_dealloc_visitor_new(void)
|
||||
Visitor *qapi_dealloc_visitor_new(void)
|
||||
{
|
||||
QapiDeallocVisitor *v;
|
||||
|
||||
|
@ -177,8 +133,7 @@ QapiDeallocVisitor *qapi_dealloc_visitor_new(void)
|
|||
v->visitor.type_number = qapi_dealloc_type_number;
|
||||
v->visitor.type_any = qapi_dealloc_type_anything;
|
||||
v->visitor.type_null = qapi_dealloc_type_null;
|
||||
v->visitor.free = qapi_dealloc_free;
|
||||
|
||||
QTAILQ_INIT(&v->stack);
|
||||
|
||||
return v;
|
||||
return &v->visitor;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,21 @@
|
|||
#include "qapi/visitor.h"
|
||||
#include "qapi/visitor-impl.h"
|
||||
|
||||
void visit_complete(Visitor *v, void *opaque)
|
||||
{
|
||||
assert(v->type != VISITOR_OUTPUT || v->complete);
|
||||
if (v->complete) {
|
||||
v->complete(v, opaque);
|
||||
}
|
||||
}
|
||||
|
||||
void visit_free(Visitor *v)
|
||||
{
|
||||
if (v) {
|
||||
v->free(v);
|
||||
}
|
||||
}
|
||||
|
||||
void visit_start_struct(Visitor *v, const char *name, void **obj,
|
||||
size_t size, Error **errp)
|
||||
{
|
||||
|
@ -27,10 +42,10 @@ void visit_start_struct(Visitor *v, const char *name, void **obj,
|
|||
|
||||
if (obj) {
|
||||
assert(size);
|
||||
assert(v->type != VISITOR_OUTPUT || *obj);
|
||||
assert(!(v->type & VISITOR_OUTPUT) || *obj);
|
||||
}
|
||||
v->start_struct(v, name, obj, size, &err);
|
||||
if (obj && v->type == VISITOR_INPUT) {
|
||||
if (obj && (v->type & VISITOR_INPUT)) {
|
||||
assert(!err != !*obj);
|
||||
}
|
||||
error_propagate(errp, err);
|
||||
|
@ -43,9 +58,9 @@ void visit_check_struct(Visitor *v, Error **errp)
|
|||
}
|
||||
}
|
||||
|
||||
void visit_end_struct(Visitor *v)
|
||||
void visit_end_struct(Visitor *v, void **obj)
|
||||
{
|
||||
v->end_struct(v);
|
||||
v->end_struct(v, obj);
|
||||
}
|
||||
|
||||
void visit_start_list(Visitor *v, const char *name, GenericList **list,
|
||||
|
@ -55,7 +70,7 @@ void visit_start_list(Visitor *v, const char *name, GenericList **list,
|
|||
|
||||
assert(!list || size >= sizeof(GenericList));
|
||||
v->start_list(v, name, list, size, &err);
|
||||
if (list && v->type == VISITOR_INPUT) {
|
||||
if (list && (v->type & VISITOR_INPUT)) {
|
||||
assert(!(err && *list));
|
||||
}
|
||||
error_propagate(errp, err);
|
||||
|
@ -67,9 +82,9 @@ GenericList *visit_next_list(Visitor *v, GenericList *tail, size_t size)
|
|||
return v->next_list(v, tail, size);
|
||||
}
|
||||
|
||||
void visit_end_list(Visitor *v)
|
||||
void visit_end_list(Visitor *v, void **obj)
|
||||
{
|
||||
v->end_list(v);
|
||||
v->end_list(v, obj);
|
||||
}
|
||||
|
||||
void visit_start_alternate(Visitor *v, const char *name,
|
||||
|
@ -79,20 +94,20 @@ void visit_start_alternate(Visitor *v, const char *name,
|
|||
Error *err = NULL;
|
||||
|
||||
assert(obj && size >= sizeof(GenericAlternate));
|
||||
assert(v->type != VISITOR_OUTPUT || *obj);
|
||||
assert(!(v->type & VISITOR_OUTPUT) || *obj);
|
||||
if (v->start_alternate) {
|
||||
v->start_alternate(v, name, obj, size, promote_int, &err);
|
||||
}
|
||||
if (v->type == VISITOR_INPUT) {
|
||||
if (v->type & VISITOR_INPUT) {
|
||||
assert(v->start_alternate && !err != !*obj);
|
||||
}
|
||||
error_propagate(errp, err);
|
||||
}
|
||||
|
||||
void visit_end_alternate(Visitor *v)
|
||||
void visit_end_alternate(Visitor *v, void **obj)
|
||||
{
|
||||
if (v->end_alternate) {
|
||||
v->end_alternate(v);
|
||||
v->end_alternate(v, obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -235,10 +250,10 @@ void visit_type_str(Visitor *v, const char *name, char **obj, Error **errp)
|
|||
assert(obj);
|
||||
/* TODO: Fix callers to not pass NULL when they mean "", so that we
|
||||
* can enable:
|
||||
assert(v->type != VISITOR_OUTPUT || *obj);
|
||||
assert(!(v->type & VISITOR_OUTPUT) || *obj);
|
||||
*/
|
||||
v->type_str(v, name, obj, &err);
|
||||
if (v->type == VISITOR_INPUT) {
|
||||
if (v->type & VISITOR_INPUT) {
|
||||
assert(!err != !*obj);
|
||||
}
|
||||
error_propagate(errp, err);
|
||||
|
@ -320,9 +335,19 @@ void visit_type_enum(Visitor *v, const char *name, int *obj,
|
|||
const char *const strings[], Error **errp)
|
||||
{
|
||||
assert(obj && strings);
|
||||
if (v->type == VISITOR_INPUT) {
|
||||
switch (v->type) {
|
||||
case VISITOR_INPUT:
|
||||
input_type_enum(v, name, obj, strings, errp);
|
||||
} else if (v->type == VISITOR_OUTPUT) {
|
||||
break;
|
||||
case VISITOR_OUTPUT:
|
||||
output_type_enum(v, name, obj, strings, errp);
|
||||
break;
|
||||
case VISITOR_CLONE:
|
||||
/* nothing further to do, scalar value was already copied by
|
||||
* g_memdup() during visit_start_*() */
|
||||
break;
|
||||
case VISITOR_DEALLOC:
|
||||
/* nothing to deallocate for a scalar */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "qapi/qmp/types.h"
|
||||
#include "qapi/qmp/dispatch.h"
|
||||
#include "qapi/qmp/json-parser.h"
|
||||
#include "qapi/qmp/qjson.h"
|
||||
#include "qapi-types.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
typedef struct StackObject
|
||||
{
|
||||
QObject *obj; /* Object being visited */
|
||||
void *qapi; /* sanity check that caller uses same pointer */
|
||||
|
||||
GHashTable *h; /* If obj is dict: unvisited keys */
|
||||
const QListEntry *entry; /* If obj is list: unvisited tail */
|
||||
|
@ -96,7 +97,7 @@ static void qdict_add_key(const char *key, QObject *obj, void *opaque)
|
|||
}
|
||||
|
||||
static const QListEntry *qmp_input_push(QmpInputVisitor *qiv, QObject *obj,
|
||||
Error **errp)
|
||||
void *qapi, Error **errp)
|
||||
{
|
||||
GHashTable *h;
|
||||
StackObject *tos = &qiv->stack[qiv->nb_stack];
|
||||
|
@ -108,6 +109,7 @@ static const QListEntry *qmp_input_push(QmpInputVisitor *qiv, QObject *obj,
|
|||
}
|
||||
|
||||
tos->obj = obj;
|
||||
tos->qapi = qapi;
|
||||
assert(!tos->h);
|
||||
assert(!tos->entry);
|
||||
|
||||
|
@ -145,12 +147,13 @@ static void qmp_input_check_struct(Visitor *v, Error **errp)
|
|||
}
|
||||
}
|
||||
|
||||
static void qmp_input_pop(Visitor *v)
|
||||
static void qmp_input_pop(Visitor *v, void **obj)
|
||||
{
|
||||
QmpInputVisitor *qiv = to_qiv(v);
|
||||
StackObject *tos = &qiv->stack[qiv->nb_stack - 1];
|
||||
|
||||
assert(qiv->nb_stack > 0);
|
||||
assert(tos->qapi == obj);
|
||||
|
||||
if (qiv->strict) {
|
||||
GHashTable * const top_ht = qiv->stack[qiv->nb_stack - 1].h;
|
||||
|
@ -179,7 +182,7 @@ static void qmp_input_start_struct(Visitor *v, const char *name, void **obj,
|
|||
return;
|
||||
}
|
||||
|
||||
qmp_input_push(qiv, qobj, &err);
|
||||
qmp_input_push(qiv, qobj, obj, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
|
@ -207,7 +210,7 @@ static void qmp_input_start_list(Visitor *v, const char *name,
|
|||
return;
|
||||
}
|
||||
|
||||
entry = qmp_input_push(qiv, qobj, errp);
|
||||
entry = qmp_input_push(qiv, qobj, list, errp);
|
||||
if (list) {
|
||||
if (entry) {
|
||||
*list = g_malloc0(size);
|
||||
|
@ -370,18 +373,15 @@ static void qmp_input_optional(Visitor *v, const char *name, bool *present)
|
|||
*present = true;
|
||||
}
|
||||
|
||||
Visitor *qmp_input_get_visitor(QmpInputVisitor *v)
|
||||
static void qmp_input_free(Visitor *v)
|
||||
{
|
||||
return &v->visitor;
|
||||
QmpInputVisitor *qiv = to_qiv(v);
|
||||
|
||||
qobject_decref(qiv->root);
|
||||
g_free(qiv);
|
||||
}
|
||||
|
||||
void qmp_input_visitor_cleanup(QmpInputVisitor *v)
|
||||
{
|
||||
qobject_decref(v->root);
|
||||
g_free(v);
|
||||
}
|
||||
|
||||
QmpInputVisitor *qmp_input_visitor_new(QObject *obj, bool strict)
|
||||
Visitor *qmp_input_visitor_new(QObject *obj, bool strict)
|
||||
{
|
||||
QmpInputVisitor *v;
|
||||
|
||||
|
@ -403,10 +403,11 @@ QmpInputVisitor *qmp_input_visitor_new(QObject *obj, bool strict)
|
|||
v->visitor.type_any = qmp_input_type_any;
|
||||
v->visitor.type_null = qmp_input_type_null;
|
||||
v->visitor.optional = qmp_input_optional;
|
||||
v->visitor.free = qmp_input_free;
|
||||
v->strict = strict;
|
||||
|
||||
v->root = obj;
|
||||
qobject_incref(obj);
|
||||
|
||||
return v;
|
||||
return &v->visitor;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
typedef struct QStackEntry
|
||||
{
|
||||
QObject *value;
|
||||
void *qapi; /* sanity check that caller uses same pointer */
|
||||
QTAILQ_ENTRY(QStackEntry) node;
|
||||
} QStackEntry;
|
||||
|
||||
|
@ -32,11 +33,13 @@ struct QmpOutputVisitor
|
|||
Visitor visitor;
|
||||
QStack stack; /* Stack of containers that haven't yet been finished */
|
||||
QObject *root; /* Root of the output visit */
|
||||
QObject **result; /* User's storage location for result */
|
||||
};
|
||||
|
||||
#define qmp_output_add(qov, name, value) \
|
||||
qmp_output_add_obj(qov, name, QOBJECT(value))
|
||||
#define qmp_output_push(qov, value) qmp_output_push_obj(qov, QOBJECT(value))
|
||||
#define qmp_output_push(qov, value, qapi) \
|
||||
qmp_output_push_obj(qov, QOBJECT(value), qapi)
|
||||
|
||||
static QmpOutputVisitor *to_qov(Visitor *v)
|
||||
{
|
||||
|
@ -44,23 +47,26 @@ static QmpOutputVisitor *to_qov(Visitor *v)
|
|||
}
|
||||
|
||||
/* Push @value onto the stack of current QObjects being built */
|
||||
static void qmp_output_push_obj(QmpOutputVisitor *qov, QObject *value)
|
||||
static void qmp_output_push_obj(QmpOutputVisitor *qov, QObject *value,
|
||||
void *qapi)
|
||||
{
|
||||
QStackEntry *e = g_malloc0(sizeof(*e));
|
||||
|
||||
assert(qov->root);
|
||||
assert(value);
|
||||
e->value = value;
|
||||
e->qapi = qapi;
|
||||
QTAILQ_INSERT_HEAD(&qov->stack, e, node);
|
||||
}
|
||||
|
||||
/* Pop a value off the stack of QObjects being built, and return it. */
|
||||
static QObject *qmp_output_pop(QmpOutputVisitor *qov)
|
||||
static QObject *qmp_output_pop(QmpOutputVisitor *qov, void *qapi)
|
||||
{
|
||||
QStackEntry *e = QTAILQ_FIRST(&qov->stack);
|
||||
QObject *value;
|
||||
|
||||
assert(e);
|
||||
assert(e->qapi == qapi);
|
||||
QTAILQ_REMOVE(&qov->stack, e, node);
|
||||
value = e->value;
|
||||
assert(value);
|
||||
|
@ -104,13 +110,13 @@ static void qmp_output_start_struct(Visitor *v, const char *name, void **obj,
|
|||
QDict *dict = qdict_new();
|
||||
|
||||
qmp_output_add(qov, name, dict);
|
||||
qmp_output_push(qov, dict);
|
||||
qmp_output_push(qov, dict, obj);
|
||||
}
|
||||
|
||||
static void qmp_output_end_struct(Visitor *v)
|
||||
static void qmp_output_end_struct(Visitor *v, void **obj)
|
||||
{
|
||||
QmpOutputVisitor *qov = to_qov(v);
|
||||
QObject *value = qmp_output_pop(qov);
|
||||
QObject *value = qmp_output_pop(qov, obj);
|
||||
assert(qobject_type(value) == QTYPE_QDICT);
|
||||
}
|
||||
|
||||
|
@ -122,7 +128,7 @@ static void qmp_output_start_list(Visitor *v, const char *name,
|
|||
QList *list = qlist_new();
|
||||
|
||||
qmp_output_add(qov, name, list);
|
||||
qmp_output_push(qov, list);
|
||||
qmp_output_push(qov, list, listp);
|
||||
}
|
||||
|
||||
static GenericList *qmp_output_next_list(Visitor *v, GenericList *tail,
|
||||
|
@ -131,10 +137,10 @@ static GenericList *qmp_output_next_list(Visitor *v, GenericList *tail,
|
|||
return tail->next;
|
||||
}
|
||||
|
||||
static void qmp_output_end_list(Visitor *v)
|
||||
static void qmp_output_end_list(Visitor *v, void **obj)
|
||||
{
|
||||
QmpOutputVisitor *qov = to_qov(v);
|
||||
QObject *value = qmp_output_pop(qov);
|
||||
QObject *value = qmp_output_pop(qov, obj);
|
||||
assert(qobject_type(value) == QTYPE_QLIST);
|
||||
}
|
||||
|
||||
|
@ -195,34 +201,34 @@ static void qmp_output_type_null(Visitor *v, const char *name, Error **errp)
|
|||
/* Finish building, and return the root object.
|
||||
* The root object is never null. The caller becomes the object's
|
||||
* owner, and should use qobject_decref() when done with it. */
|
||||
QObject *qmp_output_get_qobject(QmpOutputVisitor *qov)
|
||||
static void qmp_output_complete(Visitor *v, void *opaque)
|
||||
{
|
||||
QmpOutputVisitor *qov = to_qov(v);
|
||||
|
||||
/* A visit must have occurred, with each start paired with end. */
|
||||
assert(qov->root && QTAILQ_EMPTY(&qov->stack));
|
||||
assert(opaque == qov->result);
|
||||
|
||||
qobject_incref(qov->root);
|
||||
return qov->root;
|
||||
*qov->result = qov->root;
|
||||
qov->result = NULL;
|
||||
}
|
||||
|
||||
Visitor *qmp_output_get_visitor(QmpOutputVisitor *v)
|
||||
{
|
||||
return &v->visitor;
|
||||
}
|
||||
|
||||
void qmp_output_visitor_cleanup(QmpOutputVisitor *v)
|
||||
static void qmp_output_free(Visitor *v)
|
||||
{
|
||||
QmpOutputVisitor *qov = to_qov(v);
|
||||
QStackEntry *e, *tmp;
|
||||
|
||||
QTAILQ_FOREACH_SAFE(e, &v->stack, node, tmp) {
|
||||
QTAILQ_REMOVE(&v->stack, e, node);
|
||||
QTAILQ_FOREACH_SAFE(e, &qov->stack, node, tmp) {
|
||||
QTAILQ_REMOVE(&qov->stack, e, node);
|
||||
g_free(e);
|
||||
}
|
||||
|
||||
qobject_decref(v->root);
|
||||
g_free(v);
|
||||
qobject_decref(qov->root);
|
||||
g_free(qov);
|
||||
}
|
||||
|
||||
QmpOutputVisitor *qmp_output_visitor_new(void)
|
||||
Visitor *qmp_output_visitor_new(QObject **result)
|
||||
{
|
||||
QmpOutputVisitor *v;
|
||||
|
||||
|
@ -241,8 +247,12 @@ QmpOutputVisitor *qmp_output_visitor_new(void)
|
|||
v->visitor.type_number = qmp_output_type_number;
|
||||
v->visitor.type_any = qmp_output_type_any;
|
||||
v->visitor.type_null = qmp_output_type_null;
|
||||
v->visitor.complete = qmp_output_complete;
|
||||
v->visitor.free = qmp_output_free;
|
||||
|
||||
QTAILQ_INIT(&v->stack);
|
||||
*result = NULL;
|
||||
v->result = result;
|
||||
|
||||
return v;
|
||||
return &v->visitor;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ struct StringInputVisitor
|
|||
int64_t cur;
|
||||
|
||||
const char *string;
|
||||
void *list; /* Only needed for sanity checking the caller */
|
||||
};
|
||||
|
||||
static StringInputVisitor *to_siv(Visitor *v)
|
||||
|
@ -120,6 +121,7 @@ start_list(Visitor *v, const char *name, GenericList **list, size_t size,
|
|||
|
||||
/* We don't support visits without a list */
|
||||
assert(list);
|
||||
siv->list = list;
|
||||
|
||||
if (parse_str(siv, name, errp) < 0) {
|
||||
*list = NULL;
|
||||
|
@ -168,8 +170,11 @@ static GenericList *next_list(Visitor *v, GenericList *tail, size_t size)
|
|||
return tail->next;
|
||||
}
|
||||
|
||||
static void end_list(Visitor *v)
|
||||
static void end_list(Visitor *v, void **obj)
|
||||
{
|
||||
StringInputVisitor *siv = to_siv(v);
|
||||
|
||||
assert(siv->list == obj);
|
||||
}
|
||||
|
||||
static void parse_type_int64(Visitor *v, const char *name, int64_t *obj,
|
||||
|
@ -321,19 +326,16 @@ static void parse_optional(Visitor *v, const char *name, bool *present)
|
|||
*present = true;
|
||||
}
|
||||
|
||||
Visitor *string_input_get_visitor(StringInputVisitor *v)
|
||||
static void string_input_free(Visitor *v)
|
||||
{
|
||||
return &v->visitor;
|
||||
StringInputVisitor *siv = to_siv(v);
|
||||
|
||||
g_list_foreach(siv->ranges, free_range, NULL);
|
||||
g_list_free(siv->ranges);
|
||||
g_free(siv);
|
||||
}
|
||||
|
||||
void string_input_visitor_cleanup(StringInputVisitor *v)
|
||||
{
|
||||
g_list_foreach(v->ranges, free_range, NULL);
|
||||
g_list_free(v->ranges);
|
||||
g_free(v);
|
||||
}
|
||||
|
||||
StringInputVisitor *string_input_visitor_new(const char *str)
|
||||
Visitor *string_input_visitor_new(const char *str)
|
||||
{
|
||||
StringInputVisitor *v;
|
||||
|
||||
|
@ -350,7 +352,8 @@ StringInputVisitor *string_input_visitor_new(const char *str)
|
|||
v->visitor.next_list = next_list;
|
||||
v->visitor.end_list = end_list;
|
||||
v->visitor.optional = parse_optional;
|
||||
v->visitor.free = string_input_free;
|
||||
|
||||
v->string = str;
|
||||
return v;
|
||||
return &v->visitor;
|
||||
}
|
||||
|
|
|
@ -58,12 +58,14 @@ struct StringOutputVisitor
|
|||
Visitor visitor;
|
||||
bool human;
|
||||
GString *string;
|
||||
char **result;
|
||||
ListMode list_mode;
|
||||
union {
|
||||
int64_t s;
|
||||
uint64_t u;
|
||||
} range_start, range_end;
|
||||
GList *ranges;
|
||||
void *list; /* Only needed for sanity checking the caller */
|
||||
};
|
||||
|
||||
static StringOutputVisitor *to_sov(Visitor *v)
|
||||
|
@ -274,6 +276,7 @@ start_list(Visitor *v, const char *name, GenericList **list, size_t size,
|
|||
assert(sov->list_mode == LM_NONE);
|
||||
/* We don't support visits without a list */
|
||||
assert(list);
|
||||
sov->list = list;
|
||||
/* List handling is only needed if there are at least two elements */
|
||||
if (*list && (*list)->next) {
|
||||
sov->list_mode = LM_STARTED;
|
||||
|
@ -291,10 +294,11 @@ static GenericList *next_list(Visitor *v, GenericList *tail, size_t size)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void end_list(Visitor *v)
|
||||
static void end_list(Visitor *v, void **obj)
|
||||
{
|
||||
StringOutputVisitor *sov = to_sov(v);
|
||||
|
||||
assert(sov->list == obj);
|
||||
assert(sov->list_mode == LM_STARTED ||
|
||||
sov->list_mode == LM_END ||
|
||||
sov->list_mode == LM_NONE ||
|
||||
|
@ -302,16 +306,13 @@ static void end_list(Visitor *v)
|
|||
sov->list_mode = LM_NONE;
|
||||
}
|
||||
|
||||
char *string_output_get_string(StringOutputVisitor *sov)
|
||||
static void string_output_complete(Visitor *v, void *opaque)
|
||||
{
|
||||
char *string = g_string_free(sov->string, false);
|
||||
sov->string = NULL;
|
||||
return string;
|
||||
}
|
||||
StringOutputVisitor *sov = to_sov(v);
|
||||
|
||||
Visitor *string_output_get_visitor(StringOutputVisitor *sov)
|
||||
{
|
||||
return &sov->visitor;
|
||||
assert(opaque == sov->result);
|
||||
*sov->result = g_string_free(sov->string, false);
|
||||
sov->string = NULL;
|
||||
}
|
||||
|
||||
static void free_range(void *range, void *dummy)
|
||||
|
@ -319,8 +320,10 @@ static void free_range(void *range, void *dummy)
|
|||
g_free(range);
|
||||
}
|
||||
|
||||
void string_output_visitor_cleanup(StringOutputVisitor *sov)
|
||||
static void string_output_free(Visitor *v)
|
||||
{
|
||||
StringOutputVisitor *sov = to_sov(v);
|
||||
|
||||
if (sov->string) {
|
||||
g_string_free(sov->string, true);
|
||||
}
|
||||
|
@ -330,7 +333,7 @@ void string_output_visitor_cleanup(StringOutputVisitor *sov)
|
|||
g_free(sov);
|
||||
}
|
||||
|
||||
StringOutputVisitor *string_output_visitor_new(bool human)
|
||||
Visitor *string_output_visitor_new(bool human, char **result)
|
||||
{
|
||||
StringOutputVisitor *v;
|
||||
|
||||
|
@ -338,6 +341,9 @@ StringOutputVisitor *string_output_visitor_new(bool human)
|
|||
|
||||
v->string = g_string_new(NULL);
|
||||
v->human = human;
|
||||
v->result = result;
|
||||
*result = NULL;
|
||||
|
||||
v->visitor.type = VISITOR_OUTPUT;
|
||||
v->visitor.type_int64 = print_type_int64;
|
||||
v->visitor.type_uint64 = print_type_uint64;
|
||||
|
@ -348,6 +354,8 @@ StringOutputVisitor *string_output_visitor_new(bool human)
|
|||
v->visitor.start_list = start_list;
|
||||
v->visitor.next_list = next_list;
|
||||
v->visitor.end_list = end_list;
|
||||
v->visitor.complete = string_output_complete;
|
||||
v->visitor.free = string_output_free;
|
||||
|
||||
return v;
|
||||
return &v->visitor;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue