]> git.proxmox.com Git - mirror_qemu.git/blame - qapi/qmp-output-visitor.c
smbios: Move table build tools into an include file.
[mirror_qemu.git] / qapi / qmp-output-visitor.c
CommitLineData
e4e6aa14
MR
1/*
2 * Core Definitions for QAPI/QMP Command Registry
3 *
08f9541d 4 * Copyright (C) 2012-2016 Red Hat, Inc.
e4e6aa14
MR
5 * Copyright IBM, Corp. 2011
6 *
7 * Authors:
8 * Anthony Liguori <aliguori@us.ibm.com>
9 *
10 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
11 * See the COPYING.LIB file in the top-level directory.
12 *
13 */
14
cbf21151 15#include "qemu/osdep.h"
7b1b5d19
PB
16#include "qapi/qmp-output-visitor.h"
17#include "qapi/visitor-impl.h"
1de7afc9 18#include "qemu/queue.h"
e4e6aa14 19#include "qemu-common.h"
7b1b5d19 20#include "qapi/qmp/types.h"
e4e6aa14
MR
21
22typedef struct QStackEntry
23{
24 QObject *value;
25 QTAILQ_ENTRY(QStackEntry) node;
26} QStackEntry;
27
28typedef QTAILQ_HEAD(QStack, QStackEntry) QStack;
29
30struct QmpOutputVisitor
31{
32 Visitor visitor;
455ba08a
EB
33 QStack stack; /* Stack of containers that haven't yet been finished */
34 QObject *root; /* Root of the output visit */
e4e6aa14
MR
35};
36
37#define qmp_output_add(qov, name, value) \
38 qmp_output_add_obj(qov, name, QOBJECT(value))
39#define qmp_output_push(qov, value) qmp_output_push_obj(qov, QOBJECT(value))
40
41static QmpOutputVisitor *to_qov(Visitor *v)
42{
43 return container_of(v, QmpOutputVisitor, visitor);
44}
45
a8615640 46/* Push @value onto the stack of current QObjects being built */
e4e6aa14
MR
47static void qmp_output_push_obj(QmpOutputVisitor *qov, QObject *value)
48{
7267c094 49 QStackEntry *e = g_malloc0(sizeof(*e));
e4e6aa14 50
455ba08a 51 assert(qov->root);
a8615640 52 assert(value);
e4e6aa14
MR
53 e->value = value;
54 QTAILQ_INSERT_HEAD(&qov->stack, e, node);
55}
56
a8615640 57/* Pop a value off the stack of QObjects being built, and return it. */
e4e6aa14
MR
58static QObject *qmp_output_pop(QmpOutputVisitor *qov)
59{
60 QStackEntry *e = QTAILQ_FIRST(&qov->stack);
61 QObject *value;
a8615640
EB
62
63 assert(e);
e4e6aa14
MR
64 QTAILQ_REMOVE(&qov->stack, e, node);
65 value = e->value;
a8615640 66 assert(value);
7267c094 67 g_free(e);
e4e6aa14
MR
68 return value;
69}
70
a8615640
EB
71/* Add @value to the current QObject being built.
72 * If the stack is visiting a dictionary or list, @value is now owned
73 * by that container. Otherwise, @value is now the root. */
e4e6aa14
MR
74static void qmp_output_add_obj(QmpOutputVisitor *qov, const char *name,
75 QObject *value)
76{
455ba08a
EB
77 QStackEntry *e = QTAILQ_FIRST(&qov->stack);
78 QObject *cur = e ? e->value : NULL;
e4e6aa14 79
455ba08a 80 if (!cur) {
56a6f02b
EB
81 /* Don't allow reuse of visitor on more than one root */
82 assert(!qov->root);
455ba08a
EB
83 qov->root = value;
84 } else {
85 switch (qobject_type(cur)) {
86 case QTYPE_QDICT:
87 assert(name);
88 qdict_put_obj(qobject_to_qdict(cur), name, value);
89 break;
90 case QTYPE_QLIST:
56a6f02b 91 assert(!name);
455ba08a
EB
92 qlist_append_obj(qobject_to_qlist(cur), value);
93 break;
94 default:
95 g_assert_not_reached();
96 }
e4e6aa14
MR
97 }
98}
99
0b2a0d6b 100static void qmp_output_start_struct(Visitor *v, const char *name, void **obj,
337283df 101 size_t unused, Error **errp)
e4e6aa14
MR
102{
103 QmpOutputVisitor *qov = to_qov(v);
104 QDict *dict = qdict_new();
105
106 qmp_output_add(qov, name, dict);
107 qmp_output_push(qov, dict);
108}
109
15c2f669 110static void qmp_output_end_struct(Visitor *v)
e4e6aa14
MR
111{
112 QmpOutputVisitor *qov = to_qov(v);
56a6f02b
EB
113 QObject *value = qmp_output_pop(qov);
114 assert(qobject_type(value) == QTYPE_QDICT);
e4e6aa14
MR
115}
116
d9f62dde
EB
117static void qmp_output_start_list(Visitor *v, const char *name,
118 GenericList **listp, size_t size,
119 Error **errp)
e4e6aa14
MR
120{
121 QmpOutputVisitor *qov = to_qov(v);
122 QList *list = qlist_new();
123
124 qmp_output_add(qov, name, list);
125 qmp_output_push(qov, list);
126}
127
d9f62dde 128static GenericList *qmp_output_next_list(Visitor *v, GenericList *tail,
e65d89bf 129 size_t size)
e4e6aa14 130{
d9f62dde 131 return tail->next;
e4e6aa14
MR
132}
133
08f9541d 134static void qmp_output_end_list(Visitor *v)
e4e6aa14
MR
135{
136 QmpOutputVisitor *qov = to_qov(v);
56a6f02b
EB
137 QObject *value = qmp_output_pop(qov);
138 assert(qobject_type(value) == QTYPE_QLIST);
e4e6aa14
MR
139}
140
0b2a0d6b 141static void qmp_output_type_int64(Visitor *v, const char *name, int64_t *obj,
4c40314a 142 Error **errp)
e4e6aa14
MR
143{
144 QmpOutputVisitor *qov = to_qov(v);
145 qmp_output_add(qov, name, qint_from_int(*obj));
146}
147
0b2a0d6b 148static void qmp_output_type_uint64(Visitor *v, const char *name, uint64_t *obj,
f755dea7
EB
149 Error **errp)
150{
151 /* FIXME: QMP outputs values larger than INT64_MAX as negative */
152 QmpOutputVisitor *qov = to_qov(v);
153 qmp_output_add(qov, name, qint_from_int(*obj));
154}
155
0b2a0d6b 156static void qmp_output_type_bool(Visitor *v, const char *name, bool *obj,
e4e6aa14
MR
157 Error **errp)
158{
159 QmpOutputVisitor *qov = to_qov(v);
fc48ffc3 160 qmp_output_add(qov, name, qbool_from_bool(*obj));
e4e6aa14
MR
161}
162
0b2a0d6b 163static void qmp_output_type_str(Visitor *v, const char *name, char **obj,
e4e6aa14
MR
164 Error **errp)
165{
166 QmpOutputVisitor *qov = to_qov(v);
167 if (*obj) {
168 qmp_output_add(qov, name, qstring_from_str(*obj));
169 } else {
170 qmp_output_add(qov, name, qstring_from_str(""));
171 }
172}
173
0b2a0d6b 174static void qmp_output_type_number(Visitor *v, const char *name, double *obj,
e4e6aa14
MR
175 Error **errp)
176{
177 QmpOutputVisitor *qov = to_qov(v);
178 qmp_output_add(qov, name, qfloat_from_double(*obj));
179}
180
0b2a0d6b 181static void qmp_output_type_any(Visitor *v, const char *name, QObject **obj,
28770e05
MA
182 Error **errp)
183{
184 QmpOutputVisitor *qov = to_qov(v);
185 qobject_incref(*obj);
186 qmp_output_add_obj(qov, name, *obj);
187}
188
3bc97fd5
EB
189static void qmp_output_type_null(Visitor *v, const char *name, Error **errp)
190{
3df016f1
EB
191 QmpOutputVisitor *qov = to_qov(v);
192 qmp_output_add_obj(qov, name, qnull());
3bc97fd5
EB
193}
194
56a6f02b
EB
195/* Finish building, and return the root object.
196 * The root object is never null. The caller becomes the object's
197 * owner, and should use qobject_decref() when done with it. */
e4e6aa14
MR
198QObject *qmp_output_get_qobject(QmpOutputVisitor *qov)
199{
56a6f02b
EB
200 /* A visit must have occurred, with each start paired with end. */
201 assert(qov->root && QTAILQ_EMPTY(&qov->stack));
202
203 qobject_incref(qov->root);
204 return qov->root;
e4e6aa14
MR
205}
206
207Visitor *qmp_output_get_visitor(QmpOutputVisitor *v)
208{
209 return &v->visitor;
210}
211
212void qmp_output_visitor_cleanup(QmpOutputVisitor *v)
213{
214 QStackEntry *e, *tmp;
215
216 QTAILQ_FOREACH_SAFE(e, &v->stack, node, tmp) {
217 QTAILQ_REMOVE(&v->stack, e, node);
7267c094 218 g_free(e);
e4e6aa14
MR
219 }
220
455ba08a 221 qobject_decref(v->root);
7267c094 222 g_free(v);
e4e6aa14
MR
223}
224
225QmpOutputVisitor *qmp_output_visitor_new(void)
226{
227 QmpOutputVisitor *v;
228
7267c094 229 v = g_malloc0(sizeof(*v));
e4e6aa14 230
983f52d4 231 v->visitor.type = VISITOR_OUTPUT;
e4e6aa14
MR
232 v->visitor.start_struct = qmp_output_start_struct;
233 v->visitor.end_struct = qmp_output_end_struct;
234 v->visitor.start_list = qmp_output_start_list;
235 v->visitor.next_list = qmp_output_next_list;
236 v->visitor.end_list = qmp_output_end_list;
4c40314a 237 v->visitor.type_int64 = qmp_output_type_int64;
f755dea7 238 v->visitor.type_uint64 = qmp_output_type_uint64;
e4e6aa14
MR
239 v->visitor.type_bool = qmp_output_type_bool;
240 v->visitor.type_str = qmp_output_type_str;
241 v->visitor.type_number = qmp_output_type_number;
28770e05 242 v->visitor.type_any = qmp_output_type_any;
3bc97fd5 243 v->visitor.type_null = qmp_output_type_null;
e4e6aa14
MR
244
245 QTAILQ_INIT(&v->stack);
246
247 return v;
248}