2 * Core Definitions for QAPI/QMP Command Registry
4 * Copyright (C) 2012-2016 Red Hat, Inc.
5 * Copyright IBM, Corp. 2011
8 * Anthony Liguori <aliguori@us.ibm.com>
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.
15 #include "qemu/osdep.h"
16 #include "qapi/qmp-output-visitor.h"
17 #include "qapi/visitor-impl.h"
18 #include "qemu/queue.h"
19 #include "qemu-common.h"
20 #include "qapi/qmp/types.h"
22 typedef struct QStackEntry
26 QTAILQ_ENTRY(QStackEntry
) node
;
29 typedef QTAILQ_HEAD(QStack
, QStackEntry
) QStack
;
31 struct QmpOutputVisitor
34 QStack stack
; /* Stack of containers that haven't yet been finished */
35 QObject
*root
; /* Root of the output visit */
38 #define qmp_output_add(qov, name, value) \
39 qmp_output_add_obj(qov, name, QOBJECT(value))
40 #define qmp_output_push(qov, value) qmp_output_push_obj(qov, QOBJECT(value))
42 static QmpOutputVisitor
*to_qov(Visitor
*v
)
44 return container_of(v
, QmpOutputVisitor
, visitor
);
47 /* Push @value onto the stack of current QObjects being built */
48 static void qmp_output_push_obj(QmpOutputVisitor
*qov
, QObject
*value
)
50 QStackEntry
*e
= g_malloc0(sizeof(*e
));
55 if (qobject_type(e
->value
) == QTYPE_QLIST
) {
56 e
->is_list_head
= true;
58 QTAILQ_INSERT_HEAD(&qov
->stack
, e
, node
);
61 /* Pop a value off the stack of QObjects being built, and return it. */
62 static QObject
*qmp_output_pop(QmpOutputVisitor
*qov
)
64 QStackEntry
*e
= QTAILQ_FIRST(&qov
->stack
);
68 QTAILQ_REMOVE(&qov
->stack
, e
, node
);
75 /* Add @value to the current QObject being built.
76 * If the stack is visiting a dictionary or list, @value is now owned
77 * by that container. Otherwise, @value is now the root. */
78 static void qmp_output_add_obj(QmpOutputVisitor
*qov
, const char *name
,
81 QStackEntry
*e
= QTAILQ_FIRST(&qov
->stack
);
82 QObject
*cur
= e
? e
->value
: NULL
;
85 /* Don't allow reuse of visitor on more than one root */
89 switch (qobject_type(cur
)) {
92 qdict_put_obj(qobject_to_qdict(cur
), name
, value
);
96 qlist_append_obj(qobject_to_qlist(cur
), value
);
99 g_assert_not_reached();
104 static void qmp_output_start_struct(Visitor
*v
, const char *name
, void **obj
,
105 size_t unused
, Error
**errp
)
107 QmpOutputVisitor
*qov
= to_qov(v
);
108 QDict
*dict
= qdict_new();
110 qmp_output_add(qov
, name
, dict
);
111 qmp_output_push(qov
, dict
);
114 static void qmp_output_end_struct(Visitor
*v
, Error
**errp
)
116 QmpOutputVisitor
*qov
= to_qov(v
);
117 QObject
*value
= qmp_output_pop(qov
);
118 assert(qobject_type(value
) == QTYPE_QDICT
);
121 static void qmp_output_start_list(Visitor
*v
, const char *name
, Error
**errp
)
123 QmpOutputVisitor
*qov
= to_qov(v
);
124 QList
*list
= qlist_new();
126 qmp_output_add(qov
, name
, list
);
127 qmp_output_push(qov
, list
);
130 static GenericList
*qmp_output_next_list(Visitor
*v
, GenericList
**listp
,
133 GenericList
*list
= *listp
;
134 QmpOutputVisitor
*qov
= to_qov(v
);
135 QStackEntry
*e
= QTAILQ_FIRST(&qov
->stack
);
138 if (e
->is_list_head
) {
139 e
->is_list_head
= false;
143 return list
? list
->next
: NULL
;
146 static void qmp_output_end_list(Visitor
*v
)
148 QmpOutputVisitor
*qov
= to_qov(v
);
149 QObject
*value
= qmp_output_pop(qov
);
150 assert(qobject_type(value
) == QTYPE_QLIST
);
153 static void qmp_output_type_int64(Visitor
*v
, const char *name
, int64_t *obj
,
156 QmpOutputVisitor
*qov
= to_qov(v
);
157 qmp_output_add(qov
, name
, qint_from_int(*obj
));
160 static void qmp_output_type_uint64(Visitor
*v
, const char *name
, uint64_t *obj
,
163 /* FIXME: QMP outputs values larger than INT64_MAX as negative */
164 QmpOutputVisitor
*qov
= to_qov(v
);
165 qmp_output_add(qov
, name
, qint_from_int(*obj
));
168 static void qmp_output_type_bool(Visitor
*v
, const char *name
, bool *obj
,
171 QmpOutputVisitor
*qov
= to_qov(v
);
172 qmp_output_add(qov
, name
, qbool_from_bool(*obj
));
175 static void qmp_output_type_str(Visitor
*v
, const char *name
, char **obj
,
178 QmpOutputVisitor
*qov
= to_qov(v
);
180 qmp_output_add(qov
, name
, qstring_from_str(*obj
));
182 qmp_output_add(qov
, name
, qstring_from_str(""));
186 static void qmp_output_type_number(Visitor
*v
, const char *name
, double *obj
,
189 QmpOutputVisitor
*qov
= to_qov(v
);
190 qmp_output_add(qov
, name
, qfloat_from_double(*obj
));
193 static void qmp_output_type_any(Visitor
*v
, const char *name
, QObject
**obj
,
196 QmpOutputVisitor
*qov
= to_qov(v
);
197 qobject_incref(*obj
);
198 qmp_output_add_obj(qov
, name
, *obj
);
201 static void qmp_output_type_null(Visitor
*v
, const char *name
, Error
**errp
)
203 QmpOutputVisitor
*qov
= to_qov(v
);
204 qmp_output_add_obj(qov
, name
, qnull());
207 /* Finish building, and return the root object.
208 * The root object is never null. The caller becomes the object's
209 * owner, and should use qobject_decref() when done with it. */
210 QObject
*qmp_output_get_qobject(QmpOutputVisitor
*qov
)
212 /* A visit must have occurred, with each start paired with end. */
213 assert(qov
->root
&& QTAILQ_EMPTY(&qov
->stack
));
215 qobject_incref(qov
->root
);
219 Visitor
*qmp_output_get_visitor(QmpOutputVisitor
*v
)
224 void qmp_output_visitor_cleanup(QmpOutputVisitor
*v
)
226 QStackEntry
*e
, *tmp
;
228 QTAILQ_FOREACH_SAFE(e
, &v
->stack
, node
, tmp
) {
229 QTAILQ_REMOVE(&v
->stack
, e
, node
);
233 qobject_decref(v
->root
);
237 QmpOutputVisitor
*qmp_output_visitor_new(void)
241 v
= g_malloc0(sizeof(*v
));
243 v
->visitor
.type
= VISITOR_OUTPUT
;
244 v
->visitor
.start_struct
= qmp_output_start_struct
;
245 v
->visitor
.end_struct
= qmp_output_end_struct
;
246 v
->visitor
.start_list
= qmp_output_start_list
;
247 v
->visitor
.next_list
= qmp_output_next_list
;
248 v
->visitor
.end_list
= qmp_output_end_list
;
249 v
->visitor
.type_int64
= qmp_output_type_int64
;
250 v
->visitor
.type_uint64
= qmp_output_type_uint64
;
251 v
->visitor
.type_bool
= qmp_output_type_bool
;
252 v
->visitor
.type_str
= qmp_output_type_str
;
253 v
->visitor
.type_number
= qmp_output_type_number
;
254 v
->visitor
.type_any
= qmp_output_type_any
;
255 v
->visitor
.type_null
= qmp_output_type_null
;
257 QTAILQ_INIT(&v
->stack
);