]> Git Repo - qemu.git/blob - qapi/qmp-input-visitor.c
Merge remote-tracking branch 'remotes/lalrae/tags/mips-20160712' into staging
[qemu.git] / qapi / qmp-input-visitor.c
1 /*
2  * Input Visitor
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/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"
23
24 #define QIV_STACK_SIZE 1024
25
26 typedef struct StackObject
27 {
28     QObject *obj; /* Object being visited */
29     void *qapi; /* sanity check that caller uses same pointer */
30
31     GHashTable *h;           /* If obj is dict: unvisited keys */
32     const QListEntry *entry; /* If obj is list: unvisited tail */
33 } StackObject;
34
35 struct QmpInputVisitor
36 {
37     Visitor visitor;
38
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). */
44     StackObject stack[QIV_STACK_SIZE];
45     int nb_stack;
46
47     /* True to reject parse in visit_end_struct() if unvisited keys remain. */
48     bool strict;
49 };
50
51 static QmpInputVisitor *to_qiv(Visitor *v)
52 {
53     return container_of(v, QmpInputVisitor, visitor);
54 }
55
56 static QObject *qmp_input_get_object(QmpInputVisitor *qiv,
57                                      const char *name,
58                                      bool consume)
59 {
60     StackObject *tos;
61     QObject *qobj;
62     QObject *ret;
63
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;
72     assert(qobj);
73
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);
80         }
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);
87         }
88     }
89
90     return ret;
91 }
92
93 static 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
99 static const QListEntry *qmp_input_push(QmpInputVisitor *qiv, QObject *obj,
100                                         void *qapi, Error **errp)
101 {
102     GHashTable *h;
103     StackObject *tos = &qiv->stack[qiv->nb_stack];
104
105     assert(obj);
106     if (qiv->nb_stack >= QIV_STACK_SIZE) {
107         error_setg(errp, "An internal buffer overran");
108         return NULL;
109     }
110
111     tos->obj = obj;
112     tos->qapi = qapi;
113     assert(!tos->h);
114     assert(!tos->entry);
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);
119         tos->h = h;
120     } else if (qobject_type(obj) == QTYPE_QLIST) {
121         tos->entry = qlist_first(qobject_to_qlist(obj));
122     }
123
124     qiv->nb_stack++;
125     return tos->entry;
126 }
127
128
129 static void qmp_input_check_struct(Visitor *v, Error **errp)
130 {
131     QmpInputVisitor *qiv = to_qiv(v);
132     StackObject *tos = &qiv->stack[qiv->nb_stack - 1];
133
134     assert(qiv->nb_stack > 0);
135
136     if (qiv->strict) {
137         GHashTable *const top_ht = tos->h;
138         if (top_ht) {
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)) {
144                 error_setg(errp, QERR_QMP_EXTRA_MEMBER, key);
145             }
146         }
147     }
148 }
149
150 static void qmp_input_pop(Visitor *v, void **obj)
151 {
152     QmpInputVisitor *qiv = to_qiv(v);
153     StackObject *tos = &qiv->stack[qiv->nb_stack - 1];
154
155     assert(qiv->nb_stack > 0);
156     assert(tos->qapi == obj);
157
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);
162         }
163         tos->h = NULL;
164     }
165
166     qiv->nb_stack--;
167 }
168
169 static void qmp_input_start_struct(Visitor *v, const char *name, void **obj,
170                                    size_t size, Error **errp)
171 {
172     QmpInputVisitor *qiv = to_qiv(v);
173     QObject *qobj = qmp_input_get_object(qiv, name, true);
174     Error *err = NULL;
175
176     if (obj) {
177         *obj = NULL;
178     }
179     if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
180         error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
181                    "QDict");
182         return;
183     }
184
185     qmp_input_push(qiv, qobj, obj, &err);
186     if (err) {
187         error_propagate(errp, err);
188         return;
189     }
190
191     if (obj) {
192         *obj = g_malloc0(size);
193     }
194 }
195
196
197 static void qmp_input_start_list(Visitor *v, const char *name,
198                                  GenericList **list, size_t size, Error **errp)
199 {
200     QmpInputVisitor *qiv = to_qiv(v);
201     QObject *qobj = qmp_input_get_object(qiv, name, true);
202     const QListEntry *entry;
203
204     if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
205         if (list) {
206             *list = NULL;
207         }
208         error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
209                    "list");
210         return;
211     }
212
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;
219         }
220     }
221 }
222
223 static GenericList *qmp_input_next_list(Visitor *v, GenericList *tail,
224                                         size_t size)
225 {
226     QmpInputVisitor *qiv = to_qiv(v);
227     StackObject *so = &qiv->stack[qiv->nb_stack - 1];
228
229     if (!so->entry) {
230         return NULL;
231     }
232     tail->next = g_malloc0(size);
233     return tail->next;
234 }
235
236
237 static void qmp_input_start_alternate(Visitor *v, const char *name,
238                                       GenericAlternate **obj, size_t size,
239                                       bool promote_int, Error **errp)
240 {
241     QmpInputVisitor *qiv = to_qiv(v);
242     QObject *qobj = qmp_input_get_object(qiv, name, false);
243
244     if (!qobj) {
245         *obj = NULL;
246         error_setg(errp, QERR_MISSING_PARAMETER, name ? name : "null");
247         return;
248     }
249     *obj = g_malloc0(size);
250     (*obj)->type = qobject_type(qobj);
251     if (promote_int && (*obj)->type == QTYPE_QINT) {
252         (*obj)->type = QTYPE_QFLOAT;
253     }
254 }
255
256 static void qmp_input_type_int64(Visitor *v, const char *name, int64_t *obj,
257                                  Error **errp)
258 {
259     QmpInputVisitor *qiv = to_qiv(v);
260     QInt *qint = qobject_to_qint(qmp_input_get_object(qiv, name, true));
261
262     if (!qint) {
263         error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
264                    "integer");
265         return;
266     }
267
268     *obj = qint_get_int(qint);
269 }
270
271 static void qmp_input_type_uint64(Visitor *v, const char *name, uint64_t *obj,
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
287 static void qmp_input_type_bool(Visitor *v, const char *name, bool *obj,
288                                 Error **errp)
289 {
290     QmpInputVisitor *qiv = to_qiv(v);
291     QBool *qbool = qobject_to_qbool(qmp_input_get_object(qiv, name, true));
292
293     if (!qbool) {
294         error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
295                    "boolean");
296         return;
297     }
298
299     *obj = qbool_get_bool(qbool);
300 }
301
302 static void qmp_input_type_str(Visitor *v, const char *name, char **obj,
303                                Error **errp)
304 {
305     QmpInputVisitor *qiv = to_qiv(v);
306     QString *qstr = qobject_to_qstring(qmp_input_get_object(qiv, name, true));
307
308     if (!qstr) {
309         *obj = NULL;
310         error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
311                    "string");
312         return;
313     }
314
315     *obj = g_strdup(qstring_get_str(qstr));
316 }
317
318 static void qmp_input_type_number(Visitor *v, const char *name, double *obj,
319                                   Error **errp)
320 {
321     QmpInputVisitor *qiv = to_qiv(v);
322     QObject *qobj = qmp_input_get_object(qiv, name, true);
323     QInt *qint;
324     QFloat *qfloat;
325
326     qint = qobject_to_qint(qobj);
327     if (qint) {
328         *obj = qint_get_int(qobject_to_qint(qobj));
329         return;
330     }
331
332     qfloat = qobject_to_qfloat(qobj);
333     if (qfloat) {
334         *obj = qfloat_get_double(qobject_to_qfloat(qobj));
335         return;
336     }
337
338     error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
339                "number");
340 }
341
342 static void qmp_input_type_any(Visitor *v, const char *name, QObject **obj,
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
352 static void qmp_input_type_null(Visitor *v, const char *name, Error **errp)
353 {
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     }
361 }
362
363 static void qmp_input_optional(Visitor *v, const char *name, bool *present)
364 {
365     QmpInputVisitor *qiv = to_qiv(v);
366     QObject *qobj = qmp_input_get_object(qiv, name, false);
367
368     if (!qobj) {
369         *present = false;
370         return;
371     }
372
373     *present = true;
374 }
375
376 static void qmp_input_free(Visitor *v)
377 {
378     QmpInputVisitor *qiv = to_qiv(v);
379
380     qobject_decref(qiv->root);
381     g_free(qiv);
382 }
383
384 Visitor *qmp_input_visitor_new(QObject *obj, bool strict)
385 {
386     QmpInputVisitor *v;
387
388     v = g_malloc0(sizeof(*v));
389
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;
408
409     v->root = obj;
410     qobject_incref(obj);
411
412     return &v->visitor;
413 }
This page took 0.047884 seconds and 4 git commands to generate.