blob: 3e235a1eeefda7a10082becd2af8fd8a7e1b7a6c [file] [log] [blame]
Michael Rothc40cc0a2011-07-19 14:50:33 -05001/*
2 * Input Visitor
3 *
Daniel P. Berrangecbd8acf2017-02-28 22:26:50 +01004 * Copyright (C) 2012-2017 Red Hat, Inc.
Michael Rothc40cc0a2011-07-19 14:50:33 -05005 * 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
Peter Maydellcbf21152016-01-29 17:49:57 +000015#include "qemu/osdep.h"
Markus Armbruster5891c382017-05-22 18:42:12 +020016#include <math.h>
Markus Armbrusterda34e652016-03-14 09:01:28 +010017#include "qapi/error.h"
Daniel P. Berrangeb3db2112016-09-30 15:45:27 +010018#include "qapi/qobject-input-visitor.h"
Paolo Bonzini7b1b5d12012-12-17 18:19:43 +010019#include "qapi/visitor-impl.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010020#include "qemu/queue.h"
Michael Rothc40cc0a2011-07-19 14:50:33 -050021#include "qemu-common.h"
Markus Armbruster9d1eab42017-02-28 22:27:06 +010022#include "qapi/qmp/qjson.h"
Markus Armbruster6b673952018-02-01 12:18:35 +010023#include "qapi/qmp/qbool.h"
Paolo Bonzini7b1b5d12012-12-17 18:19:43 +010024#include "qapi/qmp/qerror.h"
Markus Armbruster47e6b292018-02-01 12:18:38 +010025#include "qapi/qmp/qlist.h"
Markus Armbruster15280c32018-02-01 12:18:36 +010026#include "qapi/qmp/qnull.h"
27#include "qapi/qmp/qnum.h"
Daniel P. Berrangecbd8acf2017-02-28 22:26:50 +010028#include "qemu/cutils.h"
Markus Armbruster9d1eab42017-02-28 22:27:06 +010029#include "qemu/option.h"
Michael Rothc40cc0a2011-07-19 14:50:33 -050030
Markus Armbrustera9fc37f2017-03-03 13:32:34 +010031typedef struct StackObject {
32 const char *name; /* Name of @obj in its parent, if any */
33 QObject *obj; /* QDict or QList being visited */
Eric Blake1158bb22016-06-09 10:48:34 -060034 void *qapi; /* sanity check that caller uses same pointer */
Eric Blakeb471d012016-04-28 15:45:12 -060035
Markus Armbrustera9fc37f2017-03-03 13:32:34 +010036 GHashTable *h; /* If @obj is QDict: unvisited keys */
37 const QListEntry *entry; /* If @obj is QList: unvisited tail */
38 unsigned index; /* If @obj is QList: list index of @entry */
Paolo Bonzini3d344c22016-07-07 17:53:18 +020039
Markus Armbrustera9fc37f2017-03-03 13:32:34 +010040 QSLIST_ENTRY(StackObject) node; /* parent */
Michael Rothc40cc0a2011-07-19 14:50:33 -050041} StackObject;
42
Markus Armbrustera9fc37f2017-03-03 13:32:34 +010043struct QObjectInputVisitor {
Michael Rothc40cc0a2011-07-19 14:50:33 -050044 Visitor visitor;
Eric Blakeb471d012016-04-28 15:45:12 -060045
Eric Blakece140b12016-04-28 15:45:18 -060046 /* Root of visit at visitor creation. */
47 QObject *root;
Markus Armbruster0b2c1be2017-02-28 22:27:10 +010048 bool keyval; /* Assume @root made with keyval_parse() */
Eric Blakece140b12016-04-28 15:45:18 -060049
50 /* Stack of objects being visited (all entries will be either
51 * QDict or QList). */
Paolo Bonzini3d344c22016-07-07 17:53:18 +020052 QSLIST_HEAD(, StackObject) stack;
Eric Blakeb471d012016-04-28 15:45:12 -060053
Markus Armbrustera9fc37f2017-03-03 13:32:34 +010054 GString *errname; /* Accumulator for full_name() */
Michael Rothc40cc0a2011-07-19 14:50:33 -050055};
56
Daniel P. Berrange09e68362016-09-30 15:45:27 +010057static QObjectInputVisitor *to_qiv(Visitor *v)
Michael Rothc40cc0a2011-07-19 14:50:33 -050058{
Daniel P. Berrange09e68362016-09-30 15:45:27 +010059 return container_of(v, QObjectInputVisitor, visitor);
Michael Rothc40cc0a2011-07-19 14:50:33 -050060}
61
Markus Armbruster6c022582017-04-27 10:41:24 +020062/*
63 * Find the full name of something @qiv is currently visiting.
64 * @qiv is visiting something named @name in the stack of containers
65 * @qiv->stack.
66 * If @n is zero, return its full name.
67 * If @n is positive, return the full name of the @n-th container
68 * counting from the top. The stack of containers must have at least
69 * @n elements.
70 * The returned string is valid until the next full_name_nth(@v) or
71 * destruction of @v.
72 */
Markus Armbrustera4a1c702017-03-03 13:32:45 +010073static const char *full_name_nth(QObjectInputVisitor *qiv, const char *name,
74 int n)
Markus Armbrustera9fc37f2017-03-03 13:32:34 +010075{
76 StackObject *so;
77 char buf[32];
78
79 if (qiv->errname) {
80 g_string_truncate(qiv->errname, 0);
81 } else {
82 qiv->errname = g_string_new("");
83 }
84
85 QSLIST_FOREACH(so , &qiv->stack, node) {
Markus Armbrustera4a1c702017-03-03 13:32:45 +010086 if (n) {
87 n--;
88 } else if (qobject_type(so->obj) == QTYPE_QDICT) {
89 g_string_prepend(qiv->errname, name ?: "<anonymous>");
Markus Armbrustera9fc37f2017-03-03 13:32:34 +010090 g_string_prepend_c(qiv->errname, '.');
91 } else {
Markus Armbruster0b2c1be2017-02-28 22:27:10 +010092 snprintf(buf, sizeof(buf),
93 qiv->keyval ? ".%u" : "[%u]",
94 so->index);
Markus Armbrustera9fc37f2017-03-03 13:32:34 +010095 g_string_prepend(qiv->errname, buf);
96 }
97 name = so->name;
98 }
Markus Armbrustera4a1c702017-03-03 13:32:45 +010099 assert(!n);
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100100
101 if (name) {
102 g_string_prepend(qiv->errname, name);
103 } else if (qiv->errname->str[0] == '.') {
104 g_string_erase(qiv->errname, 0, 1);
Markus Armbrustera4a1c702017-03-03 13:32:45 +0100105 } else if (!qiv->errname->str[0]) {
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100106 return "<anonymous>";
107 }
108
109 return qiv->errname->str;
110}
111
Markus Armbrustera4a1c702017-03-03 13:32:45 +0100112static const char *full_name(QObjectInputVisitor *qiv, const char *name)
113{
114 return full_name_nth(qiv, name, 0);
115}
116
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100117static QObject *qobject_input_try_get_object(QObjectInputVisitor *qiv,
118 const char *name,
119 bool consume)
Michael Rothc40cc0a2011-07-19 14:50:33 -0500120{
Eric Blakece140b12016-04-28 15:45:18 -0600121 StackObject *tos;
122 QObject *qobj;
Eric Blakee5826a22016-04-28 15:45:15 -0600123 QObject *ret;
Michael Rothc40cc0a2011-07-19 14:50:33 -0500124
Paolo Bonzini3d344c22016-07-07 17:53:18 +0200125 if (QSLIST_EMPTY(&qiv->stack)) {
Eric Blakece140b12016-04-28 15:45:18 -0600126 /* Starting at root, name is ignored. */
Marc-André Lureau5d0cbbc2016-09-30 13:59:46 +0400127 assert(qiv->root);
Eric Blakece140b12016-04-28 15:45:18 -0600128 return qiv->root;
129 }
130
131 /* We are in a container; find the next element. */
Paolo Bonzini3d344c22016-07-07 17:53:18 +0200132 tos = QSLIST_FIRST(&qiv->stack);
Eric Blakece140b12016-04-28 15:45:18 -0600133 qobj = tos->obj;
Eric Blakeb471d012016-04-28 15:45:12 -0600134 assert(qobj);
135
Eric Blakece140b12016-04-28 15:45:18 -0600136 if (qobject_type(qobj) == QTYPE_QDICT) {
137 assert(name);
Eric Blakee5826a22016-04-28 15:45:15 -0600138 ret = qdict_get(qobject_to_qdict(qobj), name);
139 if (tos->h && consume && ret) {
140 bool removed = g_hash_table_remove(tos->h, name);
141 assert(removed);
Paolo Bonzini47c6d3e2011-12-18 17:05:04 +0100142 }
Eric Blakece140b12016-04-28 15:45:18 -0600143 } else {
Eric Blakeb471d012016-04-28 15:45:12 -0600144 assert(qobject_type(qobj) == QTYPE_QLIST);
Eric Blakece140b12016-04-28 15:45:18 -0600145 assert(!name);
Markus Armbruster1f41a642017-03-03 13:32:47 +0100146 if (tos->entry) {
147 ret = qlist_entry_obj(tos->entry);
148 if (consume) {
149 tos->entry = qlist_next(tos->entry);
150 }
151 } else {
152 ret = NULL;
153 }
Eric Blakefcf3cb22016-04-28 15:45:19 -0600154 if (consume) {
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100155 tos->index++;
Eric Blakefcf3cb22016-04-28 15:45:19 -0600156 }
Eric Blakeb471d012016-04-28 15:45:12 -0600157 }
158
Eric Blakece140b12016-04-28 15:45:18 -0600159 return ret;
Michael Rothc40cc0a2011-07-19 14:50:33 -0500160}
161
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100162static QObject *qobject_input_get_object(QObjectInputVisitor *qiv,
163 const char *name,
164 bool consume, Error **errp)
165{
166 QObject *obj = qobject_input_try_get_object(qiv, name, consume);
167
168 if (!obj) {
169 error_setg(errp, QERR_MISSING_PARAMETER, full_name(qiv, name));
170 }
171 return obj;
172}
173
Markus Armbrustere3934b42017-02-28 22:26:53 +0100174static const char *qobject_input_get_keyval(QObjectInputVisitor *qiv,
175 const char *name,
176 Error **errp)
177{
178 QObject *qobj;
179 QString *qstr;
180
181 qobj = qobject_input_get_object(qiv, name, true, errp);
182 if (!qobj) {
183 return NULL;
184 }
185
186 qstr = qobject_to_qstring(qobj);
187 if (!qstr) {
Markus Armbruster31478f22017-02-28 22:27:08 +0100188 switch (qobject_type(qobj)) {
189 case QTYPE_QDICT:
190 case QTYPE_QLIST:
191 error_setg(errp, "Parameters '%s.*' are unexpected",
192 full_name(qiv, name));
193 return NULL;
194 default:
195 /* Non-string scalar (should this be an assertion?) */
196 error_setg(errp, "Internal error: parameter %s invalid",
197 full_name(qiv, name));
198 return NULL;
199 }
Markus Armbrustere3934b42017-02-28 22:26:53 +0100200 }
201
202 return qstring_get_str(qstr);
203}
204
Paolo Bonzinie38ac962012-03-22 12:51:10 +0100205static void qdict_add_key(const char *key, QObject *obj, void *opaque)
206{
207 GHashTable *h = opaque;
208 g_hash_table_insert(h, (gpointer) key, NULL);
209}
210
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100211static const QListEntry *qobject_input_push(QObjectInputVisitor *qiv,
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100212 const char *name,
Markus Armbrusterb8874fb2017-03-03 13:32:32 +0100213 QObject *obj, void *qapi)
Michael Rothc40cc0a2011-07-19 14:50:33 -0500214{
Paolo Bonzinie38ac962012-03-22 12:51:10 +0100215 GHashTable *h;
Paolo Bonzini3d344c22016-07-07 17:53:18 +0200216 StackObject *tos = g_new0(StackObject, 1);
Michael Rothc40cc0a2011-07-19 14:50:33 -0500217
Eric Blakeb471d012016-04-28 15:45:12 -0600218 assert(obj);
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100219 tos->name = name;
Eric Blakeb471d012016-04-28 15:45:12 -0600220 tos->obj = obj;
Eric Blake1158bb22016-06-09 10:48:34 -0600221 tos->qapi = qapi;
Paolo Bonzinie38ac962012-03-22 12:51:10 +0100222
Markus Armbruster048abb72017-03-03 13:32:39 +0100223 if (qobject_type(obj) == QTYPE_QDICT) {
Paolo Bonzinie38ac962012-03-22 12:51:10 +0100224 h = g_hash_table_new(g_str_hash, g_str_equal);
225 qdict_iter(qobject_to_qdict(obj), qdict_add_key, h);
Eric Blakeb471d012016-04-28 15:45:12 -0600226 tos->h = h;
Markus Armbruster048abb72017-03-03 13:32:39 +0100227 } else {
228 assert(qobject_type(obj) == QTYPE_QLIST);
Eric Blakefcf3cb22016-04-28 15:45:19 -0600229 tos->entry = qlist_first(qobject_to_qlist(obj));
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100230 tos->index = -1;
Paolo Bonzinie38ac962012-03-22 12:51:10 +0100231 }
232
Paolo Bonzini3d344c22016-07-07 17:53:18 +0200233 QSLIST_INSERT_HEAD(&qiv->stack, tos, node);
Eric Blaked9f62dd2016-04-28 15:45:31 -0600234 return tos->entry;
Michael Rothc40cc0a2011-07-19 14:50:33 -0500235}
236
NODA, Kai57a33d82012-04-21 22:41:27 +0900237
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100238static void qobject_input_check_struct(Visitor *v, Error **errp)
Michael Rothc40cc0a2011-07-19 14:50:33 -0500239{
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100240 QObjectInputVisitor *qiv = to_qiv(v);
Paolo Bonzini3d344c22016-07-07 17:53:18 +0200241 StackObject *tos = QSLIST_FIRST(&qiv->stack);
Markus Armbruster048abb72017-03-03 13:32:39 +0100242 GHashTableIter iter;
243 const char *key;
Eric Blake15c2f662016-04-28 15:45:27 -0600244
Paolo Bonzini3d344c22016-07-07 17:53:18 +0200245 assert(tos && !tos->entry);
Eric Blakef96493b2016-02-17 23:48:15 -0700246
Markus Armbruster048abb72017-03-03 13:32:39 +0100247 g_hash_table_iter_init(&iter, tos->h);
248 if (g_hash_table_iter_next(&iter, (void **)&key, NULL)) {
249 error_setg(errp, "Parameter '%s' is unexpected",
250 full_name(qiv, key));
Eric Blake15c2f662016-04-28 15:45:27 -0600251 }
252}
253
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100254static void qobject_input_stack_object_free(StackObject *tos)
Paolo Bonzini3d344c22016-07-07 17:53:18 +0200255{
256 if (tos->h) {
257 g_hash_table_unref(tos->h);
258 }
259
260 g_free(tos);
261}
262
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100263static void qobject_input_pop(Visitor *v, void **obj)
Eric Blake15c2f662016-04-28 15:45:27 -0600264{
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100265 QObjectInputVisitor *qiv = to_qiv(v);
Paolo Bonzini3d344c22016-07-07 17:53:18 +0200266 StackObject *tos = QSLIST_FIRST(&qiv->stack);
Eric Blake15c2f662016-04-28 15:45:27 -0600267
Paolo Bonzini3d344c22016-07-07 17:53:18 +0200268 assert(tos && tos->qapi == obj);
269 QSLIST_REMOVE_HEAD(&qiv->stack, node);
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100270 qobject_input_stack_object_free(tos);
Michael Rothc40cc0a2011-07-19 14:50:33 -0500271}
272
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100273static void qobject_input_start_struct(Visitor *v, const char *name, void **obj,
274 size_t size, Error **errp)
Michael Rothc40cc0a2011-07-19 14:50:33 -0500275{
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100276 QObjectInputVisitor *qiv = to_qiv(v);
277 QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
Michael Rothc40cc0a2011-07-19 14:50:33 -0500278
Eric Blakee58d6952016-04-28 15:45:10 -0600279 if (obj) {
280 *obj = NULL;
281 }
Marc-André Lureau1382d4a2016-09-30 13:59:48 +0400282 if (!qobj) {
283 return;
284 }
285 if (qobject_type(qobj) != QTYPE_QDICT) {
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100286 error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
287 full_name(qiv, name), "object");
Michael Rothc40cc0a2011-07-19 14:50:33 -0500288 return;
289 }
290
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100291 qobject_input_push(qiv, name, qobj, obj);
Michael Rothc40cc0a2011-07-19 14:50:33 -0500292
293 if (obj) {
Anthony Liguori7267c092011-08-20 22:09:37 -0500294 *obj = g_malloc0(size);
Michael Rothc40cc0a2011-07-19 14:50:33 -0500295 }
296}
297
Markus Armbruster8b2e41d2017-04-27 10:41:26 +0200298static void qobject_input_end_struct(Visitor *v, void **obj)
299{
300 QObjectInputVisitor *qiv = to_qiv(v);
301 StackObject *tos = QSLIST_FIRST(&qiv->stack);
302
303 assert(qobject_type(tos->obj) == QTYPE_QDICT && tos->h);
304 qobject_input_pop(v, obj);
305}
306
Michael Rothc40cc0a2011-07-19 14:50:33 -0500307
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100308static void qobject_input_start_list(Visitor *v, const char *name,
309 GenericList **list, size_t size,
310 Error **errp)
Michael Rothc40cc0a2011-07-19 14:50:33 -0500311{
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100312 QObjectInputVisitor *qiv = to_qiv(v);
313 QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
Eric Blaked9f62dd2016-04-28 15:45:31 -0600314 const QListEntry *entry;
Michael Rothc40cc0a2011-07-19 14:50:33 -0500315
Markus Armbruster58561c22017-03-03 13:32:33 +0100316 if (list) {
317 *list = NULL;
318 }
Marc-André Lureau1382d4a2016-09-30 13:59:48 +0400319 if (!qobj) {
320 return;
321 }
322 if (qobject_type(qobj) != QTYPE_QLIST) {
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100323 error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
324 full_name(qiv, name), "array");
Michael Rothc40cc0a2011-07-19 14:50:33 -0500325 return;
326 }
327
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100328 entry = qobject_input_push(qiv, name, qobj, list);
Markus Armbruster58561c22017-03-03 13:32:33 +0100329 if (entry && list) {
330 *list = g_malloc0(size);
Eric Blaked9f62dd2016-04-28 15:45:31 -0600331 }
Michael Rothc40cc0a2011-07-19 14:50:33 -0500332}
333
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100334static GenericList *qobject_input_next_list(Visitor *v, GenericList *tail,
335 size_t size)
Michael Rothc40cc0a2011-07-19 14:50:33 -0500336{
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100337 QObjectInputVisitor *qiv = to_qiv(v);
Markus Armbrustera4a1c702017-03-03 13:32:45 +0100338 StackObject *tos = QSLIST_FIRST(&qiv->stack);
Paolo Bonzini3a86a0f2012-03-22 22:38:40 +0100339
Markus Armbrustera4a1c702017-03-03 13:32:45 +0100340 assert(tos && tos->obj && qobject_type(tos->obj) == QTYPE_QLIST);
341
342 if (!tos->entry) {
Michael Rothc40cc0a2011-07-19 14:50:33 -0500343 return NULL;
344 }
Eric Blaked9f62dd2016-04-28 15:45:31 -0600345 tail->next = g_malloc0(size);
346 return tail->next;
Michael Rothc40cc0a2011-07-19 14:50:33 -0500347}
348
Markus Armbrustera4a1c702017-03-03 13:32:45 +0100349static void qobject_input_check_list(Visitor *v, Error **errp)
350{
351 QObjectInputVisitor *qiv = to_qiv(v);
352 StackObject *tos = QSLIST_FIRST(&qiv->stack);
353
354 assert(tos && tos->obj && qobject_type(tos->obj) == QTYPE_QLIST);
355
356 if (tos->entry) {
357 error_setg(errp, "Only %u list elements expected in %s",
358 tos->index + 1, full_name_nth(qiv, NULL, 1));
359 }
360}
361
Markus Armbruster8b2e41d2017-04-27 10:41:26 +0200362static void qobject_input_end_list(Visitor *v, void **obj)
363{
364 QObjectInputVisitor *qiv = to_qiv(v);
365 StackObject *tos = QSLIST_FIRST(&qiv->stack);
366
367 assert(qobject_type(tos->obj) == QTYPE_QLIST && !tos->h);
368 qobject_input_pop(v, obj);
369}
Michael Rothc40cc0a2011-07-19 14:50:33 -0500370
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100371static void qobject_input_start_alternate(Visitor *v, const char *name,
372 GenericAlternate **obj, size_t size,
Marc-André Lureau60390d22017-06-07 20:35:59 +0400373 Error **errp)
Kevin Wolf69dd62d2013-07-08 16:14:21 +0200374{
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100375 QObjectInputVisitor *qiv = to_qiv(v);
376 QObject *qobj = qobject_input_get_object(qiv, name, false, errp);
Kevin Wolf69dd62d2013-07-08 16:14:21 +0200377
378 if (!qobj) {
Eric Blakedbf11922016-02-17 23:48:29 -0700379 *obj = NULL;
Kevin Wolf69dd62d2013-07-08 16:14:21 +0200380 return;
381 }
Eric Blakedbf11922016-02-17 23:48:29 -0700382 *obj = g_malloc0(size);
383 (*obj)->type = qobject_type(qobj);
Kevin Wolf69dd62d2013-07-08 16:14:21 +0200384}
385
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100386static void qobject_input_type_int64(Visitor *v, const char *name, int64_t *obj,
387 Error **errp)
Michael Rothc40cc0a2011-07-19 14:50:33 -0500388{
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100389 QObjectInputVisitor *qiv = to_qiv(v);
390 QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
Marc-André Lureau01b2ffc2017-06-07 20:35:58 +0400391 QNum *qnum;
Michael Rothc40cc0a2011-07-19 14:50:33 -0500392
Marc-André Lureau1382d4a2016-09-30 13:59:48 +0400393 if (!qobj) {
394 return;
395 }
Marc-André Lureau01b2ffc2017-06-07 20:35:58 +0400396 qnum = qobject_to_qnum(qobj);
397 if (!qnum || !qnum_get_try_int(qnum, obj)) {
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100398 error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
399 full_name(qiv, name), "integer");
Michael Rothc40cc0a2011-07-19 14:50:33 -0500400 }
Michael Rothc40cc0a2011-07-19 14:50:33 -0500401}
402
Daniel P. Berrangecbd8acf2017-02-28 22:26:50 +0100403static void qobject_input_type_int64_keyval(Visitor *v, const char *name,
404 int64_t *obj, Error **errp)
405{
406 QObjectInputVisitor *qiv = to_qiv(v);
Markus Armbrustere3934b42017-02-28 22:26:53 +0100407 const char *str = qobject_input_get_keyval(qiv, name, errp);
Daniel P. Berrangecbd8acf2017-02-28 22:26:50 +0100408
Markus Armbrustere3934b42017-02-28 22:26:53 +0100409 if (!str) {
Daniel P. Berrangecbd8acf2017-02-28 22:26:50 +0100410 return;
411 }
412
Markus Armbrustere3934b42017-02-28 22:26:53 +0100413 if (qemu_strtoi64(str, NULL, 0, obj) < 0) {
Daniel P. Berrangecbd8acf2017-02-28 22:26:50 +0100414 /* TODO report -ERANGE more nicely */
415 error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
416 full_name(qiv, name), "integer");
417 }
418}
419
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100420static void qobject_input_type_uint64(Visitor *v, const char *name,
421 uint64_t *obj, Error **errp)
Eric Blakef755dea2016-01-29 06:48:50 -0700422{
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100423 QObjectInputVisitor *qiv = to_qiv(v);
424 QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
Marc-André Lureau01b2ffc2017-06-07 20:35:58 +0400425 QNum *qnum;
426 int64_t val;
Eric Blakef755dea2016-01-29 06:48:50 -0700427
Marc-André Lureau1382d4a2016-09-30 13:59:48 +0400428 if (!qobj) {
429 return;
430 }
Marc-André Lureau01b2ffc2017-06-07 20:35:58 +0400431 qnum = qobject_to_qnum(qobj);
Marc-André Lureau5923f852017-06-07 20:36:03 +0400432 if (!qnum) {
433 goto err;
Eric Blakef755dea2016-01-29 06:48:50 -0700434 }
Marc-André Lureau5923f852017-06-07 20:36:03 +0400435
436 if (qnum_get_try_uint(qnum, obj)) {
437 return;
438 }
439
440 /* Need to accept negative values for backward compatibility */
441 if (qnum_get_try_int(qnum, &val)) {
442 *obj = val;
443 return;
444 }
445
446err:
447 error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
448 full_name(qiv, name), "uint64");
Eric Blakef755dea2016-01-29 06:48:50 -0700449}
450
Daniel P. Berrangecbd8acf2017-02-28 22:26:50 +0100451static void qobject_input_type_uint64_keyval(Visitor *v, const char *name,
452 uint64_t *obj, Error **errp)
453{
454 QObjectInputVisitor *qiv = to_qiv(v);
Markus Armbrustere3934b42017-02-28 22:26:53 +0100455 const char *str = qobject_input_get_keyval(qiv, name, errp);
Daniel P. Berrangecbd8acf2017-02-28 22:26:50 +0100456
Markus Armbrustere3934b42017-02-28 22:26:53 +0100457 if (!str) {
Daniel P. Berrangecbd8acf2017-02-28 22:26:50 +0100458 return;
459 }
460
Markus Armbrustere3934b42017-02-28 22:26:53 +0100461 if (qemu_strtou64(str, NULL, 0, obj) < 0) {
Daniel P. Berrangecbd8acf2017-02-28 22:26:50 +0100462 /* TODO report -ERANGE more nicely */
463 error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
464 full_name(qiv, name), "integer");
465 }
466}
467
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100468static void qobject_input_type_bool(Visitor *v, const char *name, bool *obj,
469 Error **errp)
Michael Rothc40cc0a2011-07-19 14:50:33 -0500470{
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100471 QObjectInputVisitor *qiv = to_qiv(v);
472 QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
Marc-André Lureau1382d4a2016-09-30 13:59:48 +0400473 QBool *qbool;
Michael Rothc40cc0a2011-07-19 14:50:33 -0500474
Marc-André Lureau1382d4a2016-09-30 13:59:48 +0400475 if (!qobj) {
476 return;
477 }
478 qbool = qobject_to_qbool(qobj);
Markus Armbruster14b61602015-10-15 16:15:33 +0200479 if (!qbool) {
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100480 error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
481 full_name(qiv, name), "boolean");
Michael Rothc40cc0a2011-07-19 14:50:33 -0500482 return;
483 }
484
Markus Armbruster14b61602015-10-15 16:15:33 +0200485 *obj = qbool_get_bool(qbool);
Michael Rothc40cc0a2011-07-19 14:50:33 -0500486}
487
Daniel P. Berrangecbd8acf2017-02-28 22:26:50 +0100488static void qobject_input_type_bool_keyval(Visitor *v, const char *name,
489 bool *obj, Error **errp)
490{
491 QObjectInputVisitor *qiv = to_qiv(v);
Markus Armbrustere3934b42017-02-28 22:26:53 +0100492 const char *str = qobject_input_get_keyval(qiv, name, errp);
Daniel P. Berrangecbd8acf2017-02-28 22:26:50 +0100493
Markus Armbrustere3934b42017-02-28 22:26:53 +0100494 if (!str) {
Daniel P. Berrangecbd8acf2017-02-28 22:26:50 +0100495 return;
496 }
497
Daniel P. Berrangecbd8acf2017-02-28 22:26:50 +0100498 if (!strcmp(str, "on")) {
499 *obj = true;
500 } else if (!strcmp(str, "off")) {
501 *obj = false;
502 } else {
503 error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
504 full_name(qiv, name), "'on' or 'off'");
505 }
506}
507
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100508static void qobject_input_type_str(Visitor *v, const char *name, char **obj,
509 Error **errp)
Michael Rothc40cc0a2011-07-19 14:50:33 -0500510{
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100511 QObjectInputVisitor *qiv = to_qiv(v);
512 QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
Marc-André Lureau1382d4a2016-09-30 13:59:48 +0400513 QString *qstr;
Michael Rothc40cc0a2011-07-19 14:50:33 -0500514
Marc-André Lureau1382d4a2016-09-30 13:59:48 +0400515 *obj = NULL;
516 if (!qobj) {
517 return;
518 }
519 qstr = qobject_to_qstring(qobj);
Markus Armbruster7f027842015-10-15 16:15:37 +0200520 if (!qstr) {
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100521 error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
522 full_name(qiv, name), "string");
Michael Rothc40cc0a2011-07-19 14:50:33 -0500523 return;
524 }
525
Markus Armbruster7f027842015-10-15 16:15:37 +0200526 *obj = g_strdup(qstring_get_str(qstr));
Michael Rothc40cc0a2011-07-19 14:50:33 -0500527}
528
Markus Armbruster31478f22017-02-28 22:27:08 +0100529static void qobject_input_type_str_keyval(Visitor *v, const char *name,
530 char **obj, Error **errp)
531{
532 QObjectInputVisitor *qiv = to_qiv(v);
533 const char *str = qobject_input_get_keyval(qiv, name, errp);
534
535 *obj = g_strdup(str);
536}
537
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100538static void qobject_input_type_number(Visitor *v, const char *name, double *obj,
539 Error **errp)
Michael Rothc40cc0a2011-07-19 14:50:33 -0500540{
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100541 QObjectInputVisitor *qiv = to_qiv(v);
542 QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
Marc-André Lureau01b2ffc2017-06-07 20:35:58 +0400543 QNum *qnum;
Michael Rothc40cc0a2011-07-19 14:50:33 -0500544
Marc-André Lureau1382d4a2016-09-30 13:59:48 +0400545 if (!qobj) {
546 return;
547 }
Marc-André Lureau01b2ffc2017-06-07 20:35:58 +0400548 qnum = qobject_to_qnum(qobj);
549 if (!qnum) {
Marc-André Lureau58634042017-06-07 20:35:57 +0400550 error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
551 full_name(qiv, name), "number");
Markus Armbrusterfcf73f62015-10-15 16:15:35 +0200552 return;
Michael Roth1ee51872012-05-11 12:43:24 -0500553 }
Markus Armbrusterfcf73f62015-10-15 16:15:35 +0200554
Marc-André Lureau01b2ffc2017-06-07 20:35:58 +0400555 *obj = qnum_get_double(qnum);
Michael Rothc40cc0a2011-07-19 14:50:33 -0500556}
557
Daniel P. Berrangecbd8acf2017-02-28 22:26:50 +0100558static void qobject_input_type_number_keyval(Visitor *v, const char *name,
559 double *obj, Error **errp)
560{
561 QObjectInputVisitor *qiv = to_qiv(v);
Markus Armbrustere3934b42017-02-28 22:26:53 +0100562 const char *str = qobject_input_get_keyval(qiv, name, errp);
Daniel P. Berrangecbd8acf2017-02-28 22:26:50 +0100563 char *endp;
564
Markus Armbrustere3934b42017-02-28 22:26:53 +0100565 if (!str) {
Daniel P. Berrangecbd8acf2017-02-28 22:26:50 +0100566 return;
567 }
568
Daniel P. Berrangecbd8acf2017-02-28 22:26:50 +0100569 errno = 0;
570 *obj = strtod(str, &endp);
Markus Armbruster5891c382017-05-22 18:42:12 +0200571 if (errno || endp == str || *endp || !isfinite(*obj)) {
Daniel P. Berrangecbd8acf2017-02-28 22:26:50 +0100572 /* TODO report -ERANGE more nicely */
573 error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
574 full_name(qiv, name), "number");
575 }
576}
577
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100578static void qobject_input_type_any(Visitor *v, const char *name, QObject **obj,
579 Error **errp)
Markus Armbruster28770e02015-09-16 13:06:24 +0200580{
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100581 QObjectInputVisitor *qiv = to_qiv(v);
582 QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
Markus Armbruster28770e02015-09-16 13:06:24 +0200583
Marc-André Lureau1382d4a2016-09-30 13:59:48 +0400584 *obj = NULL;
Marc-André Lureauc4897802016-09-23 00:39:26 +0400585 if (!qobj) {
Marc-André Lureauc4897802016-09-23 00:39:26 +0400586 return;
587 }
588
Markus Armbruster28770e02015-09-16 13:06:24 +0200589 qobject_incref(qobj);
590 *obj = qobj;
591}
592
Markus Armbrusterd2f95f42017-06-26 18:22:59 +0200593static void qobject_input_type_null(Visitor *v, const char *name,
594 QNull **obj, Error **errp)
Eric Blake3bc97fd2016-04-28 15:45:22 -0600595{
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100596 QObjectInputVisitor *qiv = to_qiv(v);
597 QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
Eric Blake3df016f2016-04-28 15:45:23 -0600598
Markus Armbrusterd2f95f42017-06-26 18:22:59 +0200599 *obj = NULL;
Marc-André Lureauc4897802016-09-23 00:39:26 +0400600 if (!qobj) {
Marc-André Lureauc4897802016-09-23 00:39:26 +0400601 return;
602 }
603
Eric Blake3df016f2016-04-28 15:45:23 -0600604 if (qobject_type(qobj) != QTYPE_QNULL) {
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100605 error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
606 full_name(qiv, name), "null");
Markus Armbrusterd2f95f42017-06-26 18:22:59 +0200607 return;
Eric Blake3df016f2016-04-28 15:45:23 -0600608 }
Markus Armbrusterd2f95f42017-06-26 18:22:59 +0200609 *obj = qnull();
Eric Blake3bc97fd2016-04-28 15:45:22 -0600610}
611
Daniel P. Berrangecbd8acf2017-02-28 22:26:50 +0100612static void qobject_input_type_size_keyval(Visitor *v, const char *name,
613 uint64_t *obj, Error **errp)
614{
615 QObjectInputVisitor *qiv = to_qiv(v);
Markus Armbrustere3934b42017-02-28 22:26:53 +0100616 const char *str = qobject_input_get_keyval(qiv, name, errp);
Daniel P. Berrangecbd8acf2017-02-28 22:26:50 +0100617
Markus Armbrustere3934b42017-02-28 22:26:53 +0100618 if (!str) {
Daniel P. Berrangecbd8acf2017-02-28 22:26:50 +0100619 return;
620 }
621
Markus Armbrustere3934b42017-02-28 22:26:53 +0100622 if (qemu_strtosz(str, NULL, obj) < 0) {
Daniel P. Berrangecbd8acf2017-02-28 22:26:50 +0100623 /* TODO report -ERANGE more nicely */
624 error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
625 full_name(qiv, name), "size");
626 }
627}
628
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100629static void qobject_input_optional(Visitor *v, const char *name, bool *present)
Michael Rothc40cc0a2011-07-19 14:50:33 -0500630{
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100631 QObjectInputVisitor *qiv = to_qiv(v);
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100632 QObject *qobj = qobject_input_try_get_object(qiv, name, false);
Michael Rothc40cc0a2011-07-19 14:50:33 -0500633
634 if (!qobj) {
635 *present = false;
636 return;
637 }
638
639 *present = true;
640}
641
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100642static void qobject_input_free(Visitor *v)
Eric Blake2c0ef9f2016-06-09 10:48:35 -0600643{
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100644 QObjectInputVisitor *qiv = to_qiv(v);
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100645
Paolo Bonzini3d344c22016-07-07 17:53:18 +0200646 while (!QSLIST_EMPTY(&qiv->stack)) {
647 StackObject *tos = QSLIST_FIRST(&qiv->stack);
648
649 QSLIST_REMOVE_HEAD(&qiv->stack, node);
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100650 qobject_input_stack_object_free(tos);
Paolo Bonzini3d344c22016-07-07 17:53:18 +0200651 }
Eric Blake2c0ef9f2016-06-09 10:48:35 -0600652
Eric Blakeb70ce1012016-06-09 10:48:38 -0600653 qobject_decref(qiv->root);
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100654 if (qiv->errname) {
655 g_string_free(qiv->errname, TRUE);
656 }
Eric Blakeb70ce1012016-06-09 10:48:38 -0600657 g_free(qiv);
Eric Blake2c0ef9f2016-06-09 10:48:35 -0600658}
659
Markus Armbrusterabe81bc2017-02-28 22:26:52 +0100660static QObjectInputVisitor *qobject_input_visitor_base_new(QObject *obj)
Michael Rothc40cc0a2011-07-19 14:50:33 -0500661{
Markus Armbrusterabe81bc2017-02-28 22:26:52 +0100662 QObjectInputVisitor *v = g_malloc0(sizeof(*v));
Michael Rothc40cc0a2011-07-19 14:50:33 -0500663
Marc-André Lureau5d0cbbc2016-09-30 13:59:46 +0400664 assert(obj);
Michael Rothc40cc0a2011-07-19 14:50:33 -0500665
Eric Blake983f52d2016-04-28 15:45:09 -0600666 v->visitor.type = VISITOR_INPUT;
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100667 v->visitor.start_struct = qobject_input_start_struct;
668 v->visitor.check_struct = qobject_input_check_struct;
Markus Armbruster8b2e41d2017-04-27 10:41:26 +0200669 v->visitor.end_struct = qobject_input_end_struct;
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100670 v->visitor.start_list = qobject_input_start_list;
671 v->visitor.next_list = qobject_input_next_list;
Markus Armbrustera4a1c702017-03-03 13:32:45 +0100672 v->visitor.check_list = qobject_input_check_list;
Markus Armbruster8b2e41d2017-04-27 10:41:26 +0200673 v->visitor.end_list = qobject_input_end_list;
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100674 v->visitor.start_alternate = qobject_input_start_alternate;
Markus Armbrusterabe81bc2017-02-28 22:26:52 +0100675 v->visitor.optional = qobject_input_optional;
676 v->visitor.free = qobject_input_free;
677
678 v->root = obj;
679 qobject_incref(obj);
680
681 return v;
682}
683
684Visitor *qobject_input_visitor_new(QObject *obj)
685{
686 QObjectInputVisitor *v = qobject_input_visitor_base_new(obj);
687
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100688 v->visitor.type_int64 = qobject_input_type_int64;
689 v->visitor.type_uint64 = qobject_input_type_uint64;
690 v->visitor.type_bool = qobject_input_type_bool;
691 v->visitor.type_str = qobject_input_type_str;
692 v->visitor.type_number = qobject_input_type_number;
693 v->visitor.type_any = qobject_input_type_any;
694 v->visitor.type_null = qobject_input_type_null;
Michael Rothc40cc0a2011-07-19 14:50:33 -0500695
Eric Blakeb70ce1012016-06-09 10:48:38 -0600696 return &v->visitor;
Michael Rothc40cc0a2011-07-19 14:50:33 -0500697}
Daniel P. Berrangecbd8acf2017-02-28 22:26:50 +0100698
699Visitor *qobject_input_visitor_new_keyval(QObject *obj)
700{
Markus Armbrusterabe81bc2017-02-28 22:26:52 +0100701 QObjectInputVisitor *v = qobject_input_visitor_base_new(obj);
Daniel P. Berrangecbd8acf2017-02-28 22:26:50 +0100702
Daniel P. Berrangecbd8acf2017-02-28 22:26:50 +0100703 v->visitor.type_int64 = qobject_input_type_int64_keyval;
704 v->visitor.type_uint64 = qobject_input_type_uint64_keyval;
705 v->visitor.type_bool = qobject_input_type_bool_keyval;
Markus Armbruster31478f22017-02-28 22:27:08 +0100706 v->visitor.type_str = qobject_input_type_str_keyval;
Daniel P. Berrangecbd8acf2017-02-28 22:26:50 +0100707 v->visitor.type_number = qobject_input_type_number_keyval;
708 v->visitor.type_any = qobject_input_type_any;
709 v->visitor.type_null = qobject_input_type_null;
710 v->visitor.type_size = qobject_input_type_size_keyval;
Markus Armbruster0b2c1be2017-02-28 22:27:10 +0100711 v->keyval = true;
Daniel P. Berrangecbd8acf2017-02-28 22:26:50 +0100712
713 return &v->visitor;
714}
Markus Armbruster9d1eab42017-02-28 22:27:06 +0100715
716Visitor *qobject_input_visitor_new_str(const char *str,
717 const char *implied_key,
718 Error **errp)
719{
720 bool is_json = str[0] == '{';
721 QObject *obj;
722 QDict *args;
723 Visitor *v;
724
725 if (is_json) {
726 obj = qobject_from_json(str, errp);
727 if (!obj) {
728 /* Work around qobject_from_json() lossage TODO fix that */
729 if (errp && !*errp) {
730 error_setg(errp, "JSON parse error");
731 return NULL;
732 }
733 return NULL;
734 }
735 args = qobject_to_qdict(obj);
736 assert(args);
737 v = qobject_input_visitor_new(QOBJECT(args));
738 } else {
739 args = keyval_parse(str, implied_key, errp);
740 if (!args) {
741 return NULL;
742 }
743 v = qobject_input_visitor_new_keyval(QOBJECT(args));
744 }
745 QDECREF(args);
746
747 return v;
748}