]>
Commit | Line | Data |
---|---|---|
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" |
b3db211f | 16 | #include "qapi/qobject-output-visitor.h" |
7b1b5d19 | 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 | |
22 | typedef struct QStackEntry | |
23 | { | |
24 | QObject *value; | |
1158bb2a | 25 | void *qapi; /* sanity check that caller uses same pointer */ |
fc76ae8b | 26 | QSLIST_ENTRY(QStackEntry) node; |
e4e6aa14 MR |
27 | } QStackEntry; |
28 | ||
e4e6aa14 MR |
29 | struct QmpOutputVisitor |
30 | { | |
31 | Visitor visitor; | |
fc76ae8b | 32 | QSLIST_HEAD(, QStackEntry) stack; /* Stack of unfinished containers */ |
455ba08a | 33 | QObject *root; /* Root of the output visit */ |
3b098d56 | 34 | QObject **result; /* User's storage location for result */ |
e4e6aa14 MR |
35 | }; |
36 | ||
37 | #define qmp_output_add(qov, name, value) \ | |
38 | qmp_output_add_obj(qov, name, QOBJECT(value)) | |
1158bb2a EB |
39 | #define qmp_output_push(qov, value, qapi) \ |
40 | qmp_output_push_obj(qov, QOBJECT(value), qapi) | |
e4e6aa14 MR |
41 | |
42 | static QmpOutputVisitor *to_qov(Visitor *v) | |
43 | { | |
44 | return container_of(v, QmpOutputVisitor, visitor); | |
45 | } | |
46 | ||
a8615640 | 47 | /* Push @value onto the stack of current QObjects being built */ |
1158bb2a EB |
48 | static void qmp_output_push_obj(QmpOutputVisitor *qov, QObject *value, |
49 | void *qapi) | |
e4e6aa14 | 50 | { |
7267c094 | 51 | QStackEntry *e = g_malloc0(sizeof(*e)); |
e4e6aa14 | 52 | |
455ba08a | 53 | assert(qov->root); |
a8615640 | 54 | assert(value); |
e4e6aa14 | 55 | e->value = value; |
1158bb2a | 56 | e->qapi = qapi; |
fc76ae8b | 57 | QSLIST_INSERT_HEAD(&qov->stack, e, node); |
e4e6aa14 MR |
58 | } |
59 | ||
a8615640 | 60 | /* Pop a value off the stack of QObjects being built, and return it. */ |
1158bb2a | 61 | static QObject *qmp_output_pop(QmpOutputVisitor *qov, void *qapi) |
e4e6aa14 | 62 | { |
fc76ae8b | 63 | QStackEntry *e = QSLIST_FIRST(&qov->stack); |
e4e6aa14 | 64 | QObject *value; |
a8615640 EB |
65 | |
66 | assert(e); | |
1158bb2a | 67 | assert(e->qapi == qapi); |
fc76ae8b | 68 | QSLIST_REMOVE_HEAD(&qov->stack, node); |
e4e6aa14 | 69 | value = e->value; |
a8615640 | 70 | assert(value); |
7267c094 | 71 | g_free(e); |
e4e6aa14 MR |
72 | return value; |
73 | } | |
74 | ||
a8615640 EB |
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. */ | |
e4e6aa14 MR |
78 | static void qmp_output_add_obj(QmpOutputVisitor *qov, const char *name, |
79 | QObject *value) | |
80 | { | |
fc76ae8b | 81 | QStackEntry *e = QSLIST_FIRST(&qov->stack); |
455ba08a | 82 | QObject *cur = e ? e->value : NULL; |
e4e6aa14 | 83 | |
455ba08a | 84 | if (!cur) { |
56a6f02b EB |
85 | /* Don't allow reuse of visitor on more than one root */ |
86 | assert(!qov->root); | |
455ba08a EB |
87 | qov->root = value; |
88 | } else { | |
89 | switch (qobject_type(cur)) { | |
90 | case QTYPE_QDICT: | |
91 | assert(name); | |
92 | qdict_put_obj(qobject_to_qdict(cur), name, value); | |
93 | break; | |
94 | case QTYPE_QLIST: | |
56a6f02b | 95 | assert(!name); |
455ba08a EB |
96 | qlist_append_obj(qobject_to_qlist(cur), value); |
97 | break; | |
98 | default: | |
99 | g_assert_not_reached(); | |
100 | } | |
e4e6aa14 MR |
101 | } |
102 | } | |
103 | ||
0b2a0d6b | 104 | static void qmp_output_start_struct(Visitor *v, const char *name, void **obj, |
337283df | 105 | size_t unused, Error **errp) |
e4e6aa14 MR |
106 | { |
107 | QmpOutputVisitor *qov = to_qov(v); | |
108 | QDict *dict = qdict_new(); | |
109 | ||
110 | qmp_output_add(qov, name, dict); | |
1158bb2a | 111 | qmp_output_push(qov, dict, obj); |
e4e6aa14 MR |
112 | } |
113 | ||
1158bb2a | 114 | static void qmp_output_end_struct(Visitor *v, void **obj) |
e4e6aa14 MR |
115 | { |
116 | QmpOutputVisitor *qov = to_qov(v); | |
1158bb2a | 117 | QObject *value = qmp_output_pop(qov, obj); |
56a6f02b | 118 | assert(qobject_type(value) == QTYPE_QDICT); |
e4e6aa14 MR |
119 | } |
120 | ||
d9f62dde EB |
121 | static void qmp_output_start_list(Visitor *v, const char *name, |
122 | GenericList **listp, size_t size, | |
123 | Error **errp) | |
e4e6aa14 MR |
124 | { |
125 | QmpOutputVisitor *qov = to_qov(v); | |
126 | QList *list = qlist_new(); | |
127 | ||
128 | qmp_output_add(qov, name, list); | |
1158bb2a | 129 | qmp_output_push(qov, list, listp); |
e4e6aa14 MR |
130 | } |
131 | ||
d9f62dde | 132 | static GenericList *qmp_output_next_list(Visitor *v, GenericList *tail, |
e65d89bf | 133 | size_t size) |
e4e6aa14 | 134 | { |
d9f62dde | 135 | return tail->next; |
e4e6aa14 MR |
136 | } |
137 | ||
1158bb2a | 138 | static void qmp_output_end_list(Visitor *v, void **obj) |
e4e6aa14 MR |
139 | { |
140 | QmpOutputVisitor *qov = to_qov(v); | |
1158bb2a | 141 | QObject *value = qmp_output_pop(qov, obj); |
56a6f02b | 142 | assert(qobject_type(value) == QTYPE_QLIST); |
e4e6aa14 MR |
143 | } |
144 | ||
0b2a0d6b | 145 | static void qmp_output_type_int64(Visitor *v, const char *name, int64_t *obj, |
4c40314a | 146 | Error **errp) |
e4e6aa14 MR |
147 | { |
148 | QmpOutputVisitor *qov = to_qov(v); | |
149 | qmp_output_add(qov, name, qint_from_int(*obj)); | |
150 | } | |
151 | ||
0b2a0d6b | 152 | static void qmp_output_type_uint64(Visitor *v, const char *name, uint64_t *obj, |
f755dea7 EB |
153 | Error **errp) |
154 | { | |
b3db211f | 155 | /* FIXME values larger than INT64_MAX become negative */ |
f755dea7 EB |
156 | QmpOutputVisitor *qov = to_qov(v); |
157 | qmp_output_add(qov, name, qint_from_int(*obj)); | |
158 | } | |
159 | ||
0b2a0d6b | 160 | static void qmp_output_type_bool(Visitor *v, const char *name, bool *obj, |
e4e6aa14 MR |
161 | Error **errp) |
162 | { | |
163 | QmpOutputVisitor *qov = to_qov(v); | |
fc48ffc3 | 164 | qmp_output_add(qov, name, qbool_from_bool(*obj)); |
e4e6aa14 MR |
165 | } |
166 | ||
0b2a0d6b | 167 | static void qmp_output_type_str(Visitor *v, const char *name, char **obj, |
e4e6aa14 MR |
168 | Error **errp) |
169 | { | |
170 | QmpOutputVisitor *qov = to_qov(v); | |
171 | if (*obj) { | |
172 | qmp_output_add(qov, name, qstring_from_str(*obj)); | |
173 | } else { | |
174 | qmp_output_add(qov, name, qstring_from_str("")); | |
175 | } | |
176 | } | |
177 | ||
0b2a0d6b | 178 | static void qmp_output_type_number(Visitor *v, const char *name, double *obj, |
e4e6aa14 MR |
179 | Error **errp) |
180 | { | |
181 | QmpOutputVisitor *qov = to_qov(v); | |
182 | qmp_output_add(qov, name, qfloat_from_double(*obj)); | |
183 | } | |
184 | ||
0b2a0d6b | 185 | static void qmp_output_type_any(Visitor *v, const char *name, QObject **obj, |
28770e05 MA |
186 | Error **errp) |
187 | { | |
188 | QmpOutputVisitor *qov = to_qov(v); | |
189 | qobject_incref(*obj); | |
190 | qmp_output_add_obj(qov, name, *obj); | |
191 | } | |
192 | ||
3bc97fd5 EB |
193 | static void qmp_output_type_null(Visitor *v, const char *name, Error **errp) |
194 | { | |
3df016f1 EB |
195 | QmpOutputVisitor *qov = to_qov(v); |
196 | qmp_output_add_obj(qov, name, qnull()); | |
3bc97fd5 EB |
197 | } |
198 | ||
56a6f02b EB |
199 | /* Finish building, and return the root object. |
200 | * The root object is never null. The caller becomes the object's | |
201 | * owner, and should use qobject_decref() when done with it. */ | |
3b098d56 | 202 | static void qmp_output_complete(Visitor *v, void *opaque) |
e4e6aa14 | 203 | { |
3b098d56 EB |
204 | QmpOutputVisitor *qov = to_qov(v); |
205 | ||
56a6f02b | 206 | /* A visit must have occurred, with each start paired with end. */ |
fc76ae8b | 207 | assert(qov->root && QSLIST_EMPTY(&qov->stack)); |
3b098d56 | 208 | assert(opaque == qov->result); |
56a6f02b EB |
209 | |
210 | qobject_incref(qov->root); | |
3b098d56 EB |
211 | *qov->result = qov->root; |
212 | qov->result = NULL; | |
e4e6aa14 MR |
213 | } |
214 | ||
2c0ef9f4 EB |
215 | static void qmp_output_free(Visitor *v) |
216 | { | |
217 | QmpOutputVisitor *qov = to_qov(v); | |
fc76ae8b | 218 | QStackEntry *e; |
e4e6aa14 | 219 | |
fc76ae8b PB |
220 | while (!QSLIST_EMPTY(&qov->stack)) { |
221 | e = QSLIST_FIRST(&qov->stack); | |
222 | QSLIST_REMOVE_HEAD(&qov->stack, node); | |
7267c094 | 223 | g_free(e); |
e4e6aa14 MR |
224 | } |
225 | ||
1830f22a EB |
226 | qobject_decref(qov->root); |
227 | g_free(qov); | |
e4e6aa14 MR |
228 | } |
229 | ||
3b098d56 | 230 | Visitor *qmp_output_visitor_new(QObject **result) |
e4e6aa14 MR |
231 | { |
232 | QmpOutputVisitor *v; | |
233 | ||
7267c094 | 234 | v = g_malloc0(sizeof(*v)); |
e4e6aa14 | 235 | |
983f52d4 | 236 | v->visitor.type = VISITOR_OUTPUT; |
e4e6aa14 MR |
237 | v->visitor.start_struct = qmp_output_start_struct; |
238 | v->visitor.end_struct = qmp_output_end_struct; | |
239 | v->visitor.start_list = qmp_output_start_list; | |
240 | v->visitor.next_list = qmp_output_next_list; | |
241 | v->visitor.end_list = qmp_output_end_list; | |
4c40314a | 242 | v->visitor.type_int64 = qmp_output_type_int64; |
f755dea7 | 243 | v->visitor.type_uint64 = qmp_output_type_uint64; |
e4e6aa14 MR |
244 | v->visitor.type_bool = qmp_output_type_bool; |
245 | v->visitor.type_str = qmp_output_type_str; | |
246 | v->visitor.type_number = qmp_output_type_number; | |
28770e05 | 247 | v->visitor.type_any = qmp_output_type_any; |
3bc97fd5 | 248 | v->visitor.type_null = qmp_output_type_null; |
3b098d56 | 249 | v->visitor.complete = qmp_output_complete; |
2c0ef9f4 | 250 | v->visitor.free = qmp_output_free; |
e4e6aa14 | 251 | |
3b098d56 EB |
252 | *result = NULL; |
253 | v->result = result; | |
e4e6aa14 | 254 | |
3b098d56 | 255 | return &v->visitor; |
e4e6aa14 | 256 | } |