mirror of https://github.com/xqemu/xqemu.git
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
|
@ -193,17 +193,16 @@ block_crypto_open_opts_init(QCryptoBlockFormat format,
|
|||
QemuOpts *opts,
|
||||
Error **errp)
|
||||
{
|
||||
OptsVisitor *ov;
|
||||
Visitor *v;
|
||||
QCryptoBlockOpenOptions *ret = NULL;
|
||||
Error *local_err = NULL;
|
||||
|
||||
ret = g_new0(QCryptoBlockOpenOptions, 1);
|
||||
ret->format = format;
|
||||
|
||||
ov = opts_visitor_new(opts);
|
||||
v = opts_visitor_new(opts);
|
||||
|
||||
visit_start_struct(opts_get_visitor(ov),
|
||||
NULL, NULL, 0, &local_err);
|
||||
visit_start_struct(v, NULL, NULL, 0, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
|
@ -211,7 +210,7 @@ block_crypto_open_opts_init(QCryptoBlockFormat format,
|
|||
switch (format) {
|
||||
case Q_CRYPTO_BLOCK_FORMAT_LUKS:
|
||||
visit_type_QCryptoBlockOptionsLUKS_members(
|
||||
opts_get_visitor(ov), &ret->u.luks, &local_err);
|
||||
v, &ret->u.luks, &local_err);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -219,10 +218,10 @@ block_crypto_open_opts_init(QCryptoBlockFormat format,
|
|||
break;
|
||||
}
|
||||
if (!local_err) {
|
||||
visit_check_struct(opts_get_visitor(ov), &local_err);
|
||||
visit_check_struct(v, &local_err);
|
||||
}
|
||||
|
||||
visit_end_struct(opts_get_visitor(ov));
|
||||
visit_end_struct(v, NULL);
|
||||
|
||||
out:
|
||||
if (local_err) {
|
||||
|
@ -230,7 +229,7 @@ block_crypto_open_opts_init(QCryptoBlockFormat format,
|
|||
qapi_free_QCryptoBlockOpenOptions(ret);
|
||||
ret = NULL;
|
||||
}
|
||||
opts_visitor_cleanup(ov);
|
||||
visit_free(v);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -240,17 +239,16 @@ block_crypto_create_opts_init(QCryptoBlockFormat format,
|
|||
QemuOpts *opts,
|
||||
Error **errp)
|
||||
{
|
||||
OptsVisitor *ov;
|
||||
Visitor *v;
|
||||
QCryptoBlockCreateOptions *ret = NULL;
|
||||
Error *local_err = NULL;
|
||||
|
||||
ret = g_new0(QCryptoBlockCreateOptions, 1);
|
||||
ret->format = format;
|
||||
|
||||
ov = opts_visitor_new(opts);
|
||||
v = opts_visitor_new(opts);
|
||||
|
||||
visit_start_struct(opts_get_visitor(ov),
|
||||
NULL, NULL, 0, &local_err);
|
||||
visit_start_struct(v, NULL, NULL, 0, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
|
@ -258,7 +256,7 @@ block_crypto_create_opts_init(QCryptoBlockFormat format,
|
|||
switch (format) {
|
||||
case Q_CRYPTO_BLOCK_FORMAT_LUKS:
|
||||
visit_type_QCryptoBlockCreateOptionsLUKS_members(
|
||||
opts_get_visitor(ov), &ret->u.luks, &local_err);
|
||||
v, &ret->u.luks, &local_err);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -266,10 +264,10 @@ block_crypto_create_opts_init(QCryptoBlockFormat format,
|
|||
break;
|
||||
}
|
||||
if (!local_err) {
|
||||
visit_check_struct(opts_get_visitor(ov), &local_err);
|
||||
visit_check_struct(v, &local_err);
|
||||
}
|
||||
|
||||
visit_end_struct(opts_get_visitor(ov));
|
||||
visit_end_struct(v, NULL);
|
||||
|
||||
out:
|
||||
if (local_err) {
|
||||
|
@ -277,7 +275,7 @@ block_crypto_create_opts_init(QCryptoBlockFormat format,
|
|||
qapi_free_QCryptoBlockCreateOptions(ret);
|
||||
ret = NULL;
|
||||
}
|
||||
opts_visitor_cleanup(ov);
|
||||
visit_free(v);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -690,16 +690,15 @@ static void dump_qdict(fprintf_function func_fprintf, void *f, int indentation,
|
|||
void bdrv_image_info_specific_dump(fprintf_function func_fprintf, void *f,
|
||||
ImageInfoSpecific *info_spec)
|
||||
{
|
||||
QmpOutputVisitor *ov = qmp_output_visitor_new();
|
||||
QObject *obj, *data;
|
||||
Visitor *v = qmp_output_visitor_new(&obj);
|
||||
|
||||
visit_type_ImageInfoSpecific(qmp_output_get_visitor(ov), NULL, &info_spec,
|
||||
&error_abort);
|
||||
obj = qmp_output_get_qobject(ov);
|
||||
visit_type_ImageInfoSpecific(v, NULL, &info_spec, &error_abort);
|
||||
visit_complete(v, &obj);
|
||||
assert(qobject_type(obj) == QTYPE_QDICT);
|
||||
data = qdict_get(qobject_to_qdict(obj), "data");
|
||||
dump_qobject(func_fprintf, f, 1, data);
|
||||
qmp_output_visitor_cleanup(ov);
|
||||
visit_free(v);
|
||||
}
|
||||
|
||||
void bdrv_image_info_dump(fprintf_function func_fprintf, void *f,
|
||||
|
|
|
@ -3950,10 +3950,10 @@ out:
|
|||
|
||||
void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
|
||||
{
|
||||
QmpOutputVisitor *ov = qmp_output_visitor_new();
|
||||
BlockDriverState *bs;
|
||||
BlockBackend *blk = NULL;
|
||||
QObject *obj;
|
||||
Visitor *v = qmp_output_visitor_new(&obj);
|
||||
QDict *qdict;
|
||||
Error *local_err = NULL;
|
||||
|
||||
|
@ -3972,14 +3972,13 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
|
|||
}
|
||||
}
|
||||
|
||||
visit_type_BlockdevOptions(qmp_output_get_visitor(ov), NULL, &options,
|
||||
&local_err);
|
||||
visit_type_BlockdevOptions(v, NULL, &options, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
obj = qmp_output_get_qobject(ov);
|
||||
visit_complete(v, &obj);
|
||||
qdict = qobject_to_qdict(obj);
|
||||
|
||||
qdict_flatten(qdict);
|
||||
|
@ -4020,7 +4019,7 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
|
|||
}
|
||||
|
||||
fail:
|
||||
qmp_output_visitor_cleanup(ov);
|
||||
visit_free(v);
|
||||
}
|
||||
|
||||
void qmp_x_blockdev_del(bool has_id, const char *id,
|
||||
|
|
|
@ -802,32 +802,28 @@ Example:
|
|||
|
||||
void qapi_free_UserDefOne(UserDefOne *obj)
|
||||
{
|
||||
QapiDeallocVisitor *qdv;
|
||||
Visitor *v;
|
||||
|
||||
if (!obj) {
|
||||
return;
|
||||
}
|
||||
|
||||
qdv = qapi_dealloc_visitor_new();
|
||||
v = qapi_dealloc_get_visitor(qdv);
|
||||
v = qapi_dealloc_visitor_new();
|
||||
visit_type_UserDefOne(v, NULL, &obj, NULL);
|
||||
qapi_dealloc_visitor_cleanup(qdv);
|
||||
visit_free(v);
|
||||
}
|
||||
|
||||
void qapi_free_UserDefOneList(UserDefOneList *obj)
|
||||
{
|
||||
QapiDeallocVisitor *qdv;
|
||||
Visitor *v;
|
||||
|
||||
if (!obj) {
|
||||
return;
|
||||
}
|
||||
|
||||
qdv = qapi_dealloc_visitor_new();
|
||||
v = qapi_dealloc_get_visitor(qdv);
|
||||
v = qapi_dealloc_visitor_new();
|
||||
visit_type_UserDefOneList(v, NULL, &obj, NULL);
|
||||
qapi_dealloc_visitor_cleanup(qdv);
|
||||
visit_free(v);
|
||||
}
|
||||
|
||||
=== scripts/qapi-visit.py ===
|
||||
|
@ -904,7 +900,7 @@ Example:
|
|||
}
|
||||
visit_check_struct(v, &err);
|
||||
out_obj:
|
||||
visit_end_struct(v);
|
||||
visit_end_struct(v, (void **)obj);
|
||||
if (err && visit_is_input(v)) {
|
||||
qapi_free_UserDefOne(*obj);
|
||||
*obj = NULL;
|
||||
|
@ -932,7 +928,7 @@ Example:
|
|||
}
|
||||
}
|
||||
|
||||
visit_end_list(v);
|
||||
visit_end_list(v, (void **)obj);
|
||||
if (err && visit_is_input(v)) {
|
||||
qapi_free_UserDefOneList(*obj);
|
||||
*obj = NULL;
|
||||
|
@ -984,36 +980,28 @@ Example:
|
|||
static void qmp_marshal_output_UserDefOne(UserDefOne *ret_in, QObject **ret_out, Error **errp)
|
||||
{
|
||||
Error *err = NULL;
|
||||
QmpOutputVisitor *qov = qmp_output_visitor_new();
|
||||
QapiDeallocVisitor *qdv;
|
||||
Visitor *v;
|
||||
|
||||
v = qmp_output_get_visitor(qov);
|
||||
v = qmp_output_visitor_new(ret_out);
|
||||
visit_type_UserDefOne(v, "unused", &ret_in, &err);
|
||||
if (err) {
|
||||
goto out;
|
||||
if (!err) {
|
||||
visit_complete(v, ret_out);
|
||||
}
|
||||
*ret_out = qmp_output_get_qobject(qov);
|
||||
|
||||
out:
|
||||
error_propagate(errp, err);
|
||||
qmp_output_visitor_cleanup(qov);
|
||||
qdv = qapi_dealloc_visitor_new();
|
||||
v = qapi_dealloc_get_visitor(qdv);
|
||||
visit_free(v);
|
||||
v = qapi_dealloc_visitor_new();
|
||||
visit_type_UserDefOne(v, "unused", &ret_in, NULL);
|
||||
qapi_dealloc_visitor_cleanup(qdv);
|
||||
visit_free(v);
|
||||
}
|
||||
|
||||
static void qmp_marshal_my_command(QDict *args, QObject **ret, Error **errp)
|
||||
{
|
||||
Error *err = NULL;
|
||||
UserDefOne *retval;
|
||||
QmpInputVisitor *qiv = qmp_input_visitor_new(QOBJECT(args), true);
|
||||
QapiDeallocVisitor *qdv;
|
||||
Visitor *v;
|
||||
UserDefOneList *arg1 = NULL;
|
||||
|
||||
v = qmp_input_get_visitor(qiv);
|
||||
v = qmp_input_visitor_new(QOBJECT(args), true);
|
||||
visit_start_struct(v, NULL, NULL, 0, &err);
|
||||
if (err) {
|
||||
goto out;
|
||||
|
@ -1022,7 +1010,7 @@ Example:
|
|||
if (!err) {
|
||||
visit_check_struct(v, &err);
|
||||
}
|
||||
visit_end_struct(v);
|
||||
visit_end_struct(v, NULL);
|
||||
if (err) {
|
||||
goto out;
|
||||
}
|
||||
|
@ -1036,13 +1024,12 @@ Example:
|
|||
|
||||
out:
|
||||
error_propagate(errp, err);
|
||||
qmp_input_visitor_cleanup(qiv);
|
||||
qdv = qapi_dealloc_visitor_new();
|
||||
v = qapi_dealloc_get_visitor(qdv);
|
||||
visit_free(v);
|
||||
v = qapi_dealloc_visitor_new();
|
||||
visit_start_struct(v, NULL, NULL, 0, NULL);
|
||||
visit_type_UserDefOneList(v, "arg1", &arg1, NULL);
|
||||
visit_end_struct(v);
|
||||
qapi_dealloc_visitor_cleanup(qdv);
|
||||
visit_end_struct(v, NULL);
|
||||
visit_free(v);
|
||||
}
|
||||
|
||||
static void qmp_init_marshal(void)
|
||||
|
|
19
hmp.c
19
hmp.c
|
@ -1722,7 +1722,7 @@ void hmp_object_add(Monitor *mon, const QDict *qdict)
|
|||
{
|
||||
Error *err = NULL;
|
||||
QemuOpts *opts;
|
||||
OptsVisitor *ov;
|
||||
Visitor *v;
|
||||
Object *obj = NULL;
|
||||
|
||||
opts = qemu_opts_from_qdict(qemu_find_opts("object"), qdict, &err);
|
||||
|
@ -1731,9 +1731,9 @@ void hmp_object_add(Monitor *mon, const QDict *qdict)
|
|||
return;
|
||||
}
|
||||
|
||||
ov = opts_visitor_new(opts);
|
||||
obj = user_creatable_add(qdict, opts_get_visitor(ov), &err);
|
||||
opts_visitor_cleanup(ov);
|
||||
v = opts_visitor_new(opts);
|
||||
obj = user_creatable_add(qdict, v, &err);
|
||||
visit_free(v);
|
||||
qemu_opts_del(opts);
|
||||
|
||||
if (err) {
|
||||
|
@ -1983,15 +1983,14 @@ void hmp_info_memdev(Monitor *mon, const QDict *qdict)
|
|||
Error *err = NULL;
|
||||
MemdevList *memdev_list = qmp_query_memdev(&err);
|
||||
MemdevList *m = memdev_list;
|
||||
StringOutputVisitor *ov;
|
||||
Visitor *v;
|
||||
char *str;
|
||||
int i = 0;
|
||||
|
||||
|
||||
while (m) {
|
||||
ov = string_output_visitor_new(false);
|
||||
visit_type_uint16List(string_output_get_visitor(ov), NULL,
|
||||
&m->value->host_nodes, NULL);
|
||||
v = string_output_visitor_new(false, &str);
|
||||
visit_type_uint16List(v, NULL, &m->value->host_nodes, NULL);
|
||||
monitor_printf(mon, "memory backend: %d\n", i);
|
||||
monitor_printf(mon, " size: %" PRId64 "\n", m->value->size);
|
||||
monitor_printf(mon, " merge: %s\n",
|
||||
|
@ -2002,11 +2001,11 @@ void hmp_info_memdev(Monitor *mon, const QDict *qdict)
|
|||
m->value->prealloc ? "true" : "false");
|
||||
monitor_printf(mon, " policy: %s\n",
|
||||
HostMemPolicy_lookup[m->value->policy]);
|
||||
str = string_output_get_string(ov);
|
||||
visit_complete(v, &str);
|
||||
monitor_printf(mon, " host nodes: %s\n", str);
|
||||
|
||||
g_free(str);
|
||||
string_output_visitor_cleanup(ov);
|
||||
visit_free(v);
|
||||
m = m->next;
|
||||
i++;
|
||||
}
|
||||
|
|
|
@ -239,11 +239,11 @@ void acpi_table_add(const QemuOpts *opts, Error **errp)
|
|||
char unsigned *blob = NULL;
|
||||
|
||||
{
|
||||
OptsVisitor *ov;
|
||||
Visitor *v;
|
||||
|
||||
ov = opts_visitor_new(opts);
|
||||
visit_type_AcpiTableOptions(opts_get_visitor(ov), NULL, &hdrs, &err);
|
||||
opts_visitor_cleanup(ov);
|
||||
v = opts_visitor_new(opts);
|
||||
visit_type_AcpiTableOptions(v, NULL, &hdrs, &err);
|
||||
visit_free(v);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qapi/qmp/types.h"
|
||||
#include "qapi/qmp/qjson.h"
|
||||
#include "monitor/monitor.h"
|
||||
#include "hw/pci/pci_bridge.h"
|
||||
#include "hw/pci/pcie.h"
|
||||
|
|
|
@ -300,7 +300,7 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name,
|
|||
/* shouldn't ever see an FDT_END_NODE before FDT_BEGIN_NODE */
|
||||
g_assert(fdt_depth > 0);
|
||||
visit_check_struct(v, &err);
|
||||
visit_end_struct(v);
|
||||
visit_end_struct(v, NULL);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
|
@ -323,7 +323,7 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name,
|
|||
return;
|
||||
}
|
||||
}
|
||||
visit_end_list(v);
|
||||
visit_end_list(v, NULL);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -139,13 +139,13 @@ static void balloon_stats_get_all(Object *obj, Visitor *v, const char *name,
|
|||
}
|
||||
visit_check_struct(v, &err);
|
||||
out_nested:
|
||||
visit_end_struct(v);
|
||||
visit_end_struct(v, NULL);
|
||||
|
||||
if (!err) {
|
||||
visit_check_struct(v, &err);
|
||||
}
|
||||
out_end:
|
||||
visit_end_struct(v);
|
||||
visit_end_struct(v, NULL);
|
||||
out:
|
||||
error_propagate(errp, err);
|
||||
}
|
||||
|
|
|
@ -159,7 +159,7 @@ typedef int (*QIOTaskWorker)(QIOTask *task,
|
|||
* QIOTask *task;
|
||||
* SocketAddress *addrCopy;
|
||||
*
|
||||
* qapi_copy_SocketAddress(&addrCopy, addr);
|
||||
* addrCopy = QAPI_CLONE(SocketAddress, addr);
|
||||
* task = qio_task_new(OBJECT(obj), func, opaque, notify);
|
||||
*
|
||||
* qio_task_run_in_thread(task, myobject_listen_worker,
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Clone Visitor
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QAPI_CLONE_VISITOR_H
|
||||
#define QAPI_CLONE_VISITOR_H
|
||||
|
||||
#include "qemu/typedefs.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "qapi-visit.h"
|
||||
|
||||
/*
|
||||
* The clone visitor is for direct use only by the QAPI_CLONE() macro;
|
||||
* it requires that the root visit occur on an object, list, or
|
||||
* alternate, and is not usable directly on built-in QAPI types.
|
||||
*/
|
||||
typedef struct QapiCloneVisitor QapiCloneVisitor;
|
||||
|
||||
void *qapi_clone(const void *src, void (*visit_type)(Visitor *, const char *,
|
||||
void **, Error **));
|
||||
|
||||
/*
|
||||
* Deep-clone QAPI object @src of the given @type, and return the result.
|
||||
*
|
||||
* Not usable on QAPI scalars (integers, strings, enums), nor on a
|
||||
* QAPI object that references the 'any' type. Safe when @src is NULL.
|
||||
*/
|
||||
#define QAPI_CLONE(type, src) \
|
||||
((type *)qapi_clone(src, \
|
||||
(void (*)(Visitor *, const char *, void**, \
|
||||
Error **))visit_type_ ## type))
|
||||
|
||||
#endif
|
|
@ -23,9 +23,6 @@ typedef struct QapiDeallocVisitor QapiDeallocVisitor;
|
|||
* qapi_free_FOO() functions, and is the only visitor designed to work
|
||||
* correctly in the face of a partially-constructed QAPI tree.
|
||||
*/
|
||||
QapiDeallocVisitor *qapi_dealloc_visitor_new(void);
|
||||
void qapi_dealloc_visitor_cleanup(QapiDeallocVisitor *d);
|
||||
|
||||
Visitor *qapi_dealloc_get_visitor(QapiDeallocVisitor *v);
|
||||
Visitor *qapi_dealloc_visitor_new(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -35,8 +35,6 @@ typedef struct OptsVisitor OptsVisitor;
|
|||
* QTypes. It also requires a non-null list argument to
|
||||
* visit_start_list().
|
||||
*/
|
||||
OptsVisitor *opts_visitor_new(const QemuOpts *opts);
|
||||
void opts_visitor_cleanup(OptsVisitor *nv);
|
||||
Visitor *opts_get_visitor(OptsVisitor *nv);
|
||||
Visitor *opts_visitor_new(const QemuOpts *opts);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -25,10 +25,6 @@ typedef struct QmpInputVisitor QmpInputVisitor;
|
|||
* Set @strict to reject a parse that doesn't consume all keys of a
|
||||
* dictionary; otherwise excess input is ignored.
|
||||
*/
|
||||
QmpInputVisitor *qmp_input_visitor_new(QObject *obj, bool strict);
|
||||
|
||||
void qmp_input_visitor_cleanup(QmpInputVisitor *v);
|
||||
|
||||
Visitor *qmp_input_get_visitor(QmpInputVisitor *v);
|
||||
Visitor *qmp_input_visitor_new(QObject *obj, bool strict);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -19,10 +19,12 @@
|
|||
|
||||
typedef struct QmpOutputVisitor QmpOutputVisitor;
|
||||
|
||||
QmpOutputVisitor *qmp_output_visitor_new(void);
|
||||
void qmp_output_visitor_cleanup(QmpOutputVisitor *v);
|
||||
|
||||
QObject *qmp_output_get_qobject(QmpOutputVisitor *v);
|
||||
Visitor *qmp_output_get_visitor(QmpOutputVisitor *v);
|
||||
/*
|
||||
* Create a new QMP output visitor.
|
||||
*
|
||||
* If everything else succeeds, pass @result to visit_complete() to
|
||||
* collect the result of the visit.
|
||||
*/
|
||||
Visitor *qmp_output_visitor_new(QObject **result);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -20,6 +20,5 @@
|
|||
#include "qapi/qmp/qstring.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qlist.h"
|
||||
#include "qapi/qmp/qjson.h"
|
||||
|
||||
#endif /* QEMU_OBJECTS_H */
|
||||
|
|
|
@ -22,9 +22,6 @@ typedef struct StringInputVisitor StringInputVisitor;
|
|||
* QAPI structs, alternates, null, or arbitrary QTypes. It also
|
||||
* requires a non-null list argument to visit_start_list().
|
||||
*/
|
||||
StringInputVisitor *string_input_visitor_new(const char *str);
|
||||
void string_input_visitor_cleanup(StringInputVisitor *v);
|
||||
|
||||
Visitor *string_input_get_visitor(StringInputVisitor *v);
|
||||
Visitor *string_input_visitor_new(const char *str);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -18,14 +18,18 @@
|
|||
typedef struct StringOutputVisitor StringOutputVisitor;
|
||||
|
||||
/*
|
||||
* Create a new string output visitor.
|
||||
*
|
||||
* Using @human creates output that is a bit easier for humans to read
|
||||
* (for example, showing integer values in both decimal and hex).
|
||||
*
|
||||
* If everything else succeeds, pass @result to visit_complete() to
|
||||
* collect the result of the visit.
|
||||
*
|
||||
* The string output visitor does not implement support for visiting
|
||||
* QAPI structs, alternates, null, or arbitrary QTypes. It also
|
||||
* requires a non-null list argument to visit_start_list().
|
||||
*/
|
||||
StringOutputVisitor *string_output_visitor_new(bool human);
|
||||
void string_output_visitor_cleanup(StringOutputVisitor *v);
|
||||
|
||||
char *string_output_get_string(StringOutputVisitor *v);
|
||||
Visitor *string_output_get_visitor(StringOutputVisitor *v);
|
||||
Visitor *string_output_visitor_new(bool human, char **result);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -27,14 +27,18 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* There are three classes of visitors; setting the class determines
|
||||
* There are four classes of visitors; setting the class determines
|
||||
* how QAPI enums are visited, as well as what additional restrictions
|
||||
* can be asserted.
|
||||
* can be asserted. The values are intentionally chosen so as to
|
||||
* permit some assertions based on whether a given bit is set (that
|
||||
* is, some assertions apply to input and clone visitors, some
|
||||
* assertions apply to output and clone visitors).
|
||||
*/
|
||||
typedef enum VisitorType {
|
||||
VISITOR_INPUT,
|
||||
VISITOR_OUTPUT,
|
||||
VISITOR_DEALLOC,
|
||||
VISITOR_INPUT = 1,
|
||||
VISITOR_OUTPUT = 2,
|
||||
VISITOR_CLONE = 3,
|
||||
VISITOR_DEALLOC = 4,
|
||||
} VisitorType;
|
||||
|
||||
struct Visitor
|
||||
|
@ -47,7 +51,7 @@ struct Visitor
|
|||
void (*check_struct)(Visitor *v, Error **errp);
|
||||
|
||||
/* Must be set to visit structs */
|
||||
void (*end_struct)(Visitor *v);
|
||||
void (*end_struct)(Visitor *v, void **obj);
|
||||
|
||||
/* Must be set; implementations may require @list to be non-null,
|
||||
* but must document it. */
|
||||
|
@ -58,7 +62,7 @@ struct Visitor
|
|||
GenericList *(*next_list)(Visitor *v, GenericList *tail, size_t size);
|
||||
|
||||
/* Must be set */
|
||||
void (*end_list)(Visitor *v);
|
||||
void (*end_list)(Visitor *v, void **list);
|
||||
|
||||
/* Must be set by input and dealloc visitors to visit alternates;
|
||||
* optional for output visitors. */
|
||||
|
@ -67,7 +71,7 @@ struct Visitor
|
|||
bool promote_int, Error **errp);
|
||||
|
||||
/* Optional, needed for dealloc visitor */
|
||||
void (*end_alternate)(Visitor *v);
|
||||
void (*end_alternate)(Visitor *v, void **obj);
|
||||
|
||||
/* Must be set */
|
||||
void (*type_int64)(Visitor *v, const char *name, int64_t *obj,
|
||||
|
@ -104,6 +108,12 @@ struct Visitor
|
|||
|
||||
/* Must be set */
|
||||
VisitorType type;
|
||||
|
||||
/* Must be set for output visitors, optional otherwise. */
|
||||
void (*complete)(Visitor *v, void *opaque);
|
||||
|
||||
/* Must be set */
|
||||
void (*free)(Visitor *v);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -24,19 +24,32 @@
|
|||
* for doing work at each node of a QAPI graph; it can also be used
|
||||
* for a virtual walk, where there is no actual QAPI C struct.
|
||||
*
|
||||
* There are three kinds of visitor classes: input visitors (QMP,
|
||||
* There are four kinds of visitor classes: input visitors (QMP,
|
||||
* string, and QemuOpts) parse an external representation and build
|
||||
* the corresponding QAPI graph, output visitors (QMP and string) take
|
||||
* a completed QAPI graph and generate an external representation, and
|
||||
* the dealloc visitor can take a QAPI graph (possibly partially
|
||||
* constructed) and recursively free its resources. While the dealloc
|
||||
* and QMP input/output visitors are general, the string and QemuOpts
|
||||
* visitors have some implementation limitations; see the
|
||||
* documentation for each visitor for more details on what it
|
||||
* a completed QAPI graph and generate an external representation, the
|
||||
* dealloc visitor can take a QAPI graph (possibly partially
|
||||
* constructed) and recursively free its resources, and the clone
|
||||
* visitor performs a deep clone of one QAPI object to another. While
|
||||
* the dealloc and QMP input/output visitors are general, the string,
|
||||
* QemuOpts, and clone visitors have some implementation limitations;
|
||||
* see the documentation for each visitor for more details on what it
|
||||
* supports. Also, see visitor-impl.h for the callback contracts
|
||||
* implemented by each visitor, and docs/qapi-code-gen.txt for more
|
||||
* about the QAPI code generator.
|
||||
*
|
||||
* All of the visitors are created via:
|
||||
*
|
||||
* Visitor *subtype_visitor_new(parameters...);
|
||||
*
|
||||
* A visitor should be used for exactly one top-level visit_type_FOO()
|
||||
* or virtual walk; if that is successful, the caller can optionally
|
||||
* call visit_complete() (for now, useful only for output visits, but
|
||||
* safe to call on all visits). Then, regardless of success or
|
||||
* failure, the user should call visit_free() to clean up resources.
|
||||
* It is okay to free the visitor without completing the visit, if
|
||||
* some other error is detected in the meantime.
|
||||
*
|
||||
* All QAPI types have a corresponding function with a signature
|
||||
* roughly compatible with this:
|
||||
*
|
||||
|
@ -68,9 +81,9 @@
|
|||
*
|
||||
* If an error is detected during visit_type_FOO() with an input
|
||||
* visitor, then *@obj will be NULL for pointer types, and left
|
||||
* unchanged for scalar types. Using an output visitor with an
|
||||
* incomplete object has undefined behavior (other than a special case
|
||||
* for visit_type_str() treating NULL like ""), while the dealloc
|
||||
* unchanged for scalar types. Using an output or clone visitor with
|
||||
* an incomplete object has undefined behavior (other than a special
|
||||
* case for visit_type_str() treating NULL like ""), while the dealloc
|
||||
* visitor safely handles incomplete objects. Since input visitors
|
||||
* never produce an incomplete object, such an object is possible only
|
||||
* by manual construction.
|
||||
|
@ -90,11 +103,19 @@
|
|||
*
|
||||
* void qapi_free_FOO(FOO *obj);
|
||||
*
|
||||
* which behaves like free() in that @obj may be NULL. Because of
|
||||
* these functions, the dealloc visitor is seldom used directly
|
||||
* outside of generated code. QAPI types can also inherit from a base
|
||||
* class; when this happens, a function is generated for easily going
|
||||
* from the derived type to the base type:
|
||||
* where behaves like free() in that @obj may be NULL. Such objects
|
||||
* may also be used with the following macro, provided alongside the
|
||||
* clone visitor:
|
||||
*
|
||||
* Type *QAPI_CLONE(Type, src);
|
||||
*
|
||||
* in order to perform a deep clone of @src. Because of the generated
|
||||
* qapi_free functions and the QAPI_CLONE() macro, the clone and
|
||||
* dealloc visitor should not be used directly outside of QAPI code.
|
||||
*
|
||||
* QAPI types can also inherit from a base class; when this happens, a
|
||||
* function is generated for easily going from the derived type to the
|
||||
* base type:
|
||||
*
|
||||
* BASE *qapi_CHILD_base(CHILD *obj);
|
||||
*
|
||||
|
@ -105,14 +126,14 @@
|
|||
* Error *err = NULL;
|
||||
* Visitor *v;
|
||||
*
|
||||
* v = ...obtain input visitor...
|
||||
* v = FOO_visitor_new(...);
|
||||
* visit_type_Foo(v, NULL, &f, &err);
|
||||
* if (err) {
|
||||
* ...handle error...
|
||||
* } else {
|
||||
* ...use f...
|
||||
* }
|
||||
* ...clean up v...
|
||||
* visit_free(v);
|
||||
* qapi_free_Foo(f);
|
||||
* </example>
|
||||
*
|
||||
|
@ -122,7 +143,7 @@
|
|||
* Error *err = NULL;
|
||||
* Visitor *v;
|
||||
*
|
||||
* v = ...obtain input visitor...
|
||||
* v = FOO_visitor_new(...);
|
||||
* visit_type_FooList(v, NULL, &l, &err);
|
||||
* if (err) {
|
||||
* ...handle error...
|
||||
|
@ -131,7 +152,7 @@
|
|||
* ...use l->value...
|
||||
* }
|
||||
* }
|
||||
* ...clean up v...
|
||||
* visit_free(v);
|
||||
* qapi_free_FooList(l);
|
||||
* </example>
|
||||
*
|
||||
|
@ -141,13 +162,17 @@
|
|||
* Foo *f = ...obtain populated object...
|
||||
* Error *err = NULL;
|
||||
* Visitor *v;
|
||||
* Type *result;
|
||||
*
|
||||
* v = ...obtain output visitor...
|
||||
* v = FOO_visitor_new(..., &result);
|
||||
* visit_type_Foo(v, NULL, &f, &err);
|
||||
* if (err) {
|
||||
* ...handle error...
|
||||
* } else {
|
||||
* visit_complete(v, &result);
|
||||
* ...use result...
|
||||
* }
|
||||
* ...clean up v...
|
||||
* visit_free(v);
|
||||
* </example>
|
||||
*
|
||||
* When visiting a real QAPI struct, this file provides several
|
||||
|
@ -173,7 +198,7 @@
|
|||
* Error *err = NULL;
|
||||
* int value;
|
||||
*
|
||||
* v = ...obtain visitor...
|
||||
* v = FOO_visitor_new(...);
|
||||
* visit_start_struct(v, NULL, NULL, 0, &err);
|
||||
* if (err) {
|
||||
* goto out;
|
||||
|
@ -193,15 +218,15 @@
|
|||
* goto outlist;
|
||||
* }
|
||||
* outlist:
|
||||
* visit_end_list(v);
|
||||
* visit_end_list(v, NULL);
|
||||
* if (!err) {
|
||||
* visit_check_struct(v, &err);
|
||||
* }
|
||||
* outobj:
|
||||
* visit_end_struct(v);
|
||||
* visit_end_struct(v, NULL);
|
||||
* out:
|
||||
* error_propagate(errp, err);
|
||||
* ...clean up v...
|
||||
* visit_free(v);
|
||||
* </example>
|
||||
*/
|
||||
|
||||
|
@ -222,6 +247,31 @@ typedef struct GenericAlternate {
|
|||
char padding[];
|
||||
} GenericAlternate;
|
||||
|
||||
/*** Visitor cleanup ***/
|
||||
|
||||
/*
|
||||
* Complete the visit, collecting any output.
|
||||
*
|
||||
* May only be called only once after a successful top-level
|
||||
* visit_type_FOO() or visit_end_ITEM(), and marks the end of the
|
||||
* visit. The @opaque pointer should match the output parameter
|
||||
* passed to the subtype_visitor_new() used to create an output
|
||||
* visitor, or NULL for any other visitor. Needed for output
|
||||
* visitors, but may also be called with other visitors.
|
||||
*/
|
||||
void visit_complete(Visitor *v, void *opaque);
|
||||
|
||||
/*
|
||||
* Free @v and any resources it has tied up.
|
||||
*
|
||||
* May be called whether or not the visit has been successfully
|
||||
* completed, but should not be called until a top-level
|
||||
* visit_type_FOO() or visit_start_ITEM() has been performed on the
|
||||
* visitor. Safe if @v is NULL.
|
||||
*/
|
||||
void visit_free(Visitor *v);
|
||||
|
||||
|
||||
/*** Visiting structures ***/
|
||||
|
||||
/*
|
||||
|
@ -231,9 +281,9 @@ typedef struct GenericAlternate {
|
|||
* container; see the general description of @name above.
|
||||
*
|
||||
* @obj must be non-NULL for a real walk, in which case @size
|
||||
* determines how much memory an input visitor will allocate into
|
||||
* *@obj. @obj may also be NULL for a virtual walk, in which case
|
||||
* @size is ignored.
|
||||
* determines how much memory an input or clone visitor will allocate
|
||||
* into *@obj. @obj may also be NULL for a virtual walk, in which
|
||||
* case @size is ignored.
|
||||
*
|
||||
* @errp obeys typical error usage, and reports failures such as a
|
||||
* member @name is not present, or present but not an object. On
|
||||
|
@ -242,8 +292,8 @@ typedef struct GenericAlternate {
|
|||
* After visit_start_struct() succeeds, the caller may visit its
|
||||
* members one after the other, passing the member's name and address
|
||||
* within the struct. Finally, visit_end_struct() needs to be called
|
||||
* to clean up, even if intermediate visits fail. See the examples
|
||||
* above.
|
||||
* with the same @obj to clean up, even if intermediate visits fail.
|
||||
* See the examples above.
|
||||
*
|
||||
* FIXME Should this be named visit_start_object, since it is also
|
||||
* used for QAPI unions, and maps to JSON objects?
|
||||
|
@ -267,12 +317,14 @@ void visit_check_struct(Visitor *v, Error **errp);
|
|||
/*
|
||||
* Complete an object visit started earlier.
|
||||
*
|
||||
* @obj must match what was passed to the paired visit_start_struct().
|
||||
*
|
||||
* Must be called after any successful use of visit_start_struct(),
|
||||
* even if intermediate processing was skipped due to errors, to allow
|
||||
* the backend to release any resources. Destroying the visitor early
|
||||
* behaves as if this was implicitly called.
|
||||
* with visit_free() behaves as if this was implicitly called.
|
||||
*/
|
||||
void visit_end_struct(Visitor *v);
|
||||
void visit_end_struct(Visitor *v, void **obj);
|
||||
|
||||
|
||||
/*** Visiting lists ***/
|
||||
|
@ -284,9 +336,9 @@ void visit_end_struct(Visitor *v);
|
|||
* container; see the general description of @name above.
|
||||
*
|
||||
* @list must be non-NULL for a real walk, in which case @size
|
||||
* determines how much memory an input visitor will allocate into
|
||||
* *@list (at least sizeof(GenericList)). Some visitors also allow
|
||||
* @list to be NULL for a virtual walk, in which case @size is
|
||||
* determines how much memory an input or clone visitor will allocate
|
||||
* into *@list (at least sizeof(GenericList)). Some visitors also
|
||||
* allow @list to be NULL for a virtual walk, in which case @size is
|
||||
* ignored.
|
||||
*
|
||||
* @errp obeys typical error usage, and reports failures such as a
|
||||
|
@ -299,8 +351,9 @@ void visit_end_struct(Visitor *v);
|
|||
* visit (where @obj is NULL) uses other means. For each list
|
||||
* element, call the appropriate visit_type_FOO() with name set to
|
||||
* NULL and obj set to the address of the value member of the list
|
||||
* element. Finally, visit_end_list() needs to be called to clean up,
|
||||
* even if intermediate visits fail. See the examples above.
|
||||
* element. Finally, visit_end_list() needs to be called with the
|
||||
* same @list to clean up, even if intermediate visits fail. See the
|
||||
* examples above.
|
||||
*/
|
||||
void visit_start_list(Visitor *v, const char *name, GenericList **list,
|
||||
size_t size, Error **errp);
|
||||
|
@ -324,12 +377,14 @@ GenericList *visit_next_list(Visitor *v, GenericList *tail, size_t size);
|
|||
/*
|
||||
* Complete a list visit started earlier.
|
||||
*
|
||||
* @list must match what was passed to the paired visit_start_list().
|
||||
*
|
||||
* Must be called after any successful use of visit_start_list(), even
|
||||
* if intermediate processing was skipped due to errors, to allow the
|
||||
* backend to release any resources. Destroying the visitor early
|
||||
* behaves as if this was implicitly called.
|
||||
* with visit_free() behaves as if this was implicitly called.
|
||||
*/
|
||||
void visit_end_list(Visitor *v);
|
||||
void visit_end_list(Visitor *v, void **list);
|
||||
|
||||
|
||||
/*** Visiting alternates ***/
|
||||
|
@ -340,15 +395,16 @@ void visit_end_list(Visitor *v);
|
|||
* @name expresses the relationship of this alternate to its parent
|
||||
* container; see the general description of @name above.
|
||||
*
|
||||
* @obj must not be NULL. Input visitors use @size to determine how
|
||||
* much memory to allocate into *@obj, then determine the qtype of the
|
||||
* next thing to be visited, stored in (*@obj)->type. Other visitors
|
||||
* will leave @obj unchanged.
|
||||
* @obj must not be NULL. Input and clone visitors use @size to
|
||||
* determine how much memory to allocate into *@obj, then determine
|
||||
* the qtype of the next thing to be visited, stored in (*@obj)->type.
|
||||
* Other visitors will leave @obj unchanged.
|
||||
*
|
||||
* If @promote_int, treat integers as QTYPE_FLOAT.
|
||||
*
|
||||
* If successful, this must be paired with visit_end_alternate() to
|
||||
* clean up, even if visiting the contents of the alternate fails.
|
||||
* If successful, this must be paired with visit_end_alternate() with
|
||||
* the same @obj to clean up, even if visiting the contents of the
|
||||
* alternate fails.
|
||||
*/
|
||||
void visit_start_alternate(Visitor *v, const char *name,
|
||||
GenericAlternate **obj, size_t size,
|
||||
|
@ -357,15 +413,15 @@ void visit_start_alternate(Visitor *v, const char *name,
|
|||
/*
|
||||
* Finish visiting an alternate type.
|
||||
*
|
||||
* @obj must match what was passed to the paired visit_start_alternate().
|
||||
*
|
||||
* Must be called after any successful use of visit_start_alternate(),
|
||||
* even if intermediate processing was skipped due to errors, to allow
|
||||
* the backend to release any resources. Destroying the visitor early
|
||||
* behaves as if this was implicitly called.
|
||||
* with visit_free() behaves as if this was implicitly called.
|
||||
*
|
||||
* TODO: Should all the visit_end_* interfaces take obj parameter, so
|
||||
* that dealloc visitor need not track what was passed in visit_start?
|
||||
*/
|
||||
void visit_end_alternate(Visitor *v);
|
||||
void visit_end_alternate(Visitor *v, void **obj);
|
||||
|
||||
|
||||
/*** Other helpers ***/
|
||||
|
@ -507,9 +563,10 @@ void visit_type_bool(Visitor *v, const char *name, bool *obj, Error **errp);
|
|||
* @name expresses the relationship of this string to its parent
|
||||
* container; see the general description of @name above.
|
||||
*
|
||||
* @obj must be non-NULL. Input visitors set *@obj to the value
|
||||
* (never NULL). Other visitors leave *@obj unchanged, and commonly
|
||||
* treat NULL like "".
|
||||
* @obj must be non-NULL. Input and clone visitors set *@obj to the
|
||||
* value (always using "" rather than NULL for an empty string).
|
||||
* Other visitors leave *@obj unchanged, and commonly treat NULL like
|
||||
* "".
|
||||
*
|
||||
* It is safe to cast away const when preparing a (const char *) value
|
||||
* into @obj for use by an output visitor.
|
||||
|
|
|
@ -107,10 +107,6 @@ SocketAddress *socket_local_address(int fd, Error **errp);
|
|||
*/
|
||||
SocketAddress *socket_remote_address(int fd, Error **errp);
|
||||
|
||||
|
||||
void qapi_copy_SocketAddress(SocketAddress **p_dest,
|
||||
SocketAddress *src);
|
||||
|
||||
/**
|
||||
* socket_address_to_string:
|
||||
* @addr: the socket address struct
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "io/channel-socket.h"
|
||||
#include "io/channel-watch.h"
|
||||
#include "trace.h"
|
||||
#include "qapi/clone-visitor.h"
|
||||
|
||||
#define SOCKET_MAX_FDS 16
|
||||
|
||||
|
@ -189,7 +190,7 @@ void qio_channel_socket_connect_async(QIOChannelSocket *ioc,
|
|||
OBJECT(ioc), callback, opaque, destroy);
|
||||
SocketAddress *addrCopy;
|
||||
|
||||
qapi_copy_SocketAddress(&addrCopy, addr);
|
||||
addrCopy = QAPI_CLONE(SocketAddress, addr);
|
||||
|
||||
/* socket_connect() does a non-blocking connect(), but it
|
||||
* still blocks in DNS lookups, so we must use a thread */
|
||||
|
@ -251,7 +252,7 @@ void qio_channel_socket_listen_async(QIOChannelSocket *ioc,
|
|||
OBJECT(ioc), callback, opaque, destroy);
|
||||
SocketAddress *addrCopy;
|
||||
|
||||
qapi_copy_SocketAddress(&addrCopy, addr);
|
||||
addrCopy = QAPI_CLONE(SocketAddress, addr);
|
||||
|
||||
/* socket_listen() blocks in DNS lookups, so we must use a thread */
|
||||
trace_qio_channel_socket_listen_async(ioc, addr);
|
||||
|
@ -331,8 +332,8 @@ void qio_channel_socket_dgram_async(QIOChannelSocket *ioc,
|
|||
struct QIOChannelSocketDGramWorkerData *data = g_new0(
|
||||
struct QIOChannelSocketDGramWorkerData, 1);
|
||||
|
||||
qapi_copy_SocketAddress(&data->localAddr, localAddr);
|
||||
qapi_copy_SocketAddress(&data->remoteAddr, remoteAddr);
|
||||
data->localAddr = QAPI_CLONE(SocketAddress, localAddr);
|
||||
data->remoteAddr = QAPI_CLONE(SocketAddress, remoteAddr);
|
||||
|
||||
trace_qio_channel_socket_dgram_async(ioc, localAddr, remoteAddr);
|
||||
qio_task_run_in_thread(task,
|
||||
|
|
|
@ -54,11 +54,7 @@
|
|||
#include "qemu/acl.h"
|
||||
#include "sysemu/tpm.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qapi/qmp/qint.h"
|
||||
#include "qapi/qmp/qfloat.h"
|
||||
#include "qapi/qmp/qlist.h"
|
||||
#include "qapi/qmp/qbool.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "qapi/qmp/types.h"
|
||||
#include "qapi/qmp/qjson.h"
|
||||
#include "qapi/qmp/json-streamer.h"
|
||||
#include "qapi/qmp/json-parser.h"
|
||||
|
|
16
net/net.c
16
net/net.c
|
@ -1024,8 +1024,7 @@ int net_client_init(QemuOpts *opts, int is_netdev, Error **errp)
|
|||
void *object = NULL;
|
||||
Error *err = NULL;
|
||||
int ret = -1;
|
||||
OptsVisitor *ov = opts_visitor_new(opts);
|
||||
Visitor *v = opts_get_visitor(ov);
|
||||
Visitor *v = opts_visitor_new(opts);
|
||||
|
||||
{
|
||||
/* Parse convenience option format ip6-net=fec0::0[/64] */
|
||||
|
@ -1075,7 +1074,7 @@ int net_client_init(QemuOpts *opts, int is_netdev, Error **errp)
|
|||
}
|
||||
|
||||
error_propagate(errp, err);
|
||||
opts_visitor_cleanup(ov);
|
||||
visit_free(v);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1199,7 +1198,7 @@ static void netfilter_print_info(Monitor *mon, NetFilterState *nf)
|
|||
char *str;
|
||||
ObjectProperty *prop;
|
||||
ObjectPropertyIterator iter;
|
||||
StringOutputVisitor *ov;
|
||||
Visitor *v;
|
||||
|
||||
/* generate info str */
|
||||
object_property_iter_init(&iter, OBJECT(nf));
|
||||
|
@ -1207,11 +1206,10 @@ static void netfilter_print_info(Monitor *mon, NetFilterState *nf)
|
|||
if (!strcmp(prop->name, "type")) {
|
||||
continue;
|
||||
}
|
||||
ov = string_output_visitor_new(false);
|
||||
object_property_get(OBJECT(nf), string_output_get_visitor(ov),
|
||||
prop->name, NULL);
|
||||
str = string_output_get_string(ov);
|
||||
string_output_visitor_cleanup(ov);
|
||||
v = string_output_visitor_new(false, &str);
|
||||
object_property_get(OBJECT(nf), v, prop->name, NULL);
|
||||
visit_complete(v, &str);
|
||||
visit_free(v);
|
||||
monitor_printf(mon, ",%s=%s", prop->name, str);
|
||||
g_free(str);
|
||||
}
|
||||
|
|
6
numa.c
6
numa.c
|
@ -217,9 +217,9 @@ static int parse_numa(void *opaque, QemuOpts *opts, Error **errp)
|
|||
Error *err = NULL;
|
||||
|
||||
{
|
||||
OptsVisitor *ov = opts_visitor_new(opts);
|
||||
visit_type_NumaOptions(opts_get_visitor(ov), NULL, &object, &err);
|
||||
opts_visitor_cleanup(ov);
|
||||
Visitor *v = opts_visitor_new(opts);
|
||||
visit_type_NumaOptions(v, NULL, &object, &err);
|
||||
visit_free(v);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -32,8 +32,7 @@
|
|||
#include "sysemu/char.h"
|
||||
#include "hw/usb.h"
|
||||
#include "qmp-commands.h"
|
||||
#include "qapi/qmp-input-visitor.h"
|
||||
#include "qapi/qmp-output-visitor.h"
|
||||
#include "qapi/clone-visitor.h"
|
||||
#include "qapi-visit.h"
|
||||
#include "qemu/base64.h"
|
||||
#include "io/channel-socket.h"
|
||||
|
@ -4389,7 +4388,7 @@ static CharDriverState *qmp_chardev_open_socket(const char *id,
|
|||
}
|
||||
}
|
||||
|
||||
qapi_copy_SocketAddress(&s->addr, sock->addr);
|
||||
s->addr = QAPI_CLONE(SocketAddress, sock->addr);
|
||||
|
||||
chr->opaque = s;
|
||||
chr->chr_write = tcp_chr_write;
|
||||
|
|
32
qemu-img.c
32
qemu-img.c
|
@ -490,18 +490,17 @@ fail:
|
|||
|
||||
static void dump_json_image_check(ImageCheck *check, bool quiet)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
QString *str;
|
||||
QmpOutputVisitor *ov = qmp_output_visitor_new();
|
||||
QObject *obj;
|
||||
visit_type_ImageCheck(qmp_output_get_visitor(ov), NULL, &check,
|
||||
&local_err);
|
||||
obj = qmp_output_get_qobject(ov);
|
||||
Visitor *v = qmp_output_visitor_new(&obj);
|
||||
|
||||
visit_type_ImageCheck(v, NULL, &check, &error_abort);
|
||||
visit_complete(v, &obj);
|
||||
str = qobject_to_json_pretty(obj);
|
||||
assert(str != NULL);
|
||||
qprintf(quiet, "%s\n", qstring_get_str(str));
|
||||
qobject_decref(obj);
|
||||
qmp_output_visitor_cleanup(ov);
|
||||
visit_free(v);
|
||||
QDECREF(str);
|
||||
}
|
||||
|
||||
|
@ -2182,34 +2181,33 @@ static void dump_snapshots(BlockDriverState *bs)
|
|||
|
||||
static void dump_json_image_info_list(ImageInfoList *list)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
QString *str;
|
||||
QmpOutputVisitor *ov = qmp_output_visitor_new();
|
||||
QObject *obj;
|
||||
visit_type_ImageInfoList(qmp_output_get_visitor(ov), NULL, &list,
|
||||
&local_err);
|
||||
obj = qmp_output_get_qobject(ov);
|
||||
Visitor *v = qmp_output_visitor_new(&obj);
|
||||
|
||||
visit_type_ImageInfoList(v, NULL, &list, &error_abort);
|
||||
visit_complete(v, &obj);
|
||||
str = qobject_to_json_pretty(obj);
|
||||
assert(str != NULL);
|
||||
printf("%s\n", qstring_get_str(str));
|
||||
qobject_decref(obj);
|
||||
qmp_output_visitor_cleanup(ov);
|
||||
visit_free(v);
|
||||
QDECREF(str);
|
||||
}
|
||||
|
||||
static void dump_json_image_info(ImageInfo *info)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
QString *str;
|
||||
QmpOutputVisitor *ov = qmp_output_visitor_new();
|
||||
QObject *obj;
|
||||
visit_type_ImageInfo(qmp_output_get_visitor(ov), NULL, &info, &local_err);
|
||||
obj = qmp_output_get_qobject(ov);
|
||||
Visitor *v = qmp_output_visitor_new(&obj);
|
||||
|
||||
visit_type_ImageInfo(v, NULL, &info, &error_abort);
|
||||
visit_complete(v, &obj);
|
||||
str = qobject_to_json_pretty(obj);
|
||||
assert(str != NULL);
|
||||
printf("%s\n", qstring_get_str(str));
|
||||
qobject_decref(obj);
|
||||
qmp_output_visitor_cleanup(ov);
|
||||
visit_free(v);
|
||||
QDECREF(str);
|
||||
}
|
||||
|
||||
|
|
9
qmp.c
9
qmp.c
|
@ -655,7 +655,7 @@ void qmp_object_add(const char *type, const char *id,
|
|||
bool has_props, QObject *props, Error **errp)
|
||||
{
|
||||
const QDict *pdict = NULL;
|
||||
QmpInputVisitor *qiv;
|
||||
Visitor *v;
|
||||
Object *obj;
|
||||
|
||||
if (props) {
|
||||
|
@ -666,10 +666,9 @@ void qmp_object_add(const char *type, const char *id,
|
|||
}
|
||||
}
|
||||
|
||||
qiv = qmp_input_visitor_new(props, true);
|
||||
obj = user_creatable_add_type(type, id, pdict,
|
||||
qmp_input_get_visitor(qiv), errp);
|
||||
qmp_input_visitor_cleanup(qiv);
|
||||
v = qmp_input_visitor_new(props, true);
|
||||
obj = user_creatable_add_type(type, id, pdict, v, errp);
|
||||
visit_free(v);
|
||||
if (obj) {
|
||||
object_unref(obj);
|
||||
}
|
||||
|
|
|
@ -14,12 +14,7 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "qapi/qmp/qint.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qlist.h"
|
||||
#include "qapi/qmp/qfloat.h"
|
||||
#include "qapi/qmp/qbool.h"
|
||||
#include "qapi/qmp/types.h"
|
||||
#include "qapi/qmp/json-parser.h"
|
||||
#include "qapi/qmp/json-lexer.h"
|
||||
#include "qapi/qmp/json-streamer.h"
|
||||
|
|
|
@ -16,11 +16,7 @@
|
|||
#include "qapi/qmp/json-parser.h"
|
||||
#include "qapi/qmp/json-streamer.h"
|
||||
#include "qapi/qmp/qjson.h"
|
||||
#include "qapi/qmp/qint.h"
|
||||
#include "qapi/qmp/qlist.h"
|
||||
#include "qapi/qmp/qbool.h"
|
||||
#include "qapi/qmp/qfloat.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/types.h"
|
||||
#include "qemu/unicode.h"
|
||||
|
||||
typedef struct JSONParsingState
|
||||
|
|
|
@ -9,12 +9,7 @@
|
|||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qapi/qmp/qbool.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qfloat.h"
|
||||
#include "qapi/qmp/qint.h"
|
||||
#include "qapi/qmp/qlist.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "qapi/qmp/types.h"
|
||||
|
||||
static void (*qdestroy[QTYPE__MAX])(QObject *) = {
|
||||
[QTYPE_NONE] = NULL, /* No such object exists */
|
||||
|
|
58
qom/object.c
58
qom/object.c
|
@ -1221,8 +1221,7 @@ int object_property_get_enum(Object *obj, const char *name,
|
|||
const char *typename, Error **errp)
|
||||
{
|
||||
Error *err = NULL;
|
||||
StringOutputVisitor *sov;
|
||||
StringInputVisitor *siv;
|
||||
Visitor *v;
|
||||
char *str;
|
||||
int ret;
|
||||
ObjectProperty *prop = object_property_find(obj, name, errp);
|
||||
|
@ -1241,21 +1240,20 @@ int object_property_get_enum(Object *obj, const char *name,
|
|||
|
||||
enumprop = prop->opaque;
|
||||
|
||||
sov = string_output_visitor_new(false);
|
||||
object_property_get(obj, string_output_get_visitor(sov), name, &err);
|
||||
v = string_output_visitor_new(false, &str);
|
||||
object_property_get(obj, v, name, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
string_output_visitor_cleanup(sov);
|
||||
visit_free(v);
|
||||
return 0;
|
||||
}
|
||||
str = string_output_get_string(sov);
|
||||
siv = string_input_visitor_new(str);
|
||||
string_output_visitor_cleanup(sov);
|
||||
visit_type_enum(string_input_get_visitor(siv), name, &ret,
|
||||
enumprop->strings, errp);
|
||||
visit_complete(v, &str);
|
||||
visit_free(v);
|
||||
v = string_input_visitor_new(str);
|
||||
visit_type_enum(v, name, &ret, enumprop->strings, errp);
|
||||
|
||||
g_free(str);
|
||||
string_input_visitor_cleanup(siv);
|
||||
visit_free(v);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1264,55 +1262,51 @@ void object_property_get_uint16List(Object *obj, const char *name,
|
|||
uint16List **list, Error **errp)
|
||||
{
|
||||
Error *err = NULL;
|
||||
StringOutputVisitor *ov;
|
||||
StringInputVisitor *iv;
|
||||
Visitor *v;
|
||||
char *str;
|
||||
|
||||
ov = string_output_visitor_new(false);
|
||||
object_property_get(obj, string_output_get_visitor(ov),
|
||||
name, &err);
|
||||
v = string_output_visitor_new(false, &str);
|
||||
object_property_get(obj, v, name, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
goto out;
|
||||
}
|
||||
str = string_output_get_string(ov);
|
||||
iv = string_input_visitor_new(str);
|
||||
visit_type_uint16List(string_input_get_visitor(iv), NULL, list, errp);
|
||||
visit_complete(v, &str);
|
||||
visit_free(v);
|
||||
v = string_input_visitor_new(str);
|
||||
visit_type_uint16List(v, NULL, list, errp);
|
||||
|
||||
g_free(str);
|
||||
string_input_visitor_cleanup(iv);
|
||||
out:
|
||||
string_output_visitor_cleanup(ov);
|
||||
visit_free(v);
|
||||
}
|
||||
|
||||
void object_property_parse(Object *obj, const char *string,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
StringInputVisitor *siv;
|
||||
siv = string_input_visitor_new(string);
|
||||
object_property_set(obj, string_input_get_visitor(siv), name, errp);
|
||||
|
||||
string_input_visitor_cleanup(siv);
|
||||
Visitor *v = string_input_visitor_new(string);
|
||||
object_property_set(obj, v, name, errp);
|
||||
visit_free(v);
|
||||
}
|
||||
|
||||
char *object_property_print(Object *obj, const char *name, bool human,
|
||||
Error **errp)
|
||||
{
|
||||
StringOutputVisitor *sov;
|
||||
Visitor *v;
|
||||
char *string = NULL;
|
||||
Error *local_err = NULL;
|
||||
|
||||
sov = string_output_visitor_new(human);
|
||||
object_property_get(obj, string_output_get_visitor(sov), name, &local_err);
|
||||
v = string_output_visitor_new(human, &string);
|
||||
object_property_get(obj, v, name, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
string = string_output_get_string(sov);
|
||||
visit_complete(v, &string);
|
||||
|
||||
out:
|
||||
string_output_visitor_cleanup(sov);
|
||||
visit_free(v);
|
||||
return string;
|
||||
}
|
||||
|
||||
|
@ -2044,7 +2038,7 @@ static void property_get_tm(Object *obj, Visitor *v, const char *name,
|
|||
}
|
||||
visit_check_struct(v, &err);
|
||||
out_end:
|
||||
visit_end_struct(v);
|
||||
visit_end_struct(v, NULL);
|
||||
out:
|
||||
error_propagate(errp, err);
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ Object *user_creatable_add(const QDict *qdict,
|
|||
obj = user_creatable_add_type(type, id, pdict, v, &local_err);
|
||||
|
||||
out_visit:
|
||||
visit_end_struct(v);
|
||||
visit_end_struct(v, NULL);
|
||||
|
||||
out:
|
||||
QDECREF(pdict);
|
||||
|
@ -127,7 +127,7 @@ Object *user_creatable_add_type(const char *type, const char *id,
|
|||
if (!local_err) {
|
||||
visit_check_struct(v, &local_err);
|
||||
}
|
||||
visit_end_struct(v);
|
||||
visit_end_struct(v, NULL);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
|
@ -156,15 +156,15 @@ out:
|
|||
|
||||
Object *user_creatable_add_opts(QemuOpts *opts, Error **errp)
|
||||
{
|
||||
OptsVisitor *ov;
|
||||
Visitor *v;
|
||||
QDict *pdict;
|
||||
Object *obj = NULL;
|
||||
|
||||
ov = opts_visitor_new(opts);
|
||||
v = opts_visitor_new(opts);
|
||||
pdict = qemu_opts_to_qdict(opts, NULL);
|
||||
|
||||
obj = user_creatable_add(pdict, opts_get_visitor(ov), errp);
|
||||
opts_visitor_cleanup(ov);
|
||||
obj = user_creatable_add(pdict, v, errp);
|
||||
visit_free(v);
|
||||
QDECREF(pdict);
|
||||
return obj;
|
||||
}
|
||||
|
|
|
@ -21,12 +21,11 @@
|
|||
void object_property_set_qobject(Object *obj, QObject *value,
|
||||
const char *name, Error **errp)
|
||||
{
|
||||
QmpInputVisitor *qiv;
|
||||
Visitor *v;
|
||||
/* TODO: Should we reject, rather than ignore, excess input? */
|
||||
qiv = qmp_input_visitor_new(value, false);
|
||||
object_property_set(obj, qmp_input_get_visitor(qiv), name, errp);
|
||||
|
||||
qmp_input_visitor_cleanup(qiv);
|
||||
v = qmp_input_visitor_new(value, false);
|
||||
object_property_set(obj, v, name, errp);
|
||||
visit_free(v);
|
||||
}
|
||||
|
||||
QObject *object_property_get_qobject(Object *obj, const char *name,
|
||||
|
@ -34,14 +33,14 @@ QObject *object_property_get_qobject(Object *obj, const char *name,
|
|||
{
|
||||
QObject *ret = NULL;
|
||||
Error *local_err = NULL;
|
||||
QmpOutputVisitor *qov;
|
||||
Visitor *v;
|
||||
|
||||
qov = qmp_output_visitor_new();
|
||||
object_property_get(obj, qmp_output_get_visitor(qov), name, &local_err);
|
||||
v = qmp_output_visitor_new(&ret);
|
||||
object_property_get(obj, v, name, &local_err);
|
||||
if (!local_err) {
|
||||
ret = qmp_output_get_qobject(qov);
|
||||
visit_complete(v, &ret);
|
||||
}
|
||||
error_propagate(errp, local_err);
|
||||
qmp_output_visitor_cleanup(qov);
|
||||
visit_free(v);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -16,35 +16,7 @@
|
|||
#include "replay-internal.h"
|
||||
#include "qemu/notify.h"
|
||||
#include "ui/input.h"
|
||||
#include "qapi/qmp-output-visitor.h"
|
||||
#include "qapi/qmp-input-visitor.h"
|
||||
#include "qapi-visit.h"
|
||||
|
||||
static InputEvent *qapi_clone_InputEvent(InputEvent *src)
|
||||
{
|
||||
QmpOutputVisitor *qov;
|
||||
QmpInputVisitor *qiv;
|
||||
Visitor *ov, *iv;
|
||||
QObject *obj;
|
||||
InputEvent *dst = NULL;
|
||||
|
||||
qov = qmp_output_visitor_new();
|
||||
ov = qmp_output_get_visitor(qov);
|
||||
visit_type_InputEvent(ov, NULL, &src, &error_abort);
|
||||
obj = qmp_output_get_qobject(qov);
|
||||
qmp_output_visitor_cleanup(qov);
|
||||
if (!obj) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qiv = qmp_input_visitor_new(obj, true);
|
||||
iv = qmp_input_get_visitor(qiv);
|
||||
visit_type_InputEvent(iv, NULL, &dst, &error_abort);
|
||||
qmp_input_visitor_cleanup(qiv);
|
||||
qobject_decref(obj);
|
||||
|
||||
return dst;
|
||||
}
|
||||
#include "qapi/clone-visitor.h"
|
||||
|
||||
void replay_save_input_event(InputEvent *evt)
|
||||
{
|
||||
|
@ -143,7 +115,7 @@ InputEvent *replay_read_input_event(void)
|
|||
break;
|
||||
}
|
||||
|
||||
return qapi_clone_InputEvent(&evt);
|
||||
return QAPI_CLONE(InputEvent, &evt);
|
||||
}
|
||||
|
||||
void replay_input_event(QemuConsole *src, InputEvent *evt)
|
||||
|
@ -151,7 +123,7 @@ void replay_input_event(QemuConsole *src, InputEvent *evt)
|
|||
if (replay_mode == REPLAY_MODE_PLAY) {
|
||||
/* Nothing */
|
||||
} else if (replay_mode == REPLAY_MODE_RECORD) {
|
||||
replay_add_input_event(qapi_clone_InputEvent(evt));
|
||||
replay_add_input_event(QAPI_CLONE(InputEvent, evt));
|
||||
} else {
|
||||
qemu_input_event_send_impl(src, evt);
|
||||
}
|
||||
|
|
|
@ -61,24 +61,18 @@ def gen_marshal_output(ret_type):
|
|||
static void qmp_marshal_output_%(c_name)s(%(c_type)s ret_in, QObject **ret_out, Error **errp)
|
||||
{
|
||||
Error *err = NULL;
|
||||
QmpOutputVisitor *qov = qmp_output_visitor_new();
|
||||
QapiDeallocVisitor *qdv;
|
||||
Visitor *v;
|
||||
|
||||
v = qmp_output_get_visitor(qov);
|
||||
v = qmp_output_visitor_new(ret_out);
|
||||
visit_type_%(c_name)s(v, "unused", &ret_in, &err);
|
||||
if (err) {
|
||||
goto out;
|
||||
if (!err) {
|
||||
visit_complete(v, ret_out);
|
||||
}
|
||||
*ret_out = qmp_output_get_qobject(qov);
|
||||
|
||||
out:
|
||||
error_propagate(errp, err);
|
||||
qmp_output_visitor_cleanup(qov);
|
||||
qdv = qapi_dealloc_visitor_new();
|
||||
v = qapi_dealloc_get_visitor(qdv);
|
||||
visit_free(v);
|
||||
v = qapi_dealloc_visitor_new();
|
||||
visit_type_%(c_name)s(v, "unused", &ret_in, NULL);
|
||||
qapi_dealloc_visitor_cleanup(qdv);
|
||||
visit_free(v);
|
||||
}
|
||||
''',
|
||||
c_type=ret_type.c_type(), c_name=ret_type.c_name())
|
||||
|
@ -115,12 +109,10 @@ def gen_marshal(name, arg_type, ret_type):
|
|||
|
||||
if arg_type and arg_type.members:
|
||||
ret += mcgen('''
|
||||
QmpInputVisitor *qiv = qmp_input_visitor_new(QOBJECT(args), true);
|
||||
QapiDeallocVisitor *qdv;
|
||||
Visitor *v;
|
||||
%(c_name)s arg = {0};
|
||||
|
||||
v = qmp_input_get_visitor(qiv);
|
||||
v = qmp_input_visitor_new(QOBJECT(args), true);
|
||||
visit_start_struct(v, NULL, NULL, 0, &err);
|
||||
if (err) {
|
||||
goto out;
|
||||
|
@ -129,7 +121,7 @@ def gen_marshal(name, arg_type, ret_type):
|
|||
if (!err) {
|
||||
visit_check_struct(v, &err);
|
||||
}
|
||||
visit_end_struct(v);
|
||||
visit_end_struct(v, NULL);
|
||||
if (err) {
|
||||
goto out;
|
||||
}
|
||||
|
@ -155,13 +147,12 @@ out:
|
|||
''')
|
||||
if arg_type and arg_type.members:
|
||||
ret += mcgen('''
|
||||
qmp_input_visitor_cleanup(qiv);
|
||||
qdv = qapi_dealloc_visitor_new();
|
||||
v = qapi_dealloc_get_visitor(qdv);
|
||||
visit_free(v);
|
||||
v = qapi_dealloc_visitor_new();
|
||||
visit_start_struct(v, NULL, NULL, 0, NULL);
|
||||
visit_type_%(c_name)s_members(v, &arg, NULL);
|
||||
visit_end_struct(v);
|
||||
qapi_dealloc_visitor_cleanup(qdv);
|
||||
visit_end_struct(v, NULL);
|
||||
visit_free(v);
|
||||
''',
|
||||
c_name=arg_type.c_name())
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ def gen_event_send(name, arg_type):
|
|||
|
||||
if arg_type and arg_type.members:
|
||||
ret += mcgen('''
|
||||
QmpOutputVisitor *qov;
|
||||
QObject *obj;
|
||||
Visitor *v;
|
||||
''')
|
||||
ret += gen_param_var(arg_type)
|
||||
|
@ -90,8 +90,7 @@ def gen_event_send(name, arg_type):
|
|||
|
||||
if arg_type and arg_type.members:
|
||||
ret += mcgen('''
|
||||
qov = qmp_output_visitor_new();
|
||||
v = qmp_output_get_visitor(qov);
|
||||
v = qmp_output_visitor_new(&obj);
|
||||
|
||||
visit_start_struct(v, "%(name)s", NULL, 0, &err);
|
||||
if (err) {
|
||||
|
@ -101,12 +100,13 @@ def gen_event_send(name, arg_type):
|
|||
if (!err) {
|
||||
visit_check_struct(v, &err);
|
||||
}
|
||||
visit_end_struct(v);
|
||||
visit_end_struct(v, NULL);
|
||||
if (err) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
qdict_put_obj(qmp, "data", qmp_output_get_qobject(qov));
|
||||
visit_complete(v, &obj);
|
||||
qdict_put_obj(qmp, "data", obj);
|
||||
''',
|
||||
name=name, c_name=arg_type.c_name())
|
||||
|
||||
|
@ -119,7 +119,7 @@ def gen_event_send(name, arg_type):
|
|||
if arg_type and arg_type.members:
|
||||
ret += mcgen('''
|
||||
out:
|
||||
qmp_output_visitor_cleanup(qov);
|
||||
visit_free(v);
|
||||
''')
|
||||
ret += mcgen('''
|
||||
error_propagate(errp, err);
|
||||
|
|
|
@ -150,17 +150,15 @@ def gen_type_cleanup(name):
|
|||
|
||||
void qapi_free_%(c_name)s(%(c_name)s *obj)
|
||||
{
|
||||
QapiDeallocVisitor *qdv;
|
||||
Visitor *v;
|
||||
|
||||
if (!obj) {
|
||||
return;
|
||||
}
|
||||
|
||||
qdv = qapi_dealloc_visitor_new();
|
||||
v = qapi_dealloc_get_visitor(qdv);
|
||||
v = qapi_dealloc_visitor_new();
|
||||
visit_type_%(c_name)s(v, NULL, &obj, NULL);
|
||||
qapi_dealloc_visitor_cleanup(qdv);
|
||||
visit_free(v);
|
||||
}
|
||||
''',
|
||||
c_name=c_name(name))
|
||||
|
|
|
@ -129,7 +129,7 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error
|
|||
}
|
||||
}
|
||||
|
||||
visit_end_list(v);
|
||||
visit_end_list(v, (void **)obj);
|
||||
if (err && visit_is_input(v)) {
|
||||
qapi_free_%(c_name)s(*obj);
|
||||
*obj = NULL;
|
||||
|
@ -194,7 +194,7 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error
|
|||
if (!err) {
|
||||
visit_check_struct(v, &err);
|
||||
}
|
||||
visit_end_struct(v);
|
||||
visit_end_struct(v, NULL);
|
||||
''',
|
||||
c_type=var.type.c_name(),
|
||||
c_name=c_name(var.name))
|
||||
|
@ -216,7 +216,7 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error
|
|||
"%(name)s");
|
||||
}
|
||||
out_obj:
|
||||
visit_end_alternate(v);
|
||||
visit_end_alternate(v, (void **)obj);
|
||||
if (err && visit_is_input(v)) {
|
||||
qapi_free_%(c_name)s(*obj);
|
||||
*obj = NULL;
|
||||
|
@ -250,7 +250,7 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error
|
|||
}
|
||||
visit_check_struct(v, &err);
|
||||
out_obj:
|
||||
visit_end_struct(v);
|
||||
visit_end_struct(v, (void **)obj);
|
||||
if (err && visit_is_input(v)) {
|
||||
qapi_free_%(c_name)s(*obj);
|
||||
*obj = NULL;
|
||||
|
|
|
@ -13,6 +13,7 @@ test-aio
|
|||
test-base64
|
||||
test-bitops
|
||||
test-blockjob-txn
|
||||
test-clone-visitor
|
||||
test-coroutine
|
||||
test-crypto-afsplit
|
||||
test-crypto-block
|
||||
|
|
|
@ -22,6 +22,8 @@ check-unit-y += tests/check-qjson$(EXESUF)
|
|||
gcov-files-check-qjson-y = qobject/qjson.c
|
||||
check-unit-y += tests/test-qmp-output-visitor$(EXESUF)
|
||||
gcov-files-test-qmp-output-visitor-y = qapi/qmp-output-visitor.c
|
||||
check-unit-y += tests/test-clone-visitor$(EXESUF)
|
||||
gcov-files-test-clone-visitor-y = qapi/qapi-clone-visitor.c
|
||||
check-unit-y += tests/test-qmp-input-visitor$(EXESUF)
|
||||
gcov-files-test-qmp-input-visitor-y = qapi/qmp-input-visitor.c
|
||||
check-unit-y += tests/test-qmp-input-strict$(EXESUF)
|
||||
|
@ -402,6 +404,7 @@ test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \
|
|||
tests/check-qjson.o \
|
||||
tests/test-coroutine.o tests/test-string-output-visitor.o \
|
||||
tests/test-string-input-visitor.o tests/test-qmp-output-visitor.o \
|
||||
tests/test-clone-visitor.o \
|
||||
tests/test-qmp-input-visitor.o tests/test-qmp-input-strict.o \
|
||||
tests/test-qmp-commands.o tests/test-visitor-serialization.o \
|
||||
tests/test-x86-cpuid.o tests/test-mul64.o tests/test-int128.o \
|
||||
|
@ -499,6 +502,7 @@ tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(
|
|||
tests/test-string-input-visitor$(EXESUF): tests/test-string-input-visitor.o $(test-qapi-obj-y)
|
||||
tests/test-qmp-event$(EXESUF): tests/test-qmp-event.o $(test-qapi-obj-y)
|
||||
tests/test-qmp-output-visitor$(EXESUF): tests/test-qmp-output-visitor.o $(test-qapi-obj-y)
|
||||
tests/test-clone-visitor$(EXESUF): tests/test-clone-visitor.o $(test-qapi-obj-y)
|
||||
tests/test-qmp-input-visitor$(EXESUF): tests/test-qmp-input-visitor.o $(test-qapi-obj-y)
|
||||
tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-obj-y)
|
||||
tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y)
|
||||
|
|
|
@ -12,14 +12,8 @@
|
|||
*/
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "qapi/qmp/qint.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qlist.h"
|
||||
#include "qapi/qmp/qfloat.h"
|
||||
#include "qapi/qmp/qbool.h"
|
||||
#include "qapi/qmp/types.h"
|
||||
#include "qapi/qmp/qjson.h"
|
||||
|
||||
#include "qemu-common.h"
|
||||
|
||||
static void escaped_string(void)
|
||||
|
|
|
@ -37,8 +37,7 @@ static void qnull_ref_test(void)
|
|||
static void qnull_visit_test(void)
|
||||
{
|
||||
QObject *obj;
|
||||
QmpOutputVisitor *qov;
|
||||
QmpInputVisitor *qiv;
|
||||
Visitor *v;
|
||||
|
||||
/*
|
||||
* Most tests of interactions between QObject and visitors are in
|
||||
|
@ -48,17 +47,17 @@ static void qnull_visit_test(void)
|
|||
|
||||
g_assert(qnull_.refcnt == 1);
|
||||
obj = qnull();
|
||||
qiv = qmp_input_visitor_new(obj, true);
|
||||
v = qmp_input_visitor_new(obj, true);
|
||||
qobject_decref(obj);
|
||||
visit_type_null(qmp_input_get_visitor(qiv), NULL, &error_abort);
|
||||
qmp_input_visitor_cleanup(qiv);
|
||||
visit_type_null(v, NULL, &error_abort);
|
||||
visit_free(v);
|
||||
|
||||
qov = qmp_output_visitor_new();
|
||||
visit_type_null(qmp_output_get_visitor(qov), NULL, &error_abort);
|
||||
obj = qmp_output_get_qobject(qov);
|
||||
v = qmp_output_visitor_new(&obj);
|
||||
visit_type_null(v, NULL, &error_abort);
|
||||
visit_complete(v, &obj);
|
||||
g_assert(obj == &qnull_);
|
||||
qobject_decref(obj);
|
||||
qmp_output_visitor_cleanup(qov);
|
||||
visit_free(v);
|
||||
|
||||
g_assert(qnull_.refcnt == 1);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
* QAPI Clone Visitor unit-tests.
|
||||
*
|
||||
* 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 <glib.h>
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qapi/clone-visitor.h"
|
||||
#include "test-qapi-types.h"
|
||||
#include "test-qapi-visit.h"
|
||||
#include "qapi/qmp/types.h"
|
||||
|
||||
static void test_clone_struct(void)
|
||||
{
|
||||
UserDefOne *src, *dst;
|
||||
|
||||
src = g_new0(UserDefOne, 1);
|
||||
src->integer = 42;
|
||||
src->string = g_strdup("Hello");
|
||||
src->has_enum1 = false;
|
||||
src->enum1 = ENUM_ONE_VALUE2;
|
||||
|
||||
dst = QAPI_CLONE(UserDefOne, src);
|
||||
g_assert(dst);
|
||||
g_assert_cmpint(dst->integer, ==, 42);
|
||||
g_assert(dst->string != src->string);
|
||||
g_assert_cmpstr(dst->string, ==, "Hello");
|
||||
g_assert_cmpint(dst->has_enum1, ==, false);
|
||||
/* Our implementation does this, but it is not required:
|
||||
g_assert_cmpint(dst->enum1, ==, ENUM_ONE_VALUE2);
|
||||
*/
|
||||
|
||||
qapi_free_UserDefOne(src);
|
||||
qapi_free_UserDefOne(dst);
|
||||
}
|
||||
|
||||
static void test_clone_alternate(void)
|
||||
{
|
||||
AltStrBool *b_src, *s_src, *b_dst, *s_dst;
|
||||
|
||||
b_src = g_new0(AltStrBool, 1);
|
||||
b_src->type = QTYPE_QBOOL;
|
||||
b_src->u.b = true;
|
||||
s_src = g_new0(AltStrBool, 1);
|
||||
s_src->type = QTYPE_QSTRING;
|
||||
s_src->u.s = g_strdup("World");
|
||||
|
||||
b_dst = QAPI_CLONE(AltStrBool, b_src);
|
||||
g_assert(b_dst);
|
||||
g_assert_cmpint(b_dst->type, ==, b_src->type);
|
||||
g_assert_cmpint(b_dst->u.b, ==, b_src->u.b);
|
||||
s_dst = QAPI_CLONE(AltStrBool, s_src);
|
||||
g_assert(s_dst);
|
||||
g_assert_cmpint(s_dst->type, ==, s_src->type);
|
||||
g_assert_cmpstr(s_dst->u.s, ==, s_src->u.s);
|
||||
g_assert(s_dst->u.s != s_src->u.s);
|
||||
|
||||
qapi_free_AltStrBool(b_src);
|
||||
qapi_free_AltStrBool(s_src);
|
||||
qapi_free_AltStrBool(b_dst);
|
||||
qapi_free_AltStrBool(s_dst);
|
||||
}
|
||||
|
||||
static void test_clone_native_list(void)
|
||||
{
|
||||
uint8List *src, *dst;
|
||||
uint8List *tmp = NULL;
|
||||
int i;
|
||||
|
||||
/* Build list in reverse */
|
||||
for (i = 10; i; i--) {
|
||||
src = g_new0(uint8List, 1);
|
||||
src->next = tmp;
|
||||
src->value = i;
|
||||
tmp = src;
|
||||
}
|
||||
|
||||
dst = QAPI_CLONE(uint8List, src);
|
||||
for (tmp = dst, i = 1; i <= 10; i++) {
|
||||
g_assert(tmp);
|
||||
g_assert_cmpint(tmp->value, ==, i);
|
||||
tmp = tmp->next;
|
||||
}
|
||||
g_assert(!tmp);
|
||||
|
||||
qapi_free_uint8List(src);
|
||||
qapi_free_uint8List(dst);
|
||||
}
|
||||
|
||||
static void test_clone_empty(void)
|
||||
{
|
||||
Empty2 *src, *dst;
|
||||
|
||||
src = g_new0(Empty2, 1);
|
||||
dst = QAPI_CLONE(Empty2, src);
|
||||
g_assert(dst);
|
||||
qapi_free_Empty2(src);
|
||||
qapi_free_Empty2(dst);
|
||||
}
|
||||
|
||||
static void test_clone_complex1(void)
|
||||
{
|
||||
UserDefNativeListUnion *src, *dst;
|
||||
|
||||
src = g_new0(UserDefNativeListUnion, 1);
|
||||
src->type = USER_DEF_NATIVE_LIST_UNION_KIND_STRING;
|
||||
|
||||
dst = QAPI_CLONE(UserDefNativeListUnion, src);
|
||||
g_assert(dst);
|
||||
g_assert_cmpint(dst->type, ==, src->type);
|
||||
g_assert(!dst->u.string.data);
|
||||
|
||||
qapi_free_UserDefNativeListUnion(src);
|
||||
qapi_free_UserDefNativeListUnion(dst);
|
||||
}
|
||||
|
||||
static void test_clone_complex2(void)
|
||||
{
|
||||
WrapAlternate *src, *dst;
|
||||
|
||||
src = g_new0(WrapAlternate, 1);
|
||||
src->alt = g_new(UserDefAlternate, 1);
|
||||
src->alt->type = QTYPE_QDICT;
|
||||
src->alt->u.udfu.integer = 42;
|
||||
/* Clone intentionally converts NULL into "" for strings */
|
||||
src->alt->u.udfu.string = NULL;
|
||||
src->alt->u.udfu.enum1 = ENUM_ONE_VALUE3;
|
||||
src->alt->u.udfu.u.value3.intb = 99;
|
||||
src->alt->u.udfu.u.value3.has_a_b = true;
|
||||
src->alt->u.udfu.u.value3.a_b = true;
|
||||
|
||||
dst = QAPI_CLONE(WrapAlternate, src);
|
||||
g_assert(dst);
|
||||
g_assert(dst->alt);
|
||||
g_assert_cmpint(dst->alt->type, ==, QTYPE_QDICT);
|
||||
g_assert_cmpint(dst->alt->u.udfu.integer, ==, 42);
|
||||
g_assert_cmpstr(dst->alt->u.udfu.string, ==, "");
|
||||
g_assert_cmpint(dst->alt->u.udfu.enum1, ==, ENUM_ONE_VALUE3);
|
||||
g_assert_cmpint(dst->alt->u.udfu.u.value3.intb, ==, 99);
|
||||
g_assert_cmpint(dst->alt->u.udfu.u.value3.has_a_b, ==, true);
|
||||
g_assert_cmpint(dst->alt->u.udfu.u.value3.a_b, ==, true);
|
||||
|
||||
qapi_free_WrapAlternate(src);
|
||||
qapi_free_WrapAlternate(dst);
|
||||
}
|
||||
|
||||
static void test_clone_complex3(void)
|
||||
{
|
||||
__org_qemu_x_Struct2 *src, *dst;
|
||||
__org_qemu_x_Union1List *tmp;
|
||||
|
||||
src = g_new0(__org_qemu_x_Struct2, 1);
|
||||
tmp = src->array = g_new0(__org_qemu_x_Union1List, 1);
|
||||
tmp->value = g_new0(__org_qemu_x_Union1, 1);
|
||||
tmp->value->type = ORG_QEMU_X_UNION1_KIND___ORG_QEMU_X_BRANCH;
|
||||
tmp->value->u.__org_qemu_x_branch.data = g_strdup("one");
|
||||
tmp = tmp->next = g_new0(__org_qemu_x_Union1List, 1);
|
||||
tmp->value = g_new0(__org_qemu_x_Union1, 1);
|
||||
tmp->value->type = ORG_QEMU_X_UNION1_KIND___ORG_QEMU_X_BRANCH;
|
||||
tmp->value->u.__org_qemu_x_branch.data = g_strdup("two");
|
||||
tmp = tmp->next = g_new0(__org_qemu_x_Union1List, 1);
|
||||
tmp->value = g_new0(__org_qemu_x_Union1, 1);
|
||||
tmp->value->type = ORG_QEMU_X_UNION1_KIND___ORG_QEMU_X_BRANCH;
|
||||
tmp->value->u.__org_qemu_x_branch.data = g_strdup("three");
|
||||
|
||||
dst = QAPI_CLONE(__org_qemu_x_Struct2, src);
|
||||
g_assert(dst);
|
||||
tmp = dst->array;
|
||||
g_assert(tmp);
|
||||
g_assert(tmp->value);
|
||||
g_assert_cmpstr(tmp->value->u.__org_qemu_x_branch.data, ==, "one");
|
||||
tmp = tmp->next;
|
||||
g_assert(tmp);
|
||||
g_assert(tmp->value);
|
||||
g_assert_cmpstr(tmp->value->u.__org_qemu_x_branch.data, ==, "two");
|
||||
tmp = tmp->next;
|
||||
g_assert(tmp);
|
||||
g_assert(tmp->value);
|
||||
g_assert_cmpstr(tmp->value->u.__org_qemu_x_branch.data, ==, "three");
|
||||
tmp = tmp->next;
|
||||
g_assert(!tmp);
|
||||
|
||||
qapi_free___org_qemu_x_Struct2(src);
|
||||
qapi_free___org_qemu_x_Struct2(dst);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
g_test_add_func("/visitor/clone/struct", test_clone_struct);
|
||||
g_test_add_func("/visitor/clone/alternate", test_clone_alternate);
|
||||
g_test_add_func("/visitor/clone/native_list", test_clone_native_list);
|
||||
g_test_add_func("/visitor/clone/empty", test_clone_empty);
|
||||
g_test_add_func("/visitor/clone/complex1", test_clone_complex1);
|
||||
g_test_add_func("/visitor/clone/complex2", test_clone_complex2);
|
||||
g_test_add_func("/visitor/clone/complex3", test_clone_complex3);
|
||||
|
||||
return g_test_run();
|
||||
}
|
|
@ -37,16 +37,15 @@ setup_fixture(OptsVisitorFixture *f, gconstpointer test_data)
|
|||
{
|
||||
const char *opts_string = test_data;
|
||||
QemuOpts *opts;
|
||||
OptsVisitor *ov;
|
||||
Visitor *v;
|
||||
|
||||
opts = qemu_opts_parse(qemu_find_opts("userdef"), opts_string, false,
|
||||
NULL);
|
||||
g_assert(opts != NULL);
|
||||
|
||||
ov = opts_visitor_new(opts);
|
||||
visit_type_UserDefOptions(opts_get_visitor(ov), NULL, &f->userdef,
|
||||
&f->err);
|
||||
opts_visitor_cleanup(ov);
|
||||
v = opts_visitor_new(opts);
|
||||
visit_type_UserDefOptions(v, NULL, &f->userdef, &f->err);
|
||||
visit_free(v);
|
||||
qemu_opts_del(opts);
|
||||
}
|
||||
|
||||
|
|
|
@ -216,14 +216,14 @@ static void test_dealloc_partial(void)
|
|||
/* create partial object */
|
||||
{
|
||||
QDict *ud2_dict;
|
||||
QmpInputVisitor *qiv;
|
||||
Visitor *v;
|
||||
|
||||
ud2_dict = qdict_new();
|
||||
qdict_put_obj(ud2_dict, "string0", QOBJECT(qstring_from_str(text)));
|
||||
|
||||
qiv = qmp_input_visitor_new(QOBJECT(ud2_dict), true);
|
||||
visit_type_UserDefTwo(qmp_input_get_visitor(qiv), NULL, &ud2, &err);
|
||||
qmp_input_visitor_cleanup(qiv);
|
||||
v = qmp_input_visitor_new(QOBJECT(ud2_dict), true);
|
||||
visit_type_UserDefTwo(v, NULL, &ud2, &err);
|
||||
visit_free(v);
|
||||
QDECREF(ud2_dict);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,13 +19,14 @@
|
|||
#include "test-qapi-types.h"
|
||||
#include "test-qapi-visit.h"
|
||||
#include "qapi/qmp/types.h"
|
||||
#include "qapi/qmp/qjson.h"
|
||||
#include "test-qmp-introspect.h"
|
||||
#include "qmp-introspect.h"
|
||||
#include "qapi-visit.h"
|
||||
|
||||
typedef struct TestInputVisitorData {
|
||||
QObject *obj;
|
||||
QmpInputVisitor *qiv;
|
||||
Visitor *qiv;
|
||||
} TestInputVisitorData;
|
||||
|
||||
static void validate_teardown(TestInputVisitorData *data,
|
||||
|
@ -35,7 +36,7 @@ static void validate_teardown(TestInputVisitorData *data,
|
|||
data->obj = NULL;
|
||||
|
||||
if (data->qiv) {
|
||||
qmp_input_visitor_cleanup(data->qiv);
|
||||
visit_free(data->qiv);
|
||||
data->qiv = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -47,8 +48,6 @@ static Visitor *validate_test_init_internal(TestInputVisitorData *data,
|
|||
const char *json_string,
|
||||
va_list *ap)
|
||||
{
|
||||
Visitor *v;
|
||||
|
||||
validate_teardown(data, NULL);
|
||||
|
||||
data->obj = qobject_from_jsonv(json_string, ap);
|
||||
|
@ -56,11 +55,7 @@ static Visitor *validate_test_init_internal(TestInputVisitorData *data,
|
|||
|
||||
data->qiv = qmp_input_visitor_new(data->obj, true);
|
||||
g_assert(data->qiv);
|
||||
|
||||
v = qmp_input_get_visitor(data->qiv);
|
||||
g_assert(v);
|
||||
|
||||
return v;
|
||||
return data->qiv;
|
||||
}
|
||||
|
||||
static GCC_FMT_ATTR(2, 3)
|
||||
|
|
|
@ -18,10 +18,11 @@
|
|||
#include "test-qapi-types.h"
|
||||
#include "test-qapi-visit.h"
|
||||
#include "qapi/qmp/types.h"
|
||||
#include "qapi/qmp/qjson.h"
|
||||
|
||||
typedef struct TestInputVisitorData {
|
||||
QObject *obj;
|
||||
QmpInputVisitor *qiv;
|
||||
Visitor *qiv;
|
||||
} TestInputVisitorData;
|
||||
|
||||
static void visitor_input_teardown(TestInputVisitorData *data,
|
||||
|
@ -31,7 +32,7 @@ static void visitor_input_teardown(TestInputVisitorData *data,
|
|||
data->obj = NULL;
|
||||
|
||||
if (data->qiv) {
|
||||
qmp_input_visitor_cleanup(data->qiv);
|
||||
visit_free(data->qiv);
|
||||
data->qiv = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -43,8 +44,6 @@ static Visitor *visitor_input_test_init_internal(TestInputVisitorData *data,
|
|||
const char *json_string,
|
||||
va_list *ap)
|
||||
{
|
||||
Visitor *v;
|
||||
|
||||
visitor_input_teardown(data, NULL);
|
||||
|
||||
data->obj = qobject_from_jsonv(json_string, ap);
|
||||
|
@ -52,11 +51,7 @@ static Visitor *visitor_input_test_init_internal(TestInputVisitorData *data,
|
|||
|
||||
data->qiv = qmp_input_visitor_new(data->obj, false);
|
||||
g_assert(data->qiv);
|
||||
|
||||
v = qmp_input_get_visitor(data->qiv);
|
||||
g_assert(v);
|
||||
|
||||
return v;
|
||||
return data->qiv;
|
||||
}
|
||||
|
||||
static GCC_FMT_ATTR(2, 3)
|
||||
|
@ -303,7 +298,7 @@ static void test_visitor_in_null(TestInputVisitorData *data,
|
|||
visit_type_null(v, "b", &err);
|
||||
error_free_or_abort(&err);
|
||||
visit_check_struct(v, &error_abort);
|
||||
visit_end_struct(v);
|
||||
visit_end_struct(v, NULL);
|
||||
}
|
||||
|
||||
static void test_visitor_in_union_flat(TestInputVisitorData *data,
|
||||
|
|
|
@ -18,28 +18,34 @@
|
|||
#include "test-qapi-types.h"
|
||||
#include "test-qapi-visit.h"
|
||||
#include "qapi/qmp/types.h"
|
||||
#include "qapi/qmp/qjson.h"
|
||||
|
||||
typedef struct TestOutputVisitorData {
|
||||
QmpOutputVisitor *qov;
|
||||
Visitor *ov;
|
||||
QObject *obj;
|
||||
} TestOutputVisitorData;
|
||||
|
||||
static void visitor_output_setup(TestOutputVisitorData *data,
|
||||
const void *unused)
|
||||
{
|
||||
data->qov = qmp_output_visitor_new();
|
||||
g_assert(data->qov != NULL);
|
||||
|
||||
data->ov = qmp_output_get_visitor(data->qov);
|
||||
g_assert(data->ov != NULL);
|
||||
data->ov = qmp_output_visitor_new(&data->obj);
|
||||
g_assert(data->ov);
|
||||
}
|
||||
|
||||
static void visitor_output_teardown(TestOutputVisitorData *data,
|
||||
const void *unused)
|
||||
{
|
||||
qmp_output_visitor_cleanup(data->qov);
|
||||
data->qov = NULL;
|
||||
visit_free(data->ov);
|
||||
data->ov = NULL;
|
||||
qobject_decref(data->obj);
|
||||
data->obj = NULL;
|
||||
}
|
||||
|
||||
static QObject *visitor_get(TestOutputVisitorData *data)
|
||||
{
|
||||
visit_complete(data->ov, &data->obj);
|
||||
g_assert(data->obj);
|
||||
return data->obj;
|
||||
}
|
||||
|
||||
static void visitor_reset(TestOutputVisitorData *data)
|
||||
|
@ -56,12 +62,9 @@ static void test_visitor_out_int(TestOutputVisitorData *data,
|
|||
|
||||
visit_type_int(data->ov, NULL, &value, &error_abort);
|
||||
|
||||
obj = qmp_output_get_qobject(data->qov);
|
||||
g_assert(obj != NULL);
|
||||
obj = visitor_get(data);
|
||||
g_assert(qobject_type(obj) == QTYPE_QINT);
|
||||
g_assert_cmpint(qint_get_int(qobject_to_qint(obj)), ==, value);
|
||||
|
||||
qobject_decref(obj);
|
||||
}
|
||||
|
||||
static void test_visitor_out_bool(TestOutputVisitorData *data,
|
||||
|
@ -72,12 +75,9 @@ static void test_visitor_out_bool(TestOutputVisitorData *data,
|
|||
|
||||
visit_type_bool(data->ov, NULL, &value, &error_abort);
|
||||
|
||||
obj = qmp_output_get_qobject(data->qov);
|
||||
g_assert(obj != NULL);
|
||||
obj = visitor_get(data);
|
||||
g_assert(qobject_type(obj) == QTYPE_QBOOL);
|
||||
g_assert(qbool_get_bool(qobject_to_qbool(obj)) == value);
|
||||
|
||||
qobject_decref(obj);
|
||||
}
|
||||
|
||||
static void test_visitor_out_number(TestOutputVisitorData *data,
|
||||
|
@ -88,12 +88,9 @@ static void test_visitor_out_number(TestOutputVisitorData *data,
|
|||
|
||||
visit_type_number(data->ov, NULL, &value, &error_abort);
|
||||
|
||||
obj = qmp_output_get_qobject(data->qov);
|
||||
g_assert(obj != NULL);
|
||||
obj = visitor_get(data);
|
||||
g_assert(qobject_type(obj) == QTYPE_QFLOAT);
|
||||
g_assert(qfloat_get_double(qobject_to_qfloat(obj)) == value);
|
||||
|
||||
qobject_decref(obj);
|
||||
}
|
||||
|
||||
static void test_visitor_out_string(TestOutputVisitorData *data,
|
||||
|
@ -104,12 +101,9 @@ static void test_visitor_out_string(TestOutputVisitorData *data,
|
|||
|
||||
visit_type_str(data->ov, NULL, &string, &error_abort);
|
||||
|
||||
obj = qmp_output_get_qobject(data->qov);
|
||||
g_assert(obj != NULL);
|
||||
obj = visitor_get(data);
|
||||
g_assert(qobject_type(obj) == QTYPE_QSTRING);
|
||||
g_assert_cmpstr(qstring_get_str(qobject_to_qstring(obj)), ==, string);
|
||||
|
||||
qobject_decref(obj);
|
||||
}
|
||||
|
||||
static void test_visitor_out_no_string(TestOutputVisitorData *data,
|
||||
|
@ -121,12 +115,9 @@ static void test_visitor_out_no_string(TestOutputVisitorData *data,
|
|||
/* A null string should return "" */
|
||||
visit_type_str(data->ov, NULL, &string, &error_abort);
|
||||
|
||||
obj = qmp_output_get_qobject(data->qov);
|
||||
g_assert(obj != NULL);
|
||||
obj = visitor_get(data);
|
||||
g_assert(qobject_type(obj) == QTYPE_QSTRING);
|
||||
g_assert_cmpstr(qstring_get_str(qobject_to_qstring(obj)), ==, "");
|
||||
|
||||
qobject_decref(obj);
|
||||
}
|
||||
|
||||
static void test_visitor_out_enum(TestOutputVisitorData *data,
|
||||
|
@ -138,12 +129,10 @@ static void test_visitor_out_enum(TestOutputVisitorData *data,
|
|||
for (i = 0; i < ENUM_ONE__MAX; i++) {
|
||||
visit_type_EnumOne(data->ov, "unused", &i, &error_abort);
|
||||
|
||||
obj = qmp_output_get_qobject(data->qov);
|
||||
g_assert(obj != NULL);
|
||||
obj = visitor_get(data);
|
||||
g_assert(qobject_type(obj) == QTYPE_QSTRING);
|
||||
g_assert_cmpstr(qstring_get_str(qobject_to_qstring(obj)), ==,
|
||||
EnumOne_lookup[i]);
|
||||
qobject_decref(obj);
|
||||
visitor_reset(data);
|
||||
}
|
||||
}
|
||||
|
@ -176,8 +165,7 @@ static void test_visitor_out_struct(TestOutputVisitorData *data,
|
|||
|
||||
visit_type_TestStruct(data->ov, NULL, &p, &error_abort);
|
||||
|
||||
obj = qmp_output_get_qobject(data->qov);
|
||||
g_assert(obj != NULL);
|
||||
obj = visitor_get(data);
|
||||
g_assert(qobject_type(obj) == QTYPE_QDICT);
|
||||
|
||||
qdict = qobject_to_qdict(obj);
|
||||
|
@ -185,8 +173,6 @@ static void test_visitor_out_struct(TestOutputVisitorData *data,
|
|||
g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, 42);
|
||||
g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, false);
|
||||
g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, "foo");
|
||||
|
||||
QDECREF(qdict);
|
||||
}
|
||||
|
||||
static void test_visitor_out_struct_nested(TestOutputVisitorData *data,
|
||||
|
@ -221,8 +207,7 @@ static void test_visitor_out_struct_nested(TestOutputVisitorData *data,
|
|||
|
||||
visit_type_UserDefTwo(data->ov, "unused", &ud2, &error_abort);
|
||||
|
||||
obj = qmp_output_get_qobject(data->qov);
|
||||
g_assert(obj != NULL);
|
||||
obj = visitor_get(data);
|
||||
g_assert(qobject_type(obj) == QTYPE_QDICT);
|
||||
|
||||
qdict = qobject_to_qdict(obj);
|
||||
|
@ -249,7 +234,6 @@ static void test_visitor_out_struct_nested(TestOutputVisitorData *data,
|
|||
g_assert_cmpint(qdict_get_int(userdef, "integer"), ==, value);
|
||||
g_assert_cmpstr(qdict_get_str(userdef, "string"), ==, string);
|
||||
|
||||
QDECREF(qdict);
|
||||
qapi_free_UserDefTwo(ud2);
|
||||
}
|
||||
|
||||
|
@ -301,8 +285,7 @@ static void test_visitor_out_list(TestOutputVisitorData *data,
|
|||
|
||||
visit_type_TestStructList(data->ov, NULL, &head, &error_abort);
|
||||
|
||||
obj = qmp_output_get_qobject(data->qov);
|
||||
g_assert(obj != NULL);
|
||||
obj = visitor_get(data);
|
||||
g_assert(qobject_type(obj) == QTYPE_QLIST);
|
||||
|
||||
qlist = qobject_to_qlist(obj);
|
||||
|
@ -323,7 +306,6 @@ static void test_visitor_out_list(TestOutputVisitorData *data,
|
|||
}
|
||||
g_assert_cmpint(i, ==, max_items);
|
||||
|
||||
QDECREF(qlist);
|
||||
qapi_free_TestStructList(head);
|
||||
}
|
||||
|
||||
|
@ -367,11 +349,9 @@ static void test_visitor_out_any(TestOutputVisitorData *data,
|
|||
|
||||
qobj = QOBJECT(qint_from_int(-42));
|
||||
visit_type_any(data->ov, NULL, &qobj, &error_abort);
|
||||
obj = qmp_output_get_qobject(data->qov);
|
||||
g_assert(obj != NULL);
|
||||
obj = visitor_get(data);
|
||||
g_assert(qobject_type(obj) == QTYPE_QINT);
|
||||
g_assert_cmpint(qint_get_int(qobject_to_qint(obj)), ==, -42);
|
||||
qobject_decref(obj);
|
||||
qobject_decref(qobj);
|
||||
|
||||
visitor_reset(data);
|
||||
|
@ -382,8 +362,7 @@ static void test_visitor_out_any(TestOutputVisitorData *data,
|
|||
qobj = QOBJECT(qdict);
|
||||
visit_type_any(data->ov, NULL, &qobj, &error_abort);
|
||||
qobject_decref(qobj);
|
||||
obj = qmp_output_get_qobject(data->qov);
|
||||
g_assert(obj != NULL);
|
||||
obj = visitor_get(data);
|
||||
qdict = qobject_to_qdict(obj);
|
||||
g_assert(qdict);
|
||||
qobj = qdict_get(qdict, "integer");
|
||||
|
@ -401,7 +380,6 @@ static void test_visitor_out_any(TestOutputVisitorData *data,
|
|||
qstring = qobject_to_qstring(qobj);
|
||||
g_assert(qstring);
|
||||
g_assert_cmpstr(qstring_get_str(qstring), ==, "foo");
|
||||
qobject_decref(obj);
|
||||
}
|
||||
|
||||
static void test_visitor_out_union_flat(TestOutputVisitorData *data,
|
||||
|
@ -417,7 +395,7 @@ static void test_visitor_out_union_flat(TestOutputVisitorData *data,
|
|||
tmp->u.value1.boolean = true;
|
||||
|
||||
visit_type_UserDefFlatUnion(data->ov, NULL, &tmp, &error_abort);
|
||||
arg = qmp_output_get_qobject(data->qov);
|
||||
arg = visitor_get(data);
|
||||
|
||||
g_assert(qobject_type(arg) == QTYPE_QDICT);
|
||||
qdict = qobject_to_qdict(arg);
|
||||
|
@ -428,7 +406,6 @@ static void test_visitor_out_union_flat(TestOutputVisitorData *data,
|
|||
g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, true);
|
||||
|
||||
qapi_free_UserDefFlatUnion(tmp);
|
||||
QDECREF(qdict);
|
||||
}
|
||||
|
||||
static void test_visitor_out_alternate(TestOutputVisitorData *data,
|
||||
|
@ -443,13 +420,12 @@ static void test_visitor_out_alternate(TestOutputVisitorData *data,
|
|||
tmp->u.i = 42;
|
||||
|
||||
visit_type_UserDefAlternate(data->ov, NULL, &tmp, &error_abort);
|
||||
arg = qmp_output_get_qobject(data->qov);
|
||||
arg = visitor_get(data);
|
||||
|
||||
g_assert(qobject_type(arg) == QTYPE_QINT);
|
||||
g_assert_cmpint(qint_get_int(qobject_to_qint(arg)), ==, 42);
|
||||
|
||||
qapi_free_UserDefAlternate(tmp);
|
||||
qobject_decref(arg);
|
||||
|
||||
visitor_reset(data);
|
||||
tmp = g_new0(UserDefAlternate, 1);
|
||||
|
@ -457,13 +433,12 @@ static void test_visitor_out_alternate(TestOutputVisitorData *data,
|
|||
tmp->u.s = g_strdup("hello");
|
||||
|
||||
visit_type_UserDefAlternate(data->ov, NULL, &tmp, &error_abort);
|
||||
arg = qmp_output_get_qobject(data->qov);
|
||||
arg = visitor_get(data);
|
||||
|
||||
g_assert(qobject_type(arg) == QTYPE_QSTRING);
|
||||
g_assert_cmpstr(qstring_get_str(qobject_to_qstring(arg)), ==, "hello");
|
||||
|
||||
qapi_free_UserDefAlternate(tmp);
|
||||
qobject_decref(arg);
|
||||
|
||||
visitor_reset(data);
|
||||
tmp = g_new0(UserDefAlternate, 1);
|
||||
|
@ -474,7 +449,7 @@ static void test_visitor_out_alternate(TestOutputVisitorData *data,
|
|||
tmp->u.udfu.u.value1.boolean = true;
|
||||
|
||||
visit_type_UserDefAlternate(data->ov, NULL, &tmp, &error_abort);
|
||||
arg = qmp_output_get_qobject(data->qov);
|
||||
arg = visitor_get(data);
|
||||
|
||||
g_assert_cmpint(qobject_type(arg), ==, QTYPE_QDICT);
|
||||
qdict = qobject_to_qdict(arg);
|
||||
|
@ -485,7 +460,6 @@ static void test_visitor_out_alternate(TestOutputVisitorData *data,
|
|||
g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, true);
|
||||
|
||||
qapi_free_UserDefAlternate(tmp);
|
||||
qobject_decref(arg);
|
||||
}
|
||||
|
||||
static void test_visitor_out_null(TestOutputVisitorData *data,
|
||||
|
@ -498,15 +472,14 @@ static void test_visitor_out_null(TestOutputVisitorData *data,
|
|||
visit_start_struct(data->ov, NULL, NULL, 0, &error_abort);
|
||||
visit_type_null(data->ov, "a", &error_abort);
|
||||
visit_check_struct(data->ov, &error_abort);
|
||||
visit_end_struct(data->ov);
|
||||
arg = qmp_output_get_qobject(data->qov);
|
||||
visit_end_struct(data->ov, NULL);
|
||||
arg = visitor_get(data);
|
||||
g_assert(qobject_type(arg) == QTYPE_QDICT);
|
||||
qdict = qobject_to_qdict(arg);
|
||||
g_assert_cmpint(qdict_size(qdict), ==, 1);
|
||||
nil = qdict_get(qdict, "a");
|
||||
g_assert(nil);
|
||||
g_assert(qobject_type(nil) == QTYPE_QNULL);
|
||||
qobject_decref(arg);
|
||||
}
|
||||
|
||||
static void init_native_list(UserDefNativeListUnion *cvalue)
|
||||
|
@ -737,10 +710,9 @@ static void test_native_list(TestOutputVisitorData *data,
|
|||
|
||||
visit_type_UserDefNativeListUnion(data->ov, NULL, &cvalue, &error_abort);
|
||||
|
||||
obj = qmp_output_get_qobject(data->qov);
|
||||
obj = visitor_get(data);
|
||||
check_native_list(obj, cvalue->type);
|
||||
qapi_free_UserDefNativeListUnion(cvalue);
|
||||
qobject_decref(obj);
|
||||
}
|
||||
|
||||
static void test_visitor_out_native_list_int(TestOutputVisitorData *data,
|
||||
|
|
|
@ -20,15 +20,15 @@
|
|||
#include "qapi/qmp/types.h"
|
||||
|
||||
typedef struct TestInputVisitorData {
|
||||
StringInputVisitor *siv;
|
||||
Visitor *v;
|
||||
} TestInputVisitorData;
|
||||
|
||||
static void visitor_input_teardown(TestInputVisitorData *data,
|
||||
const void *unused)
|
||||
{
|
||||
if (data->siv) {
|
||||
string_input_visitor_cleanup(data->siv);
|
||||
data->siv = NULL;
|
||||
if (data->v) {
|
||||
visit_free(data->v);
|
||||
data->v = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,15 +39,9 @@ static
|
|||
Visitor *visitor_input_test_init(TestInputVisitorData *data,
|
||||
const char *string)
|
||||
{
|
||||
Visitor *v;
|
||||
|
||||
data->siv = string_input_visitor_new(string);
|
||||
g_assert(data->siv != NULL);
|
||||
|
||||
v = string_input_get_visitor(data->siv);
|
||||
g_assert(v != NULL);
|
||||
|
||||
return v;
|
||||
data->v = string_input_visitor_new(string);
|
||||
g_assert(data->v);
|
||||
return data->v;
|
||||
}
|
||||
|
||||
static void test_visitor_in_int(TestInputVisitorData *data,
|
||||
|
@ -199,8 +193,6 @@ static void test_visitor_in_enum(TestInputVisitorData *data,
|
|||
|
||||
visitor_input_teardown(data, NULL);
|
||||
}
|
||||
|
||||
data->siv = NULL;
|
||||
}
|
||||
|
||||
/* Try to crash the visitors */
|
||||
|
|
|
@ -20,39 +20,53 @@
|
|||
#include "qapi/qmp/types.h"
|
||||
|
||||
typedef struct TestOutputVisitorData {
|
||||
StringOutputVisitor *sov;
|
||||
Visitor *ov;
|
||||
char *str;
|
||||
bool human;
|
||||
} TestOutputVisitorData;
|
||||
|
||||
static void visitor_output_setup_internal(TestOutputVisitorData *data,
|
||||
bool human)
|
||||
{
|
||||
data->human = human;
|
||||
data->ov = string_output_visitor_new(human, &data->str);
|
||||
g_assert(data->ov);
|
||||
}
|
||||
|
||||
static void visitor_output_setup(TestOutputVisitorData *data,
|
||||
const void *unused)
|
||||
{
|
||||
data->human = false;
|
||||
data->sov = string_output_visitor_new(data->human);
|
||||
g_assert(data->sov != NULL);
|
||||
|
||||
data->ov = string_output_get_visitor(data->sov);
|
||||
g_assert(data->ov != NULL);
|
||||
return visitor_output_setup_internal(data, false);
|
||||
}
|
||||
|
||||
static void visitor_output_setup_human(TestOutputVisitorData *data,
|
||||
const void *unused)
|
||||
{
|
||||
data->human = true;
|
||||
data->sov = string_output_visitor_new(data->human);
|
||||
g_assert(data->sov != NULL);
|
||||
|
||||
data->ov = string_output_get_visitor(data->sov);
|
||||
g_assert(data->ov != NULL);
|
||||
return visitor_output_setup_internal(data, true);
|
||||
}
|
||||
|
||||
static void visitor_output_teardown(TestOutputVisitorData *data,
|
||||
const void *unused)
|
||||
{
|
||||
string_output_visitor_cleanup(data->sov);
|
||||
data->sov = NULL;
|
||||
visit_free(data->ov);
|
||||
data->ov = NULL;
|
||||
g_free(data->str);
|
||||
data->str = NULL;
|
||||
}
|
||||
|
||||
static char *visitor_get(TestOutputVisitorData *data)
|
||||
{
|
||||
visit_complete(data->ov, &data->str);
|
||||
g_assert(data->str);
|
||||
return data->str;
|
||||
}
|
||||
|
||||
static void visitor_reset(TestOutputVisitorData *data)
|
||||
{
|
||||
bool human = data->human;
|
||||
|
||||
visitor_output_teardown(data, NULL);
|
||||
visitor_output_setup_internal(data, human);
|
||||
}
|
||||
|
||||
static void test_visitor_out_int(TestOutputVisitorData *data,
|
||||
|
@ -65,14 +79,12 @@ static void test_visitor_out_int(TestOutputVisitorData *data,
|
|||
visit_type_int(data->ov, NULL, &value, &err);
|
||||
g_assert(!err);
|
||||
|
||||
str = string_output_get_string(data->sov);
|
||||
g_assert(str != NULL);
|
||||
str = visitor_get(data);
|
||||
if (data->human) {
|
||||
g_assert_cmpstr(str, ==, "42 (0x2a)");
|
||||
} else {
|
||||
g_assert_cmpstr(str, ==, "42");
|
||||
}
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
static void test_visitor_out_intList(TestOutputVisitorData *data,
|
||||
|
@ -94,8 +106,7 @@ static void test_visitor_out_intList(TestOutputVisitorData *data,
|
|||
visit_type_intList(data->ov, NULL, &list, &err);
|
||||
g_assert(err == NULL);
|
||||
|
||||
str = string_output_get_string(data->sov);
|
||||
g_assert(str != NULL);
|
||||
str = visitor_get(data);
|
||||
if (data->human) {
|
||||
g_assert_cmpstr(str, ==,
|
||||
"0-1,3-6,9-16,21-22,9223372036854775806-9223372036854775807 "
|
||||
|
@ -105,13 +116,7 @@ static void test_visitor_out_intList(TestOutputVisitorData *data,
|
|||
g_assert_cmpstr(str, ==,
|
||||
"0-1,3-6,9-16,21-22,9223372036854775806-9223372036854775807");
|
||||
}
|
||||
g_free(str);
|
||||
while (list) {
|
||||
intList *tmp2;
|
||||
tmp2 = list->next;
|
||||
g_free(list);
|
||||
list = tmp2;
|
||||
}
|
||||
qapi_free_intList(list);
|
||||
}
|
||||
|
||||
static void test_visitor_out_bool(TestOutputVisitorData *data,
|
||||
|
@ -124,10 +129,8 @@ static void test_visitor_out_bool(TestOutputVisitorData *data,
|
|||
visit_type_bool(data->ov, NULL, &value, &err);
|
||||
g_assert(!err);
|
||||
|
||||
str = string_output_get_string(data->sov);
|
||||
g_assert(str != NULL);
|
||||
str = visitor_get(data);
|
||||
g_assert_cmpstr(str, ==, "true");
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
static void test_visitor_out_number(TestOutputVisitorData *data,
|
||||
|
@ -140,10 +143,8 @@ static void test_visitor_out_number(TestOutputVisitorData *data,
|
|||
visit_type_number(data->ov, NULL, &value, &err);
|
||||
g_assert(!err);
|
||||
|
||||
str = string_output_get_string(data->sov);
|
||||
g_assert(str != NULL);
|
||||
str = visitor_get(data);
|
||||
g_assert_cmpstr(str, ==, "3.140000");
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
static void test_visitor_out_string(TestOutputVisitorData *data,
|
||||
|
@ -157,61 +158,50 @@ static void test_visitor_out_string(TestOutputVisitorData *data,
|
|||
visit_type_str(data->ov, NULL, &string, &err);
|
||||
g_assert(!err);
|
||||
|
||||
str = string_output_get_string(data->sov);
|
||||
g_assert(str != NULL);
|
||||
str = visitor_get(data);
|
||||
if (data->human) {
|
||||
g_assert_cmpstr(str, ==, string_human);
|
||||
} else {
|
||||
g_assert_cmpstr(str, ==, string);
|
||||
}
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
static void test_visitor_out_no_string(TestOutputVisitorData *data,
|
||||
const void *unused)
|
||||
{
|
||||
char *string = NULL;
|
||||
Error *err = NULL;
|
||||
char *str;
|
||||
|
||||
/* A null string should return "" */
|
||||
visit_type_str(data->ov, NULL, &string, &err);
|
||||
g_assert(!err);
|
||||
visit_type_str(data->ov, NULL, &string, &error_abort);
|
||||
|
||||
str = string_output_get_string(data->sov);
|
||||
g_assert(str != NULL);
|
||||
str = visitor_get(data);
|
||||
if (data->human) {
|
||||
g_assert_cmpstr(str, ==, "<null>");
|
||||
} else {
|
||||
g_assert_cmpstr(str, ==, "");
|
||||
}
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
static void test_visitor_out_enum(TestOutputVisitorData *data,
|
||||
const void *unused)
|
||||
{
|
||||
Error *err = NULL;
|
||||
char *str;
|
||||
EnumOne i;
|
||||
|
||||
for (i = 0; i < ENUM_ONE__MAX; i++) {
|
||||
char *str_human;
|
||||
visit_type_EnumOne(data->ov, "unused", &i, &error_abort);
|
||||
|
||||
visit_type_EnumOne(data->ov, "unused", &i, &err);
|
||||
g_assert(!err);
|
||||
|
||||
str_human = g_strdup_printf("\"%s\"", EnumOne_lookup[i]);
|
||||
|
||||
str = string_output_get_string(data->sov);
|
||||
g_assert(str != NULL);
|
||||
str = visitor_get(data);
|
||||
if (data->human) {
|
||||
char *str_human = g_strdup_printf("\"%s\"", EnumOne_lookup[i]);
|
||||
|
||||
g_assert_cmpstr(str, ==, str_human);
|
||||
g_free(str_human);
|
||||
} else {
|
||||
g_assert_cmpstr(str, ==, EnumOne_lookup[i]);
|
||||
}
|
||||
g_free(str_human);
|
||||
g_free(str);
|
||||
visitor_reset(data);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -224,8 +214,7 @@ static void test_visitor_out_enum_errors(TestOutputVisitorData *data,
|
|||
for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) {
|
||||
err = NULL;
|
||||
visit_type_EnumOne(data->ov, "unused", &bad_values[i], &err);
|
||||
g_assert(err);
|
||||
error_free(err);
|
||||
error_free_or_abort(&err);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "test-qapi-visit.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qmp/types.h"
|
||||
#include "qapi/qmp/qjson.h"
|
||||
#include "qapi/qmp-input-visitor.h"
|
||||
#include "qapi/qmp-output-visitor.h"
|
||||
#include "qapi/string-input-visitor.h"
|
||||
|
@ -88,11 +89,11 @@ typedef void (*VisitorFunc)(Visitor *v, void **native, Error **errp);
|
|||
|
||||
static void dealloc_helper(void *native_in, VisitorFunc visit, Error **errp)
|
||||
{
|
||||
QapiDeallocVisitor *qdv = qapi_dealloc_visitor_new();
|
||||
Visitor *v = qapi_dealloc_visitor_new();
|
||||
|
||||
visit(qapi_dealloc_get_visitor(qdv), &native_in, errp);
|
||||
visit(v, &native_in, errp);
|
||||
|
||||
qapi_dealloc_visitor_cleanup(qdv);
|
||||
visit_free(v);
|
||||
}
|
||||
|
||||
static void visit_primitive_type(Visitor *v, void **native, Error **errp)
|
||||
|
@ -1011,8 +1012,9 @@ static PrimitiveType pt_values[] = {
|
|||
/* visitor-specific op implementations */
|
||||
|
||||
typedef struct QmpSerializeData {
|
||||
QmpOutputVisitor *qov;
|
||||
QmpInputVisitor *qiv;
|
||||
Visitor *qov;
|
||||
QObject *obj;
|
||||
Visitor *qiv;
|
||||
} QmpSerializeData;
|
||||
|
||||
static void qmp_serialize(void *native_in, void **datap,
|
||||
|
@ -1020,8 +1022,8 @@ static void qmp_serialize(void *native_in, void **datap,
|
|||
{
|
||||
QmpSerializeData *d = g_malloc0(sizeof(*d));
|
||||
|
||||
d->qov = qmp_output_visitor_new();
|
||||
visit(qmp_output_get_visitor(d->qov), &native_in, errp);
|
||||
d->qov = qmp_output_visitor_new(&d->obj);
|
||||
visit(d->qov, &native_in, errp);
|
||||
*datap = d;
|
||||
}
|
||||
|
||||
|
@ -1032,7 +1034,8 @@ static void qmp_deserialize(void **native_out, void *datap,
|
|||
QString *output_json;
|
||||
QObject *obj_orig, *obj;
|
||||
|
||||
obj_orig = qmp_output_get_qobject(d->qov);
|
||||
visit_complete(d->qov, &d->obj);
|
||||
obj_orig = d->obj;
|
||||
output_json = qobject_to_json(obj_orig);
|
||||
obj = qobject_from_json(qstring_get_str(output_json));
|
||||
|
||||
|
@ -1040,22 +1043,22 @@ static void qmp_deserialize(void **native_out, void *datap,
|
|||
d->qiv = qmp_input_visitor_new(obj, true);
|
||||
qobject_decref(obj_orig);
|
||||
qobject_decref(obj);
|
||||
visit(qmp_input_get_visitor(d->qiv), native_out, errp);
|
||||
visit(d->qiv, native_out, errp);
|
||||
}
|
||||
|
||||
static void qmp_cleanup(void *datap)
|
||||
{
|
||||
QmpSerializeData *d = datap;
|
||||
qmp_output_visitor_cleanup(d->qov);
|
||||
qmp_input_visitor_cleanup(d->qiv);
|
||||
visit_free(d->qov);
|
||||
visit_free(d->qiv);
|
||||
|
||||
g_free(d);
|
||||
}
|
||||
|
||||
typedef struct StringSerializeData {
|
||||
char *string;
|
||||
StringOutputVisitor *sov;
|
||||
StringInputVisitor *siv;
|
||||
Visitor *sov;
|
||||
Visitor *siv;
|
||||
} StringSerializeData;
|
||||
|
||||
static void string_serialize(void *native_in, void **datap,
|
||||
|
@ -1063,8 +1066,8 @@ static void string_serialize(void *native_in, void **datap,
|
|||
{
|
||||
StringSerializeData *d = g_malloc0(sizeof(*d));
|
||||
|
||||
d->sov = string_output_visitor_new(false);
|
||||
visit(string_output_get_visitor(d->sov), &native_in, errp);
|
||||
d->sov = string_output_visitor_new(false, &d->string);
|
||||
visit(d->sov, &native_in, errp);
|
||||
*datap = d;
|
||||
}
|
||||
|
||||
|
@ -1073,17 +1076,17 @@ static void string_deserialize(void **native_out, void *datap,
|
|||
{
|
||||
StringSerializeData *d = datap;
|
||||
|
||||
d->string = string_output_get_string(d->sov);
|
||||
visit_complete(d->sov, &d->string);
|
||||
d->siv = string_input_visitor_new(d->string);
|
||||
visit(string_input_get_visitor(d->siv), native_out, errp);
|
||||
visit(d->siv, native_out, errp);
|
||||
}
|
||||
|
||||
static void string_cleanup(void *datap)
|
||||
{
|
||||
StringSerializeData *d = datap;
|
||||
|
||||
string_output_visitor_cleanup(d->sov);
|
||||
string_input_visitor_cleanup(d->siv);
|
||||
visit_free(d->sov);
|
||||
visit_free(d->siv);
|
||||
g_free(d->string);
|
||||
g_free(d);
|
||||
}
|
||||
|
|
|
@ -1143,33 +1143,6 @@ SocketAddress *socket_remote_address(int fd, Error **errp)
|
|||
return socket_sockaddr_to_address(&ss, sslen, errp);
|
||||
}
|
||||
|
||||
|
||||
void qapi_copy_SocketAddress(SocketAddress **p_dest,
|
||||
SocketAddress *src)
|
||||
{
|
||||
QmpOutputVisitor *qov;
|
||||
QmpInputVisitor *qiv;
|
||||
Visitor *ov, *iv;
|
||||
QObject *obj;
|
||||
|
||||
*p_dest = NULL;
|
||||
|
||||
qov = qmp_output_visitor_new();
|
||||
ov = qmp_output_get_visitor(qov);
|
||||
visit_type_SocketAddress(ov, NULL, &src, &error_abort);
|
||||
obj = qmp_output_get_qobject(qov);
|
||||
qmp_output_visitor_cleanup(qov);
|
||||
if (!obj) {
|
||||
return;
|
||||
}
|
||||
|
||||
qiv = qmp_input_visitor_new(obj, true);
|
||||
iv = qmp_input_get_visitor(qiv);
|
||||
visit_type_SocketAddress(iv, NULL, p_dest, &error_abort);
|
||||
qmp_input_visitor_cleanup(qiv);
|
||||
qobject_decref(obj);
|
||||
}
|
||||
|
||||
char *socket_address_to_string(struct SocketAddress *addr, Error **errp)
|
||||
{
|
||||
char *buf;
|
||||
|
|
Loading…
Reference in New Issue