]> git.proxmox.com Git - mirror_qemu.git/blame - qapi/qmp-input-visitor.c
qapi: change QmpOutputVisitor to QSLIST
[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 28 QObject *obj; /* Object being visited */
1158bb2a 29 void *qapi; /* sanity check that caller uses same pointer */
b471d012
EB
30
31 GHashTable *h; /* If obj is dict: unvisited keys */
32 const QListEntry *entry; /* If obj is list: unvisited tail */
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
EB
83 assert(!name);
84 ret = qlist_entry_obj(tos->entry);
fcf3cb21
EB
85 if (consume) {
86 tos->entry = qlist_next(tos->entry);
87 }
c40cc0a0
MR
88 }
89
ce140b17 90 return ret;
c40cc0a0
MR
91}
92
e38ac962
PB
93static void qdict_add_key(const char *key, QObject *obj, void *opaque)
94{
95 GHashTable *h = opaque;
96 g_hash_table_insert(h, (gpointer) key, NULL);
97}
98
d9f62dde 99static const QListEntry *qmp_input_push(QmpInputVisitor *qiv, QObject *obj,
1158bb2a 100 void *qapi, 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");
d9f62dde 108 return NULL;
c40cc0a0 109 }
e38ac962 110
b471d012 111 tos->obj = obj;
1158bb2a 112 tos->qapi = qapi;
fcf3cb21
EB
113 assert(!tos->h);
114 assert(!tos->entry);
e38ac962
PB
115
116 if (qiv->strict && qobject_type(obj) == QTYPE_QDICT) {
117 h = g_hash_table_new(g_str_hash, g_str_equal);
118 qdict_iter(qobject_to_qdict(obj), qdict_add_key, h);
b471d012 119 tos->h = h;
fcf3cb21
EB
120 } else if (qobject_type(obj) == QTYPE_QLIST) {
121 tos->entry = qlist_first(qobject_to_qlist(obj));
e38ac962
PB
122 }
123
124 qiv->nb_stack++;
d9f62dde 125 return tos->entry;
c40cc0a0
MR
126}
127
57a33d89 128
15c2f669 129static void qmp_input_check_struct(Visitor *v, Error **errp)
c40cc0a0 130{
15c2f669 131 QmpInputVisitor *qiv = to_qiv(v);
fcf3cb21 132 StackObject *tos = &qiv->stack[qiv->nb_stack - 1];
15c2f669 133
57a33d89 134 assert(qiv->nb_stack > 0);
e38ac962 135
57a33d89 136 if (qiv->strict) {
fcf3cb21 137 GHashTable *const top_ht = tos->h;
57a33d89 138 if (top_ht) {
f96493b1
EB
139 GHashTableIter iter;
140 const char *key;
141
142 g_hash_table_iter_init(&iter, top_ht);
143 if (g_hash_table_iter_next(&iter, (void **)&key, NULL)) {
c6bd8c70 144 error_setg(errp, QERR_QMP_EXTRA_MEMBER, key);
57a33d89 145 }
15c2f669
EB
146 }
147 }
148}
149
1158bb2a 150static void qmp_input_pop(Visitor *v, void **obj)
15c2f669
EB
151{
152 QmpInputVisitor *qiv = to_qiv(v);
153 StackObject *tos = &qiv->stack[qiv->nb_stack - 1];
154
155 assert(qiv->nb_stack > 0);
1158bb2a 156 assert(tos->qapi == obj);
15c2f669
EB
157
158 if (qiv->strict) {
159 GHashTable * const top_ht = qiv->stack[qiv->nb_stack - 1].h;
160 if (top_ht) {
57a33d89 161 g_hash_table_unref(top_ht);
e38ac962 162 }
fcf3cb21 163 tos->h = NULL;
e38ac962
PB
164 }
165
c40cc0a0 166 qiv->nb_stack--;
c40cc0a0
MR
167}
168
0b2a0d6b 169static void qmp_input_start_struct(Visitor *v, const char *name, void **obj,
337283df 170 size_t size, Error **errp)
c40cc0a0
MR
171{
172 QmpInputVisitor *qiv = to_qiv(v);
e8316d7e 173 QObject *qobj = qmp_input_get_object(qiv, name, true);
8b714d37 174 Error *err = NULL;
c40cc0a0 175
e58d695e
EB
176 if (obj) {
177 *obj = NULL;
178 }
c40cc0a0 179 if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
c6bd8c70
MA
180 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
181 "QDict");
c40cc0a0
MR
182 return;
183 }
184
1158bb2a 185 qmp_input_push(qiv, qobj, obj, &err);
8b714d37
PB
186 if (err) {
187 error_propagate(errp, err);
c40cc0a0
MR
188 return;
189 }
190
191 if (obj) {
7267c094 192 *obj = g_malloc0(size);
c40cc0a0
MR
193 }
194}
195
c40cc0a0 196
d9f62dde
EB
197static void qmp_input_start_list(Visitor *v, const char *name,
198 GenericList **list, size_t size, Error **errp)
c40cc0a0
MR
199{
200 QmpInputVisitor *qiv = to_qiv(v);
e8316d7e 201 QObject *qobj = qmp_input_get_object(qiv, name, true);
d9f62dde 202 const QListEntry *entry;
c40cc0a0
MR
203
204 if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
d9f62dde
EB
205 if (list) {
206 *list = NULL;
207 }
c6bd8c70
MA
208 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
209 "list");
c40cc0a0
MR
210 return;
211 }
212
1158bb2a 213 entry = qmp_input_push(qiv, qobj, list, errp);
d9f62dde
EB
214 if (list) {
215 if (entry) {
216 *list = g_malloc0(size);
217 } else {
218 *list = NULL;
219 }
220 }
c40cc0a0
MR
221}
222
d9f62dde 223static GenericList *qmp_input_next_list(Visitor *v, GenericList *tail,
e65d89bf 224 size_t size)
c40cc0a0
MR
225{
226 QmpInputVisitor *qiv = to_qiv(v);
c40cc0a0
MR
227 StackObject *so = &qiv->stack[qiv->nb_stack - 1];
228
fcf3cb21 229 if (!so->entry) {
c40cc0a0
MR
230 return NULL;
231 }
d9f62dde
EB
232 tail->next = g_malloc0(size);
233 return tail->next;
c40cc0a0
MR
234}
235
c40cc0a0 236
dbf11922
EB
237static void qmp_input_start_alternate(Visitor *v, const char *name,
238 GenericAlternate **obj, size_t size,
239 bool promote_int, Error **errp)
69dd62df
KW
240{
241 QmpInputVisitor *qiv = to_qiv(v);
242 QObject *qobj = qmp_input_get_object(qiv, name, false);
243
244 if (!qobj) {
dbf11922 245 *obj = NULL;
c6bd8c70 246 error_setg(errp, QERR_MISSING_PARAMETER, name ? name : "null");
69dd62df
KW
247 return;
248 }
dbf11922
EB
249 *obj = g_malloc0(size);
250 (*obj)->type = qobject_type(qobj);
251 if (promote_int && (*obj)->type == QTYPE_QINT) {
252 (*obj)->type = QTYPE_QFLOAT;
d00341af 253 }
69dd62df
KW
254}
255
0b2a0d6b 256static void qmp_input_type_int64(Visitor *v, const char *name, int64_t *obj,
4c40314a 257 Error **errp)
c40cc0a0
MR
258{
259 QmpInputVisitor *qiv = to_qiv(v);
fcf73f66 260 QInt *qint = qobject_to_qint(qmp_input_get_object(qiv, name, true));
c40cc0a0 261
fcf73f66 262 if (!qint) {
c6bd8c70
MA
263 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
264 "integer");
c40cc0a0
MR
265 return;
266 }
267
fcf73f66 268 *obj = qint_get_int(qint);
c40cc0a0
MR
269}
270
0b2a0d6b 271static void qmp_input_type_uint64(Visitor *v, const char *name, uint64_t *obj,
f755dea7
EB
272 Error **errp)
273{
274 /* FIXME: qobject_to_qint mishandles values over INT64_MAX */
275 QmpInputVisitor *qiv = to_qiv(v);
276 QInt *qint = qobject_to_qint(qmp_input_get_object(qiv, name, true));
277
278 if (!qint) {
279 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
280 "integer");
281 return;
282 }
283
284 *obj = qint_get_int(qint);
285}
286
0b2a0d6b 287static void qmp_input_type_bool(Visitor *v, const char *name, bool *obj,
c40cc0a0
MR
288 Error **errp)
289{
290 QmpInputVisitor *qiv = to_qiv(v);
14b61600 291 QBool *qbool = qobject_to_qbool(qmp_input_get_object(qiv, name, true));
c40cc0a0 292
14b61600 293 if (!qbool) {
c6bd8c70
MA
294 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
295 "boolean");
c40cc0a0
MR
296 return;
297 }
298
14b61600 299 *obj = qbool_get_bool(qbool);
c40cc0a0
MR
300}
301
0b2a0d6b 302static void qmp_input_type_str(Visitor *v, const char *name, char **obj,
c40cc0a0
MR
303 Error **errp)
304{
305 QmpInputVisitor *qiv = to_qiv(v);
7f027843 306 QString *qstr = qobject_to_qstring(qmp_input_get_object(qiv, name, true));
c40cc0a0 307
7f027843 308 if (!qstr) {
e58d695e 309 *obj = NULL;
c6bd8c70
MA
310 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
311 "string");
c40cc0a0
MR
312 return;
313 }
314
7f027843 315 *obj = g_strdup(qstring_get_str(qstr));
c40cc0a0
MR
316}
317
0b2a0d6b 318static void qmp_input_type_number(Visitor *v, const char *name, double *obj,
c40cc0a0
MR
319 Error **errp)
320{
321 QmpInputVisitor *qiv = to_qiv(v);
e8316d7e 322 QObject *qobj = qmp_input_get_object(qiv, name, true);
fcf73f66
MA
323 QInt *qint;
324 QFloat *qfloat;
c40cc0a0 325
fcf73f66
MA
326 qint = qobject_to_qint(qobj);
327 if (qint) {
328 *obj = qint_get_int(qobject_to_qint(qobj));
c40cc0a0
MR
329 return;
330 }
331
fcf73f66
MA
332 qfloat = qobject_to_qfloat(qobj);
333 if (qfloat) {
1ee51876 334 *obj = qfloat_get_double(qobject_to_qfloat(qobj));
fcf73f66 335 return;
1ee51876 336 }
fcf73f66
MA
337
338 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
339 "number");
c40cc0a0
MR
340}
341
0b2a0d6b 342static void qmp_input_type_any(Visitor *v, const char *name, QObject **obj,
28770e05
MA
343 Error **errp)
344{
345 QmpInputVisitor *qiv = to_qiv(v);
346 QObject *qobj = qmp_input_get_object(qiv, name, true);
347
348 qobject_incref(qobj);
349 *obj = qobj;
350}
351
3bc97fd5
EB
352static void qmp_input_type_null(Visitor *v, const char *name, Error **errp)
353{
3df016f1
EB
354 QmpInputVisitor *qiv = to_qiv(v);
355 QObject *qobj = qmp_input_get_object(qiv, name, true);
356
357 if (qobject_type(qobj) != QTYPE_QNULL) {
358 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
359 "null");
360 }
3bc97fd5
EB
361}
362
0b2a0d6b 363static void qmp_input_optional(Visitor *v, const char *name, bool *present)
c40cc0a0
MR
364{
365 QmpInputVisitor *qiv = to_qiv(v);
e5826a2f 366 QObject *qobj = qmp_input_get_object(qiv, name, false);
c40cc0a0
MR
367
368 if (!qobj) {
369 *present = false;
370 return;
371 }
372
373 *present = true;
374}
375
2c0ef9f4
EB
376static void qmp_input_free(Visitor *v)
377{
378 QmpInputVisitor *qiv = to_qiv(v);
379
b70ce101
EB
380 qobject_decref(qiv->root);
381 g_free(qiv);
2c0ef9f4
EB
382}
383
b70ce101 384Visitor *qmp_input_visitor_new(QObject *obj, bool strict)
c40cc0a0
MR
385{
386 QmpInputVisitor *v;
387
7267c094 388 v = g_malloc0(sizeof(*v));
c40cc0a0 389
983f52d4 390 v->visitor.type = VISITOR_INPUT;
c40cc0a0 391 v->visitor.start_struct = qmp_input_start_struct;
15c2f669
EB
392 v->visitor.check_struct = qmp_input_check_struct;
393 v->visitor.end_struct = qmp_input_pop;
c40cc0a0
MR
394 v->visitor.start_list = qmp_input_start_list;
395 v->visitor.next_list = qmp_input_next_list;
15c2f669 396 v->visitor.end_list = qmp_input_pop;
dbf11922 397 v->visitor.start_alternate = qmp_input_start_alternate;
4c40314a 398 v->visitor.type_int64 = qmp_input_type_int64;
f755dea7 399 v->visitor.type_uint64 = qmp_input_type_uint64;
c40cc0a0
MR
400 v->visitor.type_bool = qmp_input_type_bool;
401 v->visitor.type_str = qmp_input_type_str;
402 v->visitor.type_number = qmp_input_type_number;
28770e05 403 v->visitor.type_any = qmp_input_type_any;
3bc97fd5 404 v->visitor.type_null = qmp_input_type_null;
e2cd0f4f 405 v->visitor.optional = qmp_input_optional;
2c0ef9f4 406 v->visitor.free = qmp_input_free;
fc471c18 407 v->strict = strict;
c40cc0a0 408
ce140b17 409 v->root = obj;
4faaec6a 410 qobject_incref(obj);
c40cc0a0 411
b70ce101 412 return &v->visitor;
c40cc0a0 413}