]>
Commit | Line | Data |
---|---|---|
c40cc0a0 MR |
1 | /* |
2 | * Input Visitor | |
3 | * | |
cbd8acf3 | 4 | * Copyright (C) 2012-2017 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" |
b3db211f | 17 | #include "qapi/qobject-input-visitor.h" |
7b1b5d19 | 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" | |
cbd8acf3 | 23 | #include "qemu/cutils.h" |
c40cc0a0 | 24 | |
a9fc37f6 MA |
25 | typedef struct StackObject { |
26 | const char *name; /* Name of @obj in its parent, if any */ | |
27 | QObject *obj; /* QDict or QList being visited */ | |
1158bb2a | 28 | void *qapi; /* sanity check that caller uses same pointer */ |
b471d012 | 29 | |
a9fc37f6 MA |
30 | GHashTable *h; /* If @obj is QDict: unvisited keys */ |
31 | const QListEntry *entry; /* If @obj is QList: unvisited tail */ | |
32 | unsigned index; /* If @obj is QList: list index of @entry */ | |
3d344c2a | 33 | |
a9fc37f6 | 34 | QSLIST_ENTRY(StackObject) node; /* parent */ |
c40cc0a0 MR |
35 | } StackObject; |
36 | ||
a9fc37f6 | 37 | struct QObjectInputVisitor { |
c40cc0a0 | 38 | Visitor visitor; |
b471d012 | 39 | |
ce140b17 EB |
40 | /* Root of visit at visitor creation. */ |
41 | QObject *root; | |
42 | ||
43 | /* Stack of objects being visited (all entries will be either | |
44 | * QDict or QList). */ | |
3d344c2a | 45 | QSLIST_HEAD(, StackObject) stack; |
b471d012 | 46 | |
a9fc37f6 | 47 | GString *errname; /* Accumulator for full_name() */ |
c40cc0a0 MR |
48 | }; |
49 | ||
09e68369 | 50 | static QObjectInputVisitor *to_qiv(Visitor *v) |
c40cc0a0 | 51 | { |
09e68369 | 52 | return container_of(v, QObjectInputVisitor, visitor); |
c40cc0a0 MR |
53 | } |
54 | ||
a4a1c70d MA |
55 | static const char *full_name_nth(QObjectInputVisitor *qiv, const char *name, |
56 | int n) | |
a9fc37f6 MA |
57 | { |
58 | StackObject *so; | |
59 | char buf[32]; | |
60 | ||
61 | if (qiv->errname) { | |
62 | g_string_truncate(qiv->errname, 0); | |
63 | } else { | |
64 | qiv->errname = g_string_new(""); | |
65 | } | |
66 | ||
67 | QSLIST_FOREACH(so , &qiv->stack, node) { | |
a4a1c70d MA |
68 | if (n) { |
69 | n--; | |
70 | } else if (qobject_type(so->obj) == QTYPE_QDICT) { | |
71 | g_string_prepend(qiv->errname, name ?: "<anonymous>"); | |
a9fc37f6 MA |
72 | g_string_prepend_c(qiv->errname, '.'); |
73 | } else { | |
74 | snprintf(buf, sizeof(buf), "[%u]", so->index); | |
75 | g_string_prepend(qiv->errname, buf); | |
76 | } | |
77 | name = so->name; | |
78 | } | |
a4a1c70d | 79 | assert(!n); |
a9fc37f6 MA |
80 | |
81 | if (name) { | |
82 | g_string_prepend(qiv->errname, name); | |
83 | } else if (qiv->errname->str[0] == '.') { | |
84 | g_string_erase(qiv->errname, 0, 1); | |
a4a1c70d | 85 | } else if (!qiv->errname->str[0]) { |
a9fc37f6 MA |
86 | return "<anonymous>"; |
87 | } | |
88 | ||
89 | return qiv->errname->str; | |
90 | } | |
91 | ||
a4a1c70d MA |
92 | static const char *full_name(QObjectInputVisitor *qiv, const char *name) |
93 | { | |
94 | return full_name_nth(qiv, name, 0); | |
95 | } | |
96 | ||
a9fc37f6 MA |
97 | static QObject *qobject_input_try_get_object(QObjectInputVisitor *qiv, |
98 | const char *name, | |
99 | bool consume) | |
c40cc0a0 | 100 | { |
ce140b17 EB |
101 | StackObject *tos; |
102 | QObject *qobj; | |
e5826a2f | 103 | QObject *ret; |
b471d012 | 104 | |
3d344c2a | 105 | if (QSLIST_EMPTY(&qiv->stack)) { |
ce140b17 | 106 | /* Starting at root, name is ignored. */ |
5d0cbbcf | 107 | assert(qiv->root); |
ce140b17 EB |
108 | return qiv->root; |
109 | } | |
110 | ||
111 | /* We are in a container; find the next element. */ | |
3d344c2a | 112 | tos = QSLIST_FIRST(&qiv->stack); |
ce140b17 | 113 | qobj = tos->obj; |
b471d012 EB |
114 | assert(qobj); |
115 | ||
ce140b17 EB |
116 | if (qobject_type(qobj) == QTYPE_QDICT) { |
117 | assert(name); | |
e5826a2f EB |
118 | ret = qdict_get(qobject_to_qdict(qobj), name); |
119 | if (tos->h && consume && ret) { | |
120 | bool removed = g_hash_table_remove(tos->h, name); | |
121 | assert(removed); | |
47c6d3ec | 122 | } |
ce140b17 | 123 | } else { |
b471d012 | 124 | assert(qobject_type(qobj) == QTYPE_QLIST); |
ce140b17 | 125 | assert(!name); |
1f41a645 MA |
126 | if (tos->entry) { |
127 | ret = qlist_entry_obj(tos->entry); | |
128 | if (consume) { | |
129 | tos->entry = qlist_next(tos->entry); | |
130 | } | |
131 | } else { | |
132 | ret = NULL; | |
133 | } | |
fcf3cb21 | 134 | if (consume) { |
a9fc37f6 | 135 | tos->index++; |
fcf3cb21 | 136 | } |
c40cc0a0 MR |
137 | } |
138 | ||
ce140b17 | 139 | return ret; |
c40cc0a0 MR |
140 | } |
141 | ||
a9fc37f6 MA |
142 | static QObject *qobject_input_get_object(QObjectInputVisitor *qiv, |
143 | const char *name, | |
144 | bool consume, Error **errp) | |
145 | { | |
146 | QObject *obj = qobject_input_try_get_object(qiv, name, consume); | |
147 | ||
148 | if (!obj) { | |
149 | error_setg(errp, QERR_MISSING_PARAMETER, full_name(qiv, name)); | |
150 | } | |
151 | return obj; | |
152 | } | |
153 | ||
e38ac962 PB |
154 | static void qdict_add_key(const char *key, QObject *obj, void *opaque) |
155 | { | |
156 | GHashTable *h = opaque; | |
157 | g_hash_table_insert(h, (gpointer) key, NULL); | |
158 | } | |
159 | ||
09e68369 | 160 | static const QListEntry *qobject_input_push(QObjectInputVisitor *qiv, |
a9fc37f6 | 161 | const char *name, |
b8874fbf | 162 | QObject *obj, void *qapi) |
c40cc0a0 | 163 | { |
e38ac962 | 164 | GHashTable *h; |
3d344c2a | 165 | StackObject *tos = g_new0(StackObject, 1); |
c40cc0a0 | 166 | |
b471d012 | 167 | assert(obj); |
a9fc37f6 | 168 | tos->name = name; |
b471d012 | 169 | tos->obj = obj; |
1158bb2a | 170 | tos->qapi = qapi; |
e38ac962 | 171 | |
048abb7b | 172 | if (qobject_type(obj) == QTYPE_QDICT) { |
e38ac962 PB |
173 | h = g_hash_table_new(g_str_hash, g_str_equal); |
174 | qdict_iter(qobject_to_qdict(obj), qdict_add_key, h); | |
b471d012 | 175 | tos->h = h; |
048abb7b MA |
176 | } else { |
177 | assert(qobject_type(obj) == QTYPE_QLIST); | |
fcf3cb21 | 178 | tos->entry = qlist_first(qobject_to_qlist(obj)); |
a9fc37f6 | 179 | tos->index = -1; |
e38ac962 PB |
180 | } |
181 | ||
3d344c2a | 182 | QSLIST_INSERT_HEAD(&qiv->stack, tos, node); |
d9f62dde | 183 | return tos->entry; |
c40cc0a0 MR |
184 | } |
185 | ||
57a33d89 | 186 | |
09e68369 | 187 | static void qobject_input_check_struct(Visitor *v, Error **errp) |
c40cc0a0 | 188 | { |
09e68369 | 189 | QObjectInputVisitor *qiv = to_qiv(v); |
3d344c2a | 190 | StackObject *tos = QSLIST_FIRST(&qiv->stack); |
048abb7b MA |
191 | GHashTableIter iter; |
192 | const char *key; | |
e38ac962 | 193 | |
3d344c2a | 194 | assert(tos && !tos->entry); |
048abb7b MA |
195 | |
196 | g_hash_table_iter_init(&iter, tos->h); | |
197 | if (g_hash_table_iter_next(&iter, (void **)&key, NULL)) { | |
198 | error_setg(errp, "Parameter '%s' is unexpected", | |
199 | full_name(qiv, key)); | |
15c2f669 EB |
200 | } |
201 | } | |
202 | ||
09e68369 | 203 | static void qobject_input_stack_object_free(StackObject *tos) |
15c2f669 | 204 | { |
3d344c2a PB |
205 | if (tos->h) { |
206 | g_hash_table_unref(tos->h); | |
207 | } | |
15c2f669 | 208 | |
3d344c2a PB |
209 | g_free(tos); |
210 | } | |
15c2f669 | 211 | |
09e68369 | 212 | static void qobject_input_pop(Visitor *v, void **obj) |
3d344c2a | 213 | { |
09e68369 | 214 | QObjectInputVisitor *qiv = to_qiv(v); |
3d344c2a | 215 | StackObject *tos = QSLIST_FIRST(&qiv->stack); |
e38ac962 | 216 | |
3d344c2a PB |
217 | assert(tos && tos->qapi == obj); |
218 | QSLIST_REMOVE_HEAD(&qiv->stack, node); | |
09e68369 | 219 | qobject_input_stack_object_free(tos); |
c40cc0a0 MR |
220 | } |
221 | ||
09e68369 DB |
222 | static void qobject_input_start_struct(Visitor *v, const char *name, void **obj, |
223 | size_t size, Error **errp) | |
c40cc0a0 | 224 | { |
09e68369 DB |
225 | QObjectInputVisitor *qiv = to_qiv(v); |
226 | QObject *qobj = qobject_input_get_object(qiv, name, true, errp); | |
c40cc0a0 | 227 | |
e58d695e EB |
228 | if (obj) { |
229 | *obj = NULL; | |
230 | } | |
1382d4ab MAL |
231 | if (!qobj) { |
232 | return; | |
233 | } | |
234 | if (qobject_type(qobj) != QTYPE_QDICT) { | |
a9fc37f6 MA |
235 | error_setg(errp, QERR_INVALID_PARAMETER_TYPE, |
236 | full_name(qiv, name), "object"); | |
c40cc0a0 MR |
237 | return; |
238 | } | |
239 | ||
a9fc37f6 | 240 | qobject_input_push(qiv, name, qobj, obj); |
c40cc0a0 MR |
241 | |
242 | if (obj) { | |
7267c094 | 243 | *obj = g_malloc0(size); |
c40cc0a0 MR |
244 | } |
245 | } | |
246 | ||
c40cc0a0 | 247 | |
09e68369 DB |
248 | static void qobject_input_start_list(Visitor *v, const char *name, |
249 | GenericList **list, size_t size, | |
250 | Error **errp) | |
c40cc0a0 | 251 | { |
09e68369 DB |
252 | QObjectInputVisitor *qiv = to_qiv(v); |
253 | QObject *qobj = qobject_input_get_object(qiv, name, true, errp); | |
d9f62dde | 254 | const QListEntry *entry; |
c40cc0a0 | 255 | |
58561c27 MA |
256 | if (list) { |
257 | *list = NULL; | |
258 | } | |
1382d4ab MAL |
259 | if (!qobj) { |
260 | return; | |
261 | } | |
262 | if (qobject_type(qobj) != QTYPE_QLIST) { | |
a9fc37f6 MA |
263 | error_setg(errp, QERR_INVALID_PARAMETER_TYPE, |
264 | full_name(qiv, name), "array"); | |
c40cc0a0 MR |
265 | return; |
266 | } | |
267 | ||
a9fc37f6 | 268 | entry = qobject_input_push(qiv, name, qobj, list); |
58561c27 MA |
269 | if (entry && list) { |
270 | *list = g_malloc0(size); | |
d9f62dde | 271 | } |
c40cc0a0 MR |
272 | } |
273 | ||
09e68369 DB |
274 | static GenericList *qobject_input_next_list(Visitor *v, GenericList *tail, |
275 | size_t size) | |
c40cc0a0 | 276 | { |
09e68369 | 277 | QObjectInputVisitor *qiv = to_qiv(v); |
a4a1c70d MA |
278 | StackObject *tos = QSLIST_FIRST(&qiv->stack); |
279 | ||
280 | assert(tos && tos->obj && qobject_type(tos->obj) == QTYPE_QLIST); | |
c40cc0a0 | 281 | |
a4a1c70d | 282 | if (!tos->entry) { |
c40cc0a0 MR |
283 | return NULL; |
284 | } | |
d9f62dde EB |
285 | tail->next = g_malloc0(size); |
286 | return tail->next; | |
c40cc0a0 MR |
287 | } |
288 | ||
a4a1c70d MA |
289 | static void qobject_input_check_list(Visitor *v, Error **errp) |
290 | { | |
291 | QObjectInputVisitor *qiv = to_qiv(v); | |
292 | StackObject *tos = QSLIST_FIRST(&qiv->stack); | |
293 | ||
294 | assert(tos && tos->obj && qobject_type(tos->obj) == QTYPE_QLIST); | |
295 | ||
296 | if (tos->entry) { | |
297 | error_setg(errp, "Only %u list elements expected in %s", | |
298 | tos->index + 1, full_name_nth(qiv, NULL, 1)); | |
299 | } | |
300 | } | |
301 | ||
c40cc0a0 | 302 | |
09e68369 DB |
303 | static void qobject_input_start_alternate(Visitor *v, const char *name, |
304 | GenericAlternate **obj, size_t size, | |
305 | bool promote_int, Error **errp) | |
69dd62df | 306 | { |
09e68369 DB |
307 | QObjectInputVisitor *qiv = to_qiv(v); |
308 | QObject *qobj = qobject_input_get_object(qiv, name, false, errp); | |
69dd62df KW |
309 | |
310 | if (!qobj) { | |
dbf11922 | 311 | *obj = NULL; |
69dd62df KW |
312 | return; |
313 | } | |
dbf11922 EB |
314 | *obj = g_malloc0(size); |
315 | (*obj)->type = qobject_type(qobj); | |
316 | if (promote_int && (*obj)->type == QTYPE_QINT) { | |
317 | (*obj)->type = QTYPE_QFLOAT; | |
d00341af | 318 | } |
69dd62df KW |
319 | } |
320 | ||
09e68369 DB |
321 | static void qobject_input_type_int64(Visitor *v, const char *name, int64_t *obj, |
322 | Error **errp) | |
c40cc0a0 | 323 | { |
09e68369 DB |
324 | QObjectInputVisitor *qiv = to_qiv(v); |
325 | QObject *qobj = qobject_input_get_object(qiv, name, true, errp); | |
1382d4ab | 326 | QInt *qint; |
c40cc0a0 | 327 | |
1382d4ab MAL |
328 | if (!qobj) { |
329 | return; | |
330 | } | |
331 | qint = qobject_to_qint(qobj); | |
fcf73f66 | 332 | if (!qint) { |
a9fc37f6 MA |
333 | error_setg(errp, QERR_INVALID_PARAMETER_TYPE, |
334 | full_name(qiv, name), "integer"); | |
c40cc0a0 MR |
335 | return; |
336 | } | |
337 | ||
fcf73f66 | 338 | *obj = qint_get_int(qint); |
c40cc0a0 MR |
339 | } |
340 | ||
cbd8acf3 DB |
341 | |
342 | static void qobject_input_type_int64_keyval(Visitor *v, const char *name, | |
343 | int64_t *obj, Error **errp) | |
344 | { | |
345 | QObjectInputVisitor *qiv = to_qiv(v); | |
346 | QObject *qobj = qobject_input_get_object(qiv, name, true, errp); | |
347 | QString *qstr; | |
348 | ||
349 | if (!qobj) { | |
350 | return; | |
351 | } | |
352 | qstr = qobject_to_qstring(qobj); | |
353 | if (!qstr) { | |
354 | error_setg(errp, QERR_INVALID_PARAMETER_TYPE, | |
355 | full_name(qiv, name), "string"); | |
356 | return; | |
357 | } | |
358 | ||
359 | if (qemu_strtoi64(qstring_get_str(qstr), NULL, 0, obj) < 0) { | |
360 | /* TODO report -ERANGE more nicely */ | |
361 | error_setg(errp, QERR_INVALID_PARAMETER_VALUE, | |
362 | full_name(qiv, name), "integer"); | |
363 | } | |
364 | } | |
365 | ||
09e68369 DB |
366 | static void qobject_input_type_uint64(Visitor *v, const char *name, |
367 | uint64_t *obj, Error **errp) | |
f755dea7 EB |
368 | { |
369 | /* FIXME: qobject_to_qint mishandles values over INT64_MAX */ | |
09e68369 DB |
370 | QObjectInputVisitor *qiv = to_qiv(v); |
371 | QObject *qobj = qobject_input_get_object(qiv, name, true, errp); | |
1382d4ab | 372 | QInt *qint; |
f755dea7 | 373 | |
1382d4ab MAL |
374 | if (!qobj) { |
375 | return; | |
376 | } | |
377 | qint = qobject_to_qint(qobj); | |
f755dea7 | 378 | if (!qint) { |
a9fc37f6 MA |
379 | error_setg(errp, QERR_INVALID_PARAMETER_TYPE, |
380 | full_name(qiv, name), "integer"); | |
f755dea7 EB |
381 | return; |
382 | } | |
383 | ||
384 | *obj = qint_get_int(qint); | |
385 | } | |
386 | ||
cbd8acf3 DB |
387 | static void qobject_input_type_uint64_keyval(Visitor *v, const char *name, |
388 | uint64_t *obj, Error **errp) | |
389 | { | |
390 | QObjectInputVisitor *qiv = to_qiv(v); | |
391 | QObject *qobj = qobject_input_get_object(qiv, name, true, errp); | |
392 | QString *qstr; | |
393 | ||
394 | if (!qobj) { | |
395 | return; | |
396 | } | |
397 | qstr = qobject_to_qstring(qobj); | |
398 | if (!qstr) { | |
399 | error_setg(errp, QERR_INVALID_PARAMETER_TYPE, | |
400 | full_name(qiv, name), "string"); | |
401 | return; | |
402 | } | |
403 | ||
404 | if (qemu_strtou64(qstring_get_str(qstr), NULL, 0, obj) < 0) { | |
405 | /* TODO report -ERANGE more nicely */ | |
406 | error_setg(errp, QERR_INVALID_PARAMETER_VALUE, | |
407 | full_name(qiv, name), "integer"); | |
408 | } | |
409 | } | |
410 | ||
09e68369 DB |
411 | static void qobject_input_type_bool(Visitor *v, const char *name, bool *obj, |
412 | Error **errp) | |
c40cc0a0 | 413 | { |
09e68369 DB |
414 | QObjectInputVisitor *qiv = to_qiv(v); |
415 | QObject *qobj = qobject_input_get_object(qiv, name, true, errp); | |
1382d4ab | 416 | QBool *qbool; |
c40cc0a0 | 417 | |
1382d4ab MAL |
418 | if (!qobj) { |
419 | return; | |
420 | } | |
421 | qbool = qobject_to_qbool(qobj); | |
14b61600 | 422 | if (!qbool) { |
a9fc37f6 MA |
423 | error_setg(errp, QERR_INVALID_PARAMETER_TYPE, |
424 | full_name(qiv, name), "boolean"); | |
c40cc0a0 MR |
425 | return; |
426 | } | |
427 | ||
14b61600 | 428 | *obj = qbool_get_bool(qbool); |
c40cc0a0 MR |
429 | } |
430 | ||
cbd8acf3 DB |
431 | static void qobject_input_type_bool_keyval(Visitor *v, const char *name, |
432 | bool *obj, Error **errp) | |
433 | { | |
434 | QObjectInputVisitor *qiv = to_qiv(v); | |
435 | QObject *qobj = qobject_input_get_object(qiv, name, true, errp); | |
436 | QString *qstr; | |
437 | const char *str; | |
438 | ||
439 | if (!qobj) { | |
440 | return; | |
441 | } | |
442 | qstr = qobject_to_qstring(qobj); | |
443 | if (!qstr) { | |
444 | error_setg(errp, QERR_INVALID_PARAMETER_TYPE, | |
445 | full_name(qiv, name), "string"); | |
446 | return; | |
447 | } | |
448 | ||
449 | str = qstring_get_str(qstr); | |
450 | if (!strcmp(str, "on")) { | |
451 | *obj = true; | |
452 | } else if (!strcmp(str, "off")) { | |
453 | *obj = false; | |
454 | } else { | |
455 | error_setg(errp, QERR_INVALID_PARAMETER_VALUE, | |
456 | full_name(qiv, name), "'on' or 'off'"); | |
457 | } | |
458 | } | |
459 | ||
09e68369 DB |
460 | static void qobject_input_type_str(Visitor *v, const char *name, char **obj, |
461 | Error **errp) | |
c40cc0a0 | 462 | { |
09e68369 DB |
463 | QObjectInputVisitor *qiv = to_qiv(v); |
464 | QObject *qobj = qobject_input_get_object(qiv, name, true, errp); | |
1382d4ab | 465 | QString *qstr; |
c40cc0a0 | 466 | |
1382d4ab MAL |
467 | *obj = NULL; |
468 | if (!qobj) { | |
469 | return; | |
470 | } | |
471 | qstr = qobject_to_qstring(qobj); | |
7f027843 | 472 | if (!qstr) { |
a9fc37f6 MA |
473 | error_setg(errp, QERR_INVALID_PARAMETER_TYPE, |
474 | full_name(qiv, name), "string"); | |
c40cc0a0 MR |
475 | return; |
476 | } | |
477 | ||
7f027843 | 478 | *obj = g_strdup(qstring_get_str(qstr)); |
c40cc0a0 MR |
479 | } |
480 | ||
09e68369 DB |
481 | static void qobject_input_type_number(Visitor *v, const char *name, double *obj, |
482 | Error **errp) | |
c40cc0a0 | 483 | { |
09e68369 DB |
484 | QObjectInputVisitor *qiv = to_qiv(v); |
485 | QObject *qobj = qobject_input_get_object(qiv, name, true, errp); | |
fcf73f66 MA |
486 | QInt *qint; |
487 | QFloat *qfloat; | |
c40cc0a0 | 488 | |
1382d4ab MAL |
489 | if (!qobj) { |
490 | return; | |
491 | } | |
fcf73f66 MA |
492 | qint = qobject_to_qint(qobj); |
493 | if (qint) { | |
494 | *obj = qint_get_int(qobject_to_qint(qobj)); | |
c40cc0a0 MR |
495 | return; |
496 | } | |
497 | ||
fcf73f66 MA |
498 | qfloat = qobject_to_qfloat(qobj); |
499 | if (qfloat) { | |
1ee51876 | 500 | *obj = qfloat_get_double(qobject_to_qfloat(qobj)); |
fcf73f66 | 501 | return; |
1ee51876 | 502 | } |
fcf73f66 | 503 | |
a9fc37f6 MA |
504 | error_setg(errp, QERR_INVALID_PARAMETER_TYPE, |
505 | full_name(qiv, name), "number"); | |
c40cc0a0 MR |
506 | } |
507 | ||
cbd8acf3 DB |
508 | static void qobject_input_type_number_keyval(Visitor *v, const char *name, |
509 | double *obj, Error **errp) | |
510 | { | |
511 | QObjectInputVisitor *qiv = to_qiv(v); | |
512 | QObject *qobj = qobject_input_get_object(qiv, name, true, errp); | |
513 | QString *qstr; | |
514 | const char *str; | |
515 | char *endp; | |
516 | ||
517 | if (!qobj) { | |
518 | return; | |
519 | } | |
520 | qstr = qobject_to_qstring(qobj); | |
521 | if (!qstr) { | |
522 | error_setg(errp, QERR_INVALID_PARAMETER_TYPE, | |
523 | full_name(qiv, name), "string"); | |
524 | return; | |
525 | } | |
526 | ||
527 | str = qstring_get_str(qstr); | |
528 | errno = 0; | |
529 | *obj = strtod(str, &endp); | |
530 | if (errno || endp == str || *endp) { | |
531 | /* TODO report -ERANGE more nicely */ | |
532 | error_setg(errp, QERR_INVALID_PARAMETER_TYPE, | |
533 | full_name(qiv, name), "number"); | |
534 | } | |
535 | } | |
536 | ||
09e68369 DB |
537 | static void qobject_input_type_any(Visitor *v, const char *name, QObject **obj, |
538 | Error **errp) | |
28770e05 | 539 | { |
09e68369 DB |
540 | QObjectInputVisitor *qiv = to_qiv(v); |
541 | QObject *qobj = qobject_input_get_object(qiv, name, true, errp); | |
28770e05 | 542 | |
1382d4ab | 543 | *obj = NULL; |
c4897802 | 544 | if (!qobj) { |
c4897802 MAL |
545 | return; |
546 | } | |
547 | ||
28770e05 MA |
548 | qobject_incref(qobj); |
549 | *obj = qobj; | |
550 | } | |
551 | ||
09e68369 | 552 | static void qobject_input_type_null(Visitor *v, const char *name, Error **errp) |
3bc97fd5 | 553 | { |
09e68369 DB |
554 | QObjectInputVisitor *qiv = to_qiv(v); |
555 | QObject *qobj = qobject_input_get_object(qiv, name, true, errp); | |
3df016f1 | 556 | |
c4897802 | 557 | if (!qobj) { |
c4897802 MAL |
558 | return; |
559 | } | |
560 | ||
3df016f1 | 561 | if (qobject_type(qobj) != QTYPE_QNULL) { |
a9fc37f6 MA |
562 | error_setg(errp, QERR_INVALID_PARAMETER_TYPE, |
563 | full_name(qiv, name), "null"); | |
3df016f1 | 564 | } |
3bc97fd5 EB |
565 | } |
566 | ||
cbd8acf3 DB |
567 | static void qobject_input_type_size_keyval(Visitor *v, const char *name, |
568 | uint64_t *obj, Error **errp) | |
569 | { | |
570 | QObjectInputVisitor *qiv = to_qiv(v); | |
571 | QObject *qobj = qobject_input_get_object(qiv, name, true, errp); | |
572 | QString *qstr; | |
573 | ||
574 | if (!qobj) { | |
575 | return; | |
576 | } | |
577 | qstr = qobject_to_qstring(qobj); | |
578 | if (!qstr) { | |
579 | error_setg(errp, QERR_INVALID_PARAMETER_TYPE, | |
580 | full_name(qiv, name), "string"); | |
581 | return; | |
582 | } | |
583 | ||
584 | if (qemu_strtosz(qstring_get_str(qstr), NULL, obj) < 0) { | |
585 | /* TODO report -ERANGE more nicely */ | |
586 | error_setg(errp, QERR_INVALID_PARAMETER_VALUE, | |
587 | full_name(qiv, name), "size"); | |
588 | } | |
589 | } | |
590 | ||
09e68369 | 591 | static void qobject_input_optional(Visitor *v, const char *name, bool *present) |
c40cc0a0 | 592 | { |
09e68369 | 593 | QObjectInputVisitor *qiv = to_qiv(v); |
a9fc37f6 | 594 | QObject *qobj = qobject_input_try_get_object(qiv, name, false); |
c40cc0a0 MR |
595 | |
596 | if (!qobj) { | |
597 | *present = false; | |
598 | return; | |
599 | } | |
600 | ||
601 | *present = true; | |
602 | } | |
603 | ||
09e68369 | 604 | static void qobject_input_free(Visitor *v) |
2c0ef9f4 | 605 | { |
09e68369 | 606 | QObjectInputVisitor *qiv = to_qiv(v); |
a9fc37f6 | 607 | |
3d344c2a PB |
608 | while (!QSLIST_EMPTY(&qiv->stack)) { |
609 | StackObject *tos = QSLIST_FIRST(&qiv->stack); | |
610 | ||
611 | QSLIST_REMOVE_HEAD(&qiv->stack, node); | |
09e68369 | 612 | qobject_input_stack_object_free(tos); |
3d344c2a | 613 | } |
2c0ef9f4 | 614 | |
b70ce101 | 615 | qobject_decref(qiv->root); |
a9fc37f6 MA |
616 | if (qiv->errname) { |
617 | g_string_free(qiv->errname, TRUE); | |
618 | } | |
b70ce101 | 619 | g_free(qiv); |
2c0ef9f4 EB |
620 | } |
621 | ||
abe81bc2 | 622 | static QObjectInputVisitor *qobject_input_visitor_base_new(QObject *obj) |
c40cc0a0 | 623 | { |
abe81bc2 | 624 | QObjectInputVisitor *v = g_malloc0(sizeof(*v)); |
c40cc0a0 | 625 | |
5d0cbbcf | 626 | assert(obj); |
c40cc0a0 | 627 | |
983f52d4 | 628 | v->visitor.type = VISITOR_INPUT; |
09e68369 DB |
629 | v->visitor.start_struct = qobject_input_start_struct; |
630 | v->visitor.check_struct = qobject_input_check_struct; | |
631 | v->visitor.end_struct = qobject_input_pop; | |
632 | v->visitor.start_list = qobject_input_start_list; | |
633 | v->visitor.next_list = qobject_input_next_list; | |
a4a1c70d | 634 | v->visitor.check_list = qobject_input_check_list; |
09e68369 DB |
635 | v->visitor.end_list = qobject_input_pop; |
636 | v->visitor.start_alternate = qobject_input_start_alternate; | |
abe81bc2 MA |
637 | v->visitor.optional = qobject_input_optional; |
638 | v->visitor.free = qobject_input_free; | |
639 | ||
640 | v->root = obj; | |
641 | qobject_incref(obj); | |
642 | ||
643 | return v; | |
644 | } | |
645 | ||
646 | Visitor *qobject_input_visitor_new(QObject *obj) | |
647 | { | |
648 | QObjectInputVisitor *v = qobject_input_visitor_base_new(obj); | |
649 | ||
09e68369 DB |
650 | v->visitor.type_int64 = qobject_input_type_int64; |
651 | v->visitor.type_uint64 = qobject_input_type_uint64; | |
652 | v->visitor.type_bool = qobject_input_type_bool; | |
653 | v->visitor.type_str = qobject_input_type_str; | |
654 | v->visitor.type_number = qobject_input_type_number; | |
655 | v->visitor.type_any = qobject_input_type_any; | |
656 | v->visitor.type_null = qobject_input_type_null; | |
c40cc0a0 | 657 | |
b70ce101 | 658 | return &v->visitor; |
c40cc0a0 | 659 | } |
cbd8acf3 DB |
660 | |
661 | Visitor *qobject_input_visitor_new_keyval(QObject *obj) | |
662 | { | |
abe81bc2 | 663 | QObjectInputVisitor *v = qobject_input_visitor_base_new(obj); |
cbd8acf3 | 664 | |
cbd8acf3 DB |
665 | v->visitor.type_int64 = qobject_input_type_int64_keyval; |
666 | v->visitor.type_uint64 = qobject_input_type_uint64_keyval; | |
667 | v->visitor.type_bool = qobject_input_type_bool_keyval; | |
668 | v->visitor.type_str = qobject_input_type_str; | |
669 | v->visitor.type_number = qobject_input_type_number_keyval; | |
670 | v->visitor.type_any = qobject_input_type_any; | |
671 | v->visitor.type_null = qobject_input_type_null; | |
672 | v->visitor.type_size = qobject_input_type_size_keyval; | |
cbd8acf3 DB |
673 | |
674 | return &v->visitor; | |
675 | } |