blob: 5765e76e43b0c8346198b8f0a8bb399ec21253fb [file] [log] [blame]
Michael Rothc40cc0a2011-07-19 14:50:33 -05001/*
2 * Input Visitor
3 *
4 * Copyright IBM, Corp. 2011
5 *
6 * Authors:
7 * Anthony Liguori <aliguori@us.ibm.com>
8 *
9 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
10 * See the COPYING.LIB file in the top-level directory.
11 *
12 */
13
14#include "qmp-input-visitor.h"
Paolo Bonzini0f71a1e2012-02-09 09:11:52 +010015#include "qapi/qapi-visit-impl.h"
Michael Rothc40cc0a2011-07-19 14:50:33 -050016#include "qemu-queue.h"
17#include "qemu-common.h"
18#include "qemu-objects.h"
19#include "qerror.h"
20
21#define QIV_STACK_SIZE 1024
22
23typedef struct StackObject
24{
Paolo Bonzini4faaec62012-03-22 12:51:09 +010025 QObject *obj;
26 const QListEntry *entry;
Michael Rothc40cc0a2011-07-19 14:50:33 -050027} StackObject;
28
29struct QmpInputVisitor
30{
31 Visitor visitor;
Michael Rothc40cc0a2011-07-19 14:50:33 -050032 StackObject stack[QIV_STACK_SIZE];
33 int nb_stack;
34};
35
36static QmpInputVisitor *to_qiv(Visitor *v)
37{
38 return container_of(v, QmpInputVisitor, visitor);
39}
40
Paolo Bonzini4faaec62012-03-22 12:51:09 +010041static QObject *qmp_input_get_object(QmpInputVisitor *qiv,
42 const char *name)
Michael Rothc40cc0a2011-07-19 14:50:33 -050043{
Paolo Bonzini4faaec62012-03-22 12:51:09 +010044 QObject *qobj = qiv->stack[qiv->nb_stack - 1].obj;
Michael Rothc40cc0a2011-07-19 14:50:33 -050045
Paolo Bonzini47c6d3e2011-12-18 17:05:04 +010046 if (qobj) {
47 if (name && qobject_type(qobj) == QTYPE_QDICT) {
48 return qdict_get(qobject_to_qdict(qobj), name);
Paolo Bonzini4faaec62012-03-22 12:51:09 +010049 } else if (qiv->stack[qiv->nb_stack - 1].entry) {
Paolo Bonzini47c6d3e2011-12-18 17:05:04 +010050 return qlist_entry_obj(qiv->stack[qiv->nb_stack - 1].entry);
51 }
Michael Rothc40cc0a2011-07-19 14:50:33 -050052 }
53
54 return qobj;
55}
56
Paolo Bonzini4faaec62012-03-22 12:51:09 +010057static void qmp_input_push(QmpInputVisitor *qiv, QObject *obj, Error **errp)
Michael Rothc40cc0a2011-07-19 14:50:33 -050058{
59 qiv->stack[qiv->nb_stack].obj = obj;
Paolo Bonzini3a86a0f2012-03-22 22:38:40 +010060 qiv->stack[qiv->nb_stack].entry = NULL;
Michael Rothc40cc0a2011-07-19 14:50:33 -050061 qiv->nb_stack++;
62
63 if (qiv->nb_stack >= QIV_STACK_SIZE) {
64 error_set(errp, QERR_BUFFER_OVERRUN);
65 return;
66 }
67}
68
69static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
70{
Paolo Bonzini2c7ff932012-03-22 12:51:04 +010071 assert(qiv->nb_stack > 0);
Michael Rothc40cc0a2011-07-19 14:50:33 -050072 qiv->nb_stack--;
Michael Rothc40cc0a2011-07-19 14:50:33 -050073}
74
75static void qmp_input_start_struct(Visitor *v, void **obj, const char *kind,
76 const char *name, size_t size, Error **errp)
77{
78 QmpInputVisitor *qiv = to_qiv(v);
Paolo Bonzini4faaec62012-03-22 12:51:09 +010079 QObject *qobj = qmp_input_get_object(qiv, name);
Paolo Bonzini8b714d32012-03-22 12:51:05 +010080 Error *err = NULL;
Michael Rothc40cc0a2011-07-19 14:50:33 -050081
82 if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
83 error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
84 "QDict");
85 return;
86 }
87
Paolo Bonzini8b714d32012-03-22 12:51:05 +010088 qmp_input_push(qiv, qobj, &err);
89 if (err) {
90 error_propagate(errp, err);
Michael Rothc40cc0a2011-07-19 14:50:33 -050091 return;
92 }
93
94 if (obj) {
Anthony Liguori7267c092011-08-20 22:09:37 -050095 *obj = g_malloc0(size);
Michael Rothc40cc0a2011-07-19 14:50:33 -050096 }
97}
98
99static void qmp_input_end_struct(Visitor *v, Error **errp)
100{
101 QmpInputVisitor *qiv = to_qiv(v);
102
103 qmp_input_pop(qiv, errp);
104}
105
106static void qmp_input_start_list(Visitor *v, const char *name, Error **errp)
107{
108 QmpInputVisitor *qiv = to_qiv(v);
Paolo Bonzini4faaec62012-03-22 12:51:09 +0100109 QObject *qobj = qmp_input_get_object(qiv, name);
Michael Rothc40cc0a2011-07-19 14:50:33 -0500110
111 if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
112 error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
113 "list");
114 return;
115 }
116
117 qmp_input_push(qiv, qobj, errp);
118}
119
120static GenericList *qmp_input_next_list(Visitor *v, GenericList **list,
121 Error **errp)
122{
123 QmpInputVisitor *qiv = to_qiv(v);
124 GenericList *entry;
125 StackObject *so = &qiv->stack[qiv->nb_stack - 1];
Paolo Bonzini3a86a0f2012-03-22 22:38:40 +0100126 bool first;
127
128 if (so->entry == NULL) {
129 so->entry = qlist_first(qobject_to_qlist(so->obj));
130 first = true;
131 } else {
132 so->entry = qlist_next(so->entry);
133 first = false;
134 }
Michael Rothc40cc0a2011-07-19 14:50:33 -0500135
136 if (so->entry == NULL) {
137 return NULL;
138 }
139
Anthony Liguori7267c092011-08-20 22:09:37 -0500140 entry = g_malloc0(sizeof(*entry));
Paolo Bonzini3a86a0f2012-03-22 22:38:40 +0100141 if (first) {
142 *list = entry;
143 } else {
Michael Rothc40cc0a2011-07-19 14:50:33 -0500144 (*list)->next = entry;
145 }
Michael Rothc40cc0a2011-07-19 14:50:33 -0500146
147 return entry;
148}
149
150static void qmp_input_end_list(Visitor *v, Error **errp)
151{
152 QmpInputVisitor *qiv = to_qiv(v);
153
154 qmp_input_pop(qiv, errp);
155}
156
157static void qmp_input_type_int(Visitor *v, int64_t *obj, const char *name,
158 Error **errp)
159{
160 QmpInputVisitor *qiv = to_qiv(v);
Paolo Bonzini4faaec62012-03-22 12:51:09 +0100161 QObject *qobj = qmp_input_get_object(qiv, name);
Michael Rothc40cc0a2011-07-19 14:50:33 -0500162
163 if (!qobj || qobject_type(qobj) != QTYPE_QINT) {
164 error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
165 "integer");
166 return;
167 }
168
169 *obj = qint_get_int(qobject_to_qint(qobj));
170}
171
172static void qmp_input_type_bool(Visitor *v, bool *obj, const char *name,
173 Error **errp)
174{
175 QmpInputVisitor *qiv = to_qiv(v);
Paolo Bonzini4faaec62012-03-22 12:51:09 +0100176 QObject *qobj = qmp_input_get_object(qiv, name);
Michael Rothc40cc0a2011-07-19 14:50:33 -0500177
178 if (!qobj || qobject_type(qobj) != QTYPE_QBOOL) {
179 error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
180 "boolean");
181 return;
182 }
183
184 *obj = qbool_get_int(qobject_to_qbool(qobj));
185}
186
187static void qmp_input_type_str(Visitor *v, char **obj, const char *name,
188 Error **errp)
189{
190 QmpInputVisitor *qiv = to_qiv(v);
Paolo Bonzini4faaec62012-03-22 12:51:09 +0100191 QObject *qobj = qmp_input_get_object(qiv, name);
Michael Rothc40cc0a2011-07-19 14:50:33 -0500192
193 if (!qobj || qobject_type(qobj) != QTYPE_QSTRING) {
194 error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
195 "string");
196 return;
197 }
198
Anthony Liguori7267c092011-08-20 22:09:37 -0500199 *obj = g_strdup(qstring_get_str(qobject_to_qstring(qobj)));
Michael Rothc40cc0a2011-07-19 14:50:33 -0500200}
201
202static void qmp_input_type_number(Visitor *v, double *obj, const char *name,
203 Error **errp)
204{
205 QmpInputVisitor *qiv = to_qiv(v);
Paolo Bonzini4faaec62012-03-22 12:51:09 +0100206 QObject *qobj = qmp_input_get_object(qiv, name);
Michael Rothc40cc0a2011-07-19 14:50:33 -0500207
208 if (!qobj || qobject_type(qobj) != QTYPE_QFLOAT) {
209 error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
210 "double");
211 return;
212 }
213
214 *obj = qfloat_get_double(qobject_to_qfloat(qobj));
215}
216
Michael Rothc40cc0a2011-07-19 14:50:33 -0500217static void qmp_input_start_optional(Visitor *v, bool *present,
218 const char *name, Error **errp)
219{
220 QmpInputVisitor *qiv = to_qiv(v);
Paolo Bonzini4faaec62012-03-22 12:51:09 +0100221 QObject *qobj = qmp_input_get_object(qiv, name);
Michael Rothc40cc0a2011-07-19 14:50:33 -0500222
223 if (!qobj) {
224 *present = false;
225 return;
226 }
227
228 *present = true;
229}
230
Michael Rothc40cc0a2011-07-19 14:50:33 -0500231Visitor *qmp_input_get_visitor(QmpInputVisitor *v)
232{
233 return &v->visitor;
234}
235
236void qmp_input_visitor_cleanup(QmpInputVisitor *v)
237{
Paolo Bonzini4faaec62012-03-22 12:51:09 +0100238 qobject_decref(v->stack[0].obj);
Anthony Liguori7267c092011-08-20 22:09:37 -0500239 g_free(v);
Michael Rothc40cc0a2011-07-19 14:50:33 -0500240}
241
242QmpInputVisitor *qmp_input_visitor_new(QObject *obj)
243{
244 QmpInputVisitor *v;
245
Anthony Liguori7267c092011-08-20 22:09:37 -0500246 v = g_malloc0(sizeof(*v));
Michael Rothc40cc0a2011-07-19 14:50:33 -0500247
248 v->visitor.start_struct = qmp_input_start_struct;
249 v->visitor.end_struct = qmp_input_end_struct;
250 v->visitor.start_list = qmp_input_start_list;
251 v->visitor.next_list = qmp_input_next_list;
252 v->visitor.end_list = qmp_input_end_list;
Paolo Bonzini0f71a1e2012-02-09 09:11:52 +0100253 v->visitor.type_enum = input_type_enum;
Michael Rothc40cc0a2011-07-19 14:50:33 -0500254 v->visitor.type_int = qmp_input_type_int;
255 v->visitor.type_bool = qmp_input_type_bool;
256 v->visitor.type_str = qmp_input_type_str;
257 v->visitor.type_number = qmp_input_type_number;
258 v->visitor.start_optional = qmp_input_start_optional;
Michael Rothc40cc0a2011-07-19 14:50:33 -0500259
Paolo Bonzini4faaec62012-03-22 12:51:09 +0100260 qmp_input_push(v, obj, NULL);
261 qobject_incref(obj);
Michael Rothc40cc0a2011-07-19 14:50:33 -0500262
263 return v;
264}