]> Git Repo - qemu.git/blob - qapi/qmp-output-visitor.c
Merge remote-tracking branch 'remotes/lalrae/tags/mips-20160513' into staging
[qemu.git] / qapi / qmp-output-visitor.c
1 /*
2  * Core Definitions for QAPI/QMP Command Registry
3  *
4  * Copyright (C) 2012-2016 Red Hat, Inc.
5  * Copyright IBM, Corp. 2011
6  *
7  * Authors:
8  *  Anthony Liguori   <[email protected]>
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
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"
21
22 typedef struct QStackEntry
23 {
24     QObject *value;
25     QTAILQ_ENTRY(QStackEntry) node;
26 } QStackEntry;
27
28 typedef QTAILQ_HEAD(QStack, QStackEntry) QStack;
29
30 struct QmpOutputVisitor
31 {
32     Visitor visitor;
33     QStack stack; /* Stack of containers that haven't yet been finished */
34     QObject *root; /* Root of the output visit */
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
41 static QmpOutputVisitor *to_qov(Visitor *v)
42 {
43     return container_of(v, QmpOutputVisitor, visitor);
44 }
45
46 /* Push @value onto the stack of current QObjects being built */
47 static void qmp_output_push_obj(QmpOutputVisitor *qov, QObject *value)
48 {
49     QStackEntry *e = g_malloc0(sizeof(*e));
50
51     assert(qov->root);
52     assert(value);
53     e->value = value;
54     QTAILQ_INSERT_HEAD(&qov->stack, e, node);
55 }
56
57 /* Pop a value off the stack of QObjects being built, and return it. */
58 static QObject *qmp_output_pop(QmpOutputVisitor *qov)
59 {
60     QStackEntry *e = QTAILQ_FIRST(&qov->stack);
61     QObject *value;
62
63     assert(e);
64     QTAILQ_REMOVE(&qov->stack, e, node);
65     value = e->value;
66     assert(value);
67     g_free(e);
68     return value;
69 }
70
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.  */
74 static void qmp_output_add_obj(QmpOutputVisitor *qov, const char *name,
75                                QObject *value)
76 {
77     QStackEntry *e = QTAILQ_FIRST(&qov->stack);
78     QObject *cur = e ? e->value : NULL;
79
80     if (!cur) {
81         /* Don't allow reuse of visitor on more than one root */
82         assert(!qov->root);
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:
91             assert(!name);
92             qlist_append_obj(qobject_to_qlist(cur), value);
93             break;
94         default:
95             g_assert_not_reached();
96         }
97     }
98 }
99
100 static void qmp_output_start_struct(Visitor *v, const char *name, void **obj,
101                                     size_t unused, Error **errp)
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
110 static void qmp_output_end_struct(Visitor *v)
111 {
112     QmpOutputVisitor *qov = to_qov(v);
113     QObject *value = qmp_output_pop(qov);
114     assert(qobject_type(value) == QTYPE_QDICT);
115 }
116
117 static void qmp_output_start_list(Visitor *v, const char *name,
118                                   GenericList **listp, size_t size,
119                                   Error **errp)
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
128 static GenericList *qmp_output_next_list(Visitor *v, GenericList *tail,
129                                          size_t size)
130 {
131     return tail->next;
132 }
133
134 static void qmp_output_end_list(Visitor *v)
135 {
136     QmpOutputVisitor *qov = to_qov(v);
137     QObject *value = qmp_output_pop(qov);
138     assert(qobject_type(value) == QTYPE_QLIST);
139 }
140
141 static void qmp_output_type_int64(Visitor *v, const char *name, int64_t *obj,
142                                   Error **errp)
143 {
144     QmpOutputVisitor *qov = to_qov(v);
145     qmp_output_add(qov, name, qint_from_int(*obj));
146 }
147
148 static void qmp_output_type_uint64(Visitor *v, const char *name, uint64_t *obj,
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
156 static void qmp_output_type_bool(Visitor *v, const char *name, bool *obj,
157                                  Error **errp)
158 {
159     QmpOutputVisitor *qov = to_qov(v);
160     qmp_output_add(qov, name, qbool_from_bool(*obj));
161 }
162
163 static void qmp_output_type_str(Visitor *v, const char *name, char **obj,
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
174 static void qmp_output_type_number(Visitor *v, const char *name, double *obj,
175                                    Error **errp)
176 {
177     QmpOutputVisitor *qov = to_qov(v);
178     qmp_output_add(qov, name, qfloat_from_double(*obj));
179 }
180
181 static void qmp_output_type_any(Visitor *v, const char *name, QObject **obj,
182                                 Error **errp)
183 {
184     QmpOutputVisitor *qov = to_qov(v);
185     qobject_incref(*obj);
186     qmp_output_add_obj(qov, name, *obj);
187 }
188
189 static void qmp_output_type_null(Visitor *v, const char *name, Error **errp)
190 {
191     QmpOutputVisitor *qov = to_qov(v);
192     qmp_output_add_obj(qov, name, qnull());
193 }
194
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.  */
198 QObject *qmp_output_get_qobject(QmpOutputVisitor *qov)
199 {
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;
205 }
206
207 Visitor *qmp_output_get_visitor(QmpOutputVisitor *v)
208 {
209     return &v->visitor;
210 }
211
212 void 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);
218         g_free(e);
219     }
220
221     qobject_decref(v->root);
222     g_free(v);
223 }
224
225 QmpOutputVisitor *qmp_output_visitor_new(void)
226 {
227     QmpOutputVisitor *v;
228
229     v = g_malloc0(sizeof(*v));
230
231     v->visitor.type = VISITOR_OUTPUT;
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;
237     v->visitor.type_int64 = qmp_output_type_int64;
238     v->visitor.type_uint64 = qmp_output_type_uint64;
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;
242     v->visitor.type_any = qmp_output_type_any;
243     v->visitor.type_null = qmp_output_type_null;
244
245     QTAILQ_INIT(&v->stack);
246
247     return v;
248 }
This page took 0.037112 seconds and 4 git commands to generate.