Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-2.7-20160718' into staging
[qemu/ar7.git] / qapi / qmp-input-visitor.c
blob21edb3928edbdd518d2f88e6d924cae6241c10be
1 /*
2 * Input Visitor
4 * Copyright (C) 2012-2016 Red Hat, Inc.
5 * Copyright IBM, Corp. 2011
7 * Authors:
8 * Anthony Liguori <aliguori@us.ibm.com>
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.
15 #include "qemu/osdep.h"
16 #include "qapi/error.h"
17 #include "qapi/qmp-input-visitor.h"
18 #include "qapi/visitor-impl.h"
19 #include "qemu/queue.h"
20 #include "qemu-common.h"
21 #include "qapi/qmp/types.h"
22 #include "qapi/qmp/qerror.h"
24 #define QIV_STACK_SIZE 1024
26 typedef struct StackObject
28 QObject *obj; /* Object being visited */
29 void *qapi; /* sanity check that caller uses same pointer */
31 GHashTable *h; /* If obj is dict: unvisited keys */
32 const QListEntry *entry; /* If obj is list: unvisited tail */
33 } StackObject;
35 struct QmpInputVisitor
37 Visitor visitor;
39 /* Root of visit at visitor creation. */
40 QObject *root;
42 /* Stack of objects being visited (all entries will be either
43 * QDict or QList). */
44 StackObject stack[QIV_STACK_SIZE];
45 int nb_stack;
47 /* True to reject parse in visit_end_struct() if unvisited keys remain. */
48 bool strict;
51 static QmpInputVisitor *to_qiv(Visitor *v)
53 return container_of(v, QmpInputVisitor, visitor);
56 static QObject *qmp_input_get_object(QmpInputVisitor *qiv,
57 const char *name,
58 bool consume)
60 StackObject *tos;
61 QObject *qobj;
62 QObject *ret;
64 if (!qiv->nb_stack) {
65 /* Starting at root, name is ignored. */
66 return qiv->root;
69 /* We are in a container; find the next element. */
70 tos = &qiv->stack[qiv->nb_stack - 1];
71 qobj = tos->obj;
72 assert(qobj);
74 if (qobject_type(qobj) == QTYPE_QDICT) {
75 assert(name);
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);
81 } else {
82 assert(qobject_type(qobj) == QTYPE_QLIST);
83 assert(!name);
84 ret = qlist_entry_obj(tos->entry);
85 if (consume) {
86 tos->entry = qlist_next(tos->entry);
90 return ret;
93 static void qdict_add_key(const char *key, QObject *obj, void *opaque)
95 GHashTable *h = opaque;
96 g_hash_table_insert(h, (gpointer) key, NULL);
99 static const QListEntry *qmp_input_push(QmpInputVisitor *qiv, QObject *obj,
100 void *qapi, Error **errp)
102 GHashTable *h;
103 StackObject *tos = &qiv->stack[qiv->nb_stack];
105 assert(obj);
106 if (qiv->nb_stack >= QIV_STACK_SIZE) {
107 error_setg(errp, "An internal buffer overran");
108 return NULL;
111 tos->obj = obj;
112 tos->qapi = qapi;
113 assert(!tos->h);
114 assert(!tos->entry);
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);
119 tos->h = h;
120 } else if (qobject_type(obj) == QTYPE_QLIST) {
121 tos->entry = qlist_first(qobject_to_qlist(obj));
124 qiv->nb_stack++;
125 return tos->entry;
129 static void qmp_input_check_struct(Visitor *v, Error **errp)
131 QmpInputVisitor *qiv = to_qiv(v);
132 StackObject *tos = &qiv->stack[qiv->nb_stack - 1];
134 assert(qiv->nb_stack > 0);
136 if (qiv->strict) {
137 GHashTable *const top_ht = tos->h;
138 if (top_ht) {
139 GHashTableIter iter;
140 const char *key;
142 g_hash_table_iter_init(&iter, top_ht);
143 if (g_hash_table_iter_next(&iter, (void **)&key, NULL)) {
144 error_setg(errp, QERR_QMP_EXTRA_MEMBER, key);
150 static void qmp_input_pop(Visitor *v, void **obj)
152 QmpInputVisitor *qiv = to_qiv(v);
153 StackObject *tos = &qiv->stack[qiv->nb_stack - 1];
155 assert(qiv->nb_stack > 0);
156 assert(tos->qapi == obj);
158 if (qiv->strict) {
159 GHashTable * const top_ht = qiv->stack[qiv->nb_stack - 1].h;
160 if (top_ht) {
161 g_hash_table_unref(top_ht);
163 tos->h = NULL;
166 qiv->nb_stack--;
169 static void qmp_input_start_struct(Visitor *v, const char *name, void **obj,
170 size_t size, Error **errp)
172 QmpInputVisitor *qiv = to_qiv(v);
173 QObject *qobj = qmp_input_get_object(qiv, name, true);
174 Error *err = NULL;
176 if (obj) {
177 *obj = NULL;
179 if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
180 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
181 "QDict");
182 return;
185 qmp_input_push(qiv, qobj, obj, &err);
186 if (err) {
187 error_propagate(errp, err);
188 return;
191 if (obj) {
192 *obj = g_malloc0(size);
197 static void qmp_input_start_list(Visitor *v, const char *name,
198 GenericList **list, size_t size, Error **errp)
200 QmpInputVisitor *qiv = to_qiv(v);
201 QObject *qobj = qmp_input_get_object(qiv, name, true);
202 const QListEntry *entry;
204 if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
205 if (list) {
206 *list = NULL;
208 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
209 "list");
210 return;
213 entry = qmp_input_push(qiv, qobj, list, errp);
214 if (list) {
215 if (entry) {
216 *list = g_malloc0(size);
217 } else {
218 *list = NULL;
223 static GenericList *qmp_input_next_list(Visitor *v, GenericList *tail,
224 size_t size)
226 QmpInputVisitor *qiv = to_qiv(v);
227 StackObject *so = &qiv->stack[qiv->nb_stack - 1];
229 if (!so->entry) {
230 return NULL;
232 tail->next = g_malloc0(size);
233 return tail->next;
237 static void qmp_input_start_alternate(Visitor *v, const char *name,
238 GenericAlternate **obj, size_t size,
239 bool promote_int, Error **errp)
241 QmpInputVisitor *qiv = to_qiv(v);
242 QObject *qobj = qmp_input_get_object(qiv, name, false);
244 if (!qobj) {
245 *obj = NULL;
246 error_setg(errp, QERR_MISSING_PARAMETER, name ? name : "null");
247 return;
249 *obj = g_malloc0(size);
250 (*obj)->type = qobject_type(qobj);
251 if (promote_int && (*obj)->type == QTYPE_QINT) {
252 (*obj)->type = QTYPE_QFLOAT;
256 static void qmp_input_type_int64(Visitor *v, const char *name, int64_t *obj,
257 Error **errp)
259 QmpInputVisitor *qiv = to_qiv(v);
260 QInt *qint = qobject_to_qint(qmp_input_get_object(qiv, name, true));
262 if (!qint) {
263 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
264 "integer");
265 return;
268 *obj = qint_get_int(qint);
271 static void qmp_input_type_uint64(Visitor *v, const char *name, uint64_t *obj,
272 Error **errp)
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));
278 if (!qint) {
279 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
280 "integer");
281 return;
284 *obj = qint_get_int(qint);
287 static void qmp_input_type_bool(Visitor *v, const char *name, bool *obj,
288 Error **errp)
290 QmpInputVisitor *qiv = to_qiv(v);
291 QBool *qbool = qobject_to_qbool(qmp_input_get_object(qiv, name, true));
293 if (!qbool) {
294 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
295 "boolean");
296 return;
299 *obj = qbool_get_bool(qbool);
302 static void qmp_input_type_str(Visitor *v, const char *name, char **obj,
303 Error **errp)
305 QmpInputVisitor *qiv = to_qiv(v);
306 QString *qstr = qobject_to_qstring(qmp_input_get_object(qiv, name, true));
308 if (!qstr) {
309 *obj = NULL;
310 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
311 "string");
312 return;
315 *obj = g_strdup(qstring_get_str(qstr));
318 static void qmp_input_type_number(Visitor *v, const char *name, double *obj,
319 Error **errp)
321 QmpInputVisitor *qiv = to_qiv(v);
322 QObject *qobj = qmp_input_get_object(qiv, name, true);
323 QInt *qint;
324 QFloat *qfloat;
326 qint = qobject_to_qint(qobj);
327 if (qint) {
328 *obj = qint_get_int(qobject_to_qint(qobj));
329 return;
332 qfloat = qobject_to_qfloat(qobj);
333 if (qfloat) {
334 *obj = qfloat_get_double(qobject_to_qfloat(qobj));
335 return;
338 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
339 "number");
342 static void qmp_input_type_any(Visitor *v, const char *name, QObject **obj,
343 Error **errp)
345 QmpInputVisitor *qiv = to_qiv(v);
346 QObject *qobj = qmp_input_get_object(qiv, name, true);
348 qobject_incref(qobj);
349 *obj = qobj;
352 static void qmp_input_type_null(Visitor *v, const char *name, Error **errp)
354 QmpInputVisitor *qiv = to_qiv(v);
355 QObject *qobj = qmp_input_get_object(qiv, name, true);
357 if (qobject_type(qobj) != QTYPE_QNULL) {
358 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
359 "null");
363 static void qmp_input_optional(Visitor *v, const char *name, bool *present)
365 QmpInputVisitor *qiv = to_qiv(v);
366 QObject *qobj = qmp_input_get_object(qiv, name, false);
368 if (!qobj) {
369 *present = false;
370 return;
373 *present = true;
376 static void qmp_input_free(Visitor *v)
378 QmpInputVisitor *qiv = to_qiv(v);
380 qobject_decref(qiv->root);
381 g_free(qiv);
384 Visitor *qmp_input_visitor_new(QObject *obj, bool strict)
386 QmpInputVisitor *v;
388 v = g_malloc0(sizeof(*v));
390 v->visitor.type = VISITOR_INPUT;
391 v->visitor.start_struct = qmp_input_start_struct;
392 v->visitor.check_struct = qmp_input_check_struct;
393 v->visitor.end_struct = qmp_input_pop;
394 v->visitor.start_list = qmp_input_start_list;
395 v->visitor.next_list = qmp_input_next_list;
396 v->visitor.end_list = qmp_input_pop;
397 v->visitor.start_alternate = qmp_input_start_alternate;
398 v->visitor.type_int64 = qmp_input_type_int64;
399 v->visitor.type_uint64 = qmp_input_type_uint64;
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;
403 v->visitor.type_any = qmp_input_type_any;
404 v->visitor.type_null = qmp_input_type_null;
405 v->visitor.optional = qmp_input_optional;
406 v->visitor.free = qmp_input_free;
407 v->strict = strict;
409 v->root = obj;
410 qobject_incref(obj);
412 return &v->visitor;