mirror of https://github.com/xemu-project/xemu.git
QAPI patches for 2017-03-22
-----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJY0sGLAAoJEDhwtADrkYZTe/cP/3VKSiZkf+FxuFXImGvI8ZCG mNM0tSmvDoPZyi1CEUGz9rReRSMF6gTlgLUi/q7515Cz6unSo95KM3U33mai13NO WS2SSo5C/x1oXHjlv4bQ2h5GGYNg8jBG01pqPFjqzMrf5PVI91dzCwq0WGVPAcZ9 edlyXQpGthyv+SEV7L2KU3kU/I7yPChYaOF2MLtSvD5E/dgtw7GXqm2if4GVqQfd +aU6d1wmnaIhXqgNhW03vmEtZ0UpqsXwiSI14Nw6QoYXWozlDB53Bm4C9Ex4EPAh klFl7gNvVEkAD///WVXxNJ2GMciiSuUrZyeeE7XJ11BOh/ej+ZOHFoalsdRKDfHa jnx9yNWTBpfbqQtybBCQwM98KdmSMc9gQq5U+jKV28P2ndWq8acXtR5XOWfDzDp5 J7wp93wQaOMSyZi9vuNUIop/Wqyo41WyxDACB7UNVtHOQdU74Lp8CjXScNqiZ8uZ btrjisFpaGYlgUjskcEjbsZDA2sFde4/vnMgy3ysq83uQ0bSr58xXei7tBfaILPn nG+iBgQwOqhDMZQUeoylt7a6S6D/EymgNpJ0dIT41M658gDzBxnQZmfrm/FgWKbD NB/URDSmtL2dtP5i4F9nJoOADF2Qj/eZgR+9Q83kwFEv9YZ3ETnpyT5u0FEnSH8T rKfg3HwafWSuJsyPT/Ba =Zxxa -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2017-03-22-v3' into staging QAPI patches for 2017-03-22 # gpg: Signature made Wed 22 Mar 2017 18:25:15 GMT # gpg: using RSA key 0x3870B400EB918653 # gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" # gpg: aka "Markus Armbruster <armbru@pond.sub.org>" # Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867 4E5F 3870 B400 EB91 8653 * remotes/armbru/tags/pull-qapi-2017-03-22-v3: qapi: Fix QemuOpts visitor regression on unvisited input qom: Avoid unvisited 'id'/'qom-type' in user_creatable_add_opts tests: Expose regression in QemuOpts visitor test-qobject-input-visitor: Cover visit_type_uint64() Revert "hostmem: fix QEMU crash by 'info memdev'" qapi: Fix string input visitor regression for empty lists qapi2texi: Fix translation of *strong* and _emphasized_ tests/qapi-schema: Systematic positive doc comment tests tests/qapi-schema: Make test-qapi.py print docs again qapi: Drop unused QAPIDoc member optional qapi2texi: Fix to actually fail when 'doc-required' is false qapi: Drop excessive Make dependencies on qapi2texi.py MAINTAINERS: Add myself for files I touched recently keyval: Document issues with 'any' and alternate types test-keyval: Cover alternate and 'any' type keyval: Improve some comments test-keyval: Tweaks to improve list coverage Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
d81d857f44
11
MAINTAINERS
11
MAINTAINERS
|
@ -1231,6 +1231,15 @@ M: Samuel Thibault <samuel.thibault@ens-lyon.org>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: backends/baum.c
|
F: backends/baum.c
|
||||||
|
|
||||||
|
Command line option argument parsing
|
||||||
|
M: Markus Armbruster <armbru@redhat.com>
|
||||||
|
S: Supported
|
||||||
|
F: include/qemu/option.h
|
||||||
|
F: tests/test-keyval.c
|
||||||
|
F: tests/test-qemu-opts.c
|
||||||
|
F: util/keyval.c
|
||||||
|
F: util/qemu-option.c
|
||||||
|
|
||||||
Coverity model
|
Coverity model
|
||||||
M: Markus Armbruster <armbru@redhat.com>
|
M: Markus Armbruster <armbru@redhat.com>
|
||||||
S: Supported
|
S: Supported
|
||||||
|
@ -1365,7 +1374,9 @@ X: include/qapi/qmp/
|
||||||
F: include/qapi/qmp/dispatch.h
|
F: include/qapi/qmp/dispatch.h
|
||||||
F: tests/qapi-schema/
|
F: tests/qapi-schema/
|
||||||
F: tests/test-*-visitor.c
|
F: tests/test-*-visitor.c
|
||||||
|
F: tests/test-qapi-*.c
|
||||||
F: tests/test-qmp-*.c
|
F: tests/test-qmp-*.c
|
||||||
|
F: tests/test-visitor-serialization.c
|
||||||
F: scripts/qapi*
|
F: scripts/qapi*
|
||||||
F: docs/qapi*
|
F: docs/qapi*
|
||||||
T: git git://repo.or.cz/qemu/armbru.git qapi-next
|
T: git git://repo.or.cz/qemu/armbru.git qapi-next
|
||||||
|
|
7
Makefile
7
Makefile
|
@ -392,7 +392,6 @@ qemu-ga$(EXESUF): QEMU_CFLAGS += -I qga/qapi-generated
|
||||||
gen-out-type = $(subst .,-,$(suffix $@))
|
gen-out-type = $(subst .,-,$(suffix $@))
|
||||||
|
|
||||||
qapi-py = $(SRC_PATH)/scripts/qapi.py $(SRC_PATH)/scripts/ordereddict.py
|
qapi-py = $(SRC_PATH)/scripts/qapi.py $(SRC_PATH)/scripts/ordereddict.py
|
||||||
qapi-py += $(SRC_PATH)/scripts/qapi2texi.py
|
|
||||||
|
|
||||||
qga/qapi-generated/qga-qapi-types.c qga/qapi-generated/qga-qapi-types.h :\
|
qga/qapi-generated/qga-qapi-types.c qga/qapi-generated/qga-qapi-types.h :\
|
||||||
$(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
|
$(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
|
||||||
|
@ -701,10 +700,12 @@ qemu-monitor-info.texi: $(SRC_PATH)/hmp-commands-info.hx $(SRC_PATH)/scripts/hxt
|
||||||
qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
|
qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
|
||||||
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@")
|
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@")
|
||||||
|
|
||||||
docs/qemu-qmp-qapi.texi: $(qapi-modules) $(qapi-py)
|
docs/qemu-qmp-qapi.texi docs/qemu-ga-qapi.texi: $(SRC_PATH)/scripts/qapi2texi.py $(qapi-py)
|
||||||
|
|
||||||
|
docs/qemu-qmp-qapi.texi: $(qapi-modules)
|
||||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi2texi.py $< > $@,"GEN","$@")
|
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi2texi.py $< > $@,"GEN","$@")
|
||||||
|
|
||||||
docs/qemu-ga-qapi.texi: $(SRC_PATH)/qga/qapi-schema.json $(qapi-py)
|
docs/qemu-ga-qapi.texi: $(SRC_PATH)/qga/qapi-schema.json
|
||||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi2texi.py $< > $@,"GEN","$@")
|
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi2texi.py $< > $@,"GEN","$@")
|
||||||
|
|
||||||
qemu.1: qemu-doc.texi qemu-options.texi qemu-monitor.texi qemu-monitor-info.texi
|
qemu.1: qemu-doc.texi qemu-options.texi qemu-monitor.texi qemu-monitor-info.texi
|
||||||
|
|
|
@ -64,14 +64,6 @@ out:
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint16List **host_memory_append_node(uint16List **node,
|
|
||||||
unsigned long value)
|
|
||||||
{
|
|
||||||
*node = g_malloc0(sizeof(**node));
|
|
||||||
(*node)->value = value;
|
|
||||||
return &(*node)->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
host_memory_backend_get_host_nodes(Object *obj, Visitor *v, const char *name,
|
host_memory_backend_get_host_nodes(Object *obj, Visitor *v, const char *name,
|
||||||
void *opaque, Error **errp)
|
void *opaque, Error **errp)
|
||||||
|
@ -82,23 +74,25 @@ host_memory_backend_get_host_nodes(Object *obj, Visitor *v, const char *name,
|
||||||
unsigned long value;
|
unsigned long value;
|
||||||
|
|
||||||
value = find_first_bit(backend->host_nodes, MAX_NODES);
|
value = find_first_bit(backend->host_nodes, MAX_NODES);
|
||||||
|
|
||||||
node = host_memory_append_node(node, value);
|
|
||||||
|
|
||||||
if (value == MAX_NODES) {
|
if (value == MAX_NODES) {
|
||||||
goto out;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*node = g_malloc0(sizeof(**node));
|
||||||
|
(*node)->value = value;
|
||||||
|
node = &(*node)->next;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
value = find_next_bit(backend->host_nodes, MAX_NODES, value + 1);
|
value = find_next_bit(backend->host_nodes, MAX_NODES, value + 1);
|
||||||
if (value == MAX_NODES) {
|
if (value == MAX_NODES) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
node = host_memory_append_node(node, value);
|
*node = g_malloc0(sizeof(**node));
|
||||||
|
(*node)->value = value;
|
||||||
|
node = &(*node)->next;
|
||||||
} while (true);
|
} while (true);
|
||||||
|
|
||||||
out:
|
|
||||||
visit_type_uint16List(v, name, &host_nodes, errp);
|
visit_type_uint16List(v, name, &host_nodes, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -164,7 +164,7 @@ opts_check_struct(Visitor *v, Error **errp)
|
||||||
GHashTableIter iter;
|
GHashTableIter iter;
|
||||||
GQueue *any;
|
GQueue *any;
|
||||||
|
|
||||||
if (ov->depth > 0) {
|
if (ov->depth > 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,8 +276,8 @@ static void
|
||||||
opts_check_list(Visitor *v, Error **errp)
|
opts_check_list(Visitor *v, Error **errp)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* FIXME should set error when unvisited elements remain. Mostly
|
* Unvisited list elements will be reported later when checking
|
||||||
* harmless, as the generated visits always visit all elements.
|
* whether unvisited struct members remain.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,10 @@ static int parse_str(StringInputVisitor *siv, const char *name, Error **errp)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!*str) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
start = strtoll(str, &endptr, 0);
|
start = strtoll(str, &endptr, 0);
|
||||||
|
|
|
@ -114,7 +114,7 @@ Object *user_creatable_add_opts(QemuOpts *opts, Error **errp)
|
||||||
QDict *pdict;
|
QDict *pdict;
|
||||||
Object *obj;
|
Object *obj;
|
||||||
const char *id = qemu_opts_id(opts);
|
const char *id = qemu_opts_id(opts);
|
||||||
const char *type = qemu_opt_get(opts, "qom-type");
|
char *type = qemu_opt_get_del(opts, "qom-type");
|
||||||
|
|
||||||
if (!type) {
|
if (!type) {
|
||||||
error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
|
error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
|
||||||
|
@ -122,17 +122,19 @@ Object *user_creatable_add_opts(QemuOpts *opts, Error **errp)
|
||||||
}
|
}
|
||||||
if (!id) {
|
if (!id) {
|
||||||
error_setg(errp, QERR_MISSING_PARAMETER, "id");
|
error_setg(errp, QERR_MISSING_PARAMETER, "id");
|
||||||
|
g_free(type);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qemu_opts_set_id(opts, NULL);
|
||||||
pdict = qemu_opts_to_qdict(opts, NULL);
|
pdict = qemu_opts_to_qdict(opts, NULL);
|
||||||
qdict_del(pdict, "qom-type");
|
|
||||||
qdict_del(pdict, "id");
|
|
||||||
|
|
||||||
v = opts_visitor_new(opts);
|
v = opts_visitor_new(opts);
|
||||||
obj = user_creatable_add_type(type, id, pdict, v, errp);
|
obj = user_creatable_add_type(type, id, pdict, v, errp);
|
||||||
visit_free(v);
|
visit_free(v);
|
||||||
|
|
||||||
|
qemu_opts_set_id(opts, (char *) id);
|
||||||
|
g_free(type);
|
||||||
QDECREF(pdict);
|
QDECREF(pdict);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,7 +106,6 @@ class QAPIDoc(object):
|
||||||
self.name = name
|
self.name = name
|
||||||
# the list of lines for this section
|
# the list of lines for this section
|
||||||
self.content = []
|
self.content = []
|
||||||
self.optional = False
|
|
||||||
|
|
||||||
def append(self, line):
|
def append(self, line):
|
||||||
self.content.append(line)
|
self.content.append(line)
|
||||||
|
|
|
@ -35,12 +35,12 @@ EXAMPLE_FMT = """@example
|
||||||
|
|
||||||
def subst_strong(doc):
|
def subst_strong(doc):
|
||||||
"""Replaces *foo* by @strong{foo}"""
|
"""Replaces *foo* by @strong{foo}"""
|
||||||
return re.sub(r'\*([^*\n]+)\*', r'@emph{\1}', doc)
|
return re.sub(r'\*([^*\n]+)\*', r'@strong{\1}', doc)
|
||||||
|
|
||||||
|
|
||||||
def subst_emph(doc):
|
def subst_emph(doc):
|
||||||
"""Replaces _foo_ by @emph{foo}"""
|
"""Replaces _foo_ by @emph{foo}"""
|
||||||
return re.sub(r'\b_([^_\n]+)_\b', r' @emph{\1} ', doc)
|
return re.sub(r'\b_([^_\n]+)_\b', r'@emph{\1}', doc)
|
||||||
|
|
||||||
|
|
||||||
def subst_vars(doc):
|
def subst_vars(doc):
|
||||||
|
@ -292,6 +292,7 @@ def main(argv):
|
||||||
if not qapi.doc_required:
|
if not qapi.doc_required:
|
||||||
print >>sys.stderr, ("%s: need pragma 'doc-required' "
|
print >>sys.stderr, ("%s: need pragma 'doc-required' "
|
||||||
"to generate documentation" % argv[0])
|
"to generate documentation" % argv[0])
|
||||||
|
sys.exit(1)
|
||||||
print texi_schema(schema)
|
print texi_schema(schema)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -379,6 +379,7 @@ qapi-schema += doc-duplicated-since.json
|
||||||
qapi-schema += doc-empty-arg.json
|
qapi-schema += doc-empty-arg.json
|
||||||
qapi-schema += doc-empty-section.json
|
qapi-schema += doc-empty-section.json
|
||||||
qapi-schema += doc-empty-symbol.json
|
qapi-schema += doc-empty-symbol.json
|
||||||
|
qapi-schema += doc-good.json
|
||||||
qapi-schema += doc-interleaved-section.json
|
qapi-schema += doc-interleaved-section.json
|
||||||
qapi-schema += doc-invalid-end.json
|
qapi-schema += doc-invalid-end.json
|
||||||
qapi-schema += doc-invalid-end2.json
|
qapi-schema += doc-invalid-end2.json
|
||||||
|
@ -607,6 +608,9 @@ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-int
|
||||||
$(gen-out-type) -o tests -p "test-" $<, \
|
$(gen-out-type) -o tests -p "test-" $<, \
|
||||||
"GEN","$@")
|
"GEN","$@")
|
||||||
|
|
||||||
|
tests/qapi-schema/doc-good.test.texi: $(SRC_PATH)/tests/qapi-schema/doc-good.json $(SRC_PATH)/scripts/qapi2texi.py $(qapi-py)
|
||||||
|
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi2texi.py $< > $@,"GEN","$@")
|
||||||
|
|
||||||
tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y)
|
tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y)
|
||||||
tests/test-string-input-visitor$(EXESUF): tests/test-string-input-visitor.o $(test-qapi-obj-y)
|
tests/test-string-input-visitor$(EXESUF): tests/test-string-input-visitor.o $(test-qapi-obj-y)
|
||||||
tests/test-qmp-event$(EXESUF): tests/test-qmp-event.o $(test-qapi-obj-y)
|
tests/test-qmp-event$(EXESUF): tests/test-qmp-event.o $(test-qapi-obj-y)
|
||||||
|
@ -736,7 +740,7 @@ tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o $(test-util-obj-y) \
|
||||||
$(chardev-obj-y)
|
$(chardev-obj-y)
|
||||||
tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o
|
tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o
|
||||||
tests/test-qemu-opts$(EXESUF): tests/test-qemu-opts.o $(test-util-obj-y)
|
tests/test-qemu-opts$(EXESUF): tests/test-qemu-opts.o $(test-util-obj-y)
|
||||||
tests/test-keyval$(EXESUF): tests/test-keyval.o $(test-util-obj-y)
|
tests/test-keyval$(EXESUF): tests/test-keyval.o $(test-util-obj-y) $(test-qapi-obj-y)
|
||||||
tests/test-write-threshold$(EXESUF): tests/test-write-threshold.o $(test-block-obj-y)
|
tests/test-write-threshold$(EXESUF): tests/test-write-threshold.o $(test-block-obj-y)
|
||||||
tests/test-netfilter$(EXESUF): tests/test-netfilter.o $(qtest-obj-y)
|
tests/test-netfilter$(EXESUF): tests/test-netfilter.o $(qtest-obj-y)
|
||||||
tests/test-filter-mirror$(EXESUF): tests/test-filter-mirror.o $(qtest-obj-y)
|
tests/test-filter-mirror$(EXESUF): tests/test-filter-mirror.o $(qtest-obj-y)
|
||||||
|
@ -856,9 +860,6 @@ QEMU_IOTESTS_HELPERS-$(CONFIG_LINUX) = tests/qemu-iotests/socket_scm_helper$(EXE
|
||||||
check-tests/qemu-iotests-quick.sh: tests/qemu-iotests-quick.sh qemu-img$(EXESUF) qemu-io$(EXESUF) $(QEMU_IOTESTS_HELPERS-y)
|
check-tests/qemu-iotests-quick.sh: tests/qemu-iotests-quick.sh qemu-img$(EXESUF) qemu-io$(EXESUF) $(QEMU_IOTESTS_HELPERS-y)
|
||||||
$<
|
$<
|
||||||
|
|
||||||
.PHONY: check-tests/test-qapi.py
|
|
||||||
check-tests/test-qapi.py: tests/test-qapi.py
|
|
||||||
|
|
||||||
.PHONY: $(patsubst %, check-%, $(check-qapi-schema-y))
|
.PHONY: $(patsubst %, check-%, $(check-qapi-schema-y))
|
||||||
$(patsubst %, check-%, $(check-qapi-schema-y)): check-%.json: $(SRC_PATH)/%.json
|
$(patsubst %, check-%, $(check-qapi-schema-y)): check-%.json: $(SRC_PATH)/%.json
|
||||||
$(call quiet-command, PYTHONPATH=$(SRC_PATH)/scripts \
|
$(call quiet-command, PYTHONPATH=$(SRC_PATH)/scripts \
|
||||||
|
@ -871,10 +872,14 @@ $(patsubst %, check-%, $(check-qapi-schema-y)): check-%.json: $(SRC_PATH)/%.json
|
||||||
@perl -p -e 's|\Q$(SRC_PATH)\E/||g' $*.test.err | diff -q $(SRC_PATH)/$*.err -
|
@perl -p -e 's|\Q$(SRC_PATH)\E/||g' $*.test.err | diff -q $(SRC_PATH)/$*.err -
|
||||||
@diff -q $(SRC_PATH)/$*.exit $*.test.exit
|
@diff -q $(SRC_PATH)/$*.exit $*.test.exit
|
||||||
|
|
||||||
|
.PHONY: check-tests/qapi-schema/doc-good.texi
|
||||||
|
check-tests/qapi-schema/doc-good.texi: tests/qapi-schema/doc-good.test.texi
|
||||||
|
@diff -q $(SRC_PATH)/tests/qapi-schema/doc-good.texi $<
|
||||||
|
|
||||||
# Consolidated targets
|
# Consolidated targets
|
||||||
|
|
||||||
.PHONY: check-qapi-schema check-qtest check-unit check check-clean
|
.PHONY: check-qapi-schema check-qtest check-unit check check-clean
|
||||||
check-qapi-schema: $(patsubst %,check-%, $(check-qapi-schema-y))
|
check-qapi-schema: $(patsubst %,check-%, $(check-qapi-schema-y)) check-tests/qapi-schema/doc-good.texi
|
||||||
check-qtest: $(patsubst %,check-qtest-%, $(QTEST_TARGETS))
|
check-qtest: $(patsubst %,check-qtest-%, $(QTEST_TARGETS))
|
||||||
check-unit: $(patsubst %,check-%, $(check-unit-y))
|
check-unit: $(patsubst %,check-%, $(check-unit-y))
|
||||||
check-block: $(patsubst %,check-%, $(check-block-y))
|
check-block: $(patsubst %,check-%, $(check-block-y))
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
0
|
|
@ -0,0 +1,136 @@
|
||||||
|
# -*- Mode: Python -*-
|
||||||
|
# Positive QAPI doc comment tests
|
||||||
|
|
||||||
|
{ 'pragma': { 'doc-required': true } }
|
||||||
|
|
||||||
|
##
|
||||||
|
# = Section
|
||||||
|
#
|
||||||
|
# == Subsection
|
||||||
|
#
|
||||||
|
# *strong* _with emphasis_
|
||||||
|
# @var {in braces}
|
||||||
|
# * List item one
|
||||||
|
# - Two, multiple
|
||||||
|
# lines
|
||||||
|
#
|
||||||
|
# 3. Three
|
||||||
|
# Still in list
|
||||||
|
#
|
||||||
|
# Not in list
|
||||||
|
# - Second list
|
||||||
|
# Note: still in list
|
||||||
|
#
|
||||||
|
# Note: not in list
|
||||||
|
# 1. Third list
|
||||||
|
# is numbered
|
||||||
|
#
|
||||||
|
# - another item
|
||||||
|
#
|
||||||
|
# | example
|
||||||
|
# | multiple lines
|
||||||
|
#
|
||||||
|
# Returns: the King
|
||||||
|
# Since: the first age
|
||||||
|
# Notes:
|
||||||
|
#
|
||||||
|
# 1. Lorem ipsum dolor sit amet
|
||||||
|
#
|
||||||
|
# 2. Ut enim ad minim veniam
|
||||||
|
#
|
||||||
|
# Duis aute irure dolor
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
#
|
||||||
|
# -> in
|
||||||
|
# <- out
|
||||||
|
# Examples:
|
||||||
|
# - *verbatim*
|
||||||
|
# - {braces}
|
||||||
|
##
|
||||||
|
|
||||||
|
##
|
||||||
|
# @Enum:
|
||||||
|
# == Produces *invalid* texinfo
|
||||||
|
# @one: The _one_ {and only}
|
||||||
|
#
|
||||||
|
# @two is undocumented
|
||||||
|
##
|
||||||
|
{ 'enum': 'Enum', 'data': [ 'one', 'two' ] }
|
||||||
|
|
||||||
|
##
|
||||||
|
# @Base:
|
||||||
|
# @base1:
|
||||||
|
# the first member
|
||||||
|
##
|
||||||
|
{ 'struct': 'Base', 'data': { 'base1': 'Enum' } }
|
||||||
|
|
||||||
|
##
|
||||||
|
# @Variant1:
|
||||||
|
# A paragraph
|
||||||
|
#
|
||||||
|
# Another paragraph (but no @var: line)
|
||||||
|
##
|
||||||
|
{ 'struct': 'Variant1', 'data': { 'var1': 'str' } }
|
||||||
|
|
||||||
|
##
|
||||||
|
# @Variant2:
|
||||||
|
##
|
||||||
|
{ 'struct': 'Variant2', 'data': {} }
|
||||||
|
|
||||||
|
##
|
||||||
|
# @Object:
|
||||||
|
##
|
||||||
|
{ 'union': 'Object',
|
||||||
|
'base': 'Base',
|
||||||
|
'discriminator': 'base1',
|
||||||
|
'data': { 'one': 'Variant1', 'two': 'Variant2' } }
|
||||||
|
|
||||||
|
##
|
||||||
|
# @SugaredUnion:
|
||||||
|
##
|
||||||
|
{ 'union': 'SugaredUnion',
|
||||||
|
'data': { 'one': 'Variant1', 'two': 'Variant2' } }
|
||||||
|
|
||||||
|
##
|
||||||
|
# == Another subsection
|
||||||
|
##
|
||||||
|
|
||||||
|
##
|
||||||
|
# @cmd:
|
||||||
|
# @arg1: the first argument
|
||||||
|
#
|
||||||
|
# @arg2: the second
|
||||||
|
# argument
|
||||||
|
# Note: @arg3 is undocumented
|
||||||
|
# Returns: @Object
|
||||||
|
# TODO: frobnicate
|
||||||
|
# Notes:
|
||||||
|
# - Lorem ipsum dolor sit amet
|
||||||
|
# - Ut enim ad minim veniam
|
||||||
|
#
|
||||||
|
# Duis aute irure dolor
|
||||||
|
# Example:
|
||||||
|
#
|
||||||
|
# -> in
|
||||||
|
# <- out
|
||||||
|
# Examples:
|
||||||
|
# - *verbatim*
|
||||||
|
# - {braces}
|
||||||
|
# Since: 2.10
|
||||||
|
##
|
||||||
|
{ 'command': 'cmd',
|
||||||
|
'data': { 'arg1': 'int', '*arg2': 'str', 'arg3': 'bool' },
|
||||||
|
'returns': 'Object' }
|
||||||
|
|
||||||
|
##
|
||||||
|
# @cmd-boxed:
|
||||||
|
# If you're bored enough to read this, go see a video of boxed cats
|
||||||
|
# Example:
|
||||||
|
#
|
||||||
|
# -> in
|
||||||
|
#
|
||||||
|
# <- out
|
||||||
|
##
|
||||||
|
{ 'command': 'cmd-boxed', 'boxed': true,
|
||||||
|
'data': 'Object' }
|
|
@ -0,0 +1,148 @@
|
||||||
|
object Base
|
||||||
|
member base1: Enum optional=False
|
||||||
|
enum Enum ['one', 'two']
|
||||||
|
object Object
|
||||||
|
base Base
|
||||||
|
tag base1
|
||||||
|
case one: Variant1
|
||||||
|
case two: Variant2
|
||||||
|
enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
|
||||||
|
prefix QTYPE
|
||||||
|
object SugaredUnion
|
||||||
|
member type: SugaredUnionKind optional=False
|
||||||
|
tag type
|
||||||
|
case one: q_obj_Variant1-wrapper
|
||||||
|
case two: q_obj_Variant2-wrapper
|
||||||
|
enum SugaredUnionKind ['one', 'two']
|
||||||
|
object Variant1
|
||||||
|
member var1: str optional=False
|
||||||
|
object Variant2
|
||||||
|
command cmd q_obj_cmd-arg -> Object
|
||||||
|
gen=True success_response=True boxed=False
|
||||||
|
command cmd-boxed Object -> None
|
||||||
|
gen=True success_response=True boxed=True
|
||||||
|
object q_empty
|
||||||
|
object q_obj_Variant1-wrapper
|
||||||
|
member data: Variant1 optional=False
|
||||||
|
object q_obj_Variant2-wrapper
|
||||||
|
member data: Variant2 optional=False
|
||||||
|
object q_obj_cmd-arg
|
||||||
|
member arg1: int optional=False
|
||||||
|
member arg2: str optional=True
|
||||||
|
member arg3: bool optional=False
|
||||||
|
doc freeform
|
||||||
|
body=
|
||||||
|
= Section
|
||||||
|
|
||||||
|
== Subsection
|
||||||
|
|
||||||
|
*strong* _with emphasis_
|
||||||
|
@var {in braces}
|
||||||
|
* List item one
|
||||||
|
- Two, multiple
|
||||||
|
lines
|
||||||
|
|
||||||
|
3. Three
|
||||||
|
Still in list
|
||||||
|
|
||||||
|
Not in list
|
||||||
|
- Second list
|
||||||
|
Note: still in list
|
||||||
|
|
||||||
|
Note: not in list
|
||||||
|
1. Third list
|
||||||
|
is numbered
|
||||||
|
|
||||||
|
- another item
|
||||||
|
|
||||||
|
| example
|
||||||
|
| multiple lines
|
||||||
|
|
||||||
|
Returns: the King
|
||||||
|
Since: the first age
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
1. Lorem ipsum dolor sit amet
|
||||||
|
|
||||||
|
2. Ut enim ad minim veniam
|
||||||
|
|
||||||
|
Duis aute irure dolor
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
-> in
|
||||||
|
<- out
|
||||||
|
Examples:
|
||||||
|
- *verbatim*
|
||||||
|
- {braces}
|
||||||
|
doc symbol=Enum
|
||||||
|
body=
|
||||||
|
== Produces *invalid* texinfo
|
||||||
|
arg=one
|
||||||
|
The _one_ {and only}
|
||||||
|
arg=two
|
||||||
|
|
||||||
|
section=
|
||||||
|
@two is undocumented
|
||||||
|
doc symbol=Base
|
||||||
|
body=
|
||||||
|
|
||||||
|
arg=base1
|
||||||
|
the first member
|
||||||
|
doc symbol=Variant1
|
||||||
|
body=
|
||||||
|
A paragraph
|
||||||
|
|
||||||
|
Another paragraph (but no @var: line)
|
||||||
|
arg=var1
|
||||||
|
|
||||||
|
doc symbol=Variant2
|
||||||
|
body=
|
||||||
|
|
||||||
|
doc symbol=Object
|
||||||
|
body=
|
||||||
|
|
||||||
|
doc symbol=SugaredUnion
|
||||||
|
body=
|
||||||
|
|
||||||
|
arg=type
|
||||||
|
|
||||||
|
doc freeform
|
||||||
|
body=
|
||||||
|
== Another subsection
|
||||||
|
doc symbol=cmd
|
||||||
|
body=
|
||||||
|
|
||||||
|
arg=arg1
|
||||||
|
the first argument
|
||||||
|
arg=arg2
|
||||||
|
the second
|
||||||
|
argument
|
||||||
|
arg=arg3
|
||||||
|
|
||||||
|
section=Note
|
||||||
|
@arg3 is undocumented
|
||||||
|
section=Returns
|
||||||
|
@Object
|
||||||
|
section=TODO
|
||||||
|
frobnicate
|
||||||
|
section=Notes
|
||||||
|
- Lorem ipsum dolor sit amet
|
||||||
|
- Ut enim ad minim veniam
|
||||||
|
|
||||||
|
Duis aute irure dolor
|
||||||
|
section=Example
|
||||||
|
-> in
|
||||||
|
<- out
|
||||||
|
section=Examples
|
||||||
|
- *verbatim*
|
||||||
|
- {braces}
|
||||||
|
section=Since
|
||||||
|
2.10
|
||||||
|
doc symbol=cmd-boxed
|
||||||
|
body=
|
||||||
|
If you're bored enough to read this, go see a video of boxed cats
|
||||||
|
section=Example
|
||||||
|
-> in
|
||||||
|
|
||||||
|
<- out
|
|
@ -0,0 +1,243 @@
|
||||||
|
@section Section
|
||||||
|
|
||||||
|
@subsection Subsection
|
||||||
|
|
||||||
|
@strong{strong} @emph{with emphasis}
|
||||||
|
@code{var} @{in braces@}
|
||||||
|
@itemize @bullet
|
||||||
|
@item
|
||||||
|
List item one
|
||||||
|
@item
|
||||||
|
Two, multiple
|
||||||
|
lines
|
||||||
|
|
||||||
|
@item
|
||||||
|
Three
|
||||||
|
Still in list
|
||||||
|
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
Not in list
|
||||||
|
@itemize @minus
|
||||||
|
@item
|
||||||
|
Second list
|
||||||
|
Note: still in list
|
||||||
|
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
Note: not in list
|
||||||
|
@enumerate
|
||||||
|
@item
|
||||||
|
Third list
|
||||||
|
is numbered
|
||||||
|
|
||||||
|
@item
|
||||||
|
another item
|
||||||
|
|
||||||
|
@example
|
||||||
|
example
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@example
|
||||||
|
multiple lines
|
||||||
|
@end example
|
||||||
|
|
||||||
|
|
||||||
|
@end enumerate
|
||||||
|
|
||||||
|
Returns: the King
|
||||||
|
Since: the first age
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
@enumerate
|
||||||
|
@item
|
||||||
|
Lorem ipsum dolor sit amet
|
||||||
|
|
||||||
|
@item
|
||||||
|
Ut enim ad minim veniam
|
||||||
|
|
||||||
|
@end enumerate
|
||||||
|
|
||||||
|
Duis aute irure dolor
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
-> in
|
||||||
|
<- out
|
||||||
|
Examples:
|
||||||
|
@itemize @minus
|
||||||
|
@item
|
||||||
|
@strong{verbatim}
|
||||||
|
@item
|
||||||
|
@{braces@}
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@deftp {Enum} Enum
|
||||||
|
|
||||||
|
@subsection Produces @strong{invalid} texinfo
|
||||||
|
|
||||||
|
@b{Values:}
|
||||||
|
@table @asis
|
||||||
|
@item @code{one}
|
||||||
|
The @emph{one} @{and only@}
|
||||||
|
@item @code{two}
|
||||||
|
Not documented
|
||||||
|
@end table
|
||||||
|
@code{two} is undocumented
|
||||||
|
|
||||||
|
@end deftp
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@deftp {Object} Base
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@b{Members:}
|
||||||
|
@table @asis
|
||||||
|
@item @code{base1: Enum}
|
||||||
|
the first member
|
||||||
|
@end table
|
||||||
|
|
||||||
|
|
||||||
|
@end deftp
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@deftp {Object} Variant1
|
||||||
|
|
||||||
|
A paragraph
|
||||||
|
|
||||||
|
Another paragraph (but no @code{var}: line)
|
||||||
|
|
||||||
|
@b{Members:}
|
||||||
|
@table @asis
|
||||||
|
@item @code{var1: string}
|
||||||
|
Not documented
|
||||||
|
@end table
|
||||||
|
|
||||||
|
|
||||||
|
@end deftp
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@deftp {Object} Variant2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@end deftp
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@deftp {Object} Object
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@b{Members:}
|
||||||
|
@table @asis
|
||||||
|
@item The members of @code{Base}
|
||||||
|
@item The members of @code{Variant1} when @code{base1} is @t{"one"}
|
||||||
|
@item The members of @code{Variant2} when @code{base1} is @t{"two"}
|
||||||
|
@end table
|
||||||
|
|
||||||
|
|
||||||
|
@end deftp
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@deftp {Object} SugaredUnion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@b{Members:}
|
||||||
|
@table @asis
|
||||||
|
@item @code{type}
|
||||||
|
One of @t{"one"}, @t{"two"}
|
||||||
|
@item @code{data: Variant1} when @code{type} is @t{"one"}
|
||||||
|
@item @code{data: Variant2} when @code{type} is @t{"two"}
|
||||||
|
@end table
|
||||||
|
|
||||||
|
|
||||||
|
@end deftp
|
||||||
|
|
||||||
|
|
||||||
|
@subsection Another subsection
|
||||||
|
|
||||||
|
|
||||||
|
@deftypefn Command {} cmd
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@b{Arguments:}
|
||||||
|
@table @asis
|
||||||
|
@item @code{arg1: int}
|
||||||
|
the first argument
|
||||||
|
@item @code{arg2: string} (optional)
|
||||||
|
the second
|
||||||
|
argument
|
||||||
|
@item @code{arg3: boolean}
|
||||||
|
Not documented
|
||||||
|
@end table
|
||||||
|
|
||||||
|
|
||||||
|
@b{Note:}
|
||||||
|
@code{arg3} is undocumented
|
||||||
|
|
||||||
|
@b{Returns:}
|
||||||
|
@code{Object}
|
||||||
|
|
||||||
|
@b{TODO:}
|
||||||
|
frobnicate
|
||||||
|
|
||||||
|
@b{Notes:}
|
||||||
|
@itemize @minus
|
||||||
|
@item
|
||||||
|
Lorem ipsum dolor sit amet
|
||||||
|
@item
|
||||||
|
Ut enim ad minim veniam
|
||||||
|
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
Duis aute irure dolor
|
||||||
|
|
||||||
|
@b{Example:}
|
||||||
|
@example
|
||||||
|
-> in
|
||||||
|
<- out
|
||||||
|
@end example
|
||||||
|
|
||||||
|
|
||||||
|
@b{Examples:}
|
||||||
|
@example
|
||||||
|
- *verbatim*
|
||||||
|
- @{braces@}
|
||||||
|
@end example
|
||||||
|
|
||||||
|
|
||||||
|
@b{Since:}
|
||||||
|
2.10
|
||||||
|
|
||||||
|
@end deftypefn
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@deftypefn Command {} cmd-boxed
|
||||||
|
|
||||||
|
If you're bored enough to read this, go see a video of boxed cats
|
||||||
|
|
||||||
|
@b{Arguments:} the members of @code{Object}
|
||||||
|
|
||||||
|
@b{Example:}
|
||||||
|
@example
|
||||||
|
-> in
|
||||||
|
|
||||||
|
<- out
|
||||||
|
@end example
|
||||||
|
|
||||||
|
|
||||||
|
@end deftypefn
|
||||||
|
|
||||||
|
|
|
@ -55,3 +55,14 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
|
||||||
|
|
||||||
schema = QAPISchema(sys.argv[1])
|
schema = QAPISchema(sys.argv[1])
|
||||||
schema.visit(QAPISchemaTestVisitor())
|
schema.visit(QAPISchemaTestVisitor())
|
||||||
|
|
||||||
|
for doc in schema.docs:
|
||||||
|
if doc.symbol:
|
||||||
|
print 'doc symbol=%s' % doc.symbol
|
||||||
|
else:
|
||||||
|
print 'doc freeform'
|
||||||
|
print ' body=\n%s' % doc.body
|
||||||
|
for arg, section in doc.args.iteritems():
|
||||||
|
print ' arg=%s\n%s' % (arg, section)
|
||||||
|
for section in doc.sections:
|
||||||
|
print ' section=%s\n%s' % (section.name, section)
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
#include "qapi/qmp/qstring.h"
|
#include "qapi/qmp/qstring.h"
|
||||||
#include "qapi/qobject-input-visitor.h"
|
#include "qapi/qobject-input-visitor.h"
|
||||||
|
#include "test-qapi-visit.h"
|
||||||
#include "qemu/cutils.h"
|
#include "qemu/cutils.h"
|
||||||
#include "qemu/option.h"
|
#include "qemu/option.h"
|
||||||
|
|
||||||
|
@ -218,14 +219,14 @@ static void test_keyval_parse_list(void)
|
||||||
QDECREF(qdict);
|
QDECREF(qdict);
|
||||||
|
|
||||||
/* Multiple indexes, last one wins */
|
/* Multiple indexes, last one wins */
|
||||||
qdict = keyval_parse("list.1=goner,list.0=null,list.1=eins,list.2=zwei",
|
qdict = keyval_parse("list.1=goner,list.0=null,list.01=eins,list.2=zwei",
|
||||||
NULL, &error_abort);
|
NULL, &error_abort);
|
||||||
g_assert_cmpint(qdict_size(qdict), ==, 1);
|
g_assert_cmpint(qdict_size(qdict), ==, 1);
|
||||||
check_list012(qdict_get_qlist(qdict, "list"));
|
check_list012(qdict_get_qlist(qdict, "list"));
|
||||||
QDECREF(qdict);
|
QDECREF(qdict);
|
||||||
|
|
||||||
/* List at deeper nesting */
|
/* List at deeper nesting */
|
||||||
qdict = keyval_parse("a.list.1=eins,a.list.0=null,a.list.2=zwei",
|
qdict = keyval_parse("a.list.1=eins,a.list.00=null,a.list.2=zwei",
|
||||||
NULL, &error_abort);
|
NULL, &error_abort);
|
||||||
g_assert_cmpint(qdict_size(qdict), ==, 1);
|
g_assert_cmpint(qdict_size(qdict), ==, 1);
|
||||||
sub_qdict = qdict_get_qdict(qdict, "a");
|
sub_qdict = qdict_get_qdict(qdict, "a");
|
||||||
|
@ -242,7 +243,7 @@ static void test_keyval_parse_list(void)
|
||||||
g_assert(!qdict);
|
g_assert(!qdict);
|
||||||
|
|
||||||
/* Missing list indexes */
|
/* Missing list indexes */
|
||||||
qdict = keyval_parse("list.2=lonely", NULL, &err);
|
qdict = keyval_parse("list.1=lonely", NULL, &err);
|
||||||
error_free_or_abort(&err);
|
error_free_or_abort(&err);
|
||||||
g_assert(!qdict);
|
g_assert(!qdict);
|
||||||
qdict = keyval_parse("list.0=null,list.2=eins,list.02=zwei", NULL, &err);
|
qdict = keyval_parse("list.0=null,list.2=eins,list.02=zwei", NULL, &err);
|
||||||
|
@ -608,6 +609,56 @@ static void test_keyval_visit_optional(void)
|
||||||
visit_free(v);
|
visit_free(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_keyval_visit_alternate(void)
|
||||||
|
{
|
||||||
|
Error *err = NULL;
|
||||||
|
Visitor *v;
|
||||||
|
QDict *qdict;
|
||||||
|
AltNumStr *ans;
|
||||||
|
AltNumInt *ani;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Can't do scalar alternate variants other than string. You get
|
||||||
|
* the string variant if there is one, else an error.
|
||||||
|
*/
|
||||||
|
qdict = keyval_parse("a=1,b=2", NULL, &error_abort);
|
||||||
|
v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
|
||||||
|
QDECREF(qdict);
|
||||||
|
visit_start_struct(v, NULL, NULL, 0, &error_abort);
|
||||||
|
visit_type_AltNumStr(v, "a", &ans, &error_abort);
|
||||||
|
g_assert_cmpint(ans->type, ==, QTYPE_QSTRING);
|
||||||
|
g_assert_cmpstr(ans->u.s, ==, "1");
|
||||||
|
visit_type_AltNumInt(v, "a", &ani, &err);
|
||||||
|
error_free_or_abort(&err);
|
||||||
|
visit_end_struct(v, NULL);
|
||||||
|
visit_free(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_keyval_visit_any(void)
|
||||||
|
{
|
||||||
|
Visitor *v;
|
||||||
|
QDict *qdict;
|
||||||
|
QObject *any;
|
||||||
|
QList *qlist;
|
||||||
|
QString *qstr;
|
||||||
|
|
||||||
|
qdict = keyval_parse("a.0=null,a.1=1", NULL, &error_abort);
|
||||||
|
v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
|
||||||
|
QDECREF(qdict);
|
||||||
|
visit_start_struct(v, NULL, NULL, 0, &error_abort);
|
||||||
|
visit_type_any(v, "a", &any, &error_abort);
|
||||||
|
qlist = qobject_to_qlist(any);
|
||||||
|
g_assert(qlist);
|
||||||
|
qstr = qobject_to_qstring(qlist_pop(qlist));
|
||||||
|
g_assert_cmpstr(qstring_get_str(qstr), ==, "null");
|
||||||
|
qstr = qobject_to_qstring(qlist_pop(qlist));
|
||||||
|
g_assert_cmpstr(qstring_get_str(qstr), ==, "1");
|
||||||
|
g_assert(qlist_empty(qlist));
|
||||||
|
visit_check_struct(v, &error_abort);
|
||||||
|
visit_end_struct(v, NULL);
|
||||||
|
visit_free(v);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
g_test_init(&argc, &argv, NULL);
|
g_test_init(&argc, &argv, NULL);
|
||||||
|
@ -619,6 +670,8 @@ int main(int argc, char *argv[])
|
||||||
g_test_add_func("/keyval/visit/dict", test_keyval_visit_dict);
|
g_test_add_func("/keyval/visit/dict", test_keyval_visit_dict);
|
||||||
g_test_add_func("/keyval/visit/list", test_keyval_visit_list);
|
g_test_add_func("/keyval/visit/list", test_keyval_visit_list);
|
||||||
g_test_add_func("/keyval/visit/optional", test_keyval_visit_optional);
|
g_test_add_func("/keyval/visit/optional", test_keyval_visit_optional);
|
||||||
|
g_test_add_func("/keyval/visit/alternate", test_keyval_visit_alternate);
|
||||||
|
g_test_add_func("/keyval/visit/any", test_keyval_visit_any);
|
||||||
g_test_run();
|
g_test_run();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -175,6 +175,7 @@ expect_u64_max(OptsVisitorFixture *f, gconstpointer test_data)
|
||||||
static void
|
static void
|
||||||
test_opts_range_unvisited(void)
|
test_opts_range_unvisited(void)
|
||||||
{
|
{
|
||||||
|
Error *err = NULL;
|
||||||
intList *list = NULL;
|
intList *list = NULL;
|
||||||
intList *tail;
|
intList *tail;
|
||||||
QemuOpts *opts;
|
QemuOpts *opts;
|
||||||
|
@ -199,10 +200,11 @@ test_opts_range_unvisited(void)
|
||||||
g_assert_cmpint(tail->value, ==, 1);
|
g_assert_cmpint(tail->value, ==, 1);
|
||||||
tail = (intList *)visit_next_list(v, (GenericList *)tail, sizeof(*list));
|
tail = (intList *)visit_next_list(v, (GenericList *)tail, sizeof(*list));
|
||||||
g_assert(tail);
|
g_assert(tail);
|
||||||
visit_check_list(v, &error_abort); /* BUG: unvisited tail not reported */
|
visit_check_list(v, &error_abort); /* unvisited tail ignored until... */
|
||||||
visit_end_list(v, (void **)&list);
|
visit_end_list(v, (void **)&list);
|
||||||
|
|
||||||
visit_check_struct(v, &error_abort);
|
visit_check_struct(v, &err); /* ...here */
|
||||||
|
error_free_or_abort(&err);
|
||||||
visit_end_struct(v, NULL);
|
visit_end_struct(v, NULL);
|
||||||
|
|
||||||
qapi_free_intList(list);
|
qapi_free_intList(list);
|
||||||
|
@ -247,6 +249,25 @@ test_opts_range_beyond(void)
|
||||||
qemu_opts_del(opts);
|
qemu_opts_del(opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_opts_dict_unvisited(void)
|
||||||
|
{
|
||||||
|
Error *err = NULL;
|
||||||
|
QemuOpts *opts;
|
||||||
|
Visitor *v;
|
||||||
|
UserDefOptions *userdef;
|
||||||
|
|
||||||
|
opts = qemu_opts_parse(qemu_find_opts("userdef"), "i64x=0,bogus=1", false,
|
||||||
|
&error_abort);
|
||||||
|
|
||||||
|
v = opts_visitor_new(opts);
|
||||||
|
visit_type_UserDefOptions(v, NULL, &userdef, &err);
|
||||||
|
error_free_or_abort(&err);
|
||||||
|
visit_free(v);
|
||||||
|
qemu_opts_del(opts);
|
||||||
|
g_assert(!userdef);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
@ -343,6 +364,8 @@ main(int argc, char **argv)
|
||||||
g_test_add_func("/visitor/opts/range/beyond",
|
g_test_add_func("/visitor/opts/range/beyond",
|
||||||
test_opts_range_beyond);
|
test_opts_range_beyond);
|
||||||
|
|
||||||
|
g_test_add_func("/visitor/opts/dict/unvisited", test_opts_dict_unvisited);
|
||||||
|
|
||||||
g_test_run();
|
g_test_run();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,6 +116,34 @@ static void test_visitor_in_int(TestInputVisitorData *data,
|
||||||
g_assert_cmpint(res, ==, value);
|
g_assert_cmpint(res, ==, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_visitor_in_uint(TestInputVisitorData *data,
|
||||||
|
const void *unused)
|
||||||
|
{
|
||||||
|
Error *err = NULL;
|
||||||
|
uint64_t res = 0;
|
||||||
|
int value = 42;
|
||||||
|
Visitor *v;
|
||||||
|
|
||||||
|
v = visitor_input_test_init(data, "%d", value);
|
||||||
|
|
||||||
|
visit_type_uint64(v, NULL, &res, &error_abort);
|
||||||
|
g_assert_cmpuint(res, ==, (uint64_t)value);
|
||||||
|
|
||||||
|
/* BUG: value between INT64_MIN and -1 accepted modulo 2^64 */
|
||||||
|
|
||||||
|
v = visitor_input_test_init(data, "%d", -value);
|
||||||
|
|
||||||
|
visit_type_uint64(v, NULL, &res, &error_abort);
|
||||||
|
g_assert_cmpuint(res, ==, (uint64_t)-value);
|
||||||
|
|
||||||
|
/* BUG: value between INT64_MAX+1 and UINT64_MAX rejected */
|
||||||
|
|
||||||
|
v = visitor_input_test_init(data, "18446744073709551574");
|
||||||
|
|
||||||
|
visit_type_uint64(v, NULL, &res, &err);
|
||||||
|
error_free_or_abort(&err);
|
||||||
|
}
|
||||||
|
|
||||||
static void test_visitor_in_int_overflow(TestInputVisitorData *data,
|
static void test_visitor_in_int_overflow(TestInputVisitorData *data,
|
||||||
const void *unused)
|
const void *unused)
|
||||||
{
|
{
|
||||||
|
@ -1225,6 +1253,8 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
input_visitor_test_add("/visitor/input/int",
|
input_visitor_test_add("/visitor/input/int",
|
||||||
NULL, test_visitor_in_int);
|
NULL, test_visitor_in_int);
|
||||||
|
input_visitor_test_add("/visitor/input/uint",
|
||||||
|
NULL, test_visitor_in_uint);
|
||||||
input_visitor_test_add("/visitor/input/int_overflow",
|
input_visitor_test_add("/visitor/input/int_overflow",
|
||||||
NULL, test_visitor_in_int_overflow);
|
NULL, test_visitor_in_int_overflow);
|
||||||
input_visitor_test_add("/visitor/input/int_keyval",
|
input_visitor_test_add("/visitor/input/int_keyval",
|
||||||
|
|
|
@ -63,6 +63,11 @@ static void test_visitor_in_int(TestInputVisitorData *data,
|
||||||
|
|
||||||
visit_type_int(v, NULL, &res, &err);
|
visit_type_int(v, NULL, &res, &err);
|
||||||
error_free_or_abort(&err);
|
error_free_or_abort(&err);
|
||||||
|
|
||||||
|
v = visitor_input_test_init(data, "");
|
||||||
|
|
||||||
|
visit_type_int(v, NULL, &res, &err);
|
||||||
|
error_free_or_abort(&err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void check_ilist(Visitor *v, int64_t *expected, size_t n)
|
static void check_ilist(Visitor *v, int64_t *expected, size_t n)
|
||||||
|
@ -140,11 +145,11 @@ static void test_visitor_in_intList(TestInputVisitorData *data,
|
||||||
v = visitor_input_test_init(data, "18446744073709551615");
|
v = visitor_input_test_init(data, "18446744073709551615");
|
||||||
check_ulist(v, expect4, ARRAY_SIZE(expect4));
|
check_ulist(v, expect4, ARRAY_SIZE(expect4));
|
||||||
|
|
||||||
/* Empty list is invalid (weird) */
|
/* Empty list */
|
||||||
|
|
||||||
v = visitor_input_test_init(data, "");
|
v = visitor_input_test_init(data, "");
|
||||||
visit_type_int64List(v, NULL, &res, &err);
|
visit_type_int64List(v, NULL, &res, &error_abort);
|
||||||
error_free_or_abort(&err);
|
g_assert(!res);
|
||||||
|
|
||||||
/* Not a list */
|
/* Not a list */
|
||||||
|
|
||||||
|
|
|
@ -21,22 +21,36 @@
|
||||||
*
|
*
|
||||||
* Semantics defined by reduction to JSON:
|
* Semantics defined by reduction to JSON:
|
||||||
*
|
*
|
||||||
* key-vals is a tree of objects and arrays rooted at object R
|
* key-vals specifies a JSON object, i.e. a tree whose root is an
|
||||||
* where for each key-val = key-fragment . ... = val in key-vals
|
* object, inner nodes other than the root are objects or arrays,
|
||||||
* R op key-fragment op ... = val'
|
* and leaves are strings.
|
||||||
* where (left-associative) op is
|
|
||||||
* array subscript L[key-fragment] for numeric key-fragment
|
|
||||||
* member reference L.key-fragment otherwise
|
|
||||||
* val' is val with ',,' replaced by ','
|
|
||||||
* and only R may be empty.
|
|
||||||
*
|
*
|
||||||
* Duplicate keys are permitted; all but the last one are ignored.
|
* Each key-val = key-fragment '.' ... '=' val specifies a path from
|
||||||
|
* root to a leaf (left of '='), and the leaf's value (right of
|
||||||
|
* '=').
|
||||||
*
|
*
|
||||||
* The equations must have a solution. Counter-example: a.b=1,a=2
|
* A path from the root is defined recursively:
|
||||||
* doesn't have one, because R.a must be an object to satisfy a.b=1
|
* L '.' key-fragment is a child of the node denoted by path L
|
||||||
* and a string to satisfy a=2.
|
* key-fragment is a child of the tree root
|
||||||
|
* If key-fragment is numeric, the parent is an array and the child
|
||||||
|
* is its key-fragment-th member, counting from zero.
|
||||||
|
* Else, the parent is an object, and the child is its member named
|
||||||
|
* key-fragment.
|
||||||
*
|
*
|
||||||
* Key-fragments must be valid QAPI names or consist only of digits.
|
* This constrains inner nodes to be either array or object. The
|
||||||
|
* constraints must be satisfiable. Counter-example: a.b=1,a=2 is
|
||||||
|
* not, because root.a must be an object to satisfy a.b=1 and a
|
||||||
|
* string to satisfy a=2.
|
||||||
|
*
|
||||||
|
* Array subscripts can occur in any order, but the set of
|
||||||
|
* subscripts must not have gaps. For instance, a.1=v is not okay,
|
||||||
|
* because root.a[0] is missing.
|
||||||
|
*
|
||||||
|
* If multiple key-val denote the same leaf, the last one determines
|
||||||
|
* the value.
|
||||||
|
*
|
||||||
|
* Key-fragments must be valid QAPI names or consist only of decimal
|
||||||
|
* digits.
|
||||||
*
|
*
|
||||||
* The length of any key-fragment must be between 1 and 127.
|
* The length of any key-fragment must be between 1 and 127.
|
||||||
*
|
*
|
||||||
|
@ -47,6 +61,16 @@
|
||||||
* "key absent" already means "optional object/array absent", which
|
* "key absent" already means "optional object/array absent", which
|
||||||
* isn't the same as "empty object/array present".
|
* isn't the same as "empty object/array present".
|
||||||
*
|
*
|
||||||
|
* Design flaw: scalar values can only be strings; there is no way to
|
||||||
|
* denote numbers, true, false or null. The special QObject input
|
||||||
|
* visitor returned by qobject_input_visitor_new_keyval() mostly hides
|
||||||
|
* this by automatically converting strings to the type the visitor
|
||||||
|
* expects. Breaks down for alternate types and type 'any', where the
|
||||||
|
* visitor's expectation isn't clear. Code visiting such types needs
|
||||||
|
* to do the conversion itself, but only when using this keyval
|
||||||
|
* visitor. Awkward. Alternate types without a string member don't
|
||||||
|
* work at all.
|
||||||
|
*
|
||||||
* Additional syntax for use with an implied key:
|
* Additional syntax for use with an implied key:
|
||||||
*
|
*
|
||||||
* key-vals-ik = val-no-key [ ',' key-vals ]
|
* key-vals-ik = val-no-key [ ',' key-vals ]
|
||||||
|
@ -64,8 +88,8 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convert @key to a list index.
|
* Convert @key to a list index.
|
||||||
* Convert all leading digits to a (non-negative) number, capped at
|
* Convert all leading decimal digits to a (non-negative) number,
|
||||||
* INT_MAX.
|
* capped at INT_MAX.
|
||||||
* If @end is non-null, assign a pointer to the first character after
|
* If @end is non-null, assign a pointer to the first character after
|
||||||
* the number to *@end.
|
* the number to *@end.
|
||||||
* Else, fail if any characters follow.
|
* Else, fail if any characters follow.
|
||||||
|
@ -337,7 +361,8 @@ static QObject *keyval_listify(QDict *cur, GSList *key_of_cur, Error **errp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make a list from @elt[], reporting any missing elements.
|
* Make a list from @elt[], reporting the first missing element,
|
||||||
|
* if any.
|
||||||
* If we dropped an index >= nelt in the previous loop, this loop
|
* If we dropped an index >= nelt in the previous loop, this loop
|
||||||
* will run into the sentinel and report index @nelt missing.
|
* will run into the sentinel and report index @nelt missing.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue