]> Git Repo - qemu.git/blob - qapi/qobject-input-visitor.c
qapi: Clean up after commit 3d344c2
[qemu.git] / qapi / qobject-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/qobject-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 typedef struct StackObject
25 {
26     QObject *obj; /* Object being visited */
27     void *qapi; /* sanity check that caller uses same pointer */
28
29     GHashTable *h;           /* If obj is dict: unvisited keys */
30     const QListEntry *entry; /* If obj is list: unvisited tail */
31
32     QSLIST_ENTRY(StackObject) node;
33 } StackObject;
34
35 struct QObjectInputVisitor
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     QSLIST_HEAD(, StackObject) stack;
45
46     /* True to reject parse in visit_end_struct() if unvisited keys remain. */
47     bool strict;
48 };
49
50 static QObjectInputVisitor *to_qiv(Visitor *v)
51 {
52     return container_of(v, QObjectInputVisitor, visitor);
53 }
54
55 static QObject *qobject_input_get_object(QObjectInputVisitor *qiv,
56                                          const char *name,
57                                          bool consume, Error **errp)
58 {
59     StackObject *tos;
60     QObject *qobj;
61     QObject *ret;
62
63     if (QSLIST_EMPTY(&qiv->stack)) {
64         /* Starting at root, name is ignored. */
65         assert(qiv->root);
66         return qiv->root;
67     }
68
69     /* We are in a container; find the next element. */
70     tos = QSLIST_FIRST(&qiv->stack);
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         if (!ret) {
82             error_setg(errp, QERR_MISSING_PARAMETER, name);
83         }
84     } else {
85         assert(qobject_type(qobj) == QTYPE_QLIST);
86         assert(!name);
87         ret = qlist_entry_obj(tos->entry);
88         assert(ret);
89         if (consume) {
90             tos->entry = qlist_next(tos->entry);
91         }
92     }
93
94     return ret;
95 }
96
97 static void qdict_add_key(const char *key, QObject *obj, void *opaque)
98 {
99     GHashTable *h = opaque;
100     g_hash_table_insert(h, (gpointer) key, NULL);
101 }
102
103 static const QListEntry *qobject_input_push(QObjectInputVisitor *qiv,
104                                             QObject *obj, void *qapi)
105 {
106     GHashTable *h;
107     StackObject *tos = g_new0(StackObject, 1);
108
109     assert(obj);
110     tos->obj = obj;
111     tos->qapi = qapi;
112
113     if (qiv->strict && qobject_type(obj) == QTYPE_QDICT) {
114         h = g_hash_table_new(g_str_hash, g_str_equal);
115         qdict_iter(qobject_to_qdict(obj), qdict_add_key, h);
116         tos->h = h;
117     } else if (qobject_type(obj) == QTYPE_QLIST) {
118         tos->entry = qlist_first(qobject_to_qlist(obj));
119     }
120
121     QSLIST_INSERT_HEAD(&qiv->stack, tos, node);
122     return tos->entry;
123 }
124
125
126 static void qobject_input_check_struct(Visitor *v, Error **errp)
127 {
128     QObjectInputVisitor *qiv = to_qiv(v);
129     StackObject *tos = QSLIST_FIRST(&qiv->stack);
130
131     assert(tos && !tos->entry);
132     if (qiv->strict) {
133         GHashTable *const top_ht = tos->h;
134         if (top_ht) {
135             GHashTableIter iter;
136             const char *key;
137
138             g_hash_table_iter_init(&iter, top_ht);
139             if (g_hash_table_iter_next(&iter, (void **)&key, NULL)) {
140                 error_setg(errp, "Parameter '%s' is unexpected", key);
141             }
142         }
143     }
144 }
145
146 static void qobject_input_stack_object_free(StackObject *tos)
147 {
148     if (tos->h) {
149         g_hash_table_unref(tos->h);
150     }
151
152     g_free(tos);
153 }
154
155 static void qobject_input_pop(Visitor *v, void **obj)
156 {
157     QObjectInputVisitor *qiv = to_qiv(v);
158     StackObject *tos = QSLIST_FIRST(&qiv->stack);
159
160     assert(tos && tos->qapi == obj);
161     QSLIST_REMOVE_HEAD(&qiv->stack, node);
162     qobject_input_stack_object_free(tos);
163 }
164
165 static void qobject_input_start_struct(Visitor *v, const char *name, void **obj,
166                                        size_t size, Error **errp)
167 {
168     QObjectInputVisitor *qiv = to_qiv(v);
169     QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
170
171     if (obj) {
172         *obj = NULL;
173     }
174     if (!qobj) {
175         return;
176     }
177     if (qobject_type(qobj) != QTYPE_QDICT) {
178         error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
179                    "QDict");
180         return;
181     }
182
183     qobject_input_push(qiv, qobj, obj);
184
185     if (obj) {
186         *obj = g_malloc0(size);
187     }
188 }
189
190
191 static void qobject_input_start_list(Visitor *v, const char *name,
192                                      GenericList **list, size_t size,
193                                      Error **errp)
194 {
195     QObjectInputVisitor *qiv = to_qiv(v);
196     QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
197     const QListEntry *entry;
198
199     if (!qobj) {
200         return;
201     }
202     if (qobject_type(qobj) != QTYPE_QLIST) {
203         if (list) {
204             *list = NULL;
205         }
206         error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
207                    "list");
208         return;
209     }
210
211     entry = qobject_input_push(qiv, qobj, list);
212     if (list) {
213         if (entry) {
214             *list = g_malloc0(size);
215         } else {
216             *list = NULL;
217         }
218     }
219 }
220
221 static GenericList *qobject_input_next_list(Visitor *v, GenericList *tail,
222                                             size_t size)
223 {
224     QObjectInputVisitor *qiv = to_qiv(v);
225     StackObject *so = QSLIST_FIRST(&qiv->stack);
226
227     if (!so->entry) {
228         return NULL;
229     }
230     tail->next = g_malloc0(size);
231     return tail->next;
232 }
233
234
235 static void qobject_input_start_alternate(Visitor *v, const char *name,
236                                           GenericAlternate **obj, size_t size,
237                                           bool promote_int, Error **errp)
238 {
239     QObjectInputVisitor *qiv = to_qiv(v);
240     QObject *qobj = qobject_input_get_object(qiv, name, false, errp);
241
242     if (!qobj) {
243         *obj = NULL;
244         return;
245     }
246     *obj = g_malloc0(size);
247     (*obj)->type = qobject_type(qobj);
248     if (promote_int && (*obj)->type == QTYPE_QINT) {
249         (*obj)->type = QTYPE_QFLOAT;
250     }
251 }
252
253 static void qobject_input_type_int64(Visitor *v, const char *name, int64_t *obj,
254                                      Error **errp)
255 {
256     QObjectInputVisitor *qiv = to_qiv(v);
257     QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
258     QInt *qint;
259
260     if (!qobj) {
261         return;
262     }
263     qint = qobject_to_qint(qobj);
264     if (!qint) {
265         error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
266                    "integer");
267         return;
268     }
269
270     *obj = qint_get_int(qint);
271 }
272
273 static void qobject_input_type_uint64(Visitor *v, const char *name,
274                                       uint64_t *obj, Error **errp)
275 {
276     /* FIXME: qobject_to_qint mishandles values over INT64_MAX */
277     QObjectInputVisitor *qiv = to_qiv(v);
278     QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
279     QInt *qint;
280
281     if (!qobj) {
282         return;
283     }
284     qint = qobject_to_qint(qobj);
285     if (!qint) {
286         error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
287                    "integer");
288         return;
289     }
290
291     *obj = qint_get_int(qint);
292 }
293
294 static void qobject_input_type_bool(Visitor *v, const char *name, bool *obj,
295                                     Error **errp)
296 {
297     QObjectInputVisitor *qiv = to_qiv(v);
298     QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
299     QBool *qbool;
300
301     if (!qobj) {
302         return;
303     }
304     qbool = qobject_to_qbool(qobj);
305     if (!qbool) {
306         error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
307                    "boolean");
308         return;
309     }
310
311     *obj = qbool_get_bool(qbool);
312 }
313
314 static void qobject_input_type_str(Visitor *v, const char *name, char **obj,
315                                    Error **errp)
316 {
317     QObjectInputVisitor *qiv = to_qiv(v);
318     QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
319     QString *qstr;
320
321     *obj = NULL;
322     if (!qobj) {
323         return;
324     }
325     qstr = qobject_to_qstring(qobj);
326     if (!qstr) {
327         error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
328                    "string");
329         return;
330     }
331
332     *obj = g_strdup(qstring_get_str(qstr));
333 }
334
335 static void qobject_input_type_number(Visitor *v, const char *name, double *obj,
336                                       Error **errp)
337 {
338     QObjectInputVisitor *qiv = to_qiv(v);
339     QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
340     QInt *qint;
341     QFloat *qfloat;
342
343     if (!qobj) {
344         return;
345     }
346     qint = qobject_to_qint(qobj);
347     if (qint) {
348         *obj = qint_get_int(qobject_to_qint(qobj));
349         return;
350     }
351
352     qfloat = qobject_to_qfloat(qobj);
353     if (qfloat) {
354         *obj = qfloat_get_double(qobject_to_qfloat(qobj));
355         return;
356     }
357
358     error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
359                "number");
360 }
361
362 static void qobject_input_type_any(Visitor *v, const char *name, QObject **obj,
363                                    Error **errp)
364 {
365     QObjectInputVisitor *qiv = to_qiv(v);
366     QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
367
368     *obj = NULL;
369     if (!qobj) {
370         return;
371     }
372
373     qobject_incref(qobj);
374     *obj = qobj;
375 }
376
377 static void qobject_input_type_null(Visitor *v, const char *name, Error **errp)
378 {
379     QObjectInputVisitor *qiv = to_qiv(v);
380     QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
381
382     if (!qobj) {
383         return;
384     }
385
386     if (qobject_type(qobj) != QTYPE_QNULL) {
387         error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
388                    "null");
389     }
390 }
391
392 static void qobject_input_optional(Visitor *v, const char *name, bool *present)
393 {
394     QObjectInputVisitor *qiv = to_qiv(v);
395     QObject *qobj = qobject_input_get_object(qiv, name, false, NULL);
396
397     if (!qobj) {
398         *present = false;
399         return;
400     }
401
402     *present = true;
403 }
404
405 static void qobject_input_free(Visitor *v)
406 {
407     QObjectInputVisitor *qiv = to_qiv(v);
408     while (!QSLIST_EMPTY(&qiv->stack)) {
409         StackObject *tos = QSLIST_FIRST(&qiv->stack);
410
411         QSLIST_REMOVE_HEAD(&qiv->stack, node);
412         qobject_input_stack_object_free(tos);
413     }
414
415     qobject_decref(qiv->root);
416     g_free(qiv);
417 }
418
419 Visitor *qobject_input_visitor_new(QObject *obj, bool strict)
420 {
421     QObjectInputVisitor *v;
422
423     assert(obj);
424     v = g_malloc0(sizeof(*v));
425
426     v->visitor.type = VISITOR_INPUT;
427     v->visitor.start_struct = qobject_input_start_struct;
428     v->visitor.check_struct = qobject_input_check_struct;
429     v->visitor.end_struct = qobject_input_pop;
430     v->visitor.start_list = qobject_input_start_list;
431     v->visitor.next_list = qobject_input_next_list;
432     v->visitor.end_list = qobject_input_pop;
433     v->visitor.start_alternate = qobject_input_start_alternate;
434     v->visitor.type_int64 = qobject_input_type_int64;
435     v->visitor.type_uint64 = qobject_input_type_uint64;
436     v->visitor.type_bool = qobject_input_type_bool;
437     v->visitor.type_str = qobject_input_type_str;
438     v->visitor.type_number = qobject_input_type_number;
439     v->visitor.type_any = qobject_input_type_any;
440     v->visitor.type_null = qobject_input_type_null;
441     v->visitor.optional = qobject_input_optional;
442     v->visitor.free = qobject_input_free;
443     v->strict = strict;
444
445     v->root = obj;
446     qobject_incref(obj);
447
448     return &v->visitor;
449 }
This page took 0.046892 seconds and 4 git commands to generate.