1
2
3
4
5
6
7
8
9
10
11
12
13
14#include "qapi/qmp-output-visitor.h"
15#include "qapi/visitor-impl.h"
16#include "qemu/queue.h"
17#include "qemu-common.h"
18#include "qapi/qmp/types.h"
19
20typedef struct QStackEntry
21{
22 QObject *value;
23 bool is_list_head;
24 QTAILQ_ENTRY(QStackEntry) node;
25} QStackEntry;
26
27typedef QTAILQ_HEAD(QStack, QStackEntry) QStack;
28
29struct QmpOutputVisitor
30{
31 Visitor visitor;
32
33
34
35
36
37
38
39
40
41 QStack stack;
42};
43
44#define qmp_output_add(qov, name, value) \
45 qmp_output_add_obj(qov, name, QOBJECT(value))
46#define qmp_output_push(qov, value) qmp_output_push_obj(qov, QOBJECT(value))
47
48static QmpOutputVisitor *to_qov(Visitor *v)
49{
50 return container_of(v, QmpOutputVisitor, visitor);
51}
52
53
54static void qmp_output_push_obj(QmpOutputVisitor *qov, QObject *value)
55{
56 QStackEntry *e = g_malloc0(sizeof(*e));
57
58 assert(value);
59 e->value = value;
60 if (qobject_type(e->value) == QTYPE_QLIST) {
61 e->is_list_head = true;
62 }
63 QTAILQ_INSERT_HEAD(&qov->stack, e, node);
64}
65
66
67static QObject *qmp_output_pop(QmpOutputVisitor *qov)
68{
69 QStackEntry *e = QTAILQ_FIRST(&qov->stack);
70 QObject *value;
71
72 assert(e);
73 QTAILQ_REMOVE(&qov->stack, e, node);
74 value = e->value;
75 assert(value);
76 g_free(e);
77 return value;
78}
79
80
81static QObject *qmp_output_first(QmpOutputVisitor *qov)
82{
83 QStackEntry *e = QTAILQ_LAST(&qov->stack, QStack);
84
85 if (!e) {
86
87 return NULL;
88 }
89 assert(e->value);
90 return e->value;
91}
92
93
94
95static QObject *qmp_output_last(QmpOutputVisitor *qov)
96{
97 QStackEntry *e = QTAILQ_FIRST(&qov->stack);
98
99 assert(e && e->value);
100 return e->value;
101}
102
103
104
105
106static void qmp_output_add_obj(QmpOutputVisitor *qov, const char *name,
107 QObject *value)
108{
109 QObject *cur;
110
111 if (QTAILQ_EMPTY(&qov->stack)) {
112
113 qmp_output_push_obj(qov, value);
114 return;
115 }
116
117 cur = qmp_output_last(qov);
118
119 switch (qobject_type(cur)) {
120 case QTYPE_QDICT:
121 assert(name);
122 qdict_put_obj(qobject_to_qdict(cur), name, value);
123 break;
124 case QTYPE_QLIST:
125 qlist_append_obj(qobject_to_qlist(cur), value);
126 break;
127 default:
128
129
130 qobject_decref(qmp_output_pop(qov));
131 assert(QTAILQ_EMPTY(&qov->stack));
132 qmp_output_push_obj(qov, value);
133 break;
134 }
135}
136
137static void qmp_output_start_struct(Visitor *v, void **obj, const char *kind,
138 const char *name, size_t unused,
139 Error **errp)
140{
141 QmpOutputVisitor *qov = to_qov(v);
142 QDict *dict = qdict_new();
143
144 qmp_output_add(qov, name, dict);
145 qmp_output_push(qov, dict);
146}
147
148static void qmp_output_end_struct(Visitor *v, Error **errp)
149{
150 QmpOutputVisitor *qov = to_qov(v);
151 qmp_output_pop(qov);
152}
153
154static void qmp_output_start_list(Visitor *v, const char *name, Error **errp)
155{
156 QmpOutputVisitor *qov = to_qov(v);
157 QList *list = qlist_new();
158
159 qmp_output_add(qov, name, list);
160 qmp_output_push(qov, list);
161}
162
163static GenericList *qmp_output_next_list(Visitor *v, GenericList **listp,
164 Error **errp)
165{
166 GenericList *list = *listp;
167 QmpOutputVisitor *qov = to_qov(v);
168 QStackEntry *e = QTAILQ_FIRST(&qov->stack);
169
170 assert(e);
171 if (e->is_list_head) {
172 e->is_list_head = false;
173 return list;
174 }
175
176 return list ? list->next : NULL;
177}
178
179static void qmp_output_end_list(Visitor *v, Error **errp)
180{
181 QmpOutputVisitor *qov = to_qov(v);
182 qmp_output_pop(qov);
183}
184
185static void qmp_output_type_int(Visitor *v, int64_t *obj, const char *name,
186 Error **errp)
187{
188 QmpOutputVisitor *qov = to_qov(v);
189 qmp_output_add(qov, name, qint_from_int(*obj));
190}
191
192static void qmp_output_type_bool(Visitor *v, bool *obj, const char *name,
193 Error **errp)
194{
195 QmpOutputVisitor *qov = to_qov(v);
196 qmp_output_add(qov, name, qbool_from_bool(*obj));
197}
198
199static void qmp_output_type_str(Visitor *v, char **obj, const char *name,
200 Error **errp)
201{
202 QmpOutputVisitor *qov = to_qov(v);
203 if (*obj) {
204 qmp_output_add(qov, name, qstring_from_str(*obj));
205 } else {
206 qmp_output_add(qov, name, qstring_from_str(""));
207 }
208}
209
210static void qmp_output_type_number(Visitor *v, double *obj, const char *name,
211 Error **errp)
212{
213 QmpOutputVisitor *qov = to_qov(v);
214 qmp_output_add(qov, name, qfloat_from_double(*obj));
215}
216
217static void qmp_output_type_any(Visitor *v, QObject **obj, const char *name,
218 Error **errp)
219{
220 QmpOutputVisitor *qov = to_qov(v);
221 qobject_incref(*obj);
222 qmp_output_add_obj(qov, name, *obj);
223}
224
225
226QObject *qmp_output_get_qobject(QmpOutputVisitor *qov)
227{
228 QObject *obj = qmp_output_first(qov);
229 if (obj) {
230 qobject_incref(obj);
231 } else {
232 obj = qnull();
233 }
234 return obj;
235}
236
237Visitor *qmp_output_get_visitor(QmpOutputVisitor *v)
238{
239 return &v->visitor;
240}
241
242void qmp_output_visitor_cleanup(QmpOutputVisitor *v)
243{
244 QStackEntry *e, *tmp;
245
246
247
248 QObject *root = QTAILQ_EMPTY(&v->stack) ? NULL : qmp_output_first(v);
249
250 QTAILQ_FOREACH_SAFE(e, &v->stack, node, tmp) {
251 QTAILQ_REMOVE(&v->stack, e, node);
252 g_free(e);
253 }
254
255 qobject_decref(root);
256 g_free(v);
257}
258
259QmpOutputVisitor *qmp_output_visitor_new(void)
260{
261 QmpOutputVisitor *v;
262
263 v = g_malloc0(sizeof(*v));
264
265 v->visitor.start_struct = qmp_output_start_struct;
266 v->visitor.end_struct = qmp_output_end_struct;
267 v->visitor.start_list = qmp_output_start_list;
268 v->visitor.next_list = qmp_output_next_list;
269 v->visitor.end_list = qmp_output_end_list;
270 v->visitor.type_enum = output_type_enum;
271 v->visitor.type_int = qmp_output_type_int;
272 v->visitor.type_bool = qmp_output_type_bool;
273 v->visitor.type_str = qmp_output_type_str;
274 v->visitor.type_number = qmp_output_type_number;
275 v->visitor.type_any = qmp_output_type_any;
276
277 QTAILQ_INIT(&v->stack);
278
279 return v;
280}
281