4 * Copyright (C) 2012-2017 Red Hat, Inc.
5 * Copyright IBM, Corp. 2011
8 * Anthony Liguori <aliguori@us.ibm.com>
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.
15 #include "qemu/osdep.h"
17 #include "qapi/error.h"
18 #include "qapi/qobject-input-visitor.h"
19 #include "qapi/visitor-impl.h"
20 #include "qemu/queue.h"
21 #include "qemu-common.h"
22 #include "qapi/qmp/qjson.h"
23 #include "qapi/qmp/qbool.h"
24 #include "qapi/qmp/qdict.h"
25 #include "qapi/qmp/qerror.h"
26 #include "qapi/qmp/qlist.h"
27 #include "qapi/qmp/qnull.h"
28 #include "qapi/qmp/qnum.h"
29 #include "qapi/qmp/qstring.h"
30 #include "qemu/cutils.h"
31 #include "qemu/option.h"
33 typedef struct StackObject
{
34 const char *name
; /* Name of @obj in its parent, if any */
35 QObject
*obj
; /* QDict or QList being visited */
36 void *qapi
; /* sanity check that caller uses same pointer */
38 GHashTable
*h
; /* If @obj is QDict: unvisited keys */
39 const QListEntry
*entry
; /* If @obj is QList: unvisited tail */
40 unsigned index
; /* If @obj is QList: list index of @entry */
42 QSLIST_ENTRY(StackObject
) node
; /* parent */
45 struct QObjectInputVisitor
{
48 /* Root of visit at visitor creation. */
50 bool keyval
; /* Assume @root made with keyval_parse() */
52 /* Stack of objects being visited (all entries will be either
54 QSLIST_HEAD(, StackObject
) stack
;
56 GString
*errname
; /* Accumulator for full_name() */
59 static QObjectInputVisitor
*to_qiv(Visitor
*v
)
61 return container_of(v
, QObjectInputVisitor
, visitor
);
65 * Find the full name of something @qiv is currently visiting.
66 * @qiv is visiting something named @name in the stack of containers
68 * If @n is zero, return its full name.
69 * If @n is positive, return the full name of the @n-th container
70 * counting from the top. The stack of containers must have at least
72 * The returned string is valid until the next full_name_nth(@v) or
75 static const char *full_name_nth(QObjectInputVisitor
*qiv
, const char *name
,
82 g_string_truncate(qiv
->errname
, 0);
84 qiv
->errname
= g_string_new("");
87 QSLIST_FOREACH(so
, &qiv
->stack
, node
) {
90 } else if (qobject_type(so
->obj
) == QTYPE_QDICT
) {
91 g_string_prepend(qiv
->errname
, name
?: "<anonymous>");
92 g_string_prepend_c(qiv
->errname
, '.');
94 snprintf(buf
, sizeof(buf
),
95 qiv
->keyval
? ".%u" : "[%u]",
97 g_string_prepend(qiv
->errname
, buf
);
104 g_string_prepend(qiv
->errname
, name
);
105 } else if (qiv
->errname
->str
[0] == '.') {
106 g_string_erase(qiv
->errname
, 0, 1);
107 } else if (!qiv
->errname
->str
[0]) {
108 return "<anonymous>";
111 return qiv
->errname
->str
;
114 static const char *full_name(QObjectInputVisitor
*qiv
, const char *name
)
116 return full_name_nth(qiv
, name
, 0);
119 static QObject
*qobject_input_try_get_object(QObjectInputVisitor
*qiv
,
127 if (QSLIST_EMPTY(&qiv
->stack
)) {
128 /* Starting at root, name is ignored. */
133 /* We are in a container; find the next element. */
134 tos
= QSLIST_FIRST(&qiv
->stack
);
138 if (qobject_type(qobj
) == QTYPE_QDICT
) {
140 ret
= qdict_get(qobject_to(QDict
, qobj
), name
);
141 if (tos
->h
&& consume
&& ret
) {
142 bool removed
= g_hash_table_remove(tos
->h
, name
);
146 assert(qobject_type(qobj
) == QTYPE_QLIST
);
149 ret
= qlist_entry_obj(tos
->entry
);
151 tos
->entry
= qlist_next(tos
->entry
);
164 static QObject
*qobject_input_get_object(QObjectInputVisitor
*qiv
,
166 bool consume
, Error
**errp
)
168 QObject
*obj
= qobject_input_try_get_object(qiv
, name
, consume
);
171 error_setg(errp
, QERR_MISSING_PARAMETER
, full_name(qiv
, name
));
176 static const char *qobject_input_get_keyval(QObjectInputVisitor
*qiv
,
183 qobj
= qobject_input_get_object(qiv
, name
, true, errp
);
188 qstr
= qobject_to(QString
, qobj
);
190 switch (qobject_type(qobj
)) {
193 error_setg(errp
, "Parameters '%s.*' are unexpected",
194 full_name(qiv
, name
));
197 /* Non-string scalar (should this be an assertion?) */
198 error_setg(errp
, "Internal error: parameter %s invalid",
199 full_name(qiv
, name
));
204 return qstring_get_str(qstr
);
207 static void qdict_add_key(const char *key
, QObject
*obj
, void *opaque
)
209 GHashTable
*h
= opaque
;
210 g_hash_table_insert(h
, (gpointer
) key
, NULL
);
213 static const QListEntry
*qobject_input_push(QObjectInputVisitor
*qiv
,
215 QObject
*obj
, void *qapi
)
218 StackObject
*tos
= g_new0(StackObject
, 1);
225 if (qobject_type(obj
) == QTYPE_QDICT
) {
226 h
= g_hash_table_new(g_str_hash
, g_str_equal
);
227 qdict_iter(qobject_to(QDict
, obj
), qdict_add_key
, h
);
230 assert(qobject_type(obj
) == QTYPE_QLIST
);
231 tos
->entry
= qlist_first(qobject_to(QList
, obj
));
235 QSLIST_INSERT_HEAD(&qiv
->stack
, tos
, node
);
240 static void qobject_input_check_struct(Visitor
*v
, Error
**errp
)
242 QObjectInputVisitor
*qiv
= to_qiv(v
);
243 StackObject
*tos
= QSLIST_FIRST(&qiv
->stack
);
247 assert(tos
&& !tos
->entry
);
249 g_hash_table_iter_init(&iter
, tos
->h
);
250 if (g_hash_table_iter_next(&iter
, (void **)&key
, NULL
)) {
251 error_setg(errp
, "Parameter '%s' is unexpected",
252 full_name(qiv
, key
));
256 static void qobject_input_stack_object_free(StackObject
*tos
)
259 g_hash_table_unref(tos
->h
);
265 static void qobject_input_pop(Visitor
*v
, void **obj
)
267 QObjectInputVisitor
*qiv
= to_qiv(v
);
268 StackObject
*tos
= QSLIST_FIRST(&qiv
->stack
);
270 assert(tos
&& tos
->qapi
== obj
);
271 QSLIST_REMOVE_HEAD(&qiv
->stack
, node
);
272 qobject_input_stack_object_free(tos
);
275 static void qobject_input_start_struct(Visitor
*v
, const char *name
, void **obj
,
276 size_t size
, Error
**errp
)
278 QObjectInputVisitor
*qiv
= to_qiv(v
);
279 QObject
*qobj
= qobject_input_get_object(qiv
, name
, true, errp
);
287 if (qobject_type(qobj
) != QTYPE_QDICT
) {
288 error_setg(errp
, QERR_INVALID_PARAMETER_TYPE
,
289 full_name(qiv
, name
), "object");
293 qobject_input_push(qiv
, name
, qobj
, obj
);
296 *obj
= g_malloc0(size
);
300 static void qobject_input_end_struct(Visitor
*v
, void **obj
)
302 QObjectInputVisitor
*qiv
= to_qiv(v
);
303 StackObject
*tos
= QSLIST_FIRST(&qiv
->stack
);
305 assert(qobject_type(tos
->obj
) == QTYPE_QDICT
&& tos
->h
);
306 qobject_input_pop(v
, obj
);
310 static void qobject_input_start_list(Visitor
*v
, const char *name
,
311 GenericList
**list
, size_t size
,
314 QObjectInputVisitor
*qiv
= to_qiv(v
);
315 QObject
*qobj
= qobject_input_get_object(qiv
, name
, true, errp
);
316 const QListEntry
*entry
;
324 if (qobject_type(qobj
) != QTYPE_QLIST
) {
325 error_setg(errp
, QERR_INVALID_PARAMETER_TYPE
,
326 full_name(qiv
, name
), "array");
330 entry
= qobject_input_push(qiv
, name
, qobj
, list
);
332 *list
= g_malloc0(size
);
336 static GenericList
*qobject_input_next_list(Visitor
*v
, GenericList
*tail
,
339 QObjectInputVisitor
*qiv
= to_qiv(v
);
340 StackObject
*tos
= QSLIST_FIRST(&qiv
->stack
);
342 assert(tos
&& qobject_to(QList
, tos
->obj
));
347 tail
->next
= g_malloc0(size
);
351 static void qobject_input_check_list(Visitor
*v
, Error
**errp
)
353 QObjectInputVisitor
*qiv
= to_qiv(v
);
354 StackObject
*tos
= QSLIST_FIRST(&qiv
->stack
);
356 assert(tos
&& qobject_to(QList
, tos
->obj
));
359 error_setg(errp
, "Only %u list elements expected in %s",
360 tos
->index
+ 1, full_name_nth(qiv
, NULL
, 1));
364 static void qobject_input_end_list(Visitor
*v
, void **obj
)
366 QObjectInputVisitor
*qiv
= to_qiv(v
);
367 StackObject
*tos
= QSLIST_FIRST(&qiv
->stack
);
369 assert(qobject_type(tos
->obj
) == QTYPE_QLIST
&& !tos
->h
);
370 qobject_input_pop(v
, obj
);
373 static void qobject_input_start_alternate(Visitor
*v
, const char *name
,
374 GenericAlternate
**obj
, size_t size
,
377 QObjectInputVisitor
*qiv
= to_qiv(v
);
378 QObject
*qobj
= qobject_input_get_object(qiv
, name
, false, errp
);
384 *obj
= g_malloc0(size
);
385 (*obj
)->type
= qobject_type(qobj
);
388 static void qobject_input_type_int64(Visitor
*v
, const char *name
, int64_t *obj
,
391 QObjectInputVisitor
*qiv
= to_qiv(v
);
392 QObject
*qobj
= qobject_input_get_object(qiv
, name
, true, errp
);
398 qnum
= qobject_to(QNum
, qobj
);
399 if (!qnum
|| !qnum_get_try_int(qnum
, obj
)) {
400 error_setg(errp
, QERR_INVALID_PARAMETER_TYPE
,
401 full_name(qiv
, name
), "integer");
405 static void qobject_input_type_int64_keyval(Visitor
*v
, const char *name
,
406 int64_t *obj
, Error
**errp
)
408 QObjectInputVisitor
*qiv
= to_qiv(v
);
409 const char *str
= qobject_input_get_keyval(qiv
, name
, errp
);
415 if (qemu_strtoi64(str
, NULL
, 0, obj
) < 0) {
416 /* TODO report -ERANGE more nicely */
417 error_setg(errp
, QERR_INVALID_PARAMETER_VALUE
,
418 full_name(qiv
, name
), "integer");
422 static void qobject_input_type_uint64(Visitor
*v
, const char *name
,
423 uint64_t *obj
, Error
**errp
)
425 QObjectInputVisitor
*qiv
= to_qiv(v
);
426 QObject
*qobj
= qobject_input_get_object(qiv
, name
, true, errp
);
433 qnum
= qobject_to(QNum
, qobj
);
438 if (qnum_get_try_uint(qnum
, obj
)) {
442 /* Need to accept negative values for backward compatibility */
443 if (qnum_get_try_int(qnum
, &val
)) {
449 error_setg(errp
, QERR_INVALID_PARAMETER_VALUE
,
450 full_name(qiv
, name
), "uint64");
453 static void qobject_input_type_uint64_keyval(Visitor
*v
, const char *name
,
454 uint64_t *obj
, Error
**errp
)
456 QObjectInputVisitor
*qiv
= to_qiv(v
);
457 const char *str
= qobject_input_get_keyval(qiv
, name
, errp
);
463 if (qemu_strtou64(str
, NULL
, 0, obj
) < 0) {
464 /* TODO report -ERANGE more nicely */
465 error_setg(errp
, QERR_INVALID_PARAMETER_VALUE
,
466 full_name(qiv
, name
), "integer");
470 static void qobject_input_type_bool(Visitor
*v
, const char *name
, bool *obj
,
473 QObjectInputVisitor
*qiv
= to_qiv(v
);
474 QObject
*qobj
= qobject_input_get_object(qiv
, name
, true, errp
);
480 qbool
= qobject_to(QBool
, qobj
);
482 error_setg(errp
, QERR_INVALID_PARAMETER_TYPE
,
483 full_name(qiv
, name
), "boolean");
487 *obj
= qbool_get_bool(qbool
);
490 static void qobject_input_type_bool_keyval(Visitor
*v
, const char *name
,
491 bool *obj
, Error
**errp
)
493 QObjectInputVisitor
*qiv
= to_qiv(v
);
494 const char *str
= qobject_input_get_keyval(qiv
, name
, errp
);
500 if (!strcmp(str
, "on")) {
502 } else if (!strcmp(str
, "off")) {
505 error_setg(errp
, QERR_INVALID_PARAMETER_VALUE
,
506 full_name(qiv
, name
), "'on' or 'off'");
510 static void qobject_input_type_str(Visitor
*v
, const char *name
, char **obj
,
513 QObjectInputVisitor
*qiv
= to_qiv(v
);
514 QObject
*qobj
= qobject_input_get_object(qiv
, name
, true, errp
);
521 qstr
= qobject_to(QString
, qobj
);
523 error_setg(errp
, QERR_INVALID_PARAMETER_TYPE
,
524 full_name(qiv
, name
), "string");
528 *obj
= g_strdup(qstring_get_str(qstr
));
531 static void qobject_input_type_str_keyval(Visitor
*v
, const char *name
,
532 char **obj
, Error
**errp
)
534 QObjectInputVisitor
*qiv
= to_qiv(v
);
535 const char *str
= qobject_input_get_keyval(qiv
, name
, errp
);
537 *obj
= g_strdup(str
);
540 static void qobject_input_type_number(Visitor
*v
, const char *name
, double *obj
,
543 QObjectInputVisitor
*qiv
= to_qiv(v
);
544 QObject
*qobj
= qobject_input_get_object(qiv
, name
, true, errp
);
550 qnum
= qobject_to(QNum
, qobj
);
552 error_setg(errp
, QERR_INVALID_PARAMETER_TYPE
,
553 full_name(qiv
, name
), "number");
557 *obj
= qnum_get_double(qnum
);
560 static void qobject_input_type_number_keyval(Visitor
*v
, const char *name
,
561 double *obj
, Error
**errp
)
563 QObjectInputVisitor
*qiv
= to_qiv(v
);
564 const char *str
= qobject_input_get_keyval(qiv
, name
, errp
);
572 *obj
= strtod(str
, &endp
);
573 if (errno
|| endp
== str
|| *endp
|| !isfinite(*obj
)) {
574 /* TODO report -ERANGE more nicely */
575 error_setg(errp
, QERR_INVALID_PARAMETER_TYPE
,
576 full_name(qiv
, name
), "number");
580 static void qobject_input_type_any(Visitor
*v
, const char *name
, QObject
**obj
,
583 QObjectInputVisitor
*qiv
= to_qiv(v
);
584 QObject
*qobj
= qobject_input_get_object(qiv
, name
, true, errp
);
591 qobject_incref(qobj
);
595 static void qobject_input_type_null(Visitor
*v
, const char *name
,
596 QNull
**obj
, Error
**errp
)
598 QObjectInputVisitor
*qiv
= to_qiv(v
);
599 QObject
*qobj
= qobject_input_get_object(qiv
, name
, true, errp
);
606 if (qobject_type(qobj
) != QTYPE_QNULL
) {
607 error_setg(errp
, QERR_INVALID_PARAMETER_TYPE
,
608 full_name(qiv
, name
), "null");
614 static void qobject_input_type_size_keyval(Visitor
*v
, const char *name
,
615 uint64_t *obj
, Error
**errp
)
617 QObjectInputVisitor
*qiv
= to_qiv(v
);
618 const char *str
= qobject_input_get_keyval(qiv
, name
, errp
);
624 if (qemu_strtosz(str
, NULL
, obj
) < 0) {
625 /* TODO report -ERANGE more nicely */
626 error_setg(errp
, QERR_INVALID_PARAMETER_VALUE
,
627 full_name(qiv
, name
), "size");
631 static void qobject_input_optional(Visitor
*v
, const char *name
, bool *present
)
633 QObjectInputVisitor
*qiv
= to_qiv(v
);
634 QObject
*qobj
= qobject_input_try_get_object(qiv
, name
, false);
644 static void qobject_input_free(Visitor
*v
)
646 QObjectInputVisitor
*qiv
= to_qiv(v
);
648 while (!QSLIST_EMPTY(&qiv
->stack
)) {
649 StackObject
*tos
= QSLIST_FIRST(&qiv
->stack
);
651 QSLIST_REMOVE_HEAD(&qiv
->stack
, node
);
652 qobject_input_stack_object_free(tos
);
655 qobject_decref(qiv
->root
);
657 g_string_free(qiv
->errname
, TRUE
);
662 static QObjectInputVisitor
*qobject_input_visitor_base_new(QObject
*obj
)
664 QObjectInputVisitor
*v
= g_malloc0(sizeof(*v
));
668 v
->visitor
.type
= VISITOR_INPUT
;
669 v
->visitor
.start_struct
= qobject_input_start_struct
;
670 v
->visitor
.check_struct
= qobject_input_check_struct
;
671 v
->visitor
.end_struct
= qobject_input_end_struct
;
672 v
->visitor
.start_list
= qobject_input_start_list
;
673 v
->visitor
.next_list
= qobject_input_next_list
;
674 v
->visitor
.check_list
= qobject_input_check_list
;
675 v
->visitor
.end_list
= qobject_input_end_list
;
676 v
->visitor
.start_alternate
= qobject_input_start_alternate
;
677 v
->visitor
.optional
= qobject_input_optional
;
678 v
->visitor
.free
= qobject_input_free
;
686 Visitor
*qobject_input_visitor_new(QObject
*obj
)
688 QObjectInputVisitor
*v
= qobject_input_visitor_base_new(obj
);
690 v
->visitor
.type_int64
= qobject_input_type_int64
;
691 v
->visitor
.type_uint64
= qobject_input_type_uint64
;
692 v
->visitor
.type_bool
= qobject_input_type_bool
;
693 v
->visitor
.type_str
= qobject_input_type_str
;
694 v
->visitor
.type_number
= qobject_input_type_number
;
695 v
->visitor
.type_any
= qobject_input_type_any
;
696 v
->visitor
.type_null
= qobject_input_type_null
;
701 Visitor
*qobject_input_visitor_new_keyval(QObject
*obj
)
703 QObjectInputVisitor
*v
= qobject_input_visitor_base_new(obj
);
705 v
->visitor
.type_int64
= qobject_input_type_int64_keyval
;
706 v
->visitor
.type_uint64
= qobject_input_type_uint64_keyval
;
707 v
->visitor
.type_bool
= qobject_input_type_bool_keyval
;
708 v
->visitor
.type_str
= qobject_input_type_str_keyval
;
709 v
->visitor
.type_number
= qobject_input_type_number_keyval
;
710 v
->visitor
.type_any
= qobject_input_type_any
;
711 v
->visitor
.type_null
= qobject_input_type_null
;
712 v
->visitor
.type_size
= qobject_input_type_size_keyval
;
718 Visitor
*qobject_input_visitor_new_str(const char *str
,
719 const char *implied_key
,
722 bool is_json
= str
[0] == '{';
728 obj
= qobject_from_json(str
, errp
);
730 /* Work around qobject_from_json() lossage TODO fix that */
731 if (errp
&& !*errp
) {
732 error_setg(errp
, "JSON parse error");
737 args
= qobject_to(QDict
, obj
);
739 v
= qobject_input_visitor_new(QOBJECT(args
));
741 args
= keyval_parse(str
, implied_key
, errp
);
745 v
= qobject_input_visitor_new_keyval(QOBJECT(args
));