]> git.proxmox.com Git - mirror_qemu.git/blame - qapi/qmp-input-visitor.c
qapi: Add visit_type_null() visitor
[mirror_qemu.git] / qapi / qmp-input-visitor.c
CommitLineData
c40cc0a0
MR
1/*
2 * Input Visitor
3 *
08f9541d 4 * Copyright (C) 2012-2016 Red Hat, Inc.
c40cc0a0
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"
da34e65c 16#include "qapi/error.h"
7b1b5d19
PB
17#include "qapi/qmp-input-visitor.h"
18#include "qapi/visitor-impl.h"
1de7afc9 19#include "qemu/queue.h"
c40cc0a0 20#include "qemu-common.h"
7b1b5d19
PB
21#include "qapi/qmp/types.h"
22#include "qapi/qmp/qerror.h"
c40cc0a0
MR
23
24#define QIV_STACK_SIZE 1024
25
26typedef struct StackObject
27{
b471d012
EB
28 QObject *obj; /* Object being visited */
29
30 GHashTable *h; /* If obj is dict: unvisited keys */
31 const QListEntry *entry; /* If obj is list: unvisited tail */
fcf3cb21 32 bool first; /* If obj is list: next_list() not yet called? */
c40cc0a0
MR
33} StackObject;
34
35struct QmpInputVisitor
36{
37 Visitor visitor;
b471d012 38
ce140b17
EB
39 /* Root of visit at visitor creation. */
40 QObject *root;
41
42 /* Stack of objects being visited (all entries will be either
43 * QDict or QList). */
c40cc0a0
MR
44 StackObject stack[QIV_STACK_SIZE];
45 int nb_stack;
b471d012
EB
46
47 /* True to reject parse in visit_end_struct() if unvisited keys remain. */
e38ac962 48 bool strict;
c40cc0a0
MR
49};
50
51static QmpInputVisitor *to_qiv(Visitor *v)
52{
53 return container_of(v, QmpInputVisitor, visitor);
54}
55
4faaec6a 56static QObject *qmp_input_get_object(QmpInputVisitor *qiv,
e8316d7e
KW
57 const char *name,
58 bool consume)
c40cc0a0 59{
ce140b17
EB
60 StackObject *tos;
61 QObject *qobj;
e5826a2f 62 QObject *ret;
b471d012 63
ce140b17
EB
64 if (!qiv->nb_stack) {
65 /* Starting at root, name is ignored. */
66 return qiv->root;
67 }
68
69 /* We are in a container; find the next element. */
70 tos = &qiv->stack[qiv->nb_stack - 1];
71 qobj = tos->obj;
b471d012
EB
72 assert(qobj);
73
ce140b17
EB
74 if (qobject_type(qobj) == QTYPE_QDICT) {
75 assert(name);
e5826a2f
EB
76 ret = qdict_get(qobject_to_qdict(qobj), name);
77 if (tos->h && consume && ret) {
78 bool removed = g_hash_table_remove(tos->h, name);
79 assert(removed);
47c6d3ec 80 }
ce140b17 81 } else {
b471d012 82 assert(qobject_type(qobj) == QTYPE_QLIST);
ce140b17 83 assert(!name);
fcf3cb21 84 assert(!tos->first);
ce140b17 85 ret = qlist_entry_obj(tos->entry);
fcf3cb21
EB
86 if (consume) {
87 tos->entry = qlist_next(tos->entry);
88 }
c40cc0a0
MR
89 }
90
ce140b17 91 return ret;
c40cc0a0
MR
92}
93
e38ac962
PB
94static void qdict_add_key(const char *key, QObject *obj, void *opaque)
95{
96 GHashTable *h = opaque;
97 g_hash_table_insert(h, (gpointer) key, NULL);
98}
99
4faaec6a 100static void qmp_input_push(QmpInputVisitor *qiv, QObject *obj, Error **errp)
c40cc0a0 101{
e38ac962 102 GHashTable *h;
b471d012 103 StackObject *tos = &qiv->stack[qiv->nb_stack];
c40cc0a0 104
b471d012 105 assert(obj);
c40cc0a0 106 if (qiv->nb_stack >= QIV_STACK_SIZE) {
f231b88d 107 error_setg(errp, "An internal buffer overran");
c40cc0a0
MR
108 return;
109 }
e38ac962 110
b471d012 111 tos->obj = obj;
fcf3cb21
EB
112 assert(!tos->h);
113 assert(!tos->entry);
e38ac962
PB
114
115 if (qiv->strict && qobject_type(obj) == QTYPE_QDICT) {
116 h = g_hash_table_new(g_str_hash, g_str_equal);
117 qdict_iter(qobject_to_qdict(obj), qdict_add_key, h);
b471d012 118 tos->h = h;
fcf3cb21
EB
119 } else if (qobject_type(obj) == QTYPE_QLIST) {
120 tos->entry = qlist_first(qobject_to_qlist(obj));
121 tos->first = true;
e38ac962
PB
122 }
123
124 qiv->nb_stack++;
c40cc0a0
MR
125}
126
57a33d89 127
c40cc0a0
MR
128static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
129{
fcf3cb21 130 StackObject *tos = &qiv->stack[qiv->nb_stack - 1];
57a33d89 131 assert(qiv->nb_stack > 0);
e38ac962 132
57a33d89 133 if (qiv->strict) {
fcf3cb21 134 GHashTable *const top_ht = tos->h;
57a33d89 135 if (top_ht) {
f96493b1
EB
136 GHashTableIter iter;
137 const char *key;
138
139 g_hash_table_iter_init(&iter, top_ht);
140 if (g_hash_table_iter_next(&iter, (void **)&key, NULL)) {
c6bd8c70 141 error_setg(errp, QERR_QMP_EXTRA_MEMBER, key);
57a33d89
NK
142 }
143 g_hash_table_unref(top_ht);
e38ac962 144 }
fcf3cb21 145 tos->h = NULL;
e38ac962
PB
146 }
147
c40cc0a0 148 qiv->nb_stack--;
c40cc0a0
MR
149}
150
0b2a0d6b 151static void qmp_input_start_struct(Visitor *v, const char *name, void **obj,
337283df 152 size_t size, Error **errp)
c40cc0a0
MR
153{
154 QmpInputVisitor *qiv = to_qiv(v);
e8316d7e 155 QObject *qobj = qmp_input_get_object(qiv, name, true);
8b714d37 156 Error *err = NULL;
c40cc0a0 157
e58d695e
EB
158 if (obj) {
159 *obj = NULL;
160 }
c40cc0a0 161 if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
c6bd8c70
MA
162 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
163 "QDict");
c40cc0a0
MR
164 return;
165 }
166
8b714d37
PB
167 qmp_input_push(qiv, qobj, &err);
168 if (err) {
169 error_propagate(errp, err);
c40cc0a0
MR
170 return;
171 }
172
173 if (obj) {
7267c094 174 *obj = g_malloc0(size);
c40cc0a0
MR
175 }
176}
177
178static void qmp_input_end_struct(Visitor *v, Error **errp)
179{
180 QmpInputVisitor *qiv = to_qiv(v);
181
182 qmp_input_pop(qiv, errp);
183}
184
185static void qmp_input_start_list(Visitor *v, const char *name, Error **errp)
186{
187 QmpInputVisitor *qiv = to_qiv(v);
e8316d7e 188 QObject *qobj = qmp_input_get_object(qiv, name, true);
c40cc0a0
MR
189
190 if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
c6bd8c70
MA
191 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
192 "list");
c40cc0a0
MR
193 return;
194 }
195
196 qmp_input_push(qiv, qobj, errp);
197}
198
e65d89bf
EB
199static GenericList *qmp_input_next_list(Visitor *v, GenericList **list,
200 size_t size)
c40cc0a0
MR
201{
202 QmpInputVisitor *qiv = to_qiv(v);
203 GenericList *entry;
204 StackObject *so = &qiv->stack[qiv->nb_stack - 1];
205
fcf3cb21 206 if (!so->entry) {
c40cc0a0
MR
207 return NULL;
208 }
209
e65d89bf 210 entry = g_malloc0(size);
fcf3cb21 211 if (so->first) {
3a86a0fa 212 *list = entry;
fcf3cb21 213 so->first = false;
3a86a0fa 214 } else {
c40cc0a0
MR
215 (*list)->next = entry;
216 }
c40cc0a0
MR
217
218 return entry;
219}
220
08f9541d 221static void qmp_input_end_list(Visitor *v)
c40cc0a0
MR
222{
223 QmpInputVisitor *qiv = to_qiv(v);
224
bdd8e6b5 225 qmp_input_pop(qiv, &error_abort);
c40cc0a0
MR
226}
227
dbf11922
EB
228static void qmp_input_start_alternate(Visitor *v, const char *name,
229 GenericAlternate **obj, size_t size,
230 bool promote_int, Error **errp)
69dd62df
KW
231{
232 QmpInputVisitor *qiv = to_qiv(v);
233 QObject *qobj = qmp_input_get_object(qiv, name, false);
234
235 if (!qobj) {
dbf11922 236 *obj = NULL;
c6bd8c70 237 error_setg(errp, QERR_MISSING_PARAMETER, name ? name : "null");
69dd62df
KW
238 return;
239 }
dbf11922
EB
240 *obj = g_malloc0(size);
241 (*obj)->type = qobject_type(qobj);
242 if (promote_int && (*obj)->type == QTYPE_QINT) {
243 (*obj)->type = QTYPE_QFLOAT;
d00341af 244 }
69dd62df
KW
245}
246
0b2a0d6b 247static void qmp_input_type_int64(Visitor *v, const char *name, int64_t *obj,
4c40314a 248 Error **errp)
c40cc0a0
MR
249{
250 QmpInputVisitor *qiv = to_qiv(v);
fcf73f66 251 QInt *qint = qobject_to_qint(qmp_input_get_object(qiv, name, true));
c40cc0a0 252
fcf73f66 253 if (!qint) {
c6bd8c70
MA
254 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
255 "integer");
c40cc0a0
MR
256 return;
257 }
258
fcf73f66 259 *obj = qint_get_int(qint);
c40cc0a0
MR
260}
261
0b2a0d6b 262static void qmp_input_type_uint64(Visitor *v, const char *name, uint64_t *obj,
f755dea7
EB
263 Error **errp)
264{
265 /* FIXME: qobject_to_qint mishandles values over INT64_MAX */
266 QmpInputVisitor *qiv = to_qiv(v);
267 QInt *qint = qobject_to_qint(qmp_input_get_object(qiv, name, true));
268
269 if (!qint) {
270 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
271 "integer");
272 return;
273 }
274
275 *obj = qint_get_int(qint);
276}
277
0b2a0d6b 278static void qmp_input_type_bool(Visitor *v, const char *name, bool *obj,
c40cc0a0
MR
279 Error **errp)
280{
281 QmpInputVisitor *qiv = to_qiv(v);
14b61600 282 QBool *qbool = qobject_to_qbool(qmp_input_get_object(qiv, name, true));
c40cc0a0 283
14b61600 284 if (!qbool) {
c6bd8c70
MA
285 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
286 "boolean");
c40cc0a0
MR
287 return;
288 }
289
14b61600 290 *obj = qbool_get_bool(qbool);
c40cc0a0
MR
291}
292
0b2a0d6b 293static void qmp_input_type_str(Visitor *v, const char *name, char **obj,
c40cc0a0
MR
294 Error **errp)
295{
296 QmpInputVisitor *qiv = to_qiv(v);
7f027843 297 QString *qstr = qobject_to_qstring(qmp_input_get_object(qiv, name, true));
c40cc0a0 298
7f027843 299 if (!qstr) {
e58d695e 300 *obj = NULL;
c6bd8c70
MA
301 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
302 "string");
c40cc0a0
MR
303 return;
304 }
305
7f027843 306 *obj = g_strdup(qstring_get_str(qstr));
c40cc0a0
MR
307}
308
0b2a0d6b 309static void qmp_input_type_number(Visitor *v, const char *name, double *obj,
c40cc0a0
MR
310 Error **errp)
311{
312 QmpInputVisitor *qiv = to_qiv(v);
e8316d7e 313 QObject *qobj = qmp_input_get_object(qiv, name, true);
fcf73f66
MA
314 QInt *qint;
315 QFloat *qfloat;
c40cc0a0 316
fcf73f66
MA
317 qint = qobject_to_qint(qobj);
318 if (qint) {
319 *obj = qint_get_int(qobject_to_qint(qobj));
c40cc0a0
MR
320 return;
321 }
322
fcf73f66
MA
323 qfloat = qobject_to_qfloat(qobj);
324 if (qfloat) {
1ee51876 325 *obj = qfloat_get_double(qobject_to_qfloat(qobj));
fcf73f66 326 return;
1ee51876 327 }
fcf73f66
MA
328
329 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
330 "number");
c40cc0a0
MR
331}
332
0b2a0d6b 333static void qmp_input_type_any(Visitor *v, const char *name, QObject **obj,
28770e05
MA
334 Error **errp)
335{
336 QmpInputVisitor *qiv = to_qiv(v);
337 QObject *qobj = qmp_input_get_object(qiv, name, true);
338
339 qobject_incref(qobj);
340 *obj = qobj;
341}
342
3bc97fd5
EB
343static void qmp_input_type_null(Visitor *v, const char *name, Error **errp)
344{
345 abort();
346}
347
0b2a0d6b 348static void qmp_input_optional(Visitor *v, const char *name, bool *present)
c40cc0a0
MR
349{
350 QmpInputVisitor *qiv = to_qiv(v);
e5826a2f 351 QObject *qobj = qmp_input_get_object(qiv, name, false);
c40cc0a0
MR
352
353 if (!qobj) {
354 *present = false;
355 return;
356 }
357
358 *present = true;
359}
360
c40cc0a0
MR
361Visitor *qmp_input_get_visitor(QmpInputVisitor *v)
362{
363 return &v->visitor;
364}
365
366void qmp_input_visitor_cleanup(QmpInputVisitor *v)
367{
ce140b17 368 qobject_decref(v->root);
7267c094 369 g_free(v);
c40cc0a0
MR
370}
371
fc471c18 372QmpInputVisitor *qmp_input_visitor_new(QObject *obj, bool strict)
c40cc0a0
MR
373{
374 QmpInputVisitor *v;
375
7267c094 376 v = g_malloc0(sizeof(*v));
c40cc0a0 377
983f52d4 378 v->visitor.type = VISITOR_INPUT;
c40cc0a0
MR
379 v->visitor.start_struct = qmp_input_start_struct;
380 v->visitor.end_struct = qmp_input_end_struct;
381 v->visitor.start_list = qmp_input_start_list;
382 v->visitor.next_list = qmp_input_next_list;
383 v->visitor.end_list = qmp_input_end_list;
dbf11922 384 v->visitor.start_alternate = qmp_input_start_alternate;
4c40314a 385 v->visitor.type_int64 = qmp_input_type_int64;
f755dea7 386 v->visitor.type_uint64 = qmp_input_type_uint64;
c40cc0a0
MR
387 v->visitor.type_bool = qmp_input_type_bool;
388 v->visitor.type_str = qmp_input_type_str;
389 v->visitor.type_number = qmp_input_type_number;
28770e05 390 v->visitor.type_any = qmp_input_type_any;
3bc97fd5 391 v->visitor.type_null = qmp_input_type_null;
e2cd0f4f 392 v->visitor.optional = qmp_input_optional;
fc471c18 393 v->strict = strict;
c40cc0a0 394
ce140b17 395 v->root = obj;
4faaec6a 396 qobject_incref(obj);
c40cc0a0
MR
397
398 return v;
399}